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/lok.hxx>
28 #include <comphelper/string.hxx>
29 #include <o3tl/string_view.hxx>
30 #include <tools/debug.hxx>
31 #include <unotools/charclass.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <i18nlangtag/mslangid.hxx>
34 #include <unotools/localedatawrapper.hxx>
35 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
36 #include <com/sun/star/i18n/KNumberFormatType.hpp>
37 #include <com/sun/star/i18n/FormatElement.hpp>
38 #include <com/sun/star/i18n/Currency2.hpp>
39 #include <com/sun/star/i18n/NumberFormatCode.hpp>
40 #include <com/sun/star/i18n/XNumberFormatCode.hpp>
41 #include <com/sun/star/i18n/NumberFormatMapper.hpp>
42 #include <comphelper/processfactory.hxx>
44 #include <osl/mutex.hxx>
46 #include "zforscan.hxx"
47 #include "zforfind.hxx"
48 #include <svl/zformat.hxx>
49 #include <i18npool/reservedconstants.hxx>
51 #include <unotools/syslocaleoptions.hxx>
52 #include <unotools/digitgroupingiterator.hxx>
53 #include <rtl/strbuf.hxx>
54 #include <rtl/math.hxx>
61 using namespace ::com::sun::star
;
62 using namespace ::com::sun::star::uno
;
63 using namespace ::com::sun::star::i18n
;
64 using namespace ::com::sun::star::lang
;
66 // Constants for type offsets per Country/Language (CL)
68 #define ZF_STANDARD_PERCENT 10
69 #define ZF_STANDARD_CURRENCY 20
70 #define ZF_STANDARD_DATE 30
71 #define ZF_STANDARD_TIME 60
72 #define ZF_STANDARD_DURATION (ZF_STANDARD_TIME + 4)
73 #define ZF_STANDARD_DATETIME 70
74 #define ZF_STANDARD_SCIENTIFIC 80
75 #define ZF_STANDARD_FRACTION 85
77 // Additional builtin formats, historically not fitting into the first 10 of a
78 // category. Make sure it doesn't spill over to the next category.
79 #define ZF_STANDARD_DATE_SYS_DMMMYYYY (ZF_STANDARD_DATE + 10)
80 #define ZF_STANDARD_DATE_SYS_DMMMMYYYY (ZF_STANDARD_DATE + 11)
81 #define ZF_STANDARD_DATE_SYS_NNDMMMYY (ZF_STANDARD_DATE + 12)
82 #define ZF_STANDARD_DATE_SYS_NNDMMMMYYYY (ZF_STANDARD_DATE + 13)
83 #define ZF_STANDARD_DATE_SYS_NNNNDMMMMYYYY (ZF_STANDARD_DATE + 14)
84 #define ZF_STANDARD_DATE_DIN_DMMMYYYY (ZF_STANDARD_DATE + 15)
85 #define ZF_STANDARD_DATE_DIN_DMMMMYYYY (ZF_STANDARD_DATE + 16)
86 #define ZF_STANDARD_DATE_DIN_MMDD (ZF_STANDARD_DATE + 17)
87 #define ZF_STANDARD_DATE_DIN_YYMMDD (ZF_STANDARD_DATE + 18)
88 #define ZF_STANDARD_DATE_DIN_YYYYMMDD (ZF_STANDARD_DATE + 19)
89 #define ZF_STANDARD_DATE_WW (ZF_STANDARD_DATE + 20)
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_DATE_SYS_DMMMYYYY
, // NF_DATE_SYS_DMMMYYYY
136 ZF_STANDARD_DATE_DIN_DMMMYYYY
, // NF_DATE_DIN_DMMMYYYY
137 ZF_STANDARD_DATE_SYS_DMMMMYYYY
, // NF_DATE_SYS_DMMMMYYYY
138 ZF_STANDARD_DATE_DIN_DMMMMYYYY
, // NF_DATE_DIN_DMMMMYYYY
139 ZF_STANDARD_DATE_SYS_NNDMMMYY
, // NF_DATE_SYS_NNDMMMYY
140 ZF_STANDARD_DATE
+ 1, // NF_DATE_DEF_NNDDMMMYY
141 ZF_STANDARD_DATE_SYS_NNDMMMMYYYY
, // NF_DATE_SYS_NNDMMMMYYYY
142 ZF_STANDARD_DATE_SYS_NNNNDMMMMYYYY
, // NF_DATE_SYS_NNNNDMMMMYYYY
143 ZF_STANDARD_DATE_DIN_MMDD
, // NF_DATE_DIN_MMDD
144 ZF_STANDARD_DATE_DIN_YYMMDD
, // NF_DATE_DIN_YYMMDD
145 ZF_STANDARD_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_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
+ 2, // 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
+ 3, // NF_DATETIME_ISO_YYYYMMDD_HHMMSS
171 ZF_STANDARD_DATETIME
+ 4, // NF_DATETIME_ISO_YYYYMMDD_HHMMSS000
172 ZF_STANDARD_DATETIME
+ 5, // NF_DATETIME_ISO_YYYYMMDDTHHMMSS
173 ZF_STANDARD_DATETIME
+ 6 // NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
177 instead of every number formatter being a listener we have a registry which
178 also handles one instance of the SysLocale options
181 class SvNumberFormatterRegistry_Impl
: public utl::ConfigurationListener
183 std::vector
< SvNumberFormatter
* >
185 SvtSysLocaleOptions aSysLocaleOptions
;
186 LanguageType eSysLanguage
;
189 SvNumberFormatterRegistry_Impl();
190 virtual ~SvNumberFormatterRegistry_Impl() override
;
192 void Insert( SvNumberFormatter
* pThis
)
193 { aFormatters
.push_back( pThis
); }
195 void Remove( SvNumberFormatter
const * pThis
);
198 { return aFormatters
.size(); }
200 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster
*, ConfigurationHints
) override
;
203 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
204 : eSysLanguage(MsLangId::getRealLanguage( LANGUAGE_SYSTEM
))
206 aSysLocaleOptions
.AddListener( this );
210 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
212 aSysLocaleOptions
.RemoveListener( this );
216 void SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter
const * pThis
)
218 auto it
= std::find(aFormatters
.begin(), aFormatters
.end(), pThis
);
219 if (it
!= aFormatters
.end())
220 aFormatters
.erase( it
);
223 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster
*,
224 ConfigurationHints nHint
)
226 ::osl::MutexGuard
aGuard( SvNumberFormatter::GetGlobalMutex() );
228 if ( nHint
& ConfigurationHints::Locale
)
230 for(SvNumberFormatter
* pFormatter
: aFormatters
)
231 pFormatter
->ReplaceSystemCL( eSysLanguage
);
232 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
234 if ( nHint
& ConfigurationHints::Currency
)
236 for(SvNumberFormatter
* pFormatter
: aFormatters
)
237 pFormatter
->ResetDefaultSystemCurrency();
239 if ( nHint
& ConfigurationHints::DatePatterns
)
241 for(SvNumberFormatter
* pFormatter
: aFormatters
)
242 pFormatter
->InvalidateDateAcceptancePatterns();
246 static std::atomic
<bool> g_CurrencyTableInitialized
;
248 SvNumberFormatterRegistry_Impl
* SvNumberFormatter::pFormatterRegistry
= nullptr;
251 NfCurrencyTable
& theCurrencyTable()
253 static NfCurrencyTable SINGLETON
;
257 NfCurrencyTable
& theLegacyOnlyCurrencyTable()
259 static NfCurrencyTable SINGLETON
;
263 /** THE set of installed locales. */
264 std::set
< LanguageType
> theInstalledLocales
;
267 sal_uInt16
SvNumberFormatter::nSystemCurrencyPosition
= 0;
269 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
270 // language dependent.
271 #define NF_BANKSYMBOL_FIX_POSITION 1
273 const sal_uInt16
SvNumberFormatter::UNLIMITED_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max();
274 const sal_uInt16
SvNumberFormatter::INPUTSTRING_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max()-1;
276 void SvNFEngine::ChangeIntl(SvNFLanguageData
& rCurrentLanguage
, LanguageType eLnge
)
278 rCurrentLanguage
.ChangeIntl(eLnge
);
281 void SvNFEngine::ChangeNullDate(SvNFLanguageData
& rCurrentLanguage
, sal_uInt16 nDay
, sal_uInt16 nMonth
, sal_Int16 nYear
)
283 rCurrentLanguage
.pFormatScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
284 rCurrentLanguage
.pStringScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
287 SvNFLanguageData::SvNFLanguageData(const Reference
<XComponentContext
>& rxContext
, LanguageType eLang
,
288 const SvNumberFormatter
& rColorCallback
)
289 : xContext(rxContext
)
292 , aLanguageTag(eLang
)
293 , eEvalDateFormat(NF_EVALDATEFORMAT_INTL
)
295 xCharClass
.changeLocale(xContext
, aLanguageTag
);
296 xLocaleData
.init(xContext
, aLanguageTag
);
297 xCalendar
.init(xContext
, aLanguageTag
.getLocale());
298 xTransliteration
.init(xContext
, ActLnge
);
300 // cached locale data items
301 const LocaleDataWrapper
* pLoc
= GetLocaleData();
302 aDecimalSep
= pLoc
->getNumDecimalSep();
303 aDecimalSepAlt
= pLoc
->getNumDecimalSepAlt();
304 aThousandSep
= pLoc
->getNumThousandSep();
305 aDateSep
= pLoc
->getDateSep();
307 pStringScanner
.reset(new ImpSvNumberInputScan(*this));
308 pFormatScanner
.reset(new ImpSvNumberformatScan(*this, rColorCallback
));
311 SvNFLanguageData::SvNFLanguageData(const SvNFLanguageData
& rOther
)
312 : xContext(rOther
.xContext
)
313 , IniLnge(rOther
.IniLnge
)
314 , ActLnge(rOther
.ActLnge
)
315 , aLanguageTag(rOther
.aLanguageTag
)
316 , aDecimalSep(rOther
.aDecimalSep
)
317 , aDecimalSepAlt(rOther
.aDecimalSepAlt
)
318 , aThousandSep(rOther
.aThousandSep
)
319 , aDateSep(rOther
.aDateSep
)
320 , eEvalDateFormat(rOther
.eEvalDateFormat
)
322 xCharClass
.changeLocale(xContext
, aLanguageTag
);
323 xLocaleData
.init(xContext
, aLanguageTag
);
324 xCalendar
.init(xContext
, aLanguageTag
.getLocale());
325 xTransliteration
.init(xContext
, ActLnge
);
327 pStringScanner
.reset(new ImpSvNumberInputScan(*this));
328 pFormatScanner
.reset(new ImpSvNumberformatScan(*this, rOther
.pFormatScanner
->getColorCallback()));
331 SvNFLanguageData::~SvNFLanguageData()
335 const LocaleDataWrapper
* SvNFLanguageData::GetLocaleData() const { return xLocaleData
.get(); }
337 const CharClass
* SvNFLanguageData::GetCharClass() const { return xCharClass
.get(); }
339 CalendarWrapper
* SvNFLanguageData::GetCalendar() const { return xCalendar
.get(); }
341 const ::utl::TransliterationWrapper
* SvNFLanguageData::GetTransliteration() const
343 return xTransliteration
.get();
346 const LanguageTag
& SvNFLanguageData::GetLanguageTag() const { return aLanguageTag
; }
348 const ImpSvNumberformatScan
* SvNFLanguageData::GetFormatScanner() const { return pFormatScanner
.get(); }
350 const OUString
& SvNFLanguageData::GetNumDecimalSep() const { return aDecimalSep
; }
352 const OUString
& SvNFLanguageData::GetNumDecimalSepAlt() const { return aDecimalSepAlt
; }
354 const OUString
& SvNFLanguageData::GetNumThousandSep() const { return aThousandSep
; }
356 const OUString
& SvNFLanguageData::GetDateSep() const { return aDateSep
; }
358 bool SvNFLanguageData::IsDecimalSep( std::u16string_view rStr
) const
360 if (rStr
== GetNumDecimalSep())
362 if (GetNumDecimalSepAlt().isEmpty())
364 return rStr
== GetNumDecimalSepAlt();
367 OUString
SvNFLanguageData::GetLangDecimalSep( LanguageType nLang
)
369 if (nLang
== ActLnge
)
371 return GetNumDecimalSep();
374 LanguageType eSaveLang
= xLocaleData
.getCurrentLanguage();
375 if (nLang
== eSaveLang
)
377 aRet
= xLocaleData
->getNumDecimalSep();
381 LanguageTag
aSaveLocale( xLocaleData
->getLanguageTag() );
382 xLocaleData
.changeLocale( LanguageTag( nLang
));
383 aRet
= xLocaleData
->getNumDecimalSep();
384 xLocaleData
.changeLocale( aSaveLocale
);
389 void SvNFLanguageData::ChangeIntl(LanguageType eLnge
)
391 if (ActLnge
== eLnge
)
396 aLanguageTag
.reset( eLnge
);
397 xCharClass
.changeLocale( xContext
, aLanguageTag
);
398 xLocaleData
.changeLocale( aLanguageTag
);
399 xCalendar
.changeLocale( aLanguageTag
.getLocale() );
400 xTransliteration
.changeLocale( eLnge
);
402 // cached locale data items, initialize BEFORE calling ChangeIntl below
403 const LocaleDataWrapper
* pLoc
= GetLocaleData();
404 aDecimalSep
= pLoc
->getNumDecimalSep();
405 aDecimalSepAlt
= pLoc
->getNumDecimalSepAlt();
406 aThousandSep
= pLoc
->getNumThousandSep();
407 aDateSep
= pLoc
->getDateSep();
409 pFormatScanner
->ChangeIntl();
410 pStringScanner
->ChangeIntl();
413 SvNumberFormatter::SvNumberFormatter( const Reference
< XComponentContext
>& rxContext
,
415 : m_xContext( rxContext
)
416 , IniLnge(eLang
!= LANGUAGE_DONTKNOW
? eLang
: UNKNOWN_SUBSTITUTE
)
417 , m_aRWPolicy(SvNFEngine::GetRWPolicy(m_aFormatData
))
418 , m_aCurrentLanguage(rxContext
, IniLnge
, *this)
419 , m_xNatNum(m_xContext
)
422 // 0 .. 999 for initialized language formats
423 m_aFormatData
.ImpGenerateFormats(m_aCurrentLanguage
, GetNatNum(), 0, false);
425 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
426 GetFormatterRegistry().Insert( this );
429 SvNumberFormatter::~SvNumberFormatter()
432 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
433 pFormatterRegistry
->Remove( this );
434 if ( !pFormatterRegistry
->Count() )
436 delete pFormatterRegistry
;
437 pFormatterRegistry
= nullptr;
441 m_aFormatData
.aFTable
.clear();
445 void SvNumberFormatter::ChangeIntl(LanguageType eLnge
)
447 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
448 SvNFEngine::ChangeIntl(m_aCurrentLanguage
, eLnge
);
452 ::osl::Mutex
& SvNumberFormatter::GetGlobalMutex()
454 // #i77768# Due to a static reference in the toolkit lib
455 // we need a mutex that lives longer than the svl library.
456 // Otherwise the dtor would use a destructed mutex!!
457 static osl::Mutex
* persistentMutex(new osl::Mutex
);
459 return *persistentMutex
;
464 SvNumberFormatterRegistry_Impl
& SvNumberFormatter::GetFormatterRegistry()
466 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
467 if ( !pFormatterRegistry
)
469 pFormatterRegistry
= new SvNumberFormatterRegistry_Impl
;
471 return *pFormatterRegistry
;
474 void SvNumberFormatter::SetColorLink( const Link
<sal_uInt16
,Color
*>& rColorTableCallBack
)
476 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
477 aColorLink
= rColorTableCallBack
;
480 Color
* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex
) const
482 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
483 if( aColorLink
.IsSet() )
485 return aColorLink
.Call(nIndex
);
493 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay
,
497 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
498 SvNFEngine::ChangeNullDate(m_aCurrentLanguage
, nDay
, nMonth
, nYear
);
501 const Date
& SvNFLanguageData::GetNullDate() const
503 return pFormatScanner
->GetNullDate();
506 void SvNFLanguageData::ChangeStandardPrec(short nPrec
)
508 pFormatScanner
->ChangeStandardPrec(nPrec
);
511 const Date
& SvNumberFormatter::GetNullDate() const
513 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
514 return m_aCurrentLanguage
.GetNullDate();
517 void SvNumberFormatter::ChangeStandardPrec(short nPrec
)
519 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
520 m_aCurrentLanguage
.ChangeStandardPrec(nPrec
);
523 void SvNumberFormatter::SetNoZero(bool bNZ
)
525 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
526 m_aFormatData
.SetNoZero(bNZ
);
529 sal_uInt16
SvNumberFormatter::GetStandardPrec() const
531 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
532 return m_aCurrentLanguage
.pFormatScanner
->GetStandardPrec();
535 bool SvNumberFormatter::GetNoZero() const
537 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
538 return m_aFormatData
.GetNoZero();
541 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage
)
543 sal_uInt32 nCLOffset
= m_aFormatData
.ImpGetCLOffset( LANGUAGE_SYSTEM
);
544 if ( nCLOffset
> m_aFormatData
.MaxCLOffset
)
546 return ; // no SYSTEM entries to replace
548 const sal_uInt32 nMaxBuiltin
= nCLOffset
+ SV_MAX_COUNT_STANDARD_FORMATS
;
549 const sal_uInt32 nNextCL
= nCLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
552 // remove old builtin formats
553 auto it
= m_aFormatData
.aFTable
.find( nCLOffset
);
554 while ( it
!= m_aFormatData
.aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
<= nMaxBuiltin
)
556 it
= m_aFormatData
.aFTable
.erase(it
);
559 // move additional and user defined to temporary table
560 SvNumberFormatTable aOldTable
;
561 while ( it
!= m_aFormatData
.aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
< nNextCL
)
563 aOldTable
[ nKey
] = it
->second
.release();
564 it
= m_aFormatData
.aFTable
.erase(it
);
567 // generate new old builtin formats
568 // reset m_aCurrentLanguage.ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
569 m_aCurrentLanguage
.ActLnge
= LANGUAGE_DONTKNOW
;
570 ChangeIntl( LANGUAGE_SYSTEM
);
571 m_aFormatData
.ImpGenerateFormats(m_aCurrentLanguage
, GetNatNum(), nCLOffset
, true);
573 // convert additional and user defined from old system to new system
574 SvNumberformat
* pStdFormat
= m_aFormatData
.GetFormatEntry( nCLOffset
+ ZF_STANDARD
);
575 sal_uInt32 nLastKey
= nMaxBuiltin
;
576 m_aCurrentLanguage
.pFormatScanner
->SetConvertMode( eOldLanguage
, LANGUAGE_SYSTEM
, true , true);
577 while ( !aOldTable
.empty() )
579 nKey
= aOldTable
.begin()->first
;
580 if ( nLastKey
< nKey
)
584 std::unique_ptr
<SvNumberformat
> pOldEntry(aOldTable
.begin()->second
);
585 aOldTable
.erase( nKey
);
586 OUString
aString( pOldEntry
->GetFormatstring() );
588 // Same as PutEntry() but assures key position even if format code is
589 // a duplicate. Also won't mix up any LastInsertKey.
590 ChangeIntl( eOldLanguage
);
591 LanguageType eLge
= eOldLanguage
; // ConvertMode changes this
593 sal_Int32 nCheckPos
= -1;
594 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( aString
, m_aCurrentLanguage
.pFormatScanner
.get(),
595 m_aCurrentLanguage
.pStringScanner
.get(), GetNatNum(), nCheckPos
, eLge
));
596 if ( nCheckPos
== 0 )
598 SvNumFormatType eCheckType
= pNewEntry
->GetType();
599 if ( eCheckType
!= SvNumFormatType::UNDEFINED
)
601 pNewEntry
->SetType( eCheckType
| SvNumFormatType::DEFINED
);
605 pNewEntry
->SetType( SvNumFormatType::DEFINED
);
608 if ( m_aFormatData
.aFTable
.emplace( nKey
, std::move(pNewEntry
) ).second
)
613 DBG_ASSERT( bCheck
, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
615 m_aCurrentLanguage
.pFormatScanner
->SetConvertMode(false);
616 pStdFormat
->SetLastInsertKey( sal_uInt16(nLastKey
- nCLOffset
), SvNumberformat::FormatterPrivateAccess() );
618 // append new system additional formats
619 css::uno::Reference
< css::i18n::XNumberFormatCode
> xNFC
= i18n::NumberFormatMapper::create( m_xContext
);
620 ImpGenerateAdditionalFormats( nCLOffset
, xNFC
);
623 const css::uno::Reference
<css::uno::XComponentContext
>& SvNumberFormatter::GetComponentContext() const
628 const NativeNumberWrapper
& SvNumberFormatter::GetNatNum() const { return m_xNatNum
.get(); }
630 bool SvNFFormatData::IsTextFormat(sal_uInt32 F_Index
) const
632 const SvNumberformat
* pFormat
= GetFormatEntry(F_Index
);
633 return pFormat
&& pFormat
->IsTextFormat();
636 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index
) const
638 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
639 return m_aFormatData
.IsTextFormat(F_Index
);
642 bool SvNFFormatData::PutEntry(SvNFLanguageData
& rCurrentLanguage
,
643 const NativeNumberWrapper
& rNatNum
,
645 sal_Int32
& nCheckPos
,
646 SvNumFormatType
& nType
,
647 sal_uInt32
& nKey
, // format key
649 bool bReplaceBooleanEquivalent
)
652 if (rString
.isEmpty()) // empty string
654 nCheckPos
= 1; // -> Error
657 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
658 rCurrentLanguage
.ChangeIntl(eLnge
); // change locale if necessary
659 LanguageType eLge
= eLnge
; // non-const for ConvertMode
661 std::unique_ptr
<SvNumberformat
> p_Entry(new SvNumberformat(rString
,
662 rCurrentLanguage
.pFormatScanner
.get(),
663 rCurrentLanguage
.pStringScanner
.get(),
667 bReplaceBooleanEquivalent
));
669 if (nCheckPos
== 0) // Format ok
670 { // Type comparison:
671 SvNumFormatType eCheckType
= p_Entry
->GetType();
672 if ( eCheckType
!= SvNumFormatType::UNDEFINED
)
674 p_Entry
->SetType(eCheckType
| SvNumFormatType::DEFINED
);
679 p_Entry
->SetType(SvNumFormatType::DEFINED
);
680 nType
= SvNumFormatType::DEFINED
;
683 sal_uInt32 CLOffset
= ImpGenerateCL(rCurrentLanguage
, rNatNum
, eLge
); // create new standard formats if necessary
685 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLge
);
686 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
) // only in not yet present
688 SvNumberformat
* pStdFormat
= GetFormatEntry(CLOffset
+ ZF_STANDARD
);
689 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
690 if (nPos
+1 - CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
692 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
694 else if (!aFTable
.emplace( nPos
+1, std::move(p_Entry
)).second
)
696 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
702 pStdFormat
->SetLastInsertKey(static_cast<sal_uInt16
>(nKey
-CLOffset
), SvNumberformat::FormatterPrivateAccess());
709 bool SvNumberFormatter::PutEntry(OUString
& rString
,
710 sal_Int32
& nCheckPos
,
711 SvNumFormatType
& nType
,
712 sal_uInt32
& nKey
, // format key
714 bool bReplaceBooleanEquivalent
)
716 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
717 return m_aFormatData
.PutEntry(m_aCurrentLanguage
, GetNatNum(), rString
, nCheckPos
, nType
, nKey
, eLnge
, bReplaceBooleanEquivalent
);
720 bool SvNumberFormatter::PutandConvertEntry(OUString
& rString
,
721 sal_Int32
& nCheckPos
,
722 SvNumFormatType
& nType
,
725 LanguageType eNewLnge
,
726 bool bConvertDateOrder
,
727 bool bReplaceBooleanEquivalent
)
729 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
731 if (eNewLnge
== LANGUAGE_DONTKNOW
)
735 m_aCurrentLanguage
.pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, false, bConvertDateOrder
);
736 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
, bReplaceBooleanEquivalent
);
737 m_aCurrentLanguage
.pFormatScanner
->SetConvertMode(false);
739 if (bReplaceBooleanEquivalent
&& nCheckPos
== 0 && nType
== SvNumFormatType::DEFINED
740 && nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
742 // The boolean string formats are always "user defined" without any
744 const SvNumberformat
* pEntry
= m_aFormatData
.GetFormatEntry(nKey
);
745 if (pEntry
&& pEntry
->GetType() == SvNumFormatType::DEFINED
)
747 // Replace boolean string format with Boolean in target locale, in
748 // case the source strings are the target locale's.
749 const OUString aSaveString
= rString
;
750 ChangeIntl(eNewLnge
);
751 if (m_aCurrentLanguage
.pFormatScanner
->ReplaceBooleanEquivalent( rString
))
753 const sal_Int32 nSaveCheckPos
= nCheckPos
;
754 const SvNumFormatType nSaveType
= nType
;
755 const sal_uInt32 nSaveKey
= nKey
;
756 const bool bTargetRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eNewLnge
, false);
757 if (nCheckPos
== 0 && nType
== SvNumFormatType::LOGICAL
&& nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
763 SAL_WARN("svl.numbers", "SvNumberFormatter::PutandConvertEntry: can't scan boolean replacement");
764 // Live with the source boolean string format.
765 rString
= aSaveString
;
766 nCheckPos
= nSaveCheckPos
;
776 bool SvNumberFormatter::PutandConvertEntrySystem(OUString
& rString
,
777 sal_Int32
& nCheckPos
,
778 SvNumFormatType
& nType
,
781 LanguageType eNewLnge
)
783 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
785 if (eNewLnge
== LANGUAGE_DONTKNOW
)
789 m_aCurrentLanguage
.pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, true, true);
790 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
791 m_aCurrentLanguage
.pFormatScanner
->SetConvertMode(false);
795 sal_uInt32
SvNumberFormatter::GetIndexPuttingAndConverting( OUString
& rString
, LanguageType eLnge
,
796 LanguageType eSysLnge
, SvNumFormatType
& rType
,
797 bool & rNewInserted
, sal_Int32
& rCheckPos
)
799 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
800 sal_uInt32 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
801 rNewInserted
= false;
804 // #62389# empty format string (of Writer) => General standard format
805 if (rString
.isEmpty())
809 else if (eLnge
== LANGUAGE_SYSTEM
&& eSysLnge
!= SvtSysLocale().GetLanguageTag().getLanguageType())
811 sal_uInt32 nOrig
= GetEntryKey( rString
, eSysLnge
);
812 if (nOrig
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
814 nKey
= nOrig
; // none available, maybe user-defined
818 nKey
= GetFormatForLanguageIfBuiltIn( nOrig
, SvtSysLocale().GetLanguageTag().getLanguageType() );
822 // Not a builtin format, convert.
823 // The format code string may get modified and adapted to the real
824 // language and wouldn't match eSysLnge anymore, do that on a copy.
825 OUString
aTmp( rString
);
826 rNewInserted
= PutandConvertEntrySystem( aTmp
, rCheckPos
, rType
,
827 nKey
, eLnge
, SvtSysLocale().GetLanguageTag().getLanguageType());
830 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
831 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
837 nKey
= GetEntryKey( rString
, eLnge
);
838 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
840 rNewInserted
= PutEntry( rString
, rCheckPos
, rType
, nKey
, eLnge
);
843 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
844 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
848 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
850 nKey
= GetStandardIndex( eLnge
);
852 rType
= GetType( nKey
);
853 // Convert any (!) old "automatic" currency format to new fixed currency
855 if (rType
& SvNumFormatType::CURRENCY
)
857 const SvNumberformat
* pFormat
= GetEntry( nKey
);
858 if (!pFormat
->HasNewCurrency())
862 DeleteEntry( nKey
); // don't leave trails of rubbish
863 rNewInserted
= false;
865 nKey
= GetStandardFormat( SvNumFormatType::CURRENCY
, eLnge
);
871 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey
)
873 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
874 m_aFormatData
.aFTable
.erase(nKey
);
877 void SvNumberFormatter::GetUsedLanguages( std::vector
<LanguageType
>& rList
)
879 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
882 sal_uInt32 nOffset
= 0;
883 while (nOffset
<= m_aFormatData
.MaxCLOffset
)
885 SvNumberformat
* pFormat
= m_aFormatData
.GetFormatEntry(nOffset
);
888 rList
.push_back( pFormat
->GetLanguage() );
890 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
895 void SvNumberFormatter::FillKeywordTable( NfKeywordTable
& rKeywords
,
898 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
900 const NfKeywordTable
& rTable
= m_aCurrentLanguage
.pFormatScanner
->GetKeywords();
901 for ( sal_uInt16 i
= 0; i
< NF_KEYWORD_ENTRIES_COUNT
; ++i
)
903 rKeywords
[i
] = rTable
[i
];
908 void SvNumberFormatter::FillKeywordTableForExcel( NfKeywordTable
& rKeywords
)
910 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
911 FillKeywordTable( rKeywords
, LANGUAGE_ENGLISH_US
);
913 // Replace upper case "GENERAL" with proper case "General".
914 rKeywords
[ NF_KEY_GENERAL
] = GetStandardName( LANGUAGE_ENGLISH_US
);
916 // Excel or OOXML do not specify format code keywords case sensitivity,
917 // but given and writes them lower case. Using upper case even lead to an
918 // odd misrepresentation in iOS viewer and OSX Quicklook viewer that
919 // strangely use "D" and "DD" for "days since beginning of year", which is
920 // nowhere defined. See tdf#126773
921 // Use lower case for all date and time keywords where known. See OOXML
922 // ECMA-376-1:2016 18.8.31 numFmts (Number Formats)
923 rKeywords
[ NF_KEY_MI
] = "m";
924 rKeywords
[ NF_KEY_MMI
] = "mm";
925 rKeywords
[ NF_KEY_M
] = "m";
926 rKeywords
[ NF_KEY_MM
] = "mm";
927 rKeywords
[ NF_KEY_MMM
] = "mmm";
928 rKeywords
[ NF_KEY_MMMM
] = "mmmm";
929 rKeywords
[ NF_KEY_MMMMM
] = "mmmmm";
930 rKeywords
[ NF_KEY_H
] = "h";
931 rKeywords
[ NF_KEY_HH
] = "hh";
932 rKeywords
[ NF_KEY_S
] = "s";
933 rKeywords
[ NF_KEY_SS
] = "ss";
934 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_Q ] = "q"; */
935 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_QQ ] = "qq"; */
936 rKeywords
[ NF_KEY_D
] = "d";
937 rKeywords
[ NF_KEY_DD
] = "dd";
938 rKeywords
[ NF_KEY_DDD
] = "ddd";
939 rKeywords
[ NF_KEY_DDDD
] = "dddd";
940 rKeywords
[ NF_KEY_YY
] = "yy";
941 rKeywords
[ NF_KEY_YYYY
] = "yyyy";
942 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAA ] = "aaa"; */
943 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_AAAA ] = "aaaa"; */
944 rKeywords
[ NF_KEY_EC
] = "e";
945 rKeywords
[ NF_KEY_EEC
] = "ee";
946 rKeywords
[ NF_KEY_G
] = "g";
947 rKeywords
[ NF_KEY_GG
] = "gg";
948 rKeywords
[ NF_KEY_GGG
] = "ggg";
949 rKeywords
[ NF_KEY_R
] = "r";
950 rKeywords
[ NF_KEY_RR
] = "rr";
951 /* XXX: not defined in OOXML: rKeywords[ NF_KEY_WW ] = "ww"; */
953 // Remap codes unknown to Excel.
954 rKeywords
[ NF_KEY_NN
] = "ddd";
955 rKeywords
[ NF_KEY_NNN
] = "dddd";
956 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
957 rKeywords
[ NF_KEY_NNNN
] = "dddd";
958 // Export the Thai T NatNum modifier. This must be uppercase for internal reasons.
959 rKeywords
[ NF_KEY_THAI_T
] = "T";
962 static OUString
lcl_buildBooleanStringFormat(const SvNumberformat
* pEntry
, const NativeNumberWrapper
& rNatNum
, const SvNFLanguageData
& rCurrentLang
)
964 // Build Boolean number format, which needs non-zero and zero subformat
965 // codes with TRUE and FALSE strings.
966 const Color
* pColor
= nullptr;
967 OUString aFormatStr
, aTemp
;
968 pEntry
->GetOutputString( 1.0, aTemp
, &pColor
, rNatNum
, rCurrentLang
);
969 aFormatStr
+= "\"" + aTemp
+ "\";\"" + aTemp
+ "\";\"";
970 pEntry
->GetOutputString( 0.0, aTemp
, &pColor
, rNatNum
, rCurrentLang
);
971 aFormatStr
+= aTemp
+ "\"";
975 OUString
SvNumberFormatter::GetFormatStringForExcel( sal_uInt32 nKey
, const NfKeywordTable
& rKeywords
,
976 SvNumberFormatter
& rTempFormatter
) const
978 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
980 if (const SvNumberformat
* pEntry
= GetEntry( nKey
))
982 if (pEntry
->GetType() == SvNumFormatType::LOGICAL
)
984 // Build a source locale dependent string boolean. This is
985 // expected when loading the document in the same locale or if
986 // several locales are used, but not for other system/default
987 // locales. You can't have both. We could force to English for all
988 // locales like below, but Excel would display English strings then
989 // even for the system locale matching this locale. YMMV.
990 aFormatStr
= lcl_buildBooleanStringFormat(pEntry
, GetNatNum(), m_aCurrentLanguage
);
994 bool bIsLOK
= comphelper::LibreOfficeKit::isActive();
995 bool bSystemLanguage
= false;
996 LanguageType nLang
= pEntry
->GetLanguage();
997 if (nLang
== LANGUAGE_SYSTEM
)
999 bSystemLanguage
= true;
1000 nLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
1002 if (!bIsLOK
&& nLang
!= LANGUAGE_ENGLISH_US
)
1004 sal_Int32 nCheckPos
;
1005 SvNumFormatType nType
= SvNumFormatType::DEFINED
;
1006 sal_uInt32 nTempKey
;
1007 OUString
aTemp( pEntry
->GetFormatstring());
1008 /* TODO: do we want bReplaceBooleanEquivalent=true in any case
1009 * to write it as English string boolean? */
1010 rTempFormatter
.PutandConvertEntry( aTemp
, nCheckPos
, nType
, nTempKey
, nLang
, LANGUAGE_ENGLISH_US
,
1011 false /*bConvertDateOrder*/, false /*bReplaceBooleanEquivalent*/);
1012 SAL_WARN_IF( nCheckPos
!= 0, "svl.numbers",
1013 "SvNumberFormatter::GetFormatStringForExcel - format code not convertible");
1014 if (nTempKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1015 pEntry
= rTempFormatter
.GetEntry( nTempKey
);
1020 if (pEntry
->GetType() == SvNumFormatType::LOGICAL
)
1022 // This would be reached if bReplaceBooleanEquivalent was
1023 // true and the source format is a string boolean like
1024 // >"VRAI";"VRAI";"FAUX"< recognized as real boolean and
1025 // properly converted. Then written as
1026 // >"TRUE";"TRUE";"FALSE"<
1027 aFormatStr
= lcl_buildBooleanStringFormat(pEntry
, GetNatNum(), m_aCurrentLanguage
);
1031 // m_aCurrentLanguage.GetLocaleData() returns the current locale's data, so switch
1032 // before (which doesn't do anything if it was the same locale
1034 rTempFormatter
.ChangeIntl( LANGUAGE_ENGLISH_US
);
1035 aFormatStr
= pEntry
->GetMappedFormatstring( rKeywords
, *rTempFormatter
.m_aCurrentLanguage
.GetLocaleData(), nLang
,
1043 SAL_WARN("svl.numbers","SvNumberFormatter::GetFormatStringForExcel - format not found: " << nKey
);
1046 if (aFormatStr
.isEmpty())
1047 aFormatStr
= "General";
1052 OUString
SvNumberFormatter::GetKeyword( LanguageType eLnge
, sal_uInt16 nIndex
)
1054 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1056 const NfKeywordTable
& rTable
= m_aCurrentLanguage
.pFormatScanner
->GetKeywords();
1057 if ( nIndex
< NF_KEYWORD_ENTRIES_COUNT
)
1059 return rTable
[nIndex
];
1061 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
1066 OUString
SvNumberFormatter::GetStandardName( LanguageType eLnge
)
1068 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1069 ChangeIntl( eLnge
);
1070 return m_aCurrentLanguage
.pFormatScanner
->GetStandardName();
1073 SvNFFormatData::SvNFFormatData()
1075 , nDefaultSystemCurrencyFormat(NUMBERFORMAT_ENTRY_NOT_FOUND
)
1080 SvNFFormatData::~SvNFFormatData() = default;
1082 sal_uInt32
SvNFFormatData::ImpGetCLOffset(LanguageType eLnge
) const
1084 sal_uInt32 nOffset
= 0;
1085 while (nOffset
<= MaxCLOffset
)
1087 const SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
1088 if (pFormat
&& pFormat
->GetLanguage() == eLnge
)
1092 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
1097 sal_uInt32
SvNFFormatData::ImpIsEntry(std::u16string_view rString
,
1098 sal_uInt32 nCLOffset
,
1099 LanguageType eLnge
) const
1101 sal_uInt32 res
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1102 auto it
= aFTable
.find( nCLOffset
);
1103 while ( res
== NUMBERFORMAT_ENTRY_NOT_FOUND
&&
1104 it
!= aFTable
.end() && it
->second
->GetLanguage() == eLnge
)
1106 if ( rString
== it
->second
->GetFormatstring() )
1118 sal_uInt32
SvNumberFormatter::ImpIsEntry(std::u16string_view rString
,
1119 sal_uInt32 nCLOffset
,
1120 LanguageType eLnge
) const
1122 return m_aFormatData
.ImpIsEntry(rString
, nCLOffset
, eLnge
);
1125 SvNumberFormatTable
& SvNumberFormatter::GetFirstEntryTable(
1126 SvNumFormatType
& eType
,
1128 LanguageType
& rLnge
)
1130 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1131 SvNumFormatType eTypetmp
= eType
;
1132 if (eType
== SvNumFormatType::ALL
) // empty cell or don't care
1138 SvNumberformat
* pFormat
= m_aFormatData
.GetFormatEntry(FIndex
);
1142 eType
= SvNumFormatType::ALL
;
1147 rLnge
= pFormat
->GetLanguage();
1148 eType
= pFormat
->GetMaskedType();
1149 if (eType
== SvNumFormatType::ALL
)
1151 eType
= SvNumFormatType::DEFINED
;
1154 else if (eType
== SvNumFormatType::DATETIME
)
1157 eType
= SvNumFormatType::DATE
;
1166 return GetEntryTable(eTypetmp
, FIndex
, rLnge
);
1169 sal_uInt32
SvNFFormatData::ImpGenerateCL(SvNFLanguageData
& rCurrentLanguage
, const NativeNumberWrapper
& rNatNum
, LanguageType eLnge
)
1171 rCurrentLanguage
.ChangeIntl(eLnge
);
1172 sal_uInt32 CLOffset
= ImpGetCLOffset(rCurrentLanguage
.ActLnge
);
1173 if (CLOffset
> MaxCLOffset
)
1175 // new CL combination
1176 if (LocaleDataWrapper::areChecksEnabled())
1178 const LanguageTag
& rLoadedLocale
= rCurrentLanguage
.xLocaleData
->getLoadedLanguageTag();
1179 if ( !rLoadedLocale
.equals( rCurrentLanguage
.aLanguageTag
) )
1181 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo( u
"SvNumberFormatter::ImpGenerateCL: locales don't match:" ));
1183 // test XML locale data FormatElement entries
1185 uno::Sequence
< i18n::FormatElement
> xSeq
= rCurrentLanguage
.xLocaleData
->getAllFormats();
1186 // A test for completeness of formatindex="0" ...
1187 // formatindex="47" is not needed here since it is done in
1188 // ImpGenerateFormats().
1190 // Test for dupes of formatindex="..."
1191 for ( sal_Int32 j
= 0; j
< xSeq
.getLength(); j
++ )
1193 sal_Int16 nIdx
= xSeq
[j
].formatIndex
;
1194 OUStringBuffer aDupes
;
1195 for ( sal_Int32 i
= 0; i
< xSeq
.getLength(); i
++ )
1197 if ( i
!= j
&& xSeq
[i
].formatIndex
== nIdx
)
1199 aDupes
.append( OUString::number(i
) + "(" + xSeq
[i
].formatKey
+ ") ");
1202 if ( !aDupes
.isEmpty() )
1204 OUString aMsg
= "XML locale data FormatElement formatindex dupe: "
1205 + OUString::number(nIdx
)
1206 + "\nFormatElements: "
1207 + OUString::number( j
)
1212 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo( aMsg
));
1218 MaxCLOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
1219 ImpGenerateFormats(rCurrentLanguage
, rNatNum
, MaxCLOffset
, false/*bNoAdditionalFormats*/ );
1220 CLOffset
= MaxCLOffset
;
1225 SvNumberFormatTable
& SvNumberFormatter::ChangeCL(SvNumFormatType eType
,
1229 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1230 m_aFormatData
.ImpGenerateCL(m_aCurrentLanguage
, GetNatNum(), eLnge
);
1231 return GetEntryTable(eType
, FIndex
, m_aCurrentLanguage
.ActLnge
);
1234 SvNumberFormatTable
& SvNumberFormatter::GetEntryTable(
1235 SvNumFormatType eType
,
1239 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1242 pFormatTable
->clear();
1246 pFormatTable
.reset( new SvNumberFormatTable
);
1249 sal_uInt32 CLOffset
= m_aFormatData
.ImpGetCLOffset(m_aCurrentLanguage
.ActLnge
);
1251 // Might generate and insert a default format for the given type
1252 // (e.g. currency) => has to be done before collecting formats.
1253 sal_uInt32 nDefaultIndex
= GetStandardFormat( eType
, m_aCurrentLanguage
.ActLnge
);
1255 auto it
= m_aFormatData
.aFTable
.find( CLOffset
);
1257 if (eType
== SvNumFormatType::ALL
)
1259 while (it
!= m_aFormatData
.aFTable
.end() && it
->second
->GetLanguage() == m_aCurrentLanguage
.ActLnge
)
1260 { // copy all entries to output table
1261 (*pFormatTable
)[ it
->first
] = it
->second
.get();
1267 while (it
!= m_aFormatData
.aFTable
.end() && it
->second
->GetLanguage() == m_aCurrentLanguage
.ActLnge
)
1268 { // copy entries of queried type to output table
1269 if ((it
->second
->GetType()) & eType
)
1270 (*pFormatTable
)[ it
->first
] = it
->second
.get();
1274 if ( !pFormatTable
->empty() )
1275 { // select default if queried format doesn't exist or queried type or
1276 // language differ from existing format
1277 SvNumberformat
* pEntry
= m_aFormatData
.GetFormatEntry(FIndex
);
1278 if ( !pEntry
|| !(pEntry
->GetType() & eType
) || pEntry
->GetLanguage() != m_aCurrentLanguage
.ActLnge
)
1280 FIndex
= nDefaultIndex
;
1283 return *pFormatTable
;
1288 const SvNumberformat
* ImpSubstituteEntry(SvNFLanguageData
& rCurrentLanguage
, const SvNFFormatData
& rFormatData
,
1289 const NativeNumberWrapper
& rNatNum
, const SvNFEngine::Accessor
& rFuncs
,
1290 const SvNumberformat
* pFormat
, sal_uInt32
* o_pRealKey
)
1292 if (!pFormat
|| !pFormat
->IsSubstituted())
1295 // XXX NOTE: substitution can not be done in GetFormatEntry() as otherwise
1296 // to be substituted formats would "vanish", i.e. from the number formatter
1297 // dialog or when exporting to Excel.
1300 if (pFormat
->IsSystemTimeFormat())
1302 /* TODO: should we have NF_TIME_SYSTEM for consistency? */
1303 nKey
= SvNFEngine::GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
,
1304 SvNumFormatType::TIME
, LANGUAGE_SYSTEM
);
1306 else if (pFormat
->IsSystemLongDateFormat())
1307 /* TODO: either that above, or have a long option for GetStandardFormat() */
1309 nKey
= SvNFEngine::GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
,
1310 NF_DATE_SYSTEM_LONG
, LANGUAGE_SYSTEM
);
1317 return rFormatData
.GetFormatEntry(nKey
);
1322 bool SvNFEngine::IsNumberFormat(SvNFLanguageData
& rCurrentLanguage
,
1323 const SvNFFormatData
& rFormatData
,
1324 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
1325 const OUString
& sString
,
1326 sal_uInt32
& F_Index
,
1328 SvNumInputOptions eInputOptions
)
1330 SvNumFormatType FType
;
1331 // For the 0 General format directly use the init/system locale and avoid
1332 // all overhead that is associated with a format passed to the scanner.
1333 const SvNumberformat
* pFormat
= (F_Index
== 0 ? nullptr :
1334 ::ImpSubstituteEntry(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, rFormatData
.GetFormatEntry(F_Index
), nullptr));
1337 rCurrentLanguage
.ChangeIntl(rCurrentLanguage
.IniLnge
);
1338 FType
= SvNumFormatType::NUMBER
;
1342 FType
= pFormat
->GetMaskedType();
1343 if (FType
== SvNumFormatType::ALL
)
1345 FType
= SvNumFormatType::DEFINED
;
1347 rCurrentLanguage
.ChangeIntl(pFormat
->GetLanguage());
1348 // Avoid scanner overhead with the General format of any locale.
1349 // These are never substituted above so safe to ignore.
1350 if ((F_Index
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0)
1352 assert(FType
== SvNumFormatType::NUMBER
);
1358 SvNumFormatType RType
= FType
;
1359 if (RType
== SvNumFormatType::TEXT
)
1361 res
= false; // type text preset => no conversion to number
1365 res
= rCurrentLanguage
.pStringScanner
->IsNumberFormat(sString
, RType
, fOutNumber
, pFormat
, rNatNum
, eInputOptions
);
1367 if (res
&& !SvNumberFormatter::IsCompatible(FType
, RType
)) // non-matching type
1371 case SvNumFormatType::DATE
:
1372 // Preserve ISO 8601 input.
1373 if (rCurrentLanguage
.pStringScanner
->CanForceToIso8601( DateOrder::Invalid
))
1375 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATE_DIN_YYYYMMDD
, rCurrentLanguage
.ActLnge
);
1379 F_Index
= GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, RType
, rCurrentLanguage
.ActLnge
);
1382 case SvNumFormatType::TIME
:
1383 if ( rCurrentLanguage
.pStringScanner
->GetDecPos() )
1386 if ( rCurrentLanguage
.pStringScanner
->GetNumericsCount() > 3 || fOutNumber
< 0.0 )
1388 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_TIME_HH_MMSS00
, rCurrentLanguage
.ActLnge
);
1392 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_TIME_MMSS00
, rCurrentLanguage
.ActLnge
);
1395 else if ( fOutNumber
>= 1.0 || fOutNumber
< 0.0 )
1397 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_TIME_HH_MMSS
, rCurrentLanguage
.ActLnge
);
1401 F_Index
= GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, RType
, rCurrentLanguage
.ActLnge
);
1404 case SvNumFormatType::DATETIME
:
1405 // Preserve ISO 8601 input.
1406 if (rCurrentLanguage
.pStringScanner
->HasIso8601Tsep())
1408 if (rCurrentLanguage
.pStringScanner
->GetDecPos())
1409 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
, rCurrentLanguage
.ActLnge
);
1411 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDDTHHMMSS
, rCurrentLanguage
.ActLnge
);
1413 else if (rCurrentLanguage
.pStringScanner
->CanForceToIso8601( DateOrder::Invalid
))
1415 if (rCurrentLanguage
.pStringScanner
->GetDecPos())
1416 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDD_HHMMSS000
, rCurrentLanguage
.ActLnge
);
1418 F_Index
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, rCurrentLanguage
.ActLnge
);
1422 F_Index
= GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, RType
, rCurrentLanguage
.ActLnge
);
1426 F_Index
= GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, RType
, rCurrentLanguage
.ActLnge
);
1432 bool SvNumberFormatter::IsNumberFormat(const OUString
& sString
,
1433 sal_uInt32
& F_Index
,
1435 SvNumInputOptions eInputOptions
)
1437 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1439 return SvNFEngine::IsNumberFormat(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(),
1440 m_aRWPolicy
, sString
, F_Index
, fOutNumber
,
1444 LanguageType
SvNumberFormatter::GetLanguage() const
1446 return IniLnge
; // immutable
1450 bool SvNumberFormatter::IsCompatible(SvNumFormatType eOldType
, SvNumFormatType eNewType
)
1452 if (eOldType
== eNewType
)
1456 else if (eOldType
== SvNumFormatType::DEFINED
)
1464 case SvNumFormatType::NUMBER
:
1467 case SvNumFormatType::PERCENT
:
1468 case SvNumFormatType::CURRENCY
:
1469 case SvNumFormatType::SCIENTIFIC
:
1470 case SvNumFormatType::FRACTION
:
1471 case SvNumFormatType::DEFINED
:
1473 case SvNumFormatType::LOGICAL
:
1478 case SvNumFormatType::DATE
:
1481 case SvNumFormatType::DATETIME
:
1487 case SvNumFormatType::TIME
:
1490 case SvNumFormatType::DATETIME
:
1496 case SvNumFormatType::DATETIME
:
1499 case SvNumFormatType::TIME
:
1500 case SvNumFormatType::DATE
:
1506 case SvNumFormatType::DURATION
:
1514 static sal_uInt32
ImpGetSearchOffset(SvNumFormatType nType
, sal_uInt32 CLOffset
)
1519 case SvNumFormatType::DATE
:
1520 nSearch
= CLOffset
+ ZF_STANDARD_DATE
;
1522 case SvNumFormatType::TIME
:
1523 nSearch
= CLOffset
+ ZF_STANDARD_TIME
;
1525 case SvNumFormatType::DATETIME
:
1526 nSearch
= CLOffset
+ ZF_STANDARD_DATETIME
;
1528 case SvNumFormatType::DURATION
:
1529 nSearch
= CLOffset
+ ZF_STANDARD_DURATION
;
1531 case SvNumFormatType::PERCENT
:
1532 nSearch
= CLOffset
+ ZF_STANDARD_PERCENT
;
1534 case SvNumFormatType::SCIENTIFIC
:
1535 nSearch
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1538 nSearch
= CLOffset
+ ZF_STANDARD
;
1544 sal_uInt32
SvNFEngine::ImpGetDefaultFormat(const SvNFFormatData
& rFormatData
,
1545 const SvNFEngine::Accessor
& rFuncs
,
1546 SvNumFormatType nType
, sal_uInt32 CLOffset
)
1548 sal_uInt32 nSearch
= ImpGetSearchOffset(nType
, CLOffset
);
1550 sal_uInt32 nDefaultFormat
= rFuncs
.mFindFormat(nSearch
);
1551 if (nDefaultFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1552 return nDefaultFormat
;
1554 nDefaultFormat
= ImpGetDefaultFormat(rFormatData
, nType
, CLOffset
);
1555 rFuncs
.mCacheFormat(nSearch
, nDefaultFormat
);
1556 return nDefaultFormat
;
1561 sal_uInt32
ImpGetFormatIndex(NfIndexTableOffset nTabOff
, sal_uInt32 nCLOffset
)
1563 if (nTabOff
>= NF_INDEX_TABLE_ENTRIES
)
1564 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
1566 if (indexTable
[nTabOff
] == NUMBERFORMAT_ENTRY_NOT_FOUND
)
1567 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
1569 return nCLOffset
+ indexTable
[nTabOff
];
1572 bool ImpIsSpecialStandardFormat(sal_uInt32 nFIndex
, sal_uInt32 nCLOffset
)
1575 nFIndex
== ImpGetFormatIndex( NF_TIME_MMSS00
, nCLOffset
) ||
1576 nFIndex
== ImpGetFormatIndex( NF_TIME_HH_MMSS00
, nCLOffset
) ||
1577 nFIndex
== ImpGetFormatIndex( NF_TIME_HH_MMSS
, nCLOffset
)
1581 bool ImpIsSpecialStandardFormat(SvNFLanguageData
& rCurrentLanguage
,
1582 const NativeNumberWrapper
& rNatNum
, const SvNFEngine::Accessor
& rFuncs
,
1583 sal_uInt32 nFIndex
, LanguageType eLnge
)
1585 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
1586 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary (and allowed)
1587 return ::ImpIsSpecialStandardFormat(nFIndex
, nCLOffset
);
1591 sal_uInt32
SvNFEngine::ImpGetStandardFormat(SvNFLanguageData
& rCurrentLanguage
,
1592 const SvNFFormatData
& rFormatData
,
1593 const NativeNumberWrapper
& rNatNum
,
1594 const SvNFEngine::Accessor
& rFuncs
,
1595 SvNumFormatType eType
,
1596 sal_uInt32 CLOffset
,
1601 case SvNumFormatType::CURRENCY
:
1602 return rFuncs
.mGetDefaultCurrency(rCurrentLanguage
, rNatNum
, CLOffset
, eLnge
);
1603 case SvNumFormatType::DURATION
:
1604 return ImpGetFormatIndex(NF_TIME_HH_MMSS
, CLOffset
);
1605 case SvNumFormatType::DATE
:
1606 case SvNumFormatType::TIME
:
1607 case SvNumFormatType::DATETIME
:
1608 case SvNumFormatType::PERCENT
:
1609 case SvNumFormatType::SCIENTIFIC
:
1610 return ImpGetDefaultFormat(rFormatData
, rFuncs
, eType
, CLOffset
);
1611 case SvNumFormatType::FRACTION
:
1612 return CLOffset
+ ZF_STANDARD_FRACTION
;
1613 case SvNumFormatType::LOGICAL
:
1614 return CLOffset
+ ZF_STANDARD_LOGICAL
;
1615 case SvNumFormatType::TEXT
:
1616 return CLOffset
+ ZF_STANDARD_TEXT
;
1617 case SvNumFormatType::ALL
:
1618 case SvNumFormatType::DEFINED
:
1619 case SvNumFormatType::NUMBER
:
1620 case SvNumFormatType::UNDEFINED
:
1622 return CLOffset
+ ZF_STANDARD
;
1626 sal_uInt32
SvNFEngine::GetStandardFormat(SvNFLanguageData
& rCurrentLanguage
,
1627 const SvNFFormatData
& rFormatData
,
1628 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
1629 SvNumFormatType eType
,
1632 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
1634 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary (and allowed)
1636 return ImpGetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, eType
, nCLOffset
, eLnge
);
1639 sal_uInt32
SvNumberFormatter::GetStandardFormat( SvNumFormatType eType
, LanguageType eLnge
)
1641 ::osl::MutexGuard
aGuard(GetInstanceMutex());
1642 return SvNFEngine::GetStandardFormat(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(), m_aRWPolicy
, eType
, eLnge
);
1645 bool SvNumberFormatter::ImpIsSpecialStandardFormat(sal_uInt32 nFIndex
, LanguageType eLnge
)
1647 ::osl::MutexGuard
aGuard(GetInstanceMutex());
1648 return ::ImpIsSpecialStandardFormat(m_aCurrentLanguage
, GetNatNum(), m_aRWPolicy
, nFIndex
, eLnge
);
1651 sal_uInt32
SvNFEngine::GetStandardFormat(SvNFLanguageData
& rCurrentLanguage
,
1652 const SvNFFormatData
& rFormatData
,
1653 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
1654 sal_uInt32 nFIndex
, SvNumFormatType eType
, LanguageType eLnge
)
1656 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
1658 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary (and allowed)
1660 if (::ImpIsSpecialStandardFormat(nFIndex
, nCLOffset
))
1663 return ImpGetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, eType
, nCLOffset
, eLnge
);
1668 sal_uInt32
FindCachedDefaultFormat(const SvNFFormatData::DefaultFormatKeysMap
& rDefaultFormatKeys
, sal_uInt32 nSearch
)
1670 auto it
= rDefaultFormatKeys
.find(nSearch
);
1671 sal_uInt32 nDefaultFormat
= (it
!= rDefaultFormatKeys
.end() ?
1672 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
1673 return nDefaultFormat
;
1677 sal_uInt32
SvNFFormatData::FindCachedDefaultFormat(sal_uInt32 nSearch
) const
1679 return ::FindCachedDefaultFormat(aDefaultFormatKeys
, nSearch
);
1683 sal_uInt32
SvNFEngine::ImpGetDefaultFormat(const SvNFFormatData
& rFormatData
, SvNumFormatType nType
, sal_uInt32 CLOffset
)
1685 sal_uInt32 nDefaultFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1687 // look for a defined standard
1688 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
1690 auto it2
= rFormatData
.aFTable
.find( CLOffset
);
1691 while ( it2
!= rFormatData
.aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
1693 const SvNumberformat
* pEntry
= it2
->second
.get();
1694 if ( pEntry
->IsStandard() && (pEntry
->GetMaskedType() == nType
) )
1696 nDefaultFormat
= nKey
;
1702 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1703 { // none found, use old fixed standards
1706 case SvNumFormatType::DATE
:
1707 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATE
;
1709 case SvNumFormatType::TIME
:
1710 nDefaultFormat
= CLOffset
+ ZF_STANDARD_TIME
+1;
1712 case SvNumFormatType::DATETIME
:
1713 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATETIME
;
1715 case SvNumFormatType::DURATION
:
1716 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DURATION
;
1718 case SvNumFormatType::PERCENT
:
1719 nDefaultFormat
= CLOffset
+ ZF_STANDARD_PERCENT
+1;
1721 case SvNumFormatType::SCIENTIFIC
:
1722 nDefaultFormat
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1725 nDefaultFormat
= CLOffset
+ ZF_STANDARD
;
1729 return nDefaultFormat
;
1732 sal_uInt32
SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex
, SvNumFormatType eType
,
1733 LanguageType eLnge
)
1735 ::osl::MutexGuard
aGuard(GetInstanceMutex());
1737 return SvNFEngine::GetStandardFormat(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(),
1738 m_aRWPolicy
, nFIndex
, eType
, eLnge
);
1741 sal_uInt32
SvNFEngine::GetTimeFormat(SvNFLanguageData
& rCurrentLanguage
,
1742 const SvNFFormatData
& rFormatData
,
1743 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
1744 double fNumber
, LanguageType eLnge
, bool bForceDuration
)
1747 if ( fNumber
< 0.0 )
1754 double fSeconds
= fNumber
* 86400;
1755 if ( floor( fSeconds
+ 0.5 ) * 100 != floor( fSeconds
* 100 + 0.5 ) )
1756 { // with 100th seconds
1757 if ( bForceDuration
|| bSign
|| fSeconds
>= 3600 )
1758 return GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_TIME_HH_MMSS00
, eLnge
);
1760 return GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_TIME_MMSS00
, eLnge
);
1764 if ( bForceDuration
|| bSign
|| fNumber
>= 1.0 )
1765 return GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_TIME_HH_MMSS
, eLnge
);
1767 return GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, SvNumFormatType::TIME
, eLnge
);
1771 sal_uInt32
SvNumberFormatter::GetTimeFormat( double fNumber
, LanguageType eLnge
, bool bForceDuration
)
1773 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1775 return SvNFEngine::GetTimeFormat(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(), m_aRWPolicy
,
1776 fNumber
, eLnge
, bForceDuration
);
1779 sal_uInt32
SvNFEngine::GetStandardFormat(SvNFLanguageData
& rCurrentLanguage
,
1780 const SvNFFormatData
& rFormatData
,
1781 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
1782 double fNumber
, sal_uInt32 nFIndex
,
1783 SvNumFormatType eType
, LanguageType eLnge
)
1785 if (::ImpIsSpecialStandardFormat(rCurrentLanguage
, rNatNum
, rFuncs
, nFIndex
, eLnge
))
1790 case SvNumFormatType::DURATION
:
1791 return GetTimeFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, fNumber
, eLnge
, true);
1792 case SvNumFormatType::TIME
:
1793 return GetTimeFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, fNumber
, eLnge
, false);
1795 return GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, eType
, eLnge
);
1799 sal_uInt32
SvNumberFormatter::GetStandardFormat( double fNumber
, sal_uInt32 nFIndex
,
1800 SvNumFormatType eType
, LanguageType eLnge
)
1802 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1803 if ( ImpIsSpecialStandardFormat( nFIndex
, eLnge
) )
1808 case SvNumFormatType::DURATION
:
1809 return GetTimeFormat( fNumber
, eLnge
, true);
1810 case SvNumFormatType::TIME
:
1811 return GetTimeFormat( fNumber
, eLnge
, false);
1813 return GetStandardFormat( eType
, eLnge
);
1817 sal_uInt32
SvNumberFormatter::GuessDateTimeFormat( SvNumFormatType
& rType
, double fNumber
, LanguageType eLnge
)
1819 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1820 // Categorize the format according to the implementation of
1821 // SvNumberFormatter::GetEditFormat(), making assumptions about what
1822 // would be time only.
1824 if (0.0 <= fNumber
&& fNumber
< 1.0)
1827 rType
= SvNumFormatType::TIME
;
1828 nRet
= GetTimeFormat( fNumber
, eLnge
, false);
1830 else if (fabs( fNumber
) * 24 < 0x7fff)
1832 // Assuming duration within 32k hours or 3.7 years.
1833 // This should be SvNumFormatType::DURATION instead, but the outer
1834 // world can't cope with that.
1835 rType
= SvNumFormatType::TIME
;
1836 nRet
= GetTimeFormat( fNumber
, eLnge
, true);
1838 else if (rtl::math::approxFloor( fNumber
) != fNumber
)
1841 rType
= SvNumFormatType::DATETIME
;
1842 nRet
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLnge
);
1847 rType
= SvNumFormatType::DATE
;
1848 nRet
= GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, eLnge
);
1853 sal_uInt32
SvNFEngine::GetEditFormat(SvNFLanguageData
& rCurrentLanguage
,
1854 const SvNFFormatData
& rFormatData
,
1855 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
1856 double fNumber
, sal_uInt32 nFIndex
,
1857 SvNumFormatType eType
,
1858 const SvNumberformat
* pFormat
,
1859 LanguageType eForLocale
)
1861 const LanguageType eLang
= (pFormat
? pFormat
->GetLanguage() : LANGUAGE_SYSTEM
);
1862 if (eForLocale
== LANGUAGE_DONTKNOW
)
1864 sal_uInt32 nKey
= nFIndex
;
1867 // #61619# always edit using 4-digit year
1868 case SvNumFormatType::DATE
:
1870 // Preserve ISO 8601 format.
1872 nFIndex
== GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATE_DIN_YYYYMMDD
, eLang
) ||
1873 nFIndex
== GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATE_DIN_YYMMDD
, eLang
) ||
1874 nFIndex
== GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATE_DIN_MMDD
, eLang
) ||
1875 (pFormat
&& pFormat
->IsIso8601( 0 ));
1876 if (rtl::math::approxFloor( fNumber
) != fNumber
)
1878 // fdo#34977 preserve time when editing even if only date was
1881 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eForLocale
);
1883 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eForLocale
);
1888 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATE_ISO_YYYYMMDD
, eForLocale
);
1890 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATE_SYS_DDMMYYYY
, eForLocale
);
1894 case SvNumFormatType::TIME
:
1895 if (fNumber
< 0.0 || fNumber
>= 1.0)
1897 /* XXX NOTE: this is a purely arbitrary value within the limits
1898 * of a signed 16-bit. 32k hours are 3.7 years ... or
1899 * 1903-09-26 if date. */
1900 if (fabs( fNumber
) * 24 < 0x7fff)
1901 nKey
= GetTimeFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, fNumber
, eForLocale
, true);
1902 // Preserve duration, use [HH]:MM:SS instead of time.
1904 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eForLocale
);
1905 // Assume that a large value is a datetime with only time
1909 nKey
= GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, fNumber
, nFIndex
, eType
, eForLocale
);
1911 case SvNumFormatType::DURATION
:
1912 nKey
= GetTimeFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, fNumber
, eForLocale
, true);
1914 case SvNumFormatType::DATETIME
:
1915 if (nFIndex
== GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDDTHHMMSS
, eLang
))
1916 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDDTHHMMSS
, eForLocale
);
1917 else if (nFIndex
== GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
, eLang
))
1918 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
, eForLocale
);
1919 else if (nFIndex
== GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDD_HHMMSS000
, eLang
))
1920 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDD_HHMMSS000
, eForLocale
);
1921 else if (nFIndex
== GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eLang
) || (pFormat
&& pFormat
->IsIso8601( 0 )))
1922 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eForLocale
);
1924 nKey
= GetFormatIndex(rCurrentLanguage
, rFuncs
, rNatNum
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eForLocale
);
1926 case SvNumFormatType::NUMBER
:
1927 nKey
= GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, eType
, eForLocale
);
1930 nKey
= GetStandardFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, fNumber
, nFIndex
, eType
, eForLocale
);
1935 sal_uInt32
SvNumberFormatter::GetEditFormat( double fNumber
, sal_uInt32 nFIndex
,
1936 SvNumFormatType eType
,
1937 SvNumberformat
const * pFormat
,
1938 LanguageType eForLocale
)
1940 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1941 return SvNFEngine::GetEditFormat(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(),
1942 m_aRWPolicy
, fNumber
, nFIndex
,
1943 eType
, pFormat
, eForLocale
);
1946 void SvNFEngine::GetInputLineString(SvNFLanguageData
& rCurrentLanguage
,
1947 const SvNFFormatData
& rFormatData
,
1948 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
1949 const double& fOutNumber
,
1951 OUString
& sOutString
,
1952 bool bFiltering
, bool bForceSystemLocale
)
1954 const Color
* pColor
;
1955 sal_uInt32 nRealKey
= nFIndex
;
1957 const SvNumberformat
* pFormat
= ImpSubstituteEntry(rCurrentLanguage
, rFormatData
,
1959 rFormatData
.GetFormatEntry(nFIndex
), &nRealKey
);
1961 pFormat
= rFormatData
.GetFormatEntry(ZF_STANDARD
);
1963 LanguageType eLang
= pFormat
->GetLanguage();
1964 rCurrentLanguage
.ChangeIntl(eLang
);
1966 SvNumFormatType eType
= pFormat
->GetMaskedType();
1967 if (eType
== SvNumFormatType::ALL
)
1969 // Mixed types in subformats, use first.
1970 /* XXX we could choose a subformat according to fOutNumber and
1971 * subformat conditions, but they may exist to suppress 0 or negative
1972 * numbers so wouldn't be a safe bet. */
1973 eType
= pFormat
->GetNumForInfoScannedType(0);
1975 const SvNumFormatType eTypeOrig
= eType
;
1977 sal_uInt16 nOldPrec
= rCurrentLanguage
.pFormatScanner
->GetStandardPrec();
1978 bool bPrecChanged
= false;
1979 if (eType
== SvNumFormatType::NUMBER
||
1980 eType
== SvNumFormatType::PERCENT
||
1981 eType
== SvNumFormatType::CURRENCY
||
1982 eType
== SvNumFormatType::SCIENTIFIC
||
1983 eType
== SvNumFormatType::FRACTION
)
1985 if (eType
!= SvNumFormatType::PERCENT
) // special treatment of % later
1987 eType
= SvNumFormatType::NUMBER
;
1989 rCurrentLanguage
.ChangeStandardPrec(SvNumberFormatter::INPUTSTRING_PRECISION
);
1990 bPrecChanged
= true;
1993 // if bFiltering true keep the nRealKey format
1996 sal_uInt32 nKey
= GetEditFormat(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
,
1997 fOutNumber
, nRealKey
, eType
, pFormat
,
1998 bForceSystemLocale
? LANGUAGE_SYSTEM
: LANGUAGE_DONTKNOW
);
1999 if (nKey
!= nRealKey
)
2001 pFormat
= rFormatData
.GetFormatEntry( nKey
);
2007 if ( eType
== SvNumFormatType::TIME
&& pFormat
->GetFormatPrecision() )
2009 rCurrentLanguage
.ChangeStandardPrec(SvNumberFormatter::INPUTSTRING_PRECISION
);
2010 bPrecChanged
= true;
2012 pFormat
->GetOutputString(fOutNumber
, sOutString
, &pColor
, rNatNum
, rCurrentLanguage
);
2014 // The #FMT error string must not be used for input as it would lead to
2015 // data loss. This can happen for at least date(+time). Fall back to a
2016 // last resort of plain number in the locale the formatter was
2017 // constructed with.
2018 if (eTypeOrig
!= SvNumFormatType::NUMBER
&& sOutString
== ImpSvNumberformatScan::sErrStr
)
2020 pFormat
= rFormatData
.GetFormatEntry(ZF_STANDARD
);
2024 rCurrentLanguage
.ChangeStandardPrec(SvNumberFormatter::INPUTSTRING_PRECISION
);
2025 bPrecChanged
= true;
2026 pFormat
->GetOutputString(fOutNumber
, sOutString
, &pColor
, rNatNum
, rCurrentLanguage
);
2029 assert(sOutString
!= ImpSvNumberformatScan::sErrStr
);
2033 rCurrentLanguage
.ChangeStandardPrec(nOldPrec
);
2037 void SvNumberFormatter::GetInputLineString(const double& fOutNumber
,
2039 OUString
& sOutString
,
2040 bool bFiltering
, bool bForceSystemLocale
)
2042 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2043 SvNFEngine::GetInputLineString(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(),
2044 m_aRWPolicy
, fOutNumber
, nFIndex
, sOutString
,
2045 bFiltering
, bForceSystemLocale
);
2048 void SvNFEngine::GetOutputString(SvNFLanguageData
& rCurrentLanguage
,
2049 const SvNFFormatData
& rFormatData
,
2050 const OUString
& sString
, sal_uInt32 nFIndex
, OUString
& sOutString
,
2051 const Color
** ppColor
, bool bUseStarFormat
)
2053 const SvNumberformat
* pFormat
= rFormatData
.GetFormatEntry( nFIndex
);
2054 // ImpSubstituteEntry() is unnecessary here because so far only numeric
2055 // (time and date) are substituted.
2058 pFormat
= rFormatData
.GetFormatEntry(ZF_STANDARD_TEXT
);
2060 if (!pFormat
->IsTextFormat() && !pFormat
->HasTextFormat())
2063 sOutString
= sString
;
2067 rCurrentLanguage
.ChangeIntl(pFormat
->GetLanguage());
2068 pFormat
->GetOutputString(sString
, sOutString
, ppColor
, bUseStarFormat
);
2072 void SvNumberFormatter::GetOutputString(const OUString
& sString
,
2074 OUString
& sOutString
,
2075 const Color
** ppColor
,
2076 bool bUseStarFormat
)
2078 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2079 SvNFEngine::GetOutputString(m_aCurrentLanguage
, m_aFormatData
,
2080 sString
, nFIndex
, sOutString
,
2081 ppColor
, bUseStarFormat
);
2084 void SvNFEngine::GetOutputString(SvNFLanguageData
& rCurrentLanguage
,
2085 const SvNFFormatData
& rFormatData
,
2086 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
2087 const double& fOutNumber
, sal_uInt32 nFIndex
,
2088 OUString
& sOutString
, const Color
** ppColor
,
2089 bool bUseStarFormat
)
2091 if (rFormatData
.GetNoZero() && fOutNumber
== 0.0)
2096 const SvNumberformat
* pFormat
= ImpSubstituteEntry(rCurrentLanguage
, rFormatData
,
2098 rFormatData
.GetFormatEntry(nFIndex
), nullptr);
2100 pFormat
= rFormatData
.GetFormatEntry(ZF_STANDARD
);
2101 rCurrentLanguage
.ChangeIntl(pFormat
->GetLanguage());
2102 pFormat
->GetOutputString(fOutNumber
, sOutString
, ppColor
, rNatNum
, rCurrentLanguage
, bUseStarFormat
);
2105 void SvNumberFormatter::GetOutputString(const double& fOutNumber
,
2107 OUString
& sOutString
,
2108 const Color
** ppColor
,
2109 bool bUseStarFormat
)
2111 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2112 SvNFEngine::GetOutputString(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(),
2113 m_aRWPolicy
, fOutNumber
, nFIndex
, sOutString
,
2114 ppColor
, bUseStarFormat
);
2117 bool SvNFEngine::GetPreviewString(SvNFLanguageData
& rCurrentLanguage
,
2118 const SvNFFormatData
& rFormatData
,
2119 const NativeNumberWrapper
& rNatNum
,
2120 const Accessor
& rFuncs
,
2121 const OUString
& sFormatString
,
2122 double fPreviewNumber
,
2123 OUString
& sOutString
,
2124 const Color
** ppColor
,
2126 bool bUseStarFormat
)
2128 if (sFormatString
.isEmpty()) // no empty string
2130 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
2131 rCurrentLanguage
.ChangeIntl(eLnge
); // change locale if necessary
2132 eLnge
= rCurrentLanguage
.ActLnge
;
2133 sal_Int32 nCheckPos
= -1;
2134 OUString sTmpString
= sFormatString
;
2135 SvNumberformat
aEntry(sTmpString
,
2136 rCurrentLanguage
.pFormatScanner
.get(),
2137 rCurrentLanguage
.pStringScanner
.get(),
2141 if (nCheckPos
== 0) // String ok
2143 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary (and allowed)
2144 sal_uInt32 nKey
= rFormatData
.ImpIsEntry(aEntry
.GetFormatstring(), nCLOffset
, eLnge
);
2145 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
2147 GetOutputString(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
, fPreviewNumber
, nKey
, sOutString
, ppColor
, bUseStarFormat
);
2151 aEntry
.GetOutputString(fPreviewNumber
, sOutString
, ppColor
, rNatNum
, rCurrentLanguage
, bUseStarFormat
);
2161 bool SvNumberFormatter::GetPreviewString(const OUString
& sFormatString
,
2162 double fPreviewNumber
,
2163 OUString
& sOutString
,
2164 const Color
** ppColor
,
2166 bool bUseStarFormat
)
2168 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2169 return SvNFEngine::GetPreviewString(m_aCurrentLanguage
, m_aFormatData
,
2170 GetNatNum(), m_aRWPolicy
,
2171 sFormatString
, fPreviewNumber
,
2172 sOutString
, ppColor
, eLnge
,
2176 bool SvNFEngine::GetPreviewStringGuess(SvNFLanguageData
& rCurrentLanguage
,
2177 const SvNFFormatData
& rFormatData
,
2178 const NativeNumberWrapper
& rNatNum
,
2179 const Accessor
& rFuncs
,
2180 const OUString
& sFormatString
,
2181 double fPreviewNumber
,
2182 OUString
& sOutString
,
2183 const Color
** ppColor
,
2186 if (sFormatString
.isEmpty()) // no empty string
2188 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
2189 rCurrentLanguage
.ChangeIntl(eLnge
);
2190 eLnge
= rCurrentLanguage
.ActLnge
;
2191 bool bEnglish
= (eLnge
== LANGUAGE_ENGLISH_US
);
2193 OUString
aFormatStringUpper( rCurrentLanguage
.xCharClass
->uppercase( sFormatString
) );
2194 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary (and allowed)
2195 sal_uInt32 nKey
= rFormatData
.ImpIsEntry(aFormatStringUpper
, nCLOffset
, eLnge
);
2196 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
2198 // Target format present
2199 GetOutputString(rCurrentLanguage
, rFormatData
, rNatNum
, rFuncs
,
2200 fPreviewNumber
, nKey
, sOutString
, ppColor
, false);
2204 std::optional
<SvNumberformat
> pEntry
;
2205 sal_Int32 nCheckPos
= -1;
2206 OUString sTmpString
;
2210 sTmpString
= sFormatString
;
2211 pEntry
.emplace( sTmpString
, rCurrentLanguage
.pFormatScanner
.get(),
2212 rCurrentLanguage
.pStringScanner
.get(), rNatNum
, nCheckPos
, eLnge
);
2216 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, LANGUAGE_ENGLISH_US
);
2217 nKey
= rFormatData
.ImpIsEntry(aFormatStringUpper
, nCLOffset
, LANGUAGE_ENGLISH_US
);
2218 bool bEnglishFormat
= (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
2220 // Try English -> other or convert english to other
2221 LanguageType eFormatLang
= LANGUAGE_ENGLISH_US
;
2222 rCurrentLanguage
.pFormatScanner
->SetConvertMode( LANGUAGE_ENGLISH_US
, eLnge
, false, false);
2223 sTmpString
= sFormatString
;
2224 pEntry
.emplace( sTmpString
, rCurrentLanguage
.pFormatScanner
.get(),
2225 rCurrentLanguage
.pStringScanner
.get(), rNatNum
, nCheckPos
, eFormatLang
);
2226 rCurrentLanguage
.pFormatScanner
->SetConvertMode( false );
2227 rCurrentLanguage
.ChangeIntl(eLnge
);
2229 if ( !bEnglishFormat
)
2231 if ( nCheckPos
!= 0 || rCurrentLanguage
.xTransliteration
->isEqual( sFormatString
,
2232 pEntry
->GetFormatstring() ) )
2235 // Force locale's keywords.
2236 rCurrentLanguage
.pFormatScanner
->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy
);
2237 sTmpString
= sFormatString
;
2238 pEntry
.emplace( sTmpString
, rCurrentLanguage
.pFormatScanner
.get(),
2239 rCurrentLanguage
.pStringScanner
.get(), rNatNum
, nCheckPos
, eLnge
);
2244 sal_Int32 nCheckPos2
= -1;
2245 // try other --> english
2246 eFormatLang
= eLnge
;
2247 rCurrentLanguage
.pFormatScanner
->SetConvertMode( eLnge
, LANGUAGE_ENGLISH_US
, false, false);
2248 sTmpString
= sFormatString
;
2249 SvNumberformat
aEntry2( sTmpString
, rCurrentLanguage
.pFormatScanner
.get(),
2250 rCurrentLanguage
.pStringScanner
.get(), rNatNum
, nCheckPos2
, eFormatLang
);
2251 rCurrentLanguage
.pFormatScanner
->SetConvertMode( false );
2252 rCurrentLanguage
.ChangeIntl(eLnge
);
2253 if ( nCheckPos2
== 0 && !rCurrentLanguage
.xTransliteration
->isEqual( sFormatString
,
2254 aEntry2
.GetFormatstring() ) )
2257 // Force locale's keywords.
2258 rCurrentLanguage
.pFormatScanner
->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy
);
2259 sTmpString
= sFormatString
;
2260 pEntry
.emplace( sTmpString
, rCurrentLanguage
.pFormatScanner
.get(),
2261 rCurrentLanguage
.pStringScanner
.get(), rNatNum
, nCheckPos
, eLnge
);
2267 if (nCheckPos
== 0) // String ok
2269 rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary
2270 pEntry
->GetOutputString( fPreviewNumber
, sOutString
, ppColor
, rNatNum
, rCurrentLanguage
);
2276 bool SvNumberFormatter::GetPreviewStringGuess( const OUString
& sFormatString
,
2277 double fPreviewNumber
,
2278 OUString
& sOutString
,
2279 const Color
** ppColor
,
2280 LanguageType eLnge
)
2282 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2283 return SvNFEngine::GetPreviewStringGuess(m_aCurrentLanguage
, m_aFormatData
,
2284 GetNatNum(), m_aRWPolicy
,
2285 sFormatString
, fPreviewNumber
,
2286 sOutString
, ppColor
, eLnge
);
2289 bool SvNFEngine::GetPreviewString(SvNFLanguageData
& rCurrentLanguage
,
2290 const SvNFFormatData
& rFormatData
,
2291 const NativeNumberWrapper
& rNatNum
,
2292 const Accessor
& rFuncs
,
2293 const OUString
& sFormatString
,
2294 const OUString
& sPreviewString
,
2295 OUString
& sOutString
,
2296 const Color
** ppColor
,
2299 if (sFormatString
.isEmpty()) // no empty string
2301 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
2302 rCurrentLanguage
.ChangeIntl(eLnge
); // switch if needed
2303 eLnge
= rCurrentLanguage
.ActLnge
;
2304 sal_Int32 nCheckPos
= -1;
2305 OUString sTmpString
= sFormatString
;
2306 SvNumberformat
aEntry( sTmpString
,
2307 rCurrentLanguage
.pFormatScanner
.get(),
2308 rCurrentLanguage
.pStringScanner
.get(),
2312 if (nCheckPos
== 0) // String ok
2314 // May have to create standard formats for this locale.
2315 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
);
2316 sal_uInt32 nKey
= rFormatData
.ImpIsEntry( aEntry
.GetFormatstring(), nCLOffset
, eLnge
);
2317 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
2319 GetOutputString(rCurrentLanguage
, rFormatData
,
2320 sPreviewString
, nKey
, sOutString
, ppColor
, false);
2324 // If the format is valid but not a text format and does not
2325 // include a text subformat, an empty string would result. Same as
2326 // in SvNumberFormatter::GetOutputString()
2327 if (aEntry
.IsTextFormat() || aEntry
.HasTextFormat())
2329 aEntry
.GetOutputString( sPreviewString
, sOutString
, ppColor
);
2334 sOutString
= sPreviewString
;
2345 bool SvNumberFormatter::GetPreviewString( const OUString
& sFormatString
,
2346 const OUString
& sPreviewString
,
2347 OUString
& sOutString
,
2348 const Color
** ppColor
,
2349 LanguageType eLnge
)
2351 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2352 return SvNFEngine::GetPreviewString(m_aCurrentLanguage
, m_aFormatData
,
2353 GetNatNum(), m_aRWPolicy
,
2354 sFormatString
, sPreviewString
,
2355 sOutString
, ppColor
, eLnge
);
2358 sal_uInt32
SvNumberFormatter::TestNewString(const OUString
& sFormatString
,
2361 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2362 if (sFormatString
.isEmpty()) // no empty string
2364 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
2366 if (eLnge
== LANGUAGE_DONTKNOW
)
2370 ChangeIntl(eLnge
); // change locale if necessary
2371 eLnge
= m_aCurrentLanguage
.ActLnge
;
2373 sal_Int32 nCheckPos
= -1;
2374 OUString sTmpString
= sFormatString
;
2375 SvNumberformat
aEntry(sTmpString
,
2376 m_aCurrentLanguage
.pFormatScanner
.get(),
2377 m_aCurrentLanguage
.pStringScanner
.get(),
2381 if (nCheckPos
== 0) // String ok
2383 sal_uInt32 CLOffset
= m_aFormatData
.ImpGenerateCL(m_aCurrentLanguage
, GetNatNum(), eLnge
); // create new standard formats if necessary
2384 nRes
= ImpIsEntry(aEntry
.GetFormatstring(),CLOffset
, eLnge
);
2389 nRes
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
2394 SvNumberformat
* SvNFFormatData::ImpInsertFormat(SvNFLanguageData
& rCurrentLanguage
,
2395 const NativeNumberWrapper
& rNatNum
,
2396 const css::i18n::NumberFormatCode
& rCode
,
2397 sal_uInt32 nPos
, bool bAfterChangingSystemCL
,
2398 sal_Int16 nOrgIndex
)
2400 SAL_WARN_IF( NF_INDEX_TABLE_RESERVED_START
<= rCode
.Index
&& rCode
.Index
< NF_INDEX_TABLE_ENTRIES
,
2401 "svl.numbers", "i18npool locale '" << rCurrentLanguage
.aLanguageTag
.getBcp47() <<
2402 "' uses reserved formatIndex value " << rCode
.Index
<< ", next free: " << NF_INDEX_TABLE_ENTRIES
<<
2403 " Please see description in include/svl/zforlist.hxx at end of enum NfIndexTableOffset");
2404 assert( (rCode
.Index
< NF_INDEX_TABLE_RESERVED_START
|| NF_INDEX_TABLE_ENTRIES
<= rCode
.Index
) &&
2405 "reserved formatIndex, see warning above");
2407 OUString
aCodeStr( rCode
.Code
);
2408 if ( rCode
.Index
< NF_INDEX_TABLE_RESERVED_START
&&
2409 rCode
.Usage
== css::i18n::KNumberFormatUsage::CURRENCY
&&
2410 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
2411 { // strip surrounding [$...] on automatic currency
2412 if ( aCodeStr
.indexOf( "[$" ) >= 0)
2413 aCodeStr
= SvNumberformat::StripNewCurrencyDelimiters( aCodeStr
);
2416 if (LocaleDataWrapper::areChecksEnabled() &&
2417 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
2419 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index " +
2420 OUString::number( rCode
.Index
) +
2423 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo( aMsg
));
2427 sal_Int32 nCheckPos
= 0;
2428 std::unique_ptr
<SvNumberformat
> pFormat(new SvNumberformat(aCodeStr
,
2429 rCurrentLanguage
.pFormatScanner
.get(),
2430 rCurrentLanguage
.pStringScanner
.get(),
2433 rCurrentLanguage
.ActLnge
));
2436 if (LocaleDataWrapper::areChecksEnabled())
2438 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
2439 OUString::number( rCode
.Index
) +
2442 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo( aMsg
));
2446 if ( rCode
.Index
>= NF_INDEX_TABLE_RESERVED_START
)
2448 sal_uInt32 nCLOffset
= nPos
- (nPos
% SV_COUNTRY_LANGUAGE_OFFSET
);
2449 sal_uInt32 nKey
= ImpIsEntry( aCodeStr
, nCLOffset
, rCurrentLanguage
.ActLnge
);
2450 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
2452 // If bAfterChangingSystemCL there will definitely be some dups,
2454 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL
)
2456 // Test for duplicate indexes in locale data.
2457 switch ( nOrgIndex
)
2459 // These may be dups of integer versions for locales where
2460 // currencies have no decimals like Italian Lira.
2461 case NF_CURRENCY_1000DEC2
: // NF_CURRENCY_1000INT
2462 case NF_CURRENCY_1000DEC2_RED
: // NF_CURRENCY_1000INT_RED
2463 case NF_CURRENCY_1000DEC2_DASHED
: // NF_CURRENCY_1000INT_RED
2467 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: dup format code, index "
2468 + OUString::number( rCode
.Index
)
2471 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo( aMsg
));
2477 else if ( nPos
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2479 if (LocaleDataWrapper::areChecksEnabled())
2481 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: too many format codes, index "
2482 + OUString::number( rCode
.Index
)
2485 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo( aMsg
));
2490 auto pFormat2
= pFormat
.get();
2491 if ( !aFTable
.emplace( nPos
, std::move(pFormat
) ).second
)
2493 if (LocaleDataWrapper::areChecksEnabled())
2495 OUString aMsg
= "ImpInsertFormat: can't insert number format key pos: "
2496 + OUString::number( nPos
)
2498 + OUString::number( rCode
.Index
)
2501 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo( aMsg
));
2505 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
2509 if ( rCode
.Default
)
2510 pFormat2
->SetStandard();
2511 if ( !rCode
.DefaultName
.isEmpty() )
2512 pFormat2
->SetComment( rCode
.DefaultName
);
2516 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat
,
2519 sal_uInt16
& nPrecision
,
2520 sal_uInt16
& nLeadingCnt
)
2523 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2524 SvNumberformat
* pFormat
= m_aFormatData
.GetFormatEntry( nFormat
);
2526 pFormat
->GetFormatSpecialInfo(bThousand
, IsRed
,
2527 nPrecision
, nLeadingCnt
);
2532 nPrecision
= m_aCurrentLanguage
.pFormatScanner
->GetStandardPrec();
2537 sal_uInt16
SvNFEngine::GetFormatPrecision(SvNFLanguageData
& rCurrentLanguage
,
2538 const SvNFFormatData
& rFormatData
,
2541 const SvNumberformat
* pFormat
= rFormatData
.GetFormatEntry(nFormat
);
2543 return pFormat
->GetFormatPrecision();
2544 return rCurrentLanguage
.pFormatScanner
->GetStandardPrec();
2547 sal_uInt16
SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat
)
2549 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2550 return SvNFEngine::GetFormatPrecision(m_aCurrentLanguage
, m_aFormatData
, nFormat
);
2553 sal_uInt16
SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat
) const
2555 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2556 const SvNumberformat
* pFormat
= m_aFormatData
.GetFormatEntry( nFormat
);
2558 return pFormat
->GetFormatIntegerDigits();
2563 OUString
SvNFEngine::GetFormatDecimalSep(SvNFLanguageData
& rCurrentLanguage
,
2564 const SvNFFormatData
& rFormatData
,
2567 const SvNumberformat
* pFormat
= rFormatData
.GetFormatEntry(nFormat
);
2569 return rCurrentLanguage
.GetNumDecimalSep();
2570 return rCurrentLanguage
.GetLangDecimalSep(pFormat
->GetLanguage());
2573 OUString
SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat
)
2575 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2576 return SvNFEngine::GetFormatDecimalSep(m_aCurrentLanguage
,
2581 bool SvNumberFormatter::IsNatNum12( sal_uInt32 nFIndex
) const
2583 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2584 const SvNumberformat
* pFormat
= m_aFormatData
.GetFormatEntry( nFIndex
);
2586 return pFormat
&& pFormat
->GetNatNumModifierString().startsWith( "[NatNum12" );
2589 sal_uInt32
SvNumberFormatter::GetFormatSpecialInfo( const OUString
& rFormatString
,
2590 bool& bThousand
, bool& IsRed
, sal_uInt16
& nPrecision
,
2591 sal_uInt16
& nLeadingCnt
, LanguageType eLnge
)
2594 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2595 if (eLnge
== LANGUAGE_DONTKNOW
)
2599 ChangeIntl(eLnge
); // change locale if necessary
2600 eLnge
= m_aCurrentLanguage
.ActLnge
;
2601 OUString
aTmpStr( rFormatString
);
2602 sal_Int32 nCheckPos
= 0;
2603 SvNumberformat
aFormat( aTmpStr
, m_aCurrentLanguage
.pFormatScanner
.get(),
2604 m_aCurrentLanguage
.pStringScanner
.get(), GetNatNum(), nCheckPos
, eLnge
);
2605 if ( nCheckPos
== 0 )
2607 aFormat
.GetFormatSpecialInfo( bThousand
, IsRed
, nPrecision
, nLeadingCnt
);
2613 nPrecision
= m_aCurrentLanguage
.pFormatScanner
->GetStandardPrec();
2619 OUString
SvNFFormatData::GetCalcCellReturn(sal_uInt32 nFormat
) const
2621 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
2626 bool bAppendPrec
= true;
2627 sal_uInt16 nPrec
, nLeading
;
2628 bool bThousand
, bIsRed
;
2629 pFormat
->GetFormatSpecialInfo( bThousand
, bIsRed
, nPrec
, nLeading
);
2631 switch (pFormat
->GetMaskedType())
2633 case SvNumFormatType::NUMBER
:
2639 case SvNumFormatType::CURRENCY
:
2642 case SvNumFormatType::SCIENTIFIC
:
2645 case SvNumFormatType::PERCENT
:
2650 bAppendPrec
= false;
2651 switch (SvNumberFormatter::GetIndexTableOffset(nFormat
))
2653 case NF_DATE_SYSTEM_SHORT
:
2654 case NF_DATE_SYS_DMMMYY
:
2655 case NF_DATE_SYS_DDMMYY
:
2656 case NF_DATE_SYS_DDMMYYYY
:
2657 case NF_DATE_SYS_DMMMYYYY
:
2658 case NF_DATE_DIN_DMMMYYYY
:
2659 case NF_DATE_SYS_DMMMMYYYY
:
2660 case NF_DATE_DIN_DMMMMYYYY
: aStr
= "D1"; break;
2661 case NF_DATE_SYS_DDMMM
: aStr
= "D2"; break;
2662 case NF_DATE_SYS_MMYY
: aStr
= "D3"; break;
2663 case NF_DATETIME_SYSTEM_SHORT_HHMM
:
2664 case NF_DATETIME_SYS_DDMMYYYY_HHMM
:
2665 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS
:
2667 case NF_DATE_DIN_MMDD
: aStr
= "D5"; break;
2668 case NF_TIME_HHMMSSAMPM
: aStr
= "D6"; break;
2669 case NF_TIME_HHMMAMPM
: aStr
= "D7"; break;
2670 case NF_TIME_HHMMSS
: aStr
= "D8"; break;
2671 case NF_TIME_HHMM
: aStr
= "D9"; break;
2672 default: aStr
= "G";
2678 aStr
+= OUString::number(nPrec
);
2680 if (pFormat
->GetColor( 1 ))
2681 aStr
+= "-"; // negative color
2683 /* FIXME: this probably should not match on literal strings and only be
2684 * performed on number or currency formats, but it is what Calc originally
2686 if (pFormat
->GetFormatstring().indexOf('(') != -1)
2692 OUString
SvNumberFormatter::GetCalcCellReturn( sal_uInt32 nFormat
) const
2694 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2695 return m_aFormatData
.GetCalcCellReturn(nFormat
);
2698 // Return the index in a sequence of format codes matching an enum of
2699 // NfIndexTableOffset. If not found 0 is returned. If the sequence doesn't
2700 // contain any format code elements a default element is created and inserted.
2701 sal_Int32
SvNFFormatData::ImpGetFormatCodeIndex(const SvNFLanguageData
& rCurrentLanguage
,
2702 css::uno::Sequence
<css::i18n::NumberFormatCode
>& rSeq
,
2703 const NfIndexTableOffset nTabOff
)
2705 auto pSeq
= std::find_if(std::cbegin(rSeq
), std::cend(rSeq
),
2706 [nTabOff
](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Index
== nTabOff
; });
2707 if (pSeq
!= std::cend(rSeq
))
2708 return static_cast<sal_Int32
>(std::distance(std::cbegin(rSeq
), pSeq
));
2709 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff
< NF_CURRENCY_START
2710 || NF_CURRENCY_END
< nTabOff
|| nTabOff
== NF_CURRENCY_1000INT
2711 || nTabOff
== NF_CURRENCY_1000INT_RED
2712 || nTabOff
== NF_CURRENCY_1000DEC2_CCC
))
2713 { // currency entries with decimals might not exist, e.g. Italian Lira
2714 OUString aMsg
= "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "
2715 + OUString::number( nTabOff
);
2716 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->appendLocaleInfo(aMsg
));
2718 if ( rSeq
.hasElements() )
2720 // look for a preset default
2721 pSeq
= std::find_if(std::cbegin(rSeq
), std::cend(rSeq
),
2722 [](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Default
; });
2723 if (pSeq
!= std::cend(rSeq
))
2724 return static_cast<sal_Int32
>(std::distance(std::cbegin(rSeq
), pSeq
));
2725 // currencies are special, not all format codes must exist, but all
2726 // builtin number format key index positions must have a format assigned
2727 if ( NF_CURRENCY_START
<= nTabOff
&& nTabOff
<= NF_CURRENCY_END
)
2729 // look for a format with decimals
2730 pSeq
= std::find_if(std::cbegin(rSeq
), std::cend(rSeq
),
2731 [](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Index
== NF_CURRENCY_1000DEC2
; });
2732 if (pSeq
!= std::cend(rSeq
))
2733 return static_cast<sal_Int32
>(std::distance(std::cbegin(rSeq
), pSeq
));
2734 // last resort: look for a format without decimals
2735 pSeq
= std::find_if(std::cbegin(rSeq
), std::cend(rSeq
),
2736 [](const css::i18n::NumberFormatCode
& rCode
) { return rCode
.Index
== NF_CURRENCY_1000INT
; });
2737 if (pSeq
!= std::cend(rSeq
))
2738 return static_cast<sal_Int32
>(std::distance(std::cbegin(rSeq
), pSeq
));
2742 { // we need at least _some_ format
2743 rSeq
= { css::i18n::NumberFormatCode() };
2744 rSeq
.getArray()[0].Code
= "0" + rCurrentLanguage
.GetNumDecimalSep() + "############";
2749 // Adjust a sequence of format codes to contain only one (THE) default
2750 // instead of multiple defaults for short/medium/long types.
2751 // If there is no medium but a short and a long default the long is taken.
2752 // Non-PRODUCT version may check locale data for matching defaults in one
2753 // FormatElement group.
2754 void SvNFFormatData::ImpAdjustFormatCodeDefault(const SvNFLanguageData
& rCurrentLanguage
,
2755 css::i18n::NumberFormatCode
* pFormatArr
,
2760 if (LocaleDataWrapper::areChecksEnabled())
2762 // check the locale data for correctness
2763 OUStringBuffer aMsg
;
2764 sal_Int32 nElem
, nShort
, nMedium
, nLong
, nShortDef
, nMediumDef
, nLongDef
;
2765 nShort
= nMedium
= nLong
= nShortDef
= nMediumDef
= nLongDef
= -1;
2766 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2768 switch ( pFormatArr
[nElem
].Type
)
2770 case i18n::KNumberFormatType::SHORT
:
2773 case i18n::KNumberFormatType::MEDIUM
:
2776 case i18n::KNumberFormatType::LONG
:
2780 aMsg
.append("unknown type");
2782 if ( pFormatArr
[nElem
].Default
)
2784 switch ( pFormatArr
[nElem
].Type
)
2786 case i18n::KNumberFormatType::SHORT
:
2787 if ( nShortDef
!= -1 )
2788 aMsg
.append("dupe short type default");
2791 case i18n::KNumberFormatType::MEDIUM
:
2792 if ( nMediumDef
!= -1 )
2793 aMsg
.append("dupe medium type default");
2796 case i18n::KNumberFormatType::LONG
:
2797 if ( nLongDef
!= -1 )
2798 aMsg
.append("dupe long type default");
2803 if (!aMsg
.isEmpty())
2805 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2806 aMsg
.append("\nXML locale data FormatElement formatindex: "
2807 + OUString::number(static_cast<sal_Int32
>(pFormatArr
[nElem
].Index
)));
2808 LocaleDataWrapper::outputCheckMessage(rCurrentLanguage
.xLocaleData
->appendLocaleInfo(aMsg
));
2812 if ( nShort
!= -1 && nShortDef
== -1 )
2813 aMsg
.append("no short type default ");
2814 if ( nMedium
!= -1 && nMediumDef
== -1 )
2815 aMsg
.append("no medium type default ");
2816 if ( nLong
!= -1 && nLongDef
== -1 )
2817 aMsg
.append("no long type default ");
2818 if (!aMsg
.isEmpty())
2820 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2821 aMsg
.append("\nXML locale data FormatElement group of: ");
2822 LocaleDataWrapper::outputCheckMessage(
2823 rCurrentLanguage
.xLocaleData
->appendLocaleInfo(Concat2View(aMsg
+ pFormatArr
[0].NameID
)));
2827 // find the default (medium preferred, then long) and reset all other defaults
2828 sal_Int32 nElem
, nDef
, nMedium
;
2829 nDef
= nMedium
= -1;
2830 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2832 if ( pFormatArr
[nElem
].Default
)
2834 switch ( pFormatArr
[nElem
].Type
)
2836 case i18n::KNumberFormatType::MEDIUM
:
2837 nDef
= nMedium
= nElem
;
2839 case i18n::KNumberFormatType::LONG
:
2840 if ( nMedium
== -1 )
2846 pFormatArr
[nElem
].Default
= false;
2852 pFormatArr
[nDef
].Default
= true;
2855 SvNumberformat
* SvNFFormatData::GetEntry(sal_uInt32 nKey
) const
2857 auto it
= aFTable
.find( nKey
);
2858 if (it
!= aFTable
.end())
2859 return it
->second
.get();
2863 SvNumberformat
* SvNFFormatData::GetFormatEntry(sal_uInt32 nKey
)
2865 return GetEntry(nKey
);
2868 const SvNumberformat
* SvNFFormatData::GetFormatEntry(sal_uInt32 nKey
) const
2870 return GetEntry(nKey
);
2873 SvNumFormatType
SvNFFormatData::GetType(sal_uInt32 nFIndex
) const
2875 SvNumFormatType eType
;
2876 const SvNumberformat
* pFormat
= GetFormatEntry(nFIndex
);
2878 eType
= SvNumFormatType::UNDEFINED
;
2881 eType
= pFormat
->GetMaskedType();
2882 if (eType
== SvNumFormatType::ALL
)
2883 eType
= SvNumFormatType::DEFINED
;
2888 const SvNumberformat
* SvNumberFormatter::GetEntry( sal_uInt32 nKey
) const
2890 ::osl::MutexGuard
aGuard(GetInstanceMutex());
2891 return m_aFormatData
.GetFormatEntry(nKey
);
2894 const SvNumberformat
* SvNumberFormatter::GetSubstitutedEntry( sal_uInt32 nKey
, sal_uInt32
& o_rNewKey
)
2896 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2897 // A tad ugly, but GetStandardFormat() and GetFormatIndex() in
2898 // ImpSubstituteEntry() may have to add the LANGUAGE_SYSTEM formats if not
2899 // already present (which in practice most times they are).
2900 return ImpSubstituteEntry(m_aFormatData
.GetFormatEntry(nKey
), &o_rNewKey
);
2903 const SvNumberformat
* SvNumberFormatter::ImpSubstituteEntry( const SvNumberformat
* pFormat
, sal_uInt32
* o_pRealKey
)
2905 return ::ImpSubstituteEntry(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(), m_aRWPolicy
, pFormat
, o_pRealKey
);
2908 void SvNFFormatData::ImpGenerateFormats(SvNFLanguageData
& rCurrentLanguage
, const NativeNumberWrapper
& rNatNum
, sal_uInt32 CLOffset
, bool bNoAdditionalFormats
)
2910 bool bOldConvertMode
= rCurrentLanguage
.pFormatScanner
->GetConvertMode();
2911 if (bOldConvertMode
)
2913 rCurrentLanguage
.pFormatScanner
->SetConvertMode(false); // switch off for this function
2916 css::lang::Locale aLocale
= rCurrentLanguage
.GetLanguageTag().getLocale();
2917 css::uno::Reference
< css::i18n::XNumberFormatCode
> xNFC
= i18n::NumberFormatMapper::create(rCurrentLanguage
.GetComponentContext());
2921 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER
, aLocale
);
2922 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2925 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_NUMBER_STANDARD
);
2926 SvNumberformat
* pStdFormat
= ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
2927 CLOffset
+ ZF_STANDARD
/* NF_NUMBER_STANDARD */ );
2930 // This is _the_ standard format.
2931 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat
->GetType() != SvNumFormatType::NUMBER
)
2933 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->
2934 appendLocaleInfo( u
"SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2936 pStdFormat
->SetType( SvNumFormatType::NUMBER
);
2937 pStdFormat
->SetStandard();
2938 pStdFormat
->SetLastInsertKey( SV_MAX_COUNT_STANDARD_FORMATS
, SvNumberformat::FormatterPrivateAccess() );
2942 if (LocaleDataWrapper::areChecksEnabled())
2944 LocaleDataWrapper::outputCheckMessage( rCurrentLanguage
.xLocaleData
->
2945 appendLocaleInfo( u
"SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2951 OUString aFormatCode
= rCurrentLanguage
.pFormatScanner
->GetBooleanString();
2952 sal_Int32 nCheckPos
= 0;
2954 std::unique_ptr
<SvNumberformat
> pNewFormat(new SvNumberformat( aFormatCode
, rCurrentLanguage
.pFormatScanner
.get(),
2955 rCurrentLanguage
.pStringScanner
.get(), rNatNum
, nCheckPos
, rCurrentLanguage
.ActLnge
));
2956 pNewFormat
->SetType(SvNumFormatType::LOGICAL
);
2957 pNewFormat
->SetStandard();
2958 if ( !aFTable
.emplace(CLOffset
+ ZF_STANDARD_LOGICAL
/* NF_BOOLEAN */,
2959 std::move(pNewFormat
)).second
)
2961 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2966 pNewFormat
.reset(new SvNumberformat( aFormatCode
, rCurrentLanguage
.pFormatScanner
.get(),
2967 rCurrentLanguage
.pStringScanner
.get(), rNatNum
, nCheckPos
, rCurrentLanguage
.ActLnge
));
2968 pNewFormat
->SetType(SvNumFormatType::TEXT
);
2969 pNewFormat
->SetStandard();
2970 if ( !aFTable
.emplace( CLOffset
+ ZF_STANDARD_TEXT
/* NF_TEXT */,
2971 std::move(pNewFormat
)).second
)
2973 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2978 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_NUMBER_INT
);
2979 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
2980 CLOffset
+ ZF_STANDARD
+1 /* NF_NUMBER_INT */ );
2983 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_NUMBER_DEC2
);
2984 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
2985 CLOffset
+ ZF_STANDARD
+2 /* NF_NUMBER_DEC2 */ );
2988 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_NUMBER_1000INT
);
2989 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
2990 CLOffset
+ ZF_STANDARD
+3 /* NF_NUMBER_1000INT */ );
2993 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_NUMBER_1000DEC2
);
2994 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
2995 CLOffset
+ ZF_STANDARD
+4 /* NF_NUMBER_1000DEC2 */ );
2997 // #.##0,00 System country/language dependent
2998 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_NUMBER_SYSTEM
);
2999 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3000 CLOffset
+ ZF_STANDARD
+5 /* NF_NUMBER_SYSTEM */ );
3004 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER
, aLocale
);
3005 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aFormatSeq
.getArray(), aFormatSeq
.getLength() );
3008 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_PERCENT_INT
);
3009 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3010 CLOffset
+ ZF_STANDARD_PERCENT
/* NF_PERCENT_INT */ );
3013 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_PERCENT_DEC2
);
3014 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3015 CLOffset
+ ZF_STANDARD_PERCENT
+1 /* NF_PERCENT_DEC2 */ );
3018 // Currency. NO default standard option! Default is determined of locale
3019 // data default currency and format is generated if needed.
3020 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
, aLocale
);
3021 if (LocaleDataWrapper::areChecksEnabled())
3023 // though no default desired here, test for correctness of locale data
3024 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aFormatSeq
.getArray(), aFormatSeq
.getLength() );
3028 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_CURRENCY_1000INT
);
3029 // Just copy the format, to avoid COW on sequence after each possible reallocation
3030 auto aFormat
= aFormatSeq
[nIdx
];
3031 aFormat
.Default
= false;
3032 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormat
,
3033 CLOffset
+ ZF_STANDARD_CURRENCY
/* NF_CURRENCY_1000INT */ );
3036 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_CURRENCY_1000DEC2
);
3037 aFormat
= aFormatSeq
[nIdx
];
3038 aFormat
.Default
= false;
3039 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormat
,
3040 CLOffset
+ ZF_STANDARD_CURRENCY
+1 /* NF_CURRENCY_1000DEC2 */ );
3042 // #,##0 negative red
3043 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_CURRENCY_1000INT_RED
);
3044 aFormat
= aFormatSeq
[nIdx
];
3045 aFormat
.Default
= false;
3046 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormat
,
3047 CLOffset
+ ZF_STANDARD_CURRENCY
+2 /* NF_CURRENCY_1000INT_RED */ );
3049 // #,##0.00 negative red
3050 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_CURRENCY_1000DEC2_RED
);
3051 aFormat
= aFormatSeq
[nIdx
];
3052 aFormat
.Default
= false;
3053 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormat
,
3054 CLOffset
+ ZF_STANDARD_CURRENCY
+3 /* NF_CURRENCY_1000DEC2_RED */ );
3057 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_CURRENCY_1000DEC2_CCC
);
3058 aFormat
= aFormatSeq
[nIdx
];
3059 aFormat
.Default
= false;
3060 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormat
,
3061 CLOffset
+ ZF_STANDARD_CURRENCY
+4 /* NF_CURRENCY_1000DEC2_CCC */ );
3064 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_CURRENCY_1000DEC2_DASHED
);
3065 aFormat
= aFormatSeq
[nIdx
];
3066 aFormat
.Default
= false;
3067 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormat
,
3068 CLOffset
+ ZF_STANDARD_CURRENCY
+5 /* NF_CURRENCY_1000DEC2_DASHED */ );
3072 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::DATE
, aLocale
);
3073 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aFormatSeq
.getArray(), aFormatSeq
.getLength() );
3076 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYSTEM_SHORT
);
3077 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3078 CLOffset
+ ZF_STANDARD_DATE
/* NF_DATE_SYSTEM_SHORT */ );
3081 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_DEF_NNDDMMMYY
);
3082 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3083 CLOffset
+ ZF_STANDARD_DATE
+1 /* NF_DATE_DEF_NNDDMMMYY */ );
3085 // DD.MM.YY def/System
3086 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_MMYY
);
3087 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3088 CLOffset
+ ZF_STANDARD_DATE
+2 /* NF_DATE_SYS_MMYY */ );
3091 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_DDMMM
);
3092 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3093 CLOffset
+ ZF_STANDARD_DATE
+3 /* NF_DATE_SYS_DDMMM */ );
3096 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_MMMM
);
3097 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3098 CLOffset
+ ZF_STANDARD_DATE
+4 /* NF_DATE_MMMM */ );
3101 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_QQJJ
);
3102 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3103 CLOffset
+ ZF_STANDARD_DATE
+5 /* NF_DATE_QQJJ */ );
3105 // DD.MM.YYYY was DD.MM.[YY]YY
3106 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_DDMMYYYY
);
3107 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3108 CLOffset
+ ZF_STANDARD_DATE
+6 /* NF_DATE_SYS_DDMMYYYY */ );
3110 // DD.MM.YY def/System
3111 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_DDMMYY
);
3112 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3113 CLOffset
+ ZF_STANDARD_DATE
+7 /* NF_DATE_SYS_DDMMYY */ );
3115 // NNN, D. MMMM YYYY System
3116 // Long day of week: "NNNN" instead of "NNN," because of compatibility
3117 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYSTEM_LONG
);
3118 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3119 CLOffset
+ ZF_STANDARD_DATE
+8 /* NF_DATE_SYSTEM_LONG */ );
3121 // Hard coded but system (regional settings) delimiters dependent long date formats
3123 // D. MMM YY def/System
3124 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_DMMMYY
);
3125 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3126 CLOffset
+ ZF_STANDARD_DATE
+9 /* NF_DATE_SYS_DMMMYY */ );
3128 // D. MMM YYYY def/System
3129 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_DMMMYYYY
);
3130 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3131 CLOffset
+ ZF_STANDARD_DATE_SYS_DMMMYYYY
/* NF_DATE_SYS_DMMMYYYY */ );
3133 // D. MMMM YYYY def/System
3134 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_DMMMMYYYY
);
3135 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3136 CLOffset
+ ZF_STANDARD_DATE_SYS_DMMMMYYYY
/* NF_DATE_SYS_DMMMMYYYY */ );
3138 // NN, D. MMM YY def/System
3139 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_NNDMMMYY
);
3140 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3141 CLOffset
+ ZF_STANDARD_DATE_SYS_NNDMMMYY
/* NF_DATE_SYS_NNDMMMYY */ );
3143 // NN, D. MMMM YYYY def/System
3144 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_NNDMMMMYYYY
);
3145 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3146 CLOffset
+ ZF_STANDARD_DATE_SYS_NNDMMMMYYYY
/* NF_DATE_SYS_NNDMMMMYYYY */ );
3148 // NNN, D. MMMM YYYY def/System
3149 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_SYS_NNNNDMMMMYYYY
);
3150 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3151 CLOffset
+ ZF_STANDARD_DATE_SYS_NNNNDMMMMYYYY
/* NF_DATE_SYS_NNNNDMMMMYYYY */ );
3153 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
3155 // D. MMM. YYYY DIN/EN
3156 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_DIN_DMMMYYYY
);
3157 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3158 CLOffset
+ ZF_STANDARD_DATE_DIN_DMMMYYYY
/* NF_DATE_DIN_DMMMYYYY */ );
3160 // D. MMMM YYYY DIN/EN
3161 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_DIN_DMMMMYYYY
);
3162 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3163 CLOffset
+ ZF_STANDARD_DATE_DIN_DMMMMYYYY
/* NF_DATE_DIN_DMMMMYYYY */ );
3166 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_DIN_MMDD
);
3167 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3168 CLOffset
+ ZF_STANDARD_DATE_DIN_MMDD
/* NF_DATE_DIN_MMDD */ );
3171 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_DIN_YYMMDD
);
3172 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3173 CLOffset
+ ZF_STANDARD_DATE_DIN_YYMMDD
/* NF_DATE_DIN_YYMMDD */ );
3175 // YYYY-MM-DD DIN/EN/ISO
3176 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATE_DIN_YYYYMMDD
);
3177 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3178 CLOffset
+ ZF_STANDARD_DATE_DIN_YYYYMMDD
/* NF_DATE_DIN_YYYYMMDD */ );
3182 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::TIME
, aLocale
);
3183 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aFormatSeq
.getArray(), aFormatSeq
.getLength() );
3186 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_TIME_HHMM
);
3187 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3188 CLOffset
+ ZF_STANDARD_TIME
/* NF_TIME_HHMM */ );
3191 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_TIME_HHMMSS
);
3192 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3193 CLOffset
+ ZF_STANDARD_TIME
+1 /* NF_TIME_HHMMSS */ );
3196 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_TIME_HHMMAMPM
);
3197 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3198 CLOffset
+ ZF_STANDARD_TIME
+2 /* NF_TIME_HHMMAMPM */ );
3201 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_TIME_HHMMSSAMPM
);
3202 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3203 CLOffset
+ ZF_STANDARD_TIME
+3 /* NF_TIME_HHMMSSAMPM */ );
3206 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_TIME_HH_MMSS
);
3207 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3208 CLOffset
+ ZF_STANDARD_TIME
+4 /* NF_TIME_HH_MMSS */ );
3211 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_TIME_MMSS00
);
3212 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3213 CLOffset
+ ZF_STANDARD_TIME
+5 /* NF_TIME_MMSS00 */ );
3216 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_TIME_HH_MMSS00
);
3217 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3218 CLOffset
+ ZF_STANDARD_TIME
+6 /* NF_TIME_HH_MMSS00 */ );
3222 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME
, aLocale
);
3223 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aFormatSeq
.getArray(), aFormatSeq
.getLength() );
3225 // DD.MM.YY HH:MM System
3226 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATETIME_SYSTEM_SHORT_HHMM
);
3227 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3228 CLOffset
+ ZF_STANDARD_DATETIME
/* NF_DATETIME_SYSTEM_SHORT_HHMM */ );
3230 // DD.MM.YYYY HH:MM:SS System
3231 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
3232 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3233 CLOffset
+ ZF_STANDARD_DATETIME
+1 /* NF_DATETIME_SYS_DDMMYYYY_HHMMSS */ );
3235 // DD.MM.YYYY HH:MM System
3236 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_DATETIME_SYS_DDMMYYYY_HHMM
);
3237 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3238 CLOffset
+ ZF_STANDARD_DATETIME
+2 /* NF_DATETIME_SYS_DDMMYYYY_HHMM */ );
3240 const NfKeywordTable
& rKeyword
= rCurrentLanguage
.pFormatScanner
->GetKeywords();
3241 i18n::NumberFormatCode aSingleFormatCode
;
3242 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::DATE_TIME
;
3244 // YYYY-MM-DD HH:MM:SS ISO (with blank instead of 'T')
3245 aSingleFormatCode
.Code
=
3246 rKeyword
[NF_KEY_YYYY
] + "-" +
3247 rKeyword
[NF_KEY_MM
] + "-" +
3248 rKeyword
[NF_KEY_DD
] + " " +
3249 rKeyword
[NF_KEY_HH
] + ":" +
3250 rKeyword
[NF_KEY_MMI
] + ":" +
3251 rKeyword
[NF_KEY_SS
];
3252 SvNumberformat
* pFormat
= ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3253 CLOffset
+ ZF_STANDARD_DATETIME
+3 /* NF_DATETIME_ISO_YYYYMMDD_HHMMSS */ );
3256 // YYYY-MM-DD HH:MM:SS,000 ISO (with blank instead of 'T') and
3257 // milliseconds and locale's time decimal separator
3258 aSingleFormatCode
.Code
=
3259 rKeyword
[NF_KEY_YYYY
] + "-" +
3260 rKeyword
[NF_KEY_MM
] + "-" +
3261 rKeyword
[NF_KEY_DD
] + " " +
3262 rKeyword
[NF_KEY_HH
] + ":" +
3263 rKeyword
[NF_KEY_MMI
] + ":" +
3264 rKeyword
[NF_KEY_SS
] + rCurrentLanguage
.GetLocaleData()->getTime100SecSep() +
3266 pFormat
= ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3267 CLOffset
+ ZF_STANDARD_DATETIME
+4 /* NF_DATETIME_ISO_YYYYMMDD_HHMMSS000 */ );
3270 // YYYY-MM-DD"T"HH:MM:SS ISO
3271 aSingleFormatCode
.Code
=
3272 rKeyword
[NF_KEY_YYYY
] + "-" +
3273 rKeyword
[NF_KEY_MM
] + "-" +
3274 rKeyword
[NF_KEY_DD
] + "\"T\"" +
3275 rKeyword
[NF_KEY_HH
] + ":" +
3276 rKeyword
[NF_KEY_MMI
] + ":" +
3277 rKeyword
[NF_KEY_SS
];
3278 pFormat
= ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3279 CLOffset
+ ZF_STANDARD_DATETIME
+5 /* NF_DATETIME_ISO_YYYYMMDDTHHMMSS */ );
3281 pFormat
->SetComment("ISO 8601"); // not to be localized
3283 // YYYY-MM-DD"T"HH:MM:SS,000 ISO with milliseconds and ',' or '.' decimal separator
3284 aSingleFormatCode
.Code
=
3285 rKeyword
[NF_KEY_YYYY
] + "-" +
3286 rKeyword
[NF_KEY_MM
] + "-" +
3287 rKeyword
[NF_KEY_DD
] + "\"T\"" +
3288 rKeyword
[NF_KEY_HH
] + ":" +
3289 rKeyword
[NF_KEY_MMI
] + ":" +
3290 rKeyword
[NF_KEY_SS
] + (rCurrentLanguage
.GetLocaleData()->getTime100SecSep() == "." ? "." : ",") +
3292 pFormat
= ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3293 CLOffset
+ ZF_STANDARD_DATETIME
+6 /* NF_DATETIME_ISO_YYYYMMDDTHHMMSS000 */ );
3295 pFormat
->SetComment("ISO 8601"); // not to be localized
3298 // Scientific number
3299 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER
, aLocale
);
3300 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aFormatSeq
.getArray(), aFormatSeq
.getLength() );
3303 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_SCIENTIFIC_000E000
);
3304 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3305 CLOffset
+ ZF_STANDARD_SCIENTIFIC
/* NF_SCIENTIFIC_000E000 */ );
3308 nIdx
= ImpGetFormatCodeIndex(rCurrentLanguage
, aFormatSeq
, NF_SCIENTIFIC_000E00
);
3309 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aFormatSeq
[nIdx
],
3310 CLOffset
+ ZF_STANDARD_SCIENTIFIC
+1 /* NF_SCIENTIFIC_000E00 */ );
3313 // Fraction number (no default option)
3314 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::FRACTION_NUMBER
;
3317 aSingleFormatCode
.Code
= "# ?/?";
3318 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3319 CLOffset
+ ZF_STANDARD_FRACTION
/* NF_FRACTION_1D */ );
3322 //! "??/" would be interpreted by the compiler as a trigraph for '\'
3323 aSingleFormatCode
.Code
= "# ?\?/?\?";
3324 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3325 CLOffset
+ ZF_STANDARD_FRACTION
+1 /* NF_FRACTION_2D */ );
3328 //! "??/" would be interpreted by the compiler as a trigraph for '\'
3329 aSingleFormatCode
.Code
= "# ?\?\?/?\?\?";
3330 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3331 CLOffset
+ ZF_STANDARD_FRACTION
+2 /* NF_FRACTION_3D */ );
3334 aSingleFormatCode
.Code
= "# ?/2";
3335 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3336 CLOffset
+ ZF_STANDARD_FRACTION
+3 /* NF_FRACTION_2 */ );
3339 aSingleFormatCode
.Code
= "# ?/4";
3340 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3341 CLOffset
+ ZF_STANDARD_FRACTION
+4 /* NF_FRACTION_4 */ );
3344 aSingleFormatCode
.Code
= "# ?/8";
3345 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3346 CLOffset
+ ZF_STANDARD_FRACTION
+5 /* NF_FRACTION_8 */ );
3349 aSingleFormatCode
.Code
= "# ?\?/16";
3350 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3351 CLOffset
+ ZF_STANDARD_FRACTION
+6 /* NF_FRACTION_16 */ );
3354 aSingleFormatCode
.Code
= "# ?\?/10";
3355 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3356 CLOffset
+ ZF_STANDARD_FRACTION
+7 /* NF_FRACTION_10 */ );
3359 aSingleFormatCode
.Code
= "# ?\?/100";
3360 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3361 CLOffset
+ ZF_STANDARD_FRACTION
+8 /* NF_FRACTION_100 */ );
3365 aSingleFormatCode
.Code
= rKeyword
[NF_KEY_WW
];
3366 ImpInsertFormat(rCurrentLanguage
, rNatNum
, aSingleFormatCode
,
3367 CLOffset
+ ZF_STANDARD_DATE_WW
/* NF_DATE_WW */ );
3369 // Now all additional format codes provided by I18N, but only if not
3370 // changing SystemCL, then they are appended last after user defined.
3371 if ( !bNoAdditionalFormats
)
3373 ImpGenerateAdditionalFormats(rCurrentLanguage
, rNatNum
, CLOffset
, xNFC
, false);
3375 if (bOldConvertMode
)
3377 rCurrentLanguage
.pFormatScanner
->SetConvertMode(true);
3381 void SvNFFormatData::ImpGenerateAdditionalFormats(SvNFLanguageData
& rCurrentLanguage
,
3382 const NativeNumberWrapper
& rNatNum
, sal_uInt32 CLOffset
,
3383 css::uno::Reference
< css::i18n::XNumberFormatCode
> const & rNumberFormatCode
,
3384 bool bAfterChangingSystemCL
)
3386 SvNumberformat
* pStdFormat
= GetFormatEntry( CLOffset
+ ZF_STANDARD
);
3389 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
3392 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
3393 css::lang::Locale aLocale
= rCurrentLanguage
.GetLanguageTag().getLocale();
3395 // All currencies, this time with [$...] which was stripped in
3396 // ImpGenerateFormats for old "automatic" currency formats.
3397 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
= rNumberFormatCode
->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
, aLocale
);
3398 sal_Int32 nCodes
= aFormatSeq
.getLength();
3399 auto aNonConstRange
= asNonConstRange(aFormatSeq
);
3400 ImpAdjustFormatCodeDefault(rCurrentLanguage
, aNonConstRange
.begin(), nCodes
);
3401 for ( i18n::NumberFormatCode
& rFormat
: aNonConstRange
)
3403 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3405 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
3408 if ( rFormat
.Index
< NF_INDEX_TABLE_RESERVED_START
&&
3409 rFormat
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
3410 { // Insert only if not already inserted, but internal index must be
3411 // above so ImpInsertFormat can distinguish it.
3412 sal_Int16 nOrgIndex
= rFormat
.Index
;
3413 rFormat
.Index
= sal::static_int_cast
< sal_Int16
>(
3414 rFormat
.Index
+ nCodes
+ NF_INDEX_TABLE_ENTRIES
);
3415 //! no default on currency
3416 bool bDefault
= rFormat
.Default
;
3417 rFormat
.Default
= false;
3418 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat(rCurrentLanguage
, rNatNum
, rFormat
, nPos
+1,
3419 bAfterChangingSystemCL
, nOrgIndex
) )
3421 pNewFormat
->SetAdditionalBuiltin();
3424 rFormat
.Index
= nOrgIndex
;
3425 rFormat
.Default
= bDefault
;
3429 // All additional format codes provided by I18N that are not old standard
3430 // index. Additional formats may define defaults, currently there is no
3431 // check if more than one default of a usage/type combination is provided,
3432 // like it is done for usage groups with ImpAdjustFormatCodeDefault().
3433 // There is no harm though, on first invocation ImpGetDefaultFormat() will
3434 // use the first default encountered.
3435 aFormatSeq
= rNumberFormatCode
->getAllFormatCodes( aLocale
);
3436 for ( const auto& rFormat
: std::as_const(aFormatSeq
) )
3438 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3440 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
3443 if ( rFormat
.Index
>= NF_INDEX_TABLE_RESERVED_START
)
3445 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat(rCurrentLanguage
, rNatNum
, rFormat
, nPos
+1,
3446 bAfterChangingSystemCL
) )
3448 pNewFormat
->SetAdditionalBuiltin();
3454 pStdFormat
->SetLastInsertKey( static_cast<sal_uInt16
>(nPos
- CLOffset
), SvNumberformat::FormatterPrivateAccess() );
3457 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset
,
3458 css::uno::Reference
< css::i18n::XNumberFormatCode
> const & rNumberFormatCode
)
3460 m_aFormatData
.ImpGenerateAdditionalFormats(m_aCurrentLanguage
, GetNatNum(), CLOffset
, rNumberFormatCode
, /*bAfterChangingSystemCL*/true);
3465 // return position of a special character
3466 sal_Int32
ImpPosToken(const OUStringBuffer
& sFormat
, sal_Unicode token
, sal_Int32 nStartPos
= 0)
3468 sal_Int32 nLength
= sFormat
.getLength();
3469 for ( sal_Int32 i
=nStartPos
; i
<nLength
&& i
>=0 ; i
++ )
3473 case '\"' : // skip text
3474 i
= sFormat
.indexOf('\"',i
+1);
3476 case '[' : // skip condition
3477 i
= sFormat
.indexOf(']',i
+1);
3479 case '\\' : // skip escaped character
3489 return i
; // if 'E' is outside "" and [] it must be the 'E' exponent
3501 OUString
SvNFEngine::GenerateFormat(SvNFLanguageData
& rCurrentLanguage
,
3502 const SvNFFormatData
& rFormatData
,
3503 const NativeNumberWrapper
& rNatNum
, const Accessor
& rFuncs
,
3508 sal_uInt16 nPrecision
,
3509 sal_uInt16 nLeadingZeros
)
3511 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
3512 const SvNumberformat
* pFormat
= rFormatData
.GetFormatEntry( nIndex
);
3513 const SvNumFormatType eType
= (pFormat
? pFormat
->GetMaskedType() : SvNumFormatType::UNDEFINED
);
3515 rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary (and allowed)
3517 utl::DigitGroupingIterator
aGrouping( rCurrentLanguage
.xLocaleData
->getDigitGrouping());
3518 // always group of 3 for Engineering notation
3519 const sal_Int32 nDigitsInFirstGroup
= ( bThousand
&& (eType
== SvNumFormatType::SCIENTIFIC
) ) ? 3 : aGrouping
.get();
3520 const OUString
& rThSep
= rCurrentLanguage
.GetNumThousandSep();
3522 OUStringBuffer sString
;
3523 using comphelper::string::padToLength
;
3525 if (eType
& SvNumFormatType::TIME
)
3527 assert(pFormat
&& "with !pFormat eType can only be SvNumFormatType::UNDEFINED");
3528 sString
= pFormat
->GetFormatStringForTimePrecision( nPrecision
);
3530 else if (nLeadingZeros
== 0)
3533 sString
.append('#');
3536 if (eType
== SvNumFormatType::SCIENTIFIC
)
3537 { // for scientific, bThousand is used for Engineering notation
3538 sString
.append("###");
3542 sString
.append("#" + rThSep
);
3543 padToLength(sString
, sString
.getLength() + nDigitsInFirstGroup
, '#');
3549 for (sal_uInt16 i
= 0; i
< nLeadingZeros
; i
++)
3551 if (bThousand
&& i
> 0 && i
== aGrouping
.getPos())
3553 sString
.insert(0, rThSep
);
3554 aGrouping
.advance();
3556 sString
.insert(0, '0');
3560 sal_Int32 nDigits
= (eType
== SvNumFormatType::SCIENTIFIC
) ? 3*((nLeadingZeros
-1)/3 + 1) : nDigitsInFirstGroup
+ 1;
3561 for (sal_Int32 i
= nLeadingZeros
; i
< nDigits
; i
++)
3563 if ( i
% nDigitsInFirstGroup
== 0 )
3564 sString
.insert(0, rThSep
);
3565 sString
.insert(0, '#');
3569 if (nPrecision
> 0 && eType
!= SvNumFormatType::FRACTION
&& !( eType
& SvNumFormatType::TIME
) )
3571 sString
.append(rCurrentLanguage
.GetNumDecimalSep());
3572 padToLength(sString
, sString
.getLength() + nPrecision
, '0');
3576 const OUString sPosNatNumModifier
= pFormat
? pFormat
->GetNatNumModifierString( 0 ) : "";
3577 const OUString sNegNatNumModifier
= pFormat
?
3578 // if a negative format already exists, use its NatNum modifier
3579 // else use NatNum modifier of positive format
3580 ( pFormat
->GetNumForString( 1, 0 ) ? pFormat
->GetNatNumModifierString( 1 ) : sPosNatNumModifier
)
3583 if (eType
== SvNumFormatType::PERCENT
)
3585 sString
.append( pFormat
->GetPercentString() );
3587 else if (eType
== SvNumFormatType::SCIENTIFIC
)
3589 OUStringBuffer
sOldFormatString(pFormat
->GetFormatstring());
3590 sal_Int32 nIndexE
= ImpPosToken( sOldFormatString
, 'E' );
3593 sal_Int32 nIndexSep
= ImpPosToken( sOldFormatString
, ';', nIndexE
);
3594 if (nIndexSep
> nIndexE
)
3595 sString
.append( sOldFormatString
.subView(nIndexE
, nIndexSep
- nIndexE
) );
3597 sString
.append( sOldFormatString
.subView(nIndexE
) );
3600 else if (eType
== SvNumFormatType::CURRENCY
)
3602 OUStringBuffer
sNegStr(sString
);
3604 const NfCurrencyEntry
* pEntry
;
3606 bool isPosNatNum12
= sPosNatNumModifier
.startsWith( "[NatNum12" );
3607 bool isNegNatNum12
= sNegNatNumModifier
.startsWith( "[NatNum12" );
3608 if ( !isPosNatNum12
|| !isNegNatNum12
)
3610 if (rFormatData
.GetNewCurrencySymbolString(nIndex
, aCurr
, &pEntry
, &bBank
))
3614 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
3615 rCurrentLanguage
.xLocaleData
->getCurrPositiveFormat(),
3616 pEntry
->GetPositiveFormat(), bBank
);
3617 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
3618 rCurrentLanguage
.xLocaleData
->getCurrNegativeFormat(),
3619 pEntry
->GetNegativeFormat(), bBank
);
3620 if ( !isPosNatNum12
)
3621 pEntry
->CompletePositiveFormatString( sString
, bBank
, nPosiForm
);
3622 if ( !isNegNatNum12
)
3623 pEntry
->CompleteNegativeFormatString( sNegStr
, bBank
, nNegaForm
);
3626 { // assume currency abbreviation (AKA banking symbol), not symbol
3627 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
3628 rCurrentLanguage
.xLocaleData
->getCurrPositiveFormat(),
3629 rCurrentLanguage
.xLocaleData
->getCurrPositiveFormat(), true );
3630 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
3631 rCurrentLanguage
.xLocaleData
->getCurrNegativeFormat(),
3632 rCurrentLanguage
.xLocaleData
->getCurrNegativeFormat(), true );
3633 if ( !isPosNatNum12
)
3634 NfCurrencyEntry::CompletePositiveFormatString( sString
, aCurr
, nPosiForm
);
3635 if ( !isNegNatNum12
)
3636 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
, aCurr
, nNegaForm
);
3640 { // "automatic" old style
3641 OUString aSymbol
, aAbbrev
;
3642 rCurrentLanguage
.GetCompatibilityCurrency(aSymbol
, aAbbrev
);
3643 if ( !isPosNatNum12
)
3644 NfCurrencyEntry::CompletePositiveFormatString( sString
,
3645 aSymbol
, rCurrentLanguage
.xLocaleData
->getCurrPositiveFormat() );
3646 if ( !isNegNatNum12
)
3647 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
,
3648 aSymbol
, rCurrentLanguage
.xLocaleData
->getCurrNegativeFormat() );
3651 sString
.append( ';' );
3654 sString
.append("[" + rCurrentLanguage
.pFormatScanner
->GetRedString() + "]");
3656 sString
.append( sNegNatNumModifier
);
3657 if ( isNegNatNum12
)
3659 sString
.append( '-' );
3661 sString
.append(sNegStr
);
3663 else if (eType
== SvNumFormatType::FRACTION
)
3665 OUString aIntegerFractionDelimiterString
= pFormat
->GetIntegerFractionDelimiterString( 0 );
3666 if ( aIntegerFractionDelimiterString
== " " )
3667 sString
.append( aIntegerFractionDelimiterString
);
3670 sString
.append( "\"" + aIntegerFractionDelimiterString
+ "\"" );
3672 sString
.append( pFormat
->GetNumeratorString( 0 )
3674 if ( nPrecision
> 0 )
3675 padToLength(sString
, sString
.getLength() + nPrecision
, '?');
3677 sString
.append( '#' );
3679 if (eType
!= SvNumFormatType::CURRENCY
)
3681 bool insertBrackets
= false;
3682 if ( eType
!= SvNumFormatType::UNDEFINED
)
3684 insertBrackets
= pFormat
->IsNegativeInBracket();
3686 if (IsRed
|| insertBrackets
)
3688 OUStringBuffer
sTmpStr(sString
);
3690 if (pFormat
&& pFormat
->HasPositiveBracketPlaceholder())
3692 sTmpStr
.append("_)");
3694 sTmpStr
.append(';');
3698 sTmpStr
.append("[" + rCurrentLanguage
.pFormatScanner
->GetRedString() + "]");
3700 sTmpStr
.append( sNegNatNumModifier
);
3704 sTmpStr
.append("(" + sString
+ ")");
3708 sTmpStr
.append("-" + sString
);
3713 sString
.insert( 0, sPosNatNumModifier
);
3714 return sString
.makeStringAndClear();
3717 OUString
SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex
,
3721 sal_uInt16 nPrecision
,
3722 sal_uInt16 nLeadingZeros
)
3724 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3725 return SvNFEngine::GenerateFormat(m_aCurrentLanguage
, m_aFormatData
,
3726 GetNatNum(), m_aRWPolicy
,
3729 nPrecision
, nLeadingZeros
);
3732 bool SvNumberFormatter::IsUserDefined(sal_uInt32 F_Index
) const
3734 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3735 const SvNumberformat
* pFormat
= m_aFormatData
.GetFormatEntry(F_Index
);
3737 return pFormat
&& (pFormat
->GetType() & SvNumFormatType::DEFINED
);
3740 bool SvNumberFormatter::IsUserDefined(std::u16string_view sStr
,
3743 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3744 if (eLnge
== LANGUAGE_DONTKNOW
)
3748 sal_uInt32 CLOffset
= m_aFormatData
.ImpGenerateCL(m_aCurrentLanguage
, GetNatNum(), eLnge
); // create new standard formats if necessary
3749 eLnge
= m_aCurrentLanguage
.ActLnge
;
3751 sal_uInt32 nKey
= ImpIsEntry(sStr
, CLOffset
, eLnge
);
3752 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3756 SvNumberformat
* pEntry
= m_aFormatData
.GetFormatEntry( nKey
);
3757 return pEntry
&& (pEntry
->GetType() & SvNumFormatType::DEFINED
);
3760 sal_uInt32
SvNumberFormatter::GetEntryKey(std::u16string_view sStr
,
3763 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3764 if (eLnge
== LANGUAGE_DONTKNOW
)
3768 sal_uInt32 CLOffset
= m_aFormatData
.ImpGenerateCL(m_aCurrentLanguage
, GetNatNum(), eLnge
); // create new standard formats if necessary
3769 return ImpIsEntry(sStr
, CLOffset
, eLnge
);
3772 sal_uInt32
SvNFEngine::GetStandardIndex(SvNFLanguageData
& rCurrentLanguage
,
3773 const SvNFFormatData
& rFormatData
,
3774 const NativeNumberWrapper
& rNatNum
,
3775 const Accessor
& rFuncs
,
3778 return SvNFEngine::GetStandardFormat(rCurrentLanguage
, rFormatData
,
3780 SvNumFormatType::NUMBER
, eLnge
);
3783 sal_uInt32
SvNumberFormatter::GetStandardIndex(LanguageType eLnge
)
3785 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3786 return SvNFEngine::GetStandardIndex(m_aCurrentLanguage
, m_aFormatData
, GetNatNum(),
3787 m_aRWPolicy
, eLnge
);
3790 SvNumFormatType
SvNumberFormatter::GetType(sal_uInt32 nFIndex
) const
3792 ::osl::MutexGuard
aGuard(GetInstanceMutex());
3793 return m_aFormatData
.GetType(nFIndex
);
3796 void SvNumberFormatter::ClearMergeTable()
3798 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3801 pMergeTable
->clear();
3805 SvNumberFormatterIndexTable
* SvNumberFormatter::MergeFormatter(SvNumberFormatter
& rTable
)
3807 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3814 pMergeTable
.reset( new SvNumberFormatterIndexTable
);
3817 sal_uInt32 nCLOffset
= 0;
3818 sal_uInt32 nOldKey
, nOffset
, nNewKey
;
3820 for (const auto& rEntry
: rTable
.m_aFormatData
.aFTable
)
3822 SvNumberformat
* pFormat
= rEntry
.second
.get();
3823 nOldKey
= rEntry
.first
;
3824 nOffset
= nOldKey
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3825 if (nOffset
== 0) // 1st format of CL
3827 nCLOffset
= m_aFormatData
.ImpGenerateCL(m_aCurrentLanguage
, GetNatNum(), pFormat
->GetLanguage());
3829 if (nOffset
<= SV_MAX_COUNT_STANDARD_FORMATS
) // Std.form.
3831 nNewKey
= nCLOffset
+ nOffset
;
3832 if (m_aFormatData
.aFTable
.find( nNewKey
) == m_aFormatData
.aFTable
.end()) // not already present
3834 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( *pFormat
, *m_aCurrentLanguage
.pFormatScanner
));
3835 if (!m_aFormatData
.aFTable
.emplace( nNewKey
, std::move(pNewEntry
)).second
)
3837 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3840 if (nNewKey
!= nOldKey
) // new index
3842 (*pMergeTable
)[nOldKey
] = nNewKey
;
3845 else // user defined
3847 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( *pFormat
, *m_aCurrentLanguage
.pFormatScanner
));
3848 nNewKey
= ImpIsEntry(pNewEntry
->GetFormatstring(),
3850 pFormat
->GetLanguage());
3851 if (nNewKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
) // only if not present yet
3853 SvNumberformat
* pStdFormat
= m_aFormatData
.GetFormatEntry(nCLOffset
+ ZF_STANDARD
);
3854 sal_uInt32 nPos
= nCLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
3856 if (nNewKey
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3858 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3860 else if (!m_aFormatData
.aFTable
.emplace( nNewKey
, std::move(pNewEntry
)).second
)
3862 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3866 pStdFormat
->SetLastInsertKey(static_cast<sal_uInt16
>(nNewKey
- nCLOffset
),
3867 SvNumberformat::FormatterPrivateAccess());
3870 if (nNewKey
!= nOldKey
) // new index
3872 (*pMergeTable
)[nOldKey
] = nNewKey
;
3876 return pMergeTable
.get();
3880 SvNumberFormatterMergeMap
SvNumberFormatter::ConvertMergeTableToMap()
3882 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3883 if (!HasMergeFormatTable())
3885 return SvNumberFormatterMergeMap();
3887 SvNumberFormatterMergeMap aMap
;
3888 for (const auto& rEntry
: *pMergeTable
)
3890 sal_uInt32 nOldKey
= rEntry
.first
;
3891 aMap
[ nOldKey
] = rEntry
.second
;
3899 bool IsFormatSimpleBuiltIn(const SvNFLanguageData
& rCurrentLanguage
, sal_uInt32 nFormat
, LanguageType eLnge
)
3901 if (nFormat
< SV_COUNTRY_LANGUAGE_OFFSET
&& eLnge
== rCurrentLanguage
.GetIniLanguage())
3902 return true; // it stays as it is
3904 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3905 if (nOffset
> SV_MAX_COUNT_STANDARD_FORMATS
)
3906 return true; // not a built-in format
3912 sal_uInt32
SvNFEngine::GetCLOffsetRO(const SvNFFormatData
& rFormatData
, SvNFLanguageData
&, const NativeNumberWrapper
&, LanguageType eLnge
)
3914 sal_uInt32 nCLOffset
= rFormatData
.ImpGetCLOffset(eLnge
);
3915 assert(nCLOffset
<= rFormatData
.MaxCLOffset
&& "Language must have already been encountered");
3919 // we can't cache to SvNFFormatData in RO mode, so cache to a per-thread temp map which we can consult in FindFormatRO
3920 // caches can be merged with SvNumberFormatter::MergeDefaultFormatKeys
3921 void SvNFEngine::CacheFormatRO(SvNFFormatData::DefaultFormatKeysMap
& rFormatCache
, sal_uInt32 nSearch
, sal_uInt32 nFormat
)
3923 rFormatCache
[nSearch
] = nFormat
;
3926 sal_uInt32
SvNFEngine::FindFormatRO(const SvNFFormatData
& rFormatData
, const SvNFFormatData::DefaultFormatKeysMap
& rFormatCache
, sal_uInt32 nSearch
)
3928 sal_uInt32 nFormat
= rFormatData
.FindCachedDefaultFormat(nSearch
);
3929 if (nFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
3931 return ::FindCachedDefaultFormat(rFormatCache
, nSearch
);
3934 sal_uInt32
SvNFEngine::GetCLOffsetRW(SvNFFormatData
& rFormatData
, SvNFLanguageData
& rCurrentLanguage
, const NativeNumberWrapper
& rNatNum
, LanguageType eLnge
)
3936 return rFormatData
.ImpGenerateCL(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary
3939 void SvNFEngine::CacheFormatRW(SvNFFormatData
& rFormatData
, sal_uInt32 nSearch
, sal_uInt32 nFormat
)
3941 rFormatData
.aDefaultFormatKeys
[nSearch
] = nFormat
;
3944 sal_uInt32
SvNFEngine::FindFormatRW(const SvNFFormatData
& rFormatData
, sal_uInt32 nSearch
)
3946 return rFormatData
.FindCachedDefaultFormat(nSearch
);
3949 sal_uInt32
SvNFEngine::DefaultCurrencyRW(SvNFFormatData
& rFormatData
, SvNFLanguageData
& rCurrentLanguage
, const NativeNumberWrapper
& rNatNum
, sal_uInt32 CLOffset
, LanguageType eLnge
)
3951 if (eLnge
== LANGUAGE_SYSTEM
)
3952 return rFormatData
.ImpGetDefaultSystemCurrencyFormat(rCurrentLanguage
, rNatNum
);
3953 return rFormatData
.ImpGetDefaultCurrencyFormat(rCurrentLanguage
, rNatNum
, CLOffset
, eLnge
);
3956 sal_uInt32
SvNFEngine::DefaultCurrencyRO(const SvNFFormatData
& rFormatData
, SvNFLanguageData
&, const NativeNumberWrapper
&, sal_uInt32 CLOffset
, LanguageType eLnge
)
3958 if (eLnge
== LANGUAGE_SYSTEM
)
3960 assert(rFormatData
.nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
3961 return rFormatData
.nDefaultSystemCurrencyFormat
;
3964 SvNFFormatData::DefaultFormatKeysMap::const_iterator it
= rFormatData
.aDefaultFormatKeys
.find(CLOffset
+ ZF_STANDARD_CURRENCY
);
3965 assert(it
!= rFormatData
.aDefaultFormatKeys
.end() && it
->second
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
3969 SvNFEngine::Accessor
SvNFEngine::GetRWPolicy(SvNFFormatData
& rFormatData
)
3973 std::bind(SvNFEngine::GetCLOffsetRW
, std::ref(rFormatData
), std::placeholders::_1
, std::placeholders::_2
, std::placeholders::_3
),
3974 std::bind(SvNFEngine::CacheFormatRW
, std::ref(rFormatData
), std::placeholders::_1
, std::placeholders::_2
),
3975 std::bind(SvNFEngine::FindFormatRW
, std::ref(rFormatData
), std::placeholders::_1
),
3976 std::bind(SvNFEngine::DefaultCurrencyRW
, std::ref(rFormatData
), std::placeholders::_1
, std::placeholders::_2
, std::placeholders::_3
, std::placeholders::_4
)
3980 void SvNumberFormatter::PrepForRoMode()
3982 SvNumberFormatter::GetTheCurrencyTable(); // create this now so threads don't attempt to create it simultaneously
3983 if (m_aFormatData
.nDefaultSystemCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3985 m_aFormatData
.ImpGetDefaultSystemCurrencyFormat(m_aCurrentLanguage
, GetNatNum());
3986 assert(m_aFormatData
.nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
3990 SvNFEngine::Accessor
SvNFEngine::GetROPolicy(const SvNFFormatData
& rFormatData
, SvNFFormatData::DefaultFormatKeysMap
& rFormatCache
)
3992 assert(rFormatData
.nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
&& "ensure PrepForRoMode is called");
3993 assert(g_CurrencyTableInitialized
&& "ensure PrepForRoMode is called");
3996 std::bind(SvNFEngine::GetCLOffsetRO
, std::ref(rFormatData
), std::placeholders::_1
, std::placeholders::_2
, std::placeholders::_3
),
3997 std::bind(SvNFEngine::CacheFormatRO
, std::ref(rFormatCache
), std::placeholders::_1
, std::placeholders::_2
),
3998 std::bind(SvNFEngine::FindFormatRO
, std::ref(rFormatData
), std::ref(rFormatCache
), std::placeholders::_1
),
3999 std::bind(SvNFEngine::DefaultCurrencyRO
, std::ref(rFormatData
), std::placeholders::_1
, std::placeholders::_2
, std::placeholders::_3
, std::placeholders::_4
)
4003 sal_uInt32
SvNFEngine::GetFormatForLanguageIfBuiltIn(SvNFLanguageData
& rCurrentLanguage
,
4004 const NativeNumberWrapper
& rNatNum
,
4005 const Accessor
& rFuncs
,
4006 sal_uInt32 nFormat
, LanguageType eLnge
)
4008 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
4010 if (IsFormatSimpleBuiltIn(rCurrentLanguage
, nFormat
, eLnge
))
4013 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
);
4014 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
4015 return nCLOffset
+ nOffset
;
4018 sal_uInt32
SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat
,
4019 LanguageType eLnge
)
4021 ::osl::MutexGuard
aGuard(GetInstanceMutex());
4022 return SvNFEngine::GetFormatForLanguageIfBuiltIn(m_aCurrentLanguage
, GetNatNum(), m_aRWPolicy
, nFormat
, eLnge
);
4025 LanguageType
SvNFLanguageData::ImpResolveLanguage(LanguageType eLnge
) const
4027 return eLnge
== LANGUAGE_DONTKNOW
? IniLnge
: eLnge
;
4030 sal_uInt32
SvNFEngine::GetFormatIndex(SvNFLanguageData
& rCurrentLanguage
, const Accessor
& rFuncs
,
4031 const NativeNumberWrapper
& rNatNum
, NfIndexTableOffset nTabOff
,
4034 eLnge
= rCurrentLanguage
.ImpResolveLanguage(eLnge
);
4036 sal_uInt32 nCLOffset
= rFuncs
.mGetCLOffset(rCurrentLanguage
, rNatNum
, eLnge
); // create new standard formats if necessary (and allowed)
4038 return ImpGetFormatIndex(nTabOff
, nCLOffset
);
4041 sal_uInt32
SvNumberFormatter::GetFormatIndex(NfIndexTableOffset nTabOff
, LanguageType eLnge
)
4043 ::osl::MutexGuard
aGuard(GetInstanceMutex());
4044 return SvNFEngine::GetFormatIndex(m_aCurrentLanguage
, m_aRWPolicy
, GetNatNum(), nTabOff
, eLnge
);
4048 NfIndexTableOffset
SvNumberFormatter::GetIndexTableOffset(sal_uInt32 nFormat
)
4050 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
4051 if ( nOffset
> SV_MAX_COUNT_STANDARD_FORMATS
)
4053 return NF_INDEX_TABLE_ENTRIES
; // not a built-in format
4056 for ( sal_uInt16 j
= 0; j
< NF_INDEX_TABLE_ENTRIES
; j
++ )
4058 if (indexTable
[j
] == nOffset
)
4059 return static_cast<NfIndexTableOffset
>(j
);
4061 return NF_INDEX_TABLE_ENTRIES
; // bad luck
4064 void SvNumberFormatter::SetEvalDateFormat( NfEvalDateFormat eEDF
)
4066 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4067 m_aCurrentLanguage
.SetEvalDateFormat(eEDF
);
4070 NfEvalDateFormat
SvNumberFormatter::GetEvalDateFormat() const
4072 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4073 return m_aCurrentLanguage
.GetEvalDateFormat();
4076 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal
)
4078 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4079 m_aCurrentLanguage
.pStringScanner
->SetYear2000( nVal
);
4083 sal_uInt16
SvNumberFormatter::GetYear2000() const
4085 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4086 return m_aCurrentLanguage
.pStringScanner
->GetYear2000();
4089 sal_uInt16
SvNFLanguageData::ExpandTwoDigitYear( sal_uInt16 nYear
) const
4092 return SvNumberFormatter::ExpandTwoDigitYear( nYear
,
4093 pStringScanner
->GetYear2000() );
4097 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
) const
4099 return m_aCurrentLanguage
.ExpandTwoDigitYear(nYear
);
4103 sal_uInt16
SvNumberFormatter::GetYear2000Default()
4105 if (!comphelper::IsFuzzing())
4106 return officecfg::Office::Common::DateFormat::TwoDigitYear::get();
4111 void SvNumberFormatter::resetTheCurrencyTable()
4113 SAL_INFO("svl", "Resetting the currency table.");
4115 nSystemCurrencyPosition
= 0;
4116 g_CurrencyTableInitialized
= false;
4118 GetFormatterRegistry().ConfigurationChanged(nullptr, ConfigurationHints::Locale
| ConfigurationHints::Currency
| ConfigurationHints::DatePatterns
);
4122 const NfCurrencyTable
& SvNumberFormatter::GetTheCurrencyTable()
4124 while (!g_CurrencyTableInitialized
)
4125 ImpInitCurrencyTable();
4126 return theCurrencyTable();
4130 const NfCurrencyEntry
* SvNumberFormatter::MatchSystemCurrency()
4132 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
4133 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
4134 return nSystemCurrencyPosition
? &rTable
[nSystemCurrencyPosition
] : nullptr;
4138 const NfCurrencyEntry
& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang
)
4140 if ( eLang
== LANGUAGE_SYSTEM
)
4142 const NfCurrencyEntry
* pCurr
= MatchSystemCurrency();
4143 return pCurr
? *pCurr
: GetTheCurrencyTable()[0];
4147 eLang
= MsLangId::getRealLanguage( eLang
);
4148 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
4149 sal_uInt16 nCount
= rTable
.size();
4150 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
4152 if ( rTable
[j
].GetLanguage() == eLang
)
4161 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry(std::u16string_view rAbbrev
, LanguageType eLang
)
4163 eLang
= MsLangId::getRealLanguage( eLang
);
4164 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
4165 sal_uInt16 nCount
= rTable
.size();
4166 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
4168 if ( rTable
[j
].GetLanguage() == eLang
&&
4169 rTable
[j
].GetBankSymbol() == rAbbrev
)
4179 const NfCurrencyEntry
* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( std::u16string_view rSymbol
,
4180 std::u16string_view rAbbrev
)
4182 GetTheCurrencyTable(); // just for initialization
4183 const NfCurrencyTable
& rTable
= theLegacyOnlyCurrencyTable();
4184 sal_uInt16 nCount
= rTable
.size();
4185 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
4187 if ( rTable
[j
].GetSymbol() == rSymbol
&&
4188 rTable
[j
].GetBankSymbol() == rAbbrev
)
4198 IMPL_STATIC_LINK_NOARG( SvNumberFormatter
, CurrencyChangeLink
, LinkParamNone
*, void )
4201 LanguageType eLang
= LANGUAGE_SYSTEM
;
4202 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev
, eLang
);
4203 SetDefaultSystemCurrency( aAbbrev
, eLang
);
4208 void SvNumberFormatter::SetDefaultSystemCurrency( std::u16string_view rAbbrev
, LanguageType eLang
)
4210 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
4211 if ( eLang
== LANGUAGE_SYSTEM
)
4213 eLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
4215 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
4216 sal_uInt16 nCount
= rTable
.size();
4217 if ( !rAbbrev
.empty() )
4219 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
4221 if ( rTable
[j
].GetLanguage() == eLang
&& rTable
[j
].GetBankSymbol() == rAbbrev
)
4223 nSystemCurrencyPosition
= j
;
4230 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
4232 if ( rTable
[j
].GetLanguage() == eLang
)
4234 nSystemCurrencyPosition
= j
;
4239 nSystemCurrencyPosition
= 0; // not found => simple SYSTEM
4242 void SvNFFormatData::ResetDefaultSystemCurrency()
4244 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
4247 void SvNumberFormatter::ResetDefaultSystemCurrency()
4249 m_aFormatData
.ResetDefaultSystemCurrency();
4252 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
4254 m_aCurrentLanguage
.pStringScanner
->InvalidateDateAcceptancePatterns();
4257 sal_uInt32
SvNFFormatData::ImpGetDefaultSystemCurrencyFormat(SvNFLanguageData
& rCurrentLanguage
,
4258 const NativeNumberWrapper
& rNatNum
)
4260 if ( nDefaultSystemCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
4263 SvNumFormatType nType
;
4264 NfWSStringsDtor aCurrList
;
4265 sal_uInt16 nDefault
= rCurrentLanguage
.GetCurrencyFormatStrings( aCurrList
,
4266 SvNumberFormatter::GetCurrencyEntry( LANGUAGE_SYSTEM
), false );
4267 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency System standard format?!?" );
4268 // if already loaded or user defined nDefaultSystemCurrencyFormat
4269 // will be set to the right value
4270 PutEntry(rCurrentLanguage
, rNatNum
, aCurrList
[ nDefault
], nCheck
, nType
,
4271 nDefaultSystemCurrencyFormat
, LANGUAGE_SYSTEM
);
4272 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
4273 DBG_ASSERT( nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
4274 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
4276 return nDefaultSystemCurrencyFormat
;
4279 sal_uInt32
SvNFFormatData::ImpGetDefaultCurrencyFormat(SvNFLanguageData
& rCurrentLanguage
, const NativeNumberWrapper
& rNatNum
,
4280 sal_uInt32 CLOffset
, LanguageType eLnge
)
4282 DefaultFormatKeysMap::const_iterator it
= aDefaultFormatKeys
.find( CLOffset
+ ZF_STANDARD_CURRENCY
);
4283 sal_uInt32 nDefaultCurrencyFormat
= (it
!= aDefaultFormatKeys
.end() ?
4284 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
4285 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
4287 // look for a defined standard
4288 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
4290 auto it2
= aFTable
.lower_bound( CLOffset
);
4291 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
4293 const SvNumberformat
* pEntry
= it2
->second
.get();
4294 if ( pEntry
->IsStandard() && (pEntry
->GetType() & SvNumFormatType::CURRENCY
) )
4296 nDefaultCurrencyFormat
= nKey
;
4302 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
4303 { // none found, create one
4305 NfWSStringsDtor aCurrList
;
4306 sal_uInt16 nDefault
= rCurrentLanguage
.GetCurrencyFormatStrings( aCurrList
,
4307 SvNumberFormatter::GetCurrencyEntry(eLnge
), false );
4308 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency standard format?" );
4309 if ( !aCurrList
.empty() )
4311 // if already loaded or user defined nDefaultSystemCurrencyFormat
4312 // will be set to the right value
4313 SvNumFormatType nType
;
4314 PutEntry(rCurrentLanguage
, rNatNum
, aCurrList
[ nDefault
], nCheck
, nType
,
4315 nDefaultCurrencyFormat
, eLnge
);
4316 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
4317 DBG_ASSERT( nDefaultCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
4318 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
4320 // old automatic currency format as a last resort
4321 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
4322 nDefaultCurrencyFormat
= CLOffset
+ ZF_STANDARD_CURRENCY
+3;
4324 { // mark as standard so that it is found next time
4325 SvNumberformat
* pEntry
= GetFormatEntry( nDefaultCurrencyFormat
);
4327 pEntry
->SetStandard();
4330 aDefaultFormatKeys
[ CLOffset
+ ZF_STANDARD_CURRENCY
] = nDefaultCurrencyFormat
;
4332 return nDefaultCurrencyFormat
;
4337 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
4338 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
4339 const NfCurrencyEntry
*& pFoundEntry
, bool& bFoundBank
, const NfCurrencyEntry
* pData
,
4340 sal_uInt16 nPos
, std::u16string_view rSymbol
)
4343 if ( pData
->GetSymbol() == rSymbol
)
4348 else if ( pData
->GetBankSymbol() == rSymbol
)
4357 if ( pFoundEntry
&& pFoundEntry
!= pData
)
4359 pFoundEntry
= nullptr;
4360 return false; // break loop, not unique
4363 { // first entry is SYSTEM
4364 pFoundEntry
= MatchSystemCurrency();
4367 return false; // break loop
4368 // even if there are more matching entries
4369 // this one is probably the one we are looking for
4373 pFoundEntry
= pData
;
4378 pFoundEntry
= pData
;
4384 void SvNFFormatData::MergeDefaultFormatKeys(const DefaultFormatKeysMap
& rDefaultFormatKeys
)
4386 for (const auto& r
: rDefaultFormatKeys
)
4389 auto iter
= aDefaultFormatKeys
.find(r
.first
);
4390 assert(iter
== aDefaultFormatKeys
.end() || iter
->second
== r
.second
);
4392 aDefaultFormatKeys
[r
.first
] = r
.second
;
4396 void SvNumberFormatter::MergeDefaultFormatKeys(const SvNFFormatData::DefaultFormatKeysMap
& rDefaultFormatKeys
)
4398 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4399 m_aFormatData
.MergeDefaultFormatKeys(rDefaultFormatKeys
);
4402 bool SvNFFormatData::GetNewCurrencySymbolString(sal_uInt32 nFormat
, OUString
& rStr
,
4403 const NfCurrencyEntry
** ppEntry
/* = NULL */,
4404 bool* pBank
/* = NULL */) const
4411 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
4414 OUString aSymbol
, aExtension
;
4415 if ( pFormat
->GetNewCurrencySymbol( aSymbol
, aExtension
) )
4417 OUStringBuffer
sBuff(128); // guess-estimate of a value that will pretty much guarantee no re-alloc
4420 bool bFoundBank
= false;
4421 // we definitely need an entry matching the format code string
4422 const NfCurrencyEntry
* pFoundEntry
= SvNumberFormatter::GetCurrencyEntry(
4423 bFoundBank
, aSymbol
, aExtension
, pFormat
->GetLanguage(),
4427 *ppEntry
= pFoundEntry
;
4429 *pBank
= bFoundBank
;
4430 rStr
= pFoundEntry
->BuildSymbolString(bFoundBank
);
4433 if ( rStr
.isEmpty() )
4434 { // analog to BuildSymbolString
4436 if ( aSymbol
.indexOf( '-' ) != -1 ||
4437 aSymbol
.indexOf( ']' ) != -1 )
4439 sBuff
.append("\"" + aSymbol
+ "\"");
4443 sBuff
.append(aSymbol
);
4445 if ( !aExtension
.isEmpty() )
4447 sBuff
.append(aExtension
);
4451 rStr
= sBuff
.makeStringAndClear();
4459 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat
, OUString
& rStr
,
4460 const NfCurrencyEntry
** ppEntry
/* = NULL */,
4461 bool* pBank
/* = NULL */ ) const
4463 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4464 return m_aFormatData
.GetNewCurrencySymbolString(nFormat
, rStr
, ppEntry
, pBank
);
4468 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank
,
4469 std::u16string_view rSymbol
,
4470 std::u16string_view rExtension
,
4471 LanguageType eFormatLanguage
,
4472 bool bOnlyStringLanguage
)
4474 sal_Int32 nExtLen
= rExtension
.size();
4475 LanguageType eExtLang
;
4478 // rExtension should be a 16-bit hex value max FFFF which may contain a
4479 // leading "-" separator (that is not a minus sign, but toInt32 can be
4480 // used to parse it, with post-processing as necessary):
4481 sal_Int32 nExtLang
= o3tl::toInt32(rExtension
, 16);
4484 eExtLang
= LANGUAGE_DONTKNOW
;
4489 nExtLang
= -nExtLang
;
4490 SAL_WARN_IF(nExtLang
> 0xFFFF, "svl.numbers", "Out of range Lang Id: " << nExtLang
<< " from input string: " << OUString(rExtension
));
4491 eExtLang
= LanguageType(nExtLang
& 0xFFFF);
4496 eExtLang
= LANGUAGE_DONTKNOW
;
4498 const NfCurrencyEntry
* pFoundEntry
= nullptr;
4499 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
4500 sal_uInt16 nCount
= rTable
.size();
4503 // first try with given extension language/country
4506 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
4508 LanguageType eLang
= rTable
[j
].GetLanguage();
4509 if ( eLang
== eExtLang
||
4510 ((eExtLang
== LANGUAGE_DONTKNOW
) &&
4511 (eLang
== LANGUAGE_SYSTEM
)))
4513 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
4514 &rTable
[j
], j
, rSymbol
);
4520 if ( pFoundEntry
|| !bCont
|| (bOnlyStringLanguage
&& nExtLen
) )
4524 if ( !bOnlyStringLanguage
)
4526 // now try the language/country of the number format
4527 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
4529 LanguageType eLang
= rTable
[j
].GetLanguage();
4530 if ( eLang
== eFormatLanguage
||
4531 ((eFormatLanguage
== LANGUAGE_DONTKNOW
) &&
4532 (eLang
== LANGUAGE_SYSTEM
)))
4534 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
4535 &rTable
[j
], j
, rSymbol
);
4540 if ( pFoundEntry
|| !bCont
)
4546 // then try without language/country if no extension specified
4549 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
4551 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
4552 &rTable
[j
], j
, rSymbol
);
4559 void SvNFLanguageData::GetCompatibilityCurrency( OUString
& rSymbol
, OUString
& rAbbrev
) const
4561 const css::uno::Sequence
< css::i18n::Currency2
>
4562 xCurrencies( xLocaleData
->getAllCurrencies() );
4564 auto pCurrency
= std::find_if(xCurrencies
.begin(), xCurrencies
.end(),
4565 [](const css::i18n::Currency2
& rCurrency
) { return rCurrency
.UsedInCompatibleFormatCodes
; });
4566 if (pCurrency
!= xCurrencies
.end())
4568 rSymbol
= pCurrency
->Symbol
;
4569 rAbbrev
= pCurrency
->BankSymbol
;
4573 if (LocaleDataWrapper::areChecksEnabled())
4575 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
4576 appendLocaleInfo( u
"GetCompatibilityCurrency: none?"));
4578 rSymbol
= xLocaleData
->getCurrSymbol();
4579 rAbbrev
= xLocaleData
->getCurrBankSymbol();
4583 void SvNumberFormatter::GetCompatibilityCurrency( OUString
& rSymbol
, OUString
& rAbbrev
) const
4585 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4586 m_aCurrentLanguage
.GetCompatibilityCurrency(rSymbol
, rAbbrev
);
4589 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry
& rCurr
)
4591 switch ( rCurr
.GetPositiveFormat() )
4599 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
4602 switch ( rCurr
.GetNegativeFormat() )
4622 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
4628 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang
)
4630 // The set is initialized as a side effect of the currency table
4631 // created, make sure that exists, which usually is the case unless a
4632 // SvNumberFormatter was never instantiated.
4633 GetTheCurrencyTable();
4634 return theInstalledLocales
.find( eLang
) != theInstalledLocales
.end();
4638 void SvNumberFormatter::ImpInitCurrencyTable()
4640 // Race condition possible:
4641 // ::osl::MutexGuard aGuard( GetMutex() );
4642 // while (!g_CurrencyTableInitialized)
4643 // ImpInitCurrencyTable();
4644 static bool bInitializing
= false;
4645 if (g_CurrencyTableInitialized
|| bInitializing
)
4649 bInitializing
= true;
4651 LanguageType eSysLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
4652 std::optional
<LocaleDataWrapper
> pLocaleData(std::in_place
,
4653 ::comphelper::getProcessComponentContext(),
4654 SvtSysLocale().GetLanguageTag() );
4655 // get user configured currency
4656 OUString aConfiguredCurrencyAbbrev
;
4657 LanguageType eConfiguredCurrencyLanguage
= LANGUAGE_SYSTEM
;
4658 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
4659 aConfiguredCurrencyAbbrev
, eConfiguredCurrencyLanguage
);
4660 sal_uInt16 nSecondarySystemCurrencyPosition
= 0;
4661 sal_uInt16 nMatchingSystemCurrencyPosition
= 0;
4663 // First entry is SYSTEM:
4664 auto& rCurrencyTable
= theCurrencyTable();
4665 rCurrencyTable
.insert(
4666 rCurrencyTable
.begin(),
4667 NfCurrencyEntry(*pLocaleData
, LANGUAGE_SYSTEM
));
4668 sal_uInt16 nCurrencyPos
= 1;
4670 const css::uno::Sequence
< css::lang::Locale
> xLoc
= LocaleDataWrapper::getInstalledLocaleNames();
4671 sal_Int32 nLocaleCount
= xLoc
.getLength();
4672 SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount
<< "\"" );
4673 NfCurrencyTable
&rLegacyOnlyCurrencyTable
= theLegacyOnlyCurrencyTable();
4674 sal_uInt16 nLegacyOnlyCurrencyPos
= 0;
4675 for ( css::lang::Locale
const & rLocale
: xLoc
)
4677 LanguageType eLang
= LanguageTag::convertToLanguageType( rLocale
, false);
4678 theInstalledLocales
.insert( eLang
);
4679 pLocaleData
.emplace(
4680 ::comphelper::getProcessComponentContext(),
4681 LanguageTag(rLocale
) );
4682 Sequence
< Currency2
> aCurrSeq
= pLocaleData
->getAllCurrencies();
4683 sal_Int32 nCurrencyCount
= aCurrSeq
.getLength();
4684 Currency2
const * const pCurrencies
= aCurrSeq
.getConstArray();
4686 // one default currency for each locale, insert first so it is found first
4688 for ( nDefault
= 0; nDefault
< nCurrencyCount
; nDefault
++ )
4690 if ( pCurrencies
[nDefault
].Default
)
4693 std::optional
<NfCurrencyEntry
> pEntry
;
4694 if ( nDefault
< nCurrencyCount
)
4696 pEntry
.emplace(pCurrencies
[nDefault
], *pLocaleData
, eLang
);
4699 { // first or ShellsAndPebbles
4700 pEntry
.emplace(*pLocaleData
, eLang
);
4702 if (LocaleDataWrapper::areChecksEnabled())
4704 lcl_CheckCurrencySymbolPosition( *pEntry
);
4706 if ( !nSystemCurrencyPosition
&& !aConfiguredCurrencyAbbrev
.isEmpty() &&
4707 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
&&
4708 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
)
4710 nSystemCurrencyPosition
= nCurrencyPos
;
4712 if ( !nMatchingSystemCurrencyPosition
&&
4713 pEntry
->GetLanguage() == eSysLang
)
4715 nMatchingSystemCurrencyPosition
= nCurrencyPos
;
4717 rCurrencyTable
.insert(
4718 rCurrencyTable
.begin() + nCurrencyPos
++, std::move(*pEntry
));
4719 // all remaining currencies for each locale
4720 if ( nCurrencyCount
> 1 )
4722 sal_Int32 nCurrency
;
4723 for ( nCurrency
= 0; nCurrency
< nCurrencyCount
; nCurrency
++ )
4725 if (pCurrencies
[nCurrency
].LegacyOnly
)
4727 rLegacyOnlyCurrencyTable
.insert(
4728 rLegacyOnlyCurrencyTable
.begin() + nLegacyOnlyCurrencyPos
++,
4730 pCurrencies
[nCurrency
], *pLocaleData
, eLang
));
4732 else if ( nCurrency
!= nDefault
)
4734 pEntry
.emplace(pCurrencies
[nCurrency
], *pLocaleData
, eLang
);
4736 bool bInsert
= true;
4737 sal_uInt16 n
= rCurrencyTable
.size();
4738 sal_uInt16 aCurrencyIndex
= 1; // skip first SYSTEM entry
4739 for ( sal_uInt16 j
=1; j
<n
; j
++ )
4741 if ( rCurrencyTable
[aCurrencyIndex
++] == *pEntry
)
4753 if ( !nSecondarySystemCurrencyPosition
&&
4754 (!aConfiguredCurrencyAbbrev
.isEmpty() ?
4755 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
:
4756 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
) )
4758 nSecondarySystemCurrencyPosition
= nCurrencyPos
;
4760 if ( !nMatchingSystemCurrencyPosition
&&
4761 pEntry
->GetLanguage() == eSysLang
)
4763 nMatchingSystemCurrencyPosition
= nCurrencyPos
;
4765 rCurrencyTable
.insert(
4766 rCurrencyTable
.begin() + nCurrencyPos
++, std::move(*pEntry
));
4772 if ( !nSystemCurrencyPosition
)
4774 nSystemCurrencyPosition
= nSecondarySystemCurrencyPosition
;
4776 if ((!aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
4777 LocaleDataWrapper::areChecksEnabled())
4779 LocaleDataWrapper::outputCheckMessage(
4780 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
4782 // match SYSTEM if no configured currency found
4783 if ( !nSystemCurrencyPosition
)
4785 nSystemCurrencyPosition
= nMatchingSystemCurrencyPosition
;
4787 if ((aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
4788 LocaleDataWrapper::areChecksEnabled())
4790 LocaleDataWrapper::outputCheckMessage(
4791 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
4793 pLocaleData
.reset();
4794 SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( nullptr, SvNumberFormatter
, CurrencyChangeLink
) );
4795 bInitializing
= false;
4796 g_CurrencyTableInitialized
= true;
4799 static std::ptrdiff_t addToCurrencyFormatsList( NfWSStringsDtor
& rStrArr
, const OUString
& rFormat
)
4801 // Prevent duplicates even over subsequent calls of
4802 // GetCurrencyFormatStrings() with the same vector.
4803 NfWSStringsDtor::const_iterator
it( std::find( rStrArr
.begin(), rStrArr
.end(), rFormat
));
4804 if (it
!= rStrArr
.end())
4805 return it
- rStrArr
.begin();
4807 rStrArr
.push_back( rFormat
);
4808 return rStrArr
.size() - 1;
4811 sal_uInt16
SvNFLanguageData::GetCurrencyFormatStrings(NfWSStringsDtor
& rStrArr
,
4812 const NfCurrencyEntry
& rCurr
,
4816 + pFormatScanner
->GetRedString()
4819 sal_uInt16 nDefault
= 0;
4822 // Only bank symbols.
4823 OUString aPositiveBank
= rCurr
.BuildPositiveFormatString(true, *xLocaleData
);
4824 OUString aNegativeBank
= rCurr
.BuildNegativeFormatString(true, *xLocaleData
);
4826 OUString format1
= aPositiveBank
4829 addToCurrencyFormatsList( rStrArr
, format1
);
4831 OUString format2
= aPositiveBank
4835 nDefault
= addToCurrencyFormatsList( rStrArr
, format2
);
4839 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
4840 // duplicates if no decimals in currency.
4841 OUString aPositive
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
);
4842 OUString aNegative
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
);
4848 if (rCurr
.GetDigits())
4850 OUString aPositiveNoDec
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 0);
4851 OUString aNegativeNoDec
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 0 );
4852 OUString aPositiveDashed
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 2);
4853 OUString aNegativeDashed
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 2);
4855 format1
= aPositiveNoDec
4859 format3
= aPositiveNoDec
4864 format5
= aPositiveDashed
4879 if (rCurr
.GetDigits())
4881 addToCurrencyFormatsList( rStrArr
, format1
);
4883 addToCurrencyFormatsList( rStrArr
, format2
);
4884 if (rCurr
.GetDigits())
4886 addToCurrencyFormatsList( rStrArr
, format3
);
4888 nDefault
= addToCurrencyFormatsList( rStrArr
, format4
);
4889 if (rCurr
.GetDigits())
4891 addToCurrencyFormatsList( rStrArr
, format5
);
4897 sal_uInt16
SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor
& rStrArr
,
4898 const NfCurrencyEntry
& rCurr
,
4901 ::osl::MutexGuard
aGuard(GetInstanceMutex());
4902 return m_aCurrentLanguage
.GetCurrencyFormatStrings(rStrArr
, rCurr
, bBank
);
4905 sal_uInt32
SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt
) const
4907 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4910 SvNumberFormatterIndexTable::const_iterator it
= pMergeTable
->find(nOldFmt
);
4911 if (it
!= pMergeTable
->end())
4919 bool SvNumberFormatter::HasMergeFormatTable() const
4921 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4922 return pMergeTable
&& !pMergeTable
->empty();
4926 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
, sal_uInt16 nTwoDigitYearStart
)
4930 if ( nYear
< (nTwoDigitYearStart
% 100) )
4932 return nYear
+ (((nTwoDigitYearStart
/ 100) + 1) * 100);
4936 return nYear
+ ((nTwoDigitYearStart
/ 100) * 100);
4942 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
4944 aSymbol
= rLocaleData
.getCurrSymbol();
4945 aBankSymbol
= rLocaleData
.getCurrBankSymbol();
4947 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
4948 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
4949 nDigits
= rLocaleData
.getCurrDigits();
4950 cZeroChar
= rLocaleData
.getCurrZeroChar();
4954 NfCurrencyEntry::NfCurrencyEntry( const css::i18n::Currency
& rCurr
,
4955 const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
4957 aSymbol
= rCurr
.Symbol
;
4958 aBankSymbol
= rCurr
.BankSymbol
;
4960 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
4961 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
4962 nDigits
= rCurr
.DecimalPlaces
;
4963 cZeroChar
= rLocaleData
.getCurrZeroChar();
4966 bool NfCurrencyEntry::operator==( const NfCurrencyEntry
& r
) const
4968 return aSymbol
== r
.aSymbol
4969 && aBankSymbol
== r
.aBankSymbol
4970 && eLanguage
== r
.eLanguage
4974 OUString
NfCurrencyEntry::BuildSymbolString(bool bBank
,
4975 bool bWithoutExtension
) const
4977 OUStringBuffer
aBuf("[$");
4980 aBuf
.append(aBankSymbol
);
4984 if ( aSymbol
.indexOf( '-' ) >= 0 ||
4985 aSymbol
.indexOf( ']' ) >= 0)
4987 aBuf
.append("\"" + aSymbol
+ "\"");
4991 aBuf
.append(aSymbol
);
4993 if ( !bWithoutExtension
&& eLanguage
!= LANGUAGE_DONTKNOW
&& eLanguage
!= LANGUAGE_SYSTEM
)
4995 sal_Int32 nLang
= static_cast<sal_uInt16
>(eLanguage
);
4996 aBuf
.append("-" + OUString::number(nLang
, 16).toAsciiUpperCase());
5000 return aBuf
.makeStringAndClear();
5003 OUString
NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper
& rLoc
,
5004 sal_uInt16 nDecimalFormat
) const
5006 OUStringBuffer
aBuf("#" + rLoc
.getNumThousandSep() + "##0");
5007 if (nDecimalFormat
&& nDigits
)
5009 aBuf
.append(rLoc
.getNumDecimalSep());
5010 sal_Unicode cDecimalChar
= nDecimalFormat
== 2 ? '-' : cZeroChar
;
5011 for (sal_uInt16 i
= 0; i
< nDigits
; ++i
)
5013 aBuf
.append(cDecimalChar
);
5016 return aBuf
.makeStringAndClear();
5020 OUString
NfCurrencyEntry::BuildPositiveFormatString(bool bBank
, const LocaleDataWrapper
& rLoc
,
5021 sal_uInt16 nDecimalFormat
) const
5023 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
5024 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat( rLoc
.getCurrPositiveFormat(),
5025 nPositiveFormat
, bBank
);
5026 CompletePositiveFormatString(sBuf
, bBank
, nPosiForm
);
5027 return sBuf
.makeStringAndClear();
5031 OUString
NfCurrencyEntry::BuildNegativeFormatString(bool bBank
,
5032 const LocaleDataWrapper
& rLoc
, sal_uInt16 nDecimalFormat
) const
5034 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
5035 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc
.getCurrNegativeFormat(),
5036 nNegativeFormat
, bBank
);
5037 CompleteNegativeFormatString(sBuf
, bBank
, nNegaForm
);
5038 return sBuf
.makeStringAndClear();
5042 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, bool bBank
,
5043 sal_uInt16 nPosiForm
) const
5045 OUString aSymStr
= BuildSymbolString(bBank
);
5046 NfCurrencyEntry::CompletePositiveFormatString( rStr
, aSymStr
, nPosiForm
);
5050 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
, bool bBank
,
5051 sal_uInt16 nNegaForm
) const
5053 OUString aSymStr
= BuildSymbolString(bBank
);
5054 NfCurrencyEntry::CompleteNegativeFormatString( rStr
, aSymStr
, nNegaForm
);
5059 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, std::u16string_view rSymStr
,
5060 sal_uInt16 nPositiveFormat
)
5062 switch( nPositiveFormat
)
5065 rStr
.insert(0, rSymStr
);
5068 rStr
.append(rSymStr
);
5072 rStr
.insert(0, OUString::Concat(rSymStr
) + " ");
5078 rStr
.append(rSymStr
);
5082 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
5089 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
,
5090 std::u16string_view rSymStr
,
5091 sal_uInt16 nNegativeFormat
)
5093 switch( nNegativeFormat
)
5097 rStr
.insert(0, OUString::Concat("(") + rSymStr
);
5103 rStr
.insert(0, OUString::Concat("-") + rSymStr
);
5108 rStr
.insert(0, OUString::Concat(rSymStr
) + "-");
5113 rStr
.insert(0, rSymStr
);
5119 rStr
.insert(0, '(');
5120 rStr
.append(rSymStr
);
5126 rStr
.append(rSymStr
);
5127 rStr
.insert(0, '-');
5133 rStr
.append(rSymStr
);
5138 rStr
.append(rSymStr
);
5145 rStr
.append(rSymStr
);
5146 rStr
.insert(0, '-');
5151 rStr
.insert(0, OUString::Concat("-") + rSymStr
+ " ");
5157 rStr
.append(rSymStr
);
5163 rStr
.insert(0, OUString::Concat(rSymStr
) + " -");
5168 rStr
.insert(0, OUString::Concat(rSymStr
) + " ");
5176 rStr
.append(rSymStr
);
5181 rStr
.insert(0, OUString::Concat("(") + rSymStr
+ " ");
5187 rStr
.insert(0, '(');
5189 rStr
.append(rSymStr
);
5194 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
5201 sal_uInt16
NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat
,
5202 sal_uInt16 nCurrFormat
, bool bBank
)
5206 #if NF_BANKSYMBOL_FIX_POSITION
5207 (void) nIntlFormat
; // avoid warnings
5210 switch ( nIntlFormat
)
5213 nIntlFormat
= 2; // $ 1
5216 nIntlFormat
= 3; // 1 $
5223 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
5234 //! Call this only if nCurrFormat is really with parentheses!
5235 static sal_uInt16
lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat
, sal_uInt16 nCurrFormat
)
5237 short nSign
= 0; // -1:=bracket 0:=left, 1:=middle, 2:=right
5238 switch ( nIntlFormat
)
5264 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
5268 switch ( nCurrFormat
)
5320 sal_uInt16
NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat
,
5321 sal_uInt16 nCurrFormat
, bool bBank
)
5325 #if NF_BANKSYMBOL_FIX_POSITION
5328 switch ( nIntlFormat
)
5331 // nIntlFormat = 14; // ($ 1)
5332 nIntlFormat
= 9; // -$ 1
5335 nIntlFormat
= 9; // -$ 1
5338 nIntlFormat
= 11; // $ -1
5341 nIntlFormat
= 12; // $ 1-
5344 // nIntlFormat = 15; // (1 $)
5345 nIntlFormat
= 8; // -1 $
5348 nIntlFormat
= 8; // -1 $
5351 nIntlFormat
= 13; // 1- $
5354 nIntlFormat
= 10; // 1 $-
5369 // nIntlFormat = 14; // ($ 1)
5370 nIntlFormat
= 9; // -$ 1
5373 // nIntlFormat = 15; // (1 $)
5374 nIntlFormat
= 8; // -1 $
5377 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
5382 else if ( nIntlFormat
!= nCurrFormat
)
5384 switch ( nCurrFormat
)
5387 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
5388 nIntlFormat
, nCurrFormat
);
5391 nIntlFormat
= nCurrFormat
;
5394 nIntlFormat
= nCurrFormat
;
5397 nIntlFormat
= nCurrFormat
;
5400 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
5401 nIntlFormat
, nCurrFormat
);
5404 nIntlFormat
= nCurrFormat
;
5407 nIntlFormat
= nCurrFormat
;
5410 nIntlFormat
= nCurrFormat
;
5413 nIntlFormat
= nCurrFormat
;
5416 nIntlFormat
= nCurrFormat
;
5419 nIntlFormat
= nCurrFormat
;
5422 nIntlFormat
= nCurrFormat
;
5425 nIntlFormat
= nCurrFormat
;
5428 nIntlFormat
= nCurrFormat
;
5431 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
5432 nIntlFormat
, nCurrFormat
);
5435 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
5436 nIntlFormat
, nCurrFormat
);
5439 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
5446 const NfKeywordTable
& SvNumberFormatter::GetKeywords( sal_uInt32 nKey
)
5448 osl::MutexGuard
aGuard( GetInstanceMutex() );
5449 const SvNumberformat
* pFormat
= m_aFormatData
.GetFormatEntry( nKey
);
5451 ChangeIntl( pFormat
->GetLanguage());
5453 ChangeIntl( IniLnge
);
5454 return m_aCurrentLanguage
.pFormatScanner
->GetKeywords();
5458 const NfKeywordTable
& SvNumberFormatter::GetEnglishKeywords()
5460 return ImpSvNumberformatScan::GetEnglishKeywords();
5464 const std::vector
<Color
> & SvNumberFormatter::GetStandardColors()
5466 return ImpSvNumberformatScan::GetStandardColors();
5470 size_t SvNumberFormatter::GetMaxDefaultColors()
5472 return ImpSvNumberformatScan::GetMaxDefaultColors();
5475 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */