Bump for 3.6-28
[LibreOffice.git] / xmloff / source / style / xmlnumfi.cxx
blobfcd92bdae2800bc7fbf2719c91469734822c9676
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <unotools/syslocale.hxx>
32 #include <svl/zforlist.hxx>
34 #include <svl/zformat.hxx>
35 #include <svl/numuno.hxx>
36 #include <rtl/math.hxx>
37 #include <i18npool/mslangid.hxx>
38 #include <tools/color.hxx>
39 #include <tools/debug.hxx>
40 #include <rtl/ustrbuf.hxx>
42 #include <sax/tools/converter.hxx>
44 #include <xmloff/xmlnumfi.hxx>
45 #include <xmloff/xmltkmap.hxx>
46 #include "xmloff/xmlnmspe.hxx"
47 #include <xmloff/xmlictxt.hxx>
48 #include <xmloff/xmlimp.hxx>
49 #include <xmloff/xmluconv.hxx>
50 #include <xmloff/nmspmap.hxx>
51 #include <xmloff/families.hxx>
52 #include <xmloff/xmltoken.hxx>
54 #include <boost/ptr_container/ptr_vector.hpp>
55 #include <boost/ptr_container/ptr_set.hpp>
57 using ::rtl::OUString;
58 using ::rtl::OUStringBuffer;
60 using namespace ::com::sun::star;
61 using namespace ::xmloff::token;
63 //-------------------------------------------------------------------------
65 struct SvXMLNumFmtEntry
67 rtl::OUString aName;
68 sal_uInt32 nKey;
69 sal_Bool bRemoveAfterUse;
71 SvXMLNumFmtEntry( const rtl::OUString& rN, sal_uInt32 nK, sal_Bool bR ) :
72 aName(rN), nKey(nK), bRemoveAfterUse(bR) {}
75 typedef ::boost::ptr_vector<SvXMLNumFmtEntry> SvXMLNumFmtEntryArr;
77 struct SvXMLEmbeddedElement
79 sal_Int32 nFormatPos;
80 rtl::OUString aText;
82 SvXMLEmbeddedElement( sal_Int32 nFP, const rtl::OUString& rT ) :
83 nFormatPos(nFP), aText(rT) {}
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; }
90 typedef boost::ptr_set<SvXMLEmbeddedElement> SvXMLEmbeddedElementArr;
92 //-------------------------------------------------------------------------
94 class SvXMLNumImpData
96 SvNumberFormatter* pFormatter;
97 SvXMLTokenMap* pStylesElemTokenMap;
98 SvXMLTokenMap* pStyleElemTokenMap;
99 SvXMLTokenMap* pStyleAttrTokenMap;
100 SvXMLTokenMap* pStyleElemAttrTokenMap;
101 LocaleDataWrapper* pLocaleData;
102 SvXMLNumFmtEntryArr aNameEntries;
104 ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > mxServiceFactory;
106 public:
107 SvXMLNumImpData(
108 SvNumberFormatter* pFmt,
109 const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory );
110 ~SvXMLNumImpData();
112 SvNumberFormatter* GetNumberFormatter() const { return pFormatter; }
113 const SvXMLTokenMap& GetStylesElemTokenMap();
114 const SvXMLTokenMap& GetStyleElemTokenMap();
115 const SvXMLTokenMap& GetStyleAttrTokenMap();
116 const SvXMLTokenMap& GetStyleElemAttrTokenMap();
117 const LocaleDataWrapper& GetLocaleData( LanguageType nLang );
118 sal_uInt32 GetKeyForName( const rtl::OUString& rName );
119 void AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse );
120 void SetUsed( sal_uInt32 nKey );
121 void RemoveVolatileFormats();
125 struct SvXMLNumberInfo
127 sal_Int32 nDecimals;
128 sal_Int32 nInteger;
129 sal_Int32 nExpDigits;
130 sal_Int32 nNumerDigits;
131 sal_Int32 nDenomDigits;
132 sal_Int32 nFracDenominator;
133 sal_Bool bGrouping;
134 sal_Bool bDecReplace;
135 sal_Bool bVarDecimals;
136 double fDisplayFactor;
137 SvXMLEmbeddedElementArr aEmbeddedElements;
139 SvXMLNumberInfo()
141 nDecimals = nInteger = nExpDigits = nNumerDigits = nDenomDigits = nFracDenominator = -1;
142 bGrouping = bDecReplace = bVarDecimals = sal_False;
143 fDisplayFactor = 1.0;
147 class SvXMLNumFmtElementContext : public SvXMLImportContext
149 SvXMLNumFormatContext& rParent;
150 sal_uInt16 nType;
151 rtl::OUStringBuffer aContent;
152 SvXMLNumberInfo aNumInfo;
153 LanguageType nElementLang;
154 sal_Bool bLong;
155 sal_Bool bTextual;
156 rtl::OUString sCalendar;
158 public:
159 SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
160 const rtl::OUString& rLName,
161 SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
162 const ::com::sun::star::uno::Reference<
163 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
164 virtual ~SvXMLNumFmtElementContext();
166 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
167 const rtl::OUString& rLocalName,
168 const ::com::sun::star::uno::Reference<
169 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
170 virtual void Characters( const rtl::OUString& rChars );
171 virtual void EndElement();
173 void AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent );
177 class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext
179 SvXMLNumFmtElementContext& rParent;
180 rtl::OUStringBuffer aContent;
181 sal_Int32 nTextPosition;
183 public:
184 SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
185 const rtl::OUString& rLName,
186 SvXMLNumFmtElementContext& rParentContext,
187 const ::com::sun::star::uno::Reference<
188 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
189 virtual ~SvXMLNumFmtEmbeddedTextContext();
191 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
192 const rtl::OUString& rLocalName,
193 const ::com::sun::star::uno::Reference<
194 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
195 virtual void Characters( const rtl::OUString& rChars );
196 virtual void EndElement();
200 class SvXMLNumFmtMapContext : public SvXMLImportContext
202 SvXMLNumFormatContext& rParent;
203 rtl::OUString sCondition;
204 rtl::OUString sName;
206 public:
207 SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
208 const rtl::OUString& rLName,
209 SvXMLNumFormatContext& rParentContext,
210 const ::com::sun::star::uno::Reference<
211 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
212 virtual ~SvXMLNumFmtMapContext();
214 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
215 const rtl::OUString& rLocalName,
216 const ::com::sun::star::uno::Reference<
217 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
218 virtual void Characters( const rtl::OUString& rChars );
219 virtual void EndElement();
223 class SvXMLNumFmtPropContext : public SvXMLImportContext
225 SvXMLNumFormatContext& rParent;
226 sal_Int32 m_nColor;
227 sal_Bool bColSet;
229 public:
230 SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
231 const rtl::OUString& rLName,
232 SvXMLNumFormatContext& rParentContext,
233 const ::com::sun::star::uno::Reference<
234 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
235 virtual ~SvXMLNumFmtPropContext();
237 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
238 const rtl::OUString& rLocalName,
239 const ::com::sun::star::uno::Reference<
240 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
241 virtual void Characters( const rtl::OUString& rChars );
242 virtual void EndElement();
246 //-------------------------------------------------------------------------
248 enum SvXMLStyleTokens
250 XML_TOK_STYLE_TEXT,
251 XML_TOK_STYLE_NUMBER,
252 XML_TOK_STYLE_SCIENTIFIC_NUMBER,
253 XML_TOK_STYLE_FRACTION,
254 XML_TOK_STYLE_CURRENCY_SYMBOL,
255 XML_TOK_STYLE_DAY,
256 XML_TOK_STYLE_MONTH,
257 XML_TOK_STYLE_YEAR,
258 XML_TOK_STYLE_ERA,
259 XML_TOK_STYLE_DAY_OF_WEEK,
260 XML_TOK_STYLE_WEEK_OF_YEAR,
261 XML_TOK_STYLE_QUARTER,
262 XML_TOK_STYLE_HOURS,
263 XML_TOK_STYLE_AM_PM,
264 XML_TOK_STYLE_MINUTES,
265 XML_TOK_STYLE_SECONDS,
266 XML_TOK_STYLE_BOOLEAN,
267 XML_TOK_STYLE_TEXT_CONTENT,
268 XML_TOK_STYLE_PROPERTIES,
269 XML_TOK_STYLE_MAP
272 enum SvXMLStyleAttrTokens
274 XML_TOK_STYLE_ATTR_NAME,
275 XML_TOK_STYLE_ATTR_LANGUAGE,
276 XML_TOK_STYLE_ATTR_COUNTRY,
277 XML_TOK_STYLE_ATTR_TITLE,
278 XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER,
279 XML_TOK_STYLE_ATTR_FORMAT_SOURCE,
280 XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW,
281 XML_TOK_STYLE_ATTR_VOLATILE,
282 XML_TOK_STYLE_ATTR_TRANSL_FORMAT,
283 XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE,
284 XML_TOK_STYLE_ATTR_TRANSL_COUNTRY,
285 XML_TOK_STYLE_ATTR_TRANSL_STYLE
288 enum SvXMLStyleElemAttrTokens
290 XML_TOK_ELEM_ATTR_DECIMAL_PLACES,
291 XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS,
292 XML_TOK_ELEM_ATTR_GROUPING,
293 XML_TOK_ELEM_ATTR_DISPLAY_FACTOR,
294 XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT,
295 XML_TOK_ELEM_ATTR_DENOMINATOR_VALUE,
296 XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS,
297 XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS,
298 XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS,
299 XML_TOK_ELEM_ATTR_LANGUAGE,
300 XML_TOK_ELEM_ATTR_COUNTRY,
301 XML_TOK_ELEM_ATTR_STYLE,
302 XML_TOK_ELEM_ATTR_TEXTUAL,
303 XML_TOK_ELEM_ATTR_CALENDAR
306 //-------------------------------------------------------------------------
309 // standard colors
312 #define XML_NUMF_COLORCOUNT 10
314 static ColorData aNumFmtStdColors[XML_NUMF_COLORCOUNT] =
316 COL_BLACK,
317 COL_LIGHTBLUE,
318 COL_LIGHTGREEN,
319 COL_LIGHTCYAN,
320 COL_LIGHTRED,
321 COL_LIGHTMAGENTA,
322 COL_BROWN,
323 COL_GRAY,
324 COL_YELLOW,
325 COL_WHITE
329 // token maps
332 // maps for SvXMLUnitConverter::convertEnum
334 static SvXMLEnumMapEntry aStyleValueMap[] =
336 { XML_SHORT, sal_False },
337 { XML_LONG, sal_True },
338 { XML_TOKEN_INVALID, 0 }
341 static SvXMLEnumMapEntry aFormatSourceMap[] =
343 { XML_FIXED, sal_False },
344 { XML_LANGUAGE, sal_True },
345 { XML_TOKEN_INVALID, 0 }
348 //-------------------------------------------------------------------------
350 struct SvXMLDefaultDateFormat
352 NfIndexTableOffset eFormat;
353 SvXMLDateElementAttributes eDOW;
354 SvXMLDateElementAttributes eDay;
355 SvXMLDateElementAttributes eMonth;
356 SvXMLDateElementAttributes eYear;
357 SvXMLDateElementAttributes eHours;
358 SvXMLDateElementAttributes eMins;
359 SvXMLDateElementAttributes eSecs;
360 sal_Bool bSystem;
363 static SvXMLDefaultDateFormat aDefaultDateFormats[] =
365 // format day-of-week day month year hours minutes seconds format-source
367 { 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 },
368 { 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 },
369 { 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 },
370 { 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 },
371 { 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 },
372 { 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 },
373 { 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 },
374 { 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 },
375 { 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 },
376 { 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 },
377 { 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 },
378 { 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 },
379 { 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 },
380 { 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 //-------------------------------------------------------------------------
386 // SvXMLNumImpData
389 SvXMLNumImpData::SvXMLNumImpData(
390 SvNumberFormatter* pFmt,
391 const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
392 : pFormatter(pFmt),
393 pStylesElemTokenMap(NULL),
394 pStyleElemTokenMap(NULL),
395 pStyleAttrTokenMap(NULL),
396 pStyleElemAttrTokenMap(NULL),
397 pLocaleData(NULL),
399 mxServiceFactory(xServiceFactory)
401 DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
404 SvXMLNumImpData::~SvXMLNumImpData()
406 delete pStylesElemTokenMap;
407 delete pStyleElemTokenMap;
408 delete pStyleAttrTokenMap;
409 delete pStyleElemAttrTokenMap;
410 delete pLocaleData;
413 sal_uInt32 SvXMLNumImpData::GetKeyForName( const rtl::OUString& rName )
415 sal_uInt16 nCount = aNameEntries.size();
416 for (sal_uInt16 i=0; i<nCount; i++)
418 const SvXMLNumFmtEntry* pObj = &aNameEntries[i];
419 if ( pObj->aName == rName )
420 return pObj->nKey; // found
422 return NUMBERFORMAT_ENTRY_NOT_FOUND;
425 void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const rtl::OUString& rName, sal_Bool bRemoveAfterUse )
427 if ( bRemoveAfterUse )
429 // if there is already an entry for this key without the bRemoveAfterUse flag,
430 // clear the flag for this entry, too
432 sal_uInt16 nCount = aNameEntries.size();
433 for (sal_uInt16 i=0; i<nCount; i++)
435 SvXMLNumFmtEntry* pObj = &aNameEntries[i];
436 if ( pObj->nKey == nKey && !pObj->bRemoveAfterUse )
438 bRemoveAfterUse = sal_False; // clear flag for new entry
439 break;
443 else
445 // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key
446 SetUsed( nKey );
449 SvXMLNumFmtEntry* pObj = new SvXMLNumFmtEntry( rName, nKey, bRemoveAfterUse );
450 aNameEntries.push_back( pObj );
453 void SvXMLNumImpData::SetUsed( sal_uInt32 nKey )
455 sal_uInt16 nCount = aNameEntries.size();
456 for (sal_uInt16 i=0; i<nCount; i++)
458 SvXMLNumFmtEntry* pObj = &aNameEntries[i];
459 if ( pObj->nKey == nKey )
461 pObj->bRemoveAfterUse = sal_False; // used -> don't remove
463 // continue searching - there may be several entries for the same key
464 // (with different names), the format must not be deleted if any one of
465 // them is used
470 void SvXMLNumImpData::RemoveVolatileFormats()
472 // remove temporary (volatile) formats from NumberFormatter
473 // called at the end of each import (styles and content), so volatile formats
474 // from styles can't be used in content
476 if ( !pFormatter )
477 return;
479 sal_uInt16 nCount = aNameEntries.size();
480 for (sal_uInt16 i=0; i<nCount; i++)
482 const SvXMLNumFmtEntry* pObj = &aNameEntries[i];
483 if ( pObj->bRemoveAfterUse )
485 const SvNumberformat* pFormat = pFormatter->GetEntry(pObj->nKey);
486 if (pFormat && (pFormat->GetType() & NUMBERFORMAT_DEFINED))
487 pFormatter->DeleteEntry( pObj->nKey );
492 const SvXMLTokenMap& SvXMLNumImpData::GetStylesElemTokenMap()
494 if( !pStylesElemTokenMap )
496 static SvXMLTokenMapEntry aStylesElemMap[] =
498 // style elements
499 { XML_NAMESPACE_NUMBER, XML_NUMBER_STYLE, XML_TOK_STYLES_NUMBER_STYLE },
500 { XML_NAMESPACE_NUMBER, XML_CURRENCY_STYLE, XML_TOK_STYLES_CURRENCY_STYLE },
501 { XML_NAMESPACE_NUMBER, XML_PERCENTAGE_STYLE, XML_TOK_STYLES_PERCENTAGE_STYLE },
502 { XML_NAMESPACE_NUMBER, XML_DATE_STYLE, XML_TOK_STYLES_DATE_STYLE },
503 { XML_NAMESPACE_NUMBER, XML_TIME_STYLE, XML_TOK_STYLES_TIME_STYLE },
504 { XML_NAMESPACE_NUMBER, XML_BOOLEAN_STYLE, XML_TOK_STYLES_BOOLEAN_STYLE },
505 { XML_NAMESPACE_NUMBER, XML_TEXT_STYLE, XML_TOK_STYLES_TEXT_STYLE },
506 XML_TOKEN_MAP_END
509 pStylesElemTokenMap = new SvXMLTokenMap( aStylesElemMap );
511 return *pStylesElemTokenMap;
514 const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemTokenMap()
516 if( !pStyleElemTokenMap )
518 static SvXMLTokenMapEntry aStyleElemMap[] =
520 // elements in a style
521 { XML_NAMESPACE_NUMBER, XML_TEXT, XML_TOK_STYLE_TEXT },
522 { XML_NAMESPACE_NUMBER, XML_NUMBER, XML_TOK_STYLE_NUMBER },
523 { XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER, XML_TOK_STYLE_SCIENTIFIC_NUMBER },
524 { XML_NAMESPACE_NUMBER, XML_FRACTION, XML_TOK_STYLE_FRACTION },
525 { XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL, XML_TOK_STYLE_CURRENCY_SYMBOL },
526 { XML_NAMESPACE_NUMBER, XML_DAY, XML_TOK_STYLE_DAY },
527 { XML_NAMESPACE_NUMBER, XML_MONTH, XML_TOK_STYLE_MONTH },
528 { XML_NAMESPACE_NUMBER, XML_YEAR, XML_TOK_STYLE_YEAR },
529 { XML_NAMESPACE_NUMBER, XML_ERA, XML_TOK_STYLE_ERA },
530 { XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK, XML_TOK_STYLE_DAY_OF_WEEK },
531 { XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR, XML_TOK_STYLE_WEEK_OF_YEAR },
532 { XML_NAMESPACE_NUMBER, XML_QUARTER, XML_TOK_STYLE_QUARTER },
533 { XML_NAMESPACE_NUMBER, XML_HOURS, XML_TOK_STYLE_HOURS },
534 { XML_NAMESPACE_NUMBER, XML_AM_PM, XML_TOK_STYLE_AM_PM },
535 { XML_NAMESPACE_NUMBER, XML_MINUTES, XML_TOK_STYLE_MINUTES },
536 { XML_NAMESPACE_NUMBER, XML_SECONDS, XML_TOK_STYLE_SECONDS },
537 { XML_NAMESPACE_NUMBER, XML_BOOLEAN, XML_TOK_STYLE_BOOLEAN },
538 { XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT, XML_TOK_STYLE_TEXT_CONTENT },
539 { XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES, XML_TOK_STYLE_PROPERTIES },
540 { XML_NAMESPACE_STYLE, XML_MAP, XML_TOK_STYLE_MAP },
541 XML_TOKEN_MAP_END
544 pStyleElemTokenMap = new SvXMLTokenMap( aStyleElemMap );
546 return *pStyleElemTokenMap;
549 const SvXMLTokenMap& SvXMLNumImpData::GetStyleAttrTokenMap()
551 if( !pStyleAttrTokenMap )
553 static SvXMLTokenMapEntry aStyleAttrMap[] =
555 // attributes for a style
556 { XML_NAMESPACE_STYLE, XML_NAME, XML_TOK_STYLE_ATTR_NAME },
557 { XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_STYLE_ATTR_LANGUAGE },
558 { XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_STYLE_ATTR_COUNTRY },
559 { XML_NAMESPACE_NUMBER, XML_TITLE, XML_TOK_STYLE_ATTR_TITLE },
560 { XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER },
561 { XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE, XML_TOK_STYLE_ATTR_FORMAT_SOURCE },
562 { XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW, XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW },
563 { XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TOK_STYLE_ATTR_VOLATILE },
564 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT, XML_TOK_STYLE_ATTR_TRANSL_FORMAT },
565 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE },
566 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, XML_TOK_STYLE_ATTR_TRANSL_COUNTRY },
567 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE, XML_TOK_STYLE_ATTR_TRANSL_STYLE },
568 XML_TOKEN_MAP_END
571 pStyleAttrTokenMap = new SvXMLTokenMap( aStyleAttrMap );
573 return *pStyleAttrTokenMap;
576 const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemAttrTokenMap()
578 if( !pStyleElemAttrTokenMap )
580 static SvXMLTokenMapEntry aStyleElemAttrMap[] =
582 // attributes for an element within a style
583 { XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, XML_TOK_ELEM_ATTR_DECIMAL_PLACES },
584 { XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS },
585 { XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TOK_ELEM_ATTR_GROUPING },
586 { XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, XML_TOK_ELEM_ATTR_DISPLAY_FACTOR },
587 { XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT },
588 { XML_NAMESPACE_NUMBER, XML_DENOMINATOR_VALUE, XML_TOK_ELEM_ATTR_DENOMINATOR_VALUE },
589 { XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS, XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS },
590 { XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS },
591 { XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS },
592 { XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_ELEM_ATTR_LANGUAGE },
593 { XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_ELEM_ATTR_COUNTRY },
594 { XML_NAMESPACE_NUMBER, XML_STYLE, XML_TOK_ELEM_ATTR_STYLE },
595 { XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TOK_ELEM_ATTR_TEXTUAL },
596 { XML_NAMESPACE_NUMBER, XML_CALENDAR, XML_TOK_ELEM_ATTR_CALENDAR },
597 XML_TOKEN_MAP_END
600 pStyleElemAttrTokenMap = new SvXMLTokenMap( aStyleElemAttrMap );
602 return *pStyleElemAttrTokenMap;
605 const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang )
607 if ( !pLocaleData )
608 pLocaleData = new LocaleDataWrapper(
609 (pFormatter ? pFormatter->GetServiceManager() :
610 mxServiceFactory),
611 MsLangId::convertLanguageToLocale( nLang ) );
612 else
613 pLocaleData->setLocale( MsLangId::convertLanguageToLocale( nLang ) );
614 return *pLocaleData;
617 //-------------------------------------------------------------------------
620 // SvXMLNumFmtMapContext
623 SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport,
624 sal_uInt16 nPrfx, const rtl::OUString& rLName,
625 SvXMLNumFormatContext& rParentContext,
626 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
627 SvXMLImportContext( rImport, nPrfx, rLName ),
628 rParent( rParentContext )
630 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
631 for( sal_Int16 i=0; i < nAttrCount; i++ )
633 OUString sAttrName = xAttrList->getNameByIndex( i );
634 OUString sValue = xAttrList->getValueByIndex( i );
635 OUString aLocalName;
636 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
637 if ( nPrefix == XML_NAMESPACE_STYLE )
639 if ( IsXMLToken( aLocalName, XML_CONDITION) )
640 sCondition = sValue;
641 else if ( IsXMLToken( aLocalName, XML_APPLY_STYLE_NAME) )
642 sName = sValue;
647 SvXMLNumFmtMapContext::~SvXMLNumFmtMapContext()
651 SvXMLImportContext* SvXMLNumFmtMapContext::CreateChildContext(
652 sal_uInt16 nPrfx, const rtl::OUString& rLName,
653 const uno::Reference<xml::sax::XAttributeList>& )
655 // no elements supported - use default context
656 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
659 void SvXMLNumFmtMapContext::Characters( const rtl::OUString& )
663 void SvXMLNumFmtMapContext::EndElement()
665 rParent.AddCondition( sCondition, sName );
668 //-------------------------------------------------------------------------
671 // SvXMLNumFmtPropContext
674 SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport,
675 sal_uInt16 nPrfx, const rtl::OUString& rLName,
676 SvXMLNumFormatContext& rParentContext,
677 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
678 SvXMLImportContext( rImport, nPrfx, rLName ),
679 rParent( rParentContext ),
680 bColSet( sal_False )
682 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
683 for( sal_Int16 i=0; i < nAttrCount; i++ )
685 OUString sAttrName = xAttrList->getNameByIndex( i );
686 OUString sValue = xAttrList->getValueByIndex( i );
687 OUString aLocalName;
688 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
689 if ( nPrefix == XML_NAMESPACE_FO && IsXMLToken( aLocalName, XML_COLOR ) )
691 bColSet = ::sax::Converter::convertColor( m_nColor, sValue );
696 SvXMLNumFmtPropContext::~SvXMLNumFmtPropContext()
700 SvXMLImportContext* SvXMLNumFmtPropContext::CreateChildContext(
701 sal_uInt16 nPrfx, const rtl::OUString& rLName,
702 const uno::Reference<xml::sax::XAttributeList>& )
704 // no elements supported - use default context
705 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
708 void SvXMLNumFmtPropContext::Characters( const rtl::OUString& )
712 void SvXMLNumFmtPropContext::EndElement()
714 if (bColSet)
715 rParent.AddColor( m_nColor );
718 //-------------------------------------------------------------------------
721 // SvXMLNumFmtEmbeddedTextContext
724 SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport,
725 sal_uInt16 nPrfx, const rtl::OUString& rLName,
726 SvXMLNumFmtElementContext& rParentContext,
727 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
728 SvXMLImportContext( rImport, nPrfx, rLName ),
729 rParent( rParentContext ),
730 nTextPosition( 0 )
732 sal_Int32 nAttrVal;
734 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
735 for( sal_Int16 i=0; i < nAttrCount; i++ )
737 OUString sAttrName = xAttrList->getNameByIndex( i );
738 OUString sValue = xAttrList->getValueByIndex( i );
739 OUString aLocalName;
740 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
741 if ( nPrefix == XML_NAMESPACE_NUMBER && IsXMLToken( aLocalName, XML_POSITION ) )
743 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
744 nTextPosition = nAttrVal;
749 SvXMLNumFmtEmbeddedTextContext::~SvXMLNumFmtEmbeddedTextContext()
753 SvXMLImportContext* SvXMLNumFmtEmbeddedTextContext::CreateChildContext(
754 sal_uInt16 nPrfx, const rtl::OUString& rLName,
755 const uno::Reference<xml::sax::XAttributeList>& )
757 // no elements supported - use default context
758 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
761 void SvXMLNumFmtEmbeddedTextContext::Characters( const rtl::OUString& rChars )
763 aContent.append( rChars );
766 void SvXMLNumFmtEmbeddedTextContext::EndElement()
768 rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() );
771 //-------------------------------------------------------------------------
773 sal_Bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent )
775 sal_uInt16 nFormatType = rParent.GetType();
777 // Treat space equal to non-breaking space separator.
778 const sal_Unicode cNBSP = 0x00A0;
779 sal_Unicode cTS;
780 if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
781 nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
782 nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
783 (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep().GetChar(0)) ||
784 (cChar == ' ' && cTS == cNBSP)) )
786 // #i22394# Extra occurrences of thousands separator must be quoted, so they
787 // aren't mis-interpreted as display-factor.
788 // This must be limited to the format types that can contain a number element,
789 // because the same character can be a date separator that should not be quoted
790 // in date formats.
792 return sal_False; // force quotes
795 // see ImpSvNumberformatScan::Next_Symbol
796 if ( cChar == ' ' ||
797 cChar == '-' ||
798 cChar == '/' ||
799 cChar == '.' ||
800 cChar == ',' ||
801 cChar == ':' ||
802 cChar == '\'' )
803 return sal_True; // for all format types
805 // percent sign must be used without quotes for percentage styles only
806 if ( nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE && cChar == '%' )
807 return sal_True;
809 // don't put quotes around single parentheses (often used for negative numbers)
810 if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
811 nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
812 nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
813 ( cChar == '(' || cChar == ')' ) )
814 return sal_True;
816 return sal_False;
819 void lcl_EnquoteIfNecessary( rtl::OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent )
821 sal_Bool bQuote = sal_True;
822 sal_Int32 nLength = rContent.getLength();
824 if ( ( nLength == 1 &&
825 lcl_ValidChar( rContent[0], rParent ) ) ||
826 ( nLength == 2 &&
827 lcl_ValidChar( rContent[0], rParent ) &&
828 rContent[1] == ' ' ) )
830 // don't quote single separator characters like space or percent,
831 // or separator characters followed by space (used in date formats)
832 bQuote = sal_False;
834 else if ( rParent.GetType() == XML_TOK_STYLES_PERCENTAGE_STYLE && nLength > 1 )
836 // the percent character in percentage styles must be left out of quoting
837 // (one occurrence is enough even if there are several percent characters in the string)
839 rtl::OUString aString( rContent.getStr() );
840 sal_Int32 nPos = aString.indexOf( (sal_Unicode) '%' );
841 if ( nPos >= 0 )
843 if ( nPos + 1 < nLength )
845 if ( nPos + 2 == nLength && lcl_ValidChar( rContent[nPos + 1], rParent ) )
847 // single character that doesn't need quoting
849 else
851 // quote text behind percent character
852 rContent.insert( nPos + 1, (sal_Unicode) '"' );
853 rContent.append( (sal_Unicode) '"' );
856 if ( nPos > 0 )
858 if ( nPos == 1 && lcl_ValidChar( rContent[0], rParent ) )
860 // single character that doesn't need quoting
862 else
864 // quote text before percent character
865 rContent.insert( nPos, (sal_Unicode) '"' );
866 rContent.insert( 0, (sal_Unicode) '"' );
869 bQuote = sal_False;
871 // else: normal quoting (below)
874 if ( bQuote )
876 // #i55469# quotes in the string itself have to be escaped
877 rtl::OUString aString( rContent.getStr() );
878 bool bEscape = ( aString.indexOf( (sal_Unicode) '"' ) >= 0 );
879 if ( bEscape )
881 // A quote is turned into "\"" - a quote to end quoted text, an escaped quote,
882 // and a quote to resume quoting.
883 rtl::OUString aInsert( "\"\\\"" );
885 sal_Int32 nPos = 0;
886 while ( nPos < rContent.getLength() )
888 if ( rContent[nPos] == (sal_Unicode) '"' )
890 rContent.insert( nPos, aInsert );
891 nPos += aInsert.getLength();
893 ++nPos;
897 // quote string literals
898 rContent.insert( 0, (sal_Unicode) '"' );
899 rContent.append( (sal_Unicode) '"' );
901 // remove redundant double quotes at start or end
902 if ( bEscape )
904 if ( rContent.getLength() > 2 &&
905 rContent[0] == (sal_Unicode) '"' &&
906 rContent[1] == (sal_Unicode) '"' )
908 String aTrimmed( rContent.makeStringAndClear().copy(2) );
909 rContent = rtl::OUStringBuffer( aTrimmed );
912 sal_Int32 nLen = rContent.getLength();
913 if ( nLen > 2 &&
914 rContent[nLen - 1] == (sal_Unicode) '"' &&
915 rContent[nLen - 2] == (sal_Unicode) '"' )
917 String aTrimmed( rContent.makeStringAndClear().copy( 0, nLen - 2 ) );
918 rContent = rtl::OUStringBuffer( aTrimmed );
925 // SvXMLNumFmtElementContext
928 SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport,
929 sal_uInt16 nPrfx, const rtl::OUString& rLName,
930 SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
931 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
932 SvXMLImportContext( rImport, nPrfx, rLName ),
933 rParent( rParentContext ),
934 nType( nNewType ),
935 nElementLang( LANGUAGE_SYSTEM ),
936 bLong( sal_False ),
937 bTextual( sal_False )
939 OUString sLanguage, sCountry;
940 sal_Int32 nAttrVal;
941 bool bAttrBool(false);
942 sal_uInt16 nAttrEnum;
943 double fAttrDouble;
945 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
946 for( sal_Int16 i=0; i < nAttrCount; i++ )
948 OUString sAttrName = xAttrList->getNameByIndex( i );
949 OUString sValue = xAttrList->getValueByIndex( i );
950 OUString aLocalName;
951 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
953 const SvXMLTokenMap& rTokenMap = rParent.GetData()->GetStyleElemAttrTokenMap();
954 sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName );
956 switch (nToken)
958 case XML_TOK_ELEM_ATTR_DECIMAL_PLACES:
959 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
960 aNumInfo.nDecimals = nAttrVal;
961 break;
962 case XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS:
963 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
964 aNumInfo.nInteger = nAttrVal;
965 break;
966 case XML_TOK_ELEM_ATTR_GROUPING:
967 if (::sax::Converter::convertBool( bAttrBool, sValue ))
968 aNumInfo.bGrouping = bAttrBool;
969 break;
970 case XML_TOK_ELEM_ATTR_DISPLAY_FACTOR:
971 if (::sax::Converter::convertDouble( fAttrDouble, sValue ))
972 aNumInfo.fDisplayFactor = fAttrDouble;
973 break;
974 case XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT:
975 if ( !sValue.isEmpty() )
976 aNumInfo.bDecReplace = sal_True; // only a default string is supported
977 else
978 aNumInfo.bVarDecimals = sal_True; // empty replacement string: variable decimals
979 break;
980 case XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS:
981 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
982 aNumInfo.nExpDigits = nAttrVal;
983 break;
984 case XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS:
985 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
986 aNumInfo.nNumerDigits = nAttrVal;
987 break;
988 case XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS:
989 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
990 aNumInfo.nDenomDigits = nAttrVal;
991 break;
992 case XML_TOK_ELEM_ATTR_DENOMINATOR_VALUE:
993 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
994 aNumInfo.nFracDenominator = nAttrVal;
995 break;
996 case XML_TOK_ELEM_ATTR_LANGUAGE:
997 sLanguage = sValue;
998 break;
999 case XML_TOK_ELEM_ATTR_COUNTRY:
1000 sCountry = sValue;
1001 break;
1002 case XML_TOK_ELEM_ATTR_STYLE:
1003 if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aStyleValueMap ) )
1004 bLong = (sal_Bool) nAttrEnum;
1005 break;
1006 case XML_TOK_ELEM_ATTR_TEXTUAL:
1007 if (::sax::Converter::convertBool( bAttrBool, sValue ))
1008 bTextual = bAttrBool;
1009 break;
1010 case XML_TOK_ELEM_ATTR_CALENDAR:
1011 sCalendar = sValue;
1012 break;
1016 if ( !sLanguage.isEmpty() || !sCountry.isEmpty() )
1018 nElementLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry );
1019 if ( nElementLang == LANGUAGE_DONTKNOW )
1020 nElementLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
1024 SvXMLNumFmtElementContext::~SvXMLNumFmtElementContext()
1028 SvXMLImportContext* SvXMLNumFmtElementContext::CreateChildContext(
1029 sal_uInt16 nPrfx, const rtl::OUString& rLName,
1030 const uno::Reference<xml::sax::XAttributeList>& xAttrList )
1032 // only number:number supports number:embedded-text child element
1034 if ( nType == XML_TOK_STYLE_NUMBER &&
1035 nPrfx == XML_NAMESPACE_NUMBER && IsXMLToken( rLName, XML_EMBEDDED_TEXT ) )
1037 return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nPrfx, rLName, *this, xAttrList );
1039 else
1040 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
1043 void SvXMLNumFmtElementContext::Characters( const rtl::OUString& rChars )
1045 aContent.append( rChars );
1048 void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const rtl::OUString& rContent )
1050 if ( !rContent.isEmpty() )
1052 SvXMLEmbeddedElement* pObj = new SvXMLEmbeddedElement( nFormatPos, rContent );
1053 if ( !aNumInfo.aEmbeddedElements.insert( pObj ).second )
1055 // there's already an element at this position - append text to existing element
1057 delete pObj;
1058 for (SvXMLEmbeddedElementArr::iterator it = aNumInfo.aEmbeddedElements.begin();
1059 it != aNumInfo.aEmbeddedElements.end(); ++it)
1061 pObj = &*it;
1062 if ( pObj->nFormatPos == nFormatPos )
1064 pObj->aText += rContent;
1065 break;
1072 void SvXMLNumFmtElementContext::EndElement()
1074 sal_Bool bEffLong = bLong;
1075 switch (nType)
1077 case XML_TOK_STYLE_TEXT:
1078 if ( rParent.HasLongDoW() &&
1079 rParent.GetLocaleData().getLongDateDayOfWeekSep() ==
1080 String( aContent.getStr() ) )
1082 // skip separator constant after long day of week
1083 // (NF_KEY_NNNN contains the separator)
1085 if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) )
1087 aContent = OUStringBuffer();
1090 rParent.SetHasLongDoW( sal_False ); // only once
1092 if ( aContent.getLength() )
1094 lcl_EnquoteIfNecessary( aContent, rParent );
1095 rParent.AddToCode( aContent.makeStringAndClear() );
1097 break;
1099 case XML_TOK_STYLE_NUMBER:
1100 rParent.AddNumber( aNumInfo );
1101 break;
1103 case XML_TOK_STYLE_CURRENCY_SYMBOL:
1104 rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang );
1105 break;
1107 case XML_TOK_STYLE_TEXT_CONTENT:
1108 rParent.AddToCode( OUString::valueOf((sal_Unicode)'@') );
1109 break;
1110 case XML_TOK_STYLE_BOOLEAN:
1111 // ignored - only default boolean format is supported
1112 break;
1114 case XML_TOK_STYLE_DAY:
1115 rParent.UpdateCalendar( sCalendar );
1116 //! I18N doesn't provide SYSTEM or extended date information yet
1118 rParent.AddNfKeyword(
1119 sal::static_int_cast< sal_uInt16 >(
1120 bEffLong ? NF_KEY_DD : NF_KEY_D ) );
1121 break;
1122 case XML_TOK_STYLE_MONTH:
1123 rParent.UpdateCalendar( sCalendar );
1124 //! I18N doesn't provide SYSTEM or extended date information yet
1126 rParent.AddNfKeyword(
1127 sal::static_int_cast< sal_uInt16 >(
1128 bTextual
1129 ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM )
1130 : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) );
1131 break;
1132 case XML_TOK_STYLE_YEAR:
1133 rParent.UpdateCalendar( sCalendar );
1134 //! I18N doesn't provide SYSTEM or extended date information yet
1135 // Y after G (era) is replaced by E
1136 if ( rParent.HasEra() )
1137 rParent.AddNfKeyword(
1138 sal::static_int_cast< sal_uInt16 >(
1139 bEffLong ? NF_KEY_EEC : NF_KEY_EC ) );
1140 else
1141 rParent.AddNfKeyword(
1142 sal::static_int_cast< sal_uInt16 >(
1143 bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) );
1144 break;
1145 case XML_TOK_STYLE_ERA:
1146 rParent.UpdateCalendar( sCalendar );
1147 //! I18N doesn't provide SYSTEM or extended date information yet
1148 rParent.AddNfKeyword(
1149 sal::static_int_cast< sal_uInt16 >(
1150 bEffLong ? NF_KEY_GGG : NF_KEY_G ) );
1151 // HasEra flag is set
1152 break;
1153 case XML_TOK_STYLE_DAY_OF_WEEK:
1154 rParent.UpdateCalendar( sCalendar );
1155 //! I18N doesn't provide SYSTEM or extended date information yet
1156 rParent.AddNfKeyword(
1157 sal::static_int_cast< sal_uInt16 >(
1158 bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) );
1159 break;
1160 case XML_TOK_STYLE_WEEK_OF_YEAR:
1161 rParent.UpdateCalendar( sCalendar );
1162 rParent.AddNfKeyword( NF_KEY_WW );
1163 break;
1164 case XML_TOK_STYLE_QUARTER:
1165 rParent.UpdateCalendar( sCalendar );
1166 rParent.AddNfKeyword(
1167 sal::static_int_cast< sal_uInt16 >(
1168 bEffLong ? NF_KEY_QQ : NF_KEY_Q ) );
1169 break;
1170 case XML_TOK_STYLE_HOURS:
1171 rParent.AddNfKeyword(
1172 sal::static_int_cast< sal_uInt16 >(
1173 bEffLong ? NF_KEY_HH : NF_KEY_H ) );
1174 break;
1175 case XML_TOK_STYLE_AM_PM:
1176 //! short/long?
1177 rParent.AddNfKeyword( NF_KEY_AMPM );
1178 break;
1179 case XML_TOK_STYLE_MINUTES:
1180 rParent.AddNfKeyword(
1181 sal::static_int_cast< sal_uInt16 >(
1182 bEffLong ? NF_KEY_MMI : NF_KEY_MI ) );
1183 break;
1184 case XML_TOK_STYLE_SECONDS:
1185 rParent.AddNfKeyword(
1186 sal::static_int_cast< sal_uInt16 >(
1187 bEffLong ? NF_KEY_SS : NF_KEY_S ) );
1188 if ( aNumInfo.nDecimals > 0 )
1190 // manually add the decimal places
1191 const String& rSep = rParent.GetLocaleData().getNumDecimalSep();
1192 for ( xub_StrLen j=0; j<rSep.Len(); j++ )
1194 rParent.AddToCode( OUString::valueOf( rSep.GetChar(j) ) );
1196 for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++)
1197 rParent.AddToCode( OUString::valueOf((sal_Unicode)'0') );
1199 break;
1201 case XML_TOK_STYLE_FRACTION:
1203 if ( aNumInfo.nInteger >= 0 )
1205 // add integer part only if min-integer-digits attribute is there
1206 aNumInfo.nDecimals = 0;
1207 rParent.AddNumber( aNumInfo ); // number without decimals
1208 rParent.AddToCode( OUString::valueOf((sal_Unicode)' ') );
1211 //! build string and add at once
1213 sal_Int32 i;
1214 for (i=0; i<aNumInfo.nNumerDigits; i++)
1215 rParent.AddToCode( OUString::valueOf((sal_Unicode)'?') );
1216 rParent.AddToCode( OUString::valueOf((sal_Unicode)'/') );
1217 if ( aNumInfo.nFracDenominator > 0 )
1219 rParent.AddToCode( OUString::valueOf( aNumInfo.nFracDenominator ) );
1221 else
1223 for (i=0; i<aNumInfo.nDenomDigits; i++)
1224 rParent.AddToCode( OUString::valueOf((sal_Unicode)'?') );
1227 break;
1229 case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
1231 rParent.AddNumber( aNumInfo ); // simple number
1233 rParent.AddToCode( OUString("E+") );
1234 for (sal_Int32 i=0; i<aNumInfo.nExpDigits; i++)
1235 rParent.AddToCode( OUString::valueOf((sal_Unicode)'0') );
1237 break;
1239 default:
1240 OSL_FAIL("invalid element ID");
1244 //-------------------------------------------------------------------------
1246 sal_uInt16 SvXMLNumFmtDefaults::GetDefaultDateFormat( SvXMLDateElementAttributes eDOW,
1247 SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth,
1248 SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours,
1249 SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs,
1250 sal_Bool bSystem )
1252 const sal_uInt16 nCount = sizeof(aDefaultDateFormats) / sizeof(SvXMLDefaultDateFormat);
1253 for (sal_uInt16 nPos=0; nPos<nCount; nPos++)
1255 const SvXMLDefaultDateFormat& rEntry = aDefaultDateFormats[nPos];
1256 if ( bSystem == rEntry.bSystem &&
1257 ( eDOW == rEntry.eDOW || ( rEntry.eDOW == XML_DEA_ANY && eDOW != XML_DEA_NONE ) ) &&
1258 ( eDay == rEntry.eDay || ( rEntry.eDay == XML_DEA_ANY && eDay != XML_DEA_NONE ) ) &&
1259 ( eMonth == rEntry.eMonth || ( rEntry.eMonth == XML_DEA_ANY && eMonth != XML_DEA_NONE ) ) &&
1260 ( eYear == rEntry.eYear || ( rEntry.eYear == XML_DEA_ANY && eYear != XML_DEA_NONE ) ) &&
1261 ( eHours == rEntry.eHours || ( rEntry.eHours == XML_DEA_ANY && eHours != XML_DEA_NONE ) ) &&
1262 ( eMins == rEntry.eMins || ( rEntry.eMins == XML_DEA_ANY && eMins != XML_DEA_NONE ) ) &&
1263 ( eSecs == rEntry.eSecs || ( rEntry.eSecs == XML_DEA_ANY && eSecs != XML_DEA_NONE ) ) )
1265 return sal::static_int_cast< sal_uInt16 >(rEntry.eFormat);
1269 return NF_INDEX_TABLE_ENTRIES; // invalid
1272 //-------------------------------------------------------------------------
1275 // SvXMLNumFormatContext
1278 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport,
1279 sal_uInt16 nPrfx, const rtl::OUString& rLName,
1280 SvXMLNumImpData* pNewData, sal_uInt16 nNewType,
1281 const uno::Reference<xml::sax::XAttributeList>& xAttrList,
1282 SvXMLStylesContext& rStyles ) :
1283 SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList ),
1284 pData( pNewData ),
1285 pStyles( &rStyles ),
1286 aMyConditions(),
1287 nType( nNewType ),
1288 nKey(-1),
1289 nFormatLang( LANGUAGE_SYSTEM ),
1290 bAutoOrder( sal_False ),
1291 bFromSystem( sal_False ),
1292 bTruncate( sal_True ),
1293 bAutoDec( sal_False ),
1294 bAutoInt( sal_False ),
1295 bHasExtraText( sal_False ),
1296 bHasLongDoW( sal_False ),
1297 bHasEra( sal_False ),
1298 bHasDateTime( sal_False ),
1299 bRemoveAfterUse( sal_False ),
1300 eDateDOW( XML_DEA_NONE ),
1301 eDateDay( XML_DEA_NONE ),
1302 eDateMonth( XML_DEA_NONE ),
1303 eDateYear( XML_DEA_NONE ),
1304 eDateHours( XML_DEA_NONE ),
1305 eDateMins( XML_DEA_NONE ),
1306 eDateSecs( XML_DEA_NONE ),
1307 bDateNoDefault( sal_False )
1309 OUString sLanguage, sCountry;
1310 ::com::sun::star::i18n::NativeNumberXmlAttributes aNatNumAttr;
1311 bool bAttrBool(false);
1312 sal_uInt16 nAttrEnum;
1314 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1315 for( sal_Int16 i=0; i < nAttrCount; i++ )
1317 OUString sAttrName = xAttrList->getNameByIndex( i );
1318 OUString sValue = xAttrList->getValueByIndex( i );
1319 OUString aLocalName;
1320 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
1322 const SvXMLTokenMap& rTokenMap = pData->GetStyleAttrTokenMap();
1323 sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName );
1324 switch (nToken)
1326 case XML_TOK_STYLE_ATTR_NAME:
1327 break;
1328 case XML_TOK_STYLE_ATTR_LANGUAGE:
1329 sLanguage = sValue;
1330 break;
1331 case XML_TOK_STYLE_ATTR_COUNTRY:
1332 sCountry = sValue;
1333 break;
1334 case XML_TOK_STYLE_ATTR_TITLE:
1335 sFormatTitle = sValue;
1336 break;
1337 case XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER:
1338 if (::sax::Converter::convertBool( bAttrBool, sValue ))
1339 bAutoOrder = bAttrBool;
1340 break;
1341 case XML_TOK_STYLE_ATTR_FORMAT_SOURCE:
1342 if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aFormatSourceMap ) )
1343 bFromSystem = (sal_Bool) nAttrEnum;
1344 break;
1345 case XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW:
1346 if (::sax::Converter::convertBool( bAttrBool, sValue ))
1347 bTruncate = bAttrBool;
1348 break;
1349 case XML_TOK_STYLE_ATTR_VOLATILE:
1350 // volatile formats can be removed after importing
1351 // if not used in other styles
1352 if (::sax::Converter::convertBool( bAttrBool, sValue ))
1353 bRemoveAfterUse = bAttrBool;
1354 break;
1355 case XML_TOK_STYLE_ATTR_TRANSL_FORMAT:
1356 aNatNumAttr.Format = sValue;
1357 break;
1358 case XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE:
1359 aNatNumAttr.Locale.Language = sValue;
1360 break;
1361 case XML_TOK_STYLE_ATTR_TRANSL_COUNTRY:
1362 aNatNumAttr.Locale.Country = sValue;
1363 break;
1364 case XML_TOK_STYLE_ATTR_TRANSL_STYLE:
1365 aNatNumAttr.Style = sValue;
1366 break;
1370 if ( !sLanguage.isEmpty() || !sCountry.isEmpty() )
1372 nFormatLang = MsLangId::convertIsoNamesToLanguage( sLanguage, sCountry );
1373 if ( nFormatLang == LANGUAGE_DONTKNOW )
1374 nFormatLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
1377 if ( !aNatNumAttr.Format.isEmpty() )
1379 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1380 if ( pFormatter )
1382 sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr );
1383 aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "[NatNum" ) );
1384 aFormatCode.append( nNatNum, 10 );
1386 LanguageType eLang = MsLangId::convertLocaleToLanguage( aNatNumAttr.Locale );
1387 if ( eLang == LANGUAGE_DONTKNOW )
1388 eLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
1389 if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM )
1391 aFormatCode.appendAscii( RTL_CONSTASCII_STRINGPARAM( "][$-" ) );
1392 // language code in upper hex:
1393 aFormatCode.append(rtl::OUString::valueOf(sal_Int32(eLang), 16).toAsciiUpperCase());
1395 aFormatCode.append( sal_Unicode(']') );
1400 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport,
1401 sal_uInt16 nPrfx, const rtl::OUString& rLName,
1402 const uno::Reference<xml::sax::XAttributeList>& xAttrList,
1403 const sal_Int32 nTempKey,
1404 SvXMLStylesContext& rStyles ) :
1405 SvXMLStyleContext( rImport, nPrfx, rLName, xAttrList, XML_STYLE_FAMILY_DATA_STYLE ),
1406 pData( NULL ),
1407 pStyles( &rStyles ),
1408 aMyConditions(),
1409 nType( 0 ),
1410 nKey(nTempKey),
1411 nFormatLang( LANGUAGE_SYSTEM ),
1412 bAutoOrder( sal_False ),
1413 bFromSystem( sal_False ),
1414 bTruncate( sal_True ),
1415 bAutoDec( sal_False ),
1416 bAutoInt( sal_False ),
1417 bHasExtraText( sal_False ),
1418 bHasLongDoW( sal_False ),
1419 bHasEra( sal_False ),
1420 bHasDateTime( sal_False ),
1421 bRemoveAfterUse( sal_False ),
1422 eDateDOW( XML_DEA_NONE ),
1423 eDateDay( XML_DEA_NONE ),
1424 eDateMonth( XML_DEA_NONE ),
1425 eDateYear( XML_DEA_NONE ),
1426 eDateHours( XML_DEA_NONE ),
1427 eDateMins( XML_DEA_NONE ),
1428 eDateSecs( XML_DEA_NONE ),
1429 bDateNoDefault( sal_False )
1431 SetAttribute(XML_NAMESPACE_STYLE, GetXMLToken(XML_NAME), rLName);
1434 SvXMLNumFormatContext::~SvXMLNumFormatContext()
1438 SvXMLImportContext* SvXMLNumFormatContext::CreateChildContext(
1439 sal_uInt16 nPrfx, const rtl::OUString& rLName,
1440 const uno::Reference<xml::sax::XAttributeList>& xAttrList )
1442 SvXMLImportContext* pContext = NULL;
1444 const SvXMLTokenMap& rTokenMap = pData->GetStyleElemTokenMap();
1445 sal_uInt16 nToken = rTokenMap.Get( nPrfx, rLName );
1446 switch (nToken)
1448 case XML_TOK_STYLE_TEXT:
1449 case XML_TOK_STYLE_NUMBER:
1450 case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
1451 case XML_TOK_STYLE_FRACTION:
1452 case XML_TOK_STYLE_CURRENCY_SYMBOL:
1453 case XML_TOK_STYLE_DAY:
1454 case XML_TOK_STYLE_MONTH:
1455 case XML_TOK_STYLE_YEAR:
1456 case XML_TOK_STYLE_ERA:
1457 case XML_TOK_STYLE_DAY_OF_WEEK:
1458 case XML_TOK_STYLE_WEEK_OF_YEAR:
1459 case XML_TOK_STYLE_QUARTER:
1460 case XML_TOK_STYLE_HOURS:
1461 case XML_TOK_STYLE_AM_PM:
1462 case XML_TOK_STYLE_MINUTES:
1463 case XML_TOK_STYLE_SECONDS:
1464 case XML_TOK_STYLE_BOOLEAN:
1465 case XML_TOK_STYLE_TEXT_CONTENT:
1466 pContext = new SvXMLNumFmtElementContext( GetImport(), nPrfx, rLName,
1467 *this, nToken, xAttrList );
1468 break;
1470 case XML_TOK_STYLE_PROPERTIES:
1471 pContext = new SvXMLNumFmtPropContext( GetImport(), nPrfx, rLName,
1472 *this, xAttrList );
1473 break;
1474 case XML_TOK_STYLE_MAP:
1476 // SvXMLNumFmtMapContext::EndElement adds to aMyConditions,
1477 // so there's no need for an extra flag
1478 pContext = new SvXMLNumFmtMapContext( GetImport(), nPrfx, rLName,
1479 *this, xAttrList );
1481 break;
1484 if( !pContext )
1485 pContext = new SvXMLImportContext( GetImport(), nPrfx, rLName );
1486 return pContext;
1489 sal_Int32 SvXMLNumFormatContext::GetKey()
1491 if (nKey > -1)
1493 if (bRemoveAfterUse)
1495 // format is used -> don't remove
1496 bRemoveAfterUse = sal_False;
1497 if (pData)
1498 pData->SetUsed(nKey);
1500 // Add to import's list of keys now - CreateAndInsert didn't add
1501 // the style if bRemoveAfterUse was set.
1502 GetImport().AddNumberStyle( nKey, GetName() );
1504 return nKey;
1506 else
1508 // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set
1509 bRemoveAfterUse = sal_False;
1510 CreateAndInsert(sal_True);
1511 return nKey;
1515 sal_Int32 SvXMLNumFormatContext::PrivateGetKey()
1517 // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag
1519 if (nKey > -1)
1520 return nKey;
1521 else
1523 CreateAndInsert(sal_True);
1524 return nKey;
1528 sal_Int32 SvXMLNumFormatContext::CreateAndInsert( com::sun::star::uno::Reference< com::sun::star::util::XNumberFormatsSupplier >& xFormatsSupplier )
1530 if (nKey <= -1)
1532 SvNumberFormatter* pFormatter = NULL;
1533 SvNumberFormatsSupplierObj* pObj =
1534 SvNumberFormatsSupplierObj::getImplementation( xFormatsSupplier );
1535 if (pObj)
1536 pFormatter = pObj->GetNumberFormatter();
1538 if ( pFormatter )
1539 return CreateAndInsert( pFormatter );
1540 else
1541 return -1;
1543 else
1544 return nKey;
1547 void SvXMLNumFormatContext::CreateAndInsert(sal_Bool /*bOverwrite*/)
1549 if (!(nKey > -1))
1550 CreateAndInsert(pData->GetNumberFormatter());
1553 sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter)
1555 if (!pFormatter)
1557 OSL_FAIL("no number formatter");
1558 return -1;
1561 sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1563 for (sal_uInt32 i = 0; i < aMyConditions.size(); i++)
1565 SvXMLNumFormatContext* pStyle = (SvXMLNumFormatContext *)pStyles->FindStyleChildContext(
1566 XML_STYLE_FAMILY_DATA_STYLE, aMyConditions[i].sMapName, sal_False);
1567 if (pStyle)
1569 if ((pStyle->PrivateGetKey() > -1)) // don't reset pStyle's bRemoveAfterUse flag
1570 AddCondition(i);
1574 if ( !aFormatCode.getLength() )
1576 // insert empty format as empty string (with quotes)
1577 // #93901# this check has to be done before inserting the conditions
1578 aFormatCode.appendAscii("\"\""); // ""
1581 aFormatCode.insert( 0, aConditions.makeStringAndClear() );
1582 OUString sFormat = aFormatCode.makeStringAndClear();
1584 // test special cases
1586 if ( bAutoDec ) // automatic decimal places
1588 // #99391# adjust only if the format contains no text elements, no conditions
1589 // and no color definition (detected by the '[' at the start)
1591 if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
1592 aMyConditions.empty() && sFormat.toChar() != (sal_Unicode)'[' )
1593 nIndex = pFormatter->GetStandardIndex( nFormatLang );
1595 if ( bAutoInt ) // automatic integer digits
1597 //! only if two decimal places was set?
1599 if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
1600 aMyConditions.empty() && sFormat.toChar() != (sal_Unicode)'[' )
1601 nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang );
1604 // boolean is always the builtin boolean format
1605 // (no other boolean formats are implemented)
1606 if ( nType == XML_TOK_STYLES_BOOLEAN_STYLE )
1607 nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang );
1609 // check for default date formats
1610 if ( nType == XML_TOK_STYLES_DATE_STYLE && bAutoOrder && !bDateNoDefault )
1612 NfIndexTableOffset eFormat = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
1613 eDateDOW, eDateDay, eDateMonth, eDateYear,
1614 eDateHours, eDateMins, eDateSecs, bFromSystem );
1615 if ( eFormat < NF_INDEX_TABLE_ENTRIES )
1617 // #109651# if a date format has the automatic-order attribute and
1618 // contains exactly the elements of one of the default date formats,
1619 // use that default format, with the element order and separators
1620 // from the current locale settings
1622 nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang );
1626 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && !sFormat.isEmpty() )
1628 // insert by format string
1630 String aFormatStr( sFormat );
1631 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1632 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
1634 xub_StrLen nErrPos = 0;
1635 short l_nType = 0;
1636 sal_Bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang );
1637 if ( !bOk && nErrPos == 0 && aFormatStr != String(sFormat) )
1639 // if the string was modified by PutEntry, look for an existing format
1640 // with the modified string
1641 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1642 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1643 bOk = sal_True;
1645 if (!bOk)
1646 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1650 //! I18N doesn't provide SYSTEM or extended date information yet
1651 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder )
1653 // use fixed-order formats instead of SYS... if bAutoOrder is false
1654 // (only if the format strings are equal for the locale)
1656 NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex );
1657 if ( eOffset == NF_DATE_SYS_DMMMYYYY )
1659 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang );
1660 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1661 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1662 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1663 nIndex = nNewIndex;
1665 else if ( eOffset == NF_DATE_SYS_DMMMMYYYY )
1667 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang );
1668 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1669 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1670 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1671 nIndex = nNewIndex;
1675 if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && !sFormatTitle.isEmpty())
1677 SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex ));
1678 if (pFormat)
1680 String sTitle (sFormatTitle);
1681 pFormat->SetComment(sTitle);
1685 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
1687 OSL_FAIL("invalid number format");
1688 nIndex = pFormatter->GetStandardIndex( nFormatLang );
1691 pData->AddKey( nIndex, GetName(), bRemoveAfterUse );
1692 nKey = nIndex;
1694 // Add to import's list of keys (shared between styles and content import)
1695 // only if not volatile - formats are removed from NumberFormatter at the
1696 // end of each import (in SvXMLNumFmtHelper dtor).
1697 // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there.
1699 if (!bRemoveAfterUse)
1700 GetImport().AddNumberStyle( nKey, GetName() );
1702 return nKey;
1705 void SvXMLNumFormatContext::Finish( sal_Bool bOverwrite )
1707 SvXMLStyleContext::Finish( bOverwrite );
1710 const LocaleDataWrapper& SvXMLNumFormatContext::GetLocaleData() const
1712 return pData->GetLocaleData( nFormatLang );
1715 void SvXMLNumFormatContext::AddToCode( const rtl::OUString& rString )
1717 aFormatCode.append( rString );
1718 bHasExtraText = sal_True;
1721 void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo )
1723 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1724 if (!pFormatter)
1725 return;
1727 // store special conditions
1728 bAutoDec = ( rInfo.nDecimals < 0 );
1729 bAutoInt = ( rInfo.nInteger < 0 );
1731 sal_uInt16 nPrec = 0;
1732 sal_uInt16 nLeading = 0;
1733 if ( rInfo.nDecimals >= 0 ) // < 0 : Default
1734 nPrec = (sal_uInt16) rInfo.nDecimals;
1735 if ( rInfo.nInteger >= 0 ) // < 0 : Default
1736 nLeading = (sal_uInt16) rInfo.nInteger;
1738 if ( bAutoDec )
1740 if ( nType == XML_TOK_STYLES_CURRENCY_STYLE )
1742 // for currency formats, "automatic decimals" is used for the automatic
1743 // currency format with (fixed) decimals from the locale settings
1745 const LocaleDataWrapper& rLoc = pData->GetLocaleData( nFormatLang );
1746 nPrec = rLoc.getCurrDigits();
1748 else
1750 // for other types, "automatic decimals" means dynamic determination of
1751 // decimals, as achieved with the "general" keyword
1753 aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) );
1754 return;
1757 if ( bAutoInt )
1759 //!...
1762 sal_uInt16 nGenPrec = nPrec;
1763 if ( rInfo.bDecReplace || rInfo.bVarDecimals )
1764 nGenPrec = 0; // generate format without decimals...
1766 sal_Bool bGrouping = rInfo.bGrouping;
1767 sal_uInt16 nEmbeddedCount = rInfo.aEmbeddedElements.size();
1768 if ( nEmbeddedCount )
1769 bGrouping = sal_False; // grouping and embedded characters can't be used together
1771 String aNumStr;
1772 sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang );
1773 pFormatter->GenerateFormat( aNumStr, nStdIndex, nFormatLang,
1774 bGrouping, sal_False, nGenPrec, nLeading );
1776 if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 )
1778 // #i43959# For scientific numbers, "#" in the integer part forces a digit,
1779 // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0").
1781 aNumStr.EraseLeadingChars( (sal_Unicode)'#' );
1784 if ( nEmbeddedCount )
1786 // insert embedded strings into number string
1787 // only the integer part is supported
1788 // nZeroPos is the string position where format position 0 is inserted
1790 xub_StrLen nZeroPos = aNumStr.Search( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1791 if ( nZeroPos == STRING_NOTFOUND )
1792 nZeroPos = aNumStr.Len();
1794 // aEmbeddedElements is sorted - last entry has the largest position (leftmost)
1795 const SvXMLEmbeddedElement* pLastObj = &*rInfo.aEmbeddedElements.rbegin();
1796 sal_Int32 nLastFormatPos = pLastObj->nFormatPos;
1797 if ( nLastFormatPos >= nZeroPos )
1799 // add '#' characters so all embedded texts are really embedded in digits
1800 // (there always has to be a digit before the leftmost embedded text)
1802 xub_StrLen nAddCount = (xub_StrLen)nLastFormatPos + 1 - nZeroPos;
1803 String aDigitStr;
1804 aDigitStr.Fill( nAddCount, (sal_Unicode)'#' );
1805 aNumStr.Insert( aDigitStr, 0 );
1806 nZeroPos = nZeroPos + nAddCount;
1809 // aEmbeddedElements is sorted with ascending positions - loop is from right to left
1810 for (SvXMLEmbeddedElementArr::const_iterator it = rInfo.aEmbeddedElements.begin();
1811 it != rInfo.aEmbeddedElements.end(); ++it)
1813 const SvXMLEmbeddedElement* pObj = &*it;
1814 sal_Int32 nFormatPos = pObj->nFormatPos;
1815 sal_Int32 nInsertPos = nZeroPos - nFormatPos;
1816 if ( nFormatPos >= 0 && nInsertPos >= 0 )
1818 rtl::OUStringBuffer aContent( pObj->aText );
1819 // #107805# always quote embedded strings - even space would otherwise
1820 // be recognized as thousands separator in French.
1821 aContent.insert( 0, (sal_Unicode) '"' );
1822 aContent.append( (sal_Unicode) '"' );
1824 aNumStr.Insert( String( aContent.makeStringAndClear() ), (xub_StrLen)nInsertPos );
1829 aFormatCode.append( aNumStr );
1831 if ( ( rInfo.bDecReplace || rInfo.bVarDecimals ) && nPrec ) // add decimal replacement (dashes)
1833 // add dashes for explicit decimal replacement, # for variable decimals
1834 sal_Unicode cAdd = rInfo.bDecReplace ? '-' : '#';
1836 aFormatCode.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1837 for ( sal_uInt16 i=0; i<nPrec; i++)
1838 aFormatCode.append( cAdd );
1841 // add extra thousands separators for display factor
1843 if ( rInfo.fDisplayFactor != 1.0 && rInfo.fDisplayFactor > 0.0 )
1845 // test for 1.0 is just for optimization - nSepCount would be 0
1847 // one separator for each factor of 1000
1848 sal_Int32 nSepCount = (sal_Int32) ::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 );
1849 if ( nSepCount > 0 )
1851 OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep();
1852 for ( sal_Int32 i=0; i<nSepCount; i++ )
1853 aFormatCode.append( aSep );
1858 void SvXMLNumFormatContext::AddCurrency( const rtl::OUString& rContent, LanguageType nLang )
1860 sal_Bool bAutomatic = sal_False;
1861 OUString aSymbol = rContent;
1862 if ( aSymbol.isEmpty())
1864 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1865 if ( pFormatter )
1867 pFormatter->ChangeIntl( nFormatLang );
1868 String sCurString, sDummy;
1869 pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
1870 aSymbol = sCurString;
1872 bAutomatic = sal_True;
1875 else if ( nLang == LANGUAGE_SYSTEM && aSymbol.compareToAscii("CCC") == 0 )
1877 // "CCC" is used for automatic long symbol
1878 bAutomatic = sal_True;
1881 if ( bAutomatic )
1883 // remove unnecessary quotes before automatic symbol (formats like "-(0DM)")
1884 // otherwise the currency symbol isn't recognized (#94048#)
1886 sal_Int32 nLength = aFormatCode.getLength();
1887 if ( nLength > 1 && aFormatCode[nLength - 1] == '"' )
1889 // find start of quoted string
1890 // When SvXMLNumFmtElementContext::EndElement creates escaped quotes,
1891 // they must be handled here, too.
1893 sal_Int32 nFirst = nLength - 2;
1894 while ( nFirst >= 0 && aFormatCode[nFirst] != '"' )
1895 --nFirst;
1896 if ( nFirst >= 0 )
1898 // remove both quotes from aFormatCode
1899 rtl::OUString aOld = aFormatCode.makeStringAndClear();
1900 if ( nFirst > 0 )
1901 aFormatCode.append( aOld.copy( 0, nFirst ) );
1902 if ( nLength > nFirst + 2 )
1903 aFormatCode.append( aOld.copy( nFirst + 1, nLength - nFirst - 2 ) );
1908 if (!bAutomatic)
1909 aFormatCode.appendAscii( "[$" ); // intro for "new" currency symbols
1911 aFormatCode.append( aSymbol );
1913 if (!bAutomatic)
1915 if ( nLang != LANGUAGE_SYSTEM )
1917 // '-' sign and language code in hex:
1918 aFormatCode.append( (sal_Unicode) '-' );
1919 aFormatCode.append(rtl::OUString::valueOf(sal_Int32(nLang), 16).toAsciiUpperCase());
1922 aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbol
1926 void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex )
1928 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1929 if (!pFormatter)
1930 return;
1932 if ( nIndex == NF_KEY_G || nIndex == NF_KEY_GG || nIndex == NF_KEY_GGG )
1933 bHasEra = sal_True;
1935 if ( nIndex == NF_KEY_NNNN )
1937 nIndex = NF_KEY_NNN;
1938 bHasLongDoW = sal_True; // to remove string constant with separator
1941 String sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex );
1943 if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH ||
1944 nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI ||
1945 nIndex == NF_KEY_S || nIndex == NF_KEY_SS )
1947 if ( !bTruncate && !bHasDateTime )
1949 // with truncate-on-overflow = false, add "[]" to first time part
1951 sKeyword.Insert( (sal_Unicode) '[', 0 );
1952 sKeyword.Append( (sal_Unicode) ']' );
1954 bHasDateTime = sal_True;
1957 aFormatCode.append( sKeyword );
1959 // collect the date elements that the format contains, to recognize default date formats
1960 switch ( nIndex )
1962 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
1963 case NF_KEY_NNN:
1964 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
1965 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
1966 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
1967 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
1968 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
1969 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
1970 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
1971 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
1972 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
1973 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
1974 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
1975 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
1976 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
1977 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
1978 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
1979 case NF_KEY_AP:
1980 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1981 default:
1982 bDateNoDefault = sal_True; // any other element -> no default format
1986 sal_Bool lcl_IsAtEnd( rtl::OUStringBuffer& rBuffer, const String& rToken )
1988 sal_Int32 nBufLen = rBuffer.getLength();
1989 xub_StrLen nTokLen = rToken.Len();
1991 if ( nTokLen > nBufLen )
1992 return sal_False;
1994 sal_Int32 nStartPos = nBufLen - nTokLen;
1995 for ( xub_StrLen nTokPos = 0; nTokPos < nTokLen; nTokPos++ )
1996 if ( rToken.GetChar( nTokPos ) != rBuffer[nStartPos + nTokPos] )
1997 return sal_False;
1999 return sal_True;
2002 sal_Bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew )
2004 // replaces one keyword with another if it is found at the end of the code
2006 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2007 if (!pFormatter)
2008 return sal_False;
2010 String sOldStr = pFormatter->GetKeyword( nFormatLang, nOld );
2011 if ( lcl_IsAtEnd( aFormatCode, sOldStr ) )
2013 // remove old keyword
2014 aFormatCode.setLength( aFormatCode.getLength() - sOldStr.Len() );
2016 // add new keyword
2017 String sNewStr = pFormatter->GetKeyword( nFormatLang, nNew );
2018 aFormatCode.append( sNewStr );
2020 return sal_True; // changed
2022 return sal_False; // not found
2025 void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex )
2027 rtl::OUString rApplyName = aMyConditions[nIndex].sMapName;
2028 rtl::OUString rCondition = aMyConditions[nIndex].sCondition;
2029 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2030 sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName );
2031 OUString sValue("value()"); //! define constant
2032 sal_Int32 nValLen = sValue.getLength();
2034 if ( pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND &&
2035 rCondition.copy( 0, nValLen ) == sValue )
2037 //! test for valid conditions
2038 //! test for default conditions
2040 OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen );
2041 sal_Bool bDefaultCond = sal_False;
2043 //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count
2044 //! allow blanks in conditions
2045 sal_Bool bFirstCond = ( aConditions.getLength() == 0 );
2046 if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 )
2047 bDefaultCond = sal_True;
2049 if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 )
2051 // The third condition in a number format with a text part can only be
2052 // "all other numbers", the condition string must be empty.
2053 bDefaultCond = sal_True;
2056 if (!bDefaultCond)
2058 sal_Int32 nPos = sRealCond.indexOf( '.' );
2059 if ( nPos >= 0 )
2060 { // #i8026# #103991# localize decimal separator
2061 const String& rDecSep = GetLocaleData().getNumDecimalSep();
2062 if ( rDecSep.Len() > 1 || rDecSep.GetChar(0) != '.' )
2063 sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
2065 aConditions.append( (sal_Unicode) '[' );
2066 aConditions.append( sRealCond );
2067 aConditions.append( (sal_Unicode) ']' );
2070 const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey);
2071 if ( pFormat )
2072 aConditions.append( OUString( pFormat->GetFormatstring() ) );
2074 aConditions.append( (sal_Unicode) ';' );
2078 void SvXMLNumFormatContext::AddCondition( const rtl::OUString& rCondition, const rtl::OUString& rApplyName )
2080 MyCondition aCondition;
2081 aCondition.sCondition = rCondition;
2082 aCondition.sMapName = rApplyName;
2083 aMyConditions.push_back(aCondition);
2086 void SvXMLNumFormatContext::AddColor( sal_uInt32 const nColor )
2088 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2089 if (!pFormatter)
2090 return;
2092 OUStringBuffer aColName;
2093 for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ )
2094 if (nColor == aNumFmtStdColors[i])
2096 aColName = OUString( pFormatter->GetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ) );
2097 break;
2100 if ( aColName.getLength() )
2102 aColName.insert( 0, (sal_Unicode) '[' );
2103 aColName.append( (sal_Unicode) ']' );
2104 aFormatCode.insert( 0, aColName.makeStringAndClear() );
2108 void SvXMLNumFormatContext::UpdateCalendar( const rtl::OUString& rNewCalendar )
2110 if ( rNewCalendar != sCalendar )
2112 sCalendar = rNewCalendar;
2113 if ( !sCalendar.isEmpty() )
2115 aFormatCode.appendAscii( "[~" ); // intro for calendar code
2116 aFormatCode.append( sCalendar );
2117 aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbolcalendar code
2122 sal_Bool SvXMLNumFormatContext::IsSystemLanguage()
2124 return nFormatLang == LANGUAGE_SYSTEM;
2127 //-------------------------------------------------------------------------
2130 // SvXMLNumFmtHelper
2133 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2134 const uno::Reference<util::XNumberFormatsSupplier>& rSupp,
2135 const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
2136 : mxServiceFactory(xServiceFactory)
2138 DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
2140 SvNumberFormatter* pFormatter = NULL;
2141 SvNumberFormatsSupplierObj* pObj =
2142 SvNumberFormatsSupplierObj::getImplementation( rSupp );
2143 if (pObj)
2144 pFormatter = pObj->GetNumberFormatter();
2146 pData = new SvXMLNumImpData( pFormatter, mxServiceFactory );
2149 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2150 SvNumberFormatter* pNumberFormatter,
2151 const uno::Reference<lang::XMultiServiceFactory>& xServiceFactory )
2152 : mxServiceFactory(xServiceFactory)
2154 DBG_ASSERT( mxServiceFactory.is(), "got no service manager" );
2156 pData = new SvXMLNumImpData( pNumberFormatter, mxServiceFactory );
2159 SvXMLNumFmtHelper::~SvXMLNumFmtHelper()
2161 // remove temporary (volatile) formats from NumberFormatter
2162 pData->RemoveVolatileFormats();
2164 delete pData;
2167 SvXMLStyleContext* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport,
2168 sal_uInt16 nPrefix, const OUString& rLocalName,
2169 const uno::Reference<xml::sax::XAttributeList>& xAttrList,
2170 SvXMLStylesContext& rStyles )
2172 SvXMLStyleContext* pContext = NULL;
2174 const SvXMLTokenMap& rTokenMap = pData->GetStylesElemTokenMap();
2175 sal_uInt16 nToken = rTokenMap.Get( nPrefix, rLocalName );
2176 switch (nToken)
2178 case XML_TOK_STYLES_NUMBER_STYLE:
2179 case XML_TOK_STYLES_CURRENCY_STYLE:
2180 case XML_TOK_STYLES_PERCENTAGE_STYLE:
2181 case XML_TOK_STYLES_DATE_STYLE:
2182 case XML_TOK_STYLES_TIME_STYLE:
2183 case XML_TOK_STYLES_BOOLEAN_STYLE:
2184 case XML_TOK_STYLES_TEXT_STYLE:
2185 pContext = new SvXMLNumFormatContext( rImport, nPrefix, rLocalName,
2186 pData, nToken, xAttrList, rStyles );
2187 break;
2190 // return NULL if not a data style, caller must handle other elements
2191 return pContext;
2194 const SvXMLTokenMap& SvXMLNumFmtHelper::GetStylesElemTokenMap()
2196 return pData->GetStylesElemTokenMap();
2199 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */