LCOV - code coverage report
Current view: top level - xmloff/source/style - xmlnumfe.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 615 798 77.1 %
Date: 2014-04-11 Functions: 52 60 86.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <comphelper/string.hxx>
      21             : #include <svl/zforlist.hxx>
      22             : #include <svl/zformat.hxx>
      23             : #include <svl/numuno.hxx>
      24             : #include <i18nlangtag/mslangid.hxx>
      25             : #include <i18nlangtag/languagetag.hxx>
      26             : #include <tools/debug.hxx>
      27             : #include <rtl/math.hxx>
      28             : #include <unotools/calendarwrapper.hxx>
      29             : #include <unotools/charclass.hxx>
      30             : #include <com/sun/star/lang/Locale.hpp>
      31             : #include <rtl/ustrbuf.hxx>
      32             : #include <tools/color.hxx>
      33             : #include <sax/tools/converter.hxx>
      34             : 
      35             : #include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp>
      36             : 
      37             : #include <xmloff/xmlnumfe.hxx>
      38             : #include <xmloff/xmlnmspe.hxx>
      39             : #include <xmloff/attrlist.hxx>
      40             : #include <xmloff/nmspmap.hxx>
      41             : #include <xmloff/families.hxx>
      42             : #include <xmloff/xmlnumfi.hxx>
      43             : 
      44             : #include <svl/nfsymbol.hxx>
      45             : #include <xmloff/xmltoken.hxx>
      46             : #include <xmloff/xmlexp.hxx>
      47             : 
      48             : #include <set>
      49             : #include <boost/ptr_container/ptr_vector.hpp>
      50             : 
      51             : using namespace ::com::sun::star;
      52             : using namespace ::xmloff::token;
      53             : using namespace ::svt;
      54             : 
      55             : #define XMLNUM_MAX_PARTS    3
      56             : 
      57             : struct LessuInt32
      58             : {
      59        8719 :     bool operator() (const sal_uInt32 rValue1, const sal_uInt32 rValue2) const
      60             :     {
      61        8719 :         return rValue1 < rValue2;
      62             :     }
      63             : };
      64             : 
      65             : typedef std::set< sal_uInt32, LessuInt32 >  SvXMLuInt32Set;
      66             : 
      67             : class SvXMLNumUsedList_Impl
      68             : {
      69             :     SvXMLuInt32Set              aUsed;
      70             :     SvXMLuInt32Set              aWasUsed;
      71             :     SvXMLuInt32Set::iterator    aCurrentUsedPos;
      72             :     sal_uInt32                  nUsedCount;
      73             :     sal_uInt32                  nWasUsedCount;
      74             : 
      75             : public:
      76             :             SvXMLNumUsedList_Impl();
      77             :             ~SvXMLNumUsedList_Impl();
      78             : 
      79             :     void    SetUsed( sal_uInt32 nKey );
      80             :     bool    IsUsed( sal_uInt32 nKey ) const;
      81             :     bool    IsWasUsed( sal_uInt32 nKey ) const;
      82             :     void    Export();
      83             : 
      84             :     bool    GetFirstUsed(sal_uInt32& nKey);
      85             :     bool    GetNextUsed(sal_uInt32& nKey);
      86             : 
      87             :     void GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed);
      88             :     void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed);
      89             : };
      90             : 
      91           0 : struct SvXMLEmbeddedTextEntry
      92             : {
      93             :     sal_uInt16      nSourcePos;     // position in NumberFormat (to skip later)
      94             :     sal_Int32       nFormatPos;     // resulting position in embedded-text element
      95             :     OUString   aText;
      96             : 
      97           0 :     SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, const OUString& rT ) :
      98           0 :         nSourcePos(nSP), nFormatPos(nFP), aText(rT) {}
      99             : };
     100             : 
     101         888 : class SvXMLEmbeddedTextEntryArr : public boost::ptr_vector<SvXMLEmbeddedTextEntry> {};
     102             : 
     103             : //! SvXMLNumUsedList_Impl should be optimized!
     104             : 
     105         843 : SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
     106             :     nUsedCount(0),
     107         843 :     nWasUsedCount(0)
     108             : {
     109         843 : }
     110             : 
     111         843 : SvXMLNumUsedList_Impl::~SvXMLNumUsedList_Impl()
     112             : {
     113         843 : }
     114             : 
     115        2161 : void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey )
     116             : {
     117        2161 :     if ( !IsWasUsed(nKey) )
     118             :     {
     119        1164 :         std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey );
     120        1164 :         if (aPair.second)
     121         420 :             nUsedCount++;
     122             :     }
     123        2161 : }
     124             : 
     125        1049 : bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const
     126             : {
     127        1049 :     SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey);
     128        1049 :     return (aItr != aUsed.end());
     129             : }
     130             : 
     131        3146 : bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const
     132             : {
     133        3146 :     SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey);
     134        3146 :     return (aItr != aWasUsed.end());
     135             : }
     136             : 
     137         337 : void SvXMLNumUsedList_Impl::Export()
     138             : {
     139         337 :     SvXMLuInt32Set::const_iterator aItr = aUsed.begin();
     140        1077 :     while (aItr != aUsed.end())
     141             :     {
     142         403 :         std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( *aItr );
     143         403 :         if (aPair.second)
     144         403 :             nWasUsedCount++;
     145         403 :         ++aItr;
     146             :     }
     147         337 :     aUsed.clear();
     148         337 :     nUsedCount = 0;
     149         337 : }
     150             : 
     151         337 : bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey)
     152             : {
     153         337 :     bool bRet(false);
     154         337 :     aCurrentUsedPos = aUsed.begin();
     155         337 :     if(nUsedCount)
     156             :     {
     157             :         DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong");
     158         192 :         nKey = *aCurrentUsedPos;
     159         192 :         bRet = true;
     160             :     }
     161         337 :     return bRet;
     162             : }
     163             : 
     164         375 : bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey)
     165             : {
     166         375 :     bool bRet(false);
     167         375 :     if (aCurrentUsedPos != aUsed.end())
     168             :     {
     169         375 :         ++aCurrentUsedPos;
     170         375 :         if (aCurrentUsedPos != aUsed.end())
     171             :         {
     172         183 :             nKey = *aCurrentUsedPos;
     173         183 :             bRet = true;
     174             :         }
     175             :     }
     176         375 :     return bRet;
     177             : }
     178             : 
     179          78 : void SvXMLNumUsedList_Impl::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
     180             : {
     181          78 :     rWasUsed.realloc(nWasUsedCount);
     182          78 :     sal_Int32* pWasUsed = rWasUsed.getArray();
     183          78 :     if (pWasUsed)
     184             :     {
     185          78 :         SvXMLuInt32Set::const_iterator aItr = aWasUsed.begin();
     186         311 :         while (aItr != aWasUsed.end())
     187             :         {
     188         155 :             *pWasUsed = *aItr;
     189         155 :             ++aItr;
     190         155 :             ++pWasUsed;
     191             :         }
     192             :     }
     193          78 : }
     194             : 
     195          39 : void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
     196             : {
     197             :     DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty");
     198          39 :     sal_Int32 nCount(rWasUsed.getLength());
     199          39 :     const sal_Int32* pWasUsed = rWasUsed.getConstArray();
     200         112 :     for (sal_uInt16 i = 0; i < nCount; i++, pWasUsed++)
     201             :     {
     202          73 :         std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( *pWasUsed );
     203          73 :         if (aPair.second)
     204          73 :             nWasUsedCount++;
     205             :     }
     206          39 : }
     207             : 
     208         843 : SvXMLNumFmtExport::SvXMLNumFmtExport(
     209             :             SvXMLExport& rExp,
     210             :             const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) :
     211             :     rExport( rExp ),
     212             :     sPrefix( OUString("N") ),
     213             :     pFormatter( NULL ),
     214             :     pCharClass( NULL ),
     215         843 :     pLocaleData( NULL )
     216             : {
     217             :     //  supplier must be SvNumberFormatsSupplierObj
     218             :     SvNumberFormatsSupplierObj* pObj =
     219         843 :                     SvNumberFormatsSupplierObj::getImplementation( rSupp );
     220         843 :     if (pObj)
     221         843 :         pFormatter = pObj->GetNumberFormatter();
     222             : 
     223         843 :     if ( pFormatter )
     224             :     {
     225             :         pCharClass = new CharClass( pFormatter->GetComponentContext(),
     226         843 :             pFormatter->GetLanguageTag() );
     227             :         pLocaleData = new LocaleDataWrapper( pFormatter->GetComponentContext(),
     228         843 :             pFormatter->GetLanguageTag() );
     229             :     }
     230             :     else
     231             :     {
     232           0 :         LanguageTag aLanguageTag( MsLangId::getSystemLanguage() );
     233             : 
     234           0 :         pCharClass = new CharClass( rExport.getComponentContext(), aLanguageTag );
     235           0 :         pLocaleData = new LocaleDataWrapper( rExport.getComponentContext(), aLanguageTag );
     236             :     }
     237             : 
     238         843 :     pUsedList = new SvXMLNumUsedList_Impl;
     239         843 : }
     240             : 
     241           0 : SvXMLNumFmtExport::SvXMLNumFmtExport(
     242             :                        SvXMLExport& rExp,
     243             :                        const ::com::sun::star::uno::Reference<
     244             :                         ::com::sun::star::util::XNumberFormatsSupplier >& rSupp,
     245             :                        const OUString& rPrefix ) :
     246             :     rExport( rExp ),
     247             :     sPrefix( rPrefix ),
     248             :     pFormatter( NULL ),
     249             :     pCharClass( NULL ),
     250           0 :     pLocaleData( NULL )
     251             : {
     252             :     //  supplier must be SvNumberFormatsSupplierObj
     253             :     SvNumberFormatsSupplierObj* pObj =
     254           0 :                     SvNumberFormatsSupplierObj::getImplementation( rSupp );
     255           0 :     if (pObj)
     256           0 :         pFormatter = pObj->GetNumberFormatter();
     257             : 
     258           0 :     if ( pFormatter )
     259             :     {
     260             :         pCharClass = new CharClass( pFormatter->GetComponentContext(),
     261           0 :             pFormatter->GetLanguageTag() );
     262             :         pLocaleData = new LocaleDataWrapper( pFormatter->GetComponentContext(),
     263           0 :             pFormatter->GetLanguageTag() );
     264             :     }
     265             :     else
     266             :     {
     267           0 :         LanguageTag aLanguageTag( MsLangId::getSystemLanguage() );
     268             : 
     269           0 :         pCharClass = new CharClass( rExport.getComponentContext(), aLanguageTag );
     270           0 :         pLocaleData = new LocaleDataWrapper( rExport.getComponentContext(), aLanguageTag );
     271             :     }
     272             : 
     273           0 :     pUsedList = new SvXMLNumUsedList_Impl;
     274           0 : }
     275             : 
     276        2529 : SvXMLNumFmtExport::~SvXMLNumFmtExport()
     277             : {
     278         843 :     delete pUsedList;
     279         843 :     delete pLocaleData;
     280         843 :     delete pCharClass;
     281        1686 : }
     282             : 
     283             : //  helper methods
     284             : 
     285        1489 : static OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, bool bDefPart, const OUString& rPrefix )
     286             : {
     287        1489 :     OUStringBuffer aFmtName( 10L );
     288        1489 :     aFmtName.append( rPrefix );
     289        1489 :     aFmtName.append( nKey );
     290        1489 :     if (!bDefPart)
     291             :     {
     292          82 :         aFmtName.append( 'P' );
     293          82 :         aFmtName.append( nPart );
     294             :     }
     295        1489 :     return aFmtName.makeStringAndClear();
     296             : }
     297             : 
     298         392 : void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar )
     299             : {
     300         392 :     if ( !rCalendar.isEmpty() )
     301             :     {
     302           0 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_CALENDAR, rCalendar );
     303             :     }
     304         392 : }
     305             : 
     306         132 : void SvXMLNumFmtExport::AddTextualAttr_Impl( bool bText )
     307             : {
     308         132 :     if ( bText )            // non-textual
     309             :     {
     310           4 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE );
     311             :     }
     312         132 : }
     313             : 
     314         413 : void SvXMLNumFmtExport::AddStyleAttr_Impl( bool bLong )
     315             : {
     316         413 :     if ( bLong )            // short is default
     317             :     {
     318         395 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG );
     319             :     }
     320         413 : }
     321             : 
     322         486 : void SvXMLNumFmtExport::AddLanguageAttr_Impl( sal_Int32 nLang )
     323             : {
     324         486 :     if ( nLang != LANGUAGE_SYSTEM )
     325             :     {
     326             :         rExport.AddLanguageTagAttributes( XML_NAMESPACE_NUMBER, XML_NAMESPACE_NUMBER,
     327         228 :                 LanguageTag( (LanguageType)nLang), false);
     328             :     }
     329         486 : }
     330             : 
     331             : //  methods to write individual elements within a format
     332             : 
     333         366 : void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString& rString )
     334             : {
     335             :     //  append to sTextContent, write element in FinishTextElement_Impl
     336             :     //  to avoid several text elements following each other
     337             : 
     338         366 :     sTextContent.append( rString );
     339         366 : }
     340             : 
     341        2067 : void SvXMLNumFmtExport::FinishTextElement_Impl()
     342             : {
     343        2067 :     if ( !sTextContent.isEmpty() )
     344             :     {
     345             :         SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
     346         366 :                                   true, false );
     347         366 :         rExport.Characters( sTextContent.makeStringAndClear() );
     348             :     }
     349        2067 : }
     350             : 
     351          26 : void SvXMLNumFmtExport::WriteColorElement_Impl( const Color& rColor )
     352             : {
     353          26 :     FinishTextElement_Impl();
     354             : 
     355          26 :     OUStringBuffer aColStr( 7 );
     356          26 :     ::sax::Converter::convertColor( aColStr, rColor.GetColor() );
     357             :     rExport.AddAttribute( XML_NAMESPACE_FO, XML_COLOR,
     358          26 :                           aColStr.makeStringAndClear() );
     359             : 
     360             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES,
     361          26 :                               true, false );
     362          26 : }
     363             : 
     364          58 : void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString,
     365             :                                                     const OUString& rExt )
     366             : {
     367          58 :     FinishTextElement_Impl();
     368             : 
     369          58 :     if ( !rExt.isEmpty() )
     370             :     {
     371             :         // rExt should be a 16-bit hex value max FFFF which may contain a
     372             :         // leading "-" separator (that is not a minus sign, but toInt32 can be
     373             :         // used to parse it, with post-processing as necessary):
     374          42 :         sal_Int32 nLang = rExt.toInt32(16);
     375          42 :         if ( nLang < 0 )
     376          42 :             nLang = -nLang;
     377          42 :         AddLanguageAttr_Impl( nLang );          // adds to pAttrList
     378             :     }
     379             : 
     380             :     SvXMLElementExport aElem( rExport,
     381             :                               XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL,
     382          58 :                               true, false );
     383          58 :     rExport.Characters( rString );
     384          58 : }
     385             : 
     386           1 : void SvXMLNumFmtExport::WriteBooleanElement_Impl()
     387             : {
     388           1 :     FinishTextElement_Impl();
     389             : 
     390             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_BOOLEAN,
     391           1 :                               true, false );
     392           1 : }
     393             : 
     394           5 : void SvXMLNumFmtExport::WriteTextContentElement_Impl()
     395             : {
     396           5 :     FinishTextElement_Impl();
     397             : 
     398             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT,
     399           5 :                               true, false );
     400           5 : }
     401             : 
     402             : //  date elements
     403             : 
     404         130 : void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, bool bLong )
     405             : {
     406         130 :     FinishTextElement_Impl();
     407             : 
     408         130 :     AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
     409         130 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     410             : 
     411             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY,
     412         130 :                               true, false );
     413         130 : }
     414             : 
     415         132 : void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, bool bLong, bool bText )
     416             : {
     417         132 :     FinishTextElement_Impl();
     418             : 
     419         132 :     AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
     420         132 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     421         132 :     AddTextualAttr_Impl( bText );   // adds to pAttrList
     422             : 
     423             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MONTH,
     424         132 :                               true, false );
     425         132 : }
     426             : 
     427         130 : void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, bool bLong )
     428             : {
     429         130 :     FinishTextElement_Impl();
     430             : 
     431         130 :     AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
     432         130 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     433             : 
     434             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_YEAR,
     435         130 :                               true, false );
     436         130 : }
     437             : 
     438           0 : void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, bool bLong )
     439             : {
     440           0 :     FinishTextElement_Impl();
     441             : 
     442           0 :     AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
     443           0 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     444             : 
     445             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_ERA,
     446           0 :                               true, false );
     447           0 : }
     448             : 
     449           0 : void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, bool bLong )
     450             : {
     451           0 :     FinishTextElement_Impl();
     452             : 
     453           0 :     AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
     454           0 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     455             : 
     456             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK,
     457           0 :                               true, false );
     458           0 : }
     459             : 
     460           0 : void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar )
     461             : {
     462           0 :     FinishTextElement_Impl();
     463             : 
     464           0 :     AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
     465             : 
     466             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR,
     467           0 :                               true, false );
     468           0 : }
     469             : 
     470           0 : void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, bool bLong )
     471             : {
     472           0 :     FinishTextElement_Impl();
     473             : 
     474           0 :     AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
     475           0 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     476             : 
     477             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_QUARTER,
     478           0 :                               true, false );
     479           0 : }
     480             : 
     481             : //  time elements
     482             : 
     483           7 : void SvXMLNumFmtExport::WriteHoursElement_Impl( bool bLong )
     484             : {
     485           7 :     FinishTextElement_Impl();
     486             : 
     487           7 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     488             : 
     489             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_HOURS,
     490           7 :                               true, false );
     491           7 : }
     492             : 
     493           9 : void SvXMLNumFmtExport::WriteMinutesElement_Impl( bool bLong )
     494             : {
     495           9 :     FinishTextElement_Impl();
     496             : 
     497           9 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     498             : 
     499             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MINUTES,
     500           9 :                               true, false );
     501           9 : }
     502             : 
     503          12 : void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar )
     504             : {
     505          12 :     FinishTextElement_Impl();
     506             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_LO_EXT, XML_FILL_CHARACTER,
     507          12 :                                   true, false );
     508          12 :     rExport.Characters( OUString( nChar ) );
     509          12 : }
     510             : 
     511           5 : void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong, sal_uInt16 nDecimals )
     512             : {
     513           5 :     FinishTextElement_Impl();
     514             : 
     515           5 :     AddStyleAttr_Impl( bLong );     // adds to pAttrList
     516           5 :     if ( nDecimals > 0 )
     517             :     {
     518             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
     519           1 :                               OUString::number(  nDecimals ) );
     520             :     }
     521             : 
     522             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_SECONDS,
     523           5 :                               true, false );
     524           5 : }
     525             : 
     526           2 : void SvXMLNumFmtExport::WriteAMPMElement_Impl()
     527             : {
     528           2 :     FinishTextElement_Impl();
     529             : 
     530             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_AM_PM,
     531           2 :                               true, false );
     532           2 : }
     533             : 
     534             : //  numbers
     535             : 
     536         291 : void SvXMLNumFmtExport::WriteNumberElement_Impl(
     537             :                             sal_Int32 nDecimals, sal_Int32 nInteger,
     538             :                             const OUString& rDashStr, bool bVarDecimals,
     539             :                             bool bGrouping, sal_Int32 nTrailingThousands,
     540             :                             const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
     541             : {
     542         291 :     FinishTextElement_Impl();
     543             : 
     544             :     //  decimals
     545         291 :     if ( nDecimals >= 0 )   // negative = automatic
     546             :     {
     547             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
     548         104 :                               OUString::number( nDecimals ) );
     549             :     }
     550             : 
     551             :     //  integer digits
     552         291 :     if ( nInteger >= 0 )    // negative = automatic
     553             :     {
     554             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
     555         291 :                               OUString::number( nInteger ) );
     556             :     }
     557             : 
     558             :     //  decimal replacement (dashes) or variable decimals (#)
     559         291 :     if ( !rDashStr.isEmpty() || bVarDecimals )
     560             :     {
     561             :         //  variable decimals means an empty replacement string
     562             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT,
     563           0 :                               rDashStr );
     564             :     }
     565             : 
     566             :     //  (automatic) grouping separator
     567         291 :     if ( bGrouping )
     568             :     {
     569          71 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
     570             :     }
     571             : 
     572             :     //  display-factor if there are trailing thousands separators
     573         291 :     if ( nTrailingThousands )
     574             :     {
     575             :         //  each separator character removes three digits
     576           0 :         double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
     577             : 
     578           0 :         OUStringBuffer aFactStr;
     579           0 :         ::sax::Converter::convertDouble( aFactStr, fFactor );
     580           0 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
     581             :     }
     582             : 
     583             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_NUMBER,
     584         291 :                               true, true );
     585             : 
     586             :     //  number:embedded-text as child elements
     587             : 
     588         291 :     sal_uInt16 nEntryCount = rEmbeddedEntries.size();
     589         291 :     for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
     590             :     {
     591           0 :         const SvXMLEmbeddedTextEntry* pObj = &rEmbeddedEntries[nEntry];
     592             : 
     593             :         //  position attribute
     594             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION,
     595           0 :                                 OUString::number( pObj->nFormatPos ) );
     596             :         SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT,
     597           0 :                                           true, false );
     598             : 
     599             :         //  text as element content
     600           0 :         OUString aContent( pObj->aText );
     601           0 :         while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1].nFormatPos == pObj->nFormatPos )
     602             :         {
     603             :             // The array can contain several elements for the same position in the number
     604             :             // (for example, literal text and space from underscores). They must be merged
     605             :             // into a single embedded-text element.
     606           0 :             aContent += rEmbeddedEntries[nEntry+1].aText;
     607           0 :             ++nEntry;
     608             :         }
     609           0 :         rExport.Characters( aContent );
     610         291 :     }
     611         291 : }
     612             : 
     613           3 : void SvXMLNumFmtExport::WriteScientificElement_Impl(
     614             :                             sal_Int32 nDecimals, sal_Int32 nInteger,
     615             :                             bool bGrouping, sal_Int32 nExp )
     616             : {
     617           3 :     FinishTextElement_Impl();
     618             : 
     619             :     //  decimals
     620           3 :     if ( nDecimals >= 0 )   // negative = automatic
     621             :     {
     622             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,
     623           3 :                               OUString::number( nDecimals ) );
     624             :     }
     625             : 
     626             :     //  integer digits
     627           3 :     if ( nInteger >= 0 )    // negative = automatic
     628             :     {
     629             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
     630           3 :                               OUString::number( nInteger ) );
     631             :     }
     632             : 
     633             :     //  (automatic) grouping separator
     634           3 :     if ( bGrouping )
     635             :     {
     636           0 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
     637             :     }
     638             : 
     639             :     //  exponent digits
     640           3 :     if ( nExp >= 0 )
     641             :     {
     642             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS,
     643           3 :                               OUString::number( nExp ) );
     644             :     }
     645             : 
     646             :     SvXMLElementExport aElem( rExport,
     647             :                               XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER,
     648           3 :                               true, false );
     649           3 : }
     650             : 
     651           2 : void SvXMLNumFmtExport::WriteFractionElement_Impl(
     652             :                             sal_Int32 nInteger, bool bGrouping,
     653             :                             sal_Int32 nNumeratorDigits, sal_Int32 nDenominatorDigits, sal_Int32 nDenominator )
     654             : {
     655           2 :     FinishTextElement_Impl();
     656             : 
     657             :     //  integer digits
     658           2 :     if ( nInteger >= 0 )        // negative = default (no integer part)
     659             :     {
     660             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,
     661           2 :                               OUString::number( nInteger ) );
     662             :     }
     663             : 
     664             :     //  (automatic) grouping separator
     665           2 :     if ( bGrouping )
     666             :     {
     667           0 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE );
     668             :     }
     669             : 
     670             :     //  numerator digits
     671           2 :     if ( nNumeratorDigits >= 0 )
     672             :     {
     673             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS,
     674           2 :                                  OUString::number( nNumeratorDigits ) );
     675             :     }
     676             : 
     677           2 :     if ( nDenominator )
     678             :     {
     679             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DENOMINATOR_VALUE,
     680           0 :                               OUString::number( nDenominator) );
     681             :     }
     682             :     //  I guess it's not necessary to export nDenominatorDigits
     683             :     //  if we have a forced denominator ( remove ? )
     684           2 :     if ( nDenominatorDigits >= 0 )
     685             :     {
     686             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS,
     687           2 :                               OUString::number( nDenominatorDigits ) );
     688             :     }
     689             : 
     690             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION,
     691           2 :                               true, false );
     692           2 : }
     693             : 
     694             : //  mapping (condition)
     695             : 
     696         810 : void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
     697             :                                                 sal_Int32 nKey, sal_Int32 nPart )
     698             : {
     699         810 :     FinishTextElement_Impl();
     700             : 
     701         810 :     if ( nOp != NUMBERFORMAT_OP_NO )
     702             :     {
     703             :         // style namespace
     704             : 
     705          41 :         OUStringBuffer aCondStr( 20L );
     706          41 :         aCondStr.appendAscii( "value()" );          //! define constant
     707          41 :         switch ( nOp )
     708             :         {
     709           4 :             case NUMBERFORMAT_OP_EQ: aCondStr.append( '=' );  break;
     710           0 :             case NUMBERFORMAT_OP_NE: aCondStr.appendAscii( "!=" );          break;
     711           4 :             case NUMBERFORMAT_OP_LT: aCondStr.append( '<' );  break;
     712           0 :             case NUMBERFORMAT_OP_LE: aCondStr.appendAscii( "<=" );          break;
     713           4 :             case NUMBERFORMAT_OP_GT: aCondStr.append( '>' );  break;
     714          29 :             case NUMBERFORMAT_OP_GE: aCondStr.appendAscii( ">=" );          break;
     715             :             default:
     716             :                 OSL_FAIL("unknown operator");
     717             :         }
     718             :         ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
     719             :                 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
     720          41 :                 '.', true );
     721             : 
     722             :         rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION,
     723          41 :                               aCondStr.makeStringAndClear() );
     724             : 
     725             :         rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME,
     726             :                               rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, false,
     727          41 :                                                    sPrefix ) ) );
     728             : 
     729             :         SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_MAP,
     730          41 :                                   true, false );
     731             :     }
     732         810 : }
     733             : 
     734             : //  for old (automatic) currency formats: parse currency symbol from text
     735             : 
     736          14 : sal_Int32 lcl_FindSymbol( const OUString& sUpperStr, const OUString& sCurString )
     737             : {
     738             :     //  search for currency symbol
     739             :     //  Quoting as in ImpSvNumberformatScan::Symbol_Division
     740             : 
     741          14 :     sal_Int32 nCPos = 0;
     742          28 :     while (nCPos >= 0)
     743             :     {
     744          14 :         nCPos = sUpperStr.indexOf( sCurString, nCPos );
     745          14 :         if (nCPos >= 0)
     746             :         {
     747             :             // in Quotes?
     748          14 :             sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
     749          14 :             if ( nQ < 0 )
     750             :             {
     751             :                 //  dm can be escaped as "dm or \d
     752             :                 sal_Unicode c;
     753          32 :                 if ( nCPos == 0 ||
     754           4 :                     ((c = sUpperStr[nCPos-1]) != '"'
     755           4 :                      && c != '\\') )
     756             :                 {
     757          14 :                     return nCPos;                   // found
     758             :                 }
     759             :                 else
     760             :                 {
     761           0 :                     nCPos++;                        // continue
     762             :                 }
     763             :             }
     764             :             else
     765             :             {
     766           0 :                 nCPos = nQ + 1;                     // continue after quote end
     767             :             }
     768             :         }
     769             :     }
     770           0 :     return -1;
     771             : }
     772             : 
     773          14 : bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString,
     774             :                             const ::com::sun::star::lang::Locale& rLocale )
     775             : {
     776             :     //  returns true if currency element was written
     777             : 
     778          14 :     bool bRet = false;
     779             : 
     780          14 :     LanguageTag aLanguageTag( rLocale );
     781          14 :     pFormatter->ChangeIntl( aLanguageTag.getLanguageType( false) );
     782          28 :     OUString sCurString, sDummy;
     783          14 :     pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
     784             : 
     785          14 :     pCharClass->setLanguageTag( aLanguageTag );
     786          28 :     OUString sUpperStr = pCharClass->uppercase(rString);
     787          14 :     sal_Int32 nPos = lcl_FindSymbol( sUpperStr, sCurString );
     788          14 :     if ( nPos >= 0 )
     789             :     {
     790          14 :         sal_Int32 nLength = rString.getLength();
     791          14 :         sal_Int32 nCurLen = sCurString.getLength();
     792          14 :         sal_Int32 nCont = nPos + nCurLen;
     793             : 
     794             :         //  text before currency symbol
     795          14 :         if ( nPos > 0 )
     796             :         {
     797           4 :             AddToTextElement_Impl( rString.copy( 0, nPos ) );
     798             :         }
     799             :         //  currency symbol (empty string -> default)
     800          14 :         OUString sEmpty;
     801          14 :         WriteCurrencyElement_Impl( sEmpty, sEmpty );
     802          14 :         bRet = true;
     803             : 
     804             :         //  text after currency symbol
     805          14 :         if ( nCont < nLength )
     806             :         {
     807           0 :             AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) );
     808          14 :         }
     809             :     }
     810             :     else
     811             :     {
     812           0 :         AddToTextElement_Impl( rString );       // simple text
     813             :     }
     814             : 
     815          28 :     return bRet;        // true: currency element written
     816             : }
     817             : 
     818           0 : static OUString lcl_GetDefaultCalendar( SvNumberFormatter* pFormatter, LanguageType nLang )
     819             : {
     820             :     //  get name of first non-gregorian calendar for the language
     821             : 
     822           0 :     OUString aCalendar;
     823           0 :     CalendarWrapper* pCalendar = pFormatter->GetCalendar();
     824           0 :     if (pCalendar)
     825             :     {
     826           0 :         lang::Locale aLocale( LanguageTag::convertToLocale( nLang ) );
     827             : 
     828           0 :         uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
     829           0 :         sal_Int32 nCnt = aCals.getLength();
     830           0 :         bool bFound = false;
     831           0 :         for ( sal_Int32 j=0; j < nCnt && !bFound; j++ )
     832             :         {
     833           0 :             if ( aCals[j] != "gregorian" )
     834             :             {
     835           0 :                 aCalendar = aCals[j];
     836           0 :                 bFound = true;
     837             :             }
     838           0 :         }
     839             :     }
     840           0 :     return aCalendar;
     841             : }
     842             : 
     843         376 : static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
     844             : {
     845         376 :     sal_uInt16 nCount = rEmbeddedEntries.size();
     846         376 :     for (sal_uInt16 i=0; i<nCount; i++)
     847           0 :         if ( rEmbeddedEntries[i].nSourcePos == nPos )
     848           0 :             return true;
     849             : 
     850         376 :     return false;       // not found
     851             : }
     852             : 
     853         126 : static bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, bool bSystemDate, NfIndexTableOffset eBuiltIn )
     854             : {
     855             :     //  make an extra loop to collect date elements, to check if it is a default format
     856             :     //  before adding the automatic-order attribute
     857             : 
     858         126 :     SvXMLDateElementAttributes eDateDOW = XML_DEA_NONE;
     859         126 :     SvXMLDateElementAttributes eDateDay = XML_DEA_NONE;
     860         126 :     SvXMLDateElementAttributes eDateMonth = XML_DEA_NONE;
     861         126 :     SvXMLDateElementAttributes eDateYear = XML_DEA_NONE;
     862         126 :     SvXMLDateElementAttributes eDateHours = XML_DEA_NONE;
     863         126 :     SvXMLDateElementAttributes eDateMins = XML_DEA_NONE;
     864         126 :     SvXMLDateElementAttributes eDateSecs = XML_DEA_NONE;
     865         126 :     bool bDateNoDefault = false;
     866             : 
     867         126 :     sal_uInt16 nPos = 0;
     868         126 :     bool bEnd = false;
     869         126 :     short nLastType = 0;
     870        1008 :     while (!bEnd)
     871             :     {
     872         756 :         short nElemType = rFormat.GetNumForType( 0, nPos, false );
     873         756 :         switch ( nElemType )
     874             :         {
     875             :             case 0:
     876         126 :                 if ( nLastType == NF_SYMBOLTYPE_STRING )
     877           0 :                     bDateNoDefault = true;  // text at the end -> no default date format
     878         126 :                 bEnd = true;                // end of format reached
     879         126 :                 break;
     880             :             case NF_SYMBOLTYPE_STRING:
     881             :             case NF_SYMBOLTYPE_DATESEP:
     882             :             case NF_SYMBOLTYPE_TIMESEP:
     883             :             case NF_SYMBOLTYPE_TIME100SECSEP:
     884             :                 // text is ignored, except at the end
     885         252 :                 break;
     886             :             // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
     887           0 :             case NF_KEY_NN:     eDateDOW = XML_DEA_SHORT;       break;
     888             :             case NF_KEY_NNN:
     889           0 :             case NF_KEY_NNNN:   eDateDOW = XML_DEA_LONG;        break;
     890           0 :             case NF_KEY_D:      eDateDay = XML_DEA_SHORT;       break;
     891         126 :             case NF_KEY_DD:     eDateDay = XML_DEA_LONG;        break;
     892           0 :             case NF_KEY_M:      eDateMonth = XML_DEA_SHORT;     break;
     893         126 :             case NF_KEY_MM:     eDateMonth = XML_DEA_LONG;      break;
     894           0 :             case NF_KEY_MMM:    eDateMonth = XML_DEA_TEXTSHORT; break;
     895           0 :             case NF_KEY_MMMM:   eDateMonth = XML_DEA_TEXTLONG;  break;
     896           1 :             case NF_KEY_YY:     eDateYear = XML_DEA_SHORT;      break;
     897         125 :             case NF_KEY_YYYY:   eDateYear = XML_DEA_LONG;       break;
     898           0 :             case NF_KEY_H:      eDateHours = XML_DEA_SHORT;     break;
     899           0 :             case NF_KEY_HH:     eDateHours = XML_DEA_LONG;      break;
     900           0 :             case NF_KEY_MI:     eDateMins = XML_DEA_SHORT;      break;
     901           0 :             case NF_KEY_MMI:    eDateMins = XML_DEA_LONG;       break;
     902           0 :             case NF_KEY_S:      eDateSecs = XML_DEA_SHORT;      break;
     903           0 :             case NF_KEY_SS:     eDateSecs = XML_DEA_LONG;       break;
     904             :             case NF_KEY_AP:
     905           0 :             case NF_KEY_AMPM:   break;          // AM/PM may or may not be in date/time formats -> ignore by itself
     906             :             default:
     907           0 :                 bDateNoDefault = true;      // any other element -> no default format
     908             :         }
     909         756 :         nLastType = nElemType;
     910         756 :         ++nPos;
     911             :     }
     912             : 
     913         126 :     if ( bDateNoDefault )
     914           0 :         return false;                       // additional elements
     915             :     else
     916             :     {
     917             :         NfIndexTableOffset eFound = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
     918         126 :                 eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate );
     919             : 
     920         126 :         return ( eFound == eBuiltIn );
     921             :     }
     922             : }
     923             : 
     924             : //  export one part (condition)
     925             : 
     926         444 : void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey,
     927             :                                             sal_uInt16 nPart, bool bDefPart )
     928             : {
     929             :     //! for the default part, pass the coditions from the other parts!
     930             : 
     931             :     //  element name
     932             : 
     933         444 :     NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey );
     934             : 
     935         444 :     short nFmtType = 0;
     936         444 :     bool bThousand = false;
     937         444 :     sal_uInt16 nPrecision = 0;
     938         444 :     sal_uInt16 nLeading = 0;
     939         444 :     rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
     940         444 :     nFmtType &= ~NUMBERFORMAT_DEFINED;
     941             : 
     942             :     //  special treatment of builtin formats that aren't detected by normal parsing
     943             :     //  (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
     944         444 :     if ( eBuiltIn == NF_NUMBER_STANDARD )
     945         187 :         nFmtType = NUMBERFORMAT_NUMBER;
     946         257 :     else if ( eBuiltIn == NF_BOOLEAN )
     947           1 :         nFmtType = NUMBERFORMAT_LOGICAL;
     948         256 :     else if ( eBuiltIn == NF_TEXT )
     949           0 :         nFmtType = NUMBERFORMAT_TEXT;
     950             : 
     951             :     // #101606# An empty subformat is a valid number-style resulting in an
     952             :     // empty display string for the condition of the subformat.
     953         444 :     if ( nFmtType == NUMBERFORMAT_UNDEFINED && rFormat.GetNumForType( nPart,
     954           0 :                 0, false ) == 0 )
     955           0 :         nFmtType = 0;
     956             : 
     957         444 :     XMLTokenEnum eType = XML_TOKEN_INVALID;
     958         444 :     switch ( nFmtType )
     959             :     {
     960             :         // type is 0 if a format contains no recognized elements
     961             :         // (like text only) - this is handled as a number-style.
     962             :         case 0:
     963             :         case NUMBERFORMAT_NUMBER:
     964             :         case NUMBERFORMAT_SCIENTIFIC:
     965             :         case NUMBERFORMAT_FRACTION:
     966         217 :             eType = XML_NUMBER_STYLE;
     967         217 :             break;
     968             :         case NUMBERFORMAT_PERCENT:
     969          23 :             eType = XML_PERCENTAGE_STYLE;
     970          23 :             break;
     971             :         case NUMBERFORMAT_CURRENCY:
     972          58 :             eType = XML_CURRENCY_STYLE;
     973          58 :             break;
     974             :         case NUMBERFORMAT_DATE:
     975             :         case NUMBERFORMAT_DATETIME:
     976         132 :             eType = XML_DATE_STYLE;
     977         132 :             break;
     978             :         case NUMBERFORMAT_TIME:
     979           8 :             eType = XML_TIME_STYLE;
     980           8 :             break;
     981             :         case NUMBERFORMAT_TEXT:
     982           5 :             eType = XML_TEXT_STYLE;
     983           5 :             break;
     984             :         case NUMBERFORMAT_LOGICAL:
     985           1 :             eType = XML_BOOLEAN_STYLE;
     986           1 :             break;
     987             :     }
     988             :     DBG_ASSERT( eType != XML_TOKEN_INVALID, "unknown format type" );
     989             : 
     990         444 :     OUString sAttrValue;
     991         444 :     bool bUserDef = ( ( rFormat.GetType() & NUMBERFORMAT_DEFINED ) != 0 );
     992             : 
     993             :     //  common attributes for format
     994             : 
     995             :     //  format name (generated from key) - style namespace
     996             :     rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
     997         444 :                         lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) );
     998             : 
     999             :     //  "volatile" attribute for styles used only in maps
    1000         444 :     if ( !bDefPart )
    1001          41 :         rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE );
    1002             : 
    1003             :     //  language / country
    1004         444 :     LanguageType nLang = rFormat.GetLanguage();
    1005         444 :     AddLanguageAttr_Impl( nLang );                  // adds to pAttrList
    1006             : 
    1007             :     //  title (comment)
    1008             :     //  titles for builtin formats are not written
    1009         444 :     sAttrValue = rFormat.GetComment();
    1010         444 :     if ( !sAttrValue.isEmpty() && bUserDef && bDefPart )
    1011             :     {
    1012           0 :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue );
    1013             :     }
    1014             : 
    1015             :     //  automatic ordering for currency and date formats
    1016             :     //  only used for some built-in formats
    1017         444 :     bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT     || eBuiltIn == NF_CURRENCY_1000DEC2 ||
    1018         444 :                         eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
    1019         444 :                         eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
    1020         444 :                         eBuiltIn == NF_DATE_SYSTEM_SHORT    || eBuiltIn == NF_DATE_SYSTEM_LONG ||
    1021         444 :                         eBuiltIn == NF_DATE_SYS_MMYY        || eBuiltIn == NF_DATE_SYS_DDMMM ||
    1022         319 :                         eBuiltIn == NF_DATE_SYS_DDMMYYYY    || eBuiltIn == NF_DATE_SYS_DDMMYY ||
    1023         318 :                         eBuiltIn == NF_DATE_SYS_DMMMYY      || eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
    1024         318 :                         eBuiltIn == NF_DATE_SYS_DMMMMYYYY   || eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
    1025         318 :                         eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
    1026         762 :                         eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
    1027             : 
    1028             :     //  format source (for date and time formats)
    1029             :     //  only used for some built-in formats
    1030         444 :     bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
    1031         888 :                          eBuiltIn == NF_DATE_SYSTEM_LONG  ||
    1032         444 :                          eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
    1033         444 :     bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
    1034             : 
    1035             :     // check if the format definition matches the key
    1036         570 :     if ( bAutoOrder && ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) &&
    1037         126 :             !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
    1038             :     {
    1039           0 :         bAutoOrder = bSystemDate = bLongSysDate = false;        // don't write automatic-order attribute then
    1040             :     }
    1041             : 
    1042         570 :     if ( bAutoOrder &&
    1043         252 :         ( nFmtType == NUMBERFORMAT_CURRENCY || nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
    1044             :     {
    1045             :         //  #85109# format type must be checked to avoid dtd errors if
    1046             :         //  locale data contains other format types at the built-in positions
    1047             : 
    1048             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER,
    1049         126 :                               XML_TRUE );
    1050             :     }
    1051             : 
    1052         444 :     if ( bSystemDate && bAutoOrder &&
    1053           0 :         ( nFmtType == NUMBERFORMAT_DATE || nFmtType == NUMBERFORMAT_DATETIME ) )
    1054             :     {
    1055             :         //  #85109# format type must be checked to avoid dtd errors if
    1056             :         //  locale data contains other format types at the built-in positions
    1057             : 
    1058             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE,
    1059           0 :                               XML_LANGUAGE );
    1060             :     }
    1061             : 
    1062             :     //  overflow for time formats as in [hh]:mm
    1063             :     //  controlled by bThousand from number format info
    1064             :     //  default for truncate-on-overflow is true
    1065         444 :     if ( nFmtType == NUMBERFORMAT_TIME && bThousand )
    1066             :     {
    1067             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW,
    1068           1 :                               XML_FALSE );
    1069             :     }
    1070             : 
    1071             :     // Native number transliteration
    1072         888 :     ::com::sun::star::i18n::NativeNumberXmlAttributes aAttr;
    1073         444 :     rFormat.GetNatNumXml( aAttr, nPart );
    1074         444 :     if ( !aAttr.Format.isEmpty() )
    1075             :     {
    1076             :         /* FIXME-BCP47: ODF defines no transliteration-script or
    1077             :          * transliteration-rfc-language-tag */
    1078           0 :         LanguageTag aLanguageTag( aAttr.Locale);
    1079           0 :         OUString aLanguage, aScript, aCountry;
    1080           0 :         aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
    1081             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT,
    1082           0 :                               aAttr.Format );
    1083             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE,
    1084           0 :                               aLanguage );
    1085             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY,
    1086           0 :                               aCountry );
    1087             :         rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE,
    1088           0 :                               aAttr.Style );
    1089             :     }
    1090             : 
    1091             :     // The element
    1092             :     SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType,
    1093         888 :                               true, true );
    1094             : 
    1095             :     //  color (properties element)
    1096             : 
    1097         444 :     const Color* pCol = rFormat.GetColor( nPart );
    1098         444 :     if (pCol)
    1099          26 :         WriteColorElement_Impl(*pCol);
    1100             : 
    1101             :     //  detect if there is "real" content, excluding color and maps
    1102             :     //! move to implementation of Write... methods?
    1103         444 :     bool bAnyContent = false;
    1104             : 
    1105             :     //  format elements
    1106             : 
    1107         888 :     SvXMLEmbeddedTextEntryArr aEmbeddedEntries;
    1108         444 :     if ( eBuiltIn == NF_NUMBER_STANDARD )
    1109             :     {
    1110             :         //  default number format contains just one number element
    1111         187 :         WriteNumberElement_Impl( -1, 1, OUString(), false, false, 0, aEmbeddedEntries );
    1112         187 :         bAnyContent = true;
    1113             :     }
    1114         257 :     else if ( eBuiltIn == NF_BOOLEAN )
    1115             :     {
    1116             :         //  boolean format contains just one boolean element
    1117           1 :         WriteBooleanElement_Impl();
    1118           1 :         bAnyContent = true;
    1119             :     }
    1120             :     else
    1121             :     {
    1122             :         //  first loop to collect attributes
    1123             : 
    1124         256 :         bool bDecDashes  = false;
    1125         256 :         bool bVarDecimals = false;
    1126         256 :         bool bExpFound   = false;
    1127         256 :         bool bCurrFound  = false;
    1128         256 :         bool bInInteger  = true;
    1129         256 :         sal_Int32 nExpDigits = 0;
    1130         256 :         sal_Int32 nIntegerSymbols = 0;          // for embedded-text, including "#"
    1131         256 :         sal_Int32 nTrailingThousands = 0;       // thousands-separators after all digits
    1132         256 :         OUString sCurrExt;
    1133         512 :         OUString aCalendar;
    1134         256 :         sal_uInt16 nPos = 0;
    1135         256 :         bool bEnd = false;
    1136        2145 :         while (!bEnd)
    1137             :         {
    1138        1633 :             short nElemType = rFormat.GetNumForType( nPart, nPos, false );
    1139        1633 :             const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos, false );
    1140             : 
    1141        1633 :             switch ( nElemType )
    1142             :             {
    1143             :                 case 0:
    1144         256 :                     bEnd = true;                // end of format reached
    1145         256 :                     break;
    1146             :                 case NF_SYMBOLTYPE_DIGIT:
    1147         251 :                     if ( bExpFound && pElemStr )
    1148           3 :                         nExpDigits += pElemStr->getLength();
    1149         248 :                     else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' )
    1150           0 :                         bDecDashes = true;
    1151         248 :                     else if ( !bVarDecimals && !bInInteger && pElemStr && (*pElemStr)[0] == '#' )
    1152             :                     {
    1153             :                         //  If the decimal digits string starts with a '#', variable
    1154             :                         //  decimals is assumed (for 0.###, but not 0.0##).
    1155           0 :                         bVarDecimals = true;
    1156             :                     }
    1157         251 :                     if ( bInInteger && pElemStr )
    1158         185 :                         nIntegerSymbols += pElemStr->getLength();
    1159         251 :                     nTrailingThousands = 0;
    1160         251 :                     break;
    1161             :                 case NF_SYMBOLTYPE_DECSEP:
    1162          63 :                     bInInteger = false;
    1163          63 :                     break;
    1164             :                 case NF_SYMBOLTYPE_THSEP:
    1165          71 :                     if (pElemStr)
    1166          71 :                         nTrailingThousands += pElemStr->getLength();      // is reset to 0 if digits follow
    1167          71 :                     break;
    1168             :                 case NF_SYMBOLTYPE_EXP:
    1169           3 :                     bExpFound = true;           // following digits are exponent digits
    1170           3 :                     bInInteger = false;
    1171           3 :                     break;
    1172             :                 case NF_SYMBOLTYPE_CURRENCY:
    1173          44 :                     bCurrFound = true;
    1174          44 :                     break;
    1175             :                 case NF_SYMBOLTYPE_CURREXT:
    1176          42 :                     if (pElemStr)
    1177          42 :                         sCurrExt = *pElemStr;
    1178          42 :                     break;
    1179             : 
    1180             :                 // E, EE, R, RR: select non-gregorian calendar
    1181             :                 // AAA, AAAA: calendar is switched at the position of the element
    1182             :                 case NF_KEY_EC:
    1183             :                 case NF_KEY_EEC:
    1184             :                 case NF_KEY_R:
    1185             :                 case NF_KEY_RR:
    1186           0 :                     if (aCalendar.isEmpty())
    1187           0 :                         aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
    1188           0 :                     break;
    1189             :             }
    1190        1633 :             ++nPos;
    1191             :         }
    1192             : 
    1193             :         //  collect strings for embedded-text (must be known before number element is written)
    1194             : 
    1195         742 :         bool bAllowEmbedded = ( nFmtType == 0 || nFmtType == NUMBERFORMAT_NUMBER ||
    1196         660 :                                         nFmtType == NUMBERFORMAT_CURRENCY ||
    1197         429 :                                         nFmtType == NUMBERFORMAT_PERCENT );
    1198         256 :         if ( bAllowEmbedded )
    1199             :         {
    1200         106 :             sal_Int32 nDigitsPassed = 0;
    1201         106 :             nPos = 0;
    1202         106 :             bEnd = false;
    1203         966 :             while (!bEnd)
    1204             :             {
    1205         754 :                 short nElemType = rFormat.GetNumForType( nPart, nPos, false );
    1206         754 :                 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos, false );
    1207             : 
    1208         754 :                 switch ( nElemType )
    1209             :                 {
    1210             :                     case 0:
    1211         106 :                         bEnd = true;                // end of format reached
    1212         106 :                         break;
    1213             :                     case NF_SYMBOLTYPE_DIGIT:
    1214         235 :                         if ( pElemStr )
    1215         235 :                             nDigitsPassed += pElemStr->getLength();
    1216         235 :                         break;
    1217             :                     case NF_SYMBOLTYPE_STRING:
    1218             :                     case NF_SYMBOLTYPE_BLANK:
    1219             :                     case NF_SYMBOLTYPE_PERCENT:
    1220          96 :                         if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr )
    1221             :                         {
    1222             :                             //  text (literal or underscore) within the integer part of a number:number element
    1223             : 
    1224           0 :                             OUString aEmbeddedStr;
    1225           0 :                             if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
    1226             :                             {
    1227           0 :                                 aEmbeddedStr = *pElemStr;
    1228             :                             }
    1229             :                             else
    1230             :                             {
    1231           0 :                                 SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] );
    1232             :                             }
    1233           0 :                             sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
    1234             : 
    1235           0 :                             SvXMLEmbeddedTextEntry* pObj = new SvXMLEmbeddedTextEntry( nPos, nEmbedPos, aEmbeddedStr );
    1236           0 :                             aEmbeddedEntries.push_back( pObj );
    1237             :                         }
    1238          96 :                         break;
    1239             :                 }
    1240         754 :                 ++nPos;
    1241             :             }
    1242             :         }
    1243             : 
    1244             :         //  final loop to write elements
    1245             : 
    1246         256 :         bool bNumWritten = false;
    1247         256 :         bool bCurrencyWritten = false;
    1248         256 :         short nPrevType = 0;
    1249         256 :         nPos = 0;
    1250         256 :         bEnd = false;
    1251        2145 :         while (!bEnd)
    1252             :         {
    1253        1633 :             short nElemType = rFormat.GetNumForType( nPart, nPos, false );
    1254        1633 :             const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos, false );
    1255             : 
    1256        1633 :             switch ( nElemType )
    1257             :             {
    1258             :                 case 0:
    1259         256 :                     bEnd = true;                // end of format reached
    1260         256 :                     break;
    1261             :                 case NF_SYMBOLTYPE_STRING:
    1262             :                 case NF_SYMBOLTYPE_DATESEP:
    1263             :                 case NF_SYMBOLTYPE_TIMESEP:
    1264             :                 case NF_SYMBOLTYPE_TIME100SECSEP:
    1265             :                 case NF_SYMBOLTYPE_PERCENT:
    1266         377 :                     if (pElemStr)
    1267             :                     {
    1268         377 :                         if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
    1269           1 :                              ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
    1270           1 :                              nPrecision > 0 )
    1271             :                         {
    1272             :                             //  decimal separator after seconds is implied by
    1273             :                             //  "decimal-places" attribute and must not be written
    1274             :                             //  as text element
    1275             :                             //! difference between '.' and ',' is lost here
    1276             :                         }
    1277         376 :                         else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
    1278             :                         {
    1279             :                             //  text is written as embedded-text child of the number,
    1280             :                             //  don't create a text element
    1281             :                         }
    1282         376 :                         else if ( nFmtType == NUMBERFORMAT_CURRENCY && !bCurrFound && !bCurrencyWritten )
    1283             :                         {
    1284             :                             //  automatic currency symbol is implemented as part of
    1285             :                             //  normal text -> search for the symbol
    1286             :                             bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
    1287          14 :                                 LanguageTag::convertToLocale( nLang ) );
    1288          14 :                             bAnyContent = true;
    1289             :                         }
    1290             :                         else
    1291         362 :                             AddToTextElement_Impl( *pElemStr );
    1292             :                     }
    1293         377 :                     break;
    1294             :                 case NF_SYMBOLTYPE_BLANK:
    1295           0 :                     if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
    1296             :                     {
    1297             :                         //  turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
    1298             :                         //  (#i20396# the spaces may also be in embedded-text elements)
    1299             : 
    1300           0 :                         OUString aBlanks;
    1301           0 :                         SvNumberformat::InsertBlanks( aBlanks, 0, (*pElemStr)[1] );
    1302           0 :                         AddToTextElement_Impl( aBlanks );
    1303             :                     }
    1304           0 :                     break;
    1305             :                 case NF_KEY_GENERAL :
    1306           0 :                         WriteNumberElement_Impl( -1, 1, OUString(), false, false, 0, aEmbeddedEntries );
    1307           0 :                     break;
    1308             :                 case NF_KEY_CCC:
    1309           0 :                     if (pElemStr)
    1310             :                     {
    1311           0 :                         if ( bCurrencyWritten )
    1312           0 :                             AddToTextElement_Impl( *pElemStr );     // never more than one currency element
    1313             :                         else
    1314             :                         {
    1315             :                             //! must be different from short automatic format
    1316             :                             //! but should still be empty (meaning automatic)
    1317             :                             //  pElemStr is "CCC"
    1318             : 
    1319           0 :                             WriteCurrencyElement_Impl( *pElemStr, OUString() );
    1320           0 :                             bAnyContent = true;
    1321           0 :                             bCurrencyWritten = true;
    1322             :                         }
    1323             :                     }
    1324           0 :                     break;
    1325             :                 case NF_SYMBOLTYPE_CURRENCY:
    1326          44 :                     if (pElemStr)
    1327             :                     {
    1328          44 :                         if ( bCurrencyWritten )
    1329           0 :                             AddToTextElement_Impl( *pElemStr );     // never more than one currency element
    1330             :                         else
    1331             :                         {
    1332          44 :                             WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
    1333          44 :                             bAnyContent = true;
    1334          44 :                             bCurrencyWritten = true;
    1335             :                         }
    1336             :                     }
    1337          44 :                     break;
    1338             :                 case NF_SYMBOLTYPE_DIGIT:
    1339         251 :                     if (!bNumWritten)           // write number part
    1340             :                     {
    1341         110 :                         switch ( nFmtType )
    1342             :                         {
    1343             :                             // for type 0 (not recognized as a special type),
    1344             :                             // write a "normal" number
    1345             :                             case 0:
    1346             :                             case NUMBERFORMAT_NUMBER:
    1347             :                             case NUMBERFORMAT_CURRENCY:
    1348             :                             case NUMBERFORMAT_PERCENT:
    1349             :                                 {
    1350             :                                     //  decimals
    1351             :                                     //  only some built-in formats have automatic decimals
    1352         104 :                                     sal_Int32 nDecimals = nPrecision;   // from GetFormatSpecialInfo
    1353         104 :                                     if ( eBuiltIn == NF_NUMBER_STANDARD ||
    1354         104 :                                          eBuiltIn == NF_CURRENCY_1000DEC2 ||
    1355         104 :                                          eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
    1356         104 :                                          eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
    1357             :                                          eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
    1358           0 :                                         nDecimals = -1;
    1359             : 
    1360             :                                     //  integer digits
    1361             :                                     //  only one built-in format has automatic integer digits
    1362         104 :                                     sal_Int32 nInteger = nLeading;
    1363         104 :                                     if ( eBuiltIn == NF_NUMBER_SYSTEM )
    1364           0 :                                         nInteger = -1;
    1365             : 
    1366             :                                     //  string for decimal replacement
    1367             :                                     //  has to be taken from nPrecision
    1368             :                                     //  (positive number even for automatic decimals)
    1369         104 :                                     OUStringBuffer sDashStr;
    1370         104 :                                     if (bDecDashes && nPrecision > 0)
    1371           0 :                                         comphelper::string::padToLength(sDashStr, nPrecision, '-');
    1372             : 
    1373             :                                     WriteNumberElement_Impl(nDecimals, nInteger, sDashStr.makeStringAndClear(),
    1374         104 :                                         bVarDecimals, bThousand, nTrailingThousands, aEmbeddedEntries);
    1375         104 :                                     bAnyContent = true;
    1376             :                                 }
    1377         104 :                                 break;
    1378             :                             case NUMBERFORMAT_SCIENTIFIC:
    1379             :                                 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
    1380             :                                 // as integer digits: use nIntegerSymbols instead of nLeading
    1381             :                                 // (use of '#' to select multiples in exponent might be added later)
    1382           3 :                                 WriteScientificElement_Impl( nPrecision, nIntegerSymbols, bThousand, nExpDigits );
    1383           3 :                                 bAnyContent = true;
    1384           3 :                                 break;
    1385             :                             case NUMBERFORMAT_FRACTION:
    1386             :                                 {
    1387           2 :                                     sal_Int32 nInteger = nLeading;
    1388           2 :                                     if ( pElemStr && (*pElemStr)[0] == '?' )
    1389             :                                     {
    1390             :                                         //  If the first digit character is a question mark,
    1391             :                                         //  the fraction doesn't have an integer part, and no
    1392             :                                         //  min-integer-digits attribute must be written.
    1393           0 :                                         nInteger = -1;
    1394             :                                     }
    1395           2 :                                     sal_Int32 nDenominator = rFormat.GetForcedDenominatorForType( nPart );
    1396           2 :                                     WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nPrecision, nDenominator );
    1397           2 :                                     bAnyContent = true;
    1398             :                                 }
    1399           2 :                                 break;
    1400             :                         }
    1401             : 
    1402         110 :                         bNumWritten = true;
    1403             :                     }
    1404         251 :                     break;
    1405             :                 case NF_SYMBOLTYPE_DECSEP:
    1406          63 :                     if ( pElemStr && nPrecision == 0 )
    1407             :                     {
    1408             :                         //  A decimal separator after the number, without following decimal digits,
    1409             :                         //  isn't modelled as part of the number element, so it's written as text
    1410             :                         //  (the distinction between a quoted and non-quoted, locale-dependent
    1411             :                         //  character is lost here).
    1412             : 
    1413           0 :                         AddToTextElement_Impl( *pElemStr );
    1414             :                     }
    1415          63 :                     break;
    1416             :                 case NF_SYMBOLTYPE_DEL:
    1417           7 :                     if ( pElemStr && comphelper::string::equals(*pElemStr, '@') )
    1418             :                     {
    1419           5 :                         WriteTextContentElement_Impl();
    1420           5 :                         bAnyContent = true;
    1421             :                     }
    1422           7 :                     break;
    1423             : 
    1424             :                 case NF_SYMBOLTYPE_CALENDAR:
    1425           0 :                     if ( pElemStr )
    1426           0 :                         aCalendar = *pElemStr;
    1427           0 :                     break;
    1428             : 
    1429             :                 // date elements:
    1430             : 
    1431             :                 case NF_KEY_D:
    1432             :                 case NF_KEY_DD:
    1433             :                     {
    1434         130 :                         bool bLong = ( nElemType == NF_KEY_DD );
    1435         130 :                         WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
    1436         130 :                         bAnyContent = true;
    1437             :                     }
    1438         130 :                     break;
    1439             :                 case NF_KEY_DDD:
    1440             :                 case NF_KEY_DDDD:
    1441             :                 case NF_KEY_NN:
    1442             :                 case NF_KEY_NNN:
    1443             :                 case NF_KEY_NNNN:
    1444             :                 case NF_KEY_AAA:
    1445             :                 case NF_KEY_AAAA:
    1446             :                     {
    1447           0 :                         OUString aCalAttr = aCalendar;
    1448           0 :                         if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
    1449             :                         {
    1450             :                             //  calendar attribute for AAA and AAAA is switched only for this element
    1451           0 :                             if (aCalAttr.isEmpty())
    1452           0 :                                 aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang );
    1453             :                         }
    1454             : 
    1455           0 :                         bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
    1456           0 :                                            nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
    1457           0 :                         WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
    1458           0 :                         bAnyContent = true;
    1459           0 :                         if ( nElemType == NF_KEY_NNNN )
    1460             :                         {
    1461             :                             //  write additional text element for separator
    1462           0 :                             pLocaleData->setLanguageTag( LanguageTag( nLang ) );
    1463           0 :                             AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() );
    1464           0 :                         }
    1465             :                     }
    1466           0 :                     break;
    1467             :                 case NF_KEY_M:
    1468             :                 case NF_KEY_MM:
    1469             :                 case NF_KEY_MMM:
    1470             :                 case NF_KEY_MMMM:
    1471             :                 case NF_KEY_MMMMM:      //! first letter of month name, no attribute available
    1472             :                     {
    1473         132 :                         bool bLong = ( nElemType == NF_KEY_MM  || nElemType == NF_KEY_MMMM );
    1474         132 :                         bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
    1475         132 :                                             nElemType == NF_KEY_MMMMM );
    1476         132 :                         WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
    1477         132 :                         bAnyContent = true;
    1478             :                     }
    1479         132 :                     break;
    1480             :                 case NF_KEY_YY:
    1481             :                 case NF_KEY_YYYY:
    1482             :                 case NF_KEY_EC:
    1483             :                 case NF_KEY_EEC:
    1484             :                 case NF_KEY_R:      //! R acts as EE, no attribute available
    1485             :                     {
    1486             :                         //! distinguish EE and R
    1487             :                         //  calendar attribute for E and EE and R is set in first loop
    1488         130 :                         bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
    1489         130 :                                             nElemType == NF_KEY_R );
    1490         130 :                         WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
    1491         130 :                         bAnyContent = true;
    1492             :                     }
    1493         130 :                     break;
    1494             :                 case NF_KEY_G:
    1495             :                 case NF_KEY_GG:
    1496             :                 case NF_KEY_GGG:
    1497             :                 case NF_KEY_RR:     //! RR acts as GGGEE, no attribute available
    1498             :                     {
    1499             :                         //! distinguish GG and GGG and RR
    1500           0 :                         bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
    1501           0 :                         WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
    1502           0 :                         bAnyContent = true;
    1503           0 :                         if ( nElemType == NF_KEY_RR )
    1504             :                         {
    1505             :                             //  calendar attribute for RR is set in first loop
    1506           0 :                             WriteYearElement_Impl( aCalendar, ( bSystemDate || bLongSysDate ) );
    1507             :                         }
    1508             :                     }
    1509           0 :                     break;
    1510             :                 case NF_KEY_Q:
    1511             :                 case NF_KEY_QQ:
    1512             :                     {
    1513           0 :                         bool bLong = ( nElemType == NF_KEY_QQ );
    1514           0 :                         WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
    1515           0 :                         bAnyContent = true;
    1516             :                     }
    1517           0 :                     break;
    1518             :                 case NF_KEY_WW:
    1519           0 :                     WriteWeekElement_Impl( aCalendar );
    1520           0 :                     bAnyContent = true;
    1521           0 :                     break;
    1522             : 
    1523             :                 // time elements (bSystemDate is not used):
    1524             : 
    1525             :                 case NF_KEY_H:
    1526             :                 case NF_KEY_HH:
    1527           7 :                     WriteHoursElement_Impl( nElemType == NF_KEY_HH );
    1528           7 :                     bAnyContent = true;
    1529           7 :                     break;
    1530             :                 case NF_KEY_MI:
    1531             :                 case NF_KEY_MMI:
    1532           9 :                     WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
    1533           9 :                     bAnyContent = true;
    1534           9 :                     break;
    1535             :                 case NF_KEY_S:
    1536             :                 case NF_KEY_SS:
    1537           5 :                     WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
    1538           5 :                     bAnyContent = true;
    1539           5 :                     break;
    1540             :                 case NF_KEY_AMPM:
    1541             :                 case NF_KEY_AP:
    1542           2 :                     WriteAMPMElement_Impl();        // short/long?
    1543           2 :                     bAnyContent = true;
    1544           2 :                     break;
    1545             :                 case NF_SYMBOLTYPE_STAR :
    1546             :                     // export only if ODF 1.2 extensions are enabled
    1547          12 :                     if( SvtSaveOptions().GetODFDefaultVersion() > SvtSaveOptions::ODFVER_012 )
    1548             :                     {
    1549          12 :                         if ( pElemStr && pElemStr->getLength() > 1 )
    1550          12 :                             WriteRepeatedElement_Impl( (*pElemStr)[1] );
    1551             :                     }
    1552          12 :                     break;
    1553             :             }
    1554        1633 :             nPrevType = nElemType;
    1555        1633 :             ++nPos;
    1556         256 :         }
    1557             :     }
    1558             : 
    1559         444 :     if ( !sTextContent.isEmpty() )
    1560          53 :         bAnyContent = true;     // element written in FinishTextElement_Impl
    1561             : 
    1562         444 :     FinishTextElement_Impl();       // final text element - before maps
    1563             : 
    1564         444 :     if ( !bAnyContent )
    1565             :     {
    1566             :         //  for an empty format, write an empty text element
    1567             :         SvXMLElementExport aTElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT,
    1568           0 :                                    true, false );
    1569             :     }
    1570             : 
    1571             :     //  mapping (conditions) must be last elements
    1572             : 
    1573         444 :     if (bDefPart)
    1574             :     {
    1575             :         SvNumberformatLimitOps eOp1, eOp2;
    1576             :         double fLimit1, fLimit2;
    1577         403 :         rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
    1578             : 
    1579         403 :         WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
    1580         403 :         WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
    1581             : 
    1582         403 :         if ( rFormat.HasTextFormat() )
    1583             :         {
    1584             :             //  4th part is for text -> make an "all other numbers" condition for the 3rd part
    1585             :             //  by reversing the 2nd condition
    1586             : 
    1587           4 :             SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO;
    1588           4 :             double fLimit3 = fLimit2;
    1589           4 :             switch ( eOp2 )
    1590             :             {
    1591           0 :                 case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
    1592           0 :                 case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
    1593           4 :                 case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
    1594           0 :                 case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
    1595           0 :                 case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
    1596           0 :                 case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
    1597             :                 default:
    1598           0 :                     break;
    1599             :             }
    1600             : 
    1601           8 :             if ( fLimit1 == fLimit2 &&
    1602           8 :                     ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
    1603           8 :                       ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
    1604             :             {
    1605             :                 //  For <x and >x, add =x as last condition
    1606             :                 //  (just for readability, <=x would be valid, too)
    1607             : 
    1608           4 :                 eOp3 = NUMBERFORMAT_OP_EQ;
    1609             :             }
    1610             : 
    1611           4 :             WriteMapElement_Impl( eOp3, fLimit3, nKey, 2 );
    1612             :         }
    1613         444 :     }
    1614         444 : }
    1615             : 
    1616             : //  export one format
    1617             : 
    1618         403 : void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey )
    1619             : {
    1620         403 :     sal_uInt16 nUsedParts = 0;
    1621             :     sal_uInt16 nPart;
    1622        1612 :     for (nPart=0; nPart<XMLNUM_MAX_PARTS; nPart++)
    1623        1209 :         if (rFormat.GetNumForType( nPart, 0, false ) != 0)
    1624         440 :             nUsedParts = nPart+1;
    1625             : 
    1626             :     SvNumberformatLimitOps eOp1, eOp2;
    1627             :     double fLimit1, fLimit2;
    1628         403 :     rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
    1629             : 
    1630             :     //  if conditions are set, even empty formats must be written
    1631             : 
    1632         403 :     if ( eOp1 != NUMBERFORMAT_OP_NO && nUsedParts < 2 )
    1633           0 :         nUsedParts = 2;
    1634         403 :     if ( eOp2 != NUMBERFORMAT_OP_NO && nUsedParts < 3 )
    1635           0 :         nUsedParts = 3;
    1636         403 :     if ( rFormat.HasTextFormat() && nUsedParts < 4 )
    1637           4 :         nUsedParts = 4;
    1638             : 
    1639         847 :     for (nPart=0; nPart<nUsedParts; nPart++)
    1640             :     {
    1641         444 :         bool bDefault = ( nPart+1 == nUsedParts );          // last = default
    1642         444 :         ExportPart_Impl( rFormat, nKey, nPart, bDefault );
    1643             :     }
    1644         403 : }
    1645             : 
    1646             : //  export method called by application
    1647             : 
    1648         337 : void SvXMLNumFmtExport::Export( bool bIsAutoStyle )
    1649             : {
    1650         337 :     if ( !pFormatter )
    1651         337 :         return;                         // no formatter -> no entries
    1652             : 
    1653             :     sal_uInt32 nKey;
    1654         337 :     const SvNumberformat* pFormat = NULL;
    1655         337 :     bool bNext(pUsedList->GetFirstUsed(nKey));
    1656        1049 :     while(bNext)
    1657             :     {
    1658         375 :         pFormat = pFormatter->GetEntry(nKey);
    1659         375 :         if(pFormat)
    1660         375 :             ExportFormat_Impl( *pFormat, nKey );
    1661         375 :         bNext = pUsedList->GetNextUsed(nKey);
    1662             :     }
    1663         337 :     if (!bIsAutoStyle)
    1664             :     {
    1665         106 :         std::vector<sal_uInt16> aLanguages;
    1666         106 :         pFormatter->GetUsedLanguages( aLanguages );
    1667         216 :         for (std::vector<sal_uInt16>::const_iterator it(aLanguages.begin()); it != aLanguages.end(); ++it)
    1668             :         {
    1669         110 :             LanguageType nLang = *it;
    1670             : 
    1671         110 :             sal_uInt32 nDefaultIndex = 0;
    1672             :             SvNumberFormatTable& rTable = pFormatter->GetEntryTable(
    1673         110 :                                             NUMBERFORMAT_DEFINED, nDefaultIndex, nLang );
    1674         110 :             SvNumberFormatTable::iterator it2 = rTable.begin();
    1675         253 :             while (it2 != rTable.end())
    1676             :             {
    1677          33 :                 nKey = it2->first;
    1678          33 :                 pFormat = it2->second;
    1679          33 :                 if (!pUsedList->IsUsed(nKey))
    1680             :                 {
    1681             :                     DBG_ASSERT((pFormat->GetType() & NUMBERFORMAT_DEFINED) != 0, "a not user defined numberformat found");
    1682             :                     //  user-defined and used formats are exported
    1683          28 :                     ExportFormat_Impl( *pFormat, nKey );
    1684             :                     // if it is a user-defined Format it will be added else nothing will happen
    1685          28 :                     pUsedList->SetUsed(nKey);
    1686             :                 }
    1687             : 
    1688          33 :                 ++it2;
    1689             :             }
    1690         106 :         }
    1691             :     }
    1692         337 :     pUsedList->Export();
    1693             : }
    1694             : 
    1695        1016 : OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
    1696             : {
    1697        1016 :     if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey))
    1698        1004 :         return lcl_CreateStyleName( nKey, 0, true, sPrefix );
    1699             :     else
    1700             :     {
    1701             :         OSL_FAIL("There is no written Data-Style");
    1702          12 :         return OUString();
    1703             :     }
    1704             : }
    1705             : 
    1706        2157 : void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
    1707             : {
    1708             :     DBG_ASSERT( pFormatter != NULL, "missing formatter" );
    1709        2157 :     if( !pFormatter )
    1710        2157 :         return;
    1711             : 
    1712        2157 :     if (pFormatter->GetEntry(nKey))
    1713        2133 :         pUsedList->SetUsed( nKey );
    1714             :     else {
    1715             :         OSL_FAIL("no existing Numberformat found with this key");
    1716             :     }
    1717             : }
    1718             : 
    1719          78 : void SvXMLNumFmtExport::GetWasUsed(uno::Sequence<sal_Int32>& rWasUsed)
    1720             : {
    1721          78 :     if (pUsedList)
    1722          78 :         pUsedList->GetWasUsed(rWasUsed);
    1723          78 : }
    1724             : 
    1725          39 : void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
    1726             : {
    1727          39 :     if (pUsedList)
    1728          39 :         pUsedList->SetWasUsed(rWasUsed);
    1729          39 : }
    1730             : 
    1731          67 : static const SvNumberformat* lcl_GetFormat( SvNumberFormatter* pFormatter,
    1732             :                            sal_uInt32 nKey )
    1733             : {
    1734          67 :     return ( pFormatter != NULL ) ? pFormatter->GetEntry( nKey ) : NULL;
    1735             : }
    1736             : 
    1737          67 : sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
    1738             : {
    1739          67 :     sal_uInt32 nRet = nKey;
    1740             : 
    1741          67 :     const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey );
    1742          67 :     if( pFormat != NULL )
    1743             :     {
    1744             :         DBG_ASSERT( pFormatter != NULL, "format without formatter?" );
    1745             : 
    1746             :         sal_Int32 nErrorPos;
    1747          67 :         short nType = pFormat->GetType();
    1748             : 
    1749             :         sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn(
    1750          67 :                        nKey, LANGUAGE_SYSTEM );
    1751             : 
    1752          67 :         if( nNewKey != nKey )
    1753             :         {
    1754           0 :             nRet = nNewKey;
    1755             :         }
    1756             :         else
    1757             :         {
    1758          67 :             OUString aFormatString( pFormat->GetFormatstring() );
    1759             :             pFormatter->PutandConvertEntry(
    1760             :                             aFormatString,
    1761             :                             nErrorPos, nType, nNewKey,
    1762          67 :                             pFormat->GetLanguage(), LANGUAGE_SYSTEM );
    1763             : 
    1764             :             // success? Then use new key.
    1765          67 :             if( nErrorPos == 0 )
    1766          67 :                 nRet = nNewKey;
    1767             :         }
    1768             :     }
    1769             : 
    1770          67 :     return nRet;
    1771             : }
    1772             : 
    1773             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10