diff options
Diffstat (limited to 'oox/source')
54 files changed, 2247 insertions, 1136 deletions
diff --git a/oox/source/core/fasttokenhandler.cxx b/oox/source/core/fasttokenhandler.cxx new file mode 100644 index 000000000000..cb8841b7dc9f --- /dev/null +++ b/oox/source/core/fasttokenhandler.cxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: tokenmap.cxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/core/fasttokenhandler.hxx" +#include <osl/mutex.hxx> +#include "oox/token/tokenmap.hxx" + +using ::rtl::OUString; +using ::osl::Mutex; +using ::osl::MutexGuard; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::RuntimeException; + +namespace oox { +namespace core { + +// ============================================================================ + +namespace { + +Mutex& lclGetTokenMutex() +{ + static Mutex aMutex; + return aMutex; +} + +} // namespace + +// ============================================================================ + +FastTokenHandler::FastTokenHandler() : + mrTokenMap( StaticTokenMap::get() ) +{ +} + +FastTokenHandler::~FastTokenHandler() +{ +} + +sal_Int32 FastTokenHandler::getToken( const OUString& rIdentifier ) throw( RuntimeException ) +{ + MutexGuard aGuard( lclGetTokenMutex() ); + return mrTokenMap.getTokenFromUnicode( rIdentifier ); +} + +OUString FastTokenHandler::getIdentifier( sal_Int32 nToken ) throw( RuntimeException ) +{ + MutexGuard aGuard( lclGetTokenMutex() ); + return mrTokenMap.getUnicodeTokenName( nToken ); +} + +Sequence< sal_Int8 > FastTokenHandler::getUTF8Identifier( sal_Int32 nToken ) throw( RuntimeException ) +{ + MutexGuard aGuard( lclGetTokenMutex() ); + return mrTokenMap.getUtf8TokenName( nToken ); +} + +sal_Int32 FastTokenHandler::getTokenFromUTF8( const Sequence< sal_Int8 >& rIdentifier ) throw( RuntimeException ) +{ + MutexGuard aGuard( lclGetTokenMutex() ); + return mrTokenMap.getTokenFromUtf8( rIdentifier ); +} + +// ============================================================================ + +} // namespace core +} // namespace oox + diff --git a/oox/source/core/filterbase.cxx b/oox/source/core/filterbase.cxx index 55793859fe2e..d289255bac98 100644 --- a/oox/source/core/filterbase.cxx +++ b/oox/source/core/filterbase.cxx @@ -471,7 +471,19 @@ sal_Int32 FilterBase::getSystemColor( sal_Int32 nToken, sal_Int32 nDefaultRgb ) { FilterBaseImpl::SystemPalette::const_iterator aIt = mxImpl->maSystemPalette.find( nToken ); OSL_ENSURE( aIt != mxImpl->maSystemPalette.end(), "FilterBase::getSystemColor - invalid token identifier" ); - return (aIt == mxImpl->maSystemPalette.end()) ? ((nDefaultRgb < 0) ? API_RGB_WHITE : nDefaultRgb) : aIt->second; + return (aIt == mxImpl->maSystemPalette.end()) ? nDefaultRgb : aIt->second; +} + +sal_Int32 FilterBase::getSchemeColor( sal_Int32 /*nToken*/ ) const +{ + OSL_ENSURE( false, "FilterBase::getSchemeColor - scheme colors not implemented" ); + return API_RGB_TRANSPARENT; +} + +sal_Int32 FilterBase::getPaletteColor( sal_Int32 /*nPaletteIdx*/ ) const +{ + OSL_ENSURE( false, "FilterBase::getPaletteColor - palette colors not implemented" ); + return API_RGB_TRANSPARENT; } OUString FilterBase::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) const diff --git a/oox/source/core/makefile.mk b/oox/source/core/makefile.mk index 51804e1d04c8..84d12776eadd 100644 --- a/oox/source/core/makefile.mk +++ b/oox/source/core/makefile.mk @@ -54,6 +54,7 @@ SLOFILES = \ $(SLO)$/contexthandler.obj \ $(SLO)$/contexthandler2.obj \ $(SLO)$/facreg.obj \ + $(SLO)$/fasttokenhandler.obj \ $(SLO)$/filterbase.obj \ $(SLO)$/filterdetect.obj \ $(SLO)$/fragmenthandler.obj \ diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx index 27b3eef0ce60..07652c5c447b 100644 --- a/oox/source/core/xmlfilterbase.cxx +++ b/oox/source/core/xmlfilterbase.cxx @@ -32,6 +32,7 @@ #include <cstdio> +#include <rtl/strbuf.hxx> #include <rtl/ustrbuf.hxx> #include <com/sun/star/container/XNameContainer.hpp> #include <com/sun/star/embed/XRelationshipAccess.hpp> @@ -52,6 +53,7 @@ #include "oox/core/recordparser.hxx" #include "oox/core/relationshandler.hxx" +using ::rtl::OStringBuffer; using ::rtl::OUString; using ::rtl::OUStringBuffer; using ::com::sun::star::beans::StringPair; @@ -209,8 +211,17 @@ bool XmlFilterBase::importFragment( const ::rtl::Reference< FragmentHandler >& r InputSource aSource; aSource.aInputStream = xInStrm; aSource.sSystemId = aFragmentPath; - xParser->parseStream( aSource ); - return true; + // own try/catch block for showing parser failure assertion with fragment path + try + { + xParser->parseStream( aSource ); + return true; + } + catch( Exception& ) + { + OSL_ENSURE( false, OStringBuffer( "XmlFilterBase::importFragment - XML parser failed in fragment '" ). + append( OUStringToOString( aFragmentPath, RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() ); + } } catch( Exception& ) { diff --git a/oox/source/drawingml/chart/objectformatter.cxx b/oox/source/drawingml/chart/objectformatter.cxx index 6ddb72bd3040..46253e92dd68 100644 --- a/oox/source/drawingml/chart/objectformatter.cxx +++ b/oox/source/drawingml/chart/objectformatter.cxx @@ -892,7 +892,7 @@ void LineFormatter::convertFormatting( PropertySet& rPropSet, const ModelRef< Sh aLineProps.assignUsed( *mxAutoLine ); if( rxShapeProp.is() ) aLineProps.assignUsed( rxShapeProp->getLineProperties() ); - aLineProps.pushToPropSet( rPropSet, mrLinePropIds, mrData.mrFilter, mrData.maModelObjHelper, getPhColor( nSeriesIdx ) ); + aLineProps.pushToPropSet( rPropSet, mrData.mrFilter, mrData.maModelObjHelper, mrLinePropIds, getPhColor( nSeriesIdx ) ); } // ============================================================================ @@ -920,7 +920,7 @@ void FillFormatter::convertFormatting( PropertySet& rPropSet, const ModelRef< Sh aFillProps.assignUsed( rxShapeProp->getFillProperties() ); if( pPicOptions ) lclConvertPictureOptions( aFillProps, *pPicOptions ); - aFillProps.pushToPropSet( rPropSet, mrFillPropIds, mrData.mrFilter, mrData.maModelObjHelper, 0, getPhColor( nSeriesIdx ) ); + aFillProps.pushToPropSet( rPropSet, mrData.mrFilter, mrData.maModelObjHelper, mrFillPropIds, 0, getPhColor( nSeriesIdx ) ); } // ============================================================================ diff --git a/oox/source/drawingml/clrschemecontext.cxx b/oox/source/drawingml/clrschemecontext.cxx index 6eedb908c00e..a8fa5d737c63 100644 --- a/oox/source/drawingml/clrschemecontext.cxx +++ b/oox/source/drawingml/clrschemecontext.cxx @@ -30,6 +30,7 @@ #include "oox/drawingml/clrschemecontext.hxx" #include "oox/core/namespaces.hxx" +#include "oox/core/xmlfilterbase.hxx" #include "tokens.hxx" using namespace ::oox::core; diff --git a/oox/source/drawingml/color.cxx b/oox/source/drawingml/color.cxx index c269379b5adc..009be55424f3 100644 --- a/oox/source/drawingml/color.cxx +++ b/oox/source/drawingml/color.cxx @@ -29,11 +29,15 @@ ************************************************************************/ #include "oox/drawingml/color.hxx" -#include "oox/core/namespaces.hxx" -#include "oox/core/xmlfilterbase.hxx" -#include "tokens.hxx" #include <algorithm> #include <math.h> +#include "tokens.hxx" +#include "oox/helper/containerhelper.hxx" +#include "oox/core/namespaces.hxx" +#include "oox/core/filterbase.hxx" +#include "oox/drawingml/drawingmltypes.hxx" + +using ::rtl::OUString; namespace oox { namespace drawingml { @@ -42,164 +46,127 @@ namespace drawingml { namespace { -const sal_Int32 PER_PERCENT = 1000; -const sal_Int32 MAX_PERCENT = 100 * PER_PERCENT; +/** Global storage for predefined color values used in OOXML file formats. */ +struct PresetColorsPool +{ + typedef ::std::vector< sal_Int32 > ColorVector; -const sal_Int32 PER_DEGREE = 60000; -const sal_Int32 MAX_DEGREE = 360 * PER_DEGREE; + ColorVector maDmlColors; /// Predefined colors in DrawingML, indexed by XML token. + ColorVector maVmlColors; /// Predefined colors in VML, indexed by XML token. -const double DEC_GAMMA = 2.3; -const double INC_GAMMA = 1.0 / DEC_GAMMA; + explicit PresetColorsPool(); +}; -sal_Int32 lclGetPresetColor( sal_Int32 nToken ) +// ---------------------------------------------------------------------------- + +PresetColorsPool::PresetColorsPool() : + maDmlColors( static_cast< size_t >( XML_TOKEN_COUNT ), API_RGB_TRANSPARENT ), + maVmlColors( static_cast< size_t >( XML_TOKEN_COUNT ), API_RGB_TRANSPARENT ) { - switch( nToken ) + // predefined colors in DrawingML (map XML token identifiers to RGB values) + static const sal_Int32 spnDmlColors[] = { - case XML_aliceBlue: return 0xF0F8FF; - case XML_antiqueWhite: return 0xFAEBD7; - case XML_aqua: return 0x00FFFF; - case XML_aquamarine: return 0x7FFFD4; - case XML_azure: return 0xF0FFFF; - case XML_beige: return 0xF5F5DC; - case XML_bisque: return 0xFFE4C4; - case XML_black: return 0x000000; - case XML_blanchedAlmond: return 0xFFEBCD; - case XML_blue: return 0x0000FF; - case XML_blueViolet: return 0x8A2BE2; - case XML_brown: return 0xA52A2A; - case XML_burlyWood: return 0xDEB887; - case XML_cadetBlue: return 0x5F9EA0; - case XML_chartreuse: return 0x7FFF00; - case XML_chocolate: return 0xD2691E; - case XML_coral: return 0xFF7F50; - case XML_cornflowerBlue: return 0x6495ED; - case XML_cornsilk: return 0xFFF8DC; - case XML_crimson: return 0xDC143C; - case XML_cyan: return 0x00FFFF; - case XML_deepPink: return 0xFF1493; - case XML_deepSkyBlue: return 0x00BFFF; - case XML_dimGray: return 0x696969; - case XML_dkBlue: return 0x00008B; - case XML_dkCyan: return 0x008B8B; - case XML_dkGoldenrod: return 0xB8860B; - case XML_dkGray: return 0xA9A9A9; - case XML_dkGreen: return 0x006400; - case XML_dkKhaki: return 0xBDB76B; - case XML_dkMagenta: return 0x8B008B; - case XML_dkOliveGreen: return 0x556B2F; - case XML_dkOrange: return 0xFF8C00; - case XML_dkOrchid: return 0x9932CC; - case XML_dkRed: return 0x8B0000; - case XML_dkSalmon: return 0xE9967A; - case XML_dkSeaGreen: return 0x8FBC8B; - case XML_dkSlateBlue: return 0x483D8B; - case XML_dkSlateGray: return 0x2F4F4F; - case XML_dkTurquoise: return 0x00CED1; - case XML_dkViolet: return 0x9400D3; - case XML_dodgerBlue: return 0x1E90FF; - case XML_firebrick: return 0xB22222; - case XML_floralWhite: return 0xFFFAF0; - case XML_forestGreen: return 0x228B22; - case XML_fuchsia: return 0xFF00FF; - case XML_gainsboro: return 0xDCDCDC; - case XML_ghostWhite: return 0xF8F8FF; - case XML_gold: return 0xFFD700; - case XML_goldenrod: return 0xDAA520; - case XML_gray: return 0x808080; - case XML_green: return 0x008000; - case XML_greenYellow: return 0xADFF2F; - case XML_honeydew: return 0xF0FFF0; - case XML_hotPink: return 0xFF69B4; - case XML_indianRed: return 0xCD5C5C; - case XML_indigo: return 0x4B0082; - case XML_ivory: return 0xFFFFF0; - case XML_khaki: return 0xF0E68C; - case XML_lavender: return 0xE6E6FA; - case XML_lavenderBlush: return 0xFFF0F5; - case XML_lawnGreen: return 0x7CFC00; - case XML_lemonChiffon: return 0xFFFACD; - case XML_lime: return 0x00FF00; - case XML_limeGreen: return 0x32CD32; - case XML_linen: return 0xFAF0E6; - case XML_ltBlue: return 0xADD8E6; - case XML_ltCoral: return 0xF08080; - case XML_ltCyan: return 0xE0FFFF; - case XML_ltGoldenrodYellow: return 0xFAFA78; - case XML_ltGray: return 0xD3D3D3; - case XML_ltGreen: return 0x90EE90; - case XML_ltPink: return 0xFFB6C1; - case XML_ltSalmon: return 0xFFA07A; - case XML_ltSeaGreen: return 0x20B2AA; - case XML_ltSkyBlue: return 0x87CEFA; - case XML_ltSlateGray: return 0x778899; - case XML_ltSteelBlue: return 0xB0C4DE; - case XML_ltYellow: return 0xFFFFE0; - case XML_magenta: return 0xFF00FF; - case XML_maroon: return 0x800000; - case XML_medAquamarine: return 0x66CDAA; - case XML_medBlue: return 0x0000CD; - case XML_medOrchid: return 0xBA55D3; - case XML_medPurple: return 0x9370DB; - case XML_medSeaGreen: return 0x3CB371; - case XML_medSlateBlue: return 0x7B68EE; - case XML_medSpringGreen: return 0x00FA9A; - case XML_medTurquoise: return 0x48D1CC; - case XML_medVioletRed: return 0xC71585; - case XML_midnightBlue: return 0x191970; - case XML_mintCream: return 0xF5FFFA; - case XML_mistyRose: return 0xFFE4E1; - case XML_moccasin: return 0xFFE4B5; - case XML_navajoWhite: return 0xFFDEAD; - case XML_navy: return 0x000080; - case XML_oldLace: return 0xFDF5E6; - case XML_olive: return 0x808000; - case XML_oliveDrab: return 0x6B8E23; - case XML_orange: return 0xFFA500; - case XML_orangeRed: return 0xFF4500; - case XML_orchid: return 0xDA70D6; - case XML_paleGoldenrod: return 0xEEE8AA; - case XML_paleGreen: return 0x98FB98; - case XML_paleTurquoise: return 0xAFEEEE; - case XML_paleVioletRed: return 0xDB7093; - case XML_papayaWhip: return 0xFFEFD5; - case XML_peachPuff: return 0xFFDAB9; - case XML_peru: return 0xCD853F; - case XML_pink: return 0xFFC0CB; - case XML_plum: return 0xDDA0DD; - case XML_powderBlue: return 0xB0E0E6; - case XML_purple: return 0x800080; - case XML_red: return 0xFF0000; - case XML_rosyBrown: return 0xBC8F8F; - case XML_royalBlue: return 0x4169E1; - case XML_saddleBrown: return 0x8B4513; - case XML_salmon: return 0xFA8072; - case XML_sandyBrown: return 0xF4A460; - case XML_seaGreen: return 0x2E8B57; - case XML_seaShell: return 0xFFF5EE; - case XML_sienna: return 0xA0522D; - case XML_silver: return 0xC0C0C0; - case XML_skyBlue: return 0x87CEEB; - case XML_slateBlue: return 0x6A5ACD; - case XML_slateGray: return 0x708090; - case XML_snow: return 0xFFFAFA; - case XML_springGreen: return 0x00FF7F; - case XML_steelBlue: return 0x4682B4; - case XML_tan: return 0xD2B48C; - case XML_teal: return 0x008080; - case XML_thistle: return 0xD8BFD8; - case XML_tomato: return 0xFF6347; - case XML_turquoise: return 0x40E0D0; - case XML_violet: return 0xEE82EE; - case XML_wheat: return 0xF5DEB3; - case XML_white: return 0xFFFFFF; - case XML_whiteSmoke: return 0xF5F5F5; - case XML_yellow: return 0xFFFF00; - case XML_yellowGreen: return 0x9ACD32; - } - OSL_ENSURE( false, "lclGetPresetColor - invalid preset color token" ); - return API_RGB_BLACK; + XML_aliceBlue, 0xF0F8FF, XML_antiqueWhite, 0xFAEBD7, + XML_aqua, 0x00FFFF, XML_aquamarine, 0x7FFFD4, + XML_azure, 0xF0FFFF, XML_beige, 0xF5F5DC, + XML_bisque, 0xFFE4C4, XML_black, 0x000000, + XML_blanchedAlmond, 0xFFEBCD, XML_blue, 0x0000FF, + XML_blueViolet, 0x8A2BE2, XML_brown, 0xA52A2A, + XML_burlyWood, 0xDEB887, XML_cadetBlue, 0x5F9EA0, + XML_chartreuse, 0x7FFF00, XML_chocolate, 0xD2691E, + XML_coral, 0xFF7F50, XML_cornflowerBlue, 0x6495ED, + XML_cornsilk, 0xFFF8DC, XML_crimson, 0xDC143C, + XML_cyan, 0x00FFFF, XML_deepPink, 0xFF1493, + XML_deepSkyBlue, 0x00BFFF, XML_dimGray, 0x696969, + XML_dkBlue, 0x00008B, XML_dkCyan, 0x008B8B, + XML_dkGoldenrod, 0xB8860B, XML_dkGray, 0xA9A9A9, + XML_dkGreen, 0x006400, XML_dkKhaki, 0xBDB76B, + XML_dkMagenta, 0x8B008B, XML_dkOliveGreen, 0x556B2F, + XML_dkOrange, 0xFF8C00, XML_dkOrchid, 0x9932CC, + XML_dkRed, 0x8B0000, XML_dkSalmon, 0xE9967A, + XML_dkSeaGreen, 0x8FBC8B, XML_dkSlateBlue, 0x483D8B, + XML_dkSlateGray, 0x2F4F4F, XML_dkTurquoise, 0x00CED1, + XML_dkViolet, 0x9400D3, XML_dodgerBlue, 0x1E90FF, + XML_firebrick, 0xB22222, XML_floralWhite, 0xFFFAF0, + XML_forestGreen, 0x228B22, XML_fuchsia, 0xFF00FF, + XML_gainsboro, 0xDCDCDC, XML_ghostWhite, 0xF8F8FF, + XML_gold, 0xFFD700, XML_goldenrod, 0xDAA520, + XML_gray, 0x808080, XML_green, 0x008000, + XML_greenYellow, 0xADFF2F, XML_honeydew, 0xF0FFF0, + XML_hotPink, 0xFF69B4, XML_indianRed, 0xCD5C5C, + XML_indigo, 0x4B0082, XML_ivory, 0xFFFFF0, + XML_khaki, 0xF0E68C, XML_lavender, 0xE6E6FA, + XML_lavenderBlush, 0xFFF0F5, XML_lawnGreen, 0x7CFC00, + XML_lemonChiffon, 0xFFFACD, XML_lime, 0x00FF00, + XML_limeGreen, 0x32CD32, XML_linen, 0xFAF0E6, + XML_ltBlue, 0xADD8E6, XML_ltCoral, 0xF08080, + XML_ltCyan, 0xE0FFFF, XML_ltGoldenrodYellow, 0xFAFA78, + XML_ltGray, 0xD3D3D3, XML_ltGreen, 0x90EE90, + XML_ltPink, 0xFFB6C1, XML_ltSalmon, 0xFFA07A, + XML_ltSeaGreen, 0x20B2AA, XML_ltSkyBlue, 0x87CEFA, + XML_ltSlateGray, 0x778899, XML_ltSteelBlue, 0xB0C4DE, + XML_ltYellow, 0xFFFFE0, XML_magenta, 0xFF00FF, + XML_maroon, 0x800000, XML_medAquamarine, 0x66CDAA, + XML_medBlue, 0x0000CD, XML_medOrchid, 0xBA55D3, + XML_medPurple, 0x9370DB, XML_medSeaGreen, 0x3CB371, + XML_medSlateBlue, 0x7B68EE, XML_medSpringGreen, 0x00FA9A, + XML_medTurquoise, 0x48D1CC, XML_medVioletRed, 0xC71585, + XML_midnightBlue, 0x191970, XML_mintCream, 0xF5FFFA, + XML_mistyRose, 0xFFE4E1, XML_moccasin, 0xFFE4B5, + XML_navajoWhite, 0xFFDEAD, XML_navy, 0x000080, + XML_oldLace, 0xFDF5E6, XML_olive, 0x808000, + XML_oliveDrab, 0x6B8E23, XML_orange, 0xFFA500, + XML_orangeRed, 0xFF4500, XML_orchid, 0xDA70D6, + XML_paleGoldenrod, 0xEEE8AA, XML_paleGreen, 0x98FB98, + XML_paleTurquoise, 0xAFEEEE, XML_paleVioletRed, 0xDB7093, + XML_papayaWhip, 0xFFEFD5, XML_peachPuff, 0xFFDAB9, + XML_peru, 0xCD853F, XML_pink, 0xFFC0CB, + XML_plum, 0xDDA0DD, XML_powderBlue, 0xB0E0E6, + XML_purple, 0x800080, XML_red, 0xFF0000, + XML_rosyBrown, 0xBC8F8F, XML_royalBlue, 0x4169E1, + XML_saddleBrown, 0x8B4513, XML_salmon, 0xFA8072, + XML_sandyBrown, 0xF4A460, XML_seaGreen, 0x2E8B57, + XML_seaShell, 0xFFF5EE, XML_sienna, 0xA0522D, + XML_silver, 0xC0C0C0, XML_skyBlue, 0x87CEEB, + XML_slateBlue, 0x6A5ACD, XML_slateGray, 0x708090, + XML_snow, 0xFFFAFA, XML_springGreen, 0x00FF7F, + XML_steelBlue, 0x4682B4, XML_tan, 0xD2B48C, + XML_teal, 0x008080, XML_thistle, 0xD8BFD8, + XML_tomato, 0xFF6347, XML_turquoise, 0x40E0D0, + XML_violet, 0xEE82EE, XML_wheat, 0xF5DEB3, + XML_white, 0xFFFFFF, XML_whiteSmoke, 0xF5F5F5, + XML_yellow, 0xFFFF00, XML_yellowGreen, 0x9ACD32 + }; + for( const sal_Int32* pnEntry = spnDmlColors; pnEntry < STATIC_ARRAY_END( spnDmlColors ); pnEntry += 2 ) + maDmlColors[ static_cast< size_t >( pnEntry[ 0 ] ) ] = pnEntry[ 1 ]; + + // predefined colors in VML (map XML token identifiers to RGB values) + static const sal_Int32 spnVmlColors[] = + { + XML_aqua, 0x00FFFF, XML_black, 0x000000, + XML_blue, 0x0000FF, XML_fuchsia, 0xFF00FF, + XML_gray, 0x808080, XML_green, 0x008000, + XML_lime, 0x00FF00, XML_maroon, 0x800000, + XML_navy, 0x000080, XML_olive, 0x808000, + XML_purple, 0x800080, XML_red, 0xFF0000, + XML_silver, 0xC0C0C0, XML_teal, 0x008080, + XML_white, 0xFFFFFF, XML_yellow, 0xFFFF00 + }; + for( const sal_Int32* pnEntry = spnVmlColors; pnEntry < STATIC_ARRAY_END( spnVmlColors ); pnEntry += 2 ) + maVmlColors[ static_cast< size_t >( pnEntry[ 0 ] ) ] = pnEntry[ 1 ]; } +// ---------------------------------------------------------------------------- + +struct StaticPresetColorsPool : public ::rtl::Static< PresetColorsPool, StaticPresetColorsPool > {}; + +// ---------------------------------------------------------------------------- + +const double DEC_GAMMA = 2.3; +const double INC_GAMMA = 1.0 / DEC_GAMMA; + +// ---------------------------------------------------------------------------- + inline void lclRgbToRgbComponents( sal_Int32& ornR, sal_Int32& ornG, sal_Int32& ornB, sal_Int32 nRgb ) { ornR = (nRgb >> 16) & 0xFF; @@ -248,7 +215,7 @@ void lclOffValue( sal_Int32& ornValue, sal_Int32 nOff, sal_Int32 nMax = MAX_PERC } // namespace -// ---------------------------------------------------------------------------- +// ============================================================================ Color::Color() : meMode( COLOR_UNUSED ), @@ -263,6 +230,24 @@ Color::~Color() { } +/*static*/ sal_Int32 Color::getDmlPresetColor( sal_Int32 nToken, sal_Int32 nDefaultRgb ) +{ + /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be + able to catch the existing vector entries without corresponding XML + token identifier. */ + sal_Int32 nRgbValue = ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maDmlColors, nToken, API_RGB_TRANSPARENT ); + return (nRgbValue >= 0) ? nRgbValue : nDefaultRgb; +} + +/*static*/ sal_Int32 Color::getVmlPresetColor( sal_Int32 nToken, sal_Int32 nDefaultRgb ) +{ + /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be + able to catch the existing vector entries without corresponding XML + token identifier. */ + sal_Int32 nRgbValue = ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maVmlColors, nToken, API_RGB_TRANSPARENT ); + return (nRgbValue >= 0) ? nRgbValue : nDefaultRgb; +} + void Color::setUnused() { meMode = COLOR_UNUSED; @@ -299,7 +284,10 @@ void Color::setHslClr( sal_Int32 nHue, sal_Int32 nSat, sal_Int32 nLum ) void Color::setPrstClr( sal_Int32 nToken ) { - setSrgbClr( lclGetPresetColor( nToken ) ); + sal_Int32 nRgbValue = getDmlPresetColor( nToken, API_RGB_TRANSPARENT ); + OSL_ENSURE( nRgbValue >= 0, "Color::setPrstClr - invalid preset color token" ); + if( nRgbValue >= 0 ) + setSrgbClr( nRgbValue ); } void Color::setSchemeClr( sal_Int32 nToken ) @@ -309,6 +297,13 @@ void Color::setSchemeClr( sal_Int32 nToken ) mnC1 = nToken; } +void Color::setPaletteClr( sal_Int32 nPaletteIdx ) +{ + OSL_ENSURE( nPaletteIdx >= 0, "Color::setPaletteClr - invalid palette index" ); + meMode = COLOR_PALETTE; + mnC1 = nPaletteIdx; +} + void Color::setSysClr( sal_Int32 nToken, sal_Int32 nLastRgb ) { OSL_ENSURE( (-1 <= nLastRgb) && (nLastRgb <= 0xFFFFFF), "Color::setSysClr - invalid RGB value" ); @@ -347,12 +342,18 @@ void Color::addExcelTintTransformation( double fTint ) maTransforms.push_back( Transformation( NMSP_XLS | XML_tint, nValue ) ); } +void Color::clearTransformations() +{ + maTransforms.clear(); + clearTransparence(); +} + void Color::clearTransparence() { mnAlpha = MAX_PERCENT; } -sal_Int32 Color::getColor( const ::oox::core::XmlFilterBase& rFilter, sal_Int32 nPhClr ) const +sal_Int32 Color::getColor( const ::oox::core::FilterBase& rFilter, sal_Int32 nPhClr ) const { /* Special handling for theme style list placeholder colors (state COLOR_PH), Color::getColor() may be called with different placeholder @@ -364,151 +365,154 @@ sal_Int32 Color::getColor( const ::oox::core::XmlFilterBase& rFilter, sal_Int32 switch( meMode ) { - case COLOR_UNUSED: return -1; - case COLOR_FINAL: return mnC1; + case COLOR_UNUSED: mnC1 = API_RGB_TRANSPARENT; break; case COLOR_RGB: break; // nothing to do case COLOR_CRGB: break; // nothing to do case COLOR_HSL: break; // nothing to do - case COLOR_SCHEME: - meMode = COLOR_RGB; - lclRgbToRgbComponents( mnC1, mnC2, mnC3, rFilter.getSchemeClr( mnC1 ) ); - break; - case COLOR_PH: - meMode = COLOR_RGB; - lclRgbToRgbComponents( mnC1, mnC2, mnC3, nPhClr ); - bIsPh = true; - break; - case COLOR_SYSTEM: - meMode = COLOR_RGB; - lclRgbToRgbComponents( mnC1, mnC2, mnC3, rFilter.getSystemColor( mnC1, mnC2 ) ); - break; + case COLOR_SCHEME: setResolvedRgb( rFilter.getSchemeColor( mnC1 ) ); break; + case COLOR_PALETTE: setResolvedRgb( rFilter.getPaletteColor( mnC1 ) ); break; + case COLOR_SYSTEM: setResolvedRgb( rFilter.getSystemColor( mnC1, mnC2 ) ); break; + case COLOR_PH: setResolvedRgb( nPhClr ); bIsPh = true; break; + + case COLOR_FINAL: return mnC1; } - for( TransformVec::const_iterator aIt = maTransforms.begin(), aEnd = maTransforms.end(); aIt != aEnd; ++aIt ) + // if color is UNUSED or turns to UNUSED in setResolvedRgb, do not perform transformations + if( meMode != COLOR_UNUSED ) { - switch( aIt->mnToken ) + for( TransformVec::const_iterator aIt = maTransforms.begin(), aEnd = maTransforms.end(); aIt != aEnd; ++aIt ) { - case XML_red: toCrgb(); lclSetValue( mnC1, aIt->mnValue ); break; - case XML_redMod: toCrgb(); lclModValue( mnC1, aIt->mnValue ); break; - case XML_redOff: toCrgb(); lclOffValue( mnC1, aIt->mnValue ); break; - case XML_green: toCrgb(); lclSetValue( mnC2, aIt->mnValue ); break; - case XML_greenMod: toCrgb(); lclModValue( mnC2, aIt->mnValue ); break; - case XML_greenOff: toCrgb(); lclOffValue( mnC2, aIt->mnValue ); break; - case XML_blue: toCrgb(); lclSetValue( mnC3, aIt->mnValue ); break; - case XML_blueMod: toCrgb(); lclModValue( mnC3, aIt->mnValue ); break; - case XML_blueOff: toCrgb(); lclOffValue( mnC3, aIt->mnValue ); break; - - case XML_hue: toHsl(); lclSetValue( mnC1, aIt->mnValue, MAX_DEGREE ); break; - case XML_hueMod: toHsl(); lclModValue( mnC1, aIt->mnValue, MAX_DEGREE ); break; - case XML_hueOff: toHsl(); lclOffValue( mnC1, aIt->mnValue, MAX_DEGREE ); break; - case XML_sat: toHsl(); lclSetValue( mnC2, aIt->mnValue ); break; - case XML_satMod: toHsl(); lclModValue( mnC2, aIt->mnValue ); break; - case XML_satOff: toHsl(); lclOffValue( mnC2, aIt->mnValue ); break; - - case XML_lum: - toHsl(); - lclSetValue( mnC3, aIt->mnValue ); - // if color changes to black or white, it will stay gray if luminance changes again - if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0; - break; - case XML_lumMod: - toHsl(); - lclModValue( mnC3, aIt->mnValue ); - // if color changes to black or white, it will stay gray if luminance changes again - if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0; - break; - case XML_lumOff: - toHsl(); - lclOffValue( mnC3, aIt->mnValue ); - // if color changes to black or white, it will stay gray if luminance changes again - if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0; - break; - - case XML_shade: - // shade: 0% = black, 100% = original color - toCrgb(); - OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid shade value" ); - if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) ) - { - double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT; - mnC1 = static_cast< sal_Int32 >( mnC1 * fFactor ); - mnC2 = static_cast< sal_Int32 >( mnC2 * fFactor ); - mnC3 = static_cast< sal_Int32 >( mnC3 * fFactor ); - } - break; - case XML_tint: - // tint: 0% = white, 100% = original color - toCrgb(); - OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" ); - if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) ) - { - double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT; - mnC1 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC1) * fFactor ); - mnC2 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC2) * fFactor ); - mnC3 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC3) * fFactor ); - } - break; - case XLS_TOKEN( tint ): - // Excel tint: move luminance relative to current value - toHsl(); - OSL_ENSURE( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" ); - if( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue < 0) ) - { - // negative: luminance towards 0% (black) - lclModValue( mnC3, aIt->mnValue + MAX_PERCENT ); - } - else if( (0 < aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) ) - { - // positive: luminance towards 100% (white) - mnC3 = MAX_PERCENT - mnC3; - lclModValue( mnC3, MAX_PERCENT - aIt->mnValue ); + switch( aIt->mnToken ) + { + case XML_red: toCrgb(); lclSetValue( mnC1, aIt->mnValue ); break; + case XML_redMod: toCrgb(); lclModValue( mnC1, aIt->mnValue ); break; + case XML_redOff: toCrgb(); lclOffValue( mnC1, aIt->mnValue ); break; + case XML_green: toCrgb(); lclSetValue( mnC2, aIt->mnValue ); break; + case XML_greenMod: toCrgb(); lclModValue( mnC2, aIt->mnValue ); break; + case XML_greenOff: toCrgb(); lclOffValue( mnC2, aIt->mnValue ); break; + case XML_blue: toCrgb(); lclSetValue( mnC3, aIt->mnValue ); break; + case XML_blueMod: toCrgb(); lclModValue( mnC3, aIt->mnValue ); break; + case XML_blueOff: toCrgb(); lclOffValue( mnC3, aIt->mnValue ); break; + + case XML_hue: toHsl(); lclSetValue( mnC1, aIt->mnValue, MAX_DEGREE ); break; + case XML_hueMod: toHsl(); lclModValue( mnC1, aIt->mnValue, MAX_DEGREE ); break; + case XML_hueOff: toHsl(); lclOffValue( mnC1, aIt->mnValue, MAX_DEGREE ); break; + case XML_sat: toHsl(); lclSetValue( mnC2, aIt->mnValue ); break; + case XML_satMod: toHsl(); lclModValue( mnC2, aIt->mnValue ); break; + case XML_satOff: toHsl(); lclOffValue( mnC2, aIt->mnValue ); break; + + case XML_lum: + toHsl(); + lclSetValue( mnC3, aIt->mnValue ); + // if color changes to black or white, it will stay gray if luminance changes again + if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0; + break; + case XML_lumMod: + toHsl(); + lclModValue( mnC3, aIt->mnValue ); + // if color changes to black or white, it will stay gray if luminance changes again + if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0; + break; + case XML_lumOff: + toHsl(); + lclOffValue( mnC3, aIt->mnValue ); + // if color changes to black or white, it will stay gray if luminance changes again + if( (mnC3 == 0) || (mnC3 == MAX_PERCENT) ) mnC2 = 0; + break; + + case XML_shade: + // shade: 0% = black, 100% = original color + toCrgb(); + OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid shade value" ); + if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) ) + { + double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT; + mnC1 = static_cast< sal_Int32 >( mnC1 * fFactor ); + mnC2 = static_cast< sal_Int32 >( mnC2 * fFactor ); + mnC3 = static_cast< sal_Int32 >( mnC3 * fFactor ); + } + break; + case XML_tint: + // tint: 0% = white, 100% = original color + toCrgb(); + OSL_ENSURE( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" ); + if( (0 <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) ) + { + double fFactor = static_cast< double >( aIt->mnValue ) / MAX_PERCENT; + mnC1 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC1) * fFactor ); + mnC2 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC2) * fFactor ); + mnC3 = static_cast< sal_Int32 >( MAX_PERCENT - (MAX_PERCENT - mnC3) * fFactor ); + } + break; + case XLS_TOKEN( tint ): + // Excel tint: move luminance relative to current value + toHsl(); + OSL_ENSURE( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT), "Color::getColor - invalid tint value" ); + if( (-MAX_PERCENT <= aIt->mnValue) && (aIt->mnValue < 0) ) + { + // negative: luminance towards 0% (black) + lclModValue( mnC3, aIt->mnValue + MAX_PERCENT ); + } + else if( (0 < aIt->mnValue) && (aIt->mnValue <= MAX_PERCENT) ) + { + // positive: luminance towards 100% (white) + mnC3 = MAX_PERCENT - mnC3; + lclModValue( mnC3, MAX_PERCENT - aIt->mnValue ); + mnC3 = MAX_PERCENT - mnC3; + } + break; + + case XML_gray: + // change color to gray, weighted RGB: 22% red, 72% green, 6% blue + toRgb(); + mnC1 = mnC2 = mnC3 = (mnC1 * 22 + mnC2 * 72 + mnC3 * 6) / 100; + break; + + case XML_comp: + // comp: rotate hue by 180 degrees, do not change lum/sat + toHsl(); + (mnC1 += 180 * PER_DEGREE) %= MAX_DEGREE; + break; + case XML_inv: + // invert percentual RGB values + toCrgb(); + mnC1 = MAX_PERCENT - mnC1; + mnC2 = MAX_PERCENT - mnC2; mnC3 = MAX_PERCENT - mnC3; - } - break; - - case XML_gray: - // change color to gray, weighted RGB: 22% red, 72% green, 6% blue - toRgb(); - mnC1 = mnC2 = mnC3 = (mnC1 * 22 + mnC2 * 72 + mnC3 * 6) / 100; - break; - - case XML_comp: - // comp: rotate hue by 180 degrees, do not change lum/sat - toHsl(); - (mnC1 += 180 * PER_DEGREE) %= MAX_DEGREE; - break; - case XML_inv: - // invert percentual RGB values - toCrgb(); - mnC1 = MAX_PERCENT - mnC1; - mnC2 = MAX_PERCENT - mnC2; - mnC3 = MAX_PERCENT - mnC3; - break; - - case XML_gamma: - // increase gamma of color - toCrgb(); - mnC1 = lclGamma( mnC1, INC_GAMMA ); - mnC2 = lclGamma( mnC2, INC_GAMMA ); - mnC3 = lclGamma( mnC3, INC_GAMMA ); - break; - case XML_invGamma: - // decrease gamma of color - toCrgb(); - mnC1 = lclGamma( mnC1, DEC_GAMMA ); - mnC2 = lclGamma( mnC2, DEC_GAMMA ); - mnC3 = lclGamma( mnC3, DEC_GAMMA ); - break; + break; + + case XML_gamma: + // increase gamma of color + toCrgb(); + mnC1 = lclGamma( mnC1, INC_GAMMA ); + mnC2 = lclGamma( mnC2, INC_GAMMA ); + mnC3 = lclGamma( mnC3, INC_GAMMA ); + break; + case XML_invGamma: + // decrease gamma of color + toCrgb(); + mnC1 = lclGamma( mnC1, DEC_GAMMA ); + mnC2 = lclGamma( mnC2, DEC_GAMMA ); + mnC3 = lclGamma( mnC3, DEC_GAMMA ); + break; + } } + + // store resulting RGB value in mnC1 + toRgb(); + mnC1 = lclRgbComponentsToRgb( mnC1, mnC2, mnC3 ); + } + else // if( meMode != COLOR_UNUSED ) + { + mnC1 = API_RGB_TRANSPARENT; } - toRgb(); meMode = bIsPh ? COLOR_PH : COLOR_FINAL; if( meMode == COLOR_FINAL ) maTransforms.clear(); - return mnC1 = lclRgbComponentsToRgb( mnC1, mnC2, mnC3 ); + return mnC1; } bool Color::hasTransparence() const @@ -523,6 +527,12 @@ sal_Int16 Color::getTransparence() const // private -------------------------------------------------------------------- +void Color::setResolvedRgb( sal_Int32 nRgb ) const +{ + meMode = (nRgb < 0) ? COLOR_UNUSED : COLOR_RGB; + lclRgbToRgbComponents( mnC1, mnC2, mnC3, nRgb ); +} + void Color::toRgb() const { switch( meMode ) diff --git a/oox/source/drawingml/customshapeproperties.cxx b/oox/source/drawingml/customshapeproperties.cxx index 5a1756e6d110..fdede72a7e8e 100644 --- a/oox/source/drawingml/customshapeproperties.cxx +++ b/oox/source/drawingml/customshapeproperties.cxx @@ -63,7 +63,7 @@ void CustomShapeProperties::apply( const CustomShapePropertiesPtr& /* rSourceCus // not sure if this needs to be implemented } -void CustomShapeProperties::pushToPropSet( const ::oox::core::XmlFilterBase& /* rFilterBase */, +void CustomShapeProperties::pushToPropSet( const ::oox::core::FilterBase& /* rFilterBase */, const Reference < XPropertySet >& xPropSet, const Reference < XShape > & xShape ) const { if ( maShapePresetType.getLength() ) diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index 46fe6ae5292c..f6a72c3aafce 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -44,7 +44,8 @@ #include "oox/helper/modelobjecthelper.hxx" #include "oox/helper/propertymap.hxx" #include "oox/helper/propertyset.hxx" -#include "oox/core/xmlfilterbase.hxx" +#include "oox/core/filterbase.hxx" +#include "oox/drawingml/drawingmltypes.hxx" using namespace ::com::sun::star; using namespace ::com::sun::star::drawing; @@ -55,7 +56,8 @@ using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; -using ::oox::core::XmlFilterBase; +using ::com::sun::star::geometry::IntegerRectangle2D; +using ::oox::core::FilterBase; namespace oox { namespace drawingml { @@ -106,7 +108,7 @@ RectanglePoint lclGetRectanglePoint( sal_Int32 nToken ) return RectanglePoint_LEFT_TOP; } -const awt::Size lclGetOriginalSize( const XmlFilterBase& rFilter, const Reference< XGraphic >& rxGraphic ) +const awt::Size lclGetOriginalSize( const FilterBase& rFilter, const Reference< XGraphic >& rxGraphic ) { awt::Size aSize100thMM( 0, 0 ); try @@ -222,8 +224,8 @@ Color FillProperties::getBestSolidColor() const return aSolidColor; } -void FillProperties::pushToPropMap( PropertyMap& rPropMap, const FillPropertyIds& rPropIds, - const XmlFilterBase& rFilter, ModelObjectHelper& rModelObjHelper, +void FillProperties::pushToPropMap( PropertyMap& rPropMap, const FilterBase& rFilter, + ModelObjectHelper& rModelObjHelper, const FillPropertyIds& rPropIds, sal_Int32 nShapeRotation, sal_Int32 nPhClr ) const { if( moFillType.has() ) @@ -254,7 +256,8 @@ void FillProperties::pushToPropMap( PropertyMap& rPropMap, const FillPropertyIds aGradient.StartIntensity = 100; aGradient.EndIntensity = 100; - if( maGradientProps.maGradientStops.size() > 1 ) + size_t nColorCount = maGradientProps.maGradientStops.size(); + if( nColorCount > 1 ) { aGradient.StartColor = maGradientProps.maGradientStops.begin()->second.getColor( rFilter, nPhClr ); aGradient.EndColor = maGradientProps.maGradientStops.rbegin()->second.getColor( rFilter, nPhClr ); @@ -264,19 +267,36 @@ void FillProperties::pushToPropMap( PropertyMap& rPropMap, const FillPropertyIds if ( !maGradientProps.moRotateWithShape.get( false ) ) nShapeRotation = 0; + sal_Int32 nDmlAngle = 0; if( maGradientProps.moGradientPath.has() ) { aGradient.Style = (maGradientProps.moGradientPath.get() == XML_circle) ? awt::GradientStyle_ELLIPTICAL : awt::GradientStyle_RECT; - aGradient.Angle = static_cast< sal_Int16 >( (900 - (nShapeRotation / 6000)) % 3600 ); - aGradient.XOffset = maGradientProps.moFillToRect.has() ? getLimitedValue< sal_Int16, sal_Int32 >( maGradientProps.moFillToRect.get().X1 / 1000, 30, 70 ) : 50; - aGradient.YOffset = maGradientProps.moFillToRect.has() ? getLimitedValue< sal_Int16, sal_Int32 >( maGradientProps.moFillToRect.get().Y1 / 1000, 30, 70 ) : 50; + // position of gradient center (limited to [30%;70%], otherwise gradient is too hidden) + IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.get( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) ); + sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2; + aGradient.XOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterX / PER_PERCENT, 30, 70 ); + sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; + aGradient.YOffset = getLimitedValue< sal_Int16, sal_Int32 >( nCenterY / PER_PERCENT, 30, 70 ); ::std::swap( aGradient.StartColor, aGradient.EndColor ); + nDmlAngle = nShapeRotation; } else { - aGradient.Style = awt::GradientStyle_LINEAR; - aGradient.Angle = static_cast< sal_Int16 >( (4500 - ((maGradientProps.moShadeAngle.get( 0 ) - nShapeRotation) / 6000)) % 3600 ); + /* Try to detect a VML axial gradient. This type of + gradient is simulated by a 3-point linear gradient + with equal start and end color. */ + bool bAxial = (nColorCount == 3) && (aGradient.StartColor == aGradient.EndColor); + aGradient.Style = bAxial ? awt::GradientStyle_AXIAL : awt::GradientStyle_LINEAR; + if( bAxial ) + { + GradientFillProperties::GradientStopMap::const_iterator aIt = maGradientProps.maGradientStops.begin(); + // API StartColor is inner color in axial gradient + aGradient.StartColor = (++aIt)->second.getColor( rFilter, nPhClr ); + } + nDmlAngle = maGradientProps.moShadeAngle.get( 0 ) - nShapeRotation; } + // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees) + aGradient.Angle = static_cast< sal_Int16 >( (4500 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ); // push gradient or named gradient to property map if( rPropIds.mbNamedFillGradient ) @@ -340,10 +360,10 @@ void FillProperties::pushToPropMap( PropertyMap& rPropMap, const FillPropertyIds if( (aOriginalSize.Width > 0) && (aOriginalSize.Height > 0) ) { // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm - double fScaleX = maBlipProps.moTileScaleX.get( 100000 ) / 100000.0; + double fScaleX = maBlipProps.moTileScaleX.get( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT ); sal_Int32 nFillBmpSizeX = getLimitedValue< sal_Int32, double >( aOriginalSize.Width * fScaleX, 1, SAL_MAX_INT32 ); rPropMap.setProperty( rPropIds[ FillBitmapSizeXId ], nFillBmpSizeX ); - double fScaleY = maBlipProps.moTileScaleY.get( 100000 ) / 100000.0; + double fScaleY = maBlipProps.moTileScaleY.get( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT ); sal_Int32 nFillBmpSizeY = getLimitedValue< sal_Int32, double >( aOriginalSize.Height * fScaleY, 1, SAL_MAX_INT32 ); rPropMap.setProperty( rPropIds[ FillBitmapSizeYId ], nFillBmpSizeY ); @@ -383,12 +403,12 @@ void FillProperties::pushToPropMap( PropertyMap& rPropMap, const FillPropertyIds } } -void FillProperties::pushToPropSet( PropertySet& rPropSet, const FillPropertyIds& rPropIds, - const XmlFilterBase& rFilter, ModelObjectHelper& rModelObjHelper, +void FillProperties::pushToPropSet( PropertySet& rPropSet, const FilterBase& rFilter, + ModelObjectHelper& rModelObjHelper, const FillPropertyIds& rPropIds, sal_Int32 nShapeRotation, sal_Int32 nPhClr ) const { PropertyMap aPropMap; - pushToPropMap( aPropMap, rPropIds, rFilter, rModelObjHelper, nShapeRotation, nPhClr ); + pushToPropMap( aPropMap, rFilter, rModelObjHelper, rPropIds, nShapeRotation, nPhClr ); rPropSet.setProperties( aPropMap ); } @@ -399,7 +419,7 @@ void GraphicProperties::assignUsed( const GraphicProperties& rSourceProps ) maBlipProps.assignUsed( rSourceProps.maBlipProps ); } -void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const XmlFilterBase& rFilter, sal_Int32 nPhClr ) const +void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const FilterBase& rFilter, sal_Int32 nPhClr ) const { if( maBlipProps.mxGraphic.is() ) { @@ -436,15 +456,15 @@ void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const XmlFilterBas rPropMap[ PROP_GraphicColorMode ] <<= eColorMode; // brightness and contrast - sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.get( 0 ) / 1000, -100, 100 ); + sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.get( 0 ) / PER_PERCENT, -100, 100 ); if( nBrightness != 0 ) rPropMap[ PROP_AdjustLuminance ] <<= nBrightness; - sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.get( 0 ) / 1000, -100, 100 ); + sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.get( 0 ) / PER_PERCENT, -100, 100 ); if( nContrast != 0 ) rPropMap[ PROP_AdjustContrast ] <<= nContrast; } -void GraphicProperties::pushToPropSet( PropertySet& rPropSet, const XmlFilterBase& rFilter, sal_Int32 nPhClr ) const +void GraphicProperties::pushToPropSet( PropertySet& rPropSet, const FilterBase& rFilter, sal_Int32 nPhClr ) const { PropertyMap aPropMap; pushToPropMap( aPropMap, rFilter, nPhClr ); diff --git a/oox/source/drawingml/lineproperties.cxx b/oox/source/drawingml/lineproperties.cxx index 7f31bc05cb7e..6cee420c167d 100644 --- a/oox/source/drawingml/lineproperties.cxx +++ b/oox/source/drawingml/lineproperties.cxx @@ -43,8 +43,8 @@ #include "oox/helper/modelobjecthelper.hxx" #include "oox/helper/propertymap.hxx" #include "oox/helper/propertyset.hxx" +#include "oox/core/filterbase.hxx" #include "oox/core/namespaces.hxx" -#include "oox/core/xmlfilterbase.hxx" #include "oox/drawingml/drawingmltypes.hxx" using namespace ::com::sun::star::drawing; @@ -55,7 +55,7 @@ using ::com::sun::star::uno::Any; using ::com::sun::star::uno::Reference; using ::com::sun::star::awt::Point; using ::com::sun::star::container::XNameContainer; -using ::oox::core::XmlFilterBase; +using ::oox::core::FilterBase; namespace oox { namespace drawingml { @@ -82,6 +82,85 @@ static const sal_Int32 spnDefaultLineIds[ LineId_END ] = // ---------------------------------------------------------------------------- +void lclSetDashData( LineDash& orLineDash, sal_Int16 nDots, sal_Int32 nDotLen, + sal_Int16 nDashes, sal_Int32 nDashLen, sal_Int32 nDistance ) +{ + orLineDash.Dots = nDots; + orLineDash.DotLen = nDotLen; + orLineDash.Dashes = nDashes; + orLineDash.DashLen = nDashLen; + orLineDash.Distance = nDistance; +} + +/** Converts the specified preset dash to API dash. + + Line length and dot length are set relative to line width and have to be + multiplied by the actual line width after this function. + */ +void lclConvertPresetDash( LineDash& orLineDash, sal_Int32 nPresetDash ) +{ + switch( nPresetDash ) + { + case XML_dot: lclSetDashData( orLineDash, 1, 1, 0, 0, 3 ); break; + case XML_dash: lclSetDashData( orLineDash, 0, 0, 1, 4, 3 ); break; + case XML_dashDot: lclSetDashData( orLineDash, 1, 1, 1, 4, 3 ); break; + + case XML_lgDash: lclSetDashData( orLineDash, 0, 0, 1, 8, 3 ); break; + case XML_lgDashDot: lclSetDashData( orLineDash, 1, 1, 1, 8, 3 ); break; + case XML_lgDashDotDot: lclSetDashData( orLineDash, 2, 1, 1, 8, 3 ); break; + + case XML_sysDot: lclSetDashData( orLineDash, 1, 1, 0, 0, 1 ); break; + case XML_sysDash: lclSetDashData( orLineDash, 0, 0, 1, 3, 1 ); break; + case XML_sysDashDot: lclSetDashData( orLineDash, 1, 1, 1, 3, 1 ); break; + case XML_sysDashDotDot: lclSetDashData( orLineDash, 2, 1, 1, 3, 1 ); break; + + default: + OSL_ENSURE( false, "lclConvertPresetDash - unsupported preset dash" ); + lclSetDashData( orLineDash, 0, 0, 1, 4, 3 ); + } +} + +/** Converts the passed custom dash to API dash. + + Line length and dot length are set relative to line width and have to be + multiplied by the actual line width after this function. + */ +void lclConvertCustomDash( LineDash& orLineDash, const LineProperties::DashStopVector& rCustomDash ) +{ + if( rCustomDash.empty() ) + { + OSL_ENSURE( false, "lclConvertCustomDash - unexpected empty custom dash" ); + lclSetDashData( orLineDash, 0, 0, 1, 4, 3 ); + return; + } + + // count dashes and dots (stops equal or less than 2 are assumed to be dots) + sal_Int16 nDots = 0; + sal_Int32 nDotLen = 0; + sal_Int16 nDashes = 0; + sal_Int32 nDashLen = 0; + sal_Int32 nDistance = 0; + for( LineProperties::DashStopVector::const_iterator aIt = rCustomDash.begin(), aEnd = rCustomDash.end(); aIt != aEnd; ++aIt ) + { + if( aIt->first <= 2 ) + { + ++nDots; + nDotLen += aIt->first; + } + else + { + ++nDashes; + nDashLen += aIt->first; + } + nDistance += aIt->second; + } + orLineDash.DotLen = (nDots > 0) ? ::std::max< sal_Int32 >( nDotLen / nDots, 1 ) : 0; + orLineDash.Dots = nDots; + orLineDash.DashLen = (nDashes > 0) ? ::std::max< sal_Int32 >( nDashLen / nDashes, 1 ) : 0; + orLineDash.Dashes = nDashes; + orLineDash.Distance = ::std::max< sal_Int32 >( nDistance / rCustomDash.size(), 1 ); +} + DashStyle lclGetDashStyle( sal_Int32 nToken ) { switch( nToken ) @@ -122,7 +201,7 @@ sal_Int32 lclGetArrowSize( sal_Int32 nToken ) // ---------------------------------------------------------------------------- void lclPushMarkerProperties( PropertyMap& rPropMap, const LineArrowProperties& rArrowProps, - const LinePropertyIds& rPropIds, ModelObjectHelper& rModelObjHelper, sal_Int32 nLineWidth, bool bLineEnd ) + ModelObjectHelper& rModelObjHelper, const LinePropertyIds& rPropIds, sal_Int32 nLineWidth, bool bLineEnd ) { PolyPolygonBezierCoords aMarker; OUString aMarkerName; @@ -310,14 +389,17 @@ void LineProperties::assignUsed( const LineProperties& rSourceProps ) maStartArrow.assignUsed( rSourceProps.maStartArrow ); maEndArrow.assignUsed( rSourceProps.maEndArrow ); maLineFill.assignUsed( rSourceProps.maLineFill ); + if( !rSourceProps.maCustomDash.empty() ) + maCustomDash = rSourceProps.maCustomDash; moLineWidth.assignIfUsed( rSourceProps.moLineWidth ); moPresetDash.assignIfUsed( rSourceProps.moPresetDash ); + moLineCompound.assignIfUsed( rSourceProps.moLineCompound ); moLineCap.assignIfUsed( rSourceProps.moLineCap ); moLineJoint.assignIfUsed( rSourceProps.moLineJoint ); } -void LineProperties::pushToPropMap( PropertyMap& rPropMap, const LinePropertyIds& rPropIds, - const XmlFilterBase& rFilter, ModelObjectHelper& rModelObjHelper, sal_Int32 nPhClr ) const +void LineProperties::pushToPropMap( PropertyMap& rPropMap, const FilterBase& rFilter, + ModelObjectHelper& rModelObjHelper, const LinePropertyIds& rPropIds, sal_Int32 nPhClr ) const { // line fill type must exist, otherwise ignore other properties if( maLineFill.moFillType.has() ) @@ -326,51 +408,22 @@ void LineProperties::pushToPropMap( PropertyMap& rPropMap, const LinePropertyIds LineStyle eLineStyle = (maLineFill.moFillType.get() == XML_noFill) ? LineStyle_NONE : LineStyle_SOLID; // create line dash from preset dash token (not for invisible line) - if( (eLineStyle != LineStyle_NONE) && moPresetDash.differsFrom( XML_solid ) ) + if( (eLineStyle != LineStyle_NONE) && (moPresetDash.differsFrom( XML_solid ) || (!moPresetDash && !maCustomDash.empty())) ) { LineDash aLineDash; - - sal_Int32 nLineWidth = GetCoordinate( moLineWidth.get( 103500 ) ); aLineDash.Style = lclGetDashStyle( moLineCap.get( XML_rnd ) ); - aLineDash.Dots = 1; - aLineDash.DotLen = nLineWidth; - aLineDash.Dashes = 0; - aLineDash.DashLen = 8 * nLineWidth; - aLineDash.Distance = 3 * nLineWidth; - switch( moPresetDash.get() ) - { - default: - case XML_dash: - case XML_sysDash: - aLineDash.DashLen = 4 * nLineWidth; - // passthrough intended - case XML_lgDash: - aLineDash.Dots = 0; - aLineDash.Dashes = 1; - break; - - case XML_dashDot: - case XML_sysDashDot: - aLineDash.DashLen = 4 * nLineWidth; - // passthrough intended - case XML_lgDashDot: - aLineDash.Dashes = 1; - break; - - case XML_sysDashDotDot: - aLineDash.DashLen = 4 * nLineWidth; - // passthrough intended - case XML_lgDashDotDot: - aLineDash.Dots = 2; - aLineDash.Dashes = 1; - break; + // convert preset dash or custom dash + if( moPresetDash.has() ) + lclConvertPresetDash( aLineDash, moPresetDash.get() ); + else + lclConvertCustomDash( aLineDash, maCustomDash ); - case XML_dot: - case XML_sysDot: - aLineDash.Distance = aLineDash.DotLen; - break; - } + // convert relative dash/dot length to absolute length + sal_Int32 nLineWidth = GetCoordinate( moLineWidth.get( 103500 ) ); + aLineDash.DotLen *= nLineWidth; + aLineDash.DashLen *= nLineWidth; + aLineDash.Distance *= nLineWidth; if( rPropIds.mbNamedLineDash ) { @@ -409,16 +462,16 @@ void LineProperties::pushToPropMap( PropertyMap& rPropMap, const LinePropertyIds } // line markers - lclPushMarkerProperties( rPropMap, maStartArrow, rPropIds, rModelObjHelper, moLineWidth.get( 0 ), false ); - lclPushMarkerProperties( rPropMap, maEndArrow, rPropIds, rModelObjHelper, moLineWidth.get( 0 ), true ); + lclPushMarkerProperties( rPropMap, maStartArrow, rModelObjHelper, rPropIds, moLineWidth.get( 0 ), false ); + lclPushMarkerProperties( rPropMap, maEndArrow, rModelObjHelper, rPropIds, moLineWidth.get( 0 ), true ); } } -void LineProperties::pushToPropSet( PropertySet& rPropSet, const LinePropertyIds& rPropIds, - const XmlFilterBase& rFilter, ModelObjectHelper& rModelObjHelper, sal_Int32 nPhClr ) const +void LineProperties::pushToPropSet( PropertySet& rPropSet, const FilterBase& rFilter, + ModelObjectHelper& rModelObjHelper, const LinePropertyIds& rPropIds, sal_Int32 nPhClr ) const { PropertyMap aPropMap; - pushToPropMap( aPropMap, rPropIds, rFilter, rModelObjHelper, nPhClr ); + pushToPropMap( aPropMap, rFilter, rModelObjHelper, rPropIds, nPhClr ); rPropSet.setProperties( aPropMap ); } diff --git a/oox/source/drawingml/linepropertiescontext.cxx b/oox/source/drawingml/linepropertiescontext.cxx index b98f30738ec0..e6c6f76d5585 100644 --- a/oox/source/drawingml/linepropertiescontext.cxx +++ b/oox/source/drawingml/linepropertiescontext.cxx @@ -53,6 +53,7 @@ LinePropertiesContext::LinePropertiesContext( ContextHandler& rParent, const Ref { AttributeList aAttribs( xAttribs ); mrLineProperties.moLineWidth = aAttribs.getInteger( XML_w ); + mrLineProperties.moLineCompound = aAttribs.getToken( XML_cmpd ); mrLineProperties.moLineCap = aAttribs.getToken( XML_cap ); } @@ -79,6 +80,11 @@ Reference< XFastContextHandler > LinePropertiesContext::createFastChildContext( mrLineProperties.moPresetDash = aAttribs.getToken( XML_val ); break; case A_TOKEN( custDash ): // CT_DashStopList + xRet = this; + break; + case A_TOKEN( ds ): + mrLineProperties.maCustomDash.push_back( LineProperties::DashStop( + aAttribs.getInteger( XML_d, 0 ), aAttribs.getInteger( XML_sp, 0 ) ) ); break; // LineJoinPropertiesGroup diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 329aa6b36226..b1d68fabcb11 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -423,11 +423,11 @@ Reference< XShape > Shape::createAndInsert( // applying properties PropertySet aPropSet( xSet ); if ( aServiceName == OUString::createFromAscii( "com.sun.star.drawing.GraphicObjectShape" ) ) - mpGraphicPropertiesPtr->pushToPropSet( aPropSet, rFilterBase, -1 ); + mpGraphicPropertiesPtr->pushToPropSet( aPropSet, rFilterBase ); if ( mpTablePropertiesPtr.get() && ( aServiceName == OUString::createFromAscii( "com.sun.star.drawing.TableShape" ) ) ) mpTablePropertiesPtr->pushToPropSet( rFilterBase, xSet, mpMasterTextListStyle ); - aFillProperties.pushToPropSet( aPropSet, FillProperties::DEFAULT_IDS, rFilterBase, rFilterBase.getModelObjectHelper(), mnRotation, nFillPhClr ); - aLineProperties.pushToPropSet( aPropSet, LineProperties::DEFAULT_IDS, rFilterBase, rFilterBase.getModelObjectHelper(), nLinePhClr ); + aFillProperties.pushToPropSet( aPropSet, rFilterBase, rFilterBase.getModelObjectHelper(), FillProperties::DEFAULT_IDS, mnRotation, nFillPhClr ); + aLineProperties.pushToPropSet( aPropSet, rFilterBase, rFilterBase.getModelObjectHelper(), LineProperties::DEFAULT_IDS, nLinePhClr ); // applying autogrowheight property before setting shape size, because // the shape size might be changed if currently autogrowheight is true diff --git a/oox/source/drawingml/table/tablecell.cxx b/oox/source/drawingml/table/tablecell.cxx index 58aaf9081385..332e6f55601e 100644 --- a/oox/source/drawingml/table/tablecell.cxx +++ b/oox/source/drawingml/table/tablecell.cxx @@ -363,8 +363,7 @@ void TableCell::pushToXCell( const ::oox::core::XmlFilterBase& rFilterBase, ::oo aFillProperties.assignUsed( maFillProperties ); PropertySet aPropSet( xPropSet ); // TODO: phClr? - aFillProperties.pushToPropSet( aPropSet, FillProperties::DEFAULT_IDS, - rFilterBase, rFilterBase.getModelObjectHelper(), 0, -1 ); + aFillProperties.pushToPropSet( aPropSet, rFilterBase, rFilterBase.getModelObjectHelper() ); } } } } diff --git a/oox/source/drawingml/textcharacterproperties.cxx b/oox/source/drawingml/textcharacterproperties.cxx index a5ef7558701f..41855170d26b 100644 --- a/oox/source/drawingml/textcharacterproperties.cxx +++ b/oox/source/drawingml/textcharacterproperties.cxx @@ -34,6 +34,7 @@ #include <com/sun/star/awt/FontWeight.hpp> #include "oox/helper/helper.hxx" #include "oox/helper/propertyset.hxx" +#include "oox/core/xmlfilterbase.hxx" #include "oox/drawingml/drawingmltypes.hxx" #include "properties.hxx" #include "tokens.hxx" diff --git a/oox/source/drawingml/textparagraphproperties.cxx b/oox/source/drawingml/textparagraphproperties.cxx index c8197e3d78a3..35fe17716250 100644 --- a/oox/source/drawingml/textparagraphproperties.cxx +++ b/oox/source/drawingml/textparagraphproperties.cxx @@ -41,6 +41,7 @@ #include "oox/helper/helper.hxx" #include "oox/helper/propertyset.hxx" #include "oox/core/namespaces.hxx" +#include "oox/core/xmlfilterbase.hxx" #include "oox/drawingml/drawingmltypes.hxx" #include "properties.hxx" #include "tokens.hxx" diff --git a/oox/source/dump/biffdumper.cxx b/oox/source/dump/biffdumper.cxx index 60cca8754a91..da21926e04bf 100644 --- a/oox/source/dump/biffdumper.cxx +++ b/oox/source/dump/biffdumper.cxx @@ -685,12 +685,12 @@ sal_uInt16 BiffObjectBase::dumpRepeatedRecId() void BiffObjectBase::dumpFrHeader( bool bWithFlags, bool bWithRange ) { - dumpHex< sal_uInt16 >( "rec-id", getRecNames() ); - sal_Int16 nFlags = bWithFlags ? dumpHex< sal_uInt16 >( "flags", "FR-FLAGS" ) : 0x0001; + dumpHex< sal_uInt16 >( "fr-rec-id", getRecNames() ); + sal_Int16 nFlags = bWithFlags ? dumpHex< sal_uInt16 >( "fr-flags", "FR-FLAGS" ) : 0x0001; if( bWithRange ) { if( getFlag< sal_uInt16 >( nFlags, 0x0001 ) ) - dumpRange( "range" ); + dumpRange( "fr-range" ); else dumpUnused( 8 ); } @@ -2698,14 +2698,23 @@ void WorkbookStreamObject::implDumpRecordBody() sal_uInt16 nFlags = dumpHex< sal_uInt16 >( "flags", "STYLE-FLAGS" ); if( getFlag( nFlags, BIFF_STYLE_BUILTIN ) ) { - dumpDec< sal_uInt8 >( "builtin-idx", "STYLE-BUILTIN" ); - dumpDec< sal_uInt8 >( "outline-level" ); + dumpDec< sal_Int8 >( "builtin-idx", "STYLE-BUILTIN" ); + dumpDec< sal_Int8 >( "outline-level" ); } else dumpString( "style-name", BIFF_STR_8BITLENGTH ); } break; + case BIFF_ID_STYLEEXT: + dumpFrHeader( true, true ); + dumpHex< sal_uInt8 >( "flags", "STYLEEXT-FLAGS" ); + dumpDec< sal_uInt8 >( "category", "STYLEEXT-CATEGORY" ); + dumpDec< sal_Int8 >( "builtin-idx", "STYLEEXT-BUILTIN" ); + dumpDec< sal_Int8 >( "outline-level" ); + dumpUnicodeArray( "style-name", rStrm.readuInt16() ); + break; + case BIFF_ID_SXEXT: if( eBiff == BIFF8 ) { diff --git a/oox/source/dump/biffdumper.ini b/oox/source/dump/biffdumper.ini index 48c514b170d2..e9766865dd8b 100644 --- a/oox/source/dump/biffdumper.ini +++ b/oox/source/dump/biffdumper.ini @@ -347,6 +347,7 @@ multilist=RECORD-NAMES-BIFF8 0x0858=CHPIVOTREF,,,,,,, 0x0860=,,SHEETLAYOUT,,,,,SHEETPROTECTION 0x0868=,,,CHFRLABELPROPS,,,, + 0x0890=,,STYLEEXT,,,,, # chart records 0x1058=,,,,,,,CH3DDATAFORMAT 0x1060=CHFONTBASE,CHPIEEXT,CHLABELRANGE2,CHDATATABLE,CHPLOTGROWTH,CHSERINDEX,CHESCHERFORMAT,CHPIEEXTSETT @@ -1654,7 +1655,26 @@ combilist=STYLE-FLAGS 0x8000=builtin end -shortlist=STYLE-BUILTIN,0,normal,rowlevel,collevel,comma,currency,percent,comma-0,currency-0,hyperlink,followed-hyperlink +shortlist=STYLE-BUILTIN,-1,user-defined,normal,rowlevel,collevel,comma,currency,percent,comma-0,currency-0,hyperlink,followed-hyperlink + +# STYLEEXT ------------------------------------------------------------------- + +flagslist=STYLEEXT-FLAGS + 0x01=builtin + 0x02=hidden + 0x04=custom +end + +shortlist=STYLEEXT-CATEGORY,0,custom,good-bad-neutral,data-model,title-heading,themed,number-format + +multilist=STYLEEXT-BUILTIN + include=STYLE-BUILTIN + 10=note,warning-text,,,,title,heading-1,heading-2,heading-3,heading-4 + 20=input,output,calculation,check-cell,linked-cell,total,good,bad,neutral,accent1 + 30=20%-accent1,40%-accent1,60%-accent1,accent2,20%-accent2,40%-accent2,60%-accent2,accent3,20%-accent3,40%-accent3 + 40=60%-accent3,accent4,20%-accent4,40%-accent4,60%-accent4,accent5,20%-accent5,40%-accent5,60%-accent5,accent6 + 50=20%-accent6,40%-accent6,60%-accent6,explanatory-text +end # SXEXT ---------------------------------------------------------------------- diff --git a/oox/source/helper/propertymap.cxx b/oox/source/helper/propertymap.cxx index ccc5cfdd62b4..a40b4a737bd3 100644 --- a/oox/source/helper/propertymap.cxx +++ b/oox/source/helper/propertymap.cxx @@ -35,6 +35,7 @@ #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/beans/XPropertySetInfo.hpp> #include "properties.hxx" +#include "oox/token/propertylist.hxx" using ::rtl::OUString; using ::com::sun::star::uno::Any; @@ -59,7 +60,7 @@ namespace oox { namespace { /** Thread-save singleton of a vector of all supported property names. */ -struct PropertyNamesPool : public ::rtl::Static< PropertyNamesList, PropertyNamesPool > {}; +struct StaticPropertyList : public ::rtl::Static< PropertyList, StaticPropertyList > {}; // ---------------------------------------------------------------------------- @@ -103,7 +104,7 @@ GenericPropertySet::GenericPropertySet() GenericPropertySet::GenericPropertySet( const PropertyMap& rPropMap ) { - const PropertyNamesList& rPropNames = PropertyNamesPool::get(); + const PropertyList& rPropNames = StaticPropertyList::get(); for( PropertyMap::const_iterator aIt = rPropMap.begin(), aEnd = rPropMap.end(); aIt != aEnd; ++aIt ) maPropMap[ rPropNames[ aIt->first ] ] = aIt->second; } @@ -170,10 +171,19 @@ sal_Bool SAL_CALL GenericPropertySet::hasPropertyByName( const OUString& rProper // ============================================================================ -const OUString& PropertyMap::getPropertyName( sal_Int32 nPropId ) +PropertyMap::PropertyMap() : + mpPropNames( &StaticPropertyList::get() ) +{ +} + +PropertyMap::~PropertyMap() +{ +} + +/*static*/ const OUString& PropertyMap::getPropertyName( sal_Int32 nPropId ) { OSL_ENSURE( (0 <= nPropId) && (nPropId < PROP_COUNT), "PropertyMap::getPropertyName - invalid property identifier" ); - return PropertyNamesPool::get()[ nPropId ]; + return StaticPropertyList::get()[ nPropId ]; } const Any* PropertyMap::getProperty( sal_Int32 nPropId ) const @@ -187,12 +197,11 @@ Sequence< PropertyValue > PropertyMap::makePropertyValueSequence() const Sequence< PropertyValue > aSeq( static_cast< sal_Int32 >( size() ) ); if( !empty() ) { - const PropertyNamesList& rPropNames = PropertyNamesPool::get(); PropertyValue* pValues = aSeq.getArray(); for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt, ++pValues ) { OSL_ENSURE( (0 <= aIt->first) && (aIt->first < PROP_COUNT), "PropertyMap::makePropertyValueSequence - invalid property identifier" ); - pValues->Name = rPropNames[ aIt->first ]; + pValues->Name = (*mpPropNames)[ aIt->first ]; pValues->Value = aIt->second; pValues->State = ::com::sun::star::beans::PropertyState_DIRECT_VALUE; } @@ -206,13 +215,12 @@ void PropertyMap::fillSequences( Sequence< OUString >& rNames, Sequence< Any >& rValues.realloc( static_cast< sal_Int32 >( size() ) ); if( !empty() ) { - const PropertyNamesList& rPropNames = PropertyNamesPool::get(); OUString* pNames = rNames.getArray(); Any* pValues = rValues.getArray(); for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt, ++pNames, ++pValues ) { OSL_ENSURE( (0 <= aIt->first) && (aIt->first < PROP_COUNT), "PropertyMap::fillSequences - invalid property identifier" ); - *pNames = rPropNames[ aIt->first ]; + *pNames = (*mpPropNames)[ aIt->first ]; *pValues = aIt->second; } } diff --git a/oox/source/ole/axcontrolhelper.cxx b/oox/source/ole/axcontrolhelper.cxx index a1bd9bfd9ac7..cd8180728074 100644 --- a/oox/source/ole/axcontrolhelper.cxx +++ b/oox/source/ole/axcontrolhelper.cxx @@ -117,12 +117,12 @@ sal_Int32 AxControlHelper::convertColor( sal_uInt32 nAxColor ) const switch( meColorMode ) { case AX_DEFAULTCOLORMODE_BGR: return lclDecodeBgrColor( nAxColor ); - case AX_DEFAULTCOLORMODE_PALETTE: return getPaletteColor( static_cast< sal_uInt16 >( nAxColor & AX_PALETTECOLOR_MASK ) ); + case AX_DEFAULTCOLORMODE_PALETTE: return mrFilter.getPaletteColor( nAxColor & AX_PALETTECOLOR_MASK ); } break; case AX_COLORTYPE_PALETTE: - return getPaletteColor( static_cast< sal_uInt16 >( nAxColor & AX_PALETTECOLOR_MASK ) ); + return mrFilter.getPaletteColor( nAxColor & AX_PALETTECOLOR_MASK ); case AX_COLORTYPE_BGR: return lclDecodeBgrColor( nAxColor ); @@ -134,12 +134,6 @@ sal_Int32 AxControlHelper::convertColor( sal_uInt32 nAxColor ) const return 0; } -sal_Int32 AxControlHelper::getPaletteColor( sal_uInt16 /*nPaletteIdx*/ ) const -{ - OSL_ENSURE( false, "AxControlHelper::getPaletteColor - palette colors not implemented" ); - return 0; -} - // ============================================================================ AxEmbeddedControlHelper::AxEmbeddedControlHelper( const FilterBase& rFilter, diff --git a/oox/source/ppt/animvariantcontext.cxx b/oox/source/ppt/animvariantcontext.cxx index e8f60d9df234..f3b9de2dbf7a 100644 --- a/oox/source/ppt/animvariantcontext.cxx +++ b/oox/source/ppt/animvariantcontext.cxx @@ -40,6 +40,7 @@ #include "oox/helper/attributelist.hxx" #include "oox/core/namespaces.hxx" #include "oox/core/fragmenthandler.hxx" +#include "oox/core/xmlfilterbase.hxx" #include "oox/drawingml/colorchoicecontext.hxx" #include "pptfilterhelpers.hxx" #include "tokens.hxx" diff --git a/oox/source/ppt/pptimport.cxx b/oox/source/ppt/pptimport.cxx index f772a9236785..0e463099e9c5 100644 --- a/oox/source/ppt/pptimport.cxx +++ b/oox/source/ppt/pptimport.cxx @@ -88,12 +88,7 @@ bool PowerPointImport::exportDocument() throw() return false; } -const ::oox::drawingml::Theme* PowerPointImport::getCurrentTheme() const -{ - return mpActualSlidePersist ? mpActualSlidePersist->getTheme().get() : 0; -} - -sal_Int32 PowerPointImport::getSchemeClr( sal_Int32 nColorSchemeToken ) const +sal_Int32 PowerPointImport::getSchemeColor( sal_Int32 nToken ) const { sal_Int32 nColor = 0; if ( mpActualSlidePersist ) @@ -101,7 +96,7 @@ sal_Int32 PowerPointImport::getSchemeClr( sal_Int32 nColorSchemeToken ) const sal_Bool bColorMapped = sal_False; oox::drawingml::ClrMapPtr pClrMapPtr( mpActualSlidePersist->getClrMap() ); if ( pClrMapPtr ) - bColorMapped = pClrMapPtr->getColorMap( nColorSchemeToken ); + bColorMapped = pClrMapPtr->getColorMap( nToken ); if ( !bColorMapped ) // try masterpage mapping { @@ -110,18 +105,18 @@ sal_Int32 PowerPointImport::getSchemeClr( sal_Int32 nColorSchemeToken ) const { pClrMapPtr = pMasterPersist->getClrMap(); if ( pClrMapPtr ) - bColorMapped = pClrMapPtr->getColorMap( nColorSchemeToken ); + bColorMapped = pClrMapPtr->getColorMap( nToken ); } } oox::drawingml::ClrSchemePtr pClrSchemePtr( mpActualSlidePersist->getClrScheme() ); if ( pClrSchemePtr ) - pClrSchemePtr->getColor( nColorSchemeToken, nColor ); + pClrSchemePtr->getColor( nToken, nColor ); else { ::oox::drawingml::ThemePtr pTheme = mpActualSlidePersist->getTheme(); if( pTheme ) { - pTheme->getClrScheme().getColor( nColorSchemeToken, nColor ); + pTheme->getClrScheme().getColor( nToken, nColor ); } else { @@ -132,6 +127,11 @@ sal_Int32 PowerPointImport::getSchemeClr( sal_Int32 nColorSchemeToken ) const return nColor; } +const ::oox::drawingml::Theme* PowerPointImport::getCurrentTheme() const +{ + return mpActualSlidePersist ? mpActualSlidePersist->getTheme().get() : 0; +} + ::oox::vml::Drawing* PowerPointImport::getVmlDrawing() { return mpActualSlidePersist ? mpActualSlidePersist->getDrawing() : 0; diff --git a/oox/source/ppt/slidepersist.cxx b/oox/source/ppt/slidepersist.cxx index 5ce09bbbdbd5..f85e5ec72876 100644 --- a/oox/source/ppt/slidepersist.cxx +++ b/oox/source/ppt/slidepersist.cxx @@ -180,9 +180,7 @@ void SlidePersist::createBackground( const XmlFilterBase& rFilterBase ) uno::Reference< beans::XPropertySet > xPagePropSet( mxPage, uno::UNO_QUERY_THROW ); uno::Reference< beans::XPropertySet > xPropertySet( aPropMap.makePropertySet() ); PropertySet aPropSet( xPropertySet ); - mpBackgroundPropertiesPtr->pushToPropSet( - aPropSet, ::oox::drawingml::FillProperties::DEFAULT_IDS, - rFilterBase, rFilterBase.getModelObjectHelper(), 0, -1 ); + mpBackgroundPropertiesPtr->pushToPropSet( aPropSet, rFilterBase, rFilterBase.getModelObjectHelper() ); xPagePropSet->setPropertyValue( sBackground, Any( xPropertySet ) ); } catch( Exception ) diff --git a/oox/source/ppt/timenodelistcontext.cxx b/oox/source/ppt/timenodelistcontext.cxx index 70da57a52bd4..12fe9809ba5d 100644 --- a/oox/source/ppt/timenodelistcontext.cxx +++ b/oox/source/ppt/timenodelistcontext.cxx @@ -51,6 +51,7 @@ #include "oox/helper/attributelist.hxx" #include "oox/core/namespaces.hxx" +#include "oox/core/xmlfilterbase.hxx" #include "oox/drawingml/drawingmltypes.hxx" #include "oox/drawingml/colorchoicecontext.hxx" #include "oox/ppt/slidetransition.hxx" diff --git a/oox/source/shape/FastTokenHandlerService.hxx b/oox/source/shape/FastTokenHandlerService.hxx index 64b79ab943ee..c41403539d11 100644 --- a/oox/source/shape/FastTokenHandlerService.hxx +++ b/oox/source/shape/FastTokenHandlerService.hxx @@ -27,17 +27,16 @@ * for a copy of the LGPLv3 License. * ************************************************************************/ -#ifndef OOX_SHAPE_FAST_TOKEN_HANDLER_SERVICE_HXX -#define OOX_SHAPE_FAST_TOKEN_HANDLER_SERVICE_HXX -#include <oox/core/fasttokenhandler.hxx> +#ifndef OOX_SHAPE_FASTTOKENHANDLERSERVICE_HXX +#define OOX_SHAPE_FASTTOKENHANDLERSERVICE_HXX -#include "sal/config.h" -#include "cppuhelper/factory.hxx" -#include "cppuhelper/implementationentry.hxx" -#include "cppuhelper/implbase2.hxx" -#include "com/sun/star/lang/XServiceInfo.hpp" -#include "com/sun/star/xml/sax/XFastTokenHandler.hpp" +#include <sal/config.h> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/implbase2.hxx> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include "oox/core/fasttokenhandler.hxx" namespace css = ::com::sun::star; @@ -70,7 +69,7 @@ private: virtual ~FastTokenHandlerService() {} css::uno::Reference< css::uno::XComponentContext > m_xContext; - FastTokenHandler mFastTokenHandler; + ::oox::core::FastTokenHandler mFastTokenHandler; }; ::rtl::OUString SAL_CALL FastTokenHandlerService_getImplementationName(); diff --git a/oox/source/shape/ShapeFilterBase.cxx b/oox/source/shape/ShapeFilterBase.cxx index 0933af28ffd5..9105b6ca38eb 100644 --- a/oox/source/shape/ShapeFilterBase.cxx +++ b/oox/source/shape/ShapeFilterBase.cxx @@ -53,11 +53,6 @@ const ::oox::drawingml::Theme* ShapeFilterBase::getCurrentTheme() const return 0; } -sal_Int32 ShapeFilterBase::getSchemeClr(sal_Int32 /*nColorSchemeToken*/ ) const -{ - return 0; -} - ::oox::vml::Drawing* ShapeFilterBase::getVmlDrawing() { return 0; diff --git a/oox/source/shape/ShapeFilterBase.hxx b/oox/source/shape/ShapeFilterBase.hxx index d90904ed22cc..1a2edcb461f2 100644 --- a/oox/source/shape/ShapeFilterBase.hxx +++ b/oox/source/shape/ShapeFilterBase.hxx @@ -55,9 +55,6 @@ public: /** Has to be implemented by each filter, returns the current theme. */ virtual const ::oox::drawingml::Theme* getCurrentTheme() const; - /** Has to be implemented by each filter to resolve scheme colors. */ - virtual sal_Int32 getSchemeClr( sal_Int32 nColorSchemeToken ) const; - /** Has to be implemented by each filter to return the collection of VML shapes. */ virtual ::oox::vml::Drawing* getVmlDrawing(); diff --git a/oox/source/token/gentoken.pl b/oox/source/token/gentoken.pl index 6c7c126bc4e2..196ac37ebb5c 100644 --- a/oox/source/token/gentoken.pl +++ b/oox/source/token/gentoken.pl @@ -3,7 +3,7 @@ $ARGV1 = shift @ARGV; $ARGV2 = shift @ARGV; $ARGV3 = shift @ARGV; -open ( TOKENS, $ARGV0 ) || die "can't open token file: $!"; +open ( TOKENS, $ARGV0 ) || die "can't open $ARGV0 file: $!"; my %tokens; while ( <TOKENS> ) @@ -17,15 +17,15 @@ while ( <TOKENS> ) } close ( TOKENS ); -open ( HXX, ">$ARGV1" ) or die "can't open tokens.hxx file: $!"; -open ( WORDS, ">$ARGV2" ) or die "can't open tokenwords.inl file: $!"; -open ( GPERF, ">$ARGV3" ) or die "can't open tokens.gperf file: $!"; +open ( HXX, ">$ARGV1" ) or die "can't open $ARGV1 file: $!"; +open ( WORDS, ">$ARGV2" ) or die "can't open $ARGV2 file: $!"; +open ( GPERF, ">$ARGV3" ) or die "can't open $ARGV3 file: $!"; print ( HXX "#ifndef OOX_TOKENS_HXX\n" ); print ( HXX "#define OOX_TOKENS_HXX\n\n" ); -print ( HXX "#include <sal/types.h>\n" ); +print ( HXX "#include <com/sun/star/xml/sax/FastToken.hpp>\n" ); -print ( WORDS "static const sal_Char* tokentowordlist[] = {\n" ); +print ( WORDS "static const sal_Char* xmltokenwordlist[] = {\n" ); print ( GPERF "%language=C++\n" ); print ( GPERF "%global-table\n" ); @@ -47,7 +47,7 @@ foreach( sort( keys( %tokens ) ) ) } print ( HXX "const sal_Int32 XML_TOKEN_COUNT = $i;\n" ); -print ( HXX "const sal_Int32 XML_TOKEN_INVALID = -1;\n\n" ); +print ( HXX "const sal_Int32 XML_TOKEN_INVALID = ::com::sun::star::xml::sax::FastToken::DONTKNOW;\n\n" ); print ( HXX "const sal_Int32 XML_ROOT_CONTEXT = SAL_MAX_INT32;\n\n" ); print ( HXX "#endif\n" ); diff --git a/oox/source/token/propertylist.cxx b/oox/source/token/propertylist.cxx index b6be034daabc..153b15f32461 100644 --- a/oox/source/token/propertylist.cxx +++ b/oox/source/token/propertylist.cxx @@ -28,23 +28,31 @@ * ************************************************************************/ -#include <rtl/ustring.hxx> +#include "oox/token/propertylist.hxx" #include "properties.hxx" -#include "oox/helper/propertymap.hxx" namespace oox { +namespace { + +// include auto-generated property name lists #include "propertywords.inc" +} // namespace + // ============================================================================ -PropertyNamesList::PropertyNamesList() +PropertyList::PropertyList() { reserve( static_cast< size_t >( PROP_COUNT ) ); for( sal_Int32 nIdx = 0; nIdx < PROP_COUNT; ++nIdx ) push_back( ::rtl::OUString::createFromAscii( propertywordlist[ nIdx ] ) ); } +PropertyList::~PropertyList() +{ +} + // ============================================================================ } // namespace oox diff --git a/oox/source/token/tokenmap.cxx b/oox/source/token/tokenmap.cxx index 93da78313a69..733b18fd1f01 100644 --- a/oox/source/token/tokenmap.cxx +++ b/oox/source/token/tokenmap.cxx @@ -28,104 +28,84 @@ * ************************************************************************/ -#include <string.h> -#include <osl/mutex.hxx> +#include "oox/token/tokenmap.hxx" #include <rtl/strbuf.hxx> -#include <com/sun/star/xml/sax/FastToken.hpp> -#include "oox/core/fasttokenhandler.hxx" +#include <rtl/string.hxx> #include "tokens.hxx" +#include "oox/helper/containerhelper.hxx" using ::rtl::OString; -using ::rtl::OStringBuffer; using ::rtl::OUString; -using ::rtl::OUStringToOString; -using ::osl::Mutex; -using ::osl::MutexGuard; using ::com::sun::star::uno::Sequence; -using ::com::sun::star::uno::RuntimeException; -using ::com::sun::star::xml::sax::FastToken::DONTKNOW; namespace oox { -#include "tokens.inc" -#include "tokenwords.inc" - // ============================================================================ namespace { -Mutex& lclGetTokenMutex() -{ - static Mutex aMutex; - return aMutex; -} +// include auto-generated token lists +#include "tokens.inc" +#include "tokenwords.inc" } // namespace // ============================================================================ -FastTokenHandler::FastTokenHandler() +TokenMap::TokenMap() : + maTokenNames( static_cast< size_t >( XML_TOKEN_COUNT ) ) { + const sal_Char* const* ppcTokenWord = xmltokenwordlist; + for( TokenNameVector::iterator aIt = maTokenNames.begin(), aEnd = maTokenNames.end(); aIt != aEnd; ++aIt, ++ppcTokenWord ) + { + OString aUtf8Token( *ppcTokenWord ); + aIt->maUniName = OStringToOUString( aUtf8Token, RTL_TEXTENCODING_UTF8 ); + aIt->maUtf8Name = Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aUtf8Token.getStr() ), aUtf8Token.getLength() ); + } + #if OSL_DEBUG_LEVEL > 0 - MutexGuard aGuard( lclGetTokenMutex() ); + // check that the perfect_hash is in sync with the token name list bool bOk = true; - for( sal_Int32 nIdx = 0; bOk && (nIdx < XML_TOKEN_COUNT); ++nIdx ) + for( sal_Int32 nToken = 0; bOk && (nToken < XML_TOKEN_COUNT); ++nToken ) { // check that the getIdentifier <-> getToken roundtrip works - OUString aToken = getIdentifier( nIdx ); - bOk = getToken( aToken ) == nIdx; - OSL_ENSURE( bOk, OStringBuffer( "FastTokenHandler::FastTokenHandler - token list broken, #" ). - append( nIdx ).append( ", '" ). - append( OUStringToOString( aToken, RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() ); + OString aUtf8Name = OUStringToOString( maTokenNames[ nToken ].maUniName, RTL_TEXTENCODING_UTF8 ); + struct xmltoken* pToken = Perfect_Hash::in_word_set( aUtf8Name.getStr(), aUtf8Name.getLength() ); + bOk = pToken && (pToken->nToken == nToken); + OSL_ENSURE( bOk, ::rtl::OStringBuffer( "FastTokenHandler::FastTokenHandler - token list broken, #" ). + append( nToken ).append( ", '" ).append( aUtf8Name ).append( '\'' ).getStr() ); } #endif } -FastTokenHandler::~FastTokenHandler() +TokenMap::~TokenMap() { } -sal_Int32 FastTokenHandler::getToken( const OUString& rIdentifier ) throw( RuntimeException ) +OUString TokenMap::getUnicodeTokenName( sal_Int32 nToken ) const { - MutexGuard aGuard( lclGetTokenMutex() ); - - OString aUTF8 = OUStringToOString( rIdentifier, RTL_TEXTENCODING_UTF8 ); - - struct xmltoken * t = Perfect_Hash::in_word_set( aUTF8.getStr(), aUTF8.getLength() ); - return t ? t->nToken : DONTKNOW; + const TokenName* pTokenName = ContainerHelper::getVectorElement( maTokenNames, nToken ); + return pTokenName ? pTokenName->maUniName : OUString(); } -OUString FastTokenHandler::getIdentifier( sal_Int32 nToken ) throw( RuntimeException ) +sal_Int32 TokenMap::getTokenFromUnicode( const OUString& rUnicodeName ) const { - MutexGuard aGuard( lclGetTokenMutex() ); - - if( nToken >= XML_TOKEN_COUNT ) - return OUString(); - - static OUString aTokens[XML_TOKEN_COUNT]; - - if( aTokens[nToken].getLength() == 0 ) - aTokens[nToken] = OUString::createFromAscii( tokentowordlist[nToken] ); - - return aTokens[nToken]; + OString aUtf8Name = OUStringToOString( rUnicodeName, RTL_TEXTENCODING_UTF8 ); + struct xmltoken* pToken = Perfect_Hash::in_word_set( aUtf8Name.getStr(), aUtf8Name.getLength() ); + return pToken ? pToken->nToken : XML_TOKEN_INVALID; } -Sequence< sal_Int8 > FastTokenHandler::getUTF8Identifier( sal_Int32 nToken ) throw( RuntimeException ) +Sequence< sal_Int8 > TokenMap::getUtf8TokenName( sal_Int32 nToken ) const { - MutexGuard aGuard( lclGetTokenMutex() ); - - if( nToken >= XML_TOKEN_COUNT ) - return Sequence< sal_Int8 >(); - - return Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8 *>(tokentowordlist[nToken]), strlen(tokentowordlist[nToken])); + const TokenName* pTokenName = ContainerHelper::getVectorElement( maTokenNames, nToken ); + return pTokenName ? pTokenName->maUtf8Name : Sequence< sal_Int8 >(); } -sal_Int32 FastTokenHandler::getTokenFromUTF8( const Sequence< sal_Int8 >& rIdentifier ) throw( RuntimeException ) +sal_Int32 TokenMap::getTokenFromUtf8( const Sequence< sal_Int8 >& rUtf8Name ) const { - MutexGuard aGuard( lclGetTokenMutex() ); - - struct xmltoken * t = Perfect_Hash::in_word_set( reinterpret_cast< const char* >( rIdentifier.getConstArray() ), rIdentifier.getLength()); - return t ? t->nToken : DONTKNOW; + struct xmltoken* pToken = Perfect_Hash::in_word_set( + reinterpret_cast< const char* >( rUtf8Name.getConstArray() ), rUtf8Name.getLength() ); + return pToken ? pToken->nToken : XML_TOKEN_INVALID; } // ============================================================================ diff --git a/oox/source/token/tokens.txt b/oox/source/token/tokens.txt index 36e33e9d3f1a..4bf407747d95 100644 --- a/oox/source/token/tokens.txt +++ b/oox/source/token/tokens.txt @@ -1541,6 +1541,7 @@ dashLongHeavy dashSmallGap dashUpDiag dashVert +dashdot dashed dashedHeavy dashedSmall @@ -3063,6 +3064,9 @@ long longCurve longFileNames longText +longdash +longdashdot +longdashdotdot loop low lowKashida @@ -4448,6 +4452,10 @@ shininess shorebirdTracks short shortcutKey +shortdash +shortdashdot +shortdashdotdot +shortdot show showAll showAnimation diff --git a/oox/source/vml/makefile.mk b/oox/source/vml/makefile.mk index 305353eb8f02..e4bc963cb1f6 100644 --- a/oox/source/vml/makefile.mk +++ b/oox/source/vml/makefile.mk @@ -47,6 +47,7 @@ ENABLE_EXCEPTIONS=TRUE SLOFILES = \ $(SLO)$/vmldrawing.obj \ $(SLO)$/vmldrawingfragment.obj \ + $(SLO)$/vmlformatting.obj \ $(SLO)$/vmlinputstream.obj \ $(SLO)$/vmlshape.obj \ $(SLO)$/vmlshapecontainer.obj \ diff --git a/oox/source/vml/vmldrawing.cxx b/oox/source/vml/vmldrawing.cxx index 42529ea4a351..f7d9827851f9 100644 --- a/oox/source/vml/vmldrawing.cxx +++ b/oox/source/vml/vmldrawing.cxx @@ -147,6 +147,11 @@ const ControlInfo* Drawing::getControlInfo( const OUString& rShapeId ) const return ContainerHelper::getMapElement( maControls, rShapeId ); } +bool Drawing::isShapeSupported( const ShapeBase& /*rShape*/ ) const +{ + return true; +} + bool Drawing::convertShapeClientAnchor( Rectangle& /*orShapeRect*/, const OUString& /*rShapeAnchor*/ ) const { return false; diff --git a/oox/source/vml/vmldrawingfragment.cxx b/oox/source/vml/vmldrawingfragment.cxx index b622df39941c..6eab7efdba0e 100644 --- a/oox/source/vml/vmldrawingfragment.cxx +++ b/oox/source/vml/vmldrawingfragment.cxx @@ -63,7 +63,7 @@ ContextHandlerRef DrawingFragment::onCreateContext( sal_Int32 nElement, const At // DOCX filter handles plain shape elements with this fragment handler case VMLDRAWING_WORD: if( isRootElement() ) - return ShapeContextBase::createContext( *this, nElement, rAttribs, mrDrawing.getShapes() ); + return ShapeContextBase::createShapeContext( *this, nElement, rAttribs, mrDrawing.getShapes() ); break; // XLSX and PPTX filters load the entire VML fragment @@ -75,7 +75,7 @@ ContextHandlerRef DrawingFragment::onCreateContext( sal_Int32 nElement, const At if( nElement == XML_xml ) return this; break; case XML_xml: - return ShapeContextBase::createContext( *this, nElement, rAttribs, mrDrawing.getShapes() ); + return ShapeContextBase::createShapeContext( *this, nElement, rAttribs, mrDrawing.getShapes() ); } break; } diff --git a/oox/source/vml/vmlformatting.cxx b/oox/source/vml/vmlformatting.cxx new file mode 100644 index 000000000000..a45054a77b52 --- /dev/null +++ b/oox/source/vml/vmlformatting.cxx @@ -0,0 +1,585 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: vmlformatting.cxx,v $ + * $Revision: 1.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/vml/vmlformatting.hxx" +#include <rtl/strbuf.hxx> +#include "tokens.hxx" +#include "oox/token/tokenmap.hxx" +#include "oox/helper/propertymap.hxx" +#include "oox/core/filterbase.hxx" +#include "oox/drawingml/color.hxx" +#include "oox/drawingml/drawingmltypes.hxx" +#include "oox/drawingml/fillproperties.hxx" +#include "oox/drawingml/lineproperties.hxx" + +using ::rtl::OStringBuffer; +using ::rtl::OUString; +using ::com::sun::star::geometry::IntegerRectangle2D; +using ::oox::core::FilterBase; +using ::oox::drawingml::Color; +using ::oox::drawingml::FillProperties; +using ::oox::drawingml::LineArrowProperties; +using ::oox::drawingml::LineProperties; + +namespace oox { +namespace vml { + +// ============================================================================ + +namespace { + +bool lclExtractDouble( double& orfValue, sal_Int32& ornEndPos, const OUString& rValue ) +{ + // extract the double value and find start position of unit characters + rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok; + orfValue = ::rtl::math::stringToDouble( rValue, '.', '\0', &eConvStatus, &ornEndPos ); + return eConvStatus == rtl_math_ConversionStatus_Ok; +} + +} // namespace + +// ---------------------------------------------------------------------------- + +/*static*/ bool ConversionHelper::separatePair( OUString& orValue1, OUString& orValue2, + const OUString& rValue, sal_Unicode cSep ) +{ + sal_Int32 nSepPos = rValue.indexOf( cSep ); + if( nSepPos >= 0 ) + { + orValue1 = rValue.copy( 0, nSepPos ).trim(); + orValue2 = rValue.copy( nSepPos + 1 ).trim(); + } + else + { + orValue1 = rValue.trim(); + } + return (orValue1.getLength() > 0) && (orValue2.getLength() > 0); +} + +/*static*/ bool ConversionHelper::decodeBool( const OUString& rValue ) +{ + // anything else than 't' or 'true' is considered to be false, as specified + return ((rValue.getLength() == 1) && (rValue[ 0 ] == 't')) || (rValue == CREATE_OUSTRING( "true" )); +} + +/*static*/ double ConversionHelper::decodePercent( const OUString& rValue, double fDefValue ) +{ + if( rValue.getLength() == 0 ) + return fDefValue; + + double fValue = 0.0; + sal_Int32 nEndPos = 0; + if( !lclExtractDouble( fValue, nEndPos, rValue ) ) + return fDefValue; + + if( nEndPos == rValue.getLength() ) + return fValue; + + if( (nEndPos + 1 == rValue.getLength()) && (rValue[ nEndPos ] == '%') ) + return fValue / 100.0; + + OSL_ENSURE( false, "ConversionHelper::decodePercent - unknown measure unit" ); + return fDefValue; +} + +/*static*/ sal_Int32 ConversionHelper::decodeMeasureToEmu( const FilterBase& rFilter, + const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel ) +{ + // default for missing values is 0 + if( rValue.getLength() == 0 ) + return 0; + + // TODO: according to spec, value may contain "auto" + if( rValue.equalsAscii( "auto" ) ) + { + OSL_ENSURE( false, "ConversionHelper::decodeMeasureToEmu - special value 'auto' must be handled by caller" ); + return nRefValue; + } + + // extract the double value and find start position of unit characters + double fValue = 0.0; + sal_Int32 nEndPos = 0; + if( !lclExtractDouble( fValue, nEndPos, rValue ) || (fValue == 0.0) ) + return 0; + + // process trailing unit, convert to EMU + static const OUString saPx = CREATE_OUSTRING( "px" ); + OUString aUnit; + if( (0 < nEndPos) && (nEndPos < rValue.getLength()) ) + aUnit = rValue.copy( nEndPos ); + else if( bDefaultAsPixel ) + aUnit = saPx; + // else default is EMU + + if( aUnit.getLength() == 2 ) + { + sal_Unicode cChar1 = aUnit[ 0 ]; + sal_Unicode cChar2 = aUnit[ 1 ]; + if( (cChar1 == 'i') && (cChar2 == 'n') ) // 1 inch = 914,400 EMU + fValue *= 914400.0; + else if( (cChar1 == 'c') && (cChar2 == 'm') ) // 1 cm = 360,000 EMU + fValue *= 360000.0; + else if( (cChar1 == 'm') && (cChar2 == 'm') ) // 1 mm = 36,000 EMU + fValue *= 36000.0; + else if( (cChar1 == 'p') && (cChar2 == 't') ) // 1 point = 1/72 inch = 12,700 MEU + fValue *= 12700.0; + else if( (cChar1 == 'p') && (cChar2 == 'c') ) // 1 pica = 1/6 inch = 152,400 EMU + fValue *= 152400.0; + else if( (cChar1 == 'p') && (cChar2 == 'x') ) // 1 pixel, dependent on output device, factor 360 to convert 1/100mm to EMU + fValue = bPixelX ? rFilter.convertScreenPixelX( 360.0 * fValue ) : rFilter.convertScreenPixelY( 360.0 * fValue ); + } + else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') ) + { + fValue *= nRefValue / 100.0; + } + else if( bDefaultAsPixel || (aUnit.getLength() > 0) ) // default as EMU and no unit -> do nothing + { + OSL_ENSURE( false, "ConversionHelper::decodeMeasureToEmu - unknown measure unit" ); + fValue = nRefValue; + } + return static_cast< sal_Int32 >( fValue + 0.5 ); +} + +/*static*/ sal_Int32 ConversionHelper::decodeMeasureToHmm( const FilterBase& rFilter, + const OUString& rValue, sal_Int32 nRefValue, bool bPixelX, bool bDefaultAsPixel ) +{ + return (decodeMeasureToEmu( rFilter, rValue, nRefValue, bPixelX, bDefaultAsPixel ) + 180) / 360; +} + +// ============================================================================ + +namespace { + +/** Converts a VML color attribute to a DrawingML color. + + @param orDmlColor (out-parameter) The destination DrawingML color. + + @param roVmlColor The VML string representation of the color. If existing, + this can be a 6-digit hexadecimal RGB value with leading '#' character, + a predefined color name (e.g. 'black', 'red', etc.), the index into an + application defined color palette in brackets with leading color name + (e.g. 'red [9]' or 'windowColor [64]'), or a color modifier used in + one-color gradients (e.g. 'fill darken(128)' or 'fill lighten(0)'. + + @param roVmlOpacity The opacity of the color. If existing, this should be + a floating-point value in the range [0.0;1.0]. + + @param nDefaultRgb Deafult RGB color used if the parameter roVmlColor is + empty. + + @param nPrimaryRgb If set to something else than API_RGB_TRANSPARENT, + specifies the color to be used to resolve the color modifiers used in + one-color gradients. + */ +void lclGetColor( Color& orDmlColor, const FilterBase& rFilter, + const OptValue< OUString >& roVmlColor, const OptValue< double >& roVmlOpacity, + sal_Int32 nDefaultRgb, sal_Int32 nPrimaryRgb = API_RGB_TRANSPARENT ) +{ + // convert opacity + const sal_Int32 DML_FULL_OPAQUE = ::oox::drawingml::MAX_PERCENT; + double fOpacity = roVmlOpacity.get( 1.0 ); + sal_Int32 nOpacity = getLimitedValue< sal_Int32, double >( fOpacity * DML_FULL_OPAQUE, 0, DML_FULL_OPAQUE ); + if( nOpacity < DML_FULL_OPAQUE ) + orDmlColor.addTransformation( XML_alpha, nOpacity ); + + // color attribute not present - set passed default color + if( !roVmlColor.has() ) + { + orDmlColor.setSrgbClr( nDefaultRgb ); + return; + } + + // separate leading color name or RGB value from following palette index + OUString aColorName, aColorIndex; + ConversionHelper::separatePair( aColorName, aColorIndex, roVmlColor.get(), ' ' ); + + // RGB colors in the format '#RRGGBB' + if( (aColorName.getLength() == 7) && (aColorName[ 0 ] == '#') ) + { + orDmlColor.setSrgbClr( aColorName.copy( 1 ).toInt32( 16 ) ); + return; + } + + // RGB colors in the format '#RGB' + if( (aColorName.getLength() == 4) && (aColorName[ 0 ] == '#') ) + { + sal_Int32 nR = aColorName.copy( 1, 1 ).toInt32( 16 ) * 0x11; + sal_Int32 nG = aColorName.copy( 2, 1 ).toInt32( 16 ) * 0x11; + sal_Int32 nB = aColorName.copy( 3, 1 ).toInt32( 16 ) * 0x11; + orDmlColor.setSrgbClr( (nR << 16) | (nG << 8) | nB ); + return; + } + + /* Predefined color names or system color names (resolve to RGB to detect + valid color name). */ + sal_Int32 nColorToken = StaticTokenMap::get().getTokenFromUnicode( aColorName ); + sal_Int32 nRgbValue = Color::getVmlPresetColor( nColorToken, API_RGB_TRANSPARENT ); + if( nRgbValue == API_RGB_TRANSPARENT ) + nRgbValue = rFilter.getSystemColor( nColorToken, API_RGB_TRANSPARENT ); + if( nRgbValue != API_RGB_TRANSPARENT ) + { + orDmlColor.setSrgbClr( nRgbValue ); + return; + } + + // try palette colors enclosed in brackets + if( (aColorIndex.getLength() >= 3) && (aColorIndex[ 0 ] == '[') && (aColorIndex[ aColorIndex.getLength() - 1 ] == ']') ) + { + orDmlColor.setPaletteClr( aColorIndex.copy( 1, aColorIndex.getLength() - 2 ).toInt32() ); + return; + } + + // try fill gradient modificator 'fill <modifier>(<amount>)' + if( (nPrimaryRgb != API_RGB_TRANSPARENT) && (nColorToken == XML_fill) ) + { + sal_Int32 nOpenParen = aColorIndex.indexOf( '(' ); + sal_Int32 nCloseParen = aColorIndex.indexOf( ')' ); + if( (2 <= nOpenParen) && (nOpenParen + 1 < nCloseParen) && (nCloseParen + 1 == aColorIndex.getLength()) ) + { + sal_Int32 nModToken = XML_TOKEN_INVALID; + switch( StaticTokenMap::get().getTokenFromUnicode( aColorIndex.copy( 0, nOpenParen ) ) ) + { + case XML_darken: nModToken = XML_shade; + case XML_lighten: nModToken = XML_tint; + } + sal_Int32 nValue = aColorIndex.copy( nOpenParen + 1, nCloseParen - nOpenParen - 1 ).toInt32(); + if( (nModToken != XML_TOKEN_INVALID) && (0 <= nValue) && (nValue < 255) ) + { + /* Simulate this modifier color by a color with related transformation. + The modifier amount has to be converted from the range [0;255] to + percentage [0;100000] used by DrawingML. */ + orDmlColor.setSrgbClr( nPrimaryRgb ); + orDmlColor.addTransformation( nModToken, static_cast< sal_Int32 >( nValue * ::oox::drawingml::MAX_PERCENT / 255 ) ); + return; + } + } + } + + OSL_ENSURE( false, OStringBuffer( "lclGetColor - invalid VML color name '" ). + append( OUStringToOString( roVmlColor.get(), RTL_TEXTENCODING_ASCII_US ) ).append( '\'' ).getStr() ); + orDmlColor.setSrgbClr( nDefaultRgb ); +} + +sal_Int32 lclGetEmu( const FilterBase& rFilter, const OptValue< OUString >& roValue, sal_Int32 nDefValue ) +{ + return roValue.has() ? ConversionHelper::decodeMeasureToEmu( rFilter, roValue.get(), 0, false, false ) : nDefValue; +} + +void lclGetDmlLineDash( OptValue< sal_Int32 >& oroPresetDash, LineProperties::DashStopVector& orCustomDash, const OptValue< OUString >& roDashStyle ) +{ + if( roDashStyle.has() ) + { + const OUString& rDashStyle = roDashStyle.get(); + switch( StaticTokenMap::get().getTokenFromUnicode( rDashStyle ) ) + { + case XML_solid: oroPresetDash = XML_solid; return; + case XML_shortdot: oroPresetDash = XML_sysDot; return; + case XML_shortdash: oroPresetDash = XML_sysDash; return; + case XML_shortdashdot: oroPresetDash = XML_sysDashDot; return; + case XML_shortdashdotdot: oroPresetDash = XML_sysDashDotDot; return; + case XML_dot: oroPresetDash = XML_dot; return; + case XML_dash: oroPresetDash = XML_dash; return; + case XML_dashdot: oroPresetDash = XML_dashDot; return; + case XML_longdash: oroPresetDash = XML_lgDash; return; + case XML_longdashdot: oroPresetDash = XML_lgDashDot; return; + case XML_longdashdotdot: oroPresetDash = XML_lgDashDotDot; return; + + // try to convert user-defined dash style + default: + { + ::std::vector< sal_Int32 > aValues; + sal_Int32 nIndex = 0; + while( nIndex >= 0 ) + aValues.push_back( rDashStyle.getToken( 0, ' ', nIndex ).toInt32() ); + size_t nPairs = aValues.size() / 2; // ignore last value if size is odd + for( size_t nPairIdx = 0; nPairIdx < nPairs; ++nPairIdx ) + orCustomDash.push_back( LineProperties::DashStop( aValues[ 2 * nPairIdx ], aValues[ 2 * nPairIdx + 1 ] ) ); + } + } + } +} + +sal_Int32 lclGetDmlArrowType( const OptValue< sal_Int32 >& roArrowType ) +{ + if( roArrowType.has() ) switch( roArrowType.get() ) + { + case XML_none: return XML_none; + case XML_block: return XML_triangle; + case XML_classic: return XML_stealth; + case XML_diamond: return XML_diamond; + case XML_oval: return XML_oval; + case XML_open: return XML_arrow; + } + return XML_none; +} + +sal_Int32 lclGetDmlArrowWidth( const OptValue< sal_Int32 >& roArrowWidth ) +{ + if( roArrowWidth.has() ) switch( roArrowWidth.get() ) + { + case XML_narrow: return XML_sm; + case XML_medium: return XML_med; + case XML_wide: return XML_lg; + } + return XML_med; +} + +sal_Int32 lclGetDmlArrowLength( const OptValue< sal_Int32 >& roArrowLength ) +{ + if( roArrowLength.has() ) switch( roArrowLength.get() ) + { + case XML_short: return XML_sm; + case XML_medium: return XML_med; + case XML_long: return XML_lg; + } + return XML_med; +} + +void lclConvertArrow( LineArrowProperties& orArrowProp, const StrokeArrowModel& rStrokeArrow ) +{ + orArrowProp.moArrowType = lclGetDmlArrowType( rStrokeArrow.moArrowType ); + orArrowProp.moArrowWidth = lclGetDmlArrowWidth( rStrokeArrow.moArrowWidth ); + orArrowProp.moArrowLength = lclGetDmlArrowLength( rStrokeArrow.moArrowLength ); +} + +sal_Int32 lclGetDmlLineCompound( const OptValue< sal_Int32 >& roLineStyle ) +{ + if( roLineStyle.has() ) switch( roLineStyle.get() ) + { + case XML_single: return XML_sng; + case XML_thinThin: return XML_dbl; + case XML_thinThick: return XML_thinThick; + case XML_thickThin: return XML_thickThin; + case XML_thickBetweenThin: return XML_tri; + } + return XML_sng; +} + +sal_Int32 lclGetDmlLineCap( const OptValue< sal_Int32 >& roEndCap ) +{ + if( roEndCap.has() ) switch( roEndCap.get() ) + { + case XML_flat: return XML_flat; + case XML_square: return XML_sq; + case XML_round: return XML_rnd; + } + return XML_flat; // different defaults in VML (flat) and DrawingML (square) +} + +sal_Int32 lclGetDmlLineJoint( const OptValue< sal_Int32 >& roJoinStyle ) +{ + if( roJoinStyle.has() ) switch( roJoinStyle.get() ) + { + case XML_round: return XML_round; + case XML_bevel: return XML_bevel; + case XML_miter: return XML_miter; + } + return XML_round; +} + +} // namespace + +// ============================================================================ + +void StrokeArrowModel::assignUsed( const StrokeArrowModel& rSource ) +{ + moArrowType.assignIfUsed( rSource.moArrowType ); + moArrowWidth.assignIfUsed( rSource.moArrowWidth ); + moArrowLength.assignIfUsed( rSource.moArrowLength ); +} + +// ============================================================================ + +void StrokeModel::assignUsed( const StrokeModel& rSource ) +{ + moStroked.assignIfUsed( rSource.moStroked ); + maStartArrow.assignUsed( rSource.maStartArrow ); + maEndArrow.assignUsed( rSource.maEndArrow ); + moColor.assignIfUsed( rSource.moColor ); + moOpacity.assignIfUsed( rSource.moOpacity ); + moWeight.assignIfUsed( rSource.moWeight ); + moDashStyle.assignIfUsed( rSource.moDashStyle ); + moLineStyle.assignIfUsed( rSource.moLineStyle ); + moEndCap.assignIfUsed( rSource.moEndCap ); + moJoinStyle.assignIfUsed( rSource.moJoinStyle ); +} + +void StrokeModel::pushToPropMap( PropertyMap& rPropMap, const FilterBase& rFilter ) const +{ + /* Convert VML line formatting to DrawingML line formatting and let the + DrawingML code do the hard work. */ + LineProperties aLineProps; + + if( moStroked.get( true ) ) + { + aLineProps.maLineFill.moFillType = XML_solidFill; + lclConvertArrow( aLineProps.maStartArrow, maStartArrow ); + lclConvertArrow( aLineProps.maEndArrow, maEndArrow ); + lclGetColor( aLineProps.maLineFill.maFillColor, rFilter, moColor, moOpacity, API_RGB_BLACK ); + aLineProps.moLineWidth = lclGetEmu( rFilter, moWeight, 1 ); + lclGetDmlLineDash( aLineProps.moPresetDash, aLineProps.maCustomDash, moDashStyle ); + aLineProps.moLineCompound = lclGetDmlLineCompound( moLineStyle ); + aLineProps.moLineCap = lclGetDmlLineCap( moEndCap ); + aLineProps.moLineJoint = lclGetDmlLineJoint( moJoinStyle ); + } + else + { + aLineProps.maLineFill.moFillType = XML_noFill; + } + + aLineProps.pushToPropMap( rPropMap, rFilter, rFilter.getModelObjectHelper() ); +} + +// ============================================================================ + +void FillModel::assignUsed( const FillModel& rSource ) +{ + moFilled.assignIfUsed( rSource.moFilled ); + moColor.assignIfUsed( rSource.moColor ); + moOpacity.assignIfUsed( rSource.moOpacity ); + moColor2.assignIfUsed( rSource.moColor2 ); + moOpacity2.assignIfUsed( rSource.moOpacity2 ); + moType.assignIfUsed( rSource.moType ); + moAngle.assignIfUsed( rSource.moAngle ); + moFocus.assignIfUsed( rSource.moFocus ); + moFocusPos.assignIfUsed( rSource.moFocusPos ); + moFocusSize.assignIfUsed( rSource.moFocusSize ); + moRotate.assignIfUsed( rSource.moRotate ); +} + +void FillModel::pushToPropMap( PropertyMap& rPropMap, const FilterBase& rFilter ) const +{ + /* Convert VML fill formatting to DrawingML fill formatting and let the + DrawingML code do the hard work. */ + FillProperties aFillProps; + + if( moFilled.get( true ) ) + { + sal_Int32 nFillType = moType.get( XML_solid ); + switch( nFillType ) + { + case XML_gradient: + case XML_gradientRadial: + { + aFillProps.moFillType = XML_gradFill; + aFillProps.maGradientProps.moRotateWithShape = moRotate.get( false ); + double fFocus = moFocus.get( 0.0 ); + + // prepare colors + Color aColor1, aColor2; + lclGetColor( aColor1, rFilter, moColor, moOpacity, API_RGB_WHITE ); + lclGetColor( aColor2, rFilter, moColor2, moOpacity2, API_RGB_WHITE, aColor1.getColor( rFilter ) ); + + // type XML_gradient is linear or axial gradient + if( nFillType == XML_gradient ) + { + // normalize angle to range [0;360) degrees + sal_Int32 nVmlAngle = getIntervalValue< sal_Int32, sal_Int32 >( moAngle.get( 0 ), 0, 360 ); + + // focus of -50% or 50% is axial gradient + if( ((-0.75 <= fFocus) && (fFocus <= -0.25)) || ((0.25 <= fFocus) && (fFocus <= 0.75)) ) + { + /* According to spec, focus of 50% is outer-to-inner, + and -50% is inner-to-outer (color to color2). + BUT: For angles >= 180 deg., the behaviour is + reversed... that's not spec'ed of course. So, + [0;180) deg. and 50%, or [180;360) deg. and -50% is + outer-to-inner in fact. */ + bool bOuterToInner = (fFocus > 0.0) == (nVmlAngle < 180); + // simulate axial gradient by 3-step DrawingML gradient + const Color& rOuterColor = bOuterToInner ? aColor1 : aColor2; + const Color& rInnerColor = bOuterToInner ? aColor2 : aColor1; + aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aFillProps.maGradientProps.maGradientStops[ 1.0 ] = rOuterColor; + aFillProps.maGradientProps.maGradientStops[ 0.5 ] = rInnerColor; + } + else // focus of -100%, 0%, and 100% is linear gradient + { + /* According to spec, focus of -100% or 100% swaps the + start and stop colors, effectively reversing the + gradient. BUT: For angles >= 180 deg., the + behaviour is reversed. This means that in this case + a focus of 0% swaps the gradient. */ + if( ((fFocus < -0.75) || (fFocus > 0.75)) == (nVmlAngle < 180) ) + (nVmlAngle += 180) %= 360; + // set the start and stop colors + aFillProps.maGradientProps.maGradientStops[ 0.0 ] = aColor1; + aFillProps.maGradientProps.maGradientStops[ 1.0 ] = aColor2; + } + + // VML counts counterclockwise from bottom, DrawingML clockwise from left + sal_Int32 nDmlAngle = (630 - nVmlAngle) % 360; + aFillProps.maGradientProps.moShadeAngle = nDmlAngle * ::oox::drawingml::PER_DEGREE; + } + else // XML_gradientRadial is rectangular gradient + { + aFillProps.maGradientProps.moGradientPath = XML_rect; + // convert VML focus position and size to DrawingML fill-to-rect + DoublePair aFocusPos = moFocusPos.get( DoublePair( 0.0, 0.0 ) ); + DoublePair aFocusSize = moFocusSize.get( DoublePair( 0.0, 0.0 ) ); + double fLeft = getLimitedValue< double, double >( aFocusPos.first, 0.0, 1.0 ); + double fTop = getLimitedValue< double, double >( aFocusPos.second, 0.0, 1.0 ); + double fRight = getLimitedValue< double, double >( fLeft + aFocusSize.first, fLeft, 1.0 ); + double fBottom = getLimitedValue< double, double >( fTop + aFocusSize.second, fTop, 1.0 ); + aFillProps.maGradientProps.moFillToRect = IntegerRectangle2D( + static_cast< sal_Int32 >( fLeft * ::oox::drawingml::MAX_PERCENT ), + static_cast< sal_Int32 >( fTop * ::oox::drawingml::MAX_PERCENT ), + static_cast< sal_Int32 >( (1.0 - fRight) * ::oox::drawingml::MAX_PERCENT ), + static_cast< sal_Int32 >( (1.0 - fBottom) * ::oox::drawingml::MAX_PERCENT ) ); + + // set the start and stop colors (focus of 0% means outer-to-inner) + bool bOuterToInner = (-0.5 <= fFocus) && (fFocus <= 0.5); + aFillProps.maGradientProps.maGradientStops[ 0.0 ] = bOuterToInner ? aColor2 : aColor1; + aFillProps.maGradientProps.maGradientStops[ 1.0 ] = bOuterToInner ? aColor1 : aColor2; + } + } + break; + + case XML_solid: + default: + { + aFillProps.moFillType = XML_solidFill; + // fill color (default is white) + lclGetColor( aFillProps.maFillColor, rFilter, moColor, moOpacity, API_RGB_WHITE ); + } + } + } + else + { + aFillProps.moFillType = XML_noFill; + } + + aFillProps.pushToPropMap( rPropMap, rFilter, rFilter.getModelObjectHelper() ); +} + +// ============================================================================ + +} // namespace vml +} // namespace oox + diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx index d586196acee4..fe07172599a9 100644 --- a/oox/source/vml/vmlshape.cxx +++ b/oox/source/vml/vmlshape.cxx @@ -33,7 +33,6 @@ #include <com/sun/star/lang/XMultiServiceFactory.hpp> #include <com/sun/star/beans/PropertyValues.hpp> #include <com/sun/star/awt/XControlModel.hpp> -#include <com/sun/star/drawing/FillStyle.hpp> #include <com/sun/star/drawing/PointSequenceSequence.hpp> #include <com/sun/star/drawing/XControlShape.hpp> #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> @@ -75,57 +74,6 @@ namespace vml { namespace { -sal_Int32 lclGetMeasure( const XmlFilterBase& /*rFilter*/, const OUString& rValue, sal_Int32 nRefValue ) -{ - // default for missing values is 0 - if( rValue.getLength() == 0 ) - return 0; - - // TODO: according to spec, value may contain "auto" - if( rValue.equalsAscii( "auto" ) ) - return nRefValue; - - // extract the double value and find start position of unit characters - rtl_math_ConversionStatus eConvStatus = rtl_math_ConversionStatus_Ok; - sal_Int32 nEndPos = 0; - double fValue = ::rtl::math::stringToDouble( rValue, '.', '\0', &eConvStatus, &nEndPos ); - if( (eConvStatus != rtl_math_ConversionStatus_Ok) || (fValue == 0.0) ) - return 0; - - // process trailing unit, convert to 1/100 mm - static const OUString saPx = CREATE_OUSTRING( "px" ); - OUString aUnit = ((0 < nEndPos) && (nEndPos < rValue.getLength())) ? rValue.copy( nEndPos ) : saPx; - if( aUnit.getLength() == 2 ) - { - sal_Unicode cChar1 = aUnit[ 0 ]; - sal_Unicode cChar2 = aUnit[ 1 ]; - if( (cChar1 == 'i') && (cChar2 == 'n') ) // 1 inch = 2540 1/100mm - fValue *= 2540.0; - else if( (cChar1 == 'c') && (cChar2 == 'm') ) // 1 cm = 1000 1/100mm - fValue *= 1000.0; - else if( (cChar1 == 'm') && (cChar2 == 'm') ) // 1 mm = 100 1/100mm - fValue *= 100.0; - else if( (cChar1 == 'p') && (cChar2 == 't') ) // 1 point = 1/72 inch - fValue *= 2540.0 / 72.0; - else if( (cChar1 == 'p') && (cChar2 == 'c') ) // 1 pica = 1/6 inch - fValue *= 2540.0 / 6.0; - else if( (cChar1 == 'e') && (cChar2 == 'm') ) // relative to refvalue - fValue *= nRefValue; - else if( (cChar1 == 'p') && (cChar2 == 'x') ) // 1 pixel, dependent on output device - fValue *= 1.0; - } - else if( (aUnit.getLength() == 1) && (aUnit[ 0 ] == '%') ) - { - fValue *= nRefValue / 100.0; - } - else - { - OSL_ENSURE( false, "lclGetMeasure - unknown measure unit" ); - fValue = nRefValue; - } - return static_cast< sal_Int32 >( fValue + 0.5 ); -} - Point lclGetAbsPoint( const Point& rRelPoint, const Rectangle& rShapeRect, const Rectangle& rCoordSys ) { double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width; @@ -164,7 +112,7 @@ Reference< XShape > lclCreateXShape( const XmlFilterBase& rFilter, const OUStrin return xShape; } -void lclInsertXShape( const Reference< XShapes >& rxShapes, const Reference< XShape >& rxShape, const Rectangle& rShapeRect ) +void lclInsertXShape( const Reference< XShapes >& rxShapes, const Reference< XShape >& rxShape ) { OSL_ENSURE( rxShapes.is(), "lclInsertXShape - missing XShapes container" ); OSL_ENSURE( rxShape.is(), "lclInsertXShape - missing XShape" ); @@ -172,20 +120,28 @@ void lclInsertXShape( const Reference< XShapes >& rxShapes, const Reference< XSh { // insert shape into passed shape collection (maybe drawpage or group shape) rxShapes->add( rxShape ); - // set position/size - rxShape->setPosition( Point( rShapeRect.X, rShapeRect.Y ) ); - rxShape->setSize( Size( rShapeRect.Width, rShapeRect.Height ) ); } catch( Exception& ) { } } +void lclSetXShapeRect( const Reference< XShape >& rxShape, const Rectangle& rShapeRect ) +{ + OSL_ENSURE( rxShape.is(), "lclSetXShapeRect - missing XShape" ); + if( rxShape.is() ) + { + rxShape->setPosition( Point( rShapeRect.X, rShapeRect.Y ) ); + rxShape->setSize( Size( rShapeRect.Width, rShapeRect.Height ) ); + } +} + Reference< XShape > lclCreateAndInsertXShape( const XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes, const OUString& rService, const Rectangle& rShapeRect ) { Reference< XShape > xShape = lclCreateXShape( rFilter, rService ); - lclInsertXShape( rxShapes, xShape, rShapeRect ); + lclInsertXShape( rxShapes, xShape ); + lclSetXShapeRect( xShape, rShapeRect ); return xShape; } @@ -199,17 +155,13 @@ ShapeTypeModel::ShapeTypeModel() void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource ) { - monShapeType.assignIfUsed( rSource.monShapeType ); - monCoordLeft.assignIfUsed( rSource.monCoordLeft ); - monCoordTop.assignIfUsed( rSource.monCoordTop ); - monCoordWidth.assignIfUsed( rSource.monCoordWidth ); - monCoordHeight.assignIfUsed( rSource.monCoordHeight ); + moShapeType.assignIfUsed( rSource.moShapeType ); + moCoordPos.assignIfUsed( rSource.moCoordPos ); + moCoordSize.assignIfUsed( rSource.moCoordSize ); /* The style properties position, left, top, width, height, margin-left, margin-top are not derived from shape template to shape. */ - mobStroked.assignIfUsed( rSource.mobStroked ); - moStrokeColor.assignIfUsed( rSource.moStrokeColor ); - mobFilled.assignIfUsed( rSource.mobFilled ); - moFillColor.assignIfUsed( rSource.moFillColor ); + maStrokeModel.assignUsed( rSource.maStrokeModel ); + maFillModel.assignUsed( rSource.maFillModel ); moGraphicPath.assignIfUsed( rSource.moGraphicPath ); moGraphicTitle.assignIfUsed( rSource.moGraphicTitle ); } @@ -232,11 +184,9 @@ OUString ShapeType::getGraphicPath() const Rectangle ShapeType::getCoordSystem() const { - return Rectangle( - maTypeModel.monCoordLeft.get( 0 ), - maTypeModel.monCoordTop.get( 0 ), - maTypeModel.monCoordWidth.get( 1000 ), - maTypeModel.monCoordHeight.get( 1000 ) ); + Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) ); + Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) ); + return Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second ); } Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const @@ -250,10 +200,10 @@ Rectangle ShapeType::getAbsRectangle() const { const XmlFilterBase& rFilter = mrDrawing.getFilter(); return Rectangle( - lclGetMeasure( rFilter, maTypeModel.maLeft, 0 ) + lclGetMeasure( rFilter, maTypeModel.maMarginLeft, 0 ), - lclGetMeasure( rFilter, maTypeModel.maTop, 0 ) + lclGetMeasure( rFilter, maTypeModel.maMarginTop, 0 ), - lclGetMeasure( rFilter, maTypeModel.maWidth, 0 ), - lclGetMeasure( rFilter, maTypeModel.maHeight, 0 ) ); + ConversionHelper::decodeMeasureToHmm( rFilter, maTypeModel.maLeft, 0, true, true ) + ConversionHelper::decodeMeasureToHmm( rFilter, maTypeModel.maMarginLeft, 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rFilter, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rFilter, maTypeModel.maMarginTop, 0, false, true ), + ConversionHelper::decodeMeasureToHmm( rFilter, maTypeModel.maWidth, 0, true, true ), + ConversionHelper::decodeMeasureToHmm( rFilter, maTypeModel.maHeight, 0, false, true ) ); } Rectangle ShapeType::getRelRectangle() const @@ -269,7 +219,10 @@ Rectangle ShapeType::getRelRectangle() const ShapeClientData::ShapeClientData() : mnObjType( XML_TOKEN_INVALID ), - mbPrintObject( true ) + mnCol( -1 ), + mnRow( -1 ), + mbPrintObject( true ), + mbVisible( false ) { } @@ -313,27 +266,55 @@ const ShapeBase* ShapeBase::getChildById( const OUString& ) const Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const { Reference< XShape > xShape; + if( mrDrawing.isShapeSupported( *this ) ) + { + /* Calculate shape rectangle. Applications may do something special + according to some imported shape client data (e.g. Excel cell anchor). */ + Rectangle aShapeRect = calcShapeRectangle( pParentAnchor ); + // convert the shape, if the calculated rectangle is not empty + if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() ) + xShape = implConvertAndInsert( rxShapes, aShapeRect ); + } + return xShape; +} + +void ShapeBase::convertFormatting( const Reference< XShape >& rxShape, const ShapeParentAnchor* pParentAnchor ) const +{ + if( rxShape.is() ) + { + /* Calculate shape rectangle. Applications may do something special + according to some imported shape client data (e.g. Excel cell anchor). */ + Rectangle aShapeRect = calcShapeRectangle( pParentAnchor ); + // convert the shape, if the calculated rectangle is not empty + if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) ) + { + lclSetXShapeRect( rxShape, aShapeRect ); + convertShapeProperties( rxShape ); + } + } +} + +// protected ------------------------------------------------------------------ + +Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const +{ /* Calculate shape rectangle. Applications may do something special according to some imported shape client data (e.g. Excel cell anchor). */ Rectangle aShapeRect; if( !maShapeModel.mxClientData.get() || !mrDrawing.convertShapeClientAnchor( aShapeRect, maShapeModel.mxClientData->maAnchor ) ) aShapeRect = getRectangle( pParentAnchor ); - // convert the shape, if the calculated rectangle is not empty - if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() ) - xShape = implConvertAndInsert( rxShapes, aShapeRect ); - return xShape; + return aShapeRect; } -// protected ------------------------------------------------------------------ - void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const { - // shape properties - PropertySet aPropSet( rxShape ); + PropertyMap aPropMap; + + maTypeModel.maStrokeModel.pushToPropMap( aPropMap, mrDrawing.getFilter() ); + maTypeModel.maFillModel.pushToPropMap( aPropMap, mrDrawing.getFilter() ); - // fill style - bool bFilled = maTypeModel.mobFilled.get( true ); - aPropSet.setProperty( PROP_FillStyle, bFilled ? ::com::sun::star::drawing::FillStyle_SOLID : ::com::sun::star::drawing::FillStyle_NONE ); + PropertySet aPropSet( rxShape ); + aPropSet.setProperties( aPropMap ); } // ============================================================================ @@ -405,7 +386,7 @@ Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes { // create the custom shape geometry Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW ); - xDefaulter->createCustomShapeDefaults( OUString::valueOf( maTypeModel.monShapeType.get( 0 ) ) ); + xDefaulter->createCustomShapeDefaults( OUString::valueOf( maTypeModel.moShapeType.get( 0 ) ) ); // convert common properties convertShapeProperties( xShape ); } @@ -537,21 +518,27 @@ const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const Rectangle& rShapeRect ) const { - Reference< XShape > xShape; + Reference< XShape > xGroupShape; // check that this shape contains children and a valid coordinate system ShapeParentAnchor aParentAnchor; aParentAnchor.maShapeRect = rShapeRect; aParentAnchor.maCoordSys = getCoordSystem(); if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try { - xShape = lclCreateAndInsertXShape( mrDrawing.getFilter(), rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rShapeRect ); - Reference< XShapes > xShapes( xShape, UNO_QUERY_THROW ); - mxChildren->convertAndInsert( xShapes, &aParentAnchor ); + xGroupShape = lclCreateAndInsertXShape( mrDrawing.getFilter(), rxShapes, CREATE_OUSTRING( "com.sun.star.drawing.GroupShape" ), rShapeRect ); + Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW ); + mxChildren->convertAndInsert( xChildShapes, &aParentAnchor ); + // no child shape has been created - delete the group shape + if( !xChildShapes->hasElements() ) + { + rxShapes->remove( xGroupShape ); + xGroupShape.clear(); + } } catch( Exception& ) { } - return xShape; + return xGroupShape; } // ============================================================================ diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx index dcf842a67a8f..725af97777c3 100644 --- a/oox/source/vml/vmlshapecontext.cxx +++ b/oox/source/vml/vmlshapecontext.cxx @@ -45,19 +45,62 @@ namespace vml { namespace { -bool lclSeparateValue( OUString& orName, OUString& orValue, const OUString& rAttrib, sal_Unicode cSep = ':' ) +/** Returns the boolean value from the specified VML attribute (if present). + */ +OptValue< bool > lclDecodeBool( const AttributeList& rAttribs, sal_Int32 nElement ) +{ + OptValue< OUString > oValue = rAttribs.getString( nElement ); + if( oValue.has() ) return OptValue< bool >( ConversionHelper::decodeBool( oValue.get() ) ); + return OptValue< bool >(); +} + +/** Returns the percentage value from the specified VML attribute (if present). + The value will be normalized (1.0 is returned for 100%). + */ +OptValue< double > lclDecodePercent( const AttributeList& rAttribs, sal_Int32 nElement, double fDefValue ) +{ + OptValue< OUString > oValue = rAttribs.getString( nElement ); + if( oValue.has() ) return OptValue< double >( ConversionHelper::decodePercent( oValue.get(), fDefValue ) ); + return OptValue< double >(); +} + +/** Returns the integer value pair from the specified VML attribute (if present). + */ +OptValue< Int32Pair > lclDecodeInt32Pair( const AttributeList& rAttribs, sal_Int32 nElement ) +{ + OptValue< OUString > oValue = rAttribs.getString( nElement ); + OptValue< Int32Pair > oRetValue; + if( oValue.has() ) + { + OUString aValue1, aValue2; + ConversionHelper::separatePair( aValue1, aValue2, oValue.get(), ',' ); + oRetValue = Int32Pair( aValue1.toInt32(), aValue2.toInt32() ); + } + return oRetValue; +} + +/** Returns the percentage pair from the specified VML attribute (if present). + */ +OptValue< DoublePair > lclDecodePercentPair( const AttributeList& rAttribs, sal_Int32 nElement ) { - sal_Int32 nSepPos = rAttrib.indexOf( cSep ); - if( nSepPos <= 0 ) return false; - orName = rAttrib.copy( 0, nSepPos ).trim(); - orValue = rAttrib.copy( nSepPos + 1 ).trim(); - return (orName.getLength() > 0) && (orValue.getLength() > 0); + OptValue< OUString > oValue = rAttribs.getString( nElement ); + OptValue< DoublePair > oRetValue; + if( oValue.has() ) + { + OUString aValue1, aValue2; + ConversionHelper::separatePair( aValue1, aValue2, oValue.get(), ',' ); + oRetValue = DoublePair( + ConversionHelper::decodePercent( aValue1, 0.0 ), + ConversionHelper::decodePercent( aValue2, 0.0 ) ); + } + return oRetValue; } -/** Returns the boolean value from the passed string (supported: f, t, False, True). +/** Returns the boolean value from the passed string of an attribute in the x: + namespace (VML for spreadsheets). Supported values: f, t, False, True. @param bDefaultForEmpty Default value for the empty string. */ -bool lclDecodeBool( const OUString& rValue, bool bDefaultForEmpty ) +bool lclDecodeVmlxBool( const OUString& rValue, bool bDefaultForEmpty ) { if( rValue.getLength() == 0 ) return bDefaultForEmpty; // anything else than 't' or 'True' is considered to be false, as specified @@ -85,11 +128,14 @@ void ShapeClientDataContext::onEndElement( const OUString& rChars ) { switch( getCurrentElement() ) { - case VMLX_TOKEN( Anchor ): mrClientData.maAnchor = rChars; break; - case VMLX_TOKEN( FmlaLink ): mrClientData.maLinkedCell = rChars; break; - case VMLX_TOKEN( FmlaPict ): mrClientData.maPictureLink = rChars; break; - case VMLX_TOKEN( FmlaRange ): mrClientData.maSourceRange = rChars; break; - case VMLX_TOKEN( PrintObject ): mrClientData.mbPrintObject = lclDecodeBool( rChars, true ); break; + case VMLX_TOKEN( Anchor ): mrClientData.maAnchor = rChars; break; + case VMLX_TOKEN( FmlaPict ): mrClientData.maPictureLink = rChars; break; + case VMLX_TOKEN( FmlaLink ): mrClientData.maLinkedCell = rChars; break; + case VMLX_TOKEN( FmlaRange ): mrClientData.maSourceRange = rChars; break; + case VMLX_TOKEN( Column ): mrClientData.mnCol = rChars.toInt32(); break; + case VMLX_TOKEN( Row ): mrClientData.mnRow = rChars.toInt32(); break; + case VMLX_TOKEN( PrintObject ): mrClientData.mbPrintObject = lclDecodeVmlxBool( rChars, true ); break; + case VMLX_TOKEN( Visible ): mrClientData.mbVisible = true; break; } } @@ -100,7 +146,7 @@ ShapeContextBase::ShapeContextBase( ContextHandler2Helper& rParent ) : { } -/*static*/ ContextHandlerRef ShapeContextBase::createContext( ContextHandler2Helper& rParent, +/*static*/ ContextHandlerRef ShapeContextBase::createShapeContext( ContextHandler2Helper& rParent, sal_Int32 nElement, const AttributeList& rAttribs, ShapeContainer& rShapes ) { switch( nElement ) @@ -144,24 +190,56 @@ ShapeTypeContext::ShapeTypeContext( ContextHandler2Helper& rParent, const Attrib if( bHasOspid ) mrTypeModel.maName = rAttribs.getXString( XML_id, OUString() ); // builtin shape type identifier - mrTypeModel.monShapeType = rAttribs.getInteger( O_TOKEN( spt ) ); - // coordinate system position/size - setCoordOrigin( rAttribs.getString( XML_coordorigin, OUString() ) ); - setCoordSize( rAttribs.getString( XML_coordsize, OUString() ) ); - // CSS style + mrTypeModel.moShapeType = rAttribs.getInteger( O_TOKEN( spt ) ); + + // coordinate system position/size, CSS style + mrTypeModel.moCoordPos = lclDecodeInt32Pair( rAttribs, XML_coordorigin ); + mrTypeModel.moCoordSize = lclDecodeInt32Pair( rAttribs, XML_coordsize ); setStyle( rAttribs.getString( XML_style, OUString() ) ); - // border line - mrTypeModel.mobStroked = rAttribs.getBool( XML_stroked ); - mrTypeModel.moStrokeColor = rAttribs.getString( XML_strokecolor ); - // shape fill - mrTypeModel.mobFilled = rAttribs.getBool( XML_filled ); - mrTypeModel.moFillColor = rAttribs.getString( XML_fillcolor ); + + // stroke settings (may be overridden by v:stroke element later) + mrTypeModel.maStrokeModel.moStroked = lclDecodeBool( rAttribs, XML_stroked ); + mrTypeModel.maStrokeModel.moColor = rAttribs.getString( XML_strokecolor ); + mrTypeModel.maStrokeModel.moWeight = rAttribs.getString( XML_strokeweight ); + + // fill settings (may be overridden by v:fill element later) + mrTypeModel.maFillModel.moFilled = lclDecodeBool( rAttribs, XML_filled ); + mrTypeModel.maFillModel.moColor = rAttribs.getString( XML_fillcolor ); } ContextHandlerRef ShapeTypeContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) { if( isRootElement() ) switch( nElement ) { + case VML_TOKEN( stroke ): + mrTypeModel.maStrokeModel.moStroked.assignIfUsed( lclDecodeBool( rAttribs, XML_on ) ); + mrTypeModel.maStrokeModel.maStartArrow.moArrowType = rAttribs.getToken( XML_startarrow ); + mrTypeModel.maStrokeModel.maStartArrow.moArrowWidth = rAttribs.getToken( XML_startarrowwidth ); + mrTypeModel.maStrokeModel.maStartArrow.moArrowLength = rAttribs.getToken( XML_startarrowlength ); + mrTypeModel.maStrokeModel.maEndArrow.moArrowType = rAttribs.getToken( XML_endarrow ); + mrTypeModel.maStrokeModel.maEndArrow.moArrowWidth = rAttribs.getToken( XML_endarrowwidth ); + mrTypeModel.maStrokeModel.maEndArrow.moArrowLength = rAttribs.getToken( XML_endarrowlength ); + mrTypeModel.maStrokeModel.moColor.assignIfUsed( rAttribs.getString( XML_color ) ); + mrTypeModel.maStrokeModel.moOpacity = lclDecodePercent( rAttribs, XML_opacity, 1.0 ); + mrTypeModel.maStrokeModel.moWeight.assignIfUsed( rAttribs.getString( XML_weight ) ); + mrTypeModel.maStrokeModel.moDashStyle = rAttribs.getString( XML_dashstyle ); + mrTypeModel.maStrokeModel.moLineStyle = rAttribs.getToken( XML_linestyle ); + mrTypeModel.maStrokeModel.moEndCap = rAttribs.getToken( XML_endcap ); + mrTypeModel.maStrokeModel.moJoinStyle = rAttribs.getToken( XML_joinstyle ); + break; + case VML_TOKEN( fill ): + mrTypeModel.maFillModel.moFilled.assignIfUsed( lclDecodeBool( rAttribs, XML_on ) ); + mrTypeModel.maFillModel.moColor.assignIfUsed( rAttribs.getString( XML_color ) ); + mrTypeModel.maFillModel.moOpacity = lclDecodePercent( rAttribs, XML_opacity, 1.0 ); + mrTypeModel.maFillModel.moColor2 = rAttribs.getString( XML_color2 ); + mrTypeModel.maFillModel.moOpacity2 = lclDecodePercent( rAttribs, XML_opacity2, 1.0 ); + mrTypeModel.maFillModel.moType = rAttribs.getToken( XML_type ); + mrTypeModel.maFillModel.moAngle = rAttribs.getInteger( XML_angle ); + mrTypeModel.maFillModel.moFocus = lclDecodePercent( rAttribs, XML_focus, 0.0 ); + mrTypeModel.maFillModel.moFocusPos = lclDecodePercentPair( rAttribs, XML_focusposition ); + mrTypeModel.maFillModel.moFocusSize = lclDecodePercentPair( rAttribs, XML_focussize ); + mrTypeModel.maFillModel.moRotate = lclDecodeBool( rAttribs, XML_rotate ); + break; case VML_TOKEN( imagedata ): OptValue< OUString > oGraphicRelId = rAttribs.getString( O_TOKEN( relid ) ); if( oGraphicRelId.has() ) @@ -172,33 +250,13 @@ ContextHandlerRef ShapeTypeContext::onCreateContext( sal_Int32 nElement, const A return 0; } -void ShapeTypeContext::setCoordOrigin( const OUString& rCoordOrigin ) -{ - OUString aCoordL, aCoordT; - if( lclSeparateValue( aCoordL, aCoordT, rCoordOrigin, ',' ) ) - { - mrTypeModel.monCoordLeft = aCoordL.toInt32(); - mrTypeModel.monCoordTop = aCoordT.toInt32(); - } -} - -void ShapeTypeContext::setCoordSize( const OUString& rCoordSize ) -{ - OUString aCoordW, aCoordH; - if( lclSeparateValue( aCoordW, aCoordH, rCoordSize, ',' ) ) - { - mrTypeModel.monCoordWidth = aCoordW.toInt32(); - mrTypeModel.monCoordHeight = aCoordH.toInt32(); - } -} - void ShapeTypeContext::setStyle( const OUString& rStyle ) { sal_Int32 nIndex = 0; while( nIndex >= 0 ) { OUString aName, aValue; - if( lclSeparateValue( aName, aValue, rStyle.getToken( 0, ';', nIndex ) ) ) + if( ConversionHelper::separatePair( aName, aValue, rStyle.getToken( 0, ';', nIndex ), ':' ) ) { if( aName.equalsAscii( "position" ) ) mrTypeModel.maPosition = aValue; else if( aName.equalsAscii( "left" ) ) mrTypeModel.maLeft = aValue; @@ -255,7 +313,7 @@ GroupShapeContext::GroupShapeContext( ContextHandler2Helper& rParent, const Attr ContextHandlerRef GroupShapeContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs ) { // try to create a context of an embedded shape - ContextHandlerRef xContext = ShapeContextBase::createContext( *this, nElement, rAttribs, mrShapes ); + ContextHandlerRef xContext = createShapeContext( *this, nElement, rAttribs, mrShapes ); // handle remaining stuff of this shape in base class return xContext.get() ? xContext : ShapeContext::onCreateContext( nElement, rAttribs ); } diff --git a/oox/source/xls/chartsheetfragment.cxx b/oox/source/xls/chartsheetfragment.cxx index 3df5ff9c3e2a..7e5b9198c1da 100644 --- a/oox/source/xls/chartsheetfragment.cxx +++ b/oox/source/xls/chartsheetfragment.cxx @@ -47,7 +47,7 @@ namespace xls { // ============================================================================ OoxChartsheetFragment::OoxChartsheetFragment( const WorkbookHelper& rHelper, - const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, sal_Int32 nSheet ) : + const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, sal_Int16 nSheet ) : OoxWorksheetFragmentBase( rHelper, rFragmentPath, xProgressBar, SHEETTYPE_CHARTSHEET, nSheet ) { } @@ -185,7 +185,7 @@ void OoxChartsheetFragment::importDrawing( RecordInputStream& rStrm ) // ============================================================================ BiffChartsheetFragment::BiffChartsheetFragment( const BiffWorkbookFragmentBase& rParent, - ISegmentProgressBarRef xProgressBar, sal_Int32 nSheet ) : + ISegmentProgressBarRef xProgressBar, sal_Int16 nSheet ) : BiffWorksheetFragmentBase( rParent, xProgressBar, SHEETTYPE_CHARTSHEET, nSheet ) { } diff --git a/oox/source/xls/commentsbuffer.cxx b/oox/source/xls/commentsbuffer.cxx index 1f725bfd7fbc..c8f11d55154e 100644 --- a/oox/source/xls/commentsbuffer.cxx +++ b/oox/source/xls/commentsbuffer.cxx @@ -33,22 +33,24 @@ #include <com/sun/star/sheet/XSheetAnnotationShapeSupplier.hpp> #include <com/sun/star/sheet/XSheetAnnotations.hpp> #include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp> -#include <com/sun/star/text/XText.hpp> #include "oox/helper/attributelist.hxx" #include "oox/helper/recordinputstream.hxx" +#include "oox/vml/vmlshape.hxx" #include "oox/xls/addressconverter.hxx" +#include "oox/xls/drawingfragment.hxx" using ::rtl::OUString; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::uno::UNO_SET_THROW; +using ::com::sun::star::drawing::XShape; using ::com::sun::star::table::CellAddress; +using ::com::sun::star::sheet::XSheetAnnotation; using ::com::sun::star::sheet::XSheetAnnotationAnchor; using ::com::sun::star::sheet::XSheetAnnotationShapeSupplier; using ::com::sun::star::sheet::XSheetAnnotations; using ::com::sun::star::sheet::XSheetAnnotationsSupplier; -using ::com::sun::star::text::XText; namespace oox { namespace xls { @@ -98,16 +100,29 @@ void Comment::finalizeImport() if( getAddressConverter().checkCellAddress( aNotePos, true ) && maModel.mxText.get() ) try { maModel.mxText->finalizeImport(); - Reference< XSheetAnnotationsSupplier > xAnnosSupp( getSheet(), UNO_QUERY_THROW ); - Reference< XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), UNO_SET_THROW ); - // create note with dummy non-empty string (required by implementation) - xAnnos->insertNew( aNotePos, OUString( sal_Unicode( ' ' ) ) ); - // receive craeted note from cell (insertNew does not return the note) -// Reference< XSheetAnnotationAnchor > xAnnoAnchor( getCell( aNotePos ), UNO_QUERY_THROW ); -// Reference< XSheetAnnotationShapeSupplier > xAnnoShapeSupp( xAnnoAnchor->getAnnotation(), UNO_QUERY_THROW ); -// Reference< XText > xNoteText( xAnnoShapeSupp->getAnnotationShape(), UNO_QUERY_THROW ); -// xNoteText->setString( OUString() ); -// maModel.mxText->convert( xNoteText, -1 ); + OUString aNoteText = maModel.mxText->getPlainText(); + // non-empty string required by note implementation + if( aNoteText.getLength() > 0 ) + { + Reference< XSheetAnnotationsSupplier > xAnnosSupp( getSheet(), UNO_QUERY_THROW ); + Reference< XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), UNO_SET_THROW ); + xAnnos->insertNew( aNotePos, aNoteText ); + // receive craeted note from cell (insertNew does not return the note) + Reference< XSheetAnnotationAnchor > xAnnoAnchor( getCell( aNotePos ), UNO_QUERY_THROW ); + Reference< XSheetAnnotation > xAnno( xAnnoAnchor->getAnnotation(), UNO_SET_THROW ); + Reference< XSheetAnnotationShapeSupplier > xAnnoShapeSupp( xAnno, UNO_QUERY_THROW ); + Reference< XShape > xAnnoShape( xAnnoShapeSupp->getAnnotationShape(), UNO_SET_THROW ); + // convert shape formatting + if( const ::oox::vml::ShapeBase* pNoteShape = getVmlDrawing().getNoteShape( aNotePos ) ) + { + // position and formatting + pNoteShape->convertFormatting( xAnnoShape ); + // visibility + const ::oox::vml::ShapeModel::ShapeClientDataPtr& rxClientData = pNoteShape->getShapeModel().mxClientData; + bool bVisible = rxClientData.get() && rxClientData->mbVisible; + xAnno->setIsVisible( bVisible ); + } + } } catch( Exception& ) { diff --git a/oox/source/xls/defnamesbuffer.cxx b/oox/source/xls/defnamesbuffer.cxx index 786d0cd41334..b2c724b6728d 100644 --- a/oox/source/xls/defnamesbuffer.cxx +++ b/oox/source/xls/defnamesbuffer.cxx @@ -31,6 +31,7 @@ #include "oox/xls/defnamesbuffer.hxx" #include <rtl/ustrbuf.hxx> #include <com/sun/star/sheet/ComplexReference.hpp> +#include <com/sun/star/sheet/ExternalReference.hpp> #include <com/sun/star/sheet/NamedRangeFlag.hpp> #include <com/sun/star/sheet/ReferenceFlags.hpp> #include <com/sun/star/sheet/SingleReference.hpp> @@ -43,6 +44,7 @@ #include "oox/xls/biffinputstream.hxx" #include "oox/xls/externallinkbuffer.hxx" #include "oox/xls/formulaparser.hxx" +#include "oox/xls/worksheetbuffer.hxx" using ::rtl::OUString; using ::rtl::OUStringBuffer; @@ -52,10 +54,10 @@ using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::table::CellAddress; using ::com::sun::star::table::CellRangeAddress; using ::com::sun::star::sheet::ComplexReference; +using ::com::sun::star::sheet::ExternalReference; using ::com::sun::star::sheet::SingleReference; using ::com::sun::star::sheet::XFormulaTokens; using ::com::sun::star::sheet::XPrintAreas; -using namespace ::com::sun::star::sheet::ReferenceFlags; namespace oox { namespace xls { @@ -205,6 +207,7 @@ void lclConvertRefFlags( sal_Int32& ornFlags, sal_Int32& ornAbsPos, sal_Int32& o void lclConvertSingleRefFlags( SingleReference& orApiRef, const CellAddress& rBaseAddress, bool bColRel, bool bRowRel ) { + using namespace ::com::sun::star::sheet::ReferenceFlags; lclConvertRefFlags( orApiRef.Flags, orApiRef.Column, orApiRef.RelativeColumn, rBaseAddress.Column, COLUMN_RELATIVE, bColRel ); @@ -213,14 +216,33 @@ void lclConvertSingleRefFlags( SingleReference& orApiRef, const CellAddress& rBa rBaseAddress.Row, ROW_RELATIVE, bRowRel ); } +Any lclConvertReference( const Any& rRefAny, const CellAddress& rBaseAddress, sal_uInt16 nRelFlags ) +{ + if( rRefAny.has< SingleReference >() && !getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ) && !getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) ) + { + SingleReference aApiRef; + rRefAny >>= aApiRef; + lclConvertSingleRefFlags( aApiRef, rBaseAddress, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) ); + return Any( aApiRef ); + } + if( rRefAny.has< ComplexReference >() ) + { + ComplexReference aApiRef; + rRefAny >>= aApiRef; + lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddress, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) ); + lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddress, getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) ); + return Any( aApiRef ); + } + return Any(); +} + } // namespace // ---------------------------------------------------------------------------- -DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper, sal_Int32 nLocalSheet ) : +DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper ) : WorkbookHelper( rHelper ) { - maModel.mnSheet = nLocalSheet; } const OUString& DefinedNameBase::getUpcaseModelName() const @@ -237,62 +259,63 @@ Any DefinedNameBase::getReference( const CellAddress& rBaseAddress ) const sal_Unicode cFlagsChar = getUpcaseModelName()[ 1 ]; if( ('A' <= cFlagsChar) && (cFlagsChar <= 'P') ) { - sal_uInt16 nFlags = static_cast< sal_uInt16 >( cFlagsChar - 'A' ); - if( maRefAny.has< SingleReference >() && (cFlagsChar <= 'D') ) + sal_uInt16 nRelFlags = static_cast< sal_uInt16 >( cFlagsChar - 'A' ); + if( maRefAny.has< ExternalReference >() ) { - SingleReference aApiRef; - maRefAny >>= aApiRef; - lclConvertSingleRefFlags( aApiRef, rBaseAddress, getFlag( nFlags, BIFF_REFFLAG_COL1REL ), getFlag( nFlags, BIFF_REFFLAG_ROW1REL ) ); - return Any( aApiRef ); + ExternalReference aApiExtRef; + maRefAny >>= aApiExtRef; + Any aRefAny = lclConvertReference( aApiExtRef.Reference, rBaseAddress, nRelFlags ); + if( aRefAny.hasValue() ) + { + aApiExtRef.Reference <<= aRefAny; + return Any( aApiExtRef ); + } } - if( maRefAny.has< ComplexReference >() ) + else { - ComplexReference aApiRef; - maRefAny >>= aApiRef; - lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddress, getFlag( nFlags, BIFF_REFFLAG_COL1REL ), getFlag( nFlags, BIFF_REFFLAG_ROW1REL ) ); - lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddress, getFlag( nFlags, BIFF_REFFLAG_COL2REL ), getFlag( nFlags, BIFF_REFFLAG_ROW2REL ) ); - return Any( aApiRef ); + return lclConvertReference( maRefAny, rBaseAddress, nRelFlags ); } } } return Any(); } -void DefinedNameBase::importOoxFormula( FormulaContext& rContext ) +void DefinedNameBase::importOoxFormula( FormulaContext& rContext, sal_Int16 nBaseSheet ) { if( maModel.maFormula.getLength() > 0 ) { - rContext.setBaseAddress( CellAddress( static_cast< sal_Int16 >( maModel.mnSheet ), 0, 0 ) ); + rContext.setBaseAddress( CellAddress( nBaseSheet, 0, 0 ) ); getFormulaParser().importFormula( rContext, maModel.maFormula ); } else getFormulaParser().convertErrorToFormula( rContext, BIFF_ERR_NAME ); } -void DefinedNameBase::importOobFormula( FormulaContext& rContext, RecordInputStream& rStrm ) +void DefinedNameBase::importOobFormula( FormulaContext& rContext, sal_Int16 nBaseSheet, RecordInputStream& rStrm ) { - rContext.setBaseAddress( CellAddress( static_cast< sal_Int16 >( maModel.mnSheet ), 0, 0 ) ); + rContext.setBaseAddress( CellAddress( nBaseSheet, 0, 0 ) ); getFormulaParser().importFormula( rContext, rStrm ); } -void DefinedNameBase::importBiffFormula( FormulaContext& rContext, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) +void DefinedNameBase::importBiffFormula( FormulaContext& rContext, sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) { - rContext.setBaseAddress( CellAddress( static_cast< sal_Int16 >( maModel.mnSheet ), 0, 0 ) ); + rContext.setBaseAddress( CellAddress( nBaseSheet, 0, 0 ) ); if( !pnFmlaSize || (*pnFmlaSize > 0) ) getFormulaParser().importFormula( rContext, rStrm, pnFmlaSize ); else getFormulaParser().convertErrorToFormula( rContext, BIFF_ERR_NAME ); } -void DefinedNameBase::setReference( const ApiTokenSequence& rTokens ) +void DefinedNameBase::extractReference( const ApiTokenSequence& rTokens ) { + OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "DefinedNameBase::extractReference - unexpected call" ); maRefAny = getFormulaParser().extractReference( rTokens ); } // ============================================================================ -DefinedName::DefinedName( const WorkbookHelper& rHelper, sal_Int32 nLocalSheet ) : - DefinedNameBase( rHelper, nLocalSheet ), +DefinedName::DefinedName( const WorkbookHelper& rHelper ) : + DefinedNameBase( rHelper ), mnTokenIndex( -1 ), mcBuiltinId( OOX_DEFNAME_UNKNOWN ), mnFmlaSize( 0 ) @@ -309,6 +332,7 @@ void DefinedName::importDefinedName( const AttributeList& rAttribs ) maModel.mbVBName = rAttribs.getBool( XML_vbProcedure, false ); maModel.mbHidden = rAttribs.getBool( XML_hidden, false ); mcBuiltinId = lclGetBuiltinIdFromOox( maModel.maName ); + mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1; } void DefinedName::setFormula( const OUString& rFormula ) @@ -322,6 +346,7 @@ void DefinedName::importDefinedName( RecordInputStream& rStrm ) rStrm >> nFlags; rStrm.skip( 1 ); // keyboard shortcut rStrm >> maModel.mnSheet >> maModel.maName; + mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1; // macro function/command, hidden flag maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 9 ); @@ -351,7 +376,7 @@ void DefinedName::importDefinedName( RecordInputStream& rStrm ) } } -void DefinedName::importDefinedName( BiffInputStream& rStrm ) +void DefinedName::importDefinedName( BiffInputStream& rStrm, sal_Int16 nCalcSheet ) { BiffType eBiff = getBiff(); sal_uInt16 nFlags = 0; @@ -421,26 +446,45 @@ void DefinedName::importDefinedName( BiffInputStream& rStrm ) case BIFF2: case BIFF3: case BIFF4: + // BIFF2-BIFF4: all defined names are sheet-local + mnCalcSheet = nCalcSheet; break; case BIFF5: // #i44019# nTabId may be invalid, resolve nRefId to sheet index if( nRefId != BIFF_DEFNAME_GLOBAL ) if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() ) if( pExtLink->getLinkType() == LINKTYPE_INTERNAL ) - maModel.mnSheet = pExtLink->getSheetIndex(); + mnCalcSheet = pExtLink->getCalcSheetIndex(); break; case BIFF8: - // convert one-based sheet index to zero-based + // convert one-based worksheet index to zero-based Calc sheet index OSL_ENSURE( nTabId >= 0, "DefinedName::importDefinedName - invalid local sheet index" ); if( nTabId != BIFF_DEFNAME_GLOBAL ) - maModel.mnSheet = nTabId - 1; + mnCalcSheet = getWorksheets().getCalcSheetIndex( nTabId - 1 ); break; case BIFF_UNKNOWN: break; } - // store record position to be able to import token array later - mxBiffStrm.reset( new BiffInputStreamPos( rStrm ) ); + if( (getBiff() <= BIFF4) && maModel.mbHidden && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') ) + { + /* Read the token array of special internal names containing addresses + for BIFF3-BIFF4 3D references immediately. It is expected that + these names contain a simple cell reference or range reference. + Other regular defined names and external names rely on existence of + this reference. */ + TokensFormulaContext aContext( true, true ); + importBiffFormula( aContext, mnCalcSheet, rStrm, &mnFmlaSize ); + extractReference( aContext.getTokens() ); + } + else + { + /* Store record position of other defined names to be able to import + token array later. This is needed to correctly resolve references + to names that are stored later in the defined names list following + this name. */ + mxBiffStrm.reset( new BiffInputStreamPos( rStrm ) ); + } } void DefinedName::createNameObject() @@ -459,7 +503,8 @@ void DefinedName::createNameObject() // append sheet index for local names in multi-sheet documents if( isWorkbookFile() && !isGlobalName() ) - maCalcName = OUStringBuffer( maCalcName ).append( sal_Unicode( '_' ) ).append( maModel.mnSheet + 1 ).makeStringAndClear(); + maCalcName = OUStringBuffer( maCalcName ).append( sal_Unicode( '_' ) ). + append( static_cast< sal_Int32 >( mnCalcSheet + 1 ) ).makeStringAndClear(); // special flags for this name sal_Int32 nNameFlags = 0; @@ -506,18 +551,18 @@ void DefinedName::convertFormula() { case OOX_DEFNAME_PRINTAREA: { - Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( maModel.mnSheet ), UNO_QUERY ); + Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY ); ApiCellRangeList aPrintRanges; - getFormulaParser().extractCellRangeList( aPrintRanges, xTokens->getTokens(), false, maModel.mnSheet ); + getFormulaParser().extractCellRangeList( aPrintRanges, xTokens->getTokens(), false, mnCalcSheet ); if( xPrintAreas.is() && !aPrintRanges.empty() ) xPrintAreas->setPrintAreas( ContainerHelper::vectorToSequence( aPrintRanges ) ); } break; case OOX_DEFNAME_PRINTTITLES: { - Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( maModel.mnSheet ), UNO_QUERY ); + Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY ); ApiCellRangeList aTitleRanges; - getFormulaParser().extractCellRangeList( aTitleRanges, xTokens->getTokens(), false, maModel.mnSheet ); + getFormulaParser().extractCellRangeList( aTitleRanges, xTokens->getTokens(), false, mnCalcSheet ); if( xPrintAreas.is() && !aTitleRanges.empty() ) { bool bHasRowTitles = false; @@ -545,13 +590,6 @@ void DefinedName::convertFormula() break; } } - else if( mxBiffStrm.get() && maModel.mbHidden && (maModel.maName.getLength() > 0) && (maModel.maName[ 0 ] == '\x01') ) - { - // import BIFF2-BIFF4 external references - TokensFormulaContext aContext( true, true ); - implImportBiffFormula( aContext ); - setReference( aContext.getTokens() ); - } } bool DefinedName::getAbsoluteRange( CellRangeAddress& orRange ) const @@ -567,32 +605,34 @@ void DefinedName::implImportOoxFormula( FormulaContext& rContext ) if( mxFormula.get() ) { RecordInputStream aStrm( *mxFormula ); - importOobFormula( rContext, aStrm ); + importOobFormula( rContext, mnCalcSheet, aStrm ); } else - importOoxFormula( rContext ); + importOoxFormula( rContext, mnCalcSheet ); } void DefinedName::implImportBiffFormula( FormulaContext& rContext ) { - OSL_ENSURE( mxBiffStrm.get(), "DefinedName::importBiffFormula - missing BIFF stream" ); + OSL_ENSURE( mxBiffStrm.get(), "DefinedName::implImportBiffFormula - missing BIFF stream" ); BiffInputStream& rStrm = mxBiffStrm->getStream(); BiffInputStreamPosGuard aStrmGuard( rStrm ); if( mxBiffStrm->restorePosition() ) - importBiffFormula( rContext, rStrm, &mnFmlaSize ); + importBiffFormula( rContext, mnCalcSheet, rStrm, &mnFmlaSize ); } // ============================================================================ DefinedNamesBuffer::DefinedNamesBuffer( const WorkbookHelper& rHelper ) : WorkbookHelper( rHelper ), - mnLocalSheet( -1 ) + mnCalcSheet( -1 ) { } -void DefinedNamesBuffer::setLocalSheetIndex( sal_Int32 nLocalSheet ) +void DefinedNamesBuffer::setLocalCalcSheet( sal_Int16 nCalcSheet ) { - mnLocalSheet = nLocalSheet; + OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), + "DefinedNamesBuffer::setLocalCalcSheet - invalid call" ); + mnCalcSheet = nCalcSheet; } DefinedNameRef DefinedNamesBuffer::importDefinedName( const AttributeList& rAttribs ) @@ -609,7 +649,7 @@ void DefinedNamesBuffer::importDefinedName( RecordInputStream& rStrm ) void DefinedNamesBuffer::importDefinedName( BiffInputStream& rStrm ) { - createDefinedName()->importDefinedName( rStrm ); + createDefinedName()->importDefinedName( rStrm, mnCalcSheet ); } void DefinedNamesBuffer::finalizeImport() @@ -639,7 +679,7 @@ DefinedNameRef DefinedNamesBuffer::getByTokenIndex( sal_Int32 nIndex ) const return maDefNameMap.get( nIndex ); } -DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, sal_Int32 nSheet ) const +DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, sal_Int16 nCalcSheet ) const { DefinedNameRef xGlobalName; // a found global name DefinedNameRef xLocalName; // a found local name @@ -648,7 +688,7 @@ DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, s DefinedNameRef xCurrName = *aIt; if( xCurrName->getModelName() == rModelName ) { - if( xCurrName->getSheetIndex() == nSheet ) + if( xCurrName->getLocalCalcSheet() == nCalcSheet ) xLocalName = xCurrName; else if( xCurrName->isGlobalName() ) xGlobalName = xCurrName; @@ -659,7 +699,7 @@ DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, s DefinedNameRef DefinedNamesBuffer::createDefinedName() { - DefinedNameRef xDefName( new DefinedName( *this, mnLocalSheet ) ); + DefinedNameRef xDefName( new DefinedName( *this ) ); maDefNames.push_back( xDefName ); return xDefName; } diff --git a/oox/source/xls/drawingfragment.cxx b/oox/source/xls/drawingfragment.cxx index 7c338c55af6f..3b72126f7df6 100644 --- a/oox/source/xls/drawingfragment.cxx +++ b/oox/source/xls/drawingfragment.cxx @@ -43,7 +43,9 @@ #include "oox/drawingml/shapecontext.hxx" #include "oox/drawingml/shapegroupcontext.hxx" #include "oox/vml/vmlshape.hxx" +#include "oox/vml/vmlshapecontainer.hxx" #include "oox/xls/formulaparser.hxx" +#include "oox/xls/stylesbuffer.hxx" #include "oox/xls/themebuffer.hxx" #include "oox/xls/unitconverter.hxx" @@ -537,12 +539,52 @@ void OoxDrawingFragment::onEndElement( const OUString& rChars ) // ============================================================================ +namespace { + +class VmlFindNoteFunc +{ +public: + explicit VmlFindNoteFunc( const CellAddress& rPos ); + bool operator()( const ::oox::vml::ShapeBase& rShape ) const; + +private: + sal_Int32 mnCol; + sal_Int32 mnRow; +}; + +VmlFindNoteFunc::VmlFindNoteFunc( const CellAddress& rPos ) : + mnCol( rPos.Column ), + mnRow( rPos.Row ) +{ +} + +bool VmlFindNoteFunc::operator()( const ::oox::vml::ShapeBase& rShape ) const +{ + const ::oox::vml::ShapeModel::ShapeClientDataPtr& rxClientData = rShape.getShapeModel().mxClientData; + return rxClientData.get() && (rxClientData->mnCol == mnCol) && (rxClientData->mnRow == mnRow); +} + +} // namespace + +// ---------------------------------------------------------------------------- + VmlDrawing::VmlDrawing( const WorksheetHelper& rHelper ) : ::oox::vml::Drawing( rHelper.getOoxFilter(), rHelper.getDrawPage(), ::oox::vml::VMLDRAWING_EXCEL ), WorksheetHelper( rHelper ) { } +const ::oox::vml::ShapeBase* VmlDrawing::getNoteShape( const CellAddress& rPos ) const +{ + return getShapes().findShape( VmlFindNoteFunc( rPos ) ); +} + +bool VmlDrawing::isShapeSupported( const ::oox::vml::ShapeBase& rShape ) const +{ + const ::oox::vml::ShapeModel::ShapeClientDataPtr& rxClientData = rShape.getShapeModel().mxClientData; + return !rxClientData.get() || (rxClientData->mnObjType != XML_Note); +} + bool VmlDrawing::convertShapeClientAnchor( Rectangle& orShapeRect, const OUString& rShapeAnchor ) const { if( rShapeAnchor.getLength() == 0 ) diff --git a/oox/source/xls/excelfilter.cxx b/oox/source/xls/excelfilter.cxx index f460f3e8fdcb..a5bfe5e3d1d9 100644 --- a/oox/source/xls/excelfilter.cxx +++ b/oox/source/xls/excelfilter.cxx @@ -58,6 +58,34 @@ namespace xls { // ============================================================================ +ExcelFilterBase::ExcelFilterBase() : + mpHelper( 0 ) +{ +} + +ExcelFilterBase::~ExcelFilterBase() +{ + OSL_ENSURE( !mpHelper, "ExcelFilterBase::~ExcelFilterBase - workbook helper not cleared" ); +} + +void ExcelFilterBase::setWorkbookHelper( WorkbookHelper& rHelper ) +{ + mpHelper = &rHelper; +} + +WorkbookHelper& ExcelFilterBase::getWorkbookHelper() const +{ + OSL_ENSURE( mpHelper, "ExcelFilterBase::getWorkbookHelper - missing workbook helper" ); + return *mpHelper; +} + +void ExcelFilterBase::clearWorkbookHelper() +{ + mpHelper = 0; +} + +// ============================================================================ + OUString SAL_CALL ExcelFilter_getImplementationName() throw() { return CREATE_OUSTRING( "com.sun.star.comp.oox.ExcelFilter" ); @@ -79,8 +107,7 @@ Reference< XInterface > SAL_CALL ExcelFilter_createInstance( // ---------------------------------------------------------------------------- ExcelFilter::ExcelFilter( const Reference< XMultiServiceFactory >& rxGlobalFactory ) : - XmlFilterBase( rxGlobalFactory ), - mpHelper( 0 ) + XmlFilterBase( rxGlobalFactory ) { } @@ -102,9 +129,9 @@ bool ExcelFilter::importDocument() throw() WorkbookHelperRoot aHelper( *this ); if( aHelper.isValid() ) { - mpHelper = &aHelper; // needed for callbacks + setWorkbookHelper( aHelper ); // needed for callbacks bRet = importFragment( new OoxWorkbookFragment( aHelper, aWorkbookPath ) ); - mpHelper = 0; + clearWorkbookHelper(); } } return bRet; @@ -115,15 +142,19 @@ bool ExcelFilter::exportDocument() throw() return false; } -const ::oox::drawingml::Theme* ExcelFilter::getCurrentTheme() const +sal_Int32 ExcelFilter::getSchemeColor( sal_Int32 nToken ) const { - return &mpHelper->getTheme(); + return getWorkbookHelper().getTheme().getColorByToken( nToken ); } -sal_Int32 ExcelFilter::getSchemeClr( sal_Int32 nColorSchemeToken ) const +sal_Int32 ExcelFilter::getPaletteColor( sal_Int32 nPaletteIdx ) const { - OSL_ENSURE( mpHelper, "ExcelFilter::getSchemeClr - no workbook helper" ); - return mpHelper->getTheme().getColorByToken( nColorSchemeToken ); + return getWorkbookHelper().getStyles().getPaletteColor( nPaletteIdx ); +} + +const ::oox::drawingml::Theme* ExcelFilter::getCurrentTheme() const +{ + return &getWorkbookHelper().getTheme(); } ::oox::vml::Drawing* ExcelFilter::getVmlDrawing() @@ -138,8 +169,7 @@ const TableStyleListPtr ExcelFilter::getTableStyles() ::oox::drawingml::chart::ChartConverter& ExcelFilter::getChartConverter() { - OSL_ENSURE( mpHelper, "ExcelFilter::getChartConverter - no workbook helper" ); - return mpHelper->getChartConverter(); + return getWorkbookHelper().getChartConverter(); } OUString ExcelFilter::implGetImplementationName() const @@ -202,7 +232,12 @@ bool ExcelBiffFilter::importDocument() throw() if( eBiff != BIFF_UNKNOWN ) { WorkbookHelperRoot aHelper( *this, eBiff ); - bRet = aHelper.isValid() && BiffWorkbookFragment( aHelper, aWorkbookName ).importFragment(); + if( aHelper.isValid() ) + { + setWorkbookHelper( aHelper ); // needed for callbacks + bRet = BiffWorkbookFragment( aHelper, aWorkbookName ).importFragment(); + clearWorkbookHelper(); + } } return bRet; } @@ -212,6 +247,11 @@ bool ExcelBiffFilter::exportDocument() throw() return false; } +sal_Int32 ExcelBiffFilter::getPaletteColor( sal_Int32 nPaletteIdx ) const +{ + return getWorkbookHelper().getStyles().getPaletteColor( nPaletteIdx ); +} + OUString ExcelBiffFilter::implGetImplementationName() const { return ExcelBiffFilter_getImplementationName(); diff --git a/oox/source/xls/excelhandlers.cxx b/oox/source/xls/excelhandlers.cxx index 3941bb306177..aa5a8634a60d 100644 --- a/oox/source/xls/excelhandlers.cxx +++ b/oox/source/xls/excelhandlers.cxx @@ -52,7 +52,7 @@ OoxWorkbookFragmentBase::OoxWorkbookFragmentBase( // ============================================================================ OoxWorksheetFragmentBase::OoxWorksheetFragmentBase( const WorkbookHelper& rHelper, - const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) : + const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) : FragmentHandler2( rHelper.getOoxFilter(), rFragmentPath ), WorksheetHelperRoot( rHelper, xProgressBar, eSheetType, nSheet ) { @@ -228,7 +228,7 @@ BiffWorkbookFragmentBase::BiffWorkbookFragmentBase( const WorkbookHelper& rHelpe // ============================================================================ BiffWorksheetFragmentBase::BiffWorksheetFragmentBase( const BiffWorkbookFragmentBase& rParent, - ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) : + ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) : BiffFragmentHandler( rParent ), WorksheetHelperRoot( rParent, xProgressBar, eSheetType, nSheet ) { @@ -237,7 +237,7 @@ BiffWorksheetFragmentBase::BiffWorksheetFragmentBase( const BiffWorkbookFragment // ============================================================================ BiffSkipWorksheetFragment::BiffSkipWorksheetFragment( - const BiffWorkbookFragmentBase& rParent, ISegmentProgressBarRef xProgressBar, sal_Int32 nSheet ) : + const BiffWorkbookFragmentBase& rParent, ISegmentProgressBarRef xProgressBar, sal_Int16 nSheet ) : BiffWorksheetFragmentBase( rParent, xProgressBar, SHEETTYPE_EMPTYSHEET, nSheet ) { } diff --git a/oox/source/xls/externallinkbuffer.cxx b/oox/source/xls/externallinkbuffer.cxx index 564775228d2a..26a1df09cc69 100644 --- a/oox/source/xls/externallinkbuffer.cxx +++ b/oox/source/xls/externallinkbuffer.cxx @@ -30,8 +30,12 @@ #include "oox/xls/externallinkbuffer.hxx" #include <rtl/strbuf.hxx> +#include <com/sun/star/sheet/ComplexReference.hpp> #include <com/sun/star/sheet/DDELinkInfo.hpp> #include <com/sun/star/sheet/ExternalLinkType.hpp> +#include <com/sun/star/sheet/ExternalReference.hpp> +#include <com/sun/star/sheet/ReferenceFlags.hpp> +#include <com/sun/star/sheet/SingleReference.hpp> #include <com/sun/star/sheet/XDDELinks.hpp> #include <com/sun/star/sheet/XDDELink.hpp> #include <com/sun/star/sheet/XDDELinkResults.hpp> @@ -55,9 +59,12 @@ using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::table::CellAddress; +using ::com::sun::star::sheet::ComplexReference; using ::com::sun::star::sheet::DDEItemInfo; using ::com::sun::star::sheet::DDELinkInfo; using ::com::sun::star::sheet::ExternalLinkInfo; +using ::com::sun::star::sheet::ExternalReference; +using ::com::sun::star::sheet::SingleReference; using ::com::sun::star::sheet::XDDELinks; using ::com::sun::star::sheet::XDDELinkResults; using ::com::sun::star::sheet::XExternalDocLinks; @@ -105,8 +112,8 @@ ExternalNameModel::ExternalNameModel() : // ============================================================================ -ExternalName::ExternalName( const ExternalLink& rParentLink, sal_Int32 nLocalSheet ) : - DefinedNameBase( rParentLink, nLocalSheet ), +ExternalName::ExternalName( const ExternalLink& rParentLink ) : + DefinedNameBase( rParentLink ), mrParentLink( rParentLink ), mnStorageId( 0 ), mbDdeLinkCreated( false ) @@ -239,16 +246,27 @@ void ExternalName::importExternalName( BiffInputStream& rStrm ) rStrm.readByteStringUC( false, getTextEncoding() ); OSL_ENSURE( maModel.maName.getLength() > 0, "ExternalName::importExternalName - empty name" ); + // load cell references that are stored in hidden external names (seen in BIFF3-BIFF4) + bool bHiddenRef = (getBiff() <= BIFF4) && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') && (rStrm.getRemaining() > 2); switch( mrParentLink.getLinkType() ) { case LINKTYPE_INTERNAL: + // cell references to other internal sheets are stored in hidden external names + if( bHiddenRef && (getBiff() == BIFF4) && isWorkbookFile() ) + { + TokensFormulaContext aContext( true, true ); + importBiffFormula( aContext, mrParentLink.getCalcSheetIndex(), rStrm ); + extractReference( aContext.getTokens() ); + } + break; + case LINKTYPE_EXTERNAL: - // cell references that are stored in hidden external names (seen in BIFF3-BIFF4) - if( (getBiff() <= BIFF4) && (maModel.maName.getLength() > 0) && (maModel.maName[ 0 ] == '\x01') && (rStrm.getRemaining() > 2) ) + // cell references to other documents are stored in hidden external names + if( bHiddenRef ) { TokensFormulaContext aContext( true, true ); - importBiffFormula( aContext, rStrm ); - setReference( aContext.getTokens() ); + importBiffFormula( aContext, 0, rStrm ); + extractExternalReference( aContext.getTokens() ); } break; @@ -300,6 +318,7 @@ void ExternalName::importExternalName( BiffInputStream& rStrm ) } } +#if 0 sal_Int32 ExternalName::getSheetCacheIndex() const { OSL_ENSURE( mrParentLink.getLinkType() == LINKTYPE_DDE, "ExternalName::getSheetCacheIndex - unexpected link type" ); @@ -337,6 +356,7 @@ sal_Int32 ExternalName::getSheetCacheIndex() const } return nCacheIdx; } +#endif bool ExternalName::getDdeItemInfo( DDEItemInfo& orItemInfo ) const { @@ -381,6 +401,51 @@ bool ExternalName::getDdeLinkData( OUString& orDdeServer, OUString& orDdeTopic, return false; } +// private -------------------------------------------------------------------- + +namespace { + +void lclSetSheetCacheIndex( SingleReference& orApiRef, sal_Int32 nCacheIdx ) +{ + using namespace ::com::sun::star::sheet::ReferenceFlags; + setFlag( orApiRef.Flags, SHEET_RELATIVE, false ); + setFlag( orApiRef.Flags, SHEET_3D, true ); + orApiRef.Sheet = nCacheIdx; +} + +} // namespace + +void ExternalName::extractExternalReference( const ApiTokenSequence& rTokens ) +{ + OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "ExternalName::setExternalReference - unexpected call" ); + sal_Int32 nDocLinkIdx = mrParentLink.getDocumentLinkIndex(); + sal_Int32 nCacheIdx = mrParentLink.getSheetCacheIndex(); + if( (nDocLinkIdx >= 0) && (nCacheIdx >= 0) ) + { + ExternalReference aExtApiRef; + aExtApiRef.Index = nDocLinkIdx; + + Any aRefAny = getFormulaParser().extractReference( rTokens ); + if( aRefAny.has< SingleReference >() ) + { + SingleReference aApiRef; + aRefAny >>= aApiRef; + lclSetSheetCacheIndex( aApiRef, nCacheIdx ); + aExtApiRef.Reference <<= aApiRef; + maRefAny <<= aExtApiRef; + } + else if( aRefAny.has< ComplexReference >() ) + { + ComplexReference aApiRef; + aRefAny >>= aApiRef; + lclSetSheetCacheIndex( aApiRef.Reference1, nCacheIdx ); + lclSetSheetCacheIndex( aApiRef.Reference2, nCacheIdx ); + aExtApiRef.Reference <<= aApiRef; + maRefAny <<= aExtApiRef; + } + } +} + void ExternalName::setResultSize( sal_Int32 nColumns, sal_Int32 nRows ) { OSL_ENSURE( (mrParentLink.getLinkType() == LINKTYPE_DDE) || (mrParentLink.getLinkType() == LINKTYPE_OLE) || @@ -564,10 +629,10 @@ void ExternalLink::importExternSheet( BiffInputStream& rStrm ) switch( meLinkType ) { case LINKTYPE_INTERNAL: - maIndexes.push_back( getWorksheets().getCalcSheetIndex( aSheetName ) ); + maCalcSheets.push_back( getWorksheets().getCalcSheetIndex( aSheetName ) ); break; case LINKTYPE_EXTERNAL: - insertExternalSheet( aSheetName ); + insertExternalSheet( (aSheetName.getLength() > 0) ? aSheetName : WorksheetBuffer::getBaseFileName( maTargetUrl ) ); break; default:; } @@ -659,11 +724,41 @@ FunctionLibraryType ExternalLink::getFuncLibraryType() const return (meLinkType == LINKTYPE_LIBRARY) ? meFuncLibType : FUNCLIB_UNKNOWN; } -sal_Int32 ExternalLink::getSheetIndex( sal_Int32 nTabId ) const +sal_Int16 ExternalLink::getCalcSheetIndex( sal_Int32 nTabId ) const { + OSL_ENSURE( meLinkType == LINKTYPE_INTERNAL, "ExternalLink::getCalcSheetIndex - invalid link type" ); OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOX) || (getBiff() == BIFF8), - "ExternalLink::getSheetIndex - invalid sheet index" ); - return ContainerHelper::getVectorElement< sal_Int32 >( maIndexes, nTabId, -1 ); + "ExternalLink::getCalcSheetIndex - invalid sheet index" ); + return ContainerHelper::getVectorElement< sal_Int16 >( maCalcSheets, nTabId, -1 ); +} + +sal_Int32 ExternalLink::getDocumentLinkIndex() const +{ + OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getDocumentLinkIndex - invalid link type" ); + return mxDocLink.is() ? mxDocLink->getTokenIndex() : -1; +} + +sal_Int32 ExternalLink::getSheetCacheIndex( sal_Int32 nTabId ) const +{ + OSL_ENSURE( meLinkType == LINKTYPE_EXTERNAL, "ExternalLink::getSheetCacheIndex - invalid link type" ); + OSL_ENSURE( (nTabId == 0) || (getFilterType() == FILTER_OOX) || (getBiff() == BIFF8), + "ExternalLink::getSheetCacheIndex - invalid sheet index" ); + return ContainerHelper::getVectorElement< sal_Int32 >( maSheetCaches, nTabId, -1 ); +} + +Reference< XExternalSheetCache > ExternalLink::getSheetCache( sal_Int32 nTabId ) const +{ + sal_Int32 nCacheIdx = getSheetCacheIndex( nTabId ); + if( mxDocLink.is() && (nCacheIdx >= 0) ) try + { + // existing mxDocLink implies that this is an external link + Reference< XExternalSheetCache > xSheetCache( mxDocLink->getByIndex( nCacheIdx ), UNO_QUERY_THROW ); + return xSheetCache; + } + catch( Exception& ) + { + } + return 0; } void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId1, sal_Int32 nTabId2 ) const @@ -681,12 +776,12 @@ void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId case LINKTYPE_EXTERNAL: { - sal_Int32 nDocLinkIndex = mxDocLink.is() ? mxDocLink->getTokenIndex() : -1; + sal_Int32 nDocLinkIdx = getDocumentLinkIndex(); switch( getFilterType() ) { case FILTER_OOX: // OOBIN: passed indexes point into sheet list of EXTSHEETLIST - orSheetRange.setExternalRange( nDocLinkIndex, getSheetIndex( nTabId1 ), getSheetIndex( nTabId2 ) ); + orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) ); break; case FILTER_BIFF: switch( getBiff() ) @@ -694,17 +789,17 @@ void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId case BIFF2: case BIFF3: case BIFF4: - orSheetRange.setExternalRange( nDocLinkIndex, getSheetIndex( nTabId1 ), getSheetIndex( nTabId2 ) ); + orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) ); break; case BIFF5: // BIFF5: first sheet from this external link, last sheet is passed in nTabId2 if( const ExternalLink* pExtLink2 = getExternalLinks().getExternalLink( nTabId2 ).get() ) if( (pExtLink2->getLinkType() == LINKTYPE_EXTERNAL) && (maTargetUrl == pExtLink2->getTargetUrl()) ) - orSheetRange.setExternalRange( nDocLinkIndex, getSheetIndex(), pExtLink2->getSheetIndex() ); + orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex(), pExtLink2->getSheetCacheIndex() ); break; case BIFF8: // BIFF8: passed indexes point into sheet list of EXTERNALBOOK - orSheetRange.setExternalRange( nDocLinkIndex, getSheetIndex( nTabId1 ), getSheetIndex( nTabId2 ) ); + orSheetRange.setExternalRange( nDocLinkIdx, getSheetCacheIndex( nTabId1 ), getSheetCacheIndex( nTabId2 ) ); break; case BIFF_UNKNOWN: break; } @@ -720,21 +815,6 @@ void ExternalLink::getSheetRange( LinkSheetRange& orSheetRange, sal_Int32 nTabId } } -Reference< XExternalSheetCache > ExternalLink::getExternalSheetCache( sal_Int32 nTabId ) -{ - const sal_Int32* pnCacheId = ContainerHelper::getVectorElement( maIndexes, nTabId ); - if( mxDocLink.is() && pnCacheId ) try - { - // existing mxDocLink implies that this is an external link - Reference< XExternalSheetCache > xSheetCache( mxDocLink->getByIndex( *pnCacheId ), UNO_QUERY_THROW ); - return xSheetCache; - } - catch( Exception& ) - { - } - return 0; -} - ExternalNameRef ExternalLink::getNameByIndex( sal_Int32 nIndex ) const { return maExtNames.get( nIndex ); @@ -790,21 +870,21 @@ OUString ExternalLink::parseBiffTargetUrl( const OUString& rBiffTargetUrl ) OUString aClassName, aTargetUrl, aSheetName; switch( getAddressConverter().parseBiffTargetUrl( aClassName, aTargetUrl, aSheetName, rBiffTargetUrl ) ) - { + { case BIFF_TARGETTYPE_URL: if( aTargetUrl.getLength() == 0 ) - { + { meLinkType = (aSheetName.getLength() > 0) ? LINKTYPE_INTERNAL : LINKTYPE_SELF; - } - else if( (aTargetUrl.getLength() == 1) && (aTargetUrl[ 0 ] == ':') ) - { - if( getBiff() >= BIFF4 ) - meLinkType = LINKTYPE_ANALYSIS; - } + } + else if( (aTargetUrl.getLength() == 1) && (aTargetUrl[ 0 ] == ':') ) + { + if( getBiff() >= BIFF4 ) + meLinkType = LINKTYPE_ANALYSIS; + } else if( (aTargetUrl.getLength() > 1) || (aTargetUrl[ 0 ] != ' ') ) - { + { setExternalTargetUrl( aTargetUrl, OOX_TARGETTYPE_EXTLINK ); - } + } break; case BIFF_TARGETTYPE_SAMESHEET: @@ -834,13 +914,13 @@ void ExternalLink::insertExternalSheet( const OUString& rSheetName ) { Reference< XExternalSheetCache > xSheetCache = mxDocLink->addSheetCache( rSheetName ); sal_Int32 nCacheIdx = xSheetCache.is() ? xSheetCache->getTokenIndex() : -1; - maIndexes.push_back( nCacheIdx ); + maSheetCaches.push_back( nCacheIdx ); } } ExternalNameRef ExternalLink::createExternalName() { - ExternalNameRef xExtName( new ExternalName( *this, getSheetIndex() ) ); + ExternalNameRef xExtName( new ExternalName( *this ) ); maExtNames.push_back( xExtName ); return xExtName; } diff --git a/oox/source/xls/externallinkfragment.cxx b/oox/source/xls/externallinkfragment.cxx index 0245c44eb13c..39686ae7cb64 100644 --- a/oox/source/xls/externallinkfragment.cxx +++ b/oox/source/xls/externallinkfragment.cxx @@ -338,7 +338,7 @@ ContextHandlerRef OoxExternalLinkFragment::onCreateRecordContext( sal_Int32 nRec ContextHandlerRef OoxExternalLinkFragment::createSheetDataContext( sal_Int32 nSheetId ) { - return new OoxExternalSheetDataContext( *this, mrExtLink.getExternalSheetCache( nSheetId ) ); + return new OoxExternalSheetDataContext( *this, mrExtLink.getSheetCache( nSheetId ) ); } // oox.core.FragmentHandler2 interface ---------------------------------------- @@ -475,11 +475,11 @@ void BiffExternalLinkFragment::importXct() case BIFF3: case BIFF4: case BIFF5: - mxSheetCache = mxExtLink->getExternalSheetCache( 0 ); + mxSheetCache = mxExtLink->getSheetCache( 0 ); break; case BIFF8: mrStrm.skip( 2 ); - mxSheetCache = mxExtLink->getExternalSheetCache( mrStrm.readInt16() ); + mxSheetCache = mxExtLink->getSheetCache( mrStrm.readInt16() ); break; case BIFF_UNKNOWN: break; } diff --git a/oox/source/xls/pivotcachebuffer.cxx b/oox/source/xls/pivotcachebuffer.cxx index 33465d81d466..7b503142a89e 100644 --- a/oox/source/xls/pivotcachebuffer.cxx +++ b/oox/source/xls/pivotcachebuffer.cxx @@ -1369,7 +1369,7 @@ void PivotCache::importDConUrl( BiffInputStream& rStrm ) void PivotCache::finalizeInternalSheetSource() { // resolve sheet name to sheet index - sal_Int32 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet ); + sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet ); // if cache is based on a defined name or table, try to resolve to cell range if( maSheetSrcModel.maDefName.getLength() > 0 ) @@ -1393,7 +1393,7 @@ void PivotCache::finalizeInternalSheetSource() else if( nSheet >= 0 ) { // insert sheet index into the range, range address will be checked below - maSheetSrcModel.maRange.Sheet = static_cast< sal_Int16 >( nSheet ); + maSheetSrcModel.maRange.Sheet = nSheet; mbValidSource = true; } // else sheet has been deleted, generate the source data from cache diff --git a/oox/source/xls/richstring.cxx b/oox/source/xls/richstring.cxx index d4e93f4bf47a..a4f8f1379654 100644 --- a/oox/source/xls/richstring.cxx +++ b/oox/source/xls/richstring.cxx @@ -29,6 +29,7 @@ ************************************************************************/ #include "oox/xls/richstring.hxx" +#include <rtl/ustrbuf.hxx> #include <com/sun/star/text/XText.hpp> #include "oox/helper/attributelist.hxx" #include "oox/helper/propertyset.hxx" @@ -37,6 +38,7 @@ using ::rtl::OString; using ::rtl::OUString; +using ::rtl::OUStringBuffer; using ::com::sun::star::uno::Reference; using ::com::sun::star::text::XText; using ::com::sun::star::text::XTextRange; @@ -490,12 +492,20 @@ void RichString::finalizeImport() maFontPortions.forEachMem( &RichStringPortion::finalizeImport ); } +OUString RichString::getPlainText() const +{ + OUStringBuffer aBuffer; + for( PortionVec::const_iterator aIt = maFontPortions.begin(), aEnd = maFontPortions.end(); aIt != aEnd; ++aIt ) + aBuffer.append( (*aIt)->getText() ); + return aBuffer.makeStringAndClear(); +} + void RichString::convert( const Reference< XText >& rxText, sal_Int32 nXfId ) const { for( PortionVec::const_iterator aIt = maFontPortions.begin(), aEnd = maFontPortions.end(); aIt != aEnd; ++aIt ) { (*aIt)->convert( rxText, nXfId ); - nXfId = -1; + nXfId = -1; // use passed XF identifier for first portion only } } diff --git a/oox/source/xls/stylesbuffer.cxx b/oox/source/xls/stylesbuffer.cxx index 64d660f5c559..dc7456e1e4c9 100644 --- a/oox/source/xls/stylesbuffer.cxx +++ b/oox/source/xls/stylesbuffer.cxx @@ -29,7 +29,8 @@ ************************************************************************/ #include "oox/xls/stylesbuffer.hxx" -#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XNameAccess.hpp> #include <com/sun/star/awt/FontDescriptor.hpp> #include <com/sun/star/awt/FontFamily.hpp> #include <com/sun/star/awt/FontPitch.hpp> @@ -59,14 +60,22 @@ using ::rtl::OUString; using ::rtl::OUStringBuffer; +using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::UNO_SET_THROW; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::container::XNamed; using ::com::sun::star::awt::FontDescriptor; using ::com::sun::star::awt::XDevice; using ::com::sun::star::awt::XFont2; using ::com::sun::star::table::BorderLine; using ::com::sun::star::text::XText; using ::com::sun::star::style::XStyle; +using ::oox::core::FilterBase; namespace oox { namespace xls { @@ -257,6 +266,11 @@ const sal_uInt32 BIFF_XF_DIAG_BLTR = 0x80000000; /// Bottom-left to t const sal_uInt16 BIFF_STYLE_BUILTIN = 0x8000; const sal_uInt16 BIFF_STYLE_XFMASK = 0x0FFF; +// BIFF STYLEEXT flags +const sal_uInt8 BIFF_STYLEEXT_BUILTIN = 0x01; +const sal_uInt8 BIFF_STYLEEXT_HIDDEN = 0x02; +const sal_uInt8 BIFF_STYLEEXT_CUSTOM = 0x04; + // BIFF conditional formatting const sal_uInt32 BIFF_CFRULE_BORDER_LEFT = 0x00000400; const sal_uInt32 BIFF_CFRULE_BORDER_RIGHT = 0x00000800; @@ -280,8 +294,7 @@ const sal_uInt32 BIFF_CFRULE_FONT_ESCAPEM = 0x00000001; /// Font escapement // ---------------------------------------------------------------------------- -template< typename StreamType > -sal_Int32 lclReadRgbColor( StreamType& rStrm ) +sal_Int32 lclReadRgbColor( BinaryInputStream& rStrm ) { sal_uInt8 nR, nG, nB, nA; rStrm >> nR >> nG >> nB >> nA; @@ -299,39 +312,34 @@ sal_Int32 lclReadRgbColor( StreamType& rStrm ) // ---------------------------------------------------------------------------- -Color::Color() : - meMode( COLOR_AUTO ), - mnValue( 0 ), - mfTint( 0.0 ) -{ -} - void Color::setAuto() { - meMode = COLOR_AUTO; - mnValue = 0; - mfTint = 0.0; + clearTransformations(); + setSchemeClr( XML_phClr ); } void Color::setRgb( sal_Int32 nRgbValue, double fTint ) { - meMode = COLOR_RGB; - mnValue = nRgbValue; - mfTint = fTint; + clearTransformations(); + setSrgbClr( nRgbValue & 0xFFFFFF ); + if( fTint != 0.0 ) addExcelTintTransformation( fTint ); } void Color::setTheme( sal_Int32 nThemeIdx, double fTint ) { - meMode = COLOR_THEME; - mnValue = nThemeIdx; - mfTint = fTint; + clearTransformations(); + static const sal_Int32 spnColorTokens[] = { + XML_lt1, XML_dk1, XML_lt2, XML_dk2, XML_accent1, XML_accent2, + XML_accent3, XML_accent4, XML_accent5, XML_accent6, XML_hlink, XML_folHlink }; + setSchemeClr( STATIC_ARRAY_SELECT( spnColorTokens, nThemeIdx, XML_TOKEN_INVALID ) ); + if( fTint != 0.0 ) addExcelTintTransformation( fTint ); } void Color::setIndexed( sal_Int32 nPaletteIdx, double fTint ) { - meMode = COLOR_INDEXED; - mnValue = nPaletteIdx; - mfTint = fTint; + clearTransformations(); + setPaletteClr( nPaletteIdx ); + if( fTint != 0.0 ) addExcelTintTransformation( fTint ); } void Color::importColor( const AttributeList& rAttribs ) @@ -408,38 +416,6 @@ void Color::importColorRgb( BiffInputStream& rStrm ) setRgb( lclReadRgbColor( rStrm ) ); } -bool Color::isAuto() const -{ - return meMode == COLOR_AUTO; -} - -sal_Int32 Color::getColor( const WorkbookHelper& rHelper, sal_Int32 nAuto ) const -{ - switch( meMode ) - { - case COLOR_AUTO: return nAuto; - case COLOR_FINAL: return mnValue; - - case COLOR_RGB: mnValue &= 0xFFFFFF; break; - case COLOR_THEME: mnValue = rHelper.getTheme().getColorByIndex( mnValue ); break; - case COLOR_INDEXED: mnValue = rHelper.getStyles().getPaletteColor( mnValue ); break; - } - - // color tint - OSL_ENSURE( (rHelper.getFilterType() == FILTER_OOX) || (mfTint == 0.0), - "Color::getColor - color tint only supported in OOX filter" ); - if( (mnValue >= 0) && (rHelper.getFilterType() == FILTER_OOX) && (mfTint != 0.0) ) - { - ::oox::drawingml::Color aTransformColor; - aTransformColor.setSrgbClr( mnValue ); - aTransformColor.addExcelTintTransformation( mfTint ); - mnValue = aTransformColor.getColor( rHelper.getOoxFilter() ); - } - - meMode = COLOR_FINAL; - return mnValue; -} - RecordInputStream& operator>>( RecordInputStream& rStrm, Color& orColor ) { orColor.importColor( rStrm ); @@ -532,14 +508,13 @@ ColorPalette::ColorPalette( const WorkbookHelper& rHelper ) : void ColorPalette::importPaletteColor( const AttributeList& rAttribs ) { - appendColor( rAttribs.getIntegerHex( XML_rgb, API_RGB_TRANSPARENT ) ); + appendColor( rAttribs.getIntegerHex( XML_rgb, API_RGB_WHITE ) ); } void ColorPalette::importPaletteColor( RecordInputStream& rStrm ) { - Color aColor; - aColor.importColorRgb( rStrm ); - appendColor( aColor.getColor( *this ) ); + sal_Int32 nRgb = lclReadRgbColor( rStrm ); + appendColor( nRgb & 0xFFFFFF ); } void ColorPalette::importPalette( BiffInputStream& rStrm ) @@ -550,11 +525,10 @@ void ColorPalette::importPalette( BiffInputStream& rStrm ) // fill palette from BIFF_COLOR_USEROFFSET mnAppendIndex = BIFF_COLOR_USEROFFSET; - Color aColor; for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex ) { - aColor.importColorRgb( rStrm ); - appendColor( aColor.getColor( *this ) ); + sal_Int32 nRgb = lclReadRgbColor( rStrm ); + appendColor( nRgb & 0xFFFFFF ); } } @@ -574,7 +548,7 @@ sal_Int32 ColorPalette::getColor( sal_Int32 nPaletteIdx ) const case OOX_COLOR_WINDOWBACK: case OOX_COLOR_CHWINDOWBACK: nColor = getBaseFilter().getSystemColor( XML_window ); break; case OOX_COLOR_BUTTONBACK: nColor = getBaseFilter().getSystemColor( XML_btnFace ); break; - case OOX_COLOR_CHBORDERAUTO: nColor = 0x000000; /* really always black? */ break; + case OOX_COLOR_CHBORDERAUTO: nColor = API_RGB_BLACK; /* really always black? */ break; case OOX_COLOR_NOTEBACK: nColor = getBaseFilter().getSystemColor( XML_infoBk ); break; case OOX_COLOR_NOTETEXT: nColor = getBaseFilter().getSystemColor( XML_infoText ); break; case OOX_COLOR_FONTAUTO: nColor = API_RGB_TRANSPARENT; break; @@ -1013,7 +987,7 @@ void Font::finalizeImport() rtl_getTextEncodingFromWindowsCharset( static_cast< sal_uInt8 >( maModel.mnCharSet ) ) ); // color, height, weight, slant, strikeout, outline, shadow - maApiData.mnColor = maModel.maColor.getColor( *this, API_RGB_TRANSPARENT ); + maApiData.mnColor = maModel.maColor.getColor( getBaseFilter() ); maApiData.maDesc.Height = static_cast< sal_Int16 >( maModel.mfHeight * 20.0 ); maApiData.maDesc.Weight = maModel.mbBold ? cssawt::FontWeight::BOLD : cssawt::FontWeight::NORMAL; maApiData.maDesc.Slant = maModel.mbItalic ? cssawt::FontSlant_ITALIC : cssawt::FontSlant_NONE; @@ -1750,7 +1724,7 @@ BorderLineModel* Border::getBorderLine( sal_Int32 nElement ) bool Border::convertBorderLine( BorderLine& rBorderLine, const BorderLineModel& rModel ) { - rBorderLine.Color = rModel.maColor.getColor( *this, API_RGB_BLACK ); + rBorderLine.Color = rModel.maColor.getColor( getBaseFilter(), API_RGB_BLACK ); switch( rModel.mnStyle ) { case XML_dashDot: lclSetBorderLineWidth( rBorderLine, API_LINE_THIN ); break; @@ -2046,6 +2020,8 @@ void Fill::importCfRule( BiffInputStream& rStrm, sal_uInt32 nFlags ) void Fill::finalizeImport() { + const FilterBase& rFilter = getBaseFilter(); + if( mxPatternModel.get() ) { // finalize the OOX data struct @@ -2096,15 +2072,16 @@ void Fill::finalizeImport() case XML_solid: nAlpha = 0x80; break; } + sal_Int32 nWinTextColor = rFilter.getSystemColor( XML_windowText ); + sal_Int32 nWinColor = rFilter.getSystemColor( XML_window ); + if( !rModel.mbPattColorUsed ) rModel.maPatternColor.setAuto(); - sal_Int32 nPattColor = rModel.maPatternColor.getColor( - *this, getBaseFilter().getSystemColor( XML_windowText ) ); + sal_Int32 nPattColor = rModel.maPatternColor.getColor( rFilter, nWinTextColor ); if( !rModel.mbFillColorUsed ) rModel.maFillColor.setAuto(); - sal_Int32 nFillColor = rModel.maFillColor.getColor( - *this, getBaseFilter().getSystemColor( XML_window ) ); + sal_Int32 nFillColor = rModel.maFillColor.getColor( rFilter, nWinColor ); maApiData.mnColor = lclGetMixedColor( nPattColor, nFillColor, nAlpha ); maApiData.mbTransparent = false; @@ -2116,11 +2093,11 @@ void Fill::finalizeImport() maApiData.mbUsed = true; // no support for differential attributes GradientFillModel::ColorMap::const_iterator aIt = rModel.maColors.begin(); OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" ); - maApiData.mnColor = aIt->second.getColor( *this ); + maApiData.mnColor = aIt->second.getColor( rFilter, API_RGB_WHITE ); if( ++aIt != rModel.maColors.end() ) { OSL_ENSURE( !aIt->second.isAuto(), "Fill::finalizeImport - automatic gradient color" ); - sal_Int32 nEndColor = aIt->second.getColor( *this ); + sal_Int32 nEndColor = aIt->second.getColor( rFilter, API_RGB_WHITE ); maApiData.mnColor = lclGetMixedColor( maApiData.mnColor, nEndColor, 0x40 ); maApiData.mbTransparent = false; } @@ -2369,10 +2346,7 @@ void Xf::writeToPropertyMap( PropertyMap& rPropMap ) const // create and set cell style if( maModel.mbCellXf ) - { - const OUString& rStyleName = rStyles.createCellStyle( maModel.mnStyleXfId ); - rPropMap[ PROP_CellStyle ] <<= rStyleName; - } + rPropMap[ PROP_CellStyle ] <<= rStyles.createCellStyle( maModel.mnStyleXfId ); if( maModel.mbFontUsed ) rStyles.writeFontToPropertyMap( rPropMap, maModel.mnFontId ); @@ -2585,11 +2559,7 @@ namespace { const sal_Char* const spcLegacyStyleNamePrefix = "Excel_BuiltIn_"; const sal_Char* const sppcLegacyStyleNames[] = { -#if OOX_XLS_USE_DEFAULT_STYLE - "", // use existing "Default" style -#else "Normal", -#endif "RowLevel_", // outline level will be appended "ColumnLevel_", // outline level will be appended "Comma", @@ -2605,11 +2575,7 @@ const sal_Int32 snLegacyStyleNamesCount = static_cast< sal_Int32 >( STATIC_ARRAY const sal_Char* const spcStyleNamePrefix = "Excel Built-in "; const sal_Char* const sppcStyleNames[] = { -#if OOX_XLS_USE_DEFAULT_STYLE - "", // use existing "Default" style -#else "Normal", -#endif "RowLevel_", // outline level will be appended "ColLevel_", // outline level will be appended "Comma", @@ -2666,50 +2632,32 @@ const sal_Char* const sppcStyleNames[] = }; const sal_Int32 snStyleNamesCount = static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( sppcStyleNames ) ); -#if OOX_XLS_USE_DEFAULT_STYLE -const sal_Char* const spcDefaultStyleName = "Default"; -#endif - OUString lclGetBuiltinStyleName( sal_Int32 nBuiltinId, const OUString& rName, sal_Int32 nLevel = 0 ) { + OSL_ENSURE( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount), "lclGetBuiltinStyleName - unknown built-in style" ); OUStringBuffer aStyleName; - OSL_ENSURE( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount), "lclGetBuiltinStyleName - unknown builtin style" ); -#if OOX_XLS_USE_DEFAULT_STYLE - if( nBuiltinId == OOX_STYLE_NORMAL ) // "Normal" becomes "Default" style - { - aStyleName.appendAscii( spcDefaultStyleName ); - } + aStyleName.appendAscii( spcStyleNamePrefix ); + if( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount) && (sppcStyleNames[ nBuiltinId ][ 0 ] != 0) ) + aStyleName.appendAscii( sppcStyleNames[ nBuiltinId ] ); + else if( rName.getLength() > 0 ) + aStyleName.append( rName ); else - { -#endif - aStyleName.appendAscii( spcStyleNamePrefix ); - if( (0 <= nBuiltinId) && (nBuiltinId < snStyleNamesCount) && (sppcStyleNames[ nBuiltinId ][ 0 ] != 0) ) - aStyleName.appendAscii( sppcStyleNames[ nBuiltinId ] ); - else if( rName.getLength() > 0 ) - aStyleName.append( rName ); - else - aStyleName.append( nBuiltinId ); - if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) ) - aStyleName.append( nLevel ); -#if OOX_XLS_USE_DEFAULT_STYLE - } -#endif + aStyleName.append( nBuiltinId ); + if( (nBuiltinId == OOX_STYLE_ROWLEVEL) || (nBuiltinId == OOX_STYLE_COLLEVEL) ) + aStyleName.append( nLevel ); return aStyleName.makeStringAndClear(); } -bool lclIsBuiltinStyleName( const OUString& rStyleName, sal_Int32* pnBuiltinId, sal_Int32* pnNextChar ) +OUString lclGetBuiltInStyleName( const OUString& rName ) { -#if OOX_XLS_USE_DEFAULT_STYLE - // "Default" becomes "Normal" - if( rStyleName.equalsIgnoreAsciiCaseAscii( spcDefaultStyleName ) ) - { - if( pnBuiltinId ) *pnBuiltinId = OOX_STYLE_NORMAL; - if( pnNextChar ) *pnNextChar = rStyleName.getLength(); - return true; - } -#endif + OUStringBuffer aStyleName; + aStyleName.appendAscii( spcStyleNamePrefix ).append( rName ); + return aStyleName.makeStringAndClear(); +} - // try the other builtin styles +bool lclIsBuiltinStyleName( const OUString& rStyleName, sal_Int32* pnBuiltinId, sal_Int32* pnNextChar ) +{ + // try the other built-in styles OUString aPrefix = OUString::createFromAscii( spcStyleNamePrefix ); sal_Int32 nPrefixLen = aPrefix.getLength(); sal_Int32 nFoundId = 0; @@ -2719,20 +2667,13 @@ bool lclIsBuiltinStyleName( const OUString& rStyleName, sal_Int32* pnBuiltinId, OUString aShortName; for( sal_Int32 nId = 0; nId < snStyleNamesCount; ++nId ) { -#if OOX_XLS_USE_DEFAULT_STYLE - if( nId != OOX_STYLE_NORMAL ) + aShortName = OUString::createFromAscii( sppcStyleNames[ nId ] ); + if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) && + (nNextChar < nPrefixLen + aShortName.getLength()) ) { -#endif - aShortName = OUString::createFromAscii( sppcStyleNames[ nId ] ); - if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) && - (nNextChar < nPrefixLen + aShortName.getLength()) ) - { - nFoundId = nId; - nNextChar = nPrefixLen + aShortName.getLength(); - } -#if OOX_XLS_USE_DEFAULT_STYLE + nFoundId = nId; + nNextChar = nPrefixLen + aShortName.getLength(); } -#endif } } @@ -2796,15 +2737,11 @@ bool CellStyleModel::isDefaultStyle() const return mbBuiltin && (mnBuiltinId == OOX_STYLE_NORMAL); } -OUString CellStyleModel::createStyleName() const -{ - return isBuiltin() ? lclGetBuiltinStyleName( mnBuiltinId, maName, mnLevel ) : maName; -} - // ============================================================================ CellStyle::CellStyle( const WorkbookHelper& rHelper ) : - WorkbookHelper( rHelper ) + WorkbookHelper( rHelper ), + mbCreated( false ) { } @@ -2823,8 +2760,8 @@ void CellStyle::importCellStyle( RecordInputStream& rStrm ) { sal_uInt16 nFlags; rStrm >> maModel.mnXfId >> nFlags; - maModel.mnBuiltinId = rStrm.readuInt8(); - maModel.mnLevel = rStrm.readuInt8(); + maModel.mnBuiltinId = rStrm.readInt8(); + maModel.mnLevel = rStrm.readInt8(); rStrm >> maModel.maName; maModel.mbBuiltin = getFlag( nFlags, OOBIN_CELLSTYLE_BUILTIN ); maModel.mbCustom = getFlag( nFlags, OOBIN_CELLSTYLE_CUSTOM ); @@ -2839,62 +2776,74 @@ void CellStyle::importStyle( BiffInputStream& rStrm ) maModel.mbBuiltin = getFlag( nStyleXf, BIFF_STYLE_BUILTIN ); if( maModel.mbBuiltin ) { - maModel.mnBuiltinId = rStrm.readuInt8(); - maModel.mnLevel = rStrm.readuInt8(); + maModel.mnBuiltinId = rStrm.readInt8(); + maModel.mnLevel = rStrm.readInt8(); } else { maModel.maName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ); + // #i103281# check if this is a new built-in style introduced in XL2007 + if( (getBiff() == BIFF8) && (rStrm.getNextRecId() == BIFF_ID_STYLEEXT) && rStrm.startNextRecord() ) + { + sal_uInt8 nExtFlags; + rStrm.skip( 12 ); + rStrm >> nExtFlags; + maModel.mbBuiltin = getFlag( nExtFlags, BIFF_STYLEEXT_BUILTIN ); + maModel.mbCustom = getFlag( nExtFlags, BIFF_STYLEEXT_CUSTOM ); + maModel.mbHidden = getFlag( nExtFlags, BIFF_STYLEEXT_HIDDEN ); + if( maModel.mbBuiltin ) + { + maModel.mnBuiltinId = rStrm.readInt8(); + maModel.mnLevel = rStrm.readInt8(); + } + } } } -const OUString& CellStyle::createCellStyle( sal_Int32 nXfId, bool bSkipDefaultBuiltin ) +OUString CellStyle::calcInitialStyleName() const { - if( maCalcName.getLength() == 0 ) + return isBuiltin() ? lclGetBuiltinStyleName( maModel.mnBuiltinId, maModel.maName, maModel.mnLevel ) : maModel.maName; +} + +void CellStyle::createCellStyle() +{ + // #i1624# #i1768# ignore unnamed user styles + if( !mbCreated ) + mbCreated = maFinalName.getLength() == 0; + + /* #i103281# do not create another style of the same name, if it exists + already. This is needed to prevent that styles pasted from clipboard + get duplicated over and over. */ + if( !mbCreated ) try { - bool bBuiltin = maModel.isBuiltin(); - if( !bSkipDefaultBuiltin || !bBuiltin || maModel.mbCustom ) - { - // name of the style (generate unique name for builtin styles) - maCalcName = maModel.createStyleName(); - // #i1624# #i1768# ignore unnamed user styles - if( maCalcName.getLength() > 0 ) - { - Reference< XStyle > xStyle; -#if OOX_XLS_USE_DEFAULT_STYLE - // special handling for default style (do not create, but use existing) - if( isDefaultStyle() ) - { - /* Set all flags to true to have all properties in the style, - even if the used flags are not set (that's what Excel does). */ - if( Xf* pXf = getStyles().getStyleXf( nXfId ).get() ) - pXf->setAllUsedFlags( true ); - // use existing built-in style - xStyle = getStyleObject( maCalcName, false ); - } - else -#endif - { - /* Insert into cell styles collection, rename existing user styles, - if this is a built-in style, but do not do this in BIFF4 workspace - files, where built-in styles occur repeatedly. */ - bool bRenameExisting = bBuiltin && (getBiff() != BIFF4); - xStyle = createStyleObject( maCalcName, false, bRenameExisting ); - } - - // write style formatting properties - PropertySet aPropSet( xStyle ); - getStyles().writeStyleXfToPropertySet( aPropSet, nXfId ); -#if OOX_XLS_USE_DEFAULT_STYLE -#else - if( !isDefaultStyle() && xStyle.is() ) - xStyle->setParentStyle( getStyles().getDefaultStyleName() ); -#endif - } - } + Reference< XNameAccess > xCellStylesNA( getStyleFamily( false ), UNO_QUERY_THROW ); + mbCreated = xCellStylesNA->hasByName( maFinalName ); + } + catch( Exception& ) + { + } + + // create the style object in the document + if( !mbCreated ) try + { + mbCreated = true; + Reference< XStyle > xStyle( createStyleObject( maFinalName, false ), UNO_SET_THROW ); + // write style formatting properties + PropertySet aPropSet( xStyle ); + getStyles().writeStyleXfToPropertySet( aPropSet, maModel.mnXfId ); + if( !isDefaultStyle() ) + xStyle->setParentStyle( getStyles().getDefaultStyleName() ); } - return maCalcName; + catch( Exception& ) + { + } +} + +void CellStyle::finalizeImport() +{ + if( !isBuiltin() || maModel.mbCustom ) + createCellStyle(); } // ============================================================================ @@ -2906,6 +2855,32 @@ StylesBuffer::StylesBuffer( const WorkbookHelper& rHelper ) : maDefStyleName( lclGetBuiltinStyleName( OOX_STYLE_NORMAL, OUString() ) ), mnDefStyleXf( -1 ) { + /* Reserve style names that are built-in in Calc. This causes that + imported cell styles get different unused names and thus do not try to + overwrite these built-in styles. For BIFF4 workbooks (which contain a + separate list of cell styles per sheet), reserve all existing names if + current sheet is not the first sheet (this styles buffer will be + constructed again for every new sheet). This will create unique names + for styles in different sheets with the same name. */ + bool bReserveAll = (getFilterType() == FILTER_BIFF) && (getBiff() == BIFF4) && isWorkbookFile() && (getCurrentSheetIndex() > 0); + try + { + Reference< XEnumerationAccess > xCellStylesEA( getStyleFamily( false ), UNO_QUERY_THROW ); + Reference< XEnumeration > xCellStylesEnum( xCellStylesEA->createEnumeration(), UNO_SET_THROW ); + while( xCellStylesEnum->hasMoreElements() ) + { + Reference< XStyle > xCellStyle( xCellStylesEnum->nextElement(), UNO_QUERY_THROW ); + if( bReserveAll || !xCellStyle->isUserDefined() ) + { + Reference< XNamed > xCellStyleName( xCellStyle, UNO_QUERY_THROW ); + // create an empty entry by using ::std::map<>::operator[] + maCellStylesByName[ xCellStyleName->getName() ]; + } + } + } + catch( Exception& ) + { + } } FontRef StylesBuffer::createFont( sal_Int32* opnFontId ) @@ -3075,12 +3050,10 @@ void StylesBuffer::finalizeImport() maDxfs.forEachMem( &Dxf::finalizeImport ); // create the default cell style first - if( CellStyle* pDefStyle = maCellStyles.get( mnDefStyleXf ).get() ) - pDefStyle->createCellStyle( mnDefStyleXf ); - /* Create user-defined and modified builtin cell styles, passing true to - createStyleSheet() skips unchanged builtin styles. */ - for( CellStyleMap::iterator aIt = maCellStyles.begin(), aEnd = maCellStyles.end(); aIt != aEnd; ++aIt ) - aIt->second->createCellStyle( aIt->first, true ); + if( CellStyle* pDefStyle = maCellStylesById.get( mnDefStyleXf ).get() ) + pDefStyle->createCellStyle(); + // create user-defined and modified built-in cell styles + maCellStylesById.forEachMem( &CellStyle::finalizeImport ); } sal_Int32 StylesBuffer::getPaletteColor( sal_Int32 nPaletteIdx ) const @@ -3136,8 +3109,13 @@ const FontModel& StylesBuffer::getDefaultFontModel() const const OUString& StylesBuffer::createCellStyle( sal_Int32 nXfId ) const { - if( CellStyle* pCellStyle = maCellStyles.get( nXfId ).get() ) - return pCellStyle->createCellStyle( nXfId ); + if( CellStyle* pCellStyle = maCellStylesById.get( nXfId ).get() ) + { + pCellStyle->createCellStyle(); + const OUString& rStyleName = pCellStyle->getFinalStyleName(); + if( rStyleName.getLength() > 0 ) + return rStyleName; + } // on error: fallback to default style return maDefStyleName; } @@ -3150,13 +3128,10 @@ const OUString& StylesBuffer::createDxfStyle( sal_Int32 nDxfId ) const return maDefStyleName; } -#if OOX_XLS_USE_DEFAULT_STYLE -#else const OUString& StylesBuffer::getDefaultStyleName() const { return createCellStyle( mnDefStyleXf ); } -#endif void StylesBuffer::writeFontToPropertyMap( PropertyMap& rPropMap, sal_Int32 nFontId ) const { @@ -3207,11 +3182,38 @@ void StylesBuffer::writeStyleXfToPropertySet( PropertySet& rPropSet, sal_Int32 n void StylesBuffer::insertCellStyle( CellStyleRef xCellStyle ) { - if( xCellStyle->getXfId() >= 0 ) + sal_Int32 nXfId = xCellStyle->getXfId(); + OUString aStyleName = xCellStyle->calcInitialStyleName(); + // #i1624# #i1768# ignore unnamed user styles + if( (nXfId >= 0) && (aStyleName.getLength() > 0) ) { - maCellStyles[ xCellStyle->getXfId() ] = xCellStyle; + // insert into the XF identifier map + maCellStylesById[ nXfId ] = xCellStyle; + + // find an unused name + OUString aUnusedName = aStyleName; + sal_Int32 nIndex = 0; + while( maCellStylesByName.count( aUnusedName ) > 0 ) + aUnusedName = OUStringBuffer( aStyleName ).append( sal_Unicode( ' ' ) ).append( ++nIndex ).makeStringAndClear(); + + // move old existing style to new unused name, if new style is built-in + if( xCellStyle->isBuiltin() && (aStyleName != aUnusedName) ) + { + CellStyleRef& rxCellStyle = maCellStylesByName[ aUnusedName ]; + rxCellStyle = maCellStylesByName[ aStyleName ]; + // the entry may be empty if the style name has been reserved in c'tor + if( rxCellStyle.get() ) + rxCellStyle->setFinalStyleName( aUnusedName ); + aUnusedName = aStyleName; + } + + // insert new style + maCellStylesByName[ aUnusedName ] = xCellStyle; + xCellStyle->setFinalStyleName( aUnusedName ); + + // remember XF identifier of default cell style if( xCellStyle->isDefaultStyle() ) - mnDefStyleXf = xCellStyle->getXfId(); + mnDefStyleXf = nXfId; } } diff --git a/oox/source/xls/themebuffer.cxx b/oox/source/xls/themebuffer.cxx index b2baefccd5a5..e089e5fece77 100644 --- a/oox/source/xls/themebuffer.cxx +++ b/oox/source/xls/themebuffer.cxx @@ -117,14 +117,6 @@ sal_Int32 ThemeBuffer::getColorByToken( sal_Int32 nToken ) const return getClrScheme().getColor( nToken, nColor ) ? nColor : API_RGB_TRANSPARENT; } -sal_Int32 ThemeBuffer::getColorByIndex( sal_Int32 nIndex ) const -{ - static const sal_Int32 spnColorTokens[] = { - XML_lt1, XML_dk1, XML_lt2, XML_dk2, XML_accent1, XML_accent2, - XML_accent3, XML_accent4, XML_accent5, XML_accent6, XML_hlink, XML_folHlink }; - return getColorByToken( STATIC_ARRAY_SELECT( spnColorTokens, nIndex, XML_TOKEN_INVALID ) ); -} - // ============================================================================ } // namespace xls diff --git a/oox/source/xls/viewsettings.cxx b/oox/source/xls/viewsettings.cxx index caeacaf6d45d..2d53541b404c 100644 --- a/oox/source/xls/viewsettings.cxx +++ b/oox/source/xls/viewsettings.cxx @@ -56,7 +56,8 @@ using ::com::sun::star::container::XNameContainer; using ::com::sun::star::container::XIndexContainer; using ::com::sun::star::container::XIndexAccess; using ::com::sun::star::document::XViewDataSupplier; -using ::com::sun::star::table::CellAddress; +using ::com::sun::star::table::CellAddress;
+using ::oox::core::FilterBase; namespace oox { namespace xls { @@ -199,6 +200,11 @@ sal_Int32 SheetViewModel::getPageBreakZoom() const return getLimitedValue< sal_Int32 >( nZoom, API_ZOOMVALUE_MIN, API_ZOOMVALUE_MAX ); } +sal_Int32 SheetViewModel::getGridColor( const FilterBase& rFilter ) const +{ + return mbDefGridColor ? API_RGB_TRANSPARENT : maGridColor.getColor( rFilter ); +} + const PaneSelectionModel* SheetViewModel::getPaneSelection( sal_Int32 nPaneId ) const { return maPaneSelMap.get( nPaneId ).get(); @@ -500,7 +506,7 @@ void SheetViewSettings::finalizeImport() } // sheet selected (active sheet must be selected) - bool bSelected = xModel->mbSelected || (getSheetIndex() == getViewSettings().getActiveSheetIndex()); + bool bSelected = xModel->mbSelected || (getSheetIndex() == getViewSettings().getActiveCalcSheet()); // visible area and current cursor position (selection not supported via API) CellAddress aFirstPos = xModel->maFirstPos; @@ -560,10 +566,6 @@ void SheetViewSettings::finalizeImport() break; } - // automatic grid color - if( xModel->mbDefGridColor ) - xModel->maGridColor.setAuto(); - // write the sheet view settings into the property sequence PropertyMap aPropMap; aPropMap[ PROP_TableSelected ] <<= bSelected; @@ -581,7 +583,7 @@ void SheetViewSettings::finalizeImport() aPropMap[ PROP_ZoomType ] <<= API_ZOOMTYPE_PERCENT; aPropMap[ PROP_ZoomValue ] <<= static_cast< sal_Int16 >( xModel->getNormalZoom() ); aPropMap[ PROP_PageViewZoomValue ] <<= static_cast< sal_Int16 >( xModel->getPageBreakZoom() ); - aPropMap[ PROP_GridColor ] <<= xModel->maGridColor.getColor( *this ); + aPropMap[ PROP_GridColor ] <<= xModel->getGridColor( getBaseFilter() ); aPropMap[ PROP_ShowPageBreakPreview ] <<= xModel->isPageBreakPreview(); aPropMap[ PROP_ShowFormulas ] <<= xModel->mbShowFormulas; aPropMap[ PROP_ShowGrid ] <<= xModel->mbShowGrid; @@ -692,7 +694,7 @@ void ViewSettings::importWindow1( BiffInputStream& rStrm ) } } -void ViewSettings::setSheetViewSettings( sal_Int32 nSheet, const SheetViewModelRef& rxSheetView, const Any& rProperties ) +void ViewSettings::setSheetViewSettings( sal_Int16 nSheet, const SheetViewModelRef& rxSheetView, const Any& rProperties ) { maSheetViews[ nSheet ] = rxSheetView; maSheetProps[ nSheet ] = rProperties; @@ -701,7 +703,7 @@ void ViewSettings::setSheetViewSettings( sal_Int32 nSheet, const SheetViewModelR void ViewSettings::finalizeImport() { const WorksheetBuffer& rWorksheets = getWorksheets(); - if( rWorksheets.getSheetCount() <= 0 ) return; + if( rWorksheets.getWorksheetCount() <= 0 ) return; // force creation of workbook view model to get the Excel defaults const WorkbookViewModel& rModel = maBookViews.empty() ? createWorkbookView() : *maBookViews.front(); @@ -716,7 +718,7 @@ void ViewSettings::finalizeImport() ContainerHelper::insertByName( xSheetsNC, rWorksheets.getCalcSheetName( aIt->first ), aIt->second ); // use active sheet to set sheet properties that are document-global in Calc - sal_Int32 nActiveSheet = getActiveSheetIndex(); + sal_Int16 nActiveSheet = getActiveCalcSheet(); SheetViewModelRef& rxActiveSheetView = maSheetViews[ nActiveSheet ]; OSL_ENSURE( rxActiveSheetView.get(), "ViewSettings::finalizeImport - missing active sheet view settings" ); if( !rxActiveSheetView ) @@ -735,7 +737,7 @@ void ViewSettings::finalizeImport() aPropMap[ PROP_ShowObjects ] <<= nShowMode; aPropMap[ PROP_ShowCharts ] <<= nShowMode; aPropMap[ PROP_ShowDrawing ] <<= nShowMode; - aPropMap[ PROP_GridColor ] <<= rxActiveSheetView->maGridColor.getColor( *this ); + aPropMap[ PROP_GridColor ] <<= rxActiveSheetView->getGridColor( getBaseFilter() ); aPropMap[ PROP_ShowPageBreakPreview ] <<= rxActiveSheetView->isPageBreakPreview(); aPropMap[ PROP_ShowFormulas ] <<= rxActiveSheetView->mbShowFormulas; aPropMap[ PROP_ShowGrid ] <<= rxActiveSheetView->mbShowGrid; @@ -754,10 +756,9 @@ void ViewSettings::finalizeImport() } } -sal_Int32 ViewSettings::getActiveSheetIndex() const +sal_Int16 ViewSettings::getActiveCalcSheet() const { - sal_Int32 nSheetCount = getLimitedValue< sal_Int32, sal_Int32 >( getWorksheets().getSheetCount(), 1, SAL_MAX_INT32 ); - return maBookViews.empty() ? 0 : getLimitedValue< sal_Int32, sal_Int32 >( maBookViews.front()->mnActiveSheet, 0, nSheetCount - 1 ); + return maBookViews.empty() ? 0 : ::std::max< sal_Int16 >( getWorksheets().getCalcSheetIndex( maBookViews.front()->mnActiveSheet ), 0 ); } // private -------------------------------------------------------------------- diff --git a/oox/source/xls/workbookfragment.cxx b/oox/source/xls/workbookfragment.cxx index 1779cb4a7691..6a78c838838e 100644 --- a/oox/source/xls/workbookfragment.cxx +++ b/oox/source/xls/workbookfragment.cxx @@ -233,13 +233,15 @@ void OoxWorkbookFragment::finalizeImport() some preprocessing in the fragment constructors, e.g. loading the table fragments for all sheets that are needed before the cell formulas are loaded. */ - typedef ::std::map< sal_Int32, FragmentHandlerRef > SheetFragmentMap; - SheetFragmentMap aSheetFragments; + typedef ::std::vector< FragmentHandlerRef > SheetFragmentVector; + SheetFragmentVector aSheetFragments; WorksheetBuffer& rWorksheets = getWorksheets(); - sal_Int32 nSheetCount = rWorksheets.getSheetCount(); - for( sal_Int32 nSheet = 0; nSheet < nSheetCount; ++nSheet ) + sal_Int32 nWorksheetCount = rWorksheets.getWorksheetCount(); + for( sal_Int32 nWorksheet = 0; nWorksheet < nWorksheetCount; ++nWorksheet ) { - if( const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getSheetRelId( nSheet ) ) ) + sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet ); + const Relation* pRelation = getRelations().getRelationFromRelId( rWorksheets.getWorksheetRelId( nWorksheet ) ); + if( (nCalcSheet >= 0) && pRelation ) { // get fragment path of the sheet OUString aFragmentPath = getFragmentPathFromRelation( *pRelation ); @@ -247,33 +249,33 @@ void OoxWorkbookFragment::finalizeImport() if( aFragmentPath.getLength() > 0 ) { ::rtl::Reference< OoxWorksheetFragmentBase > xFragment; - double fSegmentLength = getProgressBar().getFreeLength() / (nSheetCount - nSheet); + double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet); ISegmentProgressBarRef xSheetSegment = getProgressBar().createSegment( fSegmentLength ); // create the fragment according to the sheet type if( pRelation->maType == CREATE_OFFICEDOC_RELATIONSTYPE( "worksheet" ) ) { - xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_WORKSHEET, nSheet ) ); + xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_WORKSHEET, nCalcSheet ) ); } else if( pRelation->maType == CREATE_OFFICEDOC_RELATIONSTYPE( "chartsheet" ) ) { - xFragment.set( new OoxChartsheetFragment( *this, aFragmentPath, xSheetSegment, nSheet ) ); + xFragment.set( new OoxChartsheetFragment( *this, aFragmentPath, xSheetSegment, nCalcSheet ) ); } else if( (pRelation->maType == CREATE_MSOFFICE_RELATIONSTYPE( "xlMacrosheet" )) || (pRelation->maType == CREATE_MSOFFICE_RELATIONSTYPE( "xlIntlMacrosheet" )) ) { - xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_MACROSHEET, nSheet ) ); + xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_MACROSHEET, nCalcSheet ) ); } else if( pRelation->maType == CREATE_OFFICEDOC_RELATIONSTYPE( "dialogsheet" ) ) { - xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_DIALOGSHEET, nSheet ) ); + xFragment.set( new OoxWorksheetFragment( *this, aFragmentPath, xSheetSegment, SHEETTYPE_DIALOGSHEET, nCalcSheet ) ); } // insert the fragment into the map OSL_ENSURE( xFragment.is(), "OoxWorkbookFragment::finalizeImport - unknown sheet type" ); OSL_ENSURE( !xFragment.is() || xFragment->isValidSheet(), "OoxWorkbookFragment::finalizeImport - missing sheet in document" ); if( xFragment.is() && xFragment->isValidSheet() ) - aSheetFragments[ nSheet ].set( xFragment.get() ); + aSheetFragments.push_back( xFragment.get() ); } } } @@ -283,17 +285,13 @@ void OoxWorkbookFragment::finalizeImport() getTables().finalizeImport(); // load all worksheets - for( sal_Int32 nSheet = 0; nSheet < nSheetCount; ++nSheet ) + for( SheetFragmentVector::iterator aIt = aSheetFragments.begin(), aEnd = aSheetFragments.end(); aIt != aEnd; ++aIt ) { - SheetFragmentMap::iterator aIt = aSheetFragments.find( nSheet ); - if( aIt != aSheetFragments.end() ) - { - OOX_LOADSAVE_TIMER( IMPORTSHEETFRAGMENT ); - // import the sheet fragment - importOoxFragment( aIt->second ); - // delete fragment object, will free all allocated sheet buffers - aSheetFragments.erase( aIt ); - } + OOX_LOADSAVE_TIMER( IMPORTSHEETFRAGMENT ); + // import the sheet fragment + importOoxFragment( *aIt ); + // delete fragment object, will free all allocated sheet buffers + aIt->clear(); } // final conversions, e.g. calculation settings and view settings @@ -368,13 +366,14 @@ bool BiffWorkbookFragment::importFragment() // load sheet fragments (do not return false in bRet on missing/broken sheets) WorksheetBuffer& rWorksheets = getWorksheets(); bool bNextSheet = bRet; - for( sal_Int32 nSheet = 0, nSheetCount = rWorksheets.getSheetCount(); bNextSheet && (nSheet < nSheetCount); ++nSheet ) + for( sal_Int32 nWorksheet = 0, nWorksheetCount = rWorksheets.getWorksheetCount(); bNextSheet && (nWorksheet < nWorksheetCount); ++nWorksheet ) { // try to start a new sheet fragment - double fSegmentLength = getProgressBar().getFreeLength() / (nSheetCount - nSheet); + double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet); ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength ); BiffFragmentType eSheetFragment = startFragment( getBiff() ); - bNextSheet = importSheetFragment( *xSheetProgress, eSheetFragment, nSheet ); + sal_Int16 nCalcSheet = rWorksheets.getCalcSheetIndex( nWorksheet ); + bNextSheet = importSheetFragment( *xSheetProgress, eSheetFragment, nCalcSheet ); } } break; @@ -435,19 +434,19 @@ bool BiffWorkbookFragment::importWorkspaceFragment() // load sheet fragments (do not return false in bRet on missing/broken sheets) bool bNextSheet = bRet; - for( sal_Int32 nSheet = 0, nSheetCount = rWorksheets.getSheetCount(); bNextSheet && (nSheet < nSheetCount); ++nSheet ) + for( sal_Int32 nWorksheet = 0, nWorksheetCount = rWorksheets.getWorksheetCount(); bNextSheet && (nWorksheet < nWorksheetCount); ++nWorksheet ) { // try to start a new sheet fragment (with leading SHEETHEADER record) bNextSheet = mrStrm.startNextRecord() && (mrStrm.getRecId() == BIFF_ID_SHEETHEADER); if( bNextSheet ) { - double fSegmentLength = getProgressBar().getFreeLength() / (nSheetCount - nSheet); + double fSegmentLength = getProgressBar().getFreeLength() / (nWorksheetCount - nWorksheet); ISegmentProgressBarRef xSheetProgress = getProgressBar().createSegment( fSegmentLength ); /* Read current sheet name (sheet substreams may not be in the same order as SHEET records are). */ mrStrm.skip( 4 ); OUString aSheetName = mrStrm.readByteStringUC( false, getTextEncoding() ); - sal_Int32 nCurrSheet = rWorksheets.getCalcSheetIndex( aSheetName ); + sal_Int16 nCurrSheet = rWorksheets.getCalcSheetIndex( aSheetName ); // load the sheet fragment records BiffFragmentType eSheetFragment = startFragment( getBiff() ); bNextSheet = importSheetFragment( *xSheetProgress, eSheetFragment, nCurrSheet ); @@ -630,8 +629,12 @@ bool BiffWorkbookFragment::importGlobalsFragment( ISegmentProgressBar& rProgress return bRet; } -bool BiffWorkbookFragment::importSheetFragment( ISegmentProgressBar& rProgressBar, BiffFragmentType eFragment, sal_Int32 nSheet ) +bool BiffWorkbookFragment::importSheetFragment( ISegmentProgressBar& rProgressBar, BiffFragmentType eFragment, sal_Int16 nCalcSheet ) { + // no Calc sheet - skip the fragment + if( nCalcSheet < 0 ) + return skipFragment(); + // find the sheet type for this fragment WorksheetType eSheetType = SHEETTYPE_EMPTYSHEET; switch( eFragment ) @@ -646,7 +649,7 @@ bool BiffWorkbookFragment::importSheetFragment( ISegmentProgressBar& rProgressBa /* #i11183# Clear buffers that are used per-sheet, e.g. external links in BIFF4W and BIFF5 files, or defined names in BIFF4W files. */ - createBuffersPerSheet(); + createBuffersPerSheet( nCalcSheet ); // preprocess some records switch( getBiff() ) @@ -656,8 +659,6 @@ bool BiffWorkbookFragment::importSheetFragment( ISegmentProgressBar& rProgressBa case BIFF3: case BIFF4: { - // set sheet index in defined names buffer to handle built-in names correctly - getDefinedNames().setLocalSheetIndex( nSheet ); // remember current record to seek back below sal_Int64 nRecHandle = mrStrm.getRecHandle(); // import the global records @@ -695,14 +696,14 @@ bool BiffWorkbookFragment::importSheetFragment( ISegmentProgressBar& rProgressBa case SHEETTYPE_WORKSHEET: case SHEETTYPE_MACROSHEET: case SHEETTYPE_DIALOGSHEET: - xFragment.reset( new BiffWorksheetFragment( *this, xSheetProgress, eSheetType, nSheet ) ); + xFragment.reset( new BiffWorksheetFragment( *this, xSheetProgress, eSheetType, nCalcSheet ) ); break; case SHEETTYPE_CHARTSHEET: - xFragment.reset( new BiffChartsheetFragment( *this, xSheetProgress, nSheet ) ); + xFragment.reset( new BiffChartsheetFragment( *this, xSheetProgress, nCalcSheet ) ); break; case SHEETTYPE_MODULESHEET: case SHEETTYPE_EMPTYSHEET: - xFragment.reset( new BiffSkipWorksheetFragment( *this, xSheetProgress, nSheet ) ); + xFragment.reset( new BiffSkipWorksheetFragment( *this, xSheetProgress, nCalcSheet ) ); break; } // load the sheet fragment records diff --git a/oox/source/xls/workbookhelper.cxx b/oox/source/xls/workbookhelper.cxx index 7cce9db80352..2b337050a996 100644 --- a/oox/source/xls/workbookhelper.cxx +++ b/oox/source/xls/workbookhelper.cxx @@ -298,8 +298,8 @@ public: Reference< XStyle > getStyleObject( const OUString& rStyleName, bool bPageStyle ) const; /** Creates and returns a defined name on-the-fly in the Calc document. */ Reference< XNamedRange > createNamedRangeObject( OUString& orName, sal_Int32 nNameFlags ) const; - /** Creates a com.sun.star.style.Style object and returns its final name. */ - Reference< XStyle > createStyleObject( OUString& orStyleName, bool bPageStyle, bool bRenameOldExisting ) const; + /** Creates and returns a com.sun.star.style.Style object for cells or pages. */ + Reference< XStyle > createStyleObject( OUString& orStyleName, bool bPageStyle ) const; // buffers ---------------------------------------------------------------- @@ -367,7 +367,7 @@ public: /** Enables workbook file mode, used for BIFF4 workspace files. */ void setIsWorkbookFile(); /** Recreates global buffers that are used per sheet in specific BIFF versions. */ - void createBuffersPerSheet(); + void createBuffersPerSheet( sal_Int16 nSheet ); /** Returns the codec helper that stores the encoder/decoder object. */ inline BiffCodecHelper& getCodecHelper() { return *mxCodecHelper; } @@ -563,14 +563,14 @@ Reference< XNamedRange > WorkbookData::createNamedRangeObject( OUString& orName, return xNamedRange; } -Reference< XStyle > WorkbookData::createStyleObject( OUString& orStyleName, bool bPageStyle, bool bRenameOldExisting ) const +Reference< XStyle > WorkbookData::createStyleObject( OUString& orStyleName, bool bPageStyle ) const { Reference< XStyle > xStyle; try { Reference< XNameContainer > xStylesNC( getStyleFamily( bPageStyle ), UNO_SET_THROW ); xStyle.set( mrBaseFilter.getModelFactory()->createInstance( bPageStyle ? maPageStyleServ : maCellStyleServ ), UNO_QUERY_THROW ); - orStyleName = ContainerHelper::insertByUnusedName( xStylesNC, orStyleName, ' ', Any( xStyle ), bRenameOldExisting ); + orStyleName = ContainerHelper::insertByUnusedName( xStylesNC, orStyleName, ' ', Any( xStyle ), false ); } catch( Exception& ) { @@ -605,22 +605,28 @@ void WorkbookData::setIsWorkbookFile() mbWorkbook = true; } -void WorkbookData::createBuffersPerSheet() +void WorkbookData::createBuffersPerSheet( sal_Int16 nSheet ) { + // set mnCurrSheet to enable usage of WorkbookHelper::getCurrentSheetIndex() + mnCurrSheet = nSheet; switch( meBiff ) { case BIFF2: case BIFF3: + OSL_ENSURE( mnCurrSheet == 0, "WorkbookData::createBuffersPerSheet - unexpected sheet index" ); + mxDefNames->setLocalCalcSheet( mnCurrSheet ); break; case BIFF4: - // #i11183# sheets in BIFF4W files have own styles or names - if( mbWorkbook ) + OSL_ENSURE( mbWorkbook || (mnCurrSheet == 0), "WorkbookData::createBuffersPerSheet - unexpected sheet index" ); + // #i11183# sheets in BIFF4W files have own styles and names + if( mbWorkbook && (mnCurrSheet > 0) ) { mxStyles.reset( new StylesBuffer( *this ) ); mxDefNames.reset( new DefinedNamesBuffer( *this ) ); mxExtLinks.reset( new ExternalLinkBuffer( *this ) ); } + mxDefNames->setLocalCalcSheet( mnCurrSheet ); break; case BIFF5: @@ -634,6 +640,7 @@ void WorkbookData::createBuffersPerSheet() case BIFF_UNKNOWN: break; } + mnCurrSheet = -1; } // private -------------------------------------------------------------------- @@ -850,7 +857,7 @@ Reference< XNameAccess > WorkbookHelper::getDdeLinks() const return mrBookData.getDdeLinks(); } -Reference< XSpreadsheet > WorkbookHelper::getSheetFromDoc( sal_Int32 nSheet ) const +Reference< XSpreadsheet > WorkbookHelper::getSheetFromDoc( sal_Int16 nSheet ) const { Reference< XSpreadsheet > xSheet; try @@ -921,9 +928,9 @@ Reference< XNamedRange > WorkbookHelper::createNamedRangeObject( OUString& orNam return mrBookData.createNamedRangeObject( orName, nNameFlags ); } -Reference< XStyle > WorkbookHelper::createStyleObject( OUString& orStyleName, bool bPageStyle, bool bRenameOldExisting ) const +Reference< XStyle > WorkbookHelper::createStyleObject( OUString& orStyleName, bool bPageStyle ) const { - return mrBookData.createStyleObject( orStyleName, bPageStyle, bRenameOldExisting ); + return mrBookData.createStyleObject( orStyleName, bPageStyle ); } // buffers -------------------------------------------------------------------- @@ -1078,9 +1085,9 @@ void WorkbookHelper::setIsWorkbookFile() mrBookData.setIsWorkbookFile(); } -void WorkbookHelper::createBuffersPerSheet() +void WorkbookHelper::createBuffersPerSheet( sal_Int16 nSheet ) { - mrBookData.createBuffersPerSheet(); + mrBookData.createBuffersPerSheet( nSheet ); } BiffCodecHelper& WorkbookHelper::getCodecHelper() const diff --git a/oox/source/xls/worksheetbuffer.cxx b/oox/source/xls/worksheetbuffer.cxx index 64e8acbb6c9c..ee2491880c4e 100644 --- a/oox/source/xls/worksheetbuffer.cxx +++ b/oox/source/xls/worksheetbuffer.cxx @@ -38,7 +38,6 @@ #include <com/sun/star/sheet/XSheetLinkable.hpp> #include "properties.hxx" #include "oox/helper/attributelist.hxx" -#include "oox/helper/containerhelper.hxx" #include "oox/helper/propertyset.hxx" #include "oox/helper/recordinputstream.hxx" #include "oox/core/filterbase.hxx" @@ -61,21 +60,6 @@ namespace xls { // ============================================================================ -namespace { - -/** Returns the base file name without path and extension. */ -OUString lclGetBaseFileName( const OUString& rUrl ) -{ - sal_Int32 nFileNamePos = ::std::max< sal_Int32 >( rUrl.lastIndexOf( '/' ) + 1, 0 ); - sal_Int32 nExtPos = rUrl.lastIndexOf( '.' ); - if( nExtPos <= nFileNamePos ) nExtPos = rUrl.getLength(); - return rUrl.copy( nFileNamePos, nExtPos - nFileNamePos ); -} - -} // namespace - -// ============================================================================ - SheetInfoModel::SheetInfoModel() : mnSheetId( -1 ), mnState( XML_visible ) @@ -89,11 +73,19 @@ WorksheetBuffer::WorksheetBuffer( const WorkbookHelper& rHelper ) : { } +/*static*/ OUString WorksheetBuffer::getBaseFileName( const OUString& rUrl ) +{ + sal_Int32 nFileNamePos = ::std::max< sal_Int32 >( rUrl.lastIndexOf( '/' ) + 1, 0 ); + sal_Int32 nExtPos = rUrl.lastIndexOf( '.' ); + if( nExtPos <= nFileNamePos ) nExtPos = rUrl.getLength(); + return rUrl.copy( nFileNamePos, nExtPos - nFileNamePos ); +} + void WorksheetBuffer::initializeSingleSheet() { OSL_ENSURE( maSheetInfos.empty(), "WorksheetBuffer::initializeSingleSheet - invalid call" ); SheetInfoModel aModel; - aModel.maName = lclGetBaseFileName( getBaseFilter().getFileUrl() ); + aModel.maName = getBaseFileName( getBaseFilter().getFileUrl() ); insertSheet( aModel ); } @@ -137,107 +129,132 @@ void WorksheetBuffer::importSheet( BiffInputStream& rStrm ) sal_Int16 WorksheetBuffer::insertEmptySheet( const OUString& rPreferredName, bool bVisible ) { - IndexNamePair aIndexName = insertSheet( rPreferredName, SAL_MAX_INT16, bVisible ); - return aIndexName.first; + return createSheet( rPreferredName, SAL_MAX_INT32, bVisible ).first; } -sal_Int32 WorksheetBuffer::getSheetCount() const +sal_Int32 WorksheetBuffer::getWorksheetCount() const { return static_cast< sal_Int32 >( maSheetInfos.size() ); } -OUString WorksheetBuffer::getSheetRelId( sal_Int32 nSheet ) const +OUString WorksheetBuffer::getWorksheetRelId( sal_Int32 nWorksheet ) const { - OUString aRelId; - if( const SheetInfoModel* pModel = getSheetInfo( nSheet ) ) - aRelId = pModel->maRelId; - return aRelId; + const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get(); + return pSheetInfo ? pSheetInfo->maRelId : OUString(); } -OUString WorksheetBuffer::getCalcSheetName( sal_Int32 nSheet ) const +sal_Int16 WorksheetBuffer::getCalcSheetIndex( sal_Int32 nWorksheet ) const { - OUString aName; - if( const SheetInfoModel* pModel = getSheetInfo( nSheet ) ) - aName = pModel->maFinalName; - return aName; + const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get(); + return pSheetInfo ? pSheetInfo->mnCalcSheet : -1; } -OUString WorksheetBuffer::getCalcSheetName( const OUString& rModelName ) const +OUString WorksheetBuffer::getCalcSheetName( sal_Int32 nWorksheet ) const { - for( SheetInfoModelVec::const_iterator aIt = maSheetInfos.begin(), aEnd = maSheetInfos.end(); aIt != aEnd; ++aIt ) - // TODO: handle encoded characters - if( aIt->maName.equalsIgnoreAsciiCase( rModelName ) ) - return aIt->maFinalName; - return OUString(); + const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get(); + return pSheetInfo ? pSheetInfo->maCalcName : OUString(); } -sal_Int32 WorksheetBuffer::getCalcSheetIndex( const OUString& rModelName ) const +sal_Int16 WorksheetBuffer::getCalcSheetIndex( const OUString& rWorksheetName ) const { - for( SheetInfoModelVec::const_iterator aIt = maSheetInfos.begin(), aEnd = maSheetInfos.end(); aIt != aEnd; ++aIt ) - // TODO: handle encoded characters - if( aIt->maName.equalsIgnoreAsciiCase( rModelName ) ) - return static_cast< sal_Int32 >( aIt - maSheetInfos.begin() ); - return -1; + const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get(); + return pSheetInfo ? pSheetInfo->mnCalcSheet : -1; +} + +OUString WorksheetBuffer::getCalcSheetName( const OUString& rWorksheetName ) const +{ + if( const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get() ) + { + bool bIsQuoted = pSheetInfo->maName != rWorksheetName; + return bIsQuoted ? pSheetInfo->maCalcQuotedName : pSheetInfo->maCalcName; + } + return OUString(); } // private -------------------------------------------------------------------- -const SheetInfoModel* WorksheetBuffer::getSheetInfo( sal_Int32 nSheet ) const +namespace { + +OUString lclQuoteName( const OUString& rName ) { - return ContainerHelper::getVectorElement( maSheetInfos, nSheet ); + OUStringBuffer aBuffer( rName ); + // duplicate all quote characters + for( sal_Int32 nPos = aBuffer.getLength() - 1; nPos >= 0; --nPos ) + if( aBuffer.charAt( nPos ) == '\'' ) + aBuffer.insert( nPos, sal_Unicode( '\'' ) ); + // add outer quotes and return + return aBuffer.insert( 0, sal_Unicode( '\'' ) ).append( sal_Unicode( '\'' ) ).makeStringAndClear(); } -WorksheetBuffer::IndexNamePair WorksheetBuffer::insertSheet( const OUString& rPreferredName, sal_Int16 nSheet, bool bVisible ) +} // namespace + +WorksheetBuffer::SheetInfo::SheetInfo( const SheetInfoModel& rModel, sal_Int16 nCalcSheet, const OUString& rCalcName ) : + SheetInfoModel( rModel ), + maCalcName( rCalcName ), + maCalcQuotedName( lclQuoteName( rCalcName ) ), + mnCalcSheet( nCalcSheet ) +{ +} + +WorksheetBuffer::IndexNamePair WorksheetBuffer::createSheet( const OUString& rPreferredName, sal_Int32 nSheetPos, bool bVisible ) { - IndexNamePair aIndexName; - aIndexName.first = -1; - aIndexName.second = (rPreferredName.getLength() == 0) ? CREATE_OUSTRING( "Sheet" ) : rPreferredName; try { Reference< XSpreadsheets > xSheets( getDocument()->getSheets(), UNO_QUERY_THROW ); Reference< XIndexAccess > xSheetsIA( xSheets, UNO_QUERY_THROW ); Reference< XNameAccess > xSheetsNA( xSheets, UNO_QUERY_THROW ); + sal_Int16 nCalcSheet = -1; + OUString aSheetName = (rPreferredName.getLength() == 0) ? CREATE_OUSTRING( "Sheet" ) : rPreferredName; PropertySet aPropSet; - if( nSheet < xSheetsIA->getCount() ) + if( nSheetPos < xSheetsIA->getCount() ) { + nCalcSheet = static_cast< sal_Int16 >( nSheetPos ); // existing sheet - try to rename - Reference< XNamed > xSheetName( xSheetsIA->getByIndex( nSheet ), UNO_QUERY_THROW ); - if( xSheetName->getName() != aIndexName.second ) + Reference< XNamed > xSheetName( xSheetsIA->getByIndex( nSheetPos ), UNO_QUERY_THROW ); + if( xSheetName->getName() != aSheetName ) { - aIndexName.second = ContainerHelper::getUnusedName( xSheetsNA, aIndexName.second, ' ' ); - xSheetName->setName( aIndexName.second ); + aSheetName = ContainerHelper::getUnusedName( xSheetsNA, aSheetName, ' ' ); + xSheetName->setName( aSheetName ); } aPropSet.set( xSheetName ); } else { + nCalcSheet = static_cast< sal_Int16 >( xSheetsIA->getCount() ); // new sheet - insert with unused name - aIndexName.second = ContainerHelper::getUnusedName( xSheetsNA, aIndexName.second, ' ' ); - nSheet = static_cast< sal_Int16 >( xSheetsIA->getCount() ); - xSheets->insertNewByName( aIndexName.second, nSheet ); - aPropSet.set( xSheetsIA->getByIndex( nSheet ) ); + aSheetName = ContainerHelper::getUnusedName( xSheetsNA, aSheetName, ' ' ); + xSheets->insertNewByName( aSheetName, nCalcSheet ); + aPropSet.set( xSheetsIA->getByIndex( nCalcSheet ) ); } // sheet properties aPropSet.setProperty( PROP_IsVisible, bVisible ); // return final sheet index if sheet exists - aIndexName.first = nSheet; + return IndexNamePair( nCalcSheet, aSheetName ); } catch( Exception& ) { - OSL_ENSURE( false, "WorksheetBuffer::insertSheet - cannot insert or rename worksheet" ); + OSL_ENSURE( false, "WorksheetBuffer::createSheet - cannot insert or rename worksheet" ); } - return aIndexName; + return IndexNamePair( -1, OUString() ); } void WorksheetBuffer::insertSheet( const SheetInfoModel& rModel ) { - sal_Int16 nSheet = static_cast< sal_Int16 >( maSheetInfos.size() ); - maSheetInfos.push_back( rModel ); - IndexNamePair aIndexName = insertSheet( rModel.maName, nSheet, rModel.mnState == XML_visible ); - if( aIndexName.first >= 0 ) - maSheetInfos.back().maFinalName = aIndexName.second; + sal_Int32 nWorksheet = static_cast< sal_Int32 >( maSheetInfos.size() ); + IndexNamePair aIndexName = createSheet( rModel.maName, nWorksheet, rModel.mnState == XML_visible ); + ::boost::shared_ptr< SheetInfo > xSheetInfo( new SheetInfo( rModel, aIndexName.first, aIndexName.second ) ); + maSheetInfos.push_back( xSheetInfo ); + maSheetInfosByName[ rModel.maName ] = xSheetInfo; + maSheetInfosByName[ lclQuoteName( rModel.maName ) ] = xSheetInfo; +} + +bool WorksheetBuffer::SheetNameCompare::operator()( const OUString& rName1, const OUString& rName2 ) const +{ + // there is no wrapper in rtl::OUString, TODO: compare with collator + return ::rtl_ustr_compareIgnoreAsciiCase_WithLength( + rName1.getStr(), rName1.getLength(), rName2.getStr(), rName2.getLength() ) < 0; } // ============================================================================ diff --git a/oox/source/xls/worksheetfragment.cxx b/oox/source/xls/worksheetfragment.cxx index 4b754114b031..ed8907cb5f03 100644 --- a/oox/source/xls/worksheetfragment.cxx +++ b/oox/source/xls/worksheetfragment.cxx @@ -228,7 +228,7 @@ void OoxDataValidationsContext::importDataValidation( RecordInputStream& rStrm ) // ============================================================================ OoxWorksheetFragment::OoxWorksheetFragment( const WorkbookHelper& rHelper, - const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) : + const OUString& rFragmentPath, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) : OoxWorksheetFragmentBase( rHelper, rFragmentPath, xProgressBar, eSheetType, nSheet ) { // import data tables related to this worksheet @@ -741,7 +741,7 @@ void OoxWorksheetFragment::importEmbeddedOleData( StreamDataSequence& orEmbedded // ============================================================================ -BiffWorksheetFragment::BiffWorksheetFragment( const BiffWorkbookFragmentBase& rParent, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) : +BiffWorksheetFragment::BiffWorksheetFragment( const BiffWorkbookFragmentBase& rParent, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) : BiffWorksheetFragmentBase( rParent, xProgressBar, eSheetType, nSheet ) { } diff --git a/oox/source/xls/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx index be8ac3d359db..ab2d5c1b1946 100644 --- a/oox/source/xls/worksheethelper.cxx +++ b/oox/source/xls/worksheethelper.cxx @@ -362,7 +362,7 @@ public: const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, - sal_Int32 nSheet ); + sal_Int16 nSheet ); /** Returns true, if this helper refers to an existing Calc sheet. */ inline bool isValidSheet() const { return mxSheet.is(); } @@ -522,8 +522,10 @@ private: /** Inserts all imported hyperlinks into their cell ranges. */ void finalizeHyperlinkRanges() const; + /** Generates the final URL for the passed hyperlink. */ + OUString getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const; /** Inserts a hyperlinks into the specified cell. */ - void finalizeHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const; + void insertHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const; /** Inserts all imported data validations into their cell ranges. */ void finalizeValidationRanges() const; @@ -593,7 +595,7 @@ private: // ---------------------------------------------------------------------------- -WorksheetData::WorksheetData( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) : +WorksheetData::WorksheetData( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) : WorkbookHelper( rHelper ), maTrueFormula( CREATE_OUSTRING( "=TRUE()" ) ), maFalseFormula( CREATE_OUSTRING( "=FALSE()" ) ), @@ -608,10 +610,9 @@ WorksheetData::WorksheetData( const WorkbookHelper& rHelper, ISegmentProgressBar maSheetViewSett( *this ), mxProgressBar( xProgressBar ), meSheetType( eSheetType ), - mnSheet( static_cast< sal_Int16 >( nSheet ) ), + mnSheet( nSheet ), mbHasDefWidth( false ) { - OSL_ENSURE( nSheet <= SAL_MAX_INT16, "WorksheetData::WorksheetData - invalid sheet index" ); mxSheet = getSheetFromDoc( nSheet ); if( !mxSheet.is() ) mnSheet = -1; @@ -978,14 +979,11 @@ void WorksheetData::convertRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, s void WorksheetData::initializeWorksheetImport() { -#if OOX_XLS_USE_DEFAULT_STYLE -#else // set default cell style for unused cells PropertySet aPropSet( mxSheet ); aPropSet.setProperty( PROP_CellStyle, getStyles().getDefaultStyleName() ); -#endif - /* remember current sheet index in global data, needed by some global + /* Remember current sheet index in global data, needed by some global objects, e.g. the chart converter. */ setCurrentSheetIndex( mnSheet ); } @@ -1006,9 +1004,9 @@ void WorksheetData::finalizeWorksheetImport() convertColumns(); convertRows(); lclUpdateProgressBar( mxFinalProgress, 0.75 ); - maComments.finalizeImport(); finalizeDrawing(); finalizeVmlDrawing(); + maComments.finalizeImport(); // after VML drawing lclUpdateProgressBar( mxFinalProgress, 1.0 ); // reset current sheet index in global data @@ -1169,42 +1167,44 @@ void WorksheetData::finalizeHyperlinkRanges() const { for( HyperlinkModelList::const_iterator aIt = maHyperlinks.begin(), aEnd = maHyperlinks.end(); aIt != aEnd; ++aIt ) { - OUStringBuffer aUrlBuffer; - if( aIt->maTarget.getLength() > 0 ) - aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( aIt->maTarget ) ); - if( aIt->maLocation.getLength() > 0 ) - aUrlBuffer.append( sal_Unicode( '#' ) ).append( aIt->maLocation ); - OUString aUrl = aUrlBuffer.makeStringAndClear(); + OUString aUrl = getHyperlinkUrl( *aIt ); + // try to insert URL into each cell of the range if( aUrl.getLength() > 0 ) - { - // convert '#SheetName!A1' to '#SheetName.A1' - if( aUrl[ 0 ] == '#' ) - { - sal_Int32 nSepPos = aUrl.lastIndexOf( '!' ); - if( nSepPos > 0 ) - { - // replace the exclamation mark with a period - aUrl = aUrl.replaceAt( nSepPos, 1, OUString( sal_Unicode( '.' ) ) ); - // #i66592# convert sheet names that have been renamed on import - bool bQuotedName = (nSepPos > 3) && (aUrl[ 1 ] == '\'') && (aUrl[ nSepPos - 1 ] == '\''); - sal_Int32 nNamePos = bQuotedName ? 2 : 1; - sal_Int32 nNameLen = nSepPos - (bQuotedName ? 3 : 1); - OUString aSheetName = aUrl.copy( nNamePos, nNameLen ); - OUString aCalcName = getWorksheets().getCalcSheetName( aSheetName ); - if( aCalcName.getLength() > 0 ) - aUrl = aUrl.replaceAt( nNamePos, nNameLen, aCalcName ); - } - } - - // try to insert URL into each cell of the range for( CellAddress aAddress( mnSheet, aIt->maRange.StartColumn, aIt->maRange.StartRow ); aAddress.Row <= aIt->maRange.EndRow; ++aAddress.Row ) for( aAddress.Column = aIt->maRange.StartColumn; aAddress.Column <= aIt->maRange.EndColumn; ++aAddress.Column ) - finalizeHyperlink( aAddress, aUrl ); + insertHyperlink( aAddress, aUrl ); + } +} + +OUString WorksheetData::getHyperlinkUrl( const HyperlinkModel& rHyperlink ) const +{ + OUStringBuffer aUrlBuffer; + if( rHyperlink.maTarget.getLength() > 0 ) + aUrlBuffer.append( getBaseFilter().getAbsoluteUrl( rHyperlink.maTarget ) ); + if( rHyperlink.maLocation.getLength() > 0 ) + aUrlBuffer.append( sal_Unicode( '#' ) ).append( rHyperlink.maLocation ); + OUString aUrl = aUrlBuffer.makeStringAndClear(); + + // convert '#SheetName!A1' to '#SheetName.A1' + if( (aUrl.getLength() > 0) && (aUrl[ 0 ] == '#') ) + { + sal_Int32 nSepPos = aUrl.lastIndexOf( '!' ); + if( nSepPos > 0 ) + { + // replace the exclamation mark with a period + aUrl = aUrl.replaceAt( nSepPos, 1, OUString( sal_Unicode( '.' ) ) ); + // #i66592# convert sheet names that have been renamed on import + OUString aSheetName = aUrl.copy( 1, nSepPos - 1 ); + OUString aCalcName = getWorksheets().getCalcSheetName( aSheetName ); + if( aCalcName.getLength() > 0 ) + aUrl = aUrl.replaceAt( 1, nSepPos - 1, aCalcName ); } } + + return aUrl; } -void WorksheetData::finalizeHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const +void WorksheetData::insertHyperlink( const CellAddress& rAddress, const OUString& rUrl ) const { Reference< XCell > xCell = getCell( rAddress ); if( xCell.is() ) switch( xCell->getType() ) @@ -1217,7 +1217,7 @@ void WorksheetData::finalizeHyperlink( const CellAddress& rAddress, const OUStri { // create a URL field object and set its properties Reference< XTextContent > xUrlField( getDocumentFactory()->createInstance( maUrlTextField ), UNO_QUERY ); - OSL_ENSURE( xUrlField.is(), "WorksheetData::finalizeHyperlink - cannot create text field" ); + OSL_ENSURE( xUrlField.is(), "WorksheetData::insertHyperlink - cannot create text field" ); if( xUrlField.is() ) { // properties of the URL field @@ -1233,7 +1233,7 @@ void WorksheetData::finalizeHyperlink( const CellAddress& rAddress, const OUStri } catch( const Exception& ) { - OSL_ENSURE( false, "WorksheetData::finalizeHyperlink - cannot insert text field" ); + OSL_ENSURE( false, "WorksheetData::insertHyperlink - cannot insert text field" ); } } } @@ -1246,7 +1246,7 @@ void WorksheetData::finalizeHyperlink( const CellAddress& rAddress, const OUStri case ::com::sun::star::table::CellContentType_VALUE: { Reference< XFormulaTokens > xTokens( xCell, UNO_QUERY ); - OSL_ENSURE( xTokens.is(), "WorksheetHelper::finalizeHyperlink - missing formula interface" ); + OSL_ENSURE( xTokens.is(), "WorksheetHelper::insertHyperlink - missing formula interface" ); if( xTokens.is() ) { SimpleFormulaContext aContext( xTokens, false, false ); @@ -2072,7 +2072,7 @@ WorksheetDataOwner::~WorksheetDataOwner() // ---------------------------------------------------------------------------- -WorksheetHelperRoot::WorksheetHelperRoot( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int32 nSheet ) : +WorksheetHelperRoot::WorksheetHelperRoot( const WorkbookHelper& rHelper, ISegmentProgressBarRef xProgressBar, WorksheetType eSheetType, sal_Int16 nSheet ) : prv::WorksheetDataOwner( prv::WorksheetDataRef( new WorksheetData( rHelper, xProgressBar, eSheetType, nSheet ) ) ), WorksheetHelper( *mxSheetData ) { |