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