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