LibreOffice Module svl (master) 1
zforlist.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 <sal/config.h>
21
22#include <sal/log.hxx>
23#include <officecfg/Office/Common.hxx>
24#include <svl/zforlist.hxx>
25#include <svl/currencytable.hxx>
26
27#include <comphelper/string.hxx>
28#include <o3tl/string_view.hxx>
29#include <tools/debug.hxx>
34#include <com/sun/star/i18n/KNumberFormatUsage.hpp>
35#include <com/sun/star/i18n/KNumberFormatType.hpp>
36#include <com/sun/star/i18n/FormatElement.hpp>
37#include <com/sun/star/i18n/Currency2.hpp>
38#include <com/sun/star/i18n/NumberFormatCode.hpp>
39#include <com/sun/star/i18n/XNumberFormatCode.hpp>
40#include <com/sun/star/i18n/NumberFormatMapper.hpp>
42
43#include <osl/mutex.hxx>
44
45#include "zforscan.hxx"
46#include "zforfind.hxx"
47#include <svl/zformat.hxx>
49
52#include <rtl/strbuf.hxx>
53#include <rtl/math.hxx>
54
55#include <math.h>
56#include <limits>
57#include <memory>
58#include <set>
59
60using namespace ::com::sun::star;
61using namespace ::com::sun::star::uno;
62using namespace ::com::sun::star::i18n;
63using namespace ::com::sun::star::lang;
64
65// Constants for type offsets per Country/Language (CL)
66#define ZF_STANDARD 0
67#define ZF_STANDARD_PERCENT 10
68#define ZF_STANDARD_CURRENCY 20
69#define ZF_STANDARD_DATE 30
70#define ZF_STANDARD_TIME 60
71#define ZF_STANDARD_DURATION (ZF_STANDARD_TIME + 4)
72#define ZF_STANDARD_DATETIME 70
73#define ZF_STANDARD_SCIENTIFIC 80
74#define ZF_STANDARD_FRACTION 85
75
76// Additional builtin formats, historically not fitting into the first 10 of a
77// category. Make sure it doesn't spill over to the next category.
78#define ZF_STANDARD_DATE_SYS_DMMMYYYY (ZF_STANDARD_DATE + 10)
79#define ZF_STANDARD_DATE_SYS_DMMMMYYYY (ZF_STANDARD_DATE + 11)
80#define ZF_STANDARD_DATE_SYS_NNDMMMYY (ZF_STANDARD_DATE + 12)
81#define ZF_STANDARD_DATE_SYS_NNDMMMMYYYY (ZF_STANDARD_DATE + 13)
82#define ZF_STANDARD_DATE_SYS_NNNNDMMMMYYYY (ZF_STANDARD_DATE + 14)
83#define ZF_STANDARD_DATE_DIN_DMMMYYYY (ZF_STANDARD_DATE + 15)
84#define ZF_STANDARD_DATE_DIN_DMMMMYYYY (ZF_STANDARD_DATE + 16)
85#define ZF_STANDARD_DATE_DIN_MMDD (ZF_STANDARD_DATE + 17)
86#define ZF_STANDARD_DATE_DIN_YYMMDD (ZF_STANDARD_DATE + 18)
87#define ZF_STANDARD_DATE_DIN_YYYYMMDD (ZF_STANDARD_DATE + 19)
88#define ZF_STANDARD_DATE_WW (ZF_STANDARD_DATE + 20)
89
90#define ZF_STANDARD_LOGICAL SV_MAX_COUNT_STANDARD_FORMATS-1 // 99
91#define ZF_STANDARD_TEXT SV_MAX_COUNT_STANDARD_FORMATS // 100
92
93static_assert( ZF_STANDARD_TEXT == NF_STANDARD_FORMAT_TEXT, "definition mismatch" );
94
96 "NfIndexTableOffset does not match i18npool's locale data predefined format code index bounds.");
97
99 "NfIndexTableOffset crosses i18npool's locale data reserved format code index bounds.\n"
100 "You will need to adapt all locale data files defining index values "
101 "(formatIndex=\"...\") in that range and increment those and when done "
102 "adjust nFirstFreeFormatIndex in include/i18npool/reservedconstants.hxx");
103
104/* Locale that is set if an unknown locale (from another system) is loaded of
105 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
106 * (old currency) is recognized as a date (#53155#). */
107#define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
108
109// Same order as in include/svl/zforlist.hxx enum NfIndexTableOffset
111 ZF_STANDARD, // NF_NUMBER_STANDARD
112 ZF_STANDARD + 1, // NF_NUMBER_INT
113 ZF_STANDARD + 2, // NF_NUMBER_DEC2
114 ZF_STANDARD + 3, // NF_NUMBER_1000INT
115 ZF_STANDARD + 4, // NF_NUMBER_1000DEC2
116 ZF_STANDARD + 5, // NF_NUMBER_SYSTEM
117 ZF_STANDARD_SCIENTIFIC, // NF_SCIENTIFIC_000E000
118 ZF_STANDARD_SCIENTIFIC + 1, // NF_SCIENTIFIC_000E00
119 ZF_STANDARD_PERCENT, // NF_PERCENT_INT
120 ZF_STANDARD_PERCENT + 1, // NF_PERCENT_DEC2
121 ZF_STANDARD_FRACTION, // NF_FRACTION_1D
122 ZF_STANDARD_FRACTION + 1, // NF_FRACTION_2D
123 ZF_STANDARD_CURRENCY, // NF_CURRENCY_1000INT
124 ZF_STANDARD_CURRENCY + 1, // NF_CURRENCY_1000DEC2
125 ZF_STANDARD_CURRENCY + 2, // NF_CURRENCY_1000INT_RED
126 ZF_STANDARD_CURRENCY + 3, // NF_CURRENCY_1000DEC2_RED
127 ZF_STANDARD_CURRENCY + 4, // NF_CURRENCY_1000DEC2_CCC
128 ZF_STANDARD_CURRENCY + 5, // NF_CURRENCY_1000DEC2_DASHED
129 ZF_STANDARD_DATE, // NF_DATE_SYSTEM_SHORT
130 ZF_STANDARD_DATE + 8, // NF_DATE_SYSTEM_LONG
131 ZF_STANDARD_DATE + 7, // NF_DATE_SYS_DDMMYY
132 ZF_STANDARD_DATE + 6, // NF_DATE_SYS_DDMMYYYY
133 ZF_STANDARD_DATE + 9, // NF_DATE_SYS_DMMMYY
134 ZF_STANDARD_DATE_SYS_DMMMYYYY, // NF_DATE_SYS_DMMMYYYY
135 ZF_STANDARD_DATE_DIN_DMMMYYYY, // NF_DATE_DIN_DMMMYYYY
136 ZF_STANDARD_DATE_SYS_DMMMMYYYY, // NF_DATE_SYS_DMMMMYYYY
137 ZF_STANDARD_DATE_DIN_DMMMMYYYY, // NF_DATE_DIN_DMMMMYYYY
138 ZF_STANDARD_DATE_SYS_NNDMMMYY, // NF_DATE_SYS_NNDMMMYY
139 ZF_STANDARD_DATE + 1, // NF_DATE_DEF_NNDDMMMYY
140 ZF_STANDARD_DATE_SYS_NNDMMMMYYYY, // NF_DATE_SYS_NNDMMMMYYYY
141 ZF_STANDARD_DATE_SYS_NNNNDMMMMYYYY, // NF_DATE_SYS_NNNNDMMMMYYYY
142 ZF_STANDARD_DATE_DIN_MMDD, // NF_DATE_DIN_MMDD
143 ZF_STANDARD_DATE_DIN_YYMMDD, // NF_DATE_DIN_YYMMDD
144 ZF_STANDARD_DATE_DIN_YYYYMMDD, // NF_DATE_DIN_YYYYMMDD
145 ZF_STANDARD_DATE + 2, // NF_DATE_SYS_MMYY
146 ZF_STANDARD_DATE + 3, // NF_DATE_SYS_DDMMM
147 ZF_STANDARD_DATE + 4, // NF_DATE_MMMM
148 ZF_STANDARD_DATE + 5, // NF_DATE_QQJJ
149 ZF_STANDARD_DATE_WW, // NF_DATE_WW
150 ZF_STANDARD_TIME, // NF_TIME_HHMM
151 ZF_STANDARD_TIME + 1, // NF_TIME_HHMMSS
152 ZF_STANDARD_TIME + 2, // NF_TIME_HHMMAMPM
153 ZF_STANDARD_TIME + 3, // NF_TIME_HHMMSSAMPM
154 ZF_STANDARD_TIME + 4, // NF_TIME_HH_MMSS
155 ZF_STANDARD_TIME + 5, // NF_TIME_MMSS00
156 ZF_STANDARD_TIME + 6, // NF_TIME_HH_MMSS00
157 ZF_STANDARD_DATETIME, // NF_DATETIME_SYSTEM_SHORT_HHMM
158 ZF_STANDARD_DATETIME + 1, // NF_DATETIME_SYS_DDMMYYYY_HHMMSS
159 ZF_STANDARD_LOGICAL, // NF_BOOLEAN
160 ZF_STANDARD_TEXT, // NF_TEXT
161 ZF_STANDARD_DATETIME + 2, // NF_DATETIME_SYS_DDMMYYYY_HHMM
162 ZF_STANDARD_FRACTION + 2, // NF_FRACTION_3D
163 ZF_STANDARD_FRACTION + 3, // NF_FRACTION_2
164 ZF_STANDARD_FRACTION + 4, // NF_FRACTION_4
165 ZF_STANDARD_FRACTION + 5, // NF_FRACTION_8
166 ZF_STANDARD_FRACTION + 6, // NF_FRACTION_16
167 ZF_STANDARD_FRACTION + 7, // NF_FRACTION_10
168 ZF_STANDARD_FRACTION + 8, // NF_FRACTION_100
169 ZF_STANDARD_DATETIME + 3, // NF_DATETIME_ISO_YYYYMMDD_HHMMSS
170 ZF_STANDARD_DATETIME + 4, // NF_DATETIME_ISO_YYYYMMDD_HHMMSS000
171 ZF_STANDARD_DATETIME + 5, // NF_DATETIME_ISO_YYYYMMDDTHHMMSS
172 ZF_STANDARD_DATETIME + 6 // NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
173};
174
181{
182 std::vector< SvNumberFormatter* >
186
187public:
189 virtual ~SvNumberFormatterRegistry_Impl() override;
190
192 { aFormatters.push_back( pThis ); }
193
194 void Remove( SvNumberFormatter const * pThis );
195
196 size_t Count() const
197 { return aFormatters.size(); }
198
200};
201
203 : eSysLanguage(MsLangId::getRealLanguage( LANGUAGE_SYSTEM ))
204{
206}
207
208
210{
212}
213
214
216{
217 auto it = std::find(aFormatters.begin(), aFormatters.end(), pThis);
218 if (it != aFormatters.end())
219 aFormatters.erase( it );
220}
221
223 ConfigurationHints nHint)
224{
225 ::osl::MutexGuard aGuard( SvNumberFormatter::GetGlobalMutex() );
226
227 if ( nHint & ConfigurationHints::Locale )
228 {
229 for(SvNumberFormatter* pFormatter : aFormatters)
230 pFormatter->ReplaceSystemCL( eSysLanguage );
232 }
233 if ( nHint & ConfigurationHints::Currency )
234 {
235 for(SvNumberFormatter* pFormatter : aFormatters)
236 pFormatter->ResetDefaultSystemCurrency();
237 }
238 if ( nHint & ConfigurationHints::DatePatterns )
239 {
240 for(SvNumberFormatter* pFormatter : aFormatters)
241 pFormatter->InvalidateDateAcceptancePatterns();
242 }
243}
244
245
248namespace
249{
250 NfCurrencyTable& theCurrencyTable()
251 {
252 static NfCurrencyTable SINGLETON;
253 return SINGLETON;
254 }
255
256 NfCurrencyTable& theLegacyOnlyCurrencyTable()
257 {
258 static NfCurrencyTable SINGLETON;
259 return SINGLETON;
260 }
261
263 std::set< LanguageType > theInstalledLocales;
264
265}
267
268// Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
269// language dependent.
270#define NF_BANKSYMBOL_FIX_POSITION 1
271
272const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION = ::std::numeric_limits<sal_uInt16>::max();
273const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1;
274
275SvNumberFormatter::SvNumberFormatter( const Reference< XComponentContext >& rxContext,
276 LanguageType eLang )
277 : m_xContext( rxContext )
278 , maLanguageTag( eLang)
279{
280 ImpConstruct( eLang );
281}
282
284{
285 {
286 ::osl::MutexGuard aGuard( GetGlobalMutex() );
287 pFormatterRegistry->Remove( this );
288 if ( !pFormatterRegistry->Count() )
289 {
290 delete pFormatterRegistry;
291 pFormatterRegistry = nullptr;
292 }
293 }
294
295 aFTable.clear();
297}
298
299
301{
302 if ( eLang == LANGUAGE_DONTKNOW )
303 {
304 eLang = UNKNOWN_SUBSTITUTE;
305 }
306 IniLnge = eLang;
307 ActLnge = eLang;
310
311 maLanguageTag.reset( eLang );
317
318 // cached locale data items
319 const LocaleDataWrapper* pLoc = GetLocaleData();
323 aDateSep = pLoc->getDateSep();
324
325 pStringScanner.reset( new ImpSvNumberInputScan( this ) );
326 pFormatScanner.reset( new ImpSvNumberformatScan( this ) );
327 pFormatTable = nullptr;
328 MaxCLOffset = 0;
329 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
330 pMergeTable = nullptr;
331 bNoZero = false;
332
333 ::osl::MutexGuard aGuard( GetGlobalMutex() );
335}
336
337
339{
340 ::osl::MutexGuard aGuard( GetInstanceMutex() );
341 if (ActLnge == eLnge)
342 return;
343
344 ActLnge = eLnge;
345
346 maLanguageTag.reset( eLnge );
351
352 // cached locale data items, initialize BEFORE calling ChangeIntl below
353 const LocaleDataWrapper* pLoc = GetLocaleData();
357 aDateSep = pLoc->getDateSep();
358
359 pFormatScanner->ChangeIntl();
360 pStringScanner->ChangeIntl();
361}
362
363
364// static
366{
367 // #i77768# Due to a static reference in the toolkit lib
368 // we need a mutex that lives longer than the svl library.
369 // Otherwise the dtor would use a destructed mutex!!
370 static osl::Mutex* persistentMutex(new osl::Mutex);
371
372 return *persistentMutex;
373}
374
375
376// static
378{
379 ::osl::MutexGuard aGuard( GetGlobalMutex() );
380 if ( !pFormatterRegistry )
381 {
383 }
384 return *pFormatterRegistry;
385}
386
388{
389 ::osl::MutexGuard aGuard( GetInstanceMutex() );
390 aColorLink = rColorTableCallBack;
391}
392
394{
395 ::osl::MutexGuard aGuard( GetInstanceMutex() );
396 if( aColorLink.IsSet() )
397 {
398 return aColorLink.Call(nIndex);
399 }
400 else
401 {
402 return nullptr;
403 }
404}
405
407 sal_uInt16 nMonth,
408 sal_Int16 nYear)
409{
410 ::osl::MutexGuard aGuard( GetInstanceMutex() );
411 pFormatScanner->ChangeNullDate(nDay, nMonth, nYear);
412 pStringScanner->ChangeNullDate(nDay, nMonth, nYear);
413}
414
416{
417 ::osl::MutexGuard aGuard( GetInstanceMutex() );
418 return pFormatScanner->GetNullDate();
419}
420
422{
423 ::osl::MutexGuard aGuard( GetInstanceMutex() );
424 pFormatScanner->ChangeStandardPrec(nPrec);
425}
426
428{
429 ::osl::MutexGuard aGuard( GetInstanceMutex() );
430 bNoZero = bNZ;
431}
432
434{
435 ::osl::MutexGuard aGuard( GetInstanceMutex() );
436 return pFormatScanner->GetStandardPrec();
437}
438
440{
441 ::osl::MutexGuard aGuard( GetInstanceMutex() );
442 return bNoZero;
443}
444
446{
447 sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM );
448 if ( nCLOffset > MaxCLOffset )
449 {
450 return ; // no SYSTEM entries to replace
451 }
452 const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_COUNT_STANDARD_FORMATS;
453 const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
454 sal_uInt32 nKey;
455
456 // remove old builtin formats
457 auto it = aFTable.find( nCLOffset );
458 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey <= nMaxBuiltin )
459 {
460 it = aFTable.erase(it);
461 }
462
463 // move additional and user defined to temporary table
464 SvNumberFormatTable aOldTable;
465 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey < nNextCL )
466 {
467 aOldTable[ nKey ] = it->second.release();
468 it = aFTable.erase(it);
469 }
470
471 // generate new old builtin formats
472 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
475 ImpGenerateFormats( nCLOffset, true );
476
477 // convert additional and user defined from old system to new system
478 SvNumberformat* pStdFormat = GetFormatEntry( nCLOffset + ZF_STANDARD );
479 sal_uInt32 nLastKey = nMaxBuiltin;
480 pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, true , true);
481 while ( !aOldTable.empty() )
482 {
483 nKey = aOldTable.begin()->first;
484 if ( nLastKey < nKey )
485 {
486 nLastKey = nKey;
487 }
488 std::unique_ptr<SvNumberformat> pOldEntry(aOldTable.begin()->second);
489 aOldTable.erase( nKey );
490 OUString aString( pOldEntry->GetFormatstring() );
491
492 // Same as PutEntry() but assures key position even if format code is
493 // a duplicate. Also won't mix up any LastInsertKey.
494 ChangeIntl( eOldLanguage );
495 LanguageType eLge = eOldLanguage; // ConvertMode changes this
496 bool bCheck = false;
497 sal_Int32 nCheckPos = -1;
498 std::unique_ptr<SvNumberformat> pNewEntry(new SvNumberformat( aString, pFormatScanner.get(),
499 pStringScanner.get(), nCheckPos, eLge ));
500 if ( nCheckPos == 0 )
501 {
502 SvNumFormatType eCheckType = pNewEntry->GetType();
503 if ( eCheckType != SvNumFormatType::UNDEFINED )
504 {
505 pNewEntry->SetType( eCheckType | SvNumFormatType::DEFINED );
506 }
507 else
508 {
509 pNewEntry->SetType( SvNumFormatType::DEFINED );
510 }
511
512 if ( aFTable.emplace( nKey, std::move(pNewEntry) ).second )
513 {
514 bCheck = true;
515 }
516 }
517 DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
518 }
519 pFormatScanner->SetConvertMode(false);
520 pStdFormat->SetLastInsertKey( sal_uInt16(nLastKey - nCLOffset), SvNumberformat::FormatterPrivateAccess() );
521
522 // append new system additional formats
523 css::uno::Reference< css::i18n::XNumberFormatCode > xNFC = i18n::NumberFormatMapper::create( m_xContext );
524 ImpGenerateAdditionalFormats( nCLOffset, xNFC, true );
525}
526
527const css::uno::Reference<css::uno::XComponentContext>& SvNumberFormatter::GetComponentContext() const
528{
529 return m_xContext;
530}
531
533
535
536const ::utl::TransliterationWrapper* SvNumberFormatter::GetTransliteration() const
537{
538 return xTransliteration.get();
539}
540
542
544
546
547const NativeNumberWrapper* SvNumberFormatter::GetNatNum() const { return xNatNum.get(); }
548
549const OUString& SvNumberFormatter::GetNumDecimalSep() const { return aDecimalSep; }
550
552
553const OUString& SvNumberFormatter::GetNumThousandSep() const { return aThousandSep; }
554
555const OUString& SvNumberFormatter::GetDateSep() const { return aDateSep; }
556
557bool SvNumberFormatter::IsDecimalSep( std::u16string_view rStr ) const
558{
559 if (rStr == GetNumDecimalSep())
560 return true;
561 if (GetNumDecimalSepAlt().isEmpty())
562 return false;
563 return rStr == GetNumDecimalSepAlt();
564}
565
566bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const
567{
568 ::osl::MutexGuard aGuard( GetInstanceMutex() );
569 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
570
571 return pFormat && pFormat->IsTextFormat();
572}
573
574bool SvNumberFormatter::PutEntry(OUString& rString,
575 sal_Int32& nCheckPos,
576 SvNumFormatType& nType,
577 sal_uInt32& nKey, // format key
578 LanguageType eLnge,
579 bool bReplaceBooleanEquivalent)
580{
581 ::osl::MutexGuard aGuard( GetInstanceMutex() );
582 nKey = 0;
583 if (rString.isEmpty()) // empty string
584 {
585 nCheckPos = 1; // -> Error
586 return false;
587 }
588 if (eLnge == LANGUAGE_DONTKNOW)
589 {
590 eLnge = IniLnge;
591 }
592 ChangeIntl(eLnge); // change locale if necessary
593 LanguageType eLge = eLnge; // non-const for ConvertMode
594 bool bCheck = false;
595 std::unique_ptr<SvNumberformat> p_Entry(new SvNumberformat(rString,
596 pFormatScanner.get(),
597 pStringScanner.get(),
598 nCheckPos,
599 eLge,
600 bReplaceBooleanEquivalent));
601
602 if (nCheckPos == 0) // Format ok
603 { // Type comparison:
604 SvNumFormatType eCheckType = p_Entry->GetType();
605 if ( eCheckType != SvNumFormatType::UNDEFINED)
606 {
607 p_Entry->SetType(eCheckType | SvNumFormatType::DEFINED);
608 nType = eCheckType;
609 }
610 else
611 {
612 p_Entry->SetType(SvNumFormatType::DEFINED);
614 }
615
616 sal_uInt32 CLOffset = ImpGenerateCL(eLge); // create new standard formats if necessary
617
618 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge);
619 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND) // only in not yet present
620 {
621 SvNumberformat* pStdFormat = GetFormatEntry(CLOffset + ZF_STANDARD);
622 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
623 if (nPos+1 - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
624 {
625 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
626 }
627 else if (!aFTable.emplace( nPos+1, std::move(p_Entry)).second)
628 {
629 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
630 }
631 else
632 {
633 bCheck = true;
634 nKey = nPos+1;
635 pStdFormat->SetLastInsertKey(static_cast<sal_uInt16>(nKey-CLOffset), SvNumberformat::FormatterPrivateAccess());
636 }
637 }
638 }
639 return bCheck;
640}
641
643 sal_Int32& nCheckPos,
644 SvNumFormatType& nType,
645 sal_uInt32& nKey,
646 LanguageType eLnge,
647 LanguageType eNewLnge,
648 bool bConvertDateOrder,
649 bool bReplaceBooleanEquivalent )
650{
651 ::osl::MutexGuard aGuard( GetInstanceMutex() );
652 bool bRes;
653 if (eNewLnge == LANGUAGE_DONTKNOW)
654 {
655 eNewLnge = IniLnge;
656 }
657 pFormatScanner->SetConvertMode(eLnge, eNewLnge, false, bConvertDateOrder);
658 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge, bReplaceBooleanEquivalent);
659 pFormatScanner->SetConvertMode(false);
660
661 if (bReplaceBooleanEquivalent && nCheckPos == 0 && nType == SvNumFormatType::DEFINED
663 {
664 // The boolean string formats are always "user defined" without any
665 // other type.
666 const SvNumberformat* pEntry = GetFormatEntry(nKey);
667 if (pEntry && pEntry->GetType() == SvNumFormatType::DEFINED)
668 {
669 // Replace boolean string format with Boolean in target locale, in
670 // case the source strings are the target locale's.
671 const OUString aSaveString = rString;
672 ChangeIntl(eNewLnge);
673 if (pFormatScanner->ReplaceBooleanEquivalent( rString))
674 {
675 const sal_Int32 nSaveCheckPos = nCheckPos;
676 const SvNumFormatType nSaveType = nType;
677 const sal_uInt32 nSaveKey = nKey;
678 const bool bTargetRes = PutEntry(rString, nCheckPos, nType, nKey, eNewLnge, false);
679 if (nCheckPos == 0 && nType == SvNumFormatType::LOGICAL && nKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
680 {
681 bRes = bTargetRes;
682 }
683 else
684 {
685 SAL_WARN("svl.numbers", "SvNumberFormatter::PutandConvertEntry: can't scan boolean replacement");
686 // Live with the source boolean string format.
687 rString = aSaveString;
688 nCheckPos = nSaveCheckPos;
689 nType = nSaveType;
690 nKey = nSaveKey;
691 }
692 }
693 }
694 }
695 return bRes;
696}
697
699 sal_Int32& nCheckPos,
700 SvNumFormatType& nType,
701 sal_uInt32& nKey,
702 LanguageType eLnge,
703 LanguageType eNewLnge)
704{
705 ::osl::MutexGuard aGuard( GetInstanceMutex() );
706 bool bRes;
707 if (eNewLnge == LANGUAGE_DONTKNOW)
708 {
709 eNewLnge = IniLnge;
710 }
711 pFormatScanner->SetConvertMode(eLnge, eNewLnge, true, true);
712 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
713 pFormatScanner->SetConvertMode(false);
714 return bRes;
715}
716
718 LanguageType eSysLnge, SvNumFormatType & rType,
719 bool & rNewInserted, sal_Int32 & rCheckPos )
720{
721 ::osl::MutexGuard aGuard( GetInstanceMutex() );
722 sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
723 rNewInserted = false;
724 rCheckPos = 0;
725
726 // #62389# empty format string (of Writer) => General standard format
727 if (rString.isEmpty())
728 {
729 // nothing
730 }
731 else if (eLnge == LANGUAGE_SYSTEM && eSysLnge != SvtSysLocale().GetLanguageTag().getLanguageType())
732 {
733 sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge );
734 if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND)
735 {
736 nKey = nOrig; // none available, maybe user-defined
737 }
738 else
739 {
740 nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguageTag().getLanguageType() );
741 }
742 if (nKey == nOrig)
743 {
744 // Not a builtin format, convert.
745 // The format code string may get modified and adapted to the real
746 // language and wouldn't match eSysLnge anymore, do that on a copy.
747 OUString aTmp( rString);
748 rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType,
749 nKey, eLnge, SvtSysLocale().GetLanguageTag().getLanguageType());
750 if (rCheckPos > 0)
751 {
752 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
754 }
755 }
756 }
757 else
758 {
759 nKey = GetEntryKey( rString, eLnge);
761 {
762 rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
763 if (rCheckPos > 0)
764 {
765 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
767 }
768 }
769 }
771 {
772 nKey = GetStandardIndex( eLnge);
773 }
774 rType = GetType( nKey);
775 // Convert any (!) old "automatic" currency format to new fixed currency
776 // default format.
777 if (rType & SvNumFormatType::CURRENCY)
778 {
779 const SvNumberformat* pFormat = GetEntry( nKey);
780 if (!pFormat->HasNewCurrency())
781 {
782 if (rNewInserted)
783 {
784 DeleteEntry( nKey); // don't leave trails of rubbish
785 rNewInserted = false;
786 }
788 }
789 }
790 return nKey;
791}
792
794{
795 ::osl::MutexGuard aGuard( GetInstanceMutex() );
796 aFTable.erase(nKey);
797}
798
799void SvNumberFormatter::GetUsedLanguages( std::vector<LanguageType>& rList )
800{
801 ::osl::MutexGuard aGuard( GetInstanceMutex() );
802 rList.clear();
803
804 sal_uInt32 nOffset = 0;
805 while (nOffset <= MaxCLOffset)
806 {
807 SvNumberformat* pFormat = GetFormatEntry(nOffset);
808 if (pFormat)
809 {
810 rList.push_back( pFormat->GetLanguage() );
811 }
813 }
814}
815
816
818 LanguageType eLang )
819{
820 ::osl::MutexGuard aGuard( GetInstanceMutex() );
821 ChangeIntl( eLang );
822 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
823 for ( sal_uInt16 i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i )
824 {
825 rKeywords[i] = rTable[i];
826 }
827}
828
829
831{
832 ::osl::MutexGuard aGuard( GetInstanceMutex() );
834
835 // Replace upper case "GENERAL" with proper case "General".
837
838 // Excel or OOXML do not specify format code keywords case sensitivity,
839 // but given and writes them lower case. Using upper case even lead to an
840 // odd misrepresentation in iOS viewer and OSX Quicklook viewer that
841 // strangely use "D" and "DD" for "days since beginning of year", which is
842 // nowhere defined. See tdf#126773
843 // Use lower case for all date and time keywords where known. See OOXML
844 // ECMA-376-1:2016 18.8.31 numFmts (Number Formats)
845 rKeywords[ NF_KEY_MI ] = "m";
846 rKeywords[ NF_KEY_MMI ] = "mm";
847 rKeywords[ NF_KEY_M ] = "m";
848 rKeywords[ NF_KEY_MM ] = "mm";
849 rKeywords[ NF_KEY_MMM ] = "mmm";
850 rKeywords[ NF_KEY_MMMM ] = "mmmm";
851 rKeywords[ NF_KEY_MMMMM ] = "mmmmm";
852 rKeywords[ NF_KEY_H ] = "h";
853 rKeywords[ NF_KEY_HH ] = "hh";
854 rKeywords[ NF_KEY_S ] = "s";
855 rKeywords[ NF_KEY_SS ] = "ss";
856 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_Q ] = "q"; */
857 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_QQ ] = "qq"; */
858 rKeywords[ NF_KEY_D ] = "d";
859 rKeywords[ NF_KEY_DD ] = "dd";
860 rKeywords[ NF_KEY_DDD ] = "ddd";
861 rKeywords[ NF_KEY_DDDD ] = "dddd";
862 rKeywords[ NF_KEY_YY ] = "yy";
863 rKeywords[ NF_KEY_YYYY ] = "yyyy";
864 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAA ] = "aaa"; */
865 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAAA ] = "aaaa"; */
866 rKeywords[ NF_KEY_EC ] = "e";
867 rKeywords[ NF_KEY_EEC ] = "ee";
868 rKeywords[ NF_KEY_G ] = "g";
869 rKeywords[ NF_KEY_GG ] = "gg";
870 rKeywords[ NF_KEY_GGG ] = "ggg";
871 rKeywords[ NF_KEY_R ] = "r";
872 rKeywords[ NF_KEY_RR ] = "rr";
873 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_WW ] = "ww"; */
874
875 // Remap codes unknown to Excel.
876 rKeywords[ NF_KEY_NN ] = "ddd";
877 rKeywords[ NF_KEY_NNN ] = "dddd";
878 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
879 rKeywords[ NF_KEY_NNNN ] = "dddd";
880 // Export the Thai T NatNum modifier. This must be uppercase for internal reasons.
881 rKeywords[ NF_KEY_THAI_T ] = "T";
882}
883
884
886{
887 // Build Boolean number format, which needs non-zero and zero subformat
888 // codes with TRUE and FALSE strings.
889 const Color* pColor = nullptr;
890 OUString aFormatStr, aTemp;
891 pEntry->GetOutputString( 1.0, aTemp, &pColor );
892 aFormatStr += "\"" + aTemp + "\";\"" + aTemp + "\";\"";
893 pEntry->GetOutputString( 0.0, aTemp, &pColor );
894 aFormatStr += aTemp + "\"";
895 return aFormatStr;
896}
897
898
899OUString SvNumberFormatter::GetFormatStringForExcel( sal_uInt32 nKey, const NfKeywordTable& rKeywords,
900 SvNumberFormatter& rTempFormatter ) const
901{
902 ::osl::MutexGuard aGuard( GetInstanceMutex() );
903 OUString aFormatStr;
904 if (const SvNumberformat* pEntry = GetEntry( nKey))
905 {
906 if (pEntry->GetType() == SvNumFormatType::LOGICAL)
907 {
908 // Build a source locale dependent string boolean. This is
909 // expected when loading the document in the same locale or if
910 // several locales are used, but not for other system/default
911 // locales. You can't have both. We could force to English for all
912 // locales like below, but Excel would display English strings then
913 // even for the system locale matching this locale. YMMV.
914 aFormatStr = lcl_buildBooleanStringFormat( const_cast< SvNumberformat* >(pEntry));
915 }
916 else
917 {
918 bool bSystemLanguage = false;
919 LanguageType nLang = pEntry->GetLanguage();
920 if (nLang == LANGUAGE_SYSTEM)
921 {
922 bSystemLanguage = true;
924 }
925 if (nLang != LANGUAGE_ENGLISH_US)
926 {
927 sal_Int32 nCheckPos;
929 sal_uInt32 nTempKey;
930 OUString aTemp( pEntry->GetFormatstring());
931 /* TODO: do we want bReplaceBooleanEquivalent=true in any case
932 * to write it as English string boolean? */
933 rTempFormatter.PutandConvertEntry( aTemp, nCheckPos, nType, nTempKey, nLang, LANGUAGE_ENGLISH_US,
934 false /*bConvertDateOrder*/, false /*bReplaceBooleanEquivalent*/);
935 SAL_WARN_IF( nCheckPos != 0, "svl.numbers",
936 "SvNumberFormatter::GetFormatStringForExcel - format code not convertible");
937 if (nTempKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
938 pEntry = rTempFormatter.GetEntry( nTempKey);
939 }
940
941 if (pEntry)
942 {
943 if (pEntry->GetType() == SvNumFormatType::LOGICAL)
944 {
945 // This would be reached if bReplaceBooleanEquivalent was
946 // true and the source format is a string boolean like
947 // >"VRAI";"VRAI";"FAUX"< recognized as real boolean and
948 // properly converted. Then written as
949 // >"TRUE";"TRUE";"FALSE"<
950 aFormatStr = lcl_buildBooleanStringFormat( const_cast< SvNumberformat* >(pEntry));
951 }
952 else
953 {
954 // GetLocaleData() returns the current locale's data, so switch
955 // before (which doesn't do anything if it was the same locale
956 // already).
957 rTempFormatter.ChangeIntl( LANGUAGE_ENGLISH_US);
958 aFormatStr = pEntry->GetMappedFormatstring( rKeywords, *rTempFormatter.GetLocaleData(), nLang,
959 bSystemLanguage);
960 }
961 }
962 }
963 }
964 else
965 {
966 SAL_WARN("svl.numbers","SvNumberFormatter::GetFormatStringForExcel - format not found: " << nKey);
967 }
968
969 if (aFormatStr.isEmpty())
970 aFormatStr = "General";
971 return aFormatStr;
972}
973
974
975OUString SvNumberFormatter::GetKeyword( LanguageType eLnge, sal_uInt16 nIndex )
976{
977 ::osl::MutexGuard aGuard( GetInstanceMutex() );
978 ChangeIntl(eLnge);
979 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
981 {
982 return rTable[nIndex];
983 }
984 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
985 return OUString();
986}
987
988
990{
991 ::osl::MutexGuard aGuard( GetInstanceMutex() );
992 ChangeIntl( eLnge );
993 return pFormatScanner->GetStandardName();
994}
995
996
998{
999 sal_uInt32 nOffset = 0;
1000 while (nOffset <= MaxCLOffset)
1001 {
1002 const SvNumberformat* pFormat = GetFormatEntry(nOffset);
1003 if (pFormat && pFormat->GetLanguage() == eLnge)
1004 {
1005 return nOffset;
1006 }
1007 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
1008 }
1009 return nOffset;
1010}
1011
1012sal_uInt32 SvNumberFormatter::ImpIsEntry(std::u16string_view rString,
1013 sal_uInt32 nCLOffset,
1014 LanguageType eLnge)
1015{
1016 sal_uInt32 res = NUMBERFORMAT_ENTRY_NOT_FOUND;
1017 auto it = aFTable.find( nCLOffset);
1018 while ( res == NUMBERFORMAT_ENTRY_NOT_FOUND &&
1019 it != aFTable.end() && it->second->GetLanguage() == eLnge )
1020 {
1021 if ( rString == it->second->GetFormatstring() )
1022 {
1023 res = it->first;
1024 }
1025 else
1026 {
1027 ++it;
1028 }
1029 }
1030 return res;
1031}
1032
1033
1035 SvNumFormatType& eType,
1036 sal_uInt32& FIndex,
1037 LanguageType& rLnge)
1038{
1039 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1040 SvNumFormatType eTypetmp = eType;
1041 if (eType == SvNumFormatType::ALL) // empty cell or don't care
1042 {
1043 rLnge = IniLnge;
1044 }
1045 else
1046 {
1047 SvNumberformat* pFormat = GetFormatEntry(FIndex);
1048 if (!pFormat)
1049 {
1050 rLnge = IniLnge;
1052 eTypetmp = eType;
1053 }
1054 else
1055 {
1056 rLnge = pFormat->GetLanguage();
1057 eType = pFormat->GetMaskedType();
1059 {
1061 eTypetmp = eType;
1062 }
1063 else if (eType == SvNumFormatType::DATETIME)
1064 {
1065 eTypetmp = eType;
1067 }
1068 else
1069 {
1070 eTypetmp = eType;
1071 }
1072 }
1073 }
1074 ChangeIntl(rLnge);
1075 return GetEntryTable(eTypetmp, FIndex, rLnge);
1076}
1077
1079{
1080 ChangeIntl(eLnge);
1081 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1082 if (CLOffset > MaxCLOffset)
1083 {
1084 // new CL combination
1086 {
1087 const LanguageTag& rLoadedLocale = xLocaleData->getLoadedLanguageTag();
1088 if ( !rLoadedLocale.equals( maLanguageTag ) )
1089 {
1090 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( u"SvNumberFormatter::ImpGenerateCL: locales don't match:" ));
1091 }
1092 // test XML locale data FormatElement entries
1093 {
1094 uno::Sequence< i18n::FormatElement > xSeq = xLocaleData->getAllFormats();
1095 // A test for completeness of formatindex="0" ...
1096 // formatindex="47" is not needed here since it is done in
1097 // ImpGenerateFormats().
1098
1099 // Test for dupes of formatindex="..."
1100 for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ )
1101 {
1102 sal_Int16 nIdx = xSeq[j].formatIndex;
1103 OUStringBuffer aDupes;
1104 for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ )
1105 {
1106 if ( i != j && xSeq[i].formatIndex == nIdx )
1107 {
1108 aDupes.append( OUString::number(i) + "(" + xSeq[i].formatKey + ") ");
1109 }
1110 }
1111 if ( !aDupes.isEmpty() )
1112 {
1113 OUString aMsg = "XML locale data FormatElement formatindex dupe: "
1114 + OUString::number(nIdx)
1115 + "\nFormatElements: "
1116 + OUString::number( j )
1117 + "("
1118 + xSeq[j].formatKey
1119 + ") "
1120 + aDupes;
1122 }
1123 }
1124 }
1125 }
1126
1128 ImpGenerateFormats( MaxCLOffset, false/*bNoAdditionalFormats*/ );
1129 CLOffset = MaxCLOffset;
1130 }
1131 return CLOffset;
1132}
1133
1135 sal_uInt32& FIndex,
1136 LanguageType eLnge)
1137{
1138 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1139 ImpGenerateCL(eLnge);
1140 return GetEntryTable(eType, FIndex, ActLnge);
1141}
1142
1144 SvNumFormatType eType,
1145 sal_uInt32& FIndex,
1146 LanguageType eLnge)
1147{
1148 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1149 if ( pFormatTable )
1150 {
1151 pFormatTable->clear();
1152 }
1153 else
1154 {
1155 pFormatTable.reset( new SvNumberFormatTable );
1156 }
1157 ChangeIntl(eLnge);
1158 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1159
1160 // Might generate and insert a default format for the given type
1161 // (e.g. currency) => has to be done before collecting formats.
1162 sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge );
1163
1164 auto it = aFTable.find( CLOffset);
1165
1167 {
1168 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1169 { // copy all entries to output table
1170 (*pFormatTable)[ it->first ] = it->second.get();
1171 ++it;
1172 }
1173 }
1174 else
1175 {
1176 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1177 { // copy entries of queried type to output table
1178 if ((it->second->GetType()) & eType)
1179 (*pFormatTable)[ it->first ] = it->second.get();
1180 ++it;
1181 }
1182 }
1183 if ( !pFormatTable->empty() )
1184 { // select default if queried format doesn't exist or queried type or
1185 // language differ from existing format
1186 SvNumberformat* pEntry = GetFormatEntry(FIndex);
1187 if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge )
1188 {
1189 FIndex = nDefaultIndex;
1190 }
1191 }
1192 return *pFormatTable;
1193}
1194
1195bool SvNumberFormatter::IsNumberFormat(const OUString& sString,
1196 sal_uInt32& F_Index,
1197 double& fOutNumber,
1198 SvNumInputOptions eInputOptions)
1199{
1200 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1201
1202 SvNumFormatType FType;
1203 // For the 0 General format directly use the init/system locale and avoid
1204 // all overhead that is associated with a format passed to the scanner.
1205 const SvNumberformat* pFormat = (F_Index == 0 ? nullptr : ImpSubstituteEntry( GetFormatEntry(F_Index)));
1206 if (!pFormat)
1207 {
1210 }
1211 else
1212 {
1213 FType = pFormat->GetMaskedType();
1214 if (FType == SvNumFormatType::ALL)
1215 {
1217 }
1218 ChangeIntl(pFormat->GetLanguage());
1219 // Avoid scanner overhead with the General format of any locale.
1220 // These are never substituted above so safe to ignore.
1221 if ((F_Index % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1222 {
1223 assert(FType == SvNumFormatType::NUMBER);
1224 pFormat = nullptr;
1225 }
1226 }
1227
1228 bool res;
1229 SvNumFormatType RType = FType;
1230 if (RType == SvNumFormatType::TEXT)
1231 {
1232 res = false; // type text preset => no conversion to number
1233 }
1234 else
1235 {
1236 res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat, eInputOptions);
1237 }
1238 if (res && !IsCompatible(FType, RType)) // non-matching type
1239 {
1240 switch ( RType )
1241 {
1243 // Preserve ISO 8601 input.
1244 if (pStringScanner->CanForceToIso8601( DateOrder::Invalid))
1245 {
1247 }
1248 else
1249 {
1250 F_Index = GetStandardFormat( RType, ActLnge );
1251 }
1252 break;
1254 if ( pStringScanner->GetDecPos() )
1255 {
1256 // 100th seconds
1257 if ( pStringScanner->GetNumericsCount() > 3 || fOutNumber < 0.0 )
1258 {
1260 }
1261 else
1262 {
1264 }
1265 }
1266 else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 )
1267 {
1269 }
1270 else
1271 {
1272 F_Index = GetStandardFormat( RType, ActLnge );
1273 }
1274 break;
1276 // Preserve ISO 8601 input.
1277 if (pStringScanner->HasIso8601Tsep())
1278 {
1279 if (pStringScanner->GetDecPos())
1281 else
1283 }
1284 else if (pStringScanner->CanForceToIso8601( DateOrder::Invalid))
1285 {
1286 if (pStringScanner->GetDecPos())
1288 else
1290 }
1291 else
1292 {
1293 F_Index = GetStandardFormat( RType, ActLnge );
1294 }
1295 break;
1296 default:
1297 F_Index = GetStandardFormat( RType, ActLnge );
1298 }
1299 }
1300 return res;
1301}
1302
1304{
1305 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1306 return IniLnge;
1307}
1308
1309// static
1311{
1312 if (eOldType == eNewType)
1313 {
1314 return true;
1315 }
1316 else if (eOldType == SvNumFormatType::DEFINED)
1317 {
1318 return true;
1319 }
1320 else
1321 {
1322 switch (eNewType)
1323 {
1325 switch (eOldType)
1326 {
1332 return true;
1334 default:
1335 return false;
1336 }
1337 break;
1339 switch (eOldType)
1340 {
1342 return true;
1343 default:
1344 return false;
1345 }
1346 break;
1348 switch (eOldType)
1349 {
1351 return true;
1352 default:
1353 return false;
1354 }
1355 break;
1357 switch (eOldType)
1358 {
1361 return true;
1362 default:
1363 return false;
1364 }
1365 break;
1367 return false;
1368 default:
1369 return false;
1370 }
1371 }
1372}
1373
1374
1376{
1377 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1378 sal_uInt32 nSearch;
1379 switch( nType )
1380 {
1382 nSearch = CLOffset + ZF_STANDARD_DATE;
1383 break;
1385 nSearch = CLOffset + ZF_STANDARD_TIME;
1386 break;
1388 nSearch = CLOffset + ZF_STANDARD_DATETIME;
1389 break;
1391 nSearch = CLOffset + ZF_STANDARD_DURATION;
1392 break;
1394 nSearch = CLOffset + ZF_STANDARD_PERCENT;
1395 break;
1397 nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1398 break;
1399 default:
1400 nSearch = CLOffset + ZF_STANDARD;
1401 }
1402
1403 DefaultFormatKeysMap::const_iterator it = aDefaultFormatKeys.find( nSearch);
1404 sal_uInt32 nDefaultFormat = (it != aDefaultFormatKeys.end() ?
1405 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
1406 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1407 {
1408 // look for a defined standard
1409 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
1410 sal_uInt32 nKey(0);
1411 auto it2 = aFTable.find( CLOffset );
1412 while ( it2 != aFTable.end() && (nKey = it2->first ) >= CLOffset && nKey < nStopKey )
1413 {
1414 const SvNumberformat* pEntry = it2->second.get();
1415 if ( pEntry->IsStandard() && (pEntry->GetMaskedType() == nType) )
1416 {
1417 nDefaultFormat = nKey;
1418 break; // while
1419 }
1420 ++it2;
1421 }
1422
1423 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1424 { // none found, use old fixed standards
1425 switch( nType )
1426 {
1428 nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1429 break;
1431 nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1432 break;
1434 nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1435 break;
1437 nDefaultFormat = CLOffset + ZF_STANDARD_DURATION;
1438 break;
1440 nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1441 break;
1443 nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1444 break;
1445 default:
1446 nDefaultFormat = CLOffset + ZF_STANDARD;
1447 }
1448 }
1449 aDefaultFormatKeys[ nSearch ] = nDefaultFormat;
1450 }
1451 return nDefaultFormat;
1452}
1453
1454
1456{
1457 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1458 if (eLnge == LANGUAGE_DONTKNOW)
1459 {
1460 eLnge = IniLnge;
1461 }
1462 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1463 switch(eType)
1464 {
1468 return GetFormatIndex( NF_TIME_HH_MMSS, eLnge);
1474 return ImpGetDefaultFormat( eType );
1476 return CLOffset + ZF_STANDARD_FRACTION;
1478 return CLOffset + ZF_STANDARD_LOGICAL;
1480 return CLOffset + ZF_STANDARD_TEXT;
1485 default:
1486 return CLOffset + ZF_STANDARD;
1487 }
1488}
1489
1491 LanguageType eLnge )
1492{
1493 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1494 return
1495 nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) ||
1496 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) ||
1497 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge )
1498 ;
1499}
1500
1501sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, SvNumFormatType eType,
1502 LanguageType eLnge )
1503{
1504 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1505 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1506 return nFIndex;
1507 else
1508 return GetStandardFormat( eType, eLnge );
1509}
1510
1511sal_uInt32 SvNumberFormatter::GetTimeFormat( double fNumber, LanguageType eLnge, bool bForceDuration )
1512{
1513 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1514 bool bSign;
1515 if ( fNumber < 0.0 )
1516 {
1517 bSign = true;
1518 fNumber = -fNumber;
1519 }
1520 else
1521 bSign = false;
1522 double fSeconds = fNumber * 86400;
1523 if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) )
1524 { // with 100th seconds
1525 if ( bForceDuration || bSign || fSeconds >= 3600 )
1526 return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge );
1527 else
1528 return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1529 }
1530 else
1531 {
1532 if ( bForceDuration || bSign || fNumber >= 1.0 )
1533 return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1534 else
1536 }
1537}
1538
1539sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex,
1540 SvNumFormatType eType, LanguageType eLnge )
1541{
1542 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1543 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1544 return nFIndex;
1545
1546 switch( eType )
1547 {
1549 return GetTimeFormat( fNumber, eLnge, true);
1551 return GetTimeFormat( fNumber, eLnge, false);
1552 default:
1553 return GetStandardFormat( eType, eLnge );
1554 }
1555}
1556
1558{
1559 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1560 // Categorize the format according to the implementation of
1561 // SvNumberFormatter::GetEditFormat(), making assumptions about what
1562 // would be time only.
1563 sal_uInt32 nRet;
1564 if (0.0 <= fNumber && fNumber < 1.0)
1565 {
1566 // Clearly a time.
1567 rType = SvNumFormatType::TIME;
1568 nRet = GetTimeFormat( fNumber, eLnge, false);
1569 }
1570 else if (fabs( fNumber) * 24 < 0x7fff)
1571 {
1572 // Assuming duration within 32k hours or 3.7 years.
1573 // This should be SvNumFormatType::DURATION instead, but the outer
1574 // world can't cope with that.
1575 rType = SvNumFormatType::TIME;
1576 nRet = GetTimeFormat( fNumber, eLnge, true);
1577 }
1578 else if (rtl::math::approxFloor( fNumber) != fNumber)
1579 {
1580 // Date+Time.
1583 }
1584 else
1585 {
1586 // Date only.
1587 rType = SvNumFormatType::DATE;
1588 nRet = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLnge);
1589 }
1590 return nRet;
1591}
1592
1593sal_uInt32 SvNumberFormatter::GetEditFormat( double fNumber, sal_uInt32 nFIndex,
1594 SvNumFormatType eType,
1595 SvNumberformat const * pFormat,
1596 LanguageType eForLocale )
1597{
1598 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1599 const LanguageType eLang = (pFormat ? pFormat->GetLanguage() : LANGUAGE_SYSTEM);
1600 if (eForLocale == LANGUAGE_DONTKNOW)
1601 eForLocale = eLang;
1602 sal_uInt32 nKey = nFIndex;
1603 switch ( eType )
1604 {
1605 // #61619# always edit using 4-digit year
1607 {
1608 // Preserve ISO 8601 format.
1609 bool bIsoDate =
1610 nFIndex == GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang) ||
1611 nFIndex == GetFormatIndex( NF_DATE_DIN_YYMMDD, eLang) ||
1612 nFIndex == GetFormatIndex( NF_DATE_DIN_MMDD, eLang) ||
1613 (pFormat && pFormat->IsIso8601( 0 ));
1614 if (rtl::math::approxFloor( fNumber) != fNumber)
1615 {
1616 // fdo#34977 preserve time when editing even if only date was
1617 // displayed.
1618 if (bIsoDate)
1620 else
1621 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eForLocale );
1622 }
1623 else
1624 {
1625 if (bIsoDate)
1626 nKey = GetFormatIndex( NF_DATE_ISO_YYYYMMDD, eForLocale);
1627 else
1628 nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eForLocale );
1629 }
1630 }
1631 break;
1633 if (fNumber < 0.0 || fNumber >= 1.0)
1634 {
1635 /* XXX NOTE: this is a purely arbitrary value within the limits
1636 * of a signed 16-bit. 32k hours are 3.7 years ... or
1637 * 1903-09-26 if date. */
1638 if (fabs( fNumber) * 24 < 0x7fff)
1639 nKey = GetTimeFormat( fNumber, eForLocale, true);
1640 // Preserve duration, use [HH]:MM:SS instead of time.
1641 else
1642 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eForLocale );
1643 // Assume that a large value is a datetime with only time
1644 // displayed.
1645 }
1646 else
1647 nKey = GetStandardFormat( fNumber, nFIndex, eType, eForLocale );
1648 break;
1650 nKey = GetTimeFormat( fNumber, eForLocale, true);
1651 break;
1653 if (nFIndex == GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS, eLang))
1654 nKey = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS, eForLocale );
1655 else if (nFIndex == GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS000, eLang))
1657 else if (nFIndex == GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS000, eLang))
1659 else if (nFIndex == GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, eLang) || (pFormat && pFormat->IsIso8601( 0 )))
1660 nKey = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, eForLocale );
1661 else
1662 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eForLocale );
1663 break;
1665 nKey = GetStandardFormat( eType, eForLocale );
1666 break;
1667 default:
1668 nKey = GetStandardFormat( fNumber, nFIndex, eType, eForLocale );
1669 }
1670 return nKey;
1671}
1672
1673void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1674 sal_uInt32 nFIndex,
1675 OUString& sOutString,
1676 bool bFiltering, bool bForceSystemLocale)
1677{
1678 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1679 const Color* pColor;
1680 sal_uInt32 nRealKey = nFIndex;
1681 SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ), &nRealKey);
1682 if (!pFormat)
1683 {
1684 pFormat = GetFormatEntry(ZF_STANDARD);
1685 }
1686
1687 LanguageType eLang = pFormat->GetLanguage();
1688 ChangeIntl( eLang );
1689
1690 SvNumFormatType eType = pFormat->GetMaskedType();
1692 {
1693 // Mixed types in subformats, use first.
1694 /* XXX we could choose a subformat according to fOutNumber and
1695 * subformat conditions, but they may exist to suppress 0 or negative
1696 * numbers so wouldn't be a safe bet. */
1697 eType = pFormat->GetNumForInfoScannedType(0);
1698 }
1699 const SvNumFormatType eTypeOrig = eType;
1700
1701 sal_uInt16 nOldPrec = pFormatScanner->GetStandardPrec();
1702 bool bPrecChanged = false;
1708 {
1709 if (eType != SvNumFormatType::PERCENT) // special treatment of % later
1710 {
1712 }
1714 bPrecChanged = true;
1715 }
1716
1717 // if bFiltering true keep the nRealKey format
1718 if (!bFiltering)
1719 {
1720 sal_uInt32 nKey = GetEditFormat( fOutNumber, nRealKey, eType, pFormat,
1721 bForceSystemLocale ? LANGUAGE_SYSTEM : LANGUAGE_DONTKNOW);
1722 if (nKey != nRealKey)
1723 {
1724 pFormat = GetFormatEntry( nKey );
1725 }
1726 }
1727 assert(pFormat);
1728 if (pFormat)
1729 {
1730 if ( eType == SvNumFormatType::TIME && pFormat->GetFormatPrecision() )
1731 {
1733 bPrecChanged = true;
1734 }
1735 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1736
1737 // The #FMT error string must not be used for input as it would lead to
1738 // data loss. This can happen for at least date(+time). Fall back to a
1739 // last resort of plain number in the locale the formatter was
1740 // constructed with.
1741 if (eTypeOrig != SvNumFormatType::NUMBER && sOutString == ImpSvNumberformatScan::sErrStr)
1742 {
1743 pFormat = GetFormatEntry(ZF_STANDARD);
1744 assert(pFormat);
1745 if (pFormat)
1746 {
1748 bPrecChanged = true;
1749 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1750 }
1751 }
1752 assert(sOutString != ImpSvNumberformatScan::sErrStr);
1753 }
1754 if (bPrecChanged)
1755 {
1756 ChangeStandardPrec(nOldPrec);
1757 }
1758}
1759
1760void SvNumberFormatter::GetOutputString(const OUString& sString,
1761 sal_uInt32 nFIndex,
1762 OUString& sOutString,
1763 const Color** ppColor,
1764 bool bUseStarFormat )
1765{
1766 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1767 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1768 // ImpSubstituteEntry() is unnecessary here because so far only numeric
1769 // (time and date) are substituted.
1770 if (!pFormat)
1771 {
1773 }
1774 if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1775 {
1776 *ppColor = nullptr;
1777 sOutString = sString;
1778 }
1779 else
1780 {
1781 ChangeIntl(pFormat->GetLanguage());
1782 if ( bUseStarFormat )
1783 {
1784 pFormat->SetStarFormatSupport( true );
1785 }
1786 pFormat->GetOutputString(sString, sOutString, ppColor);
1787 if ( bUseStarFormat )
1788 {
1789 pFormat->SetStarFormatSupport( false );
1790 }
1791 }
1792}
1793
1794void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1795 sal_uInt32 nFIndex,
1796 OUString& sOutString,
1797 const Color** ppColor,
1798 bool bUseStarFormat )
1799{
1800 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1801 if (bNoZero && fOutNumber == 0.0)
1802 {
1803 sOutString.clear();
1804 return;
1805 }
1806 SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ));
1807 if (!pFormat)
1808 pFormat = GetFormatEntry(ZF_STANDARD);
1809 ChangeIntl(pFormat->GetLanguage());
1810 if ( bUseStarFormat )
1811 pFormat->SetStarFormatSupport( true );
1812 pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1813 if ( bUseStarFormat )
1814 pFormat->SetStarFormatSupport( false );
1815}
1816
1817bool SvNumberFormatter::GetPreviewString(const OUString& sFormatString,
1818 double fPreviewNumber,
1819 OUString& sOutString,
1820 const Color** ppColor,
1821 LanguageType eLnge,
1822 bool bUseStarFormat )
1823{
1824 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1825 if (sFormatString.isEmpty()) // no empty string
1826 {
1827 return false;
1828 }
1829 if (eLnge == LANGUAGE_DONTKNOW)
1830 {
1831 eLnge = IniLnge;
1832 }
1833 ChangeIntl(eLnge); // change locale if necessary
1834 eLnge = ActLnge;
1835 sal_Int32 nCheckPos = -1;
1836 OUString sTmpString = sFormatString;
1837 SvNumberformat aEntry(sTmpString,
1838 pFormatScanner.get(),
1839 pStringScanner.get(),
1840 nCheckPos,
1841 eLnge);
1842 if (nCheckPos == 0) // String ok
1843 {
1844 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
1845 sal_uInt32 nKey = ImpIsEntry(aEntry.GetFormatstring(),CLOffset, eLnge);
1846 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
1847 {
1848 GetOutputString(fPreviewNumber, nKey, sOutString, ppColor, bUseStarFormat);
1849 }
1850 else
1851 {
1852 if ( bUseStarFormat )
1853 {
1854 aEntry.SetStarFormatSupport( true );
1855 }
1856 aEntry.GetOutputString(fPreviewNumber, sOutString, ppColor);
1857 if ( bUseStarFormat )
1858 {
1859 aEntry.SetStarFormatSupport( false );
1860 }
1861 }
1862 return true;
1863 }
1864 else
1865 {
1866 return false;
1867 }
1868}
1869
1870bool SvNumberFormatter::GetPreviewStringGuess( const OUString& sFormatString,
1871 double fPreviewNumber,
1872 OUString& sOutString,
1873 const Color** ppColor,
1874 LanguageType eLnge )
1875{
1876 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1877 if (sFormatString.isEmpty()) // no empty string
1878 {
1879 return false;
1880 }
1881 if (eLnge == LANGUAGE_DONTKNOW)
1882 {
1883 eLnge = IniLnge;
1884 }
1885 ChangeIntl( eLnge );
1886 eLnge = ActLnge;
1887 bool bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1888
1889 OUString aFormatStringUpper( xCharClass->uppercase( sFormatString ) );
1890 sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1891 sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1892 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1893 {
1894 // Target format present
1895 GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1896 return true;
1897 }
1898
1899 std::optional<SvNumberformat> pEntry;
1900 sal_Int32 nCheckPos = -1;
1901 OUString sTmpString;
1902
1903 if ( bEnglish )
1904 {
1905 sTmpString = sFormatString;
1906 pEntry.emplace( sTmpString, pFormatScanner.get(),
1907 pStringScanner.get(), nCheckPos, eLnge );
1908 }
1909 else
1910 {
1911 nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1912 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1913 bool bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1914
1915 // Try English -> other or convert english to other
1916 LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1917 pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge, false, false);
1918 sTmpString = sFormatString;
1919 pEntry.emplace( sTmpString, pFormatScanner.get(),
1920 pStringScanner.get(), nCheckPos, eFormatLang );
1921 pFormatScanner->SetConvertMode( false );
1922 ChangeIntl( eLnge );
1923
1924 if ( !bEnglishFormat )
1925 {
1926 if ( nCheckPos != 0 || xTransliteration->isEqual( sFormatString,
1927 pEntry->GetFormatstring() ) )
1928 {
1929 // other Format
1930 // Force locale's keywords.
1932 sTmpString = sFormatString;
1933 pEntry.emplace( sTmpString, pFormatScanner.get(),
1934 pStringScanner.get(), nCheckPos, eLnge );
1935 }
1936 else
1937 {
1938 // verify english
1939 sal_Int32 nCheckPos2 = -1;
1940 // try other --> english
1941 eFormatLang = eLnge;
1942 pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US, false, false);
1943 sTmpString = sFormatString;
1944 SvNumberformat aEntry2( sTmpString, pFormatScanner.get(),
1945 pStringScanner.get(), nCheckPos2, eFormatLang );
1946 pFormatScanner->SetConvertMode( false );
1947 ChangeIntl( eLnge );
1948 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1949 aEntry2.GetFormatstring() ) )
1950 {
1951 // other Format
1952 // Force locale's keywords.
1954 sTmpString = sFormatString;
1955 pEntry.emplace( sTmpString, pFormatScanner.get(),
1956 pStringScanner.get(), nCheckPos, eLnge );
1957 }
1958 }
1959 }
1960 }
1961
1962 if (nCheckPos == 0) // String ok
1963 {
1964 ImpGenerateCL( eLnge ); // create new standard formats if necessary
1965 pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1966 return true;
1967 }
1968 return false;
1969}
1970
1971bool SvNumberFormatter::GetPreviewString( const OUString& sFormatString,
1972 const OUString& sPreviewString,
1973 OUString& sOutString,
1974 const Color** ppColor,
1975 LanguageType eLnge )
1976{
1977 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1978 if (sFormatString.isEmpty()) // no empty string
1979 {
1980 return false;
1981 }
1982 if (eLnge == LANGUAGE_DONTKNOW)
1983 {
1984 eLnge = IniLnge;
1985 }
1986 ChangeIntl(eLnge); // switch if needed
1987 eLnge = ActLnge;
1988 sal_Int32 nCheckPos = -1;
1989 OUString sTmpString = sFormatString;
1990 SvNumberformat aEntry( sTmpString,
1991 pFormatScanner.get(),
1992 pStringScanner.get(),
1993 nCheckPos,
1994 eLnge);
1995 if (nCheckPos == 0) // String ok
1996 {
1997 // May have to create standard formats for this locale.
1998 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1999 sal_uInt32 nKey = ImpIsEntry( aEntry.GetFormatstring(), CLOffset, eLnge);
2000 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
2001 {
2002 GetOutputString( sPreviewString, nKey, sOutString, ppColor);
2003 }
2004 else
2005 {
2006 // If the format is valid but not a text format and does not
2007 // include a text subformat, an empty string would result. Same as
2008 // in SvNumberFormatter::GetOutputString()
2009 if (aEntry.IsTextFormat() || aEntry.HasTextFormat())
2010 {
2011 aEntry.GetOutputString( sPreviewString, sOutString, ppColor);
2012 }
2013 else
2014 {
2015 *ppColor = nullptr;
2016 sOutString = sPreviewString;
2017 }
2018 }
2019 return true;
2020 }
2021 else
2022 {
2023 return false;
2024 }
2025}
2026
2027sal_uInt32 SvNumberFormatter::TestNewString(const OUString& sFormatString,
2028 LanguageType eLnge)
2029{
2030 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2031 if (sFormatString.isEmpty()) // no empty string
2032 {
2034 }
2035 if (eLnge == LANGUAGE_DONTKNOW)
2036 {
2037 eLnge = IniLnge;
2038 }
2039 ChangeIntl(eLnge); // change locale if necessary
2040 eLnge = ActLnge;
2041 sal_uInt32 nRes;
2042 sal_Int32 nCheckPos = -1;
2043 OUString sTmpString = sFormatString;
2044 SvNumberformat aEntry(sTmpString,
2045 pFormatScanner.get(),
2046 pStringScanner.get(),
2047 nCheckPos,
2048 eLnge);
2049 if (nCheckPos == 0) // String ok
2050 {
2051 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
2052 nRes = ImpIsEntry(aEntry.GetFormatstring(),CLOffset, eLnge);
2053 // already present?
2054 }
2055 else
2056 {
2058 }
2059 return nRes;
2060}
2061
2062SvNumberformat* SvNumberFormatter::ImpInsertFormat( const css::i18n::NumberFormatCode& rCode,
2063 sal_uInt32 nPos, bool bAfterChangingSystemCL,
2064 sal_Int16 nOrgIndex )
2065{
2066 SAL_WARN_IF( NF_INDEX_TABLE_RESERVED_START <= rCode.Index && rCode.Index < NF_INDEX_TABLE_ENTRIES,
2067 "svl.numbers", "i18npool locale '" << maLanguageTag.getBcp47() <<
2068 "' uses reserved formatIndex value " << rCode.Index << ", next free: " << NF_INDEX_TABLE_ENTRIES <<
2069 " Please see description in include/svl/zforlist.hxx at end of enum NfIndexTableOffset");
2070 assert( (rCode.Index < NF_INDEX_TABLE_RESERVED_START || NF_INDEX_TABLE_ENTRIES <= rCode.Index) &&
2071 "reserved formatIndex, see warning above");
2072
2073 OUString aCodeStr( rCode.Code );
2074 if ( rCode.Index < NF_INDEX_TABLE_RESERVED_START &&
2075 rCode.Usage == css::i18n::KNumberFormatUsage::CURRENCY &&
2076 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
2077 { // strip surrounding [$...] on automatic currency
2078 if ( aCodeStr.indexOf( "[$" ) >= 0)
2079 aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr );
2080 else
2081 {
2083 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
2084 {
2085 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index " +
2086 OUString::number( rCode.Index) +
2087 ":\n" +
2088 rCode.Code;
2090 }
2091 }
2092 }
2093 sal_Int32 nCheckPos = 0;
2094 std::unique_ptr<SvNumberformat> pFormat(new SvNumberformat(aCodeStr,
2095 pFormatScanner.get(),
2096 pStringScanner.get(),
2097 nCheckPos,
2098 ActLnge));
2099 if (nCheckPos != 0)
2100 {
2102 {
2103 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
2104 OUString::number( rCode.Index ) +
2105 "\n" +
2106 rCode.Code;
2108 }
2109 return nullptr;
2110 }
2111 if ( rCode.Index >= NF_INDEX_TABLE_RESERVED_START )
2112 {
2113 sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
2114 sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
2115 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
2116 {
2117 // If bAfterChangingSystemCL there will definitely be some dups,
2118 // don't cry then.
2119 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL)
2120 {
2121 // Test for duplicate indexes in locale data.
2122 switch ( nOrgIndex )
2123 {
2124 // These may be dups of integer versions for locales where
2125 // currencies have no decimals like Italian Lira.
2126 case NF_CURRENCY_1000DEC2 : // NF_CURRENCY_1000INT
2127 case NF_CURRENCY_1000DEC2_RED : // NF_CURRENCY_1000INT_RED
2128 case NF_CURRENCY_1000DEC2_DASHED : // NF_CURRENCY_1000INT_RED
2129 break;
2130 default:
2131 {
2132 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: dup format code, index "
2133 + OUString::number( rCode.Index )
2134 + "\n"
2135 + rCode.Code;
2137 }
2138 }
2139 }
2140 return nullptr;
2141 }
2142 else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2143 {
2145 {
2146 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: too many format codes, index "
2147 + OUString::number( rCode.Index )
2148 + "\n"
2149 + rCode.Code;
2151 }
2152 return nullptr;
2153 }
2154 }
2155 auto pFormat2 = pFormat.get();
2156 if ( !aFTable.emplace( nPos, std::move(pFormat) ).second )
2157 {
2159 {
2160 OUString aMsg = "ImpInsertFormat: can't insert number format key pos: "
2161 + OUString::number( nPos )
2162 + ", code index "
2163 + OUString::number( rCode.Index )
2164 + "\n"
2165 + rCode.Code;
2167 }
2168 else
2169 {
2170 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
2171 }
2172 return nullptr;
2173 }
2174 if ( rCode.Default )
2175 pFormat2->SetStandard();
2176 if ( !rCode.DefaultName.isEmpty() )
2177 pFormat2->SetComment( rCode.DefaultName );
2178 return pFormat2;
2179}
2180
2182 bool& bThousand,
2183 bool& IsRed,
2184 sal_uInt16& nPrecision,
2185 sal_uInt16& nLeadingCnt)
2186
2187{
2188 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2189 SvNumberformat* pFormat = GetFormatEntry( nFormat );
2190 if (pFormat)
2191 pFormat->GetFormatSpecialInfo(bThousand, IsRed,
2192 nPrecision, nLeadingCnt);
2193 else
2194 {
2195 bThousand = false;
2196 IsRed = false;
2197 nPrecision = pFormatScanner->GetStandardPrec();
2198 nLeadingCnt = 0;
2199 }
2200}
2201
2202sal_uInt16 SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
2203{
2204 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2205 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
2206 if ( pFormat )
2207 return pFormat->GetFormatPrecision();
2208 else
2209 return pFormatScanner->GetStandardPrec();
2210}
2211
2212sal_uInt16 SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat ) const
2213{
2214 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2215 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
2216 if ( pFormat )
2217 return pFormat->GetFormatIntegerDigits();
2218 else
2219 return 1;
2220}
2221
2222OUString SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
2223{
2224 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2225 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
2226 if (!pFormat)
2227 {
2228 return GetNumDecimalSep();
2229 }
2230 return GetLangDecimalSep( pFormat->GetLanguage());
2231}
2232
2234{
2235 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2236 if (nLang == ActLnge)
2237 {
2238 return GetNumDecimalSep();
2239 }
2240 OUString aRet;
2242 if (nLang == eSaveLang)
2243 {
2244 aRet = xLocaleData->getNumDecimalSep();
2245 }
2246 else
2247 {
2248 LanguageTag aSaveLocale( xLocaleData->getLanguageTag() );
2249 const_cast<SvNumberFormatter*>(this)->xLocaleData.changeLocale( LanguageTag( nLang));
2250 aRet = xLocaleData->getNumDecimalSep();
2251 const_cast<SvNumberFormatter*>(this)->xLocaleData.changeLocale( aSaveLocale );
2252 }
2253 return aRet;
2254}
2255
2256bool SvNumberFormatter::IsNatNum12( sal_uInt32 nFIndex ) const
2257{
2258 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2259 const SvNumberformat* pFormat = GetFormatEntry( nFIndex );
2260
2261 return pFormat && pFormat->GetNatNumModifierString().startsWith( "[NatNum12" );
2262}
2263
2264sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const OUString& rFormatString,
2265 bool& bThousand, bool& IsRed, sal_uInt16& nPrecision,
2266 sal_uInt16& nLeadingCnt, LanguageType eLnge )
2267
2268{
2269 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2270 if (eLnge == LANGUAGE_DONTKNOW)
2271 {
2272 eLnge = IniLnge;
2273 }
2274 ChangeIntl(eLnge); // change locale if necessary
2275 eLnge = ActLnge;
2276 OUString aTmpStr( rFormatString );
2277 sal_Int32 nCheckPos = 0;
2278 SvNumberformat aFormat( aTmpStr, pFormatScanner.get(),
2279 pStringScanner.get(), nCheckPos, eLnge );
2280 if ( nCheckPos == 0 )
2281 {
2282 aFormat.GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nLeadingCnt );
2283 }
2284 else
2285 {
2286 bThousand = false;
2287 IsRed = false;
2288 nPrecision = pFormatScanner->GetStandardPrec();
2289 nLeadingCnt = 0;
2290 }
2291 return nCheckPos;
2292}
2293
2294OUString SvNumberFormatter::GetCalcCellReturn( sal_uInt32 nFormat ) const
2295{
2296 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2297 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
2298 if (!pFormat)
2299 return "G";
2300
2301 OUString aStr;
2302 bool bAppendPrec = true;
2303 sal_uInt16 nPrec, nLeading;
2304 bool bThousand, bIsRed;
2305 pFormat->GetFormatSpecialInfo( bThousand, bIsRed, nPrec, nLeading );
2306
2307 switch (pFormat->GetMaskedType())
2308 {
2310 if (bThousand)
2311 aStr = ",";
2312 else
2313 aStr = "F";
2314 break;
2316 aStr = "C";
2317 break;
2319 aStr = "S";
2320 break;
2322 aStr = "P";
2323 break;
2324 default:
2325 {
2326 bAppendPrec = false;
2327 switch (GetIndexTableOffset( nFormat ))
2328 {
2330 case NF_DATE_SYS_DMMMYY:
2331 case NF_DATE_SYS_DDMMYY:
2336 case NF_DATE_DIN_DMMMMYYYY: aStr = "D1"; break;
2337 case NF_DATE_SYS_DDMMM: aStr = "D2"; break;
2338 case NF_DATE_SYS_MMYY: aStr = "D3"; break;
2342 aStr = "D4"; break;
2343 case NF_DATE_DIN_MMDD: aStr = "D5"; break;
2344 case NF_TIME_HHMMSSAMPM: aStr = "D6"; break;
2345 case NF_TIME_HHMMAMPM: aStr = "D7"; break;
2346 case NF_TIME_HHMMSS: aStr = "D8"; break;
2347 case NF_TIME_HHMM: aStr = "D9"; break;
2348 default: aStr = "G";
2349 }
2350 }
2351 }
2352
2353 if (bAppendPrec)
2354 aStr += OUString::number(nPrec);
2355
2356 if (pFormat->GetColor( 1 ))
2357 aStr += "-"; // negative color
2358
2359 /* FIXME: this probably should not match on literal strings and only be
2360 * performed on number or currency formats, but it is what Calc originally
2361 * implemented. */
2362 if (pFormat->GetFormatstring().indexOf('(') != -1)
2363 aStr += "()";
2364
2365 return aStr;
2366}
2367
2369 css::uno::Sequence< css::i18n::NumberFormatCode >& rSeq,
2370 const NfIndexTableOffset nTabOff )
2371{
2372 auto pSeq = std::find_if(std::cbegin(rSeq), std::cend(rSeq),
2373 [nTabOff](const css::i18n::NumberFormatCode& rCode) { return rCode.Index == nTabOff; });
2374 if (pSeq != std::cend(rSeq))
2375 return static_cast<sal_Int32>(std::distance(std::cbegin(rSeq), pSeq));
2377 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
2378 || nTabOff == NF_CURRENCY_1000INT_RED
2379 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
2380 { // currency entries with decimals might not exist, e.g. Italian Lira
2381 OUString aMsg = "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "
2382 + OUString::number( nTabOff );
2384 }
2385 if ( rSeq.hasElements() )
2386 {
2387 // look for a preset default
2388 pSeq = std::find_if(std::cbegin(rSeq), std::cend(rSeq),
2389 [](const css::i18n::NumberFormatCode& rCode) { return rCode.Default; });
2390 if (pSeq != std::cend(rSeq))
2391 return static_cast<sal_Int32>(std::distance(std::cbegin(rSeq), pSeq));
2392 // currencies are special, not all format codes must exist, but all
2393 // builtin number format key index positions must have a format assigned
2394 if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
2395 {
2396 // look for a format with decimals
2397 pSeq = std::find_if(std::cbegin(rSeq), std::cend(rSeq),
2398 [](const css::i18n::NumberFormatCode& rCode) { return rCode.Index == NF_CURRENCY_1000DEC2; });
2399 if (pSeq != std::cend(rSeq))
2400 return static_cast<sal_Int32>(std::distance(std::cbegin(rSeq), pSeq));
2401 // last resort: look for a format without decimals
2402 pSeq = std::find_if(std::cbegin(rSeq), std::cend(rSeq),
2403 [](const css::i18n::NumberFormatCode& rCode) { return rCode.Index == NF_CURRENCY_1000INT; });
2404 if (pSeq != std::cend(rSeq))
2405 return static_cast<sal_Int32>(std::distance(std::cbegin(rSeq), pSeq));
2406 }
2407 }
2408 else
2409 { // we need at least _some_ format
2410 rSeq = { css::i18n::NumberFormatCode() };
2411 rSeq.getArray()[0].Code = "0" + GetNumDecimalSep() + "############";
2412 }
2413 return 0;
2414}
2415
2416
2418 css::i18n::NumberFormatCode * pFormatArr,
2419 sal_Int32 nCnt )
2420{
2421 if ( !nCnt )
2422 return;
2424 {
2425 // check the locale data for correctness
2426 OUStringBuffer aMsg;
2427 sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
2428 nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
2429 for ( nElem = 0; nElem < nCnt; nElem++ )
2430 {
2431 switch ( pFormatArr[nElem].Type )
2432 {
2433 case i18n::KNumberFormatType::SHORT :
2434 nShort = nElem;
2435 break;
2436 case i18n::KNumberFormatType::MEDIUM :
2437 nMedium = nElem;
2438 break;
2439 case i18n::KNumberFormatType::LONG :
2440 nLong = nElem;
2441 break;
2442 default:
2443 aMsg.append("unknown type");
2444 }
2445 if ( pFormatArr[nElem].Default )
2446 {
2447 switch ( pFormatArr[nElem].Type )
2448 {
2449 case i18n::KNumberFormatType::SHORT :
2450 if ( nShortDef != -1 )
2451 aMsg.append("dupe short type default");
2452 nShortDef = nElem;
2453 break;
2454 case i18n::KNumberFormatType::MEDIUM :
2455 if ( nMediumDef != -1 )
2456 aMsg.append("dupe medium type default");
2457 nMediumDef = nElem;
2458 break;
2459 case i18n::KNumberFormatType::LONG :
2460 if ( nLongDef != -1 )
2461 aMsg.append("dupe long type default");
2462 nLongDef = nElem;
2463 break;
2464 }
2465 }
2466 if (!aMsg.isEmpty())
2467 {
2468 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2469 aMsg.append("\nXML locale data FormatElement formatindex: "
2470 + OUString::number(static_cast<sal_Int32>(pFormatArr[nElem].Index)));
2472 aMsg.setLength(0);
2473 }
2474 }
2475 if ( nShort != -1 && nShortDef == -1 )
2476 aMsg.append("no short type default ");
2477 if ( nMedium != -1 && nMediumDef == -1 )
2478 aMsg.append("no medium type default ");
2479 if ( nLong != -1 && nLongDef == -1 )
2480 aMsg.append("no long type default ");
2481 if (!aMsg.isEmpty())
2482 {
2483 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2484 aMsg.append("\nXML locale data FormatElement group of: ");
2486 xLocaleData->appendLocaleInfo(Concat2View(aMsg + pFormatArr[0].NameID)));
2487 aMsg.setLength(0);
2488 }
2489 }
2490 // find the default (medium preferred, then long) and reset all other defaults
2491 sal_Int32 nElem, nDef, nMedium;
2492 nDef = nMedium = -1;
2493 for ( nElem = 0; nElem < nCnt; nElem++ )
2494 {
2495 if ( pFormatArr[nElem].Default )
2496 {
2497 switch ( pFormatArr[nElem].Type )
2498 {
2499 case i18n::KNumberFormatType::MEDIUM :
2500 nDef = nMedium = nElem;
2501 break;
2502 case i18n::KNumberFormatType::LONG :
2503 if ( nMedium == -1 )
2504 nDef = nElem;
2505 [[fallthrough]];
2506 default:
2507 if ( nDef == -1 )
2508 nDef = nElem;
2509 pFormatArr[nElem].Default = false;
2510 }
2511 }
2512 }
2513 if ( nDef == -1 )
2514 nDef = 0;
2515 pFormatArr[nDef].Default = true;
2516}
2517
2519{
2520 auto it = aFTable.find( nKey);
2521 if (it != aFTable.end())
2522 return it->second.get();
2523 return nullptr;
2524}
2525
2527{
2528 return GetEntry( nKey);
2529}
2530
2531const SvNumberformat* SvNumberFormatter::GetEntry( sal_uInt32 nKey ) const
2532{
2533 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2534 auto it = aFTable.find( nKey);
2535 if (it != aFTable.end())
2536 return it->second.get();
2537 return nullptr;
2538}
2539
2540const SvNumberformat* SvNumberFormatter::GetSubstitutedEntry( sal_uInt32 nKey, sal_uInt32 & o_rNewKey ) const
2541{
2542 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2543 // A tad ugly, but GetStandardFormat() and GetFormatIndex() in
2544 // ImpSubstituteEntry() may have to add the LANGUAGE_SYSTEM formats if not
2545 // already present (which in practice most times they are).
2546 SvNumberFormatter* pThis = const_cast<SvNumberFormatter*>(this);
2547 return pThis->ImpSubstituteEntry( pThis->GetFormatEntry( nKey), &o_rNewKey);
2548}
2549
2551{
2552 if (!pFormat || !pFormat->IsSubstituted())
2553 return pFormat;
2554
2555 // XXX NOTE: substitution can not be done in GetFormatEntry() as otherwise
2556 // to be substituted formats would "vanish", i.e. from the number formatter
2557 // dialog or when exporting to Excel.
2558
2559 sal_uInt32 nKey;
2560 if (pFormat->IsSystemTimeFormat())
2561 /* TODO: should we have NF_TIME_SYSTEM for consistency? */
2563 else if (pFormat->IsSystemLongDateFormat())
2564 /* TODO: either that above, or have a long option for GetStandardFormat() */
2566 else
2567 return pFormat;
2568
2569 if (o_pRealKey)
2570 *o_pRealKey = nKey;
2571 auto it = aFTable.find( nKey);
2572 return it == aFTable.end() ? nullptr : it->second.get();
2573}
2574
2575void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditionalFormats )
2576{
2577 bool bOldConvertMode = pFormatScanner->GetConvertMode();
2578 if (bOldConvertMode)
2579 {
2580 pFormatScanner->SetConvertMode(false); // switch off for this function
2581 }
2582
2583 css::lang::Locale aLocale = GetLanguageTag().getLocale();
2584 css::uno::Reference< css::i18n::XNumberFormatCode > xNFC = i18n::NumberFormatMapper::create( m_xContext );
2585 sal_Int32 nIdx;
2586
2587 // Number
2588 uno::Sequence< i18n::NumberFormatCode > aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER, aLocale );
2589 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2590
2591 // General
2592 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2593 SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2594 CLOffset + ZF_STANDARD /* NF_NUMBER_STANDARD */ );
2595 if (pStdFormat)
2596 {
2597 // This is _the_ standard format.
2599 {
2601 appendLocaleInfo( u"SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2602 }
2603 pStdFormat->SetType( SvNumFormatType::NUMBER );
2604 pStdFormat->SetStandard();
2606 }
2607 else
2608 {
2610 {
2612 appendLocaleInfo( u"SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2613 }
2614 }
2615
2616 {
2617 // Boolean
2618 OUString aFormatCode = pFormatScanner->GetBooleanString();
2619 sal_Int32 nCheckPos = 0;
2620
2621 std::unique_ptr<SvNumberformat> pNewFormat(new SvNumberformat( aFormatCode, pFormatScanner.get(),
2622 pStringScanner.get(), nCheckPos, ActLnge ));
2623 pNewFormat->SetType(SvNumFormatType::LOGICAL);
2624 pNewFormat->SetStandard();
2625 if ( !aFTable.emplace(CLOffset + ZF_STANDARD_LOGICAL /* NF_BOOLEAN */,
2626 std::move(pNewFormat)).second )
2627 {
2628 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2629 }
2630
2631 // Text
2632 aFormatCode = "@";
2633 pNewFormat.reset(new SvNumberformat( aFormatCode, pFormatScanner.get(),
2634 pStringScanner.get(), nCheckPos, ActLnge ));
2635 pNewFormat->SetType(SvNumFormatType::TEXT);
2636 pNewFormat->SetStandard();
2637 if ( !aFTable.emplace( CLOffset + ZF_STANDARD_TEXT /* NF_TEXT */,
2638 std::move(pNewFormat)).second )
2639 {
2640 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2641 }
2642 }
2643
2644 // 0
2645 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2646 ImpInsertFormat( aFormatSeq[nIdx],
2647 CLOffset + ZF_STANDARD+1 /* NF_NUMBER_INT */ );
2648
2649 // 0.00
2650 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2651 ImpInsertFormat( aFormatSeq[nIdx],
2652 CLOffset + ZF_STANDARD+2 /* NF_NUMBER_DEC2 */ );
2653
2654 // #,##0
2655 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2656 ImpInsertFormat( aFormatSeq[nIdx],
2657 CLOffset + ZF_STANDARD+3 /* NF_NUMBER_1000INT */ );
2658
2659 // #,##0.00
2660 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2661 ImpInsertFormat( aFormatSeq[nIdx],
2662 CLOffset + ZF_STANDARD+4 /* NF_NUMBER_1000DEC2 */ );
2663
2664 // #.##0,00 System country/language dependent
2665 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2666 ImpInsertFormat( aFormatSeq[nIdx],
2667 CLOffset + ZF_STANDARD+5 /* NF_NUMBER_SYSTEM */ );
2668
2669
2670 // Percent number
2671 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER, aLocale );
2672 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2673
2674 // 0%
2675 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2676 ImpInsertFormat( aFormatSeq[nIdx],
2677 CLOffset + ZF_STANDARD_PERCENT /* NF_PERCENT_INT */ );
2678
2679 // 0.00%
2680 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2681 ImpInsertFormat( aFormatSeq[nIdx],
2682 CLOffset + ZF_STANDARD_PERCENT+1 /* NF_PERCENT_DEC2 */ );
2683
2684
2685 // Currency. NO default standard option! Default is determined of locale
2686 // data default currency and format is generated if needed.
2687 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY, aLocale );
2689 {
2690 // though no default desired here, test for correctness of locale data
2691 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2692 }
2693
2694 // #,##0
2695 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2696 // Just copy the format, to avoid COW on sequence after each possible reallocation
2697 auto aFormat = aFormatSeq[nIdx];
2698 aFormat.Default = false;
2699 ImpInsertFormat( aFormat,
2700 CLOffset + ZF_STANDARD_CURRENCY /* NF_CURRENCY_1000INT */ );
2701
2702 // #,##0.00
2703 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2704 aFormat = aFormatSeq[nIdx];
2705 aFormat.Default = false;
2706 ImpInsertFormat( aFormat,
2707 CLOffset + ZF_STANDARD_CURRENCY+1 /* NF_CURRENCY_1000DEC2 */ );
2708
2709 // #,##0 negative red
2710 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2711 aFormat = aFormatSeq[nIdx];
2712 aFormat.Default = false;
2713 ImpInsertFormat(aFormat,
2714 CLOffset + ZF_STANDARD_CURRENCY+2 /* NF_CURRENCY_1000INT_RED */ );
2715
2716 // #,##0.00 negative red
2717 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2718 aFormat = aFormatSeq[nIdx];
2719 aFormat.Default = false;
2720 ImpInsertFormat(aFormat,
2721 CLOffset + ZF_STANDARD_CURRENCY+3 /* NF_CURRENCY_1000DEC2_RED */ );
2722
2723 // #,##0.00 USD
2724 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2725 aFormat = aFormatSeq[nIdx];
2726 aFormat.Default = false;
2727 ImpInsertFormat( aFormat,
2728 CLOffset + ZF_STANDARD_CURRENCY+4 /* NF_CURRENCY_1000DEC2_CCC */ );
2729
2730 // #.##0,--
2732 aFormat = aFormatSeq[nIdx];
2733 aFormat.Default = false;
2734 ImpInsertFormat(aFormat,
2735 CLOffset + ZF_STANDARD_CURRENCY+5 /* NF_CURRENCY_1000DEC2_DASHED */ );
2736
2737
2738 // Date
2739 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::DATE, aLocale );
2740 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2741
2742 // DD.MM.YY System
2743 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2744 ImpInsertFormat( aFormatSeq[nIdx],
2745 CLOffset + ZF_STANDARD_DATE /* NF_DATE_SYSTEM_SHORT */ );
2746
2747 // NN DD.MMM YY
2748 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2749 ImpInsertFormat( aFormatSeq[nIdx],
2750 CLOffset + ZF_STANDARD_DATE+1 /* NF_DATE_DEF_NNDDMMMYY */ );
2751
2752 // DD.MM.YY def/System
2753 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2754 ImpInsertFormat( aFormatSeq[nIdx],
2755 CLOffset + ZF_STANDARD_DATE+2 /* NF_DATE_SYS_MMYY */ );
2756
2757 // DD MMM
2758 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2759 ImpInsertFormat( aFormatSeq[nIdx],
2760 CLOffset + ZF_STANDARD_DATE+3 /* NF_DATE_SYS_DDMMM */ );
2761
2762 // MMMM
2763 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2764 ImpInsertFormat( aFormatSeq[nIdx],
2765 CLOffset + ZF_STANDARD_DATE+4 /* NF_DATE_MMMM */ );
2766
2767 // QQ YY
2768 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2769 ImpInsertFormat( aFormatSeq[nIdx],
2770 CLOffset + ZF_STANDARD_DATE+5 /* NF_DATE_QQJJ */ );
2771
2772 // DD.MM.YYYY was DD.MM.[YY]YY
2773 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2774 ImpInsertFormat( aFormatSeq[nIdx],
2775 CLOffset + ZF_STANDARD_DATE+6 /* NF_DATE_SYS_DDMMYYYY */ );
2776
2777 // DD.MM.YY def/System
2778 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2779 ImpInsertFormat( aFormatSeq[nIdx],
2780 CLOffset + ZF_STANDARD_DATE+7 /* NF_DATE_SYS_DDMMYY */ );
2781
2782 // NNN, D. MMMM YYYY System
2783 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2784 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2785 ImpInsertFormat( aFormatSeq[nIdx],
2786 CLOffset + ZF_STANDARD_DATE+8 /* NF_DATE_SYSTEM_LONG */ );
2787
2788 // Hard coded but system (regional settings) delimiters dependent long date formats
2789
2790 // D. MMM YY def/System
2791 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2792 ImpInsertFormat( aFormatSeq[nIdx],
2793 CLOffset + ZF_STANDARD_DATE+9 /* NF_DATE_SYS_DMMMYY */ );
2794
2795 // D. MMM YYYY def/System
2796 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2797 ImpInsertFormat( aFormatSeq[nIdx],
2798 CLOffset + ZF_STANDARD_DATE_SYS_DMMMYYYY /* NF_DATE_SYS_DMMMYYYY */ );
2799
2800 // D. MMMM YYYY def/System
2801 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2802 ImpInsertFormat( aFormatSeq[nIdx],
2803 CLOffset + ZF_STANDARD_DATE_SYS_DMMMMYYYY /* NF_DATE_SYS_DMMMMYYYY */ );
2804
2805 // NN, D. MMM YY def/System
2806 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2807 ImpInsertFormat( aFormatSeq[nIdx],
2808 CLOffset + ZF_STANDARD_DATE_SYS_NNDMMMYY /* NF_DATE_SYS_NNDMMMYY */ );
2809
2810 // NN, D. MMMM YYYY def/System
2811 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2812 ImpInsertFormat( aFormatSeq[nIdx],
2813 CLOffset + ZF_STANDARD_DATE_SYS_NNDMMMMYYYY /* NF_DATE_SYS_NNDMMMMYYYY */ );
2814
2815 // NNN, D. MMMM YYYY def/System
2817 ImpInsertFormat( aFormatSeq[nIdx],
2818 CLOffset + ZF_STANDARD_DATE_SYS_NNNNDMMMMYYYY /* NF_DATE_SYS_NNNNDMMMMYYYY */ );
2819
2820 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2821
2822 // D. MMM. YYYY DIN/EN
2823 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2824 ImpInsertFormat( aFormatSeq[nIdx],
2825 CLOffset + ZF_STANDARD_DATE_DIN_DMMMYYYY /* NF_DATE_DIN_DMMMYYYY */ );
2826
2827 // D. MMMM YYYY DIN/EN
2828 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2829 ImpInsertFormat( aFormatSeq[nIdx],
2830 CLOffset + ZF_STANDARD_DATE_DIN_DMMMMYYYY /* NF_DATE_DIN_DMMMMYYYY */ );
2831
2832 // MM-DD DIN/EN
2833 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2834 ImpInsertFormat( aFormatSeq[nIdx],
2835 CLOffset + ZF_STANDARD_DATE_DIN_MMDD /* NF_DATE_DIN_MMDD */ );
2836
2837 // YY-MM-DD DIN/EN
2838 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2839 ImpInsertFormat( aFormatSeq[nIdx],
2840 CLOffset + ZF_STANDARD_DATE_DIN_YYMMDD /* NF_DATE_DIN_YYMMDD */ );
2841
2842 // YYYY-MM-DD DIN/EN/ISO
2843 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2844 ImpInsertFormat( aFormatSeq[nIdx],
2845 CLOffset + ZF_STANDARD_DATE_DIN_YYYYMMDD /* NF_DATE_DIN_YYYYMMDD */ );
2846
2847
2848 // Time
2849 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::TIME, aLocale );
2850 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2851
2852 // HH:MM
2853 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2854 ImpInsertFormat( aFormatSeq[nIdx],
2855 CLOffset + ZF_STANDARD_TIME /* NF_TIME_HHMM */ );
2856
2857 // HH:MM:SS
2858 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2859 ImpInsertFormat( aFormatSeq[nIdx],
2860 CLOffset + ZF_STANDARD_TIME+1 /* NF_TIME_HHMMSS */ );
2861
2862 // HH:MM AM/PM
2863 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2864 ImpInsertFormat( aFormatSeq[nIdx],
2865 CLOffset + ZF_STANDARD_TIME+2 /* NF_TIME_HHMMAMPM */ );
2866
2867 // HH:MM:SS AM/PM
2868 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2869 ImpInsertFormat( aFormatSeq[nIdx],
2870 CLOffset + ZF_STANDARD_TIME+3 /* NF_TIME_HHMMSSAMPM */ );
2871
2872 // [HH]:MM:SS
2873 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2874 ImpInsertFormat( aFormatSeq[nIdx],
2875 CLOffset + ZF_STANDARD_TIME+4 /* NF_TIME_HH_MMSS */ );
2876
2877 // MM:SS,00
2878 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2879 ImpInsertFormat( aFormatSeq[nIdx],
2880 CLOffset + ZF_STANDARD_TIME+5 /* NF_TIME_MMSS00 */ );
2881
2882 // [HH]:MM:SS,00
2883 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2884 ImpInsertFormat( aFormatSeq[nIdx],
2885 CLOffset + ZF_STANDARD_TIME+6 /* NF_TIME_HH_MMSS00 */ );
2886
2887
2888 // DateTime
2889 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME, aLocale );
2890 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2891
2892 // DD.MM.YY HH:MM System
2894 ImpInsertFormat( aFormatSeq[nIdx],
2895 CLOffset + ZF_STANDARD_DATETIME /* NF_DATETIME_SYSTEM_SHORT_HHMM */ );
2896
2897 // DD.MM.YYYY HH:MM:SS System
2899 ImpInsertFormat( aFormatSeq[nIdx],
2900 CLOffset + ZF_STANDARD_DATETIME+1 /* NF_DATETIME_SYS_DDMMYYYY_HHMMSS */ );
2901
2902 // DD.MM.YYYY HH:MM System
2904 ImpInsertFormat( aFormatSeq[nIdx],
2905 CLOffset + ZF_STANDARD_DATETIME+2 /* NF_DATETIME_SYS_DDMMYYYY_HHMM */ );
2906
2907 const NfKeywordTable & rKeyword = pFormatScanner->GetKeywords();
2908 i18n::NumberFormatCode aSingleFormatCode;
2909 aSingleFormatCode.Usage = i18n::KNumberFormatUsage::DATE_TIME;
2910
2911 // YYYY-MM-DD HH:MM:SS ISO (with blank instead of 'T')
2912 aSingleFormatCode.Code =
2913 rKeyword[NF_KEY_YYYY] + "-" +
2914 rKeyword[NF_KEY_MM] + "-" +
2915 rKeyword[NF_KEY_DD] + " " +
2916 rKeyword[NF_KEY_HH] + ":" +
2917 rKeyword[NF_KEY_MMI] + ":" +
2918 rKeyword[NF_KEY_SS];
2919 SvNumberformat* pFormat = ImpInsertFormat( aSingleFormatCode,
2920 CLOffset + ZF_STANDARD_DATETIME+3 /* NF_DATETIME_ISO_YYYYMMDD_HHMMSS */ );
2921 assert(pFormat);
2922
2923 // YYYY-MM-DD HH:MM:SS,000 ISO (with blank instead of 'T') and
2924 // milliseconds and locale's time decimal separator
2925 aSingleFormatCode.Code =
2926 rKeyword[NF_KEY_YYYY] + "-" +
2927 rKeyword[NF_KEY_MM] + "-" +
2928 rKeyword[NF_KEY_DD] + " " +
2929 rKeyword[NF_KEY_HH] + ":" +
2930 rKeyword[NF_KEY_MMI] + ":" +
2931 rKeyword[NF_KEY_SS] + GetLocaleData()->getTime100SecSep() +
2932 "000";
2933 pFormat = ImpInsertFormat( aSingleFormatCode,
2934 CLOffset + ZF_STANDARD_DATETIME+4 /* NF_DATETIME_ISO_YYYYMMDD_HHMMSS000 */ );
2935 assert(pFormat);
2936
2937 // YYYY-MM-DD"T"HH:MM:SS ISO
2938 aSingleFormatCode.Code =
2939 rKeyword[NF_KEY_YYYY] + "-" +
2940 rKeyword[NF_KEY_MM] + "-" +
2941 rKeyword[NF_KEY_DD] + "\"T\"" +
2942 rKeyword[NF_KEY_HH] + ":" +
2943 rKeyword[NF_KEY_MMI] + ":" +
2944 rKeyword[NF_KEY_SS];
2945 pFormat = ImpInsertFormat( aSingleFormatCode,
2946 CLOffset + ZF_STANDARD_DATETIME+5 /* NF_DATETIME_ISO_YYYYMMDDTHHMMSS */ );
2947 assert(pFormat);
2948 pFormat->SetComment("ISO 8601"); // not to be localized
2949
2950 // YYYY-MM-DD"T"HH:MM:SS,000 ISO with milliseconds and ',' or '.' decimal separator
2951 aSingleFormatCode.Code =
2952 rKeyword[NF_KEY_YYYY] + "-" +
2953 rKeyword[NF_KEY_MM] + "-" +
2954 rKeyword[NF_KEY_DD] + "\"T\"" +
2955 rKeyword[NF_KEY_HH] + ":" +
2956 rKeyword[NF_KEY_MMI] + ":" +
2957 rKeyword[NF_KEY_SS] + (GetLocaleData()->getTime100SecSep() == "." ? "." : ",") +
2958 "000";
2959 pFormat = ImpInsertFormat( aSingleFormatCode,
2960 CLOffset + ZF_STANDARD_DATETIME+6 /* NF_DATETIME_ISO_YYYYMMDDTHHMMSS000 */ );
2961 assert(pFormat);
2962 pFormat->SetComment("ISO 8601"); // not to be localized
2963
2964
2965 // Scientific number
2966 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER, aLocale );
2967 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2968
2969 // 0.00E+000
2970 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2971 ImpInsertFormat( aFormatSeq[nIdx],
2972 CLOffset + ZF_STANDARD_SCIENTIFIC /* NF_SCIENTIFIC_000E000 */ );
2973
2974 // 0.00E+00
2975 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2976 ImpInsertFormat( aFormatSeq[nIdx],
2977 CLOffset + ZF_STANDARD_SCIENTIFIC+1 /* NF_SCIENTIFIC_000E00 */ );
2978
2979
2980 // Fraction number (no default option)
2981 aSingleFormatCode.Usage = i18n::KNumberFormatUsage::FRACTION_NUMBER;
2982
2983 // # ?/?
2984 aSingleFormatCode.Code = "# ?/?";
2985 ImpInsertFormat( aSingleFormatCode,
2986 CLOffset + ZF_STANDARD_FRACTION /* NF_FRACTION_1D */ );
2987
2988 // # ??/??
2990 aSingleFormatCode.Code = "# ?\?/?\?";
2991 ImpInsertFormat( aSingleFormatCode,
2992 CLOffset + ZF_STANDARD_FRACTION+1 /* NF_FRACTION_2D */ );
2993
2994 // # ???/???
2996 aSingleFormatCode.Code = "# ?\?\?/?\?\?";
2997 ImpInsertFormat( aSingleFormatCode,
2998 CLOffset + ZF_STANDARD_FRACTION+2 /* NF_FRACTION_3D */ );
2999
3000 // # ?/2
3001 aSingleFormatCode.Code = "# ?/2";
3002 ImpInsertFormat( aSingleFormatCode,
3003 CLOffset + ZF_STANDARD_FRACTION+3 /* NF_FRACTION_2 */ );
3004
3005 // # ?/4
3006 aSingleFormatCode.Code = "# ?/4";
3007 ImpInsertFormat( aSingleFormatCode,
3008 CLOffset + ZF_STANDARD_FRACTION+4 /* NF_FRACTION_4 */ );
3009
3010 // # ?/8
3011 aSingleFormatCode.Code = "# ?/8";
3012 ImpInsertFormat( aSingleFormatCode,
3013 CLOffset + ZF_STANDARD_FRACTION+5 /* NF_FRACTION_8 */ );
3014
3015 // # ??/16
3016 aSingleFormatCode.Code = "# ?\?/16";
3017 ImpInsertFormat( aSingleFormatCode,
3018 CLOffset + ZF_STANDARD_FRACTION+6 /* NF_FRACTION_16 */ );
3019
3020 // # ??/10
3021 aSingleFormatCode.Code = "# ?\?/10";
3022 ImpInsertFormat( aSingleFormatCode,
3023 CLOffset + ZF_STANDARD_FRACTION+7 /* NF_FRACTION_10 */ );
3024
3025 // # ??/100
3026 aSingleFormatCode.Code = "# ?\?/100";
3027 ImpInsertFormat( aSingleFormatCode,
3028 CLOffset + ZF_STANDARD_FRACTION+8 /* NF_FRACTION_100 */ );
3029
3030
3031 // Week of year
3032 aSingleFormatCode.Code = rKeyword[NF_KEY_WW];
3033 ImpInsertFormat( aSingleFormatCode,
3034 CLOffset + ZF_STANDARD_DATE_WW /* NF_DATE_WW */ );
3035
3036 // Now all additional format codes provided by I18N, but only if not
3037 // changing SystemCL, then they are appended last after user defined.
3038 if ( !bNoAdditionalFormats )
3039 {
3040 ImpGenerateAdditionalFormats( CLOffset, xNFC, false );
3041 }
3042 if (bOldConvertMode)
3043 {
3044 pFormatScanner->SetConvertMode(true);
3045 }
3046}
3047
3048
3050 css::uno::Reference< css::i18n::XNumberFormatCode > const & rNumberFormatCode,
3051 bool bAfterChangingSystemCL )
3052{
3053 SvNumberformat* pStdFormat = GetFormatEntry( CLOffset + ZF_STANDARD );
3054 if ( !pStdFormat )
3055 {
3056 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
3057 return ;
3058 }
3059 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
3060 css::lang::Locale aLocale = GetLanguageTag().getLocale();
3061
3062 // All currencies, this time with [$...] which was stripped in
3063 // ImpGenerateFormats for old "automatic" currency formats.
3064 uno::Sequence< i18n::NumberFormatCode > aFormatSeq = rNumberFormatCode->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY, aLocale );
3065 sal_Int32 nCodes = aFormatSeq.getLength();
3066 auto aNonConstRange = asNonConstRange(aFormatSeq);
3067 ImpAdjustFormatCodeDefault( aNonConstRange.begin(), nCodes);
3068 for ( i18n::NumberFormatCode& rFormat : aNonConstRange )
3069 {
3070 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
3071 {
3072 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
3073 break; // for
3074 }
3075 if ( rFormat.Index < NF_INDEX_TABLE_RESERVED_START &&
3076 rFormat.Index != NF_CURRENCY_1000DEC2_CCC )
3077 { // Insert only if not already inserted, but internal index must be
3078 // above so ImpInsertFormat can distinguish it.
3079 sal_Int16 nOrgIndex = rFormat.Index;
3080 rFormat.Index = sal::static_int_cast< sal_Int16 >(
3081 rFormat.Index + nCodes + NF_INDEX_TABLE_ENTRIES);
3083 bool bDefault = rFormat.Default;
3084 rFormat.Default = false;
3085 if ( SvNumberformat* pNewFormat = ImpInsertFormat( rFormat, nPos+1,
3086 bAfterChangingSystemCL, nOrgIndex ) )
3087 {
3088 pNewFormat->SetAdditionalBuiltin();
3089 nPos++;
3090 }
3091 rFormat.Index = nOrgIndex;
3092 rFormat.Default = bDefault;
3093 }
3094 }
3095
3096 // All additional format codes provided by I18N that are not old standard
3097 // index. Additional formats may define defaults, currently there is no
3098 // check if more than one default of a usage/type combination is provided,
3099 // like it is done for usage groups with ImpAdjustFormatCodeDefault().
3100 // There is no harm though, on first invocation ImpGetDefaultFormat() will
3101 // use the first default encountered.
3102 aFormatSeq = rNumberFormatCode->getAllFormatCodes( aLocale );
3103 for ( const auto& rFormat : std::as_const(aFormatSeq) )
3104 {
3105 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
3106 {
3107 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
3108 break; // for
3109 }
3110 if ( rFormat.Index >= NF_INDEX_TABLE_RESERVED_START )
3111 {
3112 if ( SvNumberformat* pNewFormat = ImpInsertFormat( rFormat, nPos+1,
3113 bAfterChangingSystemCL ) )
3114 {
3115 pNewFormat->SetAdditionalBuiltin();
3116 nPos++;
3117 }
3118 }
3119 }
3120
3121 pStdFormat->SetLastInsertKey( static_cast<sal_uInt16>(nPos - CLOffset), SvNumberformat::FormatterPrivateAccess() );
3122}
3123
3124
3125sal_Int32 SvNumberFormatter::ImpPosToken ( const OUStringBuffer & sFormat, sal_Unicode token, sal_Int32 nStartPos /* = 0*/ ) const
3126{
3127 sal_Int32 nLength = sFormat.getLength();
3128 for ( sal_Int32 i=nStartPos; i<nLength && i>=0 ; i++ )
3129 {
3130 switch(sFormat[i])
3131 {
3132 case '\"' : // skip text
3133 i = sFormat.indexOf('\"',i+1);
3134 break;
3135 case '[' : // skip condition
3136 i = sFormat.indexOf(']',i+1);
3137 break;
3138 case '\\' : // skip escaped character
3139 i++;
3140 break;
3141 case ';' :
3142 if (token == ';')
3143 return i;
3144 break;
3145 case 'e' :
3146 case 'E' :
3147 if (token == 'E')
3148 return i; // if 'E' is outside "" and [] it must be the 'E' exponent
3149 break;
3150 default : break;
3151 }
3152 if ( i<0 )
3153 i--;
3154 }
3155 return -2;
3156}
3157
3158OUString SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex,
3159 LanguageType eLnge,
3160 bool bThousand,
3161 bool IsRed,
3162 sal_uInt16 nPrecision,
3163 sal_uInt16 nLeadingZeros)
3164{
3165 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3166 if (eLnge == LANGUAGE_DONTKNOW)
3167 {
3168 eLnge = IniLnge;
3169 }
3170
3171 const SvNumberformat* pFormat = GetFormatEntry( nIndex );
3172 const SvNumFormatType eType = (pFormat ? pFormat->GetMaskedType() : SvNumFormatType::UNDEFINED);
3173
3174 ImpGenerateCL(eLnge); // create new standard formats if necessary
3175
3177 // always group of 3 for Engineering notation
3178 const sal_Int32 nDigitsInFirstGroup = ( bThousand && (eType == SvNumFormatType::SCIENTIFIC) ) ? 3 : aGrouping.get();
3179 const OUString& rThSep = GetNumThousandSep();
3180
3181 OUStringBuffer sString;
3183
3185 {
3186 assert(pFormat && "with !pFormat eType can only be SvNumFormatType::UNDEFINED");
3187 sString = pFormat->GetFormatStringForTimePrecision( nPrecision );
3188 }
3189 else if (nLeadingZeros == 0)
3190 {
3191 if (!bThousand)
3192 sString.append('#');
3193 else
3194 {
3196 { // for scientific, bThousand is used for Engineering notation
3197 sString.append("###");
3198 }
3199 else
3200 {
3201 sString.append("#" + rThSep);
3202 padToLength(sString, sString.getLength() + nDigitsInFirstGroup, '#');
3203 }
3204 }
3205 }
3206 else
3207 {
3208 for (sal_uInt16 i = 0; i < nLeadingZeros; i++)
3209 {
3210 if (bThousand && i > 0 && i == aGrouping.getPos())
3211 {
3212 sString.insert(0, rThSep);
3213 aGrouping.advance();
3214 }
3215 sString.insert(0, '0');
3216 }
3217 if ( bThousand )
3218 {
3219 sal_Int32 nDigits = (eType == SvNumFormatType::SCIENTIFIC) ? 3*((nLeadingZeros-1)/3 + 1) : nDigitsInFirstGroup + 1;
3220 for (sal_Int32 i = nLeadingZeros; i < nDigits; i++)
3221 {
3222 if ( i % nDigitsInFirstGroup == 0 )
3223 sString.insert(0, rThSep);
3224 sString.insert(0, '#');
3225 }
3226 }
3227 }
3228 if (nPrecision > 0 && eType != SvNumFormatType::FRACTION && !( eType & SvNumFormatType::TIME ) )
3229 {
3230 sString.append(GetNumDecimalSep());
3231 padToLength(sString, sString.getLength() + nPrecision, '0');
3232 }
3233
3234 // Native Number
3235 const OUString sPosNatNumModifier = pFormat ? pFormat->GetNatNumModifierString( 0 ) : "";
3236 const OUString sNegNatNumModifier = pFormat ?
3237 // if a negative format already exists, use its NatNum modifier
3238 // else use NatNum modifier of positive format
3239 ( pFormat->GetNumForString( 1, 0 ) ? pFormat->GetNatNumModifierString( 1 ) : sPosNatNumModifier )
3240 : "";
3241
3243 {
3244 sString.append( pFormat->GetPercentString() );
3245 }
3247 {
3248 OUStringBuffer sOldFormatString(pFormat->GetFormatstring());
3249 sal_Int32 nIndexE = ImpPosToken( sOldFormatString, 'E' );
3250 if (nIndexE > -1)
3251 {
3252 sal_Int32 nIndexSep = ImpPosToken( sOldFormatString, ';', nIndexE );
3253 if (nIndexSep > nIndexE)
3254 sString.append( sOldFormatString.subView(nIndexE, nIndexSep - nIndexE) );
3255 else
3256 sString.append( sOldFormatString.subView(nIndexE) );
3257 }
3258 }
3259 else if (eType == SvNumFormatType::CURRENCY)
3260 {
3261 OUStringBuffer sNegStr(sString);
3262 OUString aCurr;
3263 const NfCurrencyEntry* pEntry;
3264 bool bBank;
3265 bool isPosNatNum12 = sPosNatNumModifier.startsWith( "[NatNum12" );
3266 bool isNegNatNum12 = sNegNatNumModifier.startsWith( "[NatNum12" );
3267 if ( !isPosNatNum12 || !isNegNatNum12 )
3268 {
3269 if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
3270 {
3271 if ( pEntry )
3272 {
3273 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
3275 pEntry->GetPositiveFormat(), bBank );
3276 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
3278 pEntry->GetNegativeFormat(), bBank );
3279 if ( !isPosNatNum12 )
3280 pEntry->CompletePositiveFormatString( sString, bBank, nPosiForm );
3281 if ( !isNegNatNum12 )
3282 pEntry->CompleteNegativeFormatString( sNegStr, bBank, nNegaForm );
3283 }
3284 else
3285 { // assume currency abbreviation (AKA banking symbol), not symbol
3286 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
3289 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
3292 if ( !isPosNatNum12 )
3293 NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr, nPosiForm );
3294 if ( !isNegNatNum12 )
3295 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr, nNegaForm );
3296 }
3297 }
3298 else
3299 { // "automatic" old style
3300 OUString aSymbol, aAbbrev;
3301 GetCompatibilityCurrency( aSymbol, aAbbrev );
3302 if ( !isPosNatNum12 )
3303 NfCurrencyEntry::CompletePositiveFormatString( sString,
3304 aSymbol, xLocaleData->getCurrPositiveFormat() );
3305 if ( !isNegNatNum12 )
3306 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
3307 aSymbol, xLocaleData->getCurrNegativeFormat() );
3308 }
3309 }
3310 sString.append( ';' );
3311 if (IsRed)
3312 {
3313 sString.append("[" +pFormatScanner->GetRedString() + "]");
3314 }
3315 sString.append( sNegNatNumModifier );
3316 if ( isNegNatNum12 )
3317 {
3318 sString.append( '-' );
3319 }
3320 sString.append(sNegStr);
3321 }
3322 else if (eType == SvNumFormatType::FRACTION)
3323 {
3324 OUString aIntegerFractionDelimiterString = pFormat->GetIntegerFractionDelimiterString( 0 );
3325 if ( aIntegerFractionDelimiterString == " " )
3326 sString.append( aIntegerFractionDelimiterString );
3327 else
3328 {
3329 sString.append( "\"" + aIntegerFractionDelimiterString + "\"" );
3330 }
3331 sString.append( pFormat->GetNumeratorString( 0 )
3332 + "/" );
3333 if ( nPrecision > 0 )
3334 padToLength(sString, sString.getLength() + nPrecision, '?');
3335 else
3336 sString.append( '#' );
3337 }
3339 {
3340 bool insertBrackets = false;
3342 {
3343 insertBrackets = pFormat->IsNegativeInBracket();
3344 }
3345 if (IsRed || insertBrackets)
3346 {
3347 OUStringBuffer sTmpStr(sString);
3348
3349 if (pFormat && pFormat->HasPositiveBracketPlaceholder())
3350 {
3351 sTmpStr.append("_)");
3352 }
3353 sTmpStr.append(';');
3354
3355 if (IsRed)
3356 {
3357 sTmpStr.append("[" + pFormatScanner->GetRedString() + "]");
3358 }
3359 sTmpStr.append( sNegNatNumModifier );
3360
3361 if (insertBrackets)
3362 {
3363 sTmpStr.append("(" + sString + ")");
3364 }
3365 else
3366 {
3367 sTmpStr.append("-" + sString);
3368 }
3369 sString = sTmpStr;
3370 }
3371 }
3372 sString.insert( 0, sPosNatNumModifier );
3373 return sString.makeStringAndClear();
3374}
3375
3376bool SvNumberFormatter::IsUserDefined(sal_uInt32 F_Index) const
3377{
3378 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3379 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
3380
3381 return pFormat && (pFormat->GetType() & SvNumFormatType::DEFINED);
3382}
3383
3384bool SvNumberFormatter::IsUserDefined(std::u16string_view sStr,
3385 LanguageType eLnge)
3386{
3387 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3388 if (eLnge == LANGUAGE_DONTKNOW)
3389 {
3390 eLnge = IniLnge;
3391 }
3392 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3393 eLnge = ActLnge;
3394
3395 sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
3396 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
3397 {
3398 return true;
3399 }
3400 SvNumberformat* pEntry = GetFormatEntry( nKey );
3401 return pEntry && (pEntry->GetType() & SvNumFormatType::DEFINED);
3402}
3403
3404sal_uInt32 SvNumberFormatter::GetEntryKey(std::u16string_view sStr,
3405 LanguageType eLnge)
3406{
3407 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3408 if (eLnge == LANGUAGE_DONTKNOW)
3409 {
3410 eLnge = IniLnge;
3411 }
3412 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3413 return ImpIsEntry(sStr, CLOffset, eLnge);
3414}
3415
3417{
3418 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3419 if (eLnge == LANGUAGE_DONTKNOW)
3420 {
3421 eLnge = IniLnge;
3422 }
3424}
3425
3427{
3428 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3430 const SvNumberformat* pFormat = GetFormatEntry( nFIndex );
3431 if (!pFormat)
3432 {
3434 }
3435 else
3436 {
3437 eType = pFormat->GetMaskedType();
3439 {
3441 }
3442 }
3443 return eType;
3444}
3445
3447{
3448 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3449 if ( pMergeTable )
3450 {
3451 pMergeTable->clear();
3452 }
3453}
3454
3456{
3457 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3458 if ( pMergeTable )
3459 {
3461 }
3462 else
3463 {
3465 }
3466
3467 sal_uInt32 nCLOffset = 0;
3468 sal_uInt32 nOldKey, nOffset, nNewKey;
3469
3470 for (const auto& rEntry : rTable.aFTable)
3471 {
3472 SvNumberformat* pFormat = rEntry.second.get();
3473 nOldKey = rEntry.first;
3474 nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3475 if (nOffset == 0) // 1st format of CL
3476 {
3477 nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
3478 }
3479 if (nOffset <= SV_MAX_COUNT_STANDARD_FORMATS) // Std.form.
3480 {
3481 nNewKey = nCLOffset + nOffset;
3482 if (aFTable.find( nNewKey) == aFTable.end()) // not already present
3483 {
3484 std::unique_ptr<SvNumberformat> pNewEntry(new SvNumberformat( *pFormat, *pFormatScanner ));
3485 if (!aFTable.emplace( nNewKey, std::move(pNewEntry)).second)
3486 {
3487 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3488 }
3489 }
3490 if (nNewKey != nOldKey) // new index
3491 {
3492 (*pMergeTable)[nOldKey] = nNewKey;
3493 }
3494 }
3495 else // user defined
3496 {
3497 std::unique_ptr<SvNumberformat> pNewEntry(new SvNumberformat( *pFormat, *pFormatScanner ));
3498 nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
3499 nCLOffset,
3500 pFormat->GetLanguage());
3501 if (nNewKey == NUMBERFORMAT_ENTRY_NOT_FOUND) // only if not present yet
3502 {
3503 SvNumberformat* pStdFormat = GetFormatEntry(nCLOffset + ZF_STANDARD);
3504 sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
3505 nNewKey = nPos+1;
3506 if (nNewKey - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
3507 {
3508 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3509 }
3510 else if (!aFTable.emplace( nNewKey, std::move(pNewEntry)).second)
3511 {
3512 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3513 }
3514 else
3515 {
3516 pStdFormat->SetLastInsertKey(static_cast<sal_uInt16>(nNewKey - nCLOffset),
3518 }
3519 }
3520 if (nNewKey != nOldKey) // new index
3521 {
3522 (*pMergeTable)[nOldKey] = nNewKey;
3523 }
3524 }
3525 }
3526 return pMergeTable.get();
3527}
3528
3529
3531{
3532 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3533 if (!HasMergeFormatTable())
3534 {
3536 }
3538 for (const auto& rEntry : *pMergeTable)
3539 {
3540 sal_uInt32 nOldKey = rEntry.first;
3541 aMap[ nOldKey ] = rEntry.second;
3542 }
3544 return aMap;
3545}
3546
3547
3549 LanguageType eLnge )
3550{
3551 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3552 if ( eLnge == LANGUAGE_DONTKNOW )
3553 {
3554 eLnge = IniLnge;
3555 }
3556 if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
3557 {
3558 return nFormat; // it stays as it is
3559 }
3560 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3561 if ( nOffset > SV_MAX_COUNT_STANDARD_FORMATS )
3562 {
3563 return nFormat; // not a built-in format
3564 }
3565 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3566 return nCLOffset + nOffset;
3567}
3568
3569
3571 LanguageType eLnge )
3572{
3573 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3574 if (nTabOff >= NF_INDEX_TABLE_ENTRIES)
3576
3577 if (eLnge == LANGUAGE_DONTKNOW)
3578 eLnge = IniLnge;
3579
3582
3583 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3584
3585 return nCLOffset + indexTable[nTabOff];
3586}
3587
3588
3590{
3591 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3592 if ( nOffset > SV_MAX_COUNT_STANDARD_FORMATS )
3593 {
3594 return NF_INDEX_TABLE_ENTRIES; // not a built-in format
3595 }
3596
3597 for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
3598 {
3599 if (indexTable[j] == nOffset)
3600 return static_cast<NfIndexTableOffset>(j);
3601 }
3602 return NF_INDEX_TABLE_ENTRIES; // bad luck
3603}
3604
3606{
3607 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3608 eEvalDateFormat = eEDF;
3609}
3610
3612{
3613 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3614 return eEvalDateFormat;
3615}
3616
3617void SvNumberFormatter::SetYear2000( sal_uInt16 nVal )
3618{
3619 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3620 pStringScanner->SetYear2000( nVal );
3621}
3622
3623
3625{
3626 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3627 return pStringScanner->GetYear2000();
3628}
3629
3630
3631sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear ) const
3632{
3633 if ( nYear < 100 )
3635 pStringScanner->GetYear2000() );
3636 return nYear;
3637}
3638
3639
3640// static
3642{
3644 return officecfg::Office::Common::DateFormat::TwoDigitYear::get();
3645 return 1930;
3646}
3647
3648// static
3650{
3651 SAL_INFO("svl", "Resetting the currency table.");
3652
3655
3656 GetFormatterRegistry().ConfigurationChanged(nullptr, ConfigurationHints::Locale | ConfigurationHints::Currency | ConfigurationHints::DatePatterns);
3657}
3658
3659// static
3661{
3662 while ( !bCurrencyTableInitialized )
3664 return theCurrencyTable();
3665}
3666
3667
3668// static
3670{
3671 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3672 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3673 return nSystemCurrencyPosition ? &rTable[nSystemCurrencyPosition] : nullptr;
3674}
3675
3676
3677// static
3679{
3680 if ( eLang == LANGUAGE_SYSTEM )
3681 {
3682 const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3683 return pCurr ? *pCurr : GetTheCurrencyTable()[0];
3684 }
3685 else
3686 {
3687 eLang = MsLangId::getRealLanguage( eLang );
3688 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3689 sal_uInt16 nCount = rTable.size();
3690 for ( sal_uInt16 j = 0; j < nCount; j++ )
3691 {
3692 if ( rTable[j].GetLanguage() == eLang )
3693 return rTable[j];
3694 }
3695 return rTable[0];
3696 }
3697}
3698
3699
3700// static
3701const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(std::u16string_view rAbbrev, LanguageType eLang )
3702{
3703 eLang = MsLangId::getRealLanguage( eLang );
3704 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3705 sal_uInt16 nCount = rTable.size();
3706 for ( sal_uInt16 j = 0; j < nCount; j++ )
3707 {
3708 if ( rTable[j].GetLanguage() == eLang &&
3709 rTable[j].GetBankSymbol() == rAbbrev )
3710 {
3711 return &rTable[j];
3712 }
3713 }
3714 return nullptr;
3715}
3716
3717
3718// static
3719const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( std::u16string_view rSymbol,
3720 std::u16string_view rAbbrev )
3721{
3722 GetTheCurrencyTable(); // just for initialization
3723 const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable();
3724 sal_uInt16 nCount = rTable.size();
3725 for ( sal_uInt16 j = 0; j < nCount; j++ )
3726 {
3727 if ( rTable[j].GetSymbol() == rSymbol &&
3728 rTable[j].GetBankSymbol() == rAbbrev )
3729 {
3730 return &rTable[j];
3731 }
3732 }
3733 return nullptr;
3734}
3735
3736
3737// static
3739{
3740 OUString aAbbrev;
3743 SetDefaultSystemCurrency( aAbbrev, eLang );
3744}
3745
3746
3747// static
3748void SvNumberFormatter::SetDefaultSystemCurrency( std::u16string_view rAbbrev, LanguageType eLang )
3749{
3750 ::osl::MutexGuard aGuard( GetGlobalMutex() );
3751 if ( eLang == LANGUAGE_SYSTEM )
3752 {
3754 }
3755 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3756 sal_uInt16 nCount = rTable.size();
3757 if ( !rAbbrev.empty() )
3758 {
3759 for ( sal_uInt16 j = 0; j < nCount; j++ )
3760 {
3761 if ( rTable[j].GetLanguage() == eLang && rTable[j].GetBankSymbol() == rAbbrev )
3762 {
3764 return ;
3765 }
3766 }
3767 }
3768 else
3769 {
3770 for ( sal_uInt16 j = 0; j < nCount; j++ )
3771 {
3772 if ( rTable[j].GetLanguage() == eLang )
3773 {
3775 return ;
3776 }
3777 }
3778 }
3779 nSystemCurrencyPosition = 0; // not found => simple SYSTEM
3780}
3781
3782
3784{
3786}
3787
3788
3790{
3791 pStringScanner->InvalidateDateAcceptancePatterns();
3792}
3793
3794
3796{
3798 {
3799 sal_Int32 nCheck;
3801 NfWSStringsDtor aCurrList;
3802 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3804 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency System standard format?!?" );
3805 // if already loaded or user defined nDefaultSystemCurrencyFormat
3806 // will be set to the right value
3807 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3809 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3811 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3812 }
3814}
3815
3816
3818{
3819 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3820 DefaultFormatKeysMap::const_iterator it = aDefaultFormatKeys.find( CLOffset + ZF_STANDARD_CURRENCY );
3821 sal_uInt32 nDefaultCurrencyFormat = (it != aDefaultFormatKeys.end() ?
3822 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
3823 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3824 {
3825 // look for a defined standard
3826 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3827 sal_uInt32 nKey(0);
3828 auto it2 = aFTable.lower_bound( CLOffset );
3829 while ( it2 != aFTable.end() && (nKey = it2->first) >= CLOffset && nKey < nStopKey )
3830 {
3831 const SvNumberformat* pEntry = it2->second.get();
3832 if ( pEntry->IsStandard() && (pEntry->GetType() & SvNumFormatType::CURRENCY) )
3833 {
3834 nDefaultCurrencyFormat = nKey;
3835 break; // while
3836 }
3837 ++it2;
3838 }
3839
3840 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3841 { // none found, create one
3842 sal_Int32 nCheck;
3843 NfWSStringsDtor aCurrList;
3844 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3845 GetCurrencyEntry( ActLnge ), false );
3846 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency standard format?" );
3847 if ( !aCurrList.empty() )
3848 {
3849 // if already loaded or user defined nDefaultSystemCurrencyFormat
3850 // will be set to the right value
3852 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3853 nDefaultCurrencyFormat, ActLnge );
3854 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3855 DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3856 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3857 }
3858 // old automatic currency format as a last resort
3859 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3860 nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3861 else
3862 { // mark as standard so that it is found next time
3863 SvNumberformat* pEntry = GetFormatEntry( nDefaultCurrencyFormat );
3864 if ( pEntry )
3865 pEntry->SetStandard();
3866 }
3867 }
3868 aDefaultFormatKeys[ CLOffset + ZF_STANDARD_CURRENCY ] = nDefaultCurrencyFormat;
3869 }
3870 return nDefaultCurrencyFormat;
3871}
3872
3873
3874// static
3875// true: continue; false: break loop, if pFoundEntry==NULL dupe found
3877 const NfCurrencyEntry*& pFoundEntry, bool& bFoundBank, const NfCurrencyEntry* pData,
3878 sal_uInt16 nPos, std::u16string_view rSymbol )
3879{
3880 bool bFound;
3881 if ( pData->GetSymbol() == rSymbol )
3882 {
3883 bFound = true;
3884 bFoundBank = false;
3885 }
3886 else if ( pData->GetBankSymbol() == rSymbol )
3887 {
3888 bFound = true;
3889 bFoundBank = true;
3890 }
3891 else
3892 bFound = false;
3893 if ( bFound )
3894 {
3895 if ( pFoundEntry && pFoundEntry != pData )
3896 {
3897 pFoundEntry = nullptr;
3898 return false; // break loop, not unique
3899 }
3900 if ( nPos == 0 )
3901 { // first entry is SYSTEM
3902 pFoundEntry = MatchSystemCurrency();
3903 if ( pFoundEntry )
3904 {
3905 return false; // break loop
3906 // even if there are more matching entries
3907 // this one is probably the one we are looking for
3908 }
3909 else
3910 {
3911 pFoundEntry = pData;
3912 }
3913 }
3914 else
3915 {
3916 pFoundEntry = pData;
3917 }
3918 }
3919 return true;
3920}
3921
3922
3923bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat, OUString& rStr,
3924 const NfCurrencyEntry** ppEntry /* = NULL */,
3925 bool* pBank /* = NULL */ ) const
3926{
3927 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3928 if ( ppEntry )
3929 *ppEntry = nullptr;
3930 if ( pBank )
3931 *pBank = false;
3932
3933 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
3934 if ( pFormat )
3935 {
3936 OUString aSymbol, aExtension;
3937 if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3938 {
3939 OUStringBuffer sBuff(128); // guess-estimate of a value that will pretty much guarantee no re-alloc
3940 if ( ppEntry )
3941 {
3942 bool bFoundBank = false;
3943 // we definitely need an entry matching the format code string
3944 const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3945 bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3946 true );
3947 if ( pFoundEntry )
3948 {
3949 *ppEntry = pFoundEntry;
3950 if ( pBank )
3951 *pBank = bFoundBank;
3952 rStr = pFoundEntry->BuildSymbolString(bFoundBank);
3953 }
3954 }
3955 if ( rStr.isEmpty() )
3956 { // analog to BuildSymbolString
3957 sBuff.append("[$");
3958 if ( aSymbol.indexOf( '-' ) != -1 ||
3959 aSymbol.indexOf( ']' ) != -1 )
3960 {
3961 sBuff.append("\"" + aSymbol + "\"");
3962 }
3963 else
3964 {
3965 sBuff.append(aSymbol);
3966 }
3967 if ( !aExtension.isEmpty() )
3968 {
3969 sBuff.append(aExtension);
3970 }
3971 sBuff.append(']');
3972 }
3973 rStr = sBuff.makeStringAndClear();
3974 return true;
3975 }
3976 }
3977 rStr.clear();
3978 return false;
3979}
3980
3981
3982// static
3983const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank,
3984 std::u16string_view rSymbol,
3985 std::u16string_view rExtension,
3986 LanguageType eFormatLanguage,
3987 bool bOnlyStringLanguage )
3988{
3989 sal_Int32 nExtLen = rExtension.size();
3990 LanguageType eExtLang;
3991 if ( nExtLen )
3992 {
3993 // rExtension should be a 16-bit hex value max FFFF which may contain a
3994 // leading "-" separator (that is not a minus sign, but toInt32 can be
3995 // used to parse it, with post-processing as necessary):
3996 sal_Int32 nExtLang = o3tl::toInt32(rExtension, 16);
3997 if ( !nExtLang )
3998 {
3999 eExtLang = LANGUAGE_DONTKNOW;
4000 }
4001 else
4002 {
4003 if (nExtLang < 0)
4004 nExtLang = -nExtLang;
4005 SAL_WARN_IF(nExtLang > 0xFFFF, "svl.numbers", "Out of range Lang Id: " << nExtLang << " from input string: " << OUString(rExtension));
4006 eExtLang = LanguageType(nExtLang & 0xFFFF);
4007 }
4008 }
4009 else
4010 {
4011 eExtLang = LANGUAGE_DONTKNOW;
4012 }
4013 const NfCurrencyEntry* pFoundEntry = nullptr;
4014 const NfCurrencyTable& rTable = GetTheCurrencyTable();
4015 sal_uInt16 nCount = rTable.size();
4016 bool bCont = true;
4017
4018 // first try with given extension language/country
4019 if ( nExtLen )
4020 {
4021 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
4022 {
4023 LanguageType eLang = rTable[j].GetLanguage();
4024 if ( eLang == eExtLang ||
4025 ((eExtLang == LANGUAGE_DONTKNOW) &&
4026 (eLang == LANGUAGE_SYSTEM)))
4027 {
4028 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
4029 &rTable[j], j, rSymbol );
4030 }
4031 }
4032 }
4033
4034 // ok?
4035 if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
4036 {
4037 return pFoundEntry;
4038 }
4039 if ( !bOnlyStringLanguage )
4040 {
4041 // now try the language/country of the number format
4042 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
4043 {
4044 LanguageType eLang = rTable[j].GetLanguage();
4045 if ( eLang == eFormatLanguage ||
4046 ((eFormatLanguage == LANGUAGE_DONTKNOW) &&
4047 (eLang == LANGUAGE_SYSTEM)))
4048 {
4049 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
4050 &rTable[j], j, rSymbol );
4051 }
4052 }
4053
4054 // ok?
4055 if ( pFoundEntry || !bCont )
4056 {
4057 return pFoundEntry;
4058 }
4059 }
4060
4061 // then try without language/country if no extension specified
4062 if ( !nExtLen )
4063 {
4064 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
4065 {
4066 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
4067 &rTable[j], j, rSymbol );
4068 }
4069 }
4070
4071 return pFoundEntry;
4072}
4073
4074
4075void SvNumberFormatter::GetCompatibilityCurrency( OUString& rSymbol, OUString& rAbbrev ) const
4076{
4077 ::osl::MutexGuard aGuard( GetInstanceMutex() );
4078 const css::uno::Sequence< css::i18n::Currency2 >
4079 xCurrencies( xLocaleData->getAllCurrencies() );
4080
4081 auto pCurrency = std::find_if(xCurrencies.begin(), xCurrencies.end(),
4082 [](const css::i18n::Currency2& rCurrency) { return rCurrency.UsedInCompatibleFormatCodes; });
4083 if (pCurrency != xCurrencies.end())
4084 {
4085 rSymbol = pCurrency->Symbol;
4086 rAbbrev = pCurrency->BankSymbol;
4087 }
4088 else
4089 {
4091 {
4093 appendLocaleInfo( u"GetCompatibilityCurrency: none?"));
4094 }
4095 rSymbol = xLocaleData->getCurrSymbol();
4096 rAbbrev = xLocaleData->getCurrBankSymbol();
4097 }
4098}
4099
4100
4101static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
4102{
4103 switch ( rCurr.GetPositiveFormat() )
4104 {
4105 case 0: // $1
4106 case 1: // 1$
4107 case 2: // $ 1
4108 case 3: // 1 $
4109 break;
4110 default:
4111 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
4112 break;
4113 }
4114 switch ( rCurr.GetNegativeFormat() )
4115 {
4116 case 0: // ($1)
4117 case 1: // -$1
4118 case 2: // $-1
4119 case 3: // $1-
4120 case 4: // (1$)
4121 case 5: // -1$
4122 case 6: // 1-$
4123 case 7: // 1$-
4124 case 8: // -1 $
4125 case 9: // -$ 1
4126 case 10: // 1 $-
4127 case 11: // $ -1
4128 case 12 : // $ 1-
4129 case 13 : // 1- $
4130 case 14 : // ($ 1)
4131 case 15 : // (1 $)
4132 break;
4133 default:
4134 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
4135 break;
4136 }
4137}
4138
4139// static
4141{
4142 // The set is initialized as a side effect of the currency table
4143 // created, make sure that exists, which usually is the case unless a
4144 // SvNumberFormatter was never instantiated.
4146 return theInstalledLocales.find( eLang) != theInstalledLocales.end();
4147}
4148
4149// static
4151{
4152 // Race condition possible:
4153 // ::osl::MutexGuard aGuard( GetMutex() );
4154 // while ( !bCurrencyTableInitialized )
4155 // ImpInitCurrencyTable();
4156 static bool bInitializing = false;
4157 if ( bCurrencyTableInitialized || bInitializing )
4158 {
4159 return ;
4160 }
4161 bInitializing = true;
4162
4164 std::optional<LocaleDataWrapper> pLocaleData(std::in_place,
4165 ::comphelper::getProcessComponentContext(),
4167 // get user configured currency
4168 OUString aConfiguredCurrencyAbbrev;
4169 LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
4171 aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
4172 sal_uInt16 nSecondarySystemCurrencyPosition = 0;
4173 sal_uInt16 nMatchingSystemCurrencyPosition = 0;
4174
4175 // First entry is SYSTEM:
4176 auto& rCurrencyTable = theCurrencyTable();
4177 rCurrencyTable.insert(
4178 rCurrencyTable.begin(),
4179 NfCurrencyEntry(*pLocaleData, LANGUAGE_SYSTEM));
4180 sal_uInt16 nCurrencyPos = 1;
4181
4182 const css::uno::Sequence< css::lang::Locale > xLoc = LocaleDataWrapper::getInstalledLocaleNames();
4183 sal_Int32 nLocaleCount = xLoc.getLength();
4184 SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount << "\"" );
4185 NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable();
4186 sal_uInt16 nLegacyOnlyCurrencyPos = 0;
4187 for ( css::lang::Locale const & rLocale : xLoc )
4188 {
4189 LanguageType eLang = LanguageTag::convertToLanguageType( rLocale, false);
4190 theInstalledLocales.insert( eLang);
4191 pLocaleData.emplace(
4192 ::comphelper::getProcessComponentContext(),
4193 LanguageTag(rLocale) );
4194 Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
4195 sal_Int32 nCurrencyCount = aCurrSeq.getLength();
4196 Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
4197
4198 // one default currency for each locale, insert first so it is found first
4199 sal_Int32 nDefault;
4200 for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
4201 {
4202 if ( pCurrencies[nDefault].Default )
4203 break;
4204 }
4205 std::optional<NfCurrencyEntry> pEntry;
4206 if ( nDefault < nCurrencyCount )
4207 {
4208 pEntry.emplace(pCurrencies[nDefault], *pLocaleData, eLang);
4209 }
4210 else
4211 { // first or ShellsAndPebbles
4212 pEntry.emplace(*pLocaleData, eLang);
4213 }
4215 {
4217 }
4218 if ( !nSystemCurrencyPosition && !aConfiguredCurrencyAbbrev.isEmpty() &&
4219 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev &&
4220 pEntry->GetLanguage() == eConfiguredCurrencyLanguage )
4221 {
4222 nSystemCurrencyPosition = nCurrencyPos;
4223 }
4224 if ( !nMatchingSystemCurrencyPosition &&
4225 pEntry->GetLanguage() == eSysLang )
4226 {
4227 nMatchingSystemCurrencyPosition = nCurrencyPos;
4228 }
4229 rCurrencyTable.insert(
4230 rCurrencyTable.begin() + nCurrencyPos++, std::move(*pEntry));
4231 // all remaining currencies for each locale
4232 if ( nCurrencyCount > 1 )
4233 {
4234 sal_Int32 nCurrency;
4235 for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
4236 {
4237 if (pCurrencies[nCurrency].LegacyOnly)
4238 {
4239 rLegacyOnlyCurrencyTable.insert(
4240 rLegacyOnlyCurrencyTable.begin() + nLegacyOnlyCurrencyPos++,
4241 NfCurrencyEntry(
4242 pCurrencies[nCurrency], *pLocaleData, eLang));
4243 }
4244 else if ( nCurrency != nDefault )
4245 {
4246 pEntry.emplace(pCurrencies[nCurrency], *pLocaleData, eLang);
4247 // no dupes
4248 bool bInsert = true;
4249 sal_uInt16 n = rCurrencyTable.size();
4250 sal_uInt16 aCurrencyIndex = 1; // skip first SYSTEM entry
4251 for ( sal_uInt16 j=1; j<n; j++ )
4252 {
4253 if ( rCurrencyTable[aCurrencyIndex++] == *pEntry )
4254 {
4255 bInsert = false;
4256 break; // for
4257 }
4258 }
4259 if ( !bInsert )
4260 {
4261 pEntry.reset();
4262 }
4263 else
4264 {
4265 if ( !nSecondarySystemCurrencyPosition &&
4266 (!aConfiguredCurrencyAbbrev.isEmpty() ?
4267 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev :
4268 pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
4269 {
4270 nSecondarySystemCurrencyPosition = nCurrencyPos;
4271 }
4272 if ( !nMatchingSystemCurrencyPosition &&
4273 pEntry->GetLanguage() == eSysLang )
4274 {
4275 nMatchingSystemCurrencyPosition = nCurrencyPos;
4276 }
4277 rCurrencyTable.insert(
4278 rCurrencyTable.begin() + nCurrencyPos++, std::move(*pEntry));
4279 }
4280 }
4281 }
4282 }
4283 }
4285 {
4286 nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
4287 }
4288 if ((!aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
4290 {
4292 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
4293 }
4294 // match SYSTEM if no configured currency found
4296 {
4297 nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
4298 }
4299 if ((aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
4301 {
4303 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
4304 }
4305 pLocaleData.reset();
4306 SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( nullptr, SvNumberFormatter, CurrencyChangeLink ) );
4307 bInitializing = false;
4309}
4310
4311
4312static std::ptrdiff_t addToCurrencyFormatsList( NfWSStringsDtor& rStrArr, const OUString& rFormat )
4313{
4314 // Prevent duplicates even over subsequent calls of
4315 // GetCurrencyFormatStrings() with the same vector.
4316 NfWSStringsDtor::const_iterator it( std::find( rStrArr.begin(), rStrArr.end(), rFormat));
4317 if (it != rStrArr.end())
4318 return it - rStrArr.begin();
4319
4320 rStrArr.push_back( rFormat);
4321 return rStrArr.size() - 1;
4322}
4323
4324
4326 const NfCurrencyEntry& rCurr,
4327 bool bBank ) const
4328{
4329 ::osl::MutexGuard aGuard( GetInstanceMutex() );
4330 OUString aRed = "["
4331 + pFormatScanner->GetRedString()
4332 + "]";
4333
4334 sal_uInt16 nDefault = 0;
4335 if ( bBank )
4336 {
4337 // Only bank symbols.
4338 OUString aPositiveBank = rCurr.BuildPositiveFormatString(true, *xLocaleData);
4339 OUString aNegativeBank = rCurr.BuildNegativeFormatString(true, *xLocaleData );
4340
4341 OUString format1 = aPositiveBank
4342 + ";"
4343 + aNegativeBank;
4344 addToCurrencyFormatsList( rStrArr, format1);
4345
4346 OUString format2 = aPositiveBank
4347 + ";"
4348 + aRed
4349 + aNegativeBank;
4350 nDefault = addToCurrencyFormatsList( rStrArr, format2);
4351 }
4352 else
4353 {
4354 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
4355 // duplicates if no decimals in currency.
4356 OUString aPositive = rCurr.BuildPositiveFormatString(false, *xLocaleData );
4357 OUString aNegative = rCurr.BuildNegativeFormatString(false, *xLocaleData );
4358 OUString format1;
4359 OUString format2;
4360 OUString format3;
4361 OUString format4;
4362 OUString format5;
4363 if (rCurr.GetDigits())
4364 {
4365 OUString aPositiveNoDec = rCurr.BuildPositiveFormatString(false, *xLocaleData, 0);
4366 OUString aNegativeNoDec = rCurr.BuildNegativeFormatString(false, *xLocaleData, 0 );
4367 OUString aPositiveDashed = rCurr.BuildPositiveFormatString(false, *xLocaleData, 2);
4368 OUString aNegativeDashed = rCurr.BuildNegativeFormatString(false, *xLocaleData, 2);
4369
4370 format1 = aPositiveNoDec
4371 + ";"
4372 + aNegativeNoDec;
4373
4374 format3 = aPositiveNoDec
4375 + ";"
4376 + aRed
4377 + aNegativeNoDec;
4378
4379 format5 = aPositiveDashed
4380 + ";"
4381 + aRed
4382 + aNegativeDashed;
4383 }
4384
4385 format2 = aPositive
4386 + ";"
4387 + aNegative;
4388
4389 format4 = aPositive
4390 + ";"
4391 + aRed
4392 + aNegative;
4393
4394 if (rCurr.GetDigits())
4395 {
4396 addToCurrencyFormatsList( rStrArr, format1);
4397 }
4398 addToCurrencyFormatsList( rStrArr, format2);
4399 if (rCurr.GetDigits())
4400 {
4401 addToCurrencyFormatsList( rStrArr, format3);
4402 }
4403 nDefault = addToCurrencyFormatsList( rStrArr, format4);
4404 if (rCurr.GetDigits())
4405 {
4406 addToCurrencyFormatsList( rStrArr, format5);
4407 }
4408 }
4409 return nDefault;
4410}
4411
4412sal_uInt32 SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt ) const
4413{
4414 ::osl::MutexGuard aGuard( GetInstanceMutex() );
4415 if (pMergeTable)
4416 {
4417 SvNumberFormatterIndexTable::const_iterator it = pMergeTable->find(nOldFmt);
4418 if (it != pMergeTable->end())
4419 {
4420 return it->second;
4421 }
4422 }
4423 return nOldFmt;
4424}
4425
4427{
4428 ::osl::MutexGuard aGuard( GetInstanceMutex() );
4429 return pMergeTable && !pMergeTable->empty();
4430}
4431
4432// static
4433sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear, sal_uInt16 nTwoDigitYearStart )
4434{
4435 if ( nYear < 100 )
4436 {
4437 if ( nYear < (nTwoDigitYearStart % 100) )
4438 {
4439 return nYear + (((nTwoDigitYearStart / 100) + 1) * 100);
4440 }
4441 else
4442 {
4443 return nYear + ((nTwoDigitYearStart / 100) * 100);
4444 }
4445 }
4446 return nYear;
4447}
4448
4449NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
4450{
4451 aSymbol = rLocaleData.getCurrSymbol();
4452 aBankSymbol = rLocaleData.getCurrBankSymbol();
4453 eLanguage = eLang;
4454 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
4455 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
4456 nDigits = rLocaleData.getCurrDigits();
4457 cZeroChar = rLocaleData.getCurrZeroChar();
4458}
4459
4460
4461NfCurrencyEntry::NfCurrencyEntry( const css::i18n::Currency & rCurr,
4462 const LocaleDataWrapper& rLocaleData, LanguageType eLang )
4463{
4464 aSymbol = rCurr.Symbol;
4465 aBankSymbol = rCurr.BankSymbol;
4466 eLanguage = eLang;
4467 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
4468 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
4469 nDigits = rCurr.DecimalPlaces;
4470 cZeroChar = rLocaleData.getCurrZeroChar();
4471}
4472
4473bool NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
4474{
4475 return aSymbol == r.aSymbol
4476 && aBankSymbol == r.aBankSymbol
4477 && eLanguage == r.eLanguage
4478 ;
4479}
4480
4481OUString NfCurrencyEntry::BuildSymbolString(bool bBank,
4482 bool bWithoutExtension) const
4483{
4484 OUStringBuffer aBuf("[$");
4485 if (bBank)
4486 {
4487 aBuf.append(aBankSymbol);
4488 }
4489 else
4490 {
4491 if ( aSymbol.indexOf( '-' ) >= 0 ||
4492 aSymbol.indexOf( ']' ) >= 0)
4493 {
4494 aBuf.append("\"" + aSymbol + "\"");
4495 }
4496 else
4497 {
4498 aBuf.append(aSymbol);
4499 }
4500 if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
4501 {
4502 sal_Int32 nLang = static_cast<sal_uInt16>(eLanguage);
4503 aBuf.append("-" + OUString::number(nLang, 16).toAsciiUpperCase());
4504 }
4505 }
4506 aBuf.append(']');
4507 return aBuf.makeStringAndClear();
4508}
4509
4510OUString NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper& rLoc,
4511 sal_uInt16 nDecimalFormat) const
4512{
4513 OUStringBuffer aBuf("#" + rLoc.getNumThousandSep() + "##0");
4514 if (nDecimalFormat && nDigits)
4515 {
4516 aBuf.append(rLoc.getNumDecimalSep());
4517 sal_Unicode cDecimalChar = nDecimalFormat == 2 ? '-' : cZeroChar;
4518 for (sal_uInt16 i = 0; i < nDigits; ++i)
4519 {
4520 aBuf.append(cDecimalChar);
4521 }
4522 }
4523 return aBuf.makeStringAndClear();
4524}
4525
4526
4527OUString NfCurrencyEntry::BuildPositiveFormatString(bool bBank, const LocaleDataWrapper& rLoc,
4528 sal_uInt16 nDecimalFormat) const
4529{
4530 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4531 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( rLoc.getCurrPositiveFormat(),
4532 nPositiveFormat, bBank );
4533 CompletePositiveFormatString(sBuf, bBank, nPosiForm);
4534 return sBuf.makeStringAndClear();
4535}
4536
4537
4538OUString NfCurrencyEntry::BuildNegativeFormatString(bool bBank,
4539 const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
4540{
4541 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4542 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc.getCurrNegativeFormat(),
4543 nNegativeFormat, bBank );
4544 CompleteNegativeFormatString(sBuf, bBank, nNegaForm);
4545 return sBuf.makeStringAndClear();
4546}
4547
4548
4549void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, bool bBank,
4550 sal_uInt16 nPosiForm) const
4551{
4552 OUString aSymStr = BuildSymbolString(bBank);
4553 NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
4554}
4555
4556
4557void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr, bool bBank,
4558 sal_uInt16 nNegaForm) const
4559{
4560 OUString aSymStr = BuildSymbolString(bBank);
4561 NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
4562}
4563
4564
4565// static
4566void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, std::u16string_view rSymStr,
4567 sal_uInt16 nPositiveFormat)
4568{
4569 switch( nPositiveFormat )
4570 {
4571 case 0: // $1
4572 rStr.insert(0, rSymStr);
4573 break;
4574 case 1: // 1$
4575 rStr.append(rSymStr);
4576 break;
4577 case 2: // $ 1
4578 {
4579 rStr.insert(0, OUString::Concat(rSymStr) + " ");
4580 }
4581 break;
4582 case 3: // 1 $
4583 {
4584 rStr.append(' ');
4585 rStr.append(rSymStr);
4586 }
4587 break;
4588 default:
4589 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4590 break;
4591 }
4592}
4593
4594
4595// static
4596void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr,
4597 std::u16string_view rSymStr,
4598 sal_uInt16 nNegativeFormat)
4599{
4600 switch( nNegativeFormat )
4601 {
4602 case 0: // ($1)
4603 {
4604 rStr.insert(0, OUString::Concat("(") + rSymStr);
4605 rStr.append(')');
4606 }
4607 break;
4608 case 1: // -$1
4609 {
4610 rStr.insert(0, OUString::Concat("-") + rSymStr);
4611 }
4612 break;
4613 case 2: // $-1
4614 {
4615 rStr.insert(0, OUString::Concat(rSymStr) + "-");
4616 }
4617 break;
4618 case 3: // $1-
4619 {
4620 rStr.insert(0, rSymStr);
4621 rStr.append('-');
4622 }
4623 break;
4624 case 4: // (1$)
4625 {
4626 rStr.insert(0, '(');
4627 rStr.append(rSymStr);
4628 rStr.append(')');
4629 }
4630 break;
4631 case 5: // -1$
4632 {
4633 rStr.append(rSymStr);
4634 rStr.insert(0, '-');
4635 }
4636 break;
4637 case 6: // 1-$
4638 {
4639 rStr.append('-');
4640 rStr.append(rSymStr);
4641 }
4642 break;
4643 case 7: // 1$-
4644 {
4645 rStr.append(rSymStr);
4646 rStr.append('-');
4647 }
4648 break;
4649 case 8: // -1 $
4650 {
4651 rStr.append(' ');
4652 rStr.append(rSymStr);
4653 rStr.insert(0, '-');
4654 }
4655 break;
4656 case 9: // -$ 1
4657 {
4658 rStr.insert(0, OUString::Concat("-") + rSymStr + " ");
4659 }
4660 break;
4661 case 10: // 1 $-
4662 {
4663 rStr.append(' ');
4664 rStr.append(rSymStr);
4665 rStr.append('-');
4666 }
4667 break;
4668 case 11: // $ -1
4669 {
4670 rStr.insert(0, OUString::Concat(rSymStr) + " -");
4671 }
4672 break;
4673 case 12 : // $ 1-
4674 {
4675 rStr.insert(0, OUString::Concat(rSymStr) + " ");
4676 rStr.append('-');
4677 }
4678 break;
4679 case 13 : // 1- $
4680 {
4681 rStr.append('-');
4682 rStr.append(' ');
4683 rStr.append(rSymStr);
4684 }
4685 break;
4686 case 14 : // ($ 1)
4687 {
4688 rStr.insert(0, OUString::Concat("(") + rSymStr + " ");
4689 rStr.append(')');
4690 }
4691 break;
4692 case 15 : // (1 $)
4693 {
4694 rStr.insert(0, '(');
4695 rStr.append(' ');
4696 rStr.append(rSymStr);
4697 rStr.append(')');
4698 }
4699 break;
4700 default:
4701 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4702 break;
4703 }
4704}
4705
4706
4707// static
4708sal_uInt16 NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat,
4709 sal_uInt16 nCurrFormat, bool bBank )
4710{
4711 if ( bBank )
4712 {
4713#if NF_BANKSYMBOL_FIX_POSITION
4714 (void) nIntlFormat; // avoid warnings
4715 return 3;
4716#else
4717 switch ( nIntlFormat )
4718 {
4719 case 0: // $1
4720 nIntlFormat = 2; // $ 1
4721 break;
4722 case 1: // 1$
4723 nIntlFormat = 3; // 1 $
4724 break;
4725 case 2: // $ 1
4726 break;
4727 case 3: // 1 $
4728 break;
4729 default:
4730 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4731 break;
4732 }
4733 return nIntlFormat;
4734#endif
4735 }
4736 else
4737 return nCurrFormat;
4738}
4739
4740
4742static sal_uInt16 lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat, sal_uInt16 nCurrFormat )
4743{
4744 short nSign = 0; // -1:=bracket 0:=left, 1:=middle, 2:=right
4745 switch ( nIntlFormat )
4746 {
4747 case 0: // ($1)
4748 case 4: // (1$)
4749 case 14 : // ($ 1)
4750 case 15 : // (1 $)
4751 return nCurrFormat;
4752 case 1: // -$1
4753 case 5: // -1$
4754 case 8: // -1 $
4755 case 9: // -$ 1
4756 nSign = 0;
4757 break;
4758 case 2: // $-1
4759 case 6: // 1-$
4760 case 11 : // $ -1
4761 case 13 : // 1- $
4762 nSign = 1;
4763 break;
4764 case 3: // $1-
4765 case 7: // 1$-
4766 case 10: // 1 $-
4767 case 12 : // $ 1-
4768 nSign = 2;
4769 break;
4770 default:
4771 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4772 break;
4773 }
4774
4775 switch ( nCurrFormat )
4776 {
4777 case 0: // ($1)
4778 switch ( nSign )
4779 {
4780 case 0:
4781 return 1; // -$1
4782 case 1:
4783 return 2; // $-1
4784 case 2:
4785 return 3; // $1-
4786 }
4787 break;
4788 case 4: // (1$)
4789 switch ( nSign )
4790 {
4791 case 0:
4792 return 5; // -1$
4793 case 1:
4794 return 6; // 1-$
4795 case 2:
4796 return 7; // 1$-
4797 }
4798 break;
4799 case 14 : // ($ 1)
4800 switch ( nSign )
4801 {
4802 case 0:
4803 return 9; // -$ 1
4804 case 1:
4805 return 11; // $ -1
4806 case 2:
4807 return 12; // $ 1-
4808 }
4809 break;
4810 case 15 : // (1 $)
4811 switch ( nSign )
4812 {
4813 case 0:
4814 return 8; // -1 $
4815 case 1:
4816 return 13; // 1- $
4817 case 2:
4818 return 10; // 1 $-
4819 }
4820 break;
4821 }
4822 return nCurrFormat;
4823}
4824
4825
4826// static
4827sal_uInt16 NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat,
4828 sal_uInt16 nCurrFormat, bool bBank )
4829{
4830 if ( bBank )
4831 {
4832#if NF_BANKSYMBOL_FIX_POSITION
4833 return 8;
4834#else
4835 switch ( nIntlFormat )
4836 {
4837 case 0: // ($1)
4838// nIntlFormat = 14; // ($ 1)
4839 nIntlFormat = 9; // -$ 1
4840 break;
4841 case 1: // -$1
4842 nIntlFormat = 9; // -$ 1
4843 break;
4844 case 2: // $-1
4845 nIntlFormat = 11; // $ -1
4846 break;
4847 case 3: // $1-
4848 nIntlFormat = 12; // $ 1-
4849 break;
4850 case 4: // (1$)
4851// nIntlFormat = 15; // (1 $)
4852 nIntlFormat = 8; // -1 $
4853 break;
4854 case 5: // -1$
4855 nIntlFormat = 8; // -1 $
4856 break;
4857 case 6: // 1-$
4858 nIntlFormat = 13; // 1- $
4859 break;
4860 case 7: // 1$-
4861 nIntlFormat = 10; // 1 $-
4862 break;
4863 case 8: // -1 $
4864 break;
4865 case 9: // -$ 1
4866 break;
4867 case 10: // 1 $-
4868 break;
4869 case 11: // $ -1
4870 break;
4871 case 12 : // $ 1-
4872 break;
4873 case 13 : // 1- $
4874 break;
4875 case 14 : // ($ 1)
4876// nIntlFormat = 14; // ($ 1)
4877 nIntlFormat = 9; // -$ 1
4878 break;
4879 case 15 : // (1 $)
4880// nIntlFormat = 15; // (1 $)
4881 nIntlFormat = 8; // -1 $
4882 break;
4883 default:
4884 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4885 break;
4886 }
4887#endif
4888 }
4889 else if ( nIntlFormat != nCurrFormat )
4890 {
4891 switch ( nCurrFormat )
4892 {
4893 case 0: // ($1)
4895 nIntlFormat, nCurrFormat );
4896 break;
4897 case 1: // -$1
4898 nIntlFormat = nCurrFormat;
4899 break;
4900 case 2: // $-1
4901 nIntlFormat = nCurrFormat;
4902 break;
4903 case 3: // $1-
4904 nIntlFormat = nCurrFormat;
4905 break;
4906 case 4: // (1$)
4908 nIntlFormat, nCurrFormat );
4909 break;
4910 case 5: // -1$
4911 nIntlFormat = nCurrFormat;
4912 break;
4913 case 6: // 1-$
4914 nIntlFormat = nCurrFormat;
4915 break;
4916 case 7: // 1$-
4917 nIntlFormat = nCurrFormat;
4918 break;
4919 case 8: // -1 $
4920 nIntlFormat = nCurrFormat;
4921 break;
4922 case 9: // -$ 1
4923 nIntlFormat = nCurrFormat;
4924 break;
4925 case 10: // 1 $-
4926 nIntlFormat = nCurrFormat;
4927 break;
4928 case 11: // $ -1
4929 nIntlFormat = nCurrFormat;
4930 break;
4931 case 12 : // $ 1-
4932 nIntlFormat = nCurrFormat;
4933 break;
4934 case 13 : // 1- $
4935 nIntlFormat = nCurrFormat;
4936 break;
4937 case 14 : // ($ 1)
4939 nIntlFormat, nCurrFormat );
4940 break;
4941 case 15 : // (1 $)
4943 nIntlFormat, nCurrFormat );
4944 break;
4945 default:
4946 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4947 break;
4948 }
4949 }
4950 return nIntlFormat;
4951}
4952
4954{
4955 osl::MutexGuard aGuard( GetInstanceMutex() );
4956 const SvNumberformat* pFormat = GetFormatEntry( nKey);
4957 if (pFormat)
4958 ChangeIntl( pFormat->GetLanguage());
4959 else
4961 return pFormatScanner->GetKeywords();
4962}
4963
4965{
4967}
4968
4969const std::vector<Color> & SvNumberFormatter::GetStandardColors() const
4970{
4972}
4973
4975{
4977}
4978
4979/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
struct _ADOIndex Index
Reference< XComponentContext > m_xContext
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
static const NfKeywordTable & GetEnglishKeywords()
Definition: zforscan.hxx:79
static const ::std::vector< Color > & GetStandardColors()
Definition: zforscan.hxx:97
@ LocaleLegacy
unfortunately localized in few locales, otherwise English
static size_t GetMaxDefaultColors()
Definition: zforscan.hxx:101
static constexpr OUStringLiteral sErrStr
Definition: zforscan.hxx:178
LanguageType getLanguageType(bool bResolveSystem=true) const
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
const OUString & getBcp47(bool bResolveSystem=true) const
bool equals(const LanguageTag &rLanguageTag) const
static LanguageType convertToLanguageType(const css::lang::Locale &rLocale, bool bResolveSystem=true)
LanguageTag & reset(const OUString &rBcp47LanguageTag)
const OUString & getDateSep() const
sal_uInt16 getCurrNegativeFormat() const
const OUString & getTime100SecSep() const
sal_Unicode getCurrZeroChar() const
const OUString & getNumThousandSep() const
const OUString & getCurrBankSymbol() const
css::uno::Sequence< css::i18n::Currency2 > getAllCurrencies() const
css::uno::Sequence< css::i18n::FormatElement > getAllFormats() const
LanguageTag getLoadedLanguageTag() const
const OUString & getCurrSymbol() const
static const css::uno::Sequence< css::lang::Locale > & getInstalledLocaleNames()
const OUString & getNumDecimalSepAlt() const
sal_uInt16 getCurrPositiveFormat() const
const OUString & getNumDecimalSep() const
static bool areChecksEnabled()
sal_uInt16 getCurrDigits() const
OUString appendLocaleInfo(std::u16string_view rDebugMsg) const
static void outputCheckMessage(std::u16string_view rMsg)
const css::uno::Sequence< sal_Int32 > & getDigitGrouping() const
const LanguageTag & getLanguageTag() const
static LanguageType getRealLanguage(LanguageType nLang)
void insert(const iterator &it, NfCurrencyEntry p)
size_t size() const
iterator begin()
void init(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::lang::Locale &rLocale)
Definition: ondemand.hxx:156
void changeLocale(const css::lang::Locale &rLocale)
Definition: ondemand.hxx:165
CalendarWrapper * get() const
Definition: ondemand.hxx:167
const CharClass * get() const
Definition: ondemand.hxx:332
void changeLocale(const css::uno::Reference< css::uno::XComponentContext > &xContext, const LanguageTag &rLanguageTag)
Definition: ondemand.hxx:305
void init(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const LanguageTag &rLanguageTag)
Definition: ondemand.hxx:74
void changeLocale(const LanguageTag &rLanguageTag)
Definition: ondemand.hxx:82
LanguageType getCurrentLanguage() const
Definition: ondemand.hxx:110
const LocaleDataWrapper * get() const
Definition: ondemand.hxx:112
NativeNumberWrapper * get() const
Definition: ondemand.hxx:274
void init(const css::uno::Reference< css::uno::XComponentContext > &rxContext)
Definition: ondemand.hxx:268
void changeLocale(LanguageType eLang)
Definition: ondemand.hxx:232
const ::utl::TransliterationWrapper * get() const
Definition: ondemand.hxx:238
void init(const css::uno::Reference< css::uno::XComponentContext > &rxContext, LanguageType eLang)
Definition: ondemand.hxx:223
instead of every number formatter being a listener we have a registry which also handles one instance...
Definition: zforlist.cxx:181
SvtSysLocaleOptions aSysLocaleOptions
Definition: zforlist.cxx:184
std::vector< SvNumberFormatter * > aFormatters
Definition: zforlist.cxx:183
virtual void ConfigurationChanged(utl::ConfigurationBroadcaster *, ConfigurationHints) override
Definition: zforlist.cxx:222
void Insert(SvNumberFormatter *pThis)
Definition: zforlist.cxx:191
void Remove(SvNumberFormatter const *pThis)
Definition: zforlist.cxx:215
virtual ~SvNumberFormatterRegistry_Impl() override
Definition: zforlist.cxx:209
SVL_DLLPRIVATE void ImpConstruct(LanguageType eLang)
Definition: zforlist.cxx:300
const OUString & GetNumDecimalSepAlt() const
Definition: zforlist.cxx:551
SVL_DLLPRIVATE void ImpAdjustFormatCodeDefault(css::i18n::NumberFormatCode *pFormatArr, sal_Int32 nCount)
Definition: zforlist.cxx:2417
static bool ImpLookupCurrencyEntryLoopBody(const NfCurrencyEntry *&pFoundEntry, bool &bFoundBank, const NfCurrencyEntry *pData, sal_uInt16 nPos, std::u16string_view rSymbol)
Definition: zforlist.cxx:3876
static const NfCurrencyTable & GetTheCurrencyTable()
Return a NfCurrencyTable with pointers to <type>NfCurrencyEntry</type> entries.
Definition: zforlist.cxx:3660
sal_uInt32 GetStandardIndex(LanguageType eLnge=LANGUAGE_DONTKNOW)
Return the format index of the standard default number format for language/country.
Definition: zforlist.cxx:3416
const SvNumberformat * GetSubstitutedEntry(sal_uInt32 nKey, sal_uInt32 &o_rNewKey) const
Obtain substituted GetFormatEntry(), i.e. system formats.
Definition: zforlist.cxx:2540
sal_uInt32 MaxCLOffset
Definition: numformat.hxx:592
void GetCompatibilityCurrency(OUString &rSymbol, OUString &rAbbrev) const
Get compatibility ("automatic" old style) currency from I18N locale data.
Definition: zforlist.cxx:4075
void SetColorLink(const Link< sal_uInt16, Color * > &rColorTableCallBack)
Set CallBack to ColorTable.
Definition: zforlist.cxx:387
bool IsSpecialStandardFormat(sal_uInt32 nFIndex, LanguageType eLnge)
Whether nFIndex is a special builtin format.
Definition: zforlist.cxx:1490
const LanguageTag & GetLanguageTag() const
The following methods are not to be used from outside but must be public for the InputScanner and For...
Definition: zforlist.cxx:534
bool IsDecimalSep(std::u16string_view rStr) const
Definition: zforlist.cxx:557
void FillKeywordTable(NfKeywordTable &rKeywords, LanguageType eLang)
Fill a NfKeywordIndex table with keywords of a language/country.
Definition: zforlist.cxx:817
CalendarWrapper * GetCalendar() const
Definition: zforlist.cxx:545
const OUString & GetDateSep() const
Definition: zforlist.cxx:555
size_t GetMaxDefaultColors() const
Access for unit tests.
Definition: zforlist.cxx:4974
sal_uInt32 GetStandardFormat(SvNumFormatType eType, LanguageType eLnge=LANGUAGE_DONTKNOW)
Return the format index of the default format of a type for language/country.
Definition: zforlist.cxx:1455
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bReplaceBooleanEquivalent=true)
Create new entry of a format code string for language/country.
Definition: zforlist.cxx:574
sal_uInt32 TestNewString(const OUString &sFormatString, LanguageType eLnge=LANGUAGE_DONTKNOW)
Test whether the format code string is already present in container.
Definition: zforlist.cxx:2027
OUString GetFormatStringForExcel(sal_uInt32 nKey, const NfKeywordTable &rKeywords, SvNumberFormatter &rTempFormatter) const
Return a format code string suitable for Excel export.
Definition: zforlist.cxx:899
sal_uInt32 GuessDateTimeFormat(SvNumFormatType &rType, double fNumber, LanguageType eLnge)
Return a format and type that best matches the value of fNumber if fNumber is assumed to be a date,...
Definition: zforlist.cxx:1557
void ReplaceSystemCL(LanguageType eOldLanguage)
Definition: zforlist.cxx:445
OUString GenerateFormat(sal_uInt32 nIndex, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bThousand=false, bool IsRed=false, sal_uInt16 nPrecision=0, sal_uInt16 nLeadingCnt=1)
Create a format code string using format nIndex as a template and applying other settings (passed fro...
Definition: zforlist.cxx:3158
OUString aThousandSep
Definition: numformat.hxx:602
LanguageType ActLnge
Definition: numformat.hxx:595
sal_uInt32 GetIndexPuttingAndConverting(OUString &rString, LanguageType eLnge, LanguageType eSysLnge, SvNumFormatType &rType, bool &rNewInserted, sal_Int32 &rCheckPos)
Similar to <method>PutEntry</method> and <method>PutandConvertEntry</method> or <method>PutandConvert...
Definition: zforlist.cxx:717
sal_uInt16 GetStandardPrec() const
Return the standard decimal precision.
Definition: zforlist.cxx:433
void SetNoZero(bool bNZ)
Set zero value suppression.
Definition: zforlist.cxx:427
sal_uInt32 nDefaultSystemCurrencyFormat
Definition: numformat.hxx:593
bool GetPreviewString(const OUString &sFormatString, double fPreviewNumber, OUString &sOutString, const Color **ppColor, LanguageType eLnge, bool bUseStarFormat=false)
Format a number according to a format code string to be scanned.
Definition: zforlist.cxx:1817
OnDemandNativeNumberWrapper xNatNum
Definition: numformat.hxx:588
OnDemandCalendarWrapper xCalendar
Definition: numformat.hxx:587
NfIndexTableOffset GetIndexTableOffset(sal_uInt32 nFormat) const
Return enum index of a format index of a builtin format, NF_INDEX_TABLE_ENTRIES if it's not a builtin...
Definition: zforlist.cxx:3589
sal_uInt32 GetEditFormat(double fNumber, sal_uInt32 nFIndex, SvNumFormatType eType, SvNumberformat const *pFormat, LanguageType eForLocale=LANGUAGE_DONTKNOW)
Return the corresponding edit format of a format.
Definition: zforlist.cxx:1593
void DeleteEntry(sal_uInt32 nKey)
Delete an entry including the format it is referring to.
Definition: zforlist.cxx:793
void FillKeywordTableForExcel(NfKeywordTable &rKeywords)
Fill a NfKeywordIndex table with keywords usable in Excel export with GetFormatStringForExcel() or Sv...
Definition: zforlist.cxx:830
bool GetNoZero() const
Return whether zero suppression is switched on.
Definition: zforlist.cxx:439
SVL_DLLPRIVATE SvNumberformat * ImpInsertFormat(const css::i18n::NumberFormatCode &rCode, sal_uInt32 nPos, bool bAfterChangingSystemCL=false, sal_Int16 nOrgIndex=0)
Definition: zforlist.cxx:2062
std::unique_ptr< ImpSvNumberInputScan > pStringScanner
Definition: numformat.hxx:589
const NativeNumberWrapper * GetNatNum() const
Definition: zforlist.cxx:547
void ClearMergeTable()
As the name says.
Definition: zforlist.cxx:3446
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
Format a number according to a format index, return string and color.
Definition: zforlist.cxx:1794
bool PutandConvertEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge, LanguageType eNewLnge, bool bConvertDateOrder, bool bReplaceBooleanEquivalent=true)
Same as <method>PutEntry</method> but the format code string is considered to be of language/country ...
Definition: zforlist.cxx:642
Color * GetUserDefColor(sal_uInt16 nIndex)
Do the CallBack to ColorTable.
Definition: zforlist.cxx:393
::osl::Mutex & GetGlobalMutex()
Definition: zforlist.cxx:365
sal_uInt32 GetEntryKey(std::u16string_view sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
Return the format index of the format code string for language/country, or NUMBERFORMAT_ENTRY_NOT_FOU...
Definition: zforlist.cxx:3404
sal_uInt32 GetMergeFormatIndex(sal_uInt32 nOldFmt) const
Return the new format index for an old format index, if a merge table exists.
Definition: zforlist.cxx:4412
sal_uInt32 GetTimeFormat(double fNumber, LanguageType eLnge, bool bForceDuration)
Return a time format that best matches fNumber.
Definition: zforlist.cxx:1511
sal_uInt16 GetFormatIntegerDigits(sal_uInt32 nFormat) const
Count of integer digits.
Definition: zforlist.cxx:2212
bool IsTextFormat(sal_uInt32 nFIndex) const
Whether format index nFIndex is of type text or not.
Definition: zforlist.cxx:566
OUString GetKeyword(LanguageType eLnge, sal_uInt16 nIndex)
Return a keyword for a language/country and NfKeywordIndex for XML import, to generate number format ...
Definition: zforlist.cxx:975
std::unique_ptr< SvNumberFormatterIndexTable > pMergeTable
Definition: numformat.hxx:583
const ::utl::TransliterationWrapper * GetTransliteration() const
Definition: zforlist.cxx:536
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString, bool bFiltering=false, bool bForceSystemLocale=false)
Format a number according to the standard default format matching the given format index.
Definition: zforlist.cxx:1673
OnDemandCharClass xCharClass
Definition: numformat.hxx:584
static void resetTheCurrencyTable()
Definition: zforlist.cxx:3649
static sal_uInt16 GetYear2000Default()
Definition: zforlist.cxx:3641
SVL_DLLPRIVATE sal_uInt32 ImpIsEntry(std::u16string_view rString, sal_uInt32 CLOffset, LanguageType eLnge)
Definition: zforlist.cxx:1012
sal_uInt16 GetFormatPrecision(sal_uInt32 nFormat) const
Count of decimals.
Definition: zforlist.cxx:2202
static SVL_DLLPRIVATE SvNumberFormatterRegistry_Impl & GetFormatterRegistry()
Definition: zforlist.cxx:377
const Date & GetNullDate() const
Return the reference date.
Definition: zforlist.cxx:415
static const sal_uInt16 UNLIMITED_PRECISION
We can't technically have an "infinite" value, so we use an arbitrary upper precision threshold to re...
Definition: numformat.hxx:48
OUString GetLangDecimalSep(LanguageType nLang) const
Return the decimal separator matching the given locale / LanguageType.
Definition: zforlist.cxx:2233
sal_Int32 ImpPosToken(const OUStringBuffer &sFormat, sal_Unicode token, sal_Int32 nStartPos=0) const
Definition: zforlist.cxx:3125
static void SetDefaultSystemCurrency(std::u16string_view rAbbrev, LanguageType eLang)
Set the default system currency.
Definition: zforlist.cxx:3748
LanguageTag maLanguageTag
Definition: numformat.hxx:576
std::unique_ptr< SvNumberFormatTable > pFormatTable
Definition: numformat.hxx:581
void ChangeIntl(LanguageType eLnge)
Change language/country, also input and format scanner.
Definition: zforlist.cxx:338
SvNumberformat * ImpSubstituteEntry(SvNumberformat *pFormat, sal_uInt32 *o_pRealKey=nullptr)
Definition: zforlist.cxx:2550
void InvalidateDateAcceptancePatterns()
Definition: zforlist.cxx:3789
OnDemandLocaleDataWrapper xLocaleData
Definition: numformat.hxx:585
static const sal_uInt16 INPUTSTRING_PRECISION
Precision suitable for numbers displayed in input bar, for instance Calc's formula input bar.
Definition: numformat.hxx:54
SvNumberFormatter(const css::uno::Reference< css::uno::XComponentContext > &rxContext, LanguageType eLang)
Preferred ctor with service manager and language/country enum.
Definition: zforlist.cxx:275
static const NfCurrencyEntry * GetLegacyOnlyCurrencyEntry(std::u16string_view rSymbol, std::u16string_view rAbbrev)
Return a NfCurrencyEntry pointer matching the symbol combination of a LegacyOnly currency.
Definition: zforlist.cxx:3719
bool HasMergeFormatTable() const
Whether a merge table is present or not.
Definition: zforlist.cxx:4426
OnDemandTransliterationWrapper xTransliteration
Definition: numformat.hxx:586
SVL_DLLPRIVATE sal_uInt32 ImpGetDefaultCurrencyFormat()
Definition: zforlist.cxx:3817
bool GetNewCurrencySymbolString(sal_uInt32 nFormat, OUString &rSymbol, const NfCurrencyEntry **ppEntry, bool *pBank=nullptr) const
Whether nFormat is of type css::util::NumberFormat::CURRENCY and the format code contains a new SYMBO...
Definition: zforlist.cxx:3923
SvNumFormatType GetType(sal_uInt32 nFIndex) const
Get the type of a format (or css::util::NumberFormat::UNDEFINED if no entry), but with css::util::Num...
Definition: zforlist.cxx:3426
NfEvalDateFormat eEvalDateFormat
Definition: numformat.hxx:596
OUString aDecimalSep
Definition: numformat.hxx:600
sal_uInt32 GetFormatIndex(NfIndexTableOffset, LanguageType eLnge=LANGUAGE_DONTKNOW)
Return the format index for a builtin format of a specific language.
Definition: zforlist.cxx:3570
SVL_DLLPRIVATE sal_uInt32 ImpGetCLOffset(LanguageType eLnge) const
Definition: zforlist.cxx:997
Link< sal_uInt16, Color * > aColorLink
Definition: numformat.hxx:591
OUString GetCalcCellReturn(sal_uInt32 nFormat) const
Get return string for Calc CELL() function, "G", "D1", ...
Definition: zforlist.cxx:2294
OUString GetFormatDecimalSep(sal_uInt32 nFormat) const
Return the decimal separator matching the locale of the given format.
Definition: zforlist.cxx:2222
void ChangeNullDate(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear)
Change the reference null date.
Definition: zforlist.cxx:406
sal_uInt16 GetYear2000() const
Definition: zforlist.cxx:3624
SvNumberFormatterMergeMap ConvertMergeTableToMap()
Convert the ugly old tools' Table type bloated with new'ed sal_uInt32 entries merge table to ::std::m...
Definition: zforlist.cxx:3530
static const NfCurrencyEntry & GetCurrencyEntry(LanguageType)
Return a NfCurrencyEntry matching a language/country.
Definition: zforlist.cxx:3678
std::map< sal_uInt32, std::unique_ptr< SvNumberformat > > aFTable
Definition: numformat.hxx:578
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
Return the format for a format index.
Definition: zforlist.cxx:2531
const std::vector< Color > & GetStandardColors() const
Access for unit tests.
Definition: zforlist.cxx:4969
static bool IsCompatible(SvNumFormatType eOldType, SvNumFormatType eNewType)
Definition: zforlist.cxx:1310
DefaultFormatKeysMap aDefaultFormatKeys
Definition: numformat.hxx:580
static const NfCurrencyEntry * MatchSystemCurrency()
Searches, according to the default locale currency, an entry of the CurrencyTable which is <bold>not<...
Definition: zforlist.cxx:3669
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: numformat.hxx:575
friend class SvNumberFormatterRegistry_Impl
Definition: numformat.hxx:41
void ChangeStandardPrec(short nPrec)
Change standard precision.
Definition: zforlist.cxx:421
const NfKeywordTable & GetKeywords(sal_uInt32 nKey)
Obtain NfKeywordTable used with a format, possibly localized.
Definition: zforlist.cxx:4953
sal_uInt32 GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge=LANGUAGE_DONTKNOW)
Return the format index of a builtin format for a specific language/country.
Definition: zforlist.cxx:3548
bool IsNatNum12(sal_uInt32 nFIndex) const
Whether format index nFIndex has NatNum12 modifier.
Definition: zforlist.cxx:2256
SVL_DLLPRIVATE sal_Int32 ImpGetFormatCodeIndex(css::uno::Sequence< css::i18n::NumberFormatCode > &rSeq, const NfIndexTableOffset nTabOff)
Definition: zforlist.cxx:2368
SVL_DLLPRIVATE sal_uInt32 ImpGenerateCL(LanguageType eLnge)
Definition: zforlist.cxx:1078
void SetEvalDateFormat(NfEvalDateFormat eEDF)
Set evaluation type and order of input date strings.
Definition: zforlist.cxx:3605
SVL_DLLPRIVATE SvNumberformat * GetFormatEntry(sal_uInt32 nKey)
Definition: zforlist.cxx:2518
SVL_DLLPRIVATE void ImpGenerateAdditionalFormats(sal_uInt32 CLOffset, css::uno::Reference< css::i18n::XNumberFormatCode > const &rNumberFormatCode, bool bAfterChangingSystemCL)
Definition: zforlist.cxx:3049
static bool IsLocaleInstalled(LanguageType eLang)
Check if a specific locale has supported locale data.
Definition: zforlist.cxx:4140
sal_uInt16 ExpandTwoDigitYear(sal_uInt16 nYear) const
Definition: zforlist.cxx:3631
sal_uInt16 GetCurrencyFormatStrings(NfWSStringsDtor &, const NfCurrencyEntry &, bool bBank) const
Get all standard formats for a specific currency, formats are appended to the NfWSStringsDtor list.
Definition: zforlist.cxx:4325
static SVL_DLLPRIVATE void ImpInitCurrencyTable()
Definition: zforlist.cxx:4150
OUString aDecimalSepAlt
Definition: numformat.hxx:601
void SetYear2000(sal_uInt16 nVal)
Set TwoDigitYearStart, how the input string scanner handles a two digit year.
Definition: zforlist.cxx:3617
bool GetPreviewStringGuess(const OUString &sFormatString, double fPreviewNumber, OUString &sOutString, const Color **ppColor, LanguageType eLnge=LANGUAGE_DONTKNOW)
Same as <method>GetPreviewString</method> but the format code string may be either language/country e...
Definition: zforlist.cxx:1870
static SVL_DLLPRIVATE sal_uInt16 nSystemCurrencyPosition
Definition: numformat.hxx:606
const CharClass * GetCharClass() const
Definition: zforlist.cxx:541
std::unique_ptr< ImpSvNumberformatScan > pFormatScanner
Definition: numformat.hxx:590
const LocaleDataWrapper * GetLocaleData() const
Definition: zforlist.cxx:543
OUString GetStandardName(LanguageType eLnge)
Return the GENERAL keyword in proper case ("General") for a language/country, used in XML import.
Definition: zforlist.cxx:989
SVL_DLLPRIVATE sal_uInt32 ImpGetDefaultFormat(SvNumFormatType nType)
Definition: zforlist.cxx:1375
bool PutandConvertEntrySystem(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge, LanguageType eNewLnge)
Same as <method>PutandConvertEntry</method> but the format code string is considered to be of the Sys...
Definition: zforlist.cxx:698
void GetFormatSpecialInfo(sal_uInt32 nFormat, bool &bThousand, bool &IsRed, sal_uInt16 &nPrecision, sal_uInt16 &nLeadingCnt)
Get additional info of a format index, e.g. for dialog box.
Definition: zforlist.cxx:2181
SvNumberFormatTable & GetEntryTable(SvNumFormatType eType, sal_uInt32 &FIndex, LanguageType eLnge)
Get table of formats of a specific type of a locale.
Definition: zforlist.cxx:1143
const css::uno::Reference< css::uno::XComponentContext > & GetComponentContext() const
Definition: zforlist.cxx:527
SVL_DLLPRIVATE sal_uInt32 ImpGetDefaultSystemCurrencyFormat()
Definition: zforlist.cxx:3795
static SVL_DLLPRIVATE SvNumberFormatterRegistry_Impl * pFormatterRegistry
Definition: numformat.hxx:607
static SVL_DLLPRIVATE volatile bool bCurrencyTableInitialized
Definition: numformat.hxx:605
const OUString & GetNumDecimalSep() const
Definition: zforlist.cxx:549
const OUString & GetNumThousandSep() const
Definition: zforlist.cxx:553
void ResetDefaultSystemCurrency()
Definition: zforlist.cxx:3783
SvNumberFormatTable & GetFirstEntryTable(SvNumFormatType &eType, sal_uInt32 &FIndex, LanguageType &rLnge)
Get table of formats of the same type as FIndex; eType and rLnge are set accordingly.
Definition: zforlist.cxx:1034
LanguageType GetLanguage() const
The language with which the formatter was initialized (system setting), NOT the current language afte...
Definition: zforlist.cxx:1303
void GetUsedLanguages(std::vector< LanguageType > &rList)
Fill rList with the language/country codes that have been allocated.
Definition: zforlist.cxx:799
LanguageType IniLnge
Definition: numformat.hxx:594
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
Analyze an input string.
Definition: zforlist.cxx:1195
NfEvalDateFormat GetEvalDateFormat() const
Definition: zforlist.cxx:3611
const NfKeywordTable & GetEnglishKeywords() const
Access for unit tests.
Definition: zforlist.cxx:4964
SvNumberFormatterIndexTable * MergeFormatter(SvNumberFormatter &rNewTable)
Merge in all new entries from rNewTable and return a table of resulting new format indices.
Definition: zforlist.cxx:3455
const ImpSvNumberformatScan * GetFormatScanner() const
The following method is not to be used from outside but must be public for the InputScanner.
Definition: zforlist.cxx:532
SvNumberFormatTable & ChangeCL(SvNumFormatType eType, sal_uInt32 &FIndex, LanguageType eLnge)
Get table of formats of a specific type of a language/country.
Definition: zforlist.cxx:1134
bool IsUserDefined(sal_uInt32 F_Index) const
Definition: zforlist.cxx:3376
SVL_DLLPRIVATE void ImpGenerateFormats(sal_uInt32 CLOffset, bool bNoAdditionalFormats)
Definition: zforlist.cxx:2575
::osl::Mutex & GetInstanceMutex() const
Definition: numformat.hxx:691
SvNumFormatType GetMaskedType() const
Get type of format, does not include css::util::NumberFormat::DEFINED.
Definition: zformat.hxx:190
void SetStarFormatSupport(bool b)
Definition: zformat.hxx:238
void SetType(SvNumFormatType eSetType)
Definition: zformat.hxx:192
sal_uInt16 GetFormatIntegerDigits(sal_uInt16 nIx=0) const
Count of integer digits.
Definition: zformat.hxx:271
OUString GetPercentString(sal_uInt16 nNumFor=0) const
Definition: zformat.cxx:2374
LanguageType GetLanguage() const
Definition: zformat.hxx:201
bool IsIso8601(sal_uInt16 nNumFor) const
Whether it's a (YY)YY-M(M)-D(D) format.
Definition: zformat.hxx:497
void SetComment(const OUString &rStr)
Definition: zformat.hxx:422
bool HasNewCurrency() const
Definition: zformat.cxx:1965
void SetLastInsertKey(sal_uInt16 nKey, const FormatterPrivateAccess &)
Definition: zformat.hxx:290
sal_uInt16 GetFormatPrecision(sal_uInt16 nIx=0) const
Count of decimal precision.
Definition: zformat.hxx:267
bool IsStandard() const
Definition: zformat.hxx:195
bool IsTextFormat() const
Definition: zformat.hxx:250
const Color * GetColor(sal_uInt16 nNumFor) const
Definition: zformat.cxx:5156
bool HasPositiveBracketPlaceholder() const
Definition: zformat.cxx:5063
bool IsSystemLongDateFormat() const
If the format is a placeholder for the system long date format and needs to be substituted during for...
Definition: zformat.hxx:220
bool IsNegativeInBracket() const
Definition: zformat.cxx:5052
static OUString StripNewCurrencyDelimiters(const OUString &rStr)
Definition: zformat.cxx:1993
bool HasTextFormat() const
Definition: zformat.hxx:252
const OUString * GetNumForString(sal_uInt16 nNumFor, sal_uInt16 nPos, bool bString=false) const
Definition: zformat.cxx:4964
SvNumFormatType GetNumForInfoScannedType(sal_uInt16 nNumFor) const
Get the scanned type of the specified subformat.
Definition: zformat.hxx:346
const OUString & GetFormatstring() const
Definition: zformat.hxx:230
bool IsSystemTimeFormat() const
If the format is a placeholder for the system time format and needs to be substituted during formatti...
Definition: zformat.hxx:212
OUString GetIntegerFractionDelimiterString(sal_uInt16 nNumFor) const
Definition: zformat.cxx:2395
bool GetNewCurrencySymbol(OUString &rSymbol, OUString &rExtension) const
Definition: zformat.cxx:1977
OUString GetFormatStringForTimePrecision(int nPrecision) const
Create a format string for time with a new precision.
Definition: zformat.cxx:6002
void SetStandard()
Definition: zformat.hxx:194
void GetFormatSpecialInfo(bool &bThousand, bool &IsRed, sal_uInt16 &nPrecision, sal_uInt16 &nLeadingCnt) const
Definition: zformat.cxx:4889
SvNumFormatType GetType() const
Get type of format, may include css::util::NumberFormat::DEFINED bit.
Definition: zformat.hxx:187
bool GetOutputString(double fNumber, sal_uInt16 nCharCount, OUString &rOutString) const
Get output string from a numeric value that fits the number of characters specified.
Definition: zformat.cxx:2402
OUString GetNatNumModifierString(sal_uInt16 nNumFor=0) const
Return empty string if no NatNum modifier or invalid nNumFor otherwise return "[NatNum1]" or "[NatNum...
Definition: zformat.cxx:5762
bool IsSubstituted() const
If the format is a placeholder and needs to be substituted.
Definition: zformat.hxx:204
sal_uInt16 GetLastInsertKey(const FormatterPrivateAccess &) const
Definition: zformat.hxx:288
OUString GetNumeratorString(sal_uInt16 nNumFor) const
Definition: zformat.cxx:2388
static void SetCurrencyChangeLink(const Link< LinkParamNone *, void > &rLink)
void GetCurrencyAbbrevAndLanguage(OUString &rAbbrev, LanguageType &eLang) const
const LanguageTag & GetLanguageTag() const
static bool IsFuzzing()
void AddListener(utl::ConfigurationListener *pListener)
void RemoveListener(utl::ConfigurationListener const *pListener)
DigitGroupingIterator & advance()
sal_Int32 get() const
sal_Int32 getPos() const
bool isEqual(const OUString &rStr1, const OUString &rStr2) const
int nCount
#define DBG_ASSERT(sCon, aError)
float u
DocumentType eType
sal_Int32 nIndex
sal_Int64 n
#define LANGUAGE_SYSTEM
#define LANGUAGE_DONTKNOW
#define LANGUAGE_ENGLISH_US
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
LanguageTag maLanguageTag
aStr
aBuf
std::unique_ptr< sal_Int32[]> pData
B & padToLength(B &rBuffer, sal_Int32 nLen, U cFill)
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill='\0')
Type
int i
constexpr sal_Int16 nFirstFreeFormatIndex
constexpr sal_Int16 nStopPredefinedFormatIndex
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
NameID
HashMap_OWString_Interface aMap
::std::array< OUString, NF_KEYWORD_ENTRIES_COUNT > NfKeywordTable
Definition: nfkeytab.hxx:98
@ NF_KEYWORD_ENTRIES_COUNT
Definition: nfkeytab.hxx:95
@ NF_KEY_M
Definition: nfkeytab.hxx:42
@ NF_KEY_MI
Definition: nfkeytab.hxx:40
@ NF_KEY_D
Definition: nfkeytab.hxx:53
@ NF_KEY_EC
Definition: nfkeytab.hxx:64
@ NF_KEY_NN
Definition: nfkeytab.hxx:59
@ NF_KEY_DD
Definition: nfkeytab.hxx:54
@ NF_KEY_RR
Definition: nfkeytab.hxx:70
@ NF_KEY_NNN
Definition: nfkeytab.hxx:60
@ NF_KEY_SS
Definition: nfkeytab.hxx:50
@ NF_KEY_DDD
Definition: nfkeytab.hxx:55
@ NF_KEY_H
Definition: nfkeytab.hxx:47
@ NF_KEY_HH
Definition: nfkeytab.hxx:48
@ NF_KEY_WW
Definition: nfkeytab.hxx:71
@ NF_KEY_MMMMM
Definition: nfkeytab.hxx:46
@ NF_KEY_MMM
Definition: nfkeytab.hxx:44
@ NF_KEY_THAI_T
Definition: nfkeytab.hxx:72
@ NF_KEY_GGG
Definition: nfkeytab.hxx:68
@ NF_KEY_YYYY
Definition: nfkeytab.hxx:58
@ NF_KEY_MMMM
Definition: nfkeytab.hxx:45
@ NF_KEY_G
Definition: nfkeytab.hxx:66
@ NF_KEY_MM
Definition: nfkeytab.hxx:43
@ NF_KEY_S
Definition: nfkeytab.hxx:49
@ NF_KEY_GG
Definition: nfkeytab.hxx:67
@ NF_KEY_DDDD
Definition: nfkeytab.hxx:56
@ NF_KEY_GENERAL
Definition: nfkeytab.hxx:75
@ NF_KEY_EEC
Definition: nfkeytab.hxx:65
@ NF_KEY_R
Definition: nfkeytab.hxx:69
@ NF_KEY_NNNN
Definition: nfkeytab.hxx:61
@ NF_KEY_YY
Definition: nfkeytab.hxx:57
@ NF_KEY_MMI
Definition: nfkeytab.hxx:41
ConfigurationHints
QPRO_FUNC_TYPE nType
Read/write access on a special sal_uInt16 component, may only be used on the standard format 0,...
Definition: zformat.hxx:287
constexpr bool operator==(TypedWhichId< T > const &lhs, TypedWhichId< T > rhs)
Definition: typedwhich.hxx:43
sal_uInt16 sal_Unicode
sal_Int32 nLength
sal_uInt32 const indexTable[NF_INDEX_TABLE_ENTRIES]
Definition: zforlist.cxx:110
#define ZF_STANDARD_TIME
Definition: zforlist.cxx:70
#define ZF_STANDARD_DATETIME
Definition: zforlist.cxx:72
#define ZF_STANDARD_TEXT
Definition: zforlist.cxx:91
#define ZF_STANDARD_DATE_SYS_NNNNDMMMMYYYY
Definition: zforlist.cxx:82
#define ZF_STANDARD_DATE_SYS_NNDMMMYY
Definition: zforlist.cxx:80
#define ZF_STANDARD_PERCENT
Definition: zforlist.cxx:67
static std::ptrdiff_t addToCurrencyFormatsList(NfWSStringsDtor &rStrArr, const OUString &rFormat)
Definition: zforlist.cxx:4312
static sal_uInt16 lcl_MergeNegativeParenthesisFormat(sal_uInt16 nIntlFormat, sal_uInt16 nCurrFormat)
Call this only if nCurrFormat is really with parentheses!
Definition: zforlist.cxx:4742
#define ZF_STANDARD_DATE_SYS_DMMMMYYYY
Definition: zforlist.cxx:79
#define ZF_STANDARD_DATE_DIN_YYMMDD
Definition: zforlist.cxx:86
#define ZF_STANDARD_LOGICAL
Definition: zforlist.cxx:90
#define ZF_STANDARD_DATE
Definition: zforlist.cxx:69
#define ZF_STANDARD_DATE_SYS_DMMMYYYY
Definition: zforlist.cxx:78
#define ZF_STANDARD_DURATION
Definition: zforlist.cxx:71
#define ZF_STANDARD_DATE_SYS_NNDMMMMYYYY
Definition: zforlist.cxx:81
#define ZF_STANDARD_DATE_DIN_DMMMYYYY
Definition: zforlist.cxx:83
#define ZF_STANDARD_CURRENCY
Definition: zforlist.cxx:68
#define ZF_STANDARD_SCIENTIFIC
Definition: zforlist.cxx:73
#define ZF_STANDARD_DATE_DIN_DMMMMYYYY
Definition: zforlist.cxx:84
static void lcl_CheckCurrencySymbolPosition(const NfCurrencyEntry &rCurr)
Definition: zforlist.cxx:4101
static OUString lcl_buildBooleanStringFormat(SvNumberformat *pEntry)
Definition: zforlist.cxx:885
IMPL_STATIC_LINK_NOARG(SvNumberFormatter, CurrencyChangeLink, LinkParamNone *, void)
Definition: zforlist.cxx:3738
#define ZF_STANDARD_DATE_WW
Definition: zforlist.cxx:88
#define ZF_STANDARD_FRACTION
Definition: zforlist.cxx:74
#define ZF_STANDARD
Definition: zforlist.cxx:66
#define ZF_STANDARD_DATE_DIN_MMDD
Definition: zforlist.cxx:85
#define ZF_STANDARD_DATE_DIN_YYYYMMDD
Definition: zforlist.cxx:87
#define UNKNOWN_SUBSTITUTE
Definition: zforlist.cxx:107
std::vector< OUString > NfWSStringsDtor
Definition: zforlist.hxx:364
std::unordered_map< sal_uInt16, sal_uInt32 > SvNumberFormatterIndexTable
Definition: zforlist.hxx:287
std::map< sal_uInt32, SvNumberformat * > SvNumberFormatTable
This table is std::map because it needs to preserve insertion order, because the formats are roughly ...
Definition: zforlist.hxx:286
constexpr sal_uInt32 NF_STANDARD_FORMAT_TEXT
The built-in @ Text format, offset within a locale, key in the locale the number formatter was constr...
Definition: zforlist.hxx:45
SvNumFormatType
MAX_ULONG.
Definition: zforlist.hxx:50
@ UNDEFINED
is used as a return value if no format exists.
@ TIME
selects time formats.
@ NUMBER
selects decimal number formats.
@ LOGICAL
selects boolean number formats.
@ CURRENCY
selects currency formats.
@ FRACTION
selects number formats for fractions.
@ ALL
selects all number formats.
@ TEXT
selects text number formats.
@ DATE
selects date formats.
@ PERCENT
selects percentage number formats.
@ DATETIME
selects number formats which contain date and time.
@ SCIENTIFIC
selects scientific number formats.
@ DEFINED
selects only user-defined number formats.
std::unordered_map< sal_uInt32, sal_uInt32 > SvNumberFormatterMergeMap
Definition: zforlist.hxx:288
NfEvalDateFormat
enum values for <method>SvNumberFormatter::SetEvalDateFormat</method>
Definition: zforlist.hxx:265
@ NF_EVALDATEFORMAT_INTL
DateFormat only from International, default.
Definition: zforlist.hxx:267
#define SV_COUNTRY_LANGUAGE_OFFSET
Definition: zforlist.hxx:38
NfIndexTableOffset
enum values for <method>SvNumberFormatter::GetFormatIndex</method>
Definition: zforlist.hxx:124
@ NF_DATE_SYSTEM_SHORT
Definition: zforlist.hxx:163
@ NF_SCIENTIFIC_000E00
Definition: zforlist.hxx:138
@ NF_TIME_HHMMSSAMPM
Definition: zforlist.hxx:191
@ NF_DATETIME_SYS_DDMMYYYY_HHMMSS
Definition: zforlist.hxx:199
@ NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
Definition: zforlist.hxx:238
@ NF_DATE_SYS_DMMMYY
Definition: zforlist.hxx:167
@ NF_DATE_SYS_MMYY
Definition: zforlist.hxx:180
@ NF_CURRENCY_1000DEC2_RED
Definition: zforlist.hxx:157
@ NF_INDEX_TABLE_RESERVED_START
Definition: zforlist.hxx:225
@ NF_TIME_HHMMAMPM
Definition: zforlist.hxx:190
@ NF_DATE_SYS_DMMMMYYYY
Definition: zforlist.hxx:170
@ NF_TIME_MMSS00
Definition: zforlist.hxx:193
@ NF_DATE_DIN_DMMMYYYY
Definition: zforlist.hxx:169
@ NF_NUMBER_DEC2
Definition: zforlist.hxx:130
@ NF_TIME_HH_MMSS00
Definition: zforlist.hxx:194
@ NF_DATE_DIN_MMDD
Definition: zforlist.hxx:176
@ NF_CURRENCY_1000DEC2_DASHED
Definition: zforlist.hxx:159
@ NF_DATE_SYS_DDMMM
Definition: zforlist.hxx:181
@ NF_DATETIME_ISO_YYYYMMDD_HHMMSS000
Definition: zforlist.hxx:236
@ NF_DATE_ISO_YYYYMMDD
Definition: zforlist.hxx:179
@ NF_DATE_SYS_NNNNDMMMMYYYY
Definition: zforlist.hxx:175
@ NF_NUMBER_SYSTEM
Definition: zforlist.hxx:133
@ NF_DATE_SYS_NNDMMMYY
Definition: zforlist.hxx:172
@ NF_CURRENCY_START
Definition: zforlist.hxx:153
@ NF_CURRENCY_1000DEC2
Definition: zforlist.hxx:155
@ NF_INDEX_TABLE_ENTRIES
Definition: zforlist.hxx:243
@ NF_DATE_DIN_DMMMMYYYY
Definition: zforlist.hxx:171
@ NF_CURRENCY_END
Definition: zforlist.hxx:160
@ NF_DATE_SYS_DDMMYY
Definition: zforlist.hxx:165
@ NF_NUMBER_STANDARD
Definition: zforlist.hxx:128
@ NF_NUMBER_1000DEC2
Definition: zforlist.hxx:132
@ NF_PERCENT_DEC2
Definition: zforlist.hxx:143
@ NF_DATE_QQJJ
Definition: zforlist.hxx:183
@ NF_DATE_DIN_YYMMDD
Definition: zforlist.hxx:177
@ NF_TIME_HHMM
Definition: zforlist.hxx:188
@ NF_DATE_DEF_NNDDMMMYY
Definition: zforlist.hxx:173
@ NF_NUMBER_INT
Definition: zforlist.hxx:129
@ NF_CURRENCY_1000INT_RED
Definition: zforlist.hxx:156
@ NF_TIME_HH_MMSS
Definition: zforlist.hxx:192
@ NF_DATE_SYS_DMMMYYYY
Definition: zforlist.hxx:168
@ NF_DATE_DIN_YYYYMMDD
Definition: zforlist.hxx:178
@ NF_CURRENCY_1000INT
Definition: zforlist.hxx:154
@ NF_DATETIME_SYS_DDMMYYYY_HHMM
Definition: zforlist.hxx:222
@ NF_DATE_MMMM
Definition: zforlist.hxx:182
@ NF_TIME_HHMMSS
Definition: zforlist.hxx:189
@ NF_DATE_SYS_NNDMMMMYYYY
Definition: zforlist.hxx:174
@ NF_PERCENT_INT
Definition: zforlist.hxx:142
@ NF_SCIENTIFIC_000E000
Definition: zforlist.hxx:137
@ NF_DATETIME_ISO_YYYYMMDD_HHMMSS
Definition: zforlist.hxx:235
@ NF_CURRENCY_1000DEC2_CCC
Definition: zforlist.hxx:158
@ NF_DATE_SYS_DDMMYYYY
Definition: zforlist.hxx:166
@ NF_NUMBER_1000INT
Definition: zforlist.hxx:131
@ NF_DATETIME_ISO_YYYYMMDDTHHMMSS
Definition: zforlist.hxx:237
@ NF_DATETIME_SYSTEM_SHORT_HHMM
Definition: zforlist.hxx:198
@ NF_DATE_SYSTEM_LONG
Definition: zforlist.hxx:164
SvNumInputOptions
Input options to be used with IsNumberFormat()
Definition: zforlist.hxx:370
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND
Definition: zforlist.hxx:47
#define SV_MAX_COUNT_STANDARD_FORMATS
Definition: zforlist.hxx:39