1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include <officecfg/Office/Common.hxx>
24 #include <svl/zforlist.hxx>
25 #include <svl/currencytable.hxx>
27 #include <comphelper/string.hxx>
28 #include <tools/debug.hxx>
29 #include <unotools/charclass.hxx>
30 #include <unotools/configmgr.hxx>
31 #include <i18nlangtag/mslangid.hxx>
32 #include <unotools/localedatawrapper.hxx>
33 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
34 #include <com/sun/star/i18n/KNumberFormatType.hpp>
35 #include <com/sun/star/i18n/FormatElement.hpp>
36 #include <com/sun/star/i18n/Currency2.hpp>
37 #include <com/sun/star/i18n/NumberFormatCode.hpp>
38 #include <com/sun/star/i18n/XNumberFormatCode.hpp>
39 #include <com/sun/star/i18n/NumberFormatMapper.hpp>
40 #include <comphelper/processfactory.hxx>
42 #include <osl/mutex.hxx>
44 #include "zforscan.hxx"
45 #include "zforfind.hxx"
46 #include <svl/zformat.hxx>
47 #include <i18npool/reservedconstants.hxx>
49 #include <unotools/syslocaleoptions.hxx>
50 #include <unotools/digitgroupingiterator.hxx>
51 #include <rtl/instance.hxx>
52 #include <rtl/strbuf.hxx>
53 #include <rtl/math.hxx>
59 using namespace ::com::sun::star
;
60 using namespace ::com::sun::star::uno
;
61 using namespace ::com::sun::star::i18n
;
62 using namespace ::com::sun::star::lang
;
63 using namespace ::std
;
65 // Constants for type offsets per Country/Language (CL)
67 #define ZF_STANDARD_PERCENT 10
68 #define ZF_STANDARD_CURRENCY 20
69 #define ZF_STANDARD_DATE 30
70 #define ZF_STANDARD_TIME 40
71 #define ZF_STANDARD_DURATION (ZF_STANDARD_TIME + 4)
72 #define ZF_STANDARD_DATETIME 50
73 #define ZF_STANDARD_SCIENTIFIC 60
74 #define ZF_STANDARD_FRACTION 65
76 // Additional builtin formats not fitting into the first 10 of a category (TLOT
77 // = The Legacy Of Templin; unfortunately TLOT intended only 10 builtin formats
78 // per category, more would overwrite the next category):
79 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY 75
80 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY 76
81 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY 77
82 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY 78
83 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY 79
84 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY 80
85 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY 81
86 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD 82
87 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD 83
88 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD 84
89 #define ZF_STANDARD_NEWEXTENDED_DATE_WW 85
91 #define ZF_STANDARD_LOGICAL SV_MAX_COUNT_STANDARD_FORMATS-1 // 99
92 #define ZF_STANDARD_TEXT SV_MAX_COUNT_STANDARD_FORMATS // 100
94 static_assert( ZF_STANDARD_TEXT
== NF_STANDARD_FORMAT_TEXT
, "definition mismatch" );
96 static_assert( NF_INDEX_TABLE_RESERVED_START
== i18npool::nStopPredefinedFormatIndex
,
97 "NfIndexTableOffset does not match i18npool's locale data predefined format code index bounds.");
99 static_assert( NF_INDEX_TABLE_ENTRIES
<= i18npool::nFirstFreeFormatIndex
,
100 "NfIndexTableOffset crosses i18npool's locale data reserved format code index bounds.\n"
101 "You will need to adapt all locale data files defining index values "
102 "(formatIndex=\"...\") in that range and increment those and when done "
103 "adjust nFirstFreeFormatIndex in include/i18npool/reservedconstants.hxx");
105 /* Locale that is set if an unknown locale (from another system) is loaded of
106 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
107 * (old currency) is recognized as a date (#53155#). */
108 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
110 // Same order as in include/svl/zforlist.hxx enum NfIndexTableOffset
111 sal_uInt32
const indexTable
[NF_INDEX_TABLE_ENTRIES
] = {
112 ZF_STANDARD
, // NF_NUMBER_STANDARD
113 ZF_STANDARD
+ 1, // NF_NUMBER_INT
114 ZF_STANDARD
+ 2, // NF_NUMBER_DEC2
115 ZF_STANDARD
+ 3, // NF_NUMBER_1000INT
116 ZF_STANDARD
+ 4, // NF_NUMBER_1000DEC2
117 ZF_STANDARD
+ 5, // NF_NUMBER_SYSTEM
118 ZF_STANDARD_SCIENTIFIC
, // NF_SCIENTIFIC_000E000
119 ZF_STANDARD_SCIENTIFIC
+ 1, // NF_SCIENTIFIC_000E00
120 ZF_STANDARD_PERCENT
, // NF_PERCENT_INT
121 ZF_STANDARD_PERCENT
+ 1, // NF_PERCENT_DEC2
122 ZF_STANDARD_FRACTION
, // NF_FRACTION_1D
123 ZF_STANDARD_FRACTION
+ 1, // NF_FRACTION_2D
124 ZF_STANDARD_CURRENCY
, // NF_CURRENCY_1000INT
125 ZF_STANDARD_CURRENCY
+ 1, // NF_CURRENCY_1000DEC2
126 ZF_STANDARD_CURRENCY
+ 2, // NF_CURRENCY_1000INT_RED
127 ZF_STANDARD_CURRENCY
+ 3, // NF_CURRENCY_1000DEC2_RED
128 ZF_STANDARD_CURRENCY
+ 4, // NF_CURRENCY_1000DEC2_CCC
129 ZF_STANDARD_CURRENCY
+ 5, // NF_CURRENCY_1000DEC2_DASHED
130 ZF_STANDARD_DATE
, // NF_DATE_SYSTEM_SHORT
131 ZF_STANDARD_DATE
+ 8, // NF_DATE_SYSTEM_LONG
132 ZF_STANDARD_DATE
+ 7, // NF_DATE_SYS_DDMMYY
133 ZF_STANDARD_DATE
+ 6, // NF_DATE_SYS_DDMMYYYY
134 ZF_STANDARD_DATE
+ 9, // NF_DATE_SYS_DMMMYY
135 ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY
, // NF_DATE_SYS_DMMMYYYY
136 ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY
, // NF_DATE_DIN_DMMMYYYY
137 ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY
, // NF_DATE_SYS_DMMMMYYYY
138 ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY
, // NF_DATE_DIN_DMMMMYYYY
139 ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY
, // NF_DATE_SYS_NNDMMMYY
140 ZF_STANDARD_DATE
+ 1, // NF_DATE_DEF_NNDDMMMYY
141 ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY
, // NF_DATE_SYS_NNDMMMMYYYY
142 ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY
, // NF_DATE_SYS_NNNNDMMMMYYYY
143 ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD
, // NF_DATE_DIN_MMDD
144 ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD
, // NF_DATE_DIN_YYMMDD
145 ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD
, // NF_DATE_DIN_YYYYMMDD
146 ZF_STANDARD_DATE
+ 2, // NF_DATE_SYS_MMYY
147 ZF_STANDARD_DATE
+ 3, // NF_DATE_SYS_DDMMM
148 ZF_STANDARD_DATE
+ 4, // NF_DATE_MMMM
149 ZF_STANDARD_DATE
+ 5, // NF_DATE_QQJJ
150 ZF_STANDARD_NEWEXTENDED_DATE_WW
, // NF_DATE_WW
151 ZF_STANDARD_TIME
, // NF_TIME_HHMM
152 ZF_STANDARD_TIME
+ 1, // NF_TIME_HHMMSS
153 ZF_STANDARD_TIME
+ 2, // NF_TIME_HHMMAMPM
154 ZF_STANDARD_TIME
+ 3, // NF_TIME_HHMMSSAMPM
155 ZF_STANDARD_TIME
+ 4, // NF_TIME_HH_MMSS
156 ZF_STANDARD_TIME
+ 5, // NF_TIME_MMSS00
157 ZF_STANDARD_TIME
+ 6, // NF_TIME_HH_MMSS00
158 ZF_STANDARD_DATETIME
, // NF_DATETIME_SYSTEM_SHORT_HHMM
159 ZF_STANDARD_DATETIME
+ 1, // NF_DATETIME_SYS_DDMMYYYY_HHMMSS
160 ZF_STANDARD_LOGICAL
, // NF_BOOLEAN
161 ZF_STANDARD_TEXT
, // NF_TEXT
162 ZF_STANDARD_DATETIME
+ 4, // NF_DATETIME_SYS_DDMMYYYY_HHMM
163 ZF_STANDARD_FRACTION
+ 2, // NF_FRACTION_3D
164 ZF_STANDARD_FRACTION
+ 3, // NF_FRACTION_2
165 ZF_STANDARD_FRACTION
+ 4, // NF_FRACTION_4
166 ZF_STANDARD_FRACTION
+ 5, // NF_FRACTION_8
167 ZF_STANDARD_FRACTION
+ 6, // NF_FRACTION_16
168 ZF_STANDARD_FRACTION
+ 7, // NF_FRACTION_10
169 ZF_STANDARD_FRACTION
+ 8, // NF_FRACTION_100
170 ZF_STANDARD_DATETIME
+ 2, // NF_DATETIME_ISO_YYYYMMDD_HHMMSS
171 ZF_STANDARD_DATETIME
+ 3 // NF_DATETIME_ISO_YYYYMMDDTHHMMSS
175 instead of every number formatter being a listener we have a registry which
176 also handles one instance of the SysLocale options
179 class SvNumberFormatterRegistry_Impl
: public utl::ConfigurationListener
181 std::vector
< SvNumberFormatter
* >
183 SvtSysLocaleOptions aSysLocaleOptions
;
184 LanguageType eSysLanguage
;
187 SvNumberFormatterRegistry_Impl();
188 virtual ~SvNumberFormatterRegistry_Impl() override
;
190 void Insert( SvNumberFormatter
* pThis
)
191 { aFormatters
.push_back( pThis
); }
193 void Remove( SvNumberFormatter
const * pThis
);
196 { return aFormatters
.size(); }
198 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster
*, ConfigurationHints
) override
;
201 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
202 : eSysLanguage(MsLangId::getRealLanguage( LANGUAGE_SYSTEM
))
204 aSysLocaleOptions
.AddListener( this );
208 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
210 aSysLocaleOptions
.RemoveListener( this );
214 void SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter
const * pThis
)
216 auto it
= std::find(aFormatters
.begin(), aFormatters
.end(), pThis
);
217 if (it
!= aFormatters
.end())
218 aFormatters
.erase( it
);
221 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster
*,
222 ConfigurationHints nHint
)
224 ::osl::MutexGuard
aGuard( SvNumberFormatter::GetGlobalMutex() );
226 if ( nHint
& ConfigurationHints::Locale
)
228 for(SvNumberFormatter
* pFormatter
: aFormatters
)
229 pFormatter
->ReplaceSystemCL( eSysLanguage
);
230 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
232 if ( nHint
& ConfigurationHints::Currency
)
234 for(SvNumberFormatter
* pFormatter
: aFormatters
)
235 pFormatter
->ResetDefaultSystemCurrency();
237 if ( nHint
& ConfigurationHints::DatePatterns
)
239 for(SvNumberFormatter
* pFormatter
: aFormatters
)
240 pFormatter
->InvalidateDateAcceptancePatterns();
245 SvNumberFormatterRegistry_Impl
* SvNumberFormatter::pFormatterRegistry
= nullptr;
246 volatile bool SvNumberFormatter::bCurrencyTableInitialized
= false;
249 struct theCurrencyTable
:
250 public rtl::Static
< NfCurrencyTable
, theCurrencyTable
> {};
252 struct theLegacyOnlyCurrencyTable
:
253 public rtl::Static
< NfCurrencyTable
, theLegacyOnlyCurrencyTable
> {};
255 /** THE set of installed locales. */
256 struct theInstalledLocales
:
257 public rtl::Static
< NfInstalledLocales
, theInstalledLocales
> {};
260 sal_uInt16
SvNumberFormatter::nSystemCurrencyPosition
= 0;
262 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
263 // language dependent.
264 #define NF_BANKSYMBOL_FIX_POSITION 1
266 const sal_uInt16
SvNumberFormatter::UNLIMITED_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max();
267 const sal_uInt16
SvNumberFormatter::INPUTSTRING_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max()-1;
269 SvNumberFormatter::SvNumberFormatter( const Reference
< XComponentContext
>& rxContext
,
271 : m_xContext( rxContext
)
272 , maLanguageTag( eLang
)
274 ImpConstruct( eLang
);
277 SvNumberFormatter::~SvNumberFormatter()
280 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
281 pFormatterRegistry
->Remove( this );
282 if ( !pFormatterRegistry
->Count() )
284 delete pFormatterRegistry
;
285 pFormatterRegistry
= nullptr;
294 void SvNumberFormatter::ImpConstruct( LanguageType eLang
)
296 if ( eLang
== LANGUAGE_DONTKNOW
)
298 eLang
= UNKNOWN_SUBSTITUTE
;
302 eEvalDateFormat
= NF_EVALDATEFORMAT_INTL
;
303 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
305 maLanguageTag
.reset( eLang
);
306 pCharClass
.reset( new CharClass( m_xContext
, maLanguageTag
) );
307 xLocaleData
.init( m_xContext
, maLanguageTag
);
308 xCalendar
.init( m_xContext
, maLanguageTag
.getLocale() );
309 xTransliteration
.init( m_xContext
, eLang
);
310 xNatNum
.init( m_xContext
);
312 // cached locale data items
313 const LocaleDataWrapper
* pLoc
= GetLocaleData();
314 aDecimalSep
= pLoc
->getNumDecimalSep();
315 aDecimalSepAlt
= pLoc
->getNumDecimalSepAlt();
316 aThousandSep
= pLoc
->getNumThousandSep();
317 aDateSep
= pLoc
->getDateSep();
319 pStringScanner
.reset( new ImpSvNumberInputScan( this ) );
320 pFormatScanner
.reset( new ImpSvNumberformatScan( this ) );
321 pFormatTable
= nullptr;
323 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
324 pMergeTable
= nullptr;
327 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
328 GetFormatterRegistry().Insert( this );
332 void SvNumberFormatter::ChangeIntl(LanguageType eLnge
)
334 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
335 if (ActLnge
== eLnge
)
340 maLanguageTag
.reset( eLnge
);
341 pCharClass
->setLanguageTag( maLanguageTag
);
342 xLocaleData
.changeLocale( maLanguageTag
);
343 xCalendar
.changeLocale( maLanguageTag
.getLocale() );
344 xTransliteration
.changeLocale( eLnge
);
346 // cached locale data items, initialize BEFORE calling ChangeIntl below
347 const LocaleDataWrapper
* pLoc
= GetLocaleData();
348 aDecimalSep
= pLoc
->getNumDecimalSep();
349 aDecimalSepAlt
= pLoc
->getNumDecimalSepAlt();
350 aThousandSep
= pLoc
->getNumThousandSep();
351 aDateSep
= pLoc
->getDateSep();
353 pFormatScanner
->ChangeIntl();
354 pStringScanner
->ChangeIntl();
359 ::osl::Mutex
& SvNumberFormatter::GetGlobalMutex()
361 // #i77768# Due to a static reference in the toolkit lib
362 // we need a mutex that lives longer than the svl library.
363 // Otherwise the dtor would use a destructed mutex!!
364 static osl::Mutex
* persistentMutex(new osl::Mutex
);
366 return *persistentMutex
;
371 SvNumberFormatterRegistry_Impl
& SvNumberFormatter::GetFormatterRegistry()
373 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
374 if ( !pFormatterRegistry
)
376 pFormatterRegistry
= new SvNumberFormatterRegistry_Impl
;
378 return *pFormatterRegistry
;
381 void SvNumberFormatter::SetColorLink( const Link
<sal_uInt16
,Color
*>& rColorTableCallBack
)
383 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
384 aColorLink
= rColorTableCallBack
;
387 Color
* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex
)
389 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
390 if( aColorLink
.IsSet() )
392 return aColorLink
.Call(nIndex
);
400 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay
,
404 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
405 pFormatScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
406 pStringScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
409 const Date
& SvNumberFormatter::GetNullDate() const
411 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
412 return pFormatScanner
->GetNullDate();
415 void SvNumberFormatter::ChangeStandardPrec(short nPrec
)
417 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
418 pFormatScanner
->ChangeStandardPrec(nPrec
);
421 void SvNumberFormatter::SetNoZero(bool bNZ
)
423 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
427 sal_uInt16
SvNumberFormatter::GetStandardPrec() const
429 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
430 return pFormatScanner
->GetStandardPrec();
433 bool SvNumberFormatter::GetNoZero() const
435 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
439 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage
)
441 sal_uInt32 nCLOffset
= ImpGetCLOffset( LANGUAGE_SYSTEM
);
442 if ( nCLOffset
> MaxCLOffset
)
444 return ; // no SYSTEM entries to replace
446 const sal_uInt32 nMaxBuiltin
= nCLOffset
+ SV_MAX_COUNT_STANDARD_FORMATS
;
447 const sal_uInt32 nNextCL
= nCLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
450 // remove old builtin formats
451 auto it
= aFTable
.find( nCLOffset
);
452 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
<= nMaxBuiltin
)
454 it
= aFTable
.erase(it
);
457 // move additional and user defined to temporary table
458 SvNumberFormatTable aOldTable
;
459 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
< nNextCL
)
461 aOldTable
[ nKey
] = it
->second
.release();
462 it
= aFTable
.erase(it
);
465 // generate new old builtin formats
466 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
467 ActLnge
= LANGUAGE_DONTKNOW
;
468 ChangeIntl( LANGUAGE_SYSTEM
);
469 ImpGenerateFormats( nCLOffset
, true );
471 // convert additional and user defined from old system to new system
472 SvNumberformat
* pStdFormat
= GetFormatEntry( nCLOffset
+ ZF_STANDARD
);
473 sal_uInt32 nLastKey
= nMaxBuiltin
;
474 pFormatScanner
->SetConvertMode( eOldLanguage
, LANGUAGE_SYSTEM
, true , true);
475 while ( !aOldTable
.empty() )
477 nKey
= aOldTable
.begin()->first
;
478 if ( nLastKey
< nKey
)
482 std::unique_ptr
<SvNumberformat
> pOldEntry(aOldTable
.begin()->second
);
483 aOldTable
.erase( nKey
);
484 OUString
aString( pOldEntry
->GetFormatstring() );
486 // Same as PutEntry() but assures key position even if format code is
487 // a duplicate. Also won't mix up any LastInsertKey.
488 ChangeIntl( eOldLanguage
);
489 LanguageType eLge
= eOldLanguage
; // ConvertMode changes this
491 sal_Int32 nCheckPos
= -1;
492 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( aString
, pFormatScanner
.get(),
493 pStringScanner
.get(), nCheckPos
, eLge
));
494 if ( nCheckPos
== 0 )
496 SvNumFormatType eCheckType
= pNewEntry
->GetType();
497 if ( eCheckType
!= SvNumFormatType::UNDEFINED
)
499 pNewEntry
->SetType( eCheckType
| SvNumFormatType::DEFINED
);
503 pNewEntry
->SetType( SvNumFormatType::DEFINED
);
506 if ( aFTable
.emplace( nKey
, std::move(pNewEntry
) ).second
)
511 DBG_ASSERT( bCheck
, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
513 pFormatScanner
->SetConvertMode(false);
514 pStdFormat
->SetLastInsertKey( sal_uInt16(nLastKey
- nCLOffset
), SvNumberformat::FormatterPrivateAccess() );
516 // append new system additional formats
517 css::uno::Reference
< css::i18n::XNumberFormatCode
> xNFC
= i18n::NumberFormatMapper::create( m_xContext
);
518 ImpGenerateAdditionalFormats( nCLOffset
, xNFC
, true );
521 const css::uno::Reference
<css::uno::XComponentContext
>& SvNumberFormatter::GetComponentContext() const
526 const ImpSvNumberformatScan
* SvNumberFormatter::GetFormatScanner() const { return pFormatScanner
.get(); }
528 const LanguageTag
& SvNumberFormatter::GetLanguageTag() const { return maLanguageTag
; }
530 const ::utl::TransliterationWrapper
* SvNumberFormatter::GetTransliteration() const
532 return xTransliteration
.get();
535 const CharClass
* SvNumberFormatter::GetCharClass() const { return pCharClass
.get(); }
537 const LocaleDataWrapper
* SvNumberFormatter::GetLocaleData() const { return xLocaleData
.get(); }
539 CalendarWrapper
* SvNumberFormatter::GetCalendar() const { return xCalendar
.get(); }
541 const NativeNumberWrapper
* SvNumberFormatter::GetNatNum() const { return xNatNum
.get(); }
543 const OUString
& SvNumberFormatter::GetNumDecimalSep() const { return aDecimalSep
; }
545 const OUString
& SvNumberFormatter::GetNumDecimalSepAlt() const { return aDecimalSepAlt
; }
547 const OUString
& SvNumberFormatter::GetNumThousandSep() const { return aThousandSep
; }
549 const OUString
& SvNumberFormatter::GetDateSep() const { return aDateSep
; }
551 bool SvNumberFormatter::IsDecimalSep( std::u16string_view rStr
) const
553 if (rStr
== GetNumDecimalSep())
555 if (GetNumDecimalSepAlt().isEmpty())
557 return rStr
== GetNumDecimalSepAlt();
560 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index
) const
562 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
563 const SvNumberformat
* pFormat
= GetFormatEntry(F_Index
);
565 return pFormat
&& pFormat
->IsTextFormat();
568 bool SvNumberFormatter::PutEntry(OUString
& rString
,
569 sal_Int32
& nCheckPos
,
570 SvNumFormatType
& nType
,
571 sal_uInt32
& nKey
, // format key
573 bool bReplaceBooleanEquivalent
)
575 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
577 if (rString
.isEmpty()) // empty string
579 nCheckPos
= 1; // -> Error
582 if (eLnge
== LANGUAGE_DONTKNOW
)
586 ChangeIntl(eLnge
); // change locale if necessary
587 LanguageType eLge
= eLnge
; // non-const for ConvertMode
589 std::unique_ptr
<SvNumberformat
> p_Entry(new SvNumberformat(rString
,
590 pFormatScanner
.get(),
591 pStringScanner
.get(),
594 bReplaceBooleanEquivalent
));
596 if (nCheckPos
== 0) // Format ok
597 { // Type comparison:
598 SvNumFormatType eCheckType
= p_Entry
->GetType();
599 if ( eCheckType
!= SvNumFormatType::UNDEFINED
)
601 p_Entry
->SetType(eCheckType
| SvNumFormatType::DEFINED
);
606 p_Entry
->SetType(SvNumFormatType::DEFINED
);
607 nType
= SvNumFormatType::DEFINED
;
610 sal_uInt32 CLOffset
= ImpGenerateCL(eLge
); // create new standard formats if necessary
612 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLge
);
613 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
) // only in not yet present
615 SvNumberformat
* pStdFormat
= GetFormatEntry(CLOffset
+ ZF_STANDARD
);
616 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
617 if (nPos
+1 - CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
619 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
621 else if (!aFTable
.emplace( nPos
+1, std::move(p_Entry
)).second
)
623 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
629 pStdFormat
->SetLastInsertKey(static_cast<sal_uInt16
>(nKey
-CLOffset
), SvNumberformat::FormatterPrivateAccess());
636 bool SvNumberFormatter::PutandConvertEntry(OUString
& rString
,
637 sal_Int32
& nCheckPos
,
638 SvNumFormatType
& nType
,
641 LanguageType eNewLnge
,
642 bool bConvertDateOrder
,
643 bool bReplaceBooleanEquivalent
)
645 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
647 if (eNewLnge
== LANGUAGE_DONTKNOW
)
651 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, false, bConvertDateOrder
);
652 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
, bReplaceBooleanEquivalent
);
653 pFormatScanner
->SetConvertMode(false);
655 if (bReplaceBooleanEquivalent
&& nType
== SvNumFormatType::DEFINED
&& nCheckPos
== 0
656 && nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
658 // The boolean string formats are always "user defined" without any
660 const SvNumberformat
* pEntry
= GetFormatEntry(nKey
);
661 if (pEntry
&& pEntry
->GetType() == SvNumFormatType::DEFINED
)
663 // Replace boolean string format with Boolean in target locale, in
664 // case the source strings are the target locale's.
665 const OUString aSaveString
= rString
;
666 ChangeIntl(eNewLnge
);
667 if (pFormatScanner
->ReplaceBooleanEquivalent( rString
))
669 const sal_Int32 nSaveCheckPos
= nCheckPos
;
670 const SvNumFormatType nSaveType
= nType
;
671 const sal_uInt32 nSaveKey
= nKey
;
672 const bool bTargetRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eNewLnge
, false);
673 if (nCheckPos
== 0 && nType
== SvNumFormatType::LOGICAL
&& nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
679 SAL_WARN("svl.numbers", "SvNumberFormatter::PutandConvertEntry: can't scan boolean replacement");
680 // Live with the source boolean string format.
681 rString
= aSaveString
;
682 nCheckPos
= nSaveCheckPos
;
692 bool SvNumberFormatter::PutandConvertEntrySystem(OUString
& rString
,
693 sal_Int32
& nCheckPos
,
694 SvNumFormatType
& nType
,
697 LanguageType eNewLnge
)
699 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
701 if (eNewLnge
== LANGUAGE_DONTKNOW
)
705 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, true, true);
706 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
707 pFormatScanner
->SetConvertMode(false);
711 sal_uInt32
SvNumberFormatter::GetIndexPuttingAndConverting( OUString
& rString
, LanguageType eLnge
,
712 LanguageType eSysLnge
, SvNumFormatType
& rType
,
713 bool & rNewInserted
, sal_Int32
& rCheckPos
)
715 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
716 sal_uInt32 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
717 rNewInserted
= false;
720 // #62389# empty format string (of Writer) => General standard format
721 if (rString
.isEmpty())
725 else if (eLnge
== LANGUAGE_SYSTEM
&& eSysLnge
!= SvtSysLocale().GetLanguageTag().getLanguageType())
727 sal_uInt32 nOrig
= GetEntryKey( rString
, eSysLnge
);
728 if (nOrig
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
730 nKey
= nOrig
; // none available, maybe user-defined
734 nKey
= GetFormatForLanguageIfBuiltIn( nOrig
, SvtSysLocale().GetLanguageTag().getLanguageType() );
738 // Not a builtin format, convert.
739 // The format code string may get modified and adapted to the real
740 // language and wouldn't match eSysLnge anymore, do that on a copy.
741 OUString
aTmp( rString
);
742 rNewInserted
= PutandConvertEntrySystem( aTmp
, rCheckPos
, rType
,
743 nKey
, eLnge
, SvtSysLocale().GetLanguageTag().getLanguageType());
746 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
747 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
753 nKey
= GetEntryKey( rString
, eLnge
);
754 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
756 rNewInserted
= PutEntry( rString
, rCheckPos
, rType
, nKey
, eLnge
);
759 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
760 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
764 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
766 nKey
= GetStandardIndex( eLnge
);
768 rType
= GetType( nKey
);
769 // Convert any (!) old "automatic" currency format to new fixed currency
771 if (rType
& SvNumFormatType::CURRENCY
)
773 const SvNumberformat
* pFormat
= GetEntry( nKey
);
774 if (!pFormat
->HasNewCurrency())
778 DeleteEntry( nKey
); // don't leave trails of rubbish
779 rNewInserted
= false;
781 nKey
= GetStandardFormat( SvNumFormatType::CURRENCY
, eLnge
);
787 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey
)
789 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
793 void SvNumberFormatter::GetUsedLanguages( std::vector
<LanguageType
>& rList
)
795 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
798 sal_uInt32 nOffset
= 0;
799 while (nOffset
<= MaxCLOffset
)
801 SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
804 rList
.push_back( pFormat
->GetLanguage() );
806 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
811 void SvNumberFormatter::FillKeywordTable( NfKeywordTable
& rKeywords
,
814 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
816 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
817 for ( sal_uInt16 i
= 0; i
< NF_KEYWORD_ENTRIES_COUNT
; ++i
)
819 rKeywords
[i
] = rTable
[i
];
824 void SvNumberFormatter::FillKeywordTableForExcel( NfKeywordTable
& rKeywords
)
826 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
827 FillKeywordTable( rKeywords
, LANGUAGE_ENGLISH_US
);
829 // Replace upper case "GENERAL" with proper case "General".
830 rKeywords
[ NF_KEY_GENERAL
] = GetStandardName( LANGUAGE_ENGLISH_US
);
832 // Excel or OOXML do not specify format code keywords case sensitivity,
833 // but given and writes them lower case. Using upper case even lead to an
834 // odd misrepresentation in iOS viewer and OSX Quicklook viewer that
835 // strangely use "D" and "DD" for "days since beginning of year", which is
836 // nowhere defined. See tdf#126773
837 // Use lower case for all date and time keywords where known. See OOXML
838 // ECMA-376-1:2016 18.8.31 numFmts (Number Formats)
839 rKeywords
[ NF_KEY_MI
] = "m";
840 rKeywords
[ NF_KEY_MMI
] = "mm";
841 rKeywords
[ NF_KEY_M
] = "m";
842 rKeywords
[ NF_KEY_MM
] = "mm";
843 rKeywords
[ NF_KEY_MMM
] = "mmm";
844 rKeywords
[ NF_KEY_MMMM
] = "mmmm";
845 rKeywords
[ NF_KEY_MMMMM
] = "mmmmm";
846 rKeywords
[ NF_KEY_H
] = "h";
847 rKeywords
[ NF_KEY_HH
] = "hh";
848 rKeywords
[ NF_KEY_S
] = "s";
849 rKeywords
[ NF_KEY_SS
] = "ss";
850 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_Q ] = "q"; */
851 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_QQ ] = "qq"; */
852 rKeywords
[ NF_KEY_D
] = "d";
853 rKeywords
[ NF_KEY_DD
] = "dd";
854 rKeywords
[ NF_KEY_DDD
] = "ddd";
855 rKeywords
[ NF_KEY_DDDD
] = "dddd";
856 rKeywords
[ NF_KEY_YY
] = "yy";
857 rKeywords
[ NF_KEY_YYYY
] = "yyyy";
858 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAA ] = "aaa"; */
859 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAAA ] = "aaaa"; */
860 rKeywords
[ NF_KEY_EC
] = "e";
861 rKeywords
[ NF_KEY_EEC
] = "ee";
862 rKeywords
[ NF_KEY_G
] = "g";
863 rKeywords
[ NF_KEY_GG
] = "gg";
864 rKeywords
[ NF_KEY_GGG
] = "ggg";
865 rKeywords
[ NF_KEY_R
] = "r";
866 rKeywords
[ NF_KEY_RR
] = "rr";
867 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_WW ] = "ww"; */
869 // Remap codes unknown to Excel.
870 rKeywords
[ NF_KEY_NN
] = "ddd";
871 rKeywords
[ NF_KEY_NNN
] = "dddd";
872 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
873 rKeywords
[ NF_KEY_NNNN
] = "dddd";
874 // Export the Thai T NatNum modifier. This must be uppercase for internal reasons.
875 rKeywords
[ NF_KEY_THAI_T
] = "T";
879 static OUString
lcl_buildBooleanStringFormat( SvNumberformat
* pEntry
)
881 // Build Boolean number format, which needs non-zero and zero subformat
882 // codes with TRUE and FALSE strings.
883 const Color
* pColor
= nullptr;
884 OUString aFormatStr
, aTemp
;
885 pEntry
->GetOutputString( 1.0, aTemp
, &pColor
);
886 aFormatStr
+= "\"" + aTemp
+ "\";\"" + aTemp
+ "\";\"";
887 pEntry
->GetOutputString( 0.0, aTemp
, &pColor
);
888 aFormatStr
+= aTemp
+ "\"";
893 OUString
SvNumberFormatter::GetFormatStringForExcel( sal_uInt32 nKey
, const NfKeywordTable
& rKeywords
,
894 SvNumberFormatter
& rTempFormatter
) const
896 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
898 if (const SvNumberformat
* pEntry
= GetEntry( nKey
))
900 if (pEntry
->GetType() == SvNumFormatType::LOGICAL
)
902 // Build a source locale dependent string boolean. This is
903 // expected when loading the document in the same locale or if
904 // several locales are used, but not for other system/default
905 // locales. You can't have both. We could force to English for all
906 // locales like below, but Excel would display English strings then
907 // even for the system locale matching this locale. YMMV.
908 aFormatStr
= lcl_buildBooleanStringFormat( const_cast< SvNumberformat
* >(pEntry
));
912 bool bSystemLanguage
= false;
913 LanguageType nLang
= pEntry
->GetLanguage();
914 if (nLang
== LANGUAGE_SYSTEM
)
916 bSystemLanguage
= true;
917 nLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
919 if (nLang
!= LANGUAGE_ENGLISH_US
)
922 SvNumFormatType nType
= SvNumFormatType::DEFINED
;
924 OUString
aTemp( pEntry
->GetFormatstring());
925 /* TODO: do we want bReplaceBooleanEquivalent=true in any case
926 * to write it as English string boolean? */
927 rTempFormatter
.PutandConvertEntry( aTemp
, nCheckPos
, nType
, nTempKey
, nLang
, LANGUAGE_ENGLISH_US
,
928 false /*bConvertDateOrder*/, false /*bReplaceBooleanEquivalent*/);
929 SAL_WARN_IF( nCheckPos
!= 0, "svl.numbers",
930 "SvNumberFormatter::GetFormatStringForExcel - format code not convertible");
931 if (nTempKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
932 pEntry
= rTempFormatter
.GetEntry( nTempKey
);
937 if (pEntry
->GetType() == SvNumFormatType::LOGICAL
)
939 // This would be reached if bReplaceBooleanEquivalent was
940 // true and the source format is a string boolean like
941 // >"VRAI";"VRAI";"FAUX"< recognized as real boolean and
942 // properly converted. Then written as
943 // >"TRUE";"TRUE";"FALSE"<
944 aFormatStr
= lcl_buildBooleanStringFormat( const_cast< SvNumberformat
* >(pEntry
));
948 // GetLocaleData() returns the current locale's data, so switch
949 // before (which doesn't do anything if it was the same locale
951 rTempFormatter
.ChangeIntl( LANGUAGE_ENGLISH_US
);
952 aFormatStr
= pEntry
->GetMappedFormatstring( rKeywords
, *rTempFormatter
.GetLocaleData(), nLang
,
960 SAL_WARN("svl.numbers","SvNumberFormatter::GetFormatStringForExcel - format not found: " << nKey
);
963 if (aFormatStr
.isEmpty())
964 aFormatStr
= "General";
969 OUString
SvNumberFormatter::GetKeyword( LanguageType eLnge
, sal_uInt16 nIndex
)
971 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
973 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
974 if ( nIndex
< NF_KEYWORD_ENTRIES_COUNT
)
976 return rTable
[nIndex
];
978 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
983 OUString
SvNumberFormatter::GetStandardName( LanguageType eLnge
)
985 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
987 return pFormatScanner
->GetStandardName();
991 sal_uInt32
SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge
) const
993 sal_uInt32 nOffset
= 0;
994 while (nOffset
<= MaxCLOffset
)
996 const SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
997 if (pFormat
&& pFormat
->GetLanguage() == eLnge
)
1001 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
1006 sal_uInt32
SvNumberFormatter::ImpIsEntry(std::u16string_view rString
,
1007 sal_uInt32 nCLOffset
,
1010 sal_uInt32 res
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1011 auto it
= aFTable
.find( nCLOffset
);
1012 while ( res
== NUMBERFORMAT_ENTRY_NOT_FOUND
&&
1013 it
!= aFTable
.end() && it
->second
->GetLanguage() == eLnge
)
1015 if ( rString
== it
->second
->GetFormatstring() )
1028 SvNumberFormatTable
& SvNumberFormatter::GetFirstEntryTable(
1029 SvNumFormatType
& eType
,
1031 LanguageType
& rLnge
)
1033 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1034 SvNumFormatType eTypetmp
= eType
;
1035 if (eType
== SvNumFormatType::ALL
) // empty cell or don't care
1041 SvNumberformat
* pFormat
= GetFormatEntry(FIndex
);
1045 eType
= SvNumFormatType::ALL
;
1050 rLnge
= pFormat
->GetLanguage();
1051 eType
= pFormat
->GetMaskedType();
1052 if (eType
== SvNumFormatType::ALL
)
1054 eType
= SvNumFormatType::DEFINED
;
1057 else if (eType
== SvNumFormatType::DATETIME
)
1060 eType
= SvNumFormatType::DATE
;
1069 return GetEntryTable(eTypetmp
, FIndex
, rLnge
);
1072 sal_uInt32
SvNumberFormatter::ImpGenerateCL( LanguageType eLnge
)
1075 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
1076 if (CLOffset
> MaxCLOffset
)
1078 // new CL combination
1079 if (LocaleDataWrapper::areChecksEnabled())
1081 const LanguageTag
& rLoadedLocale
= xLocaleData
->getLoadedLanguageTag();
1082 if ( !rLoadedLocale
.equals( maLanguageTag
) )
1084 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( "SvNumberFormatter::ImpGenerateCL: locales don't match:" ));
1086 // test XML locale data FormatElement entries
1088 uno::Sequence
< i18n::FormatElement
> xSeq
= xLocaleData
->getAllFormats();
1089 // A test for completeness of formatindex="0" ...
1090 // formatindex="47" is not needed here since it is done in
1091 // ImpGenerateFormats().
1093 // Test for dupes of formatindex="..."
1094 for ( sal_Int32 j
= 0; j
< xSeq
.getLength(); j
++ )
1096 sal_Int16 nIdx
= xSeq
[j
].formatIndex
;
1097 OUStringBuffer aDupes
;
1098 for ( sal_Int32 i
= 0; i
< xSeq
.getLength(); i
++ )
1100 if ( i
!= j
&& xSeq
[i
].formatIndex
== nIdx
)
1104 aDupes
.append(xSeq
[i
].formatKey
);
1105 aDupes
.append( ") ");
1108 if ( !aDupes
.isEmpty() )
1110 OUString aMsg
= "XML locale data FormatElement formatindex dupe: "
1111 + OUString::number(nIdx
)
1112 + "\nFormatElements: "
1113 + OUString::number( j
)
1117 + aDupes
.makeStringAndClear();
1118 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1124 MaxCLOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
1125 ImpGenerateFormats( MaxCLOffset
, false/*bNoAdditionalFormats*/ );
1126 CLOffset
= MaxCLOffset
;
1131 SvNumberFormatTable
& SvNumberFormatter::ChangeCL(SvNumFormatType eType
,
1135 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1136 ImpGenerateCL(eLnge
);
1137 return GetEntryTable(eType
, FIndex
, ActLnge
);
1140 SvNumberFormatTable
& SvNumberFormatter::GetEntryTable(
1141 SvNumFormatType eType
,
1145 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1148 pFormatTable
->clear();
1152 pFormatTable
.reset( new SvNumberFormatTable
);
1155 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
1157 // Might generate and insert a default format for the given type
1158 // (e.g. currency) => has to be done before collecting formats.
1159 sal_uInt32 nDefaultIndex
= GetStandardFormat( eType
, ActLnge
);
1161 auto it
= aFTable
.find( CLOffset
);
1163 if (eType
== SvNumFormatType::ALL
)
1165 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
1166 { // copy all entries to output table
1167 (*pFormatTable
)[ it
->first
] = it
->second
.get();
1173 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
1174 { // copy entries of queried type to output table
1175 if ((it
->second
->GetType()) & eType
)
1176 (*pFormatTable
)[ it
->first
] = it
->second
.get();
1180 if ( !pFormatTable
->empty() )
1181 { // select default if queried format doesn't exist or queried type or
1182 // language differ from existing format
1183 SvNumberformat
* pEntry
= GetFormatEntry(FIndex
);
1184 if ( !pEntry
|| !(pEntry
->GetType() & eType
) || pEntry
->GetLanguage() != ActLnge
)
1186 FIndex
= nDefaultIndex
;
1189 return *pFormatTable
;
1192 bool SvNumberFormatter::IsNumberFormat(const OUString
& sString
,
1193 sal_uInt32
& F_Index
,
1195 SvNumInputOptions eInputOptions
)
1197 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1199 SvNumFormatType FType
;
1200 // For the 0 General format directly use the init/system locale and avoid
1201 // all overhead that is associated with a format passed to the scanner.
1202 const SvNumberformat
* pFormat
= (F_Index
== 0 ? nullptr : ImpSubstituteEntry( GetFormatEntry(F_Index
)));
1205 ChangeIntl(IniLnge
);
1206 FType
= SvNumFormatType::NUMBER
;
1210 FType
= pFormat
->GetMaskedType();
1211 if (FType
== SvNumFormatType::ALL
)
1213 FType
= SvNumFormatType::DEFINED
;
1215 ChangeIntl(pFormat
->GetLanguage());
1216 // Avoid scanner overhead with the General format of any locale.
1217 // These are never substituted above so safe to ignore.
1218 if ((F_Index
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0)
1220 assert(FType
== SvNumFormatType::NUMBER
);
1226 SvNumFormatType RType
= FType
;
1227 if (RType
== SvNumFormatType::TEXT
)
1229 res
= false; // type text preset => no conversion to number
1233 res
= pStringScanner
->IsNumberFormat(sString
, RType
, fOutNumber
, pFormat
, eInputOptions
);
1235 if (res
&& !IsCompatible(FType
, RType
)) // non-matching type
1239 case SvNumFormatType::DATE
:
1240 // Preserve ISO 8601 input.
1241 if (pStringScanner
->CanForceToIso8601( DateOrder::Invalid
))
1243 F_Index
= GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, ActLnge
);
1247 F_Index
= GetStandardFormat( RType
, ActLnge
);
1250 case SvNumFormatType::TIME
:
1251 if ( pStringScanner
->GetDecPos() )
1254 if ( pStringScanner
->GetNumericsCount() > 3 || fOutNumber
< 0.0 )
1256 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS00
, ActLnge
);
1260 F_Index
= GetFormatIndex( NF_TIME_MMSS00
, ActLnge
);
1263 else if ( fOutNumber
>= 1.0 || fOutNumber
< 0.0 )
1265 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS
, ActLnge
);
1269 F_Index
= GetStandardFormat( RType
, ActLnge
);
1272 case SvNumFormatType::DATETIME
:
1273 // Preserve ISO 8601 input.
1274 if (pStringScanner
->HasIso8601Tsep())
1276 F_Index
= GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS
, ActLnge
);
1278 else if (pStringScanner
->CanForceToIso8601( DateOrder::Invalid
))
1280 F_Index
= GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, ActLnge
);
1284 F_Index
= GetStandardFormat( RType
, ActLnge
);
1288 F_Index
= GetStandardFormat( RType
, ActLnge
);
1294 LanguageType
SvNumberFormatter::GetLanguage() const
1296 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1301 bool SvNumberFormatter::IsCompatible(SvNumFormatType eOldType
, SvNumFormatType eNewType
)
1303 if (eOldType
== eNewType
)
1307 else if (eOldType
== SvNumFormatType::DEFINED
)
1315 case SvNumFormatType::NUMBER
:
1318 case SvNumFormatType::PERCENT
:
1319 case SvNumFormatType::CURRENCY
:
1320 case SvNumFormatType::SCIENTIFIC
:
1321 case SvNumFormatType::FRACTION
:
1322 case SvNumFormatType::DEFINED
:
1324 case SvNumFormatType::LOGICAL
:
1329 case SvNumFormatType::DATE
:
1332 case SvNumFormatType::DATETIME
:
1338 case SvNumFormatType::TIME
:
1341 case SvNumFormatType::DATETIME
:
1347 case SvNumFormatType::DATETIME
:
1350 case SvNumFormatType::TIME
:
1351 case SvNumFormatType::DATE
:
1357 case SvNumFormatType::DURATION
:
1366 sal_uInt32
SvNumberFormatter::ImpGetDefaultFormat( SvNumFormatType nType
)
1368 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
1372 case SvNumFormatType::DATE
:
1373 nSearch
= CLOffset
+ ZF_STANDARD_DATE
;
1375 case SvNumFormatType::TIME
:
1376 nSearch
= CLOffset
+ ZF_STANDARD_TIME
;
1378 case SvNumFormatType::DATETIME
:
1379 nSearch
= CLOffset
+ ZF_STANDARD_DATETIME
;
1381 case SvNumFormatType::DURATION
:
1382 nSearch
= CLOffset
+ ZF_STANDARD_DURATION
;
1384 case SvNumFormatType::PERCENT
:
1385 nSearch
= CLOffset
+ ZF_STANDARD_PERCENT
;
1387 case SvNumFormatType::SCIENTIFIC
:
1388 nSearch
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1391 nSearch
= CLOffset
+ ZF_STANDARD
;
1394 DefaultFormatKeysMap::const_iterator it
= aDefaultFormatKeys
.find( nSearch
);
1395 sal_uInt32 nDefaultFormat
= (it
!= aDefaultFormatKeys
.end() ?
1396 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
1397 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1399 // look for a defined standard
1400 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
1402 auto it2
= aFTable
.find( CLOffset
);
1403 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
1405 const SvNumberformat
* pEntry
= it2
->second
.get();
1406 if ( pEntry
->IsStandard() && (pEntry
->GetMaskedType() == nType
) )
1408 nDefaultFormat
= nKey
;
1414 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1415 { // none found, use old fixed standards
1418 case SvNumFormatType::DATE
:
1419 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATE
;
1421 case SvNumFormatType::TIME
:
1422 nDefaultFormat
= CLOffset
+ ZF_STANDARD_TIME
+1;
1424 case SvNumFormatType::DATETIME
:
1425 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATETIME
;
1427 case SvNumFormatType::DURATION
:
1428 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DURATION
;
1430 case SvNumFormatType::PERCENT
:
1431 nDefaultFormat
= CLOffset
+ ZF_STANDARD_PERCENT
+1;
1433 case SvNumFormatType::SCIENTIFIC
:
1434 nDefaultFormat
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1437 nDefaultFormat
= CLOffset
+ ZF_STANDARD
;
1440 aDefaultFormatKeys
[ nSearch
] = nDefaultFormat
;
1442 return nDefaultFormat
;
1446 sal_uInt32
SvNumberFormatter::GetStandardFormat( SvNumFormatType eType
, LanguageType eLnge
)
1448 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1449 if (eLnge
== LANGUAGE_DONTKNOW
)
1453 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1456 case SvNumFormatType::CURRENCY
:
1457 return ( eLnge
== LANGUAGE_SYSTEM
) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1458 case SvNumFormatType::DURATION
:
1459 return GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
);
1460 case SvNumFormatType::DATE
:
1461 case SvNumFormatType::TIME
:
1462 case SvNumFormatType::DATETIME
:
1463 case SvNumFormatType::PERCENT
:
1464 case SvNumFormatType::SCIENTIFIC
:
1465 return ImpGetDefaultFormat( eType
);
1466 case SvNumFormatType::FRACTION
:
1467 return CLOffset
+ ZF_STANDARD_FRACTION
;
1468 case SvNumFormatType::LOGICAL
:
1469 return CLOffset
+ ZF_STANDARD_LOGICAL
;
1470 case SvNumFormatType::TEXT
:
1471 return CLOffset
+ ZF_STANDARD_TEXT
;
1472 case SvNumFormatType::ALL
:
1473 case SvNumFormatType::DEFINED
:
1474 case SvNumFormatType::NUMBER
:
1475 case SvNumFormatType::UNDEFINED
:
1477 return CLOffset
+ ZF_STANDARD
;
1481 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex
,
1482 LanguageType eLnge
)
1484 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1486 nFIndex
== GetFormatIndex( NF_TIME_MMSS00
, eLnge
) ||
1487 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
) ||
1488 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
)
1492 sal_uInt32
SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex
, SvNumFormatType eType
,
1493 LanguageType eLnge
)
1495 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1496 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1499 return GetStandardFormat( eType
, eLnge
);
1502 sal_uInt32
SvNumberFormatter::GetTimeFormat( double fNumber
, LanguageType eLnge
, bool bForceDuration
)
1504 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1506 if ( fNumber
< 0.0 )
1513 double fSeconds
= fNumber
* 86400;
1514 if ( floor( fSeconds
+ 0.5 ) * 100 != floor( fSeconds
* 100 + 0.5 ) )
1515 { // with 100th seconds
1516 if ( bForceDuration
|| bSign
|| fSeconds
>= 3600 )
1517 return GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
);
1519 return GetFormatIndex( NF_TIME_MMSS00
, eLnge
);
1523 if ( bForceDuration
|| bSign
|| fNumber
>= 1.0 )
1524 return GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
);
1526 return GetStandardFormat( SvNumFormatType::TIME
, eLnge
);
1530 sal_uInt32
SvNumberFormatter::GetStandardFormat( double fNumber
, sal_uInt32 nFIndex
,
1531 SvNumFormatType eType
, LanguageType eLnge
)
1533 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1534 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1539 case SvNumFormatType::DURATION
:
1540 return GetTimeFormat( fNumber
, eLnge
, true);
1541 case SvNumFormatType::TIME
:
1542 return GetTimeFormat( fNumber
, eLnge
, false);
1544 return GetStandardFormat( eType
, eLnge
);
1548 sal_uInt32
SvNumberFormatter::GuessDateTimeFormat( SvNumFormatType
& rType
, double fNumber
, LanguageType eLnge
)
1550 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1551 // Categorize the format according to the implementation of
1552 // SvNumberFormatter::GetEditFormat(), making assumptions about what
1553 // would be time only.
1555 if (0.0 <= fNumber
&& fNumber
< 1.0)
1558 rType
= SvNumFormatType::TIME
;
1559 nRet
= GetTimeFormat( fNumber
, eLnge
, false);
1561 else if (fabs( fNumber
) * 24 < 0x7fff)
1563 // Assuming duration within 32k hours or 3.7 years.
1564 // This should be SvNumFormatType::DURATION instead, but the outer
1565 // world can't cope with that.
1566 rType
= SvNumFormatType::TIME
;
1567 nRet
= GetTimeFormat( fNumber
, eLnge
, true);
1569 else if (rtl::math::approxFloor( fNumber
) != fNumber
)
1572 rType
= SvNumFormatType::DATETIME
;
1573 nRet
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLnge
);
1578 rType
= SvNumFormatType::DATE
;
1579 nRet
= GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, eLnge
);
1584 sal_uInt32
SvNumberFormatter::GetEditFormat( double fNumber
, sal_uInt32 nFIndex
,
1585 SvNumFormatType eType
, LanguageType eLang
,
1586 SvNumberformat
const * pFormat
)
1588 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1589 sal_uInt32 nKey
= nFIndex
;
1592 // #61619# always edit using 4-digit year
1593 case SvNumFormatType::DATE
:
1595 // Preserve ISO 8601 format.
1597 nFIndex
== GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, eLang
) ||
1598 nFIndex
== GetFormatIndex( NF_DATE_DIN_YYMMDD
, eLang
) ||
1599 nFIndex
== GetFormatIndex( NF_DATE_DIN_MMDD
, eLang
) ||
1600 (pFormat
&& pFormat
->IsIso8601( 0 ));
1601 if (rtl::math::approxFloor( fNumber
) != fNumber
)
1603 // fdo#34977 preserve time when editing even if only date was
1606 nKey
= GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eLang
);
1608 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1613 nKey
= GetFormatIndex( NF_DATE_ISO_YYYYMMDD
, eLang
);
1615 nKey
= GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, eLang
);
1619 case SvNumFormatType::TIME
:
1620 if (fNumber
< 0.0 || fNumber
>= 1.0)
1622 /* XXX NOTE: this is a purely arbitrary value within the limits
1623 * of a signed 16-bit. 32k hours are 3.7 years ... or
1624 * 1903-09-26 if date. */
1625 if (fabs( fNumber
) * 24 < 0x7fff)
1626 nKey
= GetTimeFormat( fNumber
, eLang
, true);
1627 // Preserve duration, use [HH]:MM:SS instead of time.
1629 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1630 // Assume that a large value is a datetime with only time
1634 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1636 case SvNumFormatType::DURATION
:
1637 nKey
= GetTimeFormat( fNumber
, eLang
, true);
1639 case SvNumFormatType::DATETIME
:
1640 if (nFIndex
== GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS
, eLang
))
1641 nKey
= GetFormatIndex( NF_DATETIME_ISO_YYYYMMDDTHHMMSS
, eLang
);
1642 else if (nFIndex
== GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eLang
) || (pFormat
&& pFormat
->IsIso8601( 0 )))
1643 nKey
= GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eLang
);
1645 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1647 case SvNumFormatType::NUMBER
:
1648 nKey
= GetStandardFormat( eType
, eLang
);
1651 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1656 void SvNumberFormatter::GetInputLineString(const double& fOutNumber
,
1658 OUString
& sOutString
,
1661 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1662 const Color
* pColor
;
1663 sal_uInt32 nRealKey
= nFIndex
;
1664 SvNumberformat
* pFormat
= ImpSubstituteEntry( GetFormatEntry( nFIndex
), &nRealKey
);
1667 pFormat
= GetFormatEntry(ZF_STANDARD
);
1670 LanguageType eLang
= pFormat
->GetLanguage();
1671 ChangeIntl( eLang
);
1673 SvNumFormatType eType
= pFormat
->GetMaskedType();
1674 if (eType
== SvNumFormatType::ALL
)
1676 // Mixed types in subformats, use first.
1677 /* XXX we could choose a subformat according to fOutNumber and
1678 * subformat conditions, but they may exist to suppress 0 or negative
1679 * numbers so wouldn't be a safe bet. */
1680 eType
= pFormat
->GetNumForInfoScannedType(0);
1683 sal_uInt16 nOldPrec
= pFormatScanner
->GetStandardPrec();
1684 bool bPrecChanged
= false;
1685 if (eType
== SvNumFormatType::NUMBER
||
1686 eType
== SvNumFormatType::PERCENT
||
1687 eType
== SvNumFormatType::CURRENCY
||
1688 eType
== SvNumFormatType::SCIENTIFIC
||
1689 eType
== SvNumFormatType::FRACTION
)
1691 if (eType
!= SvNumFormatType::PERCENT
) // special treatment of % later
1693 eType
= SvNumFormatType::NUMBER
;
1695 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1696 bPrecChanged
= true;
1699 sal_uInt32 nKey
= GetEditFormat( fOutNumber
, nRealKey
, eType
, eLang
, pFormat
);
1700 // if bFiltering true keep the nRealKey format
1701 if ( nKey
!= nRealKey
&& !bFiltering
)
1703 pFormat
= GetFormatEntry( nKey
);
1707 if ( eType
== SvNumFormatType::TIME
&& pFormat
->GetFormatPrecision() )
1709 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1710 bPrecChanged
= true;
1712 pFormat
->GetOutputString(fOutNumber
, sOutString
, &pColor
);
1716 ChangeStandardPrec(nOldPrec
);
1720 void SvNumberFormatter::GetOutputString(const OUString
& sString
,
1722 OUString
& sOutString
,
1723 const Color
** ppColor
,
1724 bool bUseStarFormat
)
1726 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1727 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1728 // ImpSubstituteEntry() is unnecessary here because so far only numeric
1729 // (time and date) are substituted.
1732 pFormat
= GetFormatEntry(ZF_STANDARD_TEXT
);
1734 if (!pFormat
->IsTextFormat() && !pFormat
->HasTextFormat())
1737 sOutString
= sString
;
1741 ChangeIntl(pFormat
->GetLanguage());
1742 if ( bUseStarFormat
)
1744 pFormat
->SetStarFormatSupport( true );
1746 pFormat
->GetOutputString(sString
, sOutString
, ppColor
);
1747 if ( bUseStarFormat
)
1749 pFormat
->SetStarFormatSupport( false );
1754 void SvNumberFormatter::GetOutputString(const double& fOutNumber
,
1756 OUString
& sOutString
,
1757 const Color
** ppColor
,
1758 bool bUseStarFormat
)
1760 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1761 if (bNoZero
&& fOutNumber
== 0.0)
1766 SvNumberformat
* pFormat
= ImpSubstituteEntry( GetFormatEntry( nFIndex
));
1768 pFormat
= GetFormatEntry(ZF_STANDARD
);
1769 ChangeIntl(pFormat
->GetLanguage());
1770 if ( bUseStarFormat
)
1771 pFormat
->SetStarFormatSupport( true );
1772 pFormat
->GetOutputString(fOutNumber
, sOutString
, ppColor
);
1773 if ( bUseStarFormat
)
1774 pFormat
->SetStarFormatSupport( false );
1777 bool SvNumberFormatter::GetPreviewString(const OUString
& sFormatString
,
1778 double fPreviewNumber
,
1779 OUString
& sOutString
,
1780 const Color
** ppColor
,
1782 bool bUseStarFormat
)
1784 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1785 if (sFormatString
.isEmpty()) // no empty string
1789 if (eLnge
== LANGUAGE_DONTKNOW
)
1793 ChangeIntl(eLnge
); // change locale if necessary
1795 sal_Int32 nCheckPos
= -1;
1796 OUString sTmpString
= sFormatString
;
1797 SvNumberformat
aEntry(sTmpString
,
1798 pFormatScanner
.get(),
1799 pStringScanner
.get(),
1802 if (nCheckPos
== 0) // String ok
1804 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
1805 sal_uInt32 nKey
= ImpIsEntry(aEntry
.GetFormatstring(),CLOffset
, eLnge
);
1806 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1808 GetOutputString(fPreviewNumber
, nKey
, sOutString
, ppColor
, bUseStarFormat
);
1812 if ( bUseStarFormat
)
1814 aEntry
.SetStarFormatSupport( true );
1816 aEntry
.GetOutputString(fPreviewNumber
, sOutString
, ppColor
);
1817 if ( bUseStarFormat
)
1819 aEntry
.SetStarFormatSupport( false );
1830 bool SvNumberFormatter::GetPreviewStringGuess( const OUString
& sFormatString
,
1831 double fPreviewNumber
,
1832 OUString
& sOutString
,
1833 const Color
** ppColor
,
1834 LanguageType eLnge
)
1836 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1837 if (sFormatString
.isEmpty()) // no empty string
1841 if (eLnge
== LANGUAGE_DONTKNOW
)
1845 ChangeIntl( eLnge
);
1847 bool bEnglish
= (eLnge
== LANGUAGE_ENGLISH_US
);
1849 OUString
aFormatStringUpper( pCharClass
->uppercase( sFormatString
) );
1850 sal_uInt32 nCLOffset
= ImpGenerateCL( eLnge
);
1851 sal_uInt32 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, eLnge
);
1852 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1854 // Target format present
1855 GetOutputString( fPreviewNumber
, nKey
, sOutString
, ppColor
);
1859 std::optional
<SvNumberformat
> pEntry
;
1860 sal_Int32 nCheckPos
= -1;
1861 OUString sTmpString
;
1865 sTmpString
= sFormatString
;
1866 pEntry
.emplace( sTmpString
, pFormatScanner
.get(),
1867 pStringScanner
.get(), nCheckPos
, eLnge
);
1871 nCLOffset
= ImpGenerateCL( LANGUAGE_ENGLISH_US
);
1872 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, LANGUAGE_ENGLISH_US
);
1873 bool bEnglishFormat
= (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
1875 // Try English -> other or convert english to other
1876 LanguageType eFormatLang
= LANGUAGE_ENGLISH_US
;
1877 pFormatScanner
->SetConvertMode( LANGUAGE_ENGLISH_US
, eLnge
, false, false);
1878 sTmpString
= sFormatString
;
1879 pEntry
.emplace( sTmpString
, pFormatScanner
.get(),
1880 pStringScanner
.get(), nCheckPos
, eFormatLang
);
1881 pFormatScanner
->SetConvertMode( false );
1882 ChangeIntl( eLnge
);
1884 if ( !bEnglishFormat
)
1886 if ( nCheckPos
!= 0 || xTransliteration
->isEqual( sFormatString
,
1887 pEntry
->GetFormatstring() ) )
1890 // Force locale's keywords.
1891 pFormatScanner
->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy
);
1892 sTmpString
= sFormatString
;
1893 pEntry
.emplace( sTmpString
, pFormatScanner
.get(),
1894 pStringScanner
.get(), nCheckPos
, eLnge
);
1899 sal_Int32 nCheckPos2
= -1;
1900 // try other --> english
1901 eFormatLang
= eLnge
;
1902 pFormatScanner
->SetConvertMode( eLnge
, LANGUAGE_ENGLISH_US
, false, false);
1903 sTmpString
= sFormatString
;
1904 SvNumberformat
aEntry2( sTmpString
, pFormatScanner
.get(),
1905 pStringScanner
.get(), nCheckPos2
, eFormatLang
);
1906 pFormatScanner
->SetConvertMode( false );
1907 ChangeIntl( eLnge
);
1908 if ( nCheckPos2
== 0 && !xTransliteration
->isEqual( sFormatString
,
1909 aEntry2
.GetFormatstring() ) )
1912 // Force locale's keywords.
1913 pFormatScanner
->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy
);
1914 sTmpString
= sFormatString
;
1915 pEntry
.emplace( sTmpString
, pFormatScanner
.get(),
1916 pStringScanner
.get(), nCheckPos
, eLnge
);
1922 if (nCheckPos
== 0) // String ok
1924 ImpGenerateCL( eLnge
); // create new standard formats if necessary
1925 pEntry
->GetOutputString( fPreviewNumber
, sOutString
, ppColor
);
1931 bool SvNumberFormatter::GetPreviewString( const OUString
& sFormatString
,
1932 const OUString
& sPreviewString
,
1933 OUString
& sOutString
,
1934 const Color
** ppColor
,
1935 LanguageType eLnge
)
1937 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1938 if (sFormatString
.isEmpty()) // no empty string
1942 if (eLnge
== LANGUAGE_DONTKNOW
)
1946 ChangeIntl(eLnge
); // switch if needed
1948 sal_Int32 nCheckPos
= -1;
1949 OUString sTmpString
= sFormatString
;
1950 SvNumberformat
aEntry( sTmpString
,
1951 pFormatScanner
.get(),
1952 pStringScanner
.get(),
1955 if (nCheckPos
== 0) // String ok
1957 // May have to create standard formats for this locale.
1958 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1959 sal_uInt32 nKey
= ImpIsEntry( aEntry
.GetFormatstring(), CLOffset
, eLnge
);
1960 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1962 GetOutputString( sPreviewString
, nKey
, sOutString
, ppColor
);
1966 // If the format is valid but not a text format and does not
1967 // include a text subformat, an empty string would result. Same as
1968 // in SvNumberFormatter::GetOutputString()
1969 if (aEntry
.IsTextFormat() || aEntry
.HasTextFormat())
1971 aEntry
.GetOutputString( sPreviewString
, sOutString
, ppColor
);
1976 sOutString
= sPreviewString
;
1987 sal_uInt32
SvNumberFormatter::TestNewString(const OUString
& sFormatString
,
1990 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1991 if (sFormatString
.isEmpty()) // no empty string
1993 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
1995 if (eLnge
== LANGUAGE_DONTKNOW
)
1999 ChangeIntl(eLnge
); // change locale if necessary
2002 sal_Int32 nCheckPos
= -1;
2003 OUString sTmpString
= sFormatString
;
2004 SvNumberformat
aEntry(sTmpString
,
2005 pFormatScanner
.get(),
2006 pStringScanner
.get(),
2009 if (nCheckPos
== 0) // String ok
2011 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
2012 nRes
= ImpIsEntry(aEntry
.GetFormatstring(),CLOffset
, eLnge
);
2017 nRes
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
2022 SvNumberformat
* SvNumberFormatter::ImpInsertFormat( const css::i18n::NumberFormatCode
& rCode
,
2023 sal_uInt32 nPos
, bool bAfterChangingSystemCL
,
2024 sal_Int16 nOrgIndex
)
2026 SAL_WARN_IF( NF_INDEX_TABLE_RESERVED_START
<= rCode
.Index
&& rCode
.Index
< NF_INDEX_TABLE_ENTRIES
,
2027 "svl.numbers", "i18npool locale '" << maLanguageTag
.getBcp47() <<
2028 "' uses reserved formatIndex value " << rCode
.Index
<< ", next free: " << NF_INDEX_TABLE_ENTRIES
<<
2029 " Please see description in include/svl/zforlist.hxx at end of enum NfIndexTableOffset");
2030 assert( (rCode
.Index
< NF_INDEX_TABLE_RESERVED_START
|| NF_INDEX_TABLE_ENTRIES
<= rCode
.Index
) &&
2031 "reserved formatIndex, see warning above");
2033 OUString
aCodeStr( rCode
.Code
);
2034 if ( rCode
.Index
< NF_INDEX_TABLE_RESERVED_START
&&
2035 rCode
.Usage
== css::i18n::KNumberFormatUsage::CURRENCY
&&
2036 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
2037 { // strip surrounding [$...] on automatic currency
2038 if ( aCodeStr
.indexOf( "[$" ) >= 0)
2039 aCodeStr
= SvNumberformat::StripNewCurrencyDelimiters( aCodeStr
);
2042 if (LocaleDataWrapper::areChecksEnabled() &&
2043 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
2045 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index " +
2046 OUString::number( rCode
.Index
) +
2049 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
2053 sal_Int32 nCheckPos
= 0;
2054 std::unique_ptr
<SvNumberformat
> pFormat(new SvNumberformat(aCodeStr
,
2055 pFormatScanner
.get(),
2056 pStringScanner
.get(),
2061 if (LocaleDataWrapper::areChecksEnabled())
2063 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
2064 OUString::number( rCode
.Index
) +
2067 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
2071 if ( rCode
.Index
>= NF_INDEX_TABLE_RESERVED_START
)
2073 sal_uInt32 nCLOffset
= nPos
- (nPos
% SV_COUNTRY_LANGUAGE_OFFSET
);
2074 sal_uInt32 nKey
= ImpIsEntry( aCodeStr
, nCLOffset
, ActLnge
);
2075 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
2077 // If bAfterChangingSystemCL there will definitely be some dups,
2079 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL
)
2081 // Test for duplicate indexes in locale data.
2082 switch ( nOrgIndex
)
2084 // These may be dups of integer versions for locales where
2085 // currencies have no decimals like Italian Lira.
2086 case NF_CURRENCY_1000DEC2
: // NF_CURRENCY_1000INT
2087 case NF_CURRENCY_1000DEC2_RED
: // NF_CURRENCY_1000INT_RED
2088 case NF_CURRENCY_1000DEC2_DASHED
: // NF_CURRENCY_1000INT_RED
2092 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: dup format code, index "
2093 + OUString::number( rCode
.Index
)
2096 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
2102 else if ( nPos
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2104 if (LocaleDataWrapper::areChecksEnabled())
2106 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: too many format codes, index "
2107 + OUString::number( rCode
.Index
)
2110 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
2115 auto pFormat2
= pFormat
.get();
2116 if ( !aFTable
.emplace( nPos
, std::move(pFormat
) ).second
)
2118 if (LocaleDataWrapper::areChecksEnabled())
2120 OUString aMsg
= "ImpInsertFormat: can't insert number format key pos: "
2121 + OUString::number( nPos
)
2123 + OUString::number( rCode
.Index
)
2126 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
2130 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
2134 if ( rCode
.Default
)
2135 pFormat2
->SetStandard();
2136 if ( !rCode
.DefaultName
.isEmpty() )
2137 pFormat2
->SetComment( rCode
.DefaultName
);
2141 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat
,
2144 sal_uInt16
& nPrecision
,
2145 sal_uInt16
& nLeadingCnt
)
2148 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2149 SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
2151 pFormat
->GetFormatSpecialInfo(bThousand
, IsRed
,
2152 nPrecision
, nLeadingCnt
);
2157 nPrecision
= pFormatScanner
->GetStandardPrec();
2162 sal_uInt16
SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat
) const
2164 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2165 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
2167 return pFormat
->GetFormatPrecision();
2169 return pFormatScanner
->GetStandardPrec();
2172 sal_uInt16
SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat
) const
2174 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2175 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
2177 return pFormat
->GetFormatIntegerDigits();
2182 OUString
SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat
) const
2184 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2185 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
2188 return GetNumDecimalSep();
2190 return GetLangDecimalSep( pFormat
->GetLanguage());
2193 OUString
SvNumberFormatter::GetLangDecimalSep( LanguageType nLang
) const
2195 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2196 if (nLang
== ActLnge
)
2198 return GetNumDecimalSep();
2201 LanguageType eSaveLang
= xLocaleData
.getCurrentLanguage();
2202 if (nLang
== eSaveLang
)
2204 aRet
= xLocaleData
->getNumDecimalSep();
2208 LanguageTag
aSaveLocale( xLocaleData
->getLanguageTag() );
2209 const_cast<SvNumberFormatter
*>(this)->xLocaleData
.changeLocale( LanguageTag( nLang
));
2210 aRet
= xLocaleData
->getNumDecimalSep();
2211 const_cast<SvNumberFormatter
*>(this)->xLocaleData
.changeLocale( aSaveLocale
);
2217 sal_uInt32
SvNumberFormatter::GetFormatSpecialInfo( const OUString
& rFormatString
,
2218 bool& bThousand
, bool& IsRed
, sal_uInt16
& nPrecision
,
2219 sal_uInt16
& nLeadingCnt
, LanguageType eLnge
)
2222 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2223 if (eLnge
== LANGUAGE_DONTKNOW
)
2227 ChangeIntl(eLnge
); // change locale if necessary
2229 OUString
aTmpStr( rFormatString
);
2230 sal_Int32 nCheckPos
= 0;
2231 SvNumberformat
aFormat( aTmpStr
, pFormatScanner
.get(),
2232 pStringScanner
.get(), nCheckPos
, eLnge
);
2233 if ( nCheckPos
== 0 )
2235 aFormat
.GetFormatSpecialInfo( bThousand
, IsRed
, nPrecision
, nLeadingCnt
);
2241 nPrecision
= pFormatScanner
->GetStandardPrec();
2247 OUString
SvNumberFormatter::GetCalcCellReturn( sal_uInt32 nFormat
) const
2249 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2250 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
2255 bool bAppendPrec
= true;
2256 sal_uInt16 nPrec
, nLeading
;
2257 bool bThousand
, bIsRed
;
2258 pFormat
->GetFormatSpecialInfo( bThousand
, bIsRed
, nPrec
, nLeading
);
2260 switch (pFormat
->GetMaskedType())
2262 case SvNumFormatType::NUMBER
:
2268 case SvNumFormatType::CURRENCY
:
2271 case SvNumFormatType::SCIENTIFIC
:
2274 case SvNumFormatType::PERCENT
:
2279 bAppendPrec
= false;
2280 switch (GetIndexTableOffset( nFormat
))
2282 case NF_DATE_SYSTEM_SHORT
:
2283 case NF_DATE_SYS_DMMMYY
:
2284 case NF_DATE_SYS_DDMMYY
:
2285 case NF_DATE_SYS_DDMMYYYY
:
2286 case NF_DATE_SYS_DMMMYYYY
:
2287 case NF_DATE_DIN_DMMMYYYY
:
2288 case NF_DATE_SYS_DMMMMYYYY
:
2289 case NF_DATE_DIN_DMMMMYYYY
: aStr
= "D1"; break;
2290 case NF_DATE_SYS_DDMMM
: aStr
= "D2"; break;
2291 case NF_DATE_SYS_MMYY
: aStr
= "D3"; break;
2292 case NF_DATETIME_SYSTEM_SHORT_HHMM
:
2293 case NF_DATETIME_SYS_DDMMYYYY_HHMM
:
2294 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS
:
2296 case NF_DATE_DIN_MMDD
: aStr
= "D5"; break;
2297 case NF_TIME_HHMMSSAMPM
: aStr
= "D6"; break;
2298 case NF_TIME_HHMMAMPM
: aStr
= "D7"; break;
2299 case NF_TIME_HHMMSS
: aStr
= "D8"; break;
2300 case NF_TIME_HHMM
: aStr
= "D9"; break;
2301 default: aStr
= "G";
2307 aStr
+= OUString::number(nPrec
);
2309 if (pFormat
->GetColor( 1 ))
2310 aStr
+= "-"; // negative color
2312 /* FIXME: this probably should not match on literal strings and only be
2313 * performed on number or currency formats, but it is what Calc originally
2315 if (pFormat
->GetFormatstring().indexOf('(') != -1)
2321 sal_Int32
SvNumberFormatter::ImpGetFormatCodeIndex(
2322 css::uno::Sequence
< css::i18n::NumberFormatCode
>& rSeq
,
2323 const NfIndexTableOffset nTabOff
)
2325 auto pSeq
= std::find_if(rSeq
.begin(), rSeq
.end(),
2326 [nTabOff
](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Index
== nTabOff
; });
2327 if (pSeq
!= rSeq
.end())
2328 return static_cast<sal_Int32
>(std::distance(rSeq
.begin(), pSeq
));
2329 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff
< NF_CURRENCY_START
2330 || NF_CURRENCY_END
< nTabOff
|| nTabOff
== NF_CURRENCY_1000INT
2331 || nTabOff
== NF_CURRENCY_1000INT_RED
2332 || nTabOff
== NF_CURRENCY_1000DEC2_CCC
))
2333 { // currency entries with decimals might not exist, e.g. Italian Lira
2334 OUString aMsg
= "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "
2335 + OUString::number( nTabOff
);
2336 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo(aMsg
));
2338 if ( rSeq
.hasElements() )
2340 // look for a preset default
2341 pSeq
= std::find_if(rSeq
.begin(), rSeq
.end(),
2342 [](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Default
; });
2343 if (pSeq
!= rSeq
.end())
2344 return static_cast<sal_Int32
>(std::distance(rSeq
.begin(), pSeq
));
2345 // currencies are special, not all format codes must exist, but all
2346 // builtin number format key index positions must have a format assigned
2347 if ( NF_CURRENCY_START
<= nTabOff
&& nTabOff
<= NF_CURRENCY_END
)
2349 // look for a format with decimals
2350 pSeq
= std::find_if(rSeq
.begin(), rSeq
.end(),
2351 [](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Index
== NF_CURRENCY_1000DEC2
; });
2352 if (pSeq
!= rSeq
.end())
2353 return static_cast<sal_Int32
>(std::distance(rSeq
.begin(), pSeq
));
2354 // last resort: look for a format without decimals
2355 pSeq
= std::find_if(rSeq
.begin(), rSeq
.end(),
2356 [](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Index
== NF_CURRENCY_1000INT
; });
2357 if (pSeq
!= rSeq
.end())
2358 return static_cast<sal_Int32
>(std::distance(rSeq
.begin(), pSeq
));
2362 { // we need at least _some_ format
2364 rSeq
[0] = css::i18n::NumberFormatCode();
2365 rSeq
[0].Code
= "0" + GetNumDecimalSep() + "############";
2371 void SvNumberFormatter::ImpAdjustFormatCodeDefault(
2372 css::i18n::NumberFormatCode
* pFormatArr
,
2377 if (LocaleDataWrapper::areChecksEnabled())
2379 // check the locale data for correctness
2381 sal_Int32 nElem
, nShort
, nMedium
, nLong
, nShortDef
, nMediumDef
, nLongDef
;
2382 nShort
= nMedium
= nLong
= nShortDef
= nMediumDef
= nLongDef
= -1;
2383 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2385 switch ( pFormatArr
[nElem
].Type
)
2387 case i18n::KNumberFormatType::SHORT
:
2390 case i18n::KNumberFormatType::MEDIUM
:
2393 case i18n::KNumberFormatType::LONG
:
2397 aMsg
.append("unknown type");
2399 if ( pFormatArr
[nElem
].Default
)
2401 switch ( pFormatArr
[nElem
].Type
)
2403 case i18n::KNumberFormatType::SHORT
:
2404 if ( nShortDef
!= -1 )
2405 aMsg
.append("dupe short type default");
2408 case i18n::KNumberFormatType::MEDIUM
:
2409 if ( nMediumDef
!= -1 )
2410 aMsg
.append("dupe medium type default");
2413 case i18n::KNumberFormatType::LONG
:
2414 if ( nLongDef
!= -1 )
2415 aMsg
.append("dupe long type default");
2420 if (!aMsg
.isEmpty())
2422 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2423 aMsg
.append("\nXML locale data FormatElement formatindex: ");
2424 aMsg
.append(static_cast<sal_Int32
>(pFormatArr
[nElem
].Index
));
2425 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(),
2426 RTL_TEXTENCODING_ASCII_US
));
2427 LocaleDataWrapper::outputCheckMessage(xLocaleData
->appendLocaleInfo(aUMsg
));
2430 if ( nShort
!= -1 && nShortDef
== -1 )
2431 aMsg
.append("no short type default ");
2432 if ( nMedium
!= -1 && nMediumDef
== -1 )
2433 aMsg
.append("no medium type default ");
2434 if ( nLong
!= -1 && nLongDef
== -1 )
2435 aMsg
.append("no long type default ");
2436 if (!aMsg
.isEmpty())
2438 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2439 aMsg
.append("\nXML locale data FormatElement group of: ");
2440 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
));
2441 LocaleDataWrapper::outputCheckMessage(
2442 xLocaleData
->appendLocaleInfo(aUMsg
+ pFormatArr
[0].NameID
));
2445 // find the default (medium preferred, then long) and reset all other defaults
2446 sal_Int32 nElem
, nDef
, nMedium
;
2447 nDef
= nMedium
= -1;
2448 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2450 if ( pFormatArr
[nElem
].Default
)
2452 switch ( pFormatArr
[nElem
].Type
)
2454 case i18n::KNumberFormatType::MEDIUM
:
2455 nDef
= nMedium
= nElem
;
2457 case i18n::KNumberFormatType::LONG
:
2458 if ( nMedium
== -1 )
2464 pFormatArr
[nElem
].Default
= false;
2470 pFormatArr
[nDef
].Default
= true;
2473 SvNumberformat
* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey
)
2475 auto it
= aFTable
.find( nKey
);
2476 if (it
!= aFTable
.end())
2477 return it
->second
.get();
2481 const SvNumberformat
* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey
) const
2483 return GetEntry( nKey
);
2486 const SvNumberformat
* SvNumberFormatter::GetEntry( sal_uInt32 nKey
) const
2488 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2489 auto it
= aFTable
.find( nKey
);
2490 if (it
!= aFTable
.end())
2491 return it
->second
.get();
2495 const SvNumberformat
* SvNumberFormatter::GetSubstitutedEntry( sal_uInt32 nKey
, sal_uInt32
& o_rNewKey
) const
2497 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2498 // A tad ugly, but GetStandardFormat() and GetFormatIndex() in
2499 // ImpSubstituteEntry() may have to add the LANGUAGE_SYSTEM formats if not
2500 // already present (which in practice most times they are).
2501 SvNumberFormatter
* pThis
= const_cast<SvNumberFormatter
*>(this);
2502 return pThis
->ImpSubstituteEntry( pThis
->GetFormatEntry( nKey
), &o_rNewKey
);
2505 SvNumberformat
* SvNumberFormatter::ImpSubstituteEntry( SvNumberformat
* pFormat
, sal_uInt32
* o_pRealKey
)
2507 if (!pFormat
|| !pFormat
->IsSubstituted())
2510 // XXX NOTE: substitution can not be done in GetFormatEntry() as otherwise
2511 // to be substituted formats would "vanish", i.e. from the number formatter
2512 // dialog or when exporting to Excel.
2515 if (pFormat
->IsSystemTimeFormat())
2516 /* TODO: should we have NF_TIME_SYSTEM for consistency? */
2517 nKey
= GetStandardFormat( SvNumFormatType::TIME
, LANGUAGE_SYSTEM
);
2518 else if (pFormat
->IsSystemLongDateFormat())
2519 /* TODO: either that above, or have a long option for GetStandardFormat() */
2520 nKey
= GetFormatIndex( NF_DATE_SYSTEM_LONG
, LANGUAGE_SYSTEM
);
2526 auto it
= aFTable
.find( nKey
);
2527 return it
== aFTable
.end() ? nullptr : it
->second
.get();
2530 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset
, bool bNoAdditionalFormats
)
2532 bool bOldConvertMode
= pFormatScanner
->GetConvertMode();
2533 if (bOldConvertMode
)
2535 pFormatScanner
->SetConvertMode(false); // switch off for this function
2538 css::lang::Locale aLocale
= GetLanguageTag().getLocale();
2539 css::uno::Reference
< css::i18n::XNumberFormatCode
> xNFC
= i18n::NumberFormatMapper::create( m_xContext
);
2544 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER
, aLocale
);
2545 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2548 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_STANDARD
);
2549 SvNumberformat
* pStdFormat
= ImpInsertFormat( aFormatSeq
[nIdx
],
2550 CLOffset
+ ZF_STANDARD
/* NF_NUMBER_STANDARD */ );
2553 // This is _the_ standard format.
2554 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat
->GetType() != SvNumFormatType::NUMBER
)
2556 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2557 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2559 pStdFormat
->SetType( SvNumFormatType::NUMBER
);
2560 pStdFormat
->SetStandard();
2561 pStdFormat
->SetLastInsertKey( SV_MAX_COUNT_STANDARD_FORMATS
, SvNumberformat::FormatterPrivateAccess() );
2565 if (LocaleDataWrapper::areChecksEnabled())
2567 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2568 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2574 OUString aFormatCode
= pFormatScanner
->GetBooleanString();
2575 sal_Int32 nCheckPos
= 0;
2577 std::unique_ptr
<SvNumberformat
> pNewFormat(new SvNumberformat( aFormatCode
, pFormatScanner
.get(),
2578 pStringScanner
.get(), nCheckPos
, ActLnge
));
2579 pNewFormat
->SetType(SvNumFormatType::LOGICAL
);
2580 pNewFormat
->SetStandard();
2581 if ( !aFTable
.emplace(CLOffset
+ ZF_STANDARD_LOGICAL
/* NF_BOOLEAN */,
2582 std::move(pNewFormat
)).second
)
2584 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2589 pNewFormat
.reset(new SvNumberformat( aFormatCode
, pFormatScanner
.get(),
2590 pStringScanner
.get(), nCheckPos
, ActLnge
));
2591 pNewFormat
->SetType(SvNumFormatType::TEXT
);
2592 pNewFormat
->SetStandard();
2593 if ( !aFTable
.emplace( CLOffset
+ ZF_STANDARD_TEXT
/* NF_TEXT */,
2594 std::move(pNewFormat
)).second
)
2596 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2601 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_INT
);
2602 ImpInsertFormat( aFormatSeq
[nIdx
],
2603 CLOffset
+ ZF_STANDARD
+1 /* NF_NUMBER_INT */ );
2606 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_DEC2
);
2607 ImpInsertFormat( aFormatSeq
[nIdx
],
2608 CLOffset
+ ZF_STANDARD
+2 /* NF_NUMBER_DEC2 */ );
2611 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000INT
);
2612 ImpInsertFormat( aFormatSeq
[nIdx
],
2613 CLOffset
+ ZF_STANDARD
+3 /* NF_NUMBER_1000INT */ );
2616 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000DEC2
);
2617 ImpInsertFormat( aFormatSeq
[nIdx
],
2618 CLOffset
+ ZF_STANDARD
+4 /* NF_NUMBER_1000DEC2 */ );
2620 // #.##0,00 System country/language dependent
2621 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_SYSTEM
);
2622 ImpInsertFormat( aFormatSeq
[nIdx
],
2623 CLOffset
+ ZF_STANDARD
+5 /* NF_NUMBER_SYSTEM */ );
2627 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER
, aLocale
);
2628 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2631 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_INT
);
2632 ImpInsertFormat( aFormatSeq
[nIdx
],
2633 CLOffset
+ ZF_STANDARD_PERCENT
/* NF_PERCENT_INT */ );
2636 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_DEC2
);
2637 ImpInsertFormat( aFormatSeq
[nIdx
],
2638 CLOffset
+ ZF_STANDARD_PERCENT
+1 /* NF_PERCENT_DEC2 */ );
2641 // Currency. NO default standard option! Default is determined of locale
2642 // data default currency and format is generated if needed.
2643 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
, aLocale
);
2644 if (LocaleDataWrapper::areChecksEnabled())
2646 // though no default desired here, test for correctness of locale data
2647 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2651 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT
);
2652 bDefault
= aFormatSeq
[nIdx
].Default
;
2653 aFormatSeq
[nIdx
].Default
= false;
2654 ImpInsertFormat( aFormatSeq
[nIdx
],
2655 CLOffset
+ ZF_STANDARD_CURRENCY
/* NF_CURRENCY_1000INT */ );
2656 aFormatSeq
[nIdx
].Default
= bDefault
;
2659 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2
);
2660 bDefault
= aFormatSeq
[nIdx
].Default
;
2661 aFormatSeq
[nIdx
].Default
= false;
2662 ImpInsertFormat( aFormatSeq
[nIdx
],
2663 CLOffset
+ ZF_STANDARD_CURRENCY
+1 /* NF_CURRENCY_1000DEC2 */ );
2664 aFormatSeq
[nIdx
].Default
= bDefault
;
2666 // #,##0 negative red
2667 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT_RED
);
2668 bDefault
= aFormatSeq
[nIdx
].Default
;
2669 aFormatSeq
[nIdx
].Default
= false;
2670 ImpInsertFormat( aFormatSeq
[nIdx
],
2671 CLOffset
+ ZF_STANDARD_CURRENCY
+2 /* NF_CURRENCY_1000INT_RED */ );
2672 aFormatSeq
[nIdx
].Default
= bDefault
;
2674 // #,##0.00 negative red
2675 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_RED
);
2676 bDefault
= aFormatSeq
[nIdx
].Default
;
2677 aFormatSeq
[nIdx
].Default
= false;
2678 ImpInsertFormat( aFormatSeq
[nIdx
],
2679 CLOffset
+ ZF_STANDARD_CURRENCY
+3 /* NF_CURRENCY_1000DEC2_RED */ );
2680 aFormatSeq
[nIdx
].Default
= bDefault
;
2683 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_CCC
);
2684 bDefault
= aFormatSeq
[nIdx
].Default
;
2685 aFormatSeq
[nIdx
].Default
= false;
2686 ImpInsertFormat( aFormatSeq
[nIdx
],
2687 CLOffset
+ ZF_STANDARD_CURRENCY
+4 /* NF_CURRENCY_1000DEC2_CCC */ );
2688 aFormatSeq
[nIdx
].Default
= bDefault
;
2691 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_DASHED
);
2692 bDefault
= aFormatSeq
[nIdx
].Default
;
2693 aFormatSeq
[nIdx
].Default
= false;
2694 ImpInsertFormat( aFormatSeq
[nIdx
],
2695 CLOffset
+ ZF_STANDARD_CURRENCY
+5 /* NF_CURRENCY_1000DEC2_DASHED */ );
2696 aFormatSeq
[nIdx
].Default
= bDefault
;
2700 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::DATE
, aLocale
);
2701 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2704 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_SHORT
);
2705 ImpInsertFormat( aFormatSeq
[nIdx
],
2706 CLOffset
+ ZF_STANDARD_DATE
/* NF_DATE_SYSTEM_SHORT */ );
2709 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DEF_NNDDMMMYY
);
2710 ImpInsertFormat( aFormatSeq
[nIdx
],
2711 CLOffset
+ ZF_STANDARD_DATE
+1 /* NF_DATE_DEF_NNDDMMMYY */ );
2713 // DD.MM.YY def/System
2714 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_MMYY
);
2715 ImpInsertFormat( aFormatSeq
[nIdx
],
2716 CLOffset
+ ZF_STANDARD_DATE
+2 /* NF_DATE_SYS_MMYY */ );
2719 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMM
);
2720 ImpInsertFormat( aFormatSeq
[nIdx
],
2721 CLOffset
+ ZF_STANDARD_DATE
+3 /* NF_DATE_SYS_DDMMM */ );
2724 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_MMMM
);
2725 ImpInsertFormat( aFormatSeq
[nIdx
],
2726 CLOffset
+ ZF_STANDARD_DATE
+4 /* NF_DATE_MMMM */ );
2729 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_QQJJ
);
2730 ImpInsertFormat( aFormatSeq
[nIdx
],
2731 CLOffset
+ ZF_STANDARD_DATE
+5 /* NF_DATE_QQJJ */ );
2733 // DD.MM.YYYY was DD.MM.[YY]YY
2734 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYYYY
);
2735 ImpInsertFormat( aFormatSeq
[nIdx
],
2736 CLOffset
+ ZF_STANDARD_DATE
+6 /* NF_DATE_SYS_DDMMYYYY */ );
2738 // DD.MM.YY def/System
2739 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYY
);
2740 ImpInsertFormat( aFormatSeq
[nIdx
],
2741 CLOffset
+ ZF_STANDARD_DATE
+7 /* NF_DATE_SYS_DDMMYY */ );
2743 // NNN, D. MMMM YYYY System
2744 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2745 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_LONG
);
2746 ImpInsertFormat( aFormatSeq
[nIdx
],
2747 CLOffset
+ ZF_STANDARD_DATE
+8 /* NF_DATE_SYSTEM_LONG */ );
2749 // Hard coded but system (regional settings) delimiters dependent long date formats
2751 // D. MMM YY def/System
2752 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYY
);
2753 ImpInsertFormat( aFormatSeq
[nIdx
],
2754 CLOffset
+ ZF_STANDARD_DATE
+9 /* NF_DATE_SYS_DMMMYY */ );
2756 // D. MMM YYYY def/System
2757 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYYYY
);
2758 ImpInsertFormat( aFormatSeq
[nIdx
],
2759 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY
/* NF_DATE_SYS_DMMMYYYY */ );
2761 // D. MMMM YYYY def/System
2762 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMMYYYY
);
2763 ImpInsertFormat( aFormatSeq
[nIdx
],
2764 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY
/* NF_DATE_SYS_DMMMMYYYY */ );
2766 // NN, D. MMM YY def/System
2767 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMYY
);
2768 ImpInsertFormat( aFormatSeq
[nIdx
],
2769 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY
/* NF_DATE_SYS_NNDMMMYY */ );
2771 // NN, D. MMMM YYYY def/System
2772 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMMYYYY
);
2773 ImpInsertFormat( aFormatSeq
[nIdx
],
2774 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY
/* NF_DATE_SYS_NNDMMMMYYYY */ );
2776 // NNN, D. MMMM YYYY def/System
2777 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNNNDMMMMYYYY
);
2778 ImpInsertFormat( aFormatSeq
[nIdx
],
2779 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY
/* NF_DATE_SYS_NNNNDMMMMYYYY */ );
2781 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2783 // D. MMM. YYYY DIN/EN
2784 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMYYYY
);
2785 ImpInsertFormat( aFormatSeq
[nIdx
],
2786 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY
/* NF_DATE_DIN_DMMMYYYY */ );
2788 // D. MMMM YYYY DIN/EN
2789 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMMYYYY
);
2790 ImpInsertFormat( aFormatSeq
[nIdx
],
2791 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY
/* NF_DATE_DIN_DMMMMYYYY */ );
2794 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_MMDD
);
2795 ImpInsertFormat( aFormatSeq
[nIdx
],
2796 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD
/* NF_DATE_DIN_MMDD */ );
2799 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYMMDD
);
2800 ImpInsertFormat( aFormatSeq
[nIdx
],
2801 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD
/* NF_DATE_DIN_YYMMDD */ );
2803 // YYYY-MM-DD DIN/EN/ISO
2804 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYYYMMDD
);
2805 ImpInsertFormat( aFormatSeq
[nIdx
],
2806 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD
/* NF_DATE_DIN_YYYYMMDD */ );
2810 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::TIME
, aLocale
);
2811 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2814 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMM
);
2815 ImpInsertFormat( aFormatSeq
[nIdx
],
2816 CLOffset
+ ZF_STANDARD_TIME
/* NF_TIME_HHMM */ );
2819 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSS
);
2820 ImpInsertFormat( aFormatSeq
[nIdx
],
2821 CLOffset
+ ZF_STANDARD_TIME
+1 /* NF_TIME_HHMMSS */ );
2824 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMAMPM
);
2825 ImpInsertFormat( aFormatSeq
[nIdx
],
2826 CLOffset
+ ZF_STANDARD_TIME
+2 /* NF_TIME_HHMMAMPM */ );
2829 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSSAMPM
);
2830 ImpInsertFormat( aFormatSeq
[nIdx
],
2831 CLOffset
+ ZF_STANDARD_TIME
+3 /* NF_TIME_HHMMSSAMPM */ );
2834 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS
);
2835 ImpInsertFormat( aFormatSeq
[nIdx
],
2836 CLOffset
+ ZF_STANDARD_TIME
+4 /* NF_TIME_HH_MMSS */ );
2839 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_MMSS00
);
2840 ImpInsertFormat( aFormatSeq
[nIdx
],
2841 CLOffset
+ ZF_STANDARD_TIME
+5 /* NF_TIME_MMSS00 */ );
2844 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS00
);
2845 ImpInsertFormat( aFormatSeq
[nIdx
],
2846 CLOffset
+ ZF_STANDARD_TIME
+6 /* NF_TIME_HH_MMSS00 */ );
2850 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME
, aLocale
);
2851 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2853 // DD.MM.YY HH:MM System
2854 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYSTEM_SHORT_HHMM
);
2855 ImpInsertFormat( aFormatSeq
[nIdx
],
2856 CLOffset
+ ZF_STANDARD_DATETIME
/* NF_DATETIME_SYSTEM_SHORT_HHMM */ );
2858 // DD.MM.YYYY HH:MM:SS System
2859 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
2860 ImpInsertFormat( aFormatSeq
[nIdx
],
2861 CLOffset
+ ZF_STANDARD_DATETIME
+1 /* NF_DATETIME_SYS_DDMMYYYY_HHMMSS */ );
2863 // DD.MM.YYYY HH:MM System
2864 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYS_DDMMYYYY_HHMM
);
2865 ImpInsertFormat( aFormatSeq
[nIdx
],
2866 CLOffset
+ ZF_STANDARD_DATETIME
+4 /* NF_DATETIME_SYS_DDMMYYYY_HHMM */ );
2868 const NfKeywordTable
& rKeyword
= pFormatScanner
->GetKeywords();
2869 i18n::NumberFormatCode aSingleFormatCode
;
2870 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::DATE_TIME
;
2872 // YYYY-MM-DD HH:MM:SS ISO (with blank instead of 'T')
2873 aSingleFormatCode
.Code
=
2874 rKeyword
[NF_KEY_YYYY
] + "-" +
2875 rKeyword
[NF_KEY_MM
] + "-" +
2876 rKeyword
[NF_KEY_DD
] + " " +
2877 rKeyword
[NF_KEY_HH
] + ":" +
2878 rKeyword
[NF_KEY_MMI
] + ":" +
2879 rKeyword
[NF_KEY_SS
];
2880 ImpInsertFormat( aSingleFormatCode
,
2881 CLOffset
+ ZF_STANDARD_DATETIME
+2 /* NF_DATETIME_ISO_YYYYMMDD_HHMMSS */ );
2883 // YYYY-MM-DD"T"HH:MM:SS ISO
2884 aSingleFormatCode
.Code
=
2885 rKeyword
[NF_KEY_YYYY
] + "-" +
2886 rKeyword
[NF_KEY_MM
] + "-" +
2887 rKeyword
[NF_KEY_DD
] + "\"T\"" +
2888 rKeyword
[NF_KEY_HH
] + ":" +
2889 rKeyword
[NF_KEY_MMI
] + ":" +
2890 rKeyword
[NF_KEY_SS
];
2891 SvNumberformat
* pFormat
= ImpInsertFormat( aSingleFormatCode
,
2892 CLOffset
+ ZF_STANDARD_DATETIME
+3 /* NF_DATETIME_ISO_YYYYMMDDTHHMMSS */ );
2894 pFormat
->SetComment("ISO 8601"); // not to be localized
2897 // Scientific number
2898 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER
, aLocale
);
2899 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2902 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E000
);
2903 ImpInsertFormat( aFormatSeq
[nIdx
],
2904 CLOffset
+ ZF_STANDARD_SCIENTIFIC
/* NF_SCIENTIFIC_000E000 */ );
2907 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E00
);
2908 ImpInsertFormat( aFormatSeq
[nIdx
],
2909 CLOffset
+ ZF_STANDARD_SCIENTIFIC
+1 /* NF_SCIENTIFIC_000E00 */ );
2912 // Fraction number (no default option)
2913 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::FRACTION_NUMBER
;
2916 aSingleFormatCode
.Code
= "# ?/?";
2917 ImpInsertFormat( aSingleFormatCode
,
2918 CLOffset
+ ZF_STANDARD_FRACTION
/* NF_FRACTION_1D */ );
2921 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2922 aSingleFormatCode
.Code
= "# ?\?/?\?";
2923 ImpInsertFormat( aSingleFormatCode
,
2924 CLOffset
+ ZF_STANDARD_FRACTION
+1 /* NF_FRACTION_2D */ );
2927 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2928 aSingleFormatCode
.Code
= "# ?\?\?/?\?\?";
2929 ImpInsertFormat( aSingleFormatCode
,
2930 CLOffset
+ ZF_STANDARD_FRACTION
+2 /* NF_FRACTION_3D */ );
2933 aSingleFormatCode
.Code
= "# ?/2";
2934 ImpInsertFormat( aSingleFormatCode
,
2935 CLOffset
+ ZF_STANDARD_FRACTION
+3 /* NF_FRACTION_2 */ );
2938 aSingleFormatCode
.Code
= "# ?/4";
2939 ImpInsertFormat( aSingleFormatCode
,
2940 CLOffset
+ ZF_STANDARD_FRACTION
+4 /* NF_FRACTION_4 */ );
2943 aSingleFormatCode
.Code
= "# ?/8";
2944 ImpInsertFormat( aSingleFormatCode
,
2945 CLOffset
+ ZF_STANDARD_FRACTION
+5 /* NF_FRACTION_8 */ );
2948 aSingleFormatCode
.Code
= "# ?\?/16";
2949 ImpInsertFormat( aSingleFormatCode
,
2950 CLOffset
+ ZF_STANDARD_FRACTION
+6 /* NF_FRACTION_16 */ );
2953 aSingleFormatCode
.Code
= "# ?\?/10";
2954 ImpInsertFormat( aSingleFormatCode
,
2955 CLOffset
+ ZF_STANDARD_FRACTION
+7 /* NF_FRACTION_10 */ );
2958 aSingleFormatCode
.Code
= "# ?\?/100";
2959 ImpInsertFormat( aSingleFormatCode
,
2960 CLOffset
+ ZF_STANDARD_FRACTION
+8 /* NF_FRACTION_100 */ );
2964 aSingleFormatCode
.Code
= rKeyword
[NF_KEY_WW
];
2965 ImpInsertFormat( aSingleFormatCode
,
2966 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_WW
/* NF_DATE_WW */ );
2968 // Now all additional format codes provided by I18N, but only if not
2969 // changing SystemCL, then they are appended last after user defined.
2970 if ( !bNoAdditionalFormats
)
2972 ImpGenerateAdditionalFormats( CLOffset
, xNFC
, false );
2974 if (bOldConvertMode
)
2976 pFormatScanner
->SetConvertMode(true);
2981 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset
,
2982 css::uno::Reference
< css::i18n::XNumberFormatCode
> const & rNumberFormatCode
,
2983 bool bAfterChangingSystemCL
)
2985 SvNumberformat
* pStdFormat
= GetFormatEntry( CLOffset
+ ZF_STANDARD
);
2988 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2991 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
2992 css::lang::Locale aLocale
= GetLanguageTag().getLocale();
2994 // All currencies, this time with [$...] which was stripped in
2995 // ImpGenerateFormats for old "automatic" currency formats.
2996 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
= rNumberFormatCode
->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
, aLocale
);
2997 sal_Int32 nCodes
= aFormatSeq
.getLength();
2998 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), nCodes
);
2999 for ( i18n::NumberFormatCode
& rFormat
: aFormatSeq
)
3001 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3003 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
3006 if ( rFormat
.Index
< NF_INDEX_TABLE_RESERVED_START
&&
3007 rFormat
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
3008 { // Insert only if not already inserted, but internal index must be
3009 // above so ImpInsertFormat can distinguish it.
3010 sal_Int16 nOrgIndex
= rFormat
.Index
;
3011 rFormat
.Index
= sal::static_int_cast
< sal_Int16
>(
3012 rFormat
.Index
+ nCodes
+ NF_INDEX_TABLE_ENTRIES
);
3013 //! no default on currency
3014 bool bDefault
= rFormat
.Default
;
3015 rFormat
.Default
= false;
3016 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat( rFormat
, nPos
+1,
3017 bAfterChangingSystemCL
, nOrgIndex
) )
3019 pNewFormat
->SetAdditionalBuiltin();
3022 rFormat
.Index
= nOrgIndex
;
3023 rFormat
.Default
= bDefault
;
3027 // All additional format codes provided by I18N that are not old standard
3028 // index. Additional formats may define defaults, currently there is no
3029 // check if more than one default of a usage/type combination is provided,
3030 // like it is done for usage groups with ImpAdjustFormatCodeDefault().
3031 // There is no harm though, on first invocation ImpGetDefaultFormat() will
3032 // use the first default encountered.
3033 aFormatSeq
= rNumberFormatCode
->getAllFormatCodes( aLocale
);
3034 for ( const auto& rFormat
: std::as_const(aFormatSeq
) )
3036 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3038 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
3041 if ( rFormat
.Index
>= NF_INDEX_TABLE_RESERVED_START
)
3043 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat( rFormat
, nPos
+1,
3044 bAfterChangingSystemCL
) )
3046 pNewFormat
->SetAdditionalBuiltin();
3052 pStdFormat
->SetLastInsertKey( static_cast<sal_uInt16
>(nPos
- CLOffset
), SvNumberformat::FormatterPrivateAccess() );
3056 sal_Int32
SvNumberFormatter::ImpPosToken ( const OUStringBuffer
& sFormat
, sal_Unicode token
, sal_Int32 nStartPos
/* = 0*/ ) const
3058 sal_Int32 nLength
= sFormat
.getLength();
3059 for ( sal_Int32 i
=nStartPos
; i
<nLength
&& i
>=0 ; i
++ )
3063 case '\"' : // skip text
3064 i
= sFormat
.indexOf('\"',i
+1);
3066 case '[' : // skip condition
3067 i
= sFormat
.indexOf(']',i
+1);
3069 case '\\' : // skip escaped character
3079 return i
; // if 'E' is outside "" and [] it must be the 'E' exponent
3089 OUString
SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex
,
3093 sal_uInt16 nPrecision
,
3094 sal_uInt16 nLeadingZeros
)
3096 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3097 if (eLnge
== LANGUAGE_DONTKNOW
)
3102 const SvNumberformat
* pFormat
= GetFormatEntry( nIndex
);
3103 const SvNumFormatType eType
= (pFormat
? pFormat
->GetMaskedType() : SvNumFormatType::UNDEFINED
);
3105 ImpGenerateCL(eLnge
); // create new standard formats if necessary
3107 utl::DigitGroupingIterator
aGrouping( xLocaleData
->getDigitGrouping());
3108 // always group of 3 for Engineering notation
3109 const sal_Int32 nDigitsInFirstGroup
= ( bThousand
&& (eType
== SvNumFormatType::SCIENTIFIC
) ) ? 3 : aGrouping
.get();
3110 const OUString
& rThSep
= GetNumThousandSep();
3112 OUStringBuffer sString
;
3113 using comphelper::string::padToLength
;
3115 if (eType
& SvNumFormatType::TIME
)
3117 assert(pFormat
&& "with !pFormat eType can only be SvNumFormatType::UNDEFINED");
3118 sString
= pFormat
->GetFormatStringForTimePrecision( nPrecision
);
3120 else if (nLeadingZeros
== 0)
3123 sString
.append('#');
3126 if (eType
== SvNumFormatType::SCIENTIFIC
)
3127 { // for scientific, bThousand is used for Engineering notation
3128 sString
.append("###");
3132 sString
.append('#');
3133 sString
.append(rThSep
);
3134 padToLength(sString
, sString
.getLength() + nDigitsInFirstGroup
, '#');
3140 for (sal_uInt16 i
= 0; i
< nLeadingZeros
; i
++)
3142 if (bThousand
&& i
> 0 && i
== aGrouping
.getPos())
3144 sString
.insert(0, rThSep
);
3145 aGrouping
.advance();
3147 sString
.insert(0, '0');
3151 sal_Int32 nDigits
= (eType
== SvNumFormatType::SCIENTIFIC
) ? 3*((nLeadingZeros
-1)/3 + 1) : nDigitsInFirstGroup
+ 1;
3152 for (sal_Int32 i
= nLeadingZeros
; i
< nDigits
; i
++)
3154 if ( i
% nDigitsInFirstGroup
== 0 )
3155 sString
.insert(0, rThSep
);
3156 sString
.insert(0, '#');
3160 if (nPrecision
> 0 && eType
!= SvNumFormatType::FRACTION
&& !( eType
& SvNumFormatType::TIME
) )
3162 sString
.append(GetNumDecimalSep());
3163 padToLength(sString
, sString
.getLength() + nPrecision
, '0');
3165 if (eType
== SvNumFormatType::PERCENT
)
3167 sString
.append( pFormat
->GetPercentString() );
3169 else if (eType
== SvNumFormatType::SCIENTIFIC
)
3171 OUStringBuffer sOldFormatString
= pFormat
->GetFormatstring();
3172 sal_Int32 nIndexE
= ImpPosToken( sOldFormatString
, 'E' );
3175 sal_Int32 nIndexSep
= ImpPosToken( sOldFormatString
, ';', nIndexE
);
3176 if (nIndexSep
> nIndexE
)
3177 sString
.append( sOldFormatString
.copy(nIndexE
, nIndexSep
- nIndexE
) );
3179 sString
.append( sOldFormatString
.copy(nIndexE
) );
3182 else if (eType
== SvNumFormatType::CURRENCY
)
3184 OUStringBuffer
sNegStr(sString
);
3186 const NfCurrencyEntry
* pEntry
;
3188 if ( GetNewCurrencySymbolString( nIndex
, aCurr
, &pEntry
, &bBank
) )
3192 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
3193 xLocaleData
->getCurrPositiveFormat(),
3194 pEntry
->GetPositiveFormat(), bBank
);
3195 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
3196 xLocaleData
->getCurrNegativeFormat(),
3197 pEntry
->GetNegativeFormat(), bBank
);
3198 pEntry
->CompletePositiveFormatString( sString
, bBank
, nPosiForm
);
3199 pEntry
->CompleteNegativeFormatString( sNegStr
, bBank
, nNegaForm
);
3202 { // assume currency abbreviation (AKA banking symbol), not symbol
3203 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
3204 xLocaleData
->getCurrPositiveFormat(),
3205 xLocaleData
->getCurrPositiveFormat(), true );
3206 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
3207 xLocaleData
->getCurrNegativeFormat(),
3208 xLocaleData
->getCurrNegativeFormat(), true );
3209 NfCurrencyEntry::CompletePositiveFormatString( sString
, aCurr
, nPosiForm
);
3210 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
, aCurr
, nNegaForm
);
3214 { // "automatic" old style
3215 OUString aSymbol
, aAbbrev
;
3216 GetCompatibilityCurrency( aSymbol
, aAbbrev
);
3217 NfCurrencyEntry::CompletePositiveFormatString( sString
,
3218 aSymbol
, xLocaleData
->getCurrPositiveFormat() );
3219 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
,
3220 aSymbol
, xLocaleData
->getCurrNegativeFormat() );
3224 sString
.append(';');
3225 sString
.append('[');
3226 sString
.append(pFormatScanner
->GetRedString());
3227 sString
.append(']');
3231 sString
.append(';');
3233 sString
.append(sNegStr
);
3235 else if (eType
== SvNumFormatType::FRACTION
)
3237 OUString aIntegerFractionDelimiterString
= pFormat
->GetIntegerFractionDelimiterString( 0 );
3238 if ( aIntegerFractionDelimiterString
== " " )
3239 sString
.append( aIntegerFractionDelimiterString
);
3242 sString
.append( '"' );
3243 sString
.append( aIntegerFractionDelimiterString
);
3244 sString
.append( '"' );
3246 sString
.append( pFormat
->GetNumeratorString( 0 ) );
3247 sString
.append( '/' );
3248 if ( nPrecision
> 0 )
3249 padToLength(sString
, sString
.getLength() + nPrecision
, '?');
3251 sString
.append( '#' );
3253 if (eType
!= SvNumFormatType::CURRENCY
)
3255 bool insertBrackets
= false;
3256 if ( eType
!= SvNumFormatType::UNDEFINED
)
3258 insertBrackets
= pFormat
->IsNegativeInBracket();
3260 if (IsRed
|| insertBrackets
)
3262 OUStringBuffer
sTmpStr(sString
);
3264 if (pFormat
&& pFormat
->HasPositiveBracketPlaceholder())
3266 sTmpStr
.append('_');
3267 sTmpStr
.append(')');
3269 sTmpStr
.append(';');
3273 sTmpStr
.append('[');
3274 sTmpStr
.append(pFormatScanner
->GetRedString());
3275 sTmpStr
.append(']');
3280 sTmpStr
.append('(');
3281 sTmpStr
.append(sString
);
3282 sTmpStr
.append(')');
3286 sTmpStr
.append('-');
3287 sTmpStr
.append(sString
);
3292 return sString
.makeStringAndClear();
3295 bool SvNumberFormatter::IsUserDefined(std::u16string_view sStr
,
3298 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3299 if (eLnge
== LANGUAGE_DONTKNOW
)
3303 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3306 sal_uInt32 nKey
= ImpIsEntry(sStr
, CLOffset
, eLnge
);
3307 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3311 SvNumberformat
* pEntry
= GetFormatEntry( nKey
);
3312 return pEntry
&& (pEntry
->GetType() & SvNumFormatType::DEFINED
);
3315 sal_uInt32
SvNumberFormatter::GetEntryKey(std::u16string_view sStr
,
3318 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3319 if (eLnge
== LANGUAGE_DONTKNOW
)
3323 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3324 return ImpIsEntry(sStr
, CLOffset
, eLnge
);
3327 sal_uInt32
SvNumberFormatter::GetStandardIndex(LanguageType eLnge
)
3329 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3330 if (eLnge
== LANGUAGE_DONTKNOW
)
3334 return GetStandardFormat(SvNumFormatType::NUMBER
, eLnge
);
3337 SvNumFormatType
SvNumberFormatter::GetType(sal_uInt32 nFIndex
) const
3339 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3340 SvNumFormatType eType
;
3341 const SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
3344 eType
= SvNumFormatType::UNDEFINED
;
3348 eType
= pFormat
->GetMaskedType();
3349 if (eType
== SvNumFormatType::ALL
)
3351 eType
= SvNumFormatType::DEFINED
;
3357 void SvNumberFormatter::ClearMergeTable()
3359 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3362 pMergeTable
->clear();
3366 SvNumberFormatterIndexTable
* SvNumberFormatter::MergeFormatter(SvNumberFormatter
& rTable
)
3368 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3375 pMergeTable
.reset( new SvNumberFormatterIndexTable
);
3378 sal_uInt32 nCLOffset
= 0;
3379 sal_uInt32 nOldKey
, nOffset
, nNewKey
;
3381 for (const auto& rEntry
: rTable
.aFTable
)
3383 SvNumberformat
* pFormat
= rEntry
.second
.get();
3384 nOldKey
= rEntry
.first
;
3385 nOffset
= nOldKey
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3386 if (nOffset
== 0) // 1st format of CL
3388 nCLOffset
= ImpGenerateCL(pFormat
->GetLanguage());
3390 if (nOffset
<= SV_MAX_COUNT_STANDARD_FORMATS
) // Std.form.
3392 nNewKey
= nCLOffset
+ nOffset
;
3393 if (aFTable
.find( nNewKey
) == aFTable
.end()) // not already present
3395 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( *pFormat
, *pFormatScanner
));
3396 if (!aFTable
.emplace( nNewKey
, std::move(pNewEntry
)).second
)
3398 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3401 if (nNewKey
!= nOldKey
) // new index
3403 (*pMergeTable
)[nOldKey
] = nNewKey
;
3406 else // user defined
3408 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( *pFormat
, *pFormatScanner
));
3409 nNewKey
= ImpIsEntry(pNewEntry
->GetFormatstring(),
3411 pFormat
->GetLanguage());
3412 if (nNewKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
) // only if not present yet
3414 SvNumberformat
* pStdFormat
= GetFormatEntry(nCLOffset
+ ZF_STANDARD
);
3415 sal_uInt32 nPos
= nCLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
3417 if (nNewKey
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3419 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3421 else if (!aFTable
.emplace( nNewKey
, std::move(pNewEntry
)).second
)
3423 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3427 pStdFormat
->SetLastInsertKey(static_cast<sal_uInt16
>(nNewKey
- nCLOffset
),
3428 SvNumberformat::FormatterPrivateAccess());
3431 if (nNewKey
!= nOldKey
) // new index
3433 (*pMergeTable
)[nOldKey
] = nNewKey
;
3437 return pMergeTable
.get();
3441 SvNumberFormatterMergeMap
SvNumberFormatter::ConvertMergeTableToMap()
3443 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3444 if (!HasMergeFormatTable())
3446 return SvNumberFormatterMergeMap();
3448 SvNumberFormatterMergeMap aMap
;
3449 for (const auto& rEntry
: *pMergeTable
)
3451 sal_uInt32 nOldKey
= rEntry
.first
;
3452 aMap
[ nOldKey
] = rEntry
.second
;
3459 sal_uInt32
SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat
,
3460 LanguageType eLnge
)
3462 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3463 if ( eLnge
== LANGUAGE_DONTKNOW
)
3467 if ( nFormat
< SV_COUNTRY_LANGUAGE_OFFSET
&& eLnge
== IniLnge
)
3469 return nFormat
; // it stays as it is
3471 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3472 if ( nOffset
> SV_MAX_COUNT_STANDARD_FORMATS
)
3474 return nFormat
; // not a built-in format
3476 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3477 return nCLOffset
+ nOffset
;
3481 sal_uInt32
SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff
,
3482 LanguageType eLnge
)
3484 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3485 if (nTabOff
>= NF_INDEX_TABLE_ENTRIES
)
3486 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
3488 if (eLnge
== LANGUAGE_DONTKNOW
)
3491 if (indexTable
[nTabOff
] == NUMBERFORMAT_ENTRY_NOT_FOUND
)
3492 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
3494 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3496 return nCLOffset
+ indexTable
[nTabOff
];
3500 NfIndexTableOffset
SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat
) const
3502 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3503 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3504 if ( nOffset
> SV_MAX_COUNT_STANDARD_FORMATS
)
3506 return NF_INDEX_TABLE_ENTRIES
; // not a built-in format
3509 for ( sal_uInt16 j
= 0; j
< NF_INDEX_TABLE_ENTRIES
; j
++ )
3511 if (indexTable
[j
] == nOffset
)
3512 return static_cast<NfIndexTableOffset
>(j
);
3514 return NF_INDEX_TABLE_ENTRIES
; // bad luck
3517 void SvNumberFormatter::SetEvalDateFormat( NfEvalDateFormat eEDF
)
3519 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3520 eEvalDateFormat
= eEDF
;
3523 NfEvalDateFormat
SvNumberFormatter::GetEvalDateFormat() const
3525 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3526 return eEvalDateFormat
;
3529 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal
)
3531 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3532 pStringScanner
->SetYear2000( nVal
);
3536 sal_uInt16
SvNumberFormatter::GetYear2000() const
3538 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3539 return pStringScanner
->GetYear2000();
3543 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
) const
3546 return SvNumberFormatter::ExpandTwoDigitYear( nYear
,
3547 pStringScanner
->GetYear2000() );
3553 sal_uInt16
SvNumberFormatter::GetYear2000Default()
3555 if (!utl::ConfigManager::IsFuzzing())
3556 return officecfg::Office::Common::DateFormat::TwoDigitYear::get();
3561 void SvNumberFormatter::resetTheCurrencyTable()
3563 SAL_INFO("svl", "Resetting the currency table.");
3565 nSystemCurrencyPosition
= 0;
3566 bCurrencyTableInitialized
= false;
3568 GetFormatterRegistry().ConfigurationChanged(nullptr, ConfigurationHints::Locale
| ConfigurationHints::Currency
| ConfigurationHints::DatePatterns
);
3572 const NfCurrencyTable
& SvNumberFormatter::GetTheCurrencyTable()
3574 while ( !bCurrencyTableInitialized
)
3575 ImpInitCurrencyTable();
3576 return theCurrencyTable::get();
3581 const NfCurrencyEntry
* SvNumberFormatter::MatchSystemCurrency()
3583 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3584 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3585 return nSystemCurrencyPosition
? &rTable
[nSystemCurrencyPosition
] : nullptr;
3590 const NfCurrencyEntry
& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang
)
3592 if ( eLang
== LANGUAGE_SYSTEM
)
3594 const NfCurrencyEntry
* pCurr
= MatchSystemCurrency();
3595 return pCurr
? *pCurr
: GetTheCurrencyTable()[0];
3599 eLang
= MsLangId::getRealLanguage( eLang
);
3600 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3601 sal_uInt16 nCount
= rTable
.size();
3602 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3604 if ( rTable
[j
].GetLanguage() == eLang
)
3613 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry(std::u16string_view rAbbrev
, LanguageType eLang
)
3615 eLang
= MsLangId::getRealLanguage( eLang
);
3616 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3617 sal_uInt16 nCount
= rTable
.size();
3618 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3620 if ( rTable
[j
].GetLanguage() == eLang
&&
3621 rTable
[j
].GetBankSymbol() == rAbbrev
)
3631 const NfCurrencyEntry
* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( std::u16string_view rSymbol
,
3632 std::u16string_view rAbbrev
)
3634 GetTheCurrencyTable(); // just for initialization
3635 const NfCurrencyTable
& rTable
= theLegacyOnlyCurrencyTable::get();
3636 sal_uInt16 nCount
= rTable
.size();
3637 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3639 if ( rTable
[j
].GetSymbol() == rSymbol
&&
3640 rTable
[j
].GetBankSymbol() == rAbbrev
)
3650 IMPL_STATIC_LINK_NOARG( SvNumberFormatter
, CurrencyChangeLink
, LinkParamNone
*, void )
3653 LanguageType eLang
= LANGUAGE_SYSTEM
;
3654 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev
, eLang
);
3655 SetDefaultSystemCurrency( aAbbrev
, eLang
);
3660 void SvNumberFormatter::SetDefaultSystemCurrency( std::u16string_view rAbbrev
, LanguageType eLang
)
3662 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
3663 if ( eLang
== LANGUAGE_SYSTEM
)
3665 eLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
3667 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3668 sal_uInt16 nCount
= rTable
.size();
3669 if ( !rAbbrev
.empty() )
3671 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3673 if ( rTable
[j
].GetLanguage() == eLang
&& rTable
[j
].GetBankSymbol() == rAbbrev
)
3675 nSystemCurrencyPosition
= j
;
3682 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3684 if ( rTable
[j
].GetLanguage() == eLang
)
3686 nSystemCurrencyPosition
= j
;
3691 nSystemCurrencyPosition
= 0; // not found => simple SYSTEM
3695 void SvNumberFormatter::ResetDefaultSystemCurrency()
3697 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
3701 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3703 pStringScanner
->InvalidateDateAcceptancePatterns();
3707 sal_uInt32
SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3709 if ( nDefaultSystemCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3712 SvNumFormatType nType
;
3713 NfWSStringsDtor aCurrList
;
3714 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3715 GetCurrencyEntry( LANGUAGE_SYSTEM
), false );
3716 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency System standard format?!?" );
3717 // if already loaded or user defined nDefaultSystemCurrencyFormat
3718 // will be set to the right value
3719 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3720 nDefaultSystemCurrencyFormat
, LANGUAGE_SYSTEM
);
3721 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3722 DBG_ASSERT( nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3723 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3725 return nDefaultSystemCurrencyFormat
;
3729 sal_uInt32
SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3731 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
3732 DefaultFormatKeysMap::const_iterator it
= aDefaultFormatKeys
.find( CLOffset
+ ZF_STANDARD_CURRENCY
);
3733 sal_uInt32 nDefaultCurrencyFormat
= (it
!= aDefaultFormatKeys
.end() ?
3734 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
3735 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3737 // look for a defined standard
3738 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
3740 auto it2
= aFTable
.lower_bound( CLOffset
);
3741 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
3743 const SvNumberformat
* pEntry
= it2
->second
.get();
3744 if ( pEntry
->IsStandard() && (pEntry
->GetType() & SvNumFormatType::CURRENCY
) )
3746 nDefaultCurrencyFormat
= nKey
;
3752 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3753 { // none found, create one
3755 NfWSStringsDtor aCurrList
;
3756 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3757 GetCurrencyEntry( ActLnge
), false );
3758 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency standard format?" );
3759 if ( !aCurrList
.empty() )
3761 // if already loaded or user defined nDefaultSystemCurrencyFormat
3762 // will be set to the right value
3763 SvNumFormatType nType
;
3764 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3765 nDefaultCurrencyFormat
, ActLnge
);
3766 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3767 DBG_ASSERT( nDefaultCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3768 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3770 // old automatic currency format as a last resort
3771 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3772 nDefaultCurrencyFormat
= CLOffset
+ ZF_STANDARD_CURRENCY
+3;
3774 { // mark as standard so that it is found next time
3775 SvNumberformat
* pEntry
= GetFormatEntry( nDefaultCurrencyFormat
);
3777 pEntry
->SetStandard();
3780 aDefaultFormatKeys
[ CLOffset
+ ZF_STANDARD_CURRENCY
] = nDefaultCurrencyFormat
;
3782 return nDefaultCurrencyFormat
;
3787 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
3788 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3789 const NfCurrencyEntry
*& pFoundEntry
, bool& bFoundBank
, const NfCurrencyEntry
* pData
,
3790 sal_uInt16 nPos
, std::u16string_view rSymbol
)
3793 if ( pData
->GetSymbol() == rSymbol
)
3798 else if ( pData
->GetBankSymbol() == rSymbol
)
3807 if ( pFoundEntry
&& pFoundEntry
!= pData
)
3809 pFoundEntry
= nullptr;
3810 return false; // break loop, not unique
3813 { // first entry is SYSTEM
3814 pFoundEntry
= MatchSystemCurrency();
3817 return false; // break loop
3818 // even if there are more matching entries
3819 // this one is probably the one we are looking for
3823 pFoundEntry
= pData
;
3828 pFoundEntry
= pData
;
3835 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat
, OUString
& rStr
,
3836 const NfCurrencyEntry
** ppEntry
/* = NULL */,
3837 bool* pBank
/* = NULL */ ) const
3839 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3845 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
3848 OUStringBuffer
sBuff(128); // guess-estimate of a value that will pretty much guarantee no re-alloc
3849 OUString aSymbol
, aExtension
;
3850 if ( pFormat
->GetNewCurrencySymbol( aSymbol
, aExtension
) )
3854 bool bFoundBank
= false;
3855 // we definitely need an entry matching the format code string
3856 const NfCurrencyEntry
* pFoundEntry
= GetCurrencyEntry(
3857 bFoundBank
, aSymbol
, aExtension
, pFormat
->GetLanguage(),
3861 *ppEntry
= pFoundEntry
;
3863 *pBank
= bFoundBank
;
3864 rStr
= pFoundEntry
->BuildSymbolString(bFoundBank
);
3867 if ( rStr
.isEmpty() )
3868 { // analog to BuildSymbolString
3870 if ( aSymbol
.indexOf( '-' ) != -1 ||
3871 aSymbol
.indexOf( ']' ) != -1 )
3874 sBuff
.append( aSymbol
);
3879 sBuff
.append(aSymbol
);
3881 if ( !aExtension
.isEmpty() )
3883 sBuff
.append(aExtension
);
3887 rStr
= sBuff
.toString();
3897 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank
,
3898 std::u16string_view rSymbol
,
3899 const OUString
& rExtension
,
3900 LanguageType eFormatLanguage
,
3901 bool bOnlyStringLanguage
)
3903 sal_Int32 nExtLen
= rExtension
.getLength();
3904 LanguageType eExtLang
;
3907 // rExtension should be a 16-bit hex value max FFFF which may contain a
3908 // leading "-" separator (that is not a minus sign, but toInt32 can be
3909 // used to parse it, with post-processing as necessary):
3910 sal_Int32 nExtLang
= rExtension
.toInt32( 16 );
3913 eExtLang
= LANGUAGE_DONTKNOW
;
3917 eExtLang
= LanguageType((nExtLang
< 0) ? -nExtLang
: nExtLang
);
3922 eExtLang
= LANGUAGE_DONTKNOW
;
3924 const NfCurrencyEntry
* pFoundEntry
= nullptr;
3925 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3926 sal_uInt16 nCount
= rTable
.size();
3929 // first try with given extension language/country
3932 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3934 LanguageType eLang
= rTable
[j
].GetLanguage();
3935 if ( eLang
== eExtLang
||
3936 ((eExtLang
== LANGUAGE_DONTKNOW
) &&
3937 (eLang
== LANGUAGE_SYSTEM
)))
3939 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3940 &rTable
[j
], j
, rSymbol
);
3946 if ( pFoundEntry
|| !bCont
|| (bOnlyStringLanguage
&& nExtLen
) )
3950 if ( !bOnlyStringLanguage
)
3952 // now try the language/country of the number format
3953 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3955 LanguageType eLang
= rTable
[j
].GetLanguage();
3956 if ( eLang
== eFormatLanguage
||
3957 ((eFormatLanguage
== LANGUAGE_DONTKNOW
) &&
3958 (eLang
== LANGUAGE_SYSTEM
)))
3960 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3961 &rTable
[j
], j
, rSymbol
);
3966 if ( pFoundEntry
|| !bCont
)
3972 // then try without language/country if no extension specified
3975 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3977 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3978 &rTable
[j
], j
, rSymbol
);
3986 void SvNumberFormatter::GetCompatibilityCurrency( OUString
& rSymbol
, OUString
& rAbbrev
) const
3988 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3989 css::uno::Sequence
< css::i18n::Currency2
>
3990 xCurrencies( xLocaleData
->getAllCurrencies() );
3992 auto pCurrency
= std::find_if(xCurrencies
.begin(), xCurrencies
.end(),
3993 [](const css::i18n::Currency2
& rCurrency
) { return rCurrency
.UsedInCompatibleFormatCodes
; });
3994 if (pCurrency
!= xCurrencies
.end())
3996 rSymbol
= pCurrency
->Symbol
;
3997 rAbbrev
= pCurrency
->BankSymbol
;
4001 if (LocaleDataWrapper::areChecksEnabled())
4003 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
4004 appendLocaleInfo( "GetCompatibilityCurrency: none?"));
4006 rSymbol
= xLocaleData
->getCurrSymbol();
4007 rAbbrev
= xLocaleData
->getCurrBankSymbol();
4012 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry
& rCurr
)
4014 switch ( rCurr
.GetPositiveFormat() )
4022 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
4025 switch ( rCurr
.GetNegativeFormat() )
4045 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
4051 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang
)
4053 // The set is initialized as a side effect of the currency table
4054 // created, make sure that exists, which usually is the case unless a
4055 // SvNumberFormatter was never instantiated.
4056 GetTheCurrencyTable();
4057 const NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
4058 return rInstalledLocales
.find( eLang
) != rInstalledLocales
.end();
4062 void SvNumberFormatter::ImpInitCurrencyTable()
4064 // Race condition possible:
4065 // ::osl::MutexGuard aGuard( GetMutex() );
4066 // while ( !bCurrencyTableInitialized )
4067 // ImpInitCurrencyTable();
4068 static bool bInitializing
= false;
4069 if ( bCurrencyTableInitialized
|| bInitializing
)
4073 bInitializing
= true;
4075 LanguageType eSysLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
4076 std::optional
<LocaleDataWrapper
> pLocaleData(std::in_place
,
4077 ::comphelper::getProcessComponentContext(),
4078 SvtSysLocale().GetLanguageTag() );
4079 // get user configured currency
4080 OUString aConfiguredCurrencyAbbrev
;
4081 LanguageType eConfiguredCurrencyLanguage
= LANGUAGE_SYSTEM
;
4082 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
4083 aConfiguredCurrencyAbbrev
, eConfiguredCurrencyLanguage
);
4084 sal_uInt16 nSecondarySystemCurrencyPosition
= 0;
4085 sal_uInt16 nMatchingSystemCurrencyPosition
= 0;
4087 // First entry is SYSTEM:
4088 theCurrencyTable::get().insert(
4089 theCurrencyTable::get().begin(),
4090 std::make_unique
<NfCurrencyEntry
>(*pLocaleData
, LANGUAGE_SYSTEM
));
4091 sal_uInt16 nCurrencyPos
= 1;
4093 const css::uno::Sequence
< css::lang::Locale
> xLoc
= LocaleDataWrapper::getInstalledLocaleNames();
4094 sal_Int32 nLocaleCount
= xLoc
.getLength();
4095 SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount
<< "\"" );
4096 NfCurrencyTable
&rCurrencyTable
= theCurrencyTable::get();
4097 NfCurrencyTable
&rLegacyOnlyCurrencyTable
= theLegacyOnlyCurrencyTable::get();
4098 NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
4099 sal_uInt16 nLegacyOnlyCurrencyPos
= 0;
4100 for ( css::lang::Locale
const & rLocale
: xLoc
)
4102 LanguageType eLang
= LanguageTag::convertToLanguageType( rLocale
, false);
4103 rInstalledLocales
.insert( eLang
);
4104 pLocaleData
.emplace(
4105 ::comphelper::getProcessComponentContext(),
4106 LanguageTag(rLocale
) );
4107 Sequence
< Currency2
> aCurrSeq
= pLocaleData
->getAllCurrencies();
4108 sal_Int32 nCurrencyCount
= aCurrSeq
.getLength();
4109 Currency2
const * const pCurrencies
= aCurrSeq
.getConstArray();
4111 // one default currency for each locale, insert first so it is found first
4113 for ( nDefault
= 0; nDefault
< nCurrencyCount
; nDefault
++ )
4115 if ( pCurrencies
[nDefault
].Default
)
4118 std::unique_ptr
<NfCurrencyEntry
> pEntry
;
4119 if ( nDefault
< nCurrencyCount
)
4121 pEntry
.reset(new NfCurrencyEntry(pCurrencies
[nDefault
], *pLocaleData
, eLang
));
4124 { // first or ShellsAndPebbles
4125 pEntry
.reset(new NfCurrencyEntry(*pLocaleData
, eLang
));
4127 if (LocaleDataWrapper::areChecksEnabled())
4129 lcl_CheckCurrencySymbolPosition( *pEntry
);
4131 if ( !nSystemCurrencyPosition
&& !aConfiguredCurrencyAbbrev
.isEmpty() &&
4132 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
&&
4133 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
)
4135 nSystemCurrencyPosition
= nCurrencyPos
;
4137 if ( !nMatchingSystemCurrencyPosition
&&
4138 pEntry
->GetLanguage() == eSysLang
)
4140 nMatchingSystemCurrencyPosition
= nCurrencyPos
;
4142 rCurrencyTable
.insert(
4143 rCurrencyTable
.begin() + nCurrencyPos
++, std::move(pEntry
));
4144 // all remaining currencies for each locale
4145 if ( nCurrencyCount
> 1 )
4147 sal_Int32 nCurrency
;
4148 for ( nCurrency
= 0; nCurrency
< nCurrencyCount
; nCurrency
++ )
4150 if (pCurrencies
[nCurrency
].LegacyOnly
)
4152 rLegacyOnlyCurrencyTable
.insert(
4153 rLegacyOnlyCurrencyTable
.begin() + nLegacyOnlyCurrencyPos
++,
4154 std::make_unique
<NfCurrencyEntry
>(
4155 pCurrencies
[nCurrency
], *pLocaleData
, eLang
));
4157 else if ( nCurrency
!= nDefault
)
4159 pEntry
.reset(new NfCurrencyEntry(pCurrencies
[nCurrency
], *pLocaleData
, eLang
));
4161 bool bInsert
= true;
4162 sal_uInt16 n
= rCurrencyTable
.size();
4163 sal_uInt16 aCurrencyIndex
= 1; // skip first SYSTEM entry
4164 for ( sal_uInt16 j
=1; j
<n
; j
++ )
4166 if ( rCurrencyTable
[aCurrencyIndex
++] == *pEntry
)
4178 if ( !nSecondarySystemCurrencyPosition
&&
4179 (!aConfiguredCurrencyAbbrev
.isEmpty() ?
4180 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
:
4181 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
) )
4183 nSecondarySystemCurrencyPosition
= nCurrencyPos
;
4185 if ( !nMatchingSystemCurrencyPosition
&&
4186 pEntry
->GetLanguage() == eSysLang
)
4188 nMatchingSystemCurrencyPosition
= nCurrencyPos
;
4190 rCurrencyTable
.insert(
4191 rCurrencyTable
.begin() + nCurrencyPos
++, std::move(pEntry
));
4197 if ( !nSystemCurrencyPosition
)
4199 nSystemCurrencyPosition
= nSecondarySystemCurrencyPosition
;
4201 if ((!aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
4202 LocaleDataWrapper::areChecksEnabled())
4204 LocaleDataWrapper::outputCheckMessage(
4205 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
4207 // match SYSTEM if no configured currency found
4208 if ( !nSystemCurrencyPosition
)
4210 nSystemCurrencyPosition
= nMatchingSystemCurrencyPosition
;
4212 if ((aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
4213 LocaleDataWrapper::areChecksEnabled())
4215 LocaleDataWrapper::outputCheckMessage(
4216 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
4218 pLocaleData
.reset();
4219 SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( nullptr, SvNumberFormatter
, CurrencyChangeLink
) );
4220 bInitializing
= false;
4221 bCurrencyTableInitialized
= true;
4225 static void addToCurrencyFormatsList( NfWSStringsDtor
& rStrArr
, const OUString
& rFormat
)
4227 // Prevent duplicates even over subsequent calls of
4228 // GetCurrencyFormatStrings() with the same vector.
4229 if (std::find( rStrArr
.begin(), rStrArr
.end(), rFormat
) == rStrArr
.end())
4230 rStrArr
.push_back( rFormat
);
4234 sal_uInt16
SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor
& rStrArr
,
4235 const NfCurrencyEntry
& rCurr
,
4238 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4240 + pFormatScanner
->GetRedString()
4243 sal_uInt16 nDefault
= 0;
4246 // Only bank symbols.
4247 OUString aPositiveBank
= rCurr
.BuildPositiveFormatString(true, *xLocaleData
);
4248 OUString aNegativeBank
= rCurr
.BuildNegativeFormatString(true, *xLocaleData
);
4250 OUString format1
= aPositiveBank
4253 addToCurrencyFormatsList( rStrArr
, format1
);
4255 OUString format2
= aPositiveBank
4259 addToCurrencyFormatsList( rStrArr
, format2
);
4261 nDefault
= rStrArr
.size() - 1;
4265 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
4266 // duplicates if no decimals in currency.
4267 OUString aPositive
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
);
4268 OUString aNegative
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
);
4274 if (rCurr
.GetDigits())
4276 OUString aPositiveNoDec
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 0);
4277 OUString aNegativeNoDec
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 0 );
4278 OUString aPositiveDashed
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 2);
4279 OUString aNegativeDashed
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 2);
4281 format1
= aPositiveNoDec
4285 format3
= aPositiveNoDec
4290 format5
= aPositiveDashed
4305 if (rCurr
.GetDigits())
4307 addToCurrencyFormatsList( rStrArr
, format1
);
4309 addToCurrencyFormatsList( rStrArr
, format2
);
4310 if (rCurr
.GetDigits())
4312 addToCurrencyFormatsList( rStrArr
, format3
);
4314 addToCurrencyFormatsList( rStrArr
, format4
);
4315 nDefault
= rStrArr
.size() - 1;
4316 if (rCurr
.GetDigits())
4318 addToCurrencyFormatsList( rStrArr
, format5
);
4324 sal_uInt32
SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt
) const
4326 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4329 SvNumberFormatterIndexTable::const_iterator it
= pMergeTable
->find(nOldFmt
);
4330 if (it
!= pMergeTable
->end())
4338 bool SvNumberFormatter::HasMergeFormatTable() const
4340 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4341 return pMergeTable
&& !pMergeTable
->empty();
4345 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
, sal_uInt16 nTwoDigitYearStart
)
4349 if ( nYear
< (nTwoDigitYearStart
% 100) )
4351 return nYear
+ (((nTwoDigitYearStart
/ 100) + 1) * 100);
4355 return nYear
+ ((nTwoDigitYearStart
/ 100) * 100);
4361 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
4363 aSymbol
= rLocaleData
.getCurrSymbol();
4364 aBankSymbol
= rLocaleData
.getCurrBankSymbol();
4366 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
4367 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
4368 nDigits
= rLocaleData
.getCurrDigits();
4369 cZeroChar
= rLocaleData
.getCurrZeroChar();
4373 NfCurrencyEntry::NfCurrencyEntry( const css::i18n::Currency
& rCurr
,
4374 const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
4376 aSymbol
= rCurr
.Symbol
;
4377 aBankSymbol
= rCurr
.BankSymbol
;
4379 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
4380 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
4381 nDigits
= rCurr
.DecimalPlaces
;
4382 cZeroChar
= rLocaleData
.getCurrZeroChar();
4385 bool NfCurrencyEntry::operator==( const NfCurrencyEntry
& r
) const
4387 return aSymbol
== r
.aSymbol
4388 && aBankSymbol
== r
.aBankSymbol
4389 && eLanguage
== r
.eLanguage
4393 OUString
NfCurrencyEntry::BuildSymbolString(bool bBank
,
4394 bool bWithoutExtension
) const
4396 OUStringBuffer
aBuf("[$");
4399 aBuf
.append(aBankSymbol
);
4403 if ( aSymbol
.indexOf( '-' ) >= 0 ||
4404 aSymbol
.indexOf( ']' ) >= 0)
4406 aBuf
.append("\"" + aSymbol
+ "\"");
4410 aBuf
.append(aSymbol
);
4412 if ( !bWithoutExtension
&& eLanguage
!= LANGUAGE_DONTKNOW
&& eLanguage
!= LANGUAGE_SYSTEM
)
4414 sal_Int32 nLang
= static_cast<sal_uInt16
>(eLanguage
);
4415 aBuf
.append('-').append(OUString::number(nLang
, 16).toAsciiUpperCase());
4419 return aBuf
.makeStringAndClear();
4422 OUString
NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper
& rLoc
,
4423 sal_uInt16 nDecimalFormat
) const
4425 OUStringBuffer aBuf
;
4426 aBuf
.append("#" + rLoc
.getNumThousandSep() + "##0");
4427 if (nDecimalFormat
&& nDigits
)
4429 aBuf
.append(rLoc
.getNumDecimalSep());
4430 sal_Unicode cDecimalChar
= nDecimalFormat
== 2 ? '-' : cZeroChar
;
4431 for (sal_uInt16 i
= 0; i
< nDigits
; ++i
)
4433 aBuf
.append(cDecimalChar
);
4436 return aBuf
.makeStringAndClear();
4440 OUString
NfCurrencyEntry::BuildPositiveFormatString(bool bBank
, const LocaleDataWrapper
& rLoc
,
4441 sal_uInt16 nDecimalFormat
) const
4443 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
4444 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat( rLoc
.getCurrPositiveFormat(),
4445 nPositiveFormat
, bBank
);
4446 CompletePositiveFormatString(sBuf
, bBank
, nPosiForm
);
4447 return sBuf
.makeStringAndClear();
4451 OUString
NfCurrencyEntry::BuildNegativeFormatString(bool bBank
,
4452 const LocaleDataWrapper
& rLoc
, sal_uInt16 nDecimalFormat
) const
4454 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
4455 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc
.getCurrNegativeFormat(),
4456 nNegativeFormat
, bBank
);
4457 CompleteNegativeFormatString(sBuf
, bBank
, nNegaForm
);
4458 return sBuf
.makeStringAndClear();
4462 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, bool bBank
,
4463 sal_uInt16 nPosiForm
) const
4465 OUString aSymStr
= BuildSymbolString(bBank
);
4466 NfCurrencyEntry::CompletePositiveFormatString( rStr
, aSymStr
, nPosiForm
);
4470 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
, bool bBank
,
4471 sal_uInt16 nNegaForm
) const
4473 OUString aSymStr
= BuildSymbolString(bBank
);
4474 NfCurrencyEntry::CompleteNegativeFormatString( rStr
, aSymStr
, nNegaForm
);
4479 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, std::u16string_view rSymStr
,
4480 sal_uInt16 nPositiveFormat
)
4482 switch( nPositiveFormat
)
4485 rStr
.insert(0, rSymStr
);
4488 rStr
.append(rSymStr
);
4492 rStr
.insert(0, ' ');
4493 rStr
.insert(0, rSymStr
);
4499 rStr
.append(rSymStr
);
4503 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4510 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
,
4511 std::u16string_view rSymStr
,
4512 sal_uInt16 nNegativeFormat
)
4514 switch( nNegativeFormat
)
4518 rStr
.insert(0, rSymStr
);
4519 rStr
.insert(0, '(');
4525 rStr
.insert(0, rSymStr
);
4526 rStr
.insert(0, '-');
4531 rStr
.insert(0, '-');
4532 rStr
.insert(0, rSymStr
);
4537 rStr
.insert(0, rSymStr
);
4543 rStr
.insert(0, '(');
4544 rStr
.append(rSymStr
);
4550 rStr
.append(rSymStr
);
4551 rStr
.insert(0, '-');
4557 rStr
.append(rSymStr
);
4562 rStr
.append(rSymStr
);
4569 rStr
.append(rSymStr
);
4570 rStr
.insert(0, '-');
4575 rStr
.insert(0, ' ');
4576 rStr
.insert(0, rSymStr
);
4577 rStr
.insert(0, '-');
4583 rStr
.append(rSymStr
);
4589 rStr
.insert(0, " -");
4590 rStr
.insert(0, rSymStr
);
4595 rStr
.insert(0, ' ');
4596 rStr
.insert(0, rSymStr
);
4604 rStr
.append(rSymStr
);
4609 rStr
.insert(0, ' ');
4610 rStr
.insert(0, rSymStr
);
4611 rStr
.insert(0, '(');
4617 rStr
.insert(0, '(');
4619 rStr
.append(rSymStr
);
4624 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4631 sal_uInt16
NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat
,
4632 sal_uInt16 nCurrFormat
, bool bBank
)
4636 #if NF_BANKSYMBOL_FIX_POSITION
4637 (void) nIntlFormat
; // avoid warnings
4640 switch ( nIntlFormat
)
4643 nIntlFormat
= 2; // $ 1
4646 nIntlFormat
= 3; // 1 $
4653 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4664 //! Call this only if nCurrFormat is really with parentheses!
4665 static sal_uInt16
lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat
, sal_uInt16 nCurrFormat
)
4667 short nSign
= 0; // -1:=bracket 0:=left, 1:=middle, 2:=right
4668 switch ( nIntlFormat
)
4694 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4698 switch ( nCurrFormat
)
4750 sal_uInt16
NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat
,
4751 sal_uInt16 nCurrFormat
, bool bBank
)
4755 #if NF_BANKSYMBOL_FIX_POSITION
4758 switch ( nIntlFormat
)
4761 // nIntlFormat = 14; // ($ 1)
4762 nIntlFormat
= 9; // -$ 1
4765 nIntlFormat
= 9; // -$ 1
4768 nIntlFormat
= 11; // $ -1
4771 nIntlFormat
= 12; // $ 1-
4774 // nIntlFormat = 15; // (1 $)
4775 nIntlFormat
= 8; // -1 $
4778 nIntlFormat
= 8; // -1 $
4781 nIntlFormat
= 13; // 1- $
4784 nIntlFormat
= 10; // 1 $-
4799 // nIntlFormat = 14; // ($ 1)
4800 nIntlFormat
= 9; // -$ 1
4803 // nIntlFormat = 15; // (1 $)
4804 nIntlFormat
= 8; // -1 $
4807 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4812 else if ( nIntlFormat
!= nCurrFormat
)
4814 switch ( nCurrFormat
)
4817 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4818 nIntlFormat
, nCurrFormat
);
4821 nIntlFormat
= nCurrFormat
;
4824 nIntlFormat
= nCurrFormat
;
4827 nIntlFormat
= nCurrFormat
;
4830 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4831 nIntlFormat
, nCurrFormat
);
4834 nIntlFormat
= nCurrFormat
;
4837 nIntlFormat
= nCurrFormat
;
4840 nIntlFormat
= nCurrFormat
;
4843 nIntlFormat
= nCurrFormat
;
4846 nIntlFormat
= nCurrFormat
;
4849 nIntlFormat
= nCurrFormat
;
4852 nIntlFormat
= nCurrFormat
;
4855 nIntlFormat
= nCurrFormat
;
4858 nIntlFormat
= nCurrFormat
;
4861 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4862 nIntlFormat
, nCurrFormat
);
4865 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4866 nIntlFormat
, nCurrFormat
);
4869 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4876 const NfKeywordTable
& SvNumberFormatter::GetKeywords( sal_uInt32 nKey
)
4878 osl::MutexGuard
aGuard( GetInstanceMutex() );
4879 const SvNumberformat
* pFormat
= GetFormatEntry( nKey
);
4881 ChangeIntl( pFormat
->GetLanguage());
4883 ChangeIntl( IniLnge
);
4884 return pFormatScanner
->GetKeywords();
4887 const NfKeywordTable
& SvNumberFormatter::GetEnglishKeywords() const
4889 return ImpSvNumberformatScan::GetEnglishKeywords();
4892 const std::vector
<Color
> & SvNumberFormatter::GetStandardColors() const
4894 return ImpSvNumberformatScan::GetStandardColors();
4897 size_t SvNumberFormatter::GetMaxDefaultColors() const
4899 return ImpSvNumberformatScan::GetMaxDefaultColors();
4902 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */