summaryrefslogtreecommitdiff
path: root/xmloff/source/style/xmlnumfe.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'xmloff/source/style/xmlnumfe.cxx')
-rw-r--r--xmloff/source/style/xmlnumfe.cxx1820
1 files changed, 1820 insertions, 0 deletions
diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx
new file mode 100644
index 000000000000..93355e914759
--- /dev/null
+++ b/xmloff/source/style/xmlnumfe.cxx
@@ -0,0 +1,1820 @@
+/*************************************************************************
+ *
+ * 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
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_xmloff.hxx"
+
+#define _SVSTDARR_ULONGS
+#define _ZFORLIST_DECLARE_TABLE
+
+#include <svl/svstdarr.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <svl/numuno.hxx>
+#include <i18npool/mslangid.hxx>
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <rtl/ustrbuf.hxx>
+
+// #110680#
+//#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp>
+
+#include <xmloff/xmlnumfe.hxx>
+#include "xmlnmspe.hxx"
+#include <xmloff/xmluconv.hxx>
+#include <xmloff/attrlist.hxx>
+#include <xmloff/nmspmap.hxx>
+#include <xmloff/families.hxx>
+#include <xmloff/xmlnumfi.hxx> // SvXMLNumFmtDefaults
+
+#define _SVSTDARR_USHORTS
+#include <svl/svstdarr.hxx>
+#include <svl/nfsymbol.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmlexp.hxx>
+
+#include <set>
+
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+
+using namespace ::com::sun::star;
+using namespace ::xmloff::token;
+using namespace ::svt;
+
+//-------------------------------------------------------------------------
+
+// 4th condition for text formats doesn't work
+//#define XMLNUM_MAX_PARTS 4
+#define XMLNUM_MAX_PARTS 3
+
+//-------------------------------------------------------------------------
+
+struct LessuInt32
+{
+ sal_Bool operator() (const sal_uInt32 rValue1, const sal_uInt32 rValue2) const
+ {
+ return rValue1 < rValue2;
+ }
+};
+
+typedef std::set< sal_uInt32, LessuInt32 > SvXMLuInt32Set;
+
+class SvXMLNumUsedList_Impl
+{
+ SvXMLuInt32Set aUsed;
+ SvXMLuInt32Set aWasUsed;
+ SvXMLuInt32Set::iterator aCurrentUsedPos;
+ sal_uInt32 nUsedCount;
+ sal_uInt32 nWasUsedCount;
+
+public:
+ SvXMLNumUsedList_Impl();
+ ~SvXMLNumUsedList_Impl();
+
+ void SetUsed( sal_uInt32 nKey );
+ sal_Bool IsUsed( sal_uInt32 nKey ) const;
+ sal_Bool IsWasUsed( sal_uInt32 nKey ) const;
+ void Export();
+
+ sal_Bool GetFirstUsed(sal_uInt32& nKey);
+ sal_Bool GetNextUsed(sal_uInt32& nKey);
+
+ void GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed);
+ void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed);
+};
+
+//-------------------------------------------------------------------------
+
+struct SvXMLEmbeddedTextEntry
+{
+ sal_uInt16 nSourcePos; // position in NumberFormat (to skip later)
+ sal_Int32 nFormatPos; // resulting position in embedded-text element
+ rtl::OUString aText;
+
+ SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, const rtl::OUString& rT ) :
+ nSourcePos(nSP), nFormatPos(nFP), aText(rT) {}
+};
+
+typedef SvXMLEmbeddedTextEntry* SvXMLEmbeddedTextEntryPtr;
+SV_DECL_PTRARR_DEL( SvXMLEmbeddedTextEntryArr, SvXMLEmbeddedTextEntryPtr, 4, 4 )
+
+//-------------------------------------------------------------------------
+
+SV_IMPL_PTRARR( SvXMLEmbeddedTextEntryArr, SvXMLEmbeddedTextEntryPtr );
+
+//-------------------------------------------------------------------------
+
+//
+//! SvXMLNumUsedList_Impl should be optimized!
+//
+
+SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
+ nUsedCount(0),
+ nWasUsedCount(0)
+{
+}
+
+SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
+{
+}
+
+void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey )
+{
+ if ( !IsWasUsed(nKey) )
+ {
+ std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey );
+ if (aPair.second)
+ nUsedCount++;
+ }
+}
+
+sal_Bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const
+{
+ SvXMLuInt32Set::iterator aItr = aUsed.find(nKey);
+ return (aItr != aUsed.end());
+}
+
+sal_Bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const
+{
+ SvXMLuInt32Set::iterator aItr = aWasUsed.find(nKey);
+ return (aItr != aWasUsed.end());
+}
+
+void SvXMLNumUsedList_Impl::Export()
+{
+ SvXMLuInt32Set::iterator aItr = aUsed.begin();
+ while (aItr != aUsed.end())
+ {
+ std::pair<SvXMLuInt32Set::iterator, bool> aPair = aWasUsed.insert( *aItr );
+ if (aPair.second)
+ nWasUsedCount++;
+ aItr++;
+ }
+ aUsed.clear();
+ nUsedCount = 0;
+}
+
+sal_Bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey)
+{
+ sal_Bool bRet(sal_False);
+ aCurrentUsedPos = aUsed.begin();
+ if(nUsedCount)
+ {
+ DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong");
+ nKey = *aCurrentUsedPos;
+ bRet = sal_True;
+ }
+ return bRet;
+}
+
+sal_Bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey)
+{
+ sal_Bool bRet(sal_False);
+ if (aCurrentUsedPos != aUsed.end())
+ {
+ aCurrentUsedPos++;
+ if (aCurrentUsedPos != aUsed.end())
+ {
+ nKey = *aCurrentUsedPos;
+ bRet = sal_True;
+ }
+ }
+ return bRet;
+}
+
+void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
+{
+ rWasUsed.realloc(nWasUsedCount);
+ sal_Int32* pWasUsed = rWasUsed.getArray();
+ if (pWasUsed)
+ {
+ SvXMLuInt32Set::iterator aItr = aWasUsed.begin();
+ while (aItr != aWasUsed.end())
+ {
+ *pWasUsed = *aItr;
+ aItr++;
+ pWasUsed++;
+ }
+ }
+}
+
+void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
+{
+ DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty");
+ sal_Int32 nCount(rWasUsed.getLength());
+ const sal_Int32* pWasUsed = rWasUsed.getConstArray();
+ for (sal_uInt16 i = 0; i < nCount; i++, pWasUsed++)
+ {
+ std::pair<SvXMLuInt32Set::iterator, bool> aPair = aWasUsed.insert( *pWasUsed );
+ if (aPair.second)
+ nWasUsedCount++;
+ }
+}
+
+//-------------------------------------------------------------------------
+
+SvXMLNumFmtExport::SvXMLNumFmtExport(
+ SvXMLExport& rExp,
+ const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) :
+ rExport( rExp ),
+ sPrefix( OUString::createFromAscii( "N" ) ),
+ pFormatter( NULL ),
+ pCharClass( NULL ),
+ pLocaleData( NULL )
+{
+ // supplier must be SvNumberFormatsSupplierObj
+ SvNumberFormatsSupplierObj* pObj =
+ SvNumberFormatsSupplierObj::getImplementation( rSupp );
+ if (pObj)
+ pFormatter = pObj->GetNumberFormatter();
+
+ if ( pFormatter )
+ {
+ pCharClass = new CharClass( pFormatter->GetServiceManager(),
+ pFormatter->GetLocale() );
+ pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(),
+ pFormatter->GetLocale() );
+ }
+ else
+ {
+ lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
+
+ // #110680#
+ // pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale );
+ // pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale );
+ pCharClass = new CharClass( rExport.getServiceFactory(), aLocale );
+ pLocaleData = new LocaleDataWrapper( rExport.getServiceFactory(), aLocale );
+ }
+
+ pUsedList = new SvXMLNumUsedList_Impl;
+}
+
+SvXMLNumFmtExport::SvXMLNumFmtExport(
+ SvXMLExport& rExp,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::util::XNumberFormatsSupplier >& rSupp,
+ const rtl::OUString& rPrefix ) :
+ rExport( rExp ),
+ sPrefix( rPrefix ),
+ pFormatter( NULL ),
+ pCharClass( NULL ),
+ pLocaleData( NULL )
+{
+ // supplier must be SvNumberFormatsSupplierObj
+ SvNumberFormatsSupplierObj* pObj =
+ SvNumberFormatsSupplierObj::getImplementation( rSupp );
+ if (pObj)
+ pFormatter = pObj->GetNumberFormatter();
+
+ if ( pFormatter )
+ {
+ pCharClass = new CharClass( pFormatter->GetServiceManager(),
+ pFormatter->GetLocale() );
+ pLocaleData = new LocaleDataWrapper( pFormatter->GetServiceManager(),
+ pFormatter->GetLocale() );
+ }
+ else
+ {
+ lang::Locale aLocale( MsLangId::convertLanguageToLocale( MsLangId::getSystemLanguage() ) );
+
+ // #110680#
+ // pCharClass = new CharClass( ::comphelper::getProcessServiceFactory(), aLocale );
+ // pLocaleData = new LocaleDataWrapper( ::comphelper::getProcessServiceFactory(), aLocale );
+ pCharClass = new CharClass( rExport.getServiceFactory(), aLocale );
+ pLocaleData = new LocaleDataWrapper( rExport.getServiceFactory(), aLocale );
+ }
+
+ pUsedList = new SvXMLNumUsedList_Impl;
+}
+
+SvXMLNumFmtExport::~SvXMLNumFmtExport()
+{
+ delete pUsedList;
+ delete pLocaleData;
+ delete pCharClass;
+}
+
+//-------------------------------------------------------------------------
+
+//
+// helper methods
+//
+
+OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, sal_Bool bDefPart, const rtl::OUString& rPrefix )
+{
+ OUStringBuffer aFmtName( 10L );
+ aFmtName.append( rPrefix );
+ aFmtName.append( nKey );
+ if (!bDefPart)
+ {
+ aFmtName.append( (sal_Unicode)'P' );
+ aFmtName.append( nPart );
+ }
+ return aFmtName.makeStringAndClear();
+}
+
+void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar )
+{
+ if ( rCalendar.getLength() )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_CALENDAR, rCalendar );
+ }
+}
+
+void SvXMLNumFmtExport::AddTextualAttr_Impl( sal_Bool bText )
+{
+ if ( bText ) // non-textual
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE );
+ }
+}
+
+void SvXMLNumFmtExport::AddStyleAttr_Impl( sal_Bool bLong )
+{
+ if ( bLong ) // short is default
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG );
+ }
+}
+
+void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang )
+{
+ if ( nLang != LANGUAGE_SYSTEM )
+ {
+ OUString aLangStr, aCountryStr;
+ MsLangId::convertLanguageToIsoNames( (LanguageType)nLang, aLangStr, aCountryStr );
+
+ if (aLangStr.getLength())
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_LANGUAGE, aLangStr );
+ if (aCountryStr.getLength())
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_COUNTRY, aCountryStr );
+ }
+}
+
+//-------------------------------------------------------------------------
+
+//
+// methods to write individual elements within a format
+//
+
+void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString& rString )
+{
+ // append to sTextContent, write element in FinishTextElement_Impl
+ // to avoid several text elements following each other
+
+ sTextContent.append( rString );
+}
+
+void SvXMLNumFmtExport::FinishTextElement_Impl()
+{
+ if ( sTextContent.getLength() )
+ {
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
+ sal_True, sal_False );
+ rExport.Characters( sTextContent.makeStringAndClear() );
+ }
+}
+
+void SvXMLNumFmtExport::WriteColorElement_Impl( const Color& rColor )
+{
+ FinishTextElement_Impl();
+
+ OUStringBuffer aColStr( 7 );
+ SvXMLUnitConverter::convertColor( aColStr, rColor );
+ rExport.AddAttribute( XML_NAMESPACE_FO, XML_COLOR,
+ aColStr.makeStringAndClear() );
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString,
+ const OUString& rExt )
+{
+ FinishTextElement_Impl();
+
+ if ( rExt.getLength() )
+ {
+ sal_Int32 nLang = rExt.toInt32(16); // hex
+ if ( nLang < 0 ) // extension string may contain "-" separator
+ nLang = -nLang;
+ AddLanguageAttr_Impl( nLang ); // adds to pAttrList
+ }
+
+ SvXMLElementExport aElem( rExport,
+ XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL,
+ sal_True, sal_False );
+ rExport.Characters( rString );
+}
+
+void SvXMLNumFmtExport::WriteBooleanElement_Impl()
+{
+ FinishTextElement_Impl();
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_BOOLEAN,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteTextContentElement_Impl()
+{
+ FinishTextElement_Impl();
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT,
+ sal_True, sal_False );
+}
+
+// date elements
+
+void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, sal_Bool bLong )
+{
+ FinishTextElement_Impl();
+
+ AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, sal_Bool bLong, sal_Bool bText )
+{
+ FinishTextElement_Impl();
+
+ AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+ AddTextualAttr_Impl( bText ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MONTH,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, sal_Bool bLong )
+{
+ FinishTextElement_Impl();
+
+ AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_YEAR,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, sal_Bool bLong )
+{
+ FinishTextElement_Impl();
+
+ AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_ERA,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, sal_Bool bLong )
+{
+ FinishTextElement_Impl();
+
+ AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar )
+{
+ FinishTextElement_Impl();
+
+ AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, sal_Bool bLong )
+{
+ FinishTextElement_Impl();
+
+ AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_QUARTER,
+ sal_True, sal_False );
+}
+
+// time elements
+
+void SvXMLNumFmtExport::WriteHoursElement_Impl( sal_Bool bLong )
+{
+ FinishTextElement_Impl();
+
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_HOURS,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteMinutesElement_Impl( sal_Bool bLong )
+{
+ FinishTextElement_Impl();
+
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MINUTES,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteSecondsElement_Impl( sal_Bool bLong, sal_uInt16 nDecimals )
+{
+ FinishTextElement_Impl();
+
+ AddStyleAttr_Impl( bLong ); // adds to pAttrList
+ if ( nDecimals > 0 )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
+ OUString::valueOf( (sal_Int32) nDecimals ) );
+ }
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_SECONDS,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteAMPMElement_Impl()
+{
+ FinishTextElement_Impl();
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_AM_PM,
+ sal_True, sal_False );
+}
+
+// numbers
+
+void SvXMLNumFmtExport::WriteNumberElement_Impl(
+ sal_Int32 nDecimals, sal_Int32 nInteger,
+ const OUString& rDashStr, sal_Bool bVarDecimals,
+ sal_Bool bGrouping, sal_Int32 nTrailingThousands,
+ const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
+{
+ FinishTextElement_Impl();
+
+ // decimals
+ if ( nDecimals >= 0 ) // negative = automatic
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
+ OUString::valueOf( nDecimals ) );
+ }
+
+ // integer digits
+ if ( nInteger >= 0 ) // negative = automatic
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
+ OUString::valueOf( nInteger ) );
+ }
+
+ // decimal replacement (dashes) or variable decimals (#)
+ if ( rDashStr.getLength() || bVarDecimals )
+ {
+ // variable decimals means an empty replacement string
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT,
+ rDashStr );
+ }
+
+ // (automatic) grouping separator
+ if ( bGrouping )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
+ }
+
+ // display-factor if there are trailing thousands separators
+ if ( nTrailingThousands )
+ {
+ // each separator character removes three digits
+ double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
+
+ OUStringBuffer aFactStr;
+ SvXMLUnitConverter::convertDouble( aFactStr, fFactor );
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
+ }
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_NUMBER,
+ sal_True, sal_True );
+
+ // number:embedded-text as child elements
+
+ sal_uInt16 nEntryCount = rEmbeddedEntries.Count();
+ for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
+ {
+ SvXMLEmbeddedTextEntry* pObj = rEmbeddedEntries[nEntry];
+
+ // position attribute
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION,
+ OUString::valueOf( pObj->nFormatPos ) );
+ SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT,
+ sal_True, sal_False );
+
+ // text as element content
+ rtl::OUString aContent( pObj->aText );
+ while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1]->nFormatPos == pObj->nFormatPos )
+ {
+ // The array can contain several elements for the same position in the number
+ // (for example, literal text and space from underscores). They must be merged
+ // into a single embedded-text element.
+ aContent += rEmbeddedEntries[nEntry+1]->aText;
+ ++nEntry;
+ }
+ rExport.Characters( aContent );
+ }
+}
+
+void SvXMLNumFmtExport::WriteScientificElement_Impl(
+ sal_Int32 nDecimals, sal_Int32 nInteger,
+ sal_Bool bGrouping, sal_Int32 nExp )
+{
+ FinishTextElement_Impl();
+
+ // decimals
+ if ( nDecimals >= 0 ) // negative = automatic
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
+ OUString::valueOf( nDecimals ) );
+ }
+
+ // integer digits
+ if ( nInteger >= 0 ) // negative = automatic
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
+ OUString::valueOf( nInteger ) );
+ }
+
+ // (automatic) grouping separator
+ if ( bGrouping )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
+ }
+
+ // exponent digits
+ if ( nExp >= 0 )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS,
+ OUString::valueOf( nExp ) );
+ }
+
+ SvXMLElementExport aElem( rExport,
+ XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER,
+ sal_True, sal_False );
+}
+
+void SvXMLNumFmtExport::WriteFractionElement_Impl(
+ sal_Int32 nInteger, sal_Bool bGrouping,
+ sal_Int32 nNumerator, sal_Int32 nDenominator )
+{
+ FinishTextElement_Impl();
+
+ // integer digits
+ if ( nInteger >= 0 ) // negative = default (no integer part)
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
+ OUString::valueOf( nInteger ) );
+ }
+
+ // (automatic) grouping separator
+ if ( bGrouping )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
+ }
+
+ // numerator digits
+ if ( nNumerator >= 0 )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS,
+ OUString::valueOf( nNumerator ) );
+ }
+
+ // denominator digits
+ if ( nDenominator >= 0 )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS,
+ OUString::valueOf( nDenominator ) );
+ }
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION,
+ sal_True, sal_False );
+}
+
+// mapping (condition)
+
+void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
+ sal_Int32 nKey, sal_Int32 nPart )
+{
+ FinishTextElement_Impl();
+
+ if ( nOp != NUMBERFORMAT_OP_NO )
+ {
+ // style namespace
+
+ OUStringBuffer aCondStr( 20L );
+ aCondStr.appendAscii( "value()" ); //! define constant
+ switch ( nOp )
+ {
+ case NUMBERFORMAT_OP_EQ: aCondStr.append( (sal_Unicode) '=' ); break;
+ case NUMBERFORMAT_OP_NE: aCondStr.appendAscii( "<>" ); break;
+ case NUMBERFORMAT_OP_LT: aCondStr.append( (sal_Unicode) '<' ); break;
+ case NUMBERFORMAT_OP_LE: aCondStr.appendAscii( "<=" ); break;
+ case NUMBERFORMAT_OP_GT: aCondStr.append( (sal_Unicode) '>' ); break;
+ case NUMBERFORMAT_OP_GE: aCondStr.appendAscii( ">=" ); break;
+ default:
+ DBG_ERROR("unknown operator");
+ }
+ ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ '.', true );
+
+ rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION,
+ aCondStr.makeStringAndClear() );
+
+ rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME,
+ rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, sal_False,
+ sPrefix ) ) );
+
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_MAP,
+ sal_True, sal_False );
+ }
+}
+
+//-------------------------------------------------------------------------
+// for old (automatic) currency formats: parse currency symbol from text
+
+xub_StrLen lcl_FindSymbol( const String& sUpperStr, const String& sCurString )
+{
+ // search for currency symbol
+ // Quoting as in ImpSvNumberformatScan::Symbol_Division
+
+ xub_StrLen nCPos = 0;
+ while (nCPos != STRING_NOTFOUND)
+ {
+ nCPos = sUpperStr.Search( sCurString, nCPos );
+ if (nCPos != STRING_NOTFOUND)
+ {
+ // in Quotes?
+ xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
+ if ( nQ == STRING_NOTFOUND )
+ {
+ // dm can be escaped as "dm or \d
+ sal_Unicode c;
+ if ( nCPos == 0 ||
+ ((c = sUpperStr.GetChar(xub_StrLen(nCPos-1))) != '"'
+ && c != '\\') )
+ {
+ return nCPos; // found
+ }
+ else
+ nCPos++; // continue
+ }
+ else
+ nCPos = nQ + 1; // continue after quote end
+ }
+ }
+ return STRING_NOTFOUND; // not found
+}
+
+sal_Bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString,
+ const ::com::sun::star::lang::Locale& rLocale )
+{
+ // returns TRUE if currency element was written
+
+ sal_Bool bRet = sal_False;
+
+// pLocaleData->setLocale( rLocale );
+// String sCurString = pLocaleData->getCurrSymbol();
+
+ LanguageType nLang = MsLangId::convertLocaleToLanguage( rLocale );
+ pFormatter->ChangeIntl( nLang );
+ String sCurString, sDummy;
+ pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
+
+ pCharClass->setLocale( rLocale );
+ String sUpperStr = pCharClass->upper(rString);
+ xub_StrLen nPos = lcl_FindSymbol( sUpperStr, sCurString );
+ if ( nPos != STRING_NOTFOUND )
+ {
+ sal_Int32 nLength = rString.getLength();
+ sal_Int32 nCurLen = sCurString.Len();
+ sal_Int32 nCont = nPos + nCurLen;
+
+ // text before currency symbol
+ if ( nPos > 0 )
+ AddToTextElement_Impl( rString.copy( 0, nPos ) );
+
+ // currency symbol (empty string -> default)
+ OUString sEmpty;
+ WriteCurrencyElement_Impl( sEmpty, sEmpty );
+ bRet = sal_True;
+
+ // text after currency symbol
+ if ( nCont < nLength )
+ AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) );
+ }
+ else
+ AddToTextElement_Impl( rString ); // simple text
+
+ return bRet; // TRUE: currency element written
+}
+
+//-------------------------------------------------------------------------
+
+OUString lcl_GetDefaultCalendar( SvNumberFormatter* pFormatter, LanguageType nLang )
+{
+ // get name of first non-gregorian calendar for the language
+
+ OUString aCalendar;
+ CalendarWrapper* pCalendar = pFormatter->GetCalendar();
+ if (pCalendar)
+ {
+ lang::Locale aLocale( MsLangId::convertLanguageToLocale( nLang ) );
+
+ uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
+ sal_Int32 nCnt = aCals.getLength();
+ sal_Bool bFound = sal_False;
+ for ( sal_Int32 j=0; j < nCnt && !bFound; j++ )
+ {
+ if ( !aCals[j].equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("gregorian") ) )
+ {
+ aCalendar = aCals[j];
+ bFound = sal_True;
+ }
+ }
+ }
+ return aCalendar;
+}
+
+//-------------------------------------------------------------------------
+
+sal_Bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
+{
+ sal_uInt16 nCount = rEmbeddedEntries.Count();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ( rEmbeddedEntries[i]->nSourcePos == nPos )
+ return sal_True;
+
+ return sal_False; // not found
+}
+
+BOOL lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, sal_Bool bSystemDate, NfIndexTableOffset eBuiltIn )
+{
+ // make an extra loop to collect date elements, to check if it is a default format
+ // before adding the automatic-order attribute
+
+ SvXMLDateElementAttributes eDateDOW = XML_DEA_NONE;
+ SvXMLDateElementAttributes eDateDay = XML_DEA_NONE;
+ SvXMLDateElementAttributes eDateMonth = XML_DEA_NONE;
+ SvXMLDateElementAttributes eDateYear = XML_DEA_NONE;
+ SvXMLDateElementAttributes eDateHours = XML_DEA_NONE;
+ SvXMLDateElementAttributes eDateMins = XML_DEA_NONE;
+ SvXMLDateElementAttributes eDateSecs = XML_DEA_NONE;
+ sal_Bool bDateNoDefault = sal_False;
+
+ sal_uInt16 nPos = 0;
+ sal_Bool bEnd = sal_False;
+ short nLastType = 0;
+ while (!bEnd)
+ {
+ short nElemType = rFormat.GetNumForType( 0, nPos, sal_False );
+ switch ( nElemType )
+ {
+ case 0:
+ if ( nLastType == NF_SYMBOLTYPE_STRING )
+ bDateNoDefault = sal_True; // text at the end -> no default date format
+ bEnd = sal_True; // end of format reached
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_DATESEP:
+ case NF_SYMBOLTYPE_TIMESEP:
+ case NF_SYMBOLTYPE_TIME100SECSEP:
+ // text is ignored, except at the end
+ break;
+ // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
+ 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
+ }
+ nLastType = nElemType;
+ ++nPos;
+ }
+
+ if ( bDateNoDefault )
+ return FALSE; // additional elements
+ else
+ {
+ NfIndexTableOffset eFound = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
+ eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate );
+
+ return ( eFound == eBuiltIn );
+ }
+}
+
+//
+// export one part (condition)
+//
+
+void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey,
+ sal_uInt16 nPart, sal_Bool bDefPart )
+{
+ //! for the default part, pass the coditions from the other parts!
+
+ //
+ // element name
+ //
+
+ NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey );
+
+ short nFmtType = 0;
+ sal_Bool bThousand = sal_False;
+ sal_uInt16 nPrecision = 0;
+ sal_uInt16 nLeading = 0;
+ rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
+ nFmtType &= ~NUMBERFORMAT_DEFINED;
+
+ // special treatment of builtin formats that aren't detected by normal parsing
+ // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
+ if ( eBuiltIn == NF_NUMBER_STANDARD )
+ nFmtType = NUMBERFORMAT_NUMBER;
+ else if ( eBuiltIn == NF_BOOLEAN )
+ nFmtType = NUMBERFORMAT_LOGICAL;
+ else if ( eBuiltIn == NF_TEXT )
+ nFmtType = NUMBERFORMAT_TEXT;
+
+ // #101606# An empty subformat is a valid number-style resulting in an
+ // empty display string for the condition of the subformat.
+ if ( nFmtType == NUMBERFORMAT_UNDEFINED && rFormat.GetNumForType( nPart,
+ 0, sal_False ) == 0 )
+ nFmtType = 0;
+
+ XMLTokenEnum eType = XML_TOKEN_INVALID;
+ switch ( nFmtType )
+ {
+ // type is 0 if a format contains no recognized elements
+ // (like text only) - this is handled as a number-style.
+ case 0:
+ case NUMBERFORMAT_NUMBER:
+ case NUMBERFORMAT_SCIENTIFIC:
+ case NUMBERFORMAT_FRACTION:
+ eType = XML_NUMBER_STYLE;
+ break;
+ case NUMBERFORMAT_PERCENT:
+ eType = XML_PERCENTAGE_STYLE;
+ break;
+ case NUMBERFORMAT_CURRENCY:
+ eType = XML_CURRENCY_STYLE;
+ break;
+ case NUMBERFORMAT_DATE:
+ case NUMBERFORMAT_DATETIME:
+ eType = XML_DATE_STYLE;
+ break;
+ case NUMBERFORMAT_TIME:
+ eType = XML_TIME_STYLE;
+ break;
+ case NUMBERFORMAT_TEXT:
+ eType = XML_TEXT_STYLE;
+ break;
+ case NUMBERFORMAT_LOGICAL:
+ eType = XML_BOOLEAN_STYLE;
+ break;
+ }
+ DBG_ASSERT( eType != XML_TOKEN_INVALID, "unknown format type" );
+
+ OUString sAttrValue;
+ sal_Bool bUserDef = ( ( rFormat.GetType() & NUMBERFORMAT_DEFINED ) != 0 );
+
+ //
+ // common attributes for format
+ //
+
+ // format name (generated from key) - style namespace
+ rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
+ lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) );
+
+ // "volatile" attribute for styles used only in maps
+ if ( !bDefPart )
+ rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE );
+
+ // language / country
+ LanguageType nLang = rFormat.GetLanguage();
+ AddLanguageAttr_Impl( nLang ); // adds to pAttrList
+
+ // title (comment)
+ // titles for builtin formats are not written
+ sAttrValue = rFormat.GetComment();
+ if ( sAttrValue.getLength() && bUserDef && bDefPart )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue );
+ }
+
+ // automatic ordering for currency and date formats
+ // only used for some built-in formats
+ BOOL bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 ||
+ eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
+ eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
+ eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG ||
+ eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM ||
+ eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY ||
+ eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
+ eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
+ eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
+ eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
+
+ // format source (for date and time formats)
+ // only used for some built-in formats
+ BOOL bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
+ eBuiltIn == NF_DATE_SYSTEM_LONG ||
+ eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
+ BOOL bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
+
+ // check if the format definition matches the key
+ if ( bAutoOrder && ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) &&
+ !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
+ {
+ bAutoOrder = bSystemDate = bLongSysDate = FALSE; // don't write automatic-order attribute then
+ }
+
+ if ( bAutoOrder &&
+ ( nFmtType == NUMBERFORMAT_CURRENCY || nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
+ {
+ // #85109# format type must be checked to avoid dtd errors if
+ // locale data contains other format types at the built-in positions
+
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER,
+ XML_TRUE );
+ }
+
+ if ( bSystemDate && bAutoOrder &&
+ ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
+ {
+ // #85109# format type must be checked to avoid dtd errors if
+ // locale data contains other format types at the built-in positions
+
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE,
+ XML_LANGUAGE );
+ }
+
+ // overflow for time formats as in [hh]:mm
+ // controlled by bThousand from number format info
+ // default for truncate-on-overflow is true
+ if ( nFmtType == NUMBERFORMAT_TIME && bThousand )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW,
+ XML_FALSE );
+ }
+
+ //
+ // Native number transliteration
+ //
+ ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr;
+ rFormat.GetNatNumXml( aAttr, nPart );
+ if ( aAttr.Format.getLength() )
+ {
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT,
+ aAttr.Format );
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE,
+ aAttr.Locale.Language );
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY,
+ aAttr.Locale.Country );
+ rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE,
+ aAttr.Style );
+ }
+
+ //
+ // The element
+ //
+ SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType,
+ sal_True, sal_True );
+
+ //
+ // color (properties element)
+ //
+
+ const Color* pCol = rFormat.GetColor( nPart );
+ if (pCol)
+ WriteColorElement_Impl(*pCol);
+
+
+ // detect if there is "real" content, excluding color and maps
+ //! move to implementation of Write... methods?
+ sal_Bool bAnyContent = sal_False;
+
+ //
+ // format elements
+ //
+
+ SvXMLEmbeddedTextEntryArr aEmbeddedEntries(0);
+ if ( eBuiltIn == NF_NUMBER_STANDARD )
+ {
+ // default number format contains just one number element
+ WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
+ bAnyContent = sal_True;
+ }
+ else if ( eBuiltIn == NF_BOOLEAN )
+ {
+ // boolean format contains just one boolean element
+ WriteBooleanElement_Impl();
+ bAnyContent = sal_True;
+ }
+ else
+ {
+ // first loop to collect attributes
+
+ sal_Bool bDecDashes = sal_False;
+ sal_Bool bVarDecimals = sal_False;
+ sal_Bool bExpFound = sal_False;
+ sal_Bool bCurrFound = sal_False;
+ sal_Bool bInInteger = sal_True;
+ sal_Int32 nExpDigits = 0;
+ sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#"
+ sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits
+ OUString sCurrExt;
+ OUString aCalendar;
+ sal_uInt16 nPos = 0;
+ sal_Bool bEnd = sal_False;
+ while (!bEnd)
+ {
+ short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
+ const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
+
+ switch ( nElemType )
+ {
+ case 0:
+ bEnd = sal_True; // end of format reached
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ if ( bExpFound && pElemStr )
+ nExpDigits += pElemStr->Len();
+ else if ( !bDecDashes && pElemStr && pElemStr->GetChar(0) == '-' )
+ bDecDashes = TRUE;
+ else if ( !bVarDecimals && !bInInteger && pElemStr && pElemStr->GetChar(0) == '#' )
+ {
+ // If the decimal digits string starts with a '#', variable
+ // decimals is assumed (for 0.###, but not 0.0##).
+ bVarDecimals = sal_True;
+ }
+ if ( bInInteger && pElemStr )
+ nIntegerSymbols += pElemStr->Len();
+ nTrailingThousands = 0;
+ break;
+ case NF_SYMBOLTYPE_DECSEP:
+ bInInteger = sal_False;
+ break;
+ case NF_SYMBOLTYPE_THSEP:
+ if (pElemStr)
+ nTrailingThousands += pElemStr->Len(); // is reset to 0 if digits follow
+ break;
+ case NF_SYMBOLTYPE_EXP:
+ bExpFound = sal_True; // following digits are exponent digits
+ bInInteger = sal_False;
+ break;
+ case NF_SYMBOLTYPE_CURRENCY:
+ bCurrFound = TRUE;
+ break;
+ case NF_SYMBOLTYPE_CURREXT:
+ if (pElemStr)
+ sCurrExt = *pElemStr;
+ break;
+
+ // E, EE, R, RR: select non-gregorian calendar
+ // AAA, AAAA: calendar is switched at the position of the element
+ case NF_KEY_EC:
+ case NF_KEY_EEC:
+ case NF_KEY_R:
+ case NF_KEY_RR:
+ if (!aCalendar.getLength())
+ aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
+ break;
+ }
+ ++nPos;
+ }
+
+ // collect strings for embedded-text (must be known before number element is written)
+
+ sal_Bool bAllowEmbedded = ( nFmtType == 0 || nFmtType == NUMBERFORMAT_NUMBER ||
+ nFmtType == NUMBERFORMAT_CURRENCY ||
+ nFmtType == NUMBERFORMAT_PERCENT );
+ if ( bAllowEmbedded )
+ {
+ sal_Int32 nDigitsPassed = 0;
+ nPos = 0;
+ bEnd = sal_False;
+ while (!bEnd)
+ {
+ short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
+ const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
+
+ switch ( nElemType )
+ {
+ case 0:
+ bEnd = sal_True; // end of format reached
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ if ( pElemStr )
+ nDigitsPassed += pElemStr->Len();
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_BLANK:
+ case NF_SYMBOLTYPE_PERCENT:
+ if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr )
+ {
+ // text (literal or underscore) within the integer part of a number:number element
+
+ String aEmbeddedStr;
+ if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
+ aEmbeddedStr = *pElemStr;
+ else
+ SvNumberformat::InsertBlanks( aEmbeddedStr, 0, pElemStr->GetChar(1) );
+
+ sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
+
+ SvXMLEmbeddedTextEntry* pObj = new SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr );
+ aEmbeddedEntries.Insert( pObj, aEmbeddedEntries.Count() );
+ }
+ break;
+ }
+ ++nPos;
+ }
+ }
+
+ // final loop to write elements
+
+ sal_Bool bNumWritten = sal_False;
+ sal_Bool bCurrencyWritten = sal_False;
+ short nPrevType = 0;
+ nPos = 0;
+ bEnd = sal_False;
+ while (!bEnd)
+ {
+ short nElemType = rFormat.GetNumForType( nPart, nPos, sal_False );
+ const XubString* pElemStr = rFormat.GetNumForString( nPart, nPos, sal_False );
+
+ switch ( nElemType )
+ {
+ case 0:
+ bEnd = sal_True; // end of format reached
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_DATESEP:
+ case NF_SYMBOLTYPE_TIMESEP:
+ case NF_SYMBOLTYPE_TIME100SECSEP:
+ case NF_SYMBOLTYPE_PERCENT:
+ if (pElemStr)
+ {
+ if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
+ ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
+ nPrecision > 0 )
+ {
+ // decimal separator after seconds is implied by
+ // "decimal-places" attribute and must not be written
+ // as text element
+ //! difference between '.' and ',' is lost here
+ }
+ else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
+ {
+ // text is written as embedded-text child of the number,
+ // don't create a text element
+ }
+ else if ( nFmtType == NUMBERFORMAT_CURRENCY && !bCurrFound && !bCurrencyWritten )
+ {
+ // automatic currency symbol is implemented as part of
+ // normal text -> search for the symbol
+ bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
+ MsLangId::convertLanguageToLocale( nLang ) );
+ bAnyContent = sal_True;
+ }
+ else
+ AddToTextElement_Impl( *pElemStr );
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
+ {
+ // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
+ // (#i20396# the spaces may also be in embedded-text elements)
+
+ String aBlanks;
+ SvNumberformat::InsertBlanks( aBlanks, 0, pElemStr->GetChar(1) );
+ AddToTextElement_Impl( aBlanks );
+ }
+ break;
+ case NF_KEY_GENERAL :
+ WriteNumberElement_Impl( -1, 1, OUString(), sal_False, sal_False, 0, aEmbeddedEntries );
+ break;
+ case NF_KEY_CCC:
+ if (pElemStr)
+ {
+ if ( bCurrencyWritten )
+ AddToTextElement_Impl( *pElemStr ); // never more than one currency element
+ else
+ {
+ //! must be different from short automatic format
+ //! but should still be empty (meaning automatic)
+ // pElemStr is "CCC"
+
+ WriteCurrencyElement_Impl( *pElemStr, OUString() );
+ bAnyContent = sal_True;
+ bCurrencyWritten = sal_True;
+ }
+ }
+ break;
+ case NF_SYMBOLTYPE_CURRENCY:
+ if (pElemStr)
+ {
+ if ( bCurrencyWritten )
+ AddToTextElement_Impl( *pElemStr ); // never more than one currency element
+ else
+ {
+ WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
+ bAnyContent = sal_True;
+ bCurrencyWritten = sal_True;
+ }
+ }
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ if (!bNumWritten) // write number part
+ {
+ switch ( nFmtType )
+ {
+ // for type 0 (not recognized as a special type),
+ // write a "normal" number
+ case 0:
+ case NUMBERFORMAT_NUMBER:
+ case NUMBERFORMAT_CURRENCY:
+ case NUMBERFORMAT_PERCENT:
+ {
+ // decimals
+ // only some built-in formats have automatic decimals
+ sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo
+ if ( eBuiltIn == NF_NUMBER_STANDARD ||
+ eBuiltIn == NF_CURRENCY_1000DEC2 ||
+ eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
+ eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
+ eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
+ nDecimals = -1;
+
+ // integer digits
+ // only one built-in format has automatic integer digits
+ sal_Int32 nInteger = nLeading;
+ if ( eBuiltIn == NF_NUMBER_SYSTEM )
+ nInteger = -1;
+
+ // string for decimal replacement
+ // has to be taken from nPrecision
+ // (positive number even for automatic decimals)
+ String sDashStr;
+ if ( bDecDashes && nPrecision > 0 )
+ sDashStr.Fill( nPrecision, '-' );
+
+ WriteNumberElement_Impl( nDecimals, nInteger, sDashStr, bVarDecimals,
+ bThousand, nTrailingThousands, aEmbeddedEntries );
+ bAnyContent = sal_True;
+ }
+ break;
+ case NUMBERFORMAT_SCIENTIFIC:
+ // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
+ // as integer digits: use nIntegerSymbols instead of nLeading
+ // (use of '#' to select multiples in exponent might be added later)
+ WriteScientificElement_Impl( nPrecision, nIntegerSymbols, bThousand, nExpDigits );
+ bAnyContent = sal_True;
+ break;
+ case NUMBERFORMAT_FRACTION:
+ {
+ sal_Int32 nInteger = nLeading;
+ if ( pElemStr && pElemStr->GetChar(0) == '?' )
+ {
+ // If the first digit character is a question mark,
+ // the fraction doesn't have an integer part, and no
+ // min-integer-digits attribute must be written.
+ nInteger = -1;
+ }
+ WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nPrecision );
+ bAnyContent = sal_True;
+ }
+ break;
+ }
+
+ bNumWritten = sal_True;
+ }
+ break;
+ case NF_SYMBOLTYPE_DECSEP:
+ if ( pElemStr && nPrecision == 0 )
+ {
+ // A decimal separator after the number, without following decimal digits,
+ // isn't modelled as part of the number element, so it's written as text
+ // (the distinction between a quoted and non-quoted, locale-dependent
+ // character is lost here).
+
+ AddToTextElement_Impl( *pElemStr );
+ }
+ break;
+ case NF_SYMBOLTYPE_DEL:
+ if ( pElemStr && *pElemStr == XubString('@') )
+ {
+ WriteTextContentElement_Impl();
+ bAnyContent = sal_True;
+ }
+ break;
+
+ case NF_SYMBOLTYPE_CALENDAR:
+ if ( pElemStr )
+ aCalendar = *pElemStr;
+ break;
+
+ // date elements:
+
+ case NF_KEY_D:
+ case NF_KEY_DD:
+ {
+ sal_Bool bLong = ( nElemType == NF_KEY_DD );
+ WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
+ bAnyContent = sal_True;
+ }
+ break;
+ case NF_KEY_DDD:
+ case NF_KEY_DDDD:
+ case NF_KEY_NN:
+ case NF_KEY_NNN:
+ case NF_KEY_NNNN:
+ case NF_KEY_AAA:
+ case NF_KEY_AAAA:
+ {
+ OUString aCalAttr = aCalendar;
+ if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
+ {
+ // calendar attribute for AAA and AAAA is switched only for this element
+ if (!aCalAttr.getLength())
+ aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang );
+ }
+
+ sal_Bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
+ nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
+ WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
+ bAnyContent = sal_True;
+ if ( nElemType == NF_KEY_NNNN )
+ {
+ // write additional text element for separator
+ pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) );
+ AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() );
+ }
+ }
+ break;
+ case NF_KEY_M:
+ case NF_KEY_MM:
+ case NF_KEY_MMM:
+ case NF_KEY_MMMM:
+ case NF_KEY_MMMMM: //! first letter of month name, no attribute available
+ {
+ sal_Bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM );
+ sal_Bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
+ nElemType == NF_KEY_MMMMM );
+ WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
+ bAnyContent = sal_True;
+ }
+ break;
+ case NF_KEY_YY:
+ case NF_KEY_YYYY:
+ case NF_KEY_EC:
+ case NF_KEY_EEC:
+ case NF_KEY_R: //! R acts as EE, no attribute available
+ {
+ //! distinguish EE and R
+ // calendar attribute for E and EE and R is set in first loop
+ sal_Bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
+ nElemType == NF_KEY_R );
+ WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
+ bAnyContent = sal_True;
+ }
+ break;
+ case NF_KEY_G:
+ case NF_KEY_GG:
+ case NF_KEY_GGG:
+ case NF_KEY_RR: //! RR acts as GGGEE, no attribute available
+ {
+ //! distinguish GG and GGG and RR
+ sal_Bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
+ WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
+ bAnyContent = sal_True;
+ if ( nElemType == NF_KEY_RR )
+ {
+ // calendar attribute for RR is set in first loop
+ WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : sal_True ) );
+ }
+ }
+ break;
+ case NF_KEY_Q:
+ case NF_KEY_QQ:
+ {
+ sal_Bool bLong = ( nElemType == NF_KEY_QQ );
+ WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
+ bAnyContent = sal_True;
+ }
+ break;
+ case NF_KEY_WW:
+ WriteWeekElement_Impl( aCalendar );
+ bAnyContent = sal_True;
+ break;
+
+ // time elements (bSystemDate is not used):
+
+ case NF_KEY_H:
+ case NF_KEY_HH:
+ WriteHoursElement_Impl( nElemType == NF_KEY_HH );
+ bAnyContent = sal_True;
+ break;
+ case NF_KEY_MI:
+ case NF_KEY_MMI:
+ WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
+ bAnyContent = sal_True;
+ break;
+ case NF_KEY_S:
+ case NF_KEY_SS:
+ WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
+ bAnyContent = sal_True;
+ break;
+ case NF_KEY_AMPM:
+ case NF_KEY_AP:
+ WriteAMPMElement_Impl(); // short/long?
+ bAnyContent = sal_True;
+ break;
+ }
+ nPrevType = nElemType;
+ ++nPos;
+ }
+ }
+
+ if ( sTextContent.getLength() )
+ bAnyContent = sal_True; // element written in FinishTextElement_Impl
+
+ FinishTextElement_Impl(); // final text element - before maps
+
+ if ( !bAnyContent )
+ {
+ // for an empty format, write an empty text element
+ SvXMLElementExport aTElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
+ sal_True, sal_False );
+ }
+
+ //
+ // mapping (conditions) must be last elements
+ //
+
+ if (bDefPart)
+ {
+ SvNumberformatLimitOps eOp1, eOp2;
+ double fLimit1, fLimit2;
+ rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
+
+ WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
+ WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
+
+ if ( rFormat.HasTextFormat() )
+ {
+ // 4th part is for text -> make an "all other numbers" condition for the 3rd part
+ // by reversing the 2nd condition
+
+ SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO;
+ double fLimit3 = fLimit2;
+ switch ( eOp2 )
+ {
+ case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
+ case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
+ case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
+ case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
+ case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
+ case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
+ default:
+ break;
+ }
+
+ if ( fLimit1 == fLimit2 &&
+ ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
+ ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
+ {
+ // For <x and >x, add =x as last condition
+ // (just for readability, <=x would be valid, too)
+
+ eOp3 = NUMBERFORMAT_OP_EQ;
+ }
+
+ WriteMapElement_Impl( eOp3, fLimit3, nKey, 2 );
+ }
+ }
+}
+
+//-------------------------------------------------------------------------
+
+//
+// export one format
+//
+
+void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey )
+{
+ sal_uInt16 nUsedParts = 0;
+ sal_uInt16 nPart;
+ for (nPart=0; nPart<XMLNUM_MAX_PARTS; nPart++)
+ if (rFormat.GetNumForType( nPart, 0, sal_False ) != 0)
+ nUsedParts = nPart+1;
+
+ SvNumberformatLimitOps eOp1, eOp2;
+ double fLimit1, fLimit2;
+ rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
+
+ // if conditions are set, even empty formats must be written
+
+ if ( eOp1 != NUMBERFORMAT_OP_NO && nUsedParts < 2 )
+ nUsedParts = 2;
+ if ( eOp2 != NUMBERFORMAT_OP_NO && nUsedParts < 3 )
+ nUsedParts = 3;
+ if ( rFormat.HasTextFormat() && nUsedParts < 4 )
+ nUsedParts = 4;
+
+ for (nPart=0; nPart<nUsedParts; nPart++)
+ {
+ sal_Bool bDefault = ( nPart+1 == nUsedParts ); // last = default
+ ExportPart_Impl( rFormat, nKey, nPart, bDefault );
+ }
+}
+
+//-------------------------------------------------------------------------
+
+//
+// export method called by application
+//
+
+void SvXMLNumFmtExport::Export( sal_Bool bIsAutoStyle )
+{
+ if ( !pFormatter )
+ return; // no formatter -> no entries
+
+ sal_uInt32 nKey;
+ const SvNumberformat* pFormat = NULL;
+ sal_Bool bNext(pUsedList->GetFirstUsed(nKey));
+ while(bNext)
+ {
+ pFormat = pFormatter->GetEntry(nKey);
+ if(pFormat)
+ ExportFormat_Impl( *pFormat, nKey );
+ bNext = pUsedList->GetNextUsed(nKey);
+ }
+ if (!bIsAutoStyle)
+ {
+ SvUShorts aLanguages;
+ pFormatter->GetUsedLanguages( aLanguages );
+ sal_uInt16 nLangCount = aLanguages.Count();
+ for (sal_uInt16 nLangPos=0; nLangPos<nLangCount; nLangPos++)
+ {
+ LanguageType nLang = aLanguages[nLangPos];
+
+ sal_uInt32 nDefaultIndex = 0;
+ SvNumberFormatTable& rTable = pFormatter->GetEntryTable(
+ NUMBERFORMAT_DEFINED, nDefaultIndex, nLang );
+ pFormat = rTable.First();
+ while (pFormat)
+ {
+ nKey = rTable.GetCurKey();
+ if (!pUsedList->IsUsed(nKey))
+ {
+ DBG_ASSERT((pFormat->GetType() & NUMBERFORMAT_DEFINED) != 0, "a not user defined numberformat found");
+ // user-defined and used formats are exported
+ ExportFormat_Impl( *pFormat, nKey );
+ // if it is a user-defined Format it will be added else nothing will hapen
+ pUsedList->SetUsed(nKey);
+ }
+
+ pFormat = rTable.Next();
+ }
+ }
+ }
+ pUsedList->Export();
+}
+
+OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
+{
+ if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey))
+ return lcl_CreateStyleName( nKey, 0, sal_True, sPrefix );
+ else
+ {
+ DBG_ERROR("There is no written Data-Style");
+ return rtl::OUString();
+ }
+}
+
+void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
+{
+ DBG_ASSERT( pFormatter != NULL, "missing formatter" );
+ if( !pFormatter )
+ return;
+
+ if (pFormatter->GetEntry(nKey))
+ pUsedList->SetUsed( nKey );
+ else {
+ DBG_ERROR("no existing Numberformat found with this key");
+ }
+}
+
+void SvXMLNumFmtExport::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
+{
+ if (pUsedList)
+ pUsedList->GetWasUsed(rWasUsed);
+}
+
+void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
+{
+ if (pUsedList)
+ pUsedList->SetWasUsed(rWasUsed);
+}
+
+
+
+const SvNumberformat* lcl_GetFormat( SvNumberFormatter* pFormatter,
+ sal_uInt32 nKey )
+{
+ return ( pFormatter != NULL ) ? pFormatter->GetEntry( nKey ) : NULL;
+}
+
+sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
+{
+ sal_uInt32 nRet = nKey;
+
+ const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey );
+ if( pFormat != NULL )
+ {
+ DBG_ASSERT( pFormatter != NULL, "format without formatter?" );
+
+ xub_StrLen nErrorPos;
+ short nType = pFormat->GetType();
+
+ sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn(
+ nKey, LANGUAGE_SYSTEM );
+
+ if( nNewKey != nKey )
+ {
+ nRet = nNewKey;
+ }
+ else
+ {
+ String aFormatString( pFormat->GetFormatstring() );
+ pFormatter->PutandConvertEntry(
+ aFormatString,
+ nErrorPos, nType, nNewKey,
+ pFormat->GetLanguage(), LANGUAGE_SYSTEM );
+
+ // success? Then use new key.
+ if( nErrorPos == 0 )
+ nRet = nNewKey;
+ }
+ }
+
+ return nRet;
+}