lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / svl / source / numbers / zforlist.cxx
blob68e9ef12e1ba8c43d116a36697ddb1942b3354ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
56 #include <math.h>
57 #include <limits>
58 #include <memory>
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)
67 #define ZF_STANDARD 0
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;
176 public:
177 SvNumberFormatterRegistry_Impl();
178 virtual ~SvNumberFormatterRegistry_Impl() override;
180 void Insert( SvNumberFormatter* pThis )
181 { aFormatters.push_back( pThis ); }
183 void Remove( SvNumberFormatter const * pThis );
185 size_t Count() const
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)
209 if ( *it == pThis )
211 aFormatters.erase( it );
212 break;
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;
243 namespace
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,
266 LanguageType eLang )
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;
285 aFTable.clear();
286 ClearMergeTable();
290 void SvNumberFormatter::ImpConstruct( LanguageType eLang )
292 if ( eLang == LANGUAGE_DONTKNOW )
294 eLang = UNKNOWN_SUBSTITUTE;
296 IniLnge = eLang;
297 ActLnge = eLang;
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;
318 MaxCLOffset = 0;
319 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
320 pMergeTable = nullptr;
321 bNoZero = false;
323 ::osl::MutexGuard aGuard( GetGlobalMutex() );
324 GetFormatterRegistry().Insert( this );
328 void SvNumberFormatter::ChangeIntl(LanguageType eLnge)
330 ::osl::MutexGuard aGuard( GetInstanceMutex() );
331 if (ActLnge == eLnge)
332 return;
334 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();
354 // static
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;
366 // static
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);
390 else
392 return nullptr;
396 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay,
397 sal_uInt16 nMonth,
398 sal_Int16 nYear)
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() );
420 bNoZero = bNZ;
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() );
432 return bNoZero;
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;
444 sal_uInt32 nKey;
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 )
476 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
486 bool bCheck = false;
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 );
497 else
499 pNewEntry->SetType( SvNumFormatType::DEFINED );
502 if ( aFTable.emplace( nKey, std::move(pNewEntry) ).second )
504 bCheck = true;
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
519 return m_xContext;
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())
550 return true;
551 if (GetNumDecimalSepAlt().isEmpty())
552 return false;
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
568 LanguageType eLnge)
570 ::osl::MutexGuard aGuard( GetInstanceMutex() );
571 nKey = 0;
572 if (rString.isEmpty()) // empty string
574 nCheckPos = 1; // -> Error
575 return false;
577 if (eLnge == LANGUAGE_DONTKNOW)
579 eLnge = IniLnge;
581 ChangeIntl(eLnge); // change locale if necessary
582 LanguageType eLge = eLnge; // non-const for ConvertMode
583 bool bCheck = false;
584 std::unique_ptr<SvNumberformat> p_Entry(new SvNumberformat(rString,
585 pFormatScanner.get(),
586 pStringScanner.get(),
587 nCheckPos,
588 eLge));
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);
596 nType = eCheckType;
598 else
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");
619 else
621 bCheck = true;
622 nKey = nPos+1;
623 pStdFormat->SetLastInsertKey(static_cast<sal_uInt16>(nKey-CLOffset), SvNumberformat::FormatterPrivateAccess());
627 return bCheck;
630 bool SvNumberFormatter::PutandConvertEntry(OUString& rString,
631 sal_Int32& nCheckPos,
632 SvNumFormatType& nType,
633 sal_uInt32& nKey,
634 LanguageType eLnge,
635 LanguageType eNewLnge,
636 bool bConvertDateOrder )
638 ::osl::MutexGuard aGuard( GetInstanceMutex() );
639 bool bRes;
640 if (eNewLnge == LANGUAGE_DONTKNOW)
642 eNewLnge = IniLnge;
644 pFormatScanner->SetConvertMode(eLnge, eNewLnge, false, bConvertDateOrder);
645 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
646 pFormatScanner->SetConvertMode(false);
647 return bRes;
650 bool SvNumberFormatter::PutandConvertEntrySystem(OUString& rString,
651 sal_Int32& nCheckPos,
652 SvNumFormatType& nType,
653 sal_uInt32& nKey,
654 LanguageType eLnge,
655 LanguageType eNewLnge)
657 ::osl::MutexGuard aGuard( GetInstanceMutex() );
658 bool bRes;
659 if (eNewLnge == LANGUAGE_DONTKNOW)
661 eNewLnge = IniLnge;
663 pFormatScanner->SetConvertMode(eLnge, eNewLnge, true, true);
664 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
665 pFormatScanner->SetConvertMode(false);
666 return bRes;
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;
676 rCheckPos = 0;
678 // #62389# empty format string (of Writer) => General standard format
679 if (rString.isEmpty())
681 // nothing
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
690 else
692 nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguageTag().getLanguageType() );
694 if (nKey == nOrig)
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());
702 if (rCheckPos > 0)
704 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
705 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
709 else
711 nKey = GetEntryKey( rString, eLnge);
712 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
714 rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
715 if (rCheckPos > 0)
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
728 // default format.
729 if (rType & SvNumFormatType::CURRENCY)
731 const SvNumberformat* pFormat = GetEntry( nKey);
732 if (!pFormat->HasNewCurrency())
734 if (rNewInserted)
736 DeleteEntry( nKey); // don't leave trails of rubbish
737 rNewInserted = false;
739 nKey = GetStandardFormat( SvNumFormatType::CURRENCY, eLnge);
742 return nKey;
745 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey)
747 ::osl::MutexGuard aGuard( GetInstanceMutex() );
748 aFTable.erase(nKey);
751 void SvNumberFormatter::GetUsedLanguages( std::vector<LanguageType>& rList )
753 ::osl::MutexGuard aGuard( GetInstanceMutex() );
754 rList.clear();
756 sal_uInt32 nOffset = 0;
757 while (nOffset <= MaxCLOffset)
759 SvNumberformat* pFormat = GetFormatEntry(nOffset);
760 if (pFormat)
762 rList.push_back( pFormat->GetLanguage() );
764 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
769 void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords,
770 LanguageType eLang )
772 ::osl::MutexGuard aGuard( GetInstanceMutex() );
773 ChangeIntl( eLang );
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() );
803 OUString aFormatStr;
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;
811 OUString aTemp;
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 + "\"";
817 else
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)
828 sal_Int32 nCheckPos;
829 SvNumFormatType nType = SvNumFormatType::DEFINED;
830 sal_uInt32 nTempKey;
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);
839 if (pEntry)
841 // GetLocaleData() returns the current locale's data, so switch
842 // before (which doesn't do anything if it was the same locale
843 // already).
844 rTempFormatter.ChangeIntl( LANGUAGE_ENGLISH_US);
845 aFormatStr = pEntry->GetMappedFormatstring( rKeywords, *rTempFormatter.GetLocaleData(), nLang,
846 bSystemLanguage);
850 else
852 SAL_WARN("svl.numbers","SvNumberFormatter::GetFormatStringForExcel - format not found: " << nKey);
855 if (aFormatStr.isEmpty())
856 aFormatStr = "General";
857 return aFormatStr;
861 OUString SvNumberFormatter::GetKeyword( LanguageType eLnge, sal_uInt16 nIndex )
863 ::osl::MutexGuard aGuard( GetInstanceMutex() );
864 ChangeIntl(eLnge);
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");
871 return OUString();
875 OUString SvNumberFormatter::GetStandardName( LanguageType eLnge )
877 ::osl::MutexGuard aGuard( GetInstanceMutex() );
878 ChangeIntl( eLnge );
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)
891 return nOffset;
893 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
895 return nOffset;
898 sal_uInt32 SvNumberFormatter::ImpIsEntry(const OUString& rString,
899 sal_uInt32 nCLOffset,
900 LanguageType eLnge)
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() )
909 res = it->first;
911 else
913 ++it;
916 return res;
920 SvNumberFormatTable& SvNumberFormatter::GetFirstEntryTable(
921 SvNumFormatType& eType,
922 sal_uInt32& FIndex,
923 LanguageType& rLnge)
925 ::osl::MutexGuard aGuard( GetInstanceMutex() );
926 SvNumFormatType eTypetmp = eType;
927 if (eType == SvNumFormatType::ALL) // empty cell or don't care
929 rLnge = IniLnge;
931 else
933 SvNumberformat* pFormat = GetFormatEntry(FIndex);
934 if (!pFormat)
936 rLnge = IniLnge;
937 eType = SvNumFormatType::ALL;
938 eTypetmp = eType;
940 else
942 rLnge = pFormat->GetLanguage();
943 eType = pFormat->GetMaskedType();
944 if (eType == SvNumFormatType::ALL)
946 eType = SvNumFormatType::DEFINED;
947 eTypetmp = eType;
949 else if (eType == SvNumFormatType::DATETIME)
951 eTypetmp = eType;
952 eType = SvNumFormatType::DATE;
954 else
956 eTypetmp = eType;
960 ChangeIntl(rLnge);
961 return GetEntryTable(eTypetmp, FIndex, rLnge);
964 sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge )
966 ChangeIntl(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 ));
996 aDupes.append("(");
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 )
1007 + "("
1008 + xSeq[j].formatKey
1009 + ") "
1010 + aDupes.makeStringAndClear();
1011 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg ));
1017 MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET;
1018 ImpGenerateFormats( MaxCLOffset, false/*bNoAdditionalFormats*/ );
1019 CLOffset = MaxCLOffset;
1021 return CLOffset;
1024 SvNumberFormatTable& SvNumberFormatter::ChangeCL(SvNumFormatType eType,
1025 sal_uInt32& FIndex,
1026 LanguageType eLnge)
1028 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1029 ImpGenerateCL(eLnge);
1030 return GetEntryTable(eType, FIndex, ActLnge);
1033 SvNumberFormatTable& SvNumberFormatter::GetEntryTable(
1034 SvNumFormatType eType,
1035 sal_uInt32& FIndex,
1036 LanguageType eLnge)
1038 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1039 if ( pFormatTable )
1041 pFormatTable->clear();
1043 else
1045 pFormatTable.reset( new SvNumberFormatTable );
1047 ChangeIntl(eLnge);
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();
1061 ++it;
1064 else
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();
1070 ++it;
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,
1087 double& fOutNumber)
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)));
1095 if (!pFormat)
1097 ChangeIntl(IniLnge);
1098 FType = SvNumFormatType::NUMBER;
1100 else
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);
1113 pFormat = nullptr;
1117 bool res;
1118 SvNumFormatType RType = FType;
1119 if (RType == SvNumFormatType::TEXT)
1121 res = false; // type text preset => no conversion to number
1123 else
1125 res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat);
1127 if (res && !IsCompatible(FType, RType)) // non-matching type
1129 switch ( RType )
1131 case SvNumFormatType::DATE :
1132 // Preserve ISO 8601 input.
1133 if (pStringScanner->CanForceToIso8601( DateOrder::Invalid))
1135 F_Index = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, ActLnge );
1137 else
1139 F_Index = GetStandardFormat( RType, ActLnge );
1141 break;
1142 case SvNumFormatType::TIME :
1143 if ( pStringScanner->GetDecPos() )
1145 // 100th seconds
1146 if ( pStringScanner->GetNumericsCount() > 3 || fOutNumber < 0.0 )
1148 F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge );
1150 else
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 );
1159 else
1161 F_Index = GetStandardFormat( RType, ActLnge );
1163 break;
1164 default:
1165 F_Index = GetStandardFormat( RType, ActLnge );
1168 return res;
1171 LanguageType SvNumberFormatter::GetLanguage() const
1173 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1174 return IniLnge;
1177 // static
1178 bool SvNumberFormatter::IsCompatible(SvNumFormatType eOldType, SvNumFormatType eNewType)
1180 if (eOldType == eNewType)
1182 return true;
1184 else if (eOldType == SvNumFormatType::DEFINED)
1186 return true;
1188 else
1190 switch (eNewType)
1192 case SvNumFormatType::NUMBER:
1193 switch (eOldType)
1195 case SvNumFormatType::PERCENT:
1196 case SvNumFormatType::CURRENCY:
1197 case SvNumFormatType::SCIENTIFIC:
1198 case SvNumFormatType::FRACTION:
1199 case SvNumFormatType::DEFINED:
1200 return true;
1201 case SvNumFormatType::LOGICAL:
1202 default:
1203 return false;
1205 break;
1206 case SvNumFormatType::DATE:
1207 switch (eOldType)
1209 case SvNumFormatType::DATETIME:
1210 return true;
1211 default:
1212 return false;
1214 break;
1215 case SvNumFormatType::TIME:
1216 switch (eOldType)
1218 case SvNumFormatType::DATETIME:
1219 return true;
1220 default:
1221 return false;
1223 break;
1224 case SvNumFormatType::DATETIME:
1225 switch (eOldType)
1227 case SvNumFormatType::TIME:
1228 case SvNumFormatType::DATE:
1229 return true;
1230 default:
1231 return false;
1233 break;
1234 default:
1235 return false;
1241 sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( SvNumFormatType nType )
1243 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1244 sal_uInt32 nSearch;
1245 switch( nType )
1247 case SvNumFormatType::DATE:
1248 nSearch = CLOffset + ZF_STANDARD_DATE;
1249 break;
1250 case SvNumFormatType::TIME:
1251 nSearch = CLOffset + ZF_STANDARD_TIME;
1252 break;
1253 case SvNumFormatType::DATETIME:
1254 nSearch = CLOffset + ZF_STANDARD_DATETIME;
1255 break;
1256 case SvNumFormatType::PERCENT:
1257 nSearch = CLOffset + ZF_STANDARD_PERCENT;
1258 break;
1259 case SvNumFormatType::SCIENTIFIC:
1260 nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1261 break;
1262 default:
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;
1273 sal_uInt32 nKey(0);
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;
1281 break; // while
1283 ++it2;
1286 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1287 { // none found, use old fixed standards
1288 switch( nType )
1290 case SvNumFormatType::DATE:
1291 nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1292 break;
1293 case SvNumFormatType::TIME:
1294 nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1295 break;
1296 case SvNumFormatType::DATETIME:
1297 nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1298 break;
1299 case SvNumFormatType::PERCENT:
1300 nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1301 break;
1302 case SvNumFormatType::SCIENTIFIC:
1303 nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1304 break;
1305 default:
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)
1320 eLnge = IniLnge;
1322 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1323 switch(eType)
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:
1343 default:
1344 return CLOffset + ZF_STANDARD;
1348 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex,
1349 LanguageType eLnge )
1351 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1352 return
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 ) )
1364 return nFIndex;
1365 else
1366 return GetStandardFormat( eType, eLnge );
1369 sal_uInt32 SvNumberFormatter::GetTimeFormat( double fNumber, LanguageType eLnge )
1371 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1372 bool bSign;
1373 if ( fNumber < 0.0 )
1375 bSign = true;
1376 fNumber = -fNumber;
1378 else
1379 bSign = false;
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 );
1385 else
1386 return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1388 else
1390 if ( bSign || fNumber >= 1.0 )
1391 return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1392 else
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 ) )
1402 return nFIndex;
1404 switch( eType )
1406 case SvNumFormatType::TIME :
1407 return GetTimeFormat( fNumber, eLnge);
1408 default:
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.
1419 sal_uInt32 nRet;
1420 if (0.0 <= fNumber && fNumber < 1.0)
1422 // Clearly a time.
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)
1434 // Date+Time.
1435 rType = SvNumFormatType::DATETIME;
1436 nRet = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLnge);
1438 else
1440 // Date only.
1441 rType = SvNumFormatType::DATE;
1442 nRet = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLnge);
1444 return nRet;
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;
1453 switch ( eType )
1455 // #61619# always edit using 4-digit year
1456 case SvNumFormatType::DATE :
1458 // Preserve ISO 8601 format.
1459 bool bIsoDate =
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
1467 // displayed.
1468 if (bIsoDate)
1469 nKey = GetFormatIndex( NF_DATETIME_ISO_YYYYMMDD_HHMMSS, eLang);
1470 else
1471 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1473 else
1475 if (bIsoDate)
1476 nKey = GetFormatIndex( NF_DATE_ISO_YYYYMMDD, eLang);
1477 else
1478 nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1481 break;
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.
1491 else
1492 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1493 // Assume that a large value is a datetime with only time
1494 // displayed.
1496 else
1497 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1498 break;
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 );
1502 else
1503 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1504 break;
1505 case SvNumFormatType::NUMBER:
1506 nKey = GetStandardFormat( eType, eLang );
1507 break;
1508 default:
1509 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1511 return nKey;
1514 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1515 sal_uInt32 nFIndex,
1516 OUString& sOutString)
1518 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1519 Color* pColor;
1520 sal_uInt32 nRealKey = nFIndex;
1521 SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ), &nRealKey);
1522 if (!pFormat)
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 );
1561 if (pFormat)
1563 if ( eType == SvNumFormatType::TIME && pFormat->GetFormatPrecision() )
1565 ChangeStandardPrec(INPUTSTRING_PRECISION);
1566 bPrecChanged = true;
1568 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1570 if (bPrecChanged)
1572 ChangeStandardPrec(nOldPrec);
1576 void SvNumberFormatter::GetOutputString(const OUString& sString,
1577 sal_uInt32 nFIndex,
1578 OUString& sOutString,
1579 Color** ppColor,
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.
1586 if (!pFormat)
1588 pFormat = GetFormatEntry(ZF_STANDARD_TEXT);
1590 if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1592 *ppColor = nullptr;
1593 sOutString = sString;
1595 else
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,
1611 sal_uInt32 nFIndex,
1612 OUString& sOutString,
1613 Color** ppColor,
1614 bool bUseStarFormat )
1616 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1617 if (bNoZero && fOutNumber == 0.0)
1619 sOutString.clear();
1620 return;
1622 SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ));
1623 if (!pFormat)
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,
1636 Color** ppColor,
1637 LanguageType eLnge,
1638 bool bUseStarFormat )
1640 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1641 if (sFormatString.isEmpty()) // no empty string
1643 return false;
1645 sal_uInt32 nKey;
1646 if (eLnge == LANGUAGE_DONTKNOW)
1648 eLnge = IniLnge;
1650 ChangeIntl(eLnge); // change locale if necessary
1651 eLnge = ActLnge;
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(),
1657 nCheckPos,
1658 eLnge));
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);
1667 else
1669 if ( bUseStarFormat )
1671 p_Entry->SetStarFormatSupport( true );
1673 p_Entry->GetOutputString(fPreviewNumber, sOutString, ppColor);
1674 if ( bUseStarFormat )
1676 p_Entry->SetStarFormatSupport( false );
1679 return true;
1681 else
1683 return false;
1687 bool SvNumberFormatter::GetPreviewStringGuess( const OUString& sFormatString,
1688 double fPreviewNumber,
1689 OUString& sOutString,
1690 Color** ppColor,
1691 LanguageType eLnge )
1693 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1694 if (sFormatString.isEmpty()) // no empty string
1696 return false;
1698 if (eLnge == LANGUAGE_DONTKNOW)
1700 eLnge = IniLnge;
1702 ChangeIntl( eLnge );
1703 eLnge = ActLnge;
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 );
1713 return true;
1716 std::unique_ptr<SvNumberformat> pEntry;
1717 sal_Int32 nCheckPos = -1;
1718 OUString sTmpString;
1720 if ( bEnglish )
1722 sTmpString = sFormatString;
1723 pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner.get(),
1724 pStringScanner.get(), nCheckPos, eLnge ));
1726 else
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() ) )
1746 // other Format
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 ));
1753 else
1755 // verify english
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() ) )
1768 // other Format
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 );
1783 return true;
1785 return false;
1788 bool SvNumberFormatter::GetPreviewString( const OUString& sFormatString,
1789 const OUString& sPreviewString,
1790 OUString& sOutString,
1791 Color** ppColor,
1792 LanguageType eLnge )
1794 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1795 if (sFormatString.isEmpty()) // no empty string
1797 return false;
1799 sal_uInt32 nKey;
1800 if (eLnge == LANGUAGE_DONTKNOW)
1802 eLnge = IniLnge;
1804 ChangeIntl(eLnge); // switch if needed
1805 eLnge = ActLnge;
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(),
1811 nCheckPos,
1812 eLnge));
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);
1822 else
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);
1831 else
1833 *ppColor = nullptr;
1834 sOutString = sPreviewString;
1837 return true;
1839 else
1841 return false;
1845 sal_uInt32 SvNumberFormatter::TestNewString(const OUString& sFormatString,
1846 LanguageType eLnge)
1848 ::osl::MutexGuard aGuard( GetInstanceMutex() );
1849 if (sFormatString.isEmpty()) // no empty string
1851 return NUMBERFORMAT_ENTRY_NOT_FOUND;
1853 if (eLnge == LANGUAGE_DONTKNOW)
1855 eLnge = IniLnge;
1857 ChangeIntl(eLnge); // change locale if necessary
1858 eLnge = ActLnge;
1859 sal_uInt32 nRes;
1860 sal_Int32 nCheckPos = -1;
1861 OUString sTmpString = sFormatString;
1862 std::unique_ptr<SvNumberformat> pEntry(new SvNumberformat(sTmpString,
1863 pFormatScanner.get(),
1864 pStringScanner.get(),
1865 nCheckPos,
1866 eLnge));
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);
1871 // already present?
1873 else
1875 nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1877 return nRes;
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 );
1898 else
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) +
1905 ":\n" +
1906 rCode.Code;
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(),
1915 nCheckPos,
1916 ActLnge));
1917 if (nCheckPos != 0)
1919 if (LocaleDataWrapper::areChecksEnabled())
1921 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
1922 OUString::number( rCode.Index ) +
1923 "\n" +
1924 rCode.Code;
1925 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1927 return nullptr;
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,
1936 // don't cry then.
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
1947 break;
1948 default:
1950 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: dup format code, index "
1951 + OUString::number( rCode.Index )
1952 + "\n"
1953 + rCode.Code;
1954 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1958 return nullptr;
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 )
1966 + "\n"
1967 + rCode.Code;
1968 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1970 return nullptr;
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 )
1980 + ", code index "
1981 + OUString::number( rCode.Index )
1982 + "\n"
1983 + rCode.Code;
1984 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1986 else
1988 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
1990 return nullptr;
1992 if ( rCode.Default )
1993 pFormat2->SetStandard();
1994 if ( !rCode.DefaultName.isEmpty() )
1995 pFormat2->SetComment( rCode.DefaultName );
1996 return pFormat2;
1999 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
2000 bool& bThousand,
2001 bool& IsRed,
2002 sal_uInt16& nPrecision,
2003 sal_uInt16& nLeadingCnt)
2006 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2007 SvNumberformat* pFormat = GetFormatEntry( nFormat );
2008 if (pFormat)
2009 pFormat->GetFormatSpecialInfo(bThousand, IsRed,
2010 nPrecision, nLeadingCnt);
2011 else
2013 bThousand = false;
2014 IsRed = false;
2015 nPrecision = pFormatScanner->GetStandardPrec();
2016 nLeadingCnt = 0;
2020 sal_uInt16 SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
2022 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2023 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
2024 if ( pFormat )
2025 return pFormat->GetFormatPrecision();
2026 else
2027 return pFormatScanner->GetStandardPrec();
2030 sal_uInt16 SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat ) const
2032 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2033 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
2034 if ( pFormat )
2035 return pFormat->GetFormatIntegerDigits();
2036 else
2037 return 1;
2040 OUString SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
2042 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2043 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
2044 if (!pFormat)
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();
2058 OUString aRet;
2059 LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
2060 if (nLang == eSaveLang)
2062 aRet = xLocaleData->getNumDecimalSep();
2064 else
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 );
2071 return aRet;
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)
2083 eLnge = IniLnge;
2085 ChangeIntl(eLnge); // change locale if necessary
2086 eLnge = ActLnge;
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 );
2095 else
2097 bThousand = false;
2098 IsRed = false;
2099 nPrecision = pFormatScanner->GetStandardPrec();
2100 nLeadingCnt = 0;
2102 return nCheckPos;
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 )
2113 return j;
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));
2124 if ( nLen )
2126 sal_Int32 j;
2127 // look for a preset default
2128 for ( j=0; j<nLen; j++ )
2130 if ( rSeq[j].Default )
2131 return j;
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 )
2141 return j;
2143 // last resort: look for a format without decimals
2144 for ( j=0; j<nLen; j++ )
2146 if ( rSeq[j].Index == NF_CURRENCY_1000INT )
2147 return j;
2151 else
2152 { // we need at least _some_ format
2153 rSeq.realloc(1);
2154 rSeq[0] = css::i18n::NumberFormatCode();
2155 rSeq[0].Code = "0" + GetNumDecimalSep() + "############";
2157 return 0;
2161 void SvNumberFormatter::ImpAdjustFormatCodeDefault(
2162 css::i18n::NumberFormatCode * pFormatArr,
2163 sal_Int32 nCnt )
2165 if ( !nCnt )
2166 return;
2167 if (LocaleDataWrapper::areChecksEnabled())
2169 // check the locale data for correctness
2170 OStringBuffer aMsg;
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 :
2178 nShort = nElem;
2179 break;
2180 case i18n::KNumberFormatType::MEDIUM :
2181 nMedium = nElem;
2182 break;
2183 case i18n::KNumberFormatType::LONG :
2184 nLong = nElem;
2185 break;
2186 default:
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");
2196 nShortDef = nElem;
2197 break;
2198 case i18n::KNumberFormatType::MEDIUM :
2199 if ( nMediumDef != -1 )
2200 aMsg.append("dupe medium type default");
2201 nMediumDef = nElem;
2202 break;
2203 case i18n::KNumberFormatType::LONG :
2204 if ( nLongDef != -1 )
2205 aMsg.append("dupe long type default");
2206 nLongDef = nElem;
2207 break;
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;
2246 break;
2247 case i18n::KNumberFormatType::LONG :
2248 if ( nMedium == -1 )
2249 nDef = nElem;
2250 SAL_FALLTHROUGH;
2251 default:
2252 if ( nDef == -1 )
2253 nDef = nElem;
2254 pFormatArr[nElem].Default = false;
2258 if ( nDef == -1 )
2259 nDef = 0;
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();
2268 return nullptr;
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();
2282 return nullptr;
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())
2298 return pFormat;
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.
2304 sal_uInt32 nKey;
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);
2311 else
2312 return pFormat;
2314 if (o_pRealKey)
2315 *o_pRealKey = nKey;
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 );
2330 sal_Int32 nIdx;
2331 bool bDefault;
2333 // Number
2334 uno::Sequence< i18n::NumberFormatCode > aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER, aLocale );
2335 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2337 // General
2338 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2339 SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2340 CLOffset + ZF_STANDARD /* NF_NUMBER_STANDARD */ );
2341 if (pStdFormat)
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() );
2353 else
2355 if (LocaleDataWrapper::areChecksEnabled())
2357 LocaleDataWrapper::outputCheckMessage( xLocaleData->
2358 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2363 // Boolean
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");
2377 // Text
2378 aFormatCode = "@";
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");
2390 // 0
2391 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2392 ImpInsertFormat( aFormatSeq[nIdx],
2393 CLOffset + ZF_STANDARD+1 /* NF_NUMBER_INT */ );
2395 // 0.00
2396 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2397 ImpInsertFormat( aFormatSeq[nIdx],
2398 CLOffset + ZF_STANDARD+2 /* NF_NUMBER_DEC2 */ );
2400 // #,##0
2401 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2402 ImpInsertFormat( aFormatSeq[nIdx],
2403 CLOffset + ZF_STANDARD+3 /* NF_NUMBER_1000INT */ );
2405 // #,##0.00
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 */ );
2416 // Percent number
2417 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER, aLocale );
2418 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2420 // 0%
2421 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2422 ImpInsertFormat( aFormatSeq[nIdx],
2423 CLOffset + ZF_STANDARD_PERCENT /* NF_PERCENT_INT */ );
2425 // 0.00%
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() );
2440 // #,##0
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;
2448 // #,##0.00
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;
2472 // #,##0.00 USD
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;
2480 // #.##0,--
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;
2489 // Date
2490 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::DATE, aLocale );
2491 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2493 // DD.MM.YY System
2494 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2495 ImpInsertFormat( aFormatSeq[nIdx],
2496 CLOffset + ZF_STANDARD_DATE /* NF_DATE_SYSTEM_SHORT */ );
2498 // NN DD.MMM YY
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 */ );
2508 // DD MMM
2509 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2510 ImpInsertFormat( aFormatSeq[nIdx],
2511 CLOffset + ZF_STANDARD_DATE+3 /* NF_DATE_SYS_DDMMM */ );
2513 // MMMM
2514 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2515 ImpInsertFormat( aFormatSeq[nIdx],
2516 CLOffset + ZF_STANDARD_DATE+4 /* NF_DATE_MMMM */ );
2518 // QQ YY
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 */ );
2583 // MM-DD DIN/EN
2584 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2585 ImpInsertFormat( aFormatSeq[nIdx],
2586 CLOffset + ZF_STANDARD_NEWEXTENDED_DATE_DIN_MMDD /* NF_DATE_DIN_MMDD */ );
2588 // YY-MM-DD DIN/EN
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 */ );
2599 // Time
2600 aFormatSeq = xNFC->getAllFormatCode( i18n::KNumberFormatUsage::TIME, aLocale );
2601 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2603 // HH:MM
2604 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2605 ImpInsertFormat( aFormatSeq[nIdx],
2606 CLOffset + ZF_STANDARD_TIME /* NF_TIME_HHMM */ );
2608 // HH:MM:SS
2609 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2610 ImpInsertFormat( aFormatSeq[nIdx],
2611 CLOffset + ZF_STANDARD_TIME+1 /* NF_TIME_HHMMSS */ );
2613 // HH:MM AM/PM
2614 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2615 ImpInsertFormat( aFormatSeq[nIdx],
2616 CLOffset + ZF_STANDARD_TIME+2 /* NF_TIME_HHMMAMPM */ );
2618 // HH:MM:SS AM/PM
2619 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2620 ImpInsertFormat( aFormatSeq[nIdx],
2621 CLOffset + ZF_STANDARD_TIME+3 /* NF_TIME_HHMMSSAMPM */ );
2623 // [HH]:MM:SS
2624 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2625 ImpInsertFormat( aFormatSeq[nIdx],
2626 CLOffset + ZF_STANDARD_TIME+4 /* NF_TIME_HH_MMSS */ );
2628 // MM:SS,00
2629 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2630 ImpInsertFormat( aFormatSeq[nIdx],
2631 CLOffset + ZF_STANDARD_TIME+5 /* NF_TIME_MMSS00 */ );
2633 // [HH]:MM:SS,00
2634 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2635 ImpInsertFormat( aFormatSeq[nIdx],
2636 CLOffset + ZF_STANDARD_TIME+6 /* NF_TIME_HH_MMSS00 */ );
2639 // DateTime
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() );
2674 // 0.00E+000
2675 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2676 ImpInsertFormat( aFormatSeq[nIdx],
2677 CLOffset + ZF_STANDARD_SCIENTIFIC /* NF_SCIENTIFIC_000E000 */ );
2679 // 0.00E+00
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;
2688 // # ?/?
2689 aSingleFormatCode.Code = "# ?/?";
2690 ImpInsertFormat( aSingleFormatCode,
2691 CLOffset + ZF_STANDARD_FRACTION /* NF_FRACTION_1D */ );
2693 // # ??/??
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 */ );
2699 // # ???/???
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 */ );
2705 // # ?/2
2706 aSingleFormatCode.Code = "# ?/2";
2707 ImpInsertFormat( aSingleFormatCode,
2708 CLOffset + ZF_STANDARD_FRACTION+3 /* NF_FRACTION_2 */ );
2710 // # ?/4
2711 aSingleFormatCode.Code = "# ?/4";
2712 ImpInsertFormat( aSingleFormatCode,
2713 CLOffset + ZF_STANDARD_FRACTION+4 /* NF_FRACTION_4 */ );
2715 // # ?/8
2716 aSingleFormatCode.Code = "# ?/8";
2717 ImpInsertFormat( aSingleFormatCode,
2718 CLOffset + ZF_STANDARD_FRACTION+5 /* NF_FRACTION_8 */ );
2720 // # ??/16
2721 aSingleFormatCode.Code = "# ?\?/16";
2722 ImpInsertFormat( aSingleFormatCode,
2723 CLOffset + ZF_STANDARD_FRACTION+6 /* NF_FRACTION_16 */ );
2725 // # ??/10
2726 aSingleFormatCode.Code = "# ?\?/10";
2727 ImpInsertFormat( aSingleFormatCode,
2728 CLOffset + ZF_STANDARD_FRACTION+7 /* NF_FRACTION_10 */ );
2730 // # ??/100
2731 aSingleFormatCode.Code = "# ?\?/100";
2732 ImpInsertFormat( aSingleFormatCode,
2733 CLOffset + ZF_STANDARD_FRACTION+8 /* NF_FRACTION_100 */ );
2736 // Week of year
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 );
2759 if ( !pStdFormat )
2761 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2762 return ;
2764 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey( SvNumberformat::FormatterPrivateAccess() );
2765 css::lang::Locale aLocale = GetLanguageTag().getLocale();
2766 sal_Int32 j;
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" );
2779 break; // for
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();
2795 nPos++;
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();
2810 if ( nCodes )
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" );
2818 break; // for
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();
2826 nPos++;
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++ )
2841 switch(sFormat[i])
2843 case '\"' : // skip text
2844 i = sFormat.indexOf('\"',i+1);
2845 break;
2846 case '[' : // skip condition
2847 i = sFormat.indexOf(']',i+1);
2848 break;
2849 case '\\' : // skip escaped character
2850 i++;
2851 break;
2852 case ';' :
2853 if (token == ';')
2854 return i;
2855 break;
2856 case 'e' :
2857 case 'E' :
2858 if (token == 'E')
2859 return i; // if 'E' is outside "" and [] it must be the 'E' exponent
2860 break;
2861 default : break;
2863 if ( i<0 )
2864 i--;
2866 return -2;
2869 OUString SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex,
2870 LanguageType eLnge,
2871 bool bThousand,
2872 bool IsRed,
2873 sal_uInt16 nPrecision,
2874 sal_uInt16 nLeadingZeros)
2876 ::osl::MutexGuard aGuard( GetInstanceMutex() );
2877 if (eLnge == LANGUAGE_DONTKNOW)
2879 eLnge = IniLnge;
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)
2897 if (!bThousand)
2898 sString.append('#');
2899 else
2901 if (eType == SvNumFormatType::SCIENTIFIC)
2902 { // for scientific, bThousand is used for Engineering notation
2903 sString.append("###");
2905 else
2907 sString.append('#');
2908 sString.append(rThSep);
2909 padToLength(sString, sString.getLength() + nDigitsInFirstGroup, '#');
2913 else
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');
2924 if ( bThousand )
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' );
2948 if (nIndexE > -1)
2950 sal_Int32 nIndexSep = ImpPosToken( sOldFormatString, ';', nIndexE );
2951 if (nIndexSep > nIndexE)
2952 sString.append( sOldFormatString.copy(nIndexE, nIndexSep - nIndexE) );
2953 else
2954 sString.append( sOldFormatString.copy(nIndexE) );
2957 else if (eType == SvNumFormatType::CURRENCY)
2959 OUStringBuffer sNegStr(sString);
2960 OUString aCurr;
2961 const NfCurrencyEntry* pEntry;
2962 bool bBank;
2963 if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
2965 if ( pEntry )
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 );
2976 else
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 );
2988 else
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() );
2997 if (IsRed)
2999 sString.append(';');
3000 sString.append('[');
3001 sString.append(pFormatScanner->GetRedString());
3002 sString.append(']');
3004 else
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 );
3015 else
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, '?');
3025 else
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(';');
3046 if (IsRed)
3048 sTmpStr.append('[');
3049 sTmpStr.append(pFormatScanner->GetRedString());
3050 sTmpStr.append(']');
3053 if (insertBrackets)
3055 sTmpStr.append('(');
3056 sTmpStr.append(sString.toString());
3057 sTmpStr.append(')');
3059 else
3061 sTmpStr.append('-');
3062 sTmpStr.append(sString.toString());
3064 sString = sTmpStr;
3067 return sString.makeStringAndClear();
3070 bool SvNumberFormatter::IsUserDefined(const OUString& sStr,
3071 LanguageType eLnge)
3073 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3074 if (eLnge == LANGUAGE_DONTKNOW)
3076 eLnge = IniLnge;
3078 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3079 eLnge = ActLnge;
3081 sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
3082 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
3084 return true;
3086 SvNumberformat* pEntry = GetFormatEntry( nKey );
3087 return pEntry && (pEntry->GetType() & SvNumFormatType::DEFINED);
3090 sal_uInt32 SvNumberFormatter::GetEntryKey(const OUString& sStr,
3091 LanguageType eLnge)
3093 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3094 if (eLnge == LANGUAGE_DONTKNOW)
3096 eLnge = IniLnge;
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)
3107 eLnge = IniLnge;
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 );
3117 if (!pFormat)
3119 eType = SvNumFormatType::UNDEFINED;
3121 else
3123 eType = pFormat->GetMaskedType();
3124 if (eType == SvNumFormatType::ALL)
3126 eType = SvNumFormatType::DEFINED;
3129 return eType;
3132 void SvNumberFormatter::ClearMergeTable()
3134 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3135 if ( pMergeTable )
3137 pMergeTable->clear();
3141 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
3143 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3144 if ( pMergeTable )
3146 ClearMergeTable();
3148 else
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(),
3186 nCLOffset,
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() );
3192 nNewKey = nPos+1;
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");
3201 else
3203 pStdFormat->SetLastInsertKey(static_cast<sal_uInt16>(nNewKey - nCLOffset),
3204 SvNumberformat::FormatterPrivateAccess());
3207 if (nNewKey != nOldKey) // new index
3209 (*pMergeTable)[nOldKey] = nNewKey;
3212 ++it;
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;
3231 ClearMergeTable();
3232 return aMap;
3236 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
3237 LanguageType eLnge )
3239 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3240 if ( eLnge == LANGUAGE_DONTKNOW )
3242 eLnge = IniLnge;
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)
3266 eLnge = IniLnge;
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
3322 if ( nYear < 100 )
3323 return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3324 pStringScanner->GetYear2000() );
3325 return nYear;
3329 // static
3330 sal_uInt16 SvNumberFormatter::GetYear2000Default()
3332 if (!utl::ConfigManager::IsFuzzing())
3333 return static_cast<sal_uInt16>(::utl::MiscCfg().GetYear2000());
3334 return 1930;
3338 // static
3339 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3341 while ( !bCurrencyTableInitialized )
3342 ImpInitCurrencyTable();
3343 return theCurrencyTable::get();
3347 // static
3348 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3350 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3351 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3352 return nSystemCurrencyPosition ? &rTable[nSystemCurrencyPosition] : nullptr;
3356 // static
3357 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3359 if ( eLang == LANGUAGE_SYSTEM )
3361 const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3362 return pCurr ? *pCurr : GetTheCurrencyTable()[0];
3364 else
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 )
3372 return rTable[j];
3374 return rTable[0];
3379 // static
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 )
3390 return &rTable[j];
3393 return nullptr;
3397 // static
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 )
3409 return &rTable[j];
3412 return nullptr;
3416 // static
3417 IMPL_STATIC_LINK_NOARG( SvNumberFormatter, CurrencyChangeLink, LinkParamNone*, void )
3419 OUString aAbbrev;
3420 LanguageType eLang = LANGUAGE_SYSTEM;
3421 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3422 SetDefaultSystemCurrency( aAbbrev, eLang );
3426 // static
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;
3443 return ;
3447 else
3449 for ( sal_uInt16 j = 0; j < nCount; j++ )
3451 if ( rTable[j].GetLanguage() == eLang )
3453 nSystemCurrencyPosition = j;
3454 return ;
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 )
3478 sal_Int32 nCheck;
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;
3506 sal_uInt32 nKey(0);
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;
3514 break; // while
3516 ++it2;
3519 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3520 { // none found, create one
3521 sal_Int32 nCheck;
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;
3540 else
3541 { // mark as standard so that it is found next time
3542 SvNumberformat* pEntry = GetFormatEntry( nDefaultCurrencyFormat );
3543 if ( pEntry )
3544 pEntry->SetStandard();
3547 aDefaultFormatKeys[ CLOffset + ZF_STANDARD_CURRENCY ] = nDefaultCurrencyFormat;
3549 return nDefaultCurrencyFormat;
3553 // static
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 )
3559 bool bFound;
3560 if ( pData->GetSymbol() == rSymbol )
3562 bFound = true;
3563 bFoundBank = false;
3565 else if ( pData->GetBankSymbol() == rSymbol )
3567 bFound = true;
3568 bFoundBank = true;
3570 else
3571 bFound = false;
3572 if ( bFound )
3574 if ( pFoundEntry && pFoundEntry != pData )
3576 pFoundEntry = nullptr;
3577 return false; // break loop, not unique
3579 if ( nPos == 0 )
3580 { // first entry is SYSTEM
3581 pFoundEntry = MatchSystemCurrency();
3582 if ( pFoundEntry )
3584 return false; // break loop
3585 // even if there are more matching entries
3586 // this one is probably the one we are looking for
3588 else
3590 pFoundEntry = pData;
3593 else
3595 pFoundEntry = pData;
3598 return true;
3602 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat, OUString& rStr,
3603 const NfCurrencyEntry** ppEntry /* = NULL */,
3604 bool* pBank /* = NULL */ ) const
3606 ::osl::MutexGuard aGuard( GetInstanceMutex() );
3607 if ( ppEntry )
3608 *ppEntry = nullptr;
3609 if ( pBank )
3610 *pBank = false;
3612 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
3613 if ( pFormat )
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 ) )
3619 if ( ppEntry )
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(),
3625 true );
3626 if ( pFoundEntry )
3628 *ppEntry = pFoundEntry;
3629 if ( pBank )
3630 *pBank = bFoundBank;
3631 rStr = pFoundEntry->BuildSymbolString(bFoundBank);
3634 if ( rStr.isEmpty() )
3635 { // analog to BuildSymbolString
3636 sBuff.append("[$");
3637 if ( aSymbol.indexOf( '-' ) != -1 ||
3638 aSymbol.indexOf( ']' ) != -1 )
3640 sBuff.append('"');
3641 sBuff.append( aSymbol);
3642 sBuff.append('"');
3644 else
3646 sBuff.append(aSymbol);
3648 if ( !aExtension.isEmpty() )
3650 sBuff.append(aExtension);
3652 sBuff.append(']');
3654 rStr = sBuff.toString();
3655 return true;
3658 rStr.clear();
3659 return false;
3663 // static
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;
3672 if ( nExtLen )
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 );
3678 if ( !nExtLang )
3680 eExtLang = LANGUAGE_DONTKNOW;
3682 else
3684 eExtLang = LanguageType((nExtLang < 0) ? -nExtLang : nExtLang);
3687 else
3689 eExtLang = LANGUAGE_DONTKNOW;
3691 const NfCurrencyEntry* pFoundEntry = nullptr;
3692 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3693 sal_uInt16 nCount = rTable.size();
3694 bool bCont = true;
3696 // first try with given extension language/country
3697 if ( nExtLen )
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 );
3712 // ok?
3713 if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3715 return pFoundEntry;
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 );
3732 // ok?
3733 if ( pFoundEntry || !bCont )
3735 return pFoundEntry;
3739 // then try without language/country if no extension specified
3740 if ( !nExtLen )
3742 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3744 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3745 &rTable[j], j, rSymbol );
3749 return pFoundEntry;
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();
3762 sal_Int32 j;
3763 for ( j=0; j < nCurrencies; ++j )
3765 if ( pCurrencies[j].UsedInCompatibleFormatCodes )
3767 rSymbol = pCurrencies[j].Symbol;
3768 rAbbrev = pCurrencies[j].BankSymbol;
3769 break;
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() )
3789 case 0: // $1
3790 case 1: // 1$
3791 case 2: // $ 1
3792 case 3: // 1 $
3793 break;
3794 default:
3795 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3796 break;
3798 switch ( rCurr.GetNegativeFormat() )
3800 case 0: // ($1)
3801 case 1: // -$1
3802 case 2: // $-1
3803 case 3: // $1-
3804 case 4: // (1$)
3805 case 5: // -1$
3806 case 6: // 1-$
3807 case 7: // 1$-
3808 case 8: // -1 $
3809 case 9: // -$ 1
3810 case 10: // 1 $-
3811 case 11: // $ -1
3812 case 12 : // $ 1-
3813 case 13 : // 1- $
3814 case 14 : // ($ 1)
3815 case 15 : // (1 $)
3816 break;
3817 default:
3818 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3819 break;
3823 // static
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();
3834 // static
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 )
3844 return ;
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
3884 sal_Int32 nDefault;
3885 for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3887 if ( pCurrencies[nDefault].Default )
3888 break;
3890 std::unique_ptr<NfCurrencyEntry> pEntry;
3891 if ( nDefault < nCurrencyCount )
3893 pEntry.reset(new NfCurrencyEntry(pCurrencies[nDefault], *pLocaleData, eLang));
3895 else
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));
3932 // no dupes
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 )
3940 bInsert = false;
3941 break; // for
3944 if ( !bInsert )
3946 pEntry.reset();
3948 else
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,
4008 bool bBank ) const
4010 ::osl::MutexGuard aGuard( GetInstanceMutex() );
4011 OUString aRed = "["
4012 + pFormatScanner->GetRedString()
4013 + "]";
4015 sal_uInt16 nDefault = 0;
4016 if ( bBank )
4018 // Only bank symbols.
4019 OUString aPositiveBank = rCurr.BuildPositiveFormatString(true, *xLocaleData);
4020 OUString aNegativeBank = rCurr.BuildNegativeFormatString(true, *xLocaleData );
4022 OUString format1 = aPositiveBank
4023 + ";"
4024 + aNegativeBank;
4025 addToCurrencyFormatsList( rStrArr, format1);
4027 OUString format2 = aPositiveBank
4028 + ";"
4029 + aRed
4030 + aNegativeBank;
4031 addToCurrencyFormatsList( rStrArr, format2);
4033 nDefault = rStrArr.size() - 1;
4035 else
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 );
4041 OUString format1;
4042 OUString format2;
4043 OUString format3;
4044 OUString format4;
4045 OUString format5;
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
4054 + ";"
4055 + aNegativeNoDec;
4057 format3 = aPositiveNoDec
4058 + ";"
4059 + aRed
4060 + aNegativeNoDec;
4062 format5 = aPositiveDashed
4063 + ";"
4064 + aRed
4065 + aNegativeDashed;
4068 format2 = aPositive
4069 + ";"
4070 + aNegative;
4072 format4 = aPositive
4073 + ";"
4074 + aRed
4075 + aNegative;
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);
4093 return nDefault;
4096 sal_uInt32 SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt ) const
4098 ::osl::MutexGuard aGuard( GetInstanceMutex() );
4099 if (pMergeTable)
4101 SvNumberFormatterIndexTable::const_iterator it = pMergeTable->find(nOldFmt);
4102 if (it != pMergeTable->end())
4104 return it->second;
4107 return nOldFmt;
4110 bool SvNumberFormatter::HasMergeFormatTable() const
4112 ::osl::MutexGuard aGuard( GetInstanceMutex() );
4113 return pMergeTable && !pMergeTable->empty();
4116 // static
4117 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear, sal_uInt16 nTwoDigitYearStart )
4119 if ( nYear < 100 )
4121 if ( nYear < (nTwoDigitYearStart % 100) )
4123 return nYear + (((nTwoDigitYearStart / 100) + 1) * 100);
4125 else
4127 return nYear + ((nTwoDigitYearStart / 100) * 100);
4130 return nYear;
4133 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
4135 aSymbol = rLocaleData.getCurrSymbol();
4136 aBankSymbol = rLocaleData.getCurrBankSymbol();
4137 eLanguage = eLang;
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;
4150 eLanguage = eLang;
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("[$");
4169 if (bBank)
4171 aBuf.append(aBankSymbol);
4173 else
4175 if ( aSymbol.indexOf( '-' ) >= 0 ||
4176 aSymbol.indexOf( ']' ) >= 0)
4178 aBuf.append('"').append(aSymbol).append('"');
4180 else
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());
4190 aBuf.append(']');
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 );
4250 // static
4251 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, const OUString& rSymStr,
4252 sal_uInt16 nPositiveFormat)
4254 switch( nPositiveFormat )
4256 case 0: // $1
4257 rStr.insert(0, rSymStr);
4258 break;
4259 case 1: // 1$
4260 rStr.append(rSymStr);
4261 break;
4262 case 2: // $ 1
4264 rStr.insert(0, ' ');
4265 rStr.insert(0, rSymStr);
4267 break;
4268 case 3: // 1 $
4270 rStr.append(' ');
4271 rStr.append(rSymStr);
4273 break;
4274 default:
4275 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4276 break;
4281 // static
4282 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr,
4283 const OUString& rSymStr,
4284 sal_uInt16 nNegativeFormat)
4286 switch( nNegativeFormat )
4288 case 0: // ($1)
4290 rStr.insert(0, rSymStr);
4291 rStr.insert(0, '(');
4292 rStr.append(')');
4294 break;
4295 case 1: // -$1
4297 rStr.insert(0, rSymStr);
4298 rStr.insert(0, '-');
4300 break;
4301 case 2: // $-1
4303 rStr.insert(0, '-');
4304 rStr.insert(0, rSymStr);
4306 break;
4307 case 3: // $1-
4309 rStr.insert(0, rSymStr);
4310 rStr.append('-');
4312 break;
4313 case 4: // (1$)
4315 rStr.insert(0, '(');
4316 rStr.append(rSymStr);
4317 rStr.append(')');
4319 break;
4320 case 5: // -1$
4322 rStr.append(rSymStr);
4323 rStr.insert(0, '-');
4325 break;
4326 case 6: // 1-$
4328 rStr.append('-');
4329 rStr.append(rSymStr);
4331 break;
4332 case 7: // 1$-
4334 rStr.append(rSymStr);
4335 rStr.append('-');
4337 break;
4338 case 8: // -1 $
4340 rStr.append(' ');
4341 rStr.append(rSymStr);
4342 rStr.insert(0, '-');
4344 break;
4345 case 9: // -$ 1
4347 rStr.insert(0, ' ');
4348 rStr.insert(0, rSymStr);
4349 rStr.insert(0, '-');
4351 break;
4352 case 10: // 1 $-
4354 rStr.append(' ');
4355 rStr.append(rSymStr);
4356 rStr.append('-');
4358 break;
4359 case 11: // $ -1
4361 rStr.insert(0, " -");
4362 rStr.insert(0, rSymStr);
4364 break;
4365 case 12 : // $ 1-
4367 rStr.insert(0, ' ');
4368 rStr.insert(0, rSymStr);
4369 rStr.append('-');
4371 break;
4372 case 13 : // 1- $
4374 rStr.append('-');
4375 rStr.append(' ');
4376 rStr.append(rSymStr);
4378 break;
4379 case 14 : // ($ 1)
4381 rStr.insert(0, ' ');
4382 rStr.insert(0, rSymStr);
4383 rStr.insert(0, '(');
4384 rStr.append(')');
4386 break;
4387 case 15 : // (1 $)
4389 rStr.insert(0, '(');
4390 rStr.append(' ');
4391 rStr.append(rSymStr);
4392 rStr.append(')');
4394 break;
4395 default:
4396 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4397 break;
4402 // static
4403 sal_uInt16 NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat,
4404 sal_uInt16 nCurrFormat, bool bBank )
4406 if ( bBank )
4408 #if NF_BANKSYMBOL_FIX_POSITION
4409 (void) nIntlFormat; // avoid warnings
4410 return 3;
4411 #else
4412 switch ( nIntlFormat )
4414 case 0: // $1
4415 nIntlFormat = 2; // $ 1
4416 break;
4417 case 1: // 1$
4418 nIntlFormat = 3; // 1 $
4419 break;
4420 case 2: // $ 1
4421 break;
4422 case 3: // 1 $
4423 break;
4424 default:
4425 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4426 break;
4428 return nIntlFormat;
4429 #endif
4431 else
4432 return nCurrFormat;
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 )
4442 case 0: // ($1)
4443 case 4: // (1$)
4444 case 14 : // ($ 1)
4445 case 15 : // (1 $)
4446 return nCurrFormat;
4447 case 1: // -$1
4448 case 5: // -1$
4449 case 8: // -1 $
4450 case 9: // -$ 1
4451 nSign = 0;
4452 break;
4453 case 2: // $-1
4454 case 6: // 1-$
4455 case 11 : // $ -1
4456 case 13 : // 1- $
4457 nSign = 1;
4458 break;
4459 case 3: // $1-
4460 case 7: // 1$-
4461 case 10: // 1 $-
4462 case 12 : // $ 1-
4463 nSign = 2;
4464 break;
4465 default:
4466 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4467 break;
4470 switch ( nCurrFormat )
4472 case 0: // ($1)
4473 switch ( nSign )
4475 case 0:
4476 return 1; // -$1
4477 case 1:
4478 return 2; // $-1
4479 case 2:
4480 return 3; // $1-
4482 break;
4483 case 4: // (1$)
4484 switch ( nSign )
4486 case 0:
4487 return 5; // -1$
4488 case 1:
4489 return 6; // 1-$
4490 case 2:
4491 return 7; // 1$-
4493 break;
4494 case 14 : // ($ 1)
4495 switch ( nSign )
4497 case 0:
4498 return 9; // -$ 1
4499 case 1:
4500 return 11; // $ -1
4501 case 2:
4502 return 12; // $ 1-
4504 break;
4505 case 15 : // (1 $)
4506 switch ( nSign )
4508 case 0:
4509 return 8; // -1 $
4510 case 1:
4511 return 13; // 1- $
4512 case 2:
4513 return 10; // 1 $-
4515 break;
4517 return nCurrFormat;
4521 // static
4522 sal_uInt16 NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat,
4523 sal_uInt16 nCurrFormat, bool bBank )
4525 if ( bBank )
4527 #if NF_BANKSYMBOL_FIX_POSITION
4528 return 8;
4529 #else
4530 switch ( nIntlFormat )
4532 case 0: // ($1)
4533 // nIntlFormat = 14; // ($ 1)
4534 nIntlFormat = 9; // -$ 1
4535 break;
4536 case 1: // -$1
4537 nIntlFormat = 9; // -$ 1
4538 break;
4539 case 2: // $-1
4540 nIntlFormat = 11; // $ -1
4541 break;
4542 case 3: // $1-
4543 nIntlFormat = 12; // $ 1-
4544 break;
4545 case 4: // (1$)
4546 // nIntlFormat = 15; // (1 $)
4547 nIntlFormat = 8; // -1 $
4548 break;
4549 case 5: // -1$
4550 nIntlFormat = 8; // -1 $
4551 break;
4552 case 6: // 1-$
4553 nIntlFormat = 13; // 1- $
4554 break;
4555 case 7: // 1$-
4556 nIntlFormat = 10; // 1 $-
4557 break;
4558 case 8: // -1 $
4559 break;
4560 case 9: // -$ 1
4561 break;
4562 case 10: // 1 $-
4563 break;
4564 case 11: // $ -1
4565 break;
4566 case 12 : // $ 1-
4567 break;
4568 case 13 : // 1- $
4569 break;
4570 case 14 : // ($ 1)
4571 // nIntlFormat = 14; // ($ 1)
4572 nIntlFormat = 9; // -$ 1
4573 break;
4574 case 15 : // (1 $)
4575 // nIntlFormat = 15; // (1 $)
4576 nIntlFormat = 8; // -1 $
4577 break;
4578 default:
4579 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4580 break;
4582 #endif
4584 else if ( nIntlFormat != nCurrFormat )
4586 switch ( nCurrFormat )
4588 case 0: // ($1)
4589 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4590 nIntlFormat, nCurrFormat );
4591 break;
4592 case 1: // -$1
4593 nIntlFormat = nCurrFormat;
4594 break;
4595 case 2: // $-1
4596 nIntlFormat = nCurrFormat;
4597 break;
4598 case 3: // $1-
4599 nIntlFormat = nCurrFormat;
4600 break;
4601 case 4: // (1$)
4602 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4603 nIntlFormat, nCurrFormat );
4604 break;
4605 case 5: // -1$
4606 nIntlFormat = nCurrFormat;
4607 break;
4608 case 6: // 1-$
4609 nIntlFormat = nCurrFormat;
4610 break;
4611 case 7: // 1$-
4612 nIntlFormat = nCurrFormat;
4613 break;
4614 case 8: // -1 $
4615 nIntlFormat = nCurrFormat;
4616 break;
4617 case 9: // -$ 1
4618 nIntlFormat = nCurrFormat;
4619 break;
4620 case 10: // 1 $-
4621 nIntlFormat = nCurrFormat;
4622 break;
4623 case 11: // $ -1
4624 nIntlFormat = nCurrFormat;
4625 break;
4626 case 12 : // $ 1-
4627 nIntlFormat = nCurrFormat;
4628 break;
4629 case 13 : // 1- $
4630 nIntlFormat = nCurrFormat;
4631 break;
4632 case 14 : // ($ 1)
4633 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4634 nIntlFormat, nCurrFormat );
4635 break;
4636 case 15 : // (1 $)
4637 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4638 nIntlFormat, nCurrFormat );
4639 break;
4640 default:
4641 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4642 break;
4645 return nIntlFormat;
4648 const NfKeywordTable & SvNumberFormatter::GetKeywords( sal_uInt32 nKey )
4650 osl::MutexGuard aGuard( GetInstanceMutex() );
4651 const SvNumberformat* pFormat = GetFormatEntry( nKey);
4652 if (pFormat)
4653 ChangeIntl( pFormat->GetLanguage());
4654 else
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: */