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

Generated by: LCOV version 1.11