GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / svl / source / numbers / zforlist.cxx
blobaccc55722a00cac1a4f2984e015915cf732f6729
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/instance.hxx>
44 #include <rtl/strbuf.hxx>
46 #include <math.h>
47 #include <limits>
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::uno;
51 using namespace ::com::sun::star::i18n;
52 using namespace ::com::sun::star::lang;
53 using namespace ::std;
55 // Constants for type offsets per Country/Language (CL)
56 #define ZF_STANDARD 0
57 #define ZF_STANDARD_PERCENT 10
58 #define ZF_STANDARD_CURRENCY 20
59 #define ZF_STANDARD_DATE 30
60 #define ZF_STANDARD_TIME 40
61 #define ZF_STANDARD_DATETIME 50
62 #define ZF_STANDARD_SCIENTIFIC 60
63 #define ZF_STANDARD_FRACTION 70
64 #define ZF_STANDARD_NEWEXTENDED 75
65 #define ZF_STANDARD_NEWEXTENDEDMAX SV_MAX_ANZ_STANDARD_FORMATE-2 // 98
66 #define ZF_STANDARD_LOGICAL SV_MAX_ANZ_STANDARD_FORMATE-1 // 99
67 #define ZF_STANDARD_TEXT SV_MAX_ANZ_STANDARD_FORMATE // 100
69 /* Locale that is set if an unknown locale (from another system) is loaded of
70 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
71 * (old currency) is recognized as a date (#53155#). */
72 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
74 struct IndexTable
76 bool mbInitialized;
77 sal_uInt32 maData[NF_INDEX_TABLE_ENTRIES];
78 osl::Mutex maMtx;
80 IndexTable() : mbInitialized(false) {}
83 static IndexTable theIndexTable;
85 // ====================================================================
87 /**
88 instead of every number formatter being a listener we have a registry which
89 also handles one instance of the SysLocale options
92 typedef ::std::vector< SvNumberFormatter* > SvNumberFormatterList_impl;
94 class SvNumberFormatterRegistry_Impl : public utl::ConfigurationListener
96 SvNumberFormatterList_impl aFormatters;
97 SvtSysLocaleOptions aSysLocaleOptions;
98 LanguageType eSysLanguage;
100 public:
101 SvNumberFormatterRegistry_Impl();
102 virtual ~SvNumberFormatterRegistry_Impl();
104 void Insert( SvNumberFormatter* pThis )
105 { aFormatters.push_back( pThis ); }
107 SvNumberFormatter* Remove( SvNumberFormatter* pThis );
109 size_t Count()
110 { return aFormatters.size(); }
112 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 );
115 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
117 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
118 aSysLocaleOptions.AddListener( this );
122 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
124 aSysLocaleOptions.RemoveListener( this );
128 SvNumberFormatter* SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter* pThis )
130 for (SvNumberFormatterList_impl::iterator it = aFormatters.begin();
131 it != aFormatters.end(); ++it)
133 if ( *it == pThis )
135 aFormatters.erase( it );
136 break;
139 return pThis;
142 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*,
143 sal_uInt32 nHint)
145 ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() );
147 if ( nHint & SYSLOCALEOPTIONS_HINT_LOCALE )
149 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
150 aFormatters[ i ]->ReplaceSystemCL( eSysLanguage );
151 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
153 if ( nHint & SYSLOCALEOPTIONS_HINT_CURRENCY )
155 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
156 aFormatters[ i ]->ResetDefaultSystemCurrency();
158 if ( nHint & SYSLOCALEOPTIONS_HINT_DATEPATTERNS )
160 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
161 aFormatters[ i ]->InvalidateDateAcceptancePatterns();
166 // ====================================================================
168 SvNumberFormatterRegistry_Impl* SvNumberFormatter::pFormatterRegistry = NULL;
169 bool SvNumberFormatter::bCurrencyTableInitialized = false;
170 namespace
172 struct theCurrencyTable :
173 public rtl::Static< NfCurrencyTable, theCurrencyTable > {};
175 struct theLegacyOnlyCurrencyTable :
176 public rtl::Static< NfCurrencyTable, theLegacyOnlyCurrencyTable > {};
178 /** THE set of installed locales. */
179 struct theInstalledLocales :
180 public rtl::Static< NfInstalledLocales, theInstalledLocales> {};
183 sal_uInt16 SvNumberFormatter::nSystemCurrencyPosition = 0;
185 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
186 // language dependent.
187 #define NF_BANKSYMBOL_FIX_POSITION 1
190 /***********************Funktionen SvNumberFormatter**************************/
192 const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION = ::std::numeric_limits<sal_uInt16>::max();
193 const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1;
195 SvNumberFormatter::SvNumberFormatter( const Reference< XComponentContext >& rxContext,
196 LanguageType eLang )
197 : m_xContext( rxContext )
198 , maLanguageTag( eLang)
200 ImpConstruct( eLang );
204 SvNumberFormatter::~SvNumberFormatter()
207 ::osl::MutexGuard aGuard( GetMutex() );
208 pFormatterRegistry->Remove( this );
209 if ( !pFormatterRegistry->Count() )
211 delete pFormatterRegistry;
212 pFormatterRegistry = NULL;
216 for (SvNumberFormatTable::iterator it = aFTable.begin(); it != aFTable.end(); ++it)
217 delete it->second;
218 delete pFormatTable;
219 delete pCharClass;
220 delete pStringScanner;
221 delete pFormatScanner;
222 ClearMergeTable();
223 delete pMergeTable;
227 void SvNumberFormatter::ImpConstruct( LanguageType eLang )
229 if ( eLang == LANGUAGE_DONTKNOW )
231 eLang = UNKNOWN_SUBSTITUTE;
233 IniLnge = eLang;
234 ActLnge = eLang;
235 eEvalDateFormat = NF_EVALDATEFORMAT_INTL;
236 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
238 maLanguageTag.reset( eLang );
239 pCharClass = new CharClass( m_xContext, maLanguageTag );
240 xLocaleData.init( m_xContext, maLanguageTag );
241 xCalendar.init( m_xContext, maLanguageTag.getLocale() );
242 xTransliteration.init( m_xContext, eLang,
243 ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE );
244 xNatNum.init( m_xContext );
246 // cached locale data items
247 const LocaleDataWrapper* pLoc = GetLocaleData();
248 aDecimalSep = pLoc->getNumDecimalSep();
249 aThousandSep = pLoc->getNumThousandSep();
250 aDateSep = pLoc->getDateSep();
252 pStringScanner = new ImpSvNumberInputScan( this );
253 pFormatScanner = new ImpSvNumberformatScan( this );
254 pFormatTable = NULL;
255 MaxCLOffset = 0;
256 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
257 pMergeTable = NULL;
258 bNoZero = false;
260 ::osl::MutexGuard aGuard( GetMutex() );
261 GetFormatterRegistry().Insert( this );
265 void SvNumberFormatter::ChangeIntl(LanguageType eLnge)
267 if (ActLnge != eLnge)
269 ActLnge = eLnge;
271 maLanguageTag.reset( eLnge );
272 pCharClass->setLanguageTag( maLanguageTag );
273 xLocaleData.changeLocale( maLanguageTag );
274 xCalendar.changeLocale( maLanguageTag.getLocale() );
275 xTransliteration.changeLocale( eLnge );
277 // cached locale data items, initialize BEFORE calling ChangeIntl below
278 const LocaleDataWrapper* pLoc = GetLocaleData();
279 aDecimalSep = pLoc->getNumDecimalSep();
280 aThousandSep = pLoc->getNumThousandSep();
281 aDateSep = pLoc->getDateSep();
283 pFormatScanner->ChangeIntl();
284 pStringScanner->ChangeIntl();
289 // static
290 ::osl::Mutex& SvNumberFormatter::GetMutex()
292 static ::osl::Mutex* pMutex = NULL;
293 if( !pMutex )
295 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
296 if( !pMutex )
298 // #i77768# Due to a static reference in the toolkit lib
299 // we need a mutex that lives longer than the svl library.
300 // Otherwise the dtor would use a destructed mutex!!
301 pMutex = new ::osl::Mutex;
304 return *pMutex;
308 // static
309 SvNumberFormatterRegistry_Impl& SvNumberFormatter::GetFormatterRegistry()
311 ::osl::MutexGuard aGuard( GetMutex() );
312 if ( !pFormatterRegistry )
314 pFormatterRegistry = new SvNumberFormatterRegistry_Impl;
316 return *pFormatterRegistry;
320 Color* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex)
322 if( aColorLink.IsSet() )
324 return (Color*) ( aColorLink.Call( (void*) &nIndex ));
326 else
328 return NULL;
332 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay,
333 sal_uInt16 nMonth,
334 sal_uInt16 nYear)
336 pFormatScanner->ChangeNullDate(nDay, nMonth, nYear);
337 pStringScanner->ChangeNullDate(nDay, nMonth, nYear);
340 Date* SvNumberFormatter::GetNullDate()
342 return pFormatScanner->GetNullDate();
345 void SvNumberFormatter::ChangeStandardPrec(short nPrec)
347 pFormatScanner->ChangeStandardPrec(nPrec);
350 sal_uInt16 SvNumberFormatter::GetStandardPrec()
352 return pFormatScanner->GetStandardPrec();
355 void SvNumberFormatter::ImpChangeSysCL( LanguageType eLnge, bool bNoAdditionalFormats )
357 if (eLnge == LANGUAGE_DONTKNOW)
359 eLnge = UNKNOWN_SUBSTITUTE;
361 if (eLnge != IniLnge)
363 IniLnge = eLnge;
364 ChangeIntl(eLnge);
365 // delete old formats
366 for (SvNumberFormatTable::iterator it = aFTable.begin(); it != aFTable.end(); ++it)
368 delete it->second;
370 aFTable.clear();
371 ImpGenerateFormats( 0, bNoAdditionalFormats ); // new standard formats
373 else if ( bNoAdditionalFormats )
375 // delete additional standard formats
376 sal_uInt32 nKey;
377 SvNumberFormatTable::iterator it = aFTable.find( SV_MAX_ANZ_STANDARD_FORMATE + 1 );
378 while ( it != aFTable.end() &&
379 (nKey = it->first) > SV_MAX_ANZ_STANDARD_FORMATE &&
380 nKey < SV_COUNTRY_LANGUAGE_OFFSET )
382 delete it->second;
383 aFTable.erase( it++ );
389 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage )
391 sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM );
392 if ( nCLOffset > MaxCLOffset )
394 return ; // no SYSTEM entries to replace
396 const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_ANZ_STANDARD_FORMATE;
397 const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
398 sal_uInt32 nKey;
400 // remove old builtin formats
401 SvNumberFormatTable::iterator it = aFTable.find( nCLOffset );
402 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey <= nMaxBuiltin )
404 delete it->second;
405 aFTable.erase( it++ );
408 // move additional and user defined to temporary table
409 SvNumberFormatTable aOldTable;
410 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey < nNextCL )
412 aOldTable[ nKey ] = it->second;
413 aFTable.erase( it++ );
416 // generate new old builtin formats
417 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
418 ActLnge = LANGUAGE_DONTKNOW;
419 ChangeIntl( LANGUAGE_SYSTEM );
420 ImpGenerateFormats( nCLOffset, true );
422 // convert additional and user defined from old system to new system
423 SvNumberformat* pStdFormat = GetFormatEntry( nCLOffset + ZF_STANDARD );
424 sal_uInt32 nLastKey = nMaxBuiltin;
425 pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, true );
426 while ( !aOldTable.empty() )
428 nKey = aOldTable.begin()->first;
429 if ( nLastKey < nKey )
431 nLastKey = nKey;
433 SvNumberformat* pOldEntry = aOldTable.begin()->second;
434 aOldTable.erase( nKey );
435 OUString aString( pOldEntry->GetFormatstring() );
437 // Same as PutEntry() but assures key position even if format code is
438 // a duplicate. Also won't mix up any LastInsertKey.
439 ChangeIntl( eOldLanguage );
440 LanguageType eLge = eOldLanguage; // ConvertMode changes this
441 bool bCheck = false;
442 sal_Int32 nCheckPos = -1;
443 SvNumberformat* pNewEntry = new SvNumberformat( aString, pFormatScanner,
444 pStringScanner, nCheckPos, eLge );
445 if ( nCheckPos != 0 )
447 delete pNewEntry;
449 else
451 short eCheckType = pNewEntry->GetType();
452 if ( eCheckType != NUMBERFORMAT_UNDEFINED )
454 pNewEntry->SetType( eCheckType | NUMBERFORMAT_DEFINED );
456 else
458 pNewEntry->SetType( NUMBERFORMAT_DEFINED );
461 if ( !aFTable.insert( make_pair( nKey, pNewEntry) ).second )
463 delete pNewEntry;
465 else
467 bCheck = true;
470 DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
471 (void)bCheck;
473 delete pOldEntry;
475 pFormatScanner->SetConvertMode(false);
476 pStdFormat->SetLastInsertKey( sal_uInt16(nLastKey - nCLOffset) );
478 // append new system additional formats
479 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
480 GetLanguageTag().getLocale() );
481 ImpGenerateAdditionalFormats( nCLOffset, aNumberFormatCode, true );
485 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const
487 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
489 return pFormat ? pFormat->IsTextFormat() : false;
492 bool SvNumberFormatter::PutEntry(OUString& rString,
493 sal_Int32& nCheckPos,
494 short& nType,
495 sal_uInt32& nKey, // format key
496 LanguageType eLnge)
498 nKey = 0;
499 if (rString.isEmpty()) // empty string
501 nCheckPos = 1; // -> Error
502 return false;
504 if (eLnge == LANGUAGE_DONTKNOW)
506 eLnge = IniLnge;
508 ChangeIntl(eLnge); // change locale if necessary
509 LanguageType eLge = eLnge; // non-const for ConvertMode
510 bool bCheck = false;
511 SvNumberformat* p_Entry = new SvNumberformat(rString,
512 pFormatScanner,
513 pStringScanner,
514 nCheckPos,
515 eLge);
517 if (nCheckPos == 0) // Format ok
518 { // Type comparison:
519 short eCheckType = p_Entry->GetType();
520 if ( eCheckType != NUMBERFORMAT_UNDEFINED)
522 p_Entry->SetType(eCheckType | NUMBERFORMAT_DEFINED);
523 nType = eCheckType;
525 else
527 p_Entry->SetType(NUMBERFORMAT_DEFINED);
528 nType = NUMBERFORMAT_DEFINED;
531 sal_uInt32 CLOffset = ImpGenerateCL(eLge); // create new standard formats if necessary
533 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge);
534 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
536 delete p_Entry;
538 else
540 SvNumberformat* pStdFormat = GetFormatEntry(CLOffset + ZF_STANDARD);
541 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
542 if (nPos+1 - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
544 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
545 delete p_Entry;
547 else if (!aFTable.insert(make_pair( nPos+1,p_Entry)).second)
549 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
550 delete p_Entry;
552 else
554 bCheck = true;
555 nKey = nPos+1;
556 pStdFormat->SetLastInsertKey((sal_uInt16) (nKey-CLOffset));
560 else
562 delete p_Entry;
564 return bCheck;
567 bool SvNumberFormatter::PutandConvertEntry(OUString& rString,
568 sal_Int32& nCheckPos,
569 short& nType,
570 sal_uInt32& nKey,
571 LanguageType eLnge,
572 LanguageType eNewLnge)
574 bool bRes;
575 if (eNewLnge == LANGUAGE_DONTKNOW)
577 eNewLnge = IniLnge;
579 pFormatScanner->SetConvertMode(eLnge, eNewLnge);
580 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
581 pFormatScanner->SetConvertMode(false);
582 return bRes;
585 bool SvNumberFormatter::PutandConvertEntrySystem(OUString& rString,
586 sal_Int32& nCheckPos,
587 short& nType,
588 sal_uInt32& nKey,
589 LanguageType eLnge,
590 LanguageType eNewLnge)
592 bool bRes;
593 if (eNewLnge == LANGUAGE_DONTKNOW)
595 eNewLnge = IniLnge;
597 pFormatScanner->SetConvertMode(eLnge, eNewLnge, true);
598 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
599 pFormatScanner->SetConvertMode(false);
600 return bRes;
603 sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( OUString & rString, LanguageType eLnge,
604 LanguageType eSysLnge, short & rType,
605 bool & rNewInserted, sal_Int32 & rCheckPos )
607 sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
608 rNewInserted = false;
609 rCheckPos = 0;
611 // #62389# empty format string (of Writer) => General standard format
612 if (rString.isEmpty())
614 // nothing
616 else if (eLnge == LANGUAGE_SYSTEM && eSysLnge != SvtSysLocale().GetLanguageTag().getLanguageType())
618 sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge );
619 if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND)
621 nKey = nOrig; // none available, maybe user-defined
623 else
625 nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguageTag().getLanguageType() );
627 if (nKey == nOrig)
629 // Not a builtin format, convert.
630 // The format code string may get modified and adapted to the real
631 // language and wouldn't match eSysLnge anymore, do that on a copy.
632 OUString aTmp( rString);
633 rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType,
634 nKey, eLnge, SvtSysLocale().GetLanguageTag().getLanguageType());
635 if (rCheckPos > 0)
637 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
638 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
642 else
644 nKey = GetEntryKey( rString, eLnge);
645 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
647 rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
648 if (rCheckPos > 0)
650 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
651 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
655 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
657 nKey = GetStandardIndex( eLnge);
659 rType = GetType( nKey);
660 // Convert any (!) old "automatic" currency format to new fixed currency
661 // default format.
662 if ((rType & NUMBERFORMAT_CURRENCY) != 0)
664 const SvNumberformat* pFormat = GetEntry( nKey);
665 if (!pFormat->HasNewCurrency())
667 if (rNewInserted)
669 DeleteEntry( nKey); // don't leave trails of rubbish
670 rNewInserted = false;
672 nKey = GetStandardFormat( NUMBERFORMAT_CURRENCY, eLnge);
675 return nKey;
679 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey)
681 delete aFTable[nKey];
682 aFTable.erase(nKey);
685 bool SvNumberFormatter::Load( SvStream& rStream )
687 LanguageType eSysLang = SvtSysLocale().GetLanguageTag().getLanguageType();
688 SvNumberFormatter* pConverter = NULL;
690 ImpSvNumMultipleReadHeader aHdr( rStream );
691 sal_uInt16 nVersion;
692 rStream >> nVersion;
693 SvNumberformat* pEntry;
694 sal_uInt32 nPos;
695 sal_uInt16 nSysOnStore, eLge, eDummy; // Dummy for compatible format
696 rStream >> nSysOnStore >> eLge; // system language from document
698 SAL_WARN_IF( nVersion < SV_NUMBERFORMATTER_VERSION_CALENDAR, "svl.numbers", "SvNumberFormatter::Load: where does this unsupported old data come from?!?");
700 LanguageType eSaveSysLang = (LanguageType) nSysOnStore;
701 LanguageType eLnge = (LanguageType) eLge;
702 ImpChangeSysCL( eLnge, true );
704 rStream >> nPos;
705 while (nPos != NUMBERFORMAT_ENTRY_NOT_FOUND)
707 rStream >> eDummy >> eLge;
708 eLnge = (LanguageType) eLge;
709 ImpGenerateCL( eLnge, true ); // create new standard formats if necessary
711 sal_uInt32 nOffset = nPos % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
712 bool bUserDefined = (nOffset > SV_MAX_ANZ_STANDARD_FORMATE);
714 pEntry = new SvNumberformat(*pFormatScanner, eLnge);
715 pEntry->Load( rStream, aHdr, NULL, *pStringScanner );
716 if ( !bUserDefined )
718 bUserDefined = (pEntry->GetNewStandardDefined() > SV_NUMBERFORMATTER_VERSION);
720 if ( bUserDefined )
722 LanguageType eLoadSysLang = (eLnge == LANGUAGE_SYSTEM ? eSysLang : eSaveSysLang);
723 if ( eSaveSysLang != eLoadSysLang )
725 // different SYSTEM locale
726 if ( !pConverter )
728 pConverter = new SvNumberFormatter( m_xContext, eSysLang );
730 pEntry->ConvertLanguage( *pConverter, eSaveSysLang, eLoadSysLang, true );
733 if ( nOffset == 0 ) // Standard/General format
735 SvNumberformat* pEnt = GetFormatEntry(nPos);
736 if (pEnt)
738 pEnt->SetLastInsertKey(pEntry->GetLastInsertKey());
741 if (!aFTable.insert(make_pair( nPos, pEntry)).second)
743 SAL_WARN( "svl.numbers", "SvNumberFormatter::Load: dup position");
744 delete pEntry;
746 rStream >> nPos;
749 // as of SV_NUMBERFORMATTER_VERSION_YEAR2000
750 if ( nVersion >= SV_NUMBERFORMATTER_VERSION_YEAR2000 )
752 aHdr.StartEntry();
753 if ( aHdr.BytesLeft() >= sizeof(sal_uInt16) )
755 sal_uInt16 nY2k;
756 rStream >> nY2k;
757 if ( nVersion < SV_NUMBERFORMATTER_VERSION_TWODIGITYEAR && nY2k < 100 )
759 nY2k += 1901; // was before src513e: 29, now: 1930
761 SetYear2000( nY2k );
763 aHdr.EndEntry();
766 if ( pConverter )
768 delete pConverter;
771 // generate additional i18n standard formats for all used locales
772 LanguageType eOldLanguage = ActLnge;
773 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
774 GetLanguageTag().getLocale() );
775 std::vector<sal_uInt16> aList;
776 GetUsedLanguages( aList );
777 for ( std::vector<sal_uInt16>::const_iterator it(aList.begin()); it != aList.end(); ++it )
779 LanguageType eLang = *it;
780 ChangeIntl( eLang );
781 sal_uInt32 CLOffset = ImpGetCLOffset( eLang );
782 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, true );
784 ChangeIntl( eOldLanguage );
786 return rStream.GetError() ? false : true;
789 bool SvNumberFormatter::Save( SvStream& rStream ) const
791 ImpSvNumMultipleWriteHeader aHdr( rStream );
792 // As of 364i we store what SYSTEM locale really was, before it was hard
793 // coded LANGUAGE_SYSTEM.
794 rStream << (sal_uInt16) SV_NUMBERFORMATTER_VERSION;
795 rStream << (sal_uInt16) SvtSysLocale().GetLanguageTag().getLanguageType() << (sal_uInt16) IniLnge;
797 const SvNumberFormatTable* pTable = &aFTable;
798 SvNumberFormatTable::const_iterator it = pTable->begin();
799 while (it != pTable->end())
801 SvNumberformat* pEntry = it->second;
802 // Stored are all marked user defined formats and for each active
803 // (selected) locale the Standard/General format and
804 // NewStandardDefined.
805 if ( pEntry->GetUsed() || (pEntry->GetType() & NUMBERFORMAT_DEFINED) ||
806 pEntry->GetNewStandardDefined() || (it->first % SV_COUNTRY_LANGUAGE_OFFSET == 0) )
808 rStream << it->first
809 << (sal_uInt16) LANGUAGE_SYSTEM
810 << (sal_uInt16) pEntry->GetLanguage();
811 pEntry->Save(rStream, aHdr);
813 ++it;
815 rStream << NUMBERFORMAT_ENTRY_NOT_FOUND; // end marker
817 // as of SV_NUMBERFORMATTER_VERSION_YEAR2000
818 aHdr.StartEntry();
819 rStream << (sal_uInt16) GetYear2000();
820 aHdr.EndEntry();
822 return rStream.GetError() ? false : true;
825 void SvNumberFormatter::GetUsedLanguages( std::vector<sal_uInt16>& rList )
827 rList.clear();
829 sal_uInt32 nOffset = 0;
830 while (nOffset <= MaxCLOffset)
832 SvNumberformat* pFormat = GetFormatEntry(nOffset);
833 if (pFormat)
835 rList.push_back( pFormat->GetLanguage() );
837 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
842 void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords,
843 LanguageType eLang )
845 ChangeIntl( eLang );
846 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
847 for ( sal_uInt16 i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i )
849 rKeywords[i] = rTable[i];
854 OUString SvNumberFormatter::GetKeyword( LanguageType eLnge, sal_uInt16 nIndex )
856 ChangeIntl(eLnge);
857 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
858 if ( nIndex < NF_KEYWORD_ENTRIES_COUNT )
860 return rTable[nIndex];
862 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
863 return OUString();
867 OUString SvNumberFormatter::GetStandardName( LanguageType eLnge )
869 ChangeIntl( eLnge );
870 return pFormatScanner->GetStandardName();
874 sal_uInt32 SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge) const
876 sal_uInt32 nOffset = 0;
877 while (nOffset <= MaxCLOffset)
879 const SvNumberformat* pFormat = GetFormatEntry(nOffset);
880 if (pFormat && pFormat->GetLanguage() == eLnge)
882 return nOffset;
884 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
886 return nOffset;
889 sal_uInt32 SvNumberFormatter::ImpIsEntry(const OUString& rString,
890 sal_uInt32 nCLOffset,
891 LanguageType eLnge)
893 sal_uInt32 res = NUMBERFORMAT_ENTRY_NOT_FOUND;
894 SvNumberFormatTable::iterator it = aFTable.find( nCLOffset);
895 while ( res == NUMBERFORMAT_ENTRY_NOT_FOUND &&
896 it != aFTable.end() && it->second->GetLanguage() == eLnge )
898 if ( rString == it->second->GetFormatstring() )
900 res = it->first;
902 else
904 ++it;
907 return res;
911 SvNumberFormatTable& SvNumberFormatter::GetFirstEntryTable(
912 short& eType,
913 sal_uInt32& FIndex,
914 LanguageType& rLnge)
916 short eTypetmp = eType;
917 if (eType == NUMBERFORMAT_ALL) // empty cell or don't care
919 rLnge = IniLnge;
921 else
923 SvNumberformat* pFormat = GetFormatEntry(FIndex);
924 if (!pFormat)
926 rLnge = IniLnge;
927 eType = NUMBERFORMAT_ALL;
928 eTypetmp = eType;
930 else
932 rLnge = pFormat->GetLanguage();
933 eType = pFormat->GetType()&~NUMBERFORMAT_DEFINED;
934 if (eType == 0)
936 eType = NUMBERFORMAT_DEFINED;
937 eTypetmp = eType;
939 else if (eType == NUMBERFORMAT_DATETIME)
941 eTypetmp = eType;
942 eType = NUMBERFORMAT_DATE;
944 else
946 eTypetmp = eType;
950 ChangeIntl(rLnge);
951 return GetEntryTable(eTypetmp, FIndex, rLnge);
954 sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge, bool bNoAdditionalFormats )
956 ChangeIntl(eLnge);
957 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
958 if (CLOffset > MaxCLOffset)
960 // new CL combination
961 if (LocaleDataWrapper::areChecksEnabled())
963 const LanguageTag& rLoadedLocale = xLocaleData->getLoadedLanguageTag();
964 if ( !rLoadedLocale.equals( maLanguageTag, true) )
966 OUString aMsg("SvNumberFormatter::ImpGenerateCL: locales don't match:");
967 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg ));
969 // test XML locale data FormatElement entries
971 uno::Sequence< i18n::FormatElement > xSeq = xLocaleData->getAllFormats();
972 // A test for completeness of formatindex="0" ...
973 // formatindex="47" is not needed here since it is done in
974 // ImpGenerateFormats().
976 // Test for dupes of formatindex="..."
977 for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ )
979 sal_Int16 nIdx = xSeq[j].formatIndex;
980 OUStringBuffer aDupes;
981 for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ )
983 if ( i != j && xSeq[i].formatIndex == nIdx )
985 aDupes.append(OUString::number( i ));
986 aDupes.append("(");
987 aDupes.append(xSeq[i].formatKey);
988 aDupes.append( ") ");
991 if ( !aDupes.isEmpty() )
993 OUStringBuffer aMsg(aDupes.getLength() + xSeq[j].formatKey.getLength() + 100);
994 aMsg.append("XML locale data FormatElement formatindex dupe: ");
995 aMsg.append(OUString::number(nIdx));
996 aMsg.append("\nFormatElements: ");
997 aMsg.append(OUString::number( j ));
998 aMsg.append("(");
999 aMsg.append( xSeq[j].formatKey );
1000 aMsg.append( ") ");
1001 aMsg.append(aDupes.makeStringAndClear());
1002 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg.makeStringAndClear() ));
1008 MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET;
1009 ImpGenerateFormats( MaxCLOffset, bNoAdditionalFormats );
1010 CLOffset = MaxCLOffset;
1012 return CLOffset;
1015 SvNumberFormatTable& SvNumberFormatter::ChangeCL(short eType,
1016 sal_uInt32& FIndex,
1017 LanguageType eLnge)
1019 ImpGenerateCL(eLnge);
1020 return GetEntryTable(eType, FIndex, ActLnge);
1023 SvNumberFormatTable& SvNumberFormatter::GetEntryTable(
1024 short eType,
1025 sal_uInt32& FIndex,
1026 LanguageType eLnge)
1028 if ( pFormatTable )
1030 pFormatTable->clear();
1032 else
1034 pFormatTable = new SvNumberFormatTable;
1036 ChangeIntl(eLnge);
1037 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1039 // Might generate and insert a default format for the given type
1040 // (e.g. currency) => has to be done before collecting formats.
1041 sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge );
1043 SvNumberFormatTable::iterator it = aFTable.find( CLOffset);
1045 if (eType == NUMBERFORMAT_ALL)
1047 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1048 { // copy all entries to output table
1049 (*pFormatTable)[ it->first ] = it->second;
1050 ++it;
1053 else
1055 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
1056 { // copy entries of queried type to output table
1057 if ((it->second->GetType()) & eType)
1058 (*pFormatTable)[ it->first ] = it->second;
1059 ++it;
1062 if ( !pFormatTable->empty() )
1063 { // select default if queried format doesn't exist or queried type or
1064 // language differ from existing format
1065 SvNumberformat* pEntry = GetFormatEntry(FIndex);
1066 if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge )
1068 FIndex = nDefaultIndex;
1071 return *pFormatTable;
1074 bool SvNumberFormatter::IsNumberFormat(const OUString& sString,
1075 sal_uInt32& F_Index,
1076 double& fOutNumber)
1078 short FType;
1079 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
1080 if (!pFormat)
1082 ChangeIntl(IniLnge);
1083 FType = NUMBERFORMAT_NUMBER;
1085 else
1087 FType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
1088 if (FType == 0)
1090 FType = NUMBERFORMAT_DEFINED;
1092 ChangeIntl(pFormat->GetLanguage());
1095 bool res;
1096 short RType = FType;
1097 if (RType == NUMBERFORMAT_TEXT)
1099 res = false; // type text preset => no conversion to number
1101 else
1103 res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat);
1105 if (res && !IsCompatible(FType, RType)) // non-matching type
1107 switch ( RType )
1109 case NUMBERFORMAT_DATE :
1110 // Preserve ISO 8601 input.
1111 if (pStringScanner->CanForceToIso8601( DMY))
1113 F_Index = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, ActLnge );
1115 else
1117 F_Index = GetStandardFormat( RType, ActLnge );
1119 break;
1120 case NUMBERFORMAT_TIME :
1121 if ( pStringScanner->GetDecPos() )
1123 // 100th seconds
1124 if ( pStringScanner->GetAnzNums() > 3 || fOutNumber < 0.0 )
1126 F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge );
1128 else
1130 F_Index = GetFormatIndex( NF_TIME_MMSS00, ActLnge );
1133 else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 )
1135 F_Index = GetFormatIndex( NF_TIME_HH_MMSS, ActLnge );
1137 else
1139 F_Index = GetStandardFormat( RType, ActLnge );
1141 break;
1142 default:
1143 F_Index = GetStandardFormat( RType, ActLnge );
1146 return res;
1149 bool SvNumberFormatter::IsCompatible(short eOldType,
1150 short eNewType)
1152 if (eOldType == eNewType)
1154 return true;
1156 else if (eOldType == NUMBERFORMAT_DEFINED)
1158 return true;
1160 else
1162 switch (eNewType)
1164 case NUMBERFORMAT_NUMBER:
1165 switch (eOldType)
1167 case NUMBERFORMAT_PERCENT:
1168 case NUMBERFORMAT_CURRENCY:
1169 case NUMBERFORMAT_SCIENTIFIC:
1170 case NUMBERFORMAT_FRACTION:
1171 // case NUMBERFORMAT_LOGICAL:
1172 case NUMBERFORMAT_DEFINED:
1173 return true;
1174 default:
1175 return false;
1177 break;
1178 case NUMBERFORMAT_DATE:
1179 switch (eOldType)
1181 case NUMBERFORMAT_DATETIME:
1182 return true;
1183 default:
1184 return false;
1186 break;
1187 case NUMBERFORMAT_TIME:
1188 switch (eOldType)
1190 case NUMBERFORMAT_DATETIME:
1191 return true;
1192 default:
1193 return false;
1195 break;
1196 case NUMBERFORMAT_DATETIME:
1197 switch (eOldType)
1199 case NUMBERFORMAT_TIME:
1200 case NUMBERFORMAT_DATE:
1201 return true;
1202 default:
1203 return false;
1205 break;
1206 default:
1207 return false;
1213 sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( short nType )
1215 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1216 sal_uInt32 nSearch;
1217 switch( nType )
1219 case NUMBERFORMAT_DATE:
1220 nSearch = CLOffset + ZF_STANDARD_DATE;
1221 break;
1222 case NUMBERFORMAT_TIME:
1223 nSearch = CLOffset + ZF_STANDARD_TIME;
1224 break;
1225 case NUMBERFORMAT_DATETIME:
1226 nSearch = CLOffset + ZF_STANDARD_DATETIME;
1227 break;
1228 case NUMBERFORMAT_PERCENT:
1229 nSearch = CLOffset + ZF_STANDARD_PERCENT;
1230 break;
1231 case NUMBERFORMAT_SCIENTIFIC:
1232 nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1233 break;
1234 default:
1235 nSearch = CLOffset + ZF_STANDARD;
1238 DefaultFormatKeysMap::iterator it = aDefaultFormatKeys.find( nSearch);
1239 sal_uInt32 nDefaultFormat = (it != aDefaultFormatKeys.end() ?
1240 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
1241 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1243 // look for a defined standard
1244 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
1245 sal_uInt32 nKey(0);
1246 SvNumberFormatTable::iterator it2 = aFTable.find( CLOffset );
1247 while ( it2 != aFTable.end() && (nKey = it2->first ) >= CLOffset && nKey < nStopKey )
1249 const SvNumberformat* pEntry = it2->second;
1250 if ( pEntry->IsStandard() && ((pEntry->GetType() &
1251 ~NUMBERFORMAT_DEFINED) == nType) )
1253 nDefaultFormat = nKey;
1254 break; // while
1256 ++it2;
1259 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1260 { // none found, use old fixed standards
1261 switch( nType )
1263 case NUMBERFORMAT_DATE:
1264 nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1265 break;
1266 case NUMBERFORMAT_TIME:
1267 nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1268 break;
1269 case NUMBERFORMAT_DATETIME:
1270 nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1271 break;
1272 case NUMBERFORMAT_PERCENT:
1273 nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1274 break;
1275 case NUMBERFORMAT_SCIENTIFIC:
1276 nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1277 break;
1278 default:
1279 nDefaultFormat = CLOffset + ZF_STANDARD;
1282 aDefaultFormatKeys[ nSearch ] = nDefaultFormat;
1284 return nDefaultFormat;
1288 sal_uInt32 SvNumberFormatter::GetStandardFormat( short eType, LanguageType eLnge )
1290 if (eLnge == LANGUAGE_DONTKNOW)
1292 eLnge = IniLnge;
1294 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1295 switch(eType)
1297 case NUMBERFORMAT_CURRENCY:
1298 return ( eLnge == LANGUAGE_SYSTEM ) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1299 case NUMBERFORMAT_DATE:
1300 case NUMBERFORMAT_TIME:
1301 case NUMBERFORMAT_DATETIME:
1302 case NUMBERFORMAT_PERCENT:
1303 case NUMBERFORMAT_SCIENTIFIC:
1304 return ImpGetDefaultFormat( eType );
1305 case NUMBERFORMAT_FRACTION:
1306 return CLOffset + ZF_STANDARD_FRACTION;
1307 case NUMBERFORMAT_LOGICAL:
1308 return CLOffset + ZF_STANDARD_LOGICAL;
1309 case NUMBERFORMAT_TEXT:
1310 return CLOffset + ZF_STANDARD_TEXT;
1311 case NUMBERFORMAT_ALL:
1312 case NUMBERFORMAT_DEFINED:
1313 case NUMBERFORMAT_NUMBER:
1314 case NUMBERFORMAT_UNDEFINED:
1315 default:
1316 return CLOffset + ZF_STANDARD;
1320 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex,
1321 LanguageType eLnge )
1323 return
1324 nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) ||
1325 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) ||
1326 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge )
1330 sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, short eType,
1331 LanguageType eLnge )
1333 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1334 return nFIndex;
1335 else
1336 return GetStandardFormat( eType, eLnge );
1339 sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex,
1340 short eType, LanguageType eLnge )
1342 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1343 return nFIndex;
1345 switch( eType )
1347 case NUMBERFORMAT_TIME :
1349 bool bSign;
1350 if ( fNumber < 0.0 )
1352 bSign = true;
1353 fNumber = -fNumber;
1355 else
1356 bSign = false;
1357 double fSeconds = fNumber * 86400;
1358 if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) )
1359 { // with 100th seconds
1360 if ( bSign || fSeconds >= 3600 )
1361 return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge );
1362 else
1363 return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1365 else
1367 if ( bSign || fNumber >= 1.0 )
1368 return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1369 else
1370 return GetStandardFormat( eType, eLnge );
1373 default:
1374 return GetStandardFormat( eType, eLnge );
1378 sal_uInt32 SvNumberFormatter::GetEditFormat( double fNumber, sal_uInt32 nFIndex,
1379 short eType, LanguageType eLang,
1380 SvNumberformat* pFormat )
1382 sal_uInt32 nKey = nFIndex;
1383 switch ( eType )
1385 // #61619# always edit using 4-digit year
1386 case NUMBERFORMAT_DATE :
1387 if (rtl::math::approxFloor( fNumber) != fNumber)
1388 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1389 // fdo#34977 preserve time when editing even if only date was
1390 // displayed.
1391 /* FIXME: in case an ISO 8601 format was used, editing should
1392 * also use such. Unfortunately we have no builtin combined
1393 * date+time ISO format defined. Needs also locale data work.
1394 * */
1395 else
1397 // Preserve ISO 8601 format.
1398 if ( nFIndex == GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang) ||
1399 nFIndex == GetFormatIndex( NF_DATE_DIN_YYMMDD, eLang) ||
1400 nFIndex == GetFormatIndex( NF_DATE_DIN_MMDD, eLang) ||
1401 (pFormat && pFormat->IsIso8601( 0 )))
1402 nKey = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang);
1403 else
1404 nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1406 break;
1407 case NUMBERFORMAT_TIME :
1408 if (fNumber < 0.0 || fNumber >= 1.0)
1410 /* XXX NOTE: this is a purely arbitrary value within the limits
1411 * of a signed 16-bit. 32k hours are 3.7 years ... or
1412 * 1903-09-26 if date. */
1413 if (fabs( fNumber) * 24 < 0x7fff)
1414 nKey = GetFormatIndex( NF_TIME_HH_MMSS, eLang );
1415 // Preserve duration, use [HH]:MM:SS instead of time.
1416 else
1417 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1418 // Assume that a large value is a datetime with only time
1419 // displayed.
1421 else
1422 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1423 break;
1424 case NUMBERFORMAT_DATETIME :
1425 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1426 /* FIXME: in case an ISO 8601 format was used, editing should
1427 * also use such. Unfortunately we have no builtin combined
1428 * date+time ISO format defined. Needs also locale data work. */
1429 break;
1430 default:
1431 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1433 return nKey;
1436 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1437 sal_uInt32 nFIndex,
1438 OUString& sOutString)
1440 Color* pColor;
1441 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1442 if (!pFormat)
1444 pFormat = GetFormatEntry(ZF_STANDARD);
1447 LanguageType eLang = pFormat->GetLanguage();
1448 ChangeIntl( eLang );
1450 short eType = pFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1451 if (eType == 0)
1453 eType = NUMBERFORMAT_DEFINED;
1456 sal_uInt16 nOldPrec = pFormatScanner->GetStandardPrec();
1457 bool bPrecChanged = false;
1458 if (eType == NUMBERFORMAT_NUMBER ||
1459 eType == NUMBERFORMAT_PERCENT ||
1460 eType == NUMBERFORMAT_CURRENCY ||
1461 eType == NUMBERFORMAT_SCIENTIFIC ||
1462 eType == NUMBERFORMAT_FRACTION)
1464 if (eType != NUMBERFORMAT_PERCENT) // special treatment of % later
1466 eType = NUMBERFORMAT_NUMBER;
1468 ChangeStandardPrec(INPUTSTRING_PRECISION);
1469 bPrecChanged = true;
1472 sal_uInt32 nKey = GetEditFormat( fOutNumber, nFIndex, eType, eLang, pFormat);
1473 if ( nKey != nFIndex )
1475 pFormat = GetFormatEntry( nKey );
1477 if (pFormat)
1479 if ( eType == NUMBERFORMAT_TIME && pFormat->GetFormatPrecision() )
1481 ChangeStandardPrec(INPUTSTRING_PRECISION);
1482 bPrecChanged = true;
1484 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1486 if (bPrecChanged)
1488 ChangeStandardPrec(nOldPrec);
1492 void SvNumberFormatter::GetOutputString(const OUString& sString,
1493 sal_uInt32 nFIndex,
1494 OUString& sOutString,
1495 Color** ppColor,
1496 bool bUseStarFormat )
1498 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1499 if (!pFormat)
1501 pFormat = GetFormatEntry(ZF_STANDARD_TEXT);
1503 if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1505 *ppColor = NULL;
1506 sOutString = sString;
1508 else
1510 ChangeIntl(pFormat->GetLanguage());
1511 if ( bUseStarFormat )
1513 pFormat->SetStarFormatSupport( true );
1515 pFormat->GetOutputString(sString, sOutString, ppColor);
1516 if ( bUseStarFormat )
1518 pFormat->SetStarFormatSupport( false );
1523 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1524 sal_uInt32 nFIndex,
1525 OUString& sOutString,
1526 Color** ppColor,
1527 bool bUseStarFormat )
1529 if (bNoZero && fOutNumber == 0.0)
1531 sOutString = OUString();
1532 return;
1534 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1535 if (!pFormat)
1536 pFormat = GetFormatEntry(ZF_STANDARD);
1537 ChangeIntl(pFormat->GetLanguage());
1538 if ( bUseStarFormat )
1539 pFormat->SetStarFormatSupport( true );
1540 pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1541 if ( bUseStarFormat )
1542 pFormat->SetStarFormatSupport( false );
1545 bool SvNumberFormatter::GetPreviewString(const OUString& sFormatString,
1546 double fPreviewNumber,
1547 OUString& sOutString,
1548 Color** ppColor,
1549 LanguageType eLnge,
1550 bool bUseStarFormat )
1552 if (sFormatString.isEmpty()) // no empty string
1554 return false;
1556 sal_uInt32 nKey;
1557 if (eLnge == LANGUAGE_DONTKNOW)
1559 eLnge = IniLnge;
1561 ChangeIntl(eLnge); // change locale if necessary
1562 eLnge = ActLnge;
1563 sal_Int32 nCheckPos = -1;
1564 OUString sTmpString = sFormatString;
1565 SvNumberformat* p_Entry = new SvNumberformat(sTmpString,
1566 pFormatScanner,
1567 pStringScanner,
1568 nCheckPos,
1569 eLnge);
1570 if (nCheckPos == 0) // String ok
1572 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
1573 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge);
1574 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
1576 GetOutputString(fPreviewNumber, nKey, sOutString, ppColor, bUseStarFormat);
1578 else
1580 if ( bUseStarFormat )
1582 p_Entry->SetStarFormatSupport( true );
1584 p_Entry->GetOutputString(fPreviewNumber, sOutString, ppColor);
1585 if ( bUseStarFormat )
1587 p_Entry->SetStarFormatSupport( false );
1590 delete p_Entry;
1591 return true;
1593 else
1595 delete p_Entry;
1596 return false;
1600 bool SvNumberFormatter::GetPreviewStringGuess( const OUString& sFormatString,
1601 double fPreviewNumber,
1602 OUString& sOutString,
1603 Color** ppColor,
1604 LanguageType eLnge )
1606 if (sFormatString.isEmpty()) // no empty string
1608 return false;
1610 if (eLnge == LANGUAGE_DONTKNOW)
1612 eLnge = IniLnge;
1614 ChangeIntl( eLnge );
1615 eLnge = ActLnge;
1616 bool bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1618 OUString aFormatStringUpper( pCharClass->uppercase( sFormatString ) );
1619 sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1620 sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1621 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1623 // Zielformat vorhanden
1624 GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1625 return true;
1628 SvNumberformat *pEntry = NULL;
1629 sal_Int32 nCheckPos = -1;
1630 OUString sTmpString;
1632 if ( bEnglish )
1634 sTmpString = sFormatString;
1635 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1636 pStringScanner, nCheckPos, eLnge );
1638 else
1640 nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1641 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1642 bool bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1644 // try english --> other bzw. english nach other konvertieren
1645 LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1646 pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge );
1647 sTmpString = sFormatString;
1648 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1649 pStringScanner, nCheckPos, eFormatLang );
1650 pFormatScanner->SetConvertMode( false );
1651 ChangeIntl( eLnge );
1653 if ( !bEnglishFormat )
1655 if ( !(nCheckPos == 0) || xTransliteration->isEqual( sFormatString,
1656 pEntry->GetFormatstring() ) )
1658 // other Format
1659 delete pEntry;
1660 sTmpString = sFormatString;
1661 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1662 pStringScanner, nCheckPos, eLnge );
1664 else
1666 // verify english
1667 sal_Int32 nCheckPos2 = -1;
1668 // try other --> english
1669 eFormatLang = eLnge;
1670 pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US );
1671 sTmpString = sFormatString;
1672 SvNumberformat* pEntry2 = new SvNumberformat( sTmpString, pFormatScanner,
1673 pStringScanner, nCheckPos2, eFormatLang );
1674 pFormatScanner->SetConvertMode( false );
1675 ChangeIntl( eLnge );
1676 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1677 pEntry2->GetFormatstring() ) )
1679 // other Format
1680 delete pEntry;
1681 sTmpString = sFormatString;
1682 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1683 pStringScanner, nCheckPos, eLnge );
1685 delete pEntry2;
1690 if (nCheckPos == 0) // String ok
1692 ImpGenerateCL( eLnge ); // create new standard formats if necessary
1693 pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1694 delete pEntry;
1695 return true;
1697 delete pEntry;
1698 return false;
1701 bool SvNumberFormatter::GetPreviewString( const OUString& sFormatString,
1702 const OUString& sPreviewString,
1703 OUString& sOutString,
1704 Color** ppColor,
1705 LanguageType eLnge )
1707 if (sFormatString.isEmpty()) // no empty string
1709 return false;
1711 sal_uInt32 nKey;
1712 if (eLnge == LANGUAGE_DONTKNOW)
1714 eLnge = IniLnge;
1716 ChangeIntl(eLnge); // switch if needed
1717 eLnge = ActLnge;
1718 sal_Int32 nCheckPos = -1;
1719 OUString sTmpString = sFormatString;
1720 SvNumberformat* p_Entry = new SvNumberformat( sTmpString,
1721 pFormatScanner,
1722 pStringScanner,
1723 nCheckPos,
1724 eLnge);
1725 if (nCheckPos == 0) // String ok
1727 // May have to create standard formats for this locale.
1728 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1729 nKey = ImpIsEntry( p_Entry->GetFormatstring(), CLOffset, eLnge);
1730 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
1732 GetOutputString( sPreviewString, nKey, sOutString, ppColor);
1734 else
1736 // If the format is valid but not a text format and does not
1737 // include a text subformat, an empty string would result. Same as
1738 // in SvNumberFormatter::GetOutputString()
1739 if (p_Entry->IsTextFormat() || p_Entry->HasTextFormat())
1741 p_Entry->GetOutputString( sPreviewString, sOutString, ppColor);
1743 else
1745 *ppColor = NULL;
1746 sOutString = sPreviewString;
1749 delete p_Entry;
1750 return true;
1752 else
1754 delete p_Entry;
1755 return false;
1759 sal_uInt32 SvNumberFormatter::TestNewString(const OUString& sFormatString,
1760 LanguageType eLnge)
1762 if (sFormatString.isEmpty()) // no empty string
1764 return NUMBERFORMAT_ENTRY_NOT_FOUND;
1766 if (eLnge == LANGUAGE_DONTKNOW)
1768 eLnge = IniLnge;
1770 ChangeIntl(eLnge); // change locale if necessary
1771 eLnge = ActLnge;
1772 sal_uInt32 nRes;
1773 sal_Int32 nCheckPos = -1;
1774 OUString sTmpString = sFormatString;
1775 SvNumberformat* pEntry = new SvNumberformat(sTmpString,
1776 pFormatScanner,
1777 pStringScanner,
1778 nCheckPos,
1779 eLnge);
1780 if (nCheckPos == 0) // String ok
1782 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
1783 nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge);
1784 // already present?
1786 else
1788 nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1790 delete pEntry;
1791 return nRes;
1794 SvNumberformat* SvNumberFormatter::ImpInsertFormat( const ::com::sun::star::i18n::NumberFormatCode& rCode,
1795 sal_uInt32 nPos, bool bAfterChangingSystemCL,
1796 sal_Int16 nOrgIndex )
1798 OUString aCodeStr( rCode.Code );
1799 if ( rCode.Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
1800 rCode.Usage == ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY &&
1801 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1802 { // strip surrounding [$...] on automatic currency
1803 if ( aCodeStr.indexOf( "[$" ) >= 0)
1804 aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr, false );
1805 else
1807 if (LocaleDataWrapper::areChecksEnabled() &&
1808 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1810 OUString aMsg(OUString("SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index ") +
1811 OUString::number( rCode.Index) +
1812 OUString(":\n") +
1813 rCode.Code);
1814 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1818 sal_Int32 nCheckPos = 0;
1819 OUString sTempIn(aCodeStr);
1820 SvNumberformat* pFormat = new SvNumberformat(sTempIn,
1821 pFormatScanner,
1822 pStringScanner,
1823 nCheckPos,
1824 ActLnge);
1825 aCodeStr = sTempIn;
1826 if ( !pFormat || !(nCheckPos == 0) )
1828 if (LocaleDataWrapper::areChecksEnabled())
1830 OUString aMsg( OUString("SvNumberFormatter::ImpInsertFormat: bad format code, index " ) +
1831 OUString::number( rCode.Index ) +
1832 OUString("\n") +
1833 rCode.Code);
1834 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1836 delete pFormat;
1837 return NULL;
1839 if ( rCode.Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
1841 sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
1842 sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
1843 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1845 // If bAfterChangingSystemCL there will definitely be some dups,
1846 // don't cry then.
1847 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL)
1849 // Test for duplicate indexes in locale data.
1850 switch ( nOrgIndex )
1852 // These may be dups of integer versions for locales where
1853 // currencies have no decimals like Italian Lira.
1854 case NF_CURRENCY_1000DEC2 : // NF_CURRENCY_1000INT
1855 case NF_CURRENCY_1000DEC2_RED : // NF_CURRENCY_1000INT_RED
1856 case NF_CURRENCY_1000DEC2_DASHED : // NF_CURRENCY_1000INT_RED
1857 break;
1858 default:
1860 OUString aMsg("SvNumberFormatter::ImpInsertFormat: dup format code, index ");
1861 aMsg += OUString::number( rCode.Index );
1862 aMsg += "\n";
1863 aMsg += rCode.Code;
1864 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1868 delete pFormat;
1869 return NULL;
1871 else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
1873 if (LocaleDataWrapper::areChecksEnabled())
1875 OUString aMsg( "SvNumberFormatter::ImpInsertFormat: too many format codes, index ");
1876 aMsg += OUString::number( rCode.Index );
1877 aMsg += "\n";
1878 aMsg += rCode.Code;
1879 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1881 delete pFormat;
1882 return NULL;
1885 if ( !aFTable.insert( make_pair( nPos, pFormat) ).second )
1887 if (LocaleDataWrapper::areChecksEnabled())
1889 OUString aMsg( "ImpInsertFormat: can't insert number format key pos: ");
1890 aMsg += OUString::number( nPos );
1891 aMsg += ", code index ";
1892 aMsg += OUString::number( rCode.Index );
1893 aMsg += "\n";
1894 aMsg += rCode.Code;
1895 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1897 else
1899 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
1901 delete pFormat;
1902 return NULL;
1904 if ( rCode.Default )
1905 pFormat->SetStandard();
1906 if ( !rCode.DefaultName.isEmpty() )
1907 pFormat->SetComment( rCode.DefaultName );
1908 return pFormat;
1911 SvNumberformat* SvNumberFormatter::ImpInsertNewStandardFormat(
1912 const ::com::sun::star::i18n::NumberFormatCode& rCode,
1913 sal_uInt32 nPos, sal_uInt16 nVersion, bool bAfterChangingSystemCL,
1914 sal_Int16 nOrgIndex )
1916 SvNumberformat* pNewFormat = ImpInsertFormat( rCode, nPos,
1917 bAfterChangingSystemCL, nOrgIndex );
1918 if (pNewFormat)
1919 pNewFormat->SetNewStandardDefined( nVersion );
1920 // so that it gets saved, displayed properly, and converted by old versions
1921 return pNewFormat;
1924 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
1925 bool& bThousand,
1926 bool& IsRed,
1927 sal_uInt16& nPrecision,
1928 sal_uInt16& nAnzLeading)
1931 SvNumberformat* pFormat = GetFormatEntry( nFormat );
1932 if (pFormat)
1933 pFormat->GetFormatSpecialInfo(bThousand, IsRed,
1934 nPrecision, nAnzLeading);
1935 else
1937 bThousand = false;
1938 IsRed = false;
1939 nPrecision = pFormatScanner->GetStandardPrec();
1940 nAnzLeading = 0;
1944 sal_uInt16 SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
1946 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
1947 if ( pFormat )
1948 return pFormat->GetFormatPrecision();
1949 else
1950 return pFormatScanner->GetStandardPrec();
1954 OUString SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
1956 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
1957 if ( !pFormat || pFormat->GetLanguage() == ActLnge )
1959 return GetNumDecimalSep();
1961 OUString aRet;
1962 LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
1963 if ( pFormat->GetLanguage() == eSaveLang )
1965 aRet = xLocaleData->getNumDecimalSep();
1967 else
1969 LanguageTag aSaveLocale( xLocaleData->getLanguageTag() );
1970 ((SvNumberFormatter*)this)->xLocaleData.changeLocale( LanguageTag( pFormat->GetLanguage()) );
1971 aRet = xLocaleData->getNumDecimalSep();
1972 ((SvNumberFormatter*)this)->xLocaleData.changeLocale( aSaveLocale );
1974 return aRet;
1978 sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const OUString& rFormatString,
1979 bool& bThousand, bool& IsRed, sal_uInt16& nPrecision,
1980 sal_uInt16& nAnzLeading, LanguageType eLnge )
1983 if (eLnge == LANGUAGE_DONTKNOW)
1985 eLnge = IniLnge;
1987 ChangeIntl(eLnge); // change locale if necessary
1988 eLnge = ActLnge;
1989 OUString aTmpStr( rFormatString );
1990 sal_Int32 nCheckPos = 0;
1991 SvNumberformat* pFormat = new SvNumberformat( aTmpStr, pFormatScanner,
1992 pStringScanner, nCheckPos, eLnge );
1993 if ( nCheckPos == 0 )
1995 pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nAnzLeading );
1997 else
1999 bThousand = false;
2000 IsRed = false;
2001 nPrecision = pFormatScanner->GetStandardPrec();
2002 nAnzLeading = 0;
2004 delete pFormat;
2005 return nCheckPos;
2009 inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff )
2011 osl::MutexGuard aGuard(&theIndexTable.maMtx);
2013 if (!theIndexTable.mbInitialized)
2015 DBG_ASSERT(theIndexTable.maData[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
2016 "SetIndexTable: theIndexTable[nTabOff] already occupied" );
2017 theIndexTable.maData[nTabOff] = nIndOff;
2019 return nIndOff;
2023 sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex(
2024 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode >& rSeq,
2025 const NfIndexTableOffset nTabOff )
2027 const sal_Int32 nLen = rSeq.getLength();
2028 for ( sal_Int32 j=0; j<nLen; j++ )
2030 if ( rSeq[j].Index == nTabOff )
2031 return j;
2033 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START
2034 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
2035 || nTabOff == NF_CURRENCY_1000INT_RED
2036 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
2037 { // currency entries with decimals might not exist, e.g. Italian Lira
2038 OUString aMsg( "SvNumberFormatter::ImpGetFormatCodeIndex: not found: " );
2039 aMsg += OUString::number( nTabOff );
2040 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo(aMsg));
2042 if ( nLen )
2044 sal_Int32 j;
2045 // look for a preset default
2046 for ( j=0; j<nLen; j++ )
2048 if ( rSeq[j].Default )
2049 return j;
2051 // currencies are special, not all format codes must exist, but all
2052 // builtin number format key index positions must have a format assigned
2053 if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
2055 // look for a format with decimals
2056 for ( j=0; j<nLen; j++ )
2058 if ( rSeq[j].Index == NF_CURRENCY_1000DEC2 )
2059 return j;
2061 // last resort: look for a format without decimals
2062 for ( j=0; j<nLen; j++ )
2064 if ( rSeq[j].Index == NF_CURRENCY_1000INT )
2065 return j;
2069 else
2070 { // we need at least _some_ format
2071 rSeq.realloc(1);
2072 rSeq[0] = ::com::sun::star::i18n::NumberFormatCode();
2073 rSeq[0].Code = OUStringBuffer().
2074 append('0').
2075 append(GetNumDecimalSep()).
2076 append("############").
2077 makeStringAndClear();
2079 return 0;
2083 sal_Int32 SvNumberFormatter::ImpAdjustFormatCodeDefault(
2084 ::com::sun::star::i18n::NumberFormatCode * pFormatArr,
2085 sal_Int32 nCnt, bool bCheckCorrectness )
2087 using namespace ::com::sun::star;
2089 if ( !nCnt )
2090 return -1;
2091 if (bCheckCorrectness && LocaleDataWrapper::areChecksEnabled())
2093 // check the locale data for correctness
2094 OStringBuffer aMsg;
2095 sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
2096 nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
2097 for ( nElem = 0; nElem < nCnt; nElem++ )
2099 switch ( pFormatArr[nElem].Type )
2101 case i18n::KNumberFormatType::SHORT :
2102 nShort = nElem;
2103 break;
2104 case i18n::KNumberFormatType::MEDIUM :
2105 nMedium = nElem;
2106 break;
2107 case i18n::KNumberFormatType::LONG :
2108 nLong = nElem;
2109 break;
2110 default:
2111 aMsg.append("unknown type");
2113 if ( pFormatArr[nElem].Default )
2115 switch ( pFormatArr[nElem].Type )
2117 case i18n::KNumberFormatType::SHORT :
2118 if ( nShortDef != -1 )
2119 aMsg.append("dupe short type default");
2120 nShortDef = nElem;
2121 break;
2122 case i18n::KNumberFormatType::MEDIUM :
2123 if ( nMediumDef != -1 )
2124 aMsg.append("dupe medium type default");
2125 nMediumDef = nElem;
2126 break;
2127 case i18n::KNumberFormatType::LONG :
2128 if ( nLongDef != -1 )
2129 aMsg.append("dupe long type default");
2130 nLongDef = nElem;
2131 break;
2134 if (!aMsg.isEmpty())
2136 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2137 aMsg.append("\nXML locale data FormatElement formatindex: ");
2138 aMsg.append(static_cast<sal_Int32>(pFormatArr[nElem].Index));
2139 OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(),
2140 RTL_TEXTENCODING_ASCII_US));
2141 LocaleDataWrapper::outputCheckMessage(xLocaleData->appendLocaleInfo(aUMsg));
2144 if ( nShort != -1 && nShortDef == -1 )
2145 aMsg.append("no short type default ");
2146 if ( nMedium != -1 && nMediumDef == -1 )
2147 aMsg.append("no medium type default ");
2148 if ( nLong != -1 && nLongDef == -1 )
2149 aMsg.append("no long type default ");
2150 if (!aMsg.isEmpty())
2152 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2153 aMsg.append("\nXML locale data FormatElement group of: ");
2154 OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US));
2155 LocaleDataWrapper::outputCheckMessage(
2156 xLocaleData->appendLocaleInfo(aUMsg + pFormatArr[0].NameID));
2159 // find the default (medium preferred, then long) and reset all other defaults
2160 sal_Int32 nElem, nDef, nMedium;
2161 nDef = nMedium = -1;
2162 for ( nElem = 0; nElem < nCnt; nElem++ )
2164 if ( pFormatArr[nElem].Default )
2166 switch ( pFormatArr[nElem].Type )
2168 case i18n::KNumberFormatType::MEDIUM :
2169 nDef = nMedium = nElem;
2170 break;
2171 case i18n::KNumberFormatType::LONG :
2172 if ( nMedium == -1 )
2173 nDef = nElem;
2174 // fallthru
2175 default:
2176 if ( nDef == -1 )
2177 nDef = nElem;
2178 pFormatArr[nElem].Default = false;
2182 if ( nDef == -1 )
2183 nDef = 0;
2184 pFormatArr[nDef].Default = true;
2185 return nDef;
2188 SvNumberformat* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey )
2190 SvNumberFormatTable::iterator it = aFTable.find( nKey);
2191 if (it != aFTable.end())
2192 return it->second;
2193 return 0;
2196 const SvNumberformat* SvNumberFormatter::GetEntry( sal_uInt32 nKey ) const
2198 SvNumberFormatTable::const_iterator it = aFTable.find( nKey);
2199 if (it != aFTable.end())
2200 return it->second;
2201 return 0;
2204 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditionalFormats )
2206 using namespace ::com::sun::star;
2209 osl::MutexGuard aGuard(&theIndexTable.maMtx);
2210 if (!theIndexTable.mbInitialized)
2212 for ( sal_uInt16 j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
2214 theIndexTable.maData[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
2219 bool bOldConvertMode = pFormatScanner->GetConvertMode();
2220 if (bOldConvertMode)
2222 pFormatScanner->SetConvertMode(false); // switch off for this function
2225 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
2226 GetLanguageTag().getLocale() );
2227 SvNumberformat* pNewFormat = NULL;
2228 sal_Int32 nIdx;
2229 bool bDefault;
2231 // Counter for additional builtin formats not fitting into the first 10
2232 // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2233 // Has to be incremented on each ImpInsertNewStandardformat, new formats
2234 // must be appended, not inserted!
2235 sal_uInt16 nNewExtended = ZF_STANDARD_NEWEXTENDED;
2237 // Number
2238 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2239 aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER );
2240 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2242 // General
2243 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2244 SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2245 CLOffset + SetIndexTable( NF_NUMBER_STANDARD, ZF_STANDARD ));
2246 if (pStdFormat)
2248 // This is _the_ standard format.
2249 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat->GetType() != NUMBERFORMAT_NUMBER)
2251 LocaleDataWrapper::outputCheckMessage( xLocaleData->
2252 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2254 pStdFormat->SetType( NUMBERFORMAT_NUMBER );
2255 pStdFormat->SetStandard();
2256 pStdFormat->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE );
2258 else
2260 if (LocaleDataWrapper::areChecksEnabled())
2262 LocaleDataWrapper::outputCheckMessage( xLocaleData->
2263 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2267 // Boolean
2268 OUString aFormatCode = pFormatScanner->GetBooleanString();
2269 sal_Int32 nCheckPos = 0;
2271 pNewFormat = new SvNumberformat( aFormatCode, pFormatScanner,
2272 pStringScanner, nCheckPos, ActLnge );
2273 pNewFormat->SetType(NUMBERFORMAT_LOGICAL);
2274 pNewFormat->SetStandard();
2275 if ( !aFTable.insert(make_pair(
2276 CLOffset + SetIndexTable( NF_BOOLEAN, ZF_STANDARD_LOGICAL ),
2277 pNewFormat)).second)
2279 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2280 delete pNewFormat;
2283 // Text
2284 aFormatCode = "@";
2285 pNewFormat = new SvNumberformat( aFormatCode, pFormatScanner,
2286 pStringScanner, nCheckPos, ActLnge );
2287 pNewFormat->SetType(NUMBERFORMAT_TEXT);
2288 pNewFormat->SetStandard();
2289 if ( !aFTable.insert(make_pair(
2290 CLOffset + SetIndexTable( NF_TEXT, ZF_STANDARD_TEXT ),
2291 pNewFormat)).second)
2293 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2294 delete pNewFormat;
2299 // 0
2300 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2301 ImpInsertFormat( aFormatSeq[nIdx],
2302 CLOffset + SetIndexTable( NF_NUMBER_INT, ZF_STANDARD+1 ));
2304 // 0.00
2305 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2306 ImpInsertFormat( aFormatSeq[nIdx],
2307 CLOffset + SetIndexTable( NF_NUMBER_DEC2, ZF_STANDARD+2 ));
2309 // #,##0
2310 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2311 ImpInsertFormat( aFormatSeq[nIdx],
2312 CLOffset + SetIndexTable( NF_NUMBER_1000INT, ZF_STANDARD+3 ));
2314 // #,##0.00
2315 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2316 ImpInsertFormat( aFormatSeq[nIdx],
2317 CLOffset + SetIndexTable( NF_NUMBER_1000DEC2, ZF_STANDARD+4 ));
2319 // #.##0,00 System country/language dependent since number formatter version 6
2320 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2321 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2322 CLOffset + SetIndexTable( NF_NUMBER_SYSTEM, ZF_STANDARD+5 ),
2323 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2326 // Percent number
2327 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER );
2328 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2330 // 0%
2331 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2332 ImpInsertFormat( aFormatSeq[nIdx],
2333 CLOffset + SetIndexTable( NF_PERCENT_INT, ZF_STANDARD_PERCENT ));
2335 // 0.00%
2336 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2337 ImpInsertFormat( aFormatSeq[nIdx],
2338 CLOffset + SetIndexTable( NF_PERCENT_DEC2, ZF_STANDARD_PERCENT+1 ));
2342 // Currency. NO default standard option! Default is determined of locale
2343 // data default currency and format is generated if needed.
2344 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2345 if (LocaleDataWrapper::areChecksEnabled())
2347 // though no default desired here, test for correctness of locale data
2348 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2351 // #,##0
2352 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2353 bDefault = aFormatSeq[nIdx].Default;
2354 aFormatSeq[nIdx].Default = false;
2355 ImpInsertFormat( aFormatSeq[nIdx],
2356 CLOffset + SetIndexTable( NF_CURRENCY_1000INT, ZF_STANDARD_CURRENCY ));
2357 aFormatSeq[nIdx].Default = bDefault;
2359 // #,##0.00
2360 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2361 bDefault = aFormatSeq[nIdx].Default;
2362 aFormatSeq[nIdx].Default = false;
2363 ImpInsertFormat( aFormatSeq[nIdx],
2364 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2, ZF_STANDARD_CURRENCY+1 ));
2365 aFormatSeq[nIdx].Default = bDefault;
2367 // #,##0 negative red
2368 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2369 bDefault = aFormatSeq[nIdx].Default;
2370 aFormatSeq[nIdx].Default = false;
2371 ImpInsertFormat( aFormatSeq[nIdx],
2372 CLOffset + SetIndexTable( NF_CURRENCY_1000INT_RED, ZF_STANDARD_CURRENCY+2 ));
2373 aFormatSeq[nIdx].Default = bDefault;
2375 // #,##0.00 negative red
2376 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2377 bDefault = aFormatSeq[nIdx].Default;
2378 aFormatSeq[nIdx].Default = false;
2379 ImpInsertFormat( aFormatSeq[nIdx],
2380 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_RED, ZF_STANDARD_CURRENCY+3 ));
2381 aFormatSeq[nIdx].Default = bDefault;
2383 // #,##0.00 USD since number formatter version 3
2384 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2385 bDefault = aFormatSeq[nIdx].Default;
2386 aFormatSeq[nIdx].Default = false;
2387 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2388 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_CCC, ZF_STANDARD_CURRENCY+4 ));
2389 if ( pNewFormat )
2390 pNewFormat->SetUsed(true); // must be saved for older versions
2391 aFormatSeq[nIdx].Default = bDefault;
2393 // #.##0,-- since number formatter version 6
2394 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED );
2395 bDefault = aFormatSeq[nIdx].Default;
2396 aFormatSeq[nIdx].Default = false;
2397 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2398 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_DASHED, ZF_STANDARD_CURRENCY+5 ),
2399 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2400 aFormatSeq[nIdx].Default = bDefault;
2404 // Date
2405 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE );
2406 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2408 // DD.MM.YY System
2409 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2410 ImpInsertFormat( aFormatSeq[nIdx],
2411 CLOffset + SetIndexTable( NF_DATE_SYSTEM_SHORT, ZF_STANDARD_DATE ));
2413 // NN DD.MMM YY
2414 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2415 ImpInsertFormat( aFormatSeq[nIdx],
2416 CLOffset + SetIndexTable( NF_DATE_DEF_NNDDMMMYY, ZF_STANDARD_DATE+1 ));
2418 // DD.MM.YY def/System
2419 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2420 ImpInsertFormat( aFormatSeq[nIdx],
2421 CLOffset + SetIndexTable( NF_DATE_SYS_MMYY, ZF_STANDARD_DATE+2 ));
2423 // DD MMM
2424 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2425 ImpInsertFormat( aFormatSeq[nIdx],
2426 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMM, ZF_STANDARD_DATE+3 ));
2428 // MMMM
2429 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2430 ImpInsertFormat( aFormatSeq[nIdx],
2431 CLOffset + SetIndexTable( NF_DATE_MMMM, ZF_STANDARD_DATE+4 ));
2433 // QQ YY
2434 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2435 ImpInsertFormat( aFormatSeq[nIdx],
2436 CLOffset + SetIndexTable( NF_DATE_QQJJ, ZF_STANDARD_DATE+5 ));
2438 // DD.MM.YYYY since number formatter version 2, was DD.MM.[YY]YY
2439 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2440 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2441 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYYYY, ZF_STANDARD_DATE+6 ));
2442 if ( pNewFormat )
2444 pNewFormat->SetUsed(true); // must be saved for older versions
2446 // DD.MM.YY def/System, since number formatter version 6
2447 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2448 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2449 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYY, ZF_STANDARD_DATE+7 ),
2450 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2452 // NNN, D. MMMM YYYY System
2453 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2454 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2455 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2456 CLOffset + SetIndexTable( NF_DATE_SYSTEM_LONG, ZF_STANDARD_DATE+8 ),
2457 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2459 // Hard coded but system (regional settings) delimiters dependent long date formats
2460 // since numberformatter version 6
2462 // D. MMM YY def/System
2463 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2464 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2465 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYY, ZF_STANDARD_DATE+9 ),
2466 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2468 //! Unfortunally TLOT intended only 10 builtin formats per category, more
2469 //! would overwrite the next category (ZF_STANDARD_TIME) :-((
2470 //! Therefore they are inserted with nNewExtended++ (which is also limited)
2472 // D. MMM YYYY def/System
2473 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2474 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2475 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYYYY, nNewExtended++ ),
2476 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2478 // D. MMMM YYYY def/System
2479 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2480 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2481 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMMYYYY, nNewExtended++ ),
2482 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2484 // NN, D. MMM YY def/System
2485 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2486 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2487 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMYY, nNewExtended++ ),
2488 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2490 // NN, D. MMMM YYYY def/System
2491 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2492 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2493 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY, nNewExtended++ ),
2494 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2496 // NNN, D. MMMM YYYY def/System
2497 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY );
2498 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2499 CLOffset + SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY, nNewExtended++ ),
2500 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2502 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2504 // D. MMM. YYYY DIN/EN
2505 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2506 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2507 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMYYYY, nNewExtended++ ),
2508 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2510 // D. MMMM YYYY DIN/EN
2511 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2512 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2513 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMMYYYY, nNewExtended++ ),
2514 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2516 // MM-DD DIN/EN
2517 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2518 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2519 CLOffset + SetIndexTable( NF_DATE_DIN_MMDD, nNewExtended++ ),
2520 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2522 // YY-MM-DD DIN/EN
2523 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2524 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2525 CLOffset + SetIndexTable( NF_DATE_DIN_YYMMDD, nNewExtended++ ),
2526 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2528 // YYYY-MM-DD DIN/EN
2529 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2530 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2531 CLOffset + SetIndexTable( NF_DATE_DIN_YYYYMMDD, nNewExtended++ ),
2532 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2536 // Time
2537 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::TIME );
2538 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2540 // HH:MM
2541 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2542 ImpInsertFormat( aFormatSeq[nIdx],
2543 CLOffset + SetIndexTable( NF_TIME_HHMM, ZF_STANDARD_TIME ));
2545 // HH:MM:SS
2546 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2547 ImpInsertFormat( aFormatSeq[nIdx],
2548 CLOffset + SetIndexTable( NF_TIME_HHMMSS, ZF_STANDARD_TIME+1 ));
2550 // HH:MM AM/PM
2551 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2552 ImpInsertFormat( aFormatSeq[nIdx],
2553 CLOffset + SetIndexTable( NF_TIME_HHMMAMPM, ZF_STANDARD_TIME+2 ));
2555 // HH:MM:SS AM/PM
2556 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2557 ImpInsertFormat( aFormatSeq[nIdx],
2558 CLOffset + SetIndexTable( NF_TIME_HHMMSSAMPM, ZF_STANDARD_TIME+3 ));
2560 // [HH]:MM:SS
2561 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2562 ImpInsertFormat( aFormatSeq[nIdx],
2563 CLOffset + SetIndexTable( NF_TIME_HH_MMSS, ZF_STANDARD_TIME+4 ));
2565 // MM:SS,00
2566 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2567 ImpInsertFormat( aFormatSeq[nIdx],
2568 CLOffset + SetIndexTable( NF_TIME_MMSS00, ZF_STANDARD_TIME+5 ));
2570 // [HH]:MM:SS,00
2571 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2572 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2573 CLOffset + SetIndexTable( NF_TIME_HH_MMSS00, ZF_STANDARD_TIME+6 ),
2574 SV_NUMBERFORMATTER_VERSION_NF_TIME_HH_MMSS00 );
2578 // DateTime
2579 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME );
2580 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2582 // DD.MM.YY HH:MM System
2583 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM );
2584 ImpInsertFormat( aFormatSeq[nIdx],
2585 CLOffset + SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM, ZF_STANDARD_DATETIME ));
2587 // DD.MM.YYYY HH:MM:SS System
2588 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2589 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2590 CLOffset + SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, ZF_STANDARD_DATETIME+1 ),
2591 SV_NUMBERFORMATTER_VERSION_NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2595 // Scientific number
2596 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER );
2597 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2599 // 0.00E+000
2600 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2601 ImpInsertFormat( aFormatSeq[nIdx],
2602 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E000, ZF_STANDARD_SCIENTIFIC ));
2604 // 0.00E+00
2605 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2606 ImpInsertFormat( aFormatSeq[nIdx],
2607 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E00, ZF_STANDARD_SCIENTIFIC+1 ));
2611 // Fraction number (no default option)
2612 i18n::NumberFormatCode aSingleFormatCode;
2613 aSingleFormatCode.Usage = i18n::KNumberFormatUsage::FRACTION_NUMBER;
2615 // # ?/?
2616 aSingleFormatCode.Code = "# ?/?";
2617 ImpInsertFormat( aSingleFormatCode,
2618 CLOffset + SetIndexTable( NF_FRACTION_1, ZF_STANDARD_FRACTION ));
2620 // # ??/??
2621 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2622 aSingleFormatCode.Code = "# ?\?/?\?";
2623 ImpInsertFormat( aSingleFormatCode,
2624 CLOffset + SetIndexTable( NF_FRACTION_2, ZF_STANDARD_FRACTION+1 ));
2626 // # ?/4
2627 aSingleFormatCode.Code = "# ?/4";
2628 ImpInsertNewStandardFormat( aSingleFormatCode,
2629 CLOffset + SetIndexTable( NF_FRACTION_3, ZF_STANDARD_FRACTION+2 ),
2630 SV_NUMBERFORMATTER_VERSION_FIXED_FRACTION );
2632 // # ??/100
2633 aSingleFormatCode.Code = "# ?\?/100";
2634 ImpInsertNewStandardFormat( aSingleFormatCode,
2635 CLOffset + SetIndexTable( NF_FRACTION_4, ZF_STANDARD_FRACTION+3 ),
2636 SV_NUMBERFORMATTER_VERSION_FIXED_FRACTION );
2640 // Week of year must be appended here because of nNewExtended
2641 const NfKeywordTable & rKeyword = pFormatScanner->GetKeywords();
2642 aSingleFormatCode.Code = rKeyword[NF_KEY_WW];
2643 ImpInsertNewStandardFormat( aSingleFormatCode,
2644 CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ),
2645 SV_NUMBERFORMATTER_VERSION_NF_DATE_WW );
2648 osl::MutexGuard aGuard(&theIndexTable.maMtx);
2649 theIndexTable.mbInitialized = true;
2651 SAL_WARN_IF( nNewExtended > ZF_STANDARD_NEWEXTENDEDMAX, "svl.numbers",
2652 "ImpGenerateFormats: overflow of nNewExtended standard formats" );
2654 // Now all additional format codes provided by I18N, but only if not
2655 // changing SystemCL, then they are appended last after user defined.
2656 if ( !bNoAdditionalFormats )
2658 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, false );
2660 if (bOldConvertMode)
2662 pFormatScanner->SetConvertMode(true);
2667 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset,
2668 NumberFormatCodeWrapper& rNumberFormatCode, bool bAfterChangingSystemCL )
2670 using namespace ::com::sun::star;
2672 SvNumberformat* pStdFormat = GetFormatEntry( CLOffset + ZF_STANDARD );
2673 if ( !pStdFormat )
2675 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2676 return ;
2678 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
2679 rNumberFormatCode.setLocale( GetLanguageTag().getLocale() );
2680 sal_Int32 j;
2682 // All currencies, this time with [$...] which was stripped in
2683 // ImpGenerateFormats for old "automatic" currency formats.
2684 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2685 rNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2686 i18n::NumberFormatCode * pFormatArr = aFormatSeq.getArray();
2687 sal_Int32 nCodes = aFormatSeq.getLength();
2688 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes );
2689 for ( j = 0; j < nCodes; j++ )
2691 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2693 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2694 break; // for
2696 if ( pFormatArr[j].Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
2697 pFormatArr[j].Index != NF_CURRENCY_1000DEC2_CCC )
2698 { // Insert only if not already inserted, but internal index must be
2699 // above so ImpInsertFormat can distinguish it.
2700 sal_Int16 nOrgIndex = pFormatArr[j].Index;
2701 pFormatArr[j].Index = sal::static_int_cast< sal_Int16 >(
2702 pFormatArr[j].Index + nCodes + NF_INDEX_TABLE_ENTRIES);
2703 //! no default on currency
2704 bool bDefault = aFormatSeq[j].Default;
2705 aFormatSeq[j].Default = false;
2706 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2707 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2708 bAfterChangingSystemCL, nOrgIndex ) )
2709 nPos++;
2710 pFormatArr[j].Index = nOrgIndex;
2711 aFormatSeq[j].Default = bDefault;
2715 // all additional format codes provided by I18N that are not old standard index
2716 aFormatSeq = rNumberFormatCode.getAllFormatCodes();
2717 nCodes = aFormatSeq.getLength();
2718 if ( nCodes )
2720 pFormatArr = aFormatSeq.getArray();
2721 // don't check ALL
2722 sal_Int32 nDef = ImpAdjustFormatCodeDefault( pFormatArr, nCodes, false);
2723 // don't have any defaults here
2724 pFormatArr[nDef].Default = false;
2725 for ( j = 0; j < nCodes; j++ )
2727 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2729 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2730 break; // for
2732 if ( pFormatArr[j].Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
2733 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2734 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2735 bAfterChangingSystemCL ) )
2736 nPos++;
2740 pStdFormat->SetLastInsertKey( (sal_uInt16)(nPos - CLOffset) );
2744 void SvNumberFormatter::ImpGetPosCurrFormat(OUStringBuffer& sPosStr, const OUString& rCurrSymbol)
2746 NfCurrencyEntry::CompletePositiveFormatString( sPosStr,
2747 rCurrSymbol, xLocaleData->getCurrPositiveFormat() );
2750 void SvNumberFormatter::ImpGetNegCurrFormat(OUStringBuffer& sNegStr, const OUString& rCurrSymbol)
2752 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
2753 rCurrSymbol, xLocaleData->getCurrNegativeFormat() );
2756 OUString SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex,
2757 LanguageType eLnge,
2758 bool bThousand,
2759 bool IsRed,
2760 sal_uInt16 nPrecision,
2761 sal_uInt16 nAnzLeading)
2763 if (eLnge == LANGUAGE_DONTKNOW)
2765 eLnge = IniLnge;
2767 short eType = GetType(nIndex);
2768 sal_uInt16 i;
2769 ImpGenerateCL(eLnge); // create new standard formats if necessary
2771 utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping());
2772 const sal_Int32 nDigitsInFirstGroup = aGrouping.get();
2773 const OUString& rThSep = GetNumThousandSep();
2775 SvNumberformat* pFormat = GetFormatEntry( nIndex );
2777 OUStringBuffer sString;
2778 using comphelper::string::padToLength;
2780 if (nAnzLeading == 0)
2782 if (!bThousand)
2783 sString.append('#');
2784 else
2786 sString.append('#');
2787 sString.append(rThSep);
2788 padToLength(sString, sString.getLength() + nDigitsInFirstGroup, '#');
2791 else
2793 for (i = 0; i < nAnzLeading; i++)
2795 if (bThousand && i > 0 && i == aGrouping.getPos())
2797 sString.insert(0, rThSep);
2798 aGrouping.advance();
2800 sString.insert(0, '0');
2802 if (bThousand && nAnzLeading < nDigitsInFirstGroup + 1)
2804 for (i = nAnzLeading; i < nDigitsInFirstGroup + 1; i++)
2806 if (bThousand && i % nDigitsInFirstGroup == 0)
2807 sString.insert(0, rThSep);
2808 sString.insert(0, '#');
2812 if (nPrecision > 0)
2814 sString.append(GetNumDecimalSep());
2815 padToLength(sString, sString.getLength() + nPrecision, '0');
2817 if (eType == NUMBERFORMAT_PERCENT)
2819 sString.append('%');
2821 else if (eType == NUMBERFORMAT_CURRENCY)
2823 OUStringBuffer sNegStr(sString);
2824 OUString aCurr;
2825 const NfCurrencyEntry* pEntry;
2826 bool bBank;
2827 if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
2829 if ( pEntry )
2831 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2832 xLocaleData->getCurrPositiveFormat(),
2833 pEntry->GetPositiveFormat(), bBank );
2834 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2835 xLocaleData->getCurrNegativeFormat(),
2836 pEntry->GetNegativeFormat(), bBank );
2837 pEntry->CompletePositiveFormatString( sString, bBank, nPosiForm );
2838 pEntry->CompleteNegativeFormatString( sNegStr, bBank, nNegaForm );
2840 else
2841 { // assume currency abbreviation (AKA banking symbol), not symbol
2842 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2843 xLocaleData->getCurrPositiveFormat(),
2844 xLocaleData->getCurrPositiveFormat(), true );
2845 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2846 xLocaleData->getCurrNegativeFormat(),
2847 xLocaleData->getCurrNegativeFormat(), true );
2848 NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr, nPosiForm );
2849 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr, nNegaForm );
2852 else
2853 { // "automatic" old style
2854 OUString aSymbol, aAbbrev;
2855 GetCompatibilityCurrency( aSymbol, aAbbrev );
2856 ImpGetPosCurrFormat( sString, aSymbol );
2857 ImpGetNegCurrFormat( sNegStr, aSymbol );
2859 if (IsRed)
2861 sString.append(';');
2862 sString.append('[');
2863 sString.append(pFormatScanner->GetRedString());
2864 sString.append(']');
2866 else
2868 sString.append(';');
2870 sString.append(sNegStr.makeStringAndClear());
2872 if (eType != NUMBERFORMAT_CURRENCY)
2874 bool insertBrackets = false;
2875 if ( eType != NUMBERFORMAT_UNDEFINED)
2877 insertBrackets = pFormat->IsNegativeInBracket();
2879 if (IsRed || insertBrackets)
2881 OUStringBuffer sTmpStr(sString);
2883 if ( pFormat->HasPositiveBracketPlaceholder() )
2885 sTmpStr.append('_');
2886 sTmpStr.append(')');
2888 sTmpStr.append(';');
2890 if (IsRed)
2892 sTmpStr.append('[');
2893 sTmpStr.append(pFormatScanner->GetRedString());
2894 sTmpStr.append(']');
2897 if (insertBrackets)
2899 sTmpStr.append('(');
2900 sTmpStr.append(sString.toString());
2901 sTmpStr.append(')');
2903 else
2905 sTmpStr.append('-');
2906 sTmpStr.append(sString.toString());
2908 sString = sTmpStr;
2911 return sString.makeStringAndClear();
2914 bool SvNumberFormatter::IsUserDefined(const OUString& sStr,
2915 LanguageType eLnge)
2917 if (eLnge == LANGUAGE_DONTKNOW)
2919 eLnge = IniLnge;
2921 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
2922 eLnge = ActLnge;
2924 sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
2925 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
2927 return true;
2929 SvNumberformat* pEntry = GetFormatEntry( nKey );
2930 if ( pEntry && ((pEntry->GetType() & NUMBERFORMAT_DEFINED) != 0) )
2932 return true;
2934 return false;
2937 sal_uInt32 SvNumberFormatter::GetEntryKey(const OUString& sStr,
2938 LanguageType eLnge)
2940 if (eLnge == LANGUAGE_DONTKNOW)
2942 eLnge = IniLnge;
2944 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
2945 return ImpIsEntry(sStr, CLOffset, eLnge);
2948 sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge)
2950 if (eLnge == LANGUAGE_DONTKNOW)
2952 eLnge = IniLnge;
2954 return GetStandardFormat(NUMBERFORMAT_NUMBER, eLnge);
2957 short SvNumberFormatter::GetType(sal_uInt32 nFIndex)
2959 short eType;
2960 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
2961 if (!pFormat)
2963 eType = NUMBERFORMAT_UNDEFINED;
2965 else
2967 eType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
2968 if (eType == 0)
2970 eType = NUMBERFORMAT_DEFINED;
2973 return eType;
2976 void SvNumberFormatter::ClearMergeTable()
2978 if ( pMergeTable )
2980 pMergeTable->clear();
2984 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
2986 if ( pMergeTable )
2988 ClearMergeTable();
2990 else
2992 pMergeTable = new SvNumberFormatterIndexTable;
2995 sal_uInt32 nCLOffset = 0;
2996 sal_uInt32 nOldKey, nOffset, nNewKey;
2997 SvNumberformat* pNewEntry;
2999 SvNumberFormatTable::iterator it = rTable.aFTable.begin();
3000 while (it != rTable.aFTable.end())
3002 SvNumberformat* pFormat = it->second;
3003 nOldKey = it->first;
3004 nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3005 if (nOffset == 0) // 1st format of CL
3007 nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
3009 if (nOffset <= SV_MAX_ANZ_STANDARD_FORMATE) // Std.form.
3011 nNewKey = nCLOffset + nOffset;
3012 if (aFTable.find( nNewKey) == aFTable.end()) // not already present
3014 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
3015 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
3016 if (!aFTable.insert(make_pair( nNewKey, pNewEntry)).second)
3018 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3019 delete pNewEntry;
3022 if (nNewKey != nOldKey) // new index
3024 (*pMergeTable)[nOldKey] = nNewKey;
3027 else // user defined
3029 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
3030 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
3031 nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
3032 nCLOffset,
3033 pFormat->GetLanguage());
3034 if (nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
3036 delete pNewEntry;
3038 else
3040 SvNumberformat* pStdFormat = GetFormatEntry(nCLOffset + ZF_STANDARD);
3041 sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey();
3042 nNewKey = nPos+1;
3043 if (nNewKey - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
3045 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3046 delete pNewEntry;
3048 else if (!aFTable.insert(make_pair( nNewKey, pNewEntry)).second)
3050 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3051 delete pNewEntry;
3053 else
3055 pStdFormat->SetLastInsertKey((sal_uInt16) (nNewKey - nCLOffset));
3058 if (nNewKey != nOldKey) // new index
3060 (*pMergeTable)[nOldKey] = nNewKey;
3063 ++it;
3065 return pMergeTable;
3069 SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap()
3071 if (!HasMergeFmtTbl())
3073 return SvNumberFormatterMergeMap();
3075 SvNumberFormatterMergeMap aMap;
3076 for (SvNumberFormatterIndexTable::iterator it = pMergeTable->begin(); it != pMergeTable->end(); ++it)
3078 sal_uInt32 nOldKey = it->first;
3079 aMap[ nOldKey ] = it->second;
3081 ClearMergeTable();
3082 return aMap;
3086 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
3087 LanguageType eLnge )
3089 if ( eLnge == LANGUAGE_DONTKNOW )
3091 eLnge = IniLnge;
3093 if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
3095 return nFormat; // it stays as it is
3097 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3098 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3100 return nFormat; // not a built-in format
3102 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3103 return nCLOffset + nOffset;
3107 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
3108 LanguageType eLnge )
3110 if (nTabOff >= NF_INDEX_TABLE_ENTRIES)
3111 return NUMBERFORMAT_ENTRY_NOT_FOUND;
3113 if (eLnge == LANGUAGE_DONTKNOW)
3114 eLnge = IniLnge;
3117 osl::MutexGuard aGuard(&theIndexTable.maMtx);
3118 if (theIndexTable.maData[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND)
3119 return NUMBERFORMAT_ENTRY_NOT_FOUND;
3122 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3125 osl::MutexGuard aGuard(&theIndexTable.maMtx);
3126 return nCLOffset + theIndexTable.maData[nTabOff];
3131 NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const
3133 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3134 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3136 return NF_INDEX_TABLE_ENTRIES; // not a built-in format
3140 osl::MutexGuard aGuard(&theIndexTable.maMtx);
3141 for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
3143 if (theIndexTable.maData[j] == nOffset)
3144 return (NfIndexTableOffset) j;
3147 return NF_INDEX_TABLE_ENTRIES; // bad luck
3151 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal )
3153 pStringScanner->SetYear2000( nVal );
3157 sal_uInt16 SvNumberFormatter::GetYear2000() const
3159 return pStringScanner->GetYear2000();
3163 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear ) const
3165 if ( nYear < 100 )
3166 return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3167 pStringScanner->GetYear2000() );
3168 return nYear;
3172 // static
3173 sal_uInt16 SvNumberFormatter::GetYear2000Default()
3175 return (sal_uInt16) ::utl::MiscCfg().GetYear2000();
3179 // static
3180 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3182 ::osl::MutexGuard aGuard( GetMutex() );
3183 while ( !bCurrencyTableInitialized )
3184 ImpInitCurrencyTable();
3185 return theCurrencyTable::get();
3189 // static
3190 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3192 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3193 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3194 return nSystemCurrencyPosition ? &rTable[nSystemCurrencyPosition] : NULL;
3198 // static
3199 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3201 if ( eLang == LANGUAGE_SYSTEM )
3203 const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3204 return pCurr ? *pCurr : GetTheCurrencyTable()[0];
3206 else
3208 eLang = MsLangId::getRealLanguage( eLang );
3209 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3210 sal_uInt16 nCount = rTable.size();
3211 for ( sal_uInt16 j = 0; j < nCount; j++ )
3213 if ( rTable[j].GetLanguage() == eLang )
3214 return rTable[j];
3216 return rTable[0];
3221 // static
3222 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(const OUString& rAbbrev, LanguageType eLang )
3224 eLang = MsLangId::getRealLanguage( eLang );
3225 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3226 sal_uInt16 nCount = rTable.size();
3227 for ( sal_uInt16 j = 0; j < nCount; j++ )
3229 if ( rTable[j].GetLanguage() == eLang &&
3230 rTable[j].GetBankSymbol() == rAbbrev )
3232 return &rTable[j];
3235 return NULL;
3239 // static
3240 const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( const OUString& rSymbol,
3241 const OUString& rAbbrev )
3243 if (!bCurrencyTableInitialized)
3245 GetTheCurrencyTable(); // just for initialization
3247 const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get();
3248 sal_uInt16 nCount = rTable.size();
3249 for ( sal_uInt16 j = 0; j < nCount; j++ )
3251 if ( rTable[j].GetSymbol() == rSymbol &&
3252 rTable[j].GetBankSymbol() == rAbbrev )
3254 return &rTable[j];
3257 return NULL;
3261 // static
3262 IMPL_STATIC_LINK_NOINSTANCE( SvNumberFormatter, CurrencyChangeLink, SAL_UNUSED_PARAMETER void*, EMPTYARG )
3264 ::osl::MutexGuard aGuard( GetMutex() );
3265 OUString aAbbrev;
3266 LanguageType eLang = LANGUAGE_SYSTEM;
3267 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3268 SetDefaultSystemCurrency( aAbbrev, eLang );
3269 return 0;
3273 // static
3274 void SvNumberFormatter::SetDefaultSystemCurrency( const OUString& rAbbrev, LanguageType eLang )
3276 ::osl::MutexGuard aGuard( GetMutex() );
3277 if ( eLang == LANGUAGE_SYSTEM )
3279 eLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3281 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3282 sal_uInt16 nCount = rTable.size();
3283 if ( !rAbbrev.isEmpty() )
3285 for ( sal_uInt16 j = 0; j < nCount; j++ )
3287 if ( rTable[j].GetLanguage() == eLang && rTable[j].GetBankSymbol() == rAbbrev )
3289 nSystemCurrencyPosition = j;
3290 return ;
3294 else
3296 for ( sal_uInt16 j = 0; j < nCount; j++ )
3298 if ( rTable[j].GetLanguage() == eLang )
3300 nSystemCurrencyPosition = j;
3301 return ;
3305 nSystemCurrencyPosition = 0; // not found => simple SYSTEM
3309 void SvNumberFormatter::ResetDefaultSystemCurrency()
3311 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3315 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3317 pStringScanner->InvalidateDateAcceptancePatterns();
3321 sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3323 if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3325 sal_Int32 nCheck;
3326 short nType;
3327 NfWSStringsDtor aCurrList;
3328 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3329 GetCurrencyEntry( LANGUAGE_SYSTEM ), false );
3330 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency System standard format?!?" );
3331 // if already loaded or user defined nDefaultSystemCurrencyFormat
3332 // will be set to the right value
3333 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3334 nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM );
3335 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3336 DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3337 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3339 return nDefaultSystemCurrencyFormat;
3343 sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3345 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3346 DefaultFormatKeysMap::iterator it = aDefaultFormatKeys.find( CLOffset + ZF_STANDARD_CURRENCY );
3347 sal_uInt32 nDefaultCurrencyFormat = (it != aDefaultFormatKeys.end() ?
3348 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
3349 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3351 // look for a defined standard
3352 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3353 sal_uInt32 nKey(0);
3354 SvNumberFormatTable::iterator it2 = aFTable.lower_bound( CLOffset );
3355 while ( it2 != aFTable.end() && (nKey = it2->first) >= CLOffset && nKey < nStopKey )
3357 const SvNumberformat* pEntry = it2->second;
3358 if ( pEntry->IsStandard() && (pEntry->GetType() & NUMBERFORMAT_CURRENCY) )
3360 nDefaultCurrencyFormat = nKey;
3361 break; // while
3363 ++it2;
3366 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3367 { // none found, create one
3368 sal_Int32 nCheck;
3369 NfWSStringsDtor aCurrList;
3370 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3371 GetCurrencyEntry( ActLnge ), false );
3372 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency standard format?" );
3373 if ( !aCurrList.empty() )
3375 // if already loaded or user defined nDefaultSystemCurrencyFormat
3376 // will be set to the right value
3377 short nType;
3378 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3379 nDefaultCurrencyFormat, ActLnge );
3380 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3381 DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3382 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3384 // old automatic currency format as a last resort
3385 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3386 nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3387 else
3388 { // mark as standard so that it is found next time
3389 SvNumberformat* pEntry = GetFormatEntry( nDefaultCurrencyFormat );
3390 if ( pEntry )
3391 pEntry->SetStandard();
3394 aDefaultFormatKeys[ CLOffset + ZF_STANDARD_CURRENCY ] = nDefaultCurrencyFormat;
3396 return nDefaultCurrencyFormat;
3400 // static
3401 // try to make it inline if possible since this a loop body
3402 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
3403 #ifndef DBG_UTIL
3404 inline
3405 #endif
3406 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody( const NfCurrencyEntry*& pFoundEntry, bool& bFoundBank,
3407 const NfCurrencyEntry* pData, sal_uInt16 nPos,
3408 const OUString& rSymbol )
3410 bool bFound;
3411 if ( pData->GetSymbol() == rSymbol )
3413 bFound = true;
3414 bFoundBank = false;
3416 else if ( pData->GetBankSymbol() == rSymbol )
3418 bFound = true;
3419 bFoundBank = true;
3421 else
3422 bFound = false;
3423 if ( bFound )
3425 if ( pFoundEntry && pFoundEntry != pData )
3427 pFoundEntry = NULL;
3428 return false; // break loop, not unique
3430 if ( nPos == 0 )
3431 { // first entry is SYSTEM
3432 pFoundEntry = MatchSystemCurrency();
3433 if ( pFoundEntry )
3435 return false; // break loop
3436 // even if there are more matching entries
3437 // this one is propably the one we are looking for
3439 else
3441 pFoundEntry = pData;
3444 else
3446 pFoundEntry = pData;
3449 return true;
3453 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat, OUString& rStr,
3454 const NfCurrencyEntry** ppEntry /* = NULL */,
3455 bool* pBank /* = NULL */ ) const
3457 if ( ppEntry )
3458 *ppEntry = NULL;
3459 if ( pBank )
3460 *pBank = false;
3462 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
3463 if ( pFormat )
3465 OUStringBuffer sBuff(128); // guess-estimate of a value that will pretty much garantee no re-alloc
3466 OUString aSymbol, aExtension;
3467 if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3469 if ( ppEntry )
3471 bool bFoundBank = false;
3472 // we definiteley need an entry matching the format code string
3473 const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3474 bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3475 true );
3476 if ( pFoundEntry )
3478 *ppEntry = pFoundEntry;
3479 if ( pBank )
3480 *pBank = bFoundBank;
3481 rStr = pFoundEntry->BuildSymbolString(bFoundBank);
3484 if ( rStr.isEmpty() )
3485 { // analog to BuildSymbolString
3486 sBuff.append("[$");
3487 if ( aSymbol.indexOf( '-' ) != -1 ||
3488 aSymbol.indexOf( ']' ) != -1 )
3490 sBuff.append('"');
3491 sBuff.append( aSymbol);
3492 sBuff.append('"');
3494 else
3496 sBuff.append(aSymbol);
3498 if ( !aExtension.isEmpty() )
3500 sBuff.append(aExtension);
3502 sBuff.append(']');
3504 rStr = sBuff.toString();
3505 return true;
3508 rStr = "";
3509 return false;
3513 // static
3514 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank,
3515 const OUString& rSymbol,
3516 const OUString& rExtension,
3517 LanguageType eFormatLanguage,
3518 bool bOnlyStringLanguage )
3520 sal_Int32 nExtLen = rExtension.getLength();
3521 LanguageType eExtLang;
3522 if ( nExtLen )
3524 // rExtension should be a 16-bit hex value max FFFF which may contain a
3525 // leading "-" separator (that is not a minus sign, but toInt32 can be
3526 // used to parse it, with post-processing as necessary):
3527 sal_Int32 nExtLang = rExtension.toInt32( 16 );
3528 if ( !nExtLang )
3530 eExtLang = LANGUAGE_DONTKNOW;
3532 else
3534 eExtLang = (LanguageType) ((nExtLang < 0) ? -nExtLang : nExtLang);
3537 else
3539 eExtLang = LANGUAGE_DONTKNOW;
3541 const NfCurrencyEntry* pFoundEntry = NULL;
3542 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3543 sal_uInt16 nCount = rTable.size();
3544 bool bCont = true;
3546 // first try with given extension language/country
3547 if ( nExtLen )
3549 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3551 LanguageType eLang = rTable[j].GetLanguage();
3552 if ( eLang == eExtLang ||
3553 ((eExtLang == LANGUAGE_DONTKNOW) &&
3554 (eLang == LANGUAGE_SYSTEM)))
3556 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3557 &rTable[j], j, rSymbol );
3562 // ok?
3563 if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3565 return pFoundEntry;
3567 if ( !bOnlyStringLanguage )
3569 // now try the language/country of the number format
3570 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3572 LanguageType eLang = rTable[j].GetLanguage();
3573 if ( eLang == eFormatLanguage ||
3574 ((eFormatLanguage == LANGUAGE_DONTKNOW) &&
3575 (eLang == LANGUAGE_SYSTEM)))
3577 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3578 &rTable[j], j, rSymbol );
3582 // ok?
3583 if ( pFoundEntry || !bCont )
3585 return pFoundEntry;
3589 // then try without language/country if no extension specified
3590 if ( !nExtLen )
3592 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3594 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3595 &rTable[j], j, rSymbol );
3599 return pFoundEntry;
3603 void SvNumberFormatter::GetCompatibilityCurrency( OUString& rSymbol, OUString& rAbbrev ) const
3605 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >
3606 xCurrencies( xLocaleData->getAllCurrencies() );
3608 const ::com::sun::star::i18n::Currency2 *pCurrencies = xCurrencies.getConstArray();
3609 sal_Int32 nCurrencies = xCurrencies.getLength();
3611 sal_Int32 j;
3612 for ( j=0; j < nCurrencies; ++j )
3614 if ( pCurrencies[j].UsedInCompatibleFormatCodes )
3616 rSymbol = pCurrencies[j].Symbol;
3617 rAbbrev = pCurrencies[j].BankSymbol;
3618 break;
3621 if ( j >= nCurrencies )
3623 if (LocaleDataWrapper::areChecksEnabled())
3625 LocaleDataWrapper::outputCheckMessage( xLocaleData->
3626 appendLocaleInfo( "GetCompatibilityCurrency: none?"));
3628 rSymbol = xLocaleData->getCurrSymbol();
3629 rAbbrev = xLocaleData->getCurrBankSymbol();
3634 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
3636 switch ( rCurr.GetPositiveFormat() )
3638 case 0: // $1
3639 case 1: // 1$
3640 case 2: // $ 1
3641 case 3: // 1 $
3642 break;
3643 default:
3644 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3645 break;
3647 switch ( rCurr.GetNegativeFormat() )
3649 case 0: // ($1)
3650 case 1: // -$1
3651 case 2: // $-1
3652 case 3: // $1-
3653 case 4: // (1$)
3654 case 5: // -1$
3655 case 6: // 1-$
3656 case 7: // 1$-
3657 case 8: // -1 $
3658 case 9: // -$ 1
3659 case 10: // 1 $-
3660 case 11: // $ -1
3661 case 12 : // $ 1-
3662 case 13 : // 1- $
3663 case 14 : // ($ 1)
3664 case 15 : // (1 $)
3665 break;
3666 default:
3667 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3668 break;
3672 // static
3673 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang )
3675 // The set is initialized as a side effect of the currency table
3676 // created, make sure that exists, which usually is the case unless a
3677 // SvNumberFormatter was never instanciated.
3678 GetTheCurrencyTable();
3679 const NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3680 return rInstalledLocales.find( eLang) != rInstalledLocales.end();
3683 // static
3684 void SvNumberFormatter::ImpInitCurrencyTable()
3686 // racing condition possible:
3687 // ::osl::MutexGuard aGuard( GetMutex() );
3688 // while ( !bCurrencyTableInitialized )
3689 // ImpInitCurrencyTable();
3690 static bool bInitializing = false;
3691 if ( bCurrencyTableInitialized || bInitializing )
3693 return ;
3695 bInitializing = true;
3697 LanguageType eSysLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3698 LocaleDataWrapper* pLocaleData = new LocaleDataWrapper(
3699 ::comphelper::getProcessComponentContext(),
3700 SvtSysLocale().GetLanguageTag() );
3701 // get user configured currency
3702 OUString aConfiguredCurrencyAbbrev;
3703 LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
3704 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3705 aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
3706 sal_uInt16 nSecondarySystemCurrencyPosition = 0;
3707 sal_uInt16 nMatchingSystemCurrencyPosition = 0;
3708 NfCurrencyEntry* pEntry;
3710 // first entry is SYSTEM
3711 pEntry = new NfCurrencyEntry( *pLocaleData, LANGUAGE_SYSTEM );
3712 theCurrencyTable::get().insert( theCurrencyTable::get().begin(), pEntry );
3713 sal_uInt16 nCurrencyPos = 1;
3715 ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc =
3716 LocaleDataWrapper::getInstalledLocaleNames();
3717 sal_Int32 nLocaleCount = xLoc.getLength();
3718 SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount << "\"" );
3719 Locale const * const pLocales = xLoc.getConstArray();
3720 NfCurrencyTable &rCurrencyTable = theCurrencyTable::get();
3721 NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get();
3722 NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3723 sal_uInt16 nLegacyOnlyCurrencyPos = 0;
3724 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
3726 LanguageType eLang = LanguageTag::convertToLanguageType( pLocales[nLocale], false);
3727 rInstalledLocales.insert( eLang);
3728 pLocaleData->setLanguageTag( LanguageTag( pLocales[nLocale]) );
3729 Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
3730 sal_Int32 nCurrencyCount = aCurrSeq.getLength();
3731 Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
3733 // one default currency for each locale, insert first so it is found first
3734 sal_Int32 nDefault;
3735 for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3737 if ( pCurrencies[nDefault].Default )
3738 break;
3740 if ( nDefault < nCurrencyCount )
3742 pEntry = new NfCurrencyEntry( pCurrencies[nDefault], *pLocaleData, eLang );
3744 else
3746 pEntry = new NfCurrencyEntry( *pLocaleData, eLang ); // first or ShellsAndPebbles
3748 if (LocaleDataWrapper::areChecksEnabled())
3750 lcl_CheckCurrencySymbolPosition( *pEntry );
3752 rCurrencyTable.insert( rCurrencyTable.begin() + nCurrencyPos++, pEntry );
3753 if ( !nSystemCurrencyPosition && (!aConfiguredCurrencyAbbrev.isEmpty() ?
3754 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev &&
3755 pEntry->GetLanguage() == eConfiguredCurrencyLanguage : false) )
3757 nSystemCurrencyPosition = nCurrencyPos-1;
3759 if ( !nMatchingSystemCurrencyPosition &&
3760 pEntry->GetLanguage() == eSysLang )
3762 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3764 // all remaining currencies for each locale
3765 if ( nCurrencyCount > 1 )
3767 sal_Int32 nCurrency;
3768 for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
3770 if (pCurrencies[nCurrency].LegacyOnly)
3772 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3773 rLegacyOnlyCurrencyTable.insert( rLegacyOnlyCurrencyTable.begin() + nLegacyOnlyCurrencyPos++, pEntry );
3775 else if ( nCurrency != nDefault )
3777 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3778 // no dupes
3779 bool bInsert = true;
3780 sal_uInt16 n = rCurrencyTable.size();
3781 sal_uInt16 aCurrencyIndex = 1; // skip first SYSTEM entry
3782 for ( sal_uInt16 j=1; j<n; j++ )
3784 if ( rCurrencyTable[aCurrencyIndex++] == *pEntry )
3786 bInsert = false;
3787 break; // for
3790 if ( !bInsert )
3792 delete pEntry;
3794 else
3796 rCurrencyTable.insert( rCurrencyTable.begin() + nCurrencyPos++, pEntry );
3797 if ( !nSecondarySystemCurrencyPosition &&
3798 (!aConfiguredCurrencyAbbrev.isEmpty() ?
3799 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev :
3800 pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
3802 nSecondarySystemCurrencyPosition = nCurrencyPos-1;
3804 if ( !nMatchingSystemCurrencyPosition &&
3805 pEntry->GetLanguage() == eSysLang )
3807 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3814 if ( !nSystemCurrencyPosition )
3816 nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
3818 if ((!aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
3819 LocaleDataWrapper::areChecksEnabled())
3821 LocaleDataWrapper::outputCheckMessage(
3822 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3824 // match SYSTEM if no configured currency found
3825 if ( !nSystemCurrencyPosition )
3827 nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
3829 if ((aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
3830 LocaleDataWrapper::areChecksEnabled())
3832 LocaleDataWrapper::outputCheckMessage(
3833 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3835 delete pLocaleData;
3836 SvtSysLocaleOptions::SetCurrencyChangeLink( STATIC_LINK( NULL, SvNumberFormatter, CurrencyChangeLink ) );
3837 bInitializing = false;
3838 bCurrencyTableInitialized = true;
3842 sal_uInt16 SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr,
3843 const NfCurrencyEntry& rCurr,
3844 bool bBank ) const
3846 OUString aRed = OUStringBuffer().
3847 append('[').
3848 append(pFormatScanner->GetRedString()).
3849 append(']').makeStringAndClear();
3851 sal_uInt16 nDefault = 0;
3852 if ( bBank )
3854 // Only bank symbols.
3855 OUString aPositiveBank = rCurr.BuildPositiveFormatString(true, *xLocaleData, 1);
3856 OUString aNegativeBank = rCurr.BuildNegativeFormatString(true, *xLocaleData, 1 );
3858 OUStringBuffer format1(aPositiveBank);
3859 format1.append(';');
3860 format1.append(aNegativeBank);
3861 rStrArr.push_back(format1.makeStringAndClear());
3863 OUStringBuffer format2(aPositiveBank);
3864 format2.append(';');
3866 format2.append(aRed);
3868 format2.append(aNegativeBank);
3869 rStrArr.push_back(format2.makeStringAndClear());
3871 nDefault = rStrArr.size() - 1;
3873 else
3875 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
3876 // duplicates if no decimals in currency.
3877 OUString aPositive = rCurr.BuildPositiveFormatString(false, *xLocaleData, 1);
3878 OUString aNegative = rCurr.BuildNegativeFormatString(false, *xLocaleData, 1 );
3879 OUStringBuffer format1;
3880 OUStringBuffer format2;
3881 OUStringBuffer format3;
3882 OUStringBuffer format4;
3883 OUStringBuffer format5;
3884 if (rCurr.GetDigits())
3886 OUString aPositiveNoDec = rCurr.BuildPositiveFormatString(false, *xLocaleData, 0);
3887 OUString aNegativeNoDec = rCurr.BuildNegativeFormatString(false, *xLocaleData, 0 );
3888 OUString aPositiveDashed = rCurr.BuildPositiveFormatString(false, *xLocaleData, 2);
3889 OUString aNegativeDashed = rCurr.BuildNegativeFormatString(false, *xLocaleData, 2);
3891 format1.append(aPositiveNoDec);
3892 format1.append(';');
3893 format1.append(aNegativeNoDec);
3895 format3.append(aPositiveNoDec);
3896 format3.append(';');
3897 format3.append(aRed);
3898 format3.append(aNegativeNoDec);
3900 format5.append(aPositiveDashed);
3901 format5.append(';');
3902 format5.append(aRed);
3903 format5.append(aNegativeDashed);
3906 format2.append(aPositive);
3907 format2.append(';');
3908 format2.append(aNegative);
3910 format4.append(aPositive);
3911 format4.append(';');
3912 format4.append(aRed);
3913 format4.append(aNegative);
3915 if (rCurr.GetDigits())
3917 rStrArr.push_back(format1.makeStringAndClear());
3919 rStrArr.push_back(format2.makeStringAndClear());
3920 if (rCurr.GetDigits())
3922 rStrArr.push_back(format3.makeStringAndClear());
3924 rStrArr.push_back(format4.makeStringAndClear());
3925 nDefault = rStrArr.size() - 1;
3926 if (rCurr.GetDigits())
3928 rStrArr.push_back(format5.makeStringAndClear());
3931 return nDefault;
3935 //--- NfCurrencyEntry ----------------------------------------------------
3938 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3940 aSymbol = rLocaleData.getCurrSymbol();
3941 aBankSymbol = rLocaleData.getCurrBankSymbol();
3942 eLanguage = eLang;
3943 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3944 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3945 nDigits = rLocaleData.getCurrDigits();
3946 cZeroChar = rLocaleData.getCurrZeroChar();
3950 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency & rCurr,
3951 const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3953 aSymbol = rCurr.Symbol;
3954 aBankSymbol = rCurr.BankSymbol;
3955 eLanguage = eLang;
3956 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3957 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3958 nDigits = rCurr.DecimalPlaces;
3959 cZeroChar = rLocaleData.getCurrZeroChar();
3963 bool NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
3965 return aSymbol == r.aSymbol
3966 && aBankSymbol == r.aBankSymbol
3967 && eLanguage == r.eLanguage
3971 OUString NfCurrencyEntry::BuildSymbolString(bool bBank,
3972 bool bWithoutExtension) const
3974 OUStringBuffer aBuf("[$");
3975 if (bBank)
3977 aBuf.append(aBankSymbol);
3979 else
3981 if ( aSymbol.indexOf( (sal_Unicode)'-' ) >= 0 ||
3982 aSymbol.indexOf( (sal_Unicode)']' ) >= 0)
3984 aBuf.append('"').append(aSymbol).append('"');
3986 else
3988 aBuf.append(aSymbol);
3990 if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
3992 sal_Int32 nLang = static_cast<sal_Int32>(eLanguage);
3993 aBuf.append('-').append( OUString::number(nLang, 16).toAsciiUpperCase());
3996 aBuf.append(']');
3997 return aBuf.makeStringAndClear();
4000 OUString NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper& rLoc,
4001 sal_uInt16 nDecimalFormat) const
4003 OUStringBuffer aBuf;
4004 aBuf.append('#').append(rLoc.getNumThousandSep()).append("##0");
4005 if (nDecimalFormat && nDigits)
4007 aBuf.append(rLoc.getNumDecimalSep());
4008 sal_Unicode cDecimalChar = nDecimalFormat == 2 ? '-' : cZeroChar;
4009 for (sal_uInt16 i = 0; i < nDigits; ++i)
4011 aBuf.append(cDecimalChar);
4014 return aBuf.makeStringAndClear();
4018 OUString NfCurrencyEntry::BuildPositiveFormatString(bool bBank, const LocaleDataWrapper& rLoc,
4019 sal_uInt16 nDecimalFormat) const
4021 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4022 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( rLoc.getCurrPositiveFormat(),
4023 nPositiveFormat, bBank );
4024 CompletePositiveFormatString(sBuf, bBank, nPosiForm);
4025 return sBuf.makeStringAndClear();
4029 OUString NfCurrencyEntry::BuildNegativeFormatString(bool bBank,
4030 const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
4032 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
4033 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc.getCurrNegativeFormat(),
4034 nNegativeFormat, bBank );
4035 CompleteNegativeFormatString(sBuf, bBank, nNegaForm);
4036 return sBuf.makeStringAndClear();
4040 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, bool bBank,
4041 sal_uInt16 nPosiForm) const
4043 OUString aSymStr = BuildSymbolString(bBank);
4044 NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
4048 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr, bool bBank,
4049 sal_uInt16 nNegaForm) const
4051 OUString aSymStr = BuildSymbolString(bBank);
4052 NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
4056 // static
4057 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, const OUString& rSymStr,
4058 sal_uInt16 nPositiveFormat)
4060 switch( nPositiveFormat )
4062 case 0: // $1
4063 rStr.insert(0, rSymStr);
4064 break;
4065 case 1: // 1$
4066 rStr.append(rSymStr);
4067 break;
4068 case 2: // $ 1
4070 rStr.insert(0, ' ');
4071 rStr.insert(0, rSymStr);
4073 break;
4074 case 3: // 1 $
4076 rStr.append(' ');
4077 rStr.append(rSymStr);
4079 break;
4080 default:
4081 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4082 break;
4087 // static
4088 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr,
4089 const OUString& rSymStr,
4090 sal_uInt16 nNegativeFormat)
4092 switch( nNegativeFormat )
4094 case 0: // ($1)
4096 rStr.insert(0, rSymStr);
4097 rStr.insert(0, '(');
4098 rStr.append(')');
4100 break;
4101 case 1: // -$1
4103 rStr.insert(0, rSymStr);
4104 rStr.insert(0, '-');
4106 break;
4107 case 2: // $-1
4109 rStr.insert(0, '-');
4110 rStr.insert(0, rSymStr);
4112 break;
4113 case 3: // $1-
4115 rStr.insert(0, rSymStr);
4116 rStr.append('-');
4118 break;
4119 case 4: // (1$)
4121 rStr.insert(0, '(');
4122 rStr.append(rSymStr);
4123 rStr.append(')');
4125 break;
4126 case 5: // -1$
4128 rStr.append(rSymStr);
4129 rStr.insert(0, '-');
4131 break;
4132 case 6: // 1-$
4134 rStr.append('-');
4135 rStr.append(rSymStr);
4137 break;
4138 case 7: // 1$-
4140 rStr.append(rSymStr);
4141 rStr.append('-');
4143 break;
4144 case 8: // -1 $
4146 rStr.append(' ');
4147 rStr.append(rSymStr);
4148 rStr.insert(0, '-');
4150 break;
4151 case 9: // -$ 1
4153 rStr.insert(0, ' ');
4154 rStr.insert(0, rSymStr);
4155 rStr.insert(0, '-');
4157 break;
4158 case 10: // 1 $-
4160 rStr.append(' ');
4161 rStr.append(rSymStr);
4162 rStr.append('-');
4164 break;
4165 case 11: // $ -1
4167 rStr.insert(0, " -");
4168 rStr.insert(0, rSymStr);
4170 break;
4171 case 12 : // $ 1-
4173 rStr.insert(0, ' ');
4174 rStr.insert(0, rSymStr);
4175 rStr.append('-');
4177 break;
4178 case 13 : // 1- $
4180 rStr.append('-');
4181 rStr.append(' ');
4182 rStr.append(rSymStr);
4184 break;
4185 case 14 : // ($ 1)
4187 rStr.insert(0, ' ');
4188 rStr.insert(0, rSymStr);
4189 rStr.insert(0, '(');
4190 rStr.append(')');
4192 break;
4193 case 15 : // (1 $)
4195 rStr.insert(0, '(');
4196 rStr.append(' ');
4197 rStr.append(rSymStr);
4198 rStr.append(')');
4200 break;
4201 default:
4202 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4203 break;
4208 // static
4209 sal_uInt16 NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat,
4210 sal_uInt16 nCurrFormat, bool bBank )
4212 if ( bBank )
4214 #if NF_BANKSYMBOL_FIX_POSITION
4215 (void) nIntlFormat; // avoid warnings
4216 return 3;
4217 #else
4218 switch ( nIntlFormat )
4220 case 0: // $1
4221 nIntlFormat = 2; // $ 1
4222 break;
4223 case 1: // 1$
4224 nIntlFormat = 3; // 1 $
4225 break;
4226 case 2: // $ 1
4227 break;
4228 case 3: // 1 $
4229 break;
4230 default:
4231 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4232 break;
4234 return nIntlFormat;
4235 #endif
4237 else
4238 return nCurrFormat;
4242 //! Call this only if nCurrFormat is really with parentheses!
4243 static sal_uInt16 lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat, sal_uInt16 nCurrFormat )
4245 short nSign = 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4246 switch ( nIntlFormat )
4248 case 0: // ($1)
4249 case 4: // (1$)
4250 case 14 : // ($ 1)
4251 case 15 : // (1 $)
4252 return nCurrFormat;
4253 case 1: // -$1
4254 case 5: // -1$
4255 case 8: // -1 $
4256 case 9: // -$ 1
4257 nSign = 0;
4258 break;
4259 case 2: // $-1
4260 case 6: // 1-$
4261 case 11 : // $ -1
4262 case 13 : // 1- $
4263 nSign = 1;
4264 break;
4265 case 3: // $1-
4266 case 7: // 1$-
4267 case 10: // 1 $-
4268 case 12 : // $ 1-
4269 nSign = 2;
4270 break;
4271 default:
4272 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4273 break;
4276 switch ( nCurrFormat )
4278 case 0: // ($1)
4279 switch ( nSign )
4281 case 0:
4282 return 1; // -$1
4283 case 1:
4284 return 2; // $-1
4285 case 2:
4286 return 3; // $1-
4288 break;
4289 case 4: // (1$)
4290 switch ( nSign )
4292 case 0:
4293 return 5; // -1$
4294 case 1:
4295 return 6; // 1-$
4296 case 2:
4297 return 7; // 1$-
4299 break;
4300 case 14 : // ($ 1)
4301 switch ( nSign )
4303 case 0:
4304 return 9; // -$ 1
4305 case 1:
4306 return 11; // $ -1
4307 case 2:
4308 return 12; // $ 1-
4310 break;
4311 case 15 : // (1 $)
4312 switch ( nSign )
4314 case 0:
4315 return 8; // -1 $
4316 case 1:
4317 return 13; // 1- $
4318 case 2:
4319 return 10; // 1 $-
4321 break;
4323 return nCurrFormat;
4327 // static
4328 sal_uInt16 NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat,
4329 sal_uInt16 nCurrFormat, bool bBank )
4331 if ( bBank )
4333 #if NF_BANKSYMBOL_FIX_POSITION
4334 return 8;
4335 #else
4336 switch ( nIntlFormat )
4338 case 0: // ($1)
4339 // nIntlFormat = 14; // ($ 1)
4340 nIntlFormat = 9; // -$ 1
4341 break;
4342 case 1: // -$1
4343 nIntlFormat = 9; // -$ 1
4344 break;
4345 case 2: // $-1
4346 nIntlFormat = 11; // $ -1
4347 break;
4348 case 3: // $1-
4349 nIntlFormat = 12; // $ 1-
4350 break;
4351 case 4: // (1$)
4352 // nIntlFormat = 15; // (1 $)
4353 nIntlFormat = 8; // -1 $
4354 break;
4355 case 5: // -1$
4356 nIntlFormat = 8; // -1 $
4357 break;
4358 case 6: // 1-$
4359 nIntlFormat = 13; // 1- $
4360 break;
4361 case 7: // 1$-
4362 nIntlFormat = 10; // 1 $-
4363 break;
4364 case 8: // -1 $
4365 break;
4366 case 9: // -$ 1
4367 break;
4368 case 10: // 1 $-
4369 break;
4370 case 11: // $ -1
4371 break;
4372 case 12 : // $ 1-
4373 break;
4374 case 13 : // 1- $
4375 break;
4376 case 14 : // ($ 1)
4377 // nIntlFormat = 14; // ($ 1)
4378 nIntlFormat = 9; // -$ 1
4379 break;
4380 case 15 : // (1 $)
4381 // nIntlFormat = 15; // (1 $)
4382 nIntlFormat = 8; // -1 $
4383 break;
4384 default:
4385 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4386 break;
4388 #endif
4390 else if ( nIntlFormat != nCurrFormat )
4392 switch ( nCurrFormat )
4394 case 0: // ($1)
4395 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4396 nIntlFormat, nCurrFormat );
4397 break;
4398 case 1: // -$1
4399 nIntlFormat = nCurrFormat;
4400 break;
4401 case 2: // $-1
4402 nIntlFormat = nCurrFormat;
4403 break;
4404 case 3: // $1-
4405 nIntlFormat = nCurrFormat;
4406 break;
4407 case 4: // (1$)
4408 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4409 nIntlFormat, nCurrFormat );
4410 break;
4411 case 5: // -1$
4412 nIntlFormat = nCurrFormat;
4413 break;
4414 case 6: // 1-$
4415 nIntlFormat = nCurrFormat;
4416 break;
4417 case 7: // 1$-
4418 nIntlFormat = nCurrFormat;
4419 break;
4420 case 8: // -1 $
4421 nIntlFormat = nCurrFormat;
4422 break;
4423 case 9: // -$ 1
4424 nIntlFormat = nCurrFormat;
4425 break;
4426 case 10: // 1 $-
4427 nIntlFormat = nCurrFormat;
4428 break;
4429 case 11: // $ -1
4430 nIntlFormat = nCurrFormat;
4431 break;
4432 case 12 : // $ 1-
4433 nIntlFormat = nCurrFormat;
4434 break;
4435 case 13 : // 1- $
4436 nIntlFormat = nCurrFormat;
4437 break;
4438 case 14 : // ($ 1)
4439 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4440 nIntlFormat, nCurrFormat );
4441 break;
4442 case 15 : // (1 $)
4443 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4444 nIntlFormat, nCurrFormat );
4445 break;
4446 default:
4447 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4448 break;
4451 return nIntlFormat;
4455 // we only support default encodings here
4456 // static
4457 sal_Char NfCurrencyEntry::GetEuroSymbol( rtl_TextEncoding eTextEncoding )
4459 switch ( eTextEncoding )
4461 case RTL_TEXTENCODING_MS_1252 :
4462 case RTL_TEXTENCODING_ISO_8859_1 :
4463 return '\x80';
4464 case RTL_TEXTENCODING_ISO_8859_15 :
4465 return '\xA4';
4466 case RTL_TEXTENCODING_IBM_850 :
4467 return '\xD5';
4468 case RTL_TEXTENCODING_APPLE_ROMAN :
4469 return '\xDB';
4470 default:
4471 return '\x80'; // Windows code for the converted TrueType fonts (whatever that means)
4477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */