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