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 <comphelper/sequence.hxx>
21 #include <comphelper/string.hxx>
22 #include <svl/numformat.hxx>
23 #include <svl/zforlist.hxx>
24 #include <svl/zformat.hxx>
25 #include <svl/numuno.hxx>
26 #include <i18nlangtag/mslangid.hxx>
27 #include <i18nlangtag/languagetag.hxx>
28 #include <tools/debug.hxx>
29 #include <rtl/math.hxx>
30 #include <unotools/calendarwrapper.hxx>
31 #include <unotools/charclass.hxx>
32 #include <com/sun/star/lang/Locale.hpp>
33 #include <rtl/ustrbuf.hxx>
34 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
36 #include <tools/color.hxx>
37 #include <sax/tools/converter.hxx>
39 #include <com/sun/star/i18n/NativeNumberXmlAttributes2.hpp>
42 #include <xmloff/xmlnumfe.hxx>
43 #include <xmloff/xmlnamespace.hxx>
44 #include <xmloff/xmlnumfi.hxx>
46 #include <svl/nfsymbol.hxx>
47 #include <xmloff/xmltoken.hxx>
48 #include <xmloff/xmlexp.hxx>
49 #include <o3tl/string_view.hxx>
53 #include <string_view>
56 using namespace ::com::sun::star
;
57 using namespace ::xmloff::token
;
58 using namespace ::svt
;
60 typedef std::set
< sal_uInt32
> SvXMLuInt32Set
;
64 struct SvXMLEmbeddedTextEntry
66 sal_uInt16 nSourcePos
; // position in NumberFormat (to skip later)
67 sal_Int32 nFormatPos
; // resulting position in embedded-text element
70 SvXMLEmbeddedTextEntry( sal_uInt16 nSP
, sal_Int32 nFP
, OUString aT
) :
71 nSourcePos(nSP
), nFormatPos(nFP
), aText(std::move(aT
)) {}
76 class SvXMLEmbeddedTextEntryArr
78 typedef std::vector
<SvXMLEmbeddedTextEntry
> DataType
;
83 void push_back( SvXMLEmbeddedTextEntry
const& r
)
88 const SvXMLEmbeddedTextEntry
& operator[] ( size_t i
) const
99 class SvXMLNumUsedList_Impl
101 SvXMLuInt32Set aUsed
;
102 SvXMLuInt32Set aWasUsed
;
103 SvXMLuInt32Set::iterator aCurrentUsedPos
;
104 sal_uInt32 nUsedCount
;
105 sal_uInt32 nWasUsedCount
;
108 SvXMLNumUsedList_Impl();
110 void SetUsed( sal_uInt32 nKey
);
111 bool IsUsed( sal_uInt32 nKey
) const;
112 bool IsWasUsed( sal_uInt32 nKey
) const;
115 bool GetFirstUsed(sal_uInt32
& nKey
);
116 bool GetNextUsed(sal_uInt32
& nKey
);
118 uno::Sequence
<sal_Int32
> GetWasUsed() const;
119 void SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
);
122 //! SvXMLNumUsedList_Impl should be optimized!
124 SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() :
130 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey
)
132 if ( !IsWasUsed(nKey
) )
134 std::pair
<SvXMLuInt32Set::iterator
, bool> aPair
= aUsed
.insert( nKey
);
140 bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey
) const
142 SvXMLuInt32Set::const_iterator aItr
= aUsed
.find(nKey
);
143 return (aItr
!= aUsed
.end());
146 bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey
) const
148 SvXMLuInt32Set::const_iterator aItr
= aWasUsed
.find(nKey
);
149 return (aItr
!= aWasUsed
.end());
152 void SvXMLNumUsedList_Impl::Export()
154 SvXMLuInt32Set::const_iterator aItr
= aUsed
.begin();
155 while (aItr
!= aUsed
.end())
157 std::pair
<SvXMLuInt32Set::const_iterator
, bool> aPair
= aWasUsed
.insert( *aItr
);
166 bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32
& nKey
)
169 aCurrentUsedPos
= aUsed
.begin();
172 DBG_ASSERT(aCurrentUsedPos
!= aUsed
.end(), "something went wrong");
173 nKey
= *aCurrentUsedPos
;
179 bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32
& nKey
)
182 if (aCurrentUsedPos
!= aUsed
.end())
185 if (aCurrentUsedPos
!= aUsed
.end())
187 nKey
= *aCurrentUsedPos
;
194 uno::Sequence
<sal_Int32
> SvXMLNumUsedList_Impl::GetWasUsed() const
196 return comphelper::containerToSequence
<sal_Int32
>(aWasUsed
);
199 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
201 DBG_ASSERT(nWasUsedCount
== 0, "WasUsed should be empty");
202 for (const auto nWasUsed
: rWasUsed
)
204 std::pair
<SvXMLuInt32Set::const_iterator
, bool> aPair
= aWasUsed
.insert( nWasUsed
);
210 SvXMLNumFmtExport::SvXMLNumFmtExport(
212 const uno::Reference
< util::XNumberFormatsSupplier
>& rSupp
) :
214 sPrefix( OUString("N") ),
215 pFormatter( nullptr ),
218 // supplier must be SvNumberFormatsSupplierObj
219 SvNumberFormatsSupplierObj
* pObj
=
220 comphelper::getFromUnoTunnel
<SvNumberFormatsSupplierObj
>( rSupp
);
222 pFormatter
= pObj
->GetNumberFormatter();
226 pLocaleData
.reset( new LocaleDataWrapper( pFormatter
->GetComponentContext(),
227 pFormatter
->GetLanguageTag() ) );
231 LanguageTag
aLanguageTag( MsLangId::getConfiguredSystemLanguage() );
233 pLocaleData
.reset( new LocaleDataWrapper( rExport
.getComponentContext(), std::move(aLanguageTag
) ) );
236 pUsedList
.reset(new SvXMLNumUsedList_Impl
);
239 SvXMLNumFmtExport::SvXMLNumFmtExport(
241 const css::uno::Reference
< css::util::XNumberFormatsSupplier
>& rSupp
,
244 sPrefix(std::move( aPrefix
)),
245 pFormatter( nullptr ),
248 // supplier must be SvNumberFormatsSupplierObj
249 SvNumberFormatsSupplierObj
* pObj
=
250 comphelper::getFromUnoTunnel
<SvNumberFormatsSupplierObj
>( rSupp
);
252 pFormatter
= pObj
->GetNumberFormatter();
256 pLocaleData
.reset( new LocaleDataWrapper( pFormatter
->GetComponentContext(),
257 pFormatter
->GetLanguageTag() ) );
261 LanguageTag
aLanguageTag( MsLangId::getConfiguredSystemLanguage() );
263 pLocaleData
.reset( new LocaleDataWrapper( rExport
.getComponentContext(), std::move(aLanguageTag
) ) );
266 pUsedList
.reset(new SvXMLNumUsedList_Impl
);
269 SvXMLNumFmtExport::~SvXMLNumFmtExport()
275 static OUString
lcl_CreateStyleName( sal_Int32 nKey
, sal_Int32 nPart
, bool bDefPart
, std::u16string_view rPrefix
)
277 OUStringBuffer
aFmtName(10);
278 aFmtName
.append( rPrefix
);
279 aFmtName
.append( nKey
);
282 aFmtName
.append( 'P' );
283 aFmtName
.append( nPart
);
285 return aFmtName
.makeStringAndClear();
288 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString
& rCalendar
)
290 if ( !rCalendar
.isEmpty() )
292 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_CALENDAR
, rCalendar
);
296 void SvXMLNumFmtExport::AddStyleAttr_Impl( bool bLong
)
298 if ( bLong
) // short is default
300 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_STYLE
, XML_LONG
);
304 void SvXMLNumFmtExport::AddLanguageAttr_Impl( LanguageType nLang
)
306 if ( nLang
!= LANGUAGE_SYSTEM
)
308 rExport
.AddLanguageTagAttributes( XML_NAMESPACE_NUMBER
, XML_NAMESPACE_NUMBER
,
309 LanguageTag( nLang
), false);
313 // methods to write individual elements within a format
315 void SvXMLNumFmtExport::AddToTextElement_Impl( std::u16string_view rString
)
317 // append to sTextContent, write element in FinishTextElement_Impl
318 // to avoid several text elements following each other
320 sTextContent
.append( rString
);
321 // Also empty string leads to a number:text element as it may separate
322 // keywords of the same letter (e.g. MM""MMM) that otherwise would be
323 // concatenated when reading back in.
327 void SvXMLNumFmtExport::FinishTextElement_Impl(bool bUseExtensionNS
)
331 sal_uInt16 nNS
= bUseExtensionNS
? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
;
332 SvXMLElementExport
aElem( rExport
, nNS
, XML_TEXT
,
334 rExport
.Characters( sTextContent
.makeStringAndClear() );
339 void SvXMLNumFmtExport::WriteColorElement_Impl( const Color
& rColor
)
341 FinishTextElement_Impl();
343 OUStringBuffer
aColStr( 7 );
344 ::sax::Converter::convertColor( aColStr
, rColor
);
345 rExport
.AddAttribute( XML_NAMESPACE_FO
, XML_COLOR
,
346 aColStr
.makeStringAndClear() );
348 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_TEXT_PROPERTIES
,
352 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString
& rString
,
353 std::u16string_view rExt
)
355 FinishTextElement_Impl();
359 // rExt should be a 16-bit hex value max FFFF which may contain a
360 // leading "-" separator (that is not a minus sign, but toInt32 can be
361 // used to parse it, with post-processing as necessary):
362 sal_Int32 nLang
= o3tl::toInt32(rExt
, 16);
365 SAL_WARN_IF(nLang
> 0xFFFF, "xmloff.style", "Out of range Lang Id: " << nLang
<< " from input string: " << OUString(rExt
));
366 AddLanguageAttr_Impl( LanguageType(nLang
& 0xFFFF) ); // adds to pAttrList
369 SvXMLElementExport
aElem( rExport
,
370 XML_NAMESPACE_NUMBER
, XML_CURRENCY_SYMBOL
,
372 rExport
.Characters( rString
);
375 void SvXMLNumFmtExport::WriteBooleanElement_Impl()
377 FinishTextElement_Impl();
379 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_BOOLEAN
,
383 void SvXMLNumFmtExport::WriteTextContentElement_Impl()
385 FinishTextElement_Impl();
387 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT_CONTENT
,
393 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString
& rCalendar
, bool bLong
)
395 FinishTextElement_Impl();
397 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
398 AddStyleAttr_Impl( bLong
); // adds to pAttrList
400 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY
,
404 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString
& rCalendar
, bool bLong
, bool bText
)
406 FinishTextElement_Impl();
408 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
409 AddStyleAttr_Impl( bLong
); // adds to pAttrList
412 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TEXTUAL
, XML_TRUE
);
415 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MONTH
,
419 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString
& rCalendar
, bool bLong
)
421 FinishTextElement_Impl();
423 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
424 AddStyleAttr_Impl( bLong
); // adds to pAttrList
426 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_YEAR
,
430 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString
& rCalendar
, bool bLong
)
432 FinishTextElement_Impl();
434 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
435 AddStyleAttr_Impl( bLong
); // adds to pAttrList
437 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_ERA
,
441 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString
& rCalendar
, bool bLong
)
443 FinishTextElement_Impl();
445 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
446 AddStyleAttr_Impl( bLong
); // adds to pAttrList
448 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_DAY_OF_WEEK
,
452 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString
& rCalendar
)
454 FinishTextElement_Impl();
456 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
458 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_WEEK_OF_YEAR
,
462 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString
& rCalendar
, bool bLong
)
464 FinishTextElement_Impl();
466 AddCalendarAttr_Impl( rCalendar
); // adds to pAttrList
467 AddStyleAttr_Impl( bLong
); // adds to pAttrList
469 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_QUARTER
,
475 void SvXMLNumFmtExport::WriteHoursElement_Impl( bool bLong
)
477 FinishTextElement_Impl();
479 AddStyleAttr_Impl( bLong
); // adds to pAttrList
481 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_HOURS
,
485 void SvXMLNumFmtExport::WriteMinutesElement_Impl( bool bLong
)
487 FinishTextElement_Impl();
489 AddStyleAttr_Impl( bLong
); // adds to pAttrList
491 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_MINUTES
,
495 void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar
)
497 // Export only for 1.2 with extensions or 1.3 and later.
498 SvtSaveOptions::ODFSaneDefaultVersion eVersion
= rExport
.getSaneDefaultVersion();
499 if (eVersion
> SvtSaveOptions::ODFSVER_012
)
501 FinishTextElement_Impl(eVersion
< SvtSaveOptions::ODFSVER_013
);
502 // OFFICE-3765 For 1.2+ use loext namespace, for 1.3 use number namespace.
503 SvXMLElementExport
aElem( rExport
,
504 ((eVersion
< SvtSaveOptions::ODFSVER_013
) ? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
),
505 XML_FILL_CHARACTER
, true, false );
506 rExport
.Characters( OUString( nChar
) );
510 void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong
, sal_uInt16 nDecimals
)
512 FinishTextElement_Impl();
514 AddStyleAttr_Impl( bLong
); // adds to pAttrList
517 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
518 OUString::number( nDecimals
) );
521 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_SECONDS
,
525 void SvXMLNumFmtExport::WriteAMPMElement_Impl()
527 FinishTextElement_Impl();
529 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_AM_PM
,
535 void SvXMLNumFmtExport::WriteNumberElement_Impl(
536 sal_Int32 nDecimals
, sal_Int32 nMinDecimals
,
537 sal_Int32 nInteger
, const OUString
& rDashStr
,
538 bool bGrouping
, sal_Int32 nTrailingThousands
,
539 const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
)
541 FinishTextElement_Impl();
544 if ( nDecimals
>= 0 ) // negative = automatic
546 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
547 OUString::number( nDecimals
) );
550 if ( nMinDecimals
>= 0 ) // negative = automatic
552 // Export only for 1.2 with extensions or 1.3 and later.
553 SvtSaveOptions::ODFSaneDefaultVersion eVersion
= rExport
.getSaneDefaultVersion();
554 if (eVersion
> SvtSaveOptions::ODFSVER_012
)
556 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
557 rExport
.AddAttribute(
558 ((eVersion
< SvtSaveOptions::ODFSVER_013
) ? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
),
559 XML_MIN_DECIMAL_PLACES
,
560 OUString::number( nMinDecimals
) );
565 if ( nInteger
>= 0 ) // negative = automatic
567 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
568 OUString::number( nInteger
) );
571 // decimal replacement (dashes) or variable decimals (#)
572 if ( !rDashStr
.isEmpty() || nMinDecimals
< nDecimals
)
574 // full variable decimals means an empty replacement string
575 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_REPLACEMENT
,
579 // (automatic) grouping separator
582 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
585 // display-factor if there are trailing thousands separators
586 if ( nTrailingThousands
)
588 // each separator character removes three digits
589 double fFactor
= ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands
);
591 OUStringBuffer aFactStr
;
592 ::sax::Converter::convertDouble( aFactStr
, fFactor
);
593 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DISPLAY_FACTOR
, aFactStr
.makeStringAndClear() );
596 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_NUMBER
,
599 // number:embedded-text as child elements
601 auto nEntryCount
= rEmbeddedEntries
.size();
602 for (decltype(nEntryCount
) nEntry
=0; nEntry
< nEntryCount
; ++nEntry
)
604 const SvXMLEmbeddedTextEntry
*const pObj
= &rEmbeddedEntries
[nEntry
];
606 // position attribute
607 // position == 0 is between first integer digit and decimal separator
608 // position < 0 is inside decimal part
609 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_POSITION
,
610 OUString::number( pObj
->nFormatPos
) );
611 SvXMLElementExport
aChildElem( rExport
, XML_NAMESPACE_NUMBER
, XML_EMBEDDED_TEXT
,
614 // text as element content
615 OUStringBuffer
aContent( pObj
->aText
);
616 while ( nEntry
+1 < nEntryCount
&& rEmbeddedEntries
[nEntry
+1].nFormatPos
== pObj
->nFormatPos
)
618 // The array can contain several elements for the same position in the number
619 // (for example, literal text and space from underscores). They must be merged
620 // into a single embedded-text element.
621 aContent
.append(rEmbeddedEntries
[nEntry
+1].aText
);
624 rExport
.Characters( aContent
.makeStringAndClear() );
628 void SvXMLNumFmtExport::WriteScientificElement_Impl(
629 sal_Int32 nDecimals
, sal_Int32 nMinDecimals
, sal_Int32 nInteger
,
630 bool bGrouping
, sal_Int32 nExp
, sal_Int32 nExpInterval
, bool bExpSign
)
632 FinishTextElement_Impl();
635 if ( nDecimals
>= 0 ) // negative = automatic
637 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DECIMAL_PLACES
,
638 OUString::number( nDecimals
) );
641 SvtSaveOptions::ODFSaneDefaultVersion eVersion
= rExport
.getSaneDefaultVersion();
642 if ( nMinDecimals
>= 0 ) // negative = automatic
644 // Export only for 1.2 with extensions or 1.3 and later.
645 if (eVersion
> SvtSaveOptions::ODFSVER_012
)
647 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
648 rExport
.AddAttribute(
649 ((eVersion
< SvtSaveOptions::ODFSVER_013
) ? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
),
650 XML_MIN_DECIMAL_PLACES
,
651 OUString::number( nMinDecimals
) );
656 if ( nInteger
>= 0 ) // negative = automatic
658 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
659 OUString::number( nInteger
) );
662 // (automatic) grouping separator
665 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
671 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_EXPONENT_DIGITS
,
672 OUString::number( nExp
) );
675 // exponent interval for engineering notation
676 if ( nExpInterval
>= 0 )
678 // Export only for 1.2 with extensions or 1.3 and later.
679 if (eVersion
> SvtSaveOptions::ODFSVER_012
)
681 // OFFICE-1828 For 1.2+ use loext namespace, for 1.3 use number namespace.
682 rExport
.AddAttribute(
683 ((eVersion
< SvtSaveOptions::ODFSVER_013
) ? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
),
684 XML_EXPONENT_INTERVAL
, OUString::number( nExpInterval
) );
689 // Export only for 1.2 with extensions or 1.3 and later.
690 if (eVersion
> SvtSaveOptions::ODFSVER_012
)
692 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
693 rExport
.AddAttribute(
694 ((eVersion
< SvtSaveOptions::ODFSVER_013
) ? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
),
695 XML_FORCED_EXPONENT_SIGN
,
696 bExpSign
? XML_TRUE
: XML_FALSE
);
699 SvXMLElementExport
aElem( rExport
,
700 XML_NAMESPACE_NUMBER
, XML_SCIENTIFIC_NUMBER
,
704 void SvXMLNumFmtExport::WriteFractionElement_Impl(
705 sal_Int32 nInteger
, bool bGrouping
,
706 const SvNumberformat
& rFormat
, sal_uInt16 nPart
)
708 FinishTextElement_Impl();
709 const OUString aNumeratorString
= rFormat
.GetNumeratorString( nPart
);
710 const OUString aDenominatorString
= rFormat
.GetDenominatorString( nPart
);
711 const OUString aIntegerFractionDelimiterString
= rFormat
.GetIntegerFractionDelimiterString( nPart
);
712 sal_Int32 nMaxNumeratorDigits
= aNumeratorString
.getLength();
714 sal_Int32 nMinNumeratorDigits
= aNumeratorString
.replaceAll("0","?").indexOf('?');
715 sal_Int32 nZerosNumeratorDigits
= aNumeratorString
.indexOf('0');
716 if ( nMinNumeratorDigits
>= 0 )
717 nMinNumeratorDigits
= nMaxNumeratorDigits
- nMinNumeratorDigits
;
719 nMinNumeratorDigits
= 0;
720 if ( nZerosNumeratorDigits
>= 0 )
721 nZerosNumeratorDigits
= nMaxNumeratorDigits
- nZerosNumeratorDigits
;
723 nZerosNumeratorDigits
= 0;
724 sal_Int32 nMaxDenominatorDigits
= aDenominatorString
.getLength();
725 sal_Int32 nMinDenominatorDigits
= aDenominatorString
.replaceAll("0","?").indexOf('?');
726 sal_Int32 nZerosDenominatorDigits
= aDenominatorString
.indexOf('0');
727 if ( nMinDenominatorDigits
>= 0 )
728 nMinDenominatorDigits
= nMaxDenominatorDigits
- nMinDenominatorDigits
;
730 nMinDenominatorDigits
= 0;
731 if ( nZerosDenominatorDigits
>= 0 )
732 nZerosDenominatorDigits
= nMaxDenominatorDigits
- nZerosDenominatorDigits
;
734 nZerosDenominatorDigits
= 0;
735 sal_Int32 nDenominator
= aDenominatorString
.toInt32();
738 if ( nInteger
>= 0 ) // negative = default (no integer part)
740 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_INTEGER_DIGITS
,
741 OUString::number( nInteger
) );
744 // (automatic) grouping separator
747 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_GROUPING
, XML_TRUE
);
750 // integer/fraction delimiter
751 SvtSaveOptions::ODFSaneDefaultVersion eVersion
= rExport
.getSaneDefaultVersion();
752 if ( !aIntegerFractionDelimiterString
.isEmpty() && aIntegerFractionDelimiterString
!= " "
753 && ((eVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) != 0) )
754 { // Export only for 1.2/1.3 with extensions.
755 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_INTEGER_FRACTION_DELIMITER
,
756 aIntegerFractionDelimiterString
);
760 if ( nMinNumeratorDigits
== 0 ) // at least one digit to keep compatibility with previous versions
761 nMinNumeratorDigits
++;
762 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_NUMERATOR_DIGITS
,
763 OUString::number( nMinNumeratorDigits
) );
764 // Export only for 1.2/1.3 with extensions.
765 if ((eVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) != 0)
767 // For extended ODF use loext namespace
768 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_MAX_NUMERATOR_DIGITS
,
769 OUString::number( nMaxNumeratorDigits
) );
771 if ( nZerosNumeratorDigits
&& ((eVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) != 0) )
772 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_ZEROS_NUMERATOR_DIGITS
,
773 OUString::number( nZerosNumeratorDigits
) );
777 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_DENOMINATOR_VALUE
,
778 OUString::number( nDenominator
) );
780 // it's not necessary to export nDenominatorDigits
781 // if we have a forced denominator
784 if ( nMinDenominatorDigits
== 0 ) // at least one digit to keep compatibility with previous versions
785 nMinDenominatorDigits
++;
786 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_MIN_DENOMINATOR_DIGITS
,
787 OUString::number( nMinDenominatorDigits
) );
788 if (eVersion
> SvtSaveOptions::ODFSVER_012
)
790 // OFFICE-3695 For 1.2+ use loext namespace, for 1.3 use number namespace.
791 rExport
.AddAttribute(
792 ((eVersion
< SvtSaveOptions::ODFSVER_013
) ? XML_NAMESPACE_LO_EXT
: XML_NAMESPACE_NUMBER
),
793 XML_MAX_DENOMINATOR_VALUE
,
794 OUString::number( pow ( 10.0, nMaxDenominatorDigits
) - 1 ) ); // 9, 99 or 999
796 if ( nZerosDenominatorDigits
&& ((eVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) != 0) )
797 rExport
.AddAttribute( XML_NAMESPACE_LO_EXT
, XML_ZEROS_DENOMINATOR_DIGITS
,
798 OUString::number( nZerosDenominatorDigits
) );
801 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, XML_FRACTION
,
805 // mapping (condition)
807 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp
, double fLimit
,
808 sal_Int32 nKey
, sal_Int32 nPart
)
810 FinishTextElement_Impl();
812 if ( nOp
== NUMBERFORMAT_OP_NO
)
817 OUStringBuffer
aCondStr(20);
818 aCondStr
.append( "value()" ); //! define constant
821 case NUMBERFORMAT_OP_EQ
: aCondStr
.append( '=' ); break;
822 case NUMBERFORMAT_OP_NE
: aCondStr
.append( "!=" ); break;
823 case NUMBERFORMAT_OP_LT
: aCondStr
.append( '<' ); break;
824 case NUMBERFORMAT_OP_LE
: aCondStr
.append( "<=" ); break;
825 case NUMBERFORMAT_OP_GT
: aCondStr
.append( '>' ); break;
826 case NUMBERFORMAT_OP_GE
: aCondStr
.append( ">=" ); break;
828 OSL_FAIL("unknown operator");
830 ::rtl::math::doubleToUStringBuffer( aCondStr
, fLimit
,
831 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
834 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_CONDITION
,
835 aCondStr
.makeStringAndClear() );
837 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_APPLY_STYLE_NAME
,
838 rExport
.EncodeStyleName( lcl_CreateStyleName( nKey
, nPart
, false,
841 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_STYLE
, XML_MAP
,
845 // for old (automatic) currency formats: parse currency symbol from text
847 static sal_Int32
lcl_FindSymbol( const OUString
& sUpperStr
, std::u16string_view sCurString
)
849 // search for currency symbol
850 // Quoting as in ImpSvNumberformatScan::Symbol_Division
855 nCPos
= sUpperStr
.indexOf( sCurString
, nCPos
);
859 sal_Int32 nQ
= SvNumberformat::GetQuoteEnd( sUpperStr
, nCPos
);
862 // dm can be escaped as "dm or \d
865 return nCPos
; // found
866 c
= sUpperStr
[nCPos
-1];
867 if ( c
!= '"' && c
!= '\\')
869 return nCPos
; // found
878 nCPos
= nQ
+ 1; // continue after quote end
885 bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString
& rString
,
886 const css::lang::Locale
& rLocale
)
888 // returns true if currency element was written
892 LanguageTag
aLanguageTag( rLocale
);
893 pFormatter
->ChangeIntl( aLanguageTag
.getLanguageType( false) );
894 OUString sCurString
, sDummy
;
895 pFormatter
->GetCompatibilityCurrency( sCurString
, sDummy
);
897 OUString sUpperStr
= pFormatter
->GetCharClass()->uppercase(rString
);
898 sal_Int32 nPos
= lcl_FindSymbol( sUpperStr
, sCurString
);
901 sal_Int32 nLength
= rString
.getLength();
902 sal_Int32 nCurLen
= sCurString
.getLength();
903 sal_Int32 nCont
= nPos
+ nCurLen
;
905 // text before currency symbol
908 AddToTextElement_Impl( rString
.subView( 0, nPos
) );
910 // currency symbol (empty string -> default)
911 WriteCurrencyElement_Impl( "", u
"" );
914 // text after currency symbol
915 if ( nCont
< nLength
)
917 AddToTextElement_Impl( rString
.subView( nCont
, nLength
-nCont
) );
922 AddToTextElement_Impl( rString
); // simple text
925 return bRet
; // true: currency element written
928 static OUString
lcl_GetDefaultCalendar( SvNumberFormatter
const * pFormatter
, LanguageType nLang
)
930 // get name of first non-gregorian calendar for the language
933 CalendarWrapper
* pCalendar
= pFormatter
->GetCalendar();
936 lang::Locale
aLocale( LanguageTag::convertToLocale( nLang
) );
938 const uno::Sequence
<OUString
> aCals
= pCalendar
->getAllCalendars( aLocale
);
939 auto pCal
= std::find_if(aCals
.begin(), aCals
.end(),
940 [](const OUString
& rCal
) { return rCal
!= "gregorian"; });
941 if (pCal
!= aCals
.end())
947 static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr
& rEmbeddedEntries
, sal_uInt16 nPos
)
949 auto nCount
= rEmbeddedEntries
.size();
950 for (decltype(nCount
) i
=0; i
<nCount
; i
++)
951 if ( rEmbeddedEntries
[i
].nSourcePos
== nPos
)
954 return false; // not found
957 static bool lcl_IsDefaultDateFormat( const SvNumberformat
& rFormat
, bool bSystemDate
, NfIndexTableOffset eBuiltIn
)
959 // make an extra loop to collect date elements, to check if it is a default format
960 // before adding the automatic-order attribute
962 SvXMLDateElementAttributes eDateDOW
= XML_DEA_NONE
;
963 SvXMLDateElementAttributes eDateDay
= XML_DEA_NONE
;
964 SvXMLDateElementAttributes eDateMonth
= XML_DEA_NONE
;
965 SvXMLDateElementAttributes eDateYear
= XML_DEA_NONE
;
966 SvXMLDateElementAttributes eDateHours
= XML_DEA_NONE
;
967 SvXMLDateElementAttributes eDateMins
= XML_DEA_NONE
;
968 SvXMLDateElementAttributes eDateSecs
= XML_DEA_NONE
;
969 bool bDateNoDefault
= false;
976 short nElemType
= rFormat
.GetNumForType( 0, nPos
);
980 if ( nLastType
== NF_SYMBOLTYPE_STRING
)
981 bDateNoDefault
= true; // text at the end -> no default date format
982 bEnd
= true; // end of format reached
984 case NF_SYMBOLTYPE_STRING
:
985 case NF_SYMBOLTYPE_DATESEP
:
986 case NF_SYMBOLTYPE_TIMESEP
:
987 case NF_SYMBOLTYPE_TIME100SECSEP
:
988 // text is ignored, except at the end
990 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
991 case NF_KEY_NN
: eDateDOW
= XML_DEA_SHORT
; break;
993 case NF_KEY_NNNN
: eDateDOW
= XML_DEA_LONG
; break;
994 case NF_KEY_D
: eDateDay
= XML_DEA_SHORT
; break;
995 case NF_KEY_DD
: eDateDay
= XML_DEA_LONG
; break;
996 case NF_KEY_M
: eDateMonth
= XML_DEA_SHORT
; break;
997 case NF_KEY_MM
: eDateMonth
= XML_DEA_LONG
; break;
998 case NF_KEY_MMM
: eDateMonth
= XML_DEA_TEXTSHORT
; break;
999 case NF_KEY_MMMM
: eDateMonth
= XML_DEA_TEXTLONG
; break;
1000 case NF_KEY_YY
: eDateYear
= XML_DEA_SHORT
; break;
1001 case NF_KEY_YYYY
: eDateYear
= XML_DEA_LONG
; break;
1002 case NF_KEY_H
: eDateHours
= XML_DEA_SHORT
; break;
1003 case NF_KEY_HH
: eDateHours
= XML_DEA_LONG
; break;
1004 case NF_KEY_MI
: eDateMins
= XML_DEA_SHORT
; break;
1005 case NF_KEY_MMI
: eDateMins
= XML_DEA_LONG
; break;
1006 case NF_KEY_S
: eDateSecs
= XML_DEA_SHORT
; break;
1007 case NF_KEY_SS
: eDateSecs
= XML_DEA_LONG
; break;
1009 case NF_KEY_AMPM
: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1011 bDateNoDefault
= true; // any other element -> no default format
1013 nLastType
= nElemType
;
1017 if ( bDateNoDefault
)
1018 return false; // additional elements
1021 NfIndexTableOffset eFound
= static_cast<NfIndexTableOffset
>(SvXMLNumFmtDefaults::GetDefaultDateFormat(
1022 eDateDOW
, eDateDay
, eDateMonth
, eDateYear
, eDateHours
, eDateMins
, eDateSecs
, bSystemDate
));
1024 return ( eFound
== eBuiltIn
);
1028 // export one part (condition)
1030 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
, sal_uInt32 nRealKey
,
1031 sal_uInt16 nPart
, bool bDefPart
)
1033 //! for the default part, pass the conditions from the other parts!
1037 NfIndexTableOffset eBuiltIn
= pFormatter
->GetIndexTableOffset( nRealKey
);
1039 SvNumFormatType nFmtType
= SvNumFormatType::ALL
;
1040 bool bThousand
= false;
1041 sal_uInt16 nPrecision
= 0;
1042 sal_uInt16 nLeading
= 0;
1043 rFormat
.GetNumForInfo( nPart
, nFmtType
, bThousand
, nPrecision
, nLeading
);
1044 nFmtType
&= ~SvNumFormatType::DEFINED
;
1046 // special treatment of builtin formats that aren't detected by normal parsing
1047 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
1048 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
1049 nFmtType
= SvNumFormatType::NUMBER
;
1050 else if ( eBuiltIn
== NF_BOOLEAN
)
1051 nFmtType
= SvNumFormatType::LOGICAL
;
1052 else if ( eBuiltIn
== NF_TEXT
)
1053 nFmtType
= SvNumFormatType::TEXT
;
1055 // #101606# An empty subformat is a valid number-style resulting in an
1056 // empty display string for the condition of the subformat.
1058 XMLTokenEnum eType
= XML_TOKEN_INVALID
;
1061 // Type UNDEFINED likely is a crappy format string for that we could
1062 // not decide on any format type (and maybe could try harder?), but the
1063 // resulting XMLTokenEnum should be something valid, so make that
1065 case SvNumFormatType::UNDEFINED
:
1066 SAL_WARN("xmloff.style","UNDEFINED number format: '" << rFormat
.GetFormatstring() << "'");
1068 // Type is 0 if a format contains no recognized elements
1069 // (like text only) - this is handled as a number-style.
1070 case SvNumFormatType::ALL
:
1071 case SvNumFormatType::EMPTY
:
1072 case SvNumFormatType::NUMBER
:
1073 case SvNumFormatType::SCIENTIFIC
:
1074 case SvNumFormatType::FRACTION
:
1075 eType
= XML_NUMBER_STYLE
;
1077 case SvNumFormatType::PERCENT
:
1078 eType
= XML_PERCENTAGE_STYLE
;
1080 case SvNumFormatType::CURRENCY
:
1081 eType
= XML_CURRENCY_STYLE
;
1083 case SvNumFormatType::DATE
:
1084 case SvNumFormatType::DATETIME
:
1085 eType
= XML_DATE_STYLE
;
1087 case SvNumFormatType::TIME
:
1088 eType
= XML_TIME_STYLE
;
1090 case SvNumFormatType::TEXT
:
1091 eType
= XML_TEXT_STYLE
;
1093 case SvNumFormatType::LOGICAL
:
1094 eType
= XML_BOOLEAN_STYLE
;
1098 SAL_WARN_IF( eType
== XML_TOKEN_INVALID
, "xmloff.style", "unknown format type" );
1100 OUString sAttrValue
;
1101 bool bUserDef( rFormat
.GetType() & SvNumFormatType::DEFINED
);
1103 // common attributes for format
1105 // format name (generated from key) - style namespace
1106 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
1107 lcl_CreateStyleName( nKey
, nPart
, bDefPart
, sPrefix
) );
1109 // "volatile" attribute for styles used only in maps
1111 rExport
.AddAttribute( XML_NAMESPACE_STYLE
, XML_VOLATILE
, XML_TRUE
);
1113 // language / country
1114 LanguageType nLang
= rFormat
.GetLanguage();
1115 AddLanguageAttr_Impl( nLang
); // adds to pAttrList
1118 // titles for builtin formats are not written
1119 sAttrValue
= rFormat
.GetComment();
1120 if ( !sAttrValue
.isEmpty() && bUserDef
&& bDefPart
)
1122 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TITLE
, sAttrValue
);
1125 // automatic ordering for currency and date formats
1126 // only used for some built-in formats
1127 bool bAutoOrder
= ( eBuiltIn
== NF_CURRENCY_1000INT
|| eBuiltIn
== NF_CURRENCY_1000DEC2
||
1128 eBuiltIn
== NF_CURRENCY_1000INT_RED
|| eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1129 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
||
1130 eBuiltIn
== NF_DATE_SYSTEM_SHORT
|| eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1131 eBuiltIn
== NF_DATE_SYS_MMYY
|| eBuiltIn
== NF_DATE_SYS_DDMMM
||
1132 eBuiltIn
== NF_DATE_SYS_DDMMYYYY
|| eBuiltIn
== NF_DATE_SYS_DDMMYY
||
1133 eBuiltIn
== NF_DATE_SYS_DMMMYY
|| eBuiltIn
== NF_DATE_SYS_DMMMYYYY
||
1134 eBuiltIn
== NF_DATE_SYS_DMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNDMMMYY
||
1135 eBuiltIn
== NF_DATE_SYS_NNDMMMMYYYY
|| eBuiltIn
== NF_DATE_SYS_NNNNDMMMMYYYY
||
1136 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
|| eBuiltIn
== NF_DATETIME_SYS_DDMMYYYY_HHMM
||
1137 eBuiltIn
== NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
1139 // format source (for date and time formats)
1140 // only used for some built-in formats
1141 bool bSystemDate
= ( eBuiltIn
== NF_DATE_SYSTEM_SHORT
||
1142 eBuiltIn
== NF_DATE_SYSTEM_LONG
||
1143 eBuiltIn
== NF_DATETIME_SYSTEM_SHORT_HHMM
);
1144 bool bLongSysDate
= ( eBuiltIn
== NF_DATE_SYSTEM_LONG
);
1146 // check if the format definition matches the key
1147 if ( bAutoOrder
&& ( nFmtType
== SvNumFormatType::DATE
|| nFmtType
== SvNumFormatType::DATETIME
) &&
1148 !lcl_IsDefaultDateFormat( rFormat
, bSystemDate
, eBuiltIn
) )
1150 bAutoOrder
= bSystemDate
= bLongSysDate
= false; // don't write automatic-order attribute then
1154 ( nFmtType
== SvNumFormatType::CURRENCY
|| nFmtType
== SvNumFormatType::DATE
|| nFmtType
== SvNumFormatType::DATETIME
) )
1156 // #85109# format type must be checked to avoid dtd errors if
1157 // locale data contains other format types at the built-in positions
1159 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_AUTOMATIC_ORDER
,
1163 if ( bSystemDate
&& bAutoOrder
&&
1164 ( nFmtType
== SvNumFormatType::DATE
|| nFmtType
== SvNumFormatType::DATETIME
) )
1166 // #85109# format type must be checked to avoid dtd errors if
1167 // locale data contains other format types at the built-in positions
1169 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_FORMAT_SOURCE
,
1173 // overflow for time formats as in [hh]:mm
1174 // controlled by bThousand from number format info
1175 // default for truncate-on-overflow is true
1176 if ( nFmtType
== SvNumFormatType::TIME
&& bThousand
)
1178 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRUNCATE_ON_OVERFLOW
,
1182 // Native number transliteration
1183 css::i18n::NativeNumberXmlAttributes2 aAttr
;
1184 rFormat
.GetNatNumXml( aAttr
, nPart
);
1185 if ( !aAttr
.Format
.isEmpty() )
1187 assert(aAttr
.Spellout
.isEmpty()); // mutually exclusive
1189 /* FIXME-BCP47: ODF defines no transliteration-script or
1190 * transliteration-rfc-language-tag */
1191 LanguageTag
aLanguageTag( aAttr
.Locale
);
1192 OUString aLanguage
, aScript
, aCountry
;
1193 aLanguageTag
.getIsoLanguageScriptCountry( aLanguage
, aScript
, aCountry
);
1194 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_FORMAT
,
1196 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_LANGUAGE
,
1198 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_COUNTRY
,
1200 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_STYLE
,
1204 if ( !aAttr
.Spellout
.isEmpty() )
1206 const bool bWriteSpellout
= aAttr
.Format
.isEmpty();
1207 assert(bWriteSpellout
); // mutually exclusive
1209 // Export only for 1.2 and later with extensions
1210 SvtSaveOptions::ODFSaneDefaultVersion eVersion
= rExport
.getSaneDefaultVersion();
1211 // Also ensure that duplicated transliteration-language and
1212 // transliteration-country attributes never escape into the wild with
1214 if ( (eVersion
& SvtSaveOptions::ODFSVER_EXTENDED
) && bWriteSpellout
)
1216 /* FIXME-BCP47: ODF defines no transliteration-script or
1217 * transliteration-rfc-language-tag */
1218 LanguageTag
aLanguageTag( aAttr
.Locale
);
1219 OUString aLanguage
, aScript
, aCountry
;
1220 aLanguageTag
.getIsoLanguageScriptCountry( aLanguage
, aScript
, aCountry
);
1221 // For 1.2/1.3+ use loext namespace.
1222 rExport
.AddAttribute( /*((eVersion < SvtSaveOptions::ODFSVER_)
1223 ? */ XML_NAMESPACE_LO_EXT
/*: XML_NAMESPACE_NUMBER)*/,
1224 XML_TRANSLITERATION_SPELLOUT
, aAttr
.Spellout
);
1225 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_LANGUAGE
,
1227 rExport
.AddAttribute( XML_NAMESPACE_NUMBER
, XML_TRANSLITERATION_COUNTRY
,
1233 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_NUMBER
, eType
,
1236 // color (properties element)
1238 const Color
* pCol
= rFormat
.GetColor( nPart
);
1240 WriteColorElement_Impl(*pCol
);
1242 // detect if there is "real" content, excluding color and maps
1243 //! move to implementation of Write... methods?
1244 bool bAnyContent
= false;
1248 SvXMLEmbeddedTextEntryArr aEmbeddedEntries
;
1249 if ( eBuiltIn
== NF_NUMBER_STANDARD
)
1251 // default number format contains just one number element
1252 WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries
);
1255 else if ( eBuiltIn
== NF_BOOLEAN
)
1257 // boolean format contains just one boolean element
1258 WriteBooleanElement_Impl();
1261 else if (eType
== XML_BOOLEAN_STYLE
)
1263 // <number:boolean-style> may contain only <number:boolean> and
1264 // <number:text> elements.
1265 sal_uInt16 nPos
= 0;
1269 const short nElemType
= rFormat
.GetNumForType( nPart
, nPos
);
1273 bEnd
= true; // end of format reached
1274 if (bHasText
&& sTextContent
.isEmpty())
1275 bHasText
= false; // don't write trailing empty text
1277 case NF_SYMBOLTYPE_STRING
:
1279 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
);
1281 AddToTextElement_Impl( *pElemStr
);
1284 case NF_KEY_BOOLEAN
:
1285 WriteBooleanElement_Impl();
1294 // first loop to collect attributes
1296 bool bDecDashes
= false;
1297 bool bExpFound
= false;
1298 bool bCurrFound
= false;
1299 bool bInInteger
= true;
1300 bool bExpSign
= true;
1301 bool bDecAlign
= false; // decimal alignment with "?"
1302 sal_Int32 nExpDigits
= 0;
1303 sal_Int32 nIntegerSymbols
= 0; // for embedded-text, including "#"
1304 sal_Int32 nTrailingThousands
= 0; // thousands-separators after all digits
1305 sal_Int32 nMinDecimals
= nPrecision
;
1308 bool bImplicitOtherCalendar
= false;
1309 bool bExplicitCalendar
= false;
1310 sal_uInt16 nPos
= 0;
1314 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
);
1315 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
);
1317 switch ( nElemType
)
1320 bEnd
= true; // end of format reached
1322 case NF_SYMBOLTYPE_DIGIT
:
1323 if ( bExpFound
&& pElemStr
)
1324 nExpDigits
+= pElemStr
->getLength();
1325 else if ( !bDecDashes
&& pElemStr
&& (*pElemStr
)[0] == '-' )
1330 else if ( !bInInteger
&& pElemStr
)
1332 for ( sal_Int32 i
= pElemStr
->getLength()-1; i
>= 0 ; i
-- )
1334 sal_Unicode aChar
= (*pElemStr
)[i
];
1335 if ( aChar
== '#' || aChar
== '?' )
1345 if ( bInInteger
&& pElemStr
)
1346 nIntegerSymbols
+= pElemStr
->getLength();
1347 nTrailingThousands
= 0;
1349 case NF_SYMBOLTYPE_DECSEP
:
1352 case NF_SYMBOLTYPE_THSEP
:
1354 nTrailingThousands
+= pElemStr
->getLength(); // is reset to 0 if digits follow
1356 case NF_SYMBOLTYPE_EXP
:
1357 bExpFound
= true; // following digits are exponent digits
1359 if ( pElemStr
&& ( pElemStr
->getLength() == 1
1360 || ( pElemStr
->getLength() == 2 && (*pElemStr
)[1] == '-' ) ) )
1361 bExpSign
= false; // for 0.00E0 or 0.00E-00
1363 case NF_SYMBOLTYPE_CURRENCY
:
1366 case NF_SYMBOLTYPE_CURREXT
:
1368 sCurrExt
= *pElemStr
;
1371 // E, EE, R, RR: select non-gregorian calendar
1372 // AAA, AAAA: calendar is switched at the position of the element
1377 if (aCalendar
.isEmpty())
1379 aCalendar
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1380 bImplicitOtherCalendar
= true;
1387 // collect strings for embedded-text (must be known before number element is written)
1389 bool bAllowEmbedded
= ( nFmtType
== SvNumFormatType::ALL
|| nFmtType
== SvNumFormatType::NUMBER
||
1390 nFmtType
== SvNumFormatType::CURRENCY
||
1391 nFmtType
== SvNumFormatType::PERCENT
);
1392 if ( bAllowEmbedded
)
1394 sal_Int32 nDigitsPassed
= 0;
1395 sal_Int32 nEmbeddedPositionsMax
= nIntegerSymbols
;
1396 // Enable embedded text in decimal part only if there's a decimal part
1398 nEmbeddedPositionsMax
+= nPrecision
+ 1;
1403 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
);
1404 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
);
1406 switch ( nElemType
)
1409 bEnd
= true; // end of format reached
1411 case NF_SYMBOLTYPE_DIGIT
:
1413 nDigitsPassed
+= pElemStr
->getLength();
1415 case NF_SYMBOLTYPE_DECSEP
:
1418 case NF_SYMBOLTYPE_STRING
:
1419 case NF_SYMBOLTYPE_BLANK
:
1420 case NF_SYMBOLTYPE_PERCENT
:
1421 if ( 0 < nDigitsPassed
&& nDigitsPassed
< nEmbeddedPositionsMax
&& pElemStr
)
1423 // text (literal or underscore) within the integer (>=0) or decimal (<0) part of a number:number element
1425 OUString aEmbeddedStr
;
1426 if ( nElemType
== NF_SYMBOLTYPE_STRING
|| nElemType
== NF_SYMBOLTYPE_PERCENT
)
1428 aEmbeddedStr
= *pElemStr
;
1430 else if (pElemStr
->getLength() >= 2)
1432 SvNumberformat::InsertBlanks( aEmbeddedStr
, 0, (*pElemStr
)[1] );
1434 sal_Int32 nEmbedPos
= nIntegerSymbols
- nDigitsPassed
;
1436 aEmbeddedEntries
.push_back(
1437 SvXMLEmbeddedTextEntry(nPos
, nEmbedPos
, aEmbeddedStr
));
1445 // final loop to write elements
1447 bool bNumWritten
= false;
1448 bool bCurrencyWritten
= false;
1449 short nPrevType
= 0;
1454 short nElemType
= rFormat
.GetNumForType( nPart
, nPos
);
1455 const OUString
* pElemStr
= rFormat
.GetNumForString( nPart
, nPos
);
1457 switch ( nElemType
)
1460 bEnd
= true; // end of format reached
1461 if (bHasText
&& sTextContent
.isEmpty())
1462 bHasText
= false; // don't write trailing empty text
1464 case NF_SYMBOLTYPE_STRING
:
1465 case NF_SYMBOLTYPE_DATESEP
:
1466 case NF_SYMBOLTYPE_TIMESEP
:
1467 case NF_SYMBOLTYPE_TIME100SECSEP
:
1468 case NF_SYMBOLTYPE_PERCENT
:
1471 if ( ( nPrevType
== NF_KEY_S
|| nPrevType
== NF_KEY_SS
) &&
1472 ( nElemType
== NF_SYMBOLTYPE_TIME100SECSEP
) &&
1475 // decimal separator after seconds is implied by
1476 // "decimal-places" attribute and must not be written
1478 //! difference between '.' and ',' is lost here
1480 else if ( lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1482 // text is written as embedded-text child of the number,
1483 // don't create a text element
1485 else if ( nFmtType
== SvNumFormatType::CURRENCY
&& !bCurrFound
&& !bCurrencyWritten
)
1487 // automatic currency symbol is implemented as part of
1488 // normal text -> search for the symbol
1489 bCurrencyWritten
= WriteTextWithCurrency_Impl( *pElemStr
,
1490 LanguageTag::convertToLocale( nLang
) );
1494 AddToTextElement_Impl( *pElemStr
);
1497 case NF_SYMBOLTYPE_BLANK
:
1498 if ( pElemStr
&& !lcl_IsInEmbedded( aEmbeddedEntries
, nPos
) )
1500 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1501 // (#i20396# the spaces may also be in embedded-text elements)
1504 if (pElemStr
->getLength() >= 2)
1505 SvNumberformat::InsertBlanks( aBlanks
, 0, (*pElemStr
)[1] );
1506 AddToTextElement_Impl( aBlanks
);
1509 case NF_KEY_GENERAL
:
1510 WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries
);
1516 if ( bCurrencyWritten
)
1517 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1520 //! must be different from short automatic format
1521 //! but should still be empty (meaning automatic)
1522 // pElemStr is "CCC"
1524 WriteCurrencyElement_Impl( *pElemStr
, u
"" );
1526 bCurrencyWritten
= true;
1530 case NF_SYMBOLTYPE_CURRENCY
:
1533 if ( bCurrencyWritten
)
1534 AddToTextElement_Impl( *pElemStr
); // never more than one currency element
1537 WriteCurrencyElement_Impl( *pElemStr
, sCurrExt
);
1539 bCurrencyWritten
= true;
1543 case NF_SYMBOLTYPE_DIGIT
:
1544 if (!bNumWritten
) // write number part
1548 // for type 0 (not recognized as a special type),
1549 // write a "normal" number
1550 case SvNumFormatType::ALL
:
1551 case SvNumFormatType::NUMBER
:
1552 case SvNumFormatType::CURRENCY
:
1553 case SvNumFormatType::PERCENT
:
1556 // only some built-in formats have automatic decimals
1557 sal_Int32 nDecimals
= nPrecision
; // from GetFormatSpecialInfo
1558 if ( eBuiltIn
== NF_NUMBER_STANDARD
||
1559 eBuiltIn
== NF_CURRENCY_1000DEC2
||
1560 eBuiltIn
== NF_CURRENCY_1000DEC2_RED
||
1561 eBuiltIn
== NF_CURRENCY_1000DEC2_CCC
||
1562 eBuiltIn
== NF_CURRENCY_1000DEC2_DASHED
)
1566 // only one built-in format has automatic integer digits
1567 sal_Int32 nInteger
= nLeading
;
1568 if ( eBuiltIn
== NF_NUMBER_SYSTEM
)
1571 // string for decimal replacement
1572 // has to be taken from nPrecision
1573 // (positive number even for automatic decimals)
1574 OUStringBuffer sDashStr
;
1575 if (bDecDashes
&& nPrecision
> 0)
1576 comphelper::string::padToLength(sDashStr
, nPrecision
, '-');
1577 // "?" in decimal part are replaced by space character
1578 if (bDecAlign
&& nPrecision
> 0)
1581 WriteNumberElement_Impl(nDecimals
, nMinDecimals
, nInteger
, sDashStr
.makeStringAndClear(),
1582 bThousand
, nTrailingThousands
, aEmbeddedEntries
);
1586 case SvNumFormatType::SCIENTIFIC
:
1587 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1588 // as integer digits: use nIntegerSymbols instead of nLeading
1589 // nIntegerSymbols represents exponent interval (for engineering notation)
1590 WriteScientificElement_Impl( nPrecision
, nMinDecimals
, nLeading
, bThousand
, nExpDigits
, nIntegerSymbols
, bExpSign
);
1593 case SvNumFormatType::FRACTION
:
1595 sal_Int32 nInteger
= nLeading
;
1596 if ( rFormat
.GetNumForNumberElementCount( nPart
) == 3 )
1598 // If there is only two numbers + fraction in format string
1599 // the fraction doesn't have an integer part, and no
1600 // min-integer-digits attribute must be written.
1603 WriteFractionElement_Impl( nInteger
, bThousand
, rFormat
, nPart
);
1613 case NF_SYMBOLTYPE_DECSEP
:
1614 if ( pElemStr
&& nPrecision
== 0 )
1616 // A decimal separator after the number, without following decimal digits,
1617 // isn't modelled as part of the number element, so it's written as text
1618 // (the distinction between a quoted and non-quoted, locale-dependent
1619 // character is lost here).
1621 AddToTextElement_Impl( *pElemStr
);
1624 case NF_SYMBOLTYPE_DEL
:
1625 if ( pElemStr
&& *pElemStr
== "@" )
1627 WriteTextContentElement_Impl();
1632 case NF_SYMBOLTYPE_CALENDAR
:
1635 aCalendar
= *pElemStr
;
1636 bExplicitCalendar
= true;
1645 bool bLong
= ( nElemType
== NF_KEY_DD
);
1646 WriteDayElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1658 OUString aCalAttr
= aCalendar
;
1659 if ( nElemType
== NF_KEY_AAA
|| nElemType
== NF_KEY_AAAA
)
1661 // calendar attribute for AAA and AAAA is switched only for this element
1662 if (aCalAttr
.isEmpty())
1663 aCalAttr
= lcl_GetDefaultCalendar( pFormatter
, nLang
);
1666 bool bLong
= ( nElemType
== NF_KEY_NNN
|| nElemType
== NF_KEY_NNNN
||
1667 nElemType
== NF_KEY_DDDD
|| nElemType
== NF_KEY_AAAA
);
1668 WriteDayOfWeekElement_Impl( aCalAttr
, ( bSystemDate
? bLongSysDate
: bLong
) );
1670 if ( nElemType
== NF_KEY_NNNN
)
1672 // write additional text element for separator
1673 pLocaleData
.reset( new LocaleDataWrapper( pFormatter
->GetComponentContext(),
1674 LanguageTag( nLang
) ) );
1675 AddToTextElement_Impl( pLocaleData
->getLongDateDayOfWeekSep() );
1683 case NF_KEY_MMMMM
: //! first letter of month name, no attribute available
1685 bool bLong
= ( nElemType
== NF_KEY_MM
|| nElemType
== NF_KEY_MMMM
);
1686 bool bText
= ( nElemType
== NF_KEY_MMM
|| nElemType
== NF_KEY_MMMM
||
1687 nElemType
== NF_KEY_MMMMM
);
1688 WriteMonthElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
), bText
);
1696 case NF_KEY_R
: //! R acts as EE, no attribute available
1698 //! distinguish EE and R
1699 // Calendar attribute for E and EE and R is set in
1700 // first loop. If set and not an explicit calendar and
1701 // YY or YYYY is encountered, switch temporarily to
1703 bool bLong
= ( nElemType
== NF_KEY_YYYY
|| nElemType
== NF_KEY_EEC
||
1704 nElemType
== NF_KEY_R
);
1705 WriteYearElement_Impl(
1706 ((bImplicitOtherCalendar
&& !bExplicitCalendar
1707 && (nElemType
== NF_KEY_YY
|| nElemType
== NF_KEY_YYYY
)) ? "gregorian" : aCalendar
),
1708 (bSystemDate
? bLongSysDate
: bLong
));
1715 case NF_KEY_RR
: //! RR acts as GGGEE, no attribute available
1717 //! distinguish GG and GGG and RR
1718 bool bLong
= ( nElemType
== NF_KEY_GGG
|| nElemType
== NF_KEY_RR
);
1719 WriteEraElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1721 if ( nElemType
== NF_KEY_RR
)
1723 // calendar attribute for RR is set in first loop
1724 WriteYearElement_Impl( aCalendar
, ( bSystemDate
|| bLongSysDate
) );
1731 bool bLong
= ( nElemType
== NF_KEY_QQ
);
1732 WriteQuarterElement_Impl( aCalendar
, ( bSystemDate
? bLongSysDate
: bLong
) );
1737 WriteWeekElement_Impl( aCalendar
);
1741 // time elements (bSystemDate is not used):
1745 WriteHoursElement_Impl( nElemType
== NF_KEY_HH
);
1750 WriteMinutesElement_Impl( nElemType
== NF_KEY_MMI
);
1755 WriteSecondsElement_Impl( ( nElemType
== NF_KEY_SS
), nPrecision
);
1760 WriteAMPMElement_Impl(); // short/long?
1763 case NF_SYMBOLTYPE_STAR
:
1764 // export only if ODF 1.2 extensions are enabled
1765 if (rExport
.getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012
)
1767 if ( pElemStr
&& pElemStr
->getLength() > 1 )
1768 WriteRepeatedElement_Impl( (*pElemStr
)[1] );
1772 nPrevType
= nElemType
;
1777 if ( !sTextContent
.isEmpty() )
1778 bAnyContent
= true; // element written in FinishTextElement_Impl
1780 FinishTextElement_Impl(); // final text element - before maps
1784 // for an empty format, write an empty text element
1785 SvXMLElementExport
aTElem( rExport
, XML_NAMESPACE_NUMBER
, XML_TEXT
,
1789 // mapping (conditions) must be last elements
1794 SvNumberformatLimitOps eOp1
, eOp2
;
1795 double fLimit1
, fLimit2
;
1796 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1798 WriteMapElement_Impl( eOp1
, fLimit1
, nKey
, 0 );
1799 WriteMapElement_Impl( eOp2
, fLimit2
, nKey
, 1 );
1801 if ( !rFormat
.HasTextFormat() )
1804 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1805 // by reversing the 2nd condition.
1806 // For a trailing text format like 0;@ that has no conditions
1807 // use a "less or equal than biggest" condition for the number
1808 // part, ODF can't store subformats (style maps) without
1811 SvNumberformatLimitOps eOp3
= NUMBERFORMAT_OP_NO
;
1812 double fLimit3
= fLimit2
;
1813 sal_uInt16 nLastPart
= 2;
1814 SvNumberformatLimitOps eOpLast
= eOp2
;
1815 if (eOp2
== NUMBERFORMAT_OP_NO
)
1819 nLastPart
= (eOp1
== NUMBERFORMAT_OP_NO
) ? 0 : 1;
1823 case NUMBERFORMAT_OP_EQ
: eOp3
= NUMBERFORMAT_OP_NE
; break;
1824 case NUMBERFORMAT_OP_NE
: eOp3
= NUMBERFORMAT_OP_EQ
; break;
1825 case NUMBERFORMAT_OP_LT
: eOp3
= NUMBERFORMAT_OP_GE
; break;
1826 case NUMBERFORMAT_OP_LE
: eOp3
= NUMBERFORMAT_OP_GT
; break;
1827 case NUMBERFORMAT_OP_GT
: eOp3
= NUMBERFORMAT_OP_LE
; break;
1828 case NUMBERFORMAT_OP_GE
: eOp3
= NUMBERFORMAT_OP_LT
; break;
1829 case NUMBERFORMAT_OP_NO
: eOp3
= NUMBERFORMAT_OP_LE
; fLimit3
= DBL_MAX
; break;
1832 if ( fLimit1
== fLimit2
&&
1833 ( ( eOp1
== NUMBERFORMAT_OP_LT
&& eOp2
== NUMBERFORMAT_OP_GT
) ||
1834 ( eOp1
== NUMBERFORMAT_OP_GT
&& eOp2
== NUMBERFORMAT_OP_LT
) ) )
1836 // For <x and >x, add =x as last condition
1837 // (just for readability, <=x would be valid, too)
1839 eOp3
= NUMBERFORMAT_OP_EQ
;
1842 WriteMapElement_Impl( eOp3
, fLimit3
, nKey
, nLastPart
);
1845 // export one format
1847 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat
& rFormat
, sal_uInt32 nKey
, sal_uInt32 nRealKey
)
1849 const sal_uInt16 XMLNUM_MAX_PARTS
= 4;
1850 bool bParts
[XMLNUM_MAX_PARTS
] = { false, false, false, false };
1851 sal_uInt16 nUsedParts
= 0;
1852 for (sal_uInt16 nPart
=0; nPart
<XMLNUM_MAX_PARTS
; ++nPart
)
1854 if (rFormat
.GetNumForInfoScannedType( nPart
) != SvNumFormatType::UNDEFINED
)
1856 bParts
[nPart
] = true;
1857 nUsedParts
= nPart
+ 1;
1861 SvNumberformatLimitOps eOp1
, eOp2
;
1862 double fLimit1
, fLimit2
;
1863 rFormat
.GetConditions( eOp1
, fLimit1
, eOp2
, fLimit2
);
1865 // if conditions are set, even empty formats must be written
1867 if ( eOp1
!= NUMBERFORMAT_OP_NO
)
1873 if ( eOp2
!= NUMBERFORMAT_OP_NO
)
1879 if ( rFormat
.HasTextFormat() )
1886 for (sal_uInt16 nPart
=0; nPart
<XMLNUM_MAX_PARTS
; ++nPart
)
1890 bool bDefault
= ( nPart
+1 == nUsedParts
); // last = default
1891 ExportPart_Impl( rFormat
, nKey
, nRealKey
, nPart
, bDefault
);
1896 // export method called by application
1898 void SvXMLNumFmtExport::Export( bool bIsAutoStyle
)
1901 return; // no formatter -> no entries
1904 const SvNumberformat
* pFormat
= nullptr;
1905 bool bNext(pUsedList
->GetFirstUsed(nKey
));
1908 // ODF has its notation of system formats, so obtain the "real" already
1909 // substituted format but use the original key for style name.
1910 sal_uInt32 nRealKey
= nKey
;
1911 pFormat
= pFormatter
->GetSubstitutedEntry( nKey
, nRealKey
);
1913 ExportFormat_Impl( *pFormat
, nKey
, nRealKey
);
1914 bNext
= pUsedList
->GetNextUsed(nKey
);
1918 std::vector
<LanguageType
> aLanguages
;
1919 pFormatter
->GetUsedLanguages( aLanguages
);
1920 for (const auto& nLang
: aLanguages
)
1922 sal_uInt32 nDefaultIndex
= 0;
1923 SvNumberFormatTable
& rTable
= pFormatter
->GetEntryTable(
1924 SvNumFormatType::DEFINED
, nDefaultIndex
, nLang
);
1925 for (const auto& rTableEntry
: rTable
)
1927 nKey
= rTableEntry
.first
;
1928 pFormat
= rTableEntry
.second
;
1929 if (!pUsedList
->IsUsed(nKey
))
1931 DBG_ASSERT((pFormat
->GetType() & SvNumFormatType::DEFINED
), "a not user defined numberformat found");
1932 sal_uInt32 nRealKey
= nKey
;
1933 if (pFormat
->IsSubstituted())
1935 pFormat
= pFormatter
->GetSubstitutedEntry( nKey
, nRealKey
); // export the "real" format
1938 // user-defined and used formats are exported
1939 ExportFormat_Impl( *pFormat
, nKey
, nRealKey
);
1940 // if it is a user-defined Format it will be added else nothing will happen
1941 pUsedList
->SetUsed(nKey
);
1946 pUsedList
->Export();
1949 OUString
SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey
)
1951 if(pUsedList
->IsUsed(nKey
) || pUsedList
->IsWasUsed(nKey
))
1952 return lcl_CreateStyleName( nKey
, 0, true, sPrefix
);
1955 OSL_FAIL("There is no written Data-Style");
1960 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey
)
1962 SAL_WARN_IF( pFormatter
== nullptr, "xmloff.style", "missing formatter" );
1966 if (pFormatter
->GetEntry(nKey
))
1967 pUsedList
->SetUsed( nKey
);
1969 OSL_FAIL("no existing Numberformat found with this key");
1973 uno::Sequence
<sal_Int32
> SvXMLNumFmtExport::GetWasUsed() const
1976 return pUsedList
->GetWasUsed();
1977 return uno::Sequence
<sal_Int32
>();
1980 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence
<sal_Int32
>& rWasUsed
)
1983 pUsedList
->SetWasUsed(rWasUsed
);
1986 static const SvNumberformat
* lcl_GetFormat( SvNumberFormatter
const * pFormatter
,
1989 return ( pFormatter
!= nullptr ) ? pFormatter
->GetEntry( nKey
) : nullptr;
1992 sal_uInt32
SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey
)
1994 sal_uInt32 nRet
= nKey
;
1996 const SvNumberformat
* pFormat
= lcl_GetFormat( pFormatter
, nKey
);
1997 if( pFormat
!= nullptr )
1999 SAL_WARN_IF( pFormatter
== nullptr, "xmloff.style", "format without formatter?" );
2001 SvNumFormatType nType
= pFormat
->GetType();
2003 sal_uInt32 nNewKey
= pFormatter
->GetFormatForLanguageIfBuiltIn(
2004 nKey
, LANGUAGE_SYSTEM
);
2006 if( nNewKey
!= nKey
)
2012 OUString
aFormatString( pFormat
->GetFormatstring() );
2013 sal_Int32 nErrorPos
;
2014 pFormatter
->PutandConvertEntry(
2016 nErrorPos
, nType
, nNewKey
,
2017 pFormat
->GetLanguage(), LANGUAGE_SYSTEM
, true);
2019 // success? Then use new key.
2020 if( nErrorPos
== 0 )
2028 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */