LibreOffice Module xmloff (master) 1
xmlnumfi.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 <svl/zforlist.hxx>
21#include <svl/numformat.hxx>
22#include <svl/zformat.hxx>
23#include <svl/numuno.hxx>
25#include <tools/color.hxx>
26#include <osl/diagnose.h>
27#include <rtl/math.hxx>
28#include <rtl/ustrbuf.hxx>
29#include <sal/log.hxx>
30
32
33#include <utility>
34#include <xmloff/xmlement.hxx>
35#include <xmloff/xmlnumfi.hxx>
36#include <xmloff/xmltkmap.hxx>
38#include <xmloff/xmlictxt.hxx>
39#include <xmloff/xmlimp.hxx>
40#include <xmloff/xmluconv.hxx>
42#include <xmloff/families.hxx>
43#include <xmloff/xmltoken.hxx>
45
46#include <memory>
47#include <string_view>
48#include <vector>
49
50using namespace ::com::sun::star;
51using namespace ::xmloff::token;
52
53namespace {
54
55struct SvXMLNumFmtEntry
56{
57 OUString aName;
58 sal_uInt32 nKey;
59 bool bRemoveAfterUse;
60
61 SvXMLNumFmtEntry( OUString aN, sal_uInt32 nK, bool bR ) :
62 aName(std::move(aN)), nKey(nK), bRemoveAfterUse(bR) {}
63};
64
65}
66
68{
70 std::unique_ptr<LocaleDataWrapper> pLocaleData;
71 std::vector<SvXMLNumFmtEntry> m_NameEntries;
72
73 uno::Reference< uno::XComponentContext > m_xContext;
74
75public:
78 const uno::Reference<uno::XComponentContext>& rxContext );
79
82 sal_uInt32 GetKeyForName( std::u16string_view rName );
83 void AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse );
84 void SetUsed( sal_uInt32 nKey );
86};
87
89{
90 sal_Int32 nDecimals = -1;
91 sal_Int32 nInteger = -1;
92 sal_Int32 nExpDigits = -1;
93 sal_Int32 nExpInterval = -1;
94 sal_Int32 nMinNumerDigits = -1;
95 sal_Int32 nMinDenomDigits = -1;
96 sal_Int32 nMaxNumerDigits = -1;
97 sal_Int32 nMaxDenomDigits = -1;
98 sal_Int32 nFracDenominator = -1;
99 sal_Int32 nMinDecimalDigits = -1;
100 sal_Int32 nZerosNumerDigits = -1;
101 sal_Int32 nZerosDenomDigits = -1;
102 bool bGrouping = false;
103 bool bDecReplace = false;
104 bool bExpSign = true;
105 bool bDecAlign = false;
106 double fDisplayFactor = 1.0;
108 std::map<sal_Int32, OUString> m_EmbeddedElements;
109};
110
111namespace {
112
113enum class SvXMLStyleTokens;
114
115class SvXMLNumFmtElementContext : public SvXMLImportContext
116{
117 SvXMLNumFormatContext& rParent;
118 SvXMLStyleTokens nType;
119 OUStringBuffer aContent;
120 SvXMLNumberInfo aNumInfo;
121 LanguageType nElementLang;
122 bool bLong;
123 bool bTextual;
124 OUString sCalendar;
125
126public:
127 SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_Int32 nElement,
128 SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType,
129 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
130
131 virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
132 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
133 virtual void SAL_CALL characters( const OUString& rChars ) override;
134 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
135
136 void AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent );
137};
138
139class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext
140{
141 SvXMLNumFmtElementContext& rParent;
142 OUStringBuffer aContent;
143 sal_Int32 nTextPosition;
144
145public:
146 SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_Int32 nElement,
147 SvXMLNumFmtElementContext& rParentContext,
148 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
149
150 virtual void SAL_CALL characters( const OUString& rChars ) override;
151 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
152};
153
154class SvXMLNumFmtMapContext : public SvXMLImportContext
155{
156 SvXMLNumFormatContext& rParent;
157 OUString sCondition;
158 OUString sName;
159
160public:
161 SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_Int32 nElement,
162 SvXMLNumFormatContext& rParentContext,
163 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
164
165 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
166};
167
168class SvXMLNumFmtPropContext : public SvXMLImportContext
169{
170 SvXMLNumFormatContext& rParent;
171 Color m_nColor;
172 bool bColSet;
173
174public:
175 SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_Int32 nElement,
176 SvXMLNumFormatContext& rParentContext,
177 const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
178
179 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
180};
181
182enum class SvXMLStyleTokens
183{
184 Text,
185 FillCharacter,
186 Number,
187 ScientificNumber,
188 Fraction,
189 CurrencySymbol,
190 Day,
191 Month,
192 Year,
193 Era,
194 DayOfWeek,
195 WeekOfYear,
196 Quarter,
197 Hours,
198 AmPm,
199 Minutes,
200 Seconds,
201 Boolean,
202 TextContent
203};
204
205}
206
207// standard colors
208
209
210#define XML_NUMF_COLORCOUNT 10
211
213{
214 COL_BLACK,
220 COL_BROWN,
221 COL_GRAY,
224};
225
226
227// token maps
228
229
230// maps for SvXMLUnitConverter::convertEnum
231
233{
234 { XML_SHORT, false },
235 { XML_LONG, true },
236 { XML_TOKEN_INVALID, false }
237};
238
240{
241 { XML_FIXED, false },
242 { XML_LANGUAGE, true },
243 { XML_TOKEN_INVALID, false }
244};
245
246namespace {
247
248struct SvXMLDefaultDateFormat
249{
250 NfIndexTableOffset eFormat;
258 bool bSystem;
259};
260
261}
262
263const SvXMLDefaultDateFormat aDefaultDateFormats[] =
264{
265 // format day-of-week day month year hours minutes seconds format-source
266
282};
283
284
285// SvXMLNumImpData
286
287
289 SvNumberFormatter* pFmt,
290 const uno::Reference<uno::XComponentContext>& rxContext )
291: pFormatter(pFmt),
292 m_xContext(rxContext)
293{
294 SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" );
295}
296
297sal_uInt32 SvXMLNumImpData::GetKeyForName( std::u16string_view rName )
298{
299 for (const auto& rObj : m_NameEntries)
300 {
301 if (rObj.aName == rName)
302 return rObj.nKey; // found
303 }
305}
306
307void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse )
308{
309 if ( bRemoveAfterUse )
310 {
311 // if there is already an entry for this key without the bRemoveAfterUse flag,
312 // clear the flag for this entry, too
313
314 for (const auto& rObj : m_NameEntries)
315 {
316 if (rObj.nKey == nKey && !rObj.bRemoveAfterUse)
317 {
318 bRemoveAfterUse = false; // clear flag for new entry
319 break;
320 }
321 }
322 }
323 else
324 {
325 // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key
326 SetUsed( nKey );
327 }
328
329 m_NameEntries.emplace_back(rName, nKey, bRemoveAfterUse);
330}
331
332void SvXMLNumImpData::SetUsed( sal_uInt32 nKey )
333{
334 for (auto& rObj : m_NameEntries)
335 {
336 if (rObj.nKey == nKey)
337 {
338 rObj.bRemoveAfterUse = false; // used -> don't remove
339
340 // continue searching - there may be several entries for the same key
341 // (with different names), the format must not be deleted if any one of
342 // them is used
343 }
344 }
345}
346
348{
349 // remove temporary (volatile) formats from NumberFormatter
350 // called at the end of each import (styles and content), so volatile formats
351 // from styles can't be used in content
352
353 if ( !pFormatter )
354 return;
355
356 for (const auto& rObj : m_NameEntries)
357 {
358 if (rObj.bRemoveAfterUse )
359 {
360 const SvNumberformat* pFormat = pFormatter->GetEntry(rObj.nKey);
361 if (pFormat && (pFormat->GetType() & SvNumFormatType::DEFINED))
362 pFormatter->DeleteEntry(rObj.nKey);
363 }
364 }
365}
366
368{
369 if ( !pLocaleData || pLocaleData->getLanguageTag() != LanguageTag(nLang) )
370 pLocaleData = std::make_unique<LocaleDataWrapper>(
372 LanguageTag( nLang ) );
373 return *pLocaleData;
374}
375
376
377// SvXMLNumFmtMapContext
378
379
380SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport,
381 sal_Int32 /*nElement*/,
382 SvXMLNumFormatContext& rParentContext,
383 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
384 SvXMLImportContext( rImport ),
385 rParent( rParentContext )
386{
387 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
388 {
389 OUString sValue = aIter.toString();
390 switch(aIter.getToken())
391 {
392 case XML_ELEMENT(STYLE, XML_CONDITION):
393 sCondition = sValue;
394 break;
396 sName = sValue;
397 break;
398 default:
399 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
400 }
401 }
402}
403
404void SvXMLNumFmtMapContext::endFastElement(sal_Int32 )
405{
406 rParent.AddCondition( sCondition, sName );
407}
408
409
410// SvXMLNumFmtPropContext
411
412
413SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport,
414 sal_Int32 /*nElement*/,
415 SvXMLNumFormatContext& rParentContext,
416 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
417 SvXMLImportContext( rImport ),
418 rParent( rParentContext ),
419 m_nColor( 0 ),
420 bColSet( false )
421{
422 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
423 {
424 switch ( aIter.getToken())
425 {
426 case XML_ELEMENT(FO, XML_COLOR):
427 case XML_ELEMENT(FO_COMPAT, XML_COLOR):
428 bColSet = ::sax::Converter::convertColor( m_nColor, aIter.toView() );
429 break;
430 default:
431 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
432 }
433 }
434}
435
436void SvXMLNumFmtPropContext::endFastElement(sal_Int32 )
437{
438 if (bColSet)
439 rParent.AddColor( m_nColor );
440}
441
442
443// SvXMLNumFmtEmbeddedTextContext
444
445
446SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport,
447 sal_Int32 /*nElement*/,
448 SvXMLNumFmtElementContext& rParentContext,
449 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
450 SvXMLImportContext( rImport ),
451 rParent( rParentContext ),
452 nTextPosition( 0 )
453{
454 sal_Int32 nAttrVal;
455
456 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
457 {
458 if ( aIter.getToken() == XML_ELEMENT(NUMBER, XML_POSITION) )
459 {
460 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView() ))
461 nTextPosition = nAttrVal;
462 }
463 else
464 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
465 }
466}
467
468void SvXMLNumFmtEmbeddedTextContext::characters( const OUString& rChars )
469{
470 aContent.append( rChars );
471}
472
473void SvXMLNumFmtEmbeddedTextContext::endFastElement(sal_Int32 )
474{
475 rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() );
476}
477
478static bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent )
479{
480 SvXMLStylesTokens nFormatType = rParent.GetType();
481
482 // Treat space equal to non-breaking space separator.
483 const sal_Unicode cNBSP = 0x00A0;
484 sal_Unicode cTS;
485 if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE ||
486 nFormatType == SvXMLStylesTokens::CURRENCY_STYLE ||
487 nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) &&
488 (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep()[0]) ||
489 (cChar == ' ' && cTS == cNBSP)) )
490 {
491 // #i22394# Extra occurrences of thousands separator must be quoted, so they
492 // aren't mis-interpreted as display-factor.
493 // This must be limited to the format types that can contain a number element,
494 // because the same character can be a date separator that should not be quoted
495 // in date formats.
496
497 return false; // force quotes
498 }
499
500 // see ImpSvNumberformatScan::Next_Symbol
501
502 // All format types except BOOLEAN may contain minus sign or delimiter.
503 if ( cChar == '-' )
504 return nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE;
505
506 if ( ( cChar == ' ' ||
507 cChar == '/' ||
508 cChar == '.' ||
509 cChar == ',' ||
510 cChar == ':' ||
511 cChar == '\'' ) &&
512 ( nFormatType == SvXMLStylesTokens::CURRENCY_STYLE ||
513 nFormatType == SvXMLStylesTokens::DATE_STYLE ||
514 nFormatType == SvXMLStylesTokens::TIME_STYLE ) ) // other formats do not require delimiter tdf#97837
515 return true;
516
517 // percent sign must be used without quotes for percentage styles only
518 if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && cChar == '%' )
519 return true;
520
521 // don't put quotes around single parentheses (often used for negative numbers)
522 if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE ||
523 nFormatType == SvXMLStylesTokens::CURRENCY_STYLE ||
524 nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) &&
525 ( cChar == '(' || cChar == ')' ) )
526 return true;
527
528 return false;
529}
530
531static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent )
532{
533 bool bQuote = true;
534 sal_Int32 nLength = rContent.getLength();
535 const SvXMLStylesTokens nFormatType = rParent.GetType();
536
537 if (nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE &&
538 ((nLength == 1 && lcl_ValidChar( rContent[0], rParent)) ||
539 (nLength == 2 &&
540 ((rContent[0] == ' ' && rContent[1] == '-') ||
541 (rContent[1] == ' ' && lcl_ValidChar( rContent[0], rParent))))))
542 {
543 // Don't quote single separator characters like space or percent,
544 // or separator characters followed by space (used in date formats).
545 // Or space followed by minus (used in currency formats) that would
546 // lead to almost duplicated formats with built-in formats just with
547 // the difference of quotes.
548 bQuote = false;
549 }
550 else if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && nLength > 1 )
551 {
552 // the percent character in percentage styles must be left out of quoting
553 // (one occurrence is enough even if there are several percent characters in the string)
554
555 sal_Int32 nPos = rContent.indexOf( '%' );
556 if ( nPos >= 0 )
557 {
558 if ( nPos + 1 < nLength )
559 {
560 if ( nPos + 2 == nLength && lcl_ValidChar( rContent[nPos + 1], rParent ) )
561 {
562 // single character that doesn't need quoting
563 }
564 else
565 {
566 // quote text behind percent character
567 rContent.insert( nPos + 1, '"' );
568 rContent.append( '"' );
569 }
570 }
571 if ( nPos > 0 )
572 {
573 if ( nPos == 1 && lcl_ValidChar( rContent[0], rParent ) )
574 {
575 // single character that doesn't need quoting
576 }
577 else
578 {
579 // quote text before percent character
580 rContent.insert( nPos, '"' );
581 rContent.insert( 0, '"' );
582 }
583 }
584 bQuote = false;
585 }
586 // else: normal quoting (below)
587 }
588
589 if ( !bQuote )
590 return;
591
592 // #i55469# quotes in the string itself have to be escaped
593 bool bEscape = ( rContent.indexOf( '"' ) >= 0 );
594 if ( bEscape )
595 {
596 // A quote is turned into "\"" - a quote to end quoted text, an escaped quote,
597 // and a quote to resume quoting.
598 OUString aInsert( "\"\\\"" );
599
600 sal_Int32 nPos = 0;
601 while ( nPos < rContent.getLength() )
602 {
603 if ( rContent[nPos] == '"' )
604 {
605 rContent.insert( nPos, aInsert );
606 nPos += aInsert.getLength();
607 }
608 ++nPos;
609 }
610 }
611
612 // quote string literals
613 rContent.insert( 0, '"' );
614 rContent.append( '"' );
615
616 // remove redundant double quotes at start or end
617 if ( !bEscape )
618 return;
619
620 if ( rContent.getLength() > 2 &&
621 rContent[0] == '"' &&
622 rContent[1] == '"' )
623 {
624 rContent.remove(0, 2);
625 }
626
627 sal_Int32 nLen = rContent.getLength();
628 if ( nLen > 2 &&
629 rContent[nLen - 1] == '"' &&
630 rContent[nLen - 2] == '"' )
631 {
632 rContent.truncate(nLen - 2);
633 }
634}
635
636
637// SvXMLNumFmtElementContext
638
639
640SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport,
641 sal_Int32 /*nElement*/,
642 SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType,
643 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
644 SvXMLImportContext( rImport ),
645 rParent( rParentContext ),
646 nType( nNewType ),
647 nElementLang( LANGUAGE_SYSTEM ),
648 bLong( false ),
649 bTextual( false )
650{
651 LanguageTagODF aLanguageTagODF;
652 sal_Int32 nAttrVal;
653 bool bAttrBool(false);
654 bool bVarDecimals = false;
655 bool bIsMaxDenominator = false;
656 double fAttrDouble;
657
658 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
659 {
660 switch (aIter.getToken())
661 {
662 case XML_ELEMENT(NUMBER, XML_DECIMAL_PLACES):
663 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
664 {
665 // fdo#58539 & gnome#627420: limit number of digits during import
666 aNumInfo.nDecimals = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS);
667 }
668 break;
671 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
672 aNumInfo.nMinDecimalDigits = nAttrVal;
673 break;
675 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
676 aNumInfo.nInteger = nAttrVal;
677 break;
678 case XML_ELEMENT(NUMBER, XML_GROUPING):
679 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() ))
680 aNumInfo.bGrouping = bAttrBool;
681 break;
682 case XML_ELEMENT(NUMBER, XML_DISPLAY_FACTOR):
683 if (::sax::Converter::convertDouble( fAttrDouble, aIter.toView() ))
684 aNumInfo.fDisplayFactor = fAttrDouble;
685 break;
687 if ( aIter.toView() == " " )
688 {
689 aNumInfo.bDecAlign = true; // space replacement for "?"
690 bVarDecimals = true;
691 }
692 else
693 if ( aIter.isEmpty() )
694 bVarDecimals = true; // empty replacement string: variable decimals
695 else // all other strings
696 aNumInfo.bDecReplace = true; // decimal replacement with dashes
697 break;
699 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
700 aNumInfo.nExpDigits = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS);
701 break;
704 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
705 aNumInfo.nExpInterval = nAttrVal;
706 break;
709 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() ))
710 aNumInfo.bExpSign = bAttrBool;
711 break;
713 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
714 aNumInfo.nMinNumerDigits = nAttrVal;
715 break;
717 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
718 aNumInfo.nMinDenomDigits = nAttrVal;
719 break;
721 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // at least one '#'
722 aNumInfo.nMaxNumerDigits = nAttrVal;
723 break;
725 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // 0 is not valid
726 {
727 aNumInfo.nFracDenominator = nAttrVal;
728 bIsMaxDenominator = false;
729 }
730 break;
731 case XML_ELEMENT(NUMBER, XML_MAX_DENOMINATOR_VALUE): // part of ODF 1.3
733 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 ) && aNumInfo.nFracDenominator <= 0)
734 { // if denominator value not yet defined
735 aNumInfo.nFracDenominator = nAttrVal;
736 bIsMaxDenominator = true;
737 }
738 break;
741 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
742 aNumInfo.nZerosNumerDigits = nAttrVal;
743 break;
746 if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 ))
747 aNumInfo.nZerosDenomDigits = nAttrVal;
748 break;
751 aNumInfo.aIntegerFractionDelimiter = aIter.toString();
752 break;
753 case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG):
754 aLanguageTagODF.maRfcLanguageTag = aIter.toString();
755 break;
756 case XML_ELEMENT(NUMBER, XML_LANGUAGE):
757 aLanguageTagODF.maLanguage = aIter.toString();
758 break;
759 case XML_ELEMENT(NUMBER, XML_SCRIPT):
760 aLanguageTagODF.maScript = aIter.toString();
761 break;
762 case XML_ELEMENT(NUMBER, XML_COUNTRY):
763 aLanguageTagODF.maCountry = aIter.toString();
764 break;
765 case XML_ELEMENT(NUMBER, XML_STYLE):
766 SvXMLUnitConverter::convertEnum( bLong, aIter.toView(), aStyleValueMap );
767 break;
768 case XML_ELEMENT(NUMBER, XML_TEXTUAL):
769 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() ))
770 bTextual = bAttrBool;
771 break;
772 case XML_ELEMENT(NUMBER, XML_CALENDAR):
773 sCalendar = aIter.toString();
774 break;
775 default:
776 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
777 }
778 }
779 if ( aNumInfo.nMinDecimalDigits == -1)
780 {
781 if ( bVarDecimals || aNumInfo.bDecReplace )
782 aNumInfo.nMinDecimalDigits = 0;
783 else
784 aNumInfo.nMinDecimalDigits = aNumInfo.nDecimals;
785 }
786 if ( aNumInfo.nZerosDenomDigits > 0 )
787 { // nMin = count of '0' and '?'
788 if ( aNumInfo.nMinDenomDigits < aNumInfo.nZerosDenomDigits )
789 aNumInfo.nMinDenomDigits = aNumInfo.nZerosDenomDigits;
790 }
791 else
792 aNumInfo.nZerosDenomDigits = 0;
793 if ( aNumInfo.nMinDenomDigits >= 0 )
794 if ( aNumInfo.nMaxDenomDigits < aNumInfo.nMinDenomDigits )
795 aNumInfo.nMaxDenomDigits = ( aNumInfo.nMinDenomDigits ? aNumInfo.nMinDenomDigits : 1 );
796 if ( aNumInfo.nZerosNumerDigits > 0 )
797 {
798 if ( aNumInfo.nMinNumerDigits < aNumInfo.nZerosNumerDigits )
799 aNumInfo.nMinNumerDigits = aNumInfo.nZerosNumerDigits;
800 }
801 else
802 aNumInfo.nZerosNumerDigits = 0;
803 if ( aNumInfo.nMinNumerDigits >= 0 )
804 if ( aNumInfo.nMaxNumerDigits < aNumInfo.nMinNumerDigits )
805 aNumInfo.nMaxNumerDigits = ( aNumInfo.nMinNumerDigits ? aNumInfo.nMinNumerDigits : 1 );
806 if ( bIsMaxDenominator && aNumInfo.nFracDenominator > 0 )
807 {
808 aNumInfo.nMaxDenomDigits = floor( log10( aNumInfo.nFracDenominator ) ) + 1;
809 aNumInfo.nFracDenominator = -1; // Max denominator value only gives number of digits at denominator
810 }
811 if ( aNumInfo.nMaxDenomDigits > 0 )
812 {
813 if ( aNumInfo.nMinDenomDigits < 0 )
814 aNumInfo.nMinDenomDigits = 0;
815 else if ( aNumInfo.nMinDenomDigits > aNumInfo.nMaxDenomDigits )
816 aNumInfo.nMinDenomDigits = aNumInfo.nMaxDenomDigits;
817 }
818
819 if ( !aLanguageTagODF.isEmpty() )
820 {
821 nElementLang = aLanguageTagODF.getLanguageTag().getLanguageType( false);
822 if ( nElementLang == LANGUAGE_DONTKNOW )
823 nElementLang = LANGUAGE_SYSTEM;
824 }
825
826 if ( aNumInfo.aIntegerFractionDelimiter.isEmpty() )
827 aNumInfo.aIntegerFractionDelimiter = " ";
828}
829
830css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFmtElementContext::createFastChildContext(
831 sal_Int32 nElement,
832 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
833{
834 // only number:number supports number:embedded-text child element
835
836 if ( nType == SvXMLStyleTokens::Number &&
837 nElement == XML_ELEMENT(NUMBER, XML_EMBEDDED_TEXT) )
838 {
839 return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nElement, *this, xAttrList );
840 }
841 else
842 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
843 return nullptr;
844}
845
846void SvXMLNumFmtElementContext::characters( const OUString& rChars )
847{
848 aContent.append( rChars );
849}
850
851void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent )
852{
853 if (rContent.isEmpty())
854 return;
855
856 auto iterPair = aNumInfo.m_EmbeddedElements.emplace(nFormatPos, rContent);
857 if (!iterPair.second)
858 // there's already an element at this position - append text to existing element
859 iterPair.first->second += rContent;
860}
861
862void SvXMLNumFmtElementContext::endFastElement(sal_Int32 )
863{
864 bool bEffLong = bLong;
865 switch (nType)
866 {
867 case SvXMLStyleTokens::Text:
868 if ( rParent.HasLongDoW() &&
869 std::u16string_view(aContent) == rParent.GetLocaleData().getLongDateDayOfWeekSep() )
870 {
871 // skip separator constant after long day of week
872 // (NF_KEY_NNNN contains the separator)
873
874 if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) )
875 {
876 aContent.truncate();
877 }
878
879 rParent.SetHasLongDoW( false ); // only once
880 }
881 if ( !aContent.isEmpty() )
882 {
883 lcl_EnquoteIfNecessary( aContent, rParent );
884 rParent.AddToCode( aContent );
885 aContent.setLength(0);
886 }
887 else
888 {
889 // Quoted empty text may be significant to separate.
890 aContent.append("\"\"");
891 rParent.AddToCode( aContent );
892 aContent.setLength(0);
893 rParent.SetHasTrailingEmptyText(true); // *after* AddToCode()
894 }
895 break;
896
897 case SvXMLStyleTokens::Number:
898 rParent.AddNumber( aNumInfo );
899 break;
900
901 case SvXMLStyleTokens::CurrencySymbol:
902 rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang );
903 break;
904
905 case SvXMLStyleTokens::TextContent:
906 rParent.AddToCode( '@');
907 break;
908 case SvXMLStyleTokens::FillCharacter:
909 if ( !aContent.isEmpty() )
910 {
911 rParent.AddToCode( '*' );
912 rParent.AddToCode( aContent[0] );
913 }
914 break;
915 case SvXMLStyleTokens::Boolean:
916 rParent.AddNfKeyword( NF_KEY_BOOLEAN );
917 break;
918
919 case SvXMLStyleTokens::Day:
920 rParent.UpdateCalendar( sCalendar );
922
923 rParent.AddNfKeyword(
924 sal::static_int_cast< sal_uInt16 >(
925 bEffLong ? NF_KEY_DD : NF_KEY_D ) );
926 break;
927 case SvXMLStyleTokens::Month:
928 rParent.UpdateCalendar( sCalendar );
930
931 rParent.AddNfKeyword(
932 sal::static_int_cast< sal_uInt16 >(
933 bTextual
934 ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM )
935 : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) );
936 break;
937 case SvXMLStyleTokens::Year:
939 {
940 // Y after G (era) is replaced by E for a secondary calendar.
941 // Do not replace for default calendar.
942 // Also replace Y by E if we're switching to the secondary
943 // calendar of a locale if it is known to implicitly use E.
944 rParent.UpdateCalendar( sCalendar);
945 const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState();
946 if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY
947 || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER)
948 {
949 rParent.AddNfKeyword(
950 sal::static_int_cast< sal_uInt16 >(
951 bEffLong ? NF_KEY_EEC : NF_KEY_EC ) );
952 }
953 else
954 {
955 rParent.AddNfKeyword(
956 sal::static_int_cast< sal_uInt16 >(
957 bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) );
958 }
959 }
960 break;
961 case SvXMLStyleTokens::Era:
962 rParent.UpdateCalendar( sCalendar );
964 rParent.AddNfKeyword(
965 sal::static_int_cast< sal_uInt16 >(
966 bEffLong ? NF_KEY_GGG : NF_KEY_G ) );
967 // HasEra flag is set
968 break;
969 case SvXMLStyleTokens::DayOfWeek:
971 {
972 // Implicit secondary calendar uses A keyword, default and
973 // explicit calendar N keyword.
974 rParent.UpdateCalendar( sCalendar);
975 const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState();
976 if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY
977 || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER)
978 {
979 rParent.AddNfKeyword(
980 sal::static_int_cast< sal_uInt16 >(
981 bEffLong ? NF_KEY_AAAA : NF_KEY_AAA ) );
982 }
983 else
984 {
985 rParent.AddNfKeyword(
986 sal::static_int_cast< sal_uInt16 >(
987 bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) );
988 }
989 }
990 break;
991 case SvXMLStyleTokens::WeekOfYear:
992 rParent.UpdateCalendar( sCalendar );
993 rParent.AddNfKeyword( NF_KEY_WW );
994 break;
995 case SvXMLStyleTokens::Quarter:
996 rParent.UpdateCalendar( sCalendar );
997 rParent.AddNfKeyword(
998 sal::static_int_cast< sal_uInt16 >(
999 bEffLong ? NF_KEY_QQ : NF_KEY_Q ) );
1000 break;
1001 case SvXMLStyleTokens::Hours:
1002 rParent.AddNfKeyword(
1003 sal::static_int_cast< sal_uInt16 >(
1004 bEffLong ? NF_KEY_HH : NF_KEY_H ) );
1005 break;
1006 case SvXMLStyleTokens::AmPm:
1008 rParent.AddNfKeyword( NF_KEY_AMPM );
1009 break;
1010 case SvXMLStyleTokens::Minutes:
1011 rParent.AddNfKeyword(
1012 sal::static_int_cast< sal_uInt16 >(
1013 bEffLong ? NF_KEY_MMI : NF_KEY_MI ) );
1014 break;
1015 case SvXMLStyleTokens::Seconds:
1016 rParent.AddNfKeyword(
1017 sal::static_int_cast< sal_uInt16 >(
1018 bEffLong ? NF_KEY_SS : NF_KEY_S ) );
1019 if ( aNumInfo.nDecimals > 0 )
1020 {
1021 // manually add the decimal places
1022 rParent.AddToCode(rParent.GetLocaleData().getNumDecimalSep());
1023 for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++)
1024 {
1025 rParent.AddToCode( '0');
1026 }
1027 }
1028 break;
1029
1030 case SvXMLStyleTokens::Fraction:
1031 {
1032 if ( aNumInfo.nInteger >= 0 )
1033 {
1034 // add integer part only if min-integer-digits attribute is there
1035 aNumInfo.nDecimals = 0;
1036 rParent.AddNumber( aNumInfo ); // number without decimals
1037 OUStringBuffer sIntegerFractionDelimiter(aNumInfo.aIntegerFractionDelimiter);
1038 lcl_EnquoteIfNecessary( sIntegerFractionDelimiter, rParent );
1039 rParent.AddToCode( sIntegerFractionDelimiter ); // default is ' '
1040 }
1041
1043
1044 sal_Int32 i;
1045 for (i=aNumInfo.nMaxNumerDigits; i > 0; i--)
1046 {
1047 if ( i > aNumInfo.nMinNumerDigits )
1048 rParent.AddToCode( '#' );
1049 else if ( i > aNumInfo.nZerosNumerDigits )
1050 rParent.AddToCode( '?' );
1051 else
1052 rParent.AddToCode( '0' );
1053 }
1054 rParent.AddToCode( '/' );
1055 if ( aNumInfo.nFracDenominator > 0 )
1056 {
1057 rParent.AddToCode( OUString::number( aNumInfo.nFracDenominator ) );
1058 }
1059 else
1060 {
1061 for (i=aNumInfo.nMaxDenomDigits; i > 0 ; i--)
1062 {
1063 if ( i > aNumInfo.nMinDenomDigits )
1064 rParent.AddToCode( '#' );
1065 else if ( i > aNumInfo.nZerosDenomDigits )
1066 rParent.AddToCode( '?' );
1067 else
1068 rParent.AddToCode( '0' );
1069 }
1070 }
1071 }
1072 break;
1073
1074 case SvXMLStyleTokens::ScientificNumber:
1075 {
1076 // exponential interval for engineering notation
1077 if( !aNumInfo.bGrouping && aNumInfo.nExpInterval > aNumInfo.nInteger )
1078 {
1079 for (sal_Int32 i=aNumInfo.nInteger; i<aNumInfo.nExpInterval; i++)
1080 {
1081 rParent.AddToCode( '#' );
1082 }
1083 }
1084 rParent.AddNumber( aNumInfo ); // simple number
1085
1086 if ( aNumInfo.bExpSign )
1087 rParent.AddToCode( u"E+" );
1088 else
1089 rParent.AddToCode( u"E" );
1090 for (sal_Int32 i=0; i<aNumInfo.nExpDigits; i++)
1091 {
1092 rParent.AddToCode( '0' );
1093 }
1094 }
1095 break;
1096
1097 default:
1098 assert(false && "invalid element ID");
1099 }
1100}
1101
1106 bool bSystem )
1107{
1108 for (const auto & rEntry : aDefaultDateFormats)
1109 {
1110 if ( bSystem == rEntry.bSystem &&
1111 ( eDOW == rEntry.eDOW || ( rEntry.eDOW == XML_DEA_ANY && eDOW != XML_DEA_NONE ) ) &&
1112 ( eDay == rEntry.eDay || ( rEntry.eDay == XML_DEA_ANY && eDay != XML_DEA_NONE ) ) &&
1113 ( eMonth == rEntry.eMonth || ( rEntry.eMonth == XML_DEA_ANY && eMonth != XML_DEA_NONE ) ) &&
1114 ( eYear == rEntry.eYear || ( rEntry.eYear == XML_DEA_ANY && eYear != XML_DEA_NONE ) ) &&
1115 ( eHours == rEntry.eHours || ( rEntry.eHours == XML_DEA_ANY && eHours != XML_DEA_NONE ) ) &&
1116 ( eMins == rEntry.eMins || ( rEntry.eMins == XML_DEA_ANY && eMins != XML_DEA_NONE ) ) &&
1117 ( eSecs == rEntry.eSecs || ( rEntry.eSecs == XML_DEA_ANY && eSecs != XML_DEA_NONE ) ) )
1118 {
1119 return sal::static_int_cast< sal_uInt16 >(rEntry.eFormat);
1120 }
1121 }
1122
1123 return NF_INDEX_TABLE_ENTRIES; // invalid
1124}
1125
1126
1127// SvXMLNumFormatContext
1128
1130 sal_Int32 /*nElement*/,
1131 SvXMLNumImpData* pNewData, SvXMLStylesTokens nNewType,
1132 const uno::Reference<xml::sax::XFastAttributeList>& xAttrList,
1133 SvXMLStylesContext& rStyles ) :
1134 SvXMLStyleContext( rImport ),
1135 pData( pNewData ),
1136 pStyles( &rStyles ),
1137 nType( nNewType ),
1138 nKey(-1),
1139 eImplicitCalendar(ImplicitCalendar::DEFAULT),
1140 nFormatLang( LANGUAGE_SYSTEM ),
1141 bAutoOrder( false ),
1142 bFromSystem( false ),
1143 bTruncate( true ),
1144 bAutoDec( false ),
1145 bAutoInt( false ),
1146 bHasExtraText( false ),
1147 bHasTrailingEmptyText( false ),
1148 bHasLongDoW( false ),
1149 bHasDateTime( false ),
1150 bRemoveAfterUse( false ),
1151 eDateDOW( XML_DEA_NONE ),
1152 eDateDay( XML_DEA_NONE ),
1153 eDateMonth( XML_DEA_NONE ),
1154 eDateYear( XML_DEA_NONE ),
1155 eDateHours( XML_DEA_NONE ),
1156 eDateMins( XML_DEA_NONE ),
1157 eDateSecs( XML_DEA_NONE ),
1158 bDateNoDefault( false )
1159{
1160 LanguageTagODF aLanguageTagODF;
1161 css::i18n::NativeNumberXmlAttributes aNatNumAttr;
1162 OUString aSpellout;
1163 bool bAttrBool(false);
1164
1165 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
1166 {
1167 switch (aIter.getToken())
1168 {
1169 // attributes for a style
1170 case XML_ELEMENT(STYLE, XML_NAME):
1171 break;
1172 case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG):
1173 aLanguageTagODF.maRfcLanguageTag = aIter.toString();
1174 break;
1175 case XML_ELEMENT(NUMBER, XML_LANGUAGE):
1176 aLanguageTagODF.maLanguage = aIter.toString();
1177 break;
1178 case XML_ELEMENT(NUMBER, XML_SCRIPT):
1179 aLanguageTagODF.maScript = aIter.toString();
1180 break;
1181 case XML_ELEMENT(NUMBER, XML_COUNTRY):
1182 aLanguageTagODF.maCountry = aIter.toString();
1183 break;
1184 case XML_ELEMENT(NUMBER, XML_TITLE):
1185 sFormatTitle = aIter.toString();
1186 break;
1187 case XML_ELEMENT(NUMBER, XML_AUTOMATIC_ORDER):
1188 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() ))
1189 bAutoOrder = bAttrBool;
1190 break;
1191 case XML_ELEMENT(NUMBER, XML_FORMAT_SOURCE):
1192 SvXMLUnitConverter::convertEnum( bFromSystem, aIter.toView(), aFormatSourceMap );
1193 break;
1195 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() ))
1196 bTruncate = bAttrBool;
1197 break;
1198 case XML_ELEMENT(STYLE, XML_VOLATILE):
1199 // volatile formats can be removed after importing
1200 // if not used in other styles
1201 if (::sax::Converter::convertBool( bAttrBool, aIter.toView() ))
1202 bRemoveAfterUse = bAttrBool;
1203 break;
1205 aNatNumAttr.Format = aIter.toString();
1206 break;
1209 aSpellout = aIter.toString();
1210 break;
1212 aNatNumAttr.Locale.Language = aIter.toString();
1213 break;
1215 aNatNumAttr.Locale.Country = aIter.toString();
1216 break;
1218 aNatNumAttr.Style = aIter.toString();
1219 break;
1220 default:
1221 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
1222 }
1223 }
1224
1225 if (!aLanguageTagODF.isEmpty())
1226 {
1227 nFormatLang = aLanguageTagODF.getLanguageTag().getLanguageType( false);
1228 if ( nFormatLang == LANGUAGE_DONTKNOW )
1229 nFormatLang = LANGUAGE_SYSTEM;
1230 }
1231
1232 if (aNatNumAttr.Format.isEmpty() && aSpellout.isEmpty())
1233 return;
1234
1235 LanguageTag aLanguageTag( OUString(), aNatNumAttr.Locale.Language,
1236 std::u16string_view(), aNatNumAttr.Locale.Country);
1237 aNatNumAttr.Locale = aLanguageTag.getLocale( false);
1238
1239 // NatNum12 spell out formula (cardinal, ordinal, ordinal-feminine etc.)
1240 if ( !aSpellout.isEmpty() )
1241 {
1242 aFormatCode.append( "[NatNum12 " );
1243 aFormatCode.append( aSpellout );
1244 } else {
1245 SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1246 if ( !pFormatter ) return;
1247
1248 sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr );
1249 aFormatCode.append( "[NatNum" );
1250 aFormatCode.append( nNatNum );
1251 }
1252
1253 LanguageType eLang = aLanguageTag.getLanguageType( false );
1254 if ( eLang == LANGUAGE_DONTKNOW )
1255 eLang = LANGUAGE_SYSTEM;
1256 if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM )
1257 {
1258 aFormatCode.append( "][$-" );
1259 // language code in upper hex:
1260 aFormatCode.append(OUString::number(static_cast<sal_uInt16>(eLang), 16).toAsciiUpperCase());
1261 }
1262 aFormatCode.append( ']' );
1263}
1264
1266 const OUString& rName,
1267 const uno::Reference<xml::sax::XFastAttributeList>& /*xAttrList*/,
1268 const sal_Int32 nTempKey, LanguageType nLang,
1269 SvXMLStylesContext& rStyles ) :
1271 pData( nullptr ),
1272 pStyles( &rStyles ),
1274 nKey(nTempKey),
1275 eImplicitCalendar(ImplicitCalendar::DEFAULT),
1276 nFormatLang( nLang ),
1277 bAutoOrder( false ),
1278 bFromSystem( false ),
1279 bTruncate( true ),
1280 bAutoDec( false ),
1281 bAutoInt( false ),
1282 bHasExtraText( false ),
1283 bHasTrailingEmptyText( false ),
1284 bHasLongDoW( false ),
1285 bHasDateTime( false ),
1286 bRemoveAfterUse( false ),
1287 eDateDOW( XML_DEA_NONE ),
1288 eDateDay( XML_DEA_NONE ),
1289 eDateMonth( XML_DEA_NONE ),
1290 eDateYear( XML_DEA_NONE ),
1291 eDateHours( XML_DEA_NONE ),
1292 eDateMins( XML_DEA_NONE ),
1293 eDateSecs( XML_DEA_NONE ),
1294 bDateNoDefault( false )
1295{
1296 SetAttribute(XML_ELEMENT(STYLE, XML_NAME), rName);
1297}
1298
1300{
1301}
1302
1303css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFormatContext::createFastChildContext(
1304 sal_Int32 nElement,
1305 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
1306{
1307 SvXMLImportContext* pContext = nullptr;
1308
1309 switch (nElement)
1310 {
1311 case XML_ELEMENT(LO_EXT, XML_TEXT):
1313 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1314 *this, SvXMLStyleTokens::Text, xAttrList );
1315 break;
1316 case XML_ELEMENT(LO_EXT, XML_FILL_CHARACTER):
1318 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1319 *this, SvXMLStyleTokens::FillCharacter, xAttrList );
1320 break;
1322 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1323 *this, SvXMLStyleTokens::Number, xAttrList );
1324 break;
1326 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1327 *this, SvXMLStyleTokens::ScientificNumber, xAttrList );
1328 break;
1330 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1331 *this, SvXMLStyleTokens::Fraction, xAttrList );
1332 break;
1334 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1335 *this, SvXMLStyleTokens::CurrencySymbol, xAttrList );
1336 break;
1337 case XML_ELEMENT(NUMBER, XML_DAY):
1338 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1339 *this, SvXMLStyleTokens::Day, xAttrList );
1340 break;
1342 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1343 *this, SvXMLStyleTokens::Month, xAttrList );
1344 break;
1346 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1347 *this, SvXMLStyleTokens::Year, xAttrList );
1348 break;
1349 case XML_ELEMENT(NUMBER, XML_ERA):
1350 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1351 *this, SvXMLStyleTokens::Era, xAttrList );
1352 break;
1354 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1355 *this, SvXMLStyleTokens::DayOfWeek, xAttrList );
1356 break;
1358 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1359 *this, SvXMLStyleTokens::WeekOfYear, xAttrList );
1360 break;
1362 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1363 *this, SvXMLStyleTokens::Quarter, xAttrList );
1364 break;
1366 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1367 *this, SvXMLStyleTokens::Hours, xAttrList );
1368 break;
1370 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1371 *this, SvXMLStyleTokens::AmPm, xAttrList );
1372 break;
1374 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1375 *this, SvXMLStyleTokens::Minutes, xAttrList );
1376 break;
1378 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1379 *this, SvXMLStyleTokens::Seconds, xAttrList );
1380 break;
1382 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1383 *this, SvXMLStyleTokens::Boolean, xAttrList );
1384 break;
1386 pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1387 *this, SvXMLStyleTokens::TextContent, xAttrList );
1388 break;
1389
1391 pContext = new SvXMLNumFmtPropContext( GetImport(), nElement,
1392 *this, xAttrList );
1393 break;
1394 case XML_ELEMENT(STYLE, XML_MAP):
1395 {
1396 // SvXMLNumFmtMapContext::EndElement adds to aMyConditions,
1397 // so there's no need for an extra flag
1398 pContext = new SvXMLNumFmtMapContext( GetImport(), nElement,
1399 *this, xAttrList );
1400 }
1401 break;
1402 }
1403
1404 if( !pContext )
1405 {
1406 SAL_WARN("xmloff.core", "No context for unknown-element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
1407 pContext = new SvXMLImportContext(GetImport());
1408 }
1409
1410 return pContext;
1411}
1412
1414{
1415 if (nKey > -1)
1416 {
1417 if (bRemoveAfterUse)
1418 {
1419 // format is used -> don't remove
1420 bRemoveAfterUse = false;
1421 if (pData)
1422 pData->SetUsed(nKey);
1423
1424 // Add to import's list of keys now - CreateAndInsert didn't add
1425 // the style if bRemoveAfterUse was set.
1426 GetImport().AddNumberStyle( nKey, GetName() );
1427 }
1428 return nKey;
1429 }
1430 else
1431 {
1432 // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set
1433 bRemoveAfterUse = false;
1434 CreateAndInsert(true);
1435 return nKey;
1436 }
1437}
1438
1440{
1441 // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag
1442
1443 if (nKey > -1)
1444 return nKey;
1445 else
1446 {
1447 CreateAndInsert(true);
1448 return nKey;
1449 }
1450}
1451
1452sal_Int32 SvXMLNumFormatContext::CreateAndInsert( css::uno::Reference< css::util::XNumberFormatsSupplier > const & xFormatsSupplier )
1453{
1454 if (nKey <= -1)
1455 {
1456 SvNumberFormatter* pFormatter = nullptr;
1458 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( xFormatsSupplier );
1459 if (pObj)
1460 pFormatter = pObj->GetNumberFormatter();
1461
1462 if ( pFormatter )
1463 return CreateAndInsert( pFormatter );
1464 else
1465 return -1;
1466 }
1467 else
1468 return nKey;
1469}
1470
1472{
1473 if (nKey <= -1)
1475}
1476
1478{
1479 if (!pFormatter)
1480 {
1481 OSL_FAIL("no number formatter");
1482 return -1;
1483 }
1484
1486
1487 for (size_t i = 0; i < aMyConditions.size(); i++)
1488 {
1491 if (this == pStyle)
1492 {
1493 SAL_INFO("xmloff.style", "invalid style:map references containing style");
1494 pStyle = nullptr;
1495 }
1496 if (pStyle)
1497 {
1498 if (pStyle->PrivateGetKey() > -1) // don't reset pStyle's bRemoveAfterUse flag
1499 AddCondition(i);
1500 }
1501 }
1502
1503 sal_Int32 nBufLen;
1504 if ( aFormatCode.isEmpty() )
1505 {
1506 // insert empty format as empty string (with quotes)
1507 // #93901# this check has to be done before inserting the conditions
1508 aFormatCode.append("\"\""); // ""
1509 }
1510 else if (bHasTrailingEmptyText && (nBufLen = aFormatCode.getLength()) >= 3)
1511 {
1512 // Remove a trailing empty text. Earlier this may had been written to
1513 // file, like in "General;General" written with elements for
1514 // 'General"";General""' (whyever); when reading, empty text was
1515 // ignored, which it isn't anymore, so get rid of those.
1516 if (aFormatCode[nBufLen-1] == '"' && aFormatCode[nBufLen-2] == '"')
1517 aFormatCode.truncate( nBufLen - 2);
1518 }
1519
1520 aFormatCode.insert( 0, aConditions );
1521 aConditions.setLength(0);
1522 OUString sFormat = aFormatCode.makeStringAndClear();
1523
1524 // test special cases
1525
1526 if ( bAutoDec ) // automatic decimal places
1527 {
1528 // #99391# adjust only if the format contains no text elements, no conditions
1529 // and no color definition (detected by the '[' at the start)
1530
1532 aMyConditions.empty() && sFormat.toChar() != '[' )
1533 nIndex = pFormatter->GetStandardIndex( nFormatLang );
1534 }
1535 if ( bAutoInt ) // automatic integer digits
1536 {
1538
1540 aMyConditions.empty() && sFormat.toChar() != '[' )
1542 }
1543
1545 aMyConditions.empty() && sFormat.toChar() != '[' )
1546 nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang );
1547
1548 // check for default date formats
1550 {
1554 if ( eFormat < NF_INDEX_TABLE_RESERVED_START )
1555 {
1556 // #109651# if a date format has the automatic-order attribute and
1557 // contains exactly the elements of one of the default date formats,
1558 // use that default format, with the element order and separators
1559 // from the current locale settings
1560
1561 nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang );
1562 }
1563 }
1564
1565 if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && !sFormat.isEmpty() )
1566 {
1567 // insert by format string
1568
1569 OUString aFormatStr( sFormat );
1570 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1572 {
1573 sal_Int32 nErrPos = 0;
1574 SvNumFormatType l_nType = SvNumFormatType::ALL;
1575 bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang );
1576 if ( !bOk && nErrPos == 0 && aFormatStr != sFormat )
1577 {
1578 // if the string was modified by PutEntry, look for an existing format
1579 // with the modified string
1580 nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1582 bOk = true;
1583 }
1584 if (!bOk)
1586 }
1587 }
1588
1591 {
1592 // use fixed-order formats instead of SYS... if bAutoOrder is false
1593 // (only if the format strings are equal for the locale)
1594
1595 NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex );
1596 if ( eOffset == NF_DATE_SYS_DMMMYYYY )
1597 {
1598 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang );
1599 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1600 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1601 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1602 nIndex = nNewIndex;
1603 }
1604 else if ( eOffset == NF_DATE_SYS_DMMMMYYYY )
1605 {
1606 sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang );
1607 const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1608 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1609 if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1610 nIndex = nNewIndex;
1611 }
1612 }
1613
1614 if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && !sFormatTitle.isEmpty())
1615 {
1616 SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex ));
1617 if (pFormat)
1618 {
1619 pFormat->SetComment(sFormatTitle);
1620 }
1621 }
1622
1624 {
1625 OSL_FAIL("invalid number format");
1626 nIndex = pFormatter->GetStandardIndex( nFormatLang );
1627 }
1628
1630 nKey = nIndex;
1631
1632 // Add to import's list of keys (shared between styles and content import)
1633 // only if not volatile - formats are removed from NumberFormatter at the
1634 // end of each import (in SvXMLNumFmtHelper dtor).
1635 // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there.
1636
1637 if (!bRemoveAfterUse)
1638 GetImport().AddNumberStyle( nKey, GetName() );
1639
1640 return nKey;
1641}
1642
1644{
1645 return pData->GetLocaleData( nFormatLang );
1646}
1647
1649{
1650 aFormatCode.append( c );
1651 bHasExtraText = true;
1652}
1653
1654void SvXMLNumFormatContext::AddToCode( std::u16string_view rString )
1655{
1656 aFormatCode.append( rString );
1657 bHasExtraText = true;
1658 bHasTrailingEmptyText = false; // is set by caller again if so
1659}
1660
1662{
1664 if (!pFormatter)
1665 return;
1666
1667 // store special conditions
1668 bAutoDec = ( rInfo.nDecimals < 0 );
1669 bAutoInt = ( rInfo.nInteger < 0 );
1670
1671 sal_uInt16 nPrec = 0;
1672 sal_uInt16 nLeading = 0;
1673 if ( rInfo.nDecimals >= 0 ) // < 0 : Default
1674 nPrec = static_cast<sal_uInt16>(rInfo.nDecimals);
1675 if ( rInfo.nInteger >= 0 ) // < 0 : Default
1676 nLeading = static_cast<sal_uInt16>(rInfo.nInteger);
1677
1678 if ( bAutoDec )
1679 {
1681 {
1682 // for currency formats, "automatic decimals" is used for the automatic
1683 // currency format with (fixed) decimals from the locale settings
1684
1686 nPrec = rLoc.getCurrDigits();
1687 }
1688 else
1689 {
1690 // for other types, "automatic decimals" means dynamic determination of
1691 // decimals, as achieved with the "general" keyword
1692
1693 aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) );
1694 return;
1695 }
1696 }
1697 if ( bAutoInt )
1698 {
1700 }
1701
1702 sal_uInt16 nGenPrec = nPrec;
1703 if ( rInfo.nMinDecimalDigits >= 0 )
1704 nGenPrec = rInfo.nMinDecimalDigits;
1705 if ( rInfo.bDecReplace )
1706 nGenPrec = 0; // generate format without decimals...
1707
1708 bool bGrouping = rInfo.bGrouping;
1709 size_t const nEmbeddedCount = rInfo.m_EmbeddedElements.size();
1710 if ( nEmbeddedCount && rInfo.m_EmbeddedElements.rbegin()->first > 0 )
1711 bGrouping = false; // grouping and embedded characters in integer part can't be used together
1712
1713 sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang );
1714 OUStringBuffer aNumStr(pFormatter->GenerateFormat( nStdIndex, nFormatLang,
1715 bGrouping, false, nGenPrec, nLeading ));
1716
1717 if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 )
1718 {
1719 // #i43959# For scientific numbers, "#" in the integer part forces a digit,
1720 // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0").
1721
1722 aNumStr.stripStart('#');
1723 }
1724
1725 if ( bGrouping && rInfo.nExpInterval > rInfo.nInteger )
1726 {
1727 sal_Int32 nIndex = 0;
1728 sal_Int32 nDigits = rInfo.nInteger;
1729 sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() );
1730 if ( nIntegerEnd < 0 )
1731 nIntegerEnd = aNumStr.getLength();
1732 while ( nIndex >= 0 && nIndex < nIntegerEnd )
1733 {
1734 if ( ( nIndex = aNumStr.indexOf( '#', nIndex ) ) >= 0 )
1735 {
1736 nDigits ++;
1737 nIndex ++;
1738 }
1739 else
1740 nIndex = -1;
1741 }
1742 while ( rInfo.nExpInterval > nDigits )
1743 {
1744 nDigits++;
1745 aNumStr.insert( 0, '#' );
1746 }
1747 }
1748
1749 if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes)
1750 {
1751 // add dashes for explicit decimal replacement, # or ? for variable decimals
1752 sal_Unicode cAdd = rInfo.bDecReplace ? '-' : ( rInfo.bDecAlign ? '?': '#' );
1753
1754 if ( rInfo.nMinDecimalDigits == 0 )
1755 aNumStr.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1756 for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i<nPrec; i++)
1757 aNumStr.append( cAdd );
1758 }
1759
1760 if ( nEmbeddedCount )
1761 {
1762 // insert embedded strings into number string
1763 // support integer (position >=0) and decimal (position <0) part
1764 // nZeroPos is the string position where format position 0 is inserted
1765
1766 sal_Int32 nZeroPos = aNumStr.indexOf( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1767 if ( nZeroPos < 0 )
1768 {
1769 nZeroPos = aNumStr.getLength();
1770 }
1771
1772 // m_EmbeddedElements is sorted - last entry has the largest position (leftmost)
1773 sal_Int32 const nLastFormatPos = rInfo.m_EmbeddedElements.rbegin()->first;
1774 if ( nLastFormatPos >= nZeroPos )
1775 {
1776 // add '#' characters so all embedded texts are really embedded in digits
1777 // (there always has to be a digit before the leftmost embedded text)
1778
1779 sal_Int32 nAddCount = nLastFormatPos + 1 - nZeroPos;
1780 for(sal_Int32 index = 0; index < nAddCount; ++index)
1781 {
1782 aNumStr.insert(0, '#');
1783 }
1784 nZeroPos = nZeroPos + nAddCount;
1785 }
1786
1787 // m_EmbeddedElements is sorted with ascending positions - loop is from right to left
1788 for (auto const& it : rInfo.m_EmbeddedElements)
1789 {
1790 sal_Int32 const nFormatPos = it.first;
1791 sal_Int32 nInsertPos = nZeroPos - nFormatPos;
1792 if ( nInsertPos >= 0 )
1793 {
1794 // #107805# always quote embedded strings - even space would otherwise
1795 // be recognized as thousands separator in French.
1796
1797 aNumStr.insert(nInsertPos, '"');
1798 aNumStr.insert(nInsertPos, it.second);
1799 aNumStr.insert(nInsertPos, '"');
1800 }
1801 }
1802 }
1803
1804 aFormatCode.append( aNumStr );
1805
1806 // add extra thousands separators for display factor
1807
1808 if (rInfo.fDisplayFactor == 1.0 || rInfo.fDisplayFactor <= 0.0)
1809 return;
1810
1811 // test for 1.0 is just for optimization - nSepCount would be 0
1812
1813 // one separator for each factor of 1000
1814 sal_Int32 nSepCount = static_cast<sal_Int32>(::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 ));
1815 if ( nSepCount > 0 )
1816 {
1817 OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep();
1818 for ( sal_Int32 i=0; i<nSepCount; i++ )
1819 aFormatCode.append( aSep );
1820 }
1821}
1822
1823void SvXMLNumFormatContext::AddCurrency( const OUString& rContent, LanguageType nLang )
1824{
1825 bool bAutomatic = false;
1826 OUString aSymbol = rContent;
1827 if ( aSymbol.isEmpty())
1828 {
1830 if ( pFormatter )
1831 {
1832 pFormatter->ChangeIntl( nFormatLang );
1833 OUString sCurString, sDummy;
1834 pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
1835 aSymbol = sCurString;
1836
1837 bAutomatic = true;
1838 }
1839 }
1840 else if ( nLang == LANGUAGE_SYSTEM && aSymbol == "CCC" )
1841 {
1842 // "CCC" is used for automatic long symbol
1843 bAutomatic = true;
1844 }
1845
1846 if ( bAutomatic )
1847 {
1848 // remove unnecessary quotes before automatic symbol (formats like "-(0DM)")
1849 // otherwise the currency symbol isn't recognized (#94048#)
1850
1851 sal_Int32 nLength = aFormatCode.getLength();
1852 if ( nLength > 1 && aFormatCode[nLength - 1] == '"' )
1853 {
1854 // find start of quoted string
1855 // When SvXMLNumFmtElementContext::EndElement creates escaped quotes,
1856 // they must be handled here, too.
1857
1858 sal_Int32 nFirst = nLength - 2;
1859 while ( nFirst >= 0 && aFormatCode[nFirst] != '"' )
1860 --nFirst;
1861 if ( nFirst >= 0 )
1862 {
1863 // remove both quotes from aFormatCode
1864 OUString aOld = aFormatCode.makeStringAndClear();
1865 if ( nFirst > 0 )
1866 aFormatCode.append( aOld.subView( 0, nFirst ) );
1867 if ( nLength > nFirst + 2 )
1868 aFormatCode.append( aOld.subView( nFirst + 1, nLength - nFirst - 2 ) );
1869 }
1870 }
1871 }
1872
1873 if (!bAutomatic)
1874 aFormatCode.append( "[$" ); // intro for "new" currency symbols
1875
1876 aFormatCode.append( aSymbol );
1877
1878 if (!bAutomatic)
1879 {
1880 if ( nLang != LANGUAGE_SYSTEM )
1881 {
1882 // '-' sign and language code in hex:
1883 aFormatCode.append("-" + OUString(OUString::number(sal_uInt16(nLang), 16)).toAsciiUpperCase());
1884 }
1885
1886 aFormatCode.append( ']' ); // end of "new" currency symbol
1887 }
1888}
1889
1891{
1893 if (!pFormatter)
1894 return;
1895
1896 if ( nIndex == NF_KEY_NNNN )
1897 {
1899 bHasLongDoW = true; // to remove string constant with separator
1900 }
1901
1902 OUString sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex );
1903
1904 if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH ||
1905 nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI ||
1906 nIndex == NF_KEY_S || nIndex == NF_KEY_SS )
1907 {
1908 if ( !bTruncate && !bHasDateTime )
1909 {
1910 // with truncate-on-overflow = false, add "[]" to first time part
1911 aFormatCode.append("[" + sKeyword + "]");
1912 }
1913 else
1914 {
1915 aFormatCode.append( sKeyword );
1916 }
1917 bHasDateTime = true;
1918 }
1919 else
1920 {
1921 aFormatCode.append( sKeyword );
1922 }
1923 // collect the date elements that the format contains, to recognize default date formats
1924 switch ( nIndex )
1925 {
1926 case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
1927 case NF_KEY_NNN:
1928 case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
1929 case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
1930 case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
1931 case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
1932 case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
1935 case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
1936 case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
1937 case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
1938 case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
1939 case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
1940 case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
1941 case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
1942 case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
1943 case NF_KEY_AP:
1944 case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1945 default:
1946 bDateNoDefault = true; // any other element -> no default format
1947 }
1948}
1949
1950static bool lcl_IsAtEnd( OUStringBuffer& rBuffer, std::u16string_view rToken )
1951{
1952 sal_Int32 nBufLen = rBuffer.getLength();
1953 sal_Int32 nTokLen = rToken.size();
1954
1955 if ( nTokLen > nBufLen )
1956 return false;
1957
1958 sal_Int32 nStartPos = nBufLen - nTokLen;
1959 for ( sal_Int32 nTokPos = 0; nTokPos < nTokLen; nTokPos++ )
1960 if ( rToken[ nTokPos ] != rBuffer[nStartPos + nTokPos] )
1961 return false;
1962
1963 return true;
1964}
1965
1966bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew )
1967{
1968 // replaces one keyword with another if it is found at the end of the code
1969
1971 if (!pFormatter)
1972 return false;
1973
1974 OUString sOldStr = pFormatter->GetKeyword( nFormatLang, nOld );
1975 if ( lcl_IsAtEnd( aFormatCode, sOldStr ) )
1976 {
1977 // remove old keyword
1978 aFormatCode.setLength( aFormatCode.getLength() - sOldStr.getLength() );
1979
1980 // add new keyword
1981 OUString sNewStr = pFormatter->GetKeyword( nFormatLang, nNew );
1982 aFormatCode.append( sNewStr );
1983
1984 return true; // changed
1985 }
1986 return false; // not found
1987}
1988
1989void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex )
1990{
1991 OUString rApplyName = aMyConditions[nIndex].sMapName;
1992 OUString rCondition = aMyConditions[nIndex].sCondition;
1994 sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName );
1995
1996 OUString sRealCond;
1997 if ( !(pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND &&
1998 rCondition.startsWith("value()", &sRealCond)) )
1999 return;
2000
2003
2004 bool bDefaultCond = false;
2005
2008 if ( aConditions.isEmpty() && aMyConditions.size() == 1 && sRealCond == ">=0" )
2009 bDefaultCond = true;
2010
2011 if ( nType == SvXMLStylesTokens::TEXT_STYLE && static_cast<size_t>(nIndex) == aMyConditions.size() - 1 )
2012 {
2013 // The last condition in a number format with a text part can only
2014 // be "all other numbers", the condition string must be empty.
2015 bDefaultCond = true;
2016 }
2017
2018 if (!bDefaultCond)
2019 {
2020 // Convert != to <>
2021 sal_Int32 nPos = sRealCond.indexOf( "!=" );
2022 if ( nPos >= 0 )
2023 {
2024 sRealCond = sRealCond.replaceAt( nPos, 2, u"<>" );
2025 }
2026
2027 nPos = sRealCond.indexOf( '.' );
2028 if ( nPos >= 0 )
2029 {
2030 // #i8026# #103991# localize decimal separator
2031 const OUString& rDecSep = GetLocaleData().getNumDecimalSep();
2032 if ( rDecSep.getLength() > 1 || rDecSep[0] != '.' )
2033 {
2034 sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
2035 }
2036 }
2037 aConditions.append("[" + sRealCond + "]");
2038 }
2039
2040 const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey);
2041 if ( pFormat )
2042 aConditions.append( pFormat->GetFormatstring() );
2043
2044 aConditions.append( ';' );
2045}
2046
2047void SvXMLNumFormatContext::AddCondition( const OUString& rCondition, const OUString& rApplyName )
2048{
2049 MyCondition aCondition;
2050 aCondition.sCondition = rCondition;
2051 aCondition.sMapName = rApplyName;
2052 aMyConditions.push_back(aCondition);
2053}
2054
2056{
2058 if (!pFormatter)
2059 return;
2060
2061 OUStringBuffer aColName;
2062 for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ )
2063 if (nColor == aNumFmtStdColors[i])
2064 {
2065 aColName = pFormatter->GetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) );
2066 break;
2067 }
2068
2069 if ( !aColName.isEmpty() )
2070 {
2071 aColName.insert( 0, '[' );
2072 aColName.append( ']' );
2073 aFormatCode.insert( 0, aColName );
2074 }
2075}
2076
2077void SvXMLNumFormatContext::UpdateCalendar( const OUString& rNewCalendar )
2078{
2079 if ( rNewCalendar == sCalendar )
2080 return;
2081
2082 if (rNewCalendar.isEmpty() || rNewCalendar == aImplicitCalendar[0])
2083 {
2084 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ?
2085 ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT);
2086 }
2087 else if (aImplicitCalendar[0].isEmpty() && rNewCalendar == GetLocaleData().getDefaultCalendar()->Name)
2088 {
2089 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ?
2090 ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT);
2091 aImplicitCalendar[0] = rNewCalendar;
2092 }
2093 else if (rNewCalendar == aImplicitCalendar[1])
2094 {
2095 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ?
2096 ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY);
2097 }
2098 else if (aImplicitCalendar[1].isEmpty() && GetLocaleData().doesSecondaryCalendarUseEC( rNewCalendar))
2099 {
2100 eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ?
2101 ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY);
2102 aImplicitCalendar[1] = rNewCalendar;
2103 }
2104 else
2105 {
2106 eImplicitCalendar = ImplicitCalendar::OTHER;
2107 }
2108
2109 if (eImplicitCalendar != ImplicitCalendar::DEFAULT && eImplicitCalendar != ImplicitCalendar::SECONDARY)
2110 {
2111 // A switch from empty default calendar to named default calendar or
2112 // vice versa is not a switch.
2113 bool bSameDefault = false;
2114 if (sCalendar.isEmpty() || rNewCalendar.isEmpty())
2115 {
2116 // As both are not equal, only one can be empty here, the other
2117 // can not.
2118 const OUString& rDefaultCalendar = GetLocaleData().getDefaultCalendar()->Name;
2119 // So if one is the named default calendar the other is the
2120 // empty default calendar.
2121 bSameDefault = (rNewCalendar == rDefaultCalendar || sCalendar == rDefaultCalendar);
2122 }
2123 if (!bSameDefault)
2124 {
2125 aFormatCode.append( "[~" ); // intro for calendar code
2126 if (rNewCalendar.isEmpty())
2127 {
2128 // Empty calendar name here means switching to default calendar
2129 // from a different calendar. Needs to be explicitly stated in
2130 // format code.
2131 aFormatCode.append( GetLocaleData().getDefaultCalendar()->Name );
2132 }
2133 else
2134 {
2135 aFormatCode.append( rNewCalendar );
2136 }
2137 aFormatCode.append( ']' ); // end of calendar code
2138 }
2139 }
2140 sCalendar = rNewCalendar;
2141}
2142
2144{
2145 return nFormatLang == LANGUAGE_SYSTEM;
2146}
2147
2148
2149// SvXMLNumFmtHelper
2150
2151
2153 const uno::Reference<util::XNumberFormatsSupplier>& rSupp,
2154 const uno::Reference<uno::XComponentContext>& rxContext )
2155{
2156 SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" );
2157
2158 SvNumberFormatter* pFormatter = nullptr;
2160 comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>( rSupp );
2161 if (pObj)
2162 pFormatter = pObj->GetNumberFormatter();
2163
2164 pData = std::make_unique<SvXMLNumImpData>( pFormatter, rxContext );
2165}
2166
2168 SvNumberFormatter* pNumberFormatter,
2169 const uno::Reference<uno::XComponentContext>& rxContext )
2170{
2171 SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" );
2172
2173 pData = std::make_unique<SvXMLNumImpData>( pNumberFormatter, rxContext );
2174}
2175
2177{
2178 // remove temporary (volatile) formats from NumberFormatter
2179 pData->RemoveVolatileFormats();
2180}
2181
2182
2184 sal_Int32 nElement,
2185 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList,
2186 SvXMLStylesContext& rStyles )
2187{
2188 SvXMLStylesTokens nStyleToken;
2189 switch (nElement)
2190 {
2192 nStyleToken = SvXMLStylesTokens::NUMBER_STYLE;
2193 break;
2196 break;
2199 break;
2201 nStyleToken = SvXMLStylesTokens::DATE_STYLE;
2202 break;
2204 nStyleToken = SvXMLStylesTokens::TIME_STYLE;
2205 break;
2208 break;
2210 nStyleToken = SvXMLStylesTokens::TEXT_STYLE;
2211 break;
2212 default:
2213 // return NULL if not a data style, caller must handle other elements
2214 return nullptr;
2215 }
2216 return new SvXMLNumFormatContext( rImport, nElement,
2217 pData.get(), nStyleToken, xAttrList, rStyles );
2218}
2219
2221{
2222 if (pData->GetNumberFormatter())
2223 {
2224 const SvNumberformat* pEntry = pData->GetNumberFormatter()->GetEntry(nKey);
2225 if (pEntry)
2226 return pEntry->GetLanguage();
2227 }
2228
2229 return LANGUAGE_SYSTEM;
2230}
2231
2232/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const uno::Reference< uno::XComponentContext > m_xContext
LanguageType getLanguageType(bool bResolveSystem=true) const
const OUString & getNumThousandSep() const
const std::shared_ptr< css::i18n::Calendar2 > & getDefaultCalendar() const
const OUString & getNumDecimalSep() const
bool doesSecondaryCalendarUseEC(std::u16string_view rName) const
sal_uInt16 getCurrDigits() const
SvNumberFormatter * GetNumberFormatter() const
sal_uInt32 GetStandardIndex(LanguageType eLnge=LANGUAGE_DONTKNOW)
void GetCompatibilityCurrency(OUString &rSymbol, OUString &rAbbrev) const
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bReplaceBooleanEquivalent=true)
OUString GenerateFormat(sal_uInt32 nIndex, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bThousand=false, bool IsRed=false, sal_uInt16 nPrecision=0, sal_uInt16 nLeadingCnt=1)
NfIndexTableOffset GetIndexTableOffset(sal_uInt32 nFormat) const
void DeleteEntry(sal_uInt32 nKey)
const NativeNumberWrapper * GetNatNum() const
sal_uInt32 GetEntryKey(std::u16string_view sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
OUString GetKeyword(LanguageType eLnge, sal_uInt16 nIndex)
void ChangeIntl(LanguageType eLnge)
sal_uInt32 GetFormatIndex(NfIndexTableOffset, LanguageType eLnge=LANGUAGE_DONTKNOW)
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
OUString GetStandardName(LanguageType eLnge)
const css::uno::Reference< css::uno::XComponentContext > & GetComponentContext() const
const OUString & GetNumDecimalSep() const
LanguageType GetLanguage() const
void SetComment(const OUString &rStr)
const OUString & GetFormatstring() const
SvNumFormatType GetType() const
This class deliberately does not support XWeak, to improve performance when loading large documents.
Definition: xmlictxt.hxx:48
virtual void SAL_CALL endFastElement(sal_Int32 Element) override
endFastElement is called before a context will be destructed, but after an elements context has been ...
Definition: xmlictxt.cxx:40
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:60
SvXMLImportContext(SvXMLImport &rImport)
A contexts constructor does anything that is required if an element starts.
Definition: xmlictxt.cxx:30
virtual css::uno::Reference< XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > &Attribs) override
Definition: xmlictxt.cxx:59
virtual void SAL_CALL characters(const OUString &aChars) override
This method is called for all characters that are contained in the current element.
Definition: xmlictxt.cxx:70
static sal_uInt16 GetDefaultDateFormat(SvXMLDateElementAttributes eDOW, SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth, SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours, SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs, bool bSystem)
Definition: xmlnumfi.cxx:1102
LanguageType GetLanguageForKey(sal_Int32 nKey) const
Definition: xmlnumfi.cxx:2220
SvXMLStyleContext * CreateChildContext(SvXMLImport &rImport, sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, SvXMLStylesContext &rStyles)
Definition: xmlnumfi.cxx:2183
SvXMLNumFmtHelper(const css::uno::Reference< css::util::XNumberFormatsSupplier > &rSupp, const css::uno::Reference< css::uno::XComponentContext > &rxContext)
std::unique_ptr< SvXMLNumImpData > pData
Definition: xmlnumfi.hxx:72
SvXMLDateElementAttributes eDateDOW
Definition: xmlnumfi.hxx:156
SvXMLStylesTokens nType
Definition: xmlnumfi.hxx:133
SvXMLDateElementAttributes eDateHours
Definition: xmlnumfi.hxx:160
OUStringBuffer aFormatCode
Definition: xmlnumfi.hxx:149
SvXMLDateElementAttributes eDateMins
Definition: xmlnumfi.hxx:161
SvXMLStylesContext * pStyles
Definition: xmlnumfi.hxx:131
const LocaleDataWrapper & GetLocaleData() const
Definition: xmlnumfi.cxx:1643
void AddColor(Color nColor)
Definition: xmlnumfi.cxx:2055
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
Definition: xmlnumfi.cxx:1303
SvXMLDateElementAttributes eDateYear
Definition: xmlnumfi.hxx:159
SvXMLDateElementAttributes eDateDay
Definition: xmlnumfi.hxx:157
void AddNfKeyword(sal_uInt16 nIndex)
Definition: xmlnumfi.cxx:1890
SvXMLNumFormatContext(SvXMLImport &rImport, sal_Int32 nElement, SvXMLNumImpData *pNewData, SvXMLStylesTokens nNewType, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, SvXMLStylesContext &rStyles)
OUString aImplicitCalendar[2]
Definition: xmlnumfi.hxx:139
void AddCondition(const sal_Int32 nIndex)
Definition: xmlnumfi.cxx:1989
ImplicitCalendar eImplicitCalendar
Definition: xmlnumfi.hxx:140
SAL_DLLPRIVATE sal_Int32 PrivateGetKey()
Definition: xmlnumfi.cxx:1439
SvXMLDateElementAttributes eDateMonth
Definition: xmlnumfi.hxx:158
virtual void CreateAndInsert(bool bOverwrite) override
Definition: xmlnumfi.cxx:1471
bool IsSystemLanguage() const
determine whether number format uses the system language
Definition: xmlnumfi.cxx:2143
void AddToCode(std::u16string_view rString)
Definition: xmlnumfi.cxx:1654
SvXMLStylesTokens GetType() const
Definition: xmlnumfi.hxx:189
SvXMLDateElementAttributes eDateSecs
Definition: xmlnumfi.hxx:162
OUStringBuffer aConditions
Definition: xmlnumfi.hxx:150
bool ReplaceNfKeyword(sal_uInt16 nOld, sal_uInt16 nNew)
Definition: xmlnumfi.cxx:1966
LanguageType nFormatLang
Definition: xmlnumfi.hxx:141
void AddCurrency(const OUString &rContent, LanguageType nLang)
Definition: xmlnumfi.cxx:1823
SvXMLNumImpData * pData
Definition: xmlnumfi.hxx:130
void AddNumber(const SvXMLNumberInfo &rInfo)
Definition: xmlnumfi.cxx:1661
std::vector< MyCondition > aMyConditions
Definition: xmlnumfi.hxx:132
void UpdateCalendar(const OUString &rNewCalendar)
Definition: xmlnumfi.cxx:2077
virtual ~SvXMLNumFormatContext() override
Definition: xmlnumfi.cxx:1299
uno::Reference< uno::XComponentContext > m_xContext
Definition: xmlnumfi.cxx:73
std::vector< SvXMLNumFmtEntry > m_NameEntries
Definition: xmlnumfi.cxx:71
void AddKey(sal_uInt32 nKey, const OUString &rName, bool bRemoveAfterUse)
Definition: xmlnumfi.cxx:307
SvNumberFormatter * pFormatter
Definition: xmlnumfi.cxx:69
std::unique_ptr< LocaleDataWrapper > pLocaleData
Definition: xmlnumfi.cxx:70
const LocaleDataWrapper & GetLocaleData(LanguageType nLang)
Definition: xmlnumfi.cxx:367
sal_uInt32 GetKeyForName(std::u16string_view rName)
Definition: xmlnumfi.cxx:297
SvXMLNumImpData(SvNumberFormatter *pFmt, const uno::Reference< uno::XComponentContext > &rxContext)
Definition: xmlnumfi.cxx:288
void RemoveVolatileFormats()
Definition: xmlnumfi.cxx:347
void SetUsed(sal_uInt32 nKey)
Definition: xmlnumfi.cxx:332
SvNumberFormatter * GetNumberFormatter() const
Definition: xmlnumfi.cxx:80
const OUString & GetName() const
Definition: xmlstyle.hxx:78
const SvXMLStyleContext * FindStyleChildContext(XmlStyleFamily nFamily, const OUString &rName, bool bCreateIndex=false) const
Definition: xmlstyle.cxx:799
the SvXMLTypeConverter converts values of various types from their internal representation to the tex...
Definition: xmluconv.hxx:83
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
constexpr ::Color COL_LIGHTRED(0xFF, 0x00, 0x00)
constexpr ::Color COL_GRAY(0x80, 0x80, 0x80)
constexpr ::Color COL_WHITE(0xFF, 0xFF, 0xFF)
constexpr ::Color COL_LIGHTCYAN(0x00, 0xFF, 0xFF)
constexpr ::Color COL_LIGHTMAGENTA(0xFF, 0x00, 0xFF)
constexpr ::Color COL_BROWN(0x80, 0x80, 0x00)
constexpr ::Color COL_YELLOW(0xFF, 0xFF, 0x00)
constexpr ::Color COL_LIGHTBLUE(0x00, 0x00, 0xFF)
constexpr ::Color COL_LIGHTGREEN(0x00, 0xFF, 0x00)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
DayOfWeek
float u
XmlStyleFamily
Definition: families.hxx:50
sal_Int32 nIndex
OUString aName
#define LANGUAGE_SYSTEM
sal_uInt16 nPos
sal_Int32 nNatNum
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
std::unique_ptr< sal_Int32[]> pData
const char * sName
int i
index
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
OUString toString(OptionInfo const *info)
Handling of tokens in XML:
@ XML_DECIMAL_REPLACEMENT
Definition: xmltoken.hxx:643
@ XML_INTEGER_FRACTION_DELIMITER
Definition: xmltoken.hxx:3446
@ XML_FORCED_EXPONENT_SIGN
Definition: xmltoken.hxx:3440
@ XML_ZEROS_NUMERATOR_DIGITS
Definition: xmltoken.hxx:3444
@ XML_MAX_NUMERATOR_DIGITS
Definition: xmltoken.hxx:3443
@ XML_TRUNCATE_ON_OVERFLOW
Definition: xmltoken.hxx:2032
@ XML_MAX_DENOMINATOR_VALUE
Definition: xmltoken.hxx:3442
@ XML_TRANSLITERATION_STYLE
Definition: xmltoken.hxx:2335
@ XML_ZEROS_DENOMINATOR_DIGITS
Definition: xmltoken.hxx:3445
@ XML_TRANSLITERATION_FORMAT
Definition: xmltoken.hxx:2332
@ XML_DENOMINATOR_VALUE
Definition: xmltoken.hxx:661
@ XML_MIN_INTEGER_DIGITS
Definition: xmltoken.hxx:1302
@ XML_APPLY_STYLE_NAME
Definition: xmltoken.hxx:269
@ XML_TRANSLITERATION_COUNTRY
Definition: xmltoken.hxx:2334
@ XML_MIN_NUMERATOR_DIGITS
Definition: xmltoken.hxx:1307
@ XML_TRANSLITERATION_SPELLOUT
Definition: xmltoken.hxx:3456
@ XML_MIN_DECIMAL_PLACES
Definition: xmltoken.hxx:3441
@ XML_MIN_EXPONENT_DIGITS
Definition: xmltoken.hxx:1300
@ XML_MIN_DENOMINATOR_DIGITS
Definition: xmltoken.hxx:1298
@ XML_TRANSLITERATION_LANGUAGE
Definition: xmltoken.hxx:2333
NF_KEY_M
NF_KEY_MI
NF_KEY_D
NF_KEY_NN
NF_KEY_DD
NF_KEY_NNN
NF_KEY_SS
NF_KEY_H
NF_KEY_AP
NF_KEY_HH
NF_KEY_AMPM
NF_KEY_MMM
NF_KEY_YYYY
NF_KEY_MMMM
NF_KEY_MM
NF_KEY_S
NF_KEY_FIRSTCOLOR
NF_KEY_NNNN
NF_KEY_YY
NF_KEY_MMI
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
QPRO_FUNC_TYPE nType
Helper to gather the single language tag relevant attributes during reading ODF and form a resulting ...
LanguageTag getLanguageTag() const
Best call this only once per instance, it recreates a LanguageTag instance on every call.
bool isEmpty() const
OUString sCondition
Definition: xmlnumfi.hxx:112
OUString sMapName
Definition: xmlnumfi.hxx:113
sal_Int32 nDecimals
Definition: xmlnumfi.cxx:90
double fDisplayFactor
Definition: xmlnumfi.cxx:106
sal_Int32 nMinNumerDigits
Definition: xmlnumfi.cxx:94
sal_Int32 nMinDecimalDigits
Definition: xmlnumfi.cxx:99
sal_Int32 nZerosNumerDigits
Definition: xmlnumfi.cxx:100
sal_Int32 nExpDigits
Definition: xmlnumfi.cxx:92
OUString aIntegerFractionDelimiter
Definition: xmlnumfi.cxx:107
sal_Int32 nZerosDenomDigits
Definition: xmlnumfi.cxx:101
sal_Int32 nMaxNumerDigits
Definition: xmlnumfi.cxx:96
sal_Int32 nFracDenominator
Definition: xmlnumfi.cxx:98
sal_Int32 nExpInterval
Definition: xmlnumfi.cxx:93
std::map< sal_Int32, OUString > m_EmbeddedElements
Definition: xmlnumfi.cxx:108
sal_Int32 nInteger
Definition: xmlnumfi.cxx:91
sal_Int32 nMinDenomDigits
Definition: xmlnumfi.cxx:95
sal_Int32 nMaxDenomDigits
Definition: xmlnumfi.cxx:97
NUMBER
sal_uInt16 sal_Unicode
static void convertNumber(OUStringBuffer &b, sal_Int32 n)
#define XMLOFF_WARN_UNKNOWN_ELEMENT(area, token)
Definition: xmlictxt.hxx:120
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:114
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:98
const SvXMLDefaultDateFormat aDefaultDateFormats[]
Definition: xmlnumfi.cxx:263
#define XML_NUMF_COLORCOUNT
Definition: xmlnumfi.cxx:210
const SvXMLEnumMapEntry< bool > aStyleValueMap[]
Definition: xmlnumfi.cxx:232
const SvXMLEnumMapEntry< bool > aFormatSourceMap[]
Definition: xmlnumfi.cxx:239
static bool lcl_ValidChar(sal_Unicode cChar, const SvXMLNumFormatContext &rParent)
Definition: xmlnumfi.cxx:478
static bool lcl_IsAtEnd(OUStringBuffer &rBuffer, std::u16string_view rToken)
Definition: xmlnumfi.cxx:1950
const Color aNumFmtStdColors[XML_NUMF_COLORCOUNT]
Definition: xmlnumfi.cxx:212
static void lcl_EnquoteIfNecessary(OUStringBuffer &rContent, const SvXMLNumFormatContext &rParent)
Definition: xmlnumfi.cxx:531
SvXMLDateElementAttributes
Definition: xmlnumfi.hxx:50
@ XML_DEA_SHORT
Definition: xmlnumfi.hxx:53
@ XML_DEA_ANY
Definition: xmlnumfi.hxx:52
@ XML_DEA_TEXTLONG
Definition: xmlnumfi.hxx:56
@ XML_DEA_TEXTSHORT
Definition: xmlnumfi.hxx:55
@ XML_DEA_LONG
Definition: xmlnumfi.hxx:54
@ XML_DEA_NONE
Definition: xmlnumfi.hxx:51
SvXMLStylesTokens
Definition: xmlnumfi.hxx:39
sal_Int32 nLength
Definition: xmltoken.cxx:38
constexpr size_t NF_MAX_FORMAT_SYMBOLS
SvNumFormatType
NfIndexTableOffset
NF_DATE_SYSTEM_SHORT
NF_DATETIME_SYS_DDMMYYYY_HHMMSS
NF_DATE_SYS_DMMMYY
NF_DATE_SYS_MMYY
NF_INDEX_TABLE_RESERVED_START
NF_DATE_SYS_DMMMMYYYY
NF_DATE_DIN_DMMMYYYY
NF_DATE_SYS_DDMMM
NF_DATE_SYS_NNNNDMMMMYYYY
NF_NUMBER_SYSTEM
NF_DATE_SYS_NNDMMMYY
NF_INDEX_TABLE_ENTRIES
NF_BOOLEAN
NF_DATE_DIN_DMMMMYYYY
NF_DATE_SYS_DDMMYY
NF_DATE_SYS_DMMMYYYY
NF_DATETIME_SYS_DDMMYYYY_HHMM
NF_DATE_SYS_NNDMMMMYYYY
NF_DATE_SYS_DDMMYYYY
NF_DATETIME_SYSTEM_SHORT_HHMM
NF_DATE_SYSTEM_LONG
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND