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