1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
20 #include <svl/zforlist.hxx>
21 #include <svl/numformat.hxx>
22 #include <svl/zformat.hxx>
23 #include <svl/numuno.hxx>
24 #include <i18nlangtag/languagetag.hxx>
25 #include <tools/color.hxx>
26 #include <osl/diagnose.h>
27 #include <rtl/math.hxx>
28 #include <rtl/ustrbuf.hxx>
29 #include <sal/log.hxx>
31 #include <sax/tools/converter.hxx>
34 #include <xmloff/xmlement.hxx>
35 #include <xmloff/xmlnumfi.hxx>
36 #include <xmloff/xmltkmap.hxx>
37 #include <xmloff/xmlnamespace.hxx>
38 #include <xmloff/xmlictxt.hxx>
39 #include <xmloff/xmlimp.hxx>
40 #include <xmloff/xmluconv.hxx>
41 #include <xmloff/namespacemap.hxx>
42 #include <xmloff/families.hxx>
43 #include <xmloff/xmltoken.hxx>
44 #include <xmloff/languagetagodf.hxx>
47 #include <string_view>
50 using namespace ::com::sun::star
;
51 using namespace ::xmloff::token
;
55 struct SvXMLNumFmtEntry
61 SvXMLNumFmtEntry( OUString aN
, sal_uInt32 nK
, bool bR
) :
62 aName(std::move(aN
)), nKey(nK
), bRemoveAfterUse(bR
) {}
69 SvNumberFormatter
* pFormatter
;
70 std::unique_ptr
<LocaleDataWrapper
> pLocaleData
;
71 std::vector
<SvXMLNumFmtEntry
> m_NameEntries
;
73 uno::Reference
< uno::XComponentContext
> m_xContext
;
77 SvNumberFormatter
* pFmt
,
78 const uno::Reference
<uno::XComponentContext
>& rxContext
);
80 SvNumberFormatter
* GetNumberFormatter() const { return pFormatter
; }
81 const LocaleDataWrapper
& GetLocaleData( LanguageType nLang
);
82 sal_uInt32
GetKeyForName( std::u16string_view rName
);
83 void AddKey( sal_uInt32 nKey
, const OUString
& rName
, bool bRemoveAfterUse
);
84 void SetUsed( sal_uInt32 nKey
);
85 void RemoveVolatileFormats();
88 struct SvXMLNumberInfo
90 sal_Int32 nDecimals
= -1;
91 sal_Int32 nInteger
= -1; /// Total min number of digits in integer part ('0' + '?')
92 sal_Int32 nBlankInteger
= -1; /// Number of '?' in integer part
93 sal_Int32 nExpDigits
= -1; /// Number of '0' and '?' in exponent
94 sal_Int32 nBlankExp
= -1; /// Number of '?' in exponent
95 sal_Int32 nExpInterval
= -1;
96 sal_Int32 nMinNumerDigits
= -1;
97 sal_Int32 nMinDenomDigits
= -1;
98 sal_Int32 nMaxNumerDigits
= -1;
99 sal_Int32 nMaxDenomDigits
= -1;
100 sal_Int32 nFracDenominator
= -1;
101 sal_Int32 nMinDecimalDigits
= -1;
102 sal_Int32 nZerosNumerDigits
= -1;
103 sal_Int32 nZerosDenomDigits
= -1;
104 bool bGrouping
= false;
105 bool bDecReplace
= false;
106 bool bExpSign
= true;
107 bool bExponentLowercase
= false; /// Exponent is 'e' instead of 'E'
108 bool bDecAlign
= false;
109 double fDisplayFactor
= 1.0;
110 OUString aIntegerFractionDelimiter
;
111 std::map
<sal_Int32
, OUString
> m_EmbeddedElements
;
116 enum class SvXMLStyleTokens
;
118 class SvXMLNumFmtElementContext
: public SvXMLImportContext
120 SvXMLNumFormatContext
& rParent
;
121 SvXMLStyleTokens nType
;
122 OUStringBuffer aContent
;
123 SvXMLNumberInfo aNumInfo
;
124 LanguageType nElementLang
;
128 OUString sBlankWidthString
;
131 SvXMLNumFmtElementContext( SvXMLImport
& rImport
, sal_Int32 nElement
,
132 SvXMLNumFormatContext
& rParentContext
, SvXMLStyleTokens nNewType
,
133 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
);
135 virtual css::uno::Reference
< css::xml::sax::XFastContextHandler
> SAL_CALL
createFastChildContext(
136 sal_Int32 nElement
, const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& AttrList
) override
;
137 virtual void SAL_CALL
characters( const OUString
& rChars
) override
;
138 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
140 void AddEmbeddedElement( sal_Int32 nFormatPos
, std::u16string_view rContent
, std::u16string_view rBlankWidthString
);
143 class SvXMLNumFmtEmbeddedTextContext
: public SvXMLImportContext
145 SvXMLNumFmtElementContext
& rParent
;
146 OUStringBuffer aContent
;
147 sal_Int32 nTextPosition
;
148 OUString aBlankWidthString
;
151 SvXMLNumFmtEmbeddedTextContext( SvXMLImport
& rImport
, sal_Int32 nElement
,
152 SvXMLNumFmtElementContext
& rParentContext
,
153 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
);
155 virtual void SAL_CALL
characters( const OUString
& rChars
) override
;
156 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
159 class SvXMLNumFmtMapContext
: public SvXMLImportContext
161 SvXMLNumFormatContext
& rParent
;
166 SvXMLNumFmtMapContext( SvXMLImport
& rImport
, sal_Int32 nElement
,
167 SvXMLNumFormatContext
& rParentContext
,
168 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
);
170 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
173 class SvXMLNumFmtPropContext
: public SvXMLImportContext
175 SvXMLNumFormatContext
& rParent
;
180 SvXMLNumFmtPropContext( SvXMLImport
& rImport
, sal_Int32 nElement
,
181 SvXMLNumFormatContext
& rParentContext
,
182 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
);
184 virtual void SAL_CALL
endFastElement(sal_Int32 nElement
) override
;
187 enum class SvXMLStyleTokens
215 #define XML_NUMF_COLORCOUNT 10
217 const Color aNumFmtStdColors
[XML_NUMF_COLORCOUNT
] =
235 // maps for SvXMLUnitConverter::convertEnum
237 const SvXMLEnumMapEntry
<bool> aStyleValueMap
[] =
239 { XML_SHORT
, false },
241 { XML_TOKEN_INVALID
, false }
244 const SvXMLEnumMapEntry
<bool> aFormatSourceMap
[] =
246 { XML_FIXED
, false },
247 { XML_LANGUAGE
, true },
248 { XML_TOKEN_INVALID
, false }
253 struct SvXMLDefaultDateFormat
255 NfIndexTableOffset eFormat
;
256 SvXMLDateElementAttributes eDOW
;
257 SvXMLDateElementAttributes eDay
;
258 SvXMLDateElementAttributes eMonth
;
259 SvXMLDateElementAttributes eYear
;
260 SvXMLDateElementAttributes eHours
;
261 SvXMLDateElementAttributes eMins
;
262 SvXMLDateElementAttributes eSecs
;
268 const SvXMLDefaultDateFormat aDefaultDateFormats
[] =
270 // format day-of-week day month year hours minutes seconds format-source
272 { 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
, true },
273 { 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
, true },
274 { 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
, false },
275 { 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
, false },
276 { 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
, false },
277 { 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
, false },
278 { 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
, false },
279 { 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
, false },
280 { 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
, false },
281 { 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
, false },
282 { 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
, false },
283 { 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
, false },
284 { NF_DATETIME_SYS_DDMMYYYY_HHMM
, XML_DEA_NONE
, XML_DEA_ANY
, XML_DEA_ANY
, XML_DEA_LONG
, XML_DEA_ANY
, XML_DEA_ANY
, XML_DEA_NONE
, false },
285 { 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
, true },
286 { 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
, false }
293 SvXMLNumImpData::SvXMLNumImpData(
294 SvNumberFormatter
* pFmt
,
295 const uno::Reference
<uno::XComponentContext
>& rxContext
)
297 m_xContext(rxContext
)
299 SAL_WARN_IF( !rxContext
.is(), "xmloff", "got no service manager" );
302 sal_uInt32
SvXMLNumImpData::GetKeyForName( std::u16string_view rName
)
304 for (const auto& rObj
: m_NameEntries
)
306 if (rObj
.aName
== rName
)
307 return rObj
.nKey
; // found
309 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
312 void SvXMLNumImpData::AddKey( sal_uInt32 nKey
, const OUString
& rName
, bool bRemoveAfterUse
)
314 if ( bRemoveAfterUse
)
316 // if there is already an entry for this key without the bRemoveAfterUse flag,
317 // clear the flag for this entry, too
319 for (const auto& rObj
: m_NameEntries
)
321 if (rObj
.nKey
== nKey
&& !rObj
.bRemoveAfterUse
)
323 bRemoveAfterUse
= false; // clear flag for new entry
330 // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key
334 m_NameEntries
.emplace_back(rName
, nKey
, bRemoveAfterUse
);
337 void SvXMLNumImpData::SetUsed( sal_uInt32 nKey
)
339 for (auto& rObj
: m_NameEntries
)
341 if (rObj
.nKey
== nKey
)
343 rObj
.bRemoveAfterUse
= false; // used -> don't remove
345 // continue searching - there may be several entries for the same key
346 // (with different names), the format must not be deleted if any one of
352 void SvXMLNumImpData::RemoveVolatileFormats()
354 // remove temporary (volatile) formats from NumberFormatter
355 // called at the end of each import (styles and content), so volatile formats
356 // from styles can't be used in content
361 for (const auto& rObj
: m_NameEntries
)
363 if (rObj
.bRemoveAfterUse
)
365 const SvNumberformat
* pFormat
= pFormatter
->GetEntry(rObj
.nKey
);
366 if (pFormat
&& (pFormat
->GetType() & SvNumFormatType::DEFINED
))
367 pFormatter
->DeleteEntry(rObj
.nKey
);
372 const LocaleDataWrapper
& SvXMLNumImpData::GetLocaleData( LanguageType nLang
)
374 if ( !pLocaleData
|| pLocaleData
->getLanguageTag() != LanguageTag(nLang
) )
375 pLocaleData
= std::make_unique
<LocaleDataWrapper
>(
376 pFormatter
? pFormatter
->GetComponentContext() : m_xContext
,
377 LanguageTag( nLang
) );
382 // SvXMLNumFmtMapContext
385 SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport
& rImport
,
386 sal_Int32
/*nElement*/,
387 SvXMLNumFormatContext
& rParentContext
,
388 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) :
389 SvXMLImportContext( rImport
),
390 rParent( rParentContext
)
392 for( auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
) )
394 OUString sValue
= aIter
.toString();
395 switch(aIter
.getToken())
397 case XML_ELEMENT(STYLE
, XML_CONDITION
):
400 case XML_ELEMENT(STYLE
, XML_APPLY_STYLE_NAME
):
404 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
409 void SvXMLNumFmtMapContext::endFastElement(sal_Int32
)
411 rParent
.AddCondition( sCondition
, sName
);
415 // SvXMLNumFmtPropContext
418 SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport
& rImport
,
419 sal_Int32
/*nElement*/,
420 SvXMLNumFormatContext
& rParentContext
,
421 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) :
422 SvXMLImportContext( rImport
),
423 rParent( rParentContext
),
427 for( auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
) )
429 switch ( aIter
.getToken())
431 case XML_ELEMENT(FO
, XML_COLOR
):
432 case XML_ELEMENT(FO_COMPAT
, XML_COLOR
):
433 bColSet
= ::sax::Converter::convertColor( m_nColor
, aIter
.toView() );
436 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
441 void SvXMLNumFmtPropContext::endFastElement(sal_Int32
)
444 rParent
.AddColor( m_nColor
);
448 // SvXMLNumFmtEmbeddedTextContext
451 SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport
& rImport
,
452 sal_Int32
/*nElement*/,
453 SvXMLNumFmtElementContext
& rParentContext
,
454 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) :
455 SvXMLImportContext( rImport
),
456 rParent( rParentContext
),
461 for( auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
) )
463 if ( aIter
.getToken() == XML_ELEMENT(NUMBER
, XML_POSITION
) )
465 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView() ))
466 nTextPosition
= nAttrVal
;
468 else if ( aIter
.getToken() == XML_ELEMENT(LO_EXT
, XML_BLANK_WIDTH_CHAR
)
469 || aIter
.getToken() == XML_ELEMENT(NUMBER
, XML_BLANK_WIDTH_CHAR
) )
471 aBlankWidthString
= aIter
.toString();
474 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
478 void SvXMLNumFmtEmbeddedTextContext::characters( const OUString
& rChars
)
480 aContent
.append( rChars
);
483 void SvXMLNumFmtEmbeddedTextContext::endFastElement(sal_Int32
)
485 rParent
.AddEmbeddedElement( nTextPosition
, aContent
.makeStringAndClear(), aBlankWidthString
);
488 static bool lcl_ValidChar( sal_Unicode cChar
, const SvXMLNumFormatContext
& rParent
)
490 SvXMLStylesTokens nFormatType
= rParent
.GetType();
492 // Treat space equal to non-breaking space separator.
493 const sal_Unicode cNBSP
= 0x00A0;
495 if ( ( nFormatType
== SvXMLStylesTokens::NUMBER_STYLE
||
496 nFormatType
== SvXMLStylesTokens::CURRENCY_STYLE
||
497 nFormatType
== SvXMLStylesTokens::PERCENTAGE_STYLE
) &&
498 (cChar
== (cTS
= rParent
.GetLocaleData().getNumThousandSep()[0]) ||
499 (cChar
== ' ' && cTS
== cNBSP
)) )
501 // #i22394# Extra occurrences of thousands separator must be quoted, so they
502 // aren't mis-interpreted as display-factor.
503 // This must be limited to the format types that can contain a number element,
504 // because the same character can be a date separator that should not be quoted
507 return false; // force quotes
510 // see ImpSvNumberformatScan::Next_Symbol
512 // All format types except BOOLEAN may contain minus sign or delimiter.
514 return nFormatType
!= SvXMLStylesTokens::BOOLEAN_STYLE
;
516 if ( ( cChar
== ' ' ||
522 ( nFormatType
== SvXMLStylesTokens::CURRENCY_STYLE
||
523 nFormatType
== SvXMLStylesTokens::DATE_STYLE
||
524 nFormatType
== SvXMLStylesTokens::TIME_STYLE
) ) // other formats do not require delimiter tdf#97837
527 // percent sign must be used without quotes for percentage styles only
528 if ( nFormatType
== SvXMLStylesTokens::PERCENTAGE_STYLE
&& cChar
== '%' )
531 // don't put quotes around single parentheses (often used for negative numbers)
532 if ( ( nFormatType
== SvXMLStylesTokens::NUMBER_STYLE
||
533 nFormatType
== SvXMLStylesTokens::CURRENCY_STYLE
||
534 nFormatType
== SvXMLStylesTokens::PERCENTAGE_STYLE
) &&
535 ( cChar
== '(' || cChar
== ')' ) )
541 static void lcl_EnquoteIfNecessary( OUStringBuffer
& rContent
, const SvXMLNumFormatContext
& rParent
)
544 sal_Int32 nLength
= rContent
.getLength();
545 const SvXMLStylesTokens nFormatType
= rParent
.GetType();
547 if (nFormatType
!= SvXMLStylesTokens::BOOLEAN_STYLE
&&
548 ((nLength
== 1 && lcl_ValidChar( rContent
[0], rParent
)) ||
550 ((rContent
[0] == ' ' && rContent
[1] == '-') ||
551 (rContent
[1] == ' ' && lcl_ValidChar( rContent
[0], rParent
))))))
553 // Don't quote single separator characters like space or percent,
554 // or separator characters followed by space (used in date formats).
555 // Or space followed by minus (used in currency formats) that would
556 // lead to almost duplicated formats with built-in formats just with
557 // the difference of quotes.
560 else if ( nFormatType
== SvXMLStylesTokens::PERCENTAGE_STYLE
&& nLength
> 1 )
562 // the percent character in percentage styles must be left out of quoting
563 // (one occurrence is enough even if there are several percent characters in the string)
565 sal_Int32 nPos
= rContent
.indexOf( '%' );
568 if ( nPos
+ 1 < nLength
)
570 if ( nPos
+ 2 == nLength
&& lcl_ValidChar( rContent
[nPos
+ 1], rParent
) )
572 // single character that doesn't need quoting
576 // quote text behind percent character
577 rContent
.insert( nPos
+ 1, '"' );
578 rContent
.append( '"' );
583 if ( nPos
== 1 && lcl_ValidChar( rContent
[0], rParent
) )
585 // single character that doesn't need quoting
589 // quote text before percent character
590 rContent
.insert( nPos
, '"' );
591 rContent
.insert( 0, '"' );
596 // else: normal quoting (below)
602 // #i55469# quotes in the string itself have to be escaped
603 bool bEscape
= ( rContent
.indexOf( '"' ) >= 0 );
606 // A quote is turned into "\"" - a quote to end quoted text, an escaped quote,
607 // and a quote to resume quoting.
608 OUString
aInsert( "\"\\\"" );
611 while ( nPos
< rContent
.getLength() )
613 if ( rContent
[nPos
] == '"' )
615 rContent
.insert( nPos
, aInsert
);
616 nPos
+= aInsert
.getLength();
622 // quote string literals
623 rContent
.insert( 0, '"' );
624 rContent
.append( '"' );
626 // remove redundant double quotes at start or end
630 if ( rContent
.getLength() > 2 &&
631 rContent
[0] == '"' &&
634 rContent
.remove(0, 2);
637 sal_Int32 nLen
= rContent
.getLength();
639 rContent
[nLen
- 1] == '"' &&
640 rContent
[nLen
- 2] == '"' )
642 rContent
.truncate(nLen
- 2);
647 // SvXMLNumFmtElementContext
650 SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport
& rImport
,
651 sal_Int32
/*nElement*/,
652 SvXMLNumFormatContext
& rParentContext
, SvXMLStyleTokens nNewType
,
653 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
) :
654 SvXMLImportContext( rImport
),
655 rParent( rParentContext
),
657 nElementLang( LANGUAGE_SYSTEM
),
661 LanguageTagODF aLanguageTagODF
;
663 bool bAttrBool(false);
664 bool bVarDecimals
= false;
665 bool bIsMaxDenominator
= false;
668 for( auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
) )
670 switch (aIter
.getToken())
672 case XML_ELEMENT(NUMBER
, XML_DECIMAL_PLACES
):
673 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
675 // fdo#58539 & gnome#627420: limit number of digits during import
676 aNumInfo
.nDecimals
= std::min
<sal_Int32
>(nAttrVal
, NF_MAX_FORMAT_SYMBOLS
);
679 case XML_ELEMENT(LO_EXT
, XML_MIN_DECIMAL_PLACES
):
680 case XML_ELEMENT(NUMBER
, XML_MIN_DECIMAL_PLACES
):
681 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
682 aNumInfo
.nMinDecimalDigits
= nAttrVal
;
684 case XML_ELEMENT(NUMBER
, XML_MIN_INTEGER_DIGITS
):
685 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
686 aNumInfo
.nInteger
= nAttrVal
;
688 case XML_ELEMENT(LO_EXT
, XML_MAX_BLANK_INTEGER_DIGITS
):
689 case XML_ELEMENT(NUMBER
, XML_MAX_BLANK_INTEGER_DIGITS
):
690 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
691 aNumInfo
.nBlankInteger
= nAttrVal
;
693 case XML_ELEMENT(NUMBER
, XML_GROUPING
):
694 if (::sax::Converter::convertBool( bAttrBool
, aIter
.toView() ))
695 aNumInfo
.bGrouping
= bAttrBool
;
697 case XML_ELEMENT(NUMBER
, XML_DISPLAY_FACTOR
):
698 if (::sax::Converter::convertDouble( fAttrDouble
, aIter
.toView() ))
699 aNumInfo
.fDisplayFactor
= fAttrDouble
;
701 case XML_ELEMENT(NUMBER
, XML_DECIMAL_REPLACEMENT
):
702 if ( aIter
.toView() == " " )
704 aNumInfo
.bDecAlign
= true; // space replacement for "?"
708 if ( aIter
.isEmpty() )
709 bVarDecimals
= true; // empty replacement string: variable decimals
710 else // all other strings
711 aNumInfo
.bDecReplace
= true; // decimal replacement with dashes
713 case XML_ELEMENT(NUMBER
, XML_MIN_EXPONENT_DIGITS
):
714 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
715 aNumInfo
.nExpDigits
= std::min
<sal_Int32
>(nAttrVal
, NF_MAX_FORMAT_SYMBOLS
);
717 case XML_ELEMENT(NUMBER
, XML_BLANK_EXPONENT_DIGITS
):
718 case XML_ELEMENT(LO_EXT
, XML_BLANK_EXPONENT_DIGITS
):
719 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
720 aNumInfo
.nBlankExp
= std::min
<sal_Int32
>(nAttrVal
, NF_MAX_FORMAT_SYMBOLS
);
722 case XML_ELEMENT(NUMBER
, XML_EXPONENT_INTERVAL
):
723 case XML_ELEMENT(LO_EXT
, XML_EXPONENT_INTERVAL
):
724 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
725 aNumInfo
.nExpInterval
= nAttrVal
;
727 case XML_ELEMENT(NUMBER
, XML_FORCED_EXPONENT_SIGN
):
728 case XML_ELEMENT(LO_EXT
, XML_FORCED_EXPONENT_SIGN
):
729 if (::sax::Converter::convertBool( bAttrBool
, aIter
.toView() ))
730 aNumInfo
.bExpSign
= bAttrBool
;
732 case XML_ELEMENT(NUMBER
, XML_EXPONENT_LOWERCASE
):
733 case XML_ELEMENT(LO_EXT
, XML_EXPONENT_LOWERCASE
):
734 if (::sax::Converter::convertBool( bAttrBool
, aIter
.toView() ))
735 aNumInfo
.bExponentLowercase
= bAttrBool
;
737 case XML_ELEMENT(NUMBER
, XML_MIN_NUMERATOR_DIGITS
):
738 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
739 aNumInfo
.nMinNumerDigits
= nAttrVal
;
741 case XML_ELEMENT(NUMBER
, XML_MIN_DENOMINATOR_DIGITS
):
742 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
743 aNumInfo
.nMinDenomDigits
= nAttrVal
;
745 case XML_ELEMENT(LO_EXT
, XML_MAX_NUMERATOR_DIGITS
):
746 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 1 )) // at least one '#'
747 aNumInfo
.nMaxNumerDigits
= nAttrVal
;
749 case XML_ELEMENT(NUMBER
, XML_DENOMINATOR_VALUE
):
750 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 1 )) // 0 is not valid
752 aNumInfo
.nFracDenominator
= nAttrVal
;
753 bIsMaxDenominator
= false;
756 case XML_ELEMENT(NUMBER
, XML_MAX_DENOMINATOR_VALUE
): // part of ODF 1.3
757 case XML_ELEMENT(LO_EXT
, XML_MAX_DENOMINATOR_VALUE
):
758 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 1 ) && aNumInfo
.nFracDenominator
<= 0)
759 { // if denominator value not yet defined
760 aNumInfo
.nFracDenominator
= nAttrVal
;
761 bIsMaxDenominator
= true;
764 case XML_ELEMENT(LO_EXT
, XML_ZEROS_NUMERATOR_DIGITS
):
765 case XML_ELEMENT(NUMBER
, XML_ZEROS_NUMERATOR_DIGITS
):
766 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
767 aNumInfo
.nZerosNumerDigits
= nAttrVal
;
769 case XML_ELEMENT(NUMBER
, XML_ZEROS_DENOMINATOR_DIGITS
):
770 case XML_ELEMENT(LO_EXT
, XML_ZEROS_DENOMINATOR_DIGITS
):
771 if (::sax::Converter::convertNumber( nAttrVal
, aIter
.toView(), 0 ))
772 aNumInfo
.nZerosDenomDigits
= nAttrVal
;
774 case XML_ELEMENT(NUMBER
, XML_INTEGER_FRACTION_DELIMITER
):
775 case XML_ELEMENT(LO_EXT
, XML_INTEGER_FRACTION_DELIMITER
):
776 aNumInfo
.aIntegerFractionDelimiter
= aIter
.toString();
778 case XML_ELEMENT(NUMBER
, XML_RFC_LANGUAGE_TAG
):
779 aLanguageTagODF
.maRfcLanguageTag
= aIter
.toString();
781 case XML_ELEMENT(NUMBER
, XML_LANGUAGE
):
782 aLanguageTagODF
.maLanguage
= aIter
.toString();
784 case XML_ELEMENT(NUMBER
, XML_SCRIPT
):
785 aLanguageTagODF
.maScript
= aIter
.toString();
787 case XML_ELEMENT(NUMBER
, XML_COUNTRY
):
788 aLanguageTagODF
.maCountry
= aIter
.toString();
790 case XML_ELEMENT(NUMBER
, XML_STYLE
):
791 SvXMLUnitConverter::convertEnum( bLong
, aIter
.toView(), aStyleValueMap
);
793 case XML_ELEMENT(NUMBER
, XML_TEXTUAL
):
794 if (::sax::Converter::convertBool( bAttrBool
, aIter
.toView() ))
795 bTextual
= bAttrBool
;
797 case XML_ELEMENT(NUMBER
, XML_CALENDAR
):
798 sCalendar
= aIter
.toString();
800 case XML_ELEMENT(NUMBER
, XML_BLANK_WIDTH_CHAR
):
801 case XML_ELEMENT(LO_EXT
, XML_BLANK_WIDTH_CHAR
):
802 sBlankWidthString
= aIter
.toString();
805 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
808 if ( aNumInfo
.nBlankInteger
> aNumInfo
.nInteger
)
809 aNumInfo
.nInteger
= aNumInfo
.nBlankInteger
;
810 if ( aNumInfo
.nMinDecimalDigits
== -1)
812 if ( bVarDecimals
|| aNumInfo
.bDecReplace
)
813 aNumInfo
.nMinDecimalDigits
= 0;
815 aNumInfo
.nMinDecimalDigits
= aNumInfo
.nDecimals
;
817 if ( aNumInfo
.nExpDigits
> 0 && aNumInfo
.nBlankExp
>= aNumInfo
.nExpDigits
)
818 aNumInfo
.nBlankExp
= aNumInfo
.nExpDigits
- 1; // at least one '0' in exponent
820 if ( aNumInfo
.nZerosDenomDigits
> 0 )
821 { // nMin = count of '0' and '?'
822 if ( aNumInfo
.nMinDenomDigits
< aNumInfo
.nZerosDenomDigits
)
823 aNumInfo
.nMinDenomDigits
= aNumInfo
.nZerosDenomDigits
;
826 aNumInfo
.nZerosDenomDigits
= 0;
827 if ( aNumInfo
.nMinDenomDigits
>= 0 )
828 if ( aNumInfo
.nMaxDenomDigits
< aNumInfo
.nMinDenomDigits
)
829 aNumInfo
.nMaxDenomDigits
= ( aNumInfo
.nMinDenomDigits
? aNumInfo
.nMinDenomDigits
: 1 );
830 if ( aNumInfo
.nZerosNumerDigits
> 0 )
832 if ( aNumInfo
.nMinNumerDigits
< aNumInfo
.nZerosNumerDigits
)
833 aNumInfo
.nMinNumerDigits
= aNumInfo
.nZerosNumerDigits
;
836 aNumInfo
.nZerosNumerDigits
= 0;
837 if ( aNumInfo
.nMinNumerDigits
>= 0 )
838 if ( aNumInfo
.nMaxNumerDigits
< aNumInfo
.nMinNumerDigits
)
839 aNumInfo
.nMaxNumerDigits
= ( aNumInfo
.nMinNumerDigits
? aNumInfo
.nMinNumerDigits
: 1 );
840 if ( bIsMaxDenominator
&& aNumInfo
.nFracDenominator
> 0 )
842 aNumInfo
.nMaxDenomDigits
= floor( log10( aNumInfo
.nFracDenominator
) ) + 1;
843 aNumInfo
.nFracDenominator
= -1; // Max denominator value only gives number of digits at denominator
845 if ( aNumInfo
.nMaxDenomDigits
> 0 )
847 if ( aNumInfo
.nMinDenomDigits
< 0 )
848 aNumInfo
.nMinDenomDigits
= 0;
849 else if ( aNumInfo
.nMinDenomDigits
> aNumInfo
.nMaxDenomDigits
)
850 aNumInfo
.nMinDenomDigits
= aNumInfo
.nMaxDenomDigits
;
853 if ( !aLanguageTagODF
.isEmpty() )
855 nElementLang
= aLanguageTagODF
.getLanguageTag().getLanguageType( false);
856 if ( nElementLang
== LANGUAGE_DONTKNOW
)
857 nElementLang
= LANGUAGE_SYSTEM
; //! error handling for unknown locales?
860 if ( aNumInfo
.aIntegerFractionDelimiter
.isEmpty() )
861 aNumInfo
.aIntegerFractionDelimiter
= " ";
864 css::uno::Reference
< css::xml::sax::XFastContextHandler
> SvXMLNumFmtElementContext::createFastChildContext(
866 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
)
868 // only number:number and number:scientific-number supports number:embedded-text child element
870 if ( ( nType
== SvXMLStyleTokens::Number
|| nType
== SvXMLStyleTokens::ScientificNumber
) &&
871 nElement
== XML_ELEMENT(NUMBER
, XML_EMBEDDED_TEXT
) )
873 return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nElement
, *this, xAttrList
);
876 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement
);
880 void SvXMLNumFmtElementContext::characters( const OUString
& rChars
)
882 aContent
.append( rChars
);
886 void lcl_InsertBlankWidthChars( std::u16string_view rBlankWidthString
, OUStringBuffer
& rContent
)
888 sal_Int32 nShiftPosition
= 1; // rContent starts with a quote
889 const size_t nLenBlank
= rBlankWidthString
.size();
890 for ( size_t i
= 0 ; i
< nLenBlank
; i
++ )
892 sal_Unicode nChar
= rBlankWidthString
[ i
];
894 SvNumberformat::InsertBlanks( aBlanks
, 0, nChar
);
895 sal_Int32 nPositionContent
= 0;
896 if ( ++i
< nLenBlank
)
898 sal_Int32 nNext
= rBlankWidthString
.find( '_', i
);
899 if ( static_cast<sal_Int32
>( i
) < nNext
)
901 nPositionContent
= o3tl::toInt32( rBlankWidthString
.substr( i
, nNext
- i
) );
905 nPositionContent
= o3tl::toInt32( rBlankWidthString
.substr( i
) );
907 nPositionContent
+= nShiftPosition
;
908 if ( nPositionContent
>= 0 )
910 rContent
.remove( nPositionContent
, aBlanks
.getLength() );
911 if ( nPositionContent
>= 1 && rContent
[ nPositionContent
-1 ] == '\"' )
914 rContent
.insert( nPositionContent
, nChar
);
915 rContent
.insert( nPositionContent
, '_' );
919 rContent
.insert( nPositionContent
, '\"' );
920 rContent
.insert( nPositionContent
, nChar
);
921 rContent
.insert( nPositionContent
, "\"_" );
924 // rContent length was modified: remove blanks, add "_x"
925 nShiftPosition
+= 2 - aBlanks
.getLength();
928 // remove empty string at the end of rContent
929 if ( std::u16string_view( rContent
).substr( rContent
.getLength() - 2 ) == u
"\"\"" )
931 sal_Int32 nLen
= rContent
.getLength();
932 if ( nLen
>= 3 && rContent
[ nLen
-3 ] != '\\' )
933 rContent
.truncate( nLen
- 2 );
938 void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos
, std::u16string_view rContentEmbedded
, std::u16string_view rBlankWidthString
)
940 if ( rContentEmbedded
.empty() )
942 OUStringBuffer
aContentEmbedded( rContentEmbedded
);
943 // #107805# always quote embedded strings - even space would otherwise
944 // be recognized as thousands separator in French.
945 aContentEmbedded
.insert( 0, '"' );
946 aContentEmbedded
.append( '"' );
947 if ( !rBlankWidthString
.empty() )
948 lcl_InsertBlankWidthChars( rBlankWidthString
, aContentEmbedded
);
950 auto iterPair
= aNumInfo
.m_EmbeddedElements
.emplace( nFormatPos
, aContentEmbedded
.toString() );
951 if (!iterPair
.second
)
953 // there's already an element at this position - append text to existing element
954 if ( iterPair
.first
->second
.endsWith( "\"" ) && aContentEmbedded
[ 0 ] == '"' )
955 { // remove double quote
956 iterPair
.first
->second
= OUString::Concat( iterPair
.first
->second
.subView( 0, iterPair
.first
->second
.getLength() - 1 ) )
957 + aContentEmbedded
.subView( 1, aContentEmbedded
.getLength() - 1 );
960 iterPair
.first
->second
+= aContentEmbedded
;
964 void SvXMLNumFmtElementContext::endFastElement(sal_Int32
)
966 bool bEffLong
= bLong
;
969 case SvXMLStyleTokens::Text
:
970 if ( rParent
.HasLongDoW() &&
971 std::u16string_view(aContent
) == rParent
.GetLocaleData().getLongDateDayOfWeekSep() )
973 // skip separator constant after long day of week
974 // (NF_KEY_NNNN contains the separator)
976 if ( rParent
.ReplaceNfKeyword( NF_KEY_NNN
, NF_KEY_NNNN
) )
981 rParent
.SetHasLongDoW( false ); // only once
983 if ( !aContent
.isEmpty() )
985 lcl_EnquoteIfNecessary( aContent
, rParent
);
986 if ( !sBlankWidthString
.isEmpty() )
988 lcl_InsertBlankWidthChars( sBlankWidthString
, aContent
);
989 sBlankWidthString
= "";
991 rParent
.AddToCode( aContent
);
992 aContent
.setLength(0);
996 // Quoted empty text may be significant to separate.
997 aContent
.append("\"\"");
998 rParent
.AddToCode( aContent
);
999 aContent
.setLength(0);
1000 rParent
.SetHasTrailingEmptyText(true); // *after* AddToCode()
1004 case SvXMLStyleTokens::Number
:
1005 rParent
.AddNumber( aNumInfo
);
1008 case SvXMLStyleTokens::CurrencySymbol
:
1009 rParent
.AddCurrency( aContent
.makeStringAndClear(), nElementLang
);
1012 case SvXMLStyleTokens::TextContent
:
1013 rParent
.AddToCode( '@');
1015 case SvXMLStyleTokens::FillCharacter
:
1016 if ( !aContent
.isEmpty() )
1018 rParent
.AddToCode( '*' );
1019 rParent
.AddToCode( aContent
[0] );
1022 case SvXMLStyleTokens::Boolean
:
1023 rParent
.AddNfKeyword( NF_KEY_BOOLEAN
);
1026 case SvXMLStyleTokens::Day
:
1027 rParent
.UpdateCalendar( sCalendar
);
1028 //! I18N doesn't provide SYSTEM or extended date information yet
1030 rParent
.AddNfKeyword(
1031 sal::static_int_cast
< sal_uInt16
>(
1032 bEffLong
? NF_KEY_DD
: NF_KEY_D
) );
1034 case SvXMLStyleTokens::Month
:
1035 rParent
.UpdateCalendar( sCalendar
);
1036 //! I18N doesn't provide SYSTEM or extended date information yet
1038 rParent
.AddNfKeyword(
1039 sal::static_int_cast
< sal_uInt16
>(
1041 ? ( bEffLong
? NF_KEY_MMMM
: NF_KEY_MMM
)
1042 : ( bEffLong
? NF_KEY_MM
: NF_KEY_M
) ) );
1044 case SvXMLStyleTokens::Year
:
1045 //! I18N doesn't provide SYSTEM or extended date information yet
1047 // Y after G (era) is replaced by E for a secondary calendar.
1048 // Do not replace for default calendar.
1049 // Also replace Y by E if we're switching to the secondary
1050 // calendar of a locale if it is known to implicitly use E.
1051 rParent
.UpdateCalendar( sCalendar
);
1052 const SvXMLNumFormatContext::ImplicitCalendar eCal
= rParent
.GetImplicitCalendarState();
1053 if (eCal
== SvXMLNumFormatContext::ImplicitCalendar::SECONDARY
1054 || eCal
== SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER
)
1056 rParent
.AddNfKeyword(
1057 sal::static_int_cast
< sal_uInt16
>(
1058 bEffLong
? NF_KEY_EEC
: NF_KEY_EC
) );
1062 rParent
.AddNfKeyword(
1063 sal::static_int_cast
< sal_uInt16
>(
1064 bEffLong
? NF_KEY_YYYY
: NF_KEY_YY
) );
1068 case SvXMLStyleTokens::Era
:
1069 rParent
.UpdateCalendar( sCalendar
);
1070 //! I18N doesn't provide SYSTEM or extended date information yet
1071 rParent
.AddNfKeyword(
1072 sal::static_int_cast
< sal_uInt16
>(
1073 bEffLong
? NF_KEY_GGG
: NF_KEY_G
) );
1074 // HasEra flag is set
1076 case SvXMLStyleTokens::DayOfWeek
:
1077 //! I18N doesn't provide SYSTEM or extended date information yet
1079 // Implicit secondary calendar uses A keyword, default and
1080 // explicit calendar N keyword.
1081 rParent
.UpdateCalendar( sCalendar
);
1082 const SvXMLNumFormatContext::ImplicitCalendar eCal
= rParent
.GetImplicitCalendarState();
1083 if (eCal
== SvXMLNumFormatContext::ImplicitCalendar::SECONDARY
1084 || eCal
== SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER
)
1086 rParent
.AddNfKeyword(
1087 sal::static_int_cast
< sal_uInt16
>(
1088 bEffLong
? NF_KEY_AAAA
: NF_KEY_AAA
) );
1092 rParent
.AddNfKeyword(
1093 sal::static_int_cast
< sal_uInt16
>(
1094 bEffLong
? NF_KEY_NNNN
: NF_KEY_NN
) );
1098 case SvXMLStyleTokens::WeekOfYear
:
1099 rParent
.UpdateCalendar( sCalendar
);
1100 rParent
.AddNfKeyword( NF_KEY_WW
);
1102 case SvXMLStyleTokens::Quarter
:
1103 rParent
.UpdateCalendar( sCalendar
);
1104 rParent
.AddNfKeyword(
1105 sal::static_int_cast
< sal_uInt16
>(
1106 bEffLong
? NF_KEY_QQ
: NF_KEY_Q
) );
1108 case SvXMLStyleTokens::Hours
:
1109 rParent
.AddNfKeyword(
1110 sal::static_int_cast
< sal_uInt16
>(
1111 bEffLong
? NF_KEY_HH
: NF_KEY_H
) );
1113 case SvXMLStyleTokens::AmPm
:
1115 rParent
.AddNfKeyword( NF_KEY_AMPM
);
1117 case SvXMLStyleTokens::Minutes
:
1118 rParent
.AddNfKeyword(
1119 sal::static_int_cast
< sal_uInt16
>(
1120 bEffLong
? NF_KEY_MMI
: NF_KEY_MI
) );
1122 case SvXMLStyleTokens::Seconds
:
1123 rParent
.AddNfKeyword(
1124 sal::static_int_cast
< sal_uInt16
>(
1125 bEffLong
? NF_KEY_SS
: NF_KEY_S
) );
1126 if ( aNumInfo
.nDecimals
> 0 )
1128 // manually add the decimal places
1129 rParent
.AddToCode(rParent
.GetLocaleData().getNumDecimalSep());
1130 for (sal_Int32 i
=0; i
<aNumInfo
.nDecimals
; i
++)
1132 rParent
.AddToCode( '0');
1137 case SvXMLStyleTokens::Fraction
:
1139 if ( aNumInfo
.nInteger
>= 0 )
1141 // add integer part only if min-integer-digits attribute is there
1142 aNumInfo
.nDecimals
= 0;
1143 rParent
.AddNumber( aNumInfo
); // number without decimals
1144 OUStringBuffer
sIntegerFractionDelimiter(aNumInfo
.aIntegerFractionDelimiter
);
1145 lcl_EnquoteIfNecessary( sIntegerFractionDelimiter
, rParent
);
1146 rParent
.AddToCode( sIntegerFractionDelimiter
); // default is ' '
1149 //! build string and add at once
1152 for (i
=aNumInfo
.nMaxNumerDigits
; i
> 0; i
--)
1154 if ( i
> aNumInfo
.nMinNumerDigits
)
1155 rParent
.AddToCode( '#' );
1156 else if ( i
> aNumInfo
.nZerosNumerDigits
)
1157 rParent
.AddToCode( '?' );
1159 rParent
.AddToCode( '0' );
1161 rParent
.AddToCode( '/' );
1162 if ( aNumInfo
.nFracDenominator
> 0 )
1164 rParent
.AddToCode( OUString::number( aNumInfo
.nFracDenominator
) );
1168 for (i
=aNumInfo
.nMaxDenomDigits
; i
> 0 ; i
--)
1170 if ( i
> aNumInfo
.nMinDenomDigits
)
1171 rParent
.AddToCode( '#' );
1172 else if ( i
> aNumInfo
.nZerosDenomDigits
)
1173 rParent
.AddToCode( '?' );
1175 rParent
.AddToCode( '0' );
1181 case SvXMLStyleTokens::ScientificNumber
:
1183 // exponential interval for engineering notation
1184 if( !aNumInfo
.bGrouping
&& aNumInfo
.nExpInterval
> aNumInfo
.nInteger
)
1186 for (sal_Int32 i
=aNumInfo
.nInteger
; i
<aNumInfo
.nExpInterval
; i
++)
1188 rParent
.AddToCode( '#' );
1191 rParent
.AddNumber( aNumInfo
); // number and exponent
1196 assert(false && "invalid element ID");
1200 sal_uInt16
SvXMLNumFmtDefaults::GetDefaultDateFormat( SvXMLDateElementAttributes eDOW
,
1201 SvXMLDateElementAttributes eDay
, SvXMLDateElementAttributes eMonth
,
1202 SvXMLDateElementAttributes eYear
, SvXMLDateElementAttributes eHours
,
1203 SvXMLDateElementAttributes eMins
, SvXMLDateElementAttributes eSecs
,
1206 for (const auto & rEntry
: aDefaultDateFormats
)
1208 if ( bSystem
== rEntry
.bSystem
&&
1209 ( eDOW
== rEntry
.eDOW
|| ( rEntry
.eDOW
== XML_DEA_ANY
&& eDOW
!= XML_DEA_NONE
) ) &&
1210 ( eDay
== rEntry
.eDay
|| ( rEntry
.eDay
== XML_DEA_ANY
&& eDay
!= XML_DEA_NONE
) ) &&
1211 ( eMonth
== rEntry
.eMonth
|| ( rEntry
.eMonth
== XML_DEA_ANY
&& eMonth
!= XML_DEA_NONE
) ) &&
1212 ( eYear
== rEntry
.eYear
|| ( rEntry
.eYear
== XML_DEA_ANY
&& eYear
!= XML_DEA_NONE
) ) &&
1213 ( eHours
== rEntry
.eHours
|| ( rEntry
.eHours
== XML_DEA_ANY
&& eHours
!= XML_DEA_NONE
) ) &&
1214 ( eMins
== rEntry
.eMins
|| ( rEntry
.eMins
== XML_DEA_ANY
&& eMins
!= XML_DEA_NONE
) ) &&
1215 ( eSecs
== rEntry
.eSecs
|| ( rEntry
.eSecs
== XML_DEA_ANY
&& eSecs
!= XML_DEA_NONE
) ) )
1217 return sal::static_int_cast
< sal_uInt16
>(rEntry
.eFormat
);
1221 return NF_INDEX_TABLE_ENTRIES
; // invalid
1225 // SvXMLNumFormatContext
1227 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport
& rImport
,
1228 sal_Int32
/*nElement*/,
1229 SvXMLNumImpData
* pNewData
, SvXMLStylesTokens nNewType
,
1230 const uno::Reference
<xml::sax::XFastAttributeList
>& xAttrList
,
1231 SvXMLStylesContext
& rStyles
) :
1232 SvXMLStyleContext( rImport
),
1233 m_pData( pNewData
),
1234 m_pStyles( &rStyles
),
1235 m_nType( nNewType
),
1237 m_eImplicitCalendar(ImplicitCalendar::DEFAULT
),
1238 m_nFormatLang( LANGUAGE_SYSTEM
),
1239 m_bAutoOrder( false ),
1240 m_bFromSystem( false ),
1241 m_bTruncate( true ),
1242 m_bAutoDec( false ),
1243 m_bAutoInt( false ),
1244 m_bHasExtraText( false ),
1245 m_bHasTrailingEmptyText( false ),
1246 m_bHasLongDoW( false ),
1247 m_bHasDateTime( false ),
1248 m_bRemoveAfterUse( false ),
1249 m_eDateDOW( XML_DEA_NONE
),
1250 m_eDateDay( XML_DEA_NONE
),
1251 m_eDateMonth( XML_DEA_NONE
),
1252 m_eDateYear( XML_DEA_NONE
),
1253 m_eDateHours( XML_DEA_NONE
),
1254 m_eDateMins( XML_DEA_NONE
),
1255 m_eDateSecs( XML_DEA_NONE
),
1256 m_bDateNoDefault( false )
1258 LanguageTagODF aLanguageTagODF
;
1259 css::i18n::NativeNumberXmlAttributes aNatNumAttr
;
1261 bool bAttrBool(false);
1263 for( auto &aIter
: sax_fastparser::castToFastAttributeList( xAttrList
) )
1265 switch (aIter
.getToken())
1267 // attributes for a style
1268 case XML_ELEMENT(STYLE
, XML_NAME
):
1270 case XML_ELEMENT(NUMBER
, XML_RFC_LANGUAGE_TAG
):
1271 aLanguageTagODF
.maRfcLanguageTag
= aIter
.toString();
1273 case XML_ELEMENT(NUMBER
, XML_LANGUAGE
):
1274 aLanguageTagODF
.maLanguage
= aIter
.toString();
1276 case XML_ELEMENT(NUMBER
, XML_SCRIPT
):
1277 aLanguageTagODF
.maScript
= aIter
.toString();
1279 case XML_ELEMENT(NUMBER
, XML_COUNTRY
):
1280 aLanguageTagODF
.maCountry
= aIter
.toString();
1282 case XML_ELEMENT(NUMBER
, XML_TITLE
):
1283 m_sFormatTitle
= aIter
.toString();
1285 case XML_ELEMENT(NUMBER
, XML_AUTOMATIC_ORDER
):
1286 if (::sax::Converter::convertBool( bAttrBool
, aIter
.toView() ))
1287 m_bAutoOrder
= bAttrBool
;
1289 case XML_ELEMENT(NUMBER
, XML_FORMAT_SOURCE
):
1290 SvXMLUnitConverter::convertEnum( m_bFromSystem
, aIter
.toView(), aFormatSourceMap
);
1292 case XML_ELEMENT(NUMBER
, XML_TRUNCATE_ON_OVERFLOW
):
1293 if (::sax::Converter::convertBool( bAttrBool
, aIter
.toView() ))
1294 m_bTruncate
= bAttrBool
;
1296 case XML_ELEMENT(STYLE
, XML_VOLATILE
):
1297 // volatile formats can be removed after importing
1298 // if not used in other styles
1299 if (::sax::Converter::convertBool( bAttrBool
, aIter
.toView() ))
1300 m_bRemoveAfterUse
= bAttrBool
;
1302 case XML_ELEMENT(NUMBER
, XML_TRANSLITERATION_FORMAT
):
1303 aNatNumAttr
.Format
= aIter
.toString();
1305 case XML_ELEMENT(LO_EXT
, XML_TRANSLITERATION_SPELLOUT
):
1306 case XML_ELEMENT(NUMBER
, XML_TRANSLITERATION_SPELLOUT
):
1307 aSpellout
= aIter
.toString();
1309 case XML_ELEMENT(NUMBER
, XML_TRANSLITERATION_LANGUAGE
):
1310 aNatNumAttr
.Locale
.Language
= aIter
.toString();
1312 case XML_ELEMENT(NUMBER
, XML_TRANSLITERATION_COUNTRY
):
1313 aNatNumAttr
.Locale
.Country
= aIter
.toString();
1315 case XML_ELEMENT(NUMBER
, XML_TRANSLITERATION_STYLE
):
1316 aNatNumAttr
.Style
= aIter
.toString();
1319 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
1323 if (!aLanguageTagODF
.isEmpty())
1325 m_nFormatLang
= aLanguageTagODF
.getLanguageTag().getLanguageType( false);
1326 if ( m_nFormatLang
== LANGUAGE_DONTKNOW
)
1327 m_nFormatLang
= LANGUAGE_SYSTEM
; //! error handling for unknown locales?
1330 if (aNatNumAttr
.Format
.isEmpty() && aSpellout
.isEmpty())
1333 LanguageTag
aLanguageTag( OUString(), aNatNumAttr
.Locale
.Language
,
1334 std::u16string_view(), aNatNumAttr
.Locale
.Country
);
1335 aNatNumAttr
.Locale
= aLanguageTag
.getLocale( false);
1337 // NatNum12 spell out formula (cardinal, ordinal, ordinal-feminine etc.)
1338 if ( !aSpellout
.isEmpty() )
1340 m_aFormatCode
.append( "[NatNum12 " );
1341 m_aFormatCode
.append( aSpellout
);
1343 SvNumberFormatter
* pFormatter
= m_pData
->GetNumberFormatter();
1344 if ( !pFormatter
) return;
1346 sal_Int32 nNatNum
= pFormatter
->GetNatNum()->convertFromXmlAttributes( aNatNumAttr
);
1347 m_aFormatCode
.append( "[NatNum" );
1348 m_aFormatCode
.append( nNatNum
);
1351 LanguageType eLang
= aLanguageTag
.getLanguageType( false );
1352 if ( eLang
== LANGUAGE_DONTKNOW
)
1353 eLang
= LANGUAGE_SYSTEM
; //! error handling for unknown locales?
1354 if ( eLang
!= m_nFormatLang
&& eLang
!= LANGUAGE_SYSTEM
)
1356 m_aFormatCode
.append( "][$-" );
1357 // language code in upper hex:
1358 m_aFormatCode
.append(OUString::number(static_cast<sal_uInt16
>(eLang
), 16).toAsciiUpperCase());
1360 m_aFormatCode
.append( ']' );
1363 SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport
& rImport
,
1364 const OUString
& rName
,
1365 const uno::Reference
<xml::sax::XFastAttributeList
>& /*xAttrList*/,
1366 const sal_Int32 nTempKey
, LanguageType nLang
,
1367 SvXMLStylesContext
& rStyles
) :
1368 SvXMLStyleContext( rImport
, XmlStyleFamily::DATA_STYLE
),
1370 m_pStyles( &rStyles
),
1371 m_nType( SvXMLStylesTokens::NUMBER_STYLE
),
1373 m_eImplicitCalendar(ImplicitCalendar::DEFAULT
),
1374 m_nFormatLang( nLang
),
1375 m_bAutoOrder( false ),
1376 m_bFromSystem( false ),
1377 m_bTruncate( true ),
1378 m_bAutoDec( false ),
1379 m_bAutoInt( false ),
1380 m_bHasExtraText( false ),
1381 m_bHasTrailingEmptyText( false ),
1382 m_bHasLongDoW( false ),
1383 m_bHasDateTime( false ),
1384 m_bRemoveAfterUse( false ),
1385 m_eDateDOW( XML_DEA_NONE
),
1386 m_eDateDay( XML_DEA_NONE
),
1387 m_eDateMonth( XML_DEA_NONE
),
1388 m_eDateYear( XML_DEA_NONE
),
1389 m_eDateHours( XML_DEA_NONE
),
1390 m_eDateMins( XML_DEA_NONE
),
1391 m_eDateSecs( XML_DEA_NONE
),
1392 m_bDateNoDefault( false )
1394 SetAttribute(XML_ELEMENT(STYLE
, XML_NAME
), rName
);
1397 SvXMLNumFormatContext::~SvXMLNumFormatContext()
1401 css::uno::Reference
< css::xml::sax::XFastContextHandler
> SvXMLNumFormatContext::createFastChildContext(
1403 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
)
1405 SvXMLImportContext
* pContext
= nullptr;
1409 case XML_ELEMENT(LO_EXT
, XML_TEXT
):
1410 case XML_ELEMENT(NUMBER
, XML_TEXT
):
1411 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1412 *this, SvXMLStyleTokens::Text
, xAttrList
);
1414 case XML_ELEMENT(LO_EXT
, XML_FILL_CHARACTER
):
1415 case XML_ELEMENT(NUMBER
, XML_FILL_CHARACTER
):
1416 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1417 *this, SvXMLStyleTokens::FillCharacter
, xAttrList
);
1419 case XML_ELEMENT(NUMBER
, XML_NUMBER
):
1420 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1421 *this, SvXMLStyleTokens::Number
, xAttrList
);
1423 case XML_ELEMENT(NUMBER
, XML_SCIENTIFIC_NUMBER
):
1424 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1425 *this, SvXMLStyleTokens::ScientificNumber
, xAttrList
);
1427 case XML_ELEMENT(NUMBER
, XML_FRACTION
):
1428 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1429 *this, SvXMLStyleTokens::Fraction
, xAttrList
);
1431 case XML_ELEMENT(NUMBER
, XML_CURRENCY_SYMBOL
):
1432 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1433 *this, SvXMLStyleTokens::CurrencySymbol
, xAttrList
);
1435 case XML_ELEMENT(NUMBER
, XML_DAY
):
1436 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1437 *this, SvXMLStyleTokens::Day
, xAttrList
);
1439 case XML_ELEMENT(NUMBER
, XML_MONTH
):
1440 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1441 *this, SvXMLStyleTokens::Month
, xAttrList
);
1443 case XML_ELEMENT(NUMBER
, XML_YEAR
):
1444 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1445 *this, SvXMLStyleTokens::Year
, xAttrList
);
1447 case XML_ELEMENT(NUMBER
, XML_ERA
):
1448 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1449 *this, SvXMLStyleTokens::Era
, xAttrList
);
1451 case XML_ELEMENT(NUMBER
, XML_DAY_OF_WEEK
):
1452 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1453 *this, SvXMLStyleTokens::DayOfWeek
, xAttrList
);
1455 case XML_ELEMENT(NUMBER
, XML_WEEK_OF_YEAR
):
1456 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1457 *this, SvXMLStyleTokens::WeekOfYear
, xAttrList
);
1459 case XML_ELEMENT(NUMBER
, XML_QUARTER
):
1460 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1461 *this, SvXMLStyleTokens::Quarter
, xAttrList
);
1463 case XML_ELEMENT(NUMBER
, XML_HOURS
):
1464 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1465 *this, SvXMLStyleTokens::Hours
, xAttrList
);
1467 case XML_ELEMENT(NUMBER
, XML_AM_PM
):
1468 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1469 *this, SvXMLStyleTokens::AmPm
, xAttrList
);
1471 case XML_ELEMENT(NUMBER
, XML_MINUTES
):
1472 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1473 *this, SvXMLStyleTokens::Minutes
, xAttrList
);
1475 case XML_ELEMENT(NUMBER
, XML_SECONDS
):
1476 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1477 *this, SvXMLStyleTokens::Seconds
, xAttrList
);
1479 case XML_ELEMENT(NUMBER
, XML_BOOLEAN
):
1480 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1481 *this, SvXMLStyleTokens::Boolean
, xAttrList
);
1483 case XML_ELEMENT(NUMBER
, XML_TEXT_CONTENT
):
1484 pContext
= new SvXMLNumFmtElementContext( GetImport(), nElement
,
1485 *this, SvXMLStyleTokens::TextContent
, xAttrList
);
1488 case XML_ELEMENT(STYLE
, XML_TEXT_PROPERTIES
):
1489 pContext
= new SvXMLNumFmtPropContext( GetImport(), nElement
,
1492 case XML_ELEMENT(STYLE
, XML_MAP
):
1494 // SvXMLNumFmtMapContext::EndElement adds to aMyConditions,
1495 // so there's no need for an extra flag
1496 pContext
= new SvXMLNumFmtMapContext( GetImport(), nElement
,
1504 SAL_WARN("xmloff.core", "No context for unknown-element " << SvXMLImport::getPrefixAndNameFromToken(nElement
));
1505 pContext
= new SvXMLImportContext(GetImport());
1511 sal_Int32
SvXMLNumFormatContext::GetKey()
1515 if (m_bRemoveAfterUse
)
1517 // format is used -> don't remove
1518 m_bRemoveAfterUse
= false;
1520 m_pData
->SetUsed(m_nKey
);
1522 // Add to import's list of keys now - CreateAndInsert didn't add
1523 // the style if bRemoveAfterUse was set.
1524 GetImport().AddNumberStyle( m_nKey
, GetName() );
1530 // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set
1531 m_bRemoveAfterUse
= false;
1532 CreateAndInsert(true);
1537 sal_Int32
SvXMLNumFormatContext::PrivateGetKey()
1539 // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag
1545 CreateAndInsert(true);
1550 sal_Int32
SvXMLNumFormatContext::CreateAndInsert( css::uno::Reference
< css::util::XNumberFormatsSupplier
> const & xFormatsSupplier
)
1554 SvNumberFormatter
* pFormatter
= nullptr;
1555 SvNumberFormatsSupplierObj
* pObj
=
1556 comphelper::getFromUnoTunnel
<SvNumberFormatsSupplierObj
>( xFormatsSupplier
);
1558 pFormatter
= pObj
->GetNumberFormatter();
1561 return CreateAndInsert( pFormatter
);
1569 void SvXMLNumFormatContext::CreateAndInsert(bool /*bOverwrite*/)
1572 CreateAndInsert(m_pData
->GetNumberFormatter());
1575 sal_Int32
SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter
* pFormatter
)
1579 OSL_FAIL("no number formatter");
1583 sal_uInt32 nIndex
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1585 for (size_t i
= 0; i
< m_aMyConditions
.size(); i
++)
1587 SvXMLNumFormatContext
* pStyle
= const_cast<SvXMLNumFormatContext
*>( static_cast<const SvXMLNumFormatContext
*>(m_pStyles
->FindStyleChildContext(
1588 XmlStyleFamily::DATA_STYLE
, m_aMyConditions
[i
].sMapName
)));
1591 SAL_INFO("xmloff.style", "invalid style:map references containing style");
1596 if (pStyle
->PrivateGetKey() > -1) // don't reset pStyle's bRemoveAfterUse flag
1602 if ( m_aFormatCode
.isEmpty() )
1604 // insert empty format as empty string (with quotes)
1605 // #93901# this check has to be done before inserting the conditions
1606 m_aFormatCode
.append("\"\""); // ""
1608 else if (m_bHasTrailingEmptyText
&& (nBufLen
= m_aFormatCode
.getLength()) >= 3)
1610 // Remove a trailing empty text. Earlier this may had been written to
1611 // file, like in "General;General" written with elements for
1612 // 'General"";General""' (whyever); when reading, empty text was
1613 // ignored, which it isn't anymore, so get rid of those.
1614 if (m_aFormatCode
[nBufLen
-1] == '"' && m_aFormatCode
[nBufLen
-2] == '"')
1615 m_aFormatCode
.truncate( nBufLen
- 2);
1618 m_aFormatCode
.insert( 0, m_aConditions
);
1619 m_aConditions
.setLength(0);
1620 OUString sFormat
= m_aFormatCode
.makeStringAndClear();
1622 // test special cases
1624 if ( m_bAutoDec
) // automatic decimal places
1626 // #99391# adjust only if the format contains no text elements, no conditions
1627 // and no color definition (detected by the '[' at the start)
1629 if ( m_nType
== SvXMLStylesTokens::NUMBER_STYLE
&& !m_bHasExtraText
&&
1630 m_aMyConditions
.empty() && sFormat
.toChar() != '[' )
1631 nIndex
= pFormatter
->GetStandardIndex( m_nFormatLang
);
1633 if ( m_bAutoInt
) // automatic integer digits
1635 //! only if two decimal places was set?
1637 if ( m_nType
== SvXMLStylesTokens::NUMBER_STYLE
&& !m_bHasExtraText
&&
1638 m_aMyConditions
.empty() && sFormat
.toChar() != '[' )
1639 nIndex
= pFormatter
->GetFormatIndex( NF_NUMBER_SYSTEM
, m_nFormatLang
);
1642 if ( m_nType
== SvXMLStylesTokens::BOOLEAN_STYLE
&& !m_bHasExtraText
&&
1643 m_aMyConditions
.empty() && sFormat
.toChar() != '[' )
1644 nIndex
= pFormatter
->GetFormatIndex( NF_BOOLEAN
, m_nFormatLang
);
1646 // check for default date formats
1647 if ( m_nType
== SvXMLStylesTokens::DATE_STYLE
&& m_bAutoOrder
&& !m_bDateNoDefault
)
1649 NfIndexTableOffset eFormat
= static_cast<NfIndexTableOffset
>(SvXMLNumFmtDefaults::GetDefaultDateFormat(
1650 m_eDateDOW
, m_eDateDay
, m_eDateMonth
, m_eDateYear
,
1651 m_eDateHours
, m_eDateMins
, m_eDateSecs
, m_bFromSystem
));
1652 if ( eFormat
< NF_INDEX_TABLE_RESERVED_START
)
1654 // #109651# if a date format has the automatic-order attribute and
1655 // contains exactly the elements of one of the default date formats,
1656 // use that default format, with the element order and separators
1657 // from the current locale settings
1659 nIndex
= pFormatter
->GetFormatIndex( eFormat
, m_nFormatLang
);
1663 if ( nIndex
== NUMBERFORMAT_ENTRY_NOT_FOUND
&& !sFormat
.isEmpty() )
1665 // insert by format string
1667 OUString
aFormatStr( sFormat
);
1668 nIndex
= pFormatter
->GetEntryKey( aFormatStr
, m_nFormatLang
);
1669 if ( nIndex
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1671 sal_Int32 nErrPos
= 0;
1672 SvNumFormatType l_nType
= SvNumFormatType::ALL
;
1673 bool bOk
= pFormatter
->PutEntry( aFormatStr
, nErrPos
, l_nType
, nIndex
, m_nFormatLang
);
1674 if ( !bOk
&& nErrPos
== 0 && aFormatStr
!= sFormat
)
1676 // if the string was modified by PutEntry, look for an existing format
1677 // with the modified string
1678 nIndex
= pFormatter
->GetEntryKey( aFormatStr
, m_nFormatLang
);
1679 if ( nIndex
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1683 nIndex
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1687 //! I18N doesn't provide SYSTEM or extended date information yet
1688 if ( nIndex
!= NUMBERFORMAT_ENTRY_NOT_FOUND
&& !m_bAutoOrder
)
1690 // use fixed-order formats instead of SYS... if bAutoOrder is false
1691 // (only if the format strings are equal for the locale)
1693 NfIndexTableOffset eOffset
= pFormatter
->GetIndexTableOffset( nIndex
);
1694 if ( eOffset
== NF_DATE_SYS_DMMMYYYY
)
1696 sal_uInt32 nNewIndex
= pFormatter
->GetFormatIndex( NF_DATE_DIN_DMMMYYYY
, m_nFormatLang
);
1697 const SvNumberformat
* pOldEntry
= pFormatter
->GetEntry( nIndex
);
1698 const SvNumberformat
* pNewEntry
= pFormatter
->GetEntry( nNewIndex
);
1699 if ( pOldEntry
&& pNewEntry
&& pOldEntry
->GetFormatstring() == pNewEntry
->GetFormatstring() )
1702 else if ( eOffset
== NF_DATE_SYS_DMMMMYYYY
)
1704 sal_uInt32 nNewIndex
= pFormatter
->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY
, m_nFormatLang
);
1705 const SvNumberformat
* pOldEntry
= pFormatter
->GetEntry( nIndex
);
1706 const SvNumberformat
* pNewEntry
= pFormatter
->GetEntry( nNewIndex
);
1707 if ( pOldEntry
&& pNewEntry
&& pOldEntry
->GetFormatstring() == pNewEntry
->GetFormatstring() )
1712 if ((nIndex
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) && !m_sFormatTitle
.isEmpty())
1714 SvNumberformat
* pFormat
= const_cast<SvNumberformat
*>(pFormatter
->GetEntry( nIndex
));
1717 pFormat
->SetComment(m_sFormatTitle
);
1721 if ( nIndex
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1723 OSL_FAIL("invalid number format");
1724 nIndex
= pFormatter
->GetStandardIndex( m_nFormatLang
);
1727 m_pData
->AddKey( nIndex
, GetName(), m_bRemoveAfterUse
);
1730 // Add to import's list of keys (shared between styles and content import)
1731 // only if not volatile - formats are removed from NumberFormatter at the
1732 // end of each import (in SvXMLNumFmtHelper dtor).
1733 // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there.
1735 if (!m_bRemoveAfterUse
)
1736 GetImport().AddNumberStyle( m_nKey
, GetName() );
1741 const LocaleDataWrapper
& SvXMLNumFormatContext::GetLocaleData() const
1743 return m_pData
->GetLocaleData( m_nFormatLang
);
1746 void SvXMLNumFormatContext::AddToCode( sal_Unicode c
)
1748 m_aFormatCode
.append( c
);
1749 m_bHasExtraText
= true;
1752 void SvXMLNumFormatContext::AddToCode( std::u16string_view rString
)
1754 m_aFormatCode
.append( rString
);
1755 m_bHasExtraText
= true;
1756 m_bHasTrailingEmptyText
= false; // is set by caller again if so
1759 void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo
& rInfo
)
1761 SvNumberFormatter
* pFormatter
= m_pData
->GetNumberFormatter();
1765 // store special conditions
1766 m_bAutoDec
= ( rInfo
.nDecimals
< 0 );
1767 m_bAutoInt
= ( rInfo
.nInteger
< 0 );
1769 sal_uInt16 nPrec
= 0;
1770 sal_uInt16 nLeading
= 0;
1771 if ( rInfo
.nDecimals
>= 0 ) // < 0 : Default
1772 nPrec
= static_cast<sal_uInt16
>(rInfo
.nDecimals
);
1773 if ( rInfo
.nInteger
>= 0 ) // < 0 : Default
1774 nLeading
= static_cast<sal_uInt16
>(rInfo
.nInteger
);
1778 if ( m_nType
== SvXMLStylesTokens::CURRENCY_STYLE
)
1780 // for currency formats, "automatic decimals" is used for the automatic
1781 // currency format with (fixed) decimals from the locale settings
1783 const LocaleDataWrapper
& rLoc
= m_pData
->GetLocaleData( m_nFormatLang
);
1784 nPrec
= rLoc
.getCurrDigits();
1788 // for other types, "automatic decimals" means dynamic determination of
1789 // decimals, as achieved with the "general" keyword
1791 m_aFormatCode
.append( pFormatter
->GetStandardName( m_nFormatLang
) );
1800 sal_uInt16 nGenPrec
= nPrec
;
1801 if ( rInfo
.nMinDecimalDigits
>= 0 )
1802 nGenPrec
= rInfo
.nMinDecimalDigits
;
1803 if ( rInfo
.bDecReplace
)
1804 nGenPrec
= 0; // generate format without decimals...
1806 bool bGrouping
= rInfo
.bGrouping
;
1807 size_t const nEmbeddedCount
= rInfo
.m_EmbeddedElements
.size();
1808 if ( nEmbeddedCount
&& rInfo
.m_EmbeddedElements
.rbegin()->first
> 0 )
1809 bGrouping
= false; // grouping and embedded characters in integer part can't be used together
1811 sal_uInt32 nStdIndex
= pFormatter
->GetStandardIndex( m_nFormatLang
);
1812 OUStringBuffer
aNumStr(pFormatter
->GenerateFormat( nStdIndex
, m_nFormatLang
,
1813 bGrouping
, false, nGenPrec
, nLeading
));
1815 if ( rInfo
.nExpDigits
>= 0 && nLeading
== 0 && !bGrouping
&& nEmbeddedCount
== 0 )
1817 // #i43959# For scientific numbers, "#" in the integer part forces a digit,
1818 // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0").
1820 aNumStr
.stripStart('#');
1823 if ( rInfo
.nBlankInteger
> 0 )
1825 // Replace nBlankInteger '0' by '?'
1826 sal_Int32 nIndex
= 0;
1827 sal_Int32 nBlanks
= rInfo
.nBlankInteger
;
1828 sal_Int32 nIntegerEnd
= aNumStr
.indexOf( pFormatter
->GetNumDecimalSep() );
1829 if ( nIntegerEnd
< 0 )
1830 nIntegerEnd
= aNumStr
.getLength();
1831 while ( nIndex
< nIntegerEnd
&& nBlanks
> 0 )
1833 if ( aNumStr
[nIndex
] == '0' )
1835 aNumStr
[nIndex
] = '?';
1842 if ( bGrouping
&& rInfo
.nExpInterval
> rInfo
.nInteger
)
1844 sal_Int32 nIndex
= 0;
1845 sal_Int32 nDigits
= rInfo
.nInteger
;
1846 sal_Int32 nIntegerEnd
= aNumStr
.indexOf( pFormatter
->GetNumDecimalSep() );
1847 if ( nIntegerEnd
< 0 )
1848 nIntegerEnd
= aNumStr
.getLength();
1849 while ( nIndex
>= 0 && nIndex
< nIntegerEnd
)
1851 if ( ( nIndex
= aNumStr
.indexOf( '#', nIndex
) ) >= 0 )
1859 while ( rInfo
.nExpInterval
> nDigits
)
1862 aNumStr
.insert( 0, '#' );
1866 if ( ( rInfo
.bDecReplace
|| rInfo
.nMinDecimalDigits
< rInfo
.nDecimals
) && nPrec
) // add decimal replacement (dashes)
1868 // add dashes for explicit decimal replacement, # or ? for variable decimals
1869 sal_Unicode cAdd
= rInfo
.bDecReplace
? '-' : ( rInfo
.bDecAlign
? '?': '#' );
1871 if ( rInfo
.nMinDecimalDigits
== 0 )
1872 aNumStr
.append( m_pData
->GetLocaleData( m_nFormatLang
).getNumDecimalSep() );
1873 for ( sal_uInt16 i
=rInfo
.nMinDecimalDigits
; i
<nPrec
; i
++)
1874 aNumStr
.append( cAdd
);
1877 // Scientific number
1878 sal_Int32 nExpPos
= -1;
1879 if ( rInfo
.nExpDigits
> 0 )
1881 nExpPos
= aNumStr
.getLength();
1882 aNumStr
.append( rInfo
.bExponentLowercase
? u
"e" : u
"E" );
1883 // exponent sign is required with embedded text in exponent
1884 if ( rInfo
.bExpSign
|| ( nEmbeddedCount
&& ( rInfo
.nDecimals
+ 1 < -rInfo
.m_EmbeddedElements
.begin()->first
) ) )
1886 aNumStr
.append( u
"+" );
1888 for (sal_Int32 i
=0; i
<rInfo
.nExpDigits
; i
++)
1890 if ( i
< rInfo
.nBlankExp
)
1891 aNumStr
.append( '?' );
1893 aNumStr
.append( '0' );
1897 if ( nEmbeddedCount
)
1899 // insert embedded strings into number string
1900 // support integer (position >=0) and decimal (position <0) part
1901 // nZeroPos is the string position where format position 0 is inserted
1903 sal_Int32 nZeroPos
= aNumStr
.indexOf( m_pData
->GetLocaleData( m_nFormatLang
).getNumDecimalSep() );
1906 nZeroPos
= aNumStr
.getLength();
1909 // m_EmbeddedElements is sorted - last entry has the largest position (leftmost)
1910 sal_Int32
const nLastFormatPos
= rInfo
.m_EmbeddedElements
.rbegin()->first
;
1911 if ( nLastFormatPos
>= nZeroPos
)
1913 // add '#' characters so all embedded texts are really embedded in digits
1914 // (there always has to be a digit before the leftmost embedded text)
1916 sal_Int32 nAddCount
= nLastFormatPos
+ 1 - nZeroPos
;
1917 for(sal_Int32 index
= 0; index
< nAddCount
; ++index
)
1919 aNumStr
.insert(0, '#');
1921 nZeroPos
= nZeroPos
+ nAddCount
;
1923 nExpPos
= nExpPos
+ nAddCount
;
1926 // m_EmbeddedElements is sorted with ascending positions - loop is from right to left
1927 for (auto const& it
: rInfo
.m_EmbeddedElements
)
1929 sal_Int32
const nFormatPos
= it
.first
;
1930 sal_Int32 nInsertPos
= nZeroPos
- nFormatPos
;
1931 if ( nExpPos
> 0 && nInsertPos
> nExpPos
)
1933 if ( 0 <= nInsertPos
&& nInsertPos
<= aNumStr
.getLength() )
1935 aNumStr
.insert( nInsertPos
, it
.second
);
1940 m_aFormatCode
.append( aNumStr
);
1942 // add extra thousands separators for display factor
1944 if (rInfo
.fDisplayFactor
== 1.0 || rInfo
.fDisplayFactor
<= 0.0)
1947 // test for 1.0 is just for optimization - nSepCount would be 0
1949 // one separator for each factor of 1000
1950 sal_Int32 nSepCount
= static_cast<sal_Int32
>(::rtl::math::round( log10(rInfo
.fDisplayFactor
) / 3.0 ));
1951 if ( nSepCount
> 0 )
1953 OUString aSep
= m_pData
->GetLocaleData( m_nFormatLang
).getNumThousandSep();
1954 for ( sal_Int32 i
=0; i
<nSepCount
; i
++ )
1955 m_aFormatCode
.append( aSep
);
1959 void SvXMLNumFormatContext::AddCurrency( const OUString
& rContent
, LanguageType nLang
)
1961 bool bAutomatic
= false;
1962 OUString aSymbol
= rContent
;
1963 if ( aSymbol
.isEmpty())
1965 SvNumberFormatter
* pFormatter
= m_pData
->GetNumberFormatter();
1968 pFormatter
->ChangeIntl( m_nFormatLang
);
1969 OUString sCurString
, sDummy
;
1970 pFormatter
->GetCompatibilityCurrency( sCurString
, sDummy
);
1971 aSymbol
= sCurString
;
1976 else if ( nLang
== LANGUAGE_SYSTEM
&& aSymbol
== "CCC" )
1978 // "CCC" is used for automatic long symbol
1984 // remove unnecessary quotes before automatic symbol (formats like "-(0DM)")
1985 // otherwise the currency symbol isn't recognized (#94048#)
1987 sal_Int32 nLength
= m_aFormatCode
.getLength();
1988 if ( nLength
> 1 && m_aFormatCode
[nLength
- 1] == '"' )
1990 // find start of quoted string
1991 // When SvXMLNumFmtElementContext::EndElement creates escaped quotes,
1992 // they must be handled here, too.
1994 sal_Int32 nFirst
= nLength
- 2;
1995 while ( nFirst
>= 0 && m_aFormatCode
[nFirst
] != '"' )
1999 // remove both quotes from aFormatCode
2000 OUString aOld
= m_aFormatCode
.makeStringAndClear();
2002 m_aFormatCode
.append( aOld
.subView( 0, nFirst
) );
2003 if ( nLength
> nFirst
+ 2 )
2004 m_aFormatCode
.append( aOld
.subView( nFirst
+ 1, nLength
- nFirst
- 2 ) );
2010 m_aFormatCode
.append( "[$" ); // intro for "new" currency symbols
2012 m_aFormatCode
.append( aSymbol
);
2016 if ( nLang
!= LANGUAGE_SYSTEM
)
2018 // '-' sign and language code in hex:
2019 m_aFormatCode
.append("-" + OUString(OUString::number(sal_uInt16(nLang
), 16)).toAsciiUpperCase());
2022 m_aFormatCode
.append( ']' ); // end of "new" currency symbol
2026 void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex
)
2028 SvNumberFormatter
* pFormatter
= m_pData
->GetNumberFormatter();
2032 if ( nIndex
== NF_KEY_NNNN
)
2034 nIndex
= NF_KEY_NNN
;
2035 m_bHasLongDoW
= true; // to remove string constant with separator
2038 OUString sKeyword
= pFormatter
->GetKeyword( m_nFormatLang
, nIndex
);
2040 if ( nIndex
== NF_KEY_H
|| nIndex
== NF_KEY_HH
||
2041 nIndex
== NF_KEY_MI
|| nIndex
== NF_KEY_MMI
||
2042 nIndex
== NF_KEY_S
|| nIndex
== NF_KEY_SS
)
2044 if ( !m_bTruncate
&& !m_bHasDateTime
)
2046 // with truncate-on-overflow = false, add "[]" to first time part
2047 m_aFormatCode
.append("[" + sKeyword
+ "]");
2051 m_aFormatCode
.append( sKeyword
);
2053 m_bHasDateTime
= true;
2057 m_aFormatCode
.append( sKeyword
);
2059 // collect the date elements that the format contains, to recognize default date formats
2062 case NF_KEY_NN
: m_eDateDOW
= XML_DEA_SHORT
; break;
2064 case NF_KEY_NNNN
: m_eDateDOW
= XML_DEA_LONG
; break;
2065 case NF_KEY_D
: m_eDateDay
= XML_DEA_SHORT
; break;
2066 case NF_KEY_DD
: m_eDateDay
= XML_DEA_LONG
; break;
2067 case NF_KEY_M
: m_eDateMonth
= XML_DEA_SHORT
; break;
2068 case NF_KEY_MM
: m_eDateMonth
= XML_DEA_LONG
; break;
2069 case NF_KEY_MMM
: m_eDateMonth
= XML_DEA_TEXTSHORT
; break;
2070 case NF_KEY_MMMM
: m_eDateMonth
= XML_DEA_TEXTLONG
; break;
2071 case NF_KEY_YY
: m_eDateYear
= XML_DEA_SHORT
; break;
2072 case NF_KEY_YYYY
: m_eDateYear
= XML_DEA_LONG
; break;
2073 case NF_KEY_H
: m_eDateHours
= XML_DEA_SHORT
; break;
2074 case NF_KEY_HH
: m_eDateHours
= XML_DEA_LONG
; break;
2075 case NF_KEY_MI
: m_eDateMins
= XML_DEA_SHORT
; break;
2076 case NF_KEY_MMI
: m_eDateMins
= XML_DEA_LONG
; break;
2077 case NF_KEY_S
: m_eDateSecs
= XML_DEA_SHORT
; break;
2078 case NF_KEY_SS
: m_eDateSecs
= XML_DEA_LONG
; break;
2080 case NF_KEY_AMPM
: break; // AM/PM may or may not be in date/time formats -> ignore by itself
2082 m_bDateNoDefault
= true; // any other element -> no default format
2086 static bool lcl_IsAtEnd( OUStringBuffer
& rBuffer
, std::u16string_view rToken
)
2088 sal_Int32 nBufLen
= rBuffer
.getLength();
2089 sal_Int32 nTokLen
= rToken
.size();
2091 if ( nTokLen
> nBufLen
)
2094 sal_Int32 nStartPos
= nBufLen
- nTokLen
;
2095 for ( sal_Int32 nTokPos
= 0; nTokPos
< nTokLen
; nTokPos
++ )
2096 if ( rToken
[ nTokPos
] != rBuffer
[nStartPos
+ nTokPos
] )
2102 bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld
, sal_uInt16 nNew
)
2104 // replaces one keyword with another if it is found at the end of the code
2106 SvNumberFormatter
* pFormatter
= m_pData
->GetNumberFormatter();
2110 OUString sOldStr
= pFormatter
->GetKeyword( m_nFormatLang
, nOld
);
2111 if ( lcl_IsAtEnd( m_aFormatCode
, sOldStr
) )
2113 // remove old keyword
2114 m_aFormatCode
.setLength( m_aFormatCode
.getLength() - sOldStr
.getLength() );
2117 OUString sNewStr
= pFormatter
->GetKeyword( m_nFormatLang
, nNew
);
2118 m_aFormatCode
.append( sNewStr
);
2120 return true; // changed
2122 return false; // not found
2125 void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex
)
2127 OUString rApplyName
= m_aMyConditions
[nIndex
].sMapName
;
2128 OUString rCondition
= m_aMyConditions
[nIndex
].sCondition
;
2129 SvNumberFormatter
* pFormatter
= m_pData
->GetNumberFormatter();
2130 sal_uInt32 l_nKey
= m_pData
->GetKeyForName( rApplyName
);
2133 if ( !(pFormatter
&& l_nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
&&
2134 rCondition
.startsWith("value()", &sRealCond
)) )
2137 //! test for valid conditions
2138 //! test for default conditions
2140 bool bDefaultCond
= false;
2142 //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count
2143 //! allow blanks in conditions
2144 if ( m_aConditions
.isEmpty() && m_aMyConditions
.size() == 1 && sRealCond
== ">=0" )
2145 bDefaultCond
= true;
2147 if ( m_nType
== SvXMLStylesTokens::TEXT_STYLE
&& static_cast<size_t>(nIndex
) == m_aMyConditions
.size() - 1 )
2149 // The last condition in a number format with a text part can only
2150 // be "all other numbers", the condition string must be empty.
2151 bDefaultCond
= true;
2157 sal_Int32 nPos
= sRealCond
.indexOf( "!=" );
2160 sRealCond
= sRealCond
.replaceAt( nPos
, 2, u
"<>" );
2163 nPos
= sRealCond
.indexOf( '.' );
2166 // #i8026# #103991# localize decimal separator
2167 const OUString
& rDecSep
= GetLocaleData().getNumDecimalSep();
2168 if ( rDecSep
.getLength() > 1 || rDecSep
[0] != '.' )
2170 sRealCond
= sRealCond
.replaceAt( nPos
, 1, rDecSep
);
2173 m_aConditions
.append("[" + sRealCond
+ "]");
2176 const SvNumberformat
* pFormat
= pFormatter
->GetEntry(l_nKey
);
2178 m_aConditions
.append( pFormat
->GetFormatstring() );
2180 m_aConditions
.append( ';' );
2183 void SvXMLNumFormatContext::AddCondition( const OUString
& rCondition
, const OUString
& rApplyName
)
2185 MyCondition aCondition
;
2186 aCondition
.sCondition
= rCondition
;
2187 aCondition
.sMapName
= rApplyName
;
2188 m_aMyConditions
.push_back(aCondition
);
2191 void SvXMLNumFormatContext::AddColor( Color
const nColor
)
2193 SvNumberFormatter
* pFormatter
= m_pData
->GetNumberFormatter();
2197 OUStringBuffer aColName
;
2198 for ( sal_uInt16 i
=0; i
<XML_NUMF_COLORCOUNT
; i
++ )
2199 if (nColor
== aNumFmtStdColors
[i
])
2201 aColName
= pFormatter
->GetKeyword( m_nFormatLang
, sal::static_int_cast
< sal_uInt16
>(NF_KEY_FIRSTCOLOR
+ i
) );
2205 if ( !aColName
.isEmpty() )
2207 aColName
.insert( 0, '[' );
2208 aColName
.append( ']' );
2209 m_aFormatCode
.insert( 0, aColName
);
2213 void SvXMLNumFormatContext::UpdateCalendar( const OUString
& rNewCalendar
)
2215 if ( rNewCalendar
== m_sCalendar
)
2218 if (rNewCalendar
.isEmpty() || rNewCalendar
== m_aImplicitCalendar
[0])
2220 m_eImplicitCalendar
= (m_eImplicitCalendar
== ImplicitCalendar::OTHER
?
2221 ImplicitCalendar::DEFAULT_FROM_OTHER
: ImplicitCalendar::DEFAULT
);
2223 else if (m_aImplicitCalendar
[0].isEmpty() && rNewCalendar
== GetLocaleData().getDefaultCalendar()->Name
)
2225 m_eImplicitCalendar
= (m_eImplicitCalendar
== ImplicitCalendar::OTHER
?
2226 ImplicitCalendar::DEFAULT_FROM_OTHER
: ImplicitCalendar::DEFAULT
);
2227 m_aImplicitCalendar
[0] = rNewCalendar
;
2229 else if (rNewCalendar
== m_aImplicitCalendar
[1])
2231 m_eImplicitCalendar
= (m_eImplicitCalendar
== ImplicitCalendar::OTHER
?
2232 ImplicitCalendar::SECONDARY_FROM_OTHER
: ImplicitCalendar::SECONDARY
);
2234 else if (m_aImplicitCalendar
[1].isEmpty() && GetLocaleData().doesSecondaryCalendarUseEC( rNewCalendar
))
2236 m_eImplicitCalendar
= (m_eImplicitCalendar
== ImplicitCalendar::OTHER
?
2237 ImplicitCalendar::SECONDARY_FROM_OTHER
: ImplicitCalendar::SECONDARY
);
2238 m_aImplicitCalendar
[1] = rNewCalendar
;
2242 m_eImplicitCalendar
= ImplicitCalendar::OTHER
;
2245 if (m_eImplicitCalendar
!= ImplicitCalendar::DEFAULT
&& m_eImplicitCalendar
!= ImplicitCalendar::SECONDARY
)
2247 // A switch from empty default calendar to named default calendar or
2248 // vice versa is not a switch.
2249 bool bSameDefault
= false;
2250 if (m_sCalendar
.isEmpty() || rNewCalendar
.isEmpty())
2252 // As both are not equal, only one can be empty here, the other
2254 const OUString
& rDefaultCalendar
= GetLocaleData().getDefaultCalendar()->Name
;
2255 // So if one is the named default calendar the other is the
2256 // empty default calendar.
2257 bSameDefault
= (rNewCalendar
== rDefaultCalendar
|| m_sCalendar
== rDefaultCalendar
);
2261 m_aFormatCode
.append( "[~" ); // intro for calendar code
2262 if (rNewCalendar
.isEmpty())
2264 // Empty calendar name here means switching to default calendar
2265 // from a different calendar. Needs to be explicitly stated in
2267 m_aFormatCode
.append( GetLocaleData().getDefaultCalendar()->Name
);
2271 m_aFormatCode
.append( rNewCalendar
);
2273 m_aFormatCode
.append( ']' ); // end of calendar code
2276 m_sCalendar
= rNewCalendar
;
2279 bool SvXMLNumFormatContext::IsSystemLanguage() const
2281 return m_nFormatLang
== LANGUAGE_SYSTEM
;
2285 // SvXMLNumFmtHelper
2288 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2289 const uno::Reference
<util::XNumberFormatsSupplier
>& rSupp
,
2290 const uno::Reference
<uno::XComponentContext
>& rxContext
)
2292 SAL_WARN_IF( !rxContext
.is(), "xmloff", "got no service manager" );
2294 SvNumberFormatter
* pFormatter
= nullptr;
2295 SvNumberFormatsSupplierObj
* pObj
=
2296 comphelper::getFromUnoTunnel
<SvNumberFormatsSupplierObj
>( rSupp
);
2298 pFormatter
= pObj
->GetNumberFormatter();
2300 m_pData
= std::make_unique
<SvXMLNumImpData
>( pFormatter
, rxContext
);
2303 SvXMLNumFmtHelper::SvXMLNumFmtHelper(
2304 SvNumberFormatter
* pNumberFormatter
,
2305 const uno::Reference
<uno::XComponentContext
>& rxContext
)
2307 SAL_WARN_IF( !rxContext
.is(), "xmloff", "got no service manager" );
2309 m_pData
= std::make_unique
<SvXMLNumImpData
>( pNumberFormatter
, rxContext
);
2312 SvXMLNumFmtHelper::~SvXMLNumFmtHelper()
2314 // remove temporary (volatile) formats from NumberFormatter
2315 m_pData
->RemoveVolatileFormats();
2319 SvXMLStyleContext
* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport
& rImport
,
2321 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
,
2322 SvXMLStylesContext
& rStyles
)
2324 SvXMLStylesTokens nStyleToken
;
2327 case XML_ELEMENT(NUMBER
, XML_NUMBER_STYLE
):
2328 nStyleToken
= SvXMLStylesTokens::NUMBER_STYLE
;
2330 case XML_ELEMENT(NUMBER
, XML_CURRENCY_STYLE
):
2331 nStyleToken
= SvXMLStylesTokens::CURRENCY_STYLE
;
2333 case XML_ELEMENT(NUMBER
, XML_PERCENTAGE_STYLE
):
2334 nStyleToken
= SvXMLStylesTokens::PERCENTAGE_STYLE
;
2336 case XML_ELEMENT(NUMBER
, XML_DATE_STYLE
):
2337 nStyleToken
= SvXMLStylesTokens::DATE_STYLE
;
2339 case XML_ELEMENT(NUMBER
, XML_TIME_STYLE
):
2340 nStyleToken
= SvXMLStylesTokens::TIME_STYLE
;
2342 case XML_ELEMENT(NUMBER
, XML_BOOLEAN_STYLE
):
2343 nStyleToken
= SvXMLStylesTokens::BOOLEAN_STYLE
;
2345 case XML_ELEMENT(NUMBER
, XML_TEXT_STYLE
):
2346 nStyleToken
= SvXMLStylesTokens::TEXT_STYLE
;
2349 // return NULL if not a data style, caller must handle other elements
2352 return new SvXMLNumFormatContext( rImport
, nElement
,
2353 m_pData
.get(), nStyleToken
, xAttrList
, rStyles
);
2356 LanguageType
SvXMLNumFmtHelper::GetLanguageForKey(sal_Int32 nKey
) const
2358 if (m_pData
->GetNumberFormatter())
2360 const SvNumberformat
* pEntry
= m_pData
->GetNumberFormatter()->GetEntry(nKey
);
2362 return pEntry
->GetLanguage();
2365 return LANGUAGE_SYSTEM
;
2368 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */