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 <svl/zforlist.hxx>
24 #include <svl/currencytable.hxx>
26 #include <comphelper/string.hxx>
27 #include <o3tl/make_unique.hxx>
28 #include <tools/debug.hxx>
29 #include <unotools/charclass.hxx>
30 #include <unotools/configmgr.hxx>
31 #include <i18nlangtag/mslangid.hxx>
32 #include <unotools/localedatawrapper.hxx>
33 #include <unotools/calendarwrapper.hxx>
34 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
35 #include <com/sun/star/i18n/KNumberFormatType.hpp>
36 #include <com/sun/star/i18n/FormatElement.hpp>
37 #include <com/sun/star/i18n/Currency2.hpp>
38 #include <com/sun/star/i18n/NumberFormatCode.hpp>
39 #include <com/sun/star/i18n/XNumberFormatCode.hpp>
40 #include <com/sun/star/i18n/NumberFormatMapper.hpp>
41 #include <comphelper/processfactory.hxx>
42 #include <unotools/misccfg.hxx>
45 #include <osl/mutex.hxx>
47 #include "zforscan.hxx"
48 #include "zforfind.hxx"
49 #include <svl/zformat.hxx>
51 #include <unotools/syslocaleoptions.hxx>
52 #include <unotools/digitgroupingiterator.hxx>
53 #include <rtl/instance.hxx>
54 #include <rtl/strbuf.hxx>
60 using namespace ::com::sun::star
;
61 using namespace ::com::sun::star::uno
;
62 using namespace ::com::sun::star::i18n
;
63 using namespace ::com::sun::star::lang
;
64 using namespace ::std
;
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 40
72 #define ZF_STANDARD_DATETIME 50
73 #define ZF_STANDARD_SCIENTIFIC 60
74 #define ZF_STANDARD_FRACTION 65
76 // Additional builtin formats not fitting into the first 10 of a category (TLOT
77 // = The Legacy Of Templin; unfortunately TLOT intended only 10 builtin formats
78 // per category, more would overwrite the next category):
79 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY 75
80 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY 76
81 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY 77
82 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY 78
83 #define ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY 79
84 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY 80
85 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY 81
86 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD 82
87 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD 83
88 #define ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD 84
89 #define ZF_STANDARD_NEWEXTENDED_DATE_WW 85
91 #define ZF_STANDARD_LOGICAL SV_MAX_COUNT_STANDARD_FORMATS-1 // 99
92 #define ZF_STANDARD_TEXT SV_MAX_COUNT_STANDARD_FORMATS // 100
94 static_assert( ZF_STANDARD_TEXT
== NF_STANDARD_FORMAT_TEXT
, "definition mismatch" );
96 /* Locale that is set if an unknown locale (from another system) is loaded of
97 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
98 * (old currency) is recognized as a date (#53155#). */
99 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
101 // Same order as in include/svl/zforlist.hxx enum NfIndexTableOffset
102 static sal_uInt32
const indexTable
[NF_INDEX_TABLE_ENTRIES
] = {
103 ZF_STANDARD
, // NF_NUMBER_STANDARD
104 ZF_STANDARD
+ 1, // NF_NUMBER_INT
105 ZF_STANDARD
+ 2, // NF_NUMBER_DEC2
106 ZF_STANDARD
+ 3, // NF_NUMBER_1000INT
107 ZF_STANDARD
+ 4, // NF_NUMBER_1000DEC2
108 ZF_STANDARD
+ 5, // NF_NUMBER_SYSTEM
109 ZF_STANDARD_SCIENTIFIC
, // NF_SCIENTIFIC_000E000
110 ZF_STANDARD_SCIENTIFIC
+ 1, // NF_SCIENTIFIC_000E00
111 ZF_STANDARD_PERCENT
, // NF_PERCENT_INT
112 ZF_STANDARD_PERCENT
+ 1, // NF_PERCENT_DEC2
113 ZF_STANDARD_FRACTION
, // NF_FRACTION_1D
114 ZF_STANDARD_FRACTION
+ 1, // NF_FRACTION_2D
115 ZF_STANDARD_CURRENCY
, // NF_CURRENCY_1000INT
116 ZF_STANDARD_CURRENCY
+ 1, // NF_CURRENCY_1000DEC2
117 ZF_STANDARD_CURRENCY
+ 2, // NF_CURRENCY_1000INT_RED
118 ZF_STANDARD_CURRENCY
+ 3, // NF_CURRENCY_1000DEC2_RED
119 ZF_STANDARD_CURRENCY
+ 4, // NF_CURRENCY_1000DEC2_CCC
120 ZF_STANDARD_CURRENCY
+ 5, // NF_CURRENCY_1000DEC2_DASHED
121 ZF_STANDARD_DATE
, // NF_DATE_SYSTEM_SHORT
122 ZF_STANDARD_DATE
+ 8, // NF_DATE_SYSTEM_LONG
123 ZF_STANDARD_DATE
+ 7, // NF_DATE_SYS_DDMMYY
124 ZF_STANDARD_DATE
+ 6, // NF_DATE_SYS_DDMMYYYY
125 ZF_STANDARD_DATE
+ 9, // NF_DATE_SYS_DMMMYY
126 ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY
, // NF_DATE_SYS_DMMMYYYY
127 ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY
, // NF_DATE_DIN_DMMMYYYY
128 ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY
, // NF_DATE_SYS_DMMMMYYYY
129 ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY
, // NF_DATE_DIN_DMMMMYYYY
130 ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY
, // NF_DATE_SYS_NNDMMMYY
131 ZF_STANDARD_DATE
+ 1, // NF_DATE_DEF_NNDDMMMYY
132 ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY
, // NF_DATE_SYS_NNDMMMMYYYY
133 ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY
, // NF_DATE_SYS_NNNNDMMMMYYYY
134 ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD
, // NF_DATE_DIN_MMDD
135 ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD
, // NF_DATE_DIN_YYMMDD
136 ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD
, // NF_DATE_DIN_YYYYMMDD
137 ZF_STANDARD_DATE
+ 2, // NF_DATE_SYS_MMYY
138 ZF_STANDARD_DATE
+ 3, // NF_DATE_SYS_DDMMM
139 ZF_STANDARD_DATE
+ 4, // NF_DATE_MMMM
140 ZF_STANDARD_DATE
+ 5, // NF_DATE_QQJJ
141 ZF_STANDARD_NEWEXTENDED_DATE_WW
, // NF_DATE_WW
142 ZF_STANDARD_TIME
, // NF_TIME_HHMM
143 ZF_STANDARD_TIME
+ 1, // NF_TIME_HHMMSS
144 ZF_STANDARD_TIME
+ 2, // NF_TIME_HHMMAMPM
145 ZF_STANDARD_TIME
+ 3, // NF_TIME_HHMMSSAMPM
146 ZF_STANDARD_TIME
+ 4, // NF_TIME_HH_MMSS
147 ZF_STANDARD_TIME
+ 5, // NF_TIME_MMSS00
148 ZF_STANDARD_TIME
+ 6, // NF_TIME_HH_MMSS00
149 ZF_STANDARD_DATETIME
, // NF_DATETIME_SYSTEM_SHORT_HHMM
150 ZF_STANDARD_DATETIME
+ 1, // NF_DATETIME_SYS_DDMMYYYY_HHMMSS
151 ZF_STANDARD_LOGICAL
, // NF_BOOLEAN
152 ZF_STANDARD_TEXT
, // NF_TEXT
153 ZF_STANDARD_FRACTION
+ 2, // NF_FRACTION_3D
154 ZF_STANDARD_FRACTION
+ 3, // NF_FRACTION_2
155 ZF_STANDARD_FRACTION
+ 4, // NF_FRACTION_4
156 ZF_STANDARD_FRACTION
+ 5, // NF_FRACTION_8
157 ZF_STANDARD_FRACTION
+ 6, // NF_FRACTION_16
158 ZF_STANDARD_FRACTION
+ 7, // NF_FRACTION_10
159 ZF_STANDARD_FRACTION
+ 8, // NF_FRACTION_100
160 ZF_STANDARD_DATETIME
+ 2 // NF_DATETIME_ISO_YYYYMMDD_HHMMSS
164 instead of every number formatter being a listener we have a registry which
165 also handles one instance of the SysLocale options
168 typedef ::std::vector
< SvNumberFormatter
* > SvNumberFormatterList_impl
;
170 class SvNumberFormatterRegistry_Impl
: public utl::ConfigurationListener
172 SvNumberFormatterList_impl aFormatters
;
173 SvtSysLocaleOptions aSysLocaleOptions
;
174 LanguageType eSysLanguage
;
177 SvNumberFormatterRegistry_Impl();
178 virtual ~SvNumberFormatterRegistry_Impl() override
;
180 void Insert( SvNumberFormatter
* pThis
)
181 { aFormatters
.push_back( pThis
); }
183 void Remove( SvNumberFormatter
const * pThis
);
186 { return aFormatters
.size(); }
188 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster
*, ConfigurationHints
) override
;
191 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
193 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
194 aSysLocaleOptions
.AddListener( this );
198 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
200 aSysLocaleOptions
.RemoveListener( this );
204 void SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter
const * pThis
)
206 for (SvNumberFormatterList_impl::iterator it
= aFormatters
.begin();
207 it
!= aFormatters
.end(); ++it
)
211 aFormatters
.erase( it
);
217 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster
*,
218 ConfigurationHints nHint
)
220 ::osl::MutexGuard
aGuard( SvNumberFormatter::GetGlobalMutex() );
222 if ( nHint
& ConfigurationHints::Locale
)
224 for(SvNumberFormatter
* pFormatter
: aFormatters
)
225 pFormatter
->ReplaceSystemCL( eSysLanguage
);
226 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
228 if ( nHint
& ConfigurationHints::Currency
)
230 for(SvNumberFormatter
* pFormatter
: aFormatters
)
231 pFormatter
->ResetDefaultSystemCurrency();
233 if ( nHint
& ConfigurationHints::DatePatterns
)
235 for(SvNumberFormatter
* pFormatter
: aFormatters
)
236 pFormatter
->InvalidateDateAcceptancePatterns();
241 SvNumberFormatterRegistry_Impl
* SvNumberFormatter::pFormatterRegistry
= nullptr;
242 volatile bool SvNumberFormatter::bCurrencyTableInitialized
= false;
245 struct theCurrencyTable
:
246 public rtl::Static
< NfCurrencyTable
, theCurrencyTable
> {};
248 struct theLegacyOnlyCurrencyTable
:
249 public rtl::Static
< NfCurrencyTable
, theLegacyOnlyCurrencyTable
> {};
251 /** THE set of installed locales. */
252 struct theInstalledLocales
:
253 public rtl::Static
< NfInstalledLocales
, theInstalledLocales
> {};
256 sal_uInt16
SvNumberFormatter::nSystemCurrencyPosition
= 0;
258 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
259 // language dependent.
260 #define NF_BANKSYMBOL_FIX_POSITION 1
262 const sal_uInt16
SvNumberFormatter::UNLIMITED_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max();
263 const sal_uInt16
SvNumberFormatter::INPUTSTRING_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max()-1;
265 SvNumberFormatter::SvNumberFormatter( const Reference
< XComponentContext
>& rxContext
,
267 : m_xContext( rxContext
)
268 , maLanguageTag( eLang
)
270 ImpConstruct( eLang
);
273 SvNumberFormatter::~SvNumberFormatter()
276 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
277 pFormatterRegistry
->Remove( this );
278 if ( !pFormatterRegistry
->Count() )
280 delete pFormatterRegistry
;
281 pFormatterRegistry
= nullptr;
290 void SvNumberFormatter::ImpConstruct( LanguageType eLang
)
292 if ( eLang
== LANGUAGE_DONTKNOW
)
294 eLang
= UNKNOWN_SUBSTITUTE
;
298 eEvalDateFormat
= NF_EVALDATEFORMAT_INTL
;
299 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
301 maLanguageTag
.reset( eLang
);
302 pCharClass
.reset( new CharClass( m_xContext
, maLanguageTag
) );
303 xLocaleData
.init( m_xContext
, maLanguageTag
);
304 xCalendar
.init( m_xContext
, maLanguageTag
.getLocale() );
305 xTransliteration
.init( m_xContext
, eLang
);
306 xNatNum
.init( m_xContext
);
308 // cached locale data items
309 const LocaleDataWrapper
* pLoc
= GetLocaleData();
310 aDecimalSep
= pLoc
->getNumDecimalSep();
311 aDecimalSepAlt
= pLoc
->getNumDecimalSepAlt();
312 aThousandSep
= pLoc
->getNumThousandSep();
313 aDateSep
= pLoc
->getDateSep();
315 pStringScanner
.reset( new ImpSvNumberInputScan( this ) );
316 pFormatScanner
.reset( new ImpSvNumberformatScan( this ) );
317 pFormatTable
= nullptr;
319 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
320 pMergeTable
= nullptr;
323 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
324 GetFormatterRegistry().Insert( this );
328 void SvNumberFormatter::ChangeIntl(LanguageType eLnge
)
330 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
331 if (ActLnge
== eLnge
)
336 maLanguageTag
.reset( eLnge
);
337 pCharClass
->setLanguageTag( maLanguageTag
);
338 xLocaleData
.changeLocale( maLanguageTag
);
339 xCalendar
.changeLocale( maLanguageTag
.getLocale() );
340 xTransliteration
.changeLocale( eLnge
);
342 // cached locale data items, initialize BEFORE calling ChangeIntl below
343 const LocaleDataWrapper
* pLoc
= GetLocaleData();
344 aDecimalSep
= pLoc
->getNumDecimalSep();
345 aDecimalSepAlt
= pLoc
->getNumDecimalSepAlt();
346 aThousandSep
= pLoc
->getNumThousandSep();
347 aDateSep
= pLoc
->getDateSep();
349 pFormatScanner
->ChangeIntl();
350 pStringScanner
->ChangeIntl();
355 ::osl::Mutex
& SvNumberFormatter::GetGlobalMutex()
357 // #i77768# Due to a static reference in the toolkit lib
358 // we need a mutex that lives longer than the svl library.
359 // Otherwise the dtor would use a destructed mutex!!
360 static osl::Mutex
* persistentMutex(new osl::Mutex
);
362 return *persistentMutex
;
367 SvNumberFormatterRegistry_Impl
& SvNumberFormatter::GetFormatterRegistry()
369 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
370 if ( !pFormatterRegistry
)
372 pFormatterRegistry
= new SvNumberFormatterRegistry_Impl
;
374 return *pFormatterRegistry
;
377 void SvNumberFormatter::SetColorLink( const Link
<sal_uInt16
,Color
*>& rColorTableCallBack
)
379 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
380 aColorLink
= rColorTableCallBack
;
383 Color
* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex
)
385 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
386 if( aColorLink
.IsSet() )
388 return aColorLink
.Call(nIndex
);
396 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay
,
400 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
401 pFormatScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
402 pStringScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
405 const Date
& SvNumberFormatter::GetNullDate() const
407 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
408 return pFormatScanner
->GetNullDate();
411 void SvNumberFormatter::ChangeStandardPrec(short nPrec
)
413 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
414 pFormatScanner
->ChangeStandardPrec(nPrec
);
417 void SvNumberFormatter::SetNoZero(bool bNZ
)
419 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
423 sal_uInt16
SvNumberFormatter::GetStandardPrec() const
425 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
426 return pFormatScanner
->GetStandardPrec();
429 bool SvNumberFormatter::GetNoZero() const
431 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
435 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage
)
437 sal_uInt32 nCLOffset
= ImpGetCLOffset( LANGUAGE_SYSTEM
);
438 if ( nCLOffset
> MaxCLOffset
)
440 return ; // no SYSTEM entries to replace
442 const sal_uInt32 nMaxBuiltin
= nCLOffset
+ SV_MAX_COUNT_STANDARD_FORMATS
;
443 const sal_uInt32 nNextCL
= nCLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
446 // remove old builtin formats
447 auto it
= aFTable
.find( nCLOffset
);
448 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
<= nMaxBuiltin
)
450 it
= aFTable
.erase(it
);
453 // move additional and user defined to temporary table
454 SvNumberFormatTable aOldTable
;
455 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
< nNextCL
)
457 aOldTable
[ nKey
] = it
->second
.release();
458 it
= aFTable
.erase(it
);
461 // generate new old builtin formats
462 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
463 ActLnge
= LANGUAGE_DONTKNOW
;
464 ChangeIntl( LANGUAGE_SYSTEM
);
465 ImpGenerateFormats( nCLOffset
, true );
467 // convert additional and user defined from old system to new system
468 SvNumberformat
* pStdFormat
= GetFormatEntry( nCLOffset
+ ZF_STANDARD
);
469 sal_uInt32 nLastKey
= nMaxBuiltin
;
470 pFormatScanner
->SetConvertMode( eOldLanguage
, LANGUAGE_SYSTEM
, true , true);
471 while ( !aOldTable
.empty() )
473 nKey
= aOldTable
.begin()->first
;
474 if ( nLastKey
< nKey
)
478 std::unique_ptr
<SvNumberformat
> pOldEntry(aOldTable
.begin()->second
);
479 aOldTable
.erase( nKey
);
480 OUString
aString( pOldEntry
->GetFormatstring() );
482 // Same as PutEntry() but assures key position even if format code is
483 // a duplicate. Also won't mix up any LastInsertKey.
484 ChangeIntl( eOldLanguage
);
485 LanguageType eLge
= eOldLanguage
; // ConvertMode changes this
487 sal_Int32 nCheckPos
= -1;
488 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( aString
, pFormatScanner
.get(),
489 pStringScanner
.get(), nCheckPos
, eLge
));
490 if ( nCheckPos
== 0 )
492 SvNumFormatType eCheckType
= pNewEntry
->GetType();
493 if ( eCheckType
!= SvNumFormatType::UNDEFINED
)
495 pNewEntry
->SetType( eCheckType
| SvNumFormatType::DEFINED
);
499 pNewEntry
->SetType( SvNumFormatType::DEFINED
);
502 if ( aFTable
.emplace( nKey
, std::move(pNewEntry
) ).second
)
507 DBG_ASSERT( bCheck
, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
509 pFormatScanner
->SetConvertMode(false);
510 pStdFormat
->SetLastInsertKey( sal_uInt16(nLastKey
- nCLOffset
), SvNumberformat::FormatterPrivateAccess() );
512 // append new system additional formats
513 css::uno::Reference
< css::i18n::XNumberFormatCode
> xNFC
= i18n::NumberFormatMapper::create( m_xContext
);
514 ImpGenerateAdditionalFormats( nCLOffset
, xNFC
, true );
517 const css::uno::Reference
<css::uno::XComponentContext
>& SvNumberFormatter::GetComponentContext() const
522 const ImpSvNumberformatScan
* SvNumberFormatter::GetFormatScanner() const { return pFormatScanner
.get(); }
524 const LanguageTag
& SvNumberFormatter::GetLanguageTag() const { return maLanguageTag
; }
526 const ::utl::TransliterationWrapper
* SvNumberFormatter::GetTransliteration() const
528 return xTransliteration
.get();
531 const CharClass
* SvNumberFormatter::GetCharClass() const { return pCharClass
.get(); }
533 const LocaleDataWrapper
* SvNumberFormatter::GetLocaleData() const { return xLocaleData
.get(); }
535 CalendarWrapper
* SvNumberFormatter::GetCalendar() const { return xCalendar
.get(); }
537 const NativeNumberWrapper
* SvNumberFormatter::GetNatNum() const { return xNatNum
.get(); }
539 const OUString
& SvNumberFormatter::GetNumDecimalSep() const { return aDecimalSep
; }
541 const OUString
& SvNumberFormatter::GetNumDecimalSepAlt() const { return aDecimalSepAlt
; }
543 const OUString
& SvNumberFormatter::GetNumThousandSep() const { return aThousandSep
; }
545 const OUString
& SvNumberFormatter::GetDateSep() const { return aDateSep
; }
547 bool SvNumberFormatter::IsDecimalSep( const OUString
& rStr
) const
549 if (rStr
== GetNumDecimalSep())
551 if (GetNumDecimalSepAlt().isEmpty())
553 return rStr
== GetNumDecimalSepAlt();
556 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index
) const
558 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
559 const SvNumberformat
* pFormat
= GetFormatEntry(F_Index
);
561 return pFormat
&& pFormat
->IsTextFormat();
564 bool SvNumberFormatter::PutEntry(OUString
& rString
,
565 sal_Int32
& nCheckPos
,
566 SvNumFormatType
& nType
,
567 sal_uInt32
& nKey
, // format key
570 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
572 if (rString
.isEmpty()) // empty string
574 nCheckPos
= 1; // -> Error
577 if (eLnge
== LANGUAGE_DONTKNOW
)
581 ChangeIntl(eLnge
); // change locale if necessary
582 LanguageType eLge
= eLnge
; // non-const for ConvertMode
584 std::unique_ptr
<SvNumberformat
> p_Entry(new SvNumberformat(rString
,
585 pFormatScanner
.get(),
586 pStringScanner
.get(),
590 if (nCheckPos
== 0) // Format ok
591 { // Type comparison:
592 SvNumFormatType eCheckType
= p_Entry
->GetType();
593 if ( eCheckType
!= SvNumFormatType::UNDEFINED
)
595 p_Entry
->SetType(eCheckType
| SvNumFormatType::DEFINED
);
600 p_Entry
->SetType(SvNumFormatType::DEFINED
);
601 nType
= SvNumFormatType::DEFINED
;
604 sal_uInt32 CLOffset
= ImpGenerateCL(eLge
); // create new standard formats if necessary
606 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLge
);
607 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
) // only in not yet present
609 SvNumberformat
* pStdFormat
= GetFormatEntry(CLOffset
+ ZF_STANDARD
);
610 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
611 if (nPos
+1 - CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
613 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
615 else if (!aFTable
.emplace( nPos
+1, std::move(p_Entry
)).second
)
617 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
623 pStdFormat
->SetLastInsertKey(static_cast<sal_uInt16
>(nKey
-CLOffset
), SvNumberformat::FormatterPrivateAccess());
630 bool SvNumberFormatter::PutandConvertEntry(OUString
& rString
,
631 sal_Int32
& nCheckPos
,
632 SvNumFormatType
& nType
,
635 LanguageType eNewLnge
,
636 bool bConvertDateOrder
)
638 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
640 if (eNewLnge
== LANGUAGE_DONTKNOW
)
644 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, false, bConvertDateOrder
);
645 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
646 pFormatScanner
->SetConvertMode(false);
650 bool SvNumberFormatter::PutandConvertEntrySystem(OUString
& rString
,
651 sal_Int32
& nCheckPos
,
652 SvNumFormatType
& nType
,
655 LanguageType eNewLnge
)
657 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
659 if (eNewLnge
== LANGUAGE_DONTKNOW
)
663 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, true, true);
664 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
665 pFormatScanner
->SetConvertMode(false);
669 sal_uInt32
SvNumberFormatter::GetIndexPuttingAndConverting( OUString
& rString
, LanguageType eLnge
,
670 LanguageType eSysLnge
, SvNumFormatType
& rType
,
671 bool & rNewInserted
, sal_Int32
& rCheckPos
)
673 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
674 sal_uInt32 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
675 rNewInserted
= false;
678 // #62389# empty format string (of Writer) => General standard format
679 if (rString
.isEmpty())
683 else if (eLnge
== LANGUAGE_SYSTEM
&& eSysLnge
!= SvtSysLocale().GetLanguageTag().getLanguageType())
685 sal_uInt32 nOrig
= GetEntryKey( rString
, eSysLnge
);
686 if (nOrig
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
688 nKey
= nOrig
; // none available, maybe user-defined
692 nKey
= GetFormatForLanguageIfBuiltIn( nOrig
, SvtSysLocale().GetLanguageTag().getLanguageType() );
696 // Not a builtin format, convert.
697 // The format code string may get modified and adapted to the real
698 // language and wouldn't match eSysLnge anymore, do that on a copy.
699 OUString
aTmp( rString
);
700 rNewInserted
= PutandConvertEntrySystem( aTmp
, rCheckPos
, rType
,
701 nKey
, eLnge
, SvtSysLocale().GetLanguageTag().getLanguageType());
704 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
705 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
711 nKey
= GetEntryKey( rString
, eLnge
);
712 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
714 rNewInserted
= PutEntry( rString
, rCheckPos
, rType
, nKey
, eLnge
);
717 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
718 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
722 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
724 nKey
= GetStandardIndex( eLnge
);
726 rType
= GetType( nKey
);
727 // Convert any (!) old "automatic" currency format to new fixed currency
729 if (rType
& SvNumFormatType::CURRENCY
)
731 const SvNumberformat
* pFormat
= GetEntry( nKey
);
732 if (!pFormat
->HasNewCurrency())
736 DeleteEntry( nKey
); // don't leave trails of rubbish
737 rNewInserted
= false;
739 nKey
= GetStandardFormat( SvNumFormatType::CURRENCY
, eLnge
);
745 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey
)
747 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
751 void SvNumberFormatter::GetUsedLanguages( std::vector
<LanguageType
>& rList
)
753 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
756 sal_uInt32 nOffset
= 0;
757 while (nOffset
<= MaxCLOffset
)
759 SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
762 rList
.push_back( pFormat
->GetLanguage() );
764 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
769 void SvNumberFormatter::FillKeywordTable( NfKeywordTable
& rKeywords
,
772 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
774 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
775 for ( sal_uInt16 i
= 0; i
< NF_KEYWORD_ENTRIES_COUNT
; ++i
)
777 rKeywords
[i
] = rTable
[i
];
782 void SvNumberFormatter::FillKeywordTableForExcel( NfKeywordTable
& rKeywords
)
784 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
785 FillKeywordTable( rKeywords
, LANGUAGE_ENGLISH_US
);
787 // Replace upper case "GENERAL" with proper case "General".
788 rKeywords
[ NF_KEY_GENERAL
] = GetStandardName( LANGUAGE_ENGLISH_US
);
789 // Remap codes unknown to Excel.
790 rKeywords
[ NF_KEY_NN
] = "DDD";
791 rKeywords
[ NF_KEY_NNN
] = "DDDD";
792 // NNNN gets a separator appended in SvNumberformat::GetMappedFormatString()
793 rKeywords
[ NF_KEY_NNNN
] = "DDDD";
794 // Export the Thai T NatNum modifier.
795 rKeywords
[ NF_KEY_THAI_T
] = "T";
799 OUString
SvNumberFormatter::GetFormatStringForExcel( sal_uInt32 nKey
, const NfKeywordTable
& rKeywords
,
800 SvNumberFormatter
& rTempFormatter
) const
802 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
804 if (const SvNumberformat
* pEntry
= GetEntry( nKey
))
806 if (pEntry
->GetType() == SvNumFormatType::LOGICAL
)
808 // Build Boolean number format, which needs non-zero and zero
809 // subformat codes with TRUE and FALSE strings.
810 Color
* pColor
= nullptr;
812 const_cast< SvNumberformat
* >( pEntry
)->GetOutputString( 1.0, aTemp
, &pColor
);
813 aFormatStr
+= "\"" + aTemp
+ "\";\"" + aTemp
+ "\";\"";
814 const_cast< SvNumberformat
* >( pEntry
)->GetOutputString( 0.0, aTemp
, &pColor
);
815 aFormatStr
+= aTemp
+ "\"";
819 bool bSystemLanguage
= false;
820 LanguageType nLang
= pEntry
->GetLanguage();
821 if (nLang
== LANGUAGE_SYSTEM
)
823 bSystemLanguage
= true;
824 nLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
826 if (nLang
!= LANGUAGE_ENGLISH_US
)
829 SvNumFormatType nType
= SvNumFormatType::DEFINED
;
831 OUString
aTemp( pEntry
->GetFormatstring());
832 rTempFormatter
.PutandConvertEntry( aTemp
, nCheckPos
, nType
, nTempKey
, nLang
, LANGUAGE_ENGLISH_US
, false);
833 SAL_WARN_IF( nCheckPos
!= 0, "svl.numbers",
834 "SvNumberFormatter::GetFormatStringForExcel - format code not convertible");
835 if (nTempKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
836 pEntry
= rTempFormatter
.GetEntry( nTempKey
);
841 // GetLocaleData() returns the current locale's data, so switch
842 // before (which doesn't do anything if it was the same locale
844 rTempFormatter
.ChangeIntl( LANGUAGE_ENGLISH_US
);
845 aFormatStr
= pEntry
->GetMappedFormatstring( rKeywords
, *rTempFormatter
.GetLocaleData(), nLang
,
852 SAL_WARN("svl.numbers","SvNumberFormatter::GetFormatStringForExcel - format not found: " << nKey
);
855 if (aFormatStr
.isEmpty())
856 aFormatStr
= "General";
861 OUString
SvNumberFormatter::GetKeyword( LanguageType eLnge
, sal_uInt16 nIndex
)
863 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
865 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
866 if ( nIndex
< NF_KEYWORD_ENTRIES_COUNT
)
868 return rTable
[nIndex
];
870 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
875 OUString
SvNumberFormatter::GetStandardName( LanguageType eLnge
)
877 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
879 return pFormatScanner
->GetStandardName();
883 sal_uInt32
SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge
) const
885 sal_uInt32 nOffset
= 0;
886 while (nOffset
<= MaxCLOffset
)
888 const SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
889 if (pFormat
&& pFormat
->GetLanguage() == eLnge
)
893 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
898 sal_uInt32
SvNumberFormatter::ImpIsEntry(const OUString
& rString
,
899 sal_uInt32 nCLOffset
,
902 sal_uInt32 res
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
903 auto it
= aFTable
.find( nCLOffset
);
904 while ( res
== NUMBERFORMAT_ENTRY_NOT_FOUND
&&
905 it
!= aFTable
.end() && it
->second
->GetLanguage() == eLnge
)
907 if ( rString
== it
->second
->GetFormatstring() )
920 SvNumberFormatTable
& SvNumberFormatter::GetFirstEntryTable(
921 SvNumFormatType
& eType
,
925 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
926 SvNumFormatType eTypetmp
= eType
;
927 if (eType
== SvNumFormatType::ALL
) // empty cell or don't care
933 SvNumberformat
* pFormat
= GetFormatEntry(FIndex
);
937 eType
= SvNumFormatType::ALL
;
942 rLnge
= pFormat
->GetLanguage();
943 eType
= pFormat
->GetMaskedType();
944 if (eType
== SvNumFormatType::ALL
)
946 eType
= SvNumFormatType::DEFINED
;
949 else if (eType
== SvNumFormatType::DATETIME
)
952 eType
= SvNumFormatType::DATE
;
961 return GetEntryTable(eTypetmp
, FIndex
, rLnge
);
964 sal_uInt32
SvNumberFormatter::ImpGenerateCL( LanguageType eLnge
)
967 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
968 if (CLOffset
> MaxCLOffset
)
970 // new CL combination
971 if (LocaleDataWrapper::areChecksEnabled())
973 const LanguageTag
& rLoadedLocale
= xLocaleData
->getLoadedLanguageTag();
974 if ( !rLoadedLocale
.equals( maLanguageTag
) )
976 OUString
const aMsg("SvNumberFormatter::ImpGenerateCL: locales don't match:");
977 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
979 // test XML locale data FormatElement entries
981 uno::Sequence
< i18n::FormatElement
> xSeq
= xLocaleData
->getAllFormats();
982 // A test for completeness of formatindex="0" ...
983 // formatindex="47" is not needed here since it is done in
984 // ImpGenerateFormats().
986 // Test for dupes of formatindex="..."
987 for ( sal_Int32 j
= 0; j
< xSeq
.getLength(); j
++ )
989 sal_Int16 nIdx
= xSeq
[j
].formatIndex
;
990 OUStringBuffer aDupes
;
991 for ( sal_Int32 i
= 0; i
< xSeq
.getLength(); i
++ )
993 if ( i
!= j
&& xSeq
[i
].formatIndex
== nIdx
)
995 aDupes
.append(OUString::number( i
));
997 aDupes
.append(xSeq
[i
].formatKey
);
998 aDupes
.append( ") ");
1001 if ( !aDupes
.isEmpty() )
1003 OUString aMsg
= "XML locale data FormatElement formatindex dupe: "
1004 + OUString::number(nIdx
)
1005 + "\nFormatElements: "
1006 + OUString::number( j
)
1010 + aDupes
.makeStringAndClear();
1011 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1017 MaxCLOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
1018 ImpGenerateFormats( MaxCLOffset
, false/*bNoAdditionalFormats*/ );
1019 CLOffset
= MaxCLOffset
;
1024 SvNumberFormatTable
& SvNumberFormatter::ChangeCL(SvNumFormatType eType
,
1028 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1029 ImpGenerateCL(eLnge
);
1030 return GetEntryTable(eType
, FIndex
, ActLnge
);
1033 SvNumberFormatTable
& SvNumberFormatter::GetEntryTable(
1034 SvNumFormatType eType
,
1038 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1041 pFormatTable
->clear();
1045 pFormatTable
.reset( new SvNumberFormatTable
);
1048 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
1050 // Might generate and insert a default format for the given type
1051 // (e.g. currency) => has to be done before collecting formats.
1052 sal_uInt32 nDefaultIndex
= GetStandardFormat( eType
, ActLnge
);
1054 auto it
= aFTable
.find( CLOffset
);
1056 if (eType
== SvNumFormatType::ALL
)
1058 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
1059 { // copy all entries to output table
1060 (*pFormatTable
)[ it
->first
] = it
->second
.get();
1066 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
1067 { // copy entries of queried type to output table
1068 if ((it
->second
->GetType()) & eType
)
1069 (*pFormatTable
)[ it
->first
] = it
->second
.get();
1073 if ( !pFormatTable
->empty() )
1074 { // select default if queried format doesn't exist or queried type or
1075 // language differ from existing format
1076 SvNumberformat
* pEntry
= GetFormatEntry(FIndex
);
1077 if ( !pEntry
|| !(pEntry
->GetType() & eType
) || pEntry
->GetLanguage() != ActLnge
)
1079 FIndex
= nDefaultIndex
;
1082 return *pFormatTable
;
1085 bool SvNumberFormatter::IsNumberFormat(const OUString
& sString
,
1086 sal_uInt32
& F_Index
,
1089 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1091 SvNumFormatType FType
;
1092 // For the 0 General format directly use the init/system locale and avoid
1093 // all overhead that is associated with a format passed to the scanner.
1094 const SvNumberformat
* pFormat
= (F_Index
== 0 ? nullptr : ImpSubstituteEntry( GetFormatEntry(F_Index
)));
1097 ChangeIntl(IniLnge
);
1098 FType
= SvNumFormatType::NUMBER
;
1102 FType
= pFormat
->GetMaskedType();
1103 if (FType
== SvNumFormatType::ALL
)
1105 FType
= SvNumFormatType::DEFINED
;
1107 ChangeIntl(pFormat
->GetLanguage());
1108 // Avoid scanner overhead with the General format of any locale.
1109 // These are never substituted above so safe to ignore.
1110 if ((F_Index
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0)
1112 assert(FType
== SvNumFormatType::NUMBER
);
1118 SvNumFormatType RType
= FType
;
1119 if (RType
== SvNumFormatType::TEXT
)
1121 res
= false; // type text preset => no conversion to number
1125 res
= pStringScanner
->IsNumberFormat(sString
, RType
, fOutNumber
, pFormat
);
1127 if (res
&& !IsCompatible(FType
, RType
)) // non-matching type
1131 case SvNumFormatType::DATE
:
1132 // Preserve ISO 8601 input.
1133 if (pStringScanner
->CanForceToIso8601( DateOrder::Invalid
))
1135 F_Index
= GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, ActLnge
);
1139 F_Index
= GetStandardFormat( RType
, ActLnge
);
1142 case SvNumFormatType::TIME
:
1143 if ( pStringScanner
->GetDecPos() )
1146 if ( pStringScanner
->GetNumericsCount() > 3 || fOutNumber
< 0.0 )
1148 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS00
, ActLnge
);
1152 F_Index
= GetFormatIndex( NF_TIME_MMSS00
, ActLnge
);
1155 else if ( fOutNumber
>= 1.0 || fOutNumber
< 0.0 )
1157 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS
, ActLnge
);
1161 F_Index
= GetStandardFormat( RType
, ActLnge
);
1165 F_Index
= GetStandardFormat( RType
, ActLnge
);
1171 LanguageType
SvNumberFormatter::GetLanguage() const
1173 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1178 bool SvNumberFormatter::IsCompatible(SvNumFormatType eOldType
, SvNumFormatType eNewType
)
1180 if (eOldType
== eNewType
)
1184 else if (eOldType
== SvNumFormatType::DEFINED
)
1192 case SvNumFormatType::NUMBER
:
1195 case SvNumFormatType::PERCENT
:
1196 case SvNumFormatType::CURRENCY
:
1197 case SvNumFormatType::SCIENTIFIC
:
1198 case SvNumFormatType::FRACTION
:
1199 case SvNumFormatType::DEFINED
:
1201 case SvNumFormatType::LOGICAL
:
1206 case SvNumFormatType::DATE
:
1209 case SvNumFormatType::DATETIME
:
1215 case SvNumFormatType::TIME
:
1218 case SvNumFormatType::DATETIME
:
1224 case SvNumFormatType::DATETIME
:
1227 case SvNumFormatType::TIME
:
1228 case SvNumFormatType::DATE
:
1241 sal_uInt32
SvNumberFormatter::ImpGetDefaultFormat( SvNumFormatType nType
)
1243 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
1247 case SvNumFormatType::DATE
:
1248 nSearch
= CLOffset
+ ZF_STANDARD_DATE
;
1250 case SvNumFormatType::TIME
:
1251 nSearch
= CLOffset
+ ZF_STANDARD_TIME
;
1253 case SvNumFormatType::DATETIME
:
1254 nSearch
= CLOffset
+ ZF_STANDARD_DATETIME
;
1256 case SvNumFormatType::PERCENT
:
1257 nSearch
= CLOffset
+ ZF_STANDARD_PERCENT
;
1259 case SvNumFormatType::SCIENTIFIC
:
1260 nSearch
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1263 nSearch
= CLOffset
+ ZF_STANDARD
;
1266 DefaultFormatKeysMap::const_iterator it
= aDefaultFormatKeys
.find( nSearch
);
1267 sal_uInt32 nDefaultFormat
= (it
!= aDefaultFormatKeys
.end() ?
1268 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
1269 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1271 // look for a defined standard
1272 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
1274 auto it2
= aFTable
.find( CLOffset
);
1275 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
1277 const SvNumberformat
* pEntry
= it2
->second
.get();
1278 if ( pEntry
->IsStandard() && (pEntry
->GetMaskedType() == nType
) )
1280 nDefaultFormat
= nKey
;
1286 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1287 { // none found, use old fixed standards
1290 case SvNumFormatType::DATE
:
1291 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATE
;
1293 case SvNumFormatType::TIME
:
1294 nDefaultFormat
= CLOffset
+ ZF_STANDARD_TIME
+1;
1296 case SvNumFormatType::DATETIME
:
1297 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATETIME
;
1299 case SvNumFormatType::PERCENT
:
1300 nDefaultFormat
= CLOffset
+ ZF_STANDARD_PERCENT
+1;
1302 case SvNumFormatType::SCIENTIFIC
:
1303 nDefaultFormat
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1306 nDefaultFormat
= CLOffset
+ ZF_STANDARD
;
1309 aDefaultFormatKeys
[ nSearch
] = nDefaultFormat
;
1311 return nDefaultFormat
;
1315 sal_uInt32
SvNumberFormatter::GetStandardFormat( SvNumFormatType eType
, LanguageType eLnge
)
1317 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1318 if (eLnge
== LANGUAGE_DONTKNOW
)
1322 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1325 case SvNumFormatType::CURRENCY
:
1326 return ( eLnge
== LANGUAGE_SYSTEM
) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1327 case SvNumFormatType::DATE
:
1328 case SvNumFormatType::TIME
:
1329 case SvNumFormatType::DATETIME
:
1330 case SvNumFormatType::PERCENT
:
1331 case SvNumFormatType::SCIENTIFIC
:
1332 return ImpGetDefaultFormat( eType
);
1333 case SvNumFormatType::FRACTION
:
1334 return CLOffset
+ ZF_STANDARD_FRACTION
;
1335 case SvNumFormatType::LOGICAL
:
1336 return CLOffset
+ ZF_STANDARD_LOGICAL
;
1337 case SvNumFormatType::TEXT
:
1338 return CLOffset
+ ZF_STANDARD_TEXT
;
1339 case SvNumFormatType::ALL
:
1340 case SvNumFormatType::DEFINED
:
1341 case SvNumFormatType::NUMBER
:
1342 case SvNumFormatType::UNDEFINED
:
1344 return CLOffset
+ ZF_STANDARD
;
1348 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex
,
1349 LanguageType eLnge
)
1351 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1353 nFIndex
== GetFormatIndex( NF_TIME_MMSS00
, eLnge
) ||
1354 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
) ||
1355 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
)
1359 sal_uInt32
SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex
, SvNumFormatType eType
,
1360 LanguageType eLnge
)
1362 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1363 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1366 return GetStandardFormat( eType
, eLnge
);
1369 sal_uInt32
SvNumberFormatter::GetTimeFormat( double fNumber
, LanguageType eLnge
)
1371 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1373 if ( fNumber
< 0.0 )
1380 double fSeconds
= fNumber
* 86400;
1381 if ( floor( fSeconds
+ 0.5 ) * 100 != floor( fSeconds
* 100 + 0.5 ) )
1382 { // with 100th seconds
1383 if ( bSign
|| fSeconds
>= 3600 )
1384 return GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
);
1386 return GetFormatIndex( NF_TIME_MMSS00
, eLnge
);
1390 if ( bSign
|| fNumber
>= 1.0 )
1391 return GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
);
1393 return GetStandardFormat( SvNumFormatType::TIME
, eLnge
);
1397 sal_uInt32
SvNumberFormatter::GetStandardFormat( double fNumber
, sal_uInt32 nFIndex
,
1398 SvNumFormatType eType
, LanguageType eLnge
)
1400 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1401 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1406 case SvNumFormatType::TIME
:
1407 return GetTimeFormat( fNumber
, eLnge
);
1409 return GetStandardFormat( eType
, eLnge
);
1413 sal_uInt32
SvNumberFormatter::GuessDateTimeFormat( SvNumFormatType
& rType
, double fNumber
, LanguageType eLnge
)
1415 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1416 // Categorize the format according to the implementation of
1417 // SvNumberFormatter::GetEditFormat(), making assumptions about what
1418 // would be time only.
1420 if (0.0 <= fNumber
&& fNumber
< 1.0)
1423 rType
= SvNumFormatType::TIME
;
1424 nRet
= GetTimeFormat( fNumber
, eLnge
);
1426 else if (fabs( fNumber
) * 24 < 0x7fff)
1428 // Assuming time within 32k hours or 3.7 years.
1429 rType
= SvNumFormatType::TIME
;
1430 nRet
= GetTimeFormat( fNumber
, eLnge
);
1432 else if (rtl::math::approxFloor( fNumber
) != fNumber
)
1435 rType
= SvNumFormatType::DATETIME
;
1436 nRet
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLnge
);
1441 rType
= SvNumFormatType::DATE
;
1442 nRet
= GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, eLnge
);
1447 sal_uInt32
SvNumberFormatter::GetEditFormat( double fNumber
, sal_uInt32 nFIndex
,
1448 SvNumFormatType eType
, LanguageType eLang
,
1449 SvNumberformat
const * pFormat
)
1451 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1452 sal_uInt32 nKey
= nFIndex
;
1455 // #61619# always edit using 4-digit year
1456 case SvNumFormatType::DATE
:
1458 // Preserve ISO 8601 format.
1460 nFIndex
== GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, eLang
) ||
1461 nFIndex
== GetFormatIndex( NF_DATE_DIN_YYMMDD
, eLang
) ||
1462 nFIndex
== GetFormatIndex( NF_DATE_DIN_MMDD
, eLang
) ||
1463 (pFormat
&& pFormat
->IsIso8601( 0 ));
1464 if (rtl::math::approxFloor( fNumber
) != fNumber
)
1466 // fdo#34977 preserve time when editing even if only date was
1469 nKey
= GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eLang
);
1471 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1476 nKey
= GetFormatIndex( NF_DATE_ISO_YYYYMMDD
, eLang
);
1478 nKey
= GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, eLang
);
1482 case SvNumFormatType::TIME
:
1483 if (fNumber
< 0.0 || fNumber
>= 1.0)
1485 /* XXX NOTE: this is a purely arbitrary value within the limits
1486 * of a signed 16-bit. 32k hours are 3.7 years ... or
1487 * 1903-09-26 if date. */
1488 if (fabs( fNumber
) * 24 < 0x7fff)
1489 nKey
= GetFormatIndex( NF_TIME_HH_MMSS
, eLang
);
1490 // Preserve duration, use [HH]:MM:SS instead of time.
1492 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1493 // Assume that a large value is a datetime with only time
1497 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1499 case SvNumFormatType::DATETIME
:
1500 if (nFIndex
== GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eLang
) || (pFormat
&& pFormat
->IsIso8601( 0 )))
1501 nKey
= GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, eLang
);
1503 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1505 case SvNumFormatType::NUMBER
:
1506 nKey
= GetStandardFormat( eType
, eLang
);
1509 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1514 void SvNumberFormatter::GetInputLineString(const double& fOutNumber
,
1516 OUString
& sOutString
)
1518 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1520 sal_uInt32 nRealKey
= nFIndex
;
1521 SvNumberformat
* pFormat
= ImpSubstituteEntry( GetFormatEntry( nFIndex
), &nRealKey
);
1524 pFormat
= GetFormatEntry(ZF_STANDARD
);
1527 LanguageType eLang
= pFormat
->GetLanguage();
1528 ChangeIntl( eLang
);
1530 SvNumFormatType eType
= pFormat
->GetMaskedType();
1531 if (eType
== SvNumFormatType::ALL
)
1533 // Mixed types in subformats, use first.
1534 /* XXX we could choose a subformat according to fOutNumber and
1535 * subformat conditions, but they may exist to suppress 0 or negative
1536 * numbers so wouldn't be a safe bet. */
1537 eType
= pFormat
->GetNumForInfoScannedType(0);
1540 sal_uInt16 nOldPrec
= pFormatScanner
->GetStandardPrec();
1541 bool bPrecChanged
= false;
1542 if (eType
== SvNumFormatType::NUMBER
||
1543 eType
== SvNumFormatType::PERCENT
||
1544 eType
== SvNumFormatType::CURRENCY
||
1545 eType
== SvNumFormatType::SCIENTIFIC
||
1546 eType
== SvNumFormatType::FRACTION
)
1548 if (eType
!= SvNumFormatType::PERCENT
) // special treatment of % later
1550 eType
= SvNumFormatType::NUMBER
;
1552 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1553 bPrecChanged
= true;
1556 sal_uInt32 nKey
= GetEditFormat( fOutNumber
, nRealKey
, eType
, eLang
, pFormat
);
1557 if ( nKey
!= nRealKey
)
1559 pFormat
= GetFormatEntry( nKey
);
1563 if ( eType
== SvNumFormatType::TIME
&& pFormat
->GetFormatPrecision() )
1565 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1566 bPrecChanged
= true;
1568 pFormat
->GetOutputString(fOutNumber
, sOutString
, &pColor
);
1572 ChangeStandardPrec(nOldPrec
);
1576 void SvNumberFormatter::GetOutputString(const OUString
& sString
,
1578 OUString
& sOutString
,
1580 bool bUseStarFormat
)
1582 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1583 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1584 // ImpSubstituteEntry() is unnecessary here because so far only numeric
1585 // (time and date) are substituted.
1588 pFormat
= GetFormatEntry(ZF_STANDARD_TEXT
);
1590 if (!pFormat
->IsTextFormat() && !pFormat
->HasTextFormat())
1593 sOutString
= sString
;
1597 ChangeIntl(pFormat
->GetLanguage());
1598 if ( bUseStarFormat
)
1600 pFormat
->SetStarFormatSupport( true );
1602 pFormat
->GetOutputString(sString
, sOutString
, ppColor
);
1603 if ( bUseStarFormat
)
1605 pFormat
->SetStarFormatSupport( false );
1610 void SvNumberFormatter::GetOutputString(const double& fOutNumber
,
1612 OUString
& sOutString
,
1614 bool bUseStarFormat
)
1616 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1617 if (bNoZero
&& fOutNumber
== 0.0)
1622 SvNumberformat
* pFormat
= ImpSubstituteEntry( GetFormatEntry( nFIndex
));
1624 pFormat
= GetFormatEntry(ZF_STANDARD
);
1625 ChangeIntl(pFormat
->GetLanguage());
1626 if ( bUseStarFormat
)
1627 pFormat
->SetStarFormatSupport( true );
1628 pFormat
->GetOutputString(fOutNumber
, sOutString
, ppColor
);
1629 if ( bUseStarFormat
)
1630 pFormat
->SetStarFormatSupport( false );
1633 bool SvNumberFormatter::GetPreviewString(const OUString
& sFormatString
,
1634 double fPreviewNumber
,
1635 OUString
& sOutString
,
1638 bool bUseStarFormat
)
1640 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1641 if (sFormatString
.isEmpty()) // no empty string
1646 if (eLnge
== LANGUAGE_DONTKNOW
)
1650 ChangeIntl(eLnge
); // change locale if necessary
1652 sal_Int32 nCheckPos
= -1;
1653 OUString sTmpString
= sFormatString
;
1654 std::unique_ptr
<SvNumberformat
> p_Entry(new SvNumberformat(sTmpString
,
1655 pFormatScanner
.get(),
1656 pStringScanner
.get(),
1659 if (nCheckPos
== 0) // String ok
1661 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
1662 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLnge
);
1663 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1665 GetOutputString(fPreviewNumber
, nKey
, sOutString
, ppColor
, bUseStarFormat
);
1669 if ( bUseStarFormat
)
1671 p_Entry
->SetStarFormatSupport( true );
1673 p_Entry
->GetOutputString(fPreviewNumber
, sOutString
, ppColor
);
1674 if ( bUseStarFormat
)
1676 p_Entry
->SetStarFormatSupport( false );
1687 bool SvNumberFormatter::GetPreviewStringGuess( const OUString
& sFormatString
,
1688 double fPreviewNumber
,
1689 OUString
& sOutString
,
1691 LanguageType eLnge
)
1693 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1694 if (sFormatString
.isEmpty()) // no empty string
1698 if (eLnge
== LANGUAGE_DONTKNOW
)
1702 ChangeIntl( eLnge
);
1704 bool bEnglish
= (eLnge
== LANGUAGE_ENGLISH_US
);
1706 OUString
aFormatStringUpper( pCharClass
->uppercase( sFormatString
) );
1707 sal_uInt32 nCLOffset
= ImpGenerateCL( eLnge
);
1708 sal_uInt32 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, eLnge
);
1709 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1711 // Target format present
1712 GetOutputString( fPreviewNumber
, nKey
, sOutString
, ppColor
);
1716 std::unique_ptr
<SvNumberformat
> pEntry
;
1717 sal_Int32 nCheckPos
= -1;
1718 OUString sTmpString
;
1722 sTmpString
= sFormatString
;
1723 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
.get(),
1724 pStringScanner
.get(), nCheckPos
, eLnge
));
1728 nCLOffset
= ImpGenerateCL( LANGUAGE_ENGLISH_US
);
1729 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, LANGUAGE_ENGLISH_US
);
1730 bool bEnglishFormat
= (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
1732 // Try English -> other or convert english to other
1733 LanguageType eFormatLang
= LANGUAGE_ENGLISH_US
;
1734 pFormatScanner
->SetConvertMode( LANGUAGE_ENGLISH_US
, eLnge
, false, false);
1735 sTmpString
= sFormatString
;
1736 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
.get(),
1737 pStringScanner
.get(), nCheckPos
, eFormatLang
));
1738 pFormatScanner
->SetConvertMode( false );
1739 ChangeIntl( eLnge
);
1741 if ( !bEnglishFormat
)
1743 if ( nCheckPos
!= 0 || xTransliteration
->isEqual( sFormatString
,
1744 pEntry
->GetFormatstring() ) )
1747 // Force locale's keywords.
1748 pFormatScanner
->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy
);
1749 sTmpString
= sFormatString
;
1750 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
.get(),
1751 pStringScanner
.get(), nCheckPos
, eLnge
));
1756 sal_Int32 nCheckPos2
= -1;
1757 // try other --> english
1758 eFormatLang
= eLnge
;
1759 pFormatScanner
->SetConvertMode( eLnge
, LANGUAGE_ENGLISH_US
, false, false);
1760 sTmpString
= sFormatString
;
1761 std::unique_ptr
<SvNumberformat
> pEntry2(new SvNumberformat( sTmpString
, pFormatScanner
.get(),
1762 pStringScanner
.get(), nCheckPos2
, eFormatLang
));
1763 pFormatScanner
->SetConvertMode( false );
1764 ChangeIntl( eLnge
);
1765 if ( nCheckPos2
== 0 && !xTransliteration
->isEqual( sFormatString
,
1766 pEntry2
->GetFormatstring() ) )
1769 // Force locale's keywords.
1770 pFormatScanner
->ChangeIntl( ImpSvNumberformatScan::KeywordLocalization::LocaleLegacy
);
1771 sTmpString
= sFormatString
;
1772 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
.get(),
1773 pStringScanner
.get(), nCheckPos
, eLnge
));
1779 if (nCheckPos
== 0) // String ok
1781 ImpGenerateCL( eLnge
); // create new standard formats if necessary
1782 pEntry
->GetOutputString( fPreviewNumber
, sOutString
, ppColor
);
1788 bool SvNumberFormatter::GetPreviewString( const OUString
& sFormatString
,
1789 const OUString
& sPreviewString
,
1790 OUString
& sOutString
,
1792 LanguageType eLnge
)
1794 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1795 if (sFormatString
.isEmpty()) // no empty string
1800 if (eLnge
== LANGUAGE_DONTKNOW
)
1804 ChangeIntl(eLnge
); // switch if needed
1806 sal_Int32 nCheckPos
= -1;
1807 OUString sTmpString
= sFormatString
;
1808 std::unique_ptr
<SvNumberformat
> p_Entry(new SvNumberformat( sTmpString
,
1809 pFormatScanner
.get(),
1810 pStringScanner
.get(),
1813 if (nCheckPos
== 0) // String ok
1815 // May have to create standard formats for this locale.
1816 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1817 nKey
= ImpIsEntry( p_Entry
->GetFormatstring(), CLOffset
, eLnge
);
1818 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1820 GetOutputString( sPreviewString
, nKey
, sOutString
, ppColor
);
1824 // If the format is valid but not a text format and does not
1825 // include a text subformat, an empty string would result. Same as
1826 // in SvNumberFormatter::GetOutputString()
1827 if (p_Entry
->IsTextFormat() || p_Entry
->HasTextFormat())
1829 p_Entry
->GetOutputString( sPreviewString
, sOutString
, ppColor
);
1834 sOutString
= sPreviewString
;
1845 sal_uInt32
SvNumberFormatter::TestNewString(const OUString
& sFormatString
,
1848 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
1849 if (sFormatString
.isEmpty()) // no empty string
1851 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
1853 if (eLnge
== LANGUAGE_DONTKNOW
)
1857 ChangeIntl(eLnge
); // change locale if necessary
1860 sal_Int32 nCheckPos
= -1;
1861 OUString sTmpString
= sFormatString
;
1862 std::unique_ptr
<SvNumberformat
> pEntry(new SvNumberformat(sTmpString
,
1863 pFormatScanner
.get(),
1864 pStringScanner
.get(),
1867 if (nCheckPos
== 0) // String ok
1869 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
1870 nRes
= ImpIsEntry(pEntry
->GetFormatstring(),CLOffset
, eLnge
);
1875 nRes
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1880 SvNumberformat
* SvNumberFormatter::ImpInsertFormat( const css::i18n::NumberFormatCode
& rCode
,
1881 sal_uInt32 nPos
, bool bAfterChangingSystemCL
,
1882 sal_Int16 nOrgIndex
)
1884 SAL_WARN_IF( NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
<= rCode
.Index
&& rCode
.Index
< NF_INDEX_TABLE_ENTRIES
,
1885 "svl.numbers", "i18npool locale '" << maLanguageTag
.getBcp47() <<
1886 "' uses reserved formatIndex value " << rCode
.Index
<< ", next free: " << NF_INDEX_TABLE_ENTRIES
<<
1887 " Please see description in include/svl/zforlist.hxx at end of enum NfIndexTableOffset");
1888 assert( (rCode
.Index
< NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
|| NF_INDEX_TABLE_ENTRIES
<= rCode
.Index
) &&
1889 "reserved formatIndex, see warning above");
1891 OUString
aCodeStr( rCode
.Code
);
1892 if ( rCode
.Index
< NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
&&
1893 rCode
.Usage
== css::i18n::KNumberFormatUsage::CURRENCY
&&
1894 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
1895 { // strip surrounding [$...] on automatic currency
1896 if ( aCodeStr
.indexOf( "[$" ) >= 0)
1897 aCodeStr
= SvNumberformat::StripNewCurrencyDelimiters( aCodeStr
);
1900 if (LocaleDataWrapper::areChecksEnabled() &&
1901 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
1903 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index " +
1904 OUString::number( rCode
.Index
) +
1907 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1911 sal_Int32 nCheckPos
= 0;
1912 std::unique_ptr
<SvNumberformat
> pFormat(new SvNumberformat(aCodeStr
,
1913 pFormatScanner
.get(),
1914 pStringScanner
.get(),
1919 if (LocaleDataWrapper::areChecksEnabled())
1921 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
1922 OUString::number( rCode
.Index
) +
1925 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1929 if ( rCode
.Index
>= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
)
1931 sal_uInt32 nCLOffset
= nPos
- (nPos
% SV_COUNTRY_LANGUAGE_OFFSET
);
1932 sal_uInt32 nKey
= ImpIsEntry( aCodeStr
, nCLOffset
, ActLnge
);
1933 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1935 // If bAfterChangingSystemCL there will definitely be some dups,
1937 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL
)
1939 // Test for duplicate indexes in locale data.
1940 switch ( nOrgIndex
)
1942 // These may be dups of integer versions for locales where
1943 // currencies have no decimals like Italian Lira.
1944 case NF_CURRENCY_1000DEC2
: // NF_CURRENCY_1000INT
1945 case NF_CURRENCY_1000DEC2_RED
: // NF_CURRENCY_1000INT_RED
1946 case NF_CURRENCY_1000DEC2_DASHED
: // NF_CURRENCY_1000INT_RED
1950 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: dup format code, index "
1951 + OUString::number( rCode
.Index
)
1954 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1960 else if ( nPos
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
1962 if (LocaleDataWrapper::areChecksEnabled())
1964 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: too many format codes, index "
1965 + OUString::number( rCode
.Index
)
1968 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1973 auto pFormat2
= pFormat
.get();
1974 if ( !aFTable
.emplace( nPos
, std::move(pFormat
) ).second
)
1976 if (LocaleDataWrapper::areChecksEnabled())
1978 OUString aMsg
= "ImpInsertFormat: can't insert number format key pos: "
1979 + OUString::number( nPos
)
1981 + OUString::number( rCode
.Index
)
1984 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1988 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
1992 if ( rCode
.Default
)
1993 pFormat2
->SetStandard();
1994 if ( !rCode
.DefaultName
.isEmpty() )
1995 pFormat2
->SetComment( rCode
.DefaultName
);
1999 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat
,
2002 sal_uInt16
& nPrecision
,
2003 sal_uInt16
& nLeadingCnt
)
2006 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2007 SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
2009 pFormat
->GetFormatSpecialInfo(bThousand
, IsRed
,
2010 nPrecision
, nLeadingCnt
);
2015 nPrecision
= pFormatScanner
->GetStandardPrec();
2020 sal_uInt16
SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat
) const
2022 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2023 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
2025 return pFormat
->GetFormatPrecision();
2027 return pFormatScanner
->GetStandardPrec();
2030 sal_uInt16
SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat
) const
2032 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2033 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
2035 return pFormat
->GetFormatIntegerDigits();
2040 OUString
SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat
) const
2042 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2043 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
2046 return GetNumDecimalSep();
2048 return GetLangDecimalSep( pFormat
->GetLanguage());
2051 OUString
SvNumberFormatter::GetLangDecimalSep( LanguageType nLang
) const
2053 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2054 if (nLang
== ActLnge
)
2056 return GetNumDecimalSep();
2059 LanguageType eSaveLang
= xLocaleData
.getCurrentLanguage();
2060 if (nLang
== eSaveLang
)
2062 aRet
= xLocaleData
->getNumDecimalSep();
2066 LanguageTag
aSaveLocale( xLocaleData
->getLanguageTag() );
2067 const_cast<SvNumberFormatter
*>(this)->xLocaleData
.changeLocale( LanguageTag( nLang
));
2068 aRet
= xLocaleData
->getNumDecimalSep();
2069 const_cast<SvNumberFormatter
*>(this)->xLocaleData
.changeLocale( aSaveLocale
);
2075 sal_uInt32
SvNumberFormatter::GetFormatSpecialInfo( const OUString
& rFormatString
,
2076 bool& bThousand
, bool& IsRed
, sal_uInt16
& nPrecision
,
2077 sal_uInt16
& nLeadingCnt
, LanguageType eLnge
)
2080 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2081 if (eLnge
== LANGUAGE_DONTKNOW
)
2085 ChangeIntl(eLnge
); // change locale if necessary
2087 OUString
aTmpStr( rFormatString
);
2088 sal_Int32 nCheckPos
= 0;
2089 std::unique_ptr
<SvNumberformat
> pFormat(new SvNumberformat( aTmpStr
, pFormatScanner
.get(),
2090 pStringScanner
.get(), nCheckPos
, eLnge
));
2091 if ( nCheckPos
== 0 )
2093 pFormat
->GetFormatSpecialInfo( bThousand
, IsRed
, nPrecision
, nLeadingCnt
);
2099 nPrecision
= pFormatScanner
->GetStandardPrec();
2105 sal_Int32
SvNumberFormatter::ImpGetFormatCodeIndex(
2106 css::uno::Sequence
< css::i18n::NumberFormatCode
>& rSeq
,
2107 const NfIndexTableOffset nTabOff
)
2109 const sal_Int32 nLen
= rSeq
.getLength();
2110 for ( sal_Int32 j
=0; j
<nLen
; j
++ )
2112 if ( rSeq
[j
].Index
== nTabOff
)
2115 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff
< NF_CURRENCY_START
2116 || NF_CURRENCY_END
< nTabOff
|| nTabOff
== NF_CURRENCY_1000INT
2117 || nTabOff
== NF_CURRENCY_1000INT_RED
2118 || nTabOff
== NF_CURRENCY_1000DEC2_CCC
))
2119 { // currency entries with decimals might not exist, e.g. Italian Lira
2120 OUString aMsg
= "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "
2121 + OUString::number( nTabOff
);
2122 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo(aMsg
));
2127 // look for a preset default
2128 for ( j
=0; j
<nLen
; j
++ )
2130 if ( rSeq
[j
].Default
)
2133 // currencies are special, not all format codes must exist, but all
2134 // builtin number format key index positions must have a format assigned
2135 if ( NF_CURRENCY_START
<= nTabOff
&& nTabOff
<= NF_CURRENCY_END
)
2137 // look for a format with decimals
2138 for ( j
=0; j
<nLen
; j
++ )
2140 if ( rSeq
[j
].Index
== NF_CURRENCY_1000DEC2
)
2143 // last resort: look for a format without decimals
2144 for ( j
=0; j
<nLen
; j
++ )
2146 if ( rSeq
[j
].Index
== NF_CURRENCY_1000INT
)
2152 { // we need at least _some_ format
2154 rSeq
[0] = css::i18n::NumberFormatCode();
2155 rSeq
[0].Code
= "0" + GetNumDecimalSep() + "############";
2161 void SvNumberFormatter::ImpAdjustFormatCodeDefault(
2162 css::i18n::NumberFormatCode
* pFormatArr
,
2167 if (LocaleDataWrapper::areChecksEnabled())
2169 // check the locale data for correctness
2171 sal_Int32 nElem
, nShort
, nMedium
, nLong
, nShortDef
, nMediumDef
, nLongDef
;
2172 nShort
= nMedium
= nLong
= nShortDef
= nMediumDef
= nLongDef
= -1;
2173 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2175 switch ( pFormatArr
[nElem
].Type
)
2177 case i18n::KNumberFormatType::SHORT
:
2180 case i18n::KNumberFormatType::MEDIUM
:
2183 case i18n::KNumberFormatType::LONG
:
2187 aMsg
.append("unknown type");
2189 if ( pFormatArr
[nElem
].Default
)
2191 switch ( pFormatArr
[nElem
].Type
)
2193 case i18n::KNumberFormatType::SHORT
:
2194 if ( nShortDef
!= -1 )
2195 aMsg
.append("dupe short type default");
2198 case i18n::KNumberFormatType::MEDIUM
:
2199 if ( nMediumDef
!= -1 )
2200 aMsg
.append("dupe medium type default");
2203 case i18n::KNumberFormatType::LONG
:
2204 if ( nLongDef
!= -1 )
2205 aMsg
.append("dupe long type default");
2210 if (!aMsg
.isEmpty())
2212 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2213 aMsg
.append("\nXML locale data FormatElement formatindex: ");
2214 aMsg
.append(static_cast<sal_Int32
>(pFormatArr
[nElem
].Index
));
2215 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(),
2216 RTL_TEXTENCODING_ASCII_US
));
2217 LocaleDataWrapper::outputCheckMessage(xLocaleData
->appendLocaleInfo(aUMsg
));
2220 if ( nShort
!= -1 && nShortDef
== -1 )
2221 aMsg
.append("no short type default ");
2222 if ( nMedium
!= -1 && nMediumDef
== -1 )
2223 aMsg
.append("no medium type default ");
2224 if ( nLong
!= -1 && nLongDef
== -1 )
2225 aMsg
.append("no long type default ");
2226 if (!aMsg
.isEmpty())
2228 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2229 aMsg
.append("\nXML locale data FormatElement group of: ");
2230 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
));
2231 LocaleDataWrapper::outputCheckMessage(
2232 xLocaleData
->appendLocaleInfo(aUMsg
+ pFormatArr
[0].NameID
));
2235 // find the default (medium preferred, then long) and reset all other defaults
2236 sal_Int32 nElem
, nDef
, nMedium
;
2237 nDef
= nMedium
= -1;
2238 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2240 if ( pFormatArr
[nElem
].Default
)
2242 switch ( pFormatArr
[nElem
].Type
)
2244 case i18n::KNumberFormatType::MEDIUM
:
2245 nDef
= nMedium
= nElem
;
2247 case i18n::KNumberFormatType::LONG
:
2248 if ( nMedium
== -1 )
2254 pFormatArr
[nElem
].Default
= false;
2260 pFormatArr
[nDef
].Default
= true;
2263 SvNumberformat
* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey
)
2265 auto it
= aFTable
.find( nKey
);
2266 if (it
!= aFTable
.end())
2267 return it
->second
.get();
2271 const SvNumberformat
* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey
) const
2273 return GetEntry( nKey
);
2276 const SvNumberformat
* SvNumberFormatter::GetEntry( sal_uInt32 nKey
) const
2278 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2279 auto it
= aFTable
.find( nKey
);
2280 if (it
!= aFTable
.end())
2281 return it
->second
.get();
2285 const SvNumberformat
* SvNumberFormatter::GetSubstitutedEntry( sal_uInt32 nKey
, sal_uInt32
& o_rNewKey
) const
2287 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2288 // A tad ugly, but GetStandardFormat() and GetFormatIndex() in
2289 // ImpSubstituteEntry() may have to add the LANGUAGE_SYSTEM formats if not
2290 // already present (which in practice most times they are).
2291 SvNumberFormatter
* pThis
= const_cast<SvNumberFormatter
*>(this);
2292 return pThis
->ImpSubstituteEntry( pThis
->GetFormatEntry( nKey
), &o_rNewKey
);
2295 SvNumberformat
* SvNumberFormatter::ImpSubstituteEntry( SvNumberformat
* pFormat
, sal_uInt32
* o_pRealKey
)
2297 if (!pFormat
|| !pFormat
->IsSubstituted())
2300 // XXX NOTE: substitution can not be done in GetFormatEntry() as otherwise
2301 // to be substituted formats would "vanish", i.e. from the number formatter
2302 // dialog or when exporting to Excel.
2305 if (pFormat
->IsSystemTimeFormat())
2306 /* TODO: should we have NF_TIME_SYSTEM for consistency? */
2307 nKey
= GetStandardFormat( SvNumFormatType::TIME
, LANGUAGE_SYSTEM
);
2308 else if (pFormat
->IsSystemLongDateFormat())
2309 /* TODO: either that above, or have a long option for GetStandardFormat() */
2310 nKey
= GetFormatIndex( NF_DATE_SYSTEM_LONG
, LANGUAGE_SYSTEM
);
2316 auto it
= aFTable
.find( nKey
);
2317 return it
== aFTable
.end() ? nullptr : it
->second
.get();
2320 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset
, bool bNoAdditionalFormats
)
2322 bool bOldConvertMode
= pFormatScanner
->GetConvertMode();
2323 if (bOldConvertMode
)
2325 pFormatScanner
->SetConvertMode(false); // switch off for this function
2328 css::lang::Locale aLocale
= GetLanguageTag().getLocale();
2329 css::uno::Reference
< css::i18n::XNumberFormatCode
> xNFC
= i18n::NumberFormatMapper::create( m_xContext
);
2334 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER
, aLocale
);
2335 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2338 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_STANDARD
);
2339 SvNumberformat
* pStdFormat
= ImpInsertFormat( aFormatSeq
[nIdx
],
2340 CLOffset
+ ZF_STANDARD
/* NF_NUMBER_STANDARD */ );
2343 // This is _the_ standard format.
2344 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat
->GetType() != SvNumFormatType::NUMBER
)
2346 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2347 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2349 pStdFormat
->SetType( SvNumFormatType::NUMBER
);
2350 pStdFormat
->SetStandard();
2351 pStdFormat
->SetLastInsertKey( SV_MAX_COUNT_STANDARD_FORMATS
, SvNumberformat::FormatterPrivateAccess() );
2355 if (LocaleDataWrapper::areChecksEnabled())
2357 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2358 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2364 OUString aFormatCode
= pFormatScanner
->GetBooleanString();
2365 sal_Int32 nCheckPos
= 0;
2367 std::unique_ptr
<SvNumberformat
> pNewFormat(new SvNumberformat( aFormatCode
, pFormatScanner
.get(),
2368 pStringScanner
.get(), nCheckPos
, ActLnge
));
2369 pNewFormat
->SetType(SvNumFormatType::LOGICAL
);
2370 pNewFormat
->SetStandard();
2371 if ( !aFTable
.emplace(CLOffset
+ ZF_STANDARD_LOGICAL
/* NF_BOOLEAN */,
2372 std::move(pNewFormat
)).second
)
2374 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2379 pNewFormat
.reset(new SvNumberformat( aFormatCode
, pFormatScanner
.get(),
2380 pStringScanner
.get(), nCheckPos
, ActLnge
));
2381 pNewFormat
->SetType(SvNumFormatType::TEXT
);
2382 pNewFormat
->SetStandard();
2383 if ( !aFTable
.emplace( CLOffset
+ ZF_STANDARD_TEXT
/* NF_TEXT */,
2384 std::move(pNewFormat
)).second
)
2386 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2391 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_INT
);
2392 ImpInsertFormat( aFormatSeq
[nIdx
],
2393 CLOffset
+ ZF_STANDARD
+1 /* NF_NUMBER_INT */ );
2396 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_DEC2
);
2397 ImpInsertFormat( aFormatSeq
[nIdx
],
2398 CLOffset
+ ZF_STANDARD
+2 /* NF_NUMBER_DEC2 */ );
2401 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000INT
);
2402 ImpInsertFormat( aFormatSeq
[nIdx
],
2403 CLOffset
+ ZF_STANDARD
+3 /* NF_NUMBER_1000INT */ );
2406 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000DEC2
);
2407 ImpInsertFormat( aFormatSeq
[nIdx
],
2408 CLOffset
+ ZF_STANDARD
+4 /* NF_NUMBER_1000DEC2 */ );
2410 // #.##0,00 System country/language dependent
2411 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_SYSTEM
);
2412 ImpInsertFormat( aFormatSeq
[nIdx
],
2413 CLOffset
+ ZF_STANDARD
+5 /* NF_NUMBER_SYSTEM */ );
2417 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER
, aLocale
);
2418 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2421 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_INT
);
2422 ImpInsertFormat( aFormatSeq
[nIdx
],
2423 CLOffset
+ ZF_STANDARD_PERCENT
/* NF_PERCENT_INT */ );
2426 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_DEC2
);
2427 ImpInsertFormat( aFormatSeq
[nIdx
],
2428 CLOffset
+ ZF_STANDARD_PERCENT
+1 /* NF_PERCENT_DEC2 */ );
2431 // Currency. NO default standard option! Default is determined of locale
2432 // data default currency and format is generated if needed.
2433 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
, aLocale
);
2434 if (LocaleDataWrapper::areChecksEnabled())
2436 // though no default desired here, test for correctness of locale data
2437 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2441 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT
);
2442 bDefault
= aFormatSeq
[nIdx
].Default
;
2443 aFormatSeq
[nIdx
].Default
= false;
2444 ImpInsertFormat( aFormatSeq
[nIdx
],
2445 CLOffset
+ ZF_STANDARD_CURRENCY
/* NF_CURRENCY_1000INT */ );
2446 aFormatSeq
[nIdx
].Default
= bDefault
;
2449 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2
);
2450 bDefault
= aFormatSeq
[nIdx
].Default
;
2451 aFormatSeq
[nIdx
].Default
= false;
2452 ImpInsertFormat( aFormatSeq
[nIdx
],
2453 CLOffset
+ ZF_STANDARD_CURRENCY
+1 /* NF_CURRENCY_1000DEC2 */ );
2454 aFormatSeq
[nIdx
].Default
= bDefault
;
2456 // #,##0 negative red
2457 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT_RED
);
2458 bDefault
= aFormatSeq
[nIdx
].Default
;
2459 aFormatSeq
[nIdx
].Default
= false;
2460 ImpInsertFormat( aFormatSeq
[nIdx
],
2461 CLOffset
+ ZF_STANDARD_CURRENCY
+2 /* NF_CURRENCY_1000INT_RED */ );
2462 aFormatSeq
[nIdx
].Default
= bDefault
;
2464 // #,##0.00 negative red
2465 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_RED
);
2466 bDefault
= aFormatSeq
[nIdx
].Default
;
2467 aFormatSeq
[nIdx
].Default
= false;
2468 ImpInsertFormat( aFormatSeq
[nIdx
],
2469 CLOffset
+ ZF_STANDARD_CURRENCY
+3 /* NF_CURRENCY_1000DEC2_RED */ );
2470 aFormatSeq
[nIdx
].Default
= bDefault
;
2473 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_CCC
);
2474 bDefault
= aFormatSeq
[nIdx
].Default
;
2475 aFormatSeq
[nIdx
].Default
= false;
2476 ImpInsertFormat( aFormatSeq
[nIdx
],
2477 CLOffset
+ ZF_STANDARD_CURRENCY
+4 /* NF_CURRENCY_1000DEC2_CCC */ );
2478 aFormatSeq
[nIdx
].Default
= bDefault
;
2481 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_DASHED
);
2482 bDefault
= aFormatSeq
[nIdx
].Default
;
2483 aFormatSeq
[nIdx
].Default
= false;
2484 ImpInsertFormat( aFormatSeq
[nIdx
],
2485 CLOffset
+ ZF_STANDARD_CURRENCY
+5 /* NF_CURRENCY_1000DEC2_DASHED */ );
2486 aFormatSeq
[nIdx
].Default
= bDefault
;
2490 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::DATE
, aLocale
);
2491 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2494 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_SHORT
);
2495 ImpInsertFormat( aFormatSeq
[nIdx
],
2496 CLOffset
+ ZF_STANDARD_DATE
/* NF_DATE_SYSTEM_SHORT */ );
2499 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DEF_NNDDMMMYY
);
2500 ImpInsertFormat( aFormatSeq
[nIdx
],
2501 CLOffset
+ ZF_STANDARD_DATE
+1 /* NF_DATE_DEF_NNDDMMMYY */ );
2503 // DD.MM.YY def/System
2504 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_MMYY
);
2505 ImpInsertFormat( aFormatSeq
[nIdx
],
2506 CLOffset
+ ZF_STANDARD_DATE
+2 /* NF_DATE_SYS_MMYY */ );
2509 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMM
);
2510 ImpInsertFormat( aFormatSeq
[nIdx
],
2511 CLOffset
+ ZF_STANDARD_DATE
+3 /* NF_DATE_SYS_DDMMM */ );
2514 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_MMMM
);
2515 ImpInsertFormat( aFormatSeq
[nIdx
],
2516 CLOffset
+ ZF_STANDARD_DATE
+4 /* NF_DATE_MMMM */ );
2519 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_QQJJ
);
2520 ImpInsertFormat( aFormatSeq
[nIdx
],
2521 CLOffset
+ ZF_STANDARD_DATE
+5 /* NF_DATE_QQJJ */ );
2523 // DD.MM.YYYY was DD.MM.[YY]YY
2524 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYYYY
);
2525 ImpInsertFormat( aFormatSeq
[nIdx
],
2526 CLOffset
+ ZF_STANDARD_DATE
+6 /* NF_DATE_SYS_DDMMYYYY */ );
2528 // DD.MM.YY def/System
2529 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYY
);
2530 ImpInsertFormat( aFormatSeq
[nIdx
],
2531 CLOffset
+ ZF_STANDARD_DATE
+7 /* NF_DATE_SYS_DDMMYY */ );
2533 // NNN, D. MMMM YYYY System
2534 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2535 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_LONG
);
2536 ImpInsertFormat( aFormatSeq
[nIdx
],
2537 CLOffset
+ ZF_STANDARD_DATE
+8 /* NF_DATE_SYSTEM_LONG */ );
2539 // Hard coded but system (regional settings) delimiters dependent long date formats
2541 // D. MMM YY def/System
2542 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYY
);
2543 ImpInsertFormat( aFormatSeq
[nIdx
],
2544 CLOffset
+ ZF_STANDARD_DATE
+9 /* NF_DATE_SYS_DMMMYY */ );
2546 // D. MMM YYYY def/System
2547 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYYYY
);
2548 ImpInsertFormat( aFormatSeq
[nIdx
],
2549 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMYYYY
/* NF_DATE_SYS_DMMMYYYY */ );
2551 // D. MMMM YYYY def/System
2552 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMMYYYY
);
2553 ImpInsertFormat( aFormatSeq
[nIdx
],
2554 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_DMMMMYYYY
/* NF_DATE_SYS_DMMMMYYYY */ );
2556 // NN, D. MMM YY def/System
2557 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMYY
);
2558 ImpInsertFormat( aFormatSeq
[nIdx
],
2559 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMYY
/* NF_DATE_SYS_NNDMMMYY */ );
2561 // NN, D. MMMM YYYY def/System
2562 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMMYYYY
);
2563 ImpInsertFormat( aFormatSeq
[nIdx
],
2564 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNDMMMMYYYY
/* NF_DATE_SYS_NNDMMMMYYYY */ );
2566 // NNN, D. MMMM YYYY def/System
2567 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNNNDMMMMYYYY
);
2568 ImpInsertFormat( aFormatSeq
[nIdx
],
2569 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_SYS_NNNNDMMMMYYYY
/* NF_DATE_SYS_NNNNDMMMMYYYY */ );
2571 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2573 // D. MMM. YYYY DIN/EN
2574 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMYYYY
);
2575 ImpInsertFormat( aFormatSeq
[nIdx
],
2576 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMYYYY
/* NF_DATE_DIN_DMMMYYYY */ );
2578 // D. MMMM YYYY DIN/EN
2579 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMMYYYY
);
2580 ImpInsertFormat( aFormatSeq
[nIdx
],
2581 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_DMMMMYYYY
/* NF_DATE_DIN_DMMMMYYYY */ );
2584 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_MMDD
);
2585 ImpInsertFormat( aFormatSeq
[nIdx
],
2586 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD
/* NF_DATE_DIN_MMDD */ );
2589 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYMMDD
);
2590 ImpInsertFormat( aFormatSeq
[nIdx
],
2591 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYMMDD
/* NF_DATE_DIN_YYMMDD */ );
2593 // YYYY-MM-DD DIN/EN/ISO
2594 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYYYMMDD
);
2595 ImpInsertFormat( aFormatSeq
[nIdx
],
2596 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_DIN_YYYYMMDD
/* NF_DATE_DIN_YYYYMMDD */ );
2600 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::TIME
, aLocale
);
2601 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2604 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMM
);
2605 ImpInsertFormat( aFormatSeq
[nIdx
],
2606 CLOffset
+ ZF_STANDARD_TIME
/* NF_TIME_HHMM */ );
2609 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSS
);
2610 ImpInsertFormat( aFormatSeq
[nIdx
],
2611 CLOffset
+ ZF_STANDARD_TIME
+1 /* NF_TIME_HHMMSS */ );
2614 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMAMPM
);
2615 ImpInsertFormat( aFormatSeq
[nIdx
],
2616 CLOffset
+ ZF_STANDARD_TIME
+2 /* NF_TIME_HHMMAMPM */ );
2619 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSSAMPM
);
2620 ImpInsertFormat( aFormatSeq
[nIdx
],
2621 CLOffset
+ ZF_STANDARD_TIME
+3 /* NF_TIME_HHMMSSAMPM */ );
2624 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS
);
2625 ImpInsertFormat( aFormatSeq
[nIdx
],
2626 CLOffset
+ ZF_STANDARD_TIME
+4 /* NF_TIME_HH_MMSS */ );
2629 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_MMSS00
);
2630 ImpInsertFormat( aFormatSeq
[nIdx
],
2631 CLOffset
+ ZF_STANDARD_TIME
+5 /* NF_TIME_MMSS00 */ );
2634 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS00
);
2635 ImpInsertFormat( aFormatSeq
[nIdx
],
2636 CLOffset
+ ZF_STANDARD_TIME
+6 /* NF_TIME_HH_MMSS00 */ );
2640 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME
, aLocale
);
2641 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2643 // DD.MM.YY HH:MM System
2644 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYSTEM_SHORT_HHMM
);
2645 ImpInsertFormat( aFormatSeq
[nIdx
],
2646 CLOffset
+ ZF_STANDARD_DATETIME
/* NF_DATETIME_SYSTEM_SHORT_HHMM */ );
2648 // DD.MM.YYYY HH:MM:SS System
2649 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
2650 ImpInsertFormat( aFormatSeq
[nIdx
],
2651 CLOffset
+ ZF_STANDARD_DATETIME
+1 /* NF_DATETIME_SYS_DDMMYYYY_HHMMSS */ );
2653 const NfKeywordTable
& rKeyword
= pFormatScanner
->GetKeywords();
2654 i18n::NumberFormatCode aSingleFormatCode
;
2655 OUStringBuffer aBuf
;
2656 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::DATE_TIME
;
2658 // YYYY-MM-DD HH:MM:SS ISO
2659 aBuf
.append( rKeyword
[NF_KEY_YYYY
]).append('-').
2660 append( rKeyword
[NF_KEY_MM
]).append('-').
2661 append( rKeyword
[NF_KEY_DD
]).append(' ').
2662 append( rKeyword
[NF_KEY_HH
]).append(':').
2663 append( rKeyword
[NF_KEY_MMI
]).append(':').
2664 append( rKeyword
[NF_KEY_SS
]);
2665 aSingleFormatCode
.Code
= aBuf
.makeStringAndClear();
2666 ImpInsertFormat( aSingleFormatCode
,
2667 CLOffset
+ ZF_STANDARD_DATETIME
+2 /* NF_DATETIME_ISO_YYYYMMDD_HHMMSS */ );
2670 // Scientific number
2671 aFormatSeq
= xNFC
->getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER
, aLocale
);
2672 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2675 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E000
);
2676 ImpInsertFormat( aFormatSeq
[nIdx
],
2677 CLOffset
+ ZF_STANDARD_SCIENTIFIC
/* NF_SCIENTIFIC_000E000 */ );
2680 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E00
);
2681 ImpInsertFormat( aFormatSeq
[nIdx
],
2682 CLOffset
+ ZF_STANDARD_SCIENTIFIC
+1 /* NF_SCIENTIFIC_000E00 */ );
2685 // Fraction number (no default option)
2686 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::FRACTION_NUMBER
;
2689 aSingleFormatCode
.Code
= "# ?/?";
2690 ImpInsertFormat( aSingleFormatCode
,
2691 CLOffset
+ ZF_STANDARD_FRACTION
/* NF_FRACTION_1D */ );
2694 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2695 aSingleFormatCode
.Code
= "# ?\?/?\?";
2696 ImpInsertFormat( aSingleFormatCode
,
2697 CLOffset
+ ZF_STANDARD_FRACTION
+1 /* NF_FRACTION_2D */ );
2700 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2701 aSingleFormatCode
.Code
= "# ?\?\?/?\?\?";
2702 ImpInsertFormat( aSingleFormatCode
,
2703 CLOffset
+ ZF_STANDARD_FRACTION
+2 /* NF_FRACTION_3D */ );
2706 aSingleFormatCode
.Code
= "# ?/2";
2707 ImpInsertFormat( aSingleFormatCode
,
2708 CLOffset
+ ZF_STANDARD_FRACTION
+3 /* NF_FRACTION_2 */ );
2711 aSingleFormatCode
.Code
= "# ?/4";
2712 ImpInsertFormat( aSingleFormatCode
,
2713 CLOffset
+ ZF_STANDARD_FRACTION
+4 /* NF_FRACTION_4 */ );
2716 aSingleFormatCode
.Code
= "# ?/8";
2717 ImpInsertFormat( aSingleFormatCode
,
2718 CLOffset
+ ZF_STANDARD_FRACTION
+5 /* NF_FRACTION_8 */ );
2721 aSingleFormatCode
.Code
= "# ?\?/16";
2722 ImpInsertFormat( aSingleFormatCode
,
2723 CLOffset
+ ZF_STANDARD_FRACTION
+6 /* NF_FRACTION_16 */ );
2726 aSingleFormatCode
.Code
= "# ?\?/10";
2727 ImpInsertFormat( aSingleFormatCode
,
2728 CLOffset
+ ZF_STANDARD_FRACTION
+7 /* NF_FRACTION_10 */ );
2731 aSingleFormatCode
.Code
= "# ?\?/100";
2732 ImpInsertFormat( aSingleFormatCode
,
2733 CLOffset
+ ZF_STANDARD_FRACTION
+8 /* NF_FRACTION_100 */ );
2737 aSingleFormatCode
.Code
= rKeyword
[NF_KEY_WW
];
2738 ImpInsertFormat( aSingleFormatCode
,
2739 CLOffset
+ ZF_STANDARD_NEWEXTENDED_DATE_WW
/* NF_DATE_WW */ );
2741 // Now all additional format codes provided by I18N, but only if not
2742 // changing SystemCL, then they are appended last after user defined.
2743 if ( !bNoAdditionalFormats
)
2745 ImpGenerateAdditionalFormats( CLOffset
, xNFC
, false );
2747 if (bOldConvertMode
)
2749 pFormatScanner
->SetConvertMode(true);
2754 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset
,
2755 css::uno::Reference
< css::i18n::XNumberFormatCode
> const & rNumberFormatCode
,
2756 bool bAfterChangingSystemCL
)
2758 SvNumberformat
* pStdFormat
= GetFormatEntry( CLOffset
+ ZF_STANDARD
);
2761 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2764 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
2765 css::lang::Locale aLocale
= GetLanguageTag().getLocale();
2768 // All currencies, this time with [$...] which was stripped in
2769 // ImpGenerateFormats for old "automatic" currency formats.
2770 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
= rNumberFormatCode
->getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
, aLocale
);
2771 i18n::NumberFormatCode
* pFormatArr
= aFormatSeq
.getArray();
2772 sal_Int32 nCodes
= aFormatSeq
.getLength();
2773 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), nCodes
);
2774 for ( j
= 0; j
< nCodes
; j
++ )
2776 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2778 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2781 if ( pFormatArr
[j
].Index
< NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
&&
2782 pFormatArr
[j
].Index
!= NF_CURRENCY_1000DEC2_CCC
)
2783 { // Insert only if not already inserted, but internal index must be
2784 // above so ImpInsertFormat can distinguish it.
2785 sal_Int16 nOrgIndex
= pFormatArr
[j
].Index
;
2786 pFormatArr
[j
].Index
= sal::static_int_cast
< sal_Int16
>(
2787 pFormatArr
[j
].Index
+ nCodes
+ NF_INDEX_TABLE_ENTRIES
);
2788 //! no default on currency
2789 bool bDefault
= aFormatSeq
[j
].Default
;
2790 aFormatSeq
[j
].Default
= false;
2791 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat( pFormatArr
[j
], nPos
+1,
2792 bAfterChangingSystemCL
, nOrgIndex
) )
2794 pNewFormat
->SetAdditionalBuiltin();
2797 pFormatArr
[j
].Index
= nOrgIndex
;
2798 aFormatSeq
[j
].Default
= bDefault
;
2802 // All additional format codes provided by I18N that are not old standard
2803 // index. Additional formats may define defaults, currently there is no
2804 // check if more than one default of a usage/type combination is provided,
2805 // like it is done for usage groups with ImpAdjustFormatCodeDefault().
2806 // There is no harm though, on first invocation ImpGetDefaultFormat() will
2807 // use the first default encountered.
2808 aFormatSeq
= rNumberFormatCode
->getAllFormatCodes( aLocale
);
2809 nCodes
= aFormatSeq
.getLength();
2812 pFormatArr
= aFormatSeq
.getArray();
2813 for ( j
= 0; j
< nCodes
; j
++ )
2815 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2817 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2820 if ( pFormatArr
[j
].Index
>= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
)
2822 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat( pFormatArr
[j
], nPos
+1,
2823 bAfterChangingSystemCL
) )
2825 pNewFormat
->SetAdditionalBuiltin();
2832 pStdFormat
->SetLastInsertKey( static_cast<sal_uInt16
>(nPos
- CLOffset
), SvNumberformat::FormatterPrivateAccess() );
2836 sal_Int32
SvNumberFormatter::ImpPosToken ( const OUStringBuffer
& sFormat
, sal_Unicode token
, sal_Int32 nStartPos
/* = 0*/ ) const
2838 sal_Int32 nLength
= sFormat
.getLength();
2839 for ( sal_Int32 i
=nStartPos
; i
<nLength
&& i
>=0 ; i
++ )
2843 case '\"' : // skip text
2844 i
= sFormat
.indexOf('\"',i
+1);
2846 case '[' : // skip condition
2847 i
= sFormat
.indexOf(']',i
+1);
2849 case '\\' : // skip escaped character
2859 return i
; // if 'E' is outside "" and [] it must be the 'E' exponent
2869 OUString
SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex
,
2873 sal_uInt16 nPrecision
,
2874 sal_uInt16 nLeadingZeros
)
2876 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
2877 if (eLnge
== LANGUAGE_DONTKNOW
)
2882 const SvNumberformat
* pFormat
= GetFormatEntry( nIndex
);
2883 const SvNumFormatType eType
= (pFormat
? pFormat
->GetMaskedType() : SvNumFormatType::UNDEFINED
);
2885 ImpGenerateCL(eLnge
); // create new standard formats if necessary
2887 utl::DigitGroupingIterator
aGrouping( xLocaleData
->getDigitGrouping());
2888 // always group of 3 for Engineering notation
2889 const sal_Int32 nDigitsInFirstGroup
= ( bThousand
&& (eType
== SvNumFormatType::SCIENTIFIC
) ) ? 3 : aGrouping
.get();
2890 const OUString
& rThSep
= GetNumThousandSep();
2892 OUStringBuffer sString
;
2893 using comphelper::string::padToLength
;
2895 if (nLeadingZeros
== 0)
2898 sString
.append('#');
2901 if (eType
== SvNumFormatType::SCIENTIFIC
)
2902 { // for scientific, bThousand is used for Engineering notation
2903 sString
.append("###");
2907 sString
.append('#');
2908 sString
.append(rThSep
);
2909 padToLength(sString
, sString
.getLength() + nDigitsInFirstGroup
, '#');
2915 for (sal_uInt16 i
= 0; i
< nLeadingZeros
; i
++)
2917 if (bThousand
&& i
> 0 && i
== aGrouping
.getPos())
2919 sString
.insert(0, rThSep
);
2920 aGrouping
.advance();
2922 sString
.insert(0, '0');
2926 sal_Int32 nDigits
= (eType
== SvNumFormatType::SCIENTIFIC
) ? 3*((nLeadingZeros
-1)/3 + 1) : nDigitsInFirstGroup
+ 1;
2927 for (sal_Int32 i
= nLeadingZeros
; i
< nDigits
; i
++)
2929 if ( i
% nDigitsInFirstGroup
== 0 )
2930 sString
.insert(0, rThSep
);
2931 sString
.insert(0, '#');
2935 if (nPrecision
> 0 && eType
!= SvNumFormatType::FRACTION
)
2937 sString
.append(GetNumDecimalSep());
2938 padToLength(sString
, sString
.getLength() + nPrecision
, '0');
2940 if (eType
== SvNumFormatType::PERCENT
)
2942 sString
.append('%');
2944 else if (eType
== SvNumFormatType::SCIENTIFIC
)
2946 OUStringBuffer sOldFormatString
= pFormat
->GetFormatstring();
2947 sal_Int32 nIndexE
= ImpPosToken( sOldFormatString
, 'E' );
2950 sal_Int32 nIndexSep
= ImpPosToken( sOldFormatString
, ';', nIndexE
);
2951 if (nIndexSep
> nIndexE
)
2952 sString
.append( sOldFormatString
.copy(nIndexE
, nIndexSep
- nIndexE
) );
2954 sString
.append( sOldFormatString
.copy(nIndexE
) );
2957 else if (eType
== SvNumFormatType::CURRENCY
)
2959 OUStringBuffer
sNegStr(sString
);
2961 const NfCurrencyEntry
* pEntry
;
2963 if ( GetNewCurrencySymbolString( nIndex
, aCurr
, &pEntry
, &bBank
) )
2967 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
2968 xLocaleData
->getCurrPositiveFormat(),
2969 pEntry
->GetPositiveFormat(), bBank
);
2970 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
2971 xLocaleData
->getCurrNegativeFormat(),
2972 pEntry
->GetNegativeFormat(), bBank
);
2973 pEntry
->CompletePositiveFormatString( sString
, bBank
, nPosiForm
);
2974 pEntry
->CompleteNegativeFormatString( sNegStr
, bBank
, nNegaForm
);
2977 { // assume currency abbreviation (AKA banking symbol), not symbol
2978 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
2979 xLocaleData
->getCurrPositiveFormat(),
2980 xLocaleData
->getCurrPositiveFormat(), true );
2981 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
2982 xLocaleData
->getCurrNegativeFormat(),
2983 xLocaleData
->getCurrNegativeFormat(), true );
2984 NfCurrencyEntry::CompletePositiveFormatString( sString
, aCurr
, nPosiForm
);
2985 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
, aCurr
, nNegaForm
);
2989 { // "automatic" old style
2990 OUString aSymbol
, aAbbrev
;
2991 GetCompatibilityCurrency( aSymbol
, aAbbrev
);
2992 NfCurrencyEntry::CompletePositiveFormatString( sString
,
2993 aSymbol
, xLocaleData
->getCurrPositiveFormat() );
2994 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
,
2995 aSymbol
, xLocaleData
->getCurrNegativeFormat() );
2999 sString
.append(';');
3000 sString
.append('[');
3001 sString
.append(pFormatScanner
->GetRedString());
3002 sString
.append(']');
3006 sString
.append(';');
3008 sString
.append(sNegStr
.makeStringAndClear());
3010 else if (eType
== SvNumFormatType::FRACTION
)
3012 OUString aIntegerFractionDelimiterString
= pFormat
->GetIntegerFractionDelimiterString( 0 );
3013 if ( aIntegerFractionDelimiterString
== " " )
3014 sString
.append( aIntegerFractionDelimiterString
);
3017 sString
.append( '"' );
3018 sString
.append( aIntegerFractionDelimiterString
);
3019 sString
.append( '"' );
3021 sString
.append( pFormat
->GetNumeratorString( 0 ) );
3022 sString
.append( '/' );
3023 if ( nPrecision
> 0 )
3024 padToLength(sString
, sString
.getLength() + nPrecision
, '?');
3026 sString
.append( '#' );
3028 if (eType
!= SvNumFormatType::CURRENCY
)
3030 bool insertBrackets
= false;
3031 if ( eType
!= SvNumFormatType::UNDEFINED
)
3033 insertBrackets
= pFormat
->IsNegativeInBracket();
3035 if (IsRed
|| insertBrackets
)
3037 OUStringBuffer
sTmpStr(sString
);
3039 if (pFormat
&& pFormat
->HasPositiveBracketPlaceholder())
3041 sTmpStr
.append('_');
3042 sTmpStr
.append(')');
3044 sTmpStr
.append(';');
3048 sTmpStr
.append('[');
3049 sTmpStr
.append(pFormatScanner
->GetRedString());
3050 sTmpStr
.append(']');
3055 sTmpStr
.append('(');
3056 sTmpStr
.append(sString
.toString());
3057 sTmpStr
.append(')');
3061 sTmpStr
.append('-');
3062 sTmpStr
.append(sString
.toString());
3067 return sString
.makeStringAndClear();
3070 bool SvNumberFormatter::IsUserDefined(const OUString
& sStr
,
3073 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3074 if (eLnge
== LANGUAGE_DONTKNOW
)
3078 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3081 sal_uInt32 nKey
= ImpIsEntry(sStr
, CLOffset
, eLnge
);
3082 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3086 SvNumberformat
* pEntry
= GetFormatEntry( nKey
);
3087 return pEntry
&& (pEntry
->GetType() & SvNumFormatType::DEFINED
);
3090 sal_uInt32
SvNumberFormatter::GetEntryKey(const OUString
& sStr
,
3093 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3094 if (eLnge
== LANGUAGE_DONTKNOW
)
3098 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3099 return ImpIsEntry(sStr
, CLOffset
, eLnge
);
3102 sal_uInt32
SvNumberFormatter::GetStandardIndex(LanguageType eLnge
)
3104 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3105 if (eLnge
== LANGUAGE_DONTKNOW
)
3109 return GetStandardFormat(SvNumFormatType::NUMBER
, eLnge
);
3112 SvNumFormatType
SvNumberFormatter::GetType(sal_uInt32 nFIndex
) const
3114 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3115 SvNumFormatType eType
;
3116 const SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
3119 eType
= SvNumFormatType::UNDEFINED
;
3123 eType
= pFormat
->GetMaskedType();
3124 if (eType
== SvNumFormatType::ALL
)
3126 eType
= SvNumFormatType::DEFINED
;
3132 void SvNumberFormatter::ClearMergeTable()
3134 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3137 pMergeTable
->clear();
3141 SvNumberFormatterIndexTable
* SvNumberFormatter::MergeFormatter(SvNumberFormatter
& rTable
)
3143 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3150 pMergeTable
.reset( new SvNumberFormatterIndexTable
);
3153 sal_uInt32 nCLOffset
= 0;
3154 sal_uInt32 nOldKey
, nOffset
, nNewKey
;
3156 auto it
= rTable
.aFTable
.begin();
3157 while (it
!= rTable
.aFTable
.end())
3159 SvNumberformat
* pFormat
= it
->second
.get();
3160 nOldKey
= it
->first
;
3161 nOffset
= nOldKey
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3162 if (nOffset
== 0) // 1st format of CL
3164 nCLOffset
= ImpGenerateCL(pFormat
->GetLanguage());
3166 if (nOffset
<= SV_MAX_COUNT_STANDARD_FORMATS
) // Std.form.
3168 nNewKey
= nCLOffset
+ nOffset
;
3169 if (aFTable
.find( nNewKey
) == aFTable
.end()) // not already present
3171 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( *pFormat
, *pFormatScanner
));
3172 if (!aFTable
.emplace( nNewKey
, std::move(pNewEntry
)).second
)
3174 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3177 if (nNewKey
!= nOldKey
) // new index
3179 (*pMergeTable
)[nOldKey
] = nNewKey
;
3182 else // user defined
3184 std::unique_ptr
<SvNumberformat
> pNewEntry(new SvNumberformat( *pFormat
, *pFormatScanner
));
3185 nNewKey
= ImpIsEntry(pNewEntry
->GetFormatstring(),
3187 pFormat
->GetLanguage());
3188 if (nNewKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
) // only if not present yet
3190 SvNumberformat
* pStdFormat
= GetFormatEntry(nCLOffset
+ ZF_STANDARD
);
3191 sal_uInt32 nPos
= nCLOffset
+ pStdFormat
->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
3193 if (nNewKey
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3195 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3197 else if (!aFTable
.emplace( nNewKey
, std::move(pNewEntry
)).second
)
3199 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3203 pStdFormat
->SetLastInsertKey(static_cast<sal_uInt16
>(nNewKey
- nCLOffset
),
3204 SvNumberformat::FormatterPrivateAccess());
3207 if (nNewKey
!= nOldKey
) // new index
3209 (*pMergeTable
)[nOldKey
] = nNewKey
;
3214 return pMergeTable
.get();
3218 SvNumberFormatterMergeMap
SvNumberFormatter::ConvertMergeTableToMap()
3220 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3221 if (!HasMergeFormatTable())
3223 return SvNumberFormatterMergeMap();
3225 SvNumberFormatterMergeMap aMap
;
3226 for (SvNumberFormatterIndexTable::const_iterator it
= pMergeTable
->begin(); it
!= pMergeTable
->end(); ++it
)
3228 sal_uInt32 nOldKey
= it
->first
;
3229 aMap
[ nOldKey
] = it
->second
;
3236 sal_uInt32
SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat
,
3237 LanguageType eLnge
)
3239 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3240 if ( eLnge
== LANGUAGE_DONTKNOW
)
3244 if ( nFormat
< SV_COUNTRY_LANGUAGE_OFFSET
&& eLnge
== IniLnge
)
3246 return nFormat
; // it stays as it is
3248 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3249 if ( nOffset
> SV_MAX_COUNT_STANDARD_FORMATS
)
3251 return nFormat
; // not a built-in format
3253 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3254 return nCLOffset
+ nOffset
;
3258 sal_uInt32
SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff
,
3259 LanguageType eLnge
)
3261 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3262 if (nTabOff
>= NF_INDEX_TABLE_ENTRIES
)
3263 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
3265 if (eLnge
== LANGUAGE_DONTKNOW
)
3268 if (indexTable
[nTabOff
] == NUMBERFORMAT_ENTRY_NOT_FOUND
)
3269 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
3271 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3273 return nCLOffset
+ indexTable
[nTabOff
];
3277 NfIndexTableOffset
SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat
) const
3279 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3280 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3281 if ( nOffset
> SV_MAX_COUNT_STANDARD_FORMATS
)
3283 return NF_INDEX_TABLE_ENTRIES
; // not a built-in format
3286 for ( sal_uInt16 j
= 0; j
< NF_INDEX_TABLE_ENTRIES
; j
++ )
3288 if (indexTable
[j
] == nOffset
)
3289 return static_cast<NfIndexTableOffset
>(j
);
3291 return NF_INDEX_TABLE_ENTRIES
; // bad luck
3294 void SvNumberFormatter::SetEvalDateFormat( NfEvalDateFormat eEDF
)
3296 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3297 eEvalDateFormat
= eEDF
;
3300 NfEvalDateFormat
SvNumberFormatter::GetEvalDateFormat() const
3302 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3303 return eEvalDateFormat
;
3306 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal
)
3308 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3309 pStringScanner
->SetYear2000( nVal
);
3313 sal_uInt16
SvNumberFormatter::GetYear2000() const
3315 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3316 return pStringScanner
->GetYear2000();
3320 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
) const
3323 return SvNumberFormatter::ExpandTwoDigitYear( nYear
,
3324 pStringScanner
->GetYear2000() );
3330 sal_uInt16
SvNumberFormatter::GetYear2000Default()
3332 if (!utl::ConfigManager::IsFuzzing())
3333 return static_cast<sal_uInt16
>(::utl::MiscCfg().GetYear2000());
3339 const NfCurrencyTable
& SvNumberFormatter::GetTheCurrencyTable()
3341 while ( !bCurrencyTableInitialized
)
3342 ImpInitCurrencyTable();
3343 return theCurrencyTable::get();
3348 const NfCurrencyEntry
* SvNumberFormatter::MatchSystemCurrency()
3350 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3351 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3352 return nSystemCurrencyPosition
? &rTable
[nSystemCurrencyPosition
] : nullptr;
3357 const NfCurrencyEntry
& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang
)
3359 if ( eLang
== LANGUAGE_SYSTEM
)
3361 const NfCurrencyEntry
* pCurr
= MatchSystemCurrency();
3362 return pCurr
? *pCurr
: GetTheCurrencyTable()[0];
3366 eLang
= MsLangId::getRealLanguage( eLang
);
3367 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3368 sal_uInt16 nCount
= rTable
.size();
3369 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3371 if ( rTable
[j
].GetLanguage() == eLang
)
3380 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry(const OUString
& rAbbrev
, LanguageType eLang
)
3382 eLang
= MsLangId::getRealLanguage( eLang
);
3383 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3384 sal_uInt16 nCount
= rTable
.size();
3385 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3387 if ( rTable
[j
].GetLanguage() == eLang
&&
3388 rTable
[j
].GetBankSymbol() == rAbbrev
)
3398 const NfCurrencyEntry
* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( const OUString
& rSymbol
,
3399 const OUString
& rAbbrev
)
3401 GetTheCurrencyTable(); // just for initialization
3402 const NfCurrencyTable
& rTable
= theLegacyOnlyCurrencyTable::get();
3403 sal_uInt16 nCount
= rTable
.size();
3404 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3406 if ( rTable
[j
].GetSymbol() == rSymbol
&&
3407 rTable
[j
].GetBankSymbol() == rAbbrev
)
3417 IMPL_STATIC_LINK_NOARG( SvNumberFormatter
, CurrencyChangeLink
, LinkParamNone
*, void )
3420 LanguageType eLang
= LANGUAGE_SYSTEM
;
3421 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev
, eLang
);
3422 SetDefaultSystemCurrency( aAbbrev
, eLang
);
3427 void SvNumberFormatter::SetDefaultSystemCurrency( const OUString
& rAbbrev
, LanguageType eLang
)
3429 ::osl::MutexGuard
aGuard( GetGlobalMutex() );
3430 if ( eLang
== LANGUAGE_SYSTEM
)
3432 eLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
3434 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3435 sal_uInt16 nCount
= rTable
.size();
3436 if ( !rAbbrev
.isEmpty() )
3438 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3440 if ( rTable
[j
].GetLanguage() == eLang
&& rTable
[j
].GetBankSymbol() == rAbbrev
)
3442 nSystemCurrencyPosition
= j
;
3449 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3451 if ( rTable
[j
].GetLanguage() == eLang
)
3453 nSystemCurrencyPosition
= j
;
3458 nSystemCurrencyPosition
= 0; // not found => simple SYSTEM
3462 void SvNumberFormatter::ResetDefaultSystemCurrency()
3464 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
3468 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3470 pStringScanner
->InvalidateDateAcceptancePatterns();
3474 sal_uInt32
SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3476 if ( nDefaultSystemCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3479 SvNumFormatType nType
;
3480 NfWSStringsDtor aCurrList
;
3481 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3482 GetCurrencyEntry( LANGUAGE_SYSTEM
), false );
3483 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency System standard format?!?" );
3484 // if already loaded or user defined nDefaultSystemCurrencyFormat
3485 // will be set to the right value
3486 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3487 nDefaultSystemCurrencyFormat
, LANGUAGE_SYSTEM
);
3488 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3489 DBG_ASSERT( nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3490 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3492 return nDefaultSystemCurrencyFormat
;
3496 sal_uInt32
SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3498 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
3499 DefaultFormatKeysMap::const_iterator it
= aDefaultFormatKeys
.find( CLOffset
+ ZF_STANDARD_CURRENCY
);
3500 sal_uInt32 nDefaultCurrencyFormat
= (it
!= aDefaultFormatKeys
.end() ?
3501 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
3502 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3504 // look for a defined standard
3505 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
3507 auto it2
= aFTable
.lower_bound( CLOffset
);
3508 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
3510 const SvNumberformat
* pEntry
= it2
->second
.get();
3511 if ( pEntry
->IsStandard() && (pEntry
->GetType() & SvNumFormatType::CURRENCY
) )
3513 nDefaultCurrencyFormat
= nKey
;
3519 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3520 { // none found, create one
3522 NfWSStringsDtor aCurrList
;
3523 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3524 GetCurrencyEntry( ActLnge
), false );
3525 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency standard format?" );
3526 if ( !aCurrList
.empty() )
3528 // if already loaded or user defined nDefaultSystemCurrencyFormat
3529 // will be set to the right value
3530 SvNumFormatType nType
;
3531 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3532 nDefaultCurrencyFormat
, ActLnge
);
3533 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3534 DBG_ASSERT( nDefaultCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3535 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3537 // old automatic currency format as a last resort
3538 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3539 nDefaultCurrencyFormat
= CLOffset
+ ZF_STANDARD_CURRENCY
+3;
3541 { // mark as standard so that it is found next time
3542 SvNumberformat
* pEntry
= GetFormatEntry( nDefaultCurrencyFormat
);
3544 pEntry
->SetStandard();
3547 aDefaultFormatKeys
[ CLOffset
+ ZF_STANDARD_CURRENCY
] = nDefaultCurrencyFormat
;
3549 return nDefaultCurrencyFormat
;
3554 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
3555 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3556 const NfCurrencyEntry
*& pFoundEntry
, bool& bFoundBank
, const NfCurrencyEntry
* pData
,
3557 sal_uInt16 nPos
, const OUString
& rSymbol
)
3560 if ( pData
->GetSymbol() == rSymbol
)
3565 else if ( pData
->GetBankSymbol() == rSymbol
)
3574 if ( pFoundEntry
&& pFoundEntry
!= pData
)
3576 pFoundEntry
= nullptr;
3577 return false; // break loop, not unique
3580 { // first entry is SYSTEM
3581 pFoundEntry
= MatchSystemCurrency();
3584 return false; // break loop
3585 // even if there are more matching entries
3586 // this one is probably the one we are looking for
3590 pFoundEntry
= pData
;
3595 pFoundEntry
= pData
;
3602 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat
, OUString
& rStr
,
3603 const NfCurrencyEntry
** ppEntry
/* = NULL */,
3604 bool* pBank
/* = NULL */ ) const
3606 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3612 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
3615 OUStringBuffer
sBuff(128); // guess-estimate of a value that will pretty much guarantee no re-alloc
3616 OUString aSymbol
, aExtension
;
3617 if ( pFormat
->GetNewCurrencySymbol( aSymbol
, aExtension
) )
3621 bool bFoundBank
= false;
3622 // we definitely need an entry matching the format code string
3623 const NfCurrencyEntry
* pFoundEntry
= GetCurrencyEntry(
3624 bFoundBank
, aSymbol
, aExtension
, pFormat
->GetLanguage(),
3628 *ppEntry
= pFoundEntry
;
3630 *pBank
= bFoundBank
;
3631 rStr
= pFoundEntry
->BuildSymbolString(bFoundBank
);
3634 if ( rStr
.isEmpty() )
3635 { // analog to BuildSymbolString
3637 if ( aSymbol
.indexOf( '-' ) != -1 ||
3638 aSymbol
.indexOf( ']' ) != -1 )
3641 sBuff
.append( aSymbol
);
3646 sBuff
.append(aSymbol
);
3648 if ( !aExtension
.isEmpty() )
3650 sBuff
.append(aExtension
);
3654 rStr
= sBuff
.toString();
3664 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank
,
3665 const OUString
& rSymbol
,
3666 const OUString
& rExtension
,
3667 LanguageType eFormatLanguage
,
3668 bool bOnlyStringLanguage
)
3670 sal_Int32 nExtLen
= rExtension
.getLength();
3671 LanguageType eExtLang
;
3674 // rExtension should be a 16-bit hex value max FFFF which may contain a
3675 // leading "-" separator (that is not a minus sign, but toInt32 can be
3676 // used to parse it, with post-processing as necessary):
3677 sal_Int32 nExtLang
= rExtension
.toInt32( 16 );
3680 eExtLang
= LANGUAGE_DONTKNOW
;
3684 eExtLang
= LanguageType((nExtLang
< 0) ? -nExtLang
: nExtLang
);
3689 eExtLang
= LANGUAGE_DONTKNOW
;
3691 const NfCurrencyEntry
* pFoundEntry
= nullptr;
3692 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3693 sal_uInt16 nCount
= rTable
.size();
3696 // first try with given extension language/country
3699 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3701 LanguageType eLang
= rTable
[j
].GetLanguage();
3702 if ( eLang
== eExtLang
||
3703 ((eExtLang
== LANGUAGE_DONTKNOW
) &&
3704 (eLang
== LANGUAGE_SYSTEM
)))
3706 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3707 &rTable
[j
], j
, rSymbol
);
3713 if ( pFoundEntry
|| !bCont
|| (bOnlyStringLanguage
&& nExtLen
) )
3717 if ( !bOnlyStringLanguage
)
3719 // now try the language/country of the number format
3720 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3722 LanguageType eLang
= rTable
[j
].GetLanguage();
3723 if ( eLang
== eFormatLanguage
||
3724 ((eFormatLanguage
== LANGUAGE_DONTKNOW
) &&
3725 (eLang
== LANGUAGE_SYSTEM
)))
3727 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3728 &rTable
[j
], j
, rSymbol
);
3733 if ( pFoundEntry
|| !bCont
)
3739 // then try without language/country if no extension specified
3742 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3744 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3745 &rTable
[j
], j
, rSymbol
);
3753 void SvNumberFormatter::GetCompatibilityCurrency( OUString
& rSymbol
, OUString
& rAbbrev
) const
3755 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
3756 css::uno::Sequence
< css::i18n::Currency2
>
3757 xCurrencies( xLocaleData
->getAllCurrencies() );
3759 const css::i18n::Currency2
*pCurrencies
= xCurrencies
.getConstArray();
3760 sal_Int32 nCurrencies
= xCurrencies
.getLength();
3763 for ( j
=0; j
< nCurrencies
; ++j
)
3765 if ( pCurrencies
[j
].UsedInCompatibleFormatCodes
)
3767 rSymbol
= pCurrencies
[j
].Symbol
;
3768 rAbbrev
= pCurrencies
[j
].BankSymbol
;
3772 if ( j
>= nCurrencies
)
3774 if (LocaleDataWrapper::areChecksEnabled())
3776 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
3777 appendLocaleInfo( "GetCompatibilityCurrency: none?"));
3779 rSymbol
= xLocaleData
->getCurrSymbol();
3780 rAbbrev
= xLocaleData
->getCurrBankSymbol();
3785 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry
& rCurr
)
3787 switch ( rCurr
.GetPositiveFormat() )
3795 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3798 switch ( rCurr
.GetNegativeFormat() )
3818 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3824 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang
)
3826 // The set is initialized as a side effect of the currency table
3827 // created, make sure that exists, which usually is the case unless a
3828 // SvNumberFormatter was never instantiated.
3829 GetTheCurrencyTable();
3830 const NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
3831 return rInstalledLocales
.find( eLang
) != rInstalledLocales
.end();
3835 void SvNumberFormatter::ImpInitCurrencyTable()
3837 // Race condition possible:
3838 // ::osl::MutexGuard aGuard( GetMutex() );
3839 // while ( !bCurrencyTableInitialized )
3840 // ImpInitCurrencyTable();
3841 static bool bInitializing
= false;
3842 if ( bCurrencyTableInitialized
|| bInitializing
)
3846 bInitializing
= true;
3848 LanguageType eSysLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
3849 std::unique_ptr
<LocaleDataWrapper
> pLocaleData(new LocaleDataWrapper(
3850 ::comphelper::getProcessComponentContext(),
3851 SvtSysLocale().GetLanguageTag() ));
3852 // get user configured currency
3853 OUString aConfiguredCurrencyAbbrev
;
3854 LanguageType eConfiguredCurrencyLanguage
= LANGUAGE_SYSTEM
;
3855 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3856 aConfiguredCurrencyAbbrev
, eConfiguredCurrencyLanguage
);
3857 sal_uInt16 nSecondarySystemCurrencyPosition
= 0;
3858 sal_uInt16 nMatchingSystemCurrencyPosition
= 0;
3860 // First entry is SYSTEM:
3861 theCurrencyTable::get().insert(
3862 theCurrencyTable::get().begin(),
3863 o3tl::make_unique
<NfCurrencyEntry
>(*pLocaleData
, LANGUAGE_SYSTEM
));
3864 sal_uInt16 nCurrencyPos
= 1;
3866 css::uno::Sequence
< css::lang::Locale
> xLoc
= LocaleDataWrapper::getInstalledLocaleNames();
3867 sal_Int32 nLocaleCount
= xLoc
.getLength();
3868 SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount
<< "\"" );
3869 css::lang::Locale
const * const pLocales
= xLoc
.getConstArray();
3870 NfCurrencyTable
&rCurrencyTable
= theCurrencyTable::get();
3871 NfCurrencyTable
&rLegacyOnlyCurrencyTable
= theLegacyOnlyCurrencyTable::get();
3872 NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
3873 sal_uInt16 nLegacyOnlyCurrencyPos
= 0;
3874 for ( sal_Int32 nLocale
= 0; nLocale
< nLocaleCount
; nLocale
++ )
3876 LanguageType eLang
= LanguageTag::convertToLanguageType( pLocales
[nLocale
], false);
3877 rInstalledLocales
.insert( eLang
);
3878 pLocaleData
->setLanguageTag( LanguageTag( pLocales
[nLocale
]) );
3879 Sequence
< Currency2
> aCurrSeq
= pLocaleData
->getAllCurrencies();
3880 sal_Int32 nCurrencyCount
= aCurrSeq
.getLength();
3881 Currency2
const * const pCurrencies
= aCurrSeq
.getConstArray();
3883 // one default currency for each locale, insert first so it is found first
3885 for ( nDefault
= 0; nDefault
< nCurrencyCount
; nDefault
++ )
3887 if ( pCurrencies
[nDefault
].Default
)
3890 std::unique_ptr
<NfCurrencyEntry
> pEntry
;
3891 if ( nDefault
< nCurrencyCount
)
3893 pEntry
.reset(new NfCurrencyEntry(pCurrencies
[nDefault
], *pLocaleData
, eLang
));
3896 { // first or ShellsAndPebbles
3897 pEntry
.reset(new NfCurrencyEntry(*pLocaleData
, eLang
));
3899 if (LocaleDataWrapper::areChecksEnabled())
3901 lcl_CheckCurrencySymbolPosition( *pEntry
);
3903 if ( !nSystemCurrencyPosition
&& !aConfiguredCurrencyAbbrev
.isEmpty() &&
3904 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
&&
3905 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
)
3907 nSystemCurrencyPosition
= nCurrencyPos
;
3909 if ( !nMatchingSystemCurrencyPosition
&&
3910 pEntry
->GetLanguage() == eSysLang
)
3912 nMatchingSystemCurrencyPosition
= nCurrencyPos
;
3914 rCurrencyTable
.insert(
3915 rCurrencyTable
.begin() + nCurrencyPos
++, std::move(pEntry
));
3916 // all remaining currencies for each locale
3917 if ( nCurrencyCount
> 1 )
3919 sal_Int32 nCurrency
;
3920 for ( nCurrency
= 0; nCurrency
< nCurrencyCount
; nCurrency
++ )
3922 if (pCurrencies
[nCurrency
].LegacyOnly
)
3924 rLegacyOnlyCurrencyTable
.insert(
3925 rLegacyOnlyCurrencyTable
.begin() + nLegacyOnlyCurrencyPos
++,
3926 o3tl::make_unique
<NfCurrencyEntry
>(
3927 pCurrencies
[nCurrency
], *pLocaleData
, eLang
));
3929 else if ( nCurrency
!= nDefault
)
3931 pEntry
.reset(new NfCurrencyEntry(pCurrencies
[nCurrency
], *pLocaleData
, eLang
));
3933 bool bInsert
= true;
3934 sal_uInt16 n
= rCurrencyTable
.size();
3935 sal_uInt16 aCurrencyIndex
= 1; // skip first SYSTEM entry
3936 for ( sal_uInt16 j
=1; j
<n
; j
++ )
3938 if ( rCurrencyTable
[aCurrencyIndex
++] == *pEntry
)
3950 if ( !nSecondarySystemCurrencyPosition
&&
3951 (!aConfiguredCurrencyAbbrev
.isEmpty() ?
3952 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
:
3953 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
) )
3955 nSecondarySystemCurrencyPosition
= nCurrencyPos
;
3957 if ( !nMatchingSystemCurrencyPosition
&&
3958 pEntry
->GetLanguage() == eSysLang
)
3960 nMatchingSystemCurrencyPosition
= nCurrencyPos
;
3962 rCurrencyTable
.insert(
3963 rCurrencyTable
.begin() + nCurrencyPos
++, std::move(pEntry
));
3969 if ( !nSystemCurrencyPosition
)
3971 nSystemCurrencyPosition
= nSecondarySystemCurrencyPosition
;
3973 if ((!aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
3974 LocaleDataWrapper::areChecksEnabled())
3976 LocaleDataWrapper::outputCheckMessage(
3977 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3979 // match SYSTEM if no configured currency found
3980 if ( !nSystemCurrencyPosition
)
3982 nSystemCurrencyPosition
= nMatchingSystemCurrencyPosition
;
3984 if ((aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
3985 LocaleDataWrapper::areChecksEnabled())
3987 LocaleDataWrapper::outputCheckMessage(
3988 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3990 pLocaleData
.reset();
3991 SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( nullptr, SvNumberFormatter
, CurrencyChangeLink
) );
3992 bInitializing
= false;
3993 bCurrencyTableInitialized
= true;
3997 static void addToCurrencyFormatsList( NfWSStringsDtor
& rStrArr
, const OUString
& rFormat
)
3999 // Prevent duplicates even over subsequent calls of
4000 // GetCurrencyFormatStrings() with the same vector.
4001 if (std::find( rStrArr
.begin(), rStrArr
.end(), rFormat
) == rStrArr
.end())
4002 rStrArr
.push_back( rFormat
);
4006 sal_uInt16
SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor
& rStrArr
,
4007 const NfCurrencyEntry
& rCurr
,
4010 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4012 + pFormatScanner
->GetRedString()
4015 sal_uInt16 nDefault
= 0;
4018 // Only bank symbols.
4019 OUString aPositiveBank
= rCurr
.BuildPositiveFormatString(true, *xLocaleData
);
4020 OUString aNegativeBank
= rCurr
.BuildNegativeFormatString(true, *xLocaleData
);
4022 OUString format1
= aPositiveBank
4025 addToCurrencyFormatsList( rStrArr
, format1
);
4027 OUString format2
= aPositiveBank
4031 addToCurrencyFormatsList( rStrArr
, format2
);
4033 nDefault
= rStrArr
.size() - 1;
4037 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
4038 // duplicates if no decimals in currency.
4039 OUString aPositive
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
);
4040 OUString aNegative
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
);
4046 if (rCurr
.GetDigits())
4048 OUString aPositiveNoDec
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 0);
4049 OUString aNegativeNoDec
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 0 );
4050 OUString aPositiveDashed
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 2);
4051 OUString aNegativeDashed
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 2);
4053 format1
= aPositiveNoDec
4057 format3
= aPositiveNoDec
4062 format5
= aPositiveDashed
4077 if (rCurr
.GetDigits())
4079 addToCurrencyFormatsList( rStrArr
, format1
);
4081 addToCurrencyFormatsList( rStrArr
, format2
);
4082 if (rCurr
.GetDigits())
4084 addToCurrencyFormatsList( rStrArr
, format3
);
4086 addToCurrencyFormatsList( rStrArr
, format4
);
4087 nDefault
= rStrArr
.size() - 1;
4088 if (rCurr
.GetDigits())
4090 addToCurrencyFormatsList( rStrArr
, format5
);
4096 sal_uInt32
SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt
) const
4098 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4101 SvNumberFormatterIndexTable::const_iterator it
= pMergeTable
->find(nOldFmt
);
4102 if (it
!= pMergeTable
->end())
4110 bool SvNumberFormatter::HasMergeFormatTable() const
4112 ::osl::MutexGuard
aGuard( GetInstanceMutex() );
4113 return pMergeTable
&& !pMergeTable
->empty();
4117 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
, sal_uInt16 nTwoDigitYearStart
)
4121 if ( nYear
< (nTwoDigitYearStart
% 100) )
4123 return nYear
+ (((nTwoDigitYearStart
/ 100) + 1) * 100);
4127 return nYear
+ ((nTwoDigitYearStart
/ 100) * 100);
4133 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
4135 aSymbol
= rLocaleData
.getCurrSymbol();
4136 aBankSymbol
= rLocaleData
.getCurrBankSymbol();
4138 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
4139 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
4140 nDigits
= rLocaleData
.getCurrDigits();
4141 cZeroChar
= rLocaleData
.getCurrZeroChar();
4145 NfCurrencyEntry::NfCurrencyEntry( const css::i18n::Currency
& rCurr
,
4146 const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
4148 aSymbol
= rCurr
.Symbol
;
4149 aBankSymbol
= rCurr
.BankSymbol
;
4151 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
4152 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
4153 nDigits
= rCurr
.DecimalPlaces
;
4154 cZeroChar
= rLocaleData
.getCurrZeroChar();
4157 bool NfCurrencyEntry::operator==( const NfCurrencyEntry
& r
) const
4159 return aSymbol
== r
.aSymbol
4160 && aBankSymbol
== r
.aBankSymbol
4161 && eLanguage
== r
.eLanguage
4165 OUString
NfCurrencyEntry::BuildSymbolString(bool bBank
,
4166 bool bWithoutExtension
) const
4168 OUStringBuffer
aBuf("[$");
4171 aBuf
.append(aBankSymbol
);
4175 if ( aSymbol
.indexOf( '-' ) >= 0 ||
4176 aSymbol
.indexOf( ']' ) >= 0)
4178 aBuf
.append('"').append(aSymbol
).append('"');
4182 aBuf
.append(aSymbol
);
4184 if ( !bWithoutExtension
&& eLanguage
!= LANGUAGE_DONTKNOW
&& eLanguage
!= LANGUAGE_SYSTEM
)
4186 sal_Int32 nLang
= static_cast<sal_uInt16
>(eLanguage
);
4187 aBuf
.append('-').append( OUString::number(nLang
, 16).toAsciiUpperCase());
4191 return aBuf
.makeStringAndClear();
4194 OUString
NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper
& rLoc
,
4195 sal_uInt16 nDecimalFormat
) const
4197 OUStringBuffer aBuf
;
4198 aBuf
.append('#').append(rLoc
.getNumThousandSep()).append("##0");
4199 if (nDecimalFormat
&& nDigits
)
4201 aBuf
.append(rLoc
.getNumDecimalSep());
4202 sal_Unicode cDecimalChar
= nDecimalFormat
== 2 ? '-' : cZeroChar
;
4203 for (sal_uInt16 i
= 0; i
< nDigits
; ++i
)
4205 aBuf
.append(cDecimalChar
);
4208 return aBuf
.makeStringAndClear();
4212 OUString
NfCurrencyEntry::BuildPositiveFormatString(bool bBank
, const LocaleDataWrapper
& rLoc
,
4213 sal_uInt16 nDecimalFormat
) const
4215 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
4216 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat( rLoc
.getCurrPositiveFormat(),
4217 nPositiveFormat
, bBank
);
4218 CompletePositiveFormatString(sBuf
, bBank
, nPosiForm
);
4219 return sBuf
.makeStringAndClear();
4223 OUString
NfCurrencyEntry::BuildNegativeFormatString(bool bBank
,
4224 const LocaleDataWrapper
& rLoc
, sal_uInt16 nDecimalFormat
) const
4226 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
4227 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc
.getCurrNegativeFormat(),
4228 nNegativeFormat
, bBank
);
4229 CompleteNegativeFormatString(sBuf
, bBank
, nNegaForm
);
4230 return sBuf
.makeStringAndClear();
4234 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, bool bBank
,
4235 sal_uInt16 nPosiForm
) const
4237 OUString aSymStr
= BuildSymbolString(bBank
);
4238 NfCurrencyEntry::CompletePositiveFormatString( rStr
, aSymStr
, nPosiForm
);
4242 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
, bool bBank
,
4243 sal_uInt16 nNegaForm
) const
4245 OUString aSymStr
= BuildSymbolString(bBank
);
4246 NfCurrencyEntry::CompleteNegativeFormatString( rStr
, aSymStr
, nNegaForm
);
4251 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, const OUString
& rSymStr
,
4252 sal_uInt16 nPositiveFormat
)
4254 switch( nPositiveFormat
)
4257 rStr
.insert(0, rSymStr
);
4260 rStr
.append(rSymStr
);
4264 rStr
.insert(0, ' ');
4265 rStr
.insert(0, rSymStr
);
4271 rStr
.append(rSymStr
);
4275 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4282 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
,
4283 const OUString
& rSymStr
,
4284 sal_uInt16 nNegativeFormat
)
4286 switch( nNegativeFormat
)
4290 rStr
.insert(0, rSymStr
);
4291 rStr
.insert(0, '(');
4297 rStr
.insert(0, rSymStr
);
4298 rStr
.insert(0, '-');
4303 rStr
.insert(0, '-');
4304 rStr
.insert(0, rSymStr
);
4309 rStr
.insert(0, rSymStr
);
4315 rStr
.insert(0, '(');
4316 rStr
.append(rSymStr
);
4322 rStr
.append(rSymStr
);
4323 rStr
.insert(0, '-');
4329 rStr
.append(rSymStr
);
4334 rStr
.append(rSymStr
);
4341 rStr
.append(rSymStr
);
4342 rStr
.insert(0, '-');
4347 rStr
.insert(0, ' ');
4348 rStr
.insert(0, rSymStr
);
4349 rStr
.insert(0, '-');
4355 rStr
.append(rSymStr
);
4361 rStr
.insert(0, " -");
4362 rStr
.insert(0, rSymStr
);
4367 rStr
.insert(0, ' ');
4368 rStr
.insert(0, rSymStr
);
4376 rStr
.append(rSymStr
);
4381 rStr
.insert(0, ' ');
4382 rStr
.insert(0, rSymStr
);
4383 rStr
.insert(0, '(');
4389 rStr
.insert(0, '(');
4391 rStr
.append(rSymStr
);
4396 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4403 sal_uInt16
NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat
,
4404 sal_uInt16 nCurrFormat
, bool bBank
)
4408 #if NF_BANKSYMBOL_FIX_POSITION
4409 (void) nIntlFormat
; // avoid warnings
4412 switch ( nIntlFormat
)
4415 nIntlFormat
= 2; // $ 1
4418 nIntlFormat
= 3; // 1 $
4425 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4436 //! Call this only if nCurrFormat is really with parentheses!
4437 static sal_uInt16
lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat
, sal_uInt16 nCurrFormat
)
4439 short nSign
= 0; // -1:=bracket 0:=left, 1:=middle, 2:=right
4440 switch ( nIntlFormat
)
4466 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4470 switch ( nCurrFormat
)
4522 sal_uInt16
NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat
,
4523 sal_uInt16 nCurrFormat
, bool bBank
)
4527 #if NF_BANKSYMBOL_FIX_POSITION
4530 switch ( nIntlFormat
)
4533 // nIntlFormat = 14; // ($ 1)
4534 nIntlFormat
= 9; // -$ 1
4537 nIntlFormat
= 9; // -$ 1
4540 nIntlFormat
= 11; // $ -1
4543 nIntlFormat
= 12; // $ 1-
4546 // nIntlFormat = 15; // (1 $)
4547 nIntlFormat
= 8; // -1 $
4550 nIntlFormat
= 8; // -1 $
4553 nIntlFormat
= 13; // 1- $
4556 nIntlFormat
= 10; // 1 $-
4571 // nIntlFormat = 14; // ($ 1)
4572 nIntlFormat
= 9; // -$ 1
4575 // nIntlFormat = 15; // (1 $)
4576 nIntlFormat
= 8; // -1 $
4579 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4584 else if ( nIntlFormat
!= nCurrFormat
)
4586 switch ( nCurrFormat
)
4589 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4590 nIntlFormat
, nCurrFormat
);
4593 nIntlFormat
= nCurrFormat
;
4596 nIntlFormat
= nCurrFormat
;
4599 nIntlFormat
= nCurrFormat
;
4602 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4603 nIntlFormat
, nCurrFormat
);
4606 nIntlFormat
= nCurrFormat
;
4609 nIntlFormat
= nCurrFormat
;
4612 nIntlFormat
= nCurrFormat
;
4615 nIntlFormat
= nCurrFormat
;
4618 nIntlFormat
= nCurrFormat
;
4621 nIntlFormat
= nCurrFormat
;
4624 nIntlFormat
= nCurrFormat
;
4627 nIntlFormat
= nCurrFormat
;
4630 nIntlFormat
= nCurrFormat
;
4633 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4634 nIntlFormat
, nCurrFormat
);
4637 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4638 nIntlFormat
, nCurrFormat
);
4641 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4648 const NfKeywordTable
& SvNumberFormatter::GetKeywords( sal_uInt32 nKey
)
4650 osl::MutexGuard
aGuard( GetInstanceMutex() );
4651 const SvNumberformat
* pFormat
= GetFormatEntry( nKey
);
4653 ChangeIntl( pFormat
->GetLanguage());
4655 ChangeIntl( IniLnge
);
4656 return pFormatScanner
->GetKeywords();
4659 const NfKeywordTable
& SvNumberFormatter::GetEnglishKeywords() const
4661 return ImpSvNumberformatScan::GetEnglishKeywords();
4664 const std::vector
<Color
> & SvNumberFormatter::GetStandardColors() const
4666 return ImpSvNumberformatScan::GetStandardColors();
4669 size_t SvNumberFormatter::GetMaxDefaultColors() const
4671 return ImpSvNumberformatScan::GetMaxDefaultColors();
4674 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */