/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ #include #define _ZFORLIST_DECLARE_TABLE #include #include #include #include #include #include #include #include #include #include #include "xmloff/xmlnmspe.hxx" #include #include #include #include #include #include using ::rtl::OUString; using ::rtl::OUStringBuffer; using namespace ::com::sun::star; using namespace ::xmloff::token; //------------------------------------------------------------------------- struct SvXMLNumFmtEntry { rtl::OUString aName; sal_uInt32 nKey; sal_Bool bRemoveAfterUse; SvXMLNumFmtEntry( const rtl::OUString& rN, sal_uInt32 nK, sal_Bool bR ) : aName(rN), nKey(nK), bRemoveAfterUse(bR) {} }; typedef SvXMLNumFmtEntry* SvXMLNumFmtEntryPtr; SV_DECL_PTRARR_DEL( SvXMLNumFmtEntryArr, SvXMLNumFmtEntryPtr, 4, 4 ) struct SvXMLEmbeddedElement { sal_Int32 nFormatPos; rtl::OUString aText; SvXMLEmbeddedElement( sal_Int32 nFP, const rtl::OUString& rT ) : nFormatPos(nFP), aText(rT) {} // comparison operators for PTRARR sorting - sorted by position sal_Bool operator ==( const SvXMLEmbeddedElement& r ) const { return nFormatPos == r.nFormatPos; } sal_Bool operator < ( const SvXMLEmbeddedElement& r ) const { return nFormatPos < r.nFormatPos; } }; typedef SvXMLEmbeddedElement* SvXMLEmbeddedElementPtr; SV_DECL_PTRARR_SORT_DEL( SvXMLEmbeddedElementArr, SvXMLEmbeddedElementPtr, 0, 4 ) //------------------------------------------------------------------------- class SvXMLNumImpData { SvNumberFormatter* pFormatter; SvXMLTokenMap* pStylesElemTokenMap; SvXMLTokenMap* pStyleElemTokenMap; SvXMLTokenMap* pStyleAttrTokenMap; SvXMLTokenMap* pStyleElemAttrTokenMap; LocaleDataWrapper* pLocaleData; SvXMLNumFmtEntryArr aNameEntries; ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxServiceFactory; public: SvXMLNumImpData( SvNumberFormatter* pFmt, const uno::Reference& xServiceFactory ); ~SvXMLNumImpData(); SvNumberFormatter* GetNumberFormatter() const { return pFormatter; } const SvXMLTokenMap& GetStylesElemTokenMap(); const SvXMLTokenMap& GetStyleElemTokenMap(); const SvXMLTokenMap& GetStyleAttrTokenMap(); const SvXMLTokenMap& GetStyleElemAttrTokenMap(); const LocaleDataWrapper& GetLocaleData( LanguageType nLang ); sal_uInt32 GetKeyForName( const rtl::OUString& rName ); void AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse ); void SetUsed( sal_uInt32 nKey ); void RemoveVolatileFormats(); }; struct SvXMLNumberInfo { sal_Int32 nDecimals; sal_Int32 nInteger; sal_Int32 nExpDigits; sal_Int32 nNumerDigits; sal_Int32 nDenomDigits; sal_Bool bGrouping; sal_Bool bDecReplace; sal_Bool bVarDecimals; double fDisplayFactor; SvXMLEmbeddedElementArr aEmbeddedElements; SvXMLNumberInfo() { nDecimals = nInteger = nExpDigits = nNumerDigits = nDenomDigits = -1; bGrouping = bDecReplace = bVarDecimals = sal_False; fDisplayFactor = 1.0; } }; class SvXMLNumFmtElementContext : public SvXMLImportContext { SvXMLNumFormatContext& rParent; sal_uInt16 nType; rtl::OUStringBuffer aContent; SvXMLNumberInfo aNumInfo; LanguageType nElementLang; sal_Bool bLong; sal_Bool bTextual; rtl::OUString sCalendar; public: SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual ~SvXMLNumFmtElementContext(); virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, const rtl::OUString& rLocalName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual void Characters( const rtl::OUString& rChars ); virtual void EndElement(); void AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent ); }; class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext { SvXMLNumFmtElementContext& rParent; rtl::OUStringBuffer aContent; sal_Int32 nTextPosition; public: SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFmtElementContext& rParentContext, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual ~SvXMLNumFmtEmbeddedTextContext(); virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, const rtl::OUString& rLocalName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual void Characters( const rtl::OUString& rChars ); virtual void EndElement(); }; class SvXMLNumFmtMapContext : public SvXMLImportContext { SvXMLNumFormatContext& rParent; rtl::OUString sCondition; rtl::OUString sName; public: SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFormatContext& rParentContext, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual ~SvXMLNumFmtMapContext(); virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, const rtl::OUString& rLocalName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual void Characters( const rtl::OUString& rChars ); virtual void EndElement(); }; class SvXMLNumFmtPropContext : public SvXMLImportContext { SvXMLNumFormatContext& rParent; sal_Int32 m_nColor; sal_Bool bColSet; public: SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFormatContext& rParentContext, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual ~SvXMLNumFmtPropContext(); virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, const rtl::OUString& rLocalName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); virtual void Characters( const rtl::OUString& rChars ); virtual void EndElement(); }; //------------------------------------------------------------------------- enum SvXMLStyleTokens { XML_TOK_STYLE_TEXT, XML_TOK_STYLE_NUMBER, XML_TOK_STYLE_SCIENTIFIC_NUMBER, XML_TOK_STYLE_FRACTION, XML_TOK_STYLE_CURRENCY_SYMBOL, XML_TOK_STYLE_DAY, XML_TOK_STYLE_MONTH, XML_TOK_STYLE_YEAR, XML_TOK_STYLE_ERA, XML_TOK_STYLE_DAY_OF_WEEK, XML_TOK_STYLE_WEEK_OF_YEAR, XML_TOK_STYLE_QUARTER, XML_TOK_STYLE_HOURS, XML_TOK_STYLE_AM_PM, XML_TOK_STYLE_MINUTES, XML_TOK_STYLE_SECONDS, XML_TOK_STYLE_BOOLEAN, XML_TOK_STYLE_TEXT_CONTENT, XML_TOK_STYLE_PROPERTIES, XML_TOK_STYLE_MAP }; enum SvXMLStyleAttrTokens { XML_TOK_STYLE_ATTR_NAME, XML_TOK_STYLE_ATTR_LANGUAGE, XML_TOK_STYLE_ATTR_COUNTRY, XML_TOK_STYLE_ATTR_TITLE, XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER, XML_TOK_STYLE_ATTR_FORMAT_SOURCE, XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW, XML_TOK_STYLE_ATTR_VOLATILE, XML_TOK_STYLE_ATTR_TRANSL_FORMAT, XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE, XML_TOK_STYLE_ATTR_TRANSL_COUNTRY, XML_TOK_STYLE_ATTR_TRANSL_STYLE }; enum SvXMLStyleElemAttrTokens { XML_TOK_ELEM_ATTR_DECIMAL_PLACES, XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS, XML_TOK_ELEM_ATTR_GROUPING, XML_TOK_ELEM_ATTR_DISPLAY_FACTOR, XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT, XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS, XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS, XML_TOK_ELEM_ATTR_LANGUAGE, XML_TOK_ELEM_ATTR_COUNTRY, XML_TOK_ELEM_ATTR_STYLE, XML_TOK_ELEM_ATTR_TEXTUAL, XML_TOK_ELEM_ATTR_CALENDAR }; //------------------------------------------------------------------------- // // standard colors // #define XML_NUMF_COLORCOUNT 10 static ColorData aNumFmtStdColors[XML_NUMF_COLORCOUNT] = { COL_BLACK, COL_LIGHTBLUE, COL_LIGHTGREEN, COL_LIGHTCYAN, COL_LIGHTRED, COL_LIGHTMAGENTA, COL_BROWN, COL_GRAY, COL_YELLOW, COL_WHITE }; // // token maps // // maps for SvXMLUnitConverter::convertEnum static SvXMLEnumMapEntry aStyleValueMap[] = { { XML_SHORT, sal_False }, { XML_LONG, sal_True }, { XML_TOKEN_INVALID, 0 } }; static SvXMLEnumMapEntry aFormatSourceMap[] = { { XML_FIXED, sal_False }, { XML_LANGUAGE, sal_True }, { XML_TOKEN_INVALID, 0 } }; //------------------------------------------------------------------------- struct SvXMLDefaultDateFormat { NfIndexTableOffset eFormat; SvXMLDateElementAttributes eDOW; SvXMLDateElementAttributes eDay; SvXMLDateElementAttributes eMonth; SvXMLDateElementAttributes eYear; SvXMLDateElementAttributes eHours; SvXMLDateElementAttributes eMins; SvXMLDateElementAttributes eSecs; sal_Bool bSystem; }; static SvXMLDefaultDateFormat aDefaultDateFormats[] = { // format day-of-week day month year hours minutes seconds format-source { NF_DATE_SYSTEM_SHORT, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_True }, { NF_DATE_SYSTEM_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_True }, { NF_DATE_SYS_MMYY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_DDMMM, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_TEXTSHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_DDMMYYYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_DDMMYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_DMMMYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_DMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_DMMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_NNDMMMYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_NNDMMMMYYYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATE_SYS_NNNNDMMMMYYYY, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, sal_False }, { NF_DATETIME_SYSTEM_SHORT_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, sal_True }, { NF_DATETIME_SYS_DDMMYYYY_HHMMSS, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, sal_False } }; //------------------------------------------------------------------------- SV_IMPL_PTRARR( SvXMLNumFmtEntryArr, SvXMLNumFmtEntryPtr ); SV_IMPL_OP_PTRARR_SORT( SvXMLEmbeddedElementArr, SvXMLEmbeddedElementPtr ); //------------------------------------------------------------------------- // // SvXMLNumImpData // SvXMLNumImpData::SvXMLNumImpData( SvNumberFormatter* pFmt, const uno::Reference& xServiceFactory ) : pFormatter(pFmt), pStylesElemTokenMap(NULL), pStyleElemTokenMap(NULL), pStyleAttrTokenMap(NULL), pStyleElemAttrTokenMap(NULL), pLocaleData(NULL), mxServiceFactory(xServiceFactory) { DBG_ASSERT( mxServiceFactory.is(), "got no service manager" ); } SvXMLNumImpData::~SvXMLNumImpData() { delete pStylesElemTokenMap; delete pStyleElemTokenMap; delete pStyleAttrTokenMap; delete pStyleElemAttrTokenMap; delete pLocaleData; } sal_uInt32 SvXMLNumImpData::GetKeyForName( const rtl::OUString& rName ) { sal_uInt16 nCount = aNameEntries.Count(); for (sal_uInt16 i=0; iaName == rName ) return pObj->nKey; // found } return NUMBERFORMAT_ENTRY_NOT_FOUND; } void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse ) { if ( bRemoveAfterUse ) { // if there is already an entry for this key without the bRemoveAfterUse flag, // clear the flag for this entry, too sal_uInt16 nCount = aNameEntries.Count(); for (sal_uInt16 i=0; inKey == nKey && !pObj->bRemoveAfterUse ) { bRemoveAfterUse = sal_False; // clear flag for new entry break; } } } else { // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key SetUsed( nKey ); } SvXMLNumFmtEntry* pObj = new SvXMLNumFmtEntry( rName, nKey, bRemoveAfterUse ); aNameEntries.Insert( pObj, aNameEntries.Count() ); } void SvXMLNumImpData::SetUsed( sal_uInt32 nKey ) { sal_uInt16 nCount = aNameEntries.Count(); for (sal_uInt16 i=0; inKey == nKey ) { pObj->bRemoveAfterUse = sal_False; // used -> don't remove // continue searching - there may be several entries for the same key // (with different names), the format must not be deleted if any one of // them is used } } } void SvXMLNumImpData::RemoveVolatileFormats() { // remove temporary (volatile) formats from NumberFormatter // called at the end of each import (styles and content), so volatile formats // from styles can't be used in content if ( !pFormatter ) return; sal_uInt16 nCount = aNameEntries.Count(); for (sal_uInt16 i=0; ibRemoveAfterUse ) { const SvNumberformat* pFormat = pFormatter->GetEntry(pObj->nKey); if (pFormat && (pFormat->GetType() & NUMBERFORMAT_DEFINED)) pFormatter->DeleteEntry( pObj->nKey ); } } } const SvXMLTokenMap& SvXMLNumImpData::GetStylesElemTokenMap() { if( !pStylesElemTokenMap ) { static SvXMLTokenMapEntry aStylesElemMap[] = { // style elements { XML_NAMESPACE_NUMBER, XML_NUMBER_STYLE, XML_TOK_STYLES_NUMBER_STYLE }, { XML_NAMESPACE_NUMBER, XML_CURRENCY_STYLE, XML_TOK_STYLES_CURRENCY_STYLE }, { XML_NAMESPACE_NUMBER, XML_PERCENTAGE_STYLE, XML_TOK_STYLES_PERCENTAGE_STYLE }, { XML_NAMESPACE_NUMBER, XML_DATE_STYLE, XML_TOK_STYLES_DATE_STYLE }, { XML_NAMESPACE_NUMBER, XML_TIME_STYLE, XML_TOK_STYLES_TIME_STYLE }, { XML_NAMESPACE_NUMBER, XML_BOOLEAN_STYLE, XML_TOK_STYLES_BOOLEAN_STYLE }, { XML_NAMESPACE_NUMBER, XML_TEXT_STYLE, XML_TOK_STYLES_TEXT_STYLE }, XML_TOKEN_MAP_END }; pStylesElemTokenMap = new SvXMLTokenMap( aStylesElemMap ); } return *pStylesElemTokenMap; } const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemTokenMap() { if( !pStyleElemTokenMap ) { static SvXMLTokenMapEntry aStyleElemMap[] = { // elements in a style { XML_NAMESPACE_NUMBER, XML_TEXT, XML_TOK_STYLE_TEXT }, { XML_NAMESPACE_NUMBER, XML_NUMBER, XML_TOK_STYLE_NUMBER }, { XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER, XML_TOK_STYLE_SCIENTIFIC_NUMBER }, { XML_NAMESPACE_NUMBER, XML_FRACTION, XML_TOK_STYLE_FRACTION }, { XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL, XML_TOK_STYLE_CURRENCY_SYMBOL }, { XML_NAMESPACE_NUMBER, XML_DAY, XML_TOK_STYLE_DAY }, { XML_NAMESPACE_NUMBER, XML_MONTH, XML_TOK_STYLE_MONTH }, { XML_NAMESPACE_NUMBER, XML_YEAR, XML_TOK_STYLE_YEAR }, { XML_NAMESPACE_NUMBER, XML_ERA, XML_TOK_STYLE_ERA }, { XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK, XML_TOK_STYLE_DAY_OF_WEEK }, { XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR, XML_TOK_STYLE_WEEK_OF_YEAR }, { XML_NAMESPACE_NUMBER, XML_QUARTER, XML_TOK_STYLE_QUARTER }, { XML_NAMESPACE_NUMBER, XML_HOURS, XML_TOK_STYLE_HOURS }, { XML_NAMESPACE_NUMBER, XML_AM_PM, XML_TOK_STYLE_AM_PM }, { XML_NAMESPACE_NUMBER, XML_MINUTES, XML_TOK_STYLE_MINUTES }, { XML_NAMESPACE_NUMBER, XML_SECONDS, XML_TOK_STYLE_SECONDS }, { XML_NAMESPACE_NUMBER, XML_BOOLEAN, XML_TOK_STYLE_BOOLEAN }, { XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT, XML_TOK_STYLE_TEXT_CONTENT }, { XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES, XML_TOK_STYLE_PROPERTIES }, { XML_NAMESPACE_STYLE, XML_MAP, XML_TOK_STYLE_MAP }, XML_TOKEN_MAP_END }; pStyleElemTokenMap = new SvXMLTokenMap( aStyleElemMap ); } return *pStyleElemTokenMap; } const SvXMLTokenMap& SvXMLNumImpData::GetStyleAttrTokenMap() { if( !pStyleAttrTokenMap ) { static SvXMLTokenMapEntry aStyleAttrMap[] = { // attributes for a style { XML_NAMESPACE_STYLE, XML_NAME, XML_TOK_STYLE_ATTR_NAME }, { XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_STYLE_ATTR_LANGUAGE }, { XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_STYLE_ATTR_COUNTRY }, { XML_NAMESPACE_NUMBER, XML_TITLE, XML_TOK_STYLE_ATTR_TITLE }, { XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER }, { XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE, XML_TOK_STYLE_ATTR_FORMAT_SOURCE }, { XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW, XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW }, { XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TOK_STYLE_ATTR_VOLATILE }, { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT, XML_TOK_STYLE_ATTR_TRANSL_FORMAT }, { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE }, { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, XML_TOK_STYLE_ATTR_TRANSL_COUNTRY }, { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE, XML_TOK_STYLE_ATTR_TRANSL_STYLE }, XML_TOKEN_MAP_END }; pStyleAttrTokenMap = new SvXMLTokenMap( aStyleAttrMap ); } return *pStyleAttrTokenMap; } const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemAttrTokenMap() { if( !pStyleElemAttrTokenMap ) { static SvXMLTokenMapEntry aStyleElemAttrMap[] = { // attributes for an element within a style { XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, XML_TOK_ELEM_ATTR_DECIMAL_PLACES }, { XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS }, { XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TOK_ELEM_ATTR_GROUPING }, { XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, XML_TOK_ELEM_ATTR_DISPLAY_FACTOR }, { XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT }, { XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS, XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS }, { XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS }, { XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS }, { XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_ELEM_ATTR_LANGUAGE }, { XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_ELEM_ATTR_COUNTRY }, { XML_NAMESPACE_NUMBER, XML_STYLE, XML_TOK_ELEM_ATTR_STYLE }, { XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TOK_ELEM_ATTR_TEXTUAL }, { XML_NAMESPACE_NUMBER, XML_CALENDAR, XML_TOK_ELEM_ATTR_CALENDAR }, XML_TOKEN_MAP_END }; pStyleElemAttrTokenMap = new SvXMLTokenMap( aStyleElemAttrMap ); } return *pStyleElemAttrTokenMap; } const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang ) { if ( !pLocaleData ) pLocaleData = new LocaleDataWrapper( (pFormatter ? pFormatter->GetServiceManager() : mxServiceFactory), MsLangId::convertLanguageToLocale( nLang ) ); else pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) ); return *pLocaleData; } //------------------------------------------------------------------------- // // SvXMLNumFmtMapContext // SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFormatContext& rParentContext, const uno::Reference& xAttrList ) : SvXMLImportContext( rImport, nPrfx, rLName ), rParent( rParentContext ) { sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for( sal_Int16 i=0; i < nAttrCount; i++ ) { OUString sAttrName = xAttrList->getNameByIndex( i ); OUString sValue = xAttrList->getValueByIndex( i ); OUString aLocalName; sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); if ( nPrefix == XML_NAMESPACE_STYLE ) { if ( IsXMLToken( aLocalName, XML_CONDITION) ) sCondition = sValue; else if ( IsXMLToken( aLocalName, XML_APPLY_STYLE_NAME) ) sName = sValue; } } } SvXMLNumFmtMapContext::~SvXMLNumFmtMapContext() { } SvXMLImportContext* SvXMLNumFmtMapContext::CreateChildContext( sal_uInt16 nPrfx, const rtl::OUString& rLName, const uno::Reference& ) { // no elements supported - use default context return new SvXMLImportContext( GetImport(), nPrfx, rLName ); } void SvXMLNumFmtMapContext::Characters( const rtl::OUString& ) { } void SvXMLNumFmtMapContext::EndElement() { rParent.AddCondition( sCondition, sName ); } //------------------------------------------------------------------------- // // SvXMLNumFmtPropContext // SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFormatContext& rParentContext, const uno::Reference& xAttrList ) : SvXMLImportContext( rImport, nPrfx, rLName ), rParent( rParentContext ), bColSet( sal_False ) { sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for( sal_Int16 i=0; i < nAttrCount; i++ ) { OUString sAttrName = xAttrList->getNameByIndex( i ); OUString sValue = xAttrList->getValueByIndex( i ); OUString aLocalName; sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); if ( nPrefix == XML_NAMESPACE_FO && IsXMLToken( aLocalName, XML_COLOR ) ) { bColSet = ::sax::Converter::convertColor( m_nColor, sValue ); } } } SvXMLNumFmtPropContext::~SvXMLNumFmtPropContext() { } SvXMLImportContext* SvXMLNumFmtPropContext::CreateChildContext( sal_uInt16 nPrfx, const rtl::OUString& rLName, const uno::Reference& ) { // no elements supported - use default context return new SvXMLImportContext( GetImport(), nPrfx, rLName ); } void SvXMLNumFmtPropContext::Characters( const rtl::OUString& ) { } void SvXMLNumFmtPropContext::EndElement() { if (bColSet) rParent.AddColor( m_nColor ); } //------------------------------------------------------------------------- // // SvXMLNumFmtEmbeddedTextContext // SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFmtElementContext& rParentContext, const uno::Reference& xAttrList ) : SvXMLImportContext( rImport, nPrfx, rLName ), rParent( rParentContext ), nTextPosition( 0 ) { sal_Int32 nAttrVal; sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for( sal_Int16 i=0; i < nAttrCount; i++ ) { OUString sAttrName = xAttrList->getNameByIndex( i ); OUString sValue = xAttrList->getValueByIndex( i ); OUString aLocalName; sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); if ( nPrefix == XML_NAMESPACE_NUMBER && IsXMLToken( aLocalName, XML_POSITION ) ) { if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) nTextPosition = nAttrVal; } } } SvXMLNumFmtEmbeddedTextContext::~SvXMLNumFmtEmbeddedTextContext() { } SvXMLImportContext* SvXMLNumFmtEmbeddedTextContext::CreateChildContext( sal_uInt16 nPrfx, const rtl::OUString& rLName, const uno::Reference& ) { // no elements supported - use default context return new SvXMLImportContext( GetImport(), nPrfx, rLName ); } void SvXMLNumFmtEmbeddedTextContext::Characters( const rtl::OUString& rChars ) { aContent.append( rChars ); } void SvXMLNumFmtEmbeddedTextContext::EndElement() { rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() ); } //------------------------------------------------------------------------- sal_Bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent ) { sal_uInt16 nFormatType = rParent.GetType(); // Treat space equal to non-breaking space separator. const sal_Unicode cNBSP = 0x00A0; sal_Unicode cTS; if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE || nFormatType == XML_TOK_STYLES_CURRENCY_STYLE || nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) && (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep().GetChar(0)) || (cChar == ' ' && cTS == cNBSP)) ) { // #i22394# Extra occurrences of thousands separator must be quoted, so they // aren't mis-interpreted as display-factor. // This must be limited to the format types that can contain a number element, // because the same character can be a date separator that should not be quoted // in date formats. return sal_False; // force quotes } // see ImpSvNumberformatScan::Next_Symbol if ( cChar == ' ' || cChar == '-' || cChar == '/' || cChar == '.' || cChar == ',' || cChar == ':' || cChar == '\'' ) return sal_True; // for all format types // percent sign must be used without quotes for percentage styles only if ( nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE && cChar == '%' ) return sal_True; // don't put quotes around single parentheses (often used for negative numbers) if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE || nFormatType == XML_TOK_STYLES_CURRENCY_STYLE || nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) && ( cChar == '(' || cChar == ')' ) ) return sal_True; return sal_False; } void lcl_EnquoteIfNecessary( rtl::OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent ) { sal_Bool bQuote = sal_True; sal_Int32 nLength = rContent.getLength(); if ( ( nLength == 1 && lcl_ValidChar( rContent.charAt(0), rParent ) ) || ( nLength == 2 && lcl_ValidChar( rContent.charAt(0), rParent ) && rContent.charAt(1) == ' ' ) ) { // don't quote single separator characters like space or percent, // or separator characters followed by space (used in date formats) bQuote = sal_False; } else if ( rParent.GetType() == XML_TOK_STYLES_PERCENTAGE_STYLE && nLength > 1 ) { // the percent character in percentage styles must be left out of quoting // (one occurrence is enough even if there are several percent characters in the string) rtl::OUString aString( rContent.getStr() ); sal_Int32 nPos = aString.indexOf( (sal_Unicode) '%' ); if ( nPos >= 0 ) { if ( nPos + 1 < nLength ) { if ( nPos + 2 == nLength && lcl_ValidChar( rContent.charAt(nPos + 1), rParent ) ) { // single character that doesn't need quoting } else { // quote text behind percent character rContent.insert( nPos + 1, (sal_Unicode) '"' ); rContent.append( (sal_Unicode) '"' ); } } if ( nPos > 0 ) { if ( nPos == 1 && lcl_ValidChar( rContent.charAt(0), rParent ) ) { // single character that doesn't need quoting } else { // quote text before percent character rContent.insert( nPos, (sal_Unicode) '"' ); rContent.insert( 0, (sal_Unicode) '"' ); } } bQuote = sal_False; } // else: normal quoting (below) } if ( bQuote ) { // #i55469# quotes in the string itself have to be escaped rtl::OUString aString( rContent.getStr() ); bool bEscape = ( aString.indexOf( (sal_Unicode) '"' ) >= 0 ); if ( bEscape ) { // A quote is turned into "\"" - a quote to end quoted text, an escaped quote, // and a quote to resume quoting. rtl::OUString aInsert( RTL_CONSTASCII_USTRINGPARAM( "\"\\\"" ) ); sal_Int32 nPos = 0; while ( nPos < rContent.getLength() ) { if ( rContent.charAt( nPos ) == (sal_Unicode) '"' ) { rContent.insert( nPos, aInsert ); nPos += aInsert.getLength(); } ++nPos; } } // quote string literals rContent.insert( 0, (sal_Unicode) '"' ); rContent.append( (sal_Unicode) '"' ); // remove redundant double quotes at start or end if ( bEscape ) { if ( rContent.getLength() > 2 && rContent.charAt(0) == (sal_Unicode) '"' && rContent.charAt(1) == (sal_Unicode) '"' ) { String aTrimmed( rContent.makeStringAndClear().copy(2) ); rContent = rtl::OUStringBuffer( aTrimmed ); } sal_Int32 nLen = rContent.getLength(); if ( nLen > 2 && rContent.charAt(nLen-1) == (sal_Unicode) '"' && rContent.charAt(nLen-2) == (sal_Unicode) '"' ) { String aTrimmed( rContent.makeStringAndClear().copy( 0, nLen - 2 ) ); rContent = rtl::OUStringBuffer( aTrimmed ); } } } } // // SvXMLNumFmtElementContext // SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType, const uno::Reference& xAttrList ) : SvXMLImportContext( rImport, nPrfx, rLName ), rParent( rParentContext ), nType( nNewType ), nElementLang( LANGUAGE_SYSTEM ), bLong( sal_False ), bTextual( sal_False ) { OUString sLanguage, sCountry; sal_Int32 nAttrVal; bool bAttrBool(false); sal_uInt16 nAttrEnum; double fAttrDouble; sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for( sal_Int16 i=0; i < nAttrCount; i++ ) { OUString sAttrName = xAttrList->getNameByIndex( i ); OUString sValue = xAttrList->getValueByIndex( i ); OUString aLocalName; sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); const SvXMLTokenMap& rTokenMap = rParent.GetData()->GetStyleElemAttrTokenMap(); sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName ); switch (nToken) { case XML_TOK_ELEM_ATTR_DECIMAL_PLACES: if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) aNumInfo.nDecimals = nAttrVal; break; case XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS: if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) aNumInfo.nInteger = nAttrVal; break; case XML_TOK_ELEM_ATTR_GROUPING: if (::sax::Converter::convertBool( bAttrBool, sValue )) aNumInfo.bGrouping = bAttrBool; break; case XML_TOK_ELEM_ATTR_DISPLAY_FACTOR: if (::sax::Converter::convertDouble( fAttrDouble, sValue )) aNumInfo.fDisplayFactor = fAttrDouble; break; case XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT: if ( sValue.getLength() > 0 ) aNumInfo.bDecReplace = sal_True; // only a default string is supported else aNumInfo.bVarDecimals = sal_True; // empty replacement string: variable decimals break; case XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS: if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) aNumInfo.nExpDigits = nAttrVal; break; case XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS: if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) aNumInfo.nNumerDigits = nAttrVal; break; case XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS: if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) aNumInfo.nDenomDigits = nAttrVal; break; case XML_TOK_ELEM_ATTR_LANGUAGE: sLanguage = sValue; break; case XML_TOK_ELEM_ATTR_COUNTRY: sCountry = sValue; break; case XML_TOK_ELEM_ATTR_STYLE: if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aStyleValueMap ) ) bLong = (sal_Bool) nAttrEnum; break; case XML_TOK_ELEM_ATTR_TEXTUAL: if (::sax::Converter::convertBool( bAttrBool, sValue )) bTextual = bAttrBool; break; case XML_TOK_ELEM_ATTR_CALENDAR: sCalendar = sValue; break; } } if ( sLanguage.getLength() || sCountry.getLength() ) { nElementLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry ); if ( nElementLang == LANGUAGE_DONTKNOW ) nElementLang = LANGUAGE_SYSTEM; //! error handling for invalid locales? } } SvXMLNumFmtElementContext::~SvXMLNumFmtElementContext() { } SvXMLImportContext* SvXMLNumFmtElementContext::CreateChildContext( sal_uInt16 nPrfx, const rtl::OUString& rLName, const uno::Reference& xAttrList ) { // only number:number supports number:embedded-text child element if ( nType == XML_TOK_STYLE_NUMBER && nPrfx == XML_NAMESPACE_NUMBER && IsXMLToken( rLName, XML_EMBEDDED_TEXT ) ) { return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nPrfx, rLName, *this, xAttrList ); } else return new SvXMLImportContext( GetImport(), nPrfx, rLName ); } void SvXMLNumFmtElementContext::Characters( const rtl::OUString& rChars ) { aContent.append( rChars ); } void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent ) { if ( rContent.getLength() ) { SvXMLEmbeddedElement* pObj = new SvXMLEmbeddedElement( nFormatPos, rContent ); if ( !aNumInfo.aEmbeddedElements.Insert( pObj ) ) { // there's already an element at this position - append text to existing element delete pObj; sal_uInt16 nElementCount = aNumInfo.aEmbeddedElements.Count(); for (sal_uInt16 i=0; inFormatPos == nFormatPos ) { pObj->aText += rContent; break; } } } } } void SvXMLNumFmtElementContext::EndElement() { sal_Bool bEffLong = bLong; switch (nType) { case XML_TOK_STYLE_TEXT: if ( rParent.HasLongDoW() && rParent.GetLocaleData().getLongDateDayOfWeekSep() == String( aContent.getStr() ) ) { // skip separator constant after long day of week // (NF_KEY_NNNN contains the separator) if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) ) { aContent = OUStringBuffer(); } rParent.SetHasLongDoW( sal_False ); // only once } if ( aContent.getLength() ) { lcl_EnquoteIfNecessary( aContent, rParent ); rParent.AddToCode( aContent.makeStringAndClear() ); } break; case XML_TOK_STYLE_NUMBER: rParent.AddNumber( aNumInfo ); break; case XML_TOK_STYLE_CURRENCY_SYMBOL: rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang ); break; case XML_TOK_STYLE_TEXT_CONTENT: rParent.AddToCode( OUString::valueOf((sal_Unicode)'@') ); break; case XML_TOK_STYLE_BOOLEAN: // ignored - only default boolean format is supported break; case XML_TOK_STYLE_DAY: rParent.UpdateCalendar( sCalendar ); //! I18N doesn't provide SYSTEM or extended date information yet rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_DD : NF_KEY_D ) ); break; case XML_TOK_STYLE_MONTH: rParent.UpdateCalendar( sCalendar ); //! I18N doesn't provide SYSTEM or extended date information yet rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bTextual ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM ) : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) ); break; case XML_TOK_STYLE_YEAR: rParent.UpdateCalendar( sCalendar ); //! I18N doesn't provide SYSTEM or extended date information yet // Y after G (era) is replaced by E if ( rParent.HasEra() ) rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_EEC : NF_KEY_EC ) ); else rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) ); break; case XML_TOK_STYLE_ERA: rParent.UpdateCalendar( sCalendar ); //! I18N doesn't provide SYSTEM or extended date information yet rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_GGG : NF_KEY_G ) ); // HasEra flag is set break; case XML_TOK_STYLE_DAY_OF_WEEK: rParent.UpdateCalendar( sCalendar ); //! I18N doesn't provide SYSTEM or extended date information yet rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) ); break; case XML_TOK_STYLE_WEEK_OF_YEAR: rParent.UpdateCalendar( sCalendar ); rParent.AddNfKeyword( NF_KEY_WW ); break; case XML_TOK_STYLE_QUARTER: rParent.UpdateCalendar( sCalendar ); rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_QQ : NF_KEY_Q ) ); break; case XML_TOK_STYLE_HOURS: rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_HH : NF_KEY_H ) ); break; case XML_TOK_STYLE_AM_PM: //! short/long? rParent.AddNfKeyword( NF_KEY_AMPM ); break; case XML_TOK_STYLE_MINUTES: rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_MMI : NF_KEY_MI ) ); break; case XML_TOK_STYLE_SECONDS: rParent.AddNfKeyword( sal::static_int_cast< sal_uInt16 >( bEffLong ? NF_KEY_SS : NF_KEY_S ) ); if ( aNumInfo.nDecimals > 0 ) { // manually add the decimal places const String& rSep = rParent.GetLocaleData().getNumDecimalSep(); for ( xub_StrLen j=0; j= 0 ) { // add integer part only if min-integer-digits attribute is there aNumInfo.nDecimals = 0; rParent.AddNumber( aNumInfo ); // number without decimals rParent.AddToCode( OUString::valueOf((sal_Unicode)' ') ); } //! build string and add at once sal_Int32 i; for (i=0; i(rEntry.eFormat); } } return NF_INDEX_TABLE_ENTRIES; // invalid } //------------------------------------------------------------------------- // // SvXMLNumFormatContext // SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, SvXMLNumImpData* pNewData, sal_uInt16 nNewType, const uno::Reference& xAttrList, SvXMLStylesContext& rStyles ) : SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList ), pData( pNewData ), pStyles( &rStyles ), aMyConditions(), nType( nNewType ), nKey(-1), nFormatLang( LANGUAGE_SYSTEM ), bAutoOrder( sal_False ), bFromSystem( sal_False ), bTruncate( sal_True ), bAutoDec( sal_False ), bAutoInt( sal_False ), bHasExtraText( sal_False ), bHasLongDoW( sal_False ), bHasEra( sal_False ), bHasDateTime( sal_False ), bRemoveAfterUse( sal_False ), eDateDOW( XML_DEA_NONE ), eDateDay( XML_DEA_NONE ), eDateMonth( XML_DEA_NONE ), eDateYear( XML_DEA_NONE ), eDateHours( XML_DEA_NONE ), eDateMins( XML_DEA_NONE ), eDateSecs( XML_DEA_NONE ), bDateNoDefault( sal_False ) { OUString sLanguage, sCountry; ::com::sun::star::i18n::NativeNumberXmlAttributes aNatNumAttr; bool bAttrBool(false); sal_uInt16 nAttrEnum; sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for( sal_Int16 i=0; i < nAttrCount; i++ ) { OUString sAttrName = xAttrList->getNameByIndex( i ); OUString sValue = xAttrList->getValueByIndex( i ); OUString aLocalName; sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName ); const SvXMLTokenMap& rTokenMap = pData->GetStyleAttrTokenMap(); sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName ); switch (nToken) { case XML_TOK_STYLE_ATTR_NAME: break; case XML_TOK_STYLE_ATTR_LANGUAGE: sLanguage = sValue; break; case XML_TOK_STYLE_ATTR_COUNTRY: sCountry = sValue; break; case XML_TOK_STYLE_ATTR_TITLE: sFormatTitle = sValue; break; case XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER: if (::sax::Converter::convertBool( bAttrBool, sValue )) bAutoOrder = bAttrBool; break; case XML_TOK_STYLE_ATTR_FORMAT_SOURCE: if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aFormatSourceMap ) ) bFromSystem = (sal_Bool) nAttrEnum; break; case XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW: if (::sax::Converter::convertBool( bAttrBool, sValue )) bTruncate = bAttrBool; break; case XML_TOK_STYLE_ATTR_VOLATILE: // volatile formats can be removed after importing // if not used in other styles if (::sax::Converter::convertBool( bAttrBool, sValue )) bRemoveAfterUse = bAttrBool; break; case XML_TOK_STYLE_ATTR_TRANSL_FORMAT: aNatNumAttr.Format = sValue; break; case XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE: aNatNumAttr.Locale.Language = sValue; break; case XML_TOK_STYLE_ATTR_TRANSL_COUNTRY: aNatNumAttr.Locale.Country = sValue; break; case XML_TOK_STYLE_ATTR_TRANSL_STYLE: aNatNumAttr.Style = sValue; break; } } if ( sLanguage.getLength() || sCountry.getLength() ) { nFormatLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry ); if ( nFormatLang == LANGUAGE_DONTKNOW ) nFormatLang = LANGUAGE_SYSTEM; //! error handling for invalid locales? } if ( aNatNumAttr.Format.getLength() ) { SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); if ( pFormatter ) { sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr ); aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "[NatNum" ) ); aFormatCode.append( nNatNum, 10 ); LanguageType eLang = MsLangId::convertLocaleToLanguage( aNatNumAttr.Locale ); if ( eLang == LANGUAGE_DONTKNOW ) eLang = LANGUAGE_SYSTEM; //! error handling for invalid locales? if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM ) { aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "][$-" ) ); // language code in upper hex: aFormatCode.append( String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii() ); } aFormatCode.append( sal_Unicode(']') ); } } } SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, sal_uInt16 nPrfx, const rtl::OUString& rLName, const uno::Reference& xAttrList, const sal_Int32 nTempKey, SvXMLStylesContext& rStyles ) : SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList, XML_STYLE_FAMILY_DATA_STYLE ), pData( NULL ), pStyles( &rStyles ), aMyConditions(), nType( 0 ), nKey(nTempKey), nFormatLang( LANGUAGE_SYSTEM ), bAutoOrder( sal_False ), bFromSystem( sal_False ), bTruncate( sal_True ), bAutoDec( sal_False ), bAutoInt( sal_False ), bHasExtraText( sal_False ), bHasLongDoW( sal_False ), bHasEra( sal_False ), bHasDateTime( sal_False ), bRemoveAfterUse( sal_False ), eDateDOW( XML_DEA_NONE ), eDateDay( XML_DEA_NONE ), eDateMonth( XML_DEA_NONE ), eDateYear( XML_DEA_NONE ), eDateHours( XML_DEA_NONE ), eDateMins( XML_DEA_NONE ), eDateSecs( XML_DEA_NONE ), bDateNoDefault( sal_False ) { SetAttribute(XML_NAMESPACE_STYLE, GetXMLToken(XML_NAME), rLName); } SvXMLNumFormatContext::~SvXMLNumFormatContext() { } SvXMLImportContext* SvXMLNumFormatContext::CreateChildContext( sal_uInt16 nPrfx, const rtl::OUString& rLName, const uno::Reference& xAttrList ) { SvXMLImportContext* pContext = NULL; const SvXMLTokenMap& rTokenMap = pData->GetStyleElemTokenMap(); sal_uInt16 nToken = rTokenMap.Get( nPrfx, rLName ); switch (nToken) { case XML_TOK_STYLE_TEXT: case XML_TOK_STYLE_NUMBER: case XML_TOK_STYLE_SCIENTIFIC_NUMBER: case XML_TOK_STYLE_FRACTION: case XML_TOK_STYLE_CURRENCY_SYMBOL: case XML_TOK_STYLE_DAY: case XML_TOK_STYLE_MONTH: case XML_TOK_STYLE_YEAR: case XML_TOK_STYLE_ERA: case XML_TOK_STYLE_DAY_OF_WEEK: case XML_TOK_STYLE_WEEK_OF_YEAR: case XML_TOK_STYLE_QUARTER: case XML_TOK_STYLE_HOURS: case XML_TOK_STYLE_AM_PM: case XML_TOK_STYLE_MINUTES: case XML_TOK_STYLE_SECONDS: case XML_TOK_STYLE_BOOLEAN: case XML_TOK_STYLE_TEXT_CONTENT: pContext = new SvXMLNumFmtElementContext( GetImport(), nPrfx, rLName, *this, nToken, xAttrList ); break; case XML_TOK_STYLE_PROPERTIES: pContext = new SvXMLNumFmtPropContext( GetImport(), nPrfx, rLName, *this, xAttrList ); break; case XML_TOK_STYLE_MAP: { // SvXMLNumFmtMapContext::EndElement adds to aMyConditions, // so there's no need for an extra flag pContext = new SvXMLNumFmtMapContext( GetImport(), nPrfx, rLName, *this, xAttrList ); } break; } if( !pContext ) pContext = new SvXMLImportContext( GetImport(), nPrfx, rLName ); return pContext; } sal_Int32 SvXMLNumFormatContext::GetKey() { if (nKey > -1) { if (bRemoveAfterUse) { // format is used -> don't remove bRemoveAfterUse = sal_False; if (pData) pData->SetUsed(nKey); // Add to import's list of keys now - CreateAndInsert didn't add // the style if bRemoveAfterUse was set. GetImport().AddNumberStyle( nKey, GetName() ); } return nKey; } else { // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set bRemoveAfterUse = sal_False; CreateAndInsert(sal_True); return nKey; } } sal_Int32 SvXMLNumFormatContext::PrivateGetKey() { // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag if (nKey > -1) return nKey; else { CreateAndInsert(sal_True); return nKey; } } sal_Int32 SvXMLNumFormatContext::CreateAndInsert( com::sun::star::uno::Reference< com::sun::star::util::XNumberFormatsSupplier >& xFormatsSupplier ) { if (nKey <= -1) { SvNumberFormatter* pFormatter = NULL; SvNumberFormatsSupplierObj* pObj = SvNumberFormatsSupplierObj::getImplementation( xFormatsSupplier ); if (pObj) pFormatter = pObj->GetNumberFormatter(); if ( pFormatter ) return CreateAndInsert( pFormatter ); else return -1; } else return nKey; } void SvXMLNumFormatContext::CreateAndInsert(sal_Bool /*bOverwrite*/) { if (!(nKey > -1)) CreateAndInsert(pData->GetNumberFormatter()); } sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter) { if (!pFormatter) { OSL_FAIL("no number formatter"); return -1; } sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; for (sal_uInt32 i = 0; i < aMyConditions.size(); i++) { SvXMLNumFormatContext* pStyle = (SvXMLNumFormatContext *)pStyles->FindStyleChildContext( XML_STYLE_FAMILY_DATA_STYLE, aMyConditions[i].sMapName, sal_False); if (pStyle) { if ((pStyle->PrivateGetKey() > -1)) // don't reset pStyle's bRemoveAfterUse flag AddCondition(i); } } if ( !aFormatCode.getLength() ) { // insert empty format as empty string (with quotes) // #93901# this check has to be done before inserting the conditions aFormatCode.appendAscii("\"\""); // "" } aFormatCode.insert( 0, aConditions.makeStringAndClear() ); OUString sFormat = aFormatCode.makeStringAndClear(); // test special cases if ( bAutoDec ) // automatic decimal places { // #99391# adjust only if the format contains no text elements, no conditions // and no color definition (detected by the '[' at the start) if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText && aMyConditions.size() == 0 && sFormat.toChar() != (sal_Unicode)'[' ) nIndex = pFormatter->GetStandardIndex( nFormatLang ); } if ( bAutoInt ) // automatic integer digits { //! only if two decimal places was set? if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText && aMyConditions.size() == 0 && sFormat.toChar() != (sal_Unicode)'[' ) nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang ); } // boolean is always the builtin boolean format // (no other boolean formats are implemented) if ( nType == XML_TOK_STYLES_BOOLEAN_STYLE ) nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang ); // check for default date formats if ( nType == XML_TOK_STYLES_DATE_STYLE && bAutoOrder && !bDateNoDefault ) { NfIndexTableOffset eFormat = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat( eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bFromSystem ); if ( eFormat < NF_INDEX_TABLE_ENTRIES ) { // #109651# if a date format has the automatic-order attribute and // contains exactly the elements of one of the default date formats, // use that default format, with the element order and separators // from the current locale settings nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang ); } } if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && sFormat.getLength() ) { // insert by format string String aFormatStr( sFormat ); nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang ); if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) { xub_StrLen nErrPos = 0; short l_nType = 0; sal_Bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang ); if ( !bOk && nErrPos == 0 && aFormatStr != String(sFormat) ) { // if the string was modified by PutEntry, look for an existing format // with the modified string nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang ); if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND ) bOk = sal_True; } if (!bOk) nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; } } //! I18N doesn't provide SYSTEM or extended date information yet if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder ) { // use fixed-order formats instead of SYS... if bAutoOrder is false // (only if the format strings are equal for the locale) NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex ); if ( eOffset == NF_DATE_SYS_DMMMYYYY ) { sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang ); const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) nIndex = nNewIndex; } else if ( eOffset == NF_DATE_SYS_DMMMMYYYY ) { sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang ); const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) nIndex = nNewIndex; } } if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && sFormatTitle.getLength()) { SvNumberformat* pFormat = const_cast(pFormatter->GetEntry( nIndex )); if (pFormat) { String sTitle (sFormatTitle); pFormat->SetComment(sTitle); } } if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) { OSL_FAIL("invalid number format"); nIndex = pFormatter->GetStandardIndex( nFormatLang ); } pData->AddKey( nIndex, GetName(), bRemoveAfterUse ); nKey = nIndex; // Add to import's list of keys (shared between styles and content import) // only if not volatile - formats are removed from NumberFormatter at the // end of each import (in SvXMLNumFmtHelper dtor). // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there. if (!bRemoveAfterUse) GetImport().AddNumberStyle( nKey, GetName() ); return nKey; } void SvXMLNumFormatContext::Finish( sal_Bool bOverwrite ) { SvXMLStyleContext::Finish( bOverwrite ); } const LocaleDataWrapper& SvXMLNumFormatContext::GetLocaleData() const { return pData->GetLocaleData( nFormatLang ); } void SvXMLNumFormatContext::AddToCode( const rtl::OUString& rString ) { aFormatCode.append( rString ); bHasExtraText = sal_True; } void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) { SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); if (!pFormatter) return; // store special conditions bAutoDec = ( rInfo.nDecimals < 0 ); bAutoInt = ( rInfo.nInteger < 0 ); sal_uInt16 nPrec = 0; sal_uInt16 nLeading = 0; if ( rInfo.nDecimals >= 0 ) // < 0 : Default nPrec = (sal_uInt16) rInfo.nDecimals; if ( rInfo.nInteger >= 0 ) // < 0 : Default nLeading = (sal_uInt16) rInfo.nInteger; if ( bAutoDec ) { if ( nType == XML_TOK_STYLES_CURRENCY_STYLE ) { // for currency formats, "automatic decimals" is used for the automatic // currency format with (fixed) decimals from the locale settings const LocaleDataWrapper& rLoc = pData->GetLocaleData( nFormatLang ); nPrec = rLoc.getCurrDigits(); } else { // for other types, "automatic decimals" means dynamic determination of // decimals, as achieved with the "general" keyword aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) ); return; } } if ( bAutoInt ) { //!... } sal_uInt16 nGenPrec = nPrec; if ( rInfo.bDecReplace || rInfo.bVarDecimals ) nGenPrec = 0; // generate format without decimals... sal_Bool bGrouping = rInfo.bGrouping; sal_uInt16 nEmbeddedCount = rInfo.aEmbeddedElements.Count(); if ( nEmbeddedCount ) bGrouping = sal_False; // grouping and embedded characters can't be used together String aNumStr; sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang ); pFormatter->GenerateFormat( aNumStr, nStdIndex, nFormatLang, bGrouping, sal_False, nGenPrec, nLeading ); if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 ) { // #i43959# For scientific numbers, "#" in the integer part forces a digit, // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0"). aNumStr.EraseLeadingChars( (sal_Unicode)'#' ); } if ( nEmbeddedCount ) { // insert embedded strings into number string // only the integer part is supported // nZeroPos is the string position where format position 0 is inserted xub_StrLen nZeroPos = aNumStr.Search( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); if ( nZeroPos == STRING_NOTFOUND ) nZeroPos = aNumStr.Len(); // aEmbeddedElements is sorted - last entry has the largest position (leftmost) const SvXMLEmbeddedElement* pLastObj = rInfo.aEmbeddedElements[nEmbeddedCount - 1]; sal_Int32 nLastFormatPos = pLastObj->nFormatPos; if ( nLastFormatPos >= nZeroPos ) { // add '#' characters so all embedded texts are really embedded in digits // (there always has to be a digit before the leftmost embedded text) xub_StrLen nAddCount = (xub_StrLen)nLastFormatPos + 1 - nZeroPos; String aDigitStr; aDigitStr.Fill( nAddCount, (sal_Unicode)'#' ); aNumStr.Insert( aDigitStr, 0 ); nZeroPos = nZeroPos + nAddCount; } // aEmbeddedElements is sorted with ascending positions - loop is from right to left for (sal_uInt16 nElement = 0; nElement < nEmbeddedCount; nElement++) { const SvXMLEmbeddedElement* pObj = rInfo.aEmbeddedElements[nElement]; sal_Int32 nFormatPos = pObj->nFormatPos; sal_Int32 nInsertPos = nZeroPos - nFormatPos; if ( nFormatPos >= 0 && nInsertPos >= 0 ) { rtl::OUStringBuffer aContent( pObj->aText ); // #107805# always quote embedded strings - even space would otherwise // be recognized as thousands separator in French. aContent.insert( 0, (sal_Unicode) '"' ); aContent.append( (sal_Unicode) '"' ); aNumStr.Insert( String( aContent.makeStringAndClear() ), (xub_StrLen)nInsertPos ); } } } aFormatCode.append( aNumStr ); if ( ( rInfo.bDecReplace || rInfo.bVarDecimals ) && nPrec ) // add decimal replacement (dashes) { // add dashes for explicit decimal replacement, # for variable decimals sal_Unicode cAdd = rInfo.bDecReplace ? '-' : '#'; aFormatCode.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); for ( sal_uInt16 i=0; i 0.0 ) { // test for 1.0 is just for optimization - nSepCount would be 0 // one separator for each factor of 1000 sal_Int32 nSepCount = (sal_Int32) ::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 ); if ( nSepCount > 0 ) { OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep(); for ( sal_Int32 i=0; iGetNumberFormatter(); if ( pFormatter ) { pFormatter->ChangeIntl( nFormatLang ); String sCurString, sDummy; pFormatter->GetCompatibilityCurrency( sCurString, sDummy ); aSymbol = sCurString; bAutomatic = sal_True; } } else if ( nLang == LANGUAGE_SYSTEM && aSymbol.compareToAscii("CCC") == 0 ) { // "CCC" is used for automatic long symbol bAutomatic = sal_True; } if ( bAutomatic ) { // remove unnecessary quotes before automatic symbol (formats like "-(0DM)") // otherwise the currency symbol isn't recognized (#94048#) sal_Int32 nLength = aFormatCode.getLength(); if ( nLength > 1 && aFormatCode.charAt( nLength-1 ) == '"' ) { // find start of quoted string // When SvXMLNumFmtElementContext::EndElement creates escaped quotes, // they must be handled here, too. sal_Int32 nFirst = nLength - 2; while ( nFirst >= 0 && aFormatCode.charAt( nFirst ) != '"' ) --nFirst; if ( nFirst >= 0 ) { // remove both quotes from aFormatCode rtl::OUString aOld = aFormatCode.makeStringAndClear(); if ( nFirst > 0 ) aFormatCode.append( aOld.copy( 0, nFirst ) ); if ( nLength > nFirst + 2 ) aFormatCode.append( aOld.copy( nFirst + 1, nLength - nFirst - 2 ) ); } } } if (!bAutomatic) aFormatCode.appendAscii( "[$" ); // intro for "new" currency symbols aFormatCode.append( aSymbol ); if (!bAutomatic) { if ( nLang != LANGUAGE_SYSTEM ) { // '-' sign and language code in hex: aFormatCode.append( (sal_Unicode) '-' ); aFormatCode.append( String::CreateFromInt32( sal_Int32( nLang ), 16 ).ToUpperAscii() ); } aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbol } } void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex ) { SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); if (!pFormatter) return; if ( nIndex == NF_KEY_G || nIndex == NF_KEY_GG || nIndex == NF_KEY_GGG ) bHasEra = sal_True; if ( nIndex == NF_KEY_NNNN ) { nIndex = NF_KEY_NNN; bHasLongDoW = sal_True; // to remove string constant with separator } String sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex ); if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH || nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI || nIndex == NF_KEY_S || nIndex == NF_KEY_SS ) { if ( !bTruncate && !bHasDateTime ) { // with truncate-on-overflow = false, add "[]" to first time part sKeyword.Insert( (sal_Unicode) '[', 0 ); sKeyword.Append( (sal_Unicode) ']' ); } bHasDateTime = sal_True; } aFormatCode.append( sKeyword ); // collect the date elements that the format contains, to recognize default date formats switch ( nIndex ) { case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break; case NF_KEY_NNN: case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break; case NF_KEY_D: eDateDay = XML_DEA_SHORT; break; case NF_KEY_DD: eDateDay = XML_DEA_LONG; break; case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break; case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break; case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break; case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break; case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break; case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break; case NF_KEY_H: eDateHours = XML_DEA_SHORT; break; case NF_KEY_HH: eDateHours = XML_DEA_LONG; break; case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break; case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break; case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break; case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break; case NF_KEY_AP: case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself default: bDateNoDefault = sal_True; // any other element -> no default format } } sal_Bool lcl_IsAtEnd( rtl::OUStringBuffer& rBuffer, const String& rToken ) { sal_Int32 nBufLen = rBuffer.getLength(); xub_StrLen nTokLen = rToken.Len(); if ( nTokLen > nBufLen ) return sal_False; sal_Int32 nStartPos = nBufLen - nTokLen; for ( xub_StrLen nTokPos = 0; nTokPos < nTokLen; nTokPos++ ) if ( rToken.GetChar( nTokPos ) != rBuffer.charAt( nStartPos + nTokPos ) ) return sal_False; return sal_True; } sal_Bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew ) { // replaces one keyword with another if it is found at the end of the code SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); if (!pFormatter) return sal_False; String sOldStr = pFormatter->GetKeyword( nFormatLang, nOld ); if ( lcl_IsAtEnd( aFormatCode, sOldStr ) ) { // remove old keyword aFormatCode.setLength( aFormatCode.getLength() - sOldStr.Len() ); // add new keyword String sNewStr = pFormatter->GetKeyword( nFormatLang, nNew ); aFormatCode.append( sNewStr ); return sal_True; // changed } return sal_False; // not found } void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex ) { rtl::OUString rApplyName = aMyConditions[nIndex].sMapName; rtl::OUString rCondition = aMyConditions[nIndex].sCondition; SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName ); OUString sValue(RTL_CONSTASCII_USTRINGPARAM("value()")); //! define constant sal_Int32 nValLen = sValue.getLength(); if ( pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND && rCondition.copy( 0, nValLen ) == sValue ) { //! test for valid conditions //! test for default conditions OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen ); sal_Bool bDefaultCond = sal_False; //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count //! allow blanks in conditions sal_Bool bFirstCond = ( aConditions.getLength() == 0 ); if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 ) bDefaultCond = sal_True; if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 ) { // The third condition in a number format with a text part can only be // "all other numbers", the condition string must be empty. bDefaultCond = sal_True; } if (!bDefaultCond) { sal_Int32 nPos = sRealCond.indexOf( '.' ); if ( nPos >= 0 ) { // #i8026# #103991# localize decimal separator const String& rDecSep = GetLocaleData().getNumDecimalSep(); if ( rDecSep.Len() > 1 || rDecSep.GetChar(0) != '.' ) sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep ); } aConditions.append( (sal_Unicode) '[' ); aConditions.append( sRealCond ); aConditions.append( (sal_Unicode) ']' ); } const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey); if ( pFormat ) aConditions.append( OUString( pFormat->GetFormatstring() ) ); aConditions.append( (sal_Unicode) ';' ); } } void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex, const rtl::OUString& rFormat, const LocaleDataWrapper& rData ) { rtl::OUString rCondition = aMyConditions[nIndex].sCondition; OUString sValue(RTL_CONSTASCII_USTRINGPARAM("value()")); //! define constant sal_Int32 nValLen = sValue.getLength(); if ( rCondition.copy( 0, nValLen ) == sValue ) { //! test for valid conditions //! test for default conditions OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen ); sal_Bool bDefaultCond = sal_False; //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count //! allow blanks in conditions sal_Bool bFirstCond = ( aConditions.getLength() == 0 ); if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 ) bDefaultCond = sal_True; if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 ) { // The third condition in a number format with a text part can only be // "all other numbers", the condition string must be empty. bDefaultCond = sal_True; } if (!bDefaultCond) { sal_Int32 nPos = sRealCond.indexOf( '.' ); if ( nPos >= 0 ) { // #i8026# #103991# localize decimal separator const String& rDecSep = rData.getNumDecimalSep(); if ( rDecSep.Len() > 1 || rDecSep.GetChar(0) != '.' ) sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep ); } aConditions.append( (sal_Unicode) '[' ); aConditions.append( sRealCond ); aConditions.append( (sal_Unicode) ']' ); } aConditions.append( rFormat ); aConditions.append( (sal_Unicode) ';' ); } } void SvXMLNumFormatContext::AddCondition( const rtl::OUString& rCondition, const rtl::OUString& rApplyName ) { MyCondition aCondition; aCondition.sCondition = rCondition; aCondition.sMapName = rApplyName; aMyConditions.push_back(aCondition); } void SvXMLNumFormatContext::AddColor( sal_uInt32 const nColor ) { SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); if (!pFormatter) return; OUStringBuffer aColName; for ( sal_uInt16 i=0; iGetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ) ); break; } if ( aColName.getLength() ) { aColName.insert( 0, (sal_Unicode) '[' ); aColName.append( (sal_Unicode) ']' ); aFormatCode.insert( 0, aColName.makeStringAndClear() ); } } void SvXMLNumFormatContext::UpdateCalendar( const rtl::OUString& rNewCalendar ) { if ( rNewCalendar != sCalendar ) { sCalendar = rNewCalendar; if ( sCalendar.getLength() ) { aFormatCode.appendAscii( "[~" ); // intro for calendar code aFormatCode.append( sCalendar ); aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbolcalendar code } } } sal_Bool SvXMLNumFormatContext::IsSystemLanguage() { return nFormatLang == LANGUAGE_SYSTEM; } //------------------------------------------------------------------------- // // SvXMLNumFmtHelper // SvXMLNumFmtHelper::SvXMLNumFmtHelper( const uno::Reference& rSupp, const uno::Reference& xServiceFactory ) : mxServiceFactory(xServiceFactory) { DBG_ASSERT( mxServiceFactory.is(), "got no service manager" ); SvNumberFormatter* pFormatter = NULL; SvNumberFormatsSupplierObj* pObj = SvNumberFormatsSupplierObj::getImplementation( rSupp ); if (pObj) pFormatter = pObj->GetNumberFormatter(); pData = new SvXMLNumImpData( pFormatter, mxServiceFactory ); } SvXMLNumFmtHelper::SvXMLNumFmtHelper( SvNumberFormatter* pNumberFormatter, const uno::Reference& xServiceFactory ) : mxServiceFactory(xServiceFactory) { DBG_ASSERT( mxServiceFactory.is(), "got no service manager" ); pData = new SvXMLNumImpData( pNumberFormatter, mxServiceFactory ); } SvXMLNumFmtHelper::~SvXMLNumFmtHelper() { // remove temporary (volatile) formats from NumberFormatter pData->RemoveVolatileFormats(); delete pData; } SvXMLStyleContext* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLocalName, const uno::Reference& xAttrList, SvXMLStylesContext& rStyles ) { SvXMLStyleContext* pContext = NULL; const SvXMLTokenMap& rTokenMap = pData->GetStylesElemTokenMap(); sal_uInt16 nToken = rTokenMap.Get( nPrefix, rLocalName ); switch (nToken) { case XML_TOK_STYLES_NUMBER_STYLE: case XML_TOK_STYLES_CURRENCY_STYLE: case XML_TOK_STYLES_PERCENTAGE_STYLE: case XML_TOK_STYLES_DATE_STYLE: case XML_TOK_STYLES_TIME_STYLE: case XML_TOK_STYLES_BOOLEAN_STYLE: case XML_TOK_STYLES_TEXT_STYLE: pContext = new SvXMLNumFormatContext( rImport, nPrefix, rLocalName, pData, nToken, xAttrList, rStyles ); break; } // return NULL if not a data style, caller must handle other elements return pContext; } const SvXMLTokenMap& SvXMLNumFmtHelper::GetStylesElemTokenMap() { return pData->GetStylesElemTokenMap(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */