xref: /trunk/main/xmloff/source/style/xmlnumfi.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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 #include <unotools/syslocale.hxx>
32 
33 #define _ZFORLIST_DECLARE_TABLE
34 #include <svl/zforlist.hxx>
35 
36 #include <svl/zformat.hxx>
37 #include <svl/numuno.hxx>
38 #include <rtl/math.hxx>
39 #include <i18npool/mslangid.hxx>
40 #include <tools/debug.hxx>
41 #include <rtl/ustrbuf.hxx>
42 
43 // #110680#
44 //#include <comphelper/processfactory.hxx>
45 
46 #include <xmloff/xmlnumfi.hxx>
47 #include <xmloff/xmltkmap.hxx>
48 #include "xmloff/xmlnmspe.hxx"
49 #include <xmloff/xmlictxt.hxx>
50 #include <xmloff/xmlimp.hxx>
51 #include <xmloff/xmluconv.hxx>
52 #include <xmloff/nmspmap.hxx>
53 #include <xmloff/families.hxx>
54 #include <xmloff/xmltoken.hxx>
55 
56 using ::rtl::OUString;
57 using ::rtl::OUStringBuffer;
58 
59 using namespace ::com::sun::star;
60 using namespace ::xmloff::token;
61 
62 //-------------------------------------------------------------------------
63 
64 struct SvXMLNumFmtEntry
65 {
66     rtl::OUString   aName;
67     sal_uInt32      nKey;
68     sal_Bool        bRemoveAfterUse;
69 
70     SvXMLNumFmtEntry( const rtl::OUString& rN, sal_uInt32 nK, sal_Bool bR ) :
71         aName(rN), nKey(nK), bRemoveAfterUse(bR) {}
72 };
73 
74 typedef SvXMLNumFmtEntry* SvXMLNumFmtEntryPtr;
75 SV_DECL_PTRARR_DEL( SvXMLNumFmtEntryArr, SvXMLNumFmtEntryPtr, 4, 4 )
76 
77 struct SvXMLEmbeddedElement
78 {
79     sal_Int32       nFormatPos;
80     rtl::OUString   aText;
81 
82     SvXMLEmbeddedElement( sal_Int32 nFP, const rtl::OUString& rT ) :
83         nFormatPos(nFP), aText(rT) {}
84 
85     //  comparison operators for PTRARR sorting - sorted by position
86     sal_Bool operator ==( const SvXMLEmbeddedElement& r ) const { return nFormatPos == r.nFormatPos; }
87     sal_Bool operator < ( const SvXMLEmbeddedElement& r ) const { return nFormatPos <  r.nFormatPos; }
88 };
89 
90 typedef SvXMLEmbeddedElement* SvXMLEmbeddedElementPtr;
91 SV_DECL_PTRARR_SORT_DEL( SvXMLEmbeddedElementArr, SvXMLEmbeddedElementPtr, 0, 4 )
92 
93 //-------------------------------------------------------------------------
94 
95 class SvXMLNumImpData
96 {
97     SvNumberFormatter*  pFormatter;
98     SvXMLTokenMap*      pStylesElemTokenMap;
99     SvXMLTokenMap*      pStyleElemTokenMap;
100     SvXMLTokenMap*      pStyleAttrTokenMap;
101     SvXMLTokenMap*      pStyleElemAttrTokenMap;
102     LocaleDataWrapper*  pLocaleData;
103     SvXMLNumFmtEntryArr aNameEntries;
104 
105     // #110680#
106     ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxServiceFactory;
107 
108 public:
109     // #110680#
110     // SvXMLNumImpData( SvNumberFormatter* pFmt );
111     SvXMLNumImpData(
112         SvNumberFormatter* pFmt,
113         const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory );
114     ~SvXMLNumImpData();
115 
116     SvNumberFormatter*      GetNumberFormatter() const  { return pFormatter; }
117     const SvXMLTokenMap&    GetStylesElemTokenMap();
118     const SvXMLTokenMap&    GetStyleElemTokenMap();
119     const SvXMLTokenMap&    GetStyleAttrTokenMap();
120     const SvXMLTokenMap&    GetStyleElemAttrTokenMap();
121     const LocaleDataWrapper&    GetLocaleData( LanguageType nLang );
122     sal_uInt32              GetKeyForName( const rtl::OUString& rName );
123     void                    AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse );
124     void                    SetUsed( sal_uInt32 nKey );
125     void                    RemoveVolatileFormats();
126 };
127 
128 
129 struct SvXMLNumberInfo
130 {
131     sal_Int32   nDecimals;
132     sal_Int32   nInteger;
133     sal_Int32   nExpDigits;
134     sal_Int32   nNumerDigits;
135     sal_Int32   nDenomDigits;
136     sal_Bool    bGrouping;
137     sal_Bool    bDecReplace;
138     sal_Bool    bVarDecimals;
139     double      fDisplayFactor;
140     SvXMLEmbeddedElementArr aEmbeddedElements;
141 
142     SvXMLNumberInfo()
143     {
144         nDecimals = nInteger = nExpDigits = nNumerDigits = nDenomDigits = -1;
145         bGrouping = bDecReplace = bVarDecimals = sal_False;
146         fDisplayFactor = 1.0;
147     }
148 };
149 
150 class SvXMLNumFmtElementContext : public SvXMLImportContext
151 {
152     SvXMLNumFormatContext&  rParent;
153     sal_uInt16              nType;
154     rtl::OUStringBuffer     aContent;
155     SvXMLNumberInfo         aNumInfo;
156     LanguageType            nElementLang;
157     sal_Bool                bLong;
158     sal_Bool                bTextual;
159     rtl::OUString           sCalendar;
160 
161 public:
162                 SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
163                                     const rtl::OUString& rLName,
164                                     SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
165                                     const ::com::sun::star::uno::Reference<
166                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
167     virtual     ~SvXMLNumFmtElementContext();
168 
169     virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
170                                     const rtl::OUString& rLocalName,
171                                     const ::com::sun::star::uno::Reference<
172                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
173     virtual void Characters( const rtl::OUString& rChars );
174     virtual void EndElement();
175 
176     void    AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent );
177 };
178 
179 
180 class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext
181 {
182     SvXMLNumFmtElementContext&  rParent;
183     rtl::OUStringBuffer         aContent;
184     sal_Int32                   nTextPosition;
185 
186 public:
187                 SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
188                                     const rtl::OUString& rLName,
189                                     SvXMLNumFmtElementContext& rParentContext,
190                                     const ::com::sun::star::uno::Reference<
191                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
192     virtual     ~SvXMLNumFmtEmbeddedTextContext();
193 
194     virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
195                                     const rtl::OUString& rLocalName,
196                                     const ::com::sun::star::uno::Reference<
197                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
198     virtual void Characters( const rtl::OUString& rChars );
199     virtual void EndElement();
200 };
201 
202 
203 class SvXMLNumFmtMapContext : public SvXMLImportContext
204 {
205     SvXMLNumFormatContext&  rParent;
206     rtl::OUString           sCondition;
207     rtl::OUString           sName;
208 
209 public:
210                 SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
211                                     const rtl::OUString& rLName,
212                                     SvXMLNumFormatContext& rParentContext,
213                                     const ::com::sun::star::uno::Reference<
214                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
215     virtual     ~SvXMLNumFmtMapContext();
216 
217     virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
218                                     const rtl::OUString& rLocalName,
219                                     const ::com::sun::star::uno::Reference<
220                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
221     virtual void Characters( const rtl::OUString& rChars );
222     virtual void EndElement();
223 };
224 
225 
226 class SvXMLNumFmtPropContext : public SvXMLImportContext
227 {
228     SvXMLNumFormatContext&  rParent;
229     Color                   aColor;
230     sal_Bool                bColSet;
231 
232 public:
233                 SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
234                                     const rtl::OUString& rLName,
235                                     SvXMLNumFormatContext& rParentContext,
236                                     const ::com::sun::star::uno::Reference<
237                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
238     virtual     ~SvXMLNumFmtPropContext();
239 
240     virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
241                                     const rtl::OUString& rLocalName,
242                                     const ::com::sun::star::uno::Reference<
243                                         ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
244     virtual void Characters( const rtl::OUString& rChars );
245     virtual void EndElement();
246 };
247 
248 
249 //-------------------------------------------------------------------------
250 
251 enum SvXMLStyleTokens
252 {
253     XML_TOK_STYLE_TEXT,
254     XML_TOK_STYLE_NUMBER,
255     XML_TOK_STYLE_SCIENTIFIC_NUMBER,
256     XML_TOK_STYLE_FRACTION,
257     XML_TOK_STYLE_CURRENCY_SYMBOL,
258     XML_TOK_STYLE_DAY,
259     XML_TOK_STYLE_MONTH,
260     XML_TOK_STYLE_YEAR,
261     XML_TOK_STYLE_ERA,
262     XML_TOK_STYLE_DAY_OF_WEEK,
263     XML_TOK_STYLE_WEEK_OF_YEAR,
264     XML_TOK_STYLE_QUARTER,
265     XML_TOK_STYLE_HOURS,
266     XML_TOK_STYLE_AM_PM,
267     XML_TOK_STYLE_MINUTES,
268     XML_TOK_STYLE_SECONDS,
269     XML_TOK_STYLE_BOOLEAN,
270     XML_TOK_STYLE_TEXT_CONTENT,
271     XML_TOK_STYLE_PROPERTIES,
272     XML_TOK_STYLE_MAP
273 };
274 
275 enum SvXMLStyleAttrTokens
276 {
277     XML_TOK_STYLE_ATTR_NAME,
278     XML_TOK_STYLE_ATTR_LANGUAGE,
279     XML_TOK_STYLE_ATTR_COUNTRY,
280     XML_TOK_STYLE_ATTR_TITLE,
281     XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER,
282     XML_TOK_STYLE_ATTR_FORMAT_SOURCE,
283     XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW,
284     XML_TOK_STYLE_ATTR_VOLATILE,
285     XML_TOK_STYLE_ATTR_TRANSL_FORMAT,
286     XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE,
287     XML_TOK_STYLE_ATTR_TRANSL_COUNTRY,
288     XML_TOK_STYLE_ATTR_TRANSL_STYLE
289 };
290 
291 enum SvXMLStyleElemAttrTokens
292 {
293     XML_TOK_ELEM_ATTR_DECIMAL_PLACES,
294     XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS,
295     XML_TOK_ELEM_ATTR_GROUPING,
296     XML_TOK_ELEM_ATTR_DISPLAY_FACTOR,
297     XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT,
298     XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS,
299     XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS,
300     XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS,
301     XML_TOK_ELEM_ATTR_LANGUAGE,
302     XML_TOK_ELEM_ATTR_COUNTRY,
303     XML_TOK_ELEM_ATTR_STYLE,
304     XML_TOK_ELEM_ATTR_TEXTUAL,
305     XML_TOK_ELEM_ATTR_CALENDAR
306 };
307 
308 //-------------------------------------------------------------------------
309 
310 //
311 //  standard colors
312 //
313 
314 #define XML_NUMF_COLORCOUNT     10
315 
316 static ColorData aNumFmtStdColors[XML_NUMF_COLORCOUNT] =
317 {
318     COL_BLACK,
319     COL_LIGHTBLUE,
320     COL_LIGHTGREEN,
321     COL_LIGHTCYAN,
322     COL_LIGHTRED,
323     COL_LIGHTMAGENTA,
324     COL_BROWN,
325     COL_GRAY,
326     COL_YELLOW,
327     COL_WHITE
328 };
329 
330 //
331 //  token maps
332 //
333 
334 // maps for SvXMLUnitConverter::convertEnum
335 
336 static __FAR_DATA SvXMLEnumMapEntry aStyleValueMap[] =
337 {
338     { XML_SHORT,            sal_False   },
339     { XML_LONG,             sal_True    },
340     { XML_TOKEN_INVALID,    0 }
341 };
342 
343 static __FAR_DATA SvXMLEnumMapEntry aFormatSourceMap[] =
344 {
345     { XML_FIXED,            sal_False },
346     { XML_LANGUAGE,         sal_True  },
347     { XML_TOKEN_INVALID,    0 }
348 };
349 
350 //-------------------------------------------------------------------------
351 
352 struct SvXMLDefaultDateFormat
353 {
354     NfIndexTableOffset          eFormat;
355     SvXMLDateElementAttributes  eDOW;
356     SvXMLDateElementAttributes  eDay;
357     SvXMLDateElementAttributes  eMonth;
358     SvXMLDateElementAttributes  eYear;
359     SvXMLDateElementAttributes  eHours;
360     SvXMLDateElementAttributes  eMins;
361     SvXMLDateElementAttributes  eSecs;
362     sal_Bool                    bSystem;
363 };
364 
365 static __FAR_DATA SvXMLDefaultDateFormat aDefaultDateFormats[] =
366 {
367     // format                           day-of-week     day             month               year            hours           minutes         seconds         format-source
368 
369     { NF_DATE_SYSTEM_SHORT,             XML_DEA_NONE,   XML_DEA_ANY,    XML_DEA_ANY,        XML_DEA_ANY,    XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_True },
370     { NF_DATE_SYSTEM_LONG,              XML_DEA_ANY,    XML_DEA_ANY,    XML_DEA_ANY,        XML_DEA_ANY,    XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_True },
371     { NF_DATE_SYS_MMYY,                 XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_LONG,       XML_DEA_SHORT,  XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
372     { NF_DATE_SYS_DDMMM,                XML_DEA_NONE,   XML_DEA_LONG,   XML_DEA_TEXTSHORT,  XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
373     { NF_DATE_SYS_DDMMYYYY,             XML_DEA_NONE,   XML_DEA_LONG,   XML_DEA_LONG,       XML_DEA_LONG,   XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
374     { NF_DATE_SYS_DDMMYY,               XML_DEA_NONE,   XML_DEA_LONG,   XML_DEA_LONG,       XML_DEA_SHORT,  XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
375     { NF_DATE_SYS_DMMMYY,               XML_DEA_NONE,   XML_DEA_SHORT,  XML_DEA_TEXTSHORT,  XML_DEA_SHORT,  XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
376     { NF_DATE_SYS_DMMMYYYY,             XML_DEA_NONE,   XML_DEA_SHORT,  XML_DEA_TEXTSHORT,  XML_DEA_LONG,   XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
377     { NF_DATE_SYS_DMMMMYYYY,            XML_DEA_NONE,   XML_DEA_SHORT,  XML_DEA_TEXTLONG,   XML_DEA_LONG,   XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
378     { NF_DATE_SYS_NNDMMMYY,             XML_DEA_SHORT,  XML_DEA_SHORT,  XML_DEA_TEXTSHORT,  XML_DEA_SHORT,  XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
379     { NF_DATE_SYS_NNDMMMMYYYY,          XML_DEA_SHORT,  XML_DEA_SHORT,  XML_DEA_TEXTLONG,   XML_DEA_LONG,   XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
380     { NF_DATE_SYS_NNNNDMMMMYYYY,        XML_DEA_LONG,   XML_DEA_SHORT,  XML_DEA_TEXTLONG,   XML_DEA_LONG,   XML_DEA_NONE,   XML_DEA_NONE,   XML_DEA_NONE,   sal_False },
381     { NF_DATETIME_SYSTEM_SHORT_HHMM,    XML_DEA_NONE,   XML_DEA_ANY,    XML_DEA_ANY,        XML_DEA_ANY,    XML_DEA_ANY,    XML_DEA_ANY,    XML_DEA_NONE,   sal_True },
382     { NF_DATETIME_SYS_DDMMYYYY_HHMMSS,  XML_DEA_NONE,   XML_DEA_ANY,    XML_DEA_ANY,        XML_DEA_ANY,    XML_DEA_ANY,    XML_DEA_ANY,    XML_DEA_ANY,    sal_False }
383 };
384 
385 //-------------------------------------------------------------------------
386 
387 SV_IMPL_PTRARR( SvXMLNumFmtEntryArr, SvXMLNumFmtEntryPtr );
388 SV_IMPL_OP_PTRARR_SORT( SvXMLEmbeddedElementArr, SvXMLEmbeddedElementPtr );
389 
390 //-------------------------------------------------------------------------
391 
392 //
393 //  SvXMLNumImpData
394 //
395 
396 // #110680#
397 // SvXMLNumImpData::SvXMLNumImpData( SvNumberFormatter* pFmt ) :
398 SvXMLNumImpData::SvXMLNumImpData(
399     SvNumberFormatter* pFmt,
400     const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
401 :   pFormatter(pFmt),
402     pStylesElemTokenMap(NULL),
403     pStyleElemTokenMap(NULL),
404     pStyleAttrTokenMap(NULL),
405     pStyleElemAttrTokenMap(NULL),
406     pLocaleData(NULL),
407 
408     // #110680#
409     mxServiceFactory(xServiceFactory)
410 {
411     DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
412 }
413 
414 SvXMLNumImpData::~SvXMLNumImpData()
415 {
416     delete pStylesElemTokenMap;
417     delete pStyleElemTokenMap;
418     delete pStyleAttrTokenMap;
419     delete pStyleElemAttrTokenMap;
420     delete pLocaleData;
421 }
422 
423 sal_uInt32 SvXMLNumImpData::GetKeyForName( const rtl::OUString& rName )
424 {
425     sal_uInt16 nCount = aNameEntries.Count();
426     for (sal_uInt16 i=0; i<nCount; i++)
427     {
428         const SvXMLNumFmtEntry* pObj = aNameEntries[i];
429         if ( pObj->aName == rName )
430             return pObj->nKey;              // found
431     }
432     return NUMBERFORMAT_ENTRY_NOT_FOUND;
433 }
434 
435 void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse )
436 {
437     if ( bRemoveAfterUse )
438     {
439         //  if there is already an entry for this key without the bRemoveAfterUse flag,
440         //  clear the flag for this entry, too
441 
442         sal_uInt16 nCount = aNameEntries.Count();
443         for (sal_uInt16 i=0; i<nCount; i++)
444         {
445             SvXMLNumFmtEntry* pObj = aNameEntries[i];
446             if ( pObj->nKey == nKey && !pObj->bRemoveAfterUse )
447             {
448                 bRemoveAfterUse = sal_False;        // clear flag for new entry
449                 break;
450             }
451         }
452     }
453     else
454     {
455         //  call SetUsed to clear the bRemoveAfterUse flag for other entries for this key
456         SetUsed( nKey );
457     }
458 
459     SvXMLNumFmtEntry* pObj = new SvXMLNumFmtEntry( rName, nKey, bRemoveAfterUse );
460     aNameEntries.Insert( pObj, aNameEntries.Count() );
461 }
462 
463 void SvXMLNumImpData::SetUsed( sal_uInt32 nKey )
464 {
465     sal_uInt16 nCount = aNameEntries.Count();
466     for (sal_uInt16 i=0; i<nCount; i++)
467     {
468         SvXMLNumFmtEntry* pObj = aNameEntries[i];
469         if ( pObj->nKey == nKey )
470         {
471             pObj->bRemoveAfterUse = sal_False;      // used -> don't remove
472 
473             //  continue searching - there may be several entries for the same key
474             //  (with different names), the format must not be deleted if any one of
475             //  them is used
476         }
477     }
478 }
479 
480 void SvXMLNumImpData::RemoveVolatileFormats()
481 {
482     //  remove temporary (volatile) formats from NumberFormatter
483     //  called at the end of each import (styles and content), so volatile formats
484     //  from styles can't be used in content
485 
486     if ( !pFormatter )
487         return;
488 
489     sal_uInt16 nCount = aNameEntries.Count();
490     for (sal_uInt16 i=0; i<nCount; i++)
491     {
492         const SvXMLNumFmtEntry* pObj = aNameEntries[i];
493         if ( pObj->bRemoveAfterUse )
494         {
495             const SvNumberformat* pFormat = pFormatter->GetEntry(pObj->nKey);
496             if (pFormat && (pFormat->GetType() & NUMBERFORMAT_DEFINED))
497                 pFormatter->DeleteEntry( pObj->nKey );
498         }
499     }
500 }
501 
502 const SvXMLTokenMap& SvXMLNumImpData::GetStylesElemTokenMap()
503 {
504     if( !pStylesElemTokenMap )
505     {
506         static __FAR_DATA SvXMLTokenMapEntry aStylesElemMap[] =
507         {
508             //  style elements
509             { XML_NAMESPACE_NUMBER, XML_NUMBER_STYLE,      XML_TOK_STYLES_NUMBER_STYLE      },
510             { XML_NAMESPACE_NUMBER, XML_CURRENCY_STYLE,    XML_TOK_STYLES_CURRENCY_STYLE    },
511             { XML_NAMESPACE_NUMBER, XML_PERCENTAGE_STYLE,  XML_TOK_STYLES_PERCENTAGE_STYLE  },
512             { XML_NAMESPACE_NUMBER, XML_DATE_STYLE,        XML_TOK_STYLES_DATE_STYLE        },
513             { XML_NAMESPACE_NUMBER, XML_TIME_STYLE,        XML_TOK_STYLES_TIME_STYLE        },
514             { XML_NAMESPACE_NUMBER, XML_BOOLEAN_STYLE,     XML_TOK_STYLES_BOOLEAN_STYLE     },
515             { XML_NAMESPACE_NUMBER, XML_TEXT_STYLE,        XML_TOK_STYLES_TEXT_STYLE        },
516             XML_TOKEN_MAP_END
517         };
518 
519         pStylesElemTokenMap = new SvXMLTokenMap( aStylesElemMap );
520     }
521     return *pStylesElemTokenMap;
522 }
523 
524 const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemTokenMap()
525 {
526     if( !pStyleElemTokenMap )
527     {
528         static __FAR_DATA SvXMLTokenMapEntry aStyleElemMap[] =
529         {
530             //  elements in a style
531             { XML_NAMESPACE_NUMBER, XML_TEXT,               XML_TOK_STYLE_TEXT              },
532             { XML_NAMESPACE_NUMBER, XML_NUMBER,             XML_TOK_STYLE_NUMBER            },
533             { XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER,  XML_TOK_STYLE_SCIENTIFIC_NUMBER },
534             { XML_NAMESPACE_NUMBER, XML_FRACTION,           XML_TOK_STYLE_FRACTION          },
535             { XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL,    XML_TOK_STYLE_CURRENCY_SYMBOL   },
536             { XML_NAMESPACE_NUMBER, XML_DAY,                XML_TOK_STYLE_DAY               },
537             { XML_NAMESPACE_NUMBER, XML_MONTH,              XML_TOK_STYLE_MONTH             },
538             { XML_NAMESPACE_NUMBER, XML_YEAR,               XML_TOK_STYLE_YEAR              },
539             { XML_NAMESPACE_NUMBER, XML_ERA,                XML_TOK_STYLE_ERA               },
540             { XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK,        XML_TOK_STYLE_DAY_OF_WEEK       },
541             { XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR,       XML_TOK_STYLE_WEEK_OF_YEAR      },
542             { XML_NAMESPACE_NUMBER, XML_QUARTER,            XML_TOK_STYLE_QUARTER           },
543             { XML_NAMESPACE_NUMBER, XML_HOURS,              XML_TOK_STYLE_HOURS             },
544             { XML_NAMESPACE_NUMBER, XML_AM_PM,              XML_TOK_STYLE_AM_PM             },
545             { XML_NAMESPACE_NUMBER, XML_MINUTES,            XML_TOK_STYLE_MINUTES           },
546             { XML_NAMESPACE_NUMBER, XML_SECONDS,            XML_TOK_STYLE_SECONDS           },
547             { XML_NAMESPACE_NUMBER, XML_BOOLEAN,            XML_TOK_STYLE_BOOLEAN           },
548             { XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT,       XML_TOK_STYLE_TEXT_CONTENT      },
549             { XML_NAMESPACE_STYLE,  XML_TEXT_PROPERTIES,    XML_TOK_STYLE_PROPERTIES        },
550             { XML_NAMESPACE_STYLE,  XML_MAP,                XML_TOK_STYLE_MAP               },
551             XML_TOKEN_MAP_END
552         };
553 
554         pStyleElemTokenMap = new SvXMLTokenMap( aStyleElemMap );
555     }
556     return *pStyleElemTokenMap;
557 }
558 
559 const SvXMLTokenMap& SvXMLNumImpData::GetStyleAttrTokenMap()
560 {
561     if( !pStyleAttrTokenMap )
562     {
563         static __FAR_DATA SvXMLTokenMapEntry aStyleAttrMap[] =
564         {
565             //  attributes for a style
566             { XML_NAMESPACE_STYLE,  XML_NAME,                  XML_TOK_STYLE_ATTR_NAME                  },
567             { XML_NAMESPACE_NUMBER, XML_LANGUAGE,              XML_TOK_STYLE_ATTR_LANGUAGE              },
568             { XML_NAMESPACE_NUMBER, XML_COUNTRY,               XML_TOK_STYLE_ATTR_COUNTRY               },
569             { XML_NAMESPACE_NUMBER, XML_TITLE,                 XML_TOK_STYLE_ATTR_TITLE                 },
570             { XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER,       XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER       },
571             { XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE,         XML_TOK_STYLE_ATTR_FORMAT_SOURCE         },
572             { XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW,  XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW  },
573             { XML_NAMESPACE_STYLE,  XML_VOLATILE,              XML_TOK_STYLE_ATTR_VOLATILE              },
574             { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT,     XML_TOK_STYLE_ATTR_TRANSL_FORMAT    },
575             { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE,   XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE  },
576             { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY,    XML_TOK_STYLE_ATTR_TRANSL_COUNTRY   },
577             { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE,      XML_TOK_STYLE_ATTR_TRANSL_STYLE     },
578             XML_TOKEN_MAP_END
579         };
580 
581         pStyleAttrTokenMap = new SvXMLTokenMap( aStyleAttrMap );
582     }
583     return *pStyleAttrTokenMap;
584 }
585 
586 const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemAttrTokenMap()
587 {
588     if( !pStyleElemAttrTokenMap )
589     {
590         static __FAR_DATA SvXMLTokenMapEntry aStyleElemAttrMap[] =
591         {
592             //  attributes for an element within a style
593             { XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES,          XML_TOK_ELEM_ATTR_DECIMAL_PLACES       },
594             { XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS,      XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS   },
595             { XML_NAMESPACE_NUMBER, XML_GROUPING,                XML_TOK_ELEM_ATTR_GROUPING             },
596             { XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR,          XML_TOK_ELEM_ATTR_DISPLAY_FACTOR       },
597             { XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT,     XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT  },
598             { XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS,     XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS  },
599             { XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS,    XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS },
600             { XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS,  XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS },
601             { XML_NAMESPACE_NUMBER, XML_LANGUAGE,                XML_TOK_ELEM_ATTR_LANGUAGE             },
602             { XML_NAMESPACE_NUMBER, XML_COUNTRY,                 XML_TOK_ELEM_ATTR_COUNTRY              },
603             { XML_NAMESPACE_NUMBER, XML_STYLE,                   XML_TOK_ELEM_ATTR_STYLE                },
604             { XML_NAMESPACE_NUMBER, XML_TEXTUAL,                 XML_TOK_ELEM_ATTR_TEXTUAL              },
605             { XML_NAMESPACE_NUMBER, XML_CALENDAR,                XML_TOK_ELEM_ATTR_CALENDAR             },
606             XML_TOKEN_MAP_END
607         };
608 
609         pStyleElemAttrTokenMap = new SvXMLTokenMap( aStyleElemAttrMap );
610     }
611     return *pStyleElemAttrTokenMap;
612 }
613 
614 const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang )
615 {
616     if ( !pLocaleData )
617         // #110680#
618         //pLocaleData = new LocaleDataWrapper(
619         //  (pFormatter ? pFormatter->GetServiceManager() :
620         //  ::comphelper::getProcessServiceFactory()),
621         //  MsLangId::convertLanguageToLocale( nLang ) );
622         pLocaleData = new LocaleDataWrapper(
623             (pFormatter ? pFormatter->GetServiceManager() :
624             mxServiceFactory),
625             MsLangId::convertLanguageToLocale( nLang ) );
626     else
627         pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) );
628     return *pLocaleData;
629 }
630 
631 //-------------------------------------------------------------------------
632 
633 //
634 //  SvXMLNumFmtMapContext
635 //
636 
637 SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport,
638                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
639                                     SvXMLNumFormatContext& rParentContext,
640                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
641     SvXMLImportContext( rImport, nPrfx, rLName ),
642     rParent( rParentContext )
643 {
644     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
645     for( sal_Int16 i=0; i < nAttrCount; i++ )
646     {
647         OUString sAttrName = xAttrList->getNameByIndex( i );
648         OUString sValue = xAttrList->getValueByIndex( i );
649         OUString aLocalName;
650         sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
651         if ( nPrefix == XML_NAMESPACE_STYLE )
652         {
653             if ( IsXMLToken( aLocalName, XML_CONDITION) )
654                 sCondition = sValue;
655             else if ( IsXMLToken( aLocalName, XML_APPLY_STYLE_NAME) )
656                 sName = sValue;
657         }
658     }
659 }
660 
661 SvXMLNumFmtMapContext::~SvXMLNumFmtMapContext()
662 {
663 }
664 
665 SvXMLImportContext* SvXMLNumFmtMapContext::CreateChildContext(
666                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
667                                     const uno::Reference<xml::sax::XAttributeList>& )
668 {
669     // no elements supported - use default context
670     return new SvXMLImportContext( GetImport(), nPrfx, rLName );
671 }
672 
673 void SvXMLNumFmtMapContext::Characters( const rtl::OUString& )
674 {
675 }
676 
677 void SvXMLNumFmtMapContext::EndElement()
678 {
679     rParent.AddCondition( sCondition, sName );
680 }
681 
682 //-------------------------------------------------------------------------
683 
684 //
685 //  SvXMLNumFmtPropContext
686 //
687 
688 SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport,
689                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
690                                     SvXMLNumFormatContext& rParentContext,
691                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
692     SvXMLImportContext( rImport, nPrfx, rLName ),
693     rParent( rParentContext ),
694     bColSet( sal_False )
695 {
696     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
697     for( sal_Int16 i=0; i < nAttrCount; i++ )
698     {
699         OUString sAttrName = xAttrList->getNameByIndex( i );
700         OUString sValue = xAttrList->getValueByIndex( i );
701         OUString aLocalName;
702         sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
703         if ( nPrefix == XML_NAMESPACE_FO && IsXMLToken( aLocalName, XML_COLOR ) )
704             bColSet = SvXMLUnitConverter::convertColor( aColor, sValue );
705     }
706 }
707 
708 SvXMLNumFmtPropContext::~SvXMLNumFmtPropContext()
709 {
710 }
711 
712 SvXMLImportContext* SvXMLNumFmtPropContext::CreateChildContext(
713                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
714                                     const uno::Reference<xml::sax::XAttributeList>& )
715 {
716     // no elements supported - use default context
717     return new SvXMLImportContext( GetImport(), nPrfx, rLName );
718 }
719 
720 void SvXMLNumFmtPropContext::Characters( const rtl::OUString& )
721 {
722 }
723 
724 void SvXMLNumFmtPropContext::EndElement()
725 {
726     if (bColSet)
727         rParent.AddColor( aColor );
728 }
729 
730 //-------------------------------------------------------------------------
731 
732 //
733 //  SvXMLNumFmtEmbeddedTextContext
734 //
735 
736 SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport,
737                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
738                                     SvXMLNumFmtElementContext& rParentContext,
739                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
740     SvXMLImportContext( rImport, nPrfx, rLName ),
741     rParent( rParentContext ),
742     nTextPosition( 0 )
743 {
744     sal_Int32 nAttrVal;
745 
746     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
747     for( sal_Int16 i=0; i < nAttrCount; i++ )
748     {
749         OUString sAttrName = xAttrList->getNameByIndex( i );
750         OUString sValue = xAttrList->getValueByIndex( i );
751         OUString aLocalName;
752         sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
753         if ( nPrefix == XML_NAMESPACE_NUMBER && IsXMLToken( aLocalName, XML_POSITION ) )
754         {
755             if ( SvXMLUnitConverter::convertNumber( nAttrVal, sValue, 0 ) )
756                 nTextPosition = nAttrVal;
757         }
758     }
759 }
760 
761 SvXMLNumFmtEmbeddedTextContext::~SvXMLNumFmtEmbeddedTextContext()
762 {
763 }
764 
765 SvXMLImportContext* SvXMLNumFmtEmbeddedTextContext::CreateChildContext(
766                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
767                                     const uno::Reference<xml::sax::XAttributeList>& )
768 {
769     // no elements supported - use default context
770     return new SvXMLImportContext( GetImport(), nPrfx, rLName );
771 }
772 
773 void SvXMLNumFmtEmbeddedTextContext::Characters( const rtl::OUString& rChars )
774 {
775     aContent.append( rChars );
776 }
777 
778 void SvXMLNumFmtEmbeddedTextContext::EndElement()
779 {
780     rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() );
781 }
782 
783 //-------------------------------------------------------------------------
784 
785 sal_Bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent )
786 {
787     sal_uInt16 nFormatType = rParent.GetType();
788 
789     // Treat space equal to non-breaking space separator.
790     const sal_Unicode cNBSP = 0x00A0;
791     sal_Unicode cTS;
792     if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
793            nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
794            nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
795             (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep().GetChar(0)) ||
796              (cChar == ' ' && cTS == cNBSP)) )
797     {
798         //  #i22394# Extra occurrences of thousands separator must be quoted, so they
799         //  aren't mis-interpreted as display-factor.
800         //  This must be limited to the format types that can contain a number element,
801         //  because the same character can be a date separator that should not be quoted
802         //  in date formats.
803 
804         return sal_False;   // force quotes
805     }
806 
807     //  see ImpSvNumberformatScan::Next_Symbol
808     if ( cChar == ' ' ||
809          cChar == '-' ||
810          cChar == '/' ||
811          cChar == '.' ||
812          cChar == ',' ||
813          cChar == ':' ||
814          cChar == '\'' )
815         return sal_True;    // for all format types
816 
817     //  percent sign must be used without quotes for percentage styles only
818     if ( nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE && cChar == '%' )
819         return sal_True;
820 
821     //  don't put quotes around single parentheses (often used for negative numbers)
822     if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
823            nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
824            nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
825          ( cChar == '(' || cChar == ')' ) )
826         return sal_True;
827 
828     return sal_False;
829 }
830 
831 void lcl_EnquoteIfNecessary( rtl::OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent )
832 {
833     sal_Bool bQuote = sal_True;
834     sal_Int32 nLength = rContent.getLength();
835 
836     if ( ( nLength == 1 &&
837             lcl_ValidChar( rContent.charAt(0), rParent ) ) ||
838          ( nLength == 2 &&
839             lcl_ValidChar( rContent.charAt(0), rParent ) &&
840             rContent.charAt(1) == ' ' ) )
841     {
842         //  don't quote single separator characters like space or percent,
843         //  or separator characters followed by space (used in date formats)
844         bQuote = sal_False;
845     }
846     else if ( rParent.GetType() == XML_TOK_STYLES_PERCENTAGE_STYLE && nLength > 1 )
847     {
848         //  the percent character in percentage styles must be left out of quoting
849         //  (one occurence is enough even if there are several percent characters in the string)
850 
851         rtl::OUString aString( rContent.getStr() );
852         sal_Int32 nPos = aString.indexOf( (sal_Unicode) '%' );
853         if ( nPos >= 0 )
854         {
855             if ( nPos + 1 < nLength )
856             {
857                 if ( nPos + 2 == nLength && lcl_ValidChar( rContent.charAt(nPos + 1), rParent ) )
858                 {
859                     //  single character that doesn't need quoting
860                 }
861                 else
862                 {
863                     //  quote text behind percent character
864                     rContent.insert( nPos + 1, (sal_Unicode) '"' );
865                     rContent.append( (sal_Unicode) '"' );
866                 }
867             }
868             if ( nPos > 0 )
869             {
870                 if ( nPos == 1 && lcl_ValidChar( rContent.charAt(0), rParent ) )
871                 {
872                     //  single character that doesn't need quoting
873                 }
874                 else
875                 {
876                     //  quote text before percent character
877                     rContent.insert( nPos, (sal_Unicode) '"' );
878                     rContent.insert( 0, (sal_Unicode) '"' );
879                 }
880             }
881             bQuote = sal_False;
882         }
883         // else: normal quoting (below)
884     }
885 
886     if ( bQuote )
887     {
888         // #i55469# quotes in the string itself have to be escaped
889         rtl::OUString aString( rContent.getStr() );
890         bool bEscape = ( aString.indexOf( (sal_Unicode) '"' ) >= 0 );
891         if ( bEscape )
892         {
893             // A quote is turned into "\"" - a quote to end quoted text, an escaped quote,
894             // and a quote to resume quoting.
895             rtl::OUString aInsert( rtl::OUString::createFromAscii( "\"\\\"" ) );
896 
897             sal_Int32 nPos = 0;
898             while ( nPos < rContent.getLength() )
899             {
900                 if ( rContent.charAt( nPos ) == (sal_Unicode) '"' )
901                 {
902                     rContent.insert( nPos, aInsert );
903                     nPos += aInsert.getLength();
904                 }
905                 ++nPos;
906             }
907         }
908 
909         //  quote string literals
910         rContent.insert( 0, (sal_Unicode) '"' );
911         rContent.append( (sal_Unicode) '"' );
912 
913         // remove redundant double quotes at start or end
914         if ( bEscape )
915         {
916             if ( rContent.getLength() > 2 &&
917                  rContent.charAt(0) == (sal_Unicode) '"' &&
918                  rContent.charAt(1) == (sal_Unicode) '"' )
919             {
920                 String aTrimmed( rContent.makeStringAndClear().copy(2) );
921                 rContent = rtl::OUStringBuffer( aTrimmed );
922             }
923 
924             sal_Int32 nLen = rContent.getLength();
925             if ( nLen > 2 &&
926                  rContent.charAt(nLen-1) == (sal_Unicode) '"' &&
927                  rContent.charAt(nLen-2) == (sal_Unicode) '"' )
928             {
929                 String aTrimmed( rContent.makeStringAndClear().copy( 0, nLen - 2 ) );
930                 rContent = rtl::OUStringBuffer( aTrimmed );
931             }
932         }
933     }
934 }
935 
936 //
937 //  SvXMLNumFmtElementContext
938 //
939 
940 SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport,
941                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
942                                     SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
943                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
944     SvXMLImportContext( rImport, nPrfx, rLName ),
945     rParent( rParentContext ),
946     nType( nNewType ),
947     nElementLang( LANGUAGE_SYSTEM ),
948     bLong( sal_False ),
949     bTextual( sal_False )
950 {
951     OUString sLanguage, sCountry;
952     sal_Int32 nAttrVal;
953     sal_Bool bAttrBool;
954     sal_uInt16 nAttrEnum;
955     double fAttrDouble;
956 
957     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
958     for( sal_Int16 i=0; i < nAttrCount; i++ )
959     {
960         OUString sAttrName = xAttrList->getNameByIndex( i );
961         OUString sValue = xAttrList->getValueByIndex( i );
962         OUString aLocalName;
963         sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
964 
965         const SvXMLTokenMap& rTokenMap = rParent.GetData()->GetStyleElemAttrTokenMap();
966         sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName );
967 
968         switch (nToken)
969         {
970             case XML_TOK_ELEM_ATTR_DECIMAL_PLACES:
971                 if ( SvXMLUnitConverter::convertNumber( nAttrVal, sValue, 0 ) )
972                     aNumInfo.nDecimals = nAttrVal;
973                 break;
974             case XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS:
975                 if ( SvXMLUnitConverter::convertNumber( nAttrVal, sValue, 0 ) )
976                     aNumInfo.nInteger = nAttrVal;
977                 break;
978             case XML_TOK_ELEM_ATTR_GROUPING:
979                 if ( SvXMLUnitConverter::convertBool( bAttrBool, sValue ) )
980                     aNumInfo.bGrouping = bAttrBool;
981                 break;
982             case XML_TOK_ELEM_ATTR_DISPLAY_FACTOR:
983                 if ( SvXMLUnitConverter::convertDouble( fAttrDouble, sValue ) )
984                     aNumInfo.fDisplayFactor = fAttrDouble;
985                 break;
986             case XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT:
987                 if ( sValue.getLength() > 0 )
988                     aNumInfo.bDecReplace = sal_True;    // only a default string is supported
989                 else
990                     aNumInfo.bVarDecimals = sal_True;   // empty replacement string: variable decimals
991                 break;
992             case XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS:
993                 if ( SvXMLUnitConverter::convertNumber( nAttrVal, sValue, 0 ) )
994                     aNumInfo.nExpDigits = nAttrVal;
995                 break;
996             case XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS:
997                 if ( SvXMLUnitConverter::convertNumber( nAttrVal, sValue, 0 ) )
998                     aNumInfo.nNumerDigits = nAttrVal;
999                 break;
1000             case XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS:
1001                 if ( SvXMLUnitConverter::convertNumber( nAttrVal, sValue, 0 ) )
1002                     aNumInfo.nDenomDigits = nAttrVal;
1003                 break;
1004             case XML_TOK_ELEM_ATTR_LANGUAGE:
1005                 sLanguage = sValue;
1006                 break;
1007             case XML_TOK_ELEM_ATTR_COUNTRY:
1008                 sCountry = sValue;
1009                 break;
1010             case XML_TOK_ELEM_ATTR_STYLE:
1011                 if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aStyleValueMap ) )
1012                     bLong = (sal_Bool) nAttrEnum;
1013                 break;
1014             case XML_TOK_ELEM_ATTR_TEXTUAL:
1015                 if ( SvXMLUnitConverter::convertBool( bAttrBool, sValue ) )
1016                     bTextual = bAttrBool;
1017                 break;
1018             case XML_TOK_ELEM_ATTR_CALENDAR:
1019                 sCalendar = sValue;
1020                 break;
1021         }
1022     }
1023 
1024     if ( sLanguage.getLength() || sCountry.getLength() )
1025     {
1026         nElementLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry );
1027         if ( nElementLang == LANGUAGE_DONTKNOW )
1028             nElementLang = LANGUAGE_SYSTEM;         //! error handling for invalid locales?
1029     }
1030 }
1031 
1032 SvXMLNumFmtElementContext::~SvXMLNumFmtElementContext()
1033 {
1034 }
1035 
1036 SvXMLImportContext* SvXMLNumFmtElementContext::CreateChildContext(
1037                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
1038                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList )
1039 {
1040     //  only number:number supports number:embedded-text child element
1041 
1042     if ( nType == XML_TOK_STYLE_NUMBER &&
1043          nPrfx == XML_NAMESPACE_NUMBER && IsXMLToken( rLName, XML_EMBEDDED_TEXT ) )
1044     {
1045         return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nPrfx, rLName, *this, xAttrList );
1046     }
1047     else
1048         return new SvXMLImportContext( GetImport(), nPrfx, rLName );
1049 }
1050 
1051 void SvXMLNumFmtElementContext::Characters( const rtl::OUString& rChars )
1052 {
1053     aContent.append( rChars );
1054 }
1055 
1056 void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent )
1057 {
1058     if ( rContent.getLength() )
1059     {
1060         SvXMLEmbeddedElement* pObj = new SvXMLEmbeddedElement( nFormatPos, rContent );
1061         if ( !aNumInfo.aEmbeddedElements.Insert( pObj ) )
1062         {
1063             //  there's already an element at this position - append text to existing element
1064 
1065             delete pObj;
1066             sal_uInt16 nElementCount = aNumInfo.aEmbeddedElements.Count();
1067             for (sal_uInt16 i=0; i<nElementCount; i++)
1068             {
1069                 pObj = aNumInfo.aEmbeddedElements[i];
1070                 if ( pObj->nFormatPos == nFormatPos )
1071                 {
1072                     pObj->aText += rContent;
1073                     break;
1074                 }
1075             }
1076         }
1077     }
1078 }
1079 
1080 void SvXMLNumFmtElementContext::EndElement()
1081 {
1082     sal_Bool bEffLong = bLong;
1083     switch (nType)
1084     {
1085         case XML_TOK_STYLE_TEXT:
1086             if ( rParent.HasLongDoW() &&
1087                     rParent.GetLocaleData().getLongDateDayOfWeekSep() ==
1088                         String( aContent.getStr() ) )
1089             {
1090                 //  skip separator constant after long day of week
1091                 //  (NF_KEY_NNNN contains the separator)
1092 
1093                 if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) )
1094                 {
1095                     //!aContent.setLength(0);       //! doesn't work, #76293#
1096                     aContent = OUStringBuffer();
1097                 }
1098 
1099                 rParent.SetHasLongDoW( sal_False );     // only once
1100             }
1101             if ( aContent.getLength() )
1102             {
1103                 lcl_EnquoteIfNecessary( aContent, rParent );
1104                 rParent.AddToCode( aContent.makeStringAndClear() );
1105             }
1106             break;
1107 
1108         case XML_TOK_STYLE_NUMBER:
1109             rParent.AddNumber( aNumInfo );
1110             break;
1111 
1112         case XML_TOK_STYLE_CURRENCY_SYMBOL:
1113             rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang );
1114             break;
1115 
1116         case XML_TOK_STYLE_TEXT_CONTENT:
1117             rParent.AddToCode( OUString::valueOf((sal_Unicode)'@') );
1118             break;
1119         case XML_TOK_STYLE_BOOLEAN:
1120             // ignored - only default boolean format is supported
1121             break;
1122 
1123         case XML_TOK_STYLE_DAY:
1124             rParent.UpdateCalendar( sCalendar );
1125 #if 0
1126 //! I18N doesn't provide SYSTEM or extended date information yet
1127             if ( rParent.IsFromSystem() )
1128                 bEffLong = SvXMLNumFmtDefaults::IsSystemLongDay( rParent.GetInternational(), bLong );
1129 #endif
1130             rParent.AddNfKeyword(
1131                 sal::static_int_cast< sal_uInt16 >(
1132                     bEffLong ? NF_KEY_DD : NF_KEY_D ) );
1133             break;
1134         case XML_TOK_STYLE_MONTH:
1135             rParent.UpdateCalendar( sCalendar );
1136 #if 0
1137 //! I18N doesn't provide SYSTEM or extended date information yet
1138             if ( rParent.IsFromSystem() )
1139             {
1140                 bEffLong = SvXMLNumFmtDefaults::IsSystemLongMonth( rParent.GetInternational(), bLong );
1141                 bTextual = SvXMLNumFmtDefaults::IsSystemTextualMonth( rParent.GetInternational(), bLong );
1142             }
1143 #endif
1144             rParent.AddNfKeyword(
1145                 sal::static_int_cast< sal_uInt16 >(
1146                     bTextual
1147                     ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM )
1148                     : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) );
1149             break;
1150         case XML_TOK_STYLE_YEAR:
1151             rParent.UpdateCalendar( sCalendar );
1152 #if 0
1153 //! I18N doesn't provide SYSTEM or extended date information yet
1154             if ( rParent.IsFromSystem() )
1155                 bEffLong = SvXMLNumFmtDefaults::IsSystemLongYear( rParent.GetInternational(), bLong );
1156 #endif
1157             // Y after G (era) is replaced by E
1158             if ( rParent.HasEra() )
1159                 rParent.AddNfKeyword(
1160                     sal::static_int_cast< sal_uInt16 >(
1161                         bEffLong ? NF_KEY_EEC : NF_KEY_EC ) );
1162             else
1163                 rParent.AddNfKeyword(
1164                     sal::static_int_cast< sal_uInt16 >(
1165                         bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) );
1166             break;
1167         case XML_TOK_STYLE_ERA:
1168             rParent.UpdateCalendar( sCalendar );
1169 #if 0
1170 //! I18N doesn't provide SYSTEM or extended date information yet
1171             if ( rParent.IsFromSystem() )
1172                 bEffLong = SvXMLNumFmtDefaults::IsSystemLongEra( rParent.GetInternational(), bLong );
1173 #endif
1174             rParent.AddNfKeyword(
1175                 sal::static_int_cast< sal_uInt16 >(
1176                     bEffLong ? NF_KEY_GGG : NF_KEY_G ) );
1177             //  HasEra flag is set
1178             break;
1179         case XML_TOK_STYLE_DAY_OF_WEEK:
1180             rParent.UpdateCalendar( sCalendar );
1181 #if 0
1182 //! I18N doesn't provide SYSTEM or extended date information yet
1183             if ( rParent.IsFromSystem() )
1184                 bEffLong = SvXMLNumFmtDefaults::IsSystemLongDayOfWeek( rParent.GetInternational(), bLong );
1185 #endif
1186             rParent.AddNfKeyword(
1187                 sal::static_int_cast< sal_uInt16 >(
1188                     bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) );
1189             break;
1190         case XML_TOK_STYLE_WEEK_OF_YEAR:
1191             rParent.UpdateCalendar( sCalendar );
1192             rParent.AddNfKeyword( NF_KEY_WW );
1193             break;
1194         case XML_TOK_STYLE_QUARTER:
1195             rParent.UpdateCalendar( sCalendar );
1196             rParent.AddNfKeyword(
1197                 sal::static_int_cast< sal_uInt16 >(
1198                     bEffLong ? NF_KEY_QQ : NF_KEY_Q ) );
1199             break;
1200         case XML_TOK_STYLE_HOURS:
1201             rParent.AddNfKeyword(
1202                 sal::static_int_cast< sal_uInt16 >(
1203                     bEffLong ? NF_KEY_HH : NF_KEY_H ) );
1204             break;
1205         case XML_TOK_STYLE_AM_PM:
1206             //! short/long?
1207             rParent.AddNfKeyword( NF_KEY_AMPM );
1208             break;
1209         case XML_TOK_STYLE_MINUTES:
1210             rParent.AddNfKeyword(
1211                 sal::static_int_cast< sal_uInt16 >(
1212                     bEffLong ? NF_KEY_MMI : NF_KEY_MI ) );
1213             break;
1214         case XML_TOK_STYLE_SECONDS:
1215             rParent.AddNfKeyword(
1216                 sal::static_int_cast< sal_uInt16 >(
1217                     bEffLong ? NF_KEY_SS : NF_KEY_S ) );
1218             if ( aNumInfo.nDecimals > 0 )
1219             {
1220                 //  manually add the decimal places
1221                 const String& rSep = rParent.GetLocaleData().getNumDecimalSep();
1222                 for ( xub_StrLen j=0; j<rSep.Len(); j++ )
1223                 {
1224                     rParent.AddToCode( OUString::valueOf( rSep.GetChar(j) ) );
1225                 }
1226                 for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++)
1227                     rParent.AddToCode( OUString::valueOf((sal_Unicode)'0') );
1228             }
1229             break;
1230 
1231         case XML_TOK_STYLE_FRACTION:
1232             {
1233                 if ( aNumInfo.nInteger >= 0 )
1234                 {
1235                     // add integer part only if min-integer-digits attribute is there
1236                     aNumInfo.nDecimals = 0;
1237                     rParent.AddNumber( aNumInfo );      // number without decimals
1238                     rParent.AddToCode( OUString::valueOf((sal_Unicode)' ') );
1239                 }
1240 
1241                 //! build string and add at once
1242 
1243                 sal_Int32 i;
1244                 for (i=0; i<aNumInfo.nNumerDigits; i++)
1245                     rParent.AddToCode( OUString::valueOf((sal_Unicode)'?') );
1246                 rParent.AddToCode( OUString::valueOf((sal_Unicode)'/') );
1247                 for (i=0; i<aNumInfo.nDenomDigits; i++)
1248                     rParent.AddToCode( OUString::valueOf((sal_Unicode)'?') );
1249             }
1250             break;
1251 
1252         case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
1253             {
1254                 rParent.AddNumber( aNumInfo );      // simple number
1255 
1256                 rParent.AddToCode( OUString::createFromAscii( "E+" ) );
1257                 for (sal_Int32 i=0; i<aNumInfo.nExpDigits; i++)
1258                     rParent.AddToCode( OUString::valueOf((sal_Unicode)'0') );
1259             }
1260             break;
1261 
1262         default:
1263             DBG_ERROR("invalid element ID");
1264     }
1265 }
1266 
1267 //-------------------------------------------------------------------------
1268 
1269 sal_Bool SvXMLNumFmtDefaults::IsSystemLongDay( const SvtSysLocale&, sal_Bool bLong )
1270 {
1271     // TODO: merge system information and defaults into i18n locale data
1272 #if 0
1273     return bLong ? rIntn.IsLongDateDayLeadingZero() : rIntn.IsDateDayLeadingZero();
1274 #else
1275     return !bLong;
1276 #endif
1277 }
1278 
1279 sal_Bool SvXMLNumFmtDefaults::IsSystemLongMonth( const SvtSysLocale&, sal_Bool bLong )
1280 {
1281     // TODO: merge system information and defaults into i18n locale data
1282 #if 0
1283     if (bLong)
1284     {
1285         MonthFormat eMonth = rIntn.GetLongDateMonthFormat();
1286         return ( eMonth == MONTH_ZERO || eMonth == MONTH_LONG );
1287     }
1288     else
1289         return rIntn.IsDateMonthLeadingZero();
1290 #else
1291     return !bLong;
1292 #endif
1293 }
1294 
1295 sal_Bool SvXMLNumFmtDefaults::IsSystemTextualMonth( const SvtSysLocale&, sal_Bool bLong )
1296 {
1297     // TODO: merge system information and defaults into i18n locale data
1298 #if 0
1299     if (bLong)
1300     {
1301         MonthFormat eMonth = rIntn.GetLongDateMonthFormat();
1302         return ( eMonth == MONTH_SHORT || eMonth == MONTH_LONG );
1303     }
1304     else
1305         return sal_False;
1306 #else
1307     return bLong;
1308 #endif
1309 }
1310 
1311 sal_Bool SvXMLNumFmtDefaults::IsSystemLongYear( const SvtSysLocale&, sal_Bool bLong )
1312 {
1313     // TODO: merge system information and defaults into i18n locale data
1314 #if 0
1315     return bLong ? rIntn.IsLongDateCentury() : rIntn.IsDateCentury();
1316 #else
1317     return bLong;
1318 #endif
1319 }
1320 
1321 sal_Bool SvXMLNumFmtDefaults::IsSystemLongEra( const SvtSysLocale& rSysLoc, sal_Bool bLong )
1322 {
1323     // TODO: merge system information and defaults into i18n locale data
1324     return IsSystemLongYear( rSysLoc, bLong );      // no separate setting
1325 }
1326 
1327 sal_Bool SvXMLNumFmtDefaults::IsSystemLongDayOfWeek( const SvtSysLocale&, sal_Bool bLong )
1328 {
1329     // TODO: merge system information and defaults into i18n locale data
1330 #if 0
1331     return ( bLong && rIntn.GetLongDateDayOfWeekFormat() == DAYOFWEEK_LONG );
1332 #else
1333     return bLong && true;
1334 #endif
1335 }
1336 
1337 sal_uInt16 SvXMLNumFmtDefaults::GetDefaultDateFormat( SvXMLDateElementAttributes eDOW,
1338                 SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth,
1339                 SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours,
1340                 SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs,
1341                 sal_Bool bSystem )
1342 {
1343     const sal_uInt16 nCount = sizeof(aDefaultDateFormats) / sizeof(SvXMLDefaultDateFormat);
1344     for (sal_uInt16 nPos=0; nPos<nCount; nPos++)
1345     {
1346         const SvXMLDefaultDateFormat& rEntry = aDefaultDateFormats[nPos];
1347         if ( bSystem == rEntry.bSystem &&
1348             ( eDOW   == rEntry.eDOW   || ( rEntry.eDOW   == XML_DEA_ANY && eDOW   != XML_DEA_NONE ) ) &&
1349             ( eDay   == rEntry.eDay   || ( rEntry.eDay   == XML_DEA_ANY && eDay   != XML_DEA_NONE ) ) &&
1350             ( eMonth == rEntry.eMonth || ( rEntry.eMonth == XML_DEA_ANY && eMonth != XML_DEA_NONE ) ) &&
1351             ( eYear  == rEntry.eYear  || ( rEntry.eYear  == XML_DEA_ANY && eYear  != XML_DEA_NONE ) ) &&
1352             ( eHours == rEntry.eHours || ( rEntry.eHours == XML_DEA_ANY && eHours != XML_DEA_NONE ) ) &&
1353             ( eMins  == rEntry.eMins  || ( rEntry.eMins  == XML_DEA_ANY && eMins  != XML_DEA_NONE ) ) &&
1354             ( eSecs  == rEntry.eSecs  || ( rEntry.eSecs  == XML_DEA_ANY && eSecs  != XML_DEA_NONE ) ) )
1355         {
1356             return sal::static_int_cast< sal_uInt16 >(rEntry.eFormat);
1357         }
1358     }
1359 
1360     return NF_INDEX_TABLE_ENTRIES;  // invalid
1361 }
1362 
1363 //-------------------------------------------------------------------------
1364 
1365 //
1366 //  SvXMLNumFormatContext
1367 //
1368 
1369 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport,
1370                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
1371                                     SvXMLNumImpData* pNewData, sal_uInt16 nNewType,
1372                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList,
1373                                     SvXMLStylesContext& rStyles ) :
1374     SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList ),
1375     pData( pNewData ),
1376     pStyles( &rStyles ),
1377     aMyConditions(),
1378     nType( nNewType ),
1379     nKey(-1),
1380     nFormatLang( LANGUAGE_SYSTEM ),
1381     bAutoOrder( sal_False ),
1382     bFromSystem( sal_False ),
1383     bTruncate( sal_True ),
1384     bAutoDec( sal_False ),
1385     bAutoInt( sal_False ),
1386     bHasExtraText( sal_False ),
1387     bHasLongDoW( sal_False ),
1388     bHasEra( sal_False ),
1389     bHasDateTime( sal_False ),
1390     bRemoveAfterUse( sal_False ),
1391     eDateDOW( XML_DEA_NONE ),
1392     eDateDay( XML_DEA_NONE ),
1393     eDateMonth( XML_DEA_NONE ),
1394     eDateYear( XML_DEA_NONE ),
1395     eDateHours( XML_DEA_NONE ),
1396     eDateMins( XML_DEA_NONE ),
1397     eDateSecs( XML_DEA_NONE ),
1398     bDateNoDefault( sal_False )
1399 {
1400     OUString sLanguage, sCountry;
1401     ::com::sun::star::i18n::NativeNumberXmlAttributes aNatNumAttr;
1402     sal_Bool bAttrBool;
1403     sal_uInt16 nAttrEnum;
1404 
1405     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1406     for( sal_Int16 i=0; i < nAttrCount; i++ )
1407     {
1408         OUString sAttrName = xAttrList->getNameByIndex( i );
1409         OUString sValue = xAttrList->getValueByIndex( i );
1410         OUString aLocalName;
1411         sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
1412 
1413         const SvXMLTokenMap& rTokenMap = pData->GetStyleAttrTokenMap();
1414         sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName );
1415         switch (nToken)
1416         {
1417             case XML_TOK_STYLE_ATTR_NAME:
1418 //              aName = sValue;
1419                 break;
1420             case XML_TOK_STYLE_ATTR_LANGUAGE:
1421                 sLanguage = sValue;
1422                 break;
1423             case XML_TOK_STYLE_ATTR_COUNTRY:
1424                 sCountry = sValue;
1425                 break;
1426             case XML_TOK_STYLE_ATTR_TITLE:
1427                 sFormatTitle = sValue;
1428                 break;
1429             case XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER:
1430                 if ( SvXMLUnitConverter::convertBool( bAttrBool, sValue ) )
1431                     bAutoOrder = bAttrBool;
1432                 break;
1433             case XML_TOK_STYLE_ATTR_FORMAT_SOURCE:
1434                 if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aFormatSourceMap ) )
1435                     bFromSystem = (sal_Bool) nAttrEnum;
1436                 break;
1437             case XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW:
1438                 if ( SvXMLUnitConverter::convertBool( bAttrBool, sValue ) )
1439                     bTruncate = bAttrBool;
1440                 break;
1441             case XML_TOK_STYLE_ATTR_VOLATILE:
1442                 //  volatile formats can be removed after importing
1443                 //  if not used in other styles
1444                 if ( SvXMLUnitConverter::convertBool( bAttrBool, sValue ) )
1445                     bRemoveAfterUse = bAttrBool;
1446                 break;
1447             case XML_TOK_STYLE_ATTR_TRANSL_FORMAT:
1448                 aNatNumAttr.Format = sValue;
1449                 break;
1450             case XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE:
1451                 aNatNumAttr.Locale.Language = sValue;
1452                 break;
1453             case XML_TOK_STYLE_ATTR_TRANSL_COUNTRY:
1454                 aNatNumAttr.Locale.Country = sValue;
1455                 break;
1456             case XML_TOK_STYLE_ATTR_TRANSL_STYLE:
1457                 aNatNumAttr.Style = sValue;
1458                 break;
1459         }
1460     }
1461 
1462     if ( sLanguage.getLength() || sCountry.getLength() )
1463     {
1464         nFormatLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry );
1465         if ( nFormatLang == LANGUAGE_DONTKNOW )
1466             nFormatLang = LANGUAGE_SYSTEM;          //! error handling for invalid locales?
1467     }
1468 
1469     if ( aNatNumAttr.Format.getLength() )
1470     {
1471         SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1472         if ( pFormatter )
1473         {
1474             sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr );
1475             aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "[NatNum" ) );
1476             aFormatCode.append( nNatNum, 10 );
1477 
1478             LanguageType eLang = MsLangId::convertLocaleToLanguage( aNatNumAttr.Locale );
1479             if ( eLang == LANGUAGE_DONTKNOW )
1480                 eLang = LANGUAGE_SYSTEM;            //! error handling for invalid locales?
1481             if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM )
1482             {
1483                 aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "][$-" ) );
1484                 // language code in upper hex:
1485                 aFormatCode.append( String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii() );
1486             }
1487             aFormatCode.append( sal_Unicode(']') );
1488         }
1489     }
1490 }
1491 
1492 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport,
1493                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
1494                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList,
1495                                     const sal_Int32 nTempKey,
1496                                     SvXMLStylesContext& rStyles ) :
1497     SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList, XML_STYLE_FAMILY_DATA_STYLE ),
1498     pData( NULL ),
1499     pStyles( &rStyles ),
1500     aMyConditions(),
1501     nType( 0 ),
1502     nKey(nTempKey),
1503     nFormatLang( LANGUAGE_SYSTEM ),
1504     bAutoOrder( sal_False ),
1505     bFromSystem( sal_False ),
1506     bTruncate( sal_True ),
1507     bAutoDec( sal_False ),
1508     bAutoInt( sal_False ),
1509     bHasExtraText( sal_False ),
1510     bHasLongDoW( sal_False ),
1511     bHasEra( sal_False ),
1512     bHasDateTime( sal_False ),
1513     bRemoveAfterUse( sal_False ),
1514     eDateDOW( XML_DEA_NONE ),
1515     eDateDay( XML_DEA_NONE ),
1516     eDateMonth( XML_DEA_NONE ),
1517     eDateYear( XML_DEA_NONE ),
1518     eDateHours( XML_DEA_NONE ),
1519     eDateMins( XML_DEA_NONE ),
1520     eDateSecs( XML_DEA_NONE ),
1521     bDateNoDefault( sal_False )
1522 {
1523     SetAttribute(XML_NAMESPACE_STYLE, GetXMLToken(XML_NAME), rLName);
1524 }
1525 
1526 SvXMLNumFormatContext::~SvXMLNumFormatContext()
1527 {
1528 }
1529 
1530 SvXMLImportContext* SvXMLNumFormatContext::CreateChildContext(
1531                                     sal_uInt16 nPrfx, const rtl::OUString& rLName,
1532                                     const uno::Reference<xml::sax::XAttributeList>& xAttrList )
1533 {
1534     SvXMLImportContext* pContext = NULL;
1535 
1536     const SvXMLTokenMap& rTokenMap = pData->GetStyleElemTokenMap();
1537     sal_uInt16 nToken = rTokenMap.Get( nPrfx, rLName );
1538     switch (nToken)
1539     {
1540         case XML_TOK_STYLE_TEXT:
1541         case XML_TOK_STYLE_NUMBER:
1542         case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
1543         case XML_TOK_STYLE_FRACTION:
1544         case XML_TOK_STYLE_CURRENCY_SYMBOL:
1545         case XML_TOK_STYLE_DAY:
1546         case XML_TOK_STYLE_MONTH:
1547         case XML_TOK_STYLE_YEAR:
1548         case XML_TOK_STYLE_ERA:
1549         case XML_TOK_STYLE_DAY_OF_WEEK:
1550         case XML_TOK_STYLE_WEEK_OF_YEAR:
1551         case XML_TOK_STYLE_QUARTER:
1552         case XML_TOK_STYLE_HOURS:
1553         case XML_TOK_STYLE_AM_PM:
1554         case XML_TOK_STYLE_MINUTES:
1555         case XML_TOK_STYLE_SECONDS:
1556         case XML_TOK_STYLE_BOOLEAN:
1557         case XML_TOK_STYLE_TEXT_CONTENT:
1558             pContext = new SvXMLNumFmtElementContext( GetImport(), nPrfx, rLName,
1559                                                         *this, nToken, xAttrList );
1560             break;
1561 
1562         case XML_TOK_STYLE_PROPERTIES:
1563             pContext = new SvXMLNumFmtPropContext( GetImport(), nPrfx, rLName,
1564                                                         *this, xAttrList );
1565             break;
1566         case XML_TOK_STYLE_MAP:
1567             {
1568                 //  SvXMLNumFmtMapContext::EndElement adds to aMyConditions,
1569                 //  so there's no need for an extra flag
1570                 pContext = new SvXMLNumFmtMapContext( GetImport(), nPrfx, rLName,
1571                                                             *this, xAttrList );
1572             }
1573             break;
1574     }
1575 
1576     if( !pContext )
1577         pContext = new SvXMLImportContext( GetImport(), nPrfx, rLName );
1578     return pContext;
1579 }
1580 
1581 sal_Int32 SvXMLNumFormatContext::GetKey()
1582 {
1583     if (nKey > -1)
1584     {
1585         if (bRemoveAfterUse)
1586         {
1587             //  format is used -> don't remove
1588             bRemoveAfterUse = sal_False;
1589             if (pData)
1590                 pData->SetUsed(nKey);
1591 
1592             //  Add to import's list of keys now - CreateAndInsert didn't add
1593             //  the style if bRemoveAfterUse was set.
1594             GetImport().AddNumberStyle( nKey, GetName() );
1595         }
1596         return nKey;
1597     }
1598     else
1599     {
1600         // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set
1601         bRemoveAfterUse = sal_False;
1602         CreateAndInsert(sal_True);
1603         return nKey;
1604     }
1605 }
1606 
1607 sal_Int32 SvXMLNumFormatContext::PrivateGetKey()
1608 {
1609     //  used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag
1610 
1611     if (nKey > -1)
1612         return nKey;
1613     else
1614     {
1615         CreateAndInsert(sal_True);
1616         return nKey;
1617     }
1618 }
1619 
1620 sal_Int32 SvXMLNumFormatContext::CreateAndInsert( com::sun::star::uno::Reference< com::sun::star::util::XNumberFormatsSupplier >& xFormatsSupplier )
1621 {
1622     if (nKey <= -1)
1623     {
1624         SvNumberFormatter* pFormatter = NULL;
1625         SvNumberFormatsSupplierObj* pObj =
1626                         SvNumberFormatsSupplierObj::getImplementation( xFormatsSupplier );
1627         if (pObj)
1628             pFormatter = pObj->GetNumberFormatter();
1629 
1630         if ( pFormatter )
1631             return CreateAndInsert( pFormatter );
1632         else
1633             return -1;
1634     }
1635     else
1636         return nKey;
1637 }
1638 
1639 void SvXMLNumFormatContext::CreateAndInsert(sal_Bool /*bOverwrite*/)
1640 {
1641     if (!(nKey > -1))
1642         CreateAndInsert(pData->GetNumberFormatter());
1643 }
1644 
1645 sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter)
1646 {
1647     if (!pFormatter)
1648     {
1649         DBG_ERROR("no number formatter");
1650         return -1;
1651     }
1652 
1653     sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1654 
1655     for (sal_uInt32 i = 0; i < aMyConditions.size(); i++)
1656     {
1657         SvXMLNumFormatContext* pStyle = (SvXMLNumFormatContext *)pStyles->FindStyleChildContext(
1658             XML_STYLE_FAMILY_DATA_STYLE, aMyConditions[i].sMapName, sal_False);
1659         if (pStyle)
1660         {
1661             if ((pStyle->PrivateGetKey() > -1))     // don't reset pStyle's bRemoveAfterUse flag
1662                 AddCondition(i);
1663         }
1664     }
1665 
1666     if ( !aFormatCode.getLength() )
1667     {
1668         //  insert empty format as empty string (with quotes)
1669         //  #93901# this check has to be done before inserting the conditions
1670         aFormatCode.appendAscii("\"\"");    // ""
1671     }
1672 
1673     aFormatCode.insert( 0, aConditions.makeStringAndClear() );
1674     OUString sFormat = aFormatCode.makeStringAndClear();
1675 
1676     //  test special cases
1677 
1678     if ( bAutoDec )         // automatic decimal places
1679     {
1680         //  #99391# adjust only if the format contains no text elements, no conditions
1681         //  and no color definition (detected by the '[' at the start)
1682 
1683         if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
1684                 aMyConditions.size() == 0 && sFormat.toChar() != (sal_Unicode)'[' )
1685             nIndex = pFormatter->GetStandardIndex( nFormatLang );
1686     }
1687     if ( bAutoInt )         // automatic integer digits
1688     {
1689         //! only if two decimal places was set?
1690 
1691         if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
1692                 aMyConditions.size() == 0 && sFormat.toChar() != (sal_Unicode)'[' )
1693             nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang );
1694     }
1695 
1696     //  boolean is always the builtin boolean format
1697     //  (no other boolean formats are implemented)
1698     if ( nType == XML_TOK_STYLES_BOOLEAN_STYLE )
1699         nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang );
1700 
1701     //  check for default date formats
1702     if ( nType == XML_TOK_STYLES_DATE_STYLE && bAutoOrder && !bDateNoDefault )
1703     {
1704         NfIndexTableOffset eFormat = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
1705             eDateDOW, eDateDay, eDateMonth, eDateYear,
1706             eDateHours, eDateMins, eDateSecs, bFromSystem );
1707         if ( eFormat < NF_INDEX_TABLE_ENTRIES )
1708         {
1709             //  #109651# if a date format has the automatic-order attribute and
1710             //  contains exactly the elements of one of the default date formats,
1711             //  use that default format, with the element order and separators
1712             //  from the current locale settings
1713 
1714             nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang );
1715         }
1716     }
1717 
1718     if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && sFormat.getLength() )
1719     {
1720         //  insert by format string
1721 
1722         String aFormatStr( sFormat );
1723         nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1724         if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
1725         {
1726             xub_StrLen  nErrPos = 0;
1727             short       l_nType = 0;
1728             sal_Bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang );
1729             if ( !bOk && nErrPos == 0 && aFormatStr != String(sFormat) )
1730             {
1731                 //  if the string was modified by PutEntry, look for an existing format
1732                 //  with the modified string
1733                 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1734                 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1735                     bOk = sal_True;
1736             }
1737             if (!bOk)
1738                 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1739         }
1740     }
1741 
1742 #if 0
1743 //! I18N doesn't provide SYSTEM or extended date information yet
1744     if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bFromSystem )
1745     {
1746         //  instead of automatic date format, use fixed formats if bFromSystem is not set
1747         //! prevent use of automatic formats in other cases, force user-defined format?
1748 
1749         sal_uInt32 nNewIndex = nIndex;
1750 
1751         NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex );
1752         if ( eOffset == NF_DATE_SYSTEM_SHORT )
1753         {
1754             const International& rInt = pData->GetInternational( nFormatLang );
1755             if ( rInt.IsDateDayLeadingZero() && rInt.IsDateMonthLeadingZero() )
1756             {
1757                 if ( rInt.IsDateCentury() )
1758                     nNewIndex = pFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYYYY, nFormatLang );
1759                 else
1760                     nNewIndex = pFormatter->GetFormatIndex( NF_DATE_SYS_DDMMYY, nFormatLang );
1761             }
1762         }
1763         else if ( eOffset == NF_DATE_SYSTEM_LONG )
1764         {
1765             const International& rInt = pData->GetInternational( nFormatLang );
1766             if ( !rInt.IsLongDateDayLeadingZero() )
1767             {
1768                 sal_Bool bCentury = rInt.IsLongDateCentury();
1769                 MonthFormat eMonth = rInt.GetLongDateMonthFormat();
1770                 if ( eMonth == MONTH_LONG && bCentury )
1771                 {
1772                     if ( rInt.GetLongDateDayOfWeekFormat() == DAYOFWEEK_LONG )
1773                         nNewIndex = pFormatter->GetFormatIndex( NF_DATE_SYS_NNNNDMMMMYYYY, nFormatLang );
1774                     else
1775                         nNewIndex = pFormatter->GetFormatIndex( NF_DATE_SYS_NNDMMMMYYYY, nFormatLang );
1776                 }
1777                 else if ( eMonth == MONTH_SHORT && !bCentury )
1778                     nNewIndex = pFormatter->GetFormatIndex( NF_DATE_SYS_NNDMMMYY, nFormatLang );
1779             }
1780         }
1781 
1782         if ( nNewIndex != nIndex )
1783         {
1784             //  verify the fixed format really matches the format string
1785             //  (not the case with some formats from locale data)
1786 
1787             const SvNumberformat* pFixedFormat = pFormatter->GetEntry( nNewIndex );
1788             if ( pFixedFormat && pFixedFormat->GetFormatstring() == String(sFormat) )
1789                 nIndex = nNewIndex;
1790         }
1791     }
1792 #endif
1793 
1794     if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder )
1795     {
1796         //  use fixed-order formats instead of SYS... if bAutoOrder is false
1797         //  (only if the format strings are equal for the locale)
1798 
1799         NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex );
1800         if ( eOffset == NF_DATE_SYS_DMMMYYYY )
1801         {
1802             sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang );
1803             const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1804             const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1805             if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1806                 nIndex = nNewIndex;
1807         }
1808         else if ( eOffset == NF_DATE_SYS_DMMMMYYYY )
1809         {
1810             sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang );
1811             const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1812             const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1813             if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1814                 nIndex = nNewIndex;
1815         }
1816     }
1817 
1818     if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && sFormatTitle.getLength())
1819     {
1820         SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex ));
1821         if (pFormat)
1822         {
1823             String sTitle (sFormatTitle);
1824             pFormat->SetComment(sTitle);
1825         }
1826     }
1827 
1828     if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
1829     {
1830         DBG_ERROR("invalid number format");
1831         nIndex = pFormatter->GetStandardIndex( nFormatLang );
1832     }
1833 
1834     pData->AddKey( nIndex, GetName(), bRemoveAfterUse );
1835     nKey = nIndex;
1836 
1837     //  Add to import's list of keys (shared between styles and content import)
1838     //  only if not volatile - formats are removed from NumberFormatter at the
1839     //  end of each import (in SvXMLNumFmtHelper dtor).
1840     //  If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there.
1841 
1842     if (!bRemoveAfterUse)
1843         GetImport().AddNumberStyle( nKey, GetName() );
1844 
1845 #if 0
1846     ByteString aByte( String(sFormatName), gsl_getSystemTextEncoding() );
1847     aByte.Append( " | " );
1848     aByte.Append(ByteString( String(sFormat), gsl_getSystemTextEncoding() ));
1849     aByte.Append( " | " );
1850     aByte.Append(ByteString::CreateFromInt32( nIndex ));
1851 
1852 //  DBG_ERROR(aByte.GetBuffer());
1853     int xxx=42;
1854 #endif
1855 
1856     return nKey;
1857 }
1858 
1859 void SvXMLNumFormatContext::Finish( sal_Bool bOverwrite )
1860 {
1861     SvXMLStyleContext::Finish( bOverwrite );
1862 //  AddCondition();
1863 }
1864 
1865 const LocaleDataWrapper& SvXMLNumFormatContext::GetLocaleData() const
1866 {
1867     return pData->GetLocaleData( nFormatLang );
1868 }
1869 
1870 void SvXMLNumFormatContext::AddToCode( const rtl::OUString& rString )
1871 {
1872     aFormatCode.append( rString );
1873     bHasExtraText = sal_True;
1874 }
1875 
1876 void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo )
1877 {
1878     SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1879     if (!pFormatter)
1880         return;
1881 
1882     //  store special conditions
1883     bAutoDec = ( rInfo.nDecimals < 0 );
1884     bAutoInt = ( rInfo.nInteger < 0 );
1885 
1886     sal_uInt16 nPrec = 0;
1887     sal_uInt16 nLeading = 0;
1888     if ( rInfo.nDecimals >= 0 )                     //  < 0 : Default
1889         nPrec = (sal_uInt16) rInfo.nDecimals;
1890     if ( rInfo.nInteger >= 0 )                      //  < 0 : Default
1891         nLeading = (sal_uInt16) rInfo.nInteger;
1892 
1893     if ( bAutoDec )
1894     {
1895         if ( nType == XML_TOK_STYLES_CURRENCY_STYLE )
1896         {
1897             //  for currency formats, "automatic decimals" is used for the automatic
1898             //  currency format with (fixed) decimals from the locale settings
1899 
1900             const LocaleDataWrapper& rLoc = pData->GetLocaleData( nFormatLang );
1901             nPrec = rLoc.getCurrDigits();
1902         }
1903         else
1904         {
1905             //  for other types, "automatic decimals" means dynamic determination of
1906             //  decimals, as achieved with the "general" keyword
1907 
1908             aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) );
1909             return;
1910         }
1911     }
1912     if ( bAutoInt )
1913     {
1914         //!...
1915     }
1916 
1917     sal_uInt16 nGenPrec = nPrec;
1918     if ( rInfo.bDecReplace || rInfo.bVarDecimals )
1919         nGenPrec = 0;               // generate format without decimals...
1920 
1921     sal_Bool bGrouping = rInfo.bGrouping;
1922     sal_uInt16 nEmbeddedCount = rInfo.aEmbeddedElements.Count();
1923     if ( nEmbeddedCount )
1924         bGrouping = sal_False;      // grouping and embedded characters can't be used together
1925 
1926     String aNumStr;
1927     sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang );
1928     pFormatter->GenerateFormat( aNumStr, nStdIndex, nFormatLang,
1929                                 bGrouping, sal_False, nGenPrec, nLeading );
1930 
1931     if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 )
1932     {
1933         // #i43959# For scientific numbers, "#" in the integer part forces a digit,
1934         // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0").
1935 
1936         aNumStr.EraseLeadingChars( (sal_Unicode)'#' );
1937     }
1938 
1939     if ( nEmbeddedCount )
1940     {
1941         //  insert embedded strings into number string
1942         //  only the integer part is supported
1943         //  nZeroPos is the string position where format position 0 is inserted
1944 
1945         xub_StrLen nZeroPos = aNumStr.Search( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1946         if ( nZeroPos == STRING_NOTFOUND )
1947             nZeroPos = aNumStr.Len();
1948 
1949         //  aEmbeddedElements is sorted - last entry has the largest position (leftmost)
1950         const SvXMLEmbeddedElement* pLastObj = rInfo.aEmbeddedElements[nEmbeddedCount - 1];
1951         sal_Int32 nLastFormatPos = pLastObj->nFormatPos;
1952         if ( nLastFormatPos >= nZeroPos )
1953         {
1954             //  add '#' characters so all embedded texts are really embedded in digits
1955             //  (there always has to be a digit before the leftmost embedded text)
1956 
1957             xub_StrLen nAddCount = (xub_StrLen)nLastFormatPos + 1 - nZeroPos;
1958             String aDigitStr;
1959             aDigitStr.Fill( nAddCount, (sal_Unicode)'#' );
1960             aNumStr.Insert( aDigitStr, 0 );
1961             nZeroPos = nZeroPos + nAddCount;
1962         }
1963 
1964         //  aEmbeddedElements is sorted with ascending positions - loop is from right to left
1965         for (sal_uInt16 nElement = 0; nElement < nEmbeddedCount; nElement++)
1966         {
1967             const SvXMLEmbeddedElement* pObj = rInfo.aEmbeddedElements[nElement];
1968             sal_Int32 nFormatPos = pObj->nFormatPos;
1969             sal_Int32 nInsertPos = nZeroPos - nFormatPos;
1970             if ( nFormatPos >= 0 && nInsertPos >= 0 )
1971             {
1972                 rtl::OUStringBuffer aContent( pObj->aText );
1973                 //  #107805# always quote embedded strings - even space would otherwise
1974                 //  be recognized as thousands separator in French.
1975                 aContent.insert( 0, (sal_Unicode) '"' );
1976                 aContent.append( (sal_Unicode) '"' );
1977 
1978                 aNumStr.Insert( String( aContent.makeStringAndClear() ), (xub_StrLen)nInsertPos );
1979             }
1980         }
1981     }
1982 
1983     aFormatCode.append( aNumStr );
1984 
1985     if ( ( rInfo.bDecReplace || rInfo.bVarDecimals ) && nPrec )     // add decimal replacement (dashes)
1986     {
1987         //  add dashes for explicit decimal replacement, # for variable decimals
1988         sal_Unicode cAdd = rInfo.bDecReplace ? '-' : '#';
1989 
1990         aFormatCode.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1991         for ( sal_uInt16 i=0; i<nPrec; i++)
1992             aFormatCode.append( cAdd );
1993     }
1994 
1995     //  add extra thousands separators for display factor
1996 
1997     if ( rInfo.fDisplayFactor != 1.0 && rInfo.fDisplayFactor > 0.0 )
1998     {
1999         //  test for 1.0 is just for optimization - nSepCount would be 0
2000 
2001         //  one separator for each factor of 1000
2002         sal_Int32 nSepCount = (sal_Int32) ::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 );
2003         if ( nSepCount > 0 )
2004         {
2005             OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep();
2006             for ( sal_Int32 i=0; i<nSepCount; i++ )
2007                 aFormatCode.append( aSep );
2008         }
2009     }
2010 }
2011 
2012 void SvXMLNumFormatContext::AddCurrency( const rtl::OUString& rContent, LanguageType nLang )
2013 {
2014     sal_Bool bAutomatic = sal_False;
2015     OUString aSymbol = rContent;
2016     if ( aSymbol.getLength() == 0 )
2017     {
2018         //  get currency symbol for language
2019 
2020         //aSymbol = pData->GetLocaleData( nFormatLang ).getCurrSymbol();
2021 
2022         SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2023         if ( pFormatter )
2024         {
2025             pFormatter->ChangeIntl( nFormatLang );
2026             String sCurString, sDummy;
2027             pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
2028             aSymbol = sCurString;
2029 
2030             bAutomatic = sal_True;
2031         }
2032     }
2033     else if ( nLang == LANGUAGE_SYSTEM && aSymbol.compareToAscii("CCC") == 0 )
2034     {
2035         //  "CCC" is used for automatic long symbol
2036         bAutomatic = sal_True;
2037     }
2038 
2039     if ( bAutomatic )
2040     {
2041         //  remove unnecessary quotes before automatic symbol (formats like "-(0DM)")
2042         //  otherwise the currency symbol isn't recognized (#94048#)
2043 
2044         sal_Int32 nLength = aFormatCode.getLength();
2045         if ( nLength > 1 && aFormatCode.charAt( nLength-1 ) == '"' )
2046         {
2047             //  find start of quoted string
2048             //  When SvXMLNumFmtElementContext::EndElement creates escaped quotes,
2049             //  they must be handled here, too.
2050 
2051             sal_Int32 nFirst = nLength - 2;
2052             while ( nFirst >= 0 && aFormatCode.charAt( nFirst ) != '"' )
2053                 --nFirst;
2054             if ( nFirst >= 0 )
2055             {
2056                 //  remove both quotes from aFormatCode
2057                 rtl::OUString aOld = aFormatCode.makeStringAndClear();
2058                 if ( nFirst > 0 )
2059                     aFormatCode.append( aOld.copy( 0, nFirst ) );
2060                 if ( nLength > nFirst + 2 )
2061                     aFormatCode.append( aOld.copy( nFirst + 1, nLength - nFirst - 2 ) );
2062             }
2063         }
2064     }
2065 
2066     if (!bAutomatic)
2067         aFormatCode.appendAscii( "[$" );            // intro for "new" currency symbols
2068 
2069     aFormatCode.append( aSymbol );
2070 
2071     if (!bAutomatic)
2072     {
2073         if ( nLang != LANGUAGE_SYSTEM )
2074         {
2075             //  '-' sign and language code in hex:
2076             aFormatCode.append( (sal_Unicode) '-' );
2077             aFormatCode.append( String::CreateFromInt32( sal_Int32( nLang ), 16 ).ToUpperAscii() );
2078         }
2079 
2080         aFormatCode.append( (sal_Unicode) ']' );    // end of "new" currency symbol
2081     }
2082 }
2083 
2084 void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex )
2085 {
2086     SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2087     if (!pFormatter)
2088         return;
2089 
2090     if ( nIndex == NF_KEY_G || nIndex == NF_KEY_GG || nIndex == NF_KEY_GGG )
2091         bHasEra = sal_True;
2092 
2093     if ( nIndex == NF_KEY_NNNN )
2094     {
2095         nIndex = NF_KEY_NNN;
2096         bHasLongDoW = sal_True;         // to remove string constant with separator
2097     }
2098 
2099     String sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex );
2100 
2101     if ( nIndex == NF_KEY_H  || nIndex == NF_KEY_HH  ||
2102          nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI ||
2103          nIndex == NF_KEY_S  || nIndex == NF_KEY_SS )
2104     {
2105         if ( !bTruncate && !bHasDateTime )
2106         {
2107             //  with truncate-on-overflow = false, add "[]" to first time part
2108 
2109             sKeyword.Insert( (sal_Unicode) '[', 0 );
2110             sKeyword.Append( (sal_Unicode) ']' );
2111         }
2112         bHasDateTime = sal_True;
2113     }
2114 
2115     aFormatCode.append( sKeyword );
2116 
2117     //  collect the date elements that the format contains, to recognize default date formats
2118     switch ( nIndex )
2119     {
2120         case NF_KEY_NN:     eDateDOW = XML_DEA_SHORT;       break;
2121         case NF_KEY_NNN:
2122         case NF_KEY_NNNN:   eDateDOW = XML_DEA_LONG;        break;
2123         case NF_KEY_D:      eDateDay = XML_DEA_SHORT;       break;
2124         case NF_KEY_DD:     eDateDay = XML_DEA_LONG;        break;
2125         case NF_KEY_M:      eDateMonth = XML_DEA_SHORT;     break;
2126         case NF_KEY_MM:     eDateMonth = XML_DEA_LONG;      break;
2127         case NF_KEY_MMM:    eDateMonth = XML_DEA_TEXTSHORT; break;
2128         case NF_KEY_MMMM:   eDateMonth = XML_DEA_TEXTLONG;  break;
2129         case NF_KEY_YY:     eDateYear = XML_DEA_SHORT;      break;
2130         case NF_KEY_YYYY:   eDateYear = XML_DEA_LONG;       break;
2131         case NF_KEY_H:      eDateHours = XML_DEA_SHORT;     break;
2132         case NF_KEY_HH:     eDateHours = XML_DEA_LONG;      break;
2133         case NF_KEY_MI:     eDateMins = XML_DEA_SHORT;      break;
2134         case NF_KEY_MMI:    eDateMins = XML_DEA_LONG;       break;
2135         case NF_KEY_S:      eDateSecs = XML_DEA_SHORT;      break;
2136         case NF_KEY_SS:     eDateSecs = XML_DEA_LONG;       break;
2137         case NF_KEY_AP:
2138         case NF_KEY_AMPM:   break;          // AM/PM may or may not be in date/time formats -> ignore by itself
2139         default:
2140             bDateNoDefault = sal_True;      // any other element -> no default format
2141     }
2142 }
2143 
2144 sal_Bool lcl_IsAtEnd( rtl::OUStringBuffer& rBuffer, const String& rToken )
2145 {
2146     sal_Int32 nBufLen = rBuffer.getLength();
2147     xub_StrLen nTokLen = rToken.Len();
2148 
2149     if ( nTokLen > nBufLen )
2150         return sal_False;
2151 
2152     sal_Int32 nStartPos = nBufLen - nTokLen;
2153     for ( xub_StrLen nTokPos = 0; nTokPos < nTokLen; nTokPos++ )
2154         if ( rToken.GetChar( nTokPos ) != rBuffer.charAt( nStartPos + nTokPos ) )
2155             return sal_False;
2156 
2157     return sal_True;
2158 }
2159 
2160 sal_Bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew )
2161 {
2162     //  replaces one keyword with another if it is found at the end of the code
2163 
2164     SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2165     if (!pFormatter)
2166         return sal_False;
2167 
2168     String sOldStr = pFormatter->GetKeyword( nFormatLang, nOld );
2169     if ( lcl_IsAtEnd( aFormatCode, sOldStr ) )
2170     {
2171         // remove old keyword
2172         aFormatCode.setLength( aFormatCode.getLength() - sOldStr.Len() );
2173 
2174         // add new keyword
2175         String sNewStr = pFormatter->GetKeyword( nFormatLang, nNew );
2176         aFormatCode.append( sNewStr );
2177 
2178         return sal_True;    // changed
2179     }
2180     return sal_False;       // not found
2181 }
2182 
2183 void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex )
2184 {
2185     rtl::OUString rApplyName = aMyConditions[nIndex].sMapName;
2186     rtl::OUString rCondition = aMyConditions[nIndex].sCondition;
2187     SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2188     sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName );
2189     OUString sValue = OUString::createFromAscii( "value()" );       //! define constant
2190     sal_Int32 nValLen = sValue.getLength();
2191 
2192     if ( pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND &&
2193             rCondition.copy( 0, nValLen ) == sValue )
2194     {
2195         //! test for valid conditions
2196         //! test for default conditions
2197 
2198         OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen );
2199         sal_Bool bDefaultCond = sal_False;
2200 
2201         //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count
2202         //! allow blanks in conditions
2203         sal_Bool bFirstCond = ( aConditions.getLength() == 0 );
2204         if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 )
2205             bDefaultCond = sal_True;
2206 
2207         if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 )
2208         {
2209             //  The third condition in a number format with a text part can only be
2210             //  "all other numbers", the condition string must be empty.
2211             bDefaultCond = sal_True;
2212         }
2213 
2214         if (!bDefaultCond)
2215         {
2216             sal_Int32 nPos = sRealCond.indexOf( '.' );
2217             if ( nPos >= 0 )
2218             {   // #i8026# #103991# localize decimal separator
2219                 const String& rDecSep = GetLocaleData().getNumDecimalSep();
2220                 if ( rDecSep.Len() > 1 || rDecSep.GetChar(0) != '.' )
2221                     sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
2222             }
2223             aConditions.append( (sal_Unicode) '[' );
2224             aConditions.append( sRealCond );
2225             aConditions.append( (sal_Unicode) ']' );
2226         }
2227 
2228         const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey);
2229         if ( pFormat )
2230             aConditions.append( OUString( pFormat->GetFormatstring() ) );
2231 
2232         aConditions.append( (sal_Unicode) ';' );
2233     }
2234 }
2235 
2236 void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex, const rtl::OUString& rFormat, const LocaleDataWrapper& rData )
2237 {
2238     rtl::OUString rCondition = aMyConditions[nIndex].sCondition;
2239     OUString sValue = OUString::createFromAscii( "value()" );       //! define constant
2240     sal_Int32 nValLen = sValue.getLength();
2241 
2242     if ( rCondition.copy( 0, nValLen ) == sValue )
2243     {
2244         //! test for valid conditions
2245         //! test for default conditions
2246 
2247         OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen );
2248         sal_Bool bDefaultCond = sal_False;
2249 
2250         //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count
2251         //! allow blanks in conditions
2252         sal_Bool bFirstCond = ( aConditions.getLength() == 0 );
2253         if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 )
2254             bDefaultCond = sal_True;
2255 
2256         if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 )
2257         {
2258             //  The third condition in a number format with a text part can only be
2259             //  "all other numbers", the condition string must be empty.
2260             bDefaultCond = sal_True;
2261         }
2262 
2263         if (!bDefaultCond)
2264         {
2265             sal_Int32 nPos = sRealCond.indexOf( '.' );
2266             if ( nPos >= 0 )
2267             {   // #i8026# #103991# localize decimal separator
2268                 const String& rDecSep = rData.getNumDecimalSep();
2269                 if ( rDecSep.Len() > 1 || rDecSep.GetChar(0) != '.' )
2270                     sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
2271             }
2272             aConditions.append( (sal_Unicode) '[' );
2273             aConditions.append( sRealCond );
2274             aConditions.append( (sal_Unicode) ']' );
2275         }
2276 
2277         aConditions.append( rFormat );
2278 
2279         aConditions.append( (sal_Unicode) ';' );
2280     }
2281 }
2282 
2283 void SvXMLNumFormatContext::AddCondition( const rtl::OUString& rCondition, const rtl::OUString& rApplyName )
2284 {
2285     MyCondition aCondition;
2286     aCondition.sCondition = rCondition;
2287     aCondition.sMapName = rApplyName;
2288     aMyConditions.push_back(aCondition);
2289 }
2290 
2291 void SvXMLNumFormatContext::AddColor( const Color& rColor )
2292 {
2293     SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2294     if (!pFormatter)
2295         return;
2296 
2297     OUStringBuffer aColName;
2298     for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ )
2299         if ( rColor == aNumFmtStdColors[i] )
2300         {
2301             aColName = OUString( pFormatter->GetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ) );
2302             break;
2303         }
2304 
2305     if ( aColName.getLength() )
2306     {
2307         aColName.insert( 0, (sal_Unicode) '[' );
2308         aColName.append( (sal_Unicode) ']' );
2309         aFormatCode.insert( 0, aColName.makeStringAndClear() );
2310     }
2311 }
2312 
2313 void SvXMLNumFormatContext::UpdateCalendar( const rtl::OUString& rNewCalendar )
2314 {
2315     if ( rNewCalendar != sCalendar )
2316     {
2317         sCalendar = rNewCalendar;
2318         if ( sCalendar.getLength() )
2319         {
2320             aFormatCode.appendAscii( "[~" );            // intro for calendar code
2321             aFormatCode.append( sCalendar );
2322             aFormatCode.append( (sal_Unicode) ']' );    // end of "new" currency symbolcalendar code
2323         }
2324     }
2325 }
2326 
2327 sal_Bool SvXMLNumFormatContext::IsSystemLanguage()
2328 {
2329     return nFormatLang == LANGUAGE_SYSTEM;
2330 }
2331 
2332 //-------------------------------------------------------------------------
2333 
2334 //
2335 //  SvXMLNumFmtHelper
2336 //
2337 
2338 // #110680#
2339 //SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2340 //                      const uno::Reference<util::XNumberFormatsSupplier>& rSupp )
2341 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2342     const uno::Reference<util::XNumberFormatsSupplier>& rSupp,
2343     const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
2344 :   mxServiceFactory(xServiceFactory)
2345 {
2346     DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
2347 
2348     SvNumberFormatter* pFormatter = NULL;
2349     SvNumberFormatsSupplierObj* pObj =
2350                     SvNumberFormatsSupplierObj::getImplementation( rSupp );
2351     if (pObj)
2352         pFormatter = pObj->GetNumberFormatter();
2353 
2354     // #110680#
2355     // pData = new SvXMLNumImpData( pFormatter );
2356     pData = new SvXMLNumImpData( pFormatter, mxServiceFactory );
2357 }
2358 
2359 // #110680#
2360 // SvXMLNumFmtHelper::SvXMLNumFmtHelper( SvNumberFormatter* pNumberFormatter )
2361 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2362     SvNumberFormatter* pNumberFormatter,
2363     const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
2364 :   mxServiceFactory(xServiceFactory)
2365 {
2366     DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
2367 
2368     // #110680#
2369     // pData = new SvXMLNumImpData( pNumberFormatter );
2370     pData = new SvXMLNumImpData( pNumberFormatter, mxServiceFactory );
2371 }
2372 
2373 SvXMLNumFmtHelper::~SvXMLNumFmtHelper()
2374 {
2375     //  remove temporary (volatile) formats from NumberFormatter
2376     pData->RemoveVolatileFormats();
2377 
2378     delete pData;
2379 }
2380 
2381 SvXMLStyleContext*  SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport,
2382                 sal_uInt16 nPrefix, const OUString& rLocalName,
2383                 const uno::Reference<xml::sax::XAttributeList>& xAttrList,
2384                 SvXMLStylesContext& rStyles )
2385 {
2386     SvXMLStyleContext* pContext = NULL;
2387 
2388     const SvXMLTokenMap& rTokenMap = pData->GetStylesElemTokenMap();
2389     sal_uInt16 nToken = rTokenMap.Get( nPrefix, rLocalName );
2390     switch (nToken)
2391     {
2392         case XML_TOK_STYLES_NUMBER_STYLE:
2393         case XML_TOK_STYLES_CURRENCY_STYLE:
2394         case XML_TOK_STYLES_PERCENTAGE_STYLE:
2395         case XML_TOK_STYLES_DATE_STYLE:
2396         case XML_TOK_STYLES_TIME_STYLE:
2397         case XML_TOK_STYLES_BOOLEAN_STYLE:
2398         case XML_TOK_STYLES_TEXT_STYLE:
2399             pContext = new SvXMLNumFormatContext( rImport, nPrefix, rLocalName,
2400                                                     pData, nToken, xAttrList, rStyles );
2401             break;
2402     }
2403 
2404     // return NULL if not a data style, caller must handle other elements
2405     return pContext;
2406 }
2407 
2408 const SvXMLTokenMap& SvXMLNumFmtHelper::GetStylesElemTokenMap()
2409 {
2410     return pData->GetStylesElemTokenMap();
2411 }
2412 
2413 /*sal_uInt32 SvXMLNumFmtHelper::GetKeyForName( const rtl::OUString& rName )
2414 {
2415     return pData->GetKeyForName( rName );
2416 }*/
2417 
2418 
2419