bump product version to 4.1.6.2
[LibreOffice.git] / svl / source / numbers / zforlist.cxx
blob0bd38ab473c18c273287d08164760a797494a410
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 <comphelper/string.hxx>
21 #include <tools/debug.hxx>
22 #include <unotools/charclass.hxx>
23 #include <i18nlangtag/mslangid.hxx>
24 #include <unotools/localedatawrapper.hxx>
25 #include <unotools/numberformatcodewrapper.hxx>
26 #include <unotools/calendarwrapper.hxx>
27 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
28 #include <com/sun/star/i18n/KNumberFormatType.hpp>
29 #include <comphelper/processfactory.hxx>
30 #include <unotools/misccfg.hxx>
33 #include <osl/mutex.hxx>
34 #include <svl/zforlist.hxx>
36 #include "zforscan.hxx"
37 #include "zforfind.hxx"
38 #include <svl/zformat.hxx>
39 #include "numhead.hxx"
41 #include <unotools/syslocaleoptions.hxx>
42 #include <unotools/digitgroupingiterator.hxx>
43 #include <rtl/logfile.hxx>
44 #include <rtl/instance.hxx>
45 #include <rtl/strbuf.hxx>
47 #include <math.h>
48 #include <limits>
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::i18n;
53 using namespace ::com::sun::star::lang;
54 using namespace ::std;
56 // Constants for type offsets per Country/Language (CL)
57 #define ZF_STANDARD 0
58 #define ZF_STANDARD_PERCENT 10
59 #define ZF_STANDARD_CURRENCY 20
60 #define ZF_STANDARD_DATE 30
61 #define ZF_STANDARD_TIME 40
62 #define ZF_STANDARD_DATETIME 50
63 #define ZF_STANDARD_SCIENTIFIC 60
64 #define ZF_STANDARD_FRACTION 70
65 #define ZF_STANDARD_NEWEXTENDED 75
66 #define ZF_STANDARD_NEWEXTENDEDMAX SV_MAX_ANZ_STANDARD_FORMATE-2 // 98
67 #define ZF_STANDARD_LOGICAL SV_MAX_ANZ_STANDARD_FORMATE-1 // 99
68 #define ZF_STANDARD_TEXT SV_MAX_ANZ_STANDARD_FORMATE // 100
70 /* Locale that is set if an unknown locale (from another system) is loaded of
71 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
72 * (old currency) is recognized as a date (#53155#). */
73 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
75 static bool bIndexTableInitialized = false;
76 static sal_uInt32 theIndexTable[NF_INDEX_TABLE_ENTRIES];
79 // ====================================================================
81 /**
82 instead of every number formatter being a listener we have a registry which
83 also handles one instance of the SysLocale options
86 typedef ::std::vector< SvNumberFormatter* > SvNumberFormatterList_impl;
88 class SvNumberFormatterRegistry_Impl : public utl::ConfigurationListener
90 SvNumberFormatterList_impl aFormatters;
91 SvtSysLocaleOptions aSysLocaleOptions;
92 LanguageType eSysLanguage;
94 public:
95 SvNumberFormatterRegistry_Impl();
96 virtual ~SvNumberFormatterRegistry_Impl();
98 void Insert( SvNumberFormatter* pThis )
99 { aFormatters.push_back( pThis ); }
101 SvNumberFormatter* Remove( SvNumberFormatter* pThis );
103 size_t Count()
104 { return aFormatters.size(); }
106 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 );
109 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
111 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
112 aSysLocaleOptions.AddListener( this );
116 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
118 aSysLocaleOptions.RemoveListener( this );
122 SvNumberFormatter* SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter* pThis )
124 for (SvNumberFormatterList_impl::iterator it = aFormatters.begin();
125 it != aFormatters.end(); ++it)
127 if ( *it == pThis )
129 aFormatters.erase( it );
130 break;
133 return pThis;
136 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*,
137 sal_uInt32 nHint)
139 ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() );
141 if ( nHint & SYSLOCALEOPTIONS_HINT_LOCALE )
143 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
144 aFormatters[ i ]->ReplaceSystemCL( eSysLanguage );
145 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
147 if ( nHint & SYSLOCALEOPTIONS_HINT_CURRENCY )
149 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
150 aFormatters[ i ]->ResetDefaultSystemCurrency();
152 if ( nHint & SYSLOCALEOPTIONS_HINT_DATEPATTERNS )
154 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
155 aFormatters[ i ]->InvalidateDateAcceptancePatterns();
160 // ====================================================================
162 SvNumberFormatterRegistry_Impl* SvNumberFormatter::pFormatterRegistry = NULL;
163 bool SvNumberFormatter::bCurrencyTableInitialized = false;
164 namespace
166 struct theCurrencyTable :
167 public rtl::Static< NfCurrencyTable, theCurrencyTable > {};
169 struct theLegacyOnlyCurrencyTable :
170 public rtl::Static< NfCurrencyTable, theLegacyOnlyCurrencyTable > {};
172 /** THE set of installed locales. */
173 struct theInstalledLocales :
174 public rtl::Static< NfInstalledLocales, theInstalledLocales> {};
177 sal_uInt16 SvNumberFormatter::nSystemCurrencyPosition = 0;
179 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
180 // language dependent.
181 #define NF_BANKSYMBOL_FIX_POSITION 1
184 /***********************Funktionen SvNumberFormatter**************************/
186 const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION = ::std::numeric_limits<sal_uInt16>::max();
187 const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1;
189 SvNumberFormatter::SvNumberFormatter( const Reference< XComponentContext >& rxContext,
190 LanguageType eLang )
191 : m_xContext( rxContext )
192 , maLanguageTag( eLang)
194 ImpConstruct( eLang );
198 SvNumberFormatter::~SvNumberFormatter()
201 ::osl::MutexGuard aGuard( GetMutex() );
202 pFormatterRegistry->Remove( this );
203 if ( !pFormatterRegistry->Count() )
205 delete pFormatterRegistry;
206 pFormatterRegistry = NULL;
210 for (SvNumberFormatTable::iterator it = aFTable.begin(); it != aFTable.end(); ++it)
211 delete it->second;
212 delete pFormatTable;
213 delete pCharClass;
214 delete pStringScanner;
215 delete pFormatScanner;
216 ClearMergeTable();
217 delete pMergeTable;
221 void SvNumberFormatter::ImpConstruct( LanguageType eLang )
223 RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svl", "er93726", "SvNumberFormatter::ImpConstruct" );
225 if ( eLang == LANGUAGE_DONTKNOW )
227 eLang = UNKNOWN_SUBSTITUTE;
229 IniLnge = eLang;
230 ActLnge = eLang;
231 eEvalDateFormat = NF_EVALDATEFORMAT_INTL;
232 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
234 maLanguageTag.reset( eLang );
235 pCharClass = new CharClass( m_xContext, maLanguageTag );
236 xLocaleData.init( m_xContext, maLanguageTag );
237 xCalendar.init( m_xContext, maLanguageTag.getLocale() );
238 xTransliteration.init( m_xContext, eLang,
239 ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE );
240 xNatNum.init( m_xContext );
242 // cached locale data items
243 const LocaleDataWrapper* pLoc = GetLocaleData();
244 aDecimalSep = pLoc->getNumDecimalSep();
245 aThousandSep = pLoc->getNumThousandSep();
246 aDateSep = pLoc->getDateSep();
248 pStringScanner = new ImpSvNumberInputScan( this );
249 pFormatScanner = new ImpSvNumberformatScan( this );
250 pFormatTable = NULL;
251 MaxCLOffset = 0;
252 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
253 pMergeTable = NULL;
254 bNoZero = false;
256 ::osl::MutexGuard aGuard( GetMutex() );
257 GetFormatterRegistry().Insert( this );
261 void SvNumberFormatter::ChangeIntl(LanguageType eLnge)
263 if (ActLnge != eLnge)
265 ActLnge = eLnge;
267 maLanguageTag.reset( eLnge );
268 pCharClass->setLanguageTag( maLanguageTag );
269 xLocaleData.changeLocale( maLanguageTag );
270 xCalendar.changeLocale( maLanguageTag.getLocale() );
271 xTransliteration.changeLocale( eLnge );
273 // cached locale data items, initialize BEFORE calling ChangeIntl below
274 const LocaleDataWrapper* pLoc = GetLocaleData();
275 aDecimalSep = pLoc->getNumDecimalSep();
276 aThousandSep = pLoc->getNumThousandSep();
277 aDateSep = pLoc->getDateSep();
279 pFormatScanner->ChangeIntl();
280 pStringScanner->ChangeIntl();
285 // static
286 ::osl::Mutex& SvNumberFormatter::GetMutex()
288 static ::osl::Mutex* pMutex = NULL;
289 if( !pMutex )
291 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
292 if( !pMutex )
294 // #i77768# Due to a static reference in the toolkit lib
295 // we need a mutex that lives longer than the svl library.
296 // Otherwise the dtor would use a destructed mutex!!
297 pMutex = new ::osl::Mutex;
300 return *pMutex;
304 // static
305 SvNumberFormatterRegistry_Impl& SvNumberFormatter::GetFormatterRegistry()
307 ::osl::MutexGuard aGuard( GetMutex() );
308 if ( !pFormatterRegistry )
310 pFormatterRegistry = new SvNumberFormatterRegistry_Impl;
312 return *pFormatterRegistry;
316 Color* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex)
318 if( aColorLink.IsSet() )
320 return (Color*) ( aColorLink.Call( (void*) &nIndex ));
322 else
324 return NULL;
328 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay,
329 sal_uInt16 nMonth,
330 sal_uInt16 nYear)
332 pFormatScanner->ChangeNullDate(nDay, nMonth, nYear);
333 pStringScanner->ChangeNullDate(nDay, nMonth, nYear);
336 Date* SvNumberFormatter::GetNullDate()
338 return pFormatScanner->GetNullDate();
341 void SvNumberFormatter::ChangeStandardPrec(short nPrec)
343 pFormatScanner->ChangeStandardPrec(nPrec);
346 sal_uInt16 SvNumberFormatter::GetStandardPrec()
348 return pFormatScanner->GetStandardPrec();
351 void SvNumberFormatter::ImpChangeSysCL( LanguageType eLnge, bool bNoAdditionalFormats )
353 if (eLnge == LANGUAGE_DONTKNOW)
355 eLnge = UNKNOWN_SUBSTITUTE;
357 if (eLnge != IniLnge)
359 IniLnge = eLnge;
360 ChangeIntl(eLnge);
361 // delete old formats
362 for (SvNumberFormatTable::iterator it = aFTable.begin(); it != aFTable.end(); ++it)
364 delete it->second;
366 aFTable.clear();
367 ImpGenerateFormats( 0, bNoAdditionalFormats ); // new standard formats
369 else if ( bNoAdditionalFormats )
371 // delete additional standard formats
372 sal_uInt32 nKey;
373 SvNumberFormatTable::iterator it = aFTable.find( SV_MAX_ANZ_STANDARD_FORMATE + 1 );
374 while ( it != aFTable.end() &&
375 (nKey = it->first) > SV_MAX_ANZ_STANDARD_FORMATE &&
376 nKey < SV_COUNTRY_LANGUAGE_OFFSET )
378 delete it->second;
379 aFTable.erase( it++ );
385 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage )
387 sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM );
388 if ( nCLOffset > MaxCLOffset )
390 return ; // no SYSTEM entries to replace
392 const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_ANZ_STANDARD_FORMATE;
393 const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
394 sal_uInt32 nKey;
396 // remove old builtin formats
397 SvNumberFormatTable::iterator it = aFTable.find( nCLOffset );
398 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey <= nMaxBuiltin )
400 delete it->second;
401 aFTable.erase( it++ );
404 // move additional and user defined to temporary table
405 SvNumberFormatTable aOldTable;
406 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey < nNextCL )
408 aOldTable[ nKey ] = it->second;
409 aFTable.erase( it++ );
412 // generate new old builtin formats
413 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
414 ActLnge = LANGUAGE_DONTKNOW;
415 ChangeIntl( LANGUAGE_SYSTEM );
416 ImpGenerateFormats( nCLOffset, true );
418 // convert additional and user defined from old system to new system
419 SvNumberformat* pStdFormat = GetFormatEntry( nCLOffset + ZF_STANDARD );
420 sal_uInt32 nLastKey = nMaxBuiltin;
421 pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, true );
422 while ( !aOldTable.empty() )
424 nKey = aOldTable.begin()->first;
425 if ( nLastKey < nKey )
427 nLastKey = nKey;
429 SvNumberformat* pOldEntry = aOldTable.begin()->second;
430 aOldTable.erase( nKey );
431 OUString aString( pOldEntry->GetFormatstring() );
433 // Same as PutEntry() but assures key position even if format code is
434 // a duplicate. Also won't mix up any LastInsertKey.
435 ChangeIntl( eOldLanguage );
436 LanguageType eLge = eOldLanguage; // ConvertMode changes this
437 bool bCheck = false;
438 sal_Int32 nCheckPos = -1;
439 SvNumberformat* pNewEntry = new SvNumberformat( aString, pFormatScanner,
440 pStringScanner, nCheckPos, eLge );
441 if ( nCheckPos != 0 )
443 delete pNewEntry;
445 else
447 short eCheckType = pNewEntry->GetType();
448 if ( eCheckType != NUMBERFORMAT_UNDEFINED )
450 pNewEntry->SetType( eCheckType | NUMBERFORMAT_DEFINED );
452 else
454 pNewEntry->SetType( NUMBERFORMAT_DEFINED );
457 if ( !aFTable.insert( make_pair( nKey, pNewEntry) ).second )
459 delete pNewEntry;
461 else
463 bCheck = true;
466 DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
467 (void)bCheck;
469 delete pOldEntry;
471 pFormatScanner->SetConvertMode(false);
472 pStdFormat->SetLastInsertKey( sal_uInt16(nLastKey - nCLOffset) );
474 // append new system additional formats
475 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
476 GetLanguageTag().getLocale() );
477 ImpGenerateAdditionalFormats( nCLOffset, aNumberFormatCode, true );
481 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const
483 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
485 return pFormat ? pFormat->IsTextFormat() : false;
488 bool SvNumberFormatter::PutEntry(OUString& rString,
489 sal_Int32& nCheckPos,
490 short& nType,
491 sal_uInt32& nKey, // format key
492 LanguageType eLnge)
494 nKey = 0;
495 if (rString.isEmpty()) // empty string
497 nCheckPos = 1; // -> Error
498 return false;
500 if (eLnge == LANGUAGE_DONTKNOW)
502 eLnge = IniLnge;
504 ChangeIntl(eLnge); // change locale if necessary
505 LanguageType eLge = eLnge; // non-const for ConvertMode
506 bool bCheck = false;
507 SvNumberformat* p_Entry = new SvNumberformat(rString,
508 pFormatScanner,
509 pStringScanner,
510 nCheckPos,
511 eLge);
513 if (nCheckPos == 0) // Format ok
514 { // Type comparison:
515 short eCheckType = p_Entry->GetType();
516 if ( eCheckType != NUMBERFORMAT_UNDEFINED)
518 p_Entry->SetType(eCheckType | NUMBERFORMAT_DEFINED);
519 nType = eCheckType;
521 else
523 p_Entry->SetType(NUMBERFORMAT_DEFINED);
524 nType = NUMBERFORMAT_DEFINED;
527 sal_uInt32 CLOffset = ImpGenerateCL(eLge); // create new standard formats if necessary
529 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge);
530 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
532 delete p_Entry;
534 else
536 SvNumberformat* pStdFormat = GetFormatEntry(CLOffset + ZF_STANDARD);
537 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
538 if (nPos+1 - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
540 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
541 delete p_Entry;
543 else if (!aFTable.insert(make_pair( nPos+1,p_Entry)).second)
545 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
546 delete p_Entry;
548 else
550 bCheck = true;
551 nKey = nPos+1;
552 pStdFormat->SetLastInsertKey((sal_uInt16) (nKey-CLOffset));
556 else
558 delete p_Entry;
560 return bCheck;
563 bool SvNumberFormatter::PutandConvertEntry(OUString& rString,
564 sal_Int32& nCheckPos,
565 short& nType,
566 sal_uInt32& nKey,
567 LanguageType eLnge,
568 LanguageType eNewLnge)
570 bool bRes;
571 if (eNewLnge == LANGUAGE_DONTKNOW)
573 eNewLnge = IniLnge;
575 pFormatScanner->SetConvertMode(eLnge, eNewLnge);
576 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
577 pFormatScanner->SetConvertMode(false);
578 return bRes;
581 bool SvNumberFormatter::PutandConvertEntrySystem(OUString& rString,
582 sal_Int32& nCheckPos,
583 short& nType,
584 sal_uInt32& nKey,
585 LanguageType eLnge,
586 LanguageType eNewLnge)
588 bool bRes;
589 if (eNewLnge == LANGUAGE_DONTKNOW)
591 eNewLnge = IniLnge;
593 pFormatScanner->SetConvertMode(eLnge, eNewLnge, true);
594 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
595 pFormatScanner->SetConvertMode(false);
596 return bRes;
599 sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( String & rString, LanguageType eLnge,
600 LanguageType eSysLnge, short & rType,
601 bool & rNewInserted, xub_StrLen & rCheckPos )
603 sal_uInt32 result;
604 OUString sTemp(rString);
605 sal_Int32 nCheckPos = (rCheckPos == (xub_StrLen)0xFFFF) ? -1 : (sal_Int32)rCheckPos;
606 result = GetIndexPuttingAndConverting(sTemp, eLnge, eSysLnge, rType, rNewInserted, nCheckPos);
607 rCheckPos = nCheckPos < 0 ? (xub_StrLen)0xFFFF : (xub_StrLen)nCheckPos;
608 rString = sTemp;
609 return result;
612 sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( OUString & rString, LanguageType eLnge,
613 LanguageType eSysLnge, short & rType,
614 bool & rNewInserted, sal_Int32 & rCheckPos )
616 sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
617 rNewInserted = false;
618 rCheckPos = 0;
620 // #62389# empty format string (of Writer) => General standard format
621 if (rString.isEmpty())
623 // nothing
625 else if (eLnge == LANGUAGE_SYSTEM && eSysLnge != SvtSysLocale().GetLanguageTag().getLanguageType())
627 sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge );
628 if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND)
630 nKey = nOrig; // none available, maybe user-defined
632 else
634 nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguageTag().getLanguageType() );
636 if (nKey == nOrig)
638 // Not a builtin format, convert.
639 // The format code string may get modified and adapted to the real
640 // language and wouldn't match eSysLnge anymore, do that on a copy.
641 OUString aTmp( rString);
642 rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType,
643 nKey, eLnge, SvtSysLocale().GetLanguageTag().getLanguageType());
644 if (rCheckPos > 0)
646 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
647 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
651 else
653 nKey = GetEntryKey( rString, eLnge);
654 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
656 rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
657 if (rCheckPos > 0)
659 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
660 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
664 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
666 nKey = GetStandardIndex( eLnge);
668 rType = GetType( nKey);
669 // Convert any (!) old "automatic" currency format to new fixed currency
670 // default format.
671 if ((rType & NUMBERFORMAT_CURRENCY) != 0)
673 const SvNumberformat* pFormat = GetEntry( nKey);
674 if (!pFormat->HasNewCurrency())
676 if (rNewInserted)
678 DeleteEntry( nKey); // don't leave trails of rubbish
679 rNewInserted = false;
681 nKey = GetStandardFormat( NUMBERFORMAT_CURRENCY, eLnge);
684 return nKey;
688 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey)
690 delete aFTable[nKey];
691 aFTable.erase(nKey);
694 bool SvNumberFormatter::Load( SvStream& rStream )
696 LanguageType eSysLang = SvtSysLocale().GetLanguageTag().getLanguageType();
697 SvNumberFormatter* pConverter = NULL;
699 ImpSvNumMultipleReadHeader aHdr( rStream );
700 sal_uInt16 nVersion;
701 rStream >> nVersion;
702 SvNumberformat* pEntry;
703 sal_uInt32 nPos;
704 sal_uInt16 nSysOnStore, eLge, eDummy; // Dummy for compatible format
705 rStream >> nSysOnStore >> eLge; // system language from document
707 SAL_WARN_IF( nVersion < SV_NUMBERFORMATTER_VERSION_CALENDAR, "svl.numbers", "SvNumberFormatter::Load: where does this unsupported old data come from?!?");
709 LanguageType eSaveSysLang = (LanguageType) nSysOnStore;
710 LanguageType eLnge = (LanguageType) eLge;
711 ImpChangeSysCL( eLnge, true );
713 rStream >> nPos;
714 while (nPos != NUMBERFORMAT_ENTRY_NOT_FOUND)
716 rStream >> eDummy >> eLge;
717 eLnge = (LanguageType) eLge;
718 ImpGenerateCL( eLnge, true ); // create new standard formats if necessary
720 sal_uInt32 nOffset = nPos % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
721 bool bUserDefined = (nOffset > SV_MAX_ANZ_STANDARD_FORMATE);
723 pEntry = new SvNumberformat(*pFormatScanner, eLnge);
724 pEntry->Load( rStream, aHdr, NULL, *pStringScanner );
725 if ( !bUserDefined )
727 bUserDefined = (pEntry->GetNewStandardDefined() > SV_NUMBERFORMATTER_VERSION);
729 if ( bUserDefined )
731 LanguageType eLoadSysLang = (eLnge == LANGUAGE_SYSTEM ? eSysLang : eSaveSysLang);
732 if ( eSaveSysLang != eLoadSysLang )
734 // different SYSTEM locale
735 if ( !pConverter )
737 pConverter = new SvNumberFormatter( m_xContext, eSysLang );
739 pEntry->ConvertLanguage( *pConverter, eSaveSysLang, eLoadSysLang, true );
742 if ( nOffset == 0 ) // Standard/General format
744 SvNumberformat* pEnt = GetFormatEntry(nPos);
745 if (pEnt)
747 pEnt->SetLastInsertKey(pEntry->GetLastInsertKey());
750 if (!aFTable.insert(make_pair( nPos, pEntry)).second)
752 SAL_WARN( "svl.numbers", "SvNumberFormatter::Load: dup position");
753 delete pEntry;
755 rStream >> nPos;
758 // as of SV_NUMBERFORMATTER_VERSION_YEAR2000
759 if ( nVersion >= SV_NUMBERFORMATTER_VERSION_YEAR2000 )
761 aHdr.StartEntry();
762 if ( aHdr.BytesLeft() >= sizeof(sal_uInt16) )
764 sal_uInt16 nY2k;
765 rStream >> nY2k;
766 if ( nVersion < SV_NUMBERFORMATTER_VERSION_TWODIGITYEAR && nY2k < 100 )
768 nY2k += 1901; // was before src513e: 29, now: 1930
770 SetYear2000( nY2k );
772 aHdr.EndEntry();
775 if ( pConverter )
777 delete pConverter;
780 // generate additional i18n standard formats for all used locales
781 LanguageType eOldLanguage = ActLnge;
782 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
783 GetLanguageTag().getLocale() );
784 std::vector<sal_uInt16> aList;
785 GetUsedLanguages( aList );
786 for ( std::vector<sal_uInt16>::const_iterator it(aList.begin()); it != aList.end(); ++it )
788 LanguageType eLang = *it;
789 ChangeIntl( eLang );
790 sal_uInt32 CLOffset = ImpGetCLOffset( eLang );
791 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, true );
793 ChangeIntl( eOldLanguage );
795 return rStream.GetError() ? false : true;
798 bool SvNumberFormatter::Save( SvStream& rStream ) const
800 ImpSvNumMultipleWriteHeader aHdr( rStream );
801 // As of 364i we store what SYSTEM locale really was, before it was hard
802 // coded LANGUAGE_SYSTEM.
803 rStream << (sal_uInt16) SV_NUMBERFORMATTER_VERSION;
804 rStream << (sal_uInt16) SvtSysLocale().GetLanguageTag().getLanguageType() << (sal_uInt16) IniLnge;
806 const SvNumberFormatTable* pTable = &aFTable;
807 SvNumberFormatTable::const_iterator it = pTable->begin();
808 while (it != pTable->end())
810 SvNumberformat* pEntry = it->second;
811 // Stored are all marked user defined formats and for each active
812 // (selected) locale the Standard/General format and
813 // NewStandardDefined.
814 if ( pEntry->GetUsed() || (pEntry->GetType() & NUMBERFORMAT_DEFINED) ||
815 pEntry->GetNewStandardDefined() || (it->first % SV_COUNTRY_LANGUAGE_OFFSET == 0) )
817 rStream << it->first
818 << (sal_uInt16) LANGUAGE_SYSTEM
819 << (sal_uInt16) pEntry->GetLanguage();
820 pEntry->Save(rStream, aHdr);
822 ++it;
824 rStream << NUMBERFORMAT_ENTRY_NOT_FOUND; // end marker
826 // as of SV_NUMBERFORMATTER_VERSION_YEAR2000
827 aHdr.StartEntry();
828 rStream << (sal_uInt16) GetYear2000();
829 aHdr.EndEntry();
831 return rStream.GetError() ? false : true;
834 void SvNumberFormatter::GetUsedLanguages( std::vector<sal_uInt16>& rList )
836 rList.clear();
838 sal_uInt32 nOffset = 0;
839 while (nOffset <= MaxCLOffset)
841 SvNumberformat* pFormat = GetFormatEntry(nOffset);
842 if (pFormat)
844 rList.push_back( pFormat->GetLanguage() );
846 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
851 void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords,
852 LanguageType eLang )
854 ChangeIntl( eLang );
855 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
856 for ( sal_uInt16 i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i )
858 rKeywords[i] = rTable[i];
863 OUString SvNumberFormatter::GetKeyword( LanguageType eLnge, sal_uInt16 nIndex )
865 ChangeIntl(eLnge);
866 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
867 if ( nIndex < NF_KEYWORD_ENTRIES_COUNT )
869 return rTable[nIndex];
871 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
872 return OUString();
876 OUString SvNumberFormatter::GetStandardName( LanguageType eLnge )
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 SvNumberFormatTable::iterator 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 short& eType,
922 sal_uInt32& FIndex,
923 LanguageType& rLnge)
925 short eTypetmp = eType;
926 if (eType == NUMBERFORMAT_ALL) // empty cell or don't care
928 rLnge = IniLnge;
930 else
932 SvNumberformat* pFormat = GetFormatEntry(FIndex);
933 if (!pFormat)
935 rLnge = IniLnge;
936 eType = NUMBERFORMAT_ALL;
937 eTypetmp = eType;
939 else
941 rLnge = pFormat->GetLanguage();
942 eType = pFormat->GetType()&~NUMBERFORMAT_DEFINED;
943 if (eType == 0)
945 eType = NUMBERFORMAT_DEFINED;
946 eTypetmp = eType;
948 else if (eType == NUMBERFORMAT_DATETIME)
950 eTypetmp = eType;
951 eType = NUMBERFORMAT_DATE;
953 else
955 eTypetmp = eType;
959 ChangeIntl(rLnge);
960 return GetEntryTable(eTypetmp, FIndex, rLnge);
963 sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge, bool bNoAdditionalFormats )
965 ChangeIntl(eLnge);
966 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
967 if (CLOffset > MaxCLOffset)
969 // new CL combination
970 if (LocaleDataWrapper::areChecksEnabled())
972 const LanguageTag& rLoadedLocale = xLocaleData->getLoadedLanguageTag();
973 if ( !rLoadedLocale.equals( maLanguageTag, true) )
975 OUString aMsg("SvNumberFormatter::ImpGenerateCL: locales don't match:");
976 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg ));
978 // test XML locale data FormatElement entries
980 uno::Sequence< i18n::FormatElement > xSeq = xLocaleData->getAllFormats();
981 // A test for completeness of formatindex="0" ...
982 // formatindex="47" is not needed here since it is done in
983 // ImpGenerateFormats().
985 // Test for dupes of formatindex="..."
986 for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ )
988 sal_Int16 nIdx = xSeq[j].formatIndex;
989 OUStringBuffer aDupes;
990 for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ )
992 if ( i != j && xSeq[i].formatIndex == nIdx )
994 aDupes.append(OUString::valueOf( i ));
995 aDupes.append("(");
996 aDupes.append(xSeq[i].formatKey);
997 aDupes.append( ") ");
1000 if ( aDupes.getLength() > 0 )
1002 OUStringBuffer aMsg(aDupes.getLength() + xSeq[j].formatKey.getLength() + 100);
1003 aMsg.append("XML locale data FormatElement formatindex dupe: ");
1004 aMsg.append(OUString::valueOf((sal_Int32)nIdx));
1005 aMsg.append("\nFormatElements: ");
1006 aMsg.append(OUString::valueOf( j ));
1007 aMsg.append("(");
1008 aMsg.append( xSeq[j].formatKey );
1009 aMsg.append( ") ");
1010 aMsg.append(aDupes.makeStringAndClear());
1011 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg.makeStringAndClear() ));
1017 MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET;
1018 ImpGenerateFormats( MaxCLOffset, bNoAdditionalFormats );
1019 CLOffset = MaxCLOffset;
1021 return CLOffset;
1024 SvNumberFormatTable& SvNumberFormatter::ChangeCL(short eType,
1025 sal_uInt32& FIndex,
1026 LanguageType eLnge)
1028 ImpGenerateCL(eLnge);
1029 return GetEntryTable(eType, FIndex, ActLnge);
1032 SvNumberFormatTable& SvNumberFormatter::GetEntryTable(
1033 short eType,
1034 sal_uInt32& FIndex,
1035 LanguageType eLnge)
1037 if ( pFormatTable )
1039 pFormatTable->clear();
1041 else
1043 pFormatTable = new SvNumberFormatTable;
1045 ChangeIntl(eLnge);
1046 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1048 // Might generate and insert a default format for the given type
1049 // (e.g. currency) => has to be done before collecting formats.
1050 sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge );
1052 SvNumberFormatTable::iterator it = aFTable.find( CLOffset);
1054 if (eType == NUMBERFORMAT_ALL)
1056 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1057 { // copy all entries to output table
1058 (*pFormatTable)[ it->first ] = it->second;
1059 ++it;
1062 else
1064 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1065 { // copy entries of queried type to output table
1066 if ((it->second->GetType()) & eType)
1067 (*pFormatTable)[ it->first ] = it->second;
1068 ++it;
1071 if ( !pFormatTable->empty() )
1072 { // select default if queried format doesn't exist or queried type or
1073 // language differ from existing format
1074 SvNumberformat* pEntry = GetFormatEntry(FIndex);
1075 if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge )
1077 FIndex = nDefaultIndex;
1080 return *pFormatTable;
1083 bool SvNumberFormatter::IsNumberFormat(const OUString& sString,
1084 sal_uInt32& F_Index,
1085 double& fOutNumber)
1087 short FType;
1088 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
1089 if (!pFormat)
1091 ChangeIntl(IniLnge);
1092 FType = NUMBERFORMAT_NUMBER;
1094 else
1096 FType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
1097 if (FType == 0)
1099 FType = NUMBERFORMAT_DEFINED;
1101 ChangeIntl(pFormat->GetLanguage());
1104 bool res;
1105 short RType = FType;
1106 if (RType == NUMBERFORMAT_TEXT)
1108 res = false; // type text preset => no conversion to number
1110 else
1112 res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat);
1114 if (res && !IsCompatible(FType, RType)) // non-matching type
1116 switch ( RType )
1118 case NUMBERFORMAT_DATE :
1119 // Preserve ISO 8601 input.
1120 if (pStringScanner->CanForceToIso8601( DMY))
1122 F_Index = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, ActLnge );
1124 else
1126 F_Index = GetStandardFormat( RType, ActLnge );
1128 break;
1129 case NUMBERFORMAT_TIME :
1130 if ( pStringScanner->GetDecPos() )
1132 // 100th seconds
1133 if ( pStringScanner->GetAnzNums() > 3 || fOutNumber < 0.0 )
1135 F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge );
1137 else
1139 F_Index = GetFormatIndex( NF_TIME_MMSS00, ActLnge );
1142 else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 )
1144 F_Index = GetFormatIndex( NF_TIME_HH_MMSS, ActLnge );
1146 else
1148 F_Index = GetStandardFormat( RType, ActLnge );
1150 break;
1151 default:
1152 F_Index = GetStandardFormat( RType, ActLnge );
1155 return res;
1158 bool SvNumberFormatter::IsCompatible(short eOldType,
1159 short eNewType)
1161 if (eOldType == eNewType)
1163 return true;
1165 else if (eOldType == NUMBERFORMAT_DEFINED)
1167 return true;
1169 else
1171 switch (eNewType)
1173 case NUMBERFORMAT_NUMBER:
1174 switch (eOldType)
1176 case NUMBERFORMAT_PERCENT:
1177 case NUMBERFORMAT_CURRENCY:
1178 case NUMBERFORMAT_SCIENTIFIC:
1179 case NUMBERFORMAT_FRACTION:
1180 // case NUMBERFORMAT_LOGICAL:
1181 case NUMBERFORMAT_DEFINED:
1182 return true;
1183 default:
1184 return false;
1186 break;
1187 case NUMBERFORMAT_DATE:
1188 switch (eOldType)
1190 case NUMBERFORMAT_DATETIME:
1191 return true;
1192 default:
1193 return false;
1195 break;
1196 case NUMBERFORMAT_TIME:
1197 switch (eOldType)
1199 case NUMBERFORMAT_DATETIME:
1200 return true;
1201 default:
1202 return false;
1204 break;
1205 case NUMBERFORMAT_DATETIME:
1206 switch (eOldType)
1208 case NUMBERFORMAT_TIME:
1209 case NUMBERFORMAT_DATE:
1210 return true;
1211 default:
1212 return false;
1214 break;
1215 default:
1216 return false;
1222 sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( short nType )
1224 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1225 sal_uInt32 nSearch;
1226 switch( nType )
1228 case NUMBERFORMAT_DATE:
1229 nSearch = CLOffset + ZF_STANDARD_DATE;
1230 break;
1231 case NUMBERFORMAT_TIME:
1232 nSearch = CLOffset + ZF_STANDARD_TIME;
1233 break;
1234 case NUMBERFORMAT_DATETIME:
1235 nSearch = CLOffset + ZF_STANDARD_DATETIME;
1236 break;
1237 case NUMBERFORMAT_PERCENT:
1238 nSearch = CLOffset + ZF_STANDARD_PERCENT;
1239 break;
1240 case NUMBERFORMAT_SCIENTIFIC:
1241 nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1242 break;
1243 default:
1244 nSearch = CLOffset + ZF_STANDARD;
1247 DefaultFormatKeysMap::iterator it = aDefaultFormatKeys.find( nSearch);
1248 sal_uInt32 nDefaultFormat = (it != aDefaultFormatKeys.end() ?
1249 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
1250 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1252 // look for a defined standard
1253 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
1254 sal_uInt32 nKey(0);
1255 SvNumberFormatTable::iterator it2 = aFTable.find( CLOffset );
1256 while ( it2 != aFTable.end() && (nKey = it2->first ) >= CLOffset && nKey < nStopKey )
1258 const SvNumberformat* pEntry = it2->second;
1259 if ( pEntry->IsStandard() && ((pEntry->GetType() &
1260 ~NUMBERFORMAT_DEFINED) == nType) )
1262 nDefaultFormat = nKey;
1263 break; // while
1265 ++it2;
1268 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1269 { // none found, use old fixed standards
1270 switch( nType )
1272 case NUMBERFORMAT_DATE:
1273 nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1274 break;
1275 case NUMBERFORMAT_TIME:
1276 nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1277 break;
1278 case NUMBERFORMAT_DATETIME:
1279 nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1280 break;
1281 case NUMBERFORMAT_PERCENT:
1282 nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1283 break;
1284 case NUMBERFORMAT_SCIENTIFIC:
1285 nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1286 break;
1287 default:
1288 nDefaultFormat = CLOffset + ZF_STANDARD;
1291 aDefaultFormatKeys[ nSearch ] = nDefaultFormat;
1293 return nDefaultFormat;
1297 sal_uInt32 SvNumberFormatter::GetStandardFormat( short eType, LanguageType eLnge )
1299 if (eLnge == LANGUAGE_DONTKNOW)
1301 eLnge = IniLnge;
1303 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1304 switch(eType)
1306 case NUMBERFORMAT_CURRENCY:
1307 return ( eLnge == LANGUAGE_SYSTEM ) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1308 case NUMBERFORMAT_DATE:
1309 case NUMBERFORMAT_TIME:
1310 case NUMBERFORMAT_DATETIME:
1311 case NUMBERFORMAT_PERCENT:
1312 case NUMBERFORMAT_SCIENTIFIC:
1313 return ImpGetDefaultFormat( eType );
1314 case NUMBERFORMAT_FRACTION:
1315 return CLOffset + ZF_STANDARD_FRACTION;
1316 case NUMBERFORMAT_LOGICAL:
1317 return CLOffset + ZF_STANDARD_LOGICAL;
1318 case NUMBERFORMAT_TEXT:
1319 return CLOffset + ZF_STANDARD_TEXT;
1320 case NUMBERFORMAT_ALL:
1321 case NUMBERFORMAT_DEFINED:
1322 case NUMBERFORMAT_NUMBER:
1323 case NUMBERFORMAT_UNDEFINED:
1324 default:
1325 return CLOffset + ZF_STANDARD;
1329 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex,
1330 LanguageType eLnge )
1332 return
1333 nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) ||
1334 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) ||
1335 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge )
1339 sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, short eType,
1340 LanguageType eLnge )
1342 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1343 return nFIndex;
1344 else
1345 return GetStandardFormat( eType, eLnge );
1348 sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex,
1349 short eType, LanguageType eLnge )
1351 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1352 return nFIndex;
1354 switch( eType )
1356 case NUMBERFORMAT_TIME :
1358 bool bSign;
1359 if ( fNumber < 0.0 )
1361 bSign = true;
1362 fNumber = -fNumber;
1364 else
1365 bSign = false;
1366 double fSeconds = fNumber * 86400;
1367 if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) )
1368 { // with 100th seconds
1369 if ( bSign || fSeconds >= 3600 )
1370 return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge );
1371 else
1372 return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1374 else
1376 if ( bSign || fNumber >= 1.0 )
1377 return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1378 else
1379 return GetStandardFormat( eType, eLnge );
1382 default:
1383 return GetStandardFormat( eType, eLnge );
1387 sal_uInt32 SvNumberFormatter::GetEditFormat( double fNumber, sal_uInt32 nFIndex,
1388 short eType, LanguageType eLang,
1389 SvNumberformat* pFormat )
1391 sal_uInt32 nKey = nFIndex;
1392 switch ( eType )
1394 // #61619# always edit using 4-digit year
1395 case NUMBERFORMAT_DATE :
1396 if (rtl::math::approxFloor( fNumber) != fNumber)
1397 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1398 // fdo#34977 preserve time when editing even if only date was
1399 // displayed.
1400 /* FIXME: in case an ISO 8601 format was used, editing should
1401 * also use such. Unfortunately we have no builtin combined
1402 * date+time ISO format defined. Needs also locale data work.
1403 * */
1404 else
1406 // Preserve ISO 8601 format.
1407 if ( nFIndex == GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang) ||
1408 nFIndex == GetFormatIndex( NF_DATE_DIN_YYMMDD, eLang) ||
1409 nFIndex == GetFormatIndex( NF_DATE_DIN_MMDD, eLang) ||
1410 (pFormat && pFormat->IsIso8601( 0 )))
1411 nKey = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang);
1412 else
1413 nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1415 break;
1416 case NUMBERFORMAT_TIME :
1417 if (fNumber < 0.0 || fNumber >= 1.0)
1419 /* XXX NOTE: this is a purely arbitrary value within the limits
1420 * of a signed 16-bit. 32k hours are 3.7 years ... or
1421 * 1903-09-26 if date. */
1422 if (fabs( fNumber) * 24 < 0x7fff)
1423 nKey = GetFormatIndex( NF_TIME_HH_MMSS, eLang );
1424 // Preserve duration, use [HH]:MM:SS instead of time.
1425 else
1426 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1427 // Assume that a large value is a datetime with only time
1428 // displayed.
1430 else
1431 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1432 break;
1433 case NUMBERFORMAT_DATETIME :
1434 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1435 /* FIXME: in case an ISO 8601 format was used, editing should
1436 * also use such. Unfortunately we have no builtin combined
1437 * date+time ISO format defined. Needs also locale data work. */
1438 break;
1439 default:
1440 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1442 return nKey;
1445 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1446 sal_uInt32 nFIndex,
1447 OUString& sOutString)
1449 Color* pColor;
1450 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1451 if (!pFormat)
1453 pFormat = GetFormatEntry(ZF_STANDARD);
1456 LanguageType eLang = pFormat->GetLanguage();
1457 ChangeIntl( eLang );
1459 short eType = pFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1460 if (eType == 0)
1462 eType = NUMBERFORMAT_DEFINED;
1465 sal_uInt16 nOldPrec = pFormatScanner->GetStandardPrec();
1466 bool bPrecChanged = false;
1467 if (eType == NUMBERFORMAT_NUMBER ||
1468 eType == NUMBERFORMAT_PERCENT ||
1469 eType == NUMBERFORMAT_CURRENCY ||
1470 eType == NUMBERFORMAT_SCIENTIFIC ||
1471 eType == NUMBERFORMAT_FRACTION)
1473 if (eType != NUMBERFORMAT_PERCENT) // special treatment of % later
1475 eType = NUMBERFORMAT_NUMBER;
1477 ChangeStandardPrec(INPUTSTRING_PRECISION);
1478 bPrecChanged = true;
1481 sal_uInt32 nKey = GetEditFormat( fOutNumber, nFIndex, eType, eLang, pFormat);
1482 if ( nKey != nFIndex )
1484 pFormat = GetFormatEntry( nKey );
1486 if (pFormat)
1488 if ( eType == NUMBERFORMAT_TIME && pFormat->GetFormatPrecision() )
1490 ChangeStandardPrec(INPUTSTRING_PRECISION);
1491 bPrecChanged = true;
1493 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1495 if (bPrecChanged)
1497 ChangeStandardPrec(nOldPrec);
1501 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1502 sal_uInt32 nFIndex,
1503 String& rOutString)
1505 OUString aTmp;
1506 GetInputLineString(fOutNumber, nFIndex, aTmp);
1507 rOutString = aTmp;
1510 void SvNumberFormatter::GetOutputString(const OUString& sString,
1511 sal_uInt32 nFIndex,
1512 OUString& sOutString,
1513 Color** ppColor,
1514 bool bUseStarFormat )
1516 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1517 if (!pFormat)
1519 pFormat = GetFormatEntry(ZF_STANDARD_TEXT);
1521 if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1523 *ppColor = NULL;
1524 sOutString = sString;
1526 else
1528 ChangeIntl(pFormat->GetLanguage());
1529 if ( bUseStarFormat )
1531 pFormat->SetStarFormatSupport( true );
1533 pFormat->GetOutputString(sString, sOutString, ppColor);
1534 if ( bUseStarFormat )
1536 pFormat->SetStarFormatSupport( false );
1541 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1542 sal_uInt32 nFIndex,
1543 OUString& sOutString,
1544 Color** ppColor,
1545 bool bUseStarFormat )
1547 if (bNoZero && fOutNumber == 0.0)
1549 sOutString = OUString();
1550 return;
1552 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1553 if (!pFormat)
1554 pFormat = GetFormatEntry(ZF_STANDARD);
1555 ChangeIntl(pFormat->GetLanguage());
1556 if ( bUseStarFormat )
1557 pFormat->SetStarFormatSupport( true );
1558 pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1559 if ( bUseStarFormat )
1560 pFormat->SetStarFormatSupport( false );
1563 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1564 sal_uInt32 nFIndex,
1565 String& sOutString,
1566 Color** ppColor,
1567 bool bUseStarFormat )
1569 OUString sTemp(sOutString);
1570 GetOutputString(fOutNumber, nFIndex, sTemp, ppColor, bUseStarFormat);
1571 sOutString = sTemp;
1574 bool SvNumberFormatter::GetPreviewString(const OUString& sFormatString,
1575 double fPreviewNumber,
1576 OUString& sOutString,
1577 Color** ppColor,
1578 LanguageType eLnge,
1579 bool bUseStarFormat )
1581 if (sFormatString.isEmpty()) // no empty string
1583 return false;
1585 sal_uInt32 nKey;
1586 if (eLnge == LANGUAGE_DONTKNOW)
1588 eLnge = IniLnge;
1590 ChangeIntl(eLnge); // change locale if necessary
1591 eLnge = ActLnge;
1592 sal_Int32 nCheckPos = -1;
1593 OUString sTmpString = sFormatString;
1594 SvNumberformat* p_Entry = new SvNumberformat(sTmpString,
1595 pFormatScanner,
1596 pStringScanner,
1597 nCheckPos,
1598 eLnge);
1599 if (nCheckPos == 0) // String ok
1601 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
1602 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge);
1603 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
1605 GetOutputString(fPreviewNumber, nKey, sOutString, ppColor, bUseStarFormat);
1607 else
1609 if ( bUseStarFormat )
1611 p_Entry->SetStarFormatSupport( true );
1613 p_Entry->GetOutputString(fPreviewNumber, sOutString, ppColor);
1614 if ( bUseStarFormat )
1616 p_Entry->SetStarFormatSupport( false );
1619 delete p_Entry;
1620 return true;
1622 else
1624 delete p_Entry;
1625 return false;
1629 bool SvNumberFormatter::GetPreviewStringGuess( const OUString& sFormatString,
1630 double fPreviewNumber,
1631 OUString& sOutString,
1632 Color** ppColor,
1633 LanguageType eLnge )
1635 if (sFormatString.isEmpty()) // no empty string
1637 return false;
1639 if (eLnge == LANGUAGE_DONTKNOW)
1641 eLnge = IniLnge;
1643 ChangeIntl( eLnge );
1644 eLnge = ActLnge;
1645 bool bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1647 OUString aFormatStringUpper( pCharClass->uppercase( sFormatString ) );
1648 sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1649 sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1650 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1652 // Zielformat vorhanden
1653 GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1654 return true;
1657 SvNumberformat *pEntry = NULL;
1658 sal_Int32 nCheckPos = -1;
1659 OUString sTmpString;
1661 if ( bEnglish )
1663 sTmpString = sFormatString;
1664 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1665 pStringScanner, nCheckPos, eLnge );
1667 else
1669 nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1670 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1671 bool bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1673 // try english --> other bzw. english nach other konvertieren
1674 LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1675 pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge );
1676 sTmpString = sFormatString;
1677 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1678 pStringScanner, nCheckPos, eFormatLang );
1679 pFormatScanner->SetConvertMode( false );
1680 ChangeIntl( eLnge );
1682 if ( !bEnglishFormat )
1684 if ( !(nCheckPos == 0) || xTransliteration->isEqual( sFormatString,
1685 pEntry->GetFormatstring() ) )
1687 // other Format
1688 delete pEntry;
1689 sTmpString = sFormatString;
1690 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1691 pStringScanner, nCheckPos, eLnge );
1693 else
1695 // verify english
1696 sal_Int32 nCheckPos2 = -1;
1697 // try other --> english
1698 eFormatLang = eLnge;
1699 pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US );
1700 sTmpString = sFormatString;
1701 SvNumberformat* pEntry2 = new SvNumberformat( sTmpString, pFormatScanner,
1702 pStringScanner, nCheckPos2, eFormatLang );
1703 pFormatScanner->SetConvertMode( false );
1704 ChangeIntl( eLnge );
1705 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1706 pEntry2->GetFormatstring() ) )
1708 // other Format
1709 delete pEntry;
1710 sTmpString = sFormatString;
1711 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1712 pStringScanner, nCheckPos, eLnge );
1714 delete pEntry2;
1719 if (nCheckPos == 0) // String ok
1721 ImpGenerateCL( eLnge ); // create new standard formats if necessary
1722 pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1723 delete pEntry;
1724 return true;
1726 delete pEntry;
1727 return false;
1730 bool SvNumberFormatter::GetPreviewString( const OUString& sFormatString,
1731 const OUString& sPreviewString,
1732 OUString& sOutString,
1733 Color** ppColor,
1734 LanguageType eLnge )
1736 if (sFormatString.isEmpty()) // no empty string
1738 return false;
1740 sal_uInt32 nKey;
1741 if (eLnge == LANGUAGE_DONTKNOW)
1743 eLnge = IniLnge;
1745 ChangeIntl(eLnge); // switch if needed
1746 eLnge = ActLnge;
1747 sal_Int32 nCheckPos = -1;
1748 OUString sTmpString = sFormatString;
1749 SvNumberformat* p_Entry = new SvNumberformat( sTmpString,
1750 pFormatScanner,
1751 pStringScanner,
1752 nCheckPos,
1753 eLnge);
1754 if (nCheckPos == 0) // String ok
1756 // May have to create standard formats for this locale.
1757 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1758 nKey = ImpIsEntry( p_Entry->GetFormatstring(), CLOffset, eLnge);
1759 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
1761 GetOutputString( sPreviewString, nKey, sOutString, ppColor);
1763 else
1765 // If the format is valid but not a text format and does not
1766 // include a text subformat, an empty string would result. Same as
1767 // in SvNumberFormatter::GetOutputString()
1768 if (p_Entry->IsTextFormat() || p_Entry->HasTextFormat())
1770 p_Entry->GetOutputString( sPreviewString, sOutString, ppColor);
1772 else
1774 *ppColor = NULL;
1775 sOutString = sPreviewString;
1778 delete p_Entry;
1779 return true;
1781 else
1783 delete p_Entry;
1784 return false;
1788 sal_uInt32 SvNumberFormatter::TestNewString(const OUString& sFormatString,
1789 LanguageType eLnge)
1791 if (sFormatString.isEmpty()) // no empty string
1793 return NUMBERFORMAT_ENTRY_NOT_FOUND;
1795 if (eLnge == LANGUAGE_DONTKNOW)
1797 eLnge = IniLnge;
1799 ChangeIntl(eLnge); // change locale if necessary
1800 eLnge = ActLnge;
1801 sal_uInt32 nRes;
1802 sal_Int32 nCheckPos = -1;
1803 OUString sTmpString = sFormatString;
1804 SvNumberformat* pEntry = new SvNumberformat(sTmpString,
1805 pFormatScanner,
1806 pStringScanner,
1807 nCheckPos,
1808 eLnge);
1809 if (nCheckPos == 0) // String ok
1811 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
1812 nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge);
1813 // already present?
1815 else
1817 nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1819 delete pEntry;
1820 return nRes;
1823 SvNumberformat* SvNumberFormatter::ImpInsertFormat( const ::com::sun::star::i18n::NumberFormatCode& rCode,
1824 sal_uInt32 nPos, bool bAfterChangingSystemCL,
1825 sal_Int16 nOrgIndex )
1827 String aCodeStr( rCode.Code );
1828 if ( rCode.Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
1829 rCode.Usage == ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY &&
1830 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1831 { // strip surrounding [$...] on automatic currency
1832 if ( aCodeStr.SearchAscii( "[$" ) != STRING_NOTFOUND )
1833 aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr, false );
1834 else
1836 if (LocaleDataWrapper::areChecksEnabled() &&
1837 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1839 OUString aMsg("SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index ");
1840 aMsg += OUString::valueOf( sal_Int32(rCode.Index) );
1841 aMsg += ":\n";
1842 aMsg += rCode.Code;
1843 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1847 sal_Int32 nCheckPos = 0;
1848 OUString sTempIn(aCodeStr);
1849 SvNumberformat* pFormat = new SvNumberformat(sTempIn,
1850 pFormatScanner,
1851 pStringScanner,
1852 nCheckPos,
1853 ActLnge);
1854 aCodeStr = sTempIn;
1855 if ( !pFormat || !(nCheckPos == 0) )
1857 if (LocaleDataWrapper::areChecksEnabled())
1859 OUString aMsg( "SvNumberFormatter::ImpInsertFormat: bad format code, index " );
1860 aMsg += OUString::valueOf( sal_Int32(rCode.Index) );
1861 aMsg += "\n";
1862 aMsg += rCode.Code;
1863 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1865 delete pFormat;
1866 return NULL;
1868 if ( rCode.Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
1870 sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
1871 sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
1872 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1874 // If bAfterChangingSystemCL there will definitely be some dups,
1875 // don't cry then.
1876 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL)
1878 // Test for duplicate indexes in locale data.
1879 switch ( nOrgIndex )
1881 // These may be dups of integer versions for locales where
1882 // currencies have no decimals like Italian Lira.
1883 case NF_CURRENCY_1000DEC2 : // NF_CURRENCY_1000INT
1884 case NF_CURRENCY_1000DEC2_RED : // NF_CURRENCY_1000INT_RED
1885 case NF_CURRENCY_1000DEC2_DASHED : // NF_CURRENCY_1000INT_RED
1886 break;
1887 default:
1889 OUString aMsg("SvNumberFormatter::ImpInsertFormat: dup format code, index ");
1890 aMsg += OUString::valueOf( sal_Int32(rCode.Index) );
1891 aMsg += "\n";
1892 aMsg += rCode.Code;
1893 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1897 delete pFormat;
1898 return NULL;
1900 else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
1902 if (LocaleDataWrapper::areChecksEnabled())
1904 OUString aMsg( "SvNumberFormatter::ImpInsertFormat: too many format codes, index ");
1905 aMsg += OUString::valueOf( sal_Int32(rCode.Index) );
1906 aMsg += "\n";
1907 aMsg += rCode.Code;
1908 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1910 delete pFormat;
1911 return NULL;
1914 if ( !aFTable.insert( make_pair( nPos, pFormat) ).second )
1916 if (LocaleDataWrapper::areChecksEnabled())
1918 OUString aMsg( "ImpInsertFormat: can't insert number format key pos: ");
1919 aMsg += OUString::valueOf( sal_Int32( nPos ) );
1920 aMsg += ", code index ";
1921 aMsg += OUString::valueOf( sal_Int32(rCode.Index) );
1922 aMsg += "\n";
1923 aMsg += rCode.Code;
1924 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1926 else
1928 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
1930 delete pFormat;
1931 return NULL;
1933 if ( rCode.Default )
1934 pFormat->SetStandard();
1935 if ( !rCode.DefaultName.isEmpty() )
1936 pFormat->SetComment( rCode.DefaultName );
1937 return pFormat;
1940 SvNumberformat* SvNumberFormatter::ImpInsertNewStandardFormat(
1941 const ::com::sun::star::i18n::NumberFormatCode& rCode,
1942 sal_uInt32 nPos, sal_uInt16 nVersion, bool bAfterChangingSystemCL,
1943 sal_Int16 nOrgIndex )
1945 SvNumberformat* pNewFormat = ImpInsertFormat( rCode, nPos,
1946 bAfterChangingSystemCL, nOrgIndex );
1947 if (pNewFormat)
1948 pNewFormat->SetNewStandardDefined( nVersion );
1949 // so that it gets saved, displayed properly, and converted by old versions
1950 return pNewFormat;
1953 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
1954 bool& bThousand,
1955 bool& IsRed,
1956 sal_uInt16& nPrecision,
1957 sal_uInt16& nAnzLeading)
1960 SvNumberformat* pFormat = GetFormatEntry( nFormat );
1961 if (pFormat)
1962 pFormat->GetFormatSpecialInfo(bThousand, IsRed,
1963 nPrecision, nAnzLeading);
1964 else
1966 bThousand = false;
1967 IsRed = false;
1968 nPrecision = pFormatScanner->GetStandardPrec();
1969 nAnzLeading = 0;
1973 sal_uInt16 SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
1975 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
1976 if ( pFormat )
1977 return pFormat->GetFormatPrecision();
1978 else
1979 return pFormatScanner->GetStandardPrec();
1983 OUString SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
1985 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
1986 if ( !pFormat || pFormat->GetLanguage() == ActLnge )
1988 return GetNumDecimalSep();
1990 OUString aRet;
1991 LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
1992 if ( pFormat->GetLanguage() == eSaveLang )
1994 aRet = xLocaleData->getNumDecimalSep();
1996 else
1998 LanguageTag aSaveLocale( xLocaleData->getLanguageTag() );
1999 ((SvNumberFormatter*)this)->xLocaleData.changeLocale( LanguageTag( pFormat->GetLanguage()) );
2000 aRet = xLocaleData->getNumDecimalSep();
2001 ((SvNumberFormatter*)this)->xLocaleData.changeLocale( aSaveLocale );
2003 return aRet;
2007 sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const OUString& rFormatString,
2008 bool& bThousand, bool& IsRed, sal_uInt16& nPrecision,
2009 sal_uInt16& nAnzLeading, LanguageType eLnge )
2012 if (eLnge == LANGUAGE_DONTKNOW)
2014 eLnge = IniLnge;
2016 ChangeIntl(eLnge); // change locale if necessary
2017 eLnge = ActLnge;
2018 OUString aTmpStr( rFormatString );
2019 sal_Int32 nCheckPos = 0;
2020 SvNumberformat* pFormat = new SvNumberformat( aTmpStr, pFormatScanner,
2021 pStringScanner, nCheckPos, eLnge );
2022 if ( nCheckPos == 0 )
2024 pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nAnzLeading );
2026 else
2028 bThousand = false;
2029 IsRed = false;
2030 nPrecision = pFormatScanner->GetStandardPrec();
2031 nAnzLeading = 0;
2033 delete pFormat;
2034 return nCheckPos;
2038 inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff )
2040 if ( !bIndexTableInitialized )
2042 DBG_ASSERT( theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
2043 "SetIndexTable: theIndexTable[nTabOff] already occupied" );
2044 theIndexTable[nTabOff] = nIndOff;
2046 return nIndOff;
2050 sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex(
2051 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode >& rSeq,
2052 const NfIndexTableOffset nTabOff )
2054 const sal_Int32 nLen = rSeq.getLength();
2055 for ( sal_Int32 j=0; j<nLen; j++ )
2057 if ( rSeq[j].Index == nTabOff )
2058 return j;
2060 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START
2061 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
2062 || nTabOff == NF_CURRENCY_1000INT_RED
2063 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
2064 { // currency entries with decimals might not exist, e.g. Italian Lira
2065 OUString aMsg( "SvNumberFormatter::ImpGetFormatCodeIndex: not found: " );
2066 aMsg += OUString::valueOf( sal_Int32( nTabOff ) );
2067 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo(aMsg));
2069 if ( nLen )
2071 sal_Int32 j;
2072 // look for a preset default
2073 for ( j=0; j<nLen; j++ )
2075 if ( rSeq[j].Default )
2076 return j;
2078 // currencies are special, not all format codes must exist, but all
2079 // builtin number format key index positions must have a format assigned
2080 if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
2082 // look for a format with decimals
2083 for ( j=0; j<nLen; j++ )
2085 if ( rSeq[j].Index == NF_CURRENCY_1000DEC2 )
2086 return j;
2088 // last resort: look for a format without decimals
2089 for ( j=0; j<nLen; j++ )
2091 if ( rSeq[j].Index == NF_CURRENCY_1000INT )
2092 return j;
2096 else
2097 { // we need at least _some_ format
2098 rSeq.realloc(1);
2099 rSeq[0] = ::com::sun::star::i18n::NumberFormatCode();
2100 rSeq[0].Code = OUStringBuffer().
2101 append('0').
2102 append(GetNumDecimalSep()).
2103 append("############").
2104 makeStringAndClear();
2106 return 0;
2110 sal_Int32 SvNumberFormatter::ImpAdjustFormatCodeDefault(
2111 ::com::sun::star::i18n::NumberFormatCode * pFormatArr,
2112 sal_Int32 nCnt, bool bCheckCorrectness )
2114 using namespace ::com::sun::star;
2116 if ( !nCnt )
2117 return -1;
2118 if (bCheckCorrectness && LocaleDataWrapper::areChecksEnabled())
2120 // check the locale data for correctness
2121 OStringBuffer aMsg;
2122 sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
2123 nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
2124 for ( nElem = 0; nElem < nCnt; nElem++ )
2126 switch ( pFormatArr[nElem].Type )
2128 case i18n::KNumberFormatType::SHORT :
2129 nShort = nElem;
2130 break;
2131 case i18n::KNumberFormatType::MEDIUM :
2132 nMedium = nElem;
2133 break;
2134 case i18n::KNumberFormatType::LONG :
2135 nLong = nElem;
2136 break;
2137 default:
2138 aMsg.append("unknown type");
2140 if ( pFormatArr[nElem].Default )
2142 switch ( pFormatArr[nElem].Type )
2144 case i18n::KNumberFormatType::SHORT :
2145 if ( nShortDef != -1 )
2146 aMsg.append("dupe short type default");
2147 nShortDef = nElem;
2148 break;
2149 case i18n::KNumberFormatType::MEDIUM :
2150 if ( nMediumDef != -1 )
2151 aMsg.append("dupe medium type default");
2152 nMediumDef = nElem;
2153 break;
2154 case i18n::KNumberFormatType::LONG :
2155 if ( nLongDef != -1 )
2156 aMsg.append("dupe long type default");
2157 nLongDef = nElem;
2158 break;
2161 if (aMsg.getLength())
2163 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2164 aMsg.append("\nXML locale data FormatElement formatindex: ");
2165 aMsg.append(static_cast<sal_Int32>(pFormatArr[nElem].Index));
2166 OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(),
2167 RTL_TEXTENCODING_ASCII_US));
2168 LocaleDataWrapper::outputCheckMessage(xLocaleData->appendLocaleInfo(aUMsg));
2171 if ( nShort != -1 && nShortDef == -1 )
2172 aMsg.append("no short type default ");
2173 if ( nMedium != -1 && nMediumDef == -1 )
2174 aMsg.append("no medium type default ");
2175 if ( nLong != -1 && nLongDef == -1 )
2176 aMsg.append("no long type default ");
2177 if (aMsg.getLength())
2179 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2180 aMsg.append("\nXML locale data FormatElement group of: ");
2181 OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US));
2182 LocaleDataWrapper::outputCheckMessage(
2183 xLocaleData->appendLocaleInfo(aUMsg + pFormatArr[0].NameID));
2186 // find the default (medium preferred, then long) and reset all other defaults
2187 sal_Int32 nElem, nDef, nMedium;
2188 nDef = nMedium = -1;
2189 for ( nElem = 0; nElem < nCnt; nElem++ )
2191 if ( pFormatArr[nElem].Default )
2193 switch ( pFormatArr[nElem].Type )
2195 case i18n::KNumberFormatType::MEDIUM :
2196 nDef = nMedium = nElem;
2197 break;
2198 case i18n::KNumberFormatType::LONG :
2199 if ( nMedium == -1 )
2200 nDef = nElem;
2201 // fallthru
2202 default:
2203 if ( nDef == -1 )
2204 nDef = nElem;
2205 pFormatArr[nElem].Default = false;
2209 if ( nDef == -1 )
2210 nDef = 0;
2211 pFormatArr[nDef].Default = true;
2212 return nDef;
2215 SvNumberformat* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey )
2217 SvNumberFormatTable::iterator it = aFTable.find( nKey);
2218 if (it != aFTable.end())
2219 return it->second;
2220 return 0;
2223 const SvNumberformat* SvNumberFormatter::GetEntry( sal_uInt32 nKey ) const
2225 SvNumberFormatTable::const_iterator it = aFTable.find( nKey);
2226 if (it != aFTable.end())
2227 return it->second;
2228 return 0;
2231 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditionalFormats )
2233 using namespace ::com::sun::star;
2235 if ( !bIndexTableInitialized )
2237 for ( sal_uInt16 j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
2239 theIndexTable[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
2242 bool bOldConvertMode = pFormatScanner->GetConvertMode();
2243 if (bOldConvertMode)
2245 pFormatScanner->SetConvertMode(false); // switch off for this function
2248 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
2249 GetLanguageTag().getLocale() );
2250 SvNumberformat* pNewFormat = NULL;
2251 sal_Int32 nIdx;
2252 bool bDefault;
2254 // Counter for additional builtin formats not fitting into the first 10
2255 // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2256 // Has to be incremented on each ImpInsertNewStandardformat, new formats
2257 // must be appended, not inserted!
2258 sal_uInt16 nNewExtended = ZF_STANDARD_NEWEXTENDED;
2260 // Number
2261 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2262 aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER );
2263 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2265 // General
2266 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2267 SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2268 CLOffset + SetIndexTable( NF_NUMBER_STANDARD, ZF_STANDARD ));
2269 if (pStdFormat)
2271 // This is _the_ standard format.
2272 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat->GetType() != NUMBERFORMAT_NUMBER)
2274 LocaleDataWrapper::outputCheckMessage( xLocaleData->
2275 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2277 pStdFormat->SetType( NUMBERFORMAT_NUMBER );
2278 pStdFormat->SetStandard();
2279 pStdFormat->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE );
2281 else
2283 if (LocaleDataWrapper::areChecksEnabled())
2285 LocaleDataWrapper::outputCheckMessage( xLocaleData->
2286 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2290 // Boolean
2291 OUString aFormatCode = pFormatScanner->GetBooleanString();
2292 sal_Int32 nCheckPos = 0;
2294 pNewFormat = new SvNumberformat( aFormatCode, pFormatScanner,
2295 pStringScanner, nCheckPos, ActLnge );
2296 pNewFormat->SetType(NUMBERFORMAT_LOGICAL);
2297 pNewFormat->SetStandard();
2298 if ( !aFTable.insert(make_pair(
2299 CLOffset + SetIndexTable( NF_BOOLEAN, ZF_STANDARD_LOGICAL ),
2300 pNewFormat)).second)
2302 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2303 delete pNewFormat;
2306 // Text
2307 aFormatCode = "@";
2308 pNewFormat = new SvNumberformat( aFormatCode, pFormatScanner,
2309 pStringScanner, nCheckPos, ActLnge );
2310 pNewFormat->SetType(NUMBERFORMAT_TEXT);
2311 pNewFormat->SetStandard();
2312 if ( !aFTable.insert(make_pair(
2313 CLOffset + SetIndexTable( NF_TEXT, ZF_STANDARD_TEXT ),
2314 pNewFormat)).second)
2316 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2317 delete pNewFormat;
2322 // 0
2323 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2324 ImpInsertFormat( aFormatSeq[nIdx],
2325 CLOffset + SetIndexTable( NF_NUMBER_INT, ZF_STANDARD+1 ));
2327 // 0.00
2328 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2329 ImpInsertFormat( aFormatSeq[nIdx],
2330 CLOffset + SetIndexTable( NF_NUMBER_DEC2, ZF_STANDARD+2 ));
2332 // #,##0
2333 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2334 ImpInsertFormat( aFormatSeq[nIdx],
2335 CLOffset + SetIndexTable( NF_NUMBER_1000INT, ZF_STANDARD+3 ));
2337 // #,##0.00
2338 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2339 ImpInsertFormat( aFormatSeq[nIdx],
2340 CLOffset + SetIndexTable( NF_NUMBER_1000DEC2, ZF_STANDARD+4 ));
2342 // #.##0,00 System country/language dependent since number formatter version 6
2343 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2344 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2345 CLOffset + SetIndexTable( NF_NUMBER_SYSTEM, ZF_STANDARD+5 ),
2346 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2349 // Percent number
2350 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER );
2351 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2353 // 0%
2354 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2355 ImpInsertFormat( aFormatSeq[nIdx],
2356 CLOffset + SetIndexTable( NF_PERCENT_INT, ZF_STANDARD_PERCENT ));
2358 // 0.00%
2359 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2360 ImpInsertFormat( aFormatSeq[nIdx],
2361 CLOffset + SetIndexTable( NF_PERCENT_DEC2, ZF_STANDARD_PERCENT+1 ));
2365 // Currency. NO default standard option! Default is determined of locale
2366 // data default currency and format is generated if needed.
2367 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2368 if (LocaleDataWrapper::areChecksEnabled())
2370 // though no default desired here, test for correctness of locale data
2371 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2374 // #,##0
2375 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2376 bDefault = aFormatSeq[nIdx].Default;
2377 aFormatSeq[nIdx].Default = false;
2378 ImpInsertFormat( aFormatSeq[nIdx],
2379 CLOffset + SetIndexTable( NF_CURRENCY_1000INT, ZF_STANDARD_CURRENCY ));
2380 aFormatSeq[nIdx].Default = bDefault;
2382 // #,##0.00
2383 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2384 bDefault = aFormatSeq[nIdx].Default;
2385 aFormatSeq[nIdx].Default = false;
2386 ImpInsertFormat( aFormatSeq[nIdx],
2387 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2, ZF_STANDARD_CURRENCY+1 ));
2388 aFormatSeq[nIdx].Default = bDefault;
2390 // #,##0 negative red
2391 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2392 bDefault = aFormatSeq[nIdx].Default;
2393 aFormatSeq[nIdx].Default = false;
2394 ImpInsertFormat( aFormatSeq[nIdx],
2395 CLOffset + SetIndexTable( NF_CURRENCY_1000INT_RED, ZF_STANDARD_CURRENCY+2 ));
2396 aFormatSeq[nIdx].Default = bDefault;
2398 // #,##0.00 negative red
2399 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2400 bDefault = aFormatSeq[nIdx].Default;
2401 aFormatSeq[nIdx].Default = false;
2402 ImpInsertFormat( aFormatSeq[nIdx],
2403 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_RED, ZF_STANDARD_CURRENCY+3 ));
2404 aFormatSeq[nIdx].Default = bDefault;
2406 // #,##0.00 USD since number formatter version 3
2407 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2408 bDefault = aFormatSeq[nIdx].Default;
2409 aFormatSeq[nIdx].Default = false;
2410 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2411 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_CCC, ZF_STANDARD_CURRENCY+4 ));
2412 if ( pNewFormat )
2413 pNewFormat->SetUsed(true); // must be saved for older versions
2414 aFormatSeq[nIdx].Default = bDefault;
2416 // #.##0,-- since number formatter version 6
2417 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED );
2418 bDefault = aFormatSeq[nIdx].Default;
2419 aFormatSeq[nIdx].Default = false;
2420 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2421 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_DASHED, ZF_STANDARD_CURRENCY+5 ),
2422 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2423 aFormatSeq[nIdx].Default = bDefault;
2427 // Date
2428 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE );
2429 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2431 // DD.MM.YY System
2432 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2433 ImpInsertFormat( aFormatSeq[nIdx],
2434 CLOffset + SetIndexTable( NF_DATE_SYSTEM_SHORT, ZF_STANDARD_DATE ));
2436 // NN DD.MMM YY
2437 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2438 ImpInsertFormat( aFormatSeq[nIdx],
2439 CLOffset + SetIndexTable( NF_DATE_DEF_NNDDMMMYY, ZF_STANDARD_DATE+1 ));
2441 // DD.MM.YY def/System
2442 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2443 ImpInsertFormat( aFormatSeq[nIdx],
2444 CLOffset + SetIndexTable( NF_DATE_SYS_MMYY, ZF_STANDARD_DATE+2 ));
2446 // DD MMM
2447 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2448 ImpInsertFormat( aFormatSeq[nIdx],
2449 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMM, ZF_STANDARD_DATE+3 ));
2451 // MMMM
2452 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2453 ImpInsertFormat( aFormatSeq[nIdx],
2454 CLOffset + SetIndexTable( NF_DATE_MMMM, ZF_STANDARD_DATE+4 ));
2456 // QQ YY
2457 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2458 ImpInsertFormat( aFormatSeq[nIdx],
2459 CLOffset + SetIndexTable( NF_DATE_QQJJ, ZF_STANDARD_DATE+5 ));
2461 // DD.MM.YYYY since number formatter version 2, was DD.MM.[YY]YY
2462 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2463 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2464 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYYYY, ZF_STANDARD_DATE+6 ));
2465 if ( pNewFormat )
2467 pNewFormat->SetUsed(true); // must be saved for older versions
2469 // DD.MM.YY def/System, since number formatter version 6
2470 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2471 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2472 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYY, ZF_STANDARD_DATE+7 ),
2473 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2475 // NNN, D. MMMM YYYY System
2476 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2477 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2478 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2479 CLOffset + SetIndexTable( NF_DATE_SYSTEM_LONG, ZF_STANDARD_DATE+8 ),
2480 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2482 // Hard coded but system (regional settings) delimiters dependent long date formats
2483 // since numberformatter version 6
2485 // D. MMM YY def/System
2486 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2487 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2488 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYY, ZF_STANDARD_DATE+9 ),
2489 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2491 //! Unfortunally TLOT intended only 10 builtin formats per category, more
2492 //! would overwrite the next category (ZF_STANDARD_TIME) :-((
2493 //! Therefore they are inserted with nNewExtended++ (which is also limited)
2495 // D. MMM YYYY def/System
2496 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2497 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2498 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYYYY, nNewExtended++ ),
2499 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2501 // D. MMMM YYYY def/System
2502 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2503 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2504 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMMYYYY, nNewExtended++ ),
2505 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2507 // NN, D. MMM YY def/System
2508 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2509 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2510 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMYY, nNewExtended++ ),
2511 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2513 // NN, D. MMMM YYYY def/System
2514 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2515 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2516 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY, nNewExtended++ ),
2517 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2519 // NNN, D. MMMM YYYY def/System
2520 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY );
2521 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2522 CLOffset + SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY, nNewExtended++ ),
2523 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2525 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2527 // D. MMM. YYYY DIN/EN
2528 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2529 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2530 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMYYYY, nNewExtended++ ),
2531 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2533 // D. MMMM YYYY DIN/EN
2534 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2535 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2536 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMMYYYY, nNewExtended++ ),
2537 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2539 // MM-DD DIN/EN
2540 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2541 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2542 CLOffset + SetIndexTable( NF_DATE_DIN_MMDD, nNewExtended++ ),
2543 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2545 // YY-MM-DD DIN/EN
2546 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2547 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2548 CLOffset + SetIndexTable( NF_DATE_DIN_YYMMDD, nNewExtended++ ),
2549 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2551 // YYYY-MM-DD DIN/EN
2552 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2553 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2554 CLOffset + SetIndexTable( NF_DATE_DIN_YYYYMMDD, nNewExtended++ ),
2555 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2559 // Time
2560 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::TIME );
2561 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2563 // HH:MM
2564 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2565 ImpInsertFormat( aFormatSeq[nIdx],
2566 CLOffset + SetIndexTable( NF_TIME_HHMM, ZF_STANDARD_TIME ));
2568 // HH:MM:SS
2569 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2570 ImpInsertFormat( aFormatSeq[nIdx],
2571 CLOffset + SetIndexTable( NF_TIME_HHMMSS, ZF_STANDARD_TIME+1 ));
2573 // HH:MM AM/PM
2574 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2575 ImpInsertFormat( aFormatSeq[nIdx],
2576 CLOffset + SetIndexTable( NF_TIME_HHMMAMPM, ZF_STANDARD_TIME+2 ));
2578 // HH:MM:SS AM/PM
2579 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2580 ImpInsertFormat( aFormatSeq[nIdx],
2581 CLOffset + SetIndexTable( NF_TIME_HHMMSSAMPM, ZF_STANDARD_TIME+3 ));
2583 // [HH]:MM:SS
2584 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2585 ImpInsertFormat( aFormatSeq[nIdx],
2586 CLOffset + SetIndexTable( NF_TIME_HH_MMSS, ZF_STANDARD_TIME+4 ));
2588 // MM:SS,00
2589 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2590 ImpInsertFormat( aFormatSeq[nIdx],
2591 CLOffset + SetIndexTable( NF_TIME_MMSS00, ZF_STANDARD_TIME+5 ));
2593 // [HH]:MM:SS,00
2594 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2595 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2596 CLOffset + SetIndexTable( NF_TIME_HH_MMSS00, ZF_STANDARD_TIME+6 ),
2597 SV_NUMBERFORMATTER_VERSION_NF_TIME_HH_MMSS00 );
2601 // DateTime
2602 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME );
2603 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2605 // DD.MM.YY HH:MM System
2606 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM );
2607 ImpInsertFormat( aFormatSeq[nIdx],
2608 CLOffset + SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM, ZF_STANDARD_DATETIME ));
2610 // DD.MM.YYYY HH:MM:SS System
2611 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2612 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2613 CLOffset + SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, ZF_STANDARD_DATETIME+1 ),
2614 SV_NUMBERFORMATTER_VERSION_NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2618 // Scientific number
2619 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER );
2620 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2622 // 0.00E+000
2623 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2624 ImpInsertFormat( aFormatSeq[nIdx],
2625 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E000, ZF_STANDARD_SCIENTIFIC ));
2627 // 0.00E+00
2628 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2629 ImpInsertFormat( aFormatSeq[nIdx],
2630 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E00, ZF_STANDARD_SCIENTIFIC+1 ));
2634 // Fraction number (no default option)
2635 i18n::NumberFormatCode aSingleFormatCode;
2636 aSingleFormatCode.Usage = i18n::KNumberFormatUsage::FRACTION_NUMBER;
2638 // # ?/?
2639 aSingleFormatCode.Code = "# ?/?";
2640 ImpInsertFormat( aSingleFormatCode,
2641 CLOffset + SetIndexTable( NF_FRACTION_1, ZF_STANDARD_FRACTION ));
2643 // # ??/??
2644 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2645 aSingleFormatCode.Code = "# ?\?/?\?";
2646 ImpInsertFormat( aSingleFormatCode,
2647 CLOffset + SetIndexTable( NF_FRACTION_2, ZF_STANDARD_FRACTION+1 ));
2649 // # ?/4
2650 aSingleFormatCode.Code = "# ?/4";
2651 ImpInsertNewStandardFormat( aSingleFormatCode,
2652 CLOffset + SetIndexTable( NF_FRACTION_3, ZF_STANDARD_FRACTION+2 ),
2653 SV_NUMBERFORMATTER_VERSION_FIXED_FRACTION );
2655 // # ??/100
2656 aSingleFormatCode.Code = "# ?\?/100";
2657 ImpInsertNewStandardFormat( aSingleFormatCode,
2658 CLOffset + SetIndexTable( NF_FRACTION_4, ZF_STANDARD_FRACTION+3 ),
2659 SV_NUMBERFORMATTER_VERSION_FIXED_FRACTION );
2663 // Week of year must be appended here because of nNewExtended
2664 const NfKeywordTable & rKeyword = pFormatScanner->GetKeywords();
2665 aSingleFormatCode.Code = rKeyword[NF_KEY_WW];
2666 ImpInsertNewStandardFormat( aSingleFormatCode,
2667 CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ),
2668 SV_NUMBERFORMATTER_VERSION_NF_DATE_WW );
2671 bIndexTableInitialized = true;
2672 SAL_WARN_IF( nNewExtended > ZF_STANDARD_NEWEXTENDEDMAX, "svl.numbers",
2673 "ImpGenerateFormats: overflow of nNewExtended standard formats" );
2675 // Now all additional format codes provided by I18N, but only if not
2676 // changing SystemCL, then they are appended last after user defined.
2677 if ( !bNoAdditionalFormats )
2679 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, false );
2681 if (bOldConvertMode)
2683 pFormatScanner->SetConvertMode(true);
2688 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset,
2689 NumberFormatCodeWrapper& rNumberFormatCode, bool bAfterChangingSystemCL )
2691 using namespace ::com::sun::star;
2693 SvNumberformat* pStdFormat = GetFormatEntry( CLOffset + ZF_STANDARD );
2694 if ( !pStdFormat )
2696 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2697 return ;
2699 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
2700 rNumberFormatCode.setLocale( GetLanguageTag().getLocale() );
2701 sal_Int32 j;
2703 // All currencies, this time with [$...] which was stripped in
2704 // ImpGenerateFormats for old "automatic" currency formats.
2705 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2706 rNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2707 i18n::NumberFormatCode * pFormatArr = aFormatSeq.getArray();
2708 sal_Int32 nCodes = aFormatSeq.getLength();
2709 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes );
2710 for ( j = 0; j < nCodes; j++ )
2712 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2714 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2715 break; // for
2717 if ( pFormatArr[j].Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
2718 pFormatArr[j].Index != NF_CURRENCY_1000DEC2_CCC )
2719 { // Insert only if not already inserted, but internal index must be
2720 // above so ImpInsertFormat can distinguish it.
2721 sal_Int16 nOrgIndex = pFormatArr[j].Index;
2722 pFormatArr[j].Index = sal::static_int_cast< sal_Int16 >(
2723 pFormatArr[j].Index + nCodes + NF_INDEX_TABLE_ENTRIES);
2724 //! no default on currency
2725 bool bDefault = aFormatSeq[j].Default;
2726 aFormatSeq[j].Default = false;
2727 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2728 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2729 bAfterChangingSystemCL, nOrgIndex ) )
2730 nPos++;
2731 pFormatArr[j].Index = nOrgIndex;
2732 aFormatSeq[j].Default = bDefault;
2736 // all additional format codes provided by I18N that are not old standard index
2737 aFormatSeq = rNumberFormatCode.getAllFormatCodes();
2738 nCodes = aFormatSeq.getLength();
2739 if ( nCodes )
2741 pFormatArr = aFormatSeq.getArray();
2742 // don't check ALL
2743 sal_Int32 nDef = ImpAdjustFormatCodeDefault( pFormatArr, nCodes, false);
2744 // don't have any defaults here
2745 pFormatArr[nDef].Default = false;
2746 for ( j = 0; j < nCodes; j++ )
2748 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2750 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2751 break; // for
2753 if ( pFormatArr[j].Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
2754 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2755 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2756 bAfterChangingSystemCL ) )
2757 nPos++;
2761 pStdFormat->SetLastInsertKey( (sal_uInt16)(nPos - CLOffset) );
2765 void SvNumberFormatter::ImpGetPosCurrFormat(OUStringBuffer& sPosStr, const OUString& rCurrSymbol)
2767 NfCurrencyEntry::CompletePositiveFormatString( sPosStr,
2768 rCurrSymbol, xLocaleData->getCurrPositiveFormat() );
2771 void SvNumberFormatter::ImpGetNegCurrFormat(OUStringBuffer& sNegStr, const OUString& rCurrSymbol)
2773 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
2774 rCurrSymbol, xLocaleData->getCurrNegativeFormat() );
2777 OUString SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex,
2778 LanguageType eLnge,
2779 bool bThousand,
2780 bool IsRed,
2781 sal_uInt16 nPrecision,
2782 sal_uInt16 nAnzLeading)
2784 if (eLnge == LANGUAGE_DONTKNOW)
2786 eLnge = IniLnge;
2788 short eType = GetType(nIndex);
2789 sal_uInt16 i;
2790 ImpGenerateCL(eLnge); // create new standard formats if necessary
2792 utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping());
2793 const sal_Int32 nDigitsInFirstGroup = aGrouping.get();
2794 const OUString& rThSep = GetNumThousandSep();
2796 SvNumberformat* pFormat = GetFormatEntry( nIndex );
2798 OUStringBuffer sString;
2799 using comphelper::string::padToLength;
2801 if (nAnzLeading == 0)
2803 if (!bThousand)
2804 sString.append('#');
2805 else
2807 sString.append('#');
2808 sString.append(rThSep);
2809 padToLength(sString, sString.getLength() + nDigitsInFirstGroup, '#');
2812 else
2814 for (i = 0; i < nAnzLeading; i++)
2816 if (bThousand && i > 0 && i == aGrouping.getPos())
2818 sString.insert(0, rThSep);
2819 aGrouping.advance();
2821 sString.insert(0, '0');
2823 if (bThousand && nAnzLeading < nDigitsInFirstGroup + 1)
2825 for (i = nAnzLeading; i < nDigitsInFirstGroup + 1; i++)
2827 if (bThousand && i % nDigitsInFirstGroup == 0)
2828 sString.insert(0, rThSep);
2829 sString.insert(0, '#');
2833 if (nPrecision > 0)
2835 sString.append(GetNumDecimalSep());
2836 padToLength(sString, sString.getLength() + nPrecision, '0');
2838 if (eType == NUMBERFORMAT_PERCENT)
2840 sString.append('%');
2842 else if (eType == NUMBERFORMAT_CURRENCY)
2844 OUStringBuffer sNegStr(sString);
2845 String aCurr;
2846 const NfCurrencyEntry* pEntry;
2847 bool bBank;
2848 if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
2850 if ( pEntry )
2852 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2853 xLocaleData->getCurrPositiveFormat(),
2854 pEntry->GetPositiveFormat(), bBank );
2855 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2856 xLocaleData->getCurrNegativeFormat(),
2857 pEntry->GetNegativeFormat(), bBank );
2858 pEntry->CompletePositiveFormatString( sString, bBank, nPosiForm );
2859 pEntry->CompleteNegativeFormatString( sNegStr, bBank, nNegaForm );
2861 else
2862 { // assume currency abbreviation (AKA banking symbol), not symbol
2863 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2864 xLocaleData->getCurrPositiveFormat(),
2865 xLocaleData->getCurrPositiveFormat(), true );
2866 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2867 xLocaleData->getCurrNegativeFormat(),
2868 xLocaleData->getCurrNegativeFormat(), true );
2869 NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr, nPosiForm );
2870 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr, nNegaForm );
2873 else
2874 { // "automatic" old style
2875 OUString aSymbol, aAbbrev;
2876 GetCompatibilityCurrency( aSymbol, aAbbrev );
2877 ImpGetPosCurrFormat( sString, aSymbol );
2878 ImpGetNegCurrFormat( sNegStr, aSymbol );
2880 if (IsRed)
2882 sString.append(';');
2883 sString.append('[');
2884 sString.append(pFormatScanner->GetRedString());
2885 sString.append(']');
2887 else
2889 sString.append(';');
2891 sString.append(sNegStr.makeStringAndClear());
2893 if (eType != NUMBERFORMAT_CURRENCY)
2895 bool insertBrackets = false;
2896 if ( eType != NUMBERFORMAT_UNDEFINED)
2898 insertBrackets = pFormat->IsNegativeInBracket();
2900 if (IsRed || insertBrackets)
2902 OUStringBuffer sTmpStr(sString);
2904 if ( pFormat->HasPositiveBracketPlaceholder() )
2906 sTmpStr.append('_');
2907 sTmpStr.append(')');
2909 sTmpStr.append(';');
2911 if (IsRed)
2913 sTmpStr.append('[');
2914 sTmpStr.append(pFormatScanner->GetRedString());
2915 sTmpStr.append(']');
2918 if (insertBrackets)
2920 sTmpStr.append('(');
2921 sTmpStr.append(sString.toString());
2922 sTmpStr.append(')');
2924 else
2926 sTmpStr.append('-');
2927 sTmpStr.append(sString.toString());
2929 sString = sTmpStr;
2932 return sString.makeStringAndClear();
2935 bool SvNumberFormatter::IsUserDefined(const OUString& sStr,
2936 LanguageType eLnge)
2938 if (eLnge == LANGUAGE_DONTKNOW)
2940 eLnge = IniLnge;
2942 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
2943 eLnge = ActLnge;
2945 sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
2946 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
2948 return true;
2950 SvNumberformat* pEntry = GetFormatEntry( nKey );
2951 if ( pEntry && ((pEntry->GetType() & NUMBERFORMAT_DEFINED) != 0) )
2953 return true;
2955 return false;
2958 sal_uInt32 SvNumberFormatter::GetEntryKey(const OUString& sStr,
2959 LanguageType eLnge)
2961 if (eLnge == LANGUAGE_DONTKNOW)
2963 eLnge = IniLnge;
2965 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
2966 return ImpIsEntry(sStr, CLOffset, eLnge);
2969 sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge)
2971 if (eLnge == LANGUAGE_DONTKNOW)
2973 eLnge = IniLnge;
2975 return GetStandardFormat(NUMBERFORMAT_NUMBER, eLnge);
2978 short SvNumberFormatter::GetType(sal_uInt32 nFIndex)
2980 short eType;
2981 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
2982 if (!pFormat)
2984 eType = NUMBERFORMAT_UNDEFINED;
2986 else
2988 eType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
2989 if (eType == 0)
2991 eType = NUMBERFORMAT_DEFINED;
2994 return eType;
2997 void SvNumberFormatter::ClearMergeTable()
2999 if ( pMergeTable )
3001 pMergeTable->clear();
3005 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
3007 if ( pMergeTable )
3009 ClearMergeTable();
3011 else
3013 pMergeTable = new SvNumberFormatterIndexTable;
3016 sal_uInt32 nCLOffset = 0;
3017 sal_uInt32 nOldKey, nOffset, nNewKey;
3018 SvNumberformat* pNewEntry;
3020 SvNumberFormatTable::iterator it = rTable.aFTable.begin();
3021 while (it != rTable.aFTable.end())
3023 SvNumberformat* pFormat = it->second;
3024 nOldKey = it->first;
3025 nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3026 if (nOffset == 0) // 1st format of CL
3028 nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
3030 if (nOffset <= SV_MAX_ANZ_STANDARD_FORMATE) // Std.form.
3032 nNewKey = nCLOffset + nOffset;
3033 if (aFTable.find( nNewKey) == aFTable.end()) // not already present
3035 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
3036 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
3037 if (!aFTable.insert(make_pair( nNewKey, pNewEntry)).second)
3039 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3040 delete pNewEntry;
3043 if (nNewKey != nOldKey) // new index
3045 (*pMergeTable)[nOldKey] = nNewKey;
3048 else // user defined
3050 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
3051 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
3052 nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
3053 nCLOffset,
3054 pFormat->GetLanguage());
3055 if (nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
3057 delete pNewEntry;
3059 else
3061 SvNumberformat* pStdFormat = GetFormatEntry(nCLOffset + ZF_STANDARD);
3062 sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey();
3063 nNewKey = nPos+1;
3064 if (nNewKey - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
3066 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3067 delete pNewEntry;
3069 else if (!aFTable.insert(make_pair( nNewKey, pNewEntry)).second)
3071 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3072 delete pNewEntry;
3074 else
3076 pStdFormat->SetLastInsertKey((sal_uInt16) (nNewKey - nCLOffset));
3079 if (nNewKey != nOldKey) // new index
3081 (*pMergeTable)[nOldKey] = nNewKey;
3084 ++it;
3086 return pMergeTable;
3090 SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap()
3092 if (!HasMergeFmtTbl())
3094 return SvNumberFormatterMergeMap();
3096 SvNumberFormatterMergeMap aMap;
3097 for (SvNumberFormatterIndexTable::iterator it = pMergeTable->begin(); it != pMergeTable->end(); ++it)
3099 sal_uInt32 nOldKey = it->first;
3100 aMap[ nOldKey ] = it->second;
3102 ClearMergeTable();
3103 return aMap;
3107 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
3108 LanguageType eLnge )
3110 if ( eLnge == LANGUAGE_DONTKNOW )
3112 eLnge = IniLnge;
3114 if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
3116 return nFormat; // it stays as it is
3118 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3119 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3121 return nFormat; // not a built-in format
3123 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3124 return nCLOffset + nOffset;
3128 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
3129 LanguageType eLnge )
3131 if ( nTabOff >= NF_INDEX_TABLE_ENTRIES ||
3132 theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND )
3134 return NUMBERFORMAT_ENTRY_NOT_FOUND;
3136 if ( eLnge == LANGUAGE_DONTKNOW )
3138 eLnge = IniLnge;
3140 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3141 return nCLOffset + theIndexTable[nTabOff];
3145 NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const
3147 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3148 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3150 return NF_INDEX_TABLE_ENTRIES; // not a built-in format
3152 for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
3154 if ( theIndexTable[j] == nOffset )
3156 return (NfIndexTableOffset) j;
3159 return NF_INDEX_TABLE_ENTRIES; // bad luck
3163 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal )
3165 pStringScanner->SetYear2000( nVal );
3169 sal_uInt16 SvNumberFormatter::GetYear2000() const
3171 return pStringScanner->GetYear2000();
3175 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear ) const
3177 if ( nYear < 100 )
3178 return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3179 pStringScanner->GetYear2000() );
3180 return nYear;
3184 // static
3185 sal_uInt16 SvNumberFormatter::GetYear2000Default()
3187 return (sal_uInt16) ::utl::MiscCfg().GetYear2000();
3191 // static
3192 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3194 ::osl::MutexGuard aGuard( GetMutex() );
3195 while ( !bCurrencyTableInitialized )
3196 ImpInitCurrencyTable();
3197 return theCurrencyTable::get();
3201 // static
3202 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3204 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3205 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3206 return nSystemCurrencyPosition ? &rTable[nSystemCurrencyPosition] : NULL;
3210 // static
3211 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3213 if ( eLang == LANGUAGE_SYSTEM )
3215 const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3216 return pCurr ? *pCurr : GetTheCurrencyTable()[0];
3218 else
3220 eLang = MsLangId::getRealLanguage( eLang );
3221 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3222 sal_uInt16 nCount = rTable.size();
3223 for ( sal_uInt16 j = 0; j < nCount; j++ )
3225 if ( rTable[j].GetLanguage() == eLang )
3226 return rTable[j];
3228 return rTable[0];
3233 // static
3234 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(const OUString& rAbbrev, LanguageType eLang )
3236 eLang = MsLangId::getRealLanguage( eLang );
3237 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3238 sal_uInt16 nCount = rTable.size();
3239 for ( sal_uInt16 j = 0; j < nCount; j++ )
3241 if ( rTable[j].GetLanguage() == eLang &&
3242 rTable[j].GetBankSymbol() == rAbbrev )
3244 return &rTable[j];
3247 return NULL;
3251 // static
3252 const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( const OUString& rSymbol,
3253 const OUString& rAbbrev )
3255 if (!bCurrencyTableInitialized)
3257 GetTheCurrencyTable(); // just for initialization
3259 const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get();
3260 sal_uInt16 nCount = rTable.size();
3261 for ( sal_uInt16 j = 0; j < nCount; j++ )
3263 if ( rTable[j].GetSymbol() == rSymbol &&
3264 rTable[j].GetBankSymbol() == rAbbrev )
3266 return &rTable[j];
3269 return NULL;
3273 // static
3274 IMPL_STATIC_LINK_NOINSTANCE( SvNumberFormatter, CurrencyChangeLink, SAL_UNUSED_PARAMETER void*, EMPTYARG )
3276 ::osl::MutexGuard aGuard( GetMutex() );
3277 String aAbbrev;
3278 LanguageType eLang = LANGUAGE_SYSTEM;
3279 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3280 SetDefaultSystemCurrency( aAbbrev, eLang );
3281 return 0;
3285 // static
3286 void SvNumberFormatter::SetDefaultSystemCurrency( const OUString& rAbbrev, LanguageType eLang )
3288 ::osl::MutexGuard aGuard( GetMutex() );
3289 if ( eLang == LANGUAGE_SYSTEM )
3291 eLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3293 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3294 sal_uInt16 nCount = rTable.size();
3295 if ( !rAbbrev.isEmpty() )
3297 for ( sal_uInt16 j = 0; j < nCount; j++ )
3299 if ( rTable[j].GetLanguage() == eLang && rTable[j].GetBankSymbol() == rAbbrev )
3301 nSystemCurrencyPosition = j;
3302 return ;
3306 else
3308 for ( sal_uInt16 j = 0; j < nCount; j++ )
3310 if ( rTable[j].GetLanguage() == eLang )
3312 nSystemCurrencyPosition = j;
3313 return ;
3317 nSystemCurrencyPosition = 0; // not found => simple SYSTEM
3321 void SvNumberFormatter::ResetDefaultSystemCurrency()
3323 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3327 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3329 pStringScanner->InvalidateDateAcceptancePatterns();
3333 sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3335 if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3337 sal_Int32 nCheck;
3338 short nType;
3339 NfWSStringsDtor aCurrList;
3340 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3341 GetCurrencyEntry( LANGUAGE_SYSTEM ), false );
3342 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency System standard format?!?" );
3343 // if already loaded or user defined nDefaultSystemCurrencyFormat
3344 // will be set to the right value
3345 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3346 nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM );
3347 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3348 DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3349 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3351 return nDefaultSystemCurrencyFormat;
3355 sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3357 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3358 DefaultFormatKeysMap::iterator it = aDefaultFormatKeys.find( CLOffset + ZF_STANDARD_CURRENCY );
3359 sal_uInt32 nDefaultCurrencyFormat = (it != aDefaultFormatKeys.end() ?
3360 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
3361 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3363 // look for a defined standard
3364 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3365 sal_uInt32 nKey(0);
3366 SvNumberFormatTable::iterator it2 = aFTable.lower_bound( CLOffset );
3367 while ( it2 != aFTable.end() && (nKey = it2->first) >= CLOffset && nKey < nStopKey )
3369 const SvNumberformat* pEntry = it2->second;
3370 if ( pEntry->IsStandard() && (pEntry->GetType() & NUMBERFORMAT_CURRENCY) )
3372 nDefaultCurrencyFormat = nKey;
3373 break; // while
3375 ++it2;
3378 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3379 { // none found, create one
3380 sal_Int32 nCheck;
3381 NfWSStringsDtor aCurrList;
3382 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3383 GetCurrencyEntry( ActLnge ), false );
3384 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency standard format?" );
3385 if ( !aCurrList.empty() )
3387 // if already loaded or user defined nDefaultSystemCurrencyFormat
3388 // will be set to the right value
3389 short nType;
3390 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3391 nDefaultCurrencyFormat, ActLnge );
3392 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3393 DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3394 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3396 // old automatic currency format as a last resort
3397 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3398 nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3399 else
3400 { // mark as standard so that it is found next time
3401 SvNumberformat* pEntry = GetFormatEntry( nDefaultCurrencyFormat );
3402 if ( pEntry )
3403 pEntry->SetStandard();
3406 aDefaultFormatKeys[ CLOffset + ZF_STANDARD_CURRENCY ] = nDefaultCurrencyFormat;
3408 return nDefaultCurrencyFormat;
3412 // static
3413 // try to make it inline if possible since this a loop body
3414 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
3415 #ifndef DBG_UTIL
3416 inline
3417 #endif
3418 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody( const NfCurrencyEntry*& pFoundEntry, bool& bFoundBank,
3419 const NfCurrencyEntry* pData, sal_uInt16 nPos,
3420 const OUString& rSymbol )
3422 bool bFound;
3423 if ( pData->GetSymbol() == rSymbol )
3425 bFound = true;
3426 bFoundBank = false;
3428 else if ( pData->GetBankSymbol() == rSymbol )
3430 bFound = true;
3431 bFoundBank = true;
3433 else
3434 bFound = false;
3435 if ( bFound )
3437 if ( pFoundEntry && pFoundEntry != pData )
3439 pFoundEntry = NULL;
3440 return false; // break loop, not unique
3442 if ( nPos == 0 )
3443 { // first entry is SYSTEM
3444 pFoundEntry = MatchSystemCurrency();
3445 if ( pFoundEntry )
3447 return false; // break loop
3448 // even if there are more matching entries
3449 // this one is propably the one we are looking for
3451 else
3453 pFoundEntry = pData;
3456 else
3458 pFoundEntry = pData;
3461 return true;
3465 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat, String& rStr,
3466 const NfCurrencyEntry** ppEntry /* = NULL */,
3467 bool* pBank /* = NULL */ ) const
3469 rStr.Erase();
3470 if ( ppEntry )
3471 *ppEntry = NULL;
3472 if ( pBank )
3473 *pBank = false;
3474 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
3475 if ( pFormat )
3477 OUString aSymbol, aExtension;
3478 if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3480 if ( ppEntry )
3482 bool bFoundBank = false;
3483 // we definiteley need an entry matching the format code string
3484 const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3485 bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3486 true );
3487 if ( pFoundEntry )
3489 *ppEntry = pFoundEntry;
3490 if ( pBank )
3491 *pBank = bFoundBank;
3492 rStr = pFoundEntry->BuildSymbolString(bFoundBank);
3495 if ( !rStr.Len() )
3496 { // analog to BuildSymbolString
3497 rStr = '[';
3498 rStr += '$';
3499 if ( aSymbol.indexOf( '-' ) != -1 ||
3500 aSymbol.indexOf( ']' ) != -1 )
3502 rStr += '"';
3503 rStr += aSymbol;
3504 rStr += '"';
3506 else
3507 rStr += aSymbol;
3508 if ( aExtension.getLength() )
3509 rStr += aExtension;
3510 rStr += ']';
3512 return true;
3515 return false;
3519 // static
3520 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank,
3521 const OUString& rSymbol,
3522 const OUString& rExtension,
3523 LanguageType eFormatLanguage,
3524 bool bOnlyStringLanguage )
3526 sal_Int32 nExtLen = rExtension.getLength();
3527 LanguageType eExtLang;
3528 if ( nExtLen )
3530 sal_Int32 nExtLang = rExtension.toInt32( 16 );
3531 if ( !nExtLang )
3533 eExtLang = LANGUAGE_DONTKNOW;
3535 else
3537 eExtLang = (LanguageType) ((nExtLang < 0) ? -nExtLang : nExtLang);
3540 else
3542 eExtLang = LANGUAGE_DONTKNOW;
3544 const NfCurrencyEntry* pFoundEntry = NULL;
3545 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3546 sal_uInt16 nCount = rTable.size();
3547 bool bCont = true;
3549 // first try with given extension language/country
3550 if ( nExtLen )
3552 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3554 LanguageType eLang = rTable[j].GetLanguage();
3555 if ( eLang == eExtLang ||
3556 ((eExtLang == LANGUAGE_DONTKNOW) &&
3557 (eLang == LANGUAGE_SYSTEM)))
3559 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3560 &rTable[j], j, rSymbol );
3565 // ok?
3566 if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3568 return pFoundEntry;
3570 if ( !bOnlyStringLanguage )
3572 // now try the language/country of the number format
3573 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3575 LanguageType eLang = rTable[j].GetLanguage();
3576 if ( eLang == eFormatLanguage ||
3577 ((eFormatLanguage == LANGUAGE_DONTKNOW) &&
3578 (eLang == LANGUAGE_SYSTEM)))
3580 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3581 &rTable[j], j, rSymbol );
3585 // ok?
3586 if ( pFoundEntry || !bCont )
3588 return pFoundEntry;
3592 // then try without language/country if no extension specified
3593 if ( !nExtLen )
3595 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3597 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3598 &rTable[j], j, rSymbol );
3602 return pFoundEntry;
3606 void SvNumberFormatter::GetCompatibilityCurrency( OUString& rSymbol, OUString& rAbbrev ) const
3608 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >
3609 xCurrencies( xLocaleData->getAllCurrencies() );
3611 const ::com::sun::star::i18n::Currency2 *pCurrencies = xCurrencies.getConstArray();
3612 sal_Int32 nCurrencies = xCurrencies.getLength();
3614 sal_Int32 j;
3615 for ( j=0; j < nCurrencies; ++j )
3617 if ( pCurrencies[j].UsedInCompatibleFormatCodes )
3619 rSymbol = pCurrencies[j].Symbol;
3620 rAbbrev = pCurrencies[j].BankSymbol;
3621 break;
3624 if ( j >= nCurrencies )
3626 if (LocaleDataWrapper::areChecksEnabled())
3628 LocaleDataWrapper::outputCheckMessage( xLocaleData->
3629 appendLocaleInfo( "GetCompatibilityCurrency: none?"));
3631 rSymbol = xLocaleData->getCurrSymbol();
3632 rAbbrev = xLocaleData->getCurrBankSymbol();
3637 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
3639 switch ( rCurr.GetPositiveFormat() )
3641 case 0: // $1
3642 case 1: // 1$
3643 case 2: // $ 1
3644 case 3: // 1 $
3645 break;
3646 default:
3647 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3648 break;
3650 switch ( rCurr.GetNegativeFormat() )
3652 case 0: // ($1)
3653 case 1: // -$1
3654 case 2: // $-1
3655 case 3: // $1-
3656 case 4: // (1$)
3657 case 5: // -1$
3658 case 6: // 1-$
3659 case 7: // 1$-
3660 case 8: // -1 $
3661 case 9: // -$ 1
3662 case 10: // 1 $-
3663 case 11: // $ -1
3664 case 12 : // $ 1-
3665 case 13 : // 1- $
3666 case 14 : // ($ 1)
3667 case 15 : // (1 $)
3668 break;
3669 default:
3670 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3671 break;
3675 // static
3676 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang )
3678 // The set is initialized as a side effect of the currency table
3679 // created, make sure that exists, which usually is the case unless a
3680 // SvNumberFormatter was never instanciated.
3681 GetTheCurrencyTable();
3682 const NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3683 return rInstalledLocales.find( eLang) != rInstalledLocales.end();
3686 // static
3687 void SvNumberFormatter::ImpInitCurrencyTable()
3689 // racing condition possible:
3690 // ::osl::MutexGuard aGuard( GetMutex() );
3691 // while ( !bCurrencyTableInitialized )
3692 // ImpInitCurrencyTable();
3693 static bool bInitializing = false;
3694 if ( bCurrencyTableInitialized || bInitializing )
3696 return ;
3698 bInitializing = true;
3700 RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svl", "er93726", "SvNumberFormatter::ImpInitCurrencyTable" );
3702 LanguageType eSysLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3703 LocaleDataWrapper* pLocaleData = new LocaleDataWrapper(
3704 ::comphelper::getProcessComponentContext(),
3705 SvtSysLocale().GetLanguageTag() );
3706 // get user configured currency
3707 String aConfiguredCurrencyAbbrev;
3708 LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
3709 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3710 aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
3711 sal_uInt16 nSecondarySystemCurrencyPosition = 0;
3712 sal_uInt16 nMatchingSystemCurrencyPosition = 0;
3713 NfCurrencyEntry* pEntry;
3715 // first entry is SYSTEM
3716 pEntry = new NfCurrencyEntry( *pLocaleData, LANGUAGE_SYSTEM );
3717 theCurrencyTable::get().insert( theCurrencyTable::get().begin(), pEntry );
3718 sal_uInt16 nCurrencyPos = 1;
3720 ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc =
3721 LocaleDataWrapper::getInstalledLocaleNames();
3722 sal_Int32 nLocaleCount = xLoc.getLength();
3723 RTL_LOGFILE_CONTEXT_TRACE1( aTimeLog, "number of locales: %ld", nLocaleCount );
3724 Locale const * const pLocales = xLoc.getConstArray();
3725 NfCurrencyTable &rCurrencyTable = theCurrencyTable::get();
3726 NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get();
3727 NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3728 sal_uInt16 nLegacyOnlyCurrencyPos = 0;
3729 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
3731 LanguageType eLang = LanguageTag( pLocales[nLocale]).getLanguageType( false);
3732 rInstalledLocales.insert( eLang);
3733 pLocaleData->setLanguageTag( LanguageTag( pLocales[nLocale]) );
3734 Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
3735 sal_Int32 nCurrencyCount = aCurrSeq.getLength();
3736 Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
3738 // one default currency for each locale, insert first so it is found first
3739 sal_Int32 nDefault;
3740 for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3742 if ( pCurrencies[nDefault].Default )
3743 break;
3745 if ( nDefault < nCurrencyCount )
3747 pEntry = new NfCurrencyEntry( pCurrencies[nDefault], *pLocaleData, eLang );
3749 else
3751 pEntry = new NfCurrencyEntry( *pLocaleData, eLang ); // first or ShellsAndPebbles
3753 if (LocaleDataWrapper::areChecksEnabled())
3755 lcl_CheckCurrencySymbolPosition( *pEntry );
3757 rCurrencyTable.insert( rCurrencyTable.begin() + nCurrencyPos++, pEntry );
3758 if ( !nSystemCurrencyPosition && (aConfiguredCurrencyAbbrev.Len() ?
3759 pEntry->GetBankSymbol() == OUString(aConfiguredCurrencyAbbrev) &&
3760 pEntry->GetLanguage() == eConfiguredCurrencyLanguage : false) )
3762 nSystemCurrencyPosition = nCurrencyPos-1;
3764 if ( !nMatchingSystemCurrencyPosition &&
3765 pEntry->GetLanguage() == eSysLang )
3767 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3769 // all remaining currencies for each locale
3770 if ( nCurrencyCount > 1 )
3772 sal_Int32 nCurrency;
3773 for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
3775 if (pCurrencies[nCurrency].LegacyOnly)
3777 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3778 rLegacyOnlyCurrencyTable.insert( rLegacyOnlyCurrencyTable.begin() + nLegacyOnlyCurrencyPos++, pEntry );
3780 else if ( nCurrency != nDefault )
3782 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3783 // no dupes
3784 bool bInsert = true;
3785 sal_uInt16 n = rCurrencyTable.size();
3786 sal_uInt16 aCurrencyIndex = 1; // skip first SYSTEM entry
3787 for ( sal_uInt16 j=1; j<n; j++ )
3789 if ( rCurrencyTable[aCurrencyIndex++] == *pEntry )
3791 bInsert = false;
3792 break; // for
3795 if ( !bInsert )
3797 delete pEntry;
3799 else
3801 rCurrencyTable.insert( rCurrencyTable.begin() + nCurrencyPos++, pEntry );
3802 if ( !nSecondarySystemCurrencyPosition &&
3803 (aConfiguredCurrencyAbbrev.Len() ?
3804 pEntry->GetBankSymbol() == OUString(aConfiguredCurrencyAbbrev) :
3805 pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
3807 nSecondarySystemCurrencyPosition = nCurrencyPos-1;
3809 if ( !nMatchingSystemCurrencyPosition &&
3810 pEntry->GetLanguage() == eSysLang )
3812 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3819 if ( !nSystemCurrencyPosition )
3821 nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
3823 if ((aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3824 LocaleDataWrapper::areChecksEnabled())
3826 LocaleDataWrapper::outputCheckMessage(
3827 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3829 // match SYSTEM if no configured currency found
3830 if ( !nSystemCurrencyPosition )
3832 nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
3834 if ((!aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3835 LocaleDataWrapper::areChecksEnabled())
3837 LocaleDataWrapper::outputCheckMessage(
3838 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3840 delete pLocaleData;
3841 SvtSysLocaleOptions::SetCurrencyChangeLink( STATIC_LINK( NULL, SvNumberFormatter, CurrencyChangeLink ) );
3842 bInitializing = false;
3843 bCurrencyTableInitialized = true;
3847 sal_uInt16 SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr,
3848 const NfCurrencyEntry& rCurr,
3849 bool bBank ) const
3851 OUString aRed = OUStringBuffer().
3852 append('[').
3853 append(pFormatScanner->GetRedString()).
3854 append(']').makeStringAndClear();
3856 sal_uInt16 nDefault = 0;
3857 if ( bBank )
3859 // Only bank symbols.
3860 OUString aPositiveBank = rCurr.BuildPositiveFormatString(true, *xLocaleData, 1);
3861 OUString aNegativeBank = rCurr.BuildNegativeFormatString(true, *xLocaleData, 1 );
3863 OUStringBuffer format1(aPositiveBank);
3864 format1.append(';');
3865 format1.append(aNegativeBank);
3866 rStrArr.push_back(format1.makeStringAndClear());
3868 OUStringBuffer format2(aPositiveBank);
3869 format2.append(';');
3871 format2.append(aRed);
3873 format2.append(aNegativeBank);
3874 rStrArr.push_back(format2.makeStringAndClear());
3876 nDefault = rStrArr.size() - 1;
3878 else
3880 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
3881 // duplicates if no decimals in currency.
3882 OUString aPositive = rCurr.BuildPositiveFormatString(false, *xLocaleData, 1);
3883 OUString aNegative = rCurr.BuildNegativeFormatString(false, *xLocaleData, 1 );
3884 OUStringBuffer format1;
3885 OUStringBuffer format2;
3886 OUStringBuffer format3;
3887 OUStringBuffer format4;
3888 OUStringBuffer format5;
3889 if (rCurr.GetDigits())
3891 OUString aPositiveNoDec = rCurr.BuildPositiveFormatString(false, *xLocaleData, 0);
3892 OUString aNegativeNoDec = rCurr.BuildNegativeFormatString(false, *xLocaleData, 0 );
3893 OUString aPositiveDashed = rCurr.BuildPositiveFormatString(false, *xLocaleData, 2);
3894 OUString aNegativeDashed = rCurr.BuildNegativeFormatString(false, *xLocaleData, 2);
3896 format1.append(aPositiveNoDec);
3897 format1.append(';');
3898 format1.append(aNegativeNoDec);
3900 format3.append(aPositiveNoDec);
3901 format3.append(';');
3902 format3.append(aRed);
3903 format3.append(aNegativeNoDec);
3905 format5.append(aPositiveDashed);
3906 format5.append(';');
3907 format5.append(aRed);
3908 format5.append(aNegativeDashed);
3911 format2.append(aPositive);
3912 format2.append(';');
3913 format2.append(aNegative);
3915 format4.append(aPositive);
3916 format4.append(';');
3917 format4.append(aRed);
3918 format4.append(aNegative);
3920 if (rCurr.GetDigits())
3922 rStrArr.push_back(format1.makeStringAndClear());
3924 rStrArr.push_back(format2.makeStringAndClear());
3925 if (rCurr.GetDigits())
3927 rStrArr.push_back(format3.makeStringAndClear());
3929 rStrArr.push_back(format4.makeStringAndClear());
3930 nDefault = rStrArr.size() - 1;
3931 if (rCurr.GetDigits())
3933 rStrArr.push_back(format5.makeStringAndClear());
3936 return nDefault;
3940 //--- NfCurrencyEntry ----------------------------------------------------
3943 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3945 aSymbol = rLocaleData.getCurrSymbol();
3946 aBankSymbol = rLocaleData.getCurrBankSymbol();
3947 eLanguage = eLang;
3948 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3949 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3950 nDigits = rLocaleData.getCurrDigits();
3951 cZeroChar = rLocaleData.getCurrZeroChar();
3955 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency & rCurr,
3956 const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3958 aSymbol = rCurr.Symbol;
3959 aBankSymbol = rCurr.BankSymbol;
3960 eLanguage = eLang;
3961 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3962 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3963 nDigits = rCurr.DecimalPlaces;
3964 cZeroChar = rLocaleData.getCurrZeroChar();
3968 bool NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
3970 return aSymbol == r.aSymbol
3971 && aBankSymbol == r.aBankSymbol
3972 && eLanguage == r.eLanguage
3976 OUString NfCurrencyEntry::BuildSymbolString(bool bBank,
3977 bool bWithoutExtension) const
3979 OUStringBuffer aBuf("[$");
3980 if (bBank)
3982 aBuf.append(aBankSymbol);
3984 else
3986 if ( aSymbol.indexOf( (sal_Unicode)'-' ) >= 0 ||
3987 aSymbol.indexOf( (sal_Unicode)']' ) >= 0)
3989 aBuf.append('"').append(aSymbol).append('"');
3991 else
3993 aBuf.append(aSymbol);
3995 if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
3997 sal_Int32 nLang = static_cast<sal_Int32>(eLanguage);
3998 aBuf.append('-').append( OUString::valueOf(nLang, 16).toAsciiUpperCase());
4001 aBuf.append(']');
4002 return aBuf.makeStringAndClear();
4005 OUString NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper& rLoc,
4006 sal_uInt16 nDecimalFormat) const
4008 OUStringBuffer aBuf;
4009 aBuf.append('#').append(rLoc.getNumThousandSep()).append("##0");
4010 if (nDecimalFormat && nDigits)
4012 aBuf.append(rLoc.getNumDecimalSep());
4013 sal_Unicode cDecimalChar = nDecimalFormat == 2 ? '-' : cZeroChar;
4014 for (sal_uInt16 i = 0; i < nDigits; ++i)
4016 aBuf.append(cDecimalChar);
4019 return aBuf.makeStringAndClear();
4023 OUString NfCurrencyEntry::BuildPositiveFormatString(bool bBank, const LocaleDataWrapper& rLoc,
4024 sal_uInt16 nDecimalFormat) const
4026 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4027 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( rLoc.getCurrPositiveFormat(),
4028 nPositiveFormat, bBank );
4029 CompletePositiveFormatString(sBuf, bBank, nPosiForm);
4030 return sBuf.makeStringAndClear();
4034 OUString NfCurrencyEntry::BuildNegativeFormatString(bool bBank,
4035 const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
4037 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4038 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc.getCurrNegativeFormat(),
4039 nNegativeFormat, bBank );
4040 CompleteNegativeFormatString(sBuf, bBank, nNegaForm);
4041 return sBuf.makeStringAndClear();
4045 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, bool bBank,
4046 sal_uInt16 nPosiForm) const
4048 OUString aSymStr = BuildSymbolString(bBank);
4049 NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
4053 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr, bool bBank,
4054 sal_uInt16 nNegaForm) const
4056 OUString aSymStr = BuildSymbolString(bBank);
4057 NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
4061 // static
4062 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, const OUString& rSymStr,
4063 sal_uInt16 nPositiveFormat)
4065 switch( nPositiveFormat )
4067 case 0: // $1
4068 rStr.insert(0, rSymStr);
4069 break;
4070 case 1: // 1$
4071 rStr.append(rSymStr);
4072 break;
4073 case 2: // $ 1
4075 rStr.insert(0, ' ');
4076 rStr.insert(0, rSymStr);
4078 break;
4079 case 3: // 1 $
4081 rStr.append(' ');
4082 rStr.append(rSymStr);
4084 break;
4085 default:
4086 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4087 break;
4092 // static
4093 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr,
4094 const OUString& rSymStr,
4095 sal_uInt16 nNegativeFormat)
4097 switch( nNegativeFormat )
4099 case 0: // ($1)
4101 rStr.insert(0, rSymStr);
4102 rStr.insert(0, '(');
4103 rStr.append(')');
4105 break;
4106 case 1: // -$1
4108 rStr.insert(0, rSymStr);
4109 rStr.insert(0, '-');
4111 break;
4112 case 2: // $-1
4114 rStr.insert(0, '-');
4115 rStr.insert(0, rSymStr);
4117 break;
4118 case 3: // $1-
4120 rStr.insert(0, rSymStr);
4121 rStr.append('-');
4123 break;
4124 case 4: // (1$)
4126 rStr.insert(0, '(');
4127 rStr.append(rSymStr);
4128 rStr.append(')');
4130 break;
4131 case 5: // -1$
4133 rStr.append(rSymStr);
4134 rStr.insert(0, '-');
4136 break;
4137 case 6: // 1-$
4139 rStr.append('-');
4140 rStr.append(rSymStr);
4142 break;
4143 case 7: // 1$-
4145 rStr.append(rSymStr);
4146 rStr.append('-');
4148 break;
4149 case 8: // -1 $
4151 rStr.append(' ');
4152 rStr.append(rSymStr);
4153 rStr.insert(0, '-');
4155 break;
4156 case 9: // -$ 1
4158 rStr.insert(0, ' ');
4159 rStr.insert(0, rSymStr);
4160 rStr.insert(0, '-');
4162 break;
4163 case 10: // 1 $-
4165 rStr.append(' ');
4166 rStr.append(rSymStr);
4167 rStr.append('-');
4169 break;
4170 case 11: // $ -1
4172 String aTmp( rSymStr );
4173 aTmp += ' ';
4174 aTmp += '-';
4175 rStr.insert(0, aTmp);
4177 break;
4178 case 12 : // $ 1-
4180 rStr.insert(0, ' ');
4181 rStr.insert(0, rSymStr);
4182 rStr.append('-');
4184 break;
4185 case 13 : // 1- $
4187 rStr.append('-');
4188 rStr.append(' ');
4189 rStr.append(rSymStr);
4191 break;
4192 case 14 : // ($ 1)
4194 rStr.insert(0, ' ');
4195 rStr.insert(0, rSymStr);
4196 rStr.insert(0, '(');
4197 rStr.append(')');
4199 break;
4200 case 15 : // (1 $)
4202 rStr.insert(0, '(');
4203 rStr.append(' ');
4204 rStr.append(rSymStr);
4205 rStr.append(')');
4207 break;
4208 default:
4209 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4210 break;
4215 // static
4216 sal_uInt16 NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat,
4217 sal_uInt16 nCurrFormat, bool bBank )
4219 if ( bBank )
4221 #if NF_BANKSYMBOL_FIX_POSITION
4222 (void) nIntlFormat; // avoid warnings
4223 return 3;
4224 #else
4225 switch ( nIntlFormat )
4227 case 0: // $1
4228 nIntlFormat = 2; // $ 1
4229 break;
4230 case 1: // 1$
4231 nIntlFormat = 3; // 1 $
4232 break;
4233 case 2: // $ 1
4234 break;
4235 case 3: // 1 $
4236 break;
4237 default:
4238 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4239 break;
4241 return nIntlFormat;
4242 #endif
4244 else
4245 return nCurrFormat;
4249 //! Call this only if nCurrFormat is really with parentheses!
4250 static sal_uInt16 lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat, sal_uInt16 nCurrFormat )
4252 short nSign = 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4253 switch ( nIntlFormat )
4255 case 0: // ($1)
4256 case 4: // (1$)
4257 case 14 : // ($ 1)
4258 case 15 : // (1 $)
4259 return nCurrFormat;
4260 case 1: // -$1
4261 case 5: // -1$
4262 case 8: // -1 $
4263 case 9: // -$ 1
4264 nSign = 0;
4265 break;
4266 case 2: // $-1
4267 case 6: // 1-$
4268 case 11 : // $ -1
4269 case 13 : // 1- $
4270 nSign = 1;
4271 break;
4272 case 3: // $1-
4273 case 7: // 1$-
4274 case 10: // 1 $-
4275 case 12 : // $ 1-
4276 nSign = 2;
4277 break;
4278 default:
4279 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4280 break;
4283 switch ( nCurrFormat )
4285 case 0: // ($1)
4286 switch ( nSign )
4288 case 0:
4289 return 1; // -$1
4290 case 1:
4291 return 2; // $-1
4292 case 2:
4293 return 3; // $1-
4295 break;
4296 case 4: // (1$)
4297 switch ( nSign )
4299 case 0:
4300 return 5; // -1$
4301 case 1:
4302 return 6; // 1-$
4303 case 2:
4304 return 7; // 1$-
4306 break;
4307 case 14 : // ($ 1)
4308 switch ( nSign )
4310 case 0:
4311 return 9; // -$ 1
4312 case 1:
4313 return 11; // $ -1
4314 case 2:
4315 return 12; // $ 1-
4317 break;
4318 case 15 : // (1 $)
4319 switch ( nSign )
4321 case 0:
4322 return 8; // -1 $
4323 case 1:
4324 return 13; // 1- $
4325 case 2:
4326 return 10; // 1 $-
4328 break;
4330 return nCurrFormat;
4334 // static
4335 sal_uInt16 NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat,
4336 sal_uInt16 nCurrFormat, bool bBank )
4338 if ( bBank )
4340 #if NF_BANKSYMBOL_FIX_POSITION
4341 return 8;
4342 #else
4343 switch ( nIntlFormat )
4345 case 0: // ($1)
4346 // nIntlFormat = 14; // ($ 1)
4347 nIntlFormat = 9; // -$ 1
4348 break;
4349 case 1: // -$1
4350 nIntlFormat = 9; // -$ 1
4351 break;
4352 case 2: // $-1
4353 nIntlFormat = 11; // $ -1
4354 break;
4355 case 3: // $1-
4356 nIntlFormat = 12; // $ 1-
4357 break;
4358 case 4: // (1$)
4359 // nIntlFormat = 15; // (1 $)
4360 nIntlFormat = 8; // -1 $
4361 break;
4362 case 5: // -1$
4363 nIntlFormat = 8; // -1 $
4364 break;
4365 case 6: // 1-$
4366 nIntlFormat = 13; // 1- $
4367 break;
4368 case 7: // 1$-
4369 nIntlFormat = 10; // 1 $-
4370 break;
4371 case 8: // -1 $
4372 break;
4373 case 9: // -$ 1
4374 break;
4375 case 10: // 1 $-
4376 break;
4377 case 11: // $ -1
4378 break;
4379 case 12 : // $ 1-
4380 break;
4381 case 13 : // 1- $
4382 break;
4383 case 14 : // ($ 1)
4384 // nIntlFormat = 14; // ($ 1)
4385 nIntlFormat = 9; // -$ 1
4386 break;
4387 case 15 : // (1 $)
4388 // nIntlFormat = 15; // (1 $)
4389 nIntlFormat = 8; // -1 $
4390 break;
4391 default:
4392 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4393 break;
4395 #endif
4397 else if ( nIntlFormat != nCurrFormat )
4399 switch ( nCurrFormat )
4401 case 0: // ($1)
4402 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4403 nIntlFormat, nCurrFormat );
4404 break;
4405 case 1: // -$1
4406 nIntlFormat = nCurrFormat;
4407 break;
4408 case 2: // $-1
4409 nIntlFormat = nCurrFormat;
4410 break;
4411 case 3: // $1-
4412 nIntlFormat = nCurrFormat;
4413 break;
4414 case 4: // (1$)
4415 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4416 nIntlFormat, nCurrFormat );
4417 break;
4418 case 5: // -1$
4419 nIntlFormat = nCurrFormat;
4420 break;
4421 case 6: // 1-$
4422 nIntlFormat = nCurrFormat;
4423 break;
4424 case 7: // 1$-
4425 nIntlFormat = nCurrFormat;
4426 break;
4427 case 8: // -1 $
4428 nIntlFormat = nCurrFormat;
4429 break;
4430 case 9: // -$ 1
4431 nIntlFormat = nCurrFormat;
4432 break;
4433 case 10: // 1 $-
4434 nIntlFormat = nCurrFormat;
4435 break;
4436 case 11: // $ -1
4437 nIntlFormat = nCurrFormat;
4438 break;
4439 case 12 : // $ 1-
4440 nIntlFormat = nCurrFormat;
4441 break;
4442 case 13 : // 1- $
4443 nIntlFormat = nCurrFormat;
4444 break;
4445 case 14 : // ($ 1)
4446 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4447 nIntlFormat, nCurrFormat );
4448 break;
4449 case 15 : // (1 $)
4450 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4451 nIntlFormat, nCurrFormat );
4452 break;
4453 default:
4454 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4455 break;
4458 return nIntlFormat;
4462 // we only support default encodings here
4463 // static
4464 sal_Char NfCurrencyEntry::GetEuroSymbol( rtl_TextEncoding eTextEncoding )
4466 switch ( eTextEncoding )
4468 case RTL_TEXTENCODING_MS_1252 : // WNT Ansi
4469 case RTL_TEXTENCODING_ISO_8859_1 : // UNX for use with TrueType fonts
4470 return '\x80';
4471 case RTL_TEXTENCODING_ISO_8859_15 : // UNX real
4472 return '\xA4';
4473 case RTL_TEXTENCODING_IBM_850 : // OS2
4474 return '\xD5';
4475 case RTL_TEXTENCODING_APPLE_ROMAN : // MAC
4476 return '\xDB';
4477 default: // default system
4478 #if defined(WNT)
4479 return '\x80';
4480 #elif defined(UNX)
4481 // return '\xA4'; // #56121# 0xA4 would be correct for iso-8859-15
4482 return '\x80'; // but Windows code for the converted TrueType fonts
4483 #else
4484 #error EuroSymbol is what?
4485 return '\x80';
4486 #endif
4492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */