LibreOffice Module xmloff (master) 1
xmlnumfe.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
28#include <tools/debug.hxx>
29#include <rtl/math.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>
38
39#include <com/sun/star/i18n/NativeNumberXmlAttributes2.hpp>
40
41#include <utility>
42#include <xmloff/xmlnumfe.hxx>
44#include <xmloff/xmlnumfi.hxx>
45
46#include <svl/nfsymbol.hxx>
47#include <xmloff/xmltoken.hxx>
48#include <xmloff/xmlexp.hxx>
49#include <o3tl/string_view.hxx>
50
51#include <float.h>
52#include <set>
53#include <string_view>
54#include <vector>
55
56using namespace ::com::sun::star;
57using namespace ::xmloff::token;
58using namespace ::svt;
59
60typedef std::set< sal_uInt32 > SvXMLuInt32Set;
61
62namespace {
63
64struct SvXMLEmbeddedTextEntry
65{
66 sal_uInt16 nSourcePos; // position in NumberFormat (to skip later)
67 sal_Int32 nFormatPos; // resulting position in embedded-text element
68 OUString aText;
69
70 SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, OUString aT ) :
71 nSourcePos(nSP), nFormatPos(nFP), aText(std::move(aT)) {}
72};
73
74}
75
77{
78 typedef std::vector<SvXMLEmbeddedTextEntry> DataType;
80
81public:
82
83 void push_back( SvXMLEmbeddedTextEntry const& r )
84 {
85 maData.push_back(r);
86 }
87
88 const SvXMLEmbeddedTextEntry& operator[] ( size_t i ) const
89 {
90 return maData[i];
91 }
92
93 size_t size() const
94 {
95 return maData.size();
96 }
97};
98
100{
103 SvXMLuInt32Set::iterator aCurrentUsedPos;
104 sal_uInt32 nUsedCount;
105 sal_uInt32 nWasUsedCount;
106
107public:
109
110 void SetUsed( sal_uInt32 nKey );
111 bool IsUsed( sal_uInt32 nKey ) const;
112 bool IsWasUsed( sal_uInt32 nKey ) const;
113 void Export();
114
115 bool GetFirstUsed(sal_uInt32& nKey);
116 bool GetNextUsed(sal_uInt32& nKey);
117
118 uno::Sequence<sal_Int32> GetWasUsed() const;
119 void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed);
120};
121
123
125 nUsedCount(0),
126 nWasUsedCount(0)
127{
128}
129
130void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey )
131{
132 if ( !IsWasUsed(nKey) )
133 {
134 std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey );
135 if (aPair.second)
136 nUsedCount++;
137 }
138}
139
140bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const
141{
142 SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey);
143 return (aItr != aUsed.end());
144}
145
146bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const
147{
148 SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey);
149 return (aItr != aWasUsed.end());
150}
151
153{
154 SvXMLuInt32Set::const_iterator aItr = aUsed.begin();
155 while (aItr != aUsed.end())
156 {
157 std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( *aItr );
158 if (aPair.second)
160 ++aItr;
161 }
162 aUsed.clear();
163 nUsedCount = 0;
164}
165
167{
168 bool bRet(false);
169 aCurrentUsedPos = aUsed.begin();
170 if(nUsedCount)
171 {
172 DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong");
173 nKey = *aCurrentUsedPos;
174 bRet = true;
175 }
176 return bRet;
177}
178
180{
181 bool bRet(false);
182 if (aCurrentUsedPos != aUsed.end())
183 {
185 if (aCurrentUsedPos != aUsed.end())
186 {
187 nKey = *aCurrentUsedPos;
188 bRet = true;
189 }
190 }
191 return bRet;
192}
193
194uno::Sequence<sal_Int32> SvXMLNumUsedList_Impl::GetWasUsed() const
195{
196 return comphelper::containerToSequence<sal_Int32>(aWasUsed);
197}
198
199void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
200{
201 DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty");
202 for (const auto nWasUsed : rWasUsed)
203 {
204 std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( nWasUsed );
205 if (aPair.second)
207 }
208}
209
211 SvXMLExport& rExp,
212 const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) :
213 m_rExport( rExp ),
214 m_sPrefix( OUString("N") ),
215 m_pFormatter( nullptr ),
216 m_bHasText( false )
217{
218 // supplier must be SvNumberFormatsSupplierObj
220 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp );
221 if (pObj)
222 m_pFormatter = pObj->GetNumberFormatter();
223
224 if ( m_pFormatter )
225 {
226 m_pLocaleData.reset( new LocaleDataWrapper( m_pFormatter->GetComponentContext(),
227 m_pFormatter->GetLanguageTag() ) );
228 }
229 else
230 {
232
233 m_pLocaleData.reset( new LocaleDataWrapper( m_rExport.getComponentContext(), std::move(aLanguageTag) ) );
234 }
235
236 m_pUsedList.reset(new SvXMLNumUsedList_Impl);
237}
238
240 SvXMLExport& rExp,
241 const css::uno::Reference< css::util::XNumberFormatsSupplier >& rSupp,
242 OUString aPrefix ) :
243 m_rExport( rExp ),
244 m_sPrefix(std::move( aPrefix )),
245 m_pFormatter( nullptr ),
246 m_bHasText( false )
247{
248 // supplier must be SvNumberFormatsSupplierObj
250 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp );
251 if (pObj)
253
254 if ( m_pFormatter )
255 {
258 }
259 else
260 {
262
263 m_pLocaleData.reset( new LocaleDataWrapper( m_rExport.getComponentContext(), std::move(aLanguageTag) ) );
264 }
265
267}
268
270{
271}
272
273// helper methods
274
275static OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, bool bDefPart, std::u16string_view rPrefix )
276{
277 if (bDefPart)
278 return rPrefix + OUString::number(nKey);
279 else
280 return rPrefix + OUString::number(nKey) + "P" + OUString::number( nPart );
281}
282
283void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar )
284{
285 if ( !rCalendar.isEmpty() )
286 {
288 }
289}
290
292{
293 if ( bLong ) // short is default
294 {
296 }
297}
298
300{
301 if ( nLang != LANGUAGE_SYSTEM )
302 {
304 LanguageTag( nLang), false);
305 }
306}
307
308// methods to write individual elements within a format
309
310void SvXMLNumFmtExport::AddToTextElement_Impl( std::u16string_view rString )
311{
312 // append to sTextContent, write element in FinishTextElement_Impl
313 // to avoid several text elements following each other
314
315 m_sTextContent.append( rString );
316 // Also empty string leads to a number:text element as it may separate
317 // keywords of the same letter (e.g. MM""MMM) that otherwise would be
318 // concatenated when reading back in.
319 m_bHasText = true;
320}
321
323{
324 if ( m_bHasText )
325 {
326 sal_uInt16 nNS = bUseExtensionNS ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER;
328 true, false );
329 m_rExport.Characters( m_sTextContent.makeStringAndClear() );
330 m_bHasText = false;
331 }
332}
333
335{
337
338 OUStringBuffer aColStr( 7 );
339 ::sax::Converter::convertColor( aColStr, rColor );
341 aColStr.makeStringAndClear() );
342
344 true, false );
345}
346
348 std::u16string_view rExt )
349{
351
352 if ( !rExt.empty() )
353 {
354 // rExt should be a 16-bit hex value max FFFF which may contain a
355 // leading "-" separator (that is not a minus sign, but toInt32 can be
356 // used to parse it, with post-processing as necessary):
357 sal_Int32 nLang = o3tl::toInt32(rExt, 16);
358 if ( nLang < 0 )
359 nLang = -nLang;
360 SAL_WARN_IF(nLang > 0xFFFF, "xmloff.style", "Out of range Lang Id: " << nLang << " from input string: " << OUString(rExt));
361 AddLanguageAttr_Impl( LanguageType(nLang & 0xFFFF) ); // adds to pAttrList
362 }
363
366 true, false );
367 m_rExport.Characters( rString );
368}
369
371{
373
375 true, false );
376}
377
379{
381
383 true, false );
384}
385
386// date elements
387
388void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, bool bLong )
389{
391
392 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
393 AddStyleAttr_Impl( bLong ); // adds to pAttrList
394
396 true, false );
397}
398
399void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, bool bLong, bool bText )
400{
402
403 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
404 AddStyleAttr_Impl( bLong ); // adds to pAttrList
405 if ( bText )
406 {
408 }
409
411 true, false );
412}
413
414void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, bool bLong )
415{
417
418 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
419 AddStyleAttr_Impl( bLong ); // adds to pAttrList
420
422 true, false );
423}
424
425void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, bool bLong )
426{
428
429 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
430 AddStyleAttr_Impl( bLong ); // adds to pAttrList
431
433 true, false );
434}
435
436void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, bool bLong )
437{
439
440 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
441 AddStyleAttr_Impl( bLong ); // adds to pAttrList
442
444 true, false );
445}
446
447void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar )
448{
450
451 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
452
454 true, false );
455}
456
457void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, bool bLong )
458{
460
461 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
462 AddStyleAttr_Impl( bLong ); // adds to pAttrList
463
465 true, false );
466}
467
468// time elements
469
471{
473
474 AddStyleAttr_Impl( bLong ); // adds to pAttrList
475
477 true, false );
478}
479
481{
483
484 AddStyleAttr_Impl( bLong ); // adds to pAttrList
485
487 true, false );
488}
489
491{
492 // Export only for 1.2 with extensions or 1.3 and later.
494 if (eVersion > SvtSaveOptions::ODFSVER_012)
495 {
497 // OFFICE-3765 For 1.2+ use loext namespace, for 1.3 use number namespace.
500 XML_FILL_CHARACTER, true, false );
501 m_rExport.Characters( OUString( nChar ) );
502 }
503}
504
505void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong, sal_uInt16 nDecimals )
506{
508
509 AddStyleAttr_Impl( bLong ); // adds to pAttrList
510 if ( nDecimals > 0 )
511 {
513 OUString::number( nDecimals ) );
514 }
515
517 true, false );
518}
519
521{
523
525 true, false );
526}
527
528// numbers
529
531 sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping )
532{
533 // integer digits: '0' and '?'
534 if ( nInteger >= 0 ) // negative = automatic
535 {
537 OUString::number( nInteger ) );
538 }
540 // blank integer digits: '?'
541 if ( nBlankInteger > 0 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 ) )
542 {
544 OUString::number( nBlankInteger ) );
545 }
546 // (automatic) grouping separator
547 if ( bGrouping )
548 {
550 }
551}
552
554{
555 auto nEntryCount = rEmbeddedEntries.size();
556 for (decltype(nEntryCount) nEntry=0; nEntry < nEntryCount; ++nEntry)
557 {
558 const SvXMLEmbeddedTextEntry *const pObj = &rEmbeddedEntries[nEntry];
559
560 // position attribute
561 // position == 0 is between first integer digit and decimal separator
562 // position < 0 is inside decimal part
564 OUString::number( pObj->nFormatPos ) );
566 true, false );
567
568 // text as element content
569 OUStringBuffer aContent( pObj->aText );
570 while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1].nFormatPos == pObj->nFormatPos )
571 {
572 // The array can contain several elements for the same position in the number
573 // (for example, literal text and space from underscores). They must be merged
574 // into a single embedded-text element.
575 aContent.append(rEmbeddedEntries[nEntry+1].aText);
576 ++nEntry;
577 }
578 m_rExport.Characters( aContent.makeStringAndClear() );
579 }
580}
581
583 sal_Int32 nDecimals, sal_Int32 nMinDecimals,
584 sal_Int32 nInteger, sal_Int32 nBlankInteger, const OUString& rDashStr,
585 bool bGrouping, sal_Int32 nTrailingThousands,
586 const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
587{
589
590 // decimals
591 if ( nDecimals >= 0 ) // negative = automatic
592 {
594 OUString::number( nDecimals ) );
595 }
596
597 if ( nMinDecimals >= 0 ) // negative = automatic
598 {
599 // Export only for 1.2 with extensions or 1.3 and later.
601 if (eVersion > SvtSaveOptions::ODFSVER_012)
602 {
603 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
607 OUString::number( nMinDecimals ) );
608 }
609 }
610 // decimal replacement (dashes) or variable decimals (#)
611 if ( !rDashStr.isEmpty() || nMinDecimals < nDecimals )
612 {
613 // full variable decimals means an empty replacement string
615 rDashStr );
616 }
617
618 WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping );
619
620 // display-factor if there are trailing thousands separators
621 if ( nTrailingThousands )
622 {
623 // each separator character removes three digits
624 double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
625
626 OUStringBuffer aFactStr;
627 ::sax::Converter::convertDouble( aFactStr, fFactor );
628 m_rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
629 }
630
632 true, true );
633
634 // number:embedded-text as child elements
635 WriteEmbeddedEntries_Impl( rEmbeddedEntries );
636}
637
639 sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, sal_Int32 nBlankInteger,
640 bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign,
641 const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
642{
644
645 // decimals
646 if ( nDecimals >= 0 ) // negative = automatic
647 {
649 OUString::number( nDecimals ) );
650 }
651
653 if ( nMinDecimals >= 0 ) // negative = automatic
654 {
655 // Export only for 1.2 with extensions or 1.3 and later.
656 if (eVersion > SvtSaveOptions::ODFSVER_012)
657 {
658 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
662 OUString::number( nMinDecimals ) );
663 }
664 }
665
666 WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping );
667
668 // exponent digits
669 if ( nExp >= 0 )
670 {
672 OUString::number( nExp ) );
673 }
674
675 // exponent interval for engineering notation
676 if ( nExpInterval >= 0 )
677 {
678 // Export only for 1.2 with extensions or 1.3 and later.
679 if (eVersion > SvtSaveOptions::ODFSVER_012)
680 {
681 // OFFICE-1828 For 1.2+ use loext namespace, for 1.3 use number namespace.
684 XML_EXPONENT_INTERVAL, OUString::number( nExpInterval ) );
685 }
686 }
687
688 // exponent sign
689 // Export only for 1.2 with extensions or 1.3 and later.
690 if (eVersion > SvtSaveOptions::ODFSVER_012)
691 {
692 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
696 bExpSign? XML_TRUE : XML_FALSE );
697 }
698
701 true, false );
702
703 // number:embedded-text as child elements
704 // Export only for 1.x with extensions
706 WriteEmbeddedEntries_Impl( rEmbeddedEntries );
707}
708
710 sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping,
711 const SvNumberformat& rFormat, sal_uInt16 nPart )
712{
714 WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping );
715
716 const OUString aNumeratorString = rFormat.GetNumeratorString( nPart );
717 const OUString aDenominatorString = rFormat.GetDenominatorString( nPart );
718 const OUString aIntegerFractionDelimiterString = rFormat.GetIntegerFractionDelimiterString( nPart );
719 sal_Int32 nMaxNumeratorDigits = aNumeratorString.getLength();
720 // Count '0' as '?'
721 sal_Int32 nMinNumeratorDigits = aNumeratorString.replaceAll("0","?").indexOf('?');
722 sal_Int32 nZerosNumeratorDigits = aNumeratorString.indexOf('0');
723 if ( nMinNumeratorDigits >= 0 )
724 nMinNumeratorDigits = nMaxNumeratorDigits - nMinNumeratorDigits;
725 else
726 nMinNumeratorDigits = 0;
727 if ( nZerosNumeratorDigits >= 0 )
728 nZerosNumeratorDigits = nMaxNumeratorDigits - nZerosNumeratorDigits;
729 else
730 nZerosNumeratorDigits = 0;
731 sal_Int32 nMaxDenominatorDigits = aDenominatorString.getLength();
732 sal_Int32 nMinDenominatorDigits = aDenominatorString.replaceAll("0","?").indexOf('?');
733 sal_Int32 nZerosDenominatorDigits = aDenominatorString.indexOf('0');
734 if ( nMinDenominatorDigits >= 0 )
735 nMinDenominatorDigits = nMaxDenominatorDigits - nMinDenominatorDigits;
736 else
737 nMinDenominatorDigits = 0;
738 if ( nZerosDenominatorDigits >= 0 )
739 nZerosDenominatorDigits = nMaxDenominatorDigits - nZerosDenominatorDigits;
740 else
741 nZerosDenominatorDigits = 0;
742 sal_Int32 nDenominator = aDenominatorString.toInt32();
743
745
746 // integer/fraction delimiter
747 if ( !aIntegerFractionDelimiterString.isEmpty() && aIntegerFractionDelimiterString != " "
748 && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
749 { // Export only for 1.2/1.3 with extensions.
751 aIntegerFractionDelimiterString );
752 }
753
754 // numerator digits
755 if ( nMinNumeratorDigits == 0 ) // at least one digit to keep compatibility with previous versions
756 nMinNumeratorDigits++;
758 OUString::number( nMinNumeratorDigits ) );
759 // Export only for 1.2/1.3 with extensions.
760 if ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0)
761 {
762 // For extended ODF use loext namespace
764 OUString::number( nMaxNumeratorDigits ) );
765 }
766 if ( nZerosNumeratorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
768 OUString::number( nZerosNumeratorDigits ) );
769
770 if ( nDenominator )
771 {
773 OUString::number( nDenominator) );
774 }
775 // it's not necessary to export nDenominatorDigits
776 // if we have a forced denominator
777 else
778 {
779 if ( nMinDenominatorDigits == 0 ) // at least one digit to keep compatibility with previous versions
780 nMinDenominatorDigits++;
782 OUString::number( nMinDenominatorDigits ) );
783 if (eVersion > SvtSaveOptions::ODFSVER_012)
784 {
785 // OFFICE-3695 For 1.2+ use loext namespace, for 1.3 use number namespace.
789 OUString::number( pow ( 10.0, nMaxDenominatorDigits ) - 1 ) ); // 9, 99 or 999
790 }
791 if ( nZerosDenominatorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
793 OUString::number( nZerosDenominatorDigits ) );
794 }
795
797 true, false );
798}
799
800// mapping (condition)
801
802void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
803 sal_Int32 nKey, sal_Int32 nPart )
804{
806
807 if ( nOp == NUMBERFORMAT_OP_NO )
808 return;
809
810 // style namespace
811
812 OUStringBuffer aCondStr(20);
813 aCondStr.append( "value()" );
814 switch ( nOp )
815 {
816 case NUMBERFORMAT_OP_EQ: aCondStr.append( '=' ); break;
817 case NUMBERFORMAT_OP_NE: aCondStr.append( "!=" ); break;
818 case NUMBERFORMAT_OP_LT: aCondStr.append( '<' ); break;
819 case NUMBERFORMAT_OP_LE: aCondStr.append( "<=" ); break;
820 case NUMBERFORMAT_OP_GT: aCondStr.append( '>' ); break;
821 case NUMBERFORMAT_OP_GE: aCondStr.append( ">=" ); break;
822 default:
823 OSL_FAIL("unknown operator");
824 }
825 ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
826 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
827 '.', true );
828
830 aCondStr.makeStringAndClear() );
831
833 m_rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, false,
834 m_sPrefix ) ) );
835
837 true, false );
838}
839
840// for old (automatic) currency formats: parse currency symbol from text
841
842static sal_Int32 lcl_FindSymbol( const OUString& sUpperStr, std::u16string_view sCurString )
843{
844 // search for currency symbol
845 // Quoting as in ImpSvNumberformatScan::Symbol_Division
846
847 sal_Int32 nCPos = 0;
848 while (nCPos >= 0)
849 {
850 nCPos = sUpperStr.indexOf( sCurString, nCPos );
851 if (nCPos >= 0)
852 {
853 // in Quotes?
854 sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
855 if ( nQ < 0 )
856 {
857 // dm can be escaped as "dm or \d
858 sal_Unicode c;
859 if ( nCPos == 0 )
860 return nCPos; // found
861 c = sUpperStr[nCPos-1];
862 if ( c != '"' && c != '\\')
863 {
864 return nCPos; // found
865 }
866 else
867 {
868 nCPos++; // continue
869 }
870 }
871 else
872 {
873 nCPos = nQ + 1; // continue after quote end
874 }
875 }
876 }
877 return -1;
878}
879
881 const css::lang::Locale& rLocale )
882{
883 // returns true if currency element was written
884
885 bool bRet = false;
886
887 LanguageTag aLanguageTag( rLocale );
888 m_pFormatter->ChangeIntl( aLanguageTag.getLanguageType( false) );
889 OUString sCurString, sDummy;
890 m_pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
891
892 OUString sUpperStr = m_pFormatter->GetCharClass()->uppercase(rString);
893 sal_Int32 nPos = lcl_FindSymbol( sUpperStr, sCurString );
894 if ( nPos >= 0 )
895 {
896 sal_Int32 nLength = rString.getLength();
897 sal_Int32 nCurLen = sCurString.getLength();
898 sal_Int32 nCont = nPos + nCurLen;
899
900 // text before currency symbol
901 if ( nPos > 0 )
902 {
903 AddToTextElement_Impl( rString.subView( 0, nPos ) );
904 }
905 // currency symbol (empty string -> default)
907 bRet = true;
908
909 // text after currency symbol
910 if ( nCont < nLength )
911 {
912 AddToTextElement_Impl( rString.subView( nCont, nLength-nCont ) );
913 }
914 }
915 else
916 {
917 AddToTextElement_Impl( rString ); // simple text
918 }
919
920 return bRet; // true: currency element written
921}
922
923static OUString lcl_GetDefaultCalendar( SvNumberFormatter const * pFormatter, LanguageType nLang )
924{
925 // get name of first non-gregorian calendar for the language
926
927 OUString aCalendar;
928 CalendarWrapper* pCalendar = pFormatter->GetCalendar();
929 if (pCalendar)
930 {
931 lang::Locale aLocale( LanguageTag::convertToLocale( nLang ) );
932
933 const uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
934 auto pCal = std::find_if(aCals.begin(), aCals.end(),
935 [](const OUString& rCal) { return rCal != "gregorian"; });
936 if (pCal != aCals.end())
937 aCalendar = *pCal;
938 }
939 return aCalendar;
940}
941
942static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
943{
944 auto nCount = rEmbeddedEntries.size();
945 for (decltype(nCount) i=0; i<nCount; i++)
946 if ( rEmbeddedEntries[i].nSourcePos == nPos )
947 return true;
948
949 return false; // not found
950}
951
952static bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, bool bSystemDate, NfIndexTableOffset eBuiltIn )
953{
954 // make an extra loop to collect date elements, to check if it is a default format
955 // before adding the automatic-order attribute
956
964 bool bDateNoDefault = false;
965
966 sal_uInt16 nPos = 0;
967 bool bEnd = false;
968 short nLastType = 0;
969 while (!bEnd)
970 {
971 short nElemType = rFormat.GetNumForType( 0, nPos );
972 switch ( nElemType )
973 {
974 case 0:
975 if ( nLastType == NF_SYMBOLTYPE_STRING )
976 bDateNoDefault = true; // text at the end -> no default date format
977 bEnd = true; // end of format reached
978 break;
983 // text is ignored, except at the end
984 break;
985 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
986 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
987 case NF_KEY_NNN:
988 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
989 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
990 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
991 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
992 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
993 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
994 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
995 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
996 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
997 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
998 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
999 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
1000 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
1001 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
1002 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
1003 case NF_KEY_AP:
1004 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1005 default:
1006 bDateNoDefault = true; // any other element -> no default format
1007 }
1008 nLastType = nElemType;
1009 ++nPos;
1010 }
1011
1012 if ( bDateNoDefault )
1013 return false; // additional elements
1014 else
1015 {
1017 eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate ));
1018
1019 return ( eFound == eBuiltIn );
1020 }
1021}
1022
1023// export one part (condition)
1024
1025void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey,
1026 sal_uInt16 nPart, bool bDefPart )
1027{
1029
1030 // element name
1031
1032 NfIndexTableOffset eBuiltIn = m_pFormatter->GetIndexTableOffset( nRealKey );
1033
1034 SvNumFormatType nFmtType = SvNumFormatType::ALL;
1035 bool bThousand = false;
1036 sal_uInt16 nPrecision = 0;
1037 sal_uInt16 nLeading = 0;
1038 rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
1039 nFmtType &= ~SvNumFormatType::DEFINED;
1040
1041 // special treatment of builtin formats that aren't detected by normal parsing
1042 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
1043 if ( eBuiltIn == NF_NUMBER_STANDARD )
1044 nFmtType = SvNumFormatType::NUMBER;
1045 else if ( eBuiltIn == NF_BOOLEAN )
1046 nFmtType = SvNumFormatType::LOGICAL;
1047 else if ( eBuiltIn == NF_TEXT )
1048 nFmtType = SvNumFormatType::TEXT;
1049
1050 // #101606# An empty subformat is a valid number-style resulting in an
1051 // empty display string for the condition of the subformat.
1052
1054 switch ( nFmtType )
1055 {
1056 // Type UNDEFINED likely is a crappy format string for that we could
1057 // not decide on any format type (and maybe could try harder?), but the
1058 // resulting XMLTokenEnum should be something valid, so make that
1059 // number-style.
1060 case SvNumFormatType::UNDEFINED:
1061 SAL_WARN("xmloff.style","UNDEFINED number format: '" << rFormat.GetFormatstring() << "'");
1062 [[fallthrough]];
1063 // Type is 0 if a format contains no recognized elements
1064 // (like text only) - this is handled as a number-style.
1065 case SvNumFormatType::ALL:
1066 case SvNumFormatType::EMPTY:
1067 case SvNumFormatType::NUMBER:
1068 case SvNumFormatType::SCIENTIFIC:
1069 case SvNumFormatType::FRACTION:
1071 break;
1072 case SvNumFormatType::PERCENT:
1074 break;
1075 case SvNumFormatType::CURRENCY:
1077 break;
1078 case SvNumFormatType::DATE:
1079 case SvNumFormatType::DATETIME:
1081 break;
1082 case SvNumFormatType::TIME:
1084 break;
1085 case SvNumFormatType::TEXT:
1087 break;
1088 case SvNumFormatType::LOGICAL:
1090 break;
1091 default: break;
1092 }
1093 SAL_WARN_IF( eType == XML_TOKEN_INVALID, "xmloff.style", "unknown format type" );
1094
1095 OUString sAttrValue;
1096 bool bUserDef( rFormat.GetType() & SvNumFormatType::DEFINED );
1097
1098 // common attributes for format
1099
1100 // format name (generated from key) - style namespace
1102 lcl_CreateStyleName( nKey, nPart, bDefPart, m_sPrefix ) );
1103
1104 // "volatile" attribute for styles used only in maps
1105 if ( !bDefPart )
1107
1108 // language / country
1109 LanguageType nLang = rFormat.GetLanguage();
1110 AddLanguageAttr_Impl( nLang ); // adds to pAttrList
1111
1112 // title (comment)
1113 // titles for builtin formats are not written
1114 sAttrValue = rFormat.GetComment();
1115 if ( !sAttrValue.isEmpty() && bUserDef && bDefPart )
1116 {
1118 }
1119
1120 // automatic ordering for currency and date formats
1121 // only used for some built-in formats
1122 bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 ||
1123 eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1124 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
1125 eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG ||
1126 eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM ||
1127 eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY ||
1128 eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
1129 eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
1130 eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
1132 eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
1133
1134 // format source (for date and time formats)
1135 // only used for some built-in formats
1136 bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
1137 eBuiltIn == NF_DATE_SYSTEM_LONG ||
1138 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
1139 bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
1140
1141 // check if the format definition matches the key
1142 if ( bAutoOrder && ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) &&
1143 !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
1144 {
1145 bAutoOrder = bSystemDate = bLongSysDate = false; // don't write automatic-order attribute then
1146 }
1147
1148 if ( bAutoOrder &&
1149 ( nFmtType == SvNumFormatType::CURRENCY || nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) )
1150 {
1151 // #85109# format type must be checked to avoid dtd errors if
1152 // locale data contains other format types at the built-in positions
1153
1155 XML_TRUE );
1156 }
1157
1158 if ( bSystemDate && bAutoOrder &&
1159 ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) )
1160 {
1161 // #85109# format type must be checked to avoid dtd errors if
1162 // locale data contains other format types at the built-in positions
1163
1165 XML_LANGUAGE );
1166 }
1167
1168 // overflow for time formats as in [hh]:mm
1169 // controlled by bThousand from number format info
1170 // default for truncate-on-overflow is true
1171 if ( nFmtType == SvNumFormatType::TIME && bThousand )
1172 {
1174 XML_FALSE );
1175 }
1176
1177 // Native number transliteration
1178 css::i18n::NativeNumberXmlAttributes2 aAttr;
1179 rFormat.GetNatNumXml( aAttr, nPart );
1180 if ( !aAttr.Format.isEmpty() )
1181 {
1182 assert(aAttr.Spellout.isEmpty()); // mutually exclusive
1183
1184 /* FIXME-BCP47: ODF defines no transliteration-script or
1185 * transliteration-rfc-language-tag */
1186 LanguageTag aLanguageTag( aAttr.Locale);
1187 OUString aLanguage, aScript, aCountry;
1188 aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
1190 aAttr.Format );
1192 aLanguage );
1194 aCountry );
1196 aAttr.Style );
1197 }
1198
1199 if ( !aAttr.Spellout.isEmpty() )
1200 {
1201 const bool bWriteSpellout = aAttr.Format.isEmpty();
1202 assert(bWriteSpellout); // mutually exclusive
1203
1204 // Export only for 1.2 and later with extensions
1206 // Also ensure that duplicated transliteration-language and
1207 // transliteration-country attributes never escape into the wild with
1208 // releases.
1209 if ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) && bWriteSpellout )
1210 {
1211 /* FIXME-BCP47: ODF defines no transliteration-script or
1212 * transliteration-rfc-language-tag */
1213 LanguageTag aLanguageTag( aAttr.Locale);
1214 OUString aLanguage, aScript, aCountry;
1215 aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
1216 // For 1.2/1.3+ use loext namespace.
1217 m_rExport.AddAttribute( /*((eVersion < SvtSaveOptions::ODFSVER_)
1218 ? */ XML_NAMESPACE_LO_EXT /*: XML_NAMESPACE_NUMBER)*/,
1219 XML_TRANSLITERATION_SPELLOUT, aAttr.Spellout );
1221 aLanguage );
1223 aCountry );
1224 }
1225 }
1226
1227 // The element
1229 true, true );
1230
1231 // color (properties element)
1232
1233 const Color* pCol = rFormat.GetColor( nPart );
1234 if (pCol)
1236
1237 // detect if there is "real" content, excluding color and maps
1239 bool bAnyContent = false;
1240
1241 // format elements
1242
1243 SvXMLEmbeddedTextEntryArr aEmbeddedEntries;
1244 if ( eBuiltIn == NF_NUMBER_STANDARD )
1245 {
1246 // default number format contains just one number element
1247 WriteNumberElement_Impl( -1, -1, 1, -1, OUString(), false, 0, aEmbeddedEntries );
1248 bAnyContent = true;
1249 }
1250 else if ( eBuiltIn == NF_BOOLEAN )
1251 {
1252 // boolean format contains just one boolean element
1254 bAnyContent = true;
1255 }
1256 else if (eType == XML_BOOLEAN_STYLE)
1257 {
1258 // <number:boolean-style> may contain only <number:boolean> and
1259 // <number:text> elements.
1260 sal_uInt16 nPos = 0;
1261 bool bEnd = false;
1262 while (!bEnd)
1263 {
1264 const short nElemType = rFormat.GetNumForType( nPart, nPos );
1265 switch (nElemType)
1266 {
1267 case 0:
1268 bEnd = true; // end of format reached
1269 if (m_bHasText && m_sTextContent.isEmpty())
1270 m_bHasText = false; // don't write trailing empty text
1271 break;
1273 {
1274 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1275 if (pElemStr)
1276 AddToTextElement_Impl( *pElemStr );
1277 }
1278 break;
1279 case NF_KEY_BOOLEAN:
1281 bAnyContent = true;
1282 break;
1283 }
1284 ++nPos;
1285 }
1286 }
1287 else
1288 {
1289 // first loop to collect attributes
1290
1291 bool bDecDashes = false;
1292 bool bExpFound = false;
1293 bool bCurrFound = false;
1294 bool bInInteger = true;
1295 bool bExpSign = true;
1296 bool bDecAlign = false; // decimal alignment with "?"
1297 sal_Int32 nExpDigits = 0;
1298 sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#"
1299 sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits
1300 sal_Int32 nMinDecimals = nPrecision;
1301 sal_Int32 nBlankInteger = 0;
1302 OUString sCurrExt;
1303 OUString aCalendar;
1304 bool bImplicitOtherCalendar = false;
1305 bool bExplicitCalendar = false;
1306 sal_uInt16 nPos = 0;
1307 bool bEnd = false;
1308 while (!bEnd)
1309 {
1310 short nElemType = rFormat.GetNumForType( nPart, nPos );
1311 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1312
1313 switch ( nElemType )
1314 {
1315 case 0:
1316 bEnd = true; // end of format reached
1317 break;
1319 if ( bExpFound && pElemStr )
1320 nExpDigits += pElemStr->getLength();
1321 else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' )
1322 {
1323 bDecDashes = true;
1324 nMinDecimals = 0;
1325 }
1326 else if ( nFmtType != SvNumFormatType::FRACTION && !bInInteger && pElemStr )
1327 {
1328 for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- )
1329 {
1330 sal_Unicode aChar = (*pElemStr)[i];
1331 if ( aChar == '#' || aChar == '?' )
1332 {
1333 nMinDecimals --;
1334 if ( aChar == '?' )
1335 bDecAlign = true;
1336 }
1337 else
1338 break;
1339 }
1340 }
1341 if ( bInInteger && pElemStr )
1342 {
1343 nIntegerSymbols += pElemStr->getLength();
1344 for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- )
1345 {
1346 if ( (*pElemStr)[i] == '?' )
1347 nBlankInteger ++;
1348 }
1349 }
1350 nTrailingThousands = 0;
1351 break;
1354 bInInteger = false;
1355 break;
1357 if (pElemStr)
1358 nTrailingThousands += pElemStr->getLength(); // is reset to 0 if digits follow
1359 break;
1360 case NF_SYMBOLTYPE_EXP:
1361 bExpFound = true; // following digits are exponent digits
1362 bInInteger = false;
1363 if ( pElemStr && ( pElemStr->getLength() == 1
1364 || ( pElemStr->getLength() == 2 && (*pElemStr)[1] == '-' ) ) )
1365 bExpSign = false; // for 0.00E0 or 0.00E-00
1366 break;
1368 bCurrFound = true;
1369 break;
1371 if (pElemStr)
1372 sCurrExt = *pElemStr;
1373 break;
1374
1375 // E, EE, R, RR: select non-gregorian calendar
1376 // AAA, AAAA: calendar is switched at the position of the element
1377 case NF_KEY_EC:
1378 case NF_KEY_EEC:
1379 case NF_KEY_R:
1380 case NF_KEY_RR:
1381 if (aCalendar.isEmpty())
1382 {
1383 aCalendar = lcl_GetDefaultCalendar( m_pFormatter, nLang );
1384 bImplicitOtherCalendar = true;
1385 }
1386 break;
1387 }
1388 ++nPos;
1389 }
1390
1391 // collect strings for embedded-text (must be known before number element is written)
1393 bool bAllowEmbedded = ( nFmtType == SvNumFormatType::ALL || nFmtType == SvNumFormatType::NUMBER ||
1394 nFmtType == SvNumFormatType::CURRENCY ||
1395 // Export only for 1.x with extensions
1396 ( nFmtType == SvNumFormatType::SCIENTIFIC && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) )||
1397 nFmtType == SvNumFormatType::PERCENT );
1398 if ( bAllowEmbedded )
1399 {
1400 sal_Int32 nDigitsPassed = 0;
1401 sal_Int32 nEmbeddedPositionsMax = nIntegerSymbols;
1402 // Enable embedded text in decimal part only if there's a decimal part
1403 if ( nPrecision )
1404 nEmbeddedPositionsMax += nPrecision + 1;
1405 nPos = 0;
1406 bEnd = false;
1407 while (!bEnd)
1408 {
1409 short nElemType = rFormat.GetNumForType( nPart, nPos );
1410 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1411
1412 switch ( nElemType )
1413 {
1414 case 0:
1415 bEnd = true; // end of format reached
1416 break;
1418 if ( pElemStr )
1419 nDigitsPassed += pElemStr->getLength();
1420 break;
1422 nDigitsPassed++;
1423 break;
1427 if ( 0 < nDigitsPassed && nDigitsPassed < nEmbeddedPositionsMax && pElemStr )
1428 {
1429 // text (literal or underscore) within the integer (>=0) or decimal (<0) part of a number:number element
1430
1431 OUString aEmbeddedStr;
1432 if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
1433 {
1434 aEmbeddedStr = *pElemStr;
1435 }
1436 else if (pElemStr->getLength() >= 2)
1437 {
1438 SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] );
1439 }
1440 sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
1441
1442 aEmbeddedEntries.push_back(
1443 SvXMLEmbeddedTextEntry(nPos, nEmbedPos, aEmbeddedStr));
1444 }
1445 break;
1446 }
1447 ++nPos;
1448 }
1449 }
1450
1451 // final loop to write elements
1452
1453 bool bNumWritten = false;
1454 bool bCurrencyWritten = false;
1455 short nPrevType = 0;
1456 nPos = 0;
1457 bEnd = false;
1458 while (!bEnd)
1459 {
1460 short nElemType = rFormat.GetNumForType( nPart, nPos );
1461 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1462
1463 switch ( nElemType )
1464 {
1465 case 0:
1466 bEnd = true; // end of format reached
1467 if (m_bHasText && m_sTextContent.isEmpty())
1468 m_bHasText = false; // don't write trailing empty text
1469 break;
1475 if (pElemStr)
1476 {
1477 if ( ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
1478 ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ||
1479 ( nPos > 0 && (*rFormat.GetNumForString( nPart, nPos-1 ))[0] == ']' &&
1480 ( nFmtType == SvNumFormatType::TIME || nFmtType == SvNumFormatType::DATETIME ) ) ) &&
1481 nPrecision > 0 )
1482 {
1483 // decimal separator after seconds or [SS] is implied by
1484 // "decimal-places" attribute and must not be written
1485 // as text element
1487 }
1488 else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1489 {
1490 // text is written as embedded-text child of the number,
1491 // don't create a text element
1492 }
1493 else if ( nFmtType == SvNumFormatType::CURRENCY && !bCurrFound && !bCurrencyWritten )
1494 {
1495 // automatic currency symbol is implemented as part of
1496 // normal text -> search for the symbol
1497 bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
1499 bAnyContent = true;
1500 }
1501 else
1502 AddToTextElement_Impl( *pElemStr );
1503 }
1504 break;
1506 if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1507 {
1508 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1509 // (#i20396# the spaces may also be in embedded-text elements)
1510
1511 OUString aBlanks;
1512 if (pElemStr->getLength() >= 2)
1513 SvNumberformat::InsertBlanks( aBlanks, 0, (*pElemStr)[1] );
1514 AddToTextElement_Impl( aBlanks );
1515 }
1516 break;
1517 case NF_KEY_GENERAL :
1518 WriteNumberElement_Impl( -1, -1, 1, -1, OUString(), false, 0, aEmbeddedEntries );
1519 bAnyContent = true;
1520 break;
1521 case NF_KEY_CCC:
1522 if (pElemStr)
1523 {
1524 if ( bCurrencyWritten )
1525 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1526 else
1527 {
1530 // pElemStr is "CCC"
1531
1532 WriteCurrencyElement_Impl( *pElemStr, u"" );
1533 bAnyContent = true;
1534 bCurrencyWritten = true;
1535 }
1536 }
1537 break;
1539 if (pElemStr)
1540 {
1541 if ( bCurrencyWritten )
1542 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1543 else
1544 {
1545 WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
1546 bAnyContent = true;
1547 bCurrencyWritten = true;
1548 }
1549 }
1550 break;
1552 if (!bNumWritten) // write number part
1553 {
1554 switch ( nFmtType )
1555 {
1556 // for type 0 (not recognized as a special type),
1557 // write a "normal" number
1558 case SvNumFormatType::ALL:
1559 case SvNumFormatType::NUMBER:
1560 case SvNumFormatType::CURRENCY:
1561 case SvNumFormatType::PERCENT:
1562 {
1563 // decimals
1564 // only some built-in formats have automatic decimals
1565 sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo
1566 if ( eBuiltIn == NF_NUMBER_STANDARD ||
1567 eBuiltIn == NF_CURRENCY_1000DEC2 ||
1568 eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1569 eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
1570 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
1571 nDecimals = -1;
1572
1573 // integer digits
1574 // only one built-in format has automatic integer digits
1575 sal_Int32 nInteger = nLeading;
1576 if ( eBuiltIn == NF_NUMBER_SYSTEM )
1577 {
1578 nInteger = -1;
1579 nBlankInteger = -1;
1580 }
1581
1582 // string for decimal replacement
1583 // has to be taken from nPrecision
1584 // (positive number even for automatic decimals)
1585 OUStringBuffer sDashStr;
1586 if (bDecDashes && nPrecision > 0)
1587 comphelper::string::padToLength(sDashStr, nPrecision, '-');
1588 // "?" in decimal part are replaced by space character
1589 if (bDecAlign && nPrecision > 0)
1590 sDashStr = " ";
1591
1592 WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, nBlankInteger, sDashStr.makeStringAndClear(),
1593 bThousand, nTrailingThousands, aEmbeddedEntries);
1594 bAnyContent = true;
1595 }
1596 break;
1597 case SvNumFormatType::SCIENTIFIC:
1598 // #i43959# for scientific numbers, count all integer symbols ("0", "?" and "#")
1599 // as integer digits: use nIntegerSymbols instead of nLeading
1600 // nIntegerSymbols represents exponent interval (for engineering notation)
1601 WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, nBlankInteger, bThousand, nExpDigits, nIntegerSymbols, bExpSign,
1602 aEmbeddedEntries );
1603 bAnyContent = true;
1604 break;
1605 case SvNumFormatType::FRACTION:
1606 {
1607 sal_Int32 nInteger = nLeading;
1608 if ( rFormat.GetNumForNumberElementCount( nPart ) == 3 )
1609 {
1610 // If there is only two numbers + fraction in format string
1611 // the fraction doesn't have an integer part, and no
1612 // min-integer-digits attribute must be written.
1613 nInteger = -1;
1614 nBlankInteger = -1;
1615 }
1616 WriteFractionElement_Impl( nInteger, nBlankInteger, bThousand, rFormat, nPart );
1617 bAnyContent = true;
1618 }
1619 break;
1620 default: break;
1621 }
1622
1623 bNumWritten = true;
1624 }
1625 break;
1627 if ( pElemStr && nPrecision == 0 )
1628 {
1629 // A decimal separator after the number, without following decimal digits,
1630 // isn't modelled as part of the number element, so it's written as text
1631 // (the distinction between a quoted and non-quoted, locale-dependent
1632 // character is lost here).
1633
1634 AddToTextElement_Impl( *pElemStr );
1635 }
1636 break;
1637 case NF_SYMBOLTYPE_DEL:
1638 if ( pElemStr && *pElemStr == "@" )
1639 {
1641 bAnyContent = true;
1642 }
1643 break;
1644
1646 if ( pElemStr )
1647 {
1648 aCalendar = *pElemStr;
1649 bExplicitCalendar = true;
1650 }
1651 break;
1652
1653 // date elements:
1654
1655 case NF_KEY_D:
1656 case NF_KEY_DD:
1657 {
1658 bool bLong = ( nElemType == NF_KEY_DD );
1659 WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1660 bAnyContent = true;
1661 }
1662 break;
1663 case NF_KEY_DDD:
1664 case NF_KEY_DDDD:
1665 case NF_KEY_NN:
1666 case NF_KEY_NNN:
1667 case NF_KEY_NNNN:
1668 case NF_KEY_AAA:
1669 case NF_KEY_AAAA:
1670 {
1671 OUString aCalAttr = aCalendar;
1672 if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
1673 {
1674 // calendar attribute for AAA and AAAA is switched only for this element
1675 if (aCalAttr.isEmpty())
1676 aCalAttr = lcl_GetDefaultCalendar( m_pFormatter, nLang );
1677 }
1678
1679 bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
1680 nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
1681 WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
1682 bAnyContent = true;
1683 if ( nElemType == NF_KEY_NNNN )
1684 {
1685 // write additional text element for separator
1687 LanguageTag( nLang ) ) );
1688 AddToTextElement_Impl( m_pLocaleData->getLongDateDayOfWeekSep() );
1689 }
1690 }
1691 break;
1692 case NF_KEY_M:
1693 case NF_KEY_MM:
1694 case NF_KEY_MMM:
1695 case NF_KEY_MMMM:
1696 case NF_KEY_MMMMM:
1697 {
1698 bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM );
1699 bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
1700 nElemType == NF_KEY_MMMMM );
1701 WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
1702 bAnyContent = true;
1703 }
1704 break;
1705 case NF_KEY_YY:
1706 case NF_KEY_YYYY:
1707 case NF_KEY_EC:
1708 case NF_KEY_EEC:
1709 case NF_KEY_R:
1710 {
1712 // Calendar attribute for E and EE and R is set in
1713 // first loop. If set and not an explicit calendar and
1714 // YY or YYYY is encountered, switch temporarily to
1715 // Gregorian.
1716 bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
1717 nElemType == NF_KEY_R );
1719 ((bImplicitOtherCalendar && !bExplicitCalendar
1720 && (nElemType == NF_KEY_YY || nElemType == NF_KEY_YYYY)) ? "gregorian" : aCalendar),
1721 (bSystemDate ? bLongSysDate : bLong));
1722 bAnyContent = true;
1723 }
1724 break;
1725 case NF_KEY_G:
1726 case NF_KEY_GG:
1727 case NF_KEY_GGG:
1728 case NF_KEY_RR:
1729 {
1731 bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
1732 WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1733 bAnyContent = true;
1734 if ( nElemType == NF_KEY_RR )
1735 {
1736 // calendar attribute for RR is set in first loop
1737 WriteYearElement_Impl( aCalendar, ( bSystemDate || bLongSysDate ) );
1738 }
1739 }
1740 break;
1741 case NF_KEY_Q:
1742 case NF_KEY_QQ:
1743 {
1744 bool bLong = ( nElemType == NF_KEY_QQ );
1745 WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1746 bAnyContent = true;
1747 }
1748 break;
1749 case NF_KEY_WW:
1750 WriteWeekElement_Impl( aCalendar );
1751 bAnyContent = true;
1752 break;
1753
1754 // time elements (bSystemDate is not used):
1755
1756 case NF_KEY_H:
1757 case NF_KEY_HH:
1758 WriteHoursElement_Impl( nElemType == NF_KEY_HH );
1759 bAnyContent = true;
1760 break;
1761 case NF_KEY_MI:
1762 case NF_KEY_MMI:
1763 WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
1764 bAnyContent = true;
1765 break;
1766 case NF_KEY_S:
1767 case NF_KEY_SS:
1768 WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
1769 bAnyContent = true;
1770 break;
1771 case NF_KEY_AMPM:
1772 case NF_KEY_AP:
1773 WriteAMPMElement_Impl(); // short/long?
1774 bAnyContent = true;
1775 break;
1776 case NF_SYMBOLTYPE_STAR :
1777 // export only if ODF 1.2 extensions are enabled
1779 {
1780 if ( pElemStr && pElemStr->getLength() > 1 )
1781 WriteRepeatedElement_Impl( (*pElemStr)[1] );
1782 }
1783 break;
1784 }
1785 nPrevType = nElemType;
1786 ++nPos;
1787 }
1788 }
1789
1790 if ( !m_sTextContent.isEmpty() )
1791 bAnyContent = true; // element written in FinishTextElement_Impl
1792
1793 FinishTextElement_Impl(); // final text element - before maps
1794
1795 if ( !bAnyContent )
1796 {
1797 // for an empty format, write an empty text element
1799 true, false );
1800 }
1801
1802 // mapping (conditions) must be last elements
1803
1804 if (!bDefPart)
1805 return;
1806
1807 SvNumberformatLimitOps eOp1, eOp2;
1808 double fLimit1, fLimit2;
1809 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1810
1811 WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
1812 WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
1813
1814 if ( !rFormat.HasTextFormat() )
1815 return;
1816
1817 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1818 // by reversing the 2nd condition.
1819 // For a trailing text format like 0;@ that has no conditions
1820 // use a "less or equal than biggest" condition for the number
1821 // part, ODF can't store subformats (style maps) without
1822 // conditions.
1823
1825 double fLimit3 = fLimit2;
1826 sal_uInt16 nLastPart = 2;
1827 SvNumberformatLimitOps eOpLast = eOp2;
1828 if (eOp2 == NUMBERFORMAT_OP_NO)
1829 {
1830 eOpLast = eOp1;
1831 fLimit3 = fLimit1;
1832 nLastPart = (eOp1 == NUMBERFORMAT_OP_NO) ? 0 : 1;
1833 }
1834 switch ( eOpLast )
1835 {
1836 case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
1837 case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
1838 case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
1839 case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
1840 case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
1841 case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
1842 case NUMBERFORMAT_OP_NO: eOp3 = NUMBERFORMAT_OP_LE; fLimit3 = DBL_MAX; break;
1843 }
1844
1845 if ( fLimit1 == fLimit2 &&
1846 ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
1847 ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
1848 {
1849 // For <x and >x, add =x as last condition
1850 // (just for readability, <=x would be valid, too)
1851
1852 eOp3 = NUMBERFORMAT_OP_EQ;
1853 }
1854
1855 WriteMapElement_Impl( eOp3, fLimit3, nKey, nLastPart );
1856}
1857
1858// export one format
1859
1860void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey )
1861{
1862 const sal_uInt16 XMLNUM_MAX_PARTS = 4;
1863 bool bParts[XMLNUM_MAX_PARTS] = { false, false, false, false };
1864 sal_uInt16 nUsedParts = 0;
1865 for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart)
1866 {
1867 if (rFormat.GetNumForInfoScannedType( nPart) != SvNumFormatType::UNDEFINED)
1868 {
1869 bParts[nPart] = true;
1870 nUsedParts = nPart + 1;
1871 }
1872 }
1873
1874 SvNumberformatLimitOps eOp1, eOp2;
1875 double fLimit1, fLimit2;
1876 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1877
1878 // if conditions are set, even empty formats must be written
1879
1880 if ( eOp1 != NUMBERFORMAT_OP_NO )
1881 {
1882 bParts[1] = true;
1883 if (nUsedParts < 2)
1884 nUsedParts = 2;
1885 }
1886 if ( eOp2 != NUMBERFORMAT_OP_NO )
1887 {
1888 bParts[2] = true;
1889 if (nUsedParts < 3)
1890 nUsedParts = 3;
1891 }
1892 if ( rFormat.HasTextFormat() )
1893 {
1894 bParts[3] = true;
1895 if (nUsedParts < 4)
1896 nUsedParts = 4;
1897 }
1898
1899 for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart)
1900 {
1901 if (bParts[nPart])
1902 {
1903 bool bDefault = ( nPart+1 == nUsedParts ); // last = default
1904 ExportPart_Impl( rFormat, nKey, nRealKey, nPart, bDefault );
1905 }
1906 }
1907}
1908
1909// export method called by application
1910
1911void SvXMLNumFmtExport::Export( bool bIsAutoStyle )
1912{
1913 if ( !m_pFormatter )
1914 return; // no formatter -> no entries
1915
1916 sal_uInt32 nKey;
1917 const SvNumberformat* pFormat = nullptr;
1918 bool bNext(m_pUsedList->GetFirstUsed(nKey));
1919 while(bNext)
1920 {
1921 // ODF has its notation of system formats, so obtain the "real" already
1922 // substituted format but use the original key for style name.
1923 sal_uInt32 nRealKey = nKey;
1924 pFormat = m_pFormatter->GetSubstitutedEntry( nKey, nRealKey);
1925 if(pFormat)
1926 ExportFormat_Impl( *pFormat, nKey, nRealKey );
1927 bNext = m_pUsedList->GetNextUsed(nKey);
1928 }
1929 if (!bIsAutoStyle)
1930 {
1931 std::vector<LanguageType> aLanguages;
1932 m_pFormatter->GetUsedLanguages( aLanguages );
1933 for (const auto& nLang : aLanguages)
1934 {
1935 sal_uInt32 nDefaultIndex = 0;
1937 SvNumFormatType::DEFINED, nDefaultIndex, nLang );
1938 for (const auto& rTableEntry : rTable)
1939 {
1940 nKey = rTableEntry.first;
1941 pFormat = rTableEntry.second;
1942 if (!m_pUsedList->IsUsed(nKey))
1943 {
1944 DBG_ASSERT((pFormat->GetType() & SvNumFormatType::DEFINED), "a not user defined numberformat found");
1945 sal_uInt32 nRealKey = nKey;
1946 if (pFormat->IsSubstituted())
1947 {
1948 pFormat = m_pFormatter->GetSubstitutedEntry( nKey, nRealKey); // export the "real" format
1949 assert(pFormat);
1950 }
1951 // user-defined and used formats are exported
1952 ExportFormat_Impl( *pFormat, nKey, nRealKey );
1953 // if it is a user-defined Format it will be added else nothing will happen
1954 m_pUsedList->SetUsed(nKey);
1955 }
1956 }
1957 }
1958 }
1959 m_pUsedList->Export();
1960}
1961
1962OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
1963{
1964 if(m_pUsedList->IsUsed(nKey) || m_pUsedList->IsWasUsed(nKey))
1965 return lcl_CreateStyleName( nKey, 0, true, m_sPrefix );
1966 else
1967 {
1968 OSL_FAIL("There is no written Data-Style");
1969 return OUString();
1970 }
1971}
1972
1973void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
1974{
1975 SAL_WARN_IF( m_pFormatter == nullptr, "xmloff.style", "missing formatter" );
1976 if( !m_pFormatter )
1977 return;
1978
1979 if (m_pFormatter->GetEntry(nKey))
1980 m_pUsedList->SetUsed( nKey );
1981 else {
1982 OSL_FAIL("no existing Numberformat found with this key");
1983 }
1984}
1985
1986uno::Sequence<sal_Int32> SvXMLNumFmtExport::GetWasUsed() const
1987{
1988 if (m_pUsedList)
1989 return m_pUsedList->GetWasUsed();
1990 return uno::Sequence<sal_Int32>();
1991}
1992
1993void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
1994{
1995 if (m_pUsedList)
1996 m_pUsedList->SetWasUsed(rWasUsed);
1997}
1998
1999static const SvNumberformat* lcl_GetFormat( SvNumberFormatter const * pFormatter,
2000 sal_uInt32 nKey )
2001{
2002 return ( pFormatter != nullptr ) ? pFormatter->GetEntry( nKey ) : nullptr;
2003}
2004
2005sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
2006{
2007 sal_uInt32 nRet = nKey;
2008
2009 const SvNumberformat* pFormat = lcl_GetFormat( m_pFormatter, nKey );
2010 if( pFormat != nullptr )
2011 {
2012 SAL_WARN_IF( m_pFormatter == nullptr, "xmloff.style", "format without formatter?" );
2013
2014 SvNumFormatType nType = pFormat->GetType();
2015
2016 sal_uInt32 nNewKey = m_pFormatter->GetFormatForLanguageIfBuiltIn(
2017 nKey, LANGUAGE_SYSTEM );
2018
2019 if( nNewKey != nKey )
2020 {
2021 nRet = nNewKey;
2022 }
2023 else
2024 {
2025 OUString aFormatString( pFormat->GetFormatstring() );
2026 sal_Int32 nErrorPos;
2028 aFormatString,
2029 nErrorPos, nType, nNewKey,
2030 pFormat->GetLanguage(), LANGUAGE_SYSTEM, true);
2031
2032 // success? Then use new key.
2033 if( nErrorPos == 0 )
2034 nRet = nNewKey;
2035 }
2036 }
2037
2038 return nRet;
2039}
2040
2041/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Sequence< OUString > getAllCalendars(const css::lang::Locale &rLocale) const
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
LanguageType getLanguageType(bool bResolveSystem=true) const
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
void getIsoLanguageScriptCountry(OUString &rLanguage, OUString &rScript, OUString &rCountry) const
static LanguageType getConfiguredSystemLanguage()
SvNumberFormatter * GetNumberFormatter() const
const SvNumberformat * GetSubstitutedEntry(sal_uInt32 nKey, sal_uInt32 &o_rNewKey) const
void GetCompatibilityCurrency(OUString &rSymbol, OUString &rAbbrev) const
const LanguageTag & GetLanguageTag() const
CalendarWrapper * GetCalendar() const
NfIndexTableOffset GetIndexTableOffset(sal_uInt32 nFormat) const
bool PutandConvertEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge, LanguageType eNewLnge, bool bConvertDateOrder, bool bReplaceBooleanEquivalent=true)
void ChangeIntl(LanguageType eLnge)
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
sal_uInt32 GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge=LANGUAGE_DONTKNOW)
const CharClass * GetCharClass() const
SvNumberFormatTable & GetEntryTable(SvNumFormatType eType, sal_uInt32 &FIndex, LanguageType eLnge)
const css::uno::Reference< css::uno::XComponentContext > & GetComponentContext() const
void GetUsedLanguages(std::vector< LanguageType > &rList)
sal_uInt16 GetNumForNumberElementCount(sal_uInt16 nNumFor) const
LanguageType GetLanguage() const
OUString GetDenominatorString(sal_uInt16 nNumFor) const
void GetConditions(SvNumberformatLimitOps &rOper1, double &rVal1, SvNumberformatLimitOps &rOper2, double &rVal2) const
const Color * GetColor(sal_uInt16 nNumFor) const
void GetNumForInfo(sal_uInt16 nNumFor, SvNumFormatType &rScannedType, bool &bThousand, sal_uInt16 &nPrecision, sal_uInt16 &nLeadingCnt) const
bool HasTextFormat() const
const OUString & GetComment() const
const OUString * GetNumForString(sal_uInt16 nNumFor, sal_uInt16 nPos, bool bString=false) const
SvNumFormatType GetNumForInfoScannedType(sal_uInt16 nNumFor) const
const OUString & GetFormatstring() const
OUString GetIntegerFractionDelimiterString(sal_uInt16 nNumFor) const
short GetNumForType(sal_uInt16 nNumFor, sal_uInt16 nPos) const
SvNumFormatType GetType() const
bool IsSubstituted() const
static sal_Int32 GetQuoteEnd(const OUString &rString, sal_Int32 nPos, sal_Unicode cQuote='"', sal_Unicode cEscIn = '\0' )
OUString GetNumeratorString(sal_uInt16 nNumFor) const
static sal_Int32 InsertBlanks(OUString &r, sal_Int32 nPos, sal_Unicode c)
void GetNatNumXml(css::i18n::NativeNumberXmlAttributes2 &rAttr, sal_uInt16 nNumFor) const
const SvXMLEmbeddedTextEntry & operator[](size_t i) const
Definition: xmlnumfe.cxx:88
std::vector< SvXMLEmbeddedTextEntry > DataType
Definition: xmlnumfe.cxx:78
void push_back(SvXMLEmbeddedTextEntry const &r)
Definition: xmlnumfe.cxx:83
size_t size() const
Definition: xmlnumfe.cxx:93
void AddAttribute(sal_uInt16 nPrefix, const OUString &rName, const OUString &rValue)
Definition: xmlexp.cxx:907
void Characters(const OUString &rChars)
Definition: xmlexp.cxx:2126
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
returns the deterministic version for odf export
Definition: xmlexp.cxx:2264
OUString EncodeStyleName(const OUString &rName, bool *pEncoded=nullptr) const
Definition: xmlexp.cxx:1934
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
Definition: xmlexp.hxx:517
void AddLanguageTagAttributes(sal_uInt16 nPrefix, sal_uInt16 nPrefixRfc, const css::lang::Locale &rLocale, bool bWriteEmpty)
Add language tag attributes, deciding which are necessary.
Definition: xmlexp.cxx:941
static sal_uInt16 GetDefaultDateFormat(SvXMLDateElementAttributes eDOW, SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth, SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours, SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs, bool bSystem)
Definition: xmlnumfi.cxx:1110
SAL_DLLPRIVATE void WriteHoursElement_Impl(bool bLong)
Definition: xmlnumfe.cxx:470
SAL_DLLPRIVATE void WriteQuarterElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:457
SAL_DLLPRIVATE void WriteSecondsElement_Impl(bool bLong, sal_uInt16 nDecimals)
Definition: xmlnumfe.cxx:505
OUString m_sPrefix
Definition: xmlnumfe.hxx:51
SAL_DLLPRIVATE void WriteEmbeddedEntries_Impl(const SvXMLEmbeddedTextEntryArr &rEmbeddedEntries)
Definition: xmlnumfe.cxx:553
SAL_DLLPRIVATE void WriteMinutesElement_Impl(bool bLong)
Definition: xmlnumfe.cxx:480
css::uno::Sequence< sal_Int32 > GetWasUsed() const
Definition: xmlnumfe.cxx:1986
SAL_DLLPRIVATE void WriteIntegerElement_Impl(sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping)
Definition: xmlnumfe.cxx:530
SAL_DLLPRIVATE void AddToTextElement_Impl(std::u16string_view rString)
Definition: xmlnumfe.cxx:310
SAL_DLLPRIVATE void ExportPart_Impl(const SvNumberformat &rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey, sal_uInt16 nPart, bool bDefPart)
Definition: xmlnumfe.cxx:1025
SAL_DLLPRIVATE void WriteNumberElement_Impl(sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, sal_Int32 nBlankInteger, const OUString &rDashStr, bool bGrouping, sal_Int32 nTrailingThousands, const SvXMLEmbeddedTextEntryArr &rEmbeddedEntries)
Definition: xmlnumfe.cxx:582
SAL_DLLPRIVATE void WriteDayOfWeekElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:436
OUStringBuffer m_sTextContent
Definition: xmlnumfe.hxx:53
std::unique_ptr< LocaleDataWrapper > m_pLocaleData
Definition: xmlnumfe.hxx:56
SAL_DLLPRIVATE void WriteAMPMElement_Impl()
Definition: xmlnumfe.cxx:520
SAL_DLLPRIVATE void WriteCurrencyElement_Impl(const OUString &rString, std::u16string_view rExt)
Definition: xmlnumfe.cxx:347
SAL_DLLPRIVATE void WriteTextContentElement_Impl()
Definition: xmlnumfe.cxx:378
SAL_DLLPRIVATE void WriteFractionElement_Impl(sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping, const SvNumberformat &rFormat, sal_uInt16 nPart)
Definition: xmlnumfe.cxx:709
SAL_DLLPRIVATE void AddCalendarAttr_Impl(const OUString &rCalendar)
Definition: xmlnumfe.cxx:283
sal_uInt32 ForceSystemLanguage(sal_uInt32 nKey)
obtain number format with system language for a given key
Definition: xmlnumfe.cxx:2005
SAL_DLLPRIVATE void WriteWeekElement_Impl(const OUString &rCalendar)
Definition: xmlnumfe.cxx:447
OUString GetStyleName(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1962
SAL_DLLPRIVATE void WriteColorElement_Impl(const Color &rColor)
Definition: xmlnumfe.cxx:334
SAL_DLLPRIVATE bool WriteTextWithCurrency_Impl(const OUString &rString, const css::lang::Locale &rLocale)
Definition: xmlnumfe.cxx:880
SAL_DLLPRIVATE void WriteMonthElement_Impl(const OUString &rCalendar, bool bLong, bool bText)
Definition: xmlnumfe.cxx:399
SvXMLExport & m_rExport
Definition: xmlnumfe.hxx:50
std::unique_ptr< SvXMLNumUsedList_Impl > m_pUsedList
Definition: xmlnumfe.hxx:55
SAL_DLLPRIVATE void ExportFormat_Impl(const SvNumberformat &rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey)
Definition: xmlnumfe.cxx:1860
SAL_DLLPRIVATE void WriteDayElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:388
void Export(bool bIsAutoStyle)
Definition: xmlnumfe.cxx:1911
SAL_DLLPRIVATE void WriteYearElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:414
SAL_DLLPRIVATE void WriteScientificElement_Impl(sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign, const SvXMLEmbeddedTextEntryArr &rEmbeddedEntries)
Definition: xmlnumfe.cxx:638
SAL_DLLPRIVATE void WriteEraElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:425
SAL_DLLPRIVATE void FinishTextElement_Impl(bool bUseExtensionNS=false)
Definition: xmlnumfe.cxx:322
SAL_DLLPRIVATE void WriteRepeatedElement_Impl(sal_Unicode ch)
Definition: xmlnumfe.cxx:490
SAL_DLLPRIVATE void AddStyleAttr_Impl(bool bLong)
Definition: xmlnumfe.cxx:291
SvXMLNumFmtExport(SvXMLExport &rExport, const css::uno::Reference< css::util::XNumberFormatsSupplier > &rSupp)
SAL_DLLPRIVATE void AddLanguageAttr_Impl(LanguageType nLang)
Definition: xmlnumfe.cxx:299
SvNumberFormatter * m_pFormatter
Definition: xmlnumfe.hxx:52
SAL_DLLPRIVATE void WriteMapElement_Impl(sal_Int32 nOp, double fLimit, sal_Int32 nKey, sal_Int32 nPart)
Definition: xmlnumfe.cxx:802
void SetUsed(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1973
SAL_DLLPRIVATE void WriteBooleanElement_Impl()
Definition: xmlnumfe.cxx:370
void SetWasUsed(const css::uno::Sequence< sal_Int32 > &rWasUsed)
Definition: xmlnumfe.cxx:1993
SvXMLuInt32Set aWasUsed
Definition: xmlnumfe.cxx:102
SvXMLuInt32Set::iterator aCurrentUsedPos
Definition: xmlnumfe.cxx:103
bool GetNextUsed(sal_uInt32 &nKey)
Definition: xmlnumfe.cxx:179
bool GetFirstUsed(sal_uInt32 &nKey)
Definition: xmlnumfe.cxx:166
sal_uInt32 nWasUsedCount
Definition: xmlnumfe.cxx:105
sal_uInt32 nUsedCount
Definition: xmlnumfe.cxx:104
bool IsWasUsed(sal_uInt32 nKey) const
Definition: xmlnumfe.cxx:146
void SetWasUsed(const uno::Sequence< sal_Int32 > &rWasUsed)
Definition: xmlnumfe.cxx:199
bool IsUsed(sal_uInt32 nKey) const
Definition: xmlnumfe.cxx:140
SvXMLuInt32Set aUsed
Definition: xmlnumfe.cxx:101
SvXMLNumUsedList_Impl()
SvXMLNumUsedList_Impl should be optimized!
Definition: xmlnumfe.cxx:124
void SetUsed(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:130
uno::Sequence< sal_Int32 > GetWasUsed() const
Definition: xmlnumfe.cxx:194
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
static bool convertColor(sal_Int32 &rColor, std::u16string_view rValue)
int nCount
#define DBG_ASSERT(sCon, aError)
float u
DocumentType eType
#define LANGUAGE_SYSTEM
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill='\0')
int i
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
NF_SYMBOLTYPE_STAR
NF_SYMBOLTYPE_CALENDAR
NF_SYMBOLTYPE_CURREXT
NF_SYMBOLTYPE_CURRENCY
NF_SYMBOLTYPE_EXP
NF_SYMBOLTYPE_FRACBLANK
NF_SYMBOLTYPE_DECSEP
NF_SYMBOLTYPE_DATESEP
NF_SYMBOLTYPE_TIME100SECSEP
NF_SYMBOLTYPE_STRING
NF_SYMBOLTYPE_BLANK
NF_SYMBOLTYPE_PERCENT
NF_SYMBOLTYPE_DIGIT
NF_SYMBOLTYPE_THSEP
NF_SYMBOLTYPE_DEL
NF_SYMBOLTYPE_TIMESEP
Handling of tokens in XML:
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:50
@ XML_DECIMAL_REPLACEMENT
Definition: xmltoken.hxx:645
@ XML_INTEGER_FRACTION_DELIMITER
Definition: xmltoken.hxx:3454
@ XML_FORCED_EXPONENT_SIGN
Definition: xmltoken.hxx:3448
@ XML_ZEROS_NUMERATOR_DIGITS
Definition: xmltoken.hxx:3452
@ XML_MAX_NUMERATOR_DIGITS
Definition: xmltoken.hxx:3451
@ XML_TRUNCATE_ON_OVERFLOW
Definition: xmltoken.hxx:2038
@ XML_MAX_DENOMINATOR_VALUE
Definition: xmltoken.hxx:3450
@ XML_TRANSLITERATION_STYLE
Definition: xmltoken.hxx:2341
@ XML_ZEROS_DENOMINATOR_DIGITS
Definition: xmltoken.hxx:3453
@ XML_TRANSLITERATION_FORMAT
Definition: xmltoken.hxx:2338
@ XML_DENOMINATOR_VALUE
Definition: xmltoken.hxx:663
@ XML_MIN_INTEGER_DIGITS
Definition: xmltoken.hxx:1307
@ XML_APPLY_STYLE_NAME
Definition: xmltoken.hxx:269
@ XML_MAX_BLANK_INTEGER_DIGITS
Definition: xmltoken.hxx:3455
@ XML_TRANSLITERATION_COUNTRY
Definition: xmltoken.hxx:2340
@ XML_MIN_NUMERATOR_DIGITS
Definition: xmltoken.hxx:1312
@ XML_TRANSLITERATION_SPELLOUT
Definition: xmltoken.hxx:3465
@ XML_MIN_DECIMAL_PLACES
Definition: xmltoken.hxx:3449
@ XML_MIN_EXPONENT_DIGITS
Definition: xmltoken.hxx:1305
@ XML_MIN_DENOMINATOR_DIGITS
Definition: xmltoken.hxx:1303
@ XML_TRANSLITERATION_LANGUAGE
Definition: xmltoken.hxx:2339
NF_KEY_M
NF_KEY_MI
NF_KEY_D
NF_KEY_EC
NF_KEY_BOOLEAN
NF_KEY_Q
NF_KEY_NN
NF_KEY_DD
NF_KEY_RR
NF_KEY_NNN
NF_KEY_AAAA
NF_KEY_CCC
NF_KEY_SS
NF_KEY_DDD
NF_KEY_H
NF_KEY_AP
NF_KEY_HH
NF_KEY_AAA
NF_KEY_AMPM
NF_KEY_WW
NF_KEY_MMMMM
NF_KEY_MMM
NF_KEY_GGG
NF_KEY_YYYY
NF_KEY_MMMM
NF_KEY_G
NF_KEY_MM
NF_KEY_S
NF_KEY_GG
NF_KEY_DDDD
NF_KEY_GENERAL
NF_KEY_EEC
NF_KEY_R
NF_KEY_NNNN
NF_KEY_YY
NF_KEY_MMI
NF_KEY_QQ
QPRO_FUNC_TYPE nType
sal_uInt16 sal_Unicode
constexpr sal_uInt16 XML_NAMESPACE_LO_EXT
constexpr sal_uInt16 XML_NAMESPACE_STYLE
constexpr sal_uInt16 XML_NAMESPACE_FO
constexpr sal_uInt16 XML_NAMESPACE_NUMBER
std::set< sal_uInt32 > SvXMLuInt32Set
Definition: xmlnumfe.cxx:60
static bool lcl_IsDefaultDateFormat(const SvNumberformat &rFormat, bool bSystemDate, NfIndexTableOffset eBuiltIn)
Definition: xmlnumfe.cxx:952
static const SvNumberformat * lcl_GetFormat(SvNumberFormatter const *pFormatter, sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1999
static OUString lcl_GetDefaultCalendar(SvNumberFormatter const *pFormatter, LanguageType nLang)
Definition: xmlnumfe.cxx:923
static OUString lcl_CreateStyleName(sal_Int32 nKey, sal_Int32 nPart, bool bDefPart, std::u16string_view rPrefix)
Definition: xmlnumfe.cxx:275
static bool lcl_IsInEmbedded(const SvXMLEmbeddedTextEntryArr &rEmbeddedEntries, sal_uInt16 nPos)
Definition: xmlnumfe.cxx:942
static sal_Int32 lcl_FindSymbol(const OUString &sUpperStr, std::u16string_view sCurString)
Definition: xmlnumfe.cxx:842
SvXMLDateElementAttributes
Definition: xmlnumfi.hxx:50
@ XML_DEA_SHORT
Definition: xmlnumfi.hxx:53
@ XML_DEA_TEXTLONG
Definition: xmlnumfi.hxx:56
@ XML_DEA_TEXTSHORT
Definition: xmlnumfi.hxx:55
@ XML_DEA_LONG
Definition: xmlnumfi.hxx:54
@ XML_DEA_NONE
Definition: xmlnumfi.hxx:51
sal_Int32 nLength
Definition: xmltoken.cxx:38
std::map< sal_uInt32, SvNumberformat * > SvNumberFormatTable
SvNumFormatType
NfIndexTableOffset
NF_DATE_SYSTEM_SHORT
NF_DATETIME_SYS_DDMMYYYY_HHMMSS
NF_DATE_SYS_DMMMYY
NF_DATE_SYS_MMYY
NF_CURRENCY_1000DEC2_RED
NF_DATE_SYS_DMMMMYYYY
NF_CURRENCY_1000DEC2_DASHED
NF_DATE_SYS_DDMMM
NF_DATE_SYS_NNNNDMMMMYYYY
NF_NUMBER_SYSTEM
NF_DATE_SYS_NNDMMMYY
NF_TEXT
NF_CURRENCY_1000DEC2
NF_BOOLEAN
NF_DATE_SYS_DDMMYY
NF_NUMBER_STANDARD
NF_CURRENCY_1000INT_RED
NF_DATE_SYS_DMMMYYYY
NF_CURRENCY_1000INT
NF_DATETIME_SYS_DDMMYYYY_HHMM
NF_DATE_SYS_NNDMMMMYYYY
NF_CURRENCY_1000DEC2_CCC
NF_DATE_SYS_DDMMYYYY
NF_DATETIME_SYSTEM_SHORT_HHMM
NF_DATE_SYSTEM_LONG
SvNumberformatLimitOps
NUMBERFORMAT_OP_LT
NUMBERFORMAT_OP_NO
NUMBERFORMAT_OP_GE
NUMBERFORMAT_OP_GT
NUMBERFORMAT_OP_LE
NUMBERFORMAT_OP_EQ
NUMBERFORMAT_OP_NE