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 rExport( rExp ),
214 sPrefix( OUString("N") ),
215 pFormatter( nullptr ),
216 bHasText( false )
217{
218 // supplier must be SvNumberFormatsSupplierObj
220 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp );
221 if (pObj)
222 pFormatter = pObj->GetNumberFormatter();
223
224 if ( pFormatter )
225 {
226 pLocaleData.reset( new LocaleDataWrapper( pFormatter->GetComponentContext(),
227 pFormatter->GetLanguageTag() ) );
228 }
229 else
230 {
232
233 pLocaleData.reset( new LocaleDataWrapper( rExport.getComponentContext(), std::move(aLanguageTag) ) );
234 }
235
236 pUsedList.reset(new SvXMLNumUsedList_Impl);
237}
238
240 SvXMLExport& rExp,
241 const css::uno::Reference< css::util::XNumberFormatsSupplier >& rSupp,
242 OUString aPrefix ) :
243 rExport( rExp ),
244 sPrefix(std::move( aPrefix )),
245 pFormatter( nullptr ),
246 bHasText( false )
247{
248 // supplier must be SvNumberFormatsSupplierObj
250 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp );
251 if (pObj)
253
254 if ( pFormatter )
255 {
258 }
259 else
260 {
262
263 pLocaleData.reset( new LocaleDataWrapper( 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 OUStringBuffer aFmtName(10);
278 aFmtName.append( rPrefix );
279 aFmtName.append( nKey );
280 if (!bDefPart)
281 {
282 aFmtName.append( 'P' );
283 aFmtName.append( nPart );
284 }
285 return aFmtName.makeStringAndClear();
286}
287
288void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar )
289{
290 if ( !rCalendar.isEmpty() )
291 {
293 }
294}
295
297{
298 if ( bLong ) // short is default
299 {
301 }
302}
303
305{
306 if ( nLang != LANGUAGE_SYSTEM )
307 {
309 LanguageTag( nLang), false);
310 }
311}
312
313// methods to write individual elements within a format
314
315void SvXMLNumFmtExport::AddToTextElement_Impl( std::u16string_view rString )
316{
317 // append to sTextContent, write element in FinishTextElement_Impl
318 // to avoid several text elements following each other
319
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.
324 bHasText = true;
325}
326
328{
329 if ( bHasText )
330 {
331 sal_uInt16 nNS = bUseExtensionNS ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER;
333 true, false );
334 rExport.Characters( sTextContent.makeStringAndClear() );
335 bHasText = false;
336 }
337}
338
340{
342
343 OUStringBuffer aColStr( 7 );
344 ::sax::Converter::convertColor( aColStr, rColor );
346 aColStr.makeStringAndClear() );
347
349 true, false );
350}
351
353 std::u16string_view rExt )
354{
356
357 if ( !rExt.empty() )
358 {
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);
363 if ( nLang < 0 )
364 nLang = -nLang;
365 AddLanguageAttr_Impl( LanguageType(nLang) ); // adds to pAttrList
366 }
367
370 true, false );
371 rExport.Characters( rString );
372}
373
375{
377
379 true, false );
380}
381
383{
385
387 true, false );
388}
389
390// date elements
391
392void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, bool bLong )
393{
395
396 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
397 AddStyleAttr_Impl( bLong ); // adds to pAttrList
398
400 true, false );
401}
402
403void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, bool bLong, bool bText )
404{
406
407 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
408 AddStyleAttr_Impl( bLong ); // adds to pAttrList
409 if ( bText )
410 {
412 }
413
415 true, false );
416}
417
418void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, bool bLong )
419{
421
422 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
423 AddStyleAttr_Impl( bLong ); // adds to pAttrList
424
426 true, false );
427}
428
429void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, bool bLong )
430{
432
433 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
434 AddStyleAttr_Impl( bLong ); // adds to pAttrList
435
437 true, false );
438}
439
440void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, bool bLong )
441{
443
444 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
445 AddStyleAttr_Impl( bLong ); // adds to pAttrList
446
448 true, false );
449}
450
451void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar )
452{
454
455 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
456
458 true, false );
459}
460
461void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, bool bLong )
462{
464
465 AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
466 AddStyleAttr_Impl( bLong ); // adds to pAttrList
467
469 true, false );
470}
471
472// time elements
473
475{
477
478 AddStyleAttr_Impl( bLong ); // adds to pAttrList
479
481 true, false );
482}
483
485{
487
488 AddStyleAttr_Impl( bLong ); // adds to pAttrList
489
491 true, false );
492}
493
495{
496 // Export only for 1.2 with extensions or 1.3 and later.
498 if (eVersion > SvtSaveOptions::ODFSVER_012)
499 {
501 // OFFICE-3765 For 1.2+ use loext namespace, for 1.3 use number namespace.
504 XML_FILL_CHARACTER, true, false );
505 rExport.Characters( OUString( nChar ) );
506 }
507}
508
509void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong, sal_uInt16 nDecimals )
510{
512
513 AddStyleAttr_Impl( bLong ); // adds to pAttrList
514 if ( nDecimals > 0 )
515 {
517 OUString::number( nDecimals ) );
518 }
519
521 true, false );
522}
523
525{
527
529 true, false );
530}
531
532// numbers
533
535 sal_Int32 nDecimals, sal_Int32 nMinDecimals,
536 sal_Int32 nInteger, const OUString& rDashStr,
537 bool bGrouping, sal_Int32 nTrailingThousands,
538 const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
539{
541
542 // decimals
543 if ( nDecimals >= 0 ) // negative = automatic
544 {
546 OUString::number( nDecimals ) );
547 }
548
549 if ( nMinDecimals >= 0 ) // negative = automatic
550 {
551 // Export only for 1.2 with extensions or 1.3 and later.
553 if (eVersion > SvtSaveOptions::ODFSVER_012)
554 {
555 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
559 OUString::number( nMinDecimals ) );
560 }
561 }
562
563 // integer digits
564 if ( nInteger >= 0 ) // negative = automatic
565 {
567 OUString::number( nInteger ) );
568 }
569
570 // decimal replacement (dashes) or variable decimals (#)
571 if ( !rDashStr.isEmpty() || nMinDecimals < nDecimals )
572 {
573 // full variable decimals means an empty replacement string
575 rDashStr );
576 }
577
578 // (automatic) grouping separator
579 if ( bGrouping )
580 {
582 }
583
584 // display-factor if there are trailing thousands separators
585 if ( nTrailingThousands )
586 {
587 // each separator character removes three digits
588 double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
589
590 OUStringBuffer aFactStr;
591 ::sax::Converter::convertDouble( aFactStr, fFactor );
592 rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
593 }
594
596 true, true );
597
598 // number:embedded-text as child elements
599
600 auto nEntryCount = rEmbeddedEntries.size();
601 for (decltype(nEntryCount) nEntry=0; nEntry < nEntryCount; ++nEntry)
602 {
603 const SvXMLEmbeddedTextEntry *const pObj = &rEmbeddedEntries[nEntry];
604
605 // position attribute
606 // position == 0 is between first integer digit and decimal separator
607 // position < 0 is inside decimal part
609 OUString::number( pObj->nFormatPos ) );
611 true, false );
612
613 // text as element content
614 OUStringBuffer aContent( pObj->aText );
615 while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1].nFormatPos == pObj->nFormatPos )
616 {
617 // The array can contain several elements for the same position in the number
618 // (for example, literal text and space from underscores). They must be merged
619 // into a single embedded-text element.
620 aContent.append(rEmbeddedEntries[nEntry+1].aText);
621 ++nEntry;
622 }
623 rExport.Characters( aContent.makeStringAndClear() );
624 }
625}
626
628 sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger,
629 bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign )
630{
632
633 // decimals
634 if ( nDecimals >= 0 ) // negative = automatic
635 {
637 OUString::number( nDecimals ) );
638 }
639
641 if ( nMinDecimals >= 0 ) // negative = automatic
642 {
643 // Export only for 1.2 with extensions or 1.3 and later.
644 if (eVersion > SvtSaveOptions::ODFSVER_012)
645 {
646 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
650 OUString::number( nMinDecimals ) );
651 }
652 }
653
654 // integer digits
655 if ( nInteger >= 0 ) // negative = automatic
656 {
658 OUString::number( nInteger ) );
659 }
660
661 // (automatic) grouping separator
662 if ( bGrouping )
663 {
665 }
666
667 // exponent digits
668 if ( nExp >= 0 )
669 {
671 OUString::number( nExp ) );
672 }
673
674 // exponent interval for engineering notation
675 if ( nExpInterval >= 0 )
676 {
677 // Export only for 1.2 with extensions or 1.3 and later.
678 if (eVersion > SvtSaveOptions::ODFSVER_012)
679 {
680 // OFFICE-1828 For 1.2+ use loext namespace, for 1.3 use number namespace.
683 XML_EXPONENT_INTERVAL, OUString::number( nExpInterval ) );
684 }
685 }
686
687 // exponent sign
688 // Export only for 1.2 with extensions or 1.3 and later.
689 if (eVersion > SvtSaveOptions::ODFSVER_012)
690 {
691 // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
695 bExpSign? XML_TRUE : XML_FALSE );
696 }
697
700 true, false );
701}
702
704 sal_Int32 nInteger, bool bGrouping,
705 const SvNumberformat& rFormat, sal_uInt16 nPart )
706{
708 const OUString aNumeratorString = rFormat.GetNumeratorString( nPart );
709 const OUString aDenominatorString = rFormat.GetDenominatorString( nPart );
710 const OUString aIntegerFractionDelimiterString = rFormat.GetIntegerFractionDelimiterString( nPart );
711 sal_Int32 nMaxNumeratorDigits = aNumeratorString.getLength();
712 // Count '0' as '?'
713 sal_Int32 nMinNumeratorDigits = aNumeratorString.replaceAll("0","?").indexOf('?');
714 sal_Int32 nZerosNumeratorDigits = aNumeratorString.indexOf('0');
715 if ( nMinNumeratorDigits >= 0 )
716 nMinNumeratorDigits = nMaxNumeratorDigits - nMinNumeratorDigits;
717 else
718 nMinNumeratorDigits = 0;
719 if ( nZerosNumeratorDigits >= 0 )
720 nZerosNumeratorDigits = nMaxNumeratorDigits - nZerosNumeratorDigits;
721 else
722 nZerosNumeratorDigits = 0;
723 sal_Int32 nMaxDenominatorDigits = aDenominatorString.getLength();
724 sal_Int32 nMinDenominatorDigits = aDenominatorString.replaceAll("0","?").indexOf('?');
725 sal_Int32 nZerosDenominatorDigits = aDenominatorString.indexOf('0');
726 if ( nMinDenominatorDigits >= 0 )
727 nMinDenominatorDigits = nMaxDenominatorDigits - nMinDenominatorDigits;
728 else
729 nMinDenominatorDigits = 0;
730 if ( nZerosDenominatorDigits >= 0 )
731 nZerosDenominatorDigits = nMaxDenominatorDigits - nZerosDenominatorDigits;
732 else
733 nZerosDenominatorDigits = 0;
734 sal_Int32 nDenominator = aDenominatorString.toInt32();
735
736 // integer digits
737 if ( nInteger >= 0 ) // negative = default (no integer part)
738 {
740 OUString::number( nInteger ) );
741 }
742
743 // (automatic) grouping separator
744 if ( bGrouping )
745 {
747 }
748
749 // integer/fraction delimiter
751 if ( !aIntegerFractionDelimiterString.isEmpty() && aIntegerFractionDelimiterString != " "
752 && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
753 { // Export only for 1.2/1.3 with extensions.
755 aIntegerFractionDelimiterString );
756 }
757
758 // numerator digits
759 if ( nMinNumeratorDigits == 0 ) // at least one digit to keep compatibility with previous versions
760 nMinNumeratorDigits++;
762 OUString::number( nMinNumeratorDigits ) );
763 // Export only for 1.2/1.3 with extensions.
764 if ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0)
765 {
766 // For extended ODF use loext namespace
768 OUString::number( nMaxNumeratorDigits ) );
769 }
770 if ( nZerosNumeratorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
772 OUString::number( nZerosNumeratorDigits ) );
773
774 if ( nDenominator )
775 {
777 OUString::number( nDenominator) );
778 }
779 // it's not necessary to export nDenominatorDigits
780 // if we have a forced denominator
781 else
782 {
783 if ( nMinDenominatorDigits == 0 ) // at least one digit to keep compatibility with previous versions
784 nMinDenominatorDigits++;
786 OUString::number( nMinDenominatorDigits ) );
787 if (eVersion > SvtSaveOptions::ODFSVER_012)
788 {
789 // OFFICE-3695 For 1.2+ use loext namespace, for 1.3 use number namespace.
793 OUString::number( pow ( 10.0, nMaxDenominatorDigits ) - 1 ) ); // 9, 99 or 999
794 }
795 if ( nZerosDenominatorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
797 OUString::number( nZerosDenominatorDigits ) );
798 }
799
801 true, false );
802}
803
804// mapping (condition)
805
806void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
807 sal_Int32 nKey, sal_Int32 nPart )
808{
810
811 if ( nOp == NUMBERFORMAT_OP_NO )
812 return;
813
814 // style namespace
815
816 OUStringBuffer aCondStr(20);
817 aCondStr.append( "value()" );
818 switch ( nOp )
819 {
820 case NUMBERFORMAT_OP_EQ: aCondStr.append( '=' ); break;
821 case NUMBERFORMAT_OP_NE: aCondStr.append( "!=" ); break;
822 case NUMBERFORMAT_OP_LT: aCondStr.append( '<' ); break;
823 case NUMBERFORMAT_OP_LE: aCondStr.append( "<=" ); break;
824 case NUMBERFORMAT_OP_GT: aCondStr.append( '>' ); break;
825 case NUMBERFORMAT_OP_GE: aCondStr.append( ">=" ); break;
826 default:
827 OSL_FAIL("unknown operator");
828 }
829 ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
830 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
831 '.', true );
832
834 aCondStr.makeStringAndClear() );
835
837 rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, false,
838 sPrefix ) ) );
839
841 true, false );
842}
843
844// for old (automatic) currency formats: parse currency symbol from text
845
846static sal_Int32 lcl_FindSymbol( const OUString& sUpperStr, std::u16string_view sCurString )
847{
848 // search for currency symbol
849 // Quoting as in ImpSvNumberformatScan::Symbol_Division
850
851 sal_Int32 nCPos = 0;
852 while (nCPos >= 0)
853 {
854 nCPos = sUpperStr.indexOf( sCurString, nCPos );
855 if (nCPos >= 0)
856 {
857 // in Quotes?
858 sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
859 if ( nQ < 0 )
860 {
861 // dm can be escaped as "dm or \d
862 sal_Unicode c;
863 if ( nCPos == 0 )
864 return nCPos; // found
865 c = sUpperStr[nCPos-1];
866 if ( c != '"' && c != '\\')
867 {
868 return nCPos; // found
869 }
870 else
871 {
872 nCPos++; // continue
873 }
874 }
875 else
876 {
877 nCPos = nQ + 1; // continue after quote end
878 }
879 }
880 }
881 return -1;
882}
883
885 const css::lang::Locale& rLocale )
886{
887 // returns true if currency element was written
888
889 bool bRet = false;
890
891 LanguageTag aLanguageTag( rLocale );
892 pFormatter->ChangeIntl( aLanguageTag.getLanguageType( false) );
893 OUString sCurString, sDummy;
894 pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
895
896 OUString sUpperStr = pFormatter->GetCharClass()->uppercase(rString);
897 sal_Int32 nPos = lcl_FindSymbol( sUpperStr, sCurString );
898 if ( nPos >= 0 )
899 {
900 sal_Int32 nLength = rString.getLength();
901 sal_Int32 nCurLen = sCurString.getLength();
902 sal_Int32 nCont = nPos + nCurLen;
903
904 // text before currency symbol
905 if ( nPos > 0 )
906 {
907 AddToTextElement_Impl( rString.subView( 0, nPos ) );
908 }
909 // currency symbol (empty string -> default)
911 bRet = true;
912
913 // text after currency symbol
914 if ( nCont < nLength )
915 {
916 AddToTextElement_Impl( rString.subView( nCont, nLength-nCont ) );
917 }
918 }
919 else
920 {
921 AddToTextElement_Impl( rString ); // simple text
922 }
923
924 return bRet; // true: currency element written
925}
926
927static OUString lcl_GetDefaultCalendar( SvNumberFormatter const * pFormatter, LanguageType nLang )
928{
929 // get name of first non-gregorian calendar for the language
930
931 OUString aCalendar;
932 CalendarWrapper* pCalendar = pFormatter->GetCalendar();
933 if (pCalendar)
934 {
935 lang::Locale aLocale( LanguageTag::convertToLocale( nLang ) );
936
937 const uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
938 auto pCal = std::find_if(aCals.begin(), aCals.end(),
939 [](const OUString& rCal) { return rCal != "gregorian"; });
940 if (pCal != aCals.end())
941 aCalendar = *pCal;
942 }
943 return aCalendar;
944}
945
946static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
947{
948 auto nCount = rEmbeddedEntries.size();
949 for (decltype(nCount) i=0; i<nCount; i++)
950 if ( rEmbeddedEntries[i].nSourcePos == nPos )
951 return true;
952
953 return false; // not found
954}
955
956static bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, bool bSystemDate, NfIndexTableOffset eBuiltIn )
957{
958 // make an extra loop to collect date elements, to check if it is a default format
959 // before adding the automatic-order attribute
960
968 bool bDateNoDefault = false;
969
970 sal_uInt16 nPos = 0;
971 bool bEnd = false;
972 short nLastType = 0;
973 while (!bEnd)
974 {
975 short nElemType = rFormat.GetNumForType( 0, nPos );
976 switch ( nElemType )
977 {
978 case 0:
979 if ( nLastType == NF_SYMBOLTYPE_STRING )
980 bDateNoDefault = true; // text at the end -> no default date format
981 bEnd = true; // end of format reached
982 break;
987 // text is ignored, except at the end
988 break;
989 // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
990 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
991 case NF_KEY_NNN:
992 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
993 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
994 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
995 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
996 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
997 case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
998 case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
999 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
1000 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
1001 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
1002 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
1003 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
1004 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
1005 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
1006 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
1007 case NF_KEY_AP:
1008 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1009 default:
1010 bDateNoDefault = true; // any other element -> no default format
1011 }
1012 nLastType = nElemType;
1013 ++nPos;
1014 }
1015
1016 if ( bDateNoDefault )
1017 return false; // additional elements
1018 else
1019 {
1021 eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate ));
1022
1023 return ( eFound == eBuiltIn );
1024 }
1025}
1026
1027// export one part (condition)
1028
1029void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey,
1030 sal_uInt16 nPart, bool bDefPart )
1031{
1033
1034 // element name
1035
1036 NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nRealKey );
1037
1038 SvNumFormatType nFmtType = SvNumFormatType::ALL;
1039 bool bThousand = false;
1040 sal_uInt16 nPrecision = 0;
1041 sal_uInt16 nLeading = 0;
1042 rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
1043 nFmtType &= ~SvNumFormatType::DEFINED;
1044
1045 // special treatment of builtin formats that aren't detected by normal parsing
1046 // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
1047 if ( eBuiltIn == NF_NUMBER_STANDARD )
1048 nFmtType = SvNumFormatType::NUMBER;
1049 else if ( eBuiltIn == NF_BOOLEAN )
1050 nFmtType = SvNumFormatType::LOGICAL;
1051 else if ( eBuiltIn == NF_TEXT )
1052 nFmtType = SvNumFormatType::TEXT;
1053
1054 // #101606# An empty subformat is a valid number-style resulting in an
1055 // empty display string for the condition of the subformat.
1056
1058 switch ( nFmtType )
1059 {
1060 // Type UNDEFINED likely is a crappy format string for that we could
1061 // not decide on any format type (and maybe could try harder?), but the
1062 // resulting XMLTokenEnum should be something valid, so make that
1063 // number-style.
1064 case SvNumFormatType::UNDEFINED:
1065 SAL_WARN("xmloff.style","UNDEFINED number format: '" << rFormat.GetFormatstring() << "'");
1066 [[fallthrough]];
1067 // Type is 0 if a format contains no recognized elements
1068 // (like text only) - this is handled as a number-style.
1069 case SvNumFormatType::ALL:
1070 case SvNumFormatType::EMPTY:
1071 case SvNumFormatType::NUMBER:
1072 case SvNumFormatType::SCIENTIFIC:
1073 case SvNumFormatType::FRACTION:
1075 break;
1076 case SvNumFormatType::PERCENT:
1078 break;
1079 case SvNumFormatType::CURRENCY:
1081 break;
1082 case SvNumFormatType::DATE:
1083 case SvNumFormatType::DATETIME:
1085 break;
1086 case SvNumFormatType::TIME:
1088 break;
1089 case SvNumFormatType::TEXT:
1091 break;
1092 case SvNumFormatType::LOGICAL:
1094 break;
1095 default: break;
1096 }
1097 SAL_WARN_IF( eType == XML_TOKEN_INVALID, "xmloff.style", "unknown format type" );
1098
1099 OUString sAttrValue;
1100 bool bUserDef( rFormat.GetType() & SvNumFormatType::DEFINED );
1101
1102 // common attributes for format
1103
1104 // format name (generated from key) - style namespace
1106 lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) );
1107
1108 // "volatile" attribute for styles used only in maps
1109 if ( !bDefPart )
1111
1112 // language / country
1113 LanguageType nLang = rFormat.GetLanguage();
1114 AddLanguageAttr_Impl( nLang ); // adds to pAttrList
1115
1116 // title (comment)
1117 // titles for builtin formats are not written
1118 sAttrValue = rFormat.GetComment();
1119 if ( !sAttrValue.isEmpty() && bUserDef && bDefPart )
1120 {
1122 }
1123
1124 // automatic ordering for currency and date formats
1125 // only used for some built-in formats
1126 bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 ||
1127 eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1128 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
1129 eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG ||
1130 eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM ||
1131 eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY ||
1132 eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
1133 eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
1134 eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
1136 eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
1137
1138 // format source (for date and time formats)
1139 // only used for some built-in formats
1140 bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
1141 eBuiltIn == NF_DATE_SYSTEM_LONG ||
1142 eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
1143 bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
1144
1145 // check if the format definition matches the key
1146 if ( bAutoOrder && ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) &&
1147 !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
1148 {
1149 bAutoOrder = bSystemDate = bLongSysDate = false; // don't write automatic-order attribute then
1150 }
1151
1152 if ( bAutoOrder &&
1153 ( nFmtType == SvNumFormatType::CURRENCY || nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) )
1154 {
1155 // #85109# format type must be checked to avoid dtd errors if
1156 // locale data contains other format types at the built-in positions
1157
1159 XML_TRUE );
1160 }
1161
1162 if ( bSystemDate && bAutoOrder &&
1163 ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) )
1164 {
1165 // #85109# format type must be checked to avoid dtd errors if
1166 // locale data contains other format types at the built-in positions
1167
1169 XML_LANGUAGE );
1170 }
1171
1172 // overflow for time formats as in [hh]:mm
1173 // controlled by bThousand from number format info
1174 // default for truncate-on-overflow is true
1175 if ( nFmtType == SvNumFormatType::TIME && bThousand )
1176 {
1178 XML_FALSE );
1179 }
1180
1181 // Native number transliteration
1182 css::i18n::NativeNumberXmlAttributes2 aAttr;
1183 rFormat.GetNatNumXml( aAttr, nPart );
1184 if ( !aAttr.Format.isEmpty() )
1185 {
1186 assert(aAttr.Spellout.isEmpty()); // mutually exclusive
1187
1188 /* FIXME-BCP47: ODF defines no transliteration-script or
1189 * transliteration-rfc-language-tag */
1190 LanguageTag aLanguageTag( aAttr.Locale);
1191 OUString aLanguage, aScript, aCountry;
1192 aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
1194 aAttr.Format );
1196 aLanguage );
1198 aCountry );
1200 aAttr.Style );
1201 }
1202
1203 if ( !aAttr.Spellout.isEmpty() )
1204 {
1205 const bool bWriteSpellout = aAttr.Format.isEmpty();
1206 assert(bWriteSpellout); // mutually exclusive
1207
1208 // Export only for 1.2 and later with extensions
1210 // Also ensure that duplicated transliteration-language and
1211 // transliteration-country attributes never escape into the wild with
1212 // releases.
1213 if ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) && bWriteSpellout )
1214 {
1215 /* FIXME-BCP47: ODF defines no transliteration-script or
1216 * transliteration-rfc-language-tag */
1217 LanguageTag aLanguageTag( aAttr.Locale);
1218 OUString aLanguage, aScript, aCountry;
1219 aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
1220 // For 1.2/1.3+ use loext namespace.
1221 rExport.AddAttribute( /*((eVersion < SvtSaveOptions::ODFSVER_)
1222 ? */ XML_NAMESPACE_LO_EXT /*: XML_NAMESPACE_NUMBER)*/,
1223 XML_TRANSLITERATION_SPELLOUT, aAttr.Spellout );
1225 aLanguage );
1227 aCountry );
1228 }
1229 }
1230
1231 // The element
1233 true, true );
1234
1235 // color (properties element)
1236
1237 const Color* pCol = rFormat.GetColor( nPart );
1238 if (pCol)
1240
1241 // detect if there is "real" content, excluding color and maps
1243 bool bAnyContent = false;
1244
1245 // format elements
1246
1247 SvXMLEmbeddedTextEntryArr aEmbeddedEntries;
1248 if ( eBuiltIn == NF_NUMBER_STANDARD )
1249 {
1250 // default number format contains just one number element
1251 WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries );
1252 bAnyContent = true;
1253 }
1254 else if ( eBuiltIn == NF_BOOLEAN )
1255 {
1256 // boolean format contains just one boolean element
1258 bAnyContent = true;
1259 }
1260 else if (eType == XML_BOOLEAN_STYLE)
1261 {
1262 // <number:boolean-style> may contain only <number:boolean> and
1263 // <number:text> elements.
1264 sal_uInt16 nPos = 0;
1265 bool bEnd = false;
1266 while (!bEnd)
1267 {
1268 const short nElemType = rFormat.GetNumForType( nPart, nPos );
1269 switch (nElemType)
1270 {
1271 case 0:
1272 bEnd = true; // end of format reached
1273 if (bHasText && sTextContent.isEmpty())
1274 bHasText = false; // don't write trailing empty text
1275 break;
1277 {
1278 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1279 if (pElemStr)
1280 AddToTextElement_Impl( *pElemStr );
1281 }
1282 break;
1283 case NF_KEY_BOOLEAN:
1285 bAnyContent = true;
1286 break;
1287 }
1288 ++nPos;
1289 }
1290 }
1291 else
1292 {
1293 // first loop to collect attributes
1294
1295 bool bDecDashes = false;
1296 bool bExpFound = false;
1297 bool bCurrFound = false;
1298 bool bInInteger = true;
1299 bool bExpSign = true;
1300 bool bDecAlign = false; // decimal alignment with "?"
1301 sal_Int32 nExpDigits = 0;
1302 sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#"
1303 sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits
1304 sal_Int32 nMinDecimals = nPrecision;
1305 OUString sCurrExt;
1306 OUString aCalendar;
1307 bool bImplicitOtherCalendar = false;
1308 bool bExplicitCalendar = false;
1309 sal_uInt16 nPos = 0;
1310 bool bEnd = false;
1311 while (!bEnd)
1312 {
1313 short nElemType = rFormat.GetNumForType( nPart, nPos );
1314 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1315
1316 switch ( nElemType )
1317 {
1318 case 0:
1319 bEnd = true; // end of format reached
1320 break;
1322 if ( bExpFound && pElemStr )
1323 nExpDigits += pElemStr->getLength();
1324 else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' )
1325 {
1326 bDecDashes = true;
1327 nMinDecimals = 0;
1328 }
1329 else if ( !bInInteger && pElemStr )
1330 {
1331 for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- )
1332 {
1333 sal_Unicode aChar = (*pElemStr)[i];
1334 if ( aChar == '#' || aChar == '?' )
1335 {
1336 nMinDecimals --;
1337 if ( aChar == '?' )
1338 bDecAlign = true;
1339 }
1340 else
1341 break;
1342 }
1343 }
1344 if ( bInInteger && pElemStr )
1345 nIntegerSymbols += pElemStr->getLength();
1346 nTrailingThousands = 0;
1347 break;
1349 bInInteger = false;
1350 break;
1352 if (pElemStr)
1353 nTrailingThousands += pElemStr->getLength(); // is reset to 0 if digits follow
1354 break;
1355 case NF_SYMBOLTYPE_EXP:
1356 bExpFound = true; // following digits are exponent digits
1357 bInInteger = false;
1358 if ( pElemStr && ( pElemStr->getLength() == 1
1359 || ( pElemStr->getLength() == 2 && (*pElemStr)[1] == '-' ) ) )
1360 bExpSign = false; // for 0.00E0 or 0.00E-00
1361 break;
1363 bCurrFound = true;
1364 break;
1366 if (pElemStr)
1367 sCurrExt = *pElemStr;
1368 break;
1369
1370 // E, EE, R, RR: select non-gregorian calendar
1371 // AAA, AAAA: calendar is switched at the position of the element
1372 case NF_KEY_EC:
1373 case NF_KEY_EEC:
1374 case NF_KEY_R:
1375 case NF_KEY_RR:
1376 if (aCalendar.isEmpty())
1377 {
1378 aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
1379 bImplicitOtherCalendar = true;
1380 }
1381 break;
1382 }
1383 ++nPos;
1384 }
1385
1386 // collect strings for embedded-text (must be known before number element is written)
1387
1388 bool bAllowEmbedded = ( nFmtType == SvNumFormatType::ALL || nFmtType == SvNumFormatType::NUMBER ||
1389 nFmtType == SvNumFormatType::CURRENCY ||
1390 nFmtType == SvNumFormatType::PERCENT );
1391 if ( bAllowEmbedded )
1392 {
1393 sal_Int32 nDigitsPassed = 0;
1394 sal_Int32 nEmbeddedPositionsMax = nIntegerSymbols;
1395 // Enable embedded text in decimal part only if there's a decimal part
1396 if ( nPrecision )
1397 nEmbeddedPositionsMax += nPrecision + 1;
1398 nPos = 0;
1399 bEnd = false;
1400 while (!bEnd)
1401 {
1402 short nElemType = rFormat.GetNumForType( nPart, nPos );
1403 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1404
1405 switch ( nElemType )
1406 {
1407 case 0:
1408 bEnd = true; // end of format reached
1409 break;
1411 if ( pElemStr )
1412 nDigitsPassed += pElemStr->getLength();
1413 break;
1415 nDigitsPassed++;
1416 break;
1420 if ( 0 < nDigitsPassed && nDigitsPassed < nEmbeddedPositionsMax && pElemStr )
1421 {
1422 // text (literal or underscore) within the integer (>=0) or decimal (<0) part of a number:number element
1423
1424 OUString aEmbeddedStr;
1425 if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
1426 {
1427 aEmbeddedStr = *pElemStr;
1428 }
1429 else if (pElemStr->getLength() >= 2)
1430 {
1431 SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] );
1432 }
1433 sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
1434
1435 aEmbeddedEntries.push_back(
1436 SvXMLEmbeddedTextEntry(nPos, nEmbedPos, aEmbeddedStr));
1437 }
1438 break;
1439 }
1440 ++nPos;
1441 }
1442 }
1443
1444 // final loop to write elements
1445
1446 bool bNumWritten = false;
1447 bool bCurrencyWritten = false;
1448 short nPrevType = 0;
1449 nPos = 0;
1450 bEnd = false;
1451 while (!bEnd)
1452 {
1453 short nElemType = rFormat.GetNumForType( nPart, nPos );
1454 const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1455
1456 switch ( nElemType )
1457 {
1458 case 0:
1459 bEnd = true; // end of format reached
1460 if (bHasText && sTextContent.isEmpty())
1461 bHasText = false; // don't write trailing empty text
1462 break;
1468 if (pElemStr)
1469 {
1470 if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
1471 ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
1472 nPrecision > 0 )
1473 {
1474 // decimal separator after seconds is implied by
1475 // "decimal-places" attribute and must not be written
1476 // as text element
1478 }
1479 else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1480 {
1481 // text is written as embedded-text child of the number,
1482 // don't create a text element
1483 }
1484 else if ( nFmtType == SvNumFormatType::CURRENCY && !bCurrFound && !bCurrencyWritten )
1485 {
1486 // automatic currency symbol is implemented as part of
1487 // normal text -> search for the symbol
1488 bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
1490 bAnyContent = true;
1491 }
1492 else
1493 AddToTextElement_Impl( *pElemStr );
1494 }
1495 break;
1497 if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1498 {
1499 // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1500 // (#i20396# the spaces may also be in embedded-text elements)
1501
1502 OUString aBlanks;
1503 if (pElemStr->getLength() >= 2)
1504 SvNumberformat::InsertBlanks( aBlanks, 0, (*pElemStr)[1] );
1505 AddToTextElement_Impl( aBlanks );
1506 }
1507 break;
1508 case NF_KEY_GENERAL :
1509 WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries );
1510 bAnyContent = true;
1511 break;
1512 case NF_KEY_CCC:
1513 if (pElemStr)
1514 {
1515 if ( bCurrencyWritten )
1516 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1517 else
1518 {
1521 // pElemStr is "CCC"
1522
1523 WriteCurrencyElement_Impl( *pElemStr, u"" );
1524 bAnyContent = true;
1525 bCurrencyWritten = true;
1526 }
1527 }
1528 break;
1530 if (pElemStr)
1531 {
1532 if ( bCurrencyWritten )
1533 AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1534 else
1535 {
1536 WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
1537 bAnyContent = true;
1538 bCurrencyWritten = true;
1539 }
1540 }
1541 break;
1543 if (!bNumWritten) // write number part
1544 {
1545 switch ( nFmtType )
1546 {
1547 // for type 0 (not recognized as a special type),
1548 // write a "normal" number
1549 case SvNumFormatType::ALL:
1550 case SvNumFormatType::NUMBER:
1551 case SvNumFormatType::CURRENCY:
1552 case SvNumFormatType::PERCENT:
1553 {
1554 // decimals
1555 // only some built-in formats have automatic decimals
1556 sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo
1557 if ( eBuiltIn == NF_NUMBER_STANDARD ||
1558 eBuiltIn == NF_CURRENCY_1000DEC2 ||
1559 eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1560 eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
1561 eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
1562 nDecimals = -1;
1563
1564 // integer digits
1565 // only one built-in format has automatic integer digits
1566 sal_Int32 nInteger = nLeading;
1567 if ( eBuiltIn == NF_NUMBER_SYSTEM )
1568 nInteger = -1;
1569
1570 // string for decimal replacement
1571 // has to be taken from nPrecision
1572 // (positive number even for automatic decimals)
1573 OUStringBuffer sDashStr;
1574 if (bDecDashes && nPrecision > 0)
1575 comphelper::string::padToLength(sDashStr, nPrecision, '-');
1576 // "?" in decimal part are replaced by space character
1577 if (bDecAlign && nPrecision > 0)
1578 sDashStr = " ";
1579
1580 WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, sDashStr.makeStringAndClear(),
1581 bThousand, nTrailingThousands, aEmbeddedEntries);
1582 bAnyContent = true;
1583 }
1584 break;
1585 case SvNumFormatType::SCIENTIFIC:
1586 // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1587 // as integer digits: use nIntegerSymbols instead of nLeading
1588 // nIntegerSymbols represents exponent interval (for engineering notation)
1589 WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, bThousand, nExpDigits, nIntegerSymbols, bExpSign );
1590 bAnyContent = true;
1591 break;
1592 case SvNumFormatType::FRACTION:
1593 {
1594 sal_Int32 nInteger = nLeading;
1595 if ( rFormat.GetNumForNumberElementCount( nPart ) == 3 )
1596 {
1597 // If there is only two numbers + fraction in format string
1598 // the fraction doesn't have an integer part, and no
1599 // min-integer-digits attribute must be written.
1600 nInteger = -1;
1601 }
1602 WriteFractionElement_Impl( nInteger, bThousand, rFormat, nPart );
1603 bAnyContent = true;
1604 }
1605 break;
1606 default: break;
1607 }
1608
1609 bNumWritten = true;
1610 }
1611 break;
1613 if ( pElemStr && nPrecision == 0 )
1614 {
1615 // A decimal separator after the number, without following decimal digits,
1616 // isn't modelled as part of the number element, so it's written as text
1617 // (the distinction between a quoted and non-quoted, locale-dependent
1618 // character is lost here).
1619
1620 AddToTextElement_Impl( *pElemStr );
1621 }
1622 break;
1623 case NF_SYMBOLTYPE_DEL:
1624 if ( pElemStr && *pElemStr == "@" )
1625 {
1627 bAnyContent = true;
1628 }
1629 break;
1630
1632 if ( pElemStr )
1633 {
1634 aCalendar = *pElemStr;
1635 bExplicitCalendar = true;
1636 }
1637 break;
1638
1639 // date elements:
1640
1641 case NF_KEY_D:
1642 case NF_KEY_DD:
1643 {
1644 bool bLong = ( nElemType == NF_KEY_DD );
1645 WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1646 bAnyContent = true;
1647 }
1648 break;
1649 case NF_KEY_DDD:
1650 case NF_KEY_DDDD:
1651 case NF_KEY_NN:
1652 case NF_KEY_NNN:
1653 case NF_KEY_NNNN:
1654 case NF_KEY_AAA:
1655 case NF_KEY_AAAA:
1656 {
1657 OUString aCalAttr = aCalendar;
1658 if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
1659 {
1660 // calendar attribute for AAA and AAAA is switched only for this element
1661 if (aCalAttr.isEmpty())
1662 aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang );
1663 }
1664
1665 bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
1666 nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
1667 WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
1668 bAnyContent = true;
1669 if ( nElemType == NF_KEY_NNNN )
1670 {
1671 // write additional text element for separator
1673 LanguageTag( nLang ) ) );
1674 AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() );
1675 }
1676 }
1677 break;
1678 case NF_KEY_M:
1679 case NF_KEY_MM:
1680 case NF_KEY_MMM:
1681 case NF_KEY_MMMM:
1682 case NF_KEY_MMMMM:
1683 {
1684 bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM );
1685 bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
1686 nElemType == NF_KEY_MMMMM );
1687 WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
1688 bAnyContent = true;
1689 }
1690 break;
1691 case NF_KEY_YY:
1692 case NF_KEY_YYYY:
1693 case NF_KEY_EC:
1694 case NF_KEY_EEC:
1695 case NF_KEY_R:
1696 {
1698 // Calendar attribute for E and EE and R is set in
1699 // first loop. If set and not an explicit calendar and
1700 // YY or YYYY is encountered, switch temporarily to
1701 // Gregorian.
1702 bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
1703 nElemType == NF_KEY_R );
1705 ((bImplicitOtherCalendar && !bExplicitCalendar
1706 && (nElemType == NF_KEY_YY || nElemType == NF_KEY_YYYY)) ? "gregorian" : aCalendar),
1707 (bSystemDate ? bLongSysDate : bLong));
1708 bAnyContent = true;
1709 }
1710 break;
1711 case NF_KEY_G:
1712 case NF_KEY_GG:
1713 case NF_KEY_GGG:
1714 case NF_KEY_RR:
1715 {
1717 bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
1718 WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1719 bAnyContent = true;
1720 if ( nElemType == NF_KEY_RR )
1721 {
1722 // calendar attribute for RR is set in first loop
1723 WriteYearElement_Impl( aCalendar, ( bSystemDate || bLongSysDate ) );
1724 }
1725 }
1726 break;
1727 case NF_KEY_Q:
1728 case NF_KEY_QQ:
1729 {
1730 bool bLong = ( nElemType == NF_KEY_QQ );
1731 WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1732 bAnyContent = true;
1733 }
1734 break;
1735 case NF_KEY_WW:
1736 WriteWeekElement_Impl( aCalendar );
1737 bAnyContent = true;
1738 break;
1739
1740 // time elements (bSystemDate is not used):
1741
1742 case NF_KEY_H:
1743 case NF_KEY_HH:
1744 WriteHoursElement_Impl( nElemType == NF_KEY_HH );
1745 bAnyContent = true;
1746 break;
1747 case NF_KEY_MI:
1748 case NF_KEY_MMI:
1749 WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
1750 bAnyContent = true;
1751 break;
1752 case NF_KEY_S:
1753 case NF_KEY_SS:
1754 WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
1755 bAnyContent = true;
1756 break;
1757 case NF_KEY_AMPM:
1758 case NF_KEY_AP:
1759 WriteAMPMElement_Impl(); // short/long?
1760 bAnyContent = true;
1761 break;
1762 case NF_SYMBOLTYPE_STAR :
1763 // export only if ODF 1.2 extensions are enabled
1765 {
1766 if ( pElemStr && pElemStr->getLength() > 1 )
1767 WriteRepeatedElement_Impl( (*pElemStr)[1] );
1768 }
1769 break;
1770 }
1771 nPrevType = nElemType;
1772 ++nPos;
1773 }
1774 }
1775
1776 if ( !sTextContent.isEmpty() )
1777 bAnyContent = true; // element written in FinishTextElement_Impl
1778
1779 FinishTextElement_Impl(); // final text element - before maps
1780
1781 if ( !bAnyContent )
1782 {
1783 // for an empty format, write an empty text element
1785 true, false );
1786 }
1787
1788 // mapping (conditions) must be last elements
1789
1790 if (!bDefPart)
1791 return;
1792
1793 SvNumberformatLimitOps eOp1, eOp2;
1794 double fLimit1, fLimit2;
1795 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1796
1797 WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
1798 WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
1799
1800 if ( !rFormat.HasTextFormat() )
1801 return;
1802
1803 // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1804 // by reversing the 2nd condition.
1805 // For a trailing text format like 0;@ that has no conditions
1806 // use a "less or equal than biggest" condition for the number
1807 // part, ODF can't store subformats (style maps) without
1808 // conditions.
1809
1811 double fLimit3 = fLimit2;
1812 sal_uInt16 nLastPart = 2;
1813 SvNumberformatLimitOps eOpLast = eOp2;
1814 if (eOp2 == NUMBERFORMAT_OP_NO)
1815 {
1816 eOpLast = eOp1;
1817 fLimit3 = fLimit1;
1818 nLastPart = (eOp1 == NUMBERFORMAT_OP_NO) ? 0 : 1;
1819 }
1820 switch ( eOpLast )
1821 {
1822 case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
1823 case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
1824 case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
1825 case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
1826 case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
1827 case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
1828 case NUMBERFORMAT_OP_NO: eOp3 = NUMBERFORMAT_OP_LE; fLimit3 = DBL_MAX; break;
1829 }
1830
1831 if ( fLimit1 == fLimit2 &&
1832 ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
1833 ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
1834 {
1835 // For <x and >x, add =x as last condition
1836 // (just for readability, <=x would be valid, too)
1837
1838 eOp3 = NUMBERFORMAT_OP_EQ;
1839 }
1840
1841 WriteMapElement_Impl( eOp3, fLimit3, nKey, nLastPart );
1842}
1843
1844// export one format
1845
1846void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey )
1847{
1848 const sal_uInt16 XMLNUM_MAX_PARTS = 4;
1849 bool bParts[XMLNUM_MAX_PARTS] = { false, false, false, false };
1850 sal_uInt16 nUsedParts = 0;
1851 for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart)
1852 {
1853 if (rFormat.GetNumForInfoScannedType( nPart) != SvNumFormatType::UNDEFINED)
1854 {
1855 bParts[nPart] = true;
1856 nUsedParts = nPart + 1;
1857 }
1858 }
1859
1860 SvNumberformatLimitOps eOp1, eOp2;
1861 double fLimit1, fLimit2;
1862 rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1863
1864 // if conditions are set, even empty formats must be written
1865
1866 if ( eOp1 != NUMBERFORMAT_OP_NO )
1867 {
1868 bParts[1] = true;
1869 if (nUsedParts < 2)
1870 nUsedParts = 2;
1871 }
1872 if ( eOp2 != NUMBERFORMAT_OP_NO )
1873 {
1874 bParts[2] = true;
1875 if (nUsedParts < 3)
1876 nUsedParts = 3;
1877 }
1878 if ( rFormat.HasTextFormat() )
1879 {
1880 bParts[3] = true;
1881 if (nUsedParts < 4)
1882 nUsedParts = 4;
1883 }
1884
1885 for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart)
1886 {
1887 if (bParts[nPart])
1888 {
1889 bool bDefault = ( nPart+1 == nUsedParts ); // last = default
1890 ExportPart_Impl( rFormat, nKey, nRealKey, nPart, bDefault );
1891 }
1892 }
1893}
1894
1895// export method called by application
1896
1897void SvXMLNumFmtExport::Export( bool bIsAutoStyle )
1898{
1899 if ( !pFormatter )
1900 return; // no formatter -> no entries
1901
1902 sal_uInt32 nKey;
1903 const SvNumberformat* pFormat = nullptr;
1904 bool bNext(pUsedList->GetFirstUsed(nKey));
1905 while(bNext)
1906 {
1907 // ODF has its notation of system formats, so obtain the "real" already
1908 // substituted format but use the original key for style name.
1909 sal_uInt32 nRealKey = nKey;
1910 pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey);
1911 if(pFormat)
1912 ExportFormat_Impl( *pFormat, nKey, nRealKey );
1913 bNext = pUsedList->GetNextUsed(nKey);
1914 }
1915 if (!bIsAutoStyle)
1916 {
1917 std::vector<LanguageType> aLanguages;
1918 pFormatter->GetUsedLanguages( aLanguages );
1919 for (const auto& nLang : aLanguages)
1920 {
1921 sal_uInt32 nDefaultIndex = 0;
1923 SvNumFormatType::DEFINED, nDefaultIndex, nLang );
1924 for (const auto& rTableEntry : rTable)
1925 {
1926 nKey = rTableEntry.first;
1927 pFormat = rTableEntry.second;
1928 if (!pUsedList->IsUsed(nKey))
1929 {
1930 DBG_ASSERT((pFormat->GetType() & SvNumFormatType::DEFINED), "a not user defined numberformat found");
1931 sal_uInt32 nRealKey = nKey;
1932 if (pFormat->IsSubstituted())
1933 {
1934 pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey); // export the "real" format
1935 assert(pFormat);
1936 }
1937 // user-defined and used formats are exported
1938 ExportFormat_Impl( *pFormat, nKey, nRealKey );
1939 // if it is a user-defined Format it will be added else nothing will happen
1940 pUsedList->SetUsed(nKey);
1941 }
1942 }
1943 }
1944 }
1945 pUsedList->Export();
1946}
1947
1948OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
1949{
1950 if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey))
1951 return lcl_CreateStyleName( nKey, 0, true, sPrefix );
1952 else
1953 {
1954 OSL_FAIL("There is no written Data-Style");
1955 return OUString();
1956 }
1957}
1958
1959void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
1960{
1961 SAL_WARN_IF( pFormatter == nullptr, "xmloff.style", "missing formatter" );
1962 if( !pFormatter )
1963 return;
1964
1965 if (pFormatter->GetEntry(nKey))
1966 pUsedList->SetUsed( nKey );
1967 else {
1968 OSL_FAIL("no existing Numberformat found with this key");
1969 }
1970}
1971
1972uno::Sequence<sal_Int32> SvXMLNumFmtExport::GetWasUsed() const
1973{
1974 if (pUsedList)
1975 return pUsedList->GetWasUsed();
1976 return uno::Sequence<sal_Int32>();
1977}
1978
1979void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
1980{
1981 if (pUsedList)
1982 pUsedList->SetWasUsed(rWasUsed);
1983}
1984
1985static const SvNumberformat* lcl_GetFormat( SvNumberFormatter const * pFormatter,
1986 sal_uInt32 nKey )
1987{
1988 return ( pFormatter != nullptr ) ? pFormatter->GetEntry( nKey ) : nullptr;
1989}
1990
1991sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
1992{
1993 sal_uInt32 nRet = nKey;
1994
1995 const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey );
1996 if( pFormat != nullptr )
1997 {
1998 SAL_WARN_IF( pFormatter == nullptr, "xmloff.style", "format without formatter?" );
1999
2000 SvNumFormatType nType = pFormat->GetType();
2001
2002 sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn(
2003 nKey, LANGUAGE_SYSTEM );
2004
2005 if( nNewKey != nKey )
2006 {
2007 nRet = nNewKey;
2008 }
2009 else
2010 {
2011 OUString aFormatString( pFormat->GetFormatstring() );
2012 sal_Int32 nErrorPos;
2014 aFormatString,
2015 nErrorPos, nType, nNewKey,
2016 pFormat->GetLanguage(), LANGUAGE_SYSTEM, true);
2017
2018 // success? Then use new key.
2019 if( nErrorPos == 0 )
2020 nRet = nNewKey;
2021 }
2022 }
2023
2024 return nRet;
2025}
2026
2027/* 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:911
void Characters(const OUString &rChars)
Definition: xmlexp.cxx:2133
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
returns the deterministic version for odf export
Definition: xmlexp.cxx:2271
OUString EncodeStyleName(const OUString &rName, bool *pEncoded=nullptr) const
Definition: xmlexp.cxx:1938
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
Definition: xmlexp.hxx:522
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:945
static sal_uInt16 GetDefaultDateFormat(SvXMLDateElementAttributes eDOW, SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth, SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours, SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs, bool bSystem)
Definition: xmlnumfi.cxx:1102
SAL_DLLPRIVATE void WriteHoursElement_Impl(bool bLong)
Definition: xmlnumfe.cxx:474
SAL_DLLPRIVATE void WriteQuarterElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:461
SAL_DLLPRIVATE void WriteSecondsElement_Impl(bool bLong, sal_uInt16 nDecimals)
Definition: xmlnumfe.cxx:509
OUStringBuffer sTextContent
Definition: xmlnumfe.hxx:53
OUString sPrefix
Definition: xmlnumfe.hxx:51
SAL_DLLPRIVATE void WriteMinutesElement_Impl(bool bLong)
Definition: xmlnumfe.cxx:484
SvXMLExport & rExport
Definition: xmlnumfe.hxx:50
std::unique_ptr< LocaleDataWrapper > pLocaleData
Definition: xmlnumfe.hxx:56
SAL_DLLPRIVATE void WriteScientificElement_Impl(sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign)
Definition: xmlnumfe.cxx:627
css::uno::Sequence< sal_Int32 > GetWasUsed() const
Definition: xmlnumfe.cxx:1972
SAL_DLLPRIVATE void AddToTextElement_Impl(std::u16string_view rString)
Definition: xmlnumfe.cxx:315
SAL_DLLPRIVATE void WriteFractionElement_Impl(sal_Int32 nInteger, bool bGrouping, const SvNumberformat &rFormat, sal_uInt16 nPart)
Definition: xmlnumfe.cxx:703
SAL_DLLPRIVATE void ExportPart_Impl(const SvNumberformat &rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey, sal_uInt16 nPart, bool bDefPart)
Definition: xmlnumfe.cxx:1029
SvNumberFormatter * pFormatter
Definition: xmlnumfe.hxx:52
SAL_DLLPRIVATE void WriteDayOfWeekElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:440
std::unique_ptr< SvXMLNumUsedList_Impl > pUsedList
Definition: xmlnumfe.hxx:55
SAL_DLLPRIVATE void WriteAMPMElement_Impl()
Definition: xmlnumfe.cxx:524
SAL_DLLPRIVATE void WriteCurrencyElement_Impl(const OUString &rString, std::u16string_view rExt)
Definition: xmlnumfe.cxx:352
SAL_DLLPRIVATE void WriteTextContentElement_Impl()
Definition: xmlnumfe.cxx:382
SAL_DLLPRIVATE void AddCalendarAttr_Impl(const OUString &rCalendar)
Definition: xmlnumfe.cxx:288
sal_uInt32 ForceSystemLanguage(sal_uInt32 nKey)
obtain number format with system language for a given key
Definition: xmlnumfe.cxx:1991
SAL_DLLPRIVATE void WriteWeekElement_Impl(const OUString &rCalendar)
Definition: xmlnumfe.cxx:451
OUString GetStyleName(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1948
SAL_DLLPRIVATE void WriteColorElement_Impl(const Color &rColor)
Definition: xmlnumfe.cxx:339
SAL_DLLPRIVATE bool WriteTextWithCurrency_Impl(const OUString &rString, const css::lang::Locale &rLocale)
Definition: xmlnumfe.cxx:884
SAL_DLLPRIVATE void WriteMonthElement_Impl(const OUString &rCalendar, bool bLong, bool bText)
Definition: xmlnumfe.cxx:403
SAL_DLLPRIVATE void ExportFormat_Impl(const SvNumberformat &rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey)
Definition: xmlnumfe.cxx:1846
SAL_DLLPRIVATE void WriteDayElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:392
SAL_DLLPRIVATE void WriteNumberElement_Impl(sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, const OUString &rDashStr, bool bGrouping, sal_Int32 nTrailingThousands, const SvXMLEmbeddedTextEntryArr &rEmbeddedEntries)
Definition: xmlnumfe.cxx:534
void Export(bool bIsAutoStyle)
Definition: xmlnumfe.cxx:1897
SAL_DLLPRIVATE void WriteYearElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:418
SAL_DLLPRIVATE void WriteEraElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:429
SAL_DLLPRIVATE void FinishTextElement_Impl(bool bUseExtensionNS=false)
Definition: xmlnumfe.cxx:327
SAL_DLLPRIVATE void WriteRepeatedElement_Impl(sal_Unicode ch)
Definition: xmlnumfe.cxx:494
SAL_DLLPRIVATE void AddStyleAttr_Impl(bool bLong)
Definition: xmlnumfe.cxx:296
SvXMLNumFmtExport(SvXMLExport &rExport, const css::uno::Reference< css::util::XNumberFormatsSupplier > &rSupp)
SAL_DLLPRIVATE void AddLanguageAttr_Impl(LanguageType nLang)
Definition: xmlnumfe.cxx:304
SAL_DLLPRIVATE void WriteMapElement_Impl(sal_Int32 nOp, double fLimit, sal_Int32 nKey, sal_Int32 nPart)
Definition: xmlnumfe.cxx:806
void SetUsed(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1959
SAL_DLLPRIVATE void WriteBooleanElement_Impl()
Definition: xmlnumfe.cxx:374
void SetWasUsed(const css::uno::Sequence< sal_Int32 > &rWasUsed)
Definition: xmlnumfe.cxx:1979
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
OUString sPrefix
#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_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:643
@ XML_INTEGER_FRACTION_DELIMITER
Definition: xmltoken.hxx:3446
@ XML_FORCED_EXPONENT_SIGN
Definition: xmltoken.hxx:3440
@ XML_ZEROS_NUMERATOR_DIGITS
Definition: xmltoken.hxx:3444
@ XML_MAX_NUMERATOR_DIGITS
Definition: xmltoken.hxx:3443
@ XML_TRUNCATE_ON_OVERFLOW
Definition: xmltoken.hxx:2032
@ XML_MAX_DENOMINATOR_VALUE
Definition: xmltoken.hxx:3442
@ XML_TRANSLITERATION_STYLE
Definition: xmltoken.hxx:2335
@ XML_ZEROS_DENOMINATOR_DIGITS
Definition: xmltoken.hxx:3445
@ XML_TRANSLITERATION_FORMAT
Definition: xmltoken.hxx:2332
@ XML_DENOMINATOR_VALUE
Definition: xmltoken.hxx:661
@ XML_MIN_INTEGER_DIGITS
Definition: xmltoken.hxx:1302
@ XML_APPLY_STYLE_NAME
Definition: xmltoken.hxx:269
@ XML_TRANSLITERATION_COUNTRY
Definition: xmltoken.hxx:2334
@ XML_MIN_NUMERATOR_DIGITS
Definition: xmltoken.hxx:1307
@ XML_TRANSLITERATION_SPELLOUT
Definition: xmltoken.hxx:3456
@ XML_MIN_DECIMAL_PLACES
Definition: xmltoken.hxx:3441
@ XML_MIN_EXPONENT_DIGITS
Definition: xmltoken.hxx:1300
@ XML_MIN_DENOMINATOR_DIGITS
Definition: xmltoken.hxx:1298
@ XML_TRANSLITERATION_LANGUAGE
Definition: xmltoken.hxx:2333
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:956
static const SvNumberformat * lcl_GetFormat(SvNumberFormatter const *pFormatter, sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1985
static OUString lcl_GetDefaultCalendar(SvNumberFormatter const *pFormatter, LanguageType nLang)
Definition: xmlnumfe.cxx:927
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:946
static sal_Int32 lcl_FindSymbol(const OUString &sUpperStr, std::u16string_view sCurString)
Definition: xmlnumfe.cxx:846
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::unordered_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