bump product version to 4.1.6.2
[LibreOffice.git] / xmloff / source / style / xmlnumfi.cxx
blob3debbf467b84b125f5bed5f443335e8058883769
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <comphelper/string.hxx>
22 #include <unotools/syslocale.hxx>
24 #include <svl/zforlist.hxx>
26 #include <svl/zformat.hxx>
27 #include <svl/numuno.hxx>
28 #include <rtl/math.hxx>
29 #include <i18nlangtag/languagetag.hxx>
30 #include <tools/color.hxx>
31 #include <tools/debug.hxx>
32 #include <rtl/ustrbuf.hxx>
34 #include <sax/tools/converter.hxx>
36 #include <xmloff/xmlnumfi.hxx>
37 #include <xmloff/xmltkmap.hxx>
38 #include "xmloff/xmlnmspe.hxx"
39 #include <xmloff/xmlictxt.hxx>
40 #include <xmloff/xmlimp.hxx>
41 #include <xmloff/xmluconv.hxx>
42 #include <xmloff/nmspmap.hxx>
43 #include <xmloff/families.hxx>
44 #include <xmloff/xmltoken.hxx>
46 #include <boost/ptr_container/ptr_vector.hpp>
47 #include <boost/ptr_container/ptr_set.hpp>
50 using namespace ::com::sun::star;
51 using namespace ::xmloff::token;
53 //-------------------------------------------------------------------------
55 struct SvXMLNumFmtEntry
57 OUString aName;
58 sal_uInt32 nKey;
59 sal_Bool bRemoveAfterUse;
61 SvXMLNumFmtEntry( const OUString& rN, sal_uInt32 nK, sal_Bool bR ) :
62 aName(rN), nKey(nK), bRemoveAfterUse(bR) {}
65 typedef ::boost::ptr_vector<SvXMLNumFmtEntry> SvXMLNumFmtEntryArr;
67 struct SvXMLEmbeddedElement
69 sal_Int32 nFormatPos;
70 OUString aText;
72 SvXMLEmbeddedElement( sal_Int32 nFP, const OUString& rT ) :
73 nFormatPos(nFP), aText(rT) {}
75 // comparison operators for PTRARR sorting - sorted by position
76 sal_Bool operator ==( const SvXMLEmbeddedElement& r ) const { return nFormatPos == r.nFormatPos; }
77 sal_Bool operator < ( const SvXMLEmbeddedElement& r ) const { return nFormatPos < r.nFormatPos; }
80 typedef boost::ptr_set<SvXMLEmbeddedElement> SvXMLEmbeddedElementArr;
82 //-------------------------------------------------------------------------
84 class SvXMLNumImpData
86 SvNumberFormatter* pFormatter;
87 SvXMLTokenMap* pStylesElemTokenMap;
88 SvXMLTokenMap* pStyleElemTokenMap;
89 SvXMLTokenMap* pStyleAttrTokenMap;
90 SvXMLTokenMap* pStyleElemAttrTokenMap;
91 LocaleDataWrapper* pLocaleData;
92 SvXMLNumFmtEntryArr aNameEntries;
94 uno::Reference< uno::XComponentContext > m_xContext;
96 public:
97 SvXMLNumImpData(
98 SvNumberFormatter* pFmt,
99 const uno::Reference<uno::XComponentContext>& rxContext );
100 ~SvXMLNumImpData();
102 SvNumberFormatter* GetNumberFormatter() const { return pFormatter; }
103 const SvXMLTokenMap& GetStylesElemTokenMap();
104 const SvXMLTokenMap& GetStyleElemTokenMap();
105 const SvXMLTokenMap& GetStyleAttrTokenMap();
106 const SvXMLTokenMap& GetStyleElemAttrTokenMap();
107 const LocaleDataWrapper& GetLocaleData( LanguageType nLang );
108 sal_uInt32 GetKeyForName( const OUString& rName );
109 void AddKey( sal_uInt32 nKey, const OUString& rName, sal_Bool bRemoveAfterUse );
110 void SetUsed( sal_uInt32 nKey );
111 void RemoveVolatileFormats();
115 struct SvXMLNumberInfo
117 sal_Int32 nDecimals;
118 sal_Int32 nInteger;
119 sal_Int32 nExpDigits;
120 sal_Int32 nNumerDigits;
121 sal_Int32 nDenomDigits;
122 sal_Int32 nFracDenominator;
123 sal_Bool bGrouping;
124 sal_Bool bDecReplace;
125 sal_Bool bVarDecimals;
126 double fDisplayFactor;
127 SvXMLEmbeddedElementArr aEmbeddedElements;
129 SvXMLNumberInfo()
131 nDecimals = nInteger = nExpDigits = nNumerDigits = nDenomDigits = nFracDenominator = -1;
132 bGrouping = bDecReplace = bVarDecimals = sal_False;
133 fDisplayFactor = 1.0;
137 class SvXMLNumFmtElementContext : public SvXMLImportContext
139 SvXMLNumFormatContext& rParent;
140 sal_uInt16 nType;
141 OUStringBuffer aContent;
142 SvXMLNumberInfo aNumInfo;
143 LanguageType nElementLang;
144 sal_Bool bLong;
145 sal_Bool bTextual;
146 OUString sCalendar;
148 public:
149 SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
150 const OUString& rLName,
151 SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
152 const ::com::sun::star::uno::Reference<
153 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
154 virtual ~SvXMLNumFmtElementContext();
156 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
157 const OUString& rLocalName,
158 const ::com::sun::star::uno::Reference<
159 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
160 virtual void Characters( const OUString& rChars );
161 virtual void EndElement();
163 void AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent );
167 class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext
169 SvXMLNumFmtElementContext& rParent;
170 OUStringBuffer aContent;
171 sal_Int32 nTextPosition;
173 public:
174 SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
175 const OUString& rLName,
176 SvXMLNumFmtElementContext& rParentContext,
177 const ::com::sun::star::uno::Reference<
178 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
179 virtual ~SvXMLNumFmtEmbeddedTextContext();
181 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
182 const OUString& rLocalName,
183 const ::com::sun::star::uno::Reference<
184 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
185 virtual void Characters( const OUString& rChars );
186 virtual void EndElement();
190 class SvXMLNumFmtMapContext : public SvXMLImportContext
192 SvXMLNumFormatContext& rParent;
193 OUString sCondition;
194 OUString sName;
196 public:
197 SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
198 const OUString& rLName,
199 SvXMLNumFormatContext& rParentContext,
200 const ::com::sun::star::uno::Reference<
201 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
202 virtual ~SvXMLNumFmtMapContext();
204 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
205 const OUString& rLocalName,
206 const ::com::sun::star::uno::Reference<
207 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
208 virtual void Characters( const OUString& rChars );
209 virtual void EndElement();
213 class SvXMLNumFmtPropContext : public SvXMLImportContext
215 SvXMLNumFormatContext& rParent;
216 sal_Int32 m_nColor;
217 sal_Bool bColSet;
219 public:
220 SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_uInt16 nPrfx,
221 const OUString& rLName,
222 SvXMLNumFormatContext& rParentContext,
223 const ::com::sun::star::uno::Reference<
224 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
225 virtual ~SvXMLNumFmtPropContext();
227 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
228 const OUString& rLocalName,
229 const ::com::sun::star::uno::Reference<
230 ::com::sun::star::xml::sax::XAttributeList>& xAttrList );
231 virtual void Characters( const OUString& rChars );
232 virtual void EndElement();
236 //-------------------------------------------------------------------------
238 enum SvXMLStyleTokens
240 XML_TOK_STYLE_TEXT,
241 XML_TOK_STYLE_FILL_CHARACTER,
242 XML_TOK_STYLE_NUMBER,
243 XML_TOK_STYLE_SCIENTIFIC_NUMBER,
244 XML_TOK_STYLE_FRACTION,
245 XML_TOK_STYLE_CURRENCY_SYMBOL,
246 XML_TOK_STYLE_DAY,
247 XML_TOK_STYLE_MONTH,
248 XML_TOK_STYLE_YEAR,
249 XML_TOK_STYLE_ERA,
250 XML_TOK_STYLE_DAY_OF_WEEK,
251 XML_TOK_STYLE_WEEK_OF_YEAR,
252 XML_TOK_STYLE_QUARTER,
253 XML_TOK_STYLE_HOURS,
254 XML_TOK_STYLE_AM_PM,
255 XML_TOK_STYLE_MINUTES,
256 XML_TOK_STYLE_SECONDS,
257 XML_TOK_STYLE_BOOLEAN,
258 XML_TOK_STYLE_TEXT_CONTENT,
259 XML_TOK_STYLE_PROPERTIES,
260 XML_TOK_STYLE_MAP
263 enum SvXMLStyleAttrTokens
265 XML_TOK_STYLE_ATTR_NAME,
266 XML_TOK_STYLE_ATTR_LANGUAGE,
267 XML_TOK_STYLE_ATTR_COUNTRY,
268 XML_TOK_STYLE_ATTR_TITLE,
269 XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER,
270 XML_TOK_STYLE_ATTR_FORMAT_SOURCE,
271 XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW,
272 XML_TOK_STYLE_ATTR_VOLATILE,
273 XML_TOK_STYLE_ATTR_TRANSL_FORMAT,
274 XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE,
275 XML_TOK_STYLE_ATTR_TRANSL_COUNTRY,
276 XML_TOK_STYLE_ATTR_TRANSL_STYLE
279 enum SvXMLStyleElemAttrTokens
281 XML_TOK_ELEM_ATTR_DECIMAL_PLACES,
282 XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS,
283 XML_TOK_ELEM_ATTR_GROUPING,
284 XML_TOK_ELEM_ATTR_DISPLAY_FACTOR,
285 XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT,
286 XML_TOK_ELEM_ATTR_DENOMINATOR_VALUE,
287 XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS,
288 XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS,
289 XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS,
290 XML_TOK_ELEM_ATTR_LANGUAGE,
291 XML_TOK_ELEM_ATTR_COUNTRY,
292 XML_TOK_ELEM_ATTR_STYLE,
293 XML_TOK_ELEM_ATTR_TEXTUAL,
294 XML_TOK_ELEM_ATTR_CALENDAR
297 //-------------------------------------------------------------------------
300 // standard colors
303 #define XML_NUMF_COLORCOUNT 10
305 static ColorData aNumFmtStdColors[XML_NUMF_COLORCOUNT] =
307 COL_BLACK,
308 COL_LIGHTBLUE,
309 COL_LIGHTGREEN,
310 COL_LIGHTCYAN,
311 COL_LIGHTRED,
312 COL_LIGHTMAGENTA,
313 COL_BROWN,
314 COL_GRAY,
315 COL_YELLOW,
316 COL_WHITE
320 // token maps
323 // maps for SvXMLUnitConverter::convertEnum
325 static SvXMLEnumMapEntry aStyleValueMap[] =
327 { XML_SHORT, sal_False },
328 { XML_LONG, sal_True },
329 { XML_TOKEN_INVALID, 0 }
332 static SvXMLEnumMapEntry aFormatSourceMap[] =
334 { XML_FIXED, sal_False },
335 { XML_LANGUAGE, sal_True },
336 { XML_TOKEN_INVALID, 0 }
339 //-------------------------------------------------------------------------
341 struct SvXMLDefaultDateFormat
343 NfIndexTableOffset eFormat;
344 SvXMLDateElementAttributes eDOW;
345 SvXMLDateElementAttributes eDay;
346 SvXMLDateElementAttributes eMonth;
347 SvXMLDateElementAttributes eYear;
348 SvXMLDateElementAttributes eHours;
349 SvXMLDateElementAttributes eMins;
350 SvXMLDateElementAttributes eSecs;
351 sal_Bool bSystem;
354 static SvXMLDefaultDateFormat aDefaultDateFormats[] =
356 // format day-of-week day month year hours minutes seconds format-source
358 { 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 },
359 { 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 },
360 { 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 },
361 { 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 },
362 { 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 },
363 { 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 },
364 { 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 },
365 { 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 },
366 { 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 },
367 { 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 },
368 { 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 },
369 { 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 },
370 { 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 },
371 { 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 }
374 //-------------------------------------------------------------------------
377 // SvXMLNumImpData
380 SvXMLNumImpData::SvXMLNumImpData(
381 SvNumberFormatter* pFmt,
382 const uno::Reference<uno::XComponentContext>& rxContext )
383 : pFormatter(pFmt),
384 pStylesElemTokenMap(NULL),
385 pStyleElemTokenMap(NULL),
386 pStyleAttrTokenMap(NULL),
387 pStyleElemAttrTokenMap(NULL),
388 pLocaleData(NULL),
389 m_xContext(rxContext)
391 DBG_ASSERT( rxContext.is(), "got no service manager" );
394 SvXMLNumImpData::~SvXMLNumImpData()
396 delete pStylesElemTokenMap;
397 delete pStyleElemTokenMap;
398 delete pStyleAttrTokenMap;
399 delete pStyleElemAttrTokenMap;
400 delete pLocaleData;
403 sal_uInt32 SvXMLNumImpData::GetKeyForName( const OUString& rName )
405 sal_uInt16 nCount = aNameEntries.size();
406 for (sal_uInt16 i=0; i<nCount; i++)
408 const SvXMLNumFmtEntry* pObj = &aNameEntries[i];
409 if ( pObj->aName == rName )
410 return pObj->nKey; // found
412 return NUMBERFORMAT_ENTRY_NOT_FOUND;
415 void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const OUString& rName, sal_Bool bRemoveAfterUse )
417 if ( bRemoveAfterUse )
419 // if there is already an entry for this key without the bRemoveAfterUse flag,
420 // clear the flag for this entry, too
422 sal_uInt16 nCount = aNameEntries.size();
423 for (sal_uInt16 i=0; i<nCount; i++)
425 SvXMLNumFmtEntry* pObj = &aNameEntries[i];
426 if ( pObj->nKey == nKey && !pObj->bRemoveAfterUse )
428 bRemoveAfterUse = sal_False; // clear flag for new entry
429 break;
433 else
435 // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key
436 SetUsed( nKey );
439 SvXMLNumFmtEntry* pObj = new SvXMLNumFmtEntry( rName, nKey, bRemoveAfterUse );
440 aNameEntries.push_back( pObj );
443 void SvXMLNumImpData::SetUsed( sal_uInt32 nKey )
445 sal_uInt16 nCount = aNameEntries.size();
446 for (sal_uInt16 i=0; i<nCount; i++)
448 SvXMLNumFmtEntry* pObj = &aNameEntries[i];
449 if ( pObj->nKey == nKey )
451 pObj->bRemoveAfterUse = sal_False; // used -> don't remove
453 // continue searching - there may be several entries for the same key
454 // (with different names), the format must not be deleted if any one of
455 // them is used
460 void SvXMLNumImpData::RemoveVolatileFormats()
462 // remove temporary (volatile) formats from NumberFormatter
463 // called at the end of each import (styles and content), so volatile formats
464 // from styles can't be used in content
466 if ( !pFormatter )
467 return;
469 sal_uInt16 nCount = aNameEntries.size();
470 for (sal_uInt16 i=0; i<nCount; i++)
472 const SvXMLNumFmtEntry* pObj = &aNameEntries[i];
473 if ( pObj->bRemoveAfterUse )
475 const SvNumberformat* pFormat = pFormatter->GetEntry(pObj->nKey);
476 if (pFormat && (pFormat->GetType() & NUMBERFORMAT_DEFINED))
477 pFormatter->DeleteEntry( pObj->nKey );
482 const SvXMLTokenMap& SvXMLNumImpData::GetStylesElemTokenMap()
484 if( !pStylesElemTokenMap )
486 static SvXMLTokenMapEntry aStylesElemMap[] =
488 // style elements
489 { XML_NAMESPACE_NUMBER, XML_NUMBER_STYLE, XML_TOK_STYLES_NUMBER_STYLE },
490 { XML_NAMESPACE_NUMBER, XML_CURRENCY_STYLE, XML_TOK_STYLES_CURRENCY_STYLE },
491 { XML_NAMESPACE_NUMBER, XML_PERCENTAGE_STYLE, XML_TOK_STYLES_PERCENTAGE_STYLE },
492 { XML_NAMESPACE_NUMBER, XML_DATE_STYLE, XML_TOK_STYLES_DATE_STYLE },
493 { XML_NAMESPACE_NUMBER, XML_TIME_STYLE, XML_TOK_STYLES_TIME_STYLE },
494 { XML_NAMESPACE_NUMBER, XML_BOOLEAN_STYLE, XML_TOK_STYLES_BOOLEAN_STYLE },
495 { XML_NAMESPACE_NUMBER, XML_TEXT_STYLE, XML_TOK_STYLES_TEXT_STYLE },
496 XML_TOKEN_MAP_END
499 pStylesElemTokenMap = new SvXMLTokenMap( aStylesElemMap );
501 return *pStylesElemTokenMap;
504 const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemTokenMap()
506 if( !pStyleElemTokenMap )
508 static SvXMLTokenMapEntry aStyleElemMap[] =
510 // elements in a style
511 { XML_NAMESPACE_NUMBER, XML_TEXT, XML_TOK_STYLE_TEXT },
512 { XML_NAMESPACE_LO_EXT, XML_FILL_CHARACTER, XML_TOK_STYLE_FILL_CHARACTER },
513 { XML_NAMESPACE_NUMBER, XML_FILL_CHARACTER, XML_TOK_STYLE_FILL_CHARACTER },
514 { XML_NAMESPACE_NUMBER, XML_NUMBER, XML_TOK_STYLE_NUMBER },
515 { XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER, XML_TOK_STYLE_SCIENTIFIC_NUMBER },
516 { XML_NAMESPACE_NUMBER, XML_FRACTION, XML_TOK_STYLE_FRACTION },
517 { XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL, XML_TOK_STYLE_CURRENCY_SYMBOL },
518 { XML_NAMESPACE_NUMBER, XML_DAY, XML_TOK_STYLE_DAY },
519 { XML_NAMESPACE_NUMBER, XML_MONTH, XML_TOK_STYLE_MONTH },
520 { XML_NAMESPACE_NUMBER, XML_YEAR, XML_TOK_STYLE_YEAR },
521 { XML_NAMESPACE_NUMBER, XML_ERA, XML_TOK_STYLE_ERA },
522 { XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK, XML_TOK_STYLE_DAY_OF_WEEK },
523 { XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR, XML_TOK_STYLE_WEEK_OF_YEAR },
524 { XML_NAMESPACE_NUMBER, XML_QUARTER, XML_TOK_STYLE_QUARTER },
525 { XML_NAMESPACE_NUMBER, XML_HOURS, XML_TOK_STYLE_HOURS },
526 { XML_NAMESPACE_NUMBER, XML_AM_PM, XML_TOK_STYLE_AM_PM },
527 { XML_NAMESPACE_NUMBER, XML_MINUTES, XML_TOK_STYLE_MINUTES },
528 { XML_NAMESPACE_NUMBER, XML_SECONDS, XML_TOK_STYLE_SECONDS },
529 { XML_NAMESPACE_NUMBER, XML_BOOLEAN, XML_TOK_STYLE_BOOLEAN },
530 { XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT, XML_TOK_STYLE_TEXT_CONTENT },
531 { XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES, XML_TOK_STYLE_PROPERTIES },
532 { XML_NAMESPACE_STYLE, XML_MAP, XML_TOK_STYLE_MAP },
533 XML_TOKEN_MAP_END
536 pStyleElemTokenMap = new SvXMLTokenMap( aStyleElemMap );
538 return *pStyleElemTokenMap;
541 const SvXMLTokenMap& SvXMLNumImpData::GetStyleAttrTokenMap()
543 if( !pStyleAttrTokenMap )
545 static SvXMLTokenMapEntry aStyleAttrMap[] =
547 // attributes for a style
548 { XML_NAMESPACE_STYLE, XML_NAME, XML_TOK_STYLE_ATTR_NAME },
549 { XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_STYLE_ATTR_LANGUAGE },
550 { XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_STYLE_ATTR_COUNTRY },
551 { XML_NAMESPACE_NUMBER, XML_TITLE, XML_TOK_STYLE_ATTR_TITLE },
552 { XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, XML_TOK_STYLE_ATTR_AUTOMATIC_ORDER },
553 { XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE, XML_TOK_STYLE_ATTR_FORMAT_SOURCE },
554 { XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW, XML_TOK_STYLE_ATTR_TRUNCATE_ON_OVERFLOW },
555 { XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TOK_STYLE_ATTR_VOLATILE },
556 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT, XML_TOK_STYLE_ATTR_TRANSL_FORMAT },
557 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, XML_TOK_STYLE_ATTR_TRANSL_LANGUAGE },
558 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, XML_TOK_STYLE_ATTR_TRANSL_COUNTRY },
559 { XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE, XML_TOK_STYLE_ATTR_TRANSL_STYLE },
560 XML_TOKEN_MAP_END
563 pStyleAttrTokenMap = new SvXMLTokenMap( aStyleAttrMap );
565 return *pStyleAttrTokenMap;
568 const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemAttrTokenMap()
570 if( !pStyleElemAttrTokenMap )
572 static SvXMLTokenMapEntry aStyleElemAttrMap[] =
574 // attributes for an element within a style
575 { XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, XML_TOK_ELEM_ATTR_DECIMAL_PLACES },
576 { XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS },
577 { XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TOK_ELEM_ATTR_GROUPING },
578 { XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, XML_TOK_ELEM_ATTR_DISPLAY_FACTOR },
579 { XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT },
580 { XML_NAMESPACE_NUMBER, XML_DENOMINATOR_VALUE, XML_TOK_ELEM_ATTR_DENOMINATOR_VALUE },
581 { XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS, XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS },
582 { XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS },
583 { XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS },
584 { XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_ELEM_ATTR_LANGUAGE },
585 { XML_NAMESPACE_NUMBER, XML_COUNTRY, XML_TOK_ELEM_ATTR_COUNTRY },
586 { XML_NAMESPACE_NUMBER, XML_STYLE, XML_TOK_ELEM_ATTR_STYLE },
587 { XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TOK_ELEM_ATTR_TEXTUAL },
588 { XML_NAMESPACE_NUMBER, XML_CALENDAR, XML_TOK_ELEM_ATTR_CALENDAR },
589 XML_TOKEN_MAP_END
592 pStyleElemAttrTokenMap = new SvXMLTokenMap( aStyleElemAttrMap );
594 return *pStyleElemAttrTokenMap;
597 const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang )
599 if ( !pLocaleData )
600 pLocaleData = new LocaleDataWrapper(
601 pFormatter ? pFormatter->GetComponentContext() : m_xContext,
602 LanguageTag( nLang ) );
603 else
604 pLocaleData->setLanguageTag( LanguageTag( nLang ) );
605 return *pLocaleData;
608 //-------------------------------------------------------------------------
611 // SvXMLNumFmtMapContext
614 SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport,
615 sal_uInt16 nPrfx, const OUString& rLName,
616 SvXMLNumFormatContext& rParentContext,
617 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
618 SvXMLImportContext( rImport, nPrfx, rLName ),
619 rParent( rParentContext )
621 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
622 for( sal_Int16 i=0; i < nAttrCount; i++ )
624 OUString sAttrName = xAttrList->getNameByIndex( i );
625 OUString sValue = xAttrList->getValueByIndex( i );
626 OUString aLocalName;
627 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
628 if ( nPrefix == XML_NAMESPACE_STYLE )
630 if ( IsXMLToken( aLocalName, XML_CONDITION) )
631 sCondition = sValue;
632 else if ( IsXMLToken( aLocalName, XML_APPLY_STYLE_NAME) )
633 sName = sValue;
638 SvXMLNumFmtMapContext::~SvXMLNumFmtMapContext()
642 SvXMLImportContext* SvXMLNumFmtMapContext::CreateChildContext(
643 sal_uInt16 nPrfx, const OUString& rLName,
644 const uno::Reference<xml::sax::XAttributeList>& )
646 // no elements supported - use default context
647 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
650 void SvXMLNumFmtMapContext::Characters( const OUString& )
654 void SvXMLNumFmtMapContext::EndElement()
656 rParent.AddCondition( sCondition, sName );
659 //-------------------------------------------------------------------------
662 // SvXMLNumFmtPropContext
665 SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport,
666 sal_uInt16 nPrfx, const OUString& rLName,
667 SvXMLNumFormatContext& rParentContext,
668 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
669 SvXMLImportContext( rImport, nPrfx, rLName ),
670 rParent( rParentContext ),
671 bColSet( sal_False )
673 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
674 for( sal_Int16 i=0; i < nAttrCount; i++ )
676 OUString sAttrName = xAttrList->getNameByIndex( i );
677 OUString sValue = xAttrList->getValueByIndex( i );
678 OUString aLocalName;
679 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
680 if ( nPrefix == XML_NAMESPACE_FO && IsXMLToken( aLocalName, XML_COLOR ) )
682 bColSet = ::sax::Converter::convertColor( m_nColor, sValue );
687 SvXMLNumFmtPropContext::~SvXMLNumFmtPropContext()
691 SvXMLImportContext* SvXMLNumFmtPropContext::CreateChildContext(
692 sal_uInt16 nPrfx, const OUString& rLName,
693 const uno::Reference<xml::sax::XAttributeList>& )
695 // no elements supported - use default context
696 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
699 void SvXMLNumFmtPropContext::Characters( const OUString& )
703 void SvXMLNumFmtPropContext::EndElement()
705 if (bColSet)
706 rParent.AddColor( m_nColor );
709 //-------------------------------------------------------------------------
712 // SvXMLNumFmtEmbeddedTextContext
715 SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport,
716 sal_uInt16 nPrfx, const OUString& rLName,
717 SvXMLNumFmtElementContext& rParentContext,
718 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
719 SvXMLImportContext( rImport, nPrfx, rLName ),
720 rParent( rParentContext ),
721 nTextPosition( 0 )
723 sal_Int32 nAttrVal;
725 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
726 for( sal_Int16 i=0; i < nAttrCount; i++ )
728 OUString sAttrName = xAttrList->getNameByIndex( i );
729 OUString sValue = xAttrList->getValueByIndex( i );
730 OUString aLocalName;
731 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
732 if ( nPrefix == XML_NAMESPACE_NUMBER && IsXMLToken( aLocalName, XML_POSITION ) )
734 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
735 nTextPosition = nAttrVal;
740 SvXMLNumFmtEmbeddedTextContext::~SvXMLNumFmtEmbeddedTextContext()
744 SvXMLImportContext* SvXMLNumFmtEmbeddedTextContext::CreateChildContext(
745 sal_uInt16 nPrfx, const OUString& rLName,
746 const uno::Reference<xml::sax::XAttributeList>& )
748 // no elements supported - use default context
749 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
752 void SvXMLNumFmtEmbeddedTextContext::Characters( const OUString& rChars )
754 aContent.append( rChars );
757 void SvXMLNumFmtEmbeddedTextContext::EndElement()
759 rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() );
762 //-------------------------------------------------------------------------
764 static sal_Bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent )
766 sal_uInt16 nFormatType = rParent.GetType();
768 // Treat space equal to non-breaking space separator.
769 const sal_Unicode cNBSP = 0x00A0;
770 sal_Unicode cTS;
771 if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
772 nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
773 nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
774 (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep()[0]) ||
775 (cChar == ' ' && cTS == cNBSP)) )
777 // #i22394# Extra occurrences of thousands separator must be quoted, so they
778 // aren't mis-interpreted as display-factor.
779 // This must be limited to the format types that can contain a number element,
780 // because the same character can be a date separator that should not be quoted
781 // in date formats.
783 return sal_False; // force quotes
786 // see ImpSvNumberformatScan::Next_Symbol
787 if ( cChar == ' ' ||
788 cChar == '-' ||
789 cChar == '/' ||
790 cChar == '.' ||
791 cChar == ',' ||
792 cChar == ':' ||
793 cChar == '\'' )
794 return sal_True; // for all format types
796 // percent sign must be used without quotes for percentage styles only
797 if ( nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE && cChar == '%' )
798 return sal_True;
800 // don't put quotes around single parentheses (often used for negative numbers)
801 if ( ( nFormatType == XML_TOK_STYLES_NUMBER_STYLE ||
802 nFormatType == XML_TOK_STYLES_CURRENCY_STYLE ||
803 nFormatType == XML_TOK_STYLES_PERCENTAGE_STYLE ) &&
804 ( cChar == '(' || cChar == ')' ) )
805 return sal_True;
807 return sal_False;
810 static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent )
812 sal_Bool bQuote = sal_True;
813 sal_Int32 nLength = rContent.getLength();
815 if ( ( nLength == 1 &&
816 lcl_ValidChar( rContent[0], rParent ) ) ||
817 ( nLength == 2 &&
818 lcl_ValidChar( rContent[0], rParent ) &&
819 rContent[1] == ' ' ) )
821 // don't quote single separator characters like space or percent,
822 // or separator characters followed by space (used in date formats)
823 bQuote = sal_False;
825 else if ( rParent.GetType() == XML_TOK_STYLES_PERCENTAGE_STYLE && nLength > 1 )
827 // the percent character in percentage styles must be left out of quoting
828 // (one occurrence is enough even if there are several percent characters in the string)
830 OUString aString( rContent.getStr() );
831 sal_Int32 nPos = aString.indexOf( (sal_Unicode) '%' );
832 if ( nPos >= 0 )
834 if ( nPos + 1 < nLength )
836 if ( nPos + 2 == nLength && lcl_ValidChar( rContent[nPos + 1], rParent ) )
838 // single character that doesn't need quoting
840 else
842 // quote text behind percent character
843 rContent.insert( nPos + 1, (sal_Unicode) '"' );
844 rContent.append( (sal_Unicode) '"' );
847 if ( nPos > 0 )
849 if ( nPos == 1 && lcl_ValidChar( rContent[0], rParent ) )
851 // single character that doesn't need quoting
853 else
855 // quote text before percent character
856 rContent.insert( nPos, (sal_Unicode) '"' );
857 rContent.insert( 0, (sal_Unicode) '"' );
860 bQuote = sal_False;
862 // else: normal quoting (below)
865 if ( bQuote )
867 // #i55469# quotes in the string itself have to be escaped
868 bool bEscape = ( rContent.indexOf( (sal_Unicode) '"' ) >= 0 );
869 if ( bEscape )
871 // A quote is turned into "\"" - a quote to end quoted text, an escaped quote,
872 // and a quote to resume quoting.
873 OUString aInsert( "\"\\\"" );
875 sal_Int32 nPos = 0;
876 while ( nPos < rContent.getLength() )
878 if ( rContent[nPos] == (sal_Unicode) '"' )
880 rContent.insert( nPos, aInsert );
881 nPos += aInsert.getLength();
883 ++nPos;
887 // quote string literals
888 rContent.insert( 0, (sal_Unicode) '"' );
889 rContent.append( (sal_Unicode) '"' );
891 // remove redundant double quotes at start or end
892 if ( bEscape )
894 if ( rContent.getLength() > 2 &&
895 rContent[0] == (sal_Unicode) '"' &&
896 rContent[1] == (sal_Unicode) '"' )
898 rContent.remove(0, 2);
901 sal_Int32 nLen = rContent.getLength();
902 if ( nLen > 2 &&
903 rContent[nLen - 1] == (sal_Unicode) '"' &&
904 rContent[nLen - 2] == (sal_Unicode) '"' )
906 rContent.truncate(nLen - 2);
913 // SvXMLNumFmtElementContext
916 const sal_Int32 MAX_SECOND_DIGITS = 20; // fdo#58539 & gnome#627420: limit number of digits during import
918 SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport,
919 sal_uInt16 nPrfx, const OUString& rLName,
920 SvXMLNumFormatContext& rParentContext, sal_uInt16 nNewType,
921 const uno::Reference<xml::sax::XAttributeList>& xAttrList ) :
922 SvXMLImportContext( rImport, nPrfx, rLName ),
923 rParent( rParentContext ),
924 nType( nNewType ),
925 nElementLang( LANGUAGE_SYSTEM ),
926 bLong( sal_False ),
927 bTextual( sal_False )
929 OUString sLanguage, sCountry;
930 sal_Int32 nAttrVal;
931 bool bAttrBool(false);
932 sal_uInt16 nAttrEnum;
933 double fAttrDouble;
935 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
936 for( sal_Int16 i=0; i < nAttrCount; i++ )
938 OUString sAttrName = xAttrList->getNameByIndex( i );
939 OUString sValue = xAttrList->getValueByIndex( i );
940 OUString aLocalName;
941 sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
943 const SvXMLTokenMap& rTokenMap = rParent.GetData()->GetStyleElemAttrTokenMap();
944 sal_uInt16 nToken = rTokenMap.Get( nPrefix, aLocalName );
946 switch (nToken)
948 case XML_TOK_ELEM_ATTR_DECIMAL_PLACES:
949 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
950 aNumInfo.nDecimals = std::min<sal_Int32>(nAttrVal, MAX_SECOND_DIGITS);
951 break;
952 case XML_TOK_ELEM_ATTR_MIN_INTEGER_DIGITS:
953 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
954 aNumInfo.nInteger = nAttrVal;
955 break;
956 case XML_TOK_ELEM_ATTR_GROUPING:
957 if (::sax::Converter::convertBool( bAttrBool, sValue ))
958 aNumInfo.bGrouping = bAttrBool;
959 break;
960 case XML_TOK_ELEM_ATTR_DISPLAY_FACTOR:
961 if (::sax::Converter::convertDouble( fAttrDouble, sValue ))
962 aNumInfo.fDisplayFactor = fAttrDouble;
963 break;
964 case XML_TOK_ELEM_ATTR_DECIMAL_REPLACEMENT:
965 if ( !sValue.isEmpty() )
966 aNumInfo.bDecReplace = sal_True; // only a default string is supported
967 else
968 aNumInfo.bVarDecimals = sal_True; // empty replacement string: variable decimals
969 break;
970 case XML_TOK_ELEM_ATTR_MIN_EXPONENT_DIGITS:
971 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
972 aNumInfo.nExpDigits = nAttrVal;
973 break;
974 case XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS:
975 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
976 aNumInfo.nNumerDigits = nAttrVal;
977 break;
978 case XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS:
979 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
980 aNumInfo.nDenomDigits = nAttrVal;
981 break;
982 case XML_TOK_ELEM_ATTR_DENOMINATOR_VALUE:
983 if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
984 aNumInfo.nFracDenominator = nAttrVal;
985 break;
986 case XML_TOK_ELEM_ATTR_LANGUAGE:
987 sLanguage = sValue;
988 break;
989 case XML_TOK_ELEM_ATTR_COUNTRY:
990 sCountry = sValue;
991 break;
992 case XML_TOK_ELEM_ATTR_STYLE:
993 if ( SvXMLUnitConverter::convertEnum( nAttrEnum, sValue, aStyleValueMap ) )
994 bLong = (sal_Bool) nAttrEnum;
995 break;
996 case XML_TOK_ELEM_ATTR_TEXTUAL:
997 if (::sax::Converter::convertBool( bAttrBool, sValue ))
998 bTextual = bAttrBool;
999 break;
1000 case XML_TOK_ELEM_ATTR_CALENDAR:
1001 sCalendar = sValue;
1002 break;
1006 if ( !sLanguage.isEmpty() || !sCountry.isEmpty() )
1008 nElementLang = LanguageTag( sLanguage, sCountry ).getLanguageType( false);
1009 if ( nElementLang == LANGUAGE_DONTKNOW )
1010 nElementLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
1014 SvXMLNumFmtElementContext::~SvXMLNumFmtElementContext()
1018 SvXMLImportContext* SvXMLNumFmtElementContext::CreateChildContext(
1019 sal_uInt16 nPrfx, const OUString& rLName,
1020 const uno::Reference<xml::sax::XAttributeList>& xAttrList )
1022 // only number:number supports number:embedded-text child element
1024 if ( nType == XML_TOK_STYLE_NUMBER &&
1025 nPrfx == XML_NAMESPACE_NUMBER && IsXMLToken( rLName, XML_EMBEDDED_TEXT ) )
1027 return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nPrfx, rLName, *this, xAttrList );
1029 else
1030 return new SvXMLImportContext( GetImport(), nPrfx, rLName );
1033 void SvXMLNumFmtElementContext::Characters( const OUString& rChars )
1035 aContent.append( rChars );
1038 void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent )
1040 if ( !rContent.isEmpty() )
1042 SvXMLEmbeddedElement* pObj = new SvXMLEmbeddedElement( nFormatPos, rContent );
1043 if ( !aNumInfo.aEmbeddedElements.insert( pObj ).second )
1045 // there's already an element at this position - append text to existing element
1047 delete pObj;
1048 for (SvXMLEmbeddedElementArr::iterator it = aNumInfo.aEmbeddedElements.begin();
1049 it != aNumInfo.aEmbeddedElements.end(); ++it)
1051 pObj = &*it;
1052 if ( pObj->nFormatPos == nFormatPos )
1054 pObj->aText += rContent;
1055 break;
1062 void SvXMLNumFmtElementContext::EndElement()
1064 sal_Bool bEffLong = bLong;
1065 switch (nType)
1067 case XML_TOK_STYLE_TEXT:
1068 if ( rParent.HasLongDoW() &&
1069 aContent.toString().equals(rParent.GetLocaleData().getLongDateDayOfWeekSep()) )
1071 // skip separator constant after long day of week
1072 // (NF_KEY_NNNN contains the separator)
1074 if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) )
1076 aContent = OUStringBuffer();
1079 rParent.SetHasLongDoW( sal_False ); // only once
1081 if ( aContent.getLength() )
1083 lcl_EnquoteIfNecessary( aContent, rParent );
1084 rParent.AddToCode( aContent.makeStringAndClear() );
1086 break;
1088 case XML_TOK_STYLE_NUMBER:
1089 rParent.AddNumber( aNumInfo );
1090 break;
1092 case XML_TOK_STYLE_CURRENCY_SYMBOL:
1093 rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang );
1094 break;
1096 case XML_TOK_STYLE_TEXT_CONTENT:
1097 rParent.AddToCode( (sal_Unicode)'@');
1098 break;
1099 case XML_TOK_STYLE_FILL_CHARACTER:
1100 if ( aContent.getLength() )
1102 rParent.AddToCode( (sal_Unicode)'*' );
1103 rParent.AddToCode( aContent[0] );
1105 break;
1106 case XML_TOK_STYLE_BOOLEAN:
1107 // ignored - only default boolean format is supported
1108 break;
1110 case XML_TOK_STYLE_DAY:
1111 rParent.UpdateCalendar( sCalendar );
1112 //! I18N doesn't provide SYSTEM or extended date information yet
1114 rParent.AddNfKeyword(
1115 sal::static_int_cast< sal_uInt16 >(
1116 bEffLong ? NF_KEY_DD : NF_KEY_D ) );
1117 break;
1118 case XML_TOK_STYLE_MONTH:
1119 rParent.UpdateCalendar( sCalendar );
1120 //! I18N doesn't provide SYSTEM or extended date information yet
1122 rParent.AddNfKeyword(
1123 sal::static_int_cast< sal_uInt16 >(
1124 bTextual
1125 ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM )
1126 : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) );
1127 break;
1128 case XML_TOK_STYLE_YEAR:
1129 rParent.UpdateCalendar( sCalendar );
1130 //! I18N doesn't provide SYSTEM or extended date information yet
1131 // Y after G (era) is replaced by E
1132 if ( rParent.HasEra() )
1133 rParent.AddNfKeyword(
1134 sal::static_int_cast< sal_uInt16 >(
1135 bEffLong ? NF_KEY_EEC : NF_KEY_EC ) );
1136 else
1137 rParent.AddNfKeyword(
1138 sal::static_int_cast< sal_uInt16 >(
1139 bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) );
1140 break;
1141 case XML_TOK_STYLE_ERA:
1142 rParent.UpdateCalendar( sCalendar );
1143 //! I18N doesn't provide SYSTEM or extended date information yet
1144 rParent.AddNfKeyword(
1145 sal::static_int_cast< sal_uInt16 >(
1146 bEffLong ? NF_KEY_GGG : NF_KEY_G ) );
1147 // HasEra flag is set
1148 break;
1149 case XML_TOK_STYLE_DAY_OF_WEEK:
1150 rParent.UpdateCalendar( sCalendar );
1151 //! I18N doesn't provide SYSTEM or extended date information yet
1152 rParent.AddNfKeyword(
1153 sal::static_int_cast< sal_uInt16 >(
1154 bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) );
1155 break;
1156 case XML_TOK_STYLE_WEEK_OF_YEAR:
1157 rParent.UpdateCalendar( sCalendar );
1158 rParent.AddNfKeyword( NF_KEY_WW );
1159 break;
1160 case XML_TOK_STYLE_QUARTER:
1161 rParent.UpdateCalendar( sCalendar );
1162 rParent.AddNfKeyword(
1163 sal::static_int_cast< sal_uInt16 >(
1164 bEffLong ? NF_KEY_QQ : NF_KEY_Q ) );
1165 break;
1166 case XML_TOK_STYLE_HOURS:
1167 rParent.AddNfKeyword(
1168 sal::static_int_cast< sal_uInt16 >(
1169 bEffLong ? NF_KEY_HH : NF_KEY_H ) );
1170 break;
1171 case XML_TOK_STYLE_AM_PM:
1172 //! short/long?
1173 rParent.AddNfKeyword( NF_KEY_AMPM );
1174 break;
1175 case XML_TOK_STYLE_MINUTES:
1176 rParent.AddNfKeyword(
1177 sal::static_int_cast< sal_uInt16 >(
1178 bEffLong ? NF_KEY_MMI : NF_KEY_MI ) );
1179 break;
1180 case XML_TOK_STYLE_SECONDS:
1181 rParent.AddNfKeyword(
1182 sal::static_int_cast< sal_uInt16 >(
1183 bEffLong ? NF_KEY_SS : NF_KEY_S ) );
1184 if ( aNumInfo.nDecimals > 0 )
1186 // manually add the decimal places
1187 rParent.AddToCode(rParent.GetLocaleData().getNumDecimalSep());
1188 for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++)
1190 rParent.AddToCode( (sal_Unicode)'0');
1193 break;
1195 case XML_TOK_STYLE_FRACTION:
1197 if ( aNumInfo.nInteger >= 0 )
1199 // add integer part only if min-integer-digits attribute is there
1200 aNumInfo.nDecimals = 0;
1201 rParent.AddNumber( aNumInfo ); // number without decimals
1202 rParent.AddToCode( (sal_Unicode)' ' );
1205 //! build string and add at once
1207 sal_Int32 i;
1208 for (i=0; i<aNumInfo.nNumerDigits; i++)
1210 rParent.AddToCode( (sal_Unicode)'?' );
1212 rParent.AddToCode( (sal_Unicode)'/' );
1213 if ( aNumInfo.nFracDenominator > 0 )
1215 rParent.AddToCode( OUString::valueOf( aNumInfo.nFracDenominator ) );
1217 else
1219 for (i=0; i<aNumInfo.nDenomDigits; i++)
1221 rParent.AddToCode( (sal_Unicode)'?');
1225 break;
1227 case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
1229 rParent.AddNumber( aNumInfo ); // simple number
1231 rParent.AddToCode( OUString("E+") );
1232 for (sal_Int32 i=0; i<aNumInfo.nExpDigits; i++)
1234 rParent.AddToCode( (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 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 = LanguageTag( sLanguage, sCountry ).getLanguageType( false);
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.append( "[NatNum" );
1384 aFormatCode.append( nNatNum, 10 );
1386 LanguageType eLang = LanguageTag( aNatNumAttr.Locale ).getLanguageType( false);
1387 if ( eLang == LANGUAGE_DONTKNOW )
1388 eLang = LANGUAGE_SYSTEM; //! error handling for invalid locales?
1389 if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM )
1391 aFormatCode.append( "][$-" );
1392 // language code in upper hex:
1393 aFormatCode.append(OUString::valueOf(sal_Int32(eLang), 16).toAsciiUpperCase());
1395 aFormatCode.append( sal_Unicode(']') );
1400 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport,
1401 sal_uInt16 nPrfx, const 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 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_FILL_CHARACTER:
1450 case XML_TOK_STYLE_NUMBER:
1451 case XML_TOK_STYLE_SCIENTIFIC_NUMBER:
1452 case XML_TOK_STYLE_FRACTION:
1453 case XML_TOK_STYLE_CURRENCY_SYMBOL:
1454 case XML_TOK_STYLE_DAY:
1455 case XML_TOK_STYLE_MONTH:
1456 case XML_TOK_STYLE_YEAR:
1457 case XML_TOK_STYLE_ERA:
1458 case XML_TOK_STYLE_DAY_OF_WEEK:
1459 case XML_TOK_STYLE_WEEK_OF_YEAR:
1460 case XML_TOK_STYLE_QUARTER:
1461 case XML_TOK_STYLE_HOURS:
1462 case XML_TOK_STYLE_AM_PM:
1463 case XML_TOK_STYLE_MINUTES:
1464 case XML_TOK_STYLE_SECONDS:
1465 case XML_TOK_STYLE_BOOLEAN:
1466 case XML_TOK_STYLE_TEXT_CONTENT:
1467 pContext = new SvXMLNumFmtElementContext( GetImport(), nPrfx, rLName,
1468 *this, nToken, xAttrList );
1469 break;
1471 case XML_TOK_STYLE_PROPERTIES:
1472 pContext = new SvXMLNumFmtPropContext( GetImport(), nPrfx, rLName,
1473 *this, xAttrList );
1474 break;
1475 case XML_TOK_STYLE_MAP:
1477 // SvXMLNumFmtMapContext::EndElement adds to aMyConditions,
1478 // so there's no need for an extra flag
1479 pContext = new SvXMLNumFmtMapContext( GetImport(), nPrfx, rLName,
1480 *this, xAttrList );
1482 break;
1485 if( !pContext )
1486 pContext = new SvXMLImportContext( GetImport(), nPrfx, rLName );
1487 return pContext;
1490 sal_Int32 SvXMLNumFormatContext::GetKey()
1492 if (nKey > -1)
1494 if (bRemoveAfterUse)
1496 // format is used -> don't remove
1497 bRemoveAfterUse = sal_False;
1498 if (pData)
1499 pData->SetUsed(nKey);
1501 // Add to import's list of keys now - CreateAndInsert didn't add
1502 // the style if bRemoveAfterUse was set.
1503 GetImport().AddNumberStyle( nKey, GetName() );
1505 return nKey;
1507 else
1509 // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set
1510 bRemoveAfterUse = sal_False;
1511 CreateAndInsert(sal_True);
1512 return nKey;
1516 sal_Int32 SvXMLNumFormatContext::PrivateGetKey()
1518 // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag
1520 if (nKey > -1)
1521 return nKey;
1522 else
1524 CreateAndInsert(sal_True);
1525 return nKey;
1529 sal_Int32 SvXMLNumFormatContext::CreateAndInsert( com::sun::star::uno::Reference< com::sun::star::util::XNumberFormatsSupplier >& xFormatsSupplier )
1531 if (nKey <= -1)
1533 SvNumberFormatter* pFormatter = NULL;
1534 SvNumberFormatsSupplierObj* pObj =
1535 SvNumberFormatsSupplierObj::getImplementation( xFormatsSupplier );
1536 if (pObj)
1537 pFormatter = pObj->GetNumberFormatter();
1539 if ( pFormatter )
1540 return CreateAndInsert( pFormatter );
1541 else
1542 return -1;
1544 else
1545 return nKey;
1548 void SvXMLNumFormatContext::CreateAndInsert(sal_Bool /*bOverwrite*/)
1550 if (!(nKey > -1))
1551 CreateAndInsert(pData->GetNumberFormatter());
1554 sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter)
1556 if (!pFormatter)
1558 OSL_FAIL("no number formatter");
1559 return -1;
1562 sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1564 for (sal_uInt32 i = 0; i < aMyConditions.size(); i++)
1566 SvXMLNumFormatContext* pStyle = (SvXMLNumFormatContext *)pStyles->FindStyleChildContext(
1567 XML_STYLE_FAMILY_DATA_STYLE, aMyConditions[i].sMapName, sal_False);
1568 if (pStyle)
1570 if ((pStyle->PrivateGetKey() > -1)) // don't reset pStyle's bRemoveAfterUse flag
1571 AddCondition(i);
1575 if ( !aFormatCode.getLength() )
1577 // insert empty format as empty string (with quotes)
1578 // #93901# this check has to be done before inserting the conditions
1579 aFormatCode.appendAscii("\"\""); // ""
1582 aFormatCode.insert( 0, aConditions.makeStringAndClear() );
1583 OUString sFormat = aFormatCode.makeStringAndClear();
1585 // test special cases
1587 if ( bAutoDec ) // automatic decimal places
1589 // #99391# adjust only if the format contains no text elements, no conditions
1590 // and no color definition (detected by the '[' at the start)
1592 if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
1593 aMyConditions.empty() && sFormat.toChar() != (sal_Unicode)'[' )
1594 nIndex = pFormatter->GetStandardIndex( nFormatLang );
1596 if ( bAutoInt ) // automatic integer digits
1598 //! only if two decimal places was set?
1600 if ( nType == XML_TOK_STYLES_NUMBER_STYLE && !bHasExtraText &&
1601 aMyConditions.empty() && sFormat.toChar() != (sal_Unicode)'[' )
1602 nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang );
1605 // boolean is always the builtin boolean format
1606 // (no other boolean formats are implemented)
1607 if ( nType == XML_TOK_STYLES_BOOLEAN_STYLE )
1608 nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang );
1610 // check for default date formats
1611 if ( nType == XML_TOK_STYLES_DATE_STYLE && bAutoOrder && !bDateNoDefault )
1613 NfIndexTableOffset eFormat = (NfIndexTableOffset) SvXMLNumFmtDefaults::GetDefaultDateFormat(
1614 eDateDOW, eDateDay, eDateMonth, eDateYear,
1615 eDateHours, eDateMins, eDateSecs, bFromSystem );
1616 if ( eFormat < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
1618 // #109651# if a date format has the automatic-order attribute and
1619 // contains exactly the elements of one of the default date formats,
1620 // use that default format, with the element order and separators
1621 // from the current locale settings
1623 nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang );
1627 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && !sFormat.isEmpty() )
1629 // insert by format string
1631 OUString aFormatStr( sFormat );
1632 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1633 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
1635 sal_Int32 nErrPos = 0;
1636 short l_nType = 0;
1637 sal_Bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang );
1638 if ( !bOk && nErrPos == 0 && aFormatStr != sFormat )
1640 // if the string was modified by PutEntry, look for an existing format
1641 // with the modified string
1642 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1643 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1644 bOk = sal_True;
1646 if (!bOk)
1647 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1651 //! I18N doesn't provide SYSTEM or extended date information yet
1652 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder )
1654 // use fixed-order formats instead of SYS... if bAutoOrder is false
1655 // (only if the format strings are equal for the locale)
1657 NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex );
1658 if ( eOffset == NF_DATE_SYS_DMMMYYYY )
1660 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang );
1661 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1662 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1663 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1664 nIndex = nNewIndex;
1666 else if ( eOffset == NF_DATE_SYS_DMMMMYYYY )
1668 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang );
1669 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1670 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1671 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1672 nIndex = nNewIndex;
1676 if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && !sFormatTitle.isEmpty())
1678 SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex ));
1679 if (pFormat)
1681 pFormat->SetComment(sFormatTitle);
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( sal_Unicode c )
1717 aFormatCode.append( c );
1718 bHasExtraText = sal_True;
1721 void SvXMLNumFormatContext::AddToCode( const OUString& rString )
1723 aFormatCode.append( rString );
1724 bHasExtraText = sal_True;
1727 void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo )
1729 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1730 if (!pFormatter)
1731 return;
1733 // store special conditions
1734 bAutoDec = ( rInfo.nDecimals < 0 );
1735 bAutoInt = ( rInfo.nInteger < 0 );
1737 sal_uInt16 nPrec = 0;
1738 sal_uInt16 nLeading = 0;
1739 if ( rInfo.nDecimals >= 0 ) // < 0 : Default
1740 nPrec = (sal_uInt16) rInfo.nDecimals;
1741 if ( rInfo.nInteger >= 0 ) // < 0 : Default
1742 nLeading = (sal_uInt16) rInfo.nInteger;
1744 if ( bAutoDec )
1746 if ( nType == XML_TOK_STYLES_CURRENCY_STYLE )
1748 // for currency formats, "automatic decimals" is used for the automatic
1749 // currency format with (fixed) decimals from the locale settings
1751 const LocaleDataWrapper& rLoc = pData->GetLocaleData( nFormatLang );
1752 nPrec = rLoc.getCurrDigits();
1754 else
1756 // for other types, "automatic decimals" means dynamic determination of
1757 // decimals, as achieved with the "general" keyword
1759 aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) );
1760 return;
1763 if ( bAutoInt )
1765 //!...
1768 sal_uInt16 nGenPrec = nPrec;
1769 if ( rInfo.bDecReplace || rInfo.bVarDecimals )
1770 nGenPrec = 0; // generate format without decimals...
1772 sal_Bool bGrouping = rInfo.bGrouping;
1773 sal_uInt16 nEmbeddedCount = rInfo.aEmbeddedElements.size();
1774 if ( nEmbeddedCount )
1775 bGrouping = sal_False; // grouping and embedded characters can't be used together
1777 sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang );
1778 OUStringBuffer aNumStr = pFormatter->GenerateFormat( nStdIndex, nFormatLang,
1779 bGrouping, sal_False, nGenPrec, nLeading );
1781 if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 )
1783 // #i43959# For scientific numbers, "#" in the integer part forces a digit,
1784 // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0").
1786 aNumStr.stripStart((sal_Unicode)'#');
1789 if ( nEmbeddedCount )
1791 // insert embedded strings into number string
1792 // only the integer part is supported
1793 // nZeroPos is the string position where format position 0 is inserted
1795 sal_Int32 nZeroPos = aNumStr.indexOf( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1796 if ( nZeroPos < 0 )
1798 nZeroPos = aNumStr.getLength();
1801 // aEmbeddedElements is sorted - last entry has the largest position (leftmost)
1802 const SvXMLEmbeddedElement* pLastObj = &*rInfo.aEmbeddedElements.rbegin();
1803 sal_Int32 nLastFormatPos = pLastObj->nFormatPos;
1804 if ( nLastFormatPos >= nZeroPos )
1806 // add '#' characters so all embedded texts are really embedded in digits
1807 // (there always has to be a digit before the leftmost embedded text)
1809 sal_Int32 nAddCount = nLastFormatPos + 1 - nZeroPos;
1810 for(sal_Int32 index = 0; index < nAddCount; ++index)
1812 aNumStr.insert(0, (sal_Unicode)'#');
1814 nZeroPos = nZeroPos + nAddCount;
1817 // aEmbeddedElements is sorted with ascending positions - loop is from right to left
1818 for (SvXMLEmbeddedElementArr::const_iterator it = rInfo.aEmbeddedElements.begin();
1819 it != rInfo.aEmbeddedElements.end(); ++it)
1821 const SvXMLEmbeddedElement* pObj = &*it;
1822 sal_Int32 nFormatPos = pObj->nFormatPos;
1823 sal_Int32 nInsertPos = nZeroPos - nFormatPos;
1824 if ( nFormatPos >= 0 && nInsertPos >= 0 )
1826 // #107805# always quote embedded strings - even space would otherwise
1827 // be recognized as thousands separator in French.
1829 aNumStr.insert(nInsertPos, '"');
1830 aNumStr.insert(nInsertPos, pObj->aText);
1831 aNumStr.insert(nInsertPos, '"');
1836 aFormatCode.append( aNumStr.makeStringAndClear() );
1838 if ( ( rInfo.bDecReplace || rInfo.bVarDecimals ) && nPrec ) // add decimal replacement (dashes)
1840 // add dashes for explicit decimal replacement, # for variable decimals
1841 sal_Unicode cAdd = rInfo.bDecReplace ? '-' : '#';
1843 aFormatCode.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1844 for ( sal_uInt16 i=0; i<nPrec; i++)
1845 aFormatCode.append( cAdd );
1848 // add extra thousands separators for display factor
1850 if ( rInfo.fDisplayFactor != 1.0 && rInfo.fDisplayFactor > 0.0 )
1852 // test for 1.0 is just for optimization - nSepCount would be 0
1854 // one separator for each factor of 1000
1855 sal_Int32 nSepCount = (sal_Int32) ::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 );
1856 if ( nSepCount > 0 )
1858 OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep();
1859 for ( sal_Int32 i=0; i<nSepCount; i++ )
1860 aFormatCode.append( aSep );
1865 void SvXMLNumFormatContext::AddCurrency( const OUString& rContent, LanguageType nLang )
1867 sal_Bool bAutomatic = sal_False;
1868 OUString aSymbol = rContent;
1869 if ( aSymbol.isEmpty())
1871 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1872 if ( pFormatter )
1874 pFormatter->ChangeIntl( nFormatLang );
1875 OUString sCurString, sDummy;
1876 pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
1877 aSymbol = sCurString;
1879 bAutomatic = sal_True;
1882 else if ( nLang == LANGUAGE_SYSTEM && aSymbol.compareToAscii("CCC") == 0 )
1884 // "CCC" is used for automatic long symbol
1885 bAutomatic = sal_True;
1888 if ( bAutomatic )
1890 // remove unnecessary quotes before automatic symbol (formats like "-(0DM)")
1891 // otherwise the currency symbol isn't recognized (#94048#)
1893 sal_Int32 nLength = aFormatCode.getLength();
1894 if ( nLength > 1 && aFormatCode[nLength - 1] == '"' )
1896 // find start of quoted string
1897 // When SvXMLNumFmtElementContext::EndElement creates escaped quotes,
1898 // they must be handled here, too.
1900 sal_Int32 nFirst = nLength - 2;
1901 while ( nFirst >= 0 && aFormatCode[nFirst] != '"' )
1902 --nFirst;
1903 if ( nFirst >= 0 )
1905 // remove both quotes from aFormatCode
1906 OUString aOld = aFormatCode.makeStringAndClear();
1907 if ( nFirst > 0 )
1908 aFormatCode.append( aOld.copy( 0, nFirst ) );
1909 if ( nLength > nFirst + 2 )
1910 aFormatCode.append( aOld.copy( nFirst + 1, nLength - nFirst - 2 ) );
1915 if (!bAutomatic)
1916 aFormatCode.appendAscii( "[$" ); // intro for "new" currency symbols
1918 aFormatCode.append( aSymbol );
1920 if (!bAutomatic)
1922 if ( nLang != LANGUAGE_SYSTEM )
1924 // '-' sign and language code in hex:
1925 aFormatCode.append( (sal_Unicode) '-' );
1926 aFormatCode.append(OUString::valueOf(sal_Int32(nLang), 16).toAsciiUpperCase());
1929 aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbol
1933 void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex )
1935 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1936 if (!pFormatter)
1937 return;
1939 if ( nIndex == NF_KEY_G || nIndex == NF_KEY_GG || nIndex == NF_KEY_GGG )
1940 bHasEra = sal_True;
1942 if ( nIndex == NF_KEY_NNNN )
1944 nIndex = NF_KEY_NNN;
1945 bHasLongDoW = sal_True; // to remove string constant with separator
1948 OUString sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex );
1950 if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH ||
1951 nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI ||
1952 nIndex == NF_KEY_S || nIndex == NF_KEY_SS )
1954 if ( !bTruncate && !bHasDateTime )
1956 // with truncate-on-overflow = false, add "[]" to first time part
1957 aFormatCode.append( (sal_Unicode)'[' );
1958 aFormatCode.append( sKeyword );
1959 aFormatCode.append( (sal_Unicode)']' );
1961 else
1963 aFormatCode.append( sKeyword );
1965 bHasDateTime = sal_True;
1967 else
1969 aFormatCode.append( sKeyword );
1971 // collect the date elements that the format contains, to recognize default date formats
1972 switch ( nIndex )
1974 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
1975 case NF_KEY_NNN:
1976 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
1977 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
1978 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
1979 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
1980 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
1981 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
1982 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
1983 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
1984 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
1985 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
1986 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
1987 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
1988 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
1989 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
1990 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
1991 case NF_KEY_AP:
1992 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1993 default:
1994 bDateNoDefault = sal_True; // any other element -> no default format
1998 static sal_Bool lcl_IsAtEnd( OUStringBuffer& rBuffer, const OUString& rToken )
2000 sal_Int32 nBufLen = rBuffer.getLength();
2001 sal_Int32 nTokLen = rToken.getLength();
2003 if ( nTokLen > nBufLen )
2004 return sal_False;
2006 sal_Int32 nStartPos = nBufLen - nTokLen;
2007 for ( sal_Int32 nTokPos = 0; nTokPos < nTokLen; nTokPos++ )
2008 if ( rToken[ nTokPos ] != rBuffer[nStartPos + nTokPos] )
2009 return sal_False;
2011 return sal_True;
2014 sal_Bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew )
2016 // replaces one keyword with another if it is found at the end of the code
2018 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2019 if (!pFormatter)
2020 return sal_False;
2022 OUString sOldStr = pFormatter->GetKeyword( nFormatLang, nOld );
2023 if ( lcl_IsAtEnd( aFormatCode, sOldStr ) )
2025 // remove old keyword
2026 aFormatCode.setLength( aFormatCode.getLength() - sOldStr.getLength() );
2028 // add new keyword
2029 OUString sNewStr = pFormatter->GetKeyword( nFormatLang, nNew );
2030 aFormatCode.append( sNewStr );
2032 return sal_True; // changed
2034 return sal_False; // not found
2037 void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex )
2039 OUString rApplyName = aMyConditions[nIndex].sMapName;
2040 OUString rCondition = aMyConditions[nIndex].sCondition;
2041 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2042 sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName );
2043 OUString sValue("value()"); //! define constant
2044 sal_Int32 nValLen = sValue.getLength();
2046 if ( pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND &&
2047 rCondition.copy( 0, nValLen ) == sValue )
2049 //! test for valid conditions
2050 //! test for default conditions
2052 OUString sRealCond = rCondition.copy( nValLen, rCondition.getLength() - nValLen );
2053 sal_Bool bDefaultCond = sal_False;
2055 //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count
2056 //! allow blanks in conditions
2057 sal_Bool bFirstCond = ( aConditions.getLength() == 0 );
2058 if ( bFirstCond && aMyConditions.size() == 1 && sRealCond.compareToAscii( ">=0" ) == 0 )
2059 bDefaultCond = sal_True;
2061 if ( nType == XML_TOK_STYLES_TEXT_STYLE && nIndex == 2 )
2063 // The third condition in a number format with a text part can only be
2064 // "all other numbers", the condition string must be empty.
2065 bDefaultCond = sal_True;
2068 if (!bDefaultCond)
2070 // Convert != to <>
2071 sal_Int32 nPos = sRealCond.indexOf( "!=" );
2072 if ( nPos >= 0 )
2074 sRealCond = sRealCond.replaceAt( nPos, 2, "<>" );
2077 nPos = sRealCond.indexOf( '.' );
2078 if ( nPos >= 0 )
2080 // #i8026# #103991# localize decimal separator
2081 const OUString& rDecSep = GetLocaleData().getNumDecimalSep();
2082 if ( rDecSep.getLength() > 1 || rDecSep[0] != '.' )
2084 sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
2087 aConditions.append( (sal_Unicode) '[' );
2088 aConditions.append( sRealCond );
2089 aConditions.append( (sal_Unicode) ']' );
2092 const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey);
2093 if ( pFormat )
2094 aConditions.append( OUString( pFormat->GetFormatstring() ) );
2096 aConditions.append( (sal_Unicode) ';' );
2100 void SvXMLNumFormatContext::AddCondition( const OUString& rCondition, const OUString& rApplyName )
2102 MyCondition aCondition;
2103 aCondition.sCondition = rCondition;
2104 aCondition.sMapName = rApplyName;
2105 aMyConditions.push_back(aCondition);
2108 void SvXMLNumFormatContext::AddColor( sal_uInt32 const nColor )
2110 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2111 if (!pFormatter)
2112 return;
2114 OUStringBuffer aColName;
2115 for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ )
2116 if (nColor == aNumFmtStdColors[i])
2118 aColName = OUString( pFormatter->GetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ) );
2119 break;
2122 if ( aColName.getLength() )
2124 aColName.insert( 0, (sal_Unicode) '[' );
2125 aColName.append( (sal_Unicode) ']' );
2126 aFormatCode.insert( 0, aColName.makeStringAndClear() );
2130 void SvXMLNumFormatContext::UpdateCalendar( const OUString& rNewCalendar )
2132 if ( rNewCalendar != sCalendar )
2134 sCalendar = rNewCalendar;
2135 if ( !sCalendar.isEmpty() )
2137 aFormatCode.appendAscii( "[~" ); // intro for calendar code
2138 aFormatCode.append( sCalendar );
2139 aFormatCode.append( (sal_Unicode) ']' ); // end of "new" currency symbolcalendar code
2144 sal_Bool SvXMLNumFormatContext::IsSystemLanguage()
2146 return nFormatLang == LANGUAGE_SYSTEM;
2149 //-------------------------------------------------------------------------
2152 // SvXMLNumFmtHelper
2155 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2156 const uno::Reference<util::XNumberFormatsSupplier>& rSupp,
2157 const uno::Reference<uno::XComponentContext>& rxContext )
2159 DBG_ASSERT( rxContext.is(), "got no service manager" );
2161 SvNumberFormatter* pFormatter = NULL;
2162 SvNumberFormatsSupplierObj* pObj =
2163 SvNumberFormatsSupplierObj::getImplementation( rSupp );
2164 if (pObj)
2165 pFormatter = pObj->GetNumberFormatter();
2167 pData = new SvXMLNumImpData( pFormatter, rxContext );
2170 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2171 SvNumberFormatter* pNumberFormatter,
2172 const uno::Reference<uno::XComponentContext>& rxContext )
2174 DBG_ASSERT( rxContext.is(), "got no service manager" );
2176 pData = new SvXMLNumImpData( pNumberFormatter, rxContext );
2179 SvXMLNumFmtHelper::~SvXMLNumFmtHelper()
2181 // remove temporary (volatile) formats from NumberFormatter
2182 pData->RemoveVolatileFormats();
2184 delete pData;
2187 SvXMLStyleContext* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport,
2188 sal_uInt16 nPrefix, const OUString& rLocalName,
2189 const uno::Reference<xml::sax::XAttributeList>& xAttrList,
2190 SvXMLStylesContext& rStyles )
2192 SvXMLStyleContext* pContext = NULL;
2194 const SvXMLTokenMap& rTokenMap = pData->GetStylesElemTokenMap();
2195 sal_uInt16 nToken = rTokenMap.Get( nPrefix, rLocalName );
2196 switch (nToken)
2198 case XML_TOK_STYLES_NUMBER_STYLE:
2199 case XML_TOK_STYLES_CURRENCY_STYLE:
2200 case XML_TOK_STYLES_PERCENTAGE_STYLE:
2201 case XML_TOK_STYLES_DATE_STYLE:
2202 case XML_TOK_STYLES_TIME_STYLE:
2203 case XML_TOK_STYLES_BOOLEAN_STYLE:
2204 case XML_TOK_STYLES_TEXT_STYLE:
2205 pContext = new SvXMLNumFormatContext( rImport, nPrefix, rLocalName,
2206 pData, nToken, xAttrList, rStyles );
2207 break;
2210 // return NULL if not a data style, caller must handle other elements
2211 return pContext;
2214 const SvXMLTokenMap& SvXMLNumFmtHelper::GetStylesElemTokenMap()
2216 return pData->GetStylesElemTokenMap();
2219 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */