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