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