bump product version to 5.0.4.1
[LibreOffice.git] / svl / source / numbers / zforlist.cxx
blobd17954ec99cff5da23a731e96edcd3a353413a3a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include <svl/zforlist.hxx>
24 #include <svl/currencytable.hxx>
26 #include <comphelper/string.hxx>
27 #include <tools/debug.hxx>
28 #include <unotools/charclass.hxx>
29 #include <i18nlangtag/mslangid.hxx>
30 #include <unotools/localedatawrapper.hxx>
31 #include <unotools/numberformatcodewrapper.hxx>
32 #include <unotools/calendarwrapper.hxx>
33 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
34 #include <com/sun/star/i18n/KNumberFormatType.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <unotools/misccfg.hxx>
39 #include <osl/mutex.hxx>
41 #include "zforscan.hxx"
42 #include "zforfind.hxx"
43 #include <svl/zformat.hxx>
45 #include <unotools/syslocaleoptions.hxx>
46 #include <unotools/digitgroupingiterator.hxx>
47 #include <rtl/instance.hxx>
48 #include <rtl/strbuf.hxx>
50 #include <math.h>
51 #include <limits>
52 #include <boost/scoped_ptr.hpp>
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::uno;
56 using namespace ::com::sun::star::i18n;
57 using namespace ::com::sun::star::lang;
58 using namespace ::std;
60 // Constants for type offsets per Country/Language (CL)
61 #define ZF_STANDARD 0
62 #define ZF_STANDARD_PERCENT 10
63 #define ZF_STANDARD_CURRENCY 20
64 #define ZF_STANDARD_DATE 30
65 #define ZF_STANDARD_TIME 40
66 #define ZF_STANDARD_DATETIME 50
67 #define ZF_STANDARD_SCIENTIFIC 60
68 #define ZF_STANDARD_FRACTION 70
69 #define ZF_STANDARD_NEWEXTENDED 75
70 #define ZF_STANDARD_NEWEXTENDEDMAX SV_MAX_ANZ_STANDARD_FORMATE-2 // 98
71 #define ZF_STANDARD_LOGICAL SV_MAX_ANZ_STANDARD_FORMATE-1 // 99
72 #define ZF_STANDARD_TEXT SV_MAX_ANZ_STANDARD_FORMATE // 100
74 /* Locale that is set if an unknown locale (from another system) is loaded of
75 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
76 * (old currency) is recognized as a date (#53155#). */
77 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
79 struct IndexTable
81 bool mbInitialized;
82 sal_uInt32 maData[NF_INDEX_TABLE_ENTRIES];
83 osl::Mutex maMtx;
85 IndexTable() : mbInitialized(false) {}
88 static IndexTable theIndexTable;
92 /**
93 instead of every number formatter being a listener we have a registry which
94 also handles one instance of the SysLocale options
97 typedef ::std::vector< SvNumberFormatter* > SvNumberFormatterList_impl;
99 class SvNumberFormatterRegistry_Impl : public utl::ConfigurationListener
101 SvNumberFormatterList_impl aFormatters;
102 SvtSysLocaleOptions aSysLocaleOptions;
103 LanguageType eSysLanguage;
105 public:
106 SvNumberFormatterRegistry_Impl();
107 virtual ~SvNumberFormatterRegistry_Impl();
109 void Insert( SvNumberFormatter* pThis )
110 { aFormatters.push_back( pThis ); }
112 SvNumberFormatter* Remove( SvNumberFormatter* pThis );
114 size_t Count()
115 { return aFormatters.size(); }
117 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 ) SAL_OVERRIDE;
120 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
122 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
123 aSysLocaleOptions.AddListener( this );
127 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
129 aSysLocaleOptions.RemoveListener( this );
133 SvNumberFormatter* SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter* pThis )
135 for (SvNumberFormatterList_impl::iterator it = aFormatters.begin();
136 it != aFormatters.end(); ++it)
138 if ( *it == pThis )
140 aFormatters.erase( it );
141 break;
144 return pThis;
147 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*,
148 sal_uInt32 nHint)
150 ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() );
152 if ( nHint & SYSLOCALEOPTIONS_HINT_LOCALE )
154 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
155 aFormatters[ i ]->ReplaceSystemCL( eSysLanguage );
156 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
158 if ( nHint & SYSLOCALEOPTIONS_HINT_CURRENCY )
160 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
161 aFormatters[ i ]->ResetDefaultSystemCurrency();
163 if ( nHint & SYSLOCALEOPTIONS_HINT_DATEPATTERNS )
165 for( size_t i = 0, n = aFormatters.size(); i < n; ++i )
166 aFormatters[ i ]->InvalidateDateAcceptancePatterns();
173 SvNumberFormatterRegistry_Impl* SvNumberFormatter::pFormatterRegistry = NULL;
174 bool SvNumberFormatter::bCurrencyTableInitialized = false;
175 namespace
177 struct theCurrencyTable :
178 public rtl::Static< NfCurrencyTable, theCurrencyTable > {};
180 struct theLegacyOnlyCurrencyTable :
181 public rtl::Static< NfCurrencyTable, theLegacyOnlyCurrencyTable > {};
183 /** THE set of installed locales. */
184 struct theInstalledLocales :
185 public rtl::Static< NfInstalledLocales, theInstalledLocales> {};
188 sal_uInt16 SvNumberFormatter::nSystemCurrencyPosition = 0;
190 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
191 // language dependent.
192 #define NF_BANKSYMBOL_FIX_POSITION 1
194 const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION = ::std::numeric_limits<sal_uInt16>::max();
195 const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1;
197 SvNumberFormatter::SvNumberFormatter( const Reference< XComponentContext >& rxContext,
198 LanguageType eLang )
199 : m_xContext( rxContext )
200 , maLanguageTag( eLang)
202 ImpConstruct( eLang );
205 SvNumberFormatter::~SvNumberFormatter()
208 ::osl::MutexGuard aGuard( GetMutex() );
209 pFormatterRegistry->Remove( this );
210 if ( !pFormatterRegistry->Count() )
212 delete pFormatterRegistry;
213 pFormatterRegistry = NULL;
217 for (SvNumberFormatTable::iterator it = aFTable.begin(); it != aFTable.end(); ++it)
218 delete it->second;
219 delete pFormatTable;
220 delete pCharClass;
221 delete pStringScanner;
222 delete pFormatScanner;
223 ClearMergeTable();
224 delete pMergeTable;
228 void SvNumberFormatter::ImpConstruct( LanguageType eLang )
230 if ( eLang == LANGUAGE_DONTKNOW )
232 eLang = UNKNOWN_SUBSTITUTE;
234 IniLnge = eLang;
235 ActLnge = eLang;
236 eEvalDateFormat = NF_EVALDATEFORMAT_INTL;
237 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
239 maLanguageTag.reset( eLang );
240 pCharClass = new CharClass( m_xContext, maLanguageTag );
241 xLocaleData.init( m_xContext, maLanguageTag );
242 xCalendar.init( m_xContext, maLanguageTag.getLocale() );
243 xTransliteration.init( m_xContext, eLang,
244 ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE );
245 xNatNum.init( m_xContext );
247 // cached locale data items
248 const LocaleDataWrapper* pLoc = GetLocaleData();
249 aDecimalSep = pLoc->getNumDecimalSep();
250 aThousandSep = pLoc->getNumThousandSep();
251 aDateSep = pLoc->getDateSep();
253 pStringScanner = new ImpSvNumberInputScan( this );
254 pFormatScanner = new ImpSvNumberformatScan( this );
255 pFormatTable = NULL;
256 MaxCLOffset = 0;
257 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
258 pMergeTable = NULL;
259 bNoZero = false;
261 ::osl::MutexGuard aGuard( GetMutex() );
262 GetFormatterRegistry().Insert( this );
266 void SvNumberFormatter::ChangeIntl(LanguageType eLnge)
268 if (ActLnge != eLnge)
270 ActLnge = eLnge;
272 maLanguageTag.reset( eLnge );
273 pCharClass->setLanguageTag( maLanguageTag );
274 xLocaleData.changeLocale( maLanguageTag );
275 xCalendar.changeLocale( maLanguageTag.getLocale() );
276 xTransliteration.changeLocale( eLnge );
278 // cached locale data items, initialize BEFORE calling ChangeIntl below
279 const LocaleDataWrapper* pLoc = GetLocaleData();
280 aDecimalSep = pLoc->getNumDecimalSep();
281 aThousandSep = pLoc->getNumThousandSep();
282 aDateSep = pLoc->getDateSep();
284 pFormatScanner->ChangeIntl();
285 pStringScanner->ChangeIntl();
290 // static
291 ::osl::Mutex& SvNumberFormatter::GetMutex()
293 static ::osl::Mutex* pMutex = NULL;
294 if( !pMutex )
296 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
297 if( !pMutex )
299 // #i77768# Due to a static reference in the toolkit lib
300 // we need a mutex that lives longer than the svl library.
301 // Otherwise the dtor would use a destructed mutex!!
302 pMutex = new ::osl::Mutex;
305 return *pMutex;
309 // static
310 SvNumberFormatterRegistry_Impl& SvNumberFormatter::GetFormatterRegistry()
312 ::osl::MutexGuard aGuard( GetMutex() );
313 if ( !pFormatterRegistry )
315 pFormatterRegistry = new SvNumberFormatterRegistry_Impl;
317 return *pFormatterRegistry;
320 void SvNumberFormatter::SetColorLink( const Link<>& rColorTableCallBack )
322 aColorLink = rColorTableCallBack;
325 Color* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex)
327 if( aColorLink.IsSet() )
329 return reinterpret_cast<Color*>( aColorLink.Call( (void*) &nIndex )) ;
331 else
333 return NULL;
337 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay,
338 sal_uInt16 nMonth,
339 sal_uInt16 nYear)
341 pFormatScanner->ChangeNullDate(nDay, nMonth, nYear);
342 pStringScanner->ChangeNullDate(nDay, nMonth, nYear);
345 Date* SvNumberFormatter::GetNullDate()
347 return pFormatScanner->GetNullDate();
350 void SvNumberFormatter::ChangeStandardPrec(short nPrec)
352 pFormatScanner->ChangeStandardPrec(nPrec);
355 void SvNumberFormatter::SetNoZero(bool bNZ)
357 bNoZero = bNZ;
360 sal_uInt16 SvNumberFormatter::GetStandardPrec()
362 return pFormatScanner->GetStandardPrec();
365 bool SvNumberFormatter::GetNoZero()
367 return bNoZero;
370 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage )
372 sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM );
373 if ( nCLOffset > MaxCLOffset )
375 return ; // no SYSTEM entries to replace
377 const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_ANZ_STANDARD_FORMATE;
378 const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
379 sal_uInt32 nKey;
381 // remove old builtin formats
382 SvNumberFormatTable::iterator it = aFTable.find( nCLOffset );
383 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey <= nMaxBuiltin )
385 delete it->second;
386 it = aFTable.erase(it);
389 // move additional and user defined to temporary table
390 SvNumberFormatTable aOldTable;
391 while ( it != aFTable.end() && (nKey = it->first) >= nCLOffset && nKey < nNextCL )
393 aOldTable[ nKey ] = it->second;
394 it = aFTable.erase(it);
397 // generate new old builtin formats
398 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
399 ActLnge = LANGUAGE_DONTKNOW;
400 ChangeIntl( LANGUAGE_SYSTEM );
401 ImpGenerateFormats( nCLOffset, true );
403 // convert additional and user defined from old system to new system
404 SvNumberformat* pStdFormat = GetFormatEntry( nCLOffset + ZF_STANDARD );
405 sal_uInt32 nLastKey = nMaxBuiltin;
406 pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, true );
407 while ( !aOldTable.empty() )
409 nKey = aOldTable.begin()->first;
410 if ( nLastKey < nKey )
412 nLastKey = nKey;
414 SvNumberformat* pOldEntry = aOldTable.begin()->second;
415 aOldTable.erase( nKey );
416 OUString aString( pOldEntry->GetFormatstring() );
418 // Same as PutEntry() but assures key position even if format code is
419 // a duplicate. Also won't mix up any LastInsertKey.
420 ChangeIntl( eOldLanguage );
421 LanguageType eLge = eOldLanguage; // ConvertMode changes this
422 bool bCheck = false;
423 sal_Int32 nCheckPos = -1;
424 SvNumberformat* pNewEntry = new SvNumberformat( aString, pFormatScanner,
425 pStringScanner, nCheckPos, eLge );
426 if ( nCheckPos != 0 )
428 delete pNewEntry;
430 else
432 short eCheckType = pNewEntry->GetType();
433 if ( eCheckType != css::util::NumberFormat::UNDEFINED )
435 pNewEntry->SetType( eCheckType | css::util::NumberFormat::DEFINED );
437 else
439 pNewEntry->SetType( css::util::NumberFormat::DEFINED );
442 if ( !aFTable.insert( make_pair( nKey, pNewEntry) ).second )
444 delete pNewEntry;
446 else
448 bCheck = true;
451 DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
452 (void)bCheck;
454 delete pOldEntry;
456 pFormatScanner->SetConvertMode(false);
457 pStdFormat->SetLastInsertKey( sal_uInt16(nLastKey - nCLOffset) );
459 // append new system additional formats
460 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
461 GetLanguageTag().getLocale() );
462 ImpGenerateAdditionalFormats( nCLOffset, aNumberFormatCode, true );
465 css::uno::Reference<css::uno::XComponentContext> SvNumberFormatter::GetComponentContext() const
467 return m_xContext;
470 const ImpSvNumberformatScan* SvNumberFormatter::GetFormatScanner() const { return pFormatScanner; }
472 const LanguageTag& SvNumberFormatter::GetLanguageTag() const { return maLanguageTag; }
474 const ::utl::TransliterationWrapper* SvNumberFormatter::GetTransliteration() const
476 return xTransliteration.get();
479 const CharClass* SvNumberFormatter::GetCharClass() const { return pCharClass; }
481 const LocaleDataWrapper* SvNumberFormatter::GetLocaleData() const { return xLocaleData.get(); }
483 CalendarWrapper* SvNumberFormatter::GetCalendar() const { return xCalendar.get(); }
485 const NativeNumberWrapper* SvNumberFormatter::GetNatNum() const { return xNatNum.get(); }
487 const OUString& SvNumberFormatter::GetNumDecimalSep() const { return aDecimalSep; }
489 const OUString& SvNumberFormatter::GetNumThousandSep() const { return aThousandSep; }
491 const OUString& SvNumberFormatter::GetDateSep() const { return aDateSep; }
493 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const
495 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
497 return pFormat && pFormat->IsTextFormat();
500 bool SvNumberFormatter::PutEntry(OUString& rString,
501 sal_Int32& nCheckPos,
502 short& nType,
503 sal_uInt32& nKey, // format key
504 LanguageType eLnge)
506 nKey = 0;
507 if (rString.isEmpty()) // empty string
509 nCheckPos = 1; // -> Error
510 return false;
512 if (eLnge == LANGUAGE_DONTKNOW)
514 eLnge = IniLnge;
516 ChangeIntl(eLnge); // change locale if necessary
517 LanguageType eLge = eLnge; // non-const for ConvertMode
518 bool bCheck = false;
519 SvNumberformat* p_Entry = new SvNumberformat(rString,
520 pFormatScanner,
521 pStringScanner,
522 nCheckPos,
523 eLge);
525 if (nCheckPos == 0) // Format ok
526 { // Type comparison:
527 short eCheckType = p_Entry->GetType();
528 if ( eCheckType != css::util::NumberFormat::UNDEFINED)
530 p_Entry->SetType(eCheckType | css::util::NumberFormat::DEFINED);
531 nType = eCheckType;
533 else
535 p_Entry->SetType(css::util::NumberFormat::DEFINED);
536 nType = css::util::NumberFormat::DEFINED;
539 sal_uInt32 CLOffset = ImpGenerateCL(eLge); // create new standard formats if necessary
541 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge);
542 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
544 delete p_Entry;
546 else
548 SvNumberformat* pStdFormat = GetFormatEntry(CLOffset + ZF_STANDARD);
549 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
550 if (nPos+1 - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
552 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
553 delete p_Entry;
555 else if (!aFTable.insert(make_pair( nPos+1,p_Entry)).second)
557 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
558 delete p_Entry;
560 else
562 bCheck = true;
563 nKey = nPos+1;
564 pStdFormat->SetLastInsertKey((sal_uInt16) (nKey-CLOffset));
568 else
570 delete p_Entry;
572 return bCheck;
575 bool SvNumberFormatter::PutandConvertEntry(OUString& rString,
576 sal_Int32& nCheckPos,
577 short& nType,
578 sal_uInt32& nKey,
579 LanguageType eLnge,
580 LanguageType eNewLnge)
582 bool bRes;
583 if (eNewLnge == LANGUAGE_DONTKNOW)
585 eNewLnge = IniLnge;
587 pFormatScanner->SetConvertMode(eLnge, eNewLnge);
588 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
589 pFormatScanner->SetConvertMode(false);
590 return bRes;
593 bool SvNumberFormatter::PutandConvertEntrySystem(OUString& rString,
594 sal_Int32& nCheckPos,
595 short& nType,
596 sal_uInt32& nKey,
597 LanguageType eLnge,
598 LanguageType eNewLnge)
600 bool bRes;
601 if (eNewLnge == LANGUAGE_DONTKNOW)
603 eNewLnge = IniLnge;
605 pFormatScanner->SetConvertMode(eLnge, eNewLnge, true);
606 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
607 pFormatScanner->SetConvertMode(false);
608 return bRes;
611 sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( OUString & rString, LanguageType eLnge,
612 LanguageType eSysLnge, short & rType,
613 bool & rNewInserted, sal_Int32 & rCheckPos )
615 sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
616 rNewInserted = false;
617 rCheckPos = 0;
619 // #62389# empty format string (of Writer) => General standard format
620 if (rString.isEmpty())
622 // nothing
624 else if (eLnge == LANGUAGE_SYSTEM && eSysLnge != SvtSysLocale().GetLanguageTag().getLanguageType())
626 sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge );
627 if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND)
629 nKey = nOrig; // none available, maybe user-defined
631 else
633 nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguageTag().getLanguageType() );
635 if (nKey == nOrig)
637 // Not a builtin format, convert.
638 // The format code string may get modified and adapted to the real
639 // language and wouldn't match eSysLnge anymore, do that on a copy.
640 OUString aTmp( rString);
641 rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType,
642 nKey, eLnge, SvtSysLocale().GetLanguageTag().getLanguageType());
643 if (rCheckPos > 0)
645 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
646 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
650 else
652 nKey = GetEntryKey( rString, eLnge);
653 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
655 rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
656 if (rCheckPos > 0)
658 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
659 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
663 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
665 nKey = GetStandardIndex( eLnge);
667 rType = GetType( nKey);
668 // Convert any (!) old "automatic" currency format to new fixed currency
669 // default format.
670 if ((rType & css::util::NumberFormat::CURRENCY) != 0)
672 const SvNumberformat* pFormat = GetEntry( nKey);
673 if (!pFormat->HasNewCurrency())
675 if (rNewInserted)
677 DeleteEntry( nKey); // don't leave trails of rubbish
678 rNewInserted = false;
680 nKey = GetStandardFormat( css::util::NumberFormat::CURRENCY, eLnge);
683 return nKey;
686 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey)
688 delete aFTable[nKey];
689 aFTable.erase(nKey);
692 void SvNumberFormatter::GetUsedLanguages( std::vector<sal_uInt16>& rList )
694 rList.clear();
696 sal_uInt32 nOffset = 0;
697 while (nOffset <= MaxCLOffset)
699 SvNumberformat* pFormat = GetFormatEntry(nOffset);
700 if (pFormat)
702 rList.push_back( pFormat->GetLanguage() );
704 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
709 void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords,
710 LanguageType eLang )
712 ChangeIntl( eLang );
713 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
714 for ( sal_uInt16 i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i )
716 rKeywords[i] = rTable[i];
721 OUString SvNumberFormatter::GetKeyword( LanguageType eLnge, sal_uInt16 nIndex )
723 ChangeIntl(eLnge);
724 const NfKeywordTable & rTable = pFormatScanner->GetKeywords();
725 if ( nIndex < NF_KEYWORD_ENTRIES_COUNT )
727 return rTable[nIndex];
729 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
730 return OUString();
734 OUString SvNumberFormatter::GetStandardName( LanguageType eLnge )
736 ChangeIntl( eLnge );
737 return pFormatScanner->GetStandardName();
741 sal_uInt32 SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge) const
743 sal_uInt32 nOffset = 0;
744 while (nOffset <= MaxCLOffset)
746 const SvNumberformat* pFormat = GetFormatEntry(nOffset);
747 if (pFormat && pFormat->GetLanguage() == eLnge)
749 return nOffset;
751 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
753 return nOffset;
756 sal_uInt32 SvNumberFormatter::ImpIsEntry(const OUString& rString,
757 sal_uInt32 nCLOffset,
758 LanguageType eLnge)
760 sal_uInt32 res = NUMBERFORMAT_ENTRY_NOT_FOUND;
761 SvNumberFormatTable::iterator it = aFTable.find( nCLOffset);
762 while ( res == NUMBERFORMAT_ENTRY_NOT_FOUND &&
763 it != aFTable.end() && it->second->GetLanguage() == eLnge )
765 if ( rString == it->second->GetFormatstring() )
767 res = it->first;
769 else
771 ++it;
774 return res;
778 SvNumberFormatTable& SvNumberFormatter::GetFirstEntryTable(
779 short& eType,
780 sal_uInt32& FIndex,
781 LanguageType& rLnge)
783 short eTypetmp = eType;
784 if (eType == css::util::NumberFormat::ALL) // empty cell or don't care
786 rLnge = IniLnge;
788 else
790 SvNumberformat* pFormat = GetFormatEntry(FIndex);
791 if (!pFormat)
793 rLnge = IniLnge;
794 eType = css::util::NumberFormat::ALL;
795 eTypetmp = eType;
797 else
799 rLnge = pFormat->GetLanguage();
800 eType = pFormat->GetType()&~css::util::NumberFormat::DEFINED;
801 if (eType == 0)
803 eType = css::util::NumberFormat::DEFINED;
804 eTypetmp = eType;
806 else if (eType == css::util::NumberFormat::DATETIME)
808 eTypetmp = eType;
809 eType = css::util::NumberFormat::DATE;
811 else
813 eTypetmp = eType;
817 ChangeIntl(rLnge);
818 return GetEntryTable(eTypetmp, FIndex, rLnge);
821 sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge, bool bNoAdditionalFormats )
823 ChangeIntl(eLnge);
824 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
825 if (CLOffset > MaxCLOffset)
827 // new CL combination
828 if (LocaleDataWrapper::areChecksEnabled())
830 const LanguageTag& rLoadedLocale = xLocaleData->getLoadedLanguageTag();
831 if ( !rLoadedLocale.equals( maLanguageTag, true) )
833 OUString aMsg("SvNumberFormatter::ImpGenerateCL: locales don't match:");
834 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg ));
836 // test XML locale data FormatElement entries
838 uno::Sequence< i18n::FormatElement > xSeq = xLocaleData->getAllFormats();
839 // A test for completeness of formatindex="0" ...
840 // formatindex="47" is not needed here since it is done in
841 // ImpGenerateFormats().
843 // Test for dupes of formatindex="..."
844 for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ )
846 sal_Int16 nIdx = xSeq[j].formatIndex;
847 OUStringBuffer aDupes;
848 for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ )
850 if ( i != j && xSeq[i].formatIndex == nIdx )
852 aDupes.append(OUString::number( i ));
853 aDupes.append("(");
854 aDupes.append(xSeq[i].formatKey);
855 aDupes.append( ") ");
858 if ( !aDupes.isEmpty() )
860 OUStringBuffer aMsg(aDupes.getLength() + xSeq[j].formatKey.getLength() + 100);
861 aMsg.append("XML locale data FormatElement formatindex dupe: ");
862 aMsg.append(OUString::number(nIdx));
863 aMsg.append("\nFormatElements: ");
864 aMsg.append(OUString::number( j ));
865 aMsg.append("(");
866 aMsg.append( xSeq[j].formatKey );
867 aMsg.append( ") ");
868 aMsg.append(aDupes.makeStringAndClear());
869 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg.makeStringAndClear() ));
875 MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET;
876 ImpGenerateFormats( MaxCLOffset, bNoAdditionalFormats );
877 CLOffset = MaxCLOffset;
879 return CLOffset;
882 SvNumberFormatTable& SvNumberFormatter::ChangeCL(short eType,
883 sal_uInt32& FIndex,
884 LanguageType eLnge)
886 ImpGenerateCL(eLnge);
887 return GetEntryTable(eType, FIndex, ActLnge);
890 SvNumberFormatTable& SvNumberFormatter::GetEntryTable(
891 short eType,
892 sal_uInt32& FIndex,
893 LanguageType eLnge)
895 if ( pFormatTable )
897 pFormatTable->clear();
899 else
901 pFormatTable = new SvNumberFormatTable;
903 ChangeIntl(eLnge);
904 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
906 // Might generate and insert a default format for the given type
907 // (e.g. currency) => has to be done before collecting formats.
908 sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge );
910 SvNumberFormatTable::iterator it = aFTable.find( CLOffset);
912 if (eType == css::util::NumberFormat::ALL)
914 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
915 { // copy all entries to output table
916 (*pFormatTable)[ it->first ] = it->second;
917 ++it;
920 else
922 while (it != aFTable.end() && it->second->GetLanguage() == ActLnge)
923 { // copy entries of queried type to output table
924 if ((it->second->GetType()) & eType)
925 (*pFormatTable)[ it->first ] = it->second;
926 ++it;
929 if ( !pFormatTable->empty() )
930 { // select default if queried format doesn't exist or queried type or
931 // language differ from existing format
932 SvNumberformat* pEntry = GetFormatEntry(FIndex);
933 if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge )
935 FIndex = nDefaultIndex;
938 return *pFormatTable;
941 bool SvNumberFormatter::IsNumberFormat(const OUString& sString,
942 sal_uInt32& F_Index,
943 double& fOutNumber)
945 short FType;
946 const SvNumberformat* pFormat = GetFormatEntry(F_Index);
947 if (!pFormat)
949 ChangeIntl(IniLnge);
950 FType = css::util::NumberFormat::NUMBER;
952 else
954 FType = pFormat->GetType() &~css::util::NumberFormat::DEFINED;
955 if (FType == 0)
957 FType = css::util::NumberFormat::DEFINED;
959 ChangeIntl(pFormat->GetLanguage());
962 bool res;
963 short RType = FType;
964 if (RType == css::util::NumberFormat::TEXT)
966 res = false; // type text preset => no conversion to number
968 else
970 res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat);
972 if (res && !IsCompatible(FType, RType)) // non-matching type
974 switch ( RType )
976 case css::util::NumberFormat::DATE :
977 // Preserve ISO 8601 input.
978 if (pStringScanner->CanForceToIso8601( DMY))
980 F_Index = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, ActLnge );
982 else
984 F_Index = GetStandardFormat( RType, ActLnge );
986 break;
987 case css::util::NumberFormat::TIME :
988 if ( pStringScanner->GetDecPos() )
990 // 100th seconds
991 if ( pStringScanner->GetAnzNums() > 3 || fOutNumber < 0.0 )
993 F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge );
995 else
997 F_Index = GetFormatIndex( NF_TIME_MMSS00, ActLnge );
1000 else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 )
1002 F_Index = GetFormatIndex( NF_TIME_HH_MMSS, ActLnge );
1004 else
1006 F_Index = GetStandardFormat( RType, ActLnge );
1008 break;
1009 default:
1010 F_Index = GetStandardFormat( RType, ActLnge );
1013 return res;
1016 LanguageType SvNumberFormatter::GetLanguage() const
1018 return IniLnge;
1021 bool SvNumberFormatter::IsCompatible(short eOldType,
1022 short eNewType)
1024 if (eOldType == eNewType)
1026 return true;
1028 else if (eOldType == css::util::NumberFormat::DEFINED)
1030 return true;
1032 else
1034 switch (eNewType)
1036 case css::util::NumberFormat::NUMBER:
1037 switch (eOldType)
1039 case css::util::NumberFormat::PERCENT:
1040 case css::util::NumberFormat::CURRENCY:
1041 case css::util::NumberFormat::SCIENTIFIC:
1042 case css::util::NumberFormat::FRACTION:
1043 // case css::util::NumberFormat::LOGICAL:
1044 case css::util::NumberFormat::DEFINED:
1045 return true;
1046 default:
1047 return false;
1049 break;
1050 case css::util::NumberFormat::DATE:
1051 switch (eOldType)
1053 case css::util::NumberFormat::DATETIME:
1054 return true;
1055 default:
1056 return false;
1058 break;
1059 case css::util::NumberFormat::TIME:
1060 switch (eOldType)
1062 case css::util::NumberFormat::DATETIME:
1063 return true;
1064 default:
1065 return false;
1067 break;
1068 case css::util::NumberFormat::DATETIME:
1069 switch (eOldType)
1071 case css::util::NumberFormat::TIME:
1072 case css::util::NumberFormat::DATE:
1073 return true;
1074 default:
1075 return false;
1077 break;
1078 default:
1079 return false;
1085 sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( short nType )
1087 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1088 sal_uInt32 nSearch;
1089 switch( nType )
1091 case css::util::NumberFormat::DATE:
1092 nSearch = CLOffset + ZF_STANDARD_DATE;
1093 break;
1094 case css::util::NumberFormat::TIME:
1095 nSearch = CLOffset + ZF_STANDARD_TIME;
1096 break;
1097 case css::util::NumberFormat::DATETIME:
1098 nSearch = CLOffset + ZF_STANDARD_DATETIME;
1099 break;
1100 case css::util::NumberFormat::PERCENT:
1101 nSearch = CLOffset + ZF_STANDARD_PERCENT;
1102 break;
1103 case css::util::NumberFormat::SCIENTIFIC:
1104 nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1105 break;
1106 default:
1107 nSearch = CLOffset + ZF_STANDARD;
1110 DefaultFormatKeysMap::iterator it = aDefaultFormatKeys.find( nSearch);
1111 sal_uInt32 nDefaultFormat = (it != aDefaultFormatKeys.end() ?
1112 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
1113 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1115 // look for a defined standard
1116 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
1117 sal_uInt32 nKey(0);
1118 SvNumberFormatTable::iterator it2 = aFTable.find( CLOffset );
1119 while ( it2 != aFTable.end() && (nKey = it2->first ) >= CLOffset && nKey < nStopKey )
1121 const SvNumberformat* pEntry = it2->second;
1122 if ( pEntry->IsStandard() && ((pEntry->GetType() &
1123 ~css::util::NumberFormat::DEFINED) == nType) )
1125 nDefaultFormat = nKey;
1126 break; // while
1128 ++it2;
1131 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1132 { // none found, use old fixed standards
1133 switch( nType )
1135 case css::util::NumberFormat::DATE:
1136 nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1137 break;
1138 case css::util::NumberFormat::TIME:
1139 nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1140 break;
1141 case css::util::NumberFormat::DATETIME:
1142 nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1143 break;
1144 case css::util::NumberFormat::PERCENT:
1145 nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1146 break;
1147 case css::util::NumberFormat::SCIENTIFIC:
1148 nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1149 break;
1150 default:
1151 nDefaultFormat = CLOffset + ZF_STANDARD;
1154 aDefaultFormatKeys[ nSearch ] = nDefaultFormat;
1156 return nDefaultFormat;
1160 sal_uInt32 SvNumberFormatter::GetStandardFormat( short eType, LanguageType eLnge )
1162 if (eLnge == LANGUAGE_DONTKNOW)
1164 eLnge = IniLnge;
1166 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1167 switch(eType)
1169 case css::util::NumberFormat::CURRENCY:
1170 return ( eLnge == LANGUAGE_SYSTEM ) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1171 case css::util::NumberFormat::DATE:
1172 case css::util::NumberFormat::TIME:
1173 case css::util::NumberFormat::DATETIME:
1174 case css::util::NumberFormat::PERCENT:
1175 case css::util::NumberFormat::SCIENTIFIC:
1176 return ImpGetDefaultFormat( eType );
1177 case css::util::NumberFormat::FRACTION:
1178 return CLOffset + ZF_STANDARD_FRACTION;
1179 case css::util::NumberFormat::LOGICAL:
1180 return CLOffset + ZF_STANDARD_LOGICAL;
1181 case css::util::NumberFormat::TEXT:
1182 return CLOffset + ZF_STANDARD_TEXT;
1183 case css::util::NumberFormat::ALL:
1184 case css::util::NumberFormat::DEFINED:
1185 case css::util::NumberFormat::NUMBER:
1186 case css::util::NumberFormat::UNDEFINED:
1187 default:
1188 return CLOffset + ZF_STANDARD;
1192 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex,
1193 LanguageType eLnge )
1195 return
1196 nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) ||
1197 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) ||
1198 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge )
1202 sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, short eType,
1203 LanguageType eLnge )
1205 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1206 return nFIndex;
1207 else
1208 return GetStandardFormat( eType, eLnge );
1211 sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex,
1212 short eType, LanguageType eLnge )
1214 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1215 return nFIndex;
1217 switch( eType )
1219 case css::util::NumberFormat::TIME :
1221 bool bSign;
1222 if ( fNumber < 0.0 )
1224 bSign = true;
1225 fNumber = -fNumber;
1227 else
1228 bSign = false;
1229 double fSeconds = fNumber * 86400;
1230 if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) )
1231 { // with 100th seconds
1232 if ( bSign || fSeconds >= 3600 )
1233 return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge );
1234 else
1235 return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1237 else
1239 if ( bSign || fNumber >= 1.0 )
1240 return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1241 else
1242 return GetStandardFormat( eType, eLnge );
1245 default:
1246 return GetStandardFormat( eType, eLnge );
1250 sal_uInt32 SvNumberFormatter::GetEditFormat( double fNumber, sal_uInt32 nFIndex,
1251 short eType, LanguageType eLang,
1252 SvNumberformat* pFormat )
1254 sal_uInt32 nKey = nFIndex;
1255 switch ( eType )
1257 // #61619# always edit using 4-digit year
1258 case css::util::NumberFormat::DATE :
1259 if (rtl::math::approxFloor( fNumber) != fNumber)
1260 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1261 // fdo#34977 preserve time when editing even if only date was
1262 // displayed.
1263 /* FIXME: in case an ISO 8601 format was used, editing should
1264 * also use such. Unfortunately we have no builtin combined
1265 * date+time ISO format defined. Needs also locale data work.
1266 * */
1267 else
1269 // Preserve ISO 8601 format.
1270 if ( nFIndex == GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang) ||
1271 nFIndex == GetFormatIndex( NF_DATE_DIN_YYMMDD, eLang) ||
1272 nFIndex == GetFormatIndex( NF_DATE_DIN_MMDD, eLang) ||
1273 (pFormat && pFormat->IsIso8601( 0 )))
1274 nKey = GetFormatIndex( NF_DATE_DIN_YYYYMMDD, eLang);
1275 else
1276 nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1278 break;
1279 case css::util::NumberFormat::TIME :
1280 if (fNumber < 0.0 || fNumber >= 1.0)
1282 /* XXX NOTE: this is a purely arbitrary value within the limits
1283 * of a signed 16-bit. 32k hours are 3.7 years ... or
1284 * 1903-09-26 if date. */
1285 if (fabs( fNumber) * 24 < 0x7fff)
1286 nKey = GetFormatIndex( NF_TIME_HH_MMSS, eLang );
1287 // Preserve duration, use [HH]:MM:SS instead of time.
1288 else
1289 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1290 // Assume that a large value is a datetime with only time
1291 // displayed.
1293 else
1294 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1295 break;
1296 case css::util::NumberFormat::DATETIME :
1297 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1298 /* FIXME: in case an ISO 8601 format was used, editing should
1299 * also use such. Unfortunately we have no builtin combined
1300 * date+time ISO format defined. Needs also locale data work. */
1301 break;
1302 default:
1303 nKey = GetStandardFormat( fNumber, nFIndex, eType, eLang );
1305 return nKey;
1308 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1309 sal_uInt32 nFIndex,
1310 OUString& sOutString)
1312 Color* pColor;
1313 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1314 if (!pFormat)
1316 pFormat = GetFormatEntry(ZF_STANDARD);
1319 LanguageType eLang = pFormat->GetLanguage();
1320 ChangeIntl( eLang );
1322 short eType = pFormat->GetType() & ~css::util::NumberFormat::DEFINED;
1323 if (eType == 0)
1325 eType = css::util::NumberFormat::DEFINED;
1328 sal_uInt16 nOldPrec = pFormatScanner->GetStandardPrec();
1329 bool bPrecChanged = false;
1330 if (eType == css::util::NumberFormat::NUMBER ||
1331 eType == css::util::NumberFormat::PERCENT ||
1332 eType == css::util::NumberFormat::CURRENCY ||
1333 eType == css::util::NumberFormat::SCIENTIFIC ||
1334 eType == css::util::NumberFormat::FRACTION)
1336 if (eType != css::util::NumberFormat::PERCENT) // special treatment of % later
1338 eType = css::util::NumberFormat::NUMBER;
1340 ChangeStandardPrec(INPUTSTRING_PRECISION);
1341 bPrecChanged = true;
1344 sal_uInt32 nKey = GetEditFormat( fOutNumber, nFIndex, eType, eLang, pFormat);
1345 if ( nKey != nFIndex )
1347 pFormat = GetFormatEntry( nKey );
1349 if (pFormat)
1351 if ( eType == css::util::NumberFormat::TIME && pFormat->GetFormatPrecision() )
1353 ChangeStandardPrec(INPUTSTRING_PRECISION);
1354 bPrecChanged = true;
1356 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1358 if (bPrecChanged)
1360 ChangeStandardPrec(nOldPrec);
1364 void SvNumberFormatter::GetOutputString(const OUString& sString,
1365 sal_uInt32 nFIndex,
1366 OUString& sOutString,
1367 Color** ppColor,
1368 bool bUseStarFormat )
1370 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1371 if (!pFormat)
1373 pFormat = GetFormatEntry(ZF_STANDARD_TEXT);
1375 if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1377 *ppColor = NULL;
1378 sOutString = sString;
1380 else
1382 ChangeIntl(pFormat->GetLanguage());
1383 if ( bUseStarFormat )
1385 pFormat->SetStarFormatSupport( true );
1387 pFormat->GetOutputString(sString, sOutString, ppColor);
1388 if ( bUseStarFormat )
1390 pFormat->SetStarFormatSupport( false );
1395 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1396 sal_uInt32 nFIndex,
1397 OUString& sOutString,
1398 Color** ppColor,
1399 bool bUseStarFormat )
1401 if (bNoZero && fOutNumber == 0.0)
1403 sOutString.clear();
1404 return;
1406 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
1407 if (!pFormat)
1408 pFormat = GetFormatEntry(ZF_STANDARD);
1409 ChangeIntl(pFormat->GetLanguage());
1410 if ( bUseStarFormat )
1411 pFormat->SetStarFormatSupport( true );
1412 pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1413 if ( bUseStarFormat )
1414 pFormat->SetStarFormatSupport( false );
1417 bool SvNumberFormatter::GetPreviewString(const OUString& sFormatString,
1418 double fPreviewNumber,
1419 OUString& sOutString,
1420 Color** ppColor,
1421 LanguageType eLnge,
1422 bool bUseStarFormat )
1424 if (sFormatString.isEmpty()) // no empty string
1426 return false;
1428 sal_uInt32 nKey;
1429 if (eLnge == LANGUAGE_DONTKNOW)
1431 eLnge = IniLnge;
1433 ChangeIntl(eLnge); // change locale if necessary
1434 eLnge = ActLnge;
1435 sal_Int32 nCheckPos = -1;
1436 OUString sTmpString = sFormatString;
1437 boost::scoped_ptr<SvNumberformat> p_Entry(new SvNumberformat(sTmpString,
1438 pFormatScanner,
1439 pStringScanner,
1440 nCheckPos,
1441 eLnge));
1442 if (nCheckPos == 0) // String ok
1444 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
1445 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge);
1446 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
1448 GetOutputString(fPreviewNumber, nKey, sOutString, ppColor, bUseStarFormat);
1450 else
1452 if ( bUseStarFormat )
1454 p_Entry->SetStarFormatSupport( true );
1456 p_Entry->GetOutputString(fPreviewNumber, sOutString, ppColor);
1457 if ( bUseStarFormat )
1459 p_Entry->SetStarFormatSupport( false );
1462 return true;
1464 else
1466 return false;
1470 bool SvNumberFormatter::GetPreviewStringGuess( const OUString& sFormatString,
1471 double fPreviewNumber,
1472 OUString& sOutString,
1473 Color** ppColor,
1474 LanguageType eLnge )
1476 if (sFormatString.isEmpty()) // no empty string
1478 return false;
1480 if (eLnge == LANGUAGE_DONTKNOW)
1482 eLnge = IniLnge;
1484 ChangeIntl( eLnge );
1485 eLnge = ActLnge;
1486 bool bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1488 OUString aFormatStringUpper( pCharClass->uppercase( sFormatString ) );
1489 sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1490 sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1491 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1493 // Target format present
1494 GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1495 return true;
1498 boost::scoped_ptr<SvNumberformat> pEntry;
1499 sal_Int32 nCheckPos = -1;
1500 OUString sTmpString;
1502 if ( bEnglish )
1504 sTmpString = sFormatString;
1505 pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner,
1506 pStringScanner, nCheckPos, eLnge ));
1508 else
1510 nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1511 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1512 bool bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1514 // Try English -> other or convert english to other
1515 LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1516 pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge );
1517 sTmpString = sFormatString;
1518 pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner,
1519 pStringScanner, nCheckPos, eFormatLang ));
1520 pFormatScanner->SetConvertMode( false );
1521 ChangeIntl( eLnge );
1523 if ( !bEnglishFormat )
1525 if ( !(nCheckPos == 0) || xTransliteration->isEqual( sFormatString,
1526 pEntry->GetFormatstring() ) )
1528 // other Format
1529 sTmpString = sFormatString;
1530 pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner,
1531 pStringScanner, nCheckPos, eLnge ));
1533 else
1535 // verify english
1536 sal_Int32 nCheckPos2 = -1;
1537 // try other --> english
1538 eFormatLang = eLnge;
1539 pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US );
1540 sTmpString = sFormatString;
1541 boost::scoped_ptr<SvNumberformat> pEntry2(new SvNumberformat( sTmpString, pFormatScanner,
1542 pStringScanner, nCheckPos2, eFormatLang ));
1543 pFormatScanner->SetConvertMode( false );
1544 ChangeIntl( eLnge );
1545 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1546 pEntry2->GetFormatstring() ) )
1548 // other Format
1549 sTmpString = sFormatString;
1550 pEntry.reset(new SvNumberformat( sTmpString, pFormatScanner,
1551 pStringScanner, nCheckPos, eLnge ));
1557 if (nCheckPos == 0) // String ok
1559 ImpGenerateCL( eLnge ); // create new standard formats if necessary
1560 pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1561 return true;
1563 return false;
1566 bool SvNumberFormatter::GetPreviewString( const OUString& sFormatString,
1567 const OUString& sPreviewString,
1568 OUString& sOutString,
1569 Color** ppColor,
1570 LanguageType eLnge )
1572 if (sFormatString.isEmpty()) // no empty string
1574 return false;
1576 sal_uInt32 nKey;
1577 if (eLnge == LANGUAGE_DONTKNOW)
1579 eLnge = IniLnge;
1581 ChangeIntl(eLnge); // switch if needed
1582 eLnge = ActLnge;
1583 sal_Int32 nCheckPos = -1;
1584 OUString sTmpString = sFormatString;
1585 boost::scoped_ptr<SvNumberformat> p_Entry(new SvNumberformat( sTmpString,
1586 pFormatScanner,
1587 pStringScanner,
1588 nCheckPos,
1589 eLnge));
1590 if (nCheckPos == 0) // String ok
1592 // May have to create standard formats for this locale.
1593 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1594 nKey = ImpIsEntry( p_Entry->GetFormatstring(), CLOffset, eLnge);
1595 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
1597 GetOutputString( sPreviewString, nKey, sOutString, ppColor);
1599 else
1601 // If the format is valid but not a text format and does not
1602 // include a text subformat, an empty string would result. Same as
1603 // in SvNumberFormatter::GetOutputString()
1604 if (p_Entry->IsTextFormat() || p_Entry->HasTextFormat())
1606 p_Entry->GetOutputString( sPreviewString, sOutString, ppColor);
1608 else
1610 *ppColor = NULL;
1611 sOutString = sPreviewString;
1614 return true;
1616 else
1618 return false;
1622 sal_uInt32 SvNumberFormatter::TestNewString(const OUString& sFormatString,
1623 LanguageType eLnge)
1625 if (sFormatString.isEmpty()) // no empty string
1627 return NUMBERFORMAT_ENTRY_NOT_FOUND;
1629 if (eLnge == LANGUAGE_DONTKNOW)
1631 eLnge = IniLnge;
1633 ChangeIntl(eLnge); // change locale if necessary
1634 eLnge = ActLnge;
1635 sal_uInt32 nRes;
1636 sal_Int32 nCheckPos = -1;
1637 OUString sTmpString = sFormatString;
1638 boost::scoped_ptr<SvNumberformat> pEntry(new SvNumberformat(sTmpString,
1639 pFormatScanner,
1640 pStringScanner,
1641 nCheckPos,
1642 eLnge));
1643 if (nCheckPos == 0) // String ok
1645 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
1646 nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge);
1647 // already present?
1649 else
1651 nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1653 return nRes;
1656 SvNumberformat* SvNumberFormatter::ImpInsertFormat( const ::com::sun::star::i18n::NumberFormatCode& rCode,
1657 sal_uInt32 nPos, bool bAfterChangingSystemCL,
1658 sal_Int16 nOrgIndex )
1660 OUString aCodeStr( rCode.Code );
1661 if ( rCode.Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
1662 rCode.Usage == ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY &&
1663 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1664 { // strip surrounding [$...] on automatic currency
1665 if ( aCodeStr.indexOf( "[$" ) >= 0)
1666 aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr, false );
1667 else
1669 if (LocaleDataWrapper::areChecksEnabled() &&
1670 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1672 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index " +
1673 OUString::number( rCode.Index) +
1674 ":\n" +
1675 rCode.Code;
1676 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1680 sal_Int32 nCheckPos = 0;
1681 SvNumberformat* pFormat = new SvNumberformat(aCodeStr,
1682 pFormatScanner,
1683 pStringScanner,
1684 nCheckPos,
1685 ActLnge);
1686 if (nCheckPos != 0)
1688 if (LocaleDataWrapper::areChecksEnabled())
1690 OUString aMsg = "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
1691 OUString::number( rCode.Index ) +
1692 "\n" +
1693 rCode.Code;
1694 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1696 delete pFormat;
1697 return NULL;
1699 if ( rCode.Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
1701 sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
1702 sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
1703 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1705 // If bAfterChangingSystemCL there will definitely be some dups,
1706 // don't cry then.
1707 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL)
1709 // Test for duplicate indexes in locale data.
1710 switch ( nOrgIndex )
1712 // These may be dups of integer versions for locales where
1713 // currencies have no decimals like Italian Lira.
1714 case NF_CURRENCY_1000DEC2 : // NF_CURRENCY_1000INT
1715 case NF_CURRENCY_1000DEC2_RED : // NF_CURRENCY_1000INT_RED
1716 case NF_CURRENCY_1000DEC2_DASHED : // NF_CURRENCY_1000INT_RED
1717 break;
1718 default:
1720 OUString aMsg("SvNumberFormatter::ImpInsertFormat: dup format code, index ");
1721 aMsg += OUString::number( rCode.Index );
1722 aMsg += "\n";
1723 aMsg += rCode.Code;
1724 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1728 delete pFormat;
1729 return NULL;
1731 else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
1733 if (LocaleDataWrapper::areChecksEnabled())
1735 OUString aMsg( "SvNumberFormatter::ImpInsertFormat: too many format codes, index ");
1736 aMsg += OUString::number( rCode.Index );
1737 aMsg += "\n";
1738 aMsg += rCode.Code;
1739 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1741 delete pFormat;
1742 return NULL;
1745 if ( !aFTable.insert( make_pair( nPos, pFormat) ).second )
1747 if (LocaleDataWrapper::areChecksEnabled())
1749 OUString aMsg( "ImpInsertFormat: can't insert number format key pos: ");
1750 aMsg += OUString::number( nPos );
1751 aMsg += ", code index ";
1752 aMsg += OUString::number( rCode.Index );
1753 aMsg += "\n";
1754 aMsg += rCode.Code;
1755 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( aMsg));
1757 else
1759 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
1761 delete pFormat;
1762 return NULL;
1764 if ( rCode.Default )
1765 pFormat->SetStandard();
1766 if ( !rCode.DefaultName.isEmpty() )
1767 pFormat->SetComment( rCode.DefaultName );
1768 return pFormat;
1771 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
1772 bool& bThousand,
1773 bool& IsRed,
1774 sal_uInt16& nPrecision,
1775 sal_uInt16& nAnzLeading)
1778 SvNumberformat* pFormat = GetFormatEntry( nFormat );
1779 if (pFormat)
1780 pFormat->GetFormatSpecialInfo(bThousand, IsRed,
1781 nPrecision, nAnzLeading);
1782 else
1784 bThousand = false;
1785 IsRed = false;
1786 nPrecision = pFormatScanner->GetStandardPrec();
1787 nAnzLeading = 0;
1791 sal_uInt16 SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
1793 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
1794 if ( pFormat )
1795 return pFormat->GetFormatPrecision();
1796 else
1797 return pFormatScanner->GetStandardPrec();
1800 sal_uInt16 SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat ) const
1802 const SvNumberformat* pFormat = GetFormatEntry( nFormat );
1803 if ( pFormat )
1804 return pFormat->GetFormatIntegerDigits();
1805 else
1806 return 1;
1809 sal_Unicode SvNumberFormatter::GetDecSep() const
1811 return GetNumDecimalSep()[0];
1814 OUString SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
1816 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
1817 if ( !pFormat || pFormat->GetLanguage() == ActLnge )
1819 return GetNumDecimalSep();
1821 OUString aRet;
1822 LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
1823 if ( pFormat->GetLanguage() == eSaveLang )
1825 aRet = xLocaleData->getNumDecimalSep();
1827 else
1829 LanguageTag aSaveLocale( xLocaleData->getLanguageTag() );
1830 const_cast<SvNumberFormatter*>(this)->xLocaleData.changeLocale( LanguageTag( pFormat->GetLanguage()) );
1831 aRet = xLocaleData->getNumDecimalSep();
1832 const_cast<SvNumberFormatter*>(this)->xLocaleData.changeLocale( aSaveLocale );
1834 return aRet;
1838 sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const OUString& rFormatString,
1839 bool& bThousand, bool& IsRed, sal_uInt16& nPrecision,
1840 sal_uInt16& nAnzLeading, LanguageType eLnge )
1843 if (eLnge == LANGUAGE_DONTKNOW)
1845 eLnge = IniLnge;
1847 ChangeIntl(eLnge); // change locale if necessary
1848 eLnge = ActLnge;
1849 OUString aTmpStr( rFormatString );
1850 sal_Int32 nCheckPos = 0;
1851 boost::scoped_ptr<SvNumberformat> pFormat(new SvNumberformat( aTmpStr, pFormatScanner,
1852 pStringScanner, nCheckPos, eLnge ));
1853 if ( nCheckPos == 0 )
1855 pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nAnzLeading );
1857 else
1859 bThousand = false;
1860 IsRed = false;
1861 nPrecision = pFormatScanner->GetStandardPrec();
1862 nAnzLeading = 0;
1864 return nCheckPos;
1868 inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff )
1870 osl::MutexGuard aGuard(&theIndexTable.maMtx);
1872 if (!theIndexTable.mbInitialized)
1874 DBG_ASSERT(theIndexTable.maData[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
1875 "SetIndexTable: theIndexTable[nTabOff] already occupied" );
1876 theIndexTable.maData[nTabOff] = nIndOff;
1878 return nIndOff;
1882 sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex(
1883 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode >& rSeq,
1884 const NfIndexTableOffset nTabOff )
1886 const sal_Int32 nLen = rSeq.getLength();
1887 for ( sal_Int32 j=0; j<nLen; j++ )
1889 if ( rSeq[j].Index == nTabOff )
1890 return j;
1892 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START
1893 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
1894 || nTabOff == NF_CURRENCY_1000INT_RED
1895 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
1896 { // currency entries with decimals might not exist, e.g. Italian Lira
1897 OUString aMsg( "SvNumberFormatter::ImpGetFormatCodeIndex: not found: " );
1898 aMsg += OUString::number( nTabOff );
1899 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo(aMsg));
1901 if ( nLen )
1903 sal_Int32 j;
1904 // look for a preset default
1905 for ( j=0; j<nLen; j++ )
1907 if ( rSeq[j].Default )
1908 return j;
1910 // currencies are special, not all format codes must exist, but all
1911 // builtin number format key index positions must have a format assigned
1912 if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
1914 // look for a format with decimals
1915 for ( j=0; j<nLen; j++ )
1917 if ( rSeq[j].Index == NF_CURRENCY_1000DEC2 )
1918 return j;
1920 // last resort: look for a format without decimals
1921 for ( j=0; j<nLen; j++ )
1923 if ( rSeq[j].Index == NF_CURRENCY_1000INT )
1924 return j;
1928 else
1929 { // we need at least _some_ format
1930 rSeq.realloc(1);
1931 rSeq[0] = ::com::sun::star::i18n::NumberFormatCode();
1932 rSeq[0].Code = OUStringBuffer().
1933 append('0').
1934 append(GetNumDecimalSep()).
1935 append("############").
1936 makeStringAndClear();
1938 return 0;
1942 sal_Int32 SvNumberFormatter::ImpAdjustFormatCodeDefault(
1943 ::com::sun::star::i18n::NumberFormatCode * pFormatArr,
1944 sal_Int32 nCnt, bool bCheckCorrectness )
1946 using namespace ::com::sun::star;
1948 if ( !nCnt )
1949 return -1;
1950 if (bCheckCorrectness && LocaleDataWrapper::areChecksEnabled())
1952 // check the locale data for correctness
1953 OStringBuffer aMsg;
1954 sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
1955 nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
1956 for ( nElem = 0; nElem < nCnt; nElem++ )
1958 switch ( pFormatArr[nElem].Type )
1960 case i18n::KNumberFormatType::SHORT :
1961 nShort = nElem;
1962 break;
1963 case i18n::KNumberFormatType::MEDIUM :
1964 nMedium = nElem;
1965 break;
1966 case i18n::KNumberFormatType::LONG :
1967 nLong = nElem;
1968 break;
1969 default:
1970 aMsg.append("unknown type");
1972 if ( pFormatArr[nElem].Default )
1974 switch ( pFormatArr[nElem].Type )
1976 case i18n::KNumberFormatType::SHORT :
1977 if ( nShortDef != -1 )
1978 aMsg.append("dupe short type default");
1979 nShortDef = nElem;
1980 break;
1981 case i18n::KNumberFormatType::MEDIUM :
1982 if ( nMediumDef != -1 )
1983 aMsg.append("dupe medium type default");
1984 nMediumDef = nElem;
1985 break;
1986 case i18n::KNumberFormatType::LONG :
1987 if ( nLongDef != -1 )
1988 aMsg.append("dupe long type default");
1989 nLongDef = nElem;
1990 break;
1993 if (!aMsg.isEmpty())
1995 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
1996 aMsg.append("\nXML locale data FormatElement formatindex: ");
1997 aMsg.append(static_cast<sal_Int32>(pFormatArr[nElem].Index));
1998 OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(),
1999 RTL_TEXTENCODING_ASCII_US));
2000 LocaleDataWrapper::outputCheckMessage(xLocaleData->appendLocaleInfo(aUMsg));
2003 if ( nShort != -1 && nShortDef == -1 )
2004 aMsg.append("no short type default ");
2005 if ( nMedium != -1 && nMediumDef == -1 )
2006 aMsg.append("no medium type default ");
2007 if ( nLong != -1 && nLongDef == -1 )
2008 aMsg.append("no long type default ");
2009 if (!aMsg.isEmpty())
2011 aMsg.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2012 aMsg.append("\nXML locale data FormatElement group of: ");
2013 OUString aUMsg(OStringToOUString(aMsg.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US));
2014 LocaleDataWrapper::outputCheckMessage(
2015 xLocaleData->appendLocaleInfo(aUMsg + pFormatArr[0].NameID));
2018 // find the default (medium preferred, then long) and reset all other defaults
2019 sal_Int32 nElem, nDef, nMedium;
2020 nDef = nMedium = -1;
2021 for ( nElem = 0; nElem < nCnt; nElem++ )
2023 if ( pFormatArr[nElem].Default )
2025 switch ( pFormatArr[nElem].Type )
2027 case i18n::KNumberFormatType::MEDIUM :
2028 nDef = nMedium = nElem;
2029 break;
2030 case i18n::KNumberFormatType::LONG :
2031 if ( nMedium == -1 )
2032 nDef = nElem;
2033 // fallthru
2034 default:
2035 if ( nDef == -1 )
2036 nDef = nElem;
2037 pFormatArr[nElem].Default = false;
2041 if ( nDef == -1 )
2042 nDef = 0;
2043 pFormatArr[nDef].Default = true;
2044 return nDef;
2047 SvNumberformat* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey )
2049 SvNumberFormatTable::iterator it = aFTable.find( nKey);
2050 if (it != aFTable.end())
2051 return it->second;
2052 return 0;
2055 const SvNumberformat* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey ) const
2057 return GetEntry( nKey);
2060 const SvNumberformat* SvNumberFormatter::GetEntry( sal_uInt32 nKey ) const
2062 SvNumberFormatTable::const_iterator it = aFTable.find( nKey);
2063 if (it != aFTable.end())
2064 return it->second;
2065 return 0;
2068 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditionalFormats )
2070 using namespace ::com::sun::star;
2073 osl::MutexGuard aGuard(&theIndexTable.maMtx);
2074 if (!theIndexTable.mbInitialized)
2076 for ( sal_uInt16 j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
2078 theIndexTable.maData[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
2083 bool bOldConvertMode = pFormatScanner->GetConvertMode();
2084 if (bOldConvertMode)
2086 pFormatScanner->SetConvertMode(false); // switch off for this function
2089 NumberFormatCodeWrapper aNumberFormatCode( m_xContext,
2090 GetLanguageTag().getLocale() );
2091 SvNumberformat* pNewFormat = NULL;
2092 sal_Int32 nIdx;
2093 bool bDefault;
2095 // Counter for additional builtin formats not fitting into the first 10
2096 // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2097 // Has to be incremented on each ImpInsertNewStandardformat, new formats
2098 // must be appended, not inserted!
2099 sal_uInt16 nNewExtended = ZF_STANDARD_NEWEXTENDED;
2101 // Number
2102 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2103 aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER );
2104 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2106 // General
2107 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2108 SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2109 CLOffset + SetIndexTable( NF_NUMBER_STANDARD, ZF_STANDARD ));
2110 if (pStdFormat)
2112 // This is _the_ standard format.
2113 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat->GetType() != css::util::NumberFormat::NUMBER)
2115 LocaleDataWrapper::outputCheckMessage( xLocaleData->
2116 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2118 pStdFormat->SetType( css::util::NumberFormat::NUMBER );
2119 pStdFormat->SetStandard();
2120 pStdFormat->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE );
2122 else
2124 if (LocaleDataWrapper::areChecksEnabled())
2126 LocaleDataWrapper::outputCheckMessage( xLocaleData->
2127 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2131 // Boolean
2132 OUString aFormatCode = pFormatScanner->GetBooleanString();
2133 sal_Int32 nCheckPos = 0;
2135 pNewFormat = new SvNumberformat( aFormatCode, pFormatScanner,
2136 pStringScanner, nCheckPos, ActLnge );
2137 pNewFormat->SetType(css::util::NumberFormat::LOGICAL);
2138 pNewFormat->SetStandard();
2139 if ( !aFTable.insert(make_pair(
2140 CLOffset + SetIndexTable( NF_BOOLEAN, ZF_STANDARD_LOGICAL ),
2141 pNewFormat)).second)
2143 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2144 delete pNewFormat;
2147 // Text
2148 aFormatCode = "@";
2149 pNewFormat = new SvNumberformat( aFormatCode, pFormatScanner,
2150 pStringScanner, nCheckPos, ActLnge );
2151 pNewFormat->SetType(css::util::NumberFormat::TEXT);
2152 pNewFormat->SetStandard();
2153 if ( !aFTable.insert(make_pair(
2154 CLOffset + SetIndexTable( NF_TEXT, ZF_STANDARD_TEXT ),
2155 pNewFormat)).second)
2157 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2158 delete pNewFormat;
2163 // 0
2164 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2165 ImpInsertFormat( aFormatSeq[nIdx],
2166 CLOffset + SetIndexTable( NF_NUMBER_INT, ZF_STANDARD+1 ));
2168 // 0.00
2169 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2170 ImpInsertFormat( aFormatSeq[nIdx],
2171 CLOffset + SetIndexTable( NF_NUMBER_DEC2, ZF_STANDARD+2 ));
2173 // #,##0
2174 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2175 ImpInsertFormat( aFormatSeq[nIdx],
2176 CLOffset + SetIndexTable( NF_NUMBER_1000INT, ZF_STANDARD+3 ));
2178 // #,##0.00
2179 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2180 ImpInsertFormat( aFormatSeq[nIdx],
2181 CLOffset + SetIndexTable( NF_NUMBER_1000DEC2, ZF_STANDARD+4 ));
2183 // #.##0,00 System country/language dependent
2184 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2185 ImpInsertFormat( aFormatSeq[nIdx],
2186 CLOffset + SetIndexTable( NF_NUMBER_SYSTEM, ZF_STANDARD+5 ));
2189 // Percent number
2190 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER );
2191 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2193 // 0%
2194 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2195 ImpInsertFormat( aFormatSeq[nIdx],
2196 CLOffset + SetIndexTable( NF_PERCENT_INT, ZF_STANDARD_PERCENT ));
2198 // 0.00%
2199 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2200 ImpInsertFormat( aFormatSeq[nIdx],
2201 CLOffset + SetIndexTable( NF_PERCENT_DEC2, ZF_STANDARD_PERCENT+1 ));
2205 // Currency. NO default standard option! Default is determined of locale
2206 // data default currency and format is generated if needed.
2207 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2208 if (LocaleDataWrapper::areChecksEnabled())
2210 // though no default desired here, test for correctness of locale data
2211 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2214 // #,##0
2215 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2216 bDefault = aFormatSeq[nIdx].Default;
2217 aFormatSeq[nIdx].Default = false;
2218 ImpInsertFormat( aFormatSeq[nIdx],
2219 CLOffset + SetIndexTable( NF_CURRENCY_1000INT, ZF_STANDARD_CURRENCY ));
2220 aFormatSeq[nIdx].Default = bDefault;
2222 // #,##0.00
2223 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2224 bDefault = aFormatSeq[nIdx].Default;
2225 aFormatSeq[nIdx].Default = false;
2226 ImpInsertFormat( aFormatSeq[nIdx],
2227 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2, ZF_STANDARD_CURRENCY+1 ));
2228 aFormatSeq[nIdx].Default = bDefault;
2230 // #,##0 negative red
2231 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2232 bDefault = aFormatSeq[nIdx].Default;
2233 aFormatSeq[nIdx].Default = false;
2234 ImpInsertFormat( aFormatSeq[nIdx],
2235 CLOffset + SetIndexTable( NF_CURRENCY_1000INT_RED, ZF_STANDARD_CURRENCY+2 ));
2236 aFormatSeq[nIdx].Default = bDefault;
2238 // #,##0.00 negative red
2239 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2240 bDefault = aFormatSeq[nIdx].Default;
2241 aFormatSeq[nIdx].Default = false;
2242 ImpInsertFormat( aFormatSeq[nIdx],
2243 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_RED, ZF_STANDARD_CURRENCY+3 ));
2244 aFormatSeq[nIdx].Default = bDefault;
2246 // #,##0.00 USD
2247 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2248 bDefault = aFormatSeq[nIdx].Default;
2249 aFormatSeq[nIdx].Default = false;
2250 ImpInsertFormat( aFormatSeq[nIdx],
2251 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_CCC, ZF_STANDARD_CURRENCY+4 ));
2252 aFormatSeq[nIdx].Default = bDefault;
2254 // #.##0,--
2255 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED );
2256 bDefault = aFormatSeq[nIdx].Default;
2257 aFormatSeq[nIdx].Default = false;
2258 ImpInsertFormat( aFormatSeq[nIdx],
2259 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_DASHED, ZF_STANDARD_CURRENCY+5 ));
2260 aFormatSeq[nIdx].Default = bDefault;
2264 // Date
2265 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE );
2266 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2268 // DD.MM.YY System
2269 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2270 ImpInsertFormat( aFormatSeq[nIdx],
2271 CLOffset + SetIndexTable( NF_DATE_SYSTEM_SHORT, ZF_STANDARD_DATE ));
2273 // NN DD.MMM YY
2274 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2275 ImpInsertFormat( aFormatSeq[nIdx],
2276 CLOffset + SetIndexTable( NF_DATE_DEF_NNDDMMMYY, ZF_STANDARD_DATE+1 ));
2278 // DD.MM.YY def/System
2279 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2280 ImpInsertFormat( aFormatSeq[nIdx],
2281 CLOffset + SetIndexTable( NF_DATE_SYS_MMYY, ZF_STANDARD_DATE+2 ));
2283 // DD MMM
2284 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2285 ImpInsertFormat( aFormatSeq[nIdx],
2286 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMM, ZF_STANDARD_DATE+3 ));
2288 // MMMM
2289 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2290 ImpInsertFormat( aFormatSeq[nIdx],
2291 CLOffset + SetIndexTable( NF_DATE_MMMM, ZF_STANDARD_DATE+4 ));
2293 // QQ YY
2294 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2295 ImpInsertFormat( aFormatSeq[nIdx],
2296 CLOffset + SetIndexTable( NF_DATE_QQJJ, ZF_STANDARD_DATE+5 ));
2298 // DD.MM.YYYY was DD.MM.[YY]YY
2299 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2300 ImpInsertFormat( aFormatSeq[nIdx],
2301 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYYYY, ZF_STANDARD_DATE+6 ));
2303 // DD.MM.YY def/System
2304 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2305 ImpInsertFormat( aFormatSeq[nIdx],
2306 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYY, ZF_STANDARD_DATE+7 ));
2308 // NNN, D. MMMM YYYY System
2309 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2310 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2311 ImpInsertFormat( aFormatSeq[nIdx],
2312 CLOffset + SetIndexTable( NF_DATE_SYSTEM_LONG, ZF_STANDARD_DATE+8 ));
2314 // Hard coded but system (regional settings) delimiters dependent long date formats
2316 // D. MMM YY def/System
2317 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2318 ImpInsertFormat( aFormatSeq[nIdx],
2319 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYY, ZF_STANDARD_DATE+9 ));
2321 //! Unfortunately TLOT intended only 10 builtin formats per category, more
2322 //! would overwrite the next category (ZF_STANDARD_TIME) :-((
2323 //! Therefore they are inserted with nNewExtended++ (which is also limited)
2325 // D. MMM YYYY def/System
2326 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2327 ImpInsertFormat( aFormatSeq[nIdx],
2328 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYYYY, nNewExtended++ ));
2330 // D. MMMM YYYY def/System
2331 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2332 ImpInsertFormat( aFormatSeq[nIdx],
2333 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMMYYYY, nNewExtended++ ));
2335 // NN, D. MMM YY def/System
2336 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2337 ImpInsertFormat( aFormatSeq[nIdx],
2338 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMYY, nNewExtended++ ));
2340 // NN, D. MMMM YYYY def/System
2341 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2342 ImpInsertFormat( aFormatSeq[nIdx],
2343 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY, nNewExtended++ ));
2345 // NNN, D. MMMM YYYY def/System
2346 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY );
2347 ImpInsertFormat( aFormatSeq[nIdx],
2348 CLOffset + SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY, nNewExtended++ ));
2350 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2352 // D. MMM. YYYY DIN/EN
2353 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2354 ImpInsertFormat( aFormatSeq[nIdx],
2355 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMYYYY, nNewExtended++ ));
2357 // D. MMMM YYYY DIN/EN
2358 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2359 ImpInsertFormat( aFormatSeq[nIdx],
2360 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMMYYYY, nNewExtended++ ));
2362 // MM-DD DIN/EN
2363 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2364 ImpInsertFormat( aFormatSeq[nIdx],
2365 CLOffset + SetIndexTable( NF_DATE_DIN_MMDD, nNewExtended++ ));
2367 // YY-MM-DD DIN/EN
2368 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2369 ImpInsertFormat( aFormatSeq[nIdx],
2370 CLOffset + SetIndexTable( NF_DATE_DIN_YYMMDD, nNewExtended++ ));
2372 // YYYY-MM-DD DIN/EN
2373 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2374 ImpInsertFormat( aFormatSeq[nIdx],
2375 CLOffset + SetIndexTable( NF_DATE_DIN_YYYYMMDD, nNewExtended++ ));
2379 // Time
2380 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::TIME );
2381 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2383 // HH:MM
2384 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2385 ImpInsertFormat( aFormatSeq[nIdx],
2386 CLOffset + SetIndexTable( NF_TIME_HHMM, ZF_STANDARD_TIME ));
2388 // HH:MM:SS
2389 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2390 ImpInsertFormat( aFormatSeq[nIdx],
2391 CLOffset + SetIndexTable( NF_TIME_HHMMSS, ZF_STANDARD_TIME+1 ));
2393 // HH:MM AM/PM
2394 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2395 ImpInsertFormat( aFormatSeq[nIdx],
2396 CLOffset + SetIndexTable( NF_TIME_HHMMAMPM, ZF_STANDARD_TIME+2 ));
2398 // HH:MM:SS AM/PM
2399 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2400 ImpInsertFormat( aFormatSeq[nIdx],
2401 CLOffset + SetIndexTable( NF_TIME_HHMMSSAMPM, ZF_STANDARD_TIME+3 ));
2403 // [HH]:MM:SS
2404 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2405 ImpInsertFormat( aFormatSeq[nIdx],
2406 CLOffset + SetIndexTable( NF_TIME_HH_MMSS, ZF_STANDARD_TIME+4 ));
2408 // MM:SS,00
2409 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2410 ImpInsertFormat( aFormatSeq[nIdx],
2411 CLOffset + SetIndexTable( NF_TIME_MMSS00, ZF_STANDARD_TIME+5 ));
2413 // [HH]:MM:SS,00
2414 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2415 ImpInsertFormat( aFormatSeq[nIdx],
2416 CLOffset + SetIndexTable( NF_TIME_HH_MMSS00, ZF_STANDARD_TIME+6 ));
2420 // DateTime
2421 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME );
2422 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2424 // DD.MM.YY HH:MM System
2425 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM );
2426 ImpInsertFormat( aFormatSeq[nIdx],
2427 CLOffset + SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM, ZF_STANDARD_DATETIME ));
2429 // DD.MM.YYYY HH:MM:SS System
2430 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2431 ImpInsertFormat( aFormatSeq[nIdx],
2432 CLOffset + SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, ZF_STANDARD_DATETIME+1 ));
2436 // Scientific number
2437 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER );
2438 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2440 // 0.00E+000
2441 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2442 ImpInsertFormat( aFormatSeq[nIdx],
2443 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E000, ZF_STANDARD_SCIENTIFIC ));
2445 // 0.00E+00
2446 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2447 ImpInsertFormat( aFormatSeq[nIdx],
2448 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E00, ZF_STANDARD_SCIENTIFIC+1 ));
2452 // Fraction number (no default option)
2453 i18n::NumberFormatCode aSingleFormatCode;
2454 aSingleFormatCode.Usage = i18n::KNumberFormatUsage::FRACTION_NUMBER;
2456 // # ?/?
2457 aSingleFormatCode.Code = "# ?/?";
2458 ImpInsertFormat( aSingleFormatCode,
2459 CLOffset + SetIndexTable( NF_FRACTION_1, ZF_STANDARD_FRACTION ));
2461 // # ??/??
2462 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2463 aSingleFormatCode.Code = "# ?\?/?\?";
2464 ImpInsertFormat( aSingleFormatCode,
2465 CLOffset + SetIndexTable( NF_FRACTION_2, ZF_STANDARD_FRACTION+1 ));
2467 // # ?/4
2468 aSingleFormatCode.Code = "# ?/4";
2469 ImpInsertFormat( aSingleFormatCode,
2470 CLOffset + SetIndexTable( NF_FRACTION_3, ZF_STANDARD_FRACTION+2 ));
2472 // # ??/100
2473 aSingleFormatCode.Code = "# ?\?/100";
2474 ImpInsertFormat( aSingleFormatCode,
2475 CLOffset + SetIndexTable( NF_FRACTION_4, ZF_STANDARD_FRACTION+3 ));
2479 // Week of year must be appended here because of nNewExtended
2480 const NfKeywordTable & rKeyword = pFormatScanner->GetKeywords();
2481 aSingleFormatCode.Code = rKeyword[NF_KEY_WW];
2482 ImpInsertFormat( aSingleFormatCode,
2483 CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ));
2486 osl::MutexGuard aGuard(&theIndexTable.maMtx);
2487 theIndexTable.mbInitialized = true;
2489 SAL_WARN_IF( nNewExtended > ZF_STANDARD_NEWEXTENDEDMAX, "svl.numbers",
2490 "ImpGenerateFormats: overflow of nNewExtended standard formats" );
2491 assert( nNewExtended <= ZF_STANDARD_NEWEXTENDEDMAX );
2493 // Now all additional format codes provided by I18N, but only if not
2494 // changing SystemCL, then they are appended last after user defined.
2495 if ( !bNoAdditionalFormats )
2497 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, false );
2499 if (bOldConvertMode)
2501 pFormatScanner->SetConvertMode(true);
2506 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset,
2507 NumberFormatCodeWrapper& rNumberFormatCode, bool bAfterChangingSystemCL )
2509 using namespace ::com::sun::star;
2511 SvNumberformat* pStdFormat = GetFormatEntry( CLOffset + ZF_STANDARD );
2512 if ( !pStdFormat )
2514 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2515 return ;
2517 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
2518 rNumberFormatCode.setLocale( GetLanguageTag().getLocale() );
2519 sal_Int32 j;
2521 // All currencies, this time with [$...] which was stripped in
2522 // ImpGenerateFormats for old "automatic" currency formats.
2523 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2524 rNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2525 i18n::NumberFormatCode * pFormatArr = aFormatSeq.getArray();
2526 sal_Int32 nCodes = aFormatSeq.getLength();
2527 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes );
2528 for ( j = 0; j < nCodes; j++ )
2530 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2532 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2533 break; // for
2535 if ( pFormatArr[j].Index < NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS &&
2536 pFormatArr[j].Index != NF_CURRENCY_1000DEC2_CCC )
2537 { // Insert only if not already inserted, but internal index must be
2538 // above so ImpInsertFormat can distinguish it.
2539 sal_Int16 nOrgIndex = pFormatArr[j].Index;
2540 pFormatArr[j].Index = sal::static_int_cast< sal_Int16 >(
2541 pFormatArr[j].Index + nCodes + NF_INDEX_TABLE_ENTRIES);
2542 //! no default on currency
2543 bool bDefault = aFormatSeq[j].Default;
2544 aFormatSeq[j].Default = false;
2545 if ( SvNumberformat* pNewFormat = ImpInsertFormat( pFormatArr[j], nPos+1,
2546 bAfterChangingSystemCL, nOrgIndex ) )
2548 pNewFormat->SetAdditionalBuiltin();
2549 nPos++;
2551 pFormatArr[j].Index = nOrgIndex;
2552 aFormatSeq[j].Default = bDefault;
2556 // All additional format codes provided by I18N that are not old standard
2557 // index. Additional formats may define defaults, currently there is no
2558 // check if more than one default of a usage/type combination is provided,
2559 // like it is done for usage groups with ImpAdjustFormatCodeDefault().
2560 // There is no harm though, on first invocation ImpGetDefaultFormat() will
2561 // use the first default encountered.
2562 aFormatSeq = rNumberFormatCode.getAllFormatCodes();
2563 nCodes = aFormatSeq.getLength();
2564 if ( nCodes )
2566 pFormatArr = aFormatSeq.getArray();
2567 for ( j = 0; j < nCodes; j++ )
2569 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2571 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2572 break; // for
2574 if ( pFormatArr[j].Index >= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS )
2576 if ( SvNumberformat* pNewFormat = ImpInsertFormat( pFormatArr[j], nPos+1,
2577 bAfterChangingSystemCL ) )
2579 pNewFormat->SetAdditionalBuiltin();
2580 nPos++;
2586 pStdFormat->SetLastInsertKey( (sal_uInt16)(nPos - CLOffset) );
2590 void SvNumberFormatter::ImpGetPosCurrFormat(OUStringBuffer& sPosStr, const OUString& rCurrSymbol)
2592 NfCurrencyEntry::CompletePositiveFormatString( sPosStr,
2593 rCurrSymbol, xLocaleData->getCurrPositiveFormat() );
2596 void SvNumberFormatter::ImpGetNegCurrFormat(OUStringBuffer& sNegStr, const OUString& rCurrSymbol)
2598 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
2599 rCurrSymbol, xLocaleData->getCurrNegativeFormat() );
2602 sal_Int32 SvNumberFormatter::ImpPosToken ( const OUStringBuffer & sFormat, sal_Unicode token, sal_Int32 nStartPos /* = 0*/ )
2604 sal_Int32 nLength = sFormat.getLength();
2605 for ( sal_Int32 i=nStartPos; i<nLength && i>=0 ; i++ )
2607 switch(sFormat[i])
2609 case '\"' : // skip text
2610 i = sFormat.indexOf('\"',i+1);
2611 break;
2612 case '[' : // skip condition
2613 i = sFormat.indexOf(']',i+1);
2614 break;
2615 case '\\' : // skip escaped character
2616 i++;
2617 break;
2618 case ';' :
2619 if (token == ';')
2620 return i;
2621 break;
2622 case 'e' :
2623 case 'E' :
2624 if (token == 'E')
2625 return i; // if 'E' is outside "" and [] it must be the 'E' exponent
2626 break;
2627 default : break;
2629 if ( i<0 )
2630 i--;
2632 return -2;
2635 OUString SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex,
2636 LanguageType eLnge,
2637 bool bThousand,
2638 bool IsRed,
2639 sal_uInt16 nPrecision,
2640 sal_uInt16 nLeadingZeros)
2642 if (eLnge == LANGUAGE_DONTKNOW)
2644 eLnge = IniLnge;
2646 short eType = GetType(nIndex);
2647 sal_uInt16 i;
2648 ImpGenerateCL(eLnge); // create new standard formats if necessary
2650 utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping());
2651 // always group of 3 for Engineering notation
2652 const sal_Int32 nDigitsInFirstGroup = ( bThousand && (eType == css::util::NumberFormat::SCIENTIFIC) ) ? 3 : aGrouping.get();
2653 const OUString& rThSep = GetNumThousandSep();
2655 SvNumberformat* pFormat = GetFormatEntry( nIndex );
2657 OUStringBuffer sString;
2658 using comphelper::string::padToLength;
2660 if (nLeadingZeros == 0)
2662 if (!bThousand)
2663 sString.append('#');
2664 else
2666 if (eType == css::util::NumberFormat::SCIENTIFIC)
2667 { // for scientific, bThousand is used for Engineering notation
2668 sString.append("###");
2670 else
2672 sString.append('#');
2673 sString.append(rThSep);
2674 padToLength(sString, sString.getLength() + nDigitsInFirstGroup, '#');
2678 else
2680 for (i = 0; i < nLeadingZeros; i++)
2682 if (bThousand && i > 0 && i == aGrouping.getPos())
2684 sString.insert(0, rThSep);
2685 aGrouping.advance();
2687 sString.insert(0, '0');
2689 if ( bThousand )
2691 sal_Int32 nDigits = (eType == css::util::NumberFormat::SCIENTIFIC) ? 3*((nLeadingZeros-1)/3 + 1) : nDigitsInFirstGroup + 1;
2692 for (i = nLeadingZeros; i < nDigits; i++)
2694 if ( i % nDigitsInFirstGroup == 0 )
2695 sString.insert(0, rThSep);
2696 sString.insert(0, '#');
2700 if (nPrecision > 0)
2702 sString.append(GetNumDecimalSep());
2703 padToLength(sString, sString.getLength() + nPrecision, '0');
2705 if (eType == css::util::NumberFormat::PERCENT)
2707 sString.append('%');
2709 else if (eType == css::util::NumberFormat::SCIENTIFIC)
2711 OUStringBuffer sOldFormatString = pFormat->GetFormatstring();
2712 sal_Int32 nIndexE = ImpPosToken( sOldFormatString, 'E' );
2713 if (nIndexE > -1)
2715 sal_Int32 nIndexSep = ImpPosToken( sOldFormatString, ';', nIndexE );
2716 if (nIndexSep > nIndexE)
2717 sString.append( sOldFormatString.copy(nIndexE, nIndexSep - nIndexE) );
2718 else
2719 sString.append( sOldFormatString.copy(nIndexE) );
2722 else if (eType == css::util::NumberFormat::CURRENCY)
2724 OUStringBuffer sNegStr(sString);
2725 OUString aCurr;
2726 const NfCurrencyEntry* pEntry;
2727 bool bBank;
2728 if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
2730 if ( pEntry )
2732 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2733 xLocaleData->getCurrPositiveFormat(),
2734 pEntry->GetPositiveFormat(), bBank );
2735 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2736 xLocaleData->getCurrNegativeFormat(),
2737 pEntry->GetNegativeFormat(), bBank );
2738 pEntry->CompletePositiveFormatString( sString, bBank, nPosiForm );
2739 pEntry->CompleteNegativeFormatString( sNegStr, bBank, nNegaForm );
2741 else
2742 { // assume currency abbreviation (AKA banking symbol), not symbol
2743 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2744 xLocaleData->getCurrPositiveFormat(),
2745 xLocaleData->getCurrPositiveFormat(), true );
2746 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2747 xLocaleData->getCurrNegativeFormat(),
2748 xLocaleData->getCurrNegativeFormat(), true );
2749 NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr, nPosiForm );
2750 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr, nNegaForm );
2753 else
2754 { // "automatic" old style
2755 OUString aSymbol, aAbbrev;
2756 GetCompatibilityCurrency( aSymbol, aAbbrev );
2757 ImpGetPosCurrFormat( sString, aSymbol );
2758 ImpGetNegCurrFormat( sNegStr, aSymbol );
2760 if (IsRed)
2762 sString.append(';');
2763 sString.append('[');
2764 sString.append(pFormatScanner->GetRedString());
2765 sString.append(']');
2767 else
2769 sString.append(';');
2771 sString.append(sNegStr.makeStringAndClear());
2773 if (eType != css::util::NumberFormat::CURRENCY)
2775 bool insertBrackets = false;
2776 if ( eType != css::util::NumberFormat::UNDEFINED)
2778 insertBrackets = pFormat->IsNegativeInBracket();
2780 if (IsRed || insertBrackets)
2782 OUStringBuffer sTmpStr(sString);
2784 if ( pFormat->HasPositiveBracketPlaceholder() )
2786 sTmpStr.append('_');
2787 sTmpStr.append(')');
2789 sTmpStr.append(';');
2791 if (IsRed)
2793 sTmpStr.append('[');
2794 sTmpStr.append(pFormatScanner->GetRedString());
2795 sTmpStr.append(']');
2798 if (insertBrackets)
2800 sTmpStr.append('(');
2801 sTmpStr.append(sString.toString());
2802 sTmpStr.append(')');
2804 else
2806 sTmpStr.append('-');
2807 sTmpStr.append(sString.toString());
2809 sString = sTmpStr;
2812 return sString.makeStringAndClear();
2815 bool SvNumberFormatter::IsUserDefined(const OUString& sStr,
2816 LanguageType eLnge)
2818 if (eLnge == LANGUAGE_DONTKNOW)
2820 eLnge = IniLnge;
2822 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
2823 eLnge = ActLnge;
2825 sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
2826 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
2828 return true;
2830 SvNumberformat* pEntry = GetFormatEntry( nKey );
2831 if ( pEntry && ((pEntry->GetType() & css::util::NumberFormat::DEFINED) != 0) )
2833 return true;
2835 return false;
2838 sal_uInt32 SvNumberFormatter::GetEntryKey(const OUString& sStr,
2839 LanguageType eLnge)
2841 if (eLnge == LANGUAGE_DONTKNOW)
2843 eLnge = IniLnge;
2845 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
2846 return ImpIsEntry(sStr, CLOffset, eLnge);
2849 sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge)
2851 if (eLnge == LANGUAGE_DONTKNOW)
2853 eLnge = IniLnge;
2855 return GetStandardFormat(css::util::NumberFormat::NUMBER, eLnge);
2858 short SvNumberFormatter::GetType(sal_uInt32 nFIndex)
2860 short eType;
2861 SvNumberformat* pFormat = GetFormatEntry( nFIndex );
2862 if (!pFormat)
2864 eType = css::util::NumberFormat::UNDEFINED;
2866 else
2868 eType = pFormat->GetType() &~css::util::NumberFormat::DEFINED;
2869 if (eType == 0)
2871 eType = css::util::NumberFormat::DEFINED;
2874 return eType;
2877 void SvNumberFormatter::ClearMergeTable()
2879 if ( pMergeTable )
2881 pMergeTable->clear();
2885 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
2887 if ( pMergeTable )
2889 ClearMergeTable();
2891 else
2893 pMergeTable = new SvNumberFormatterIndexTable;
2896 sal_uInt32 nCLOffset = 0;
2897 sal_uInt32 nOldKey, nOffset, nNewKey;
2898 SvNumberformat* pNewEntry;
2900 SvNumberFormatTable::iterator it = rTable.aFTable.begin();
2901 while (it != rTable.aFTable.end())
2903 SvNumberformat* pFormat = it->second;
2904 nOldKey = it->first;
2905 nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
2906 if (nOffset == 0) // 1st format of CL
2908 nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
2910 if (nOffset <= SV_MAX_ANZ_STANDARD_FORMATE) // Std.form.
2912 nNewKey = nCLOffset + nOffset;
2913 if (aFTable.find( nNewKey) == aFTable.end()) // not already present
2915 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
2916 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2917 if (!aFTable.insert(make_pair( nNewKey, pNewEntry)).second)
2919 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
2920 delete pNewEntry;
2923 if (nNewKey != nOldKey) // new index
2925 (*pMergeTable)[nOldKey] = nNewKey;
2928 else // user defined
2930 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
2931 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2932 nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
2933 nCLOffset,
2934 pFormat->GetLanguage());
2935 if (nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // already present
2937 delete pNewEntry;
2939 else
2941 SvNumberformat* pStdFormat = GetFormatEntry(nCLOffset + ZF_STANDARD);
2942 sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey();
2943 nNewKey = nPos+1;
2944 if (nNewKey - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
2946 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
2947 delete pNewEntry;
2949 else if (!aFTable.insert(make_pair( nNewKey, pNewEntry)).second)
2951 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
2952 delete pNewEntry;
2954 else
2956 pStdFormat->SetLastInsertKey((sal_uInt16) (nNewKey - nCLOffset));
2959 if (nNewKey != nOldKey) // new index
2961 (*pMergeTable)[nOldKey] = nNewKey;
2964 ++it;
2966 return pMergeTable;
2970 SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap()
2972 if (!HasMergeFormatTable())
2974 return SvNumberFormatterMergeMap();
2976 SvNumberFormatterMergeMap aMap;
2977 for (SvNumberFormatterIndexTable::iterator it = pMergeTable->begin(); it != pMergeTable->end(); ++it)
2979 sal_uInt32 nOldKey = it->first;
2980 aMap[ nOldKey ] = it->second;
2982 ClearMergeTable();
2983 return aMap;
2987 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
2988 LanguageType eLnge )
2990 if ( eLnge == LANGUAGE_DONTKNOW )
2992 eLnge = IniLnge;
2994 if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
2996 return nFormat; // it stays as it is
2998 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
2999 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3001 return nFormat; // not a built-in format
3003 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3004 return nCLOffset + nOffset;
3008 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
3009 LanguageType eLnge )
3011 if (nTabOff >= NF_INDEX_TABLE_ENTRIES)
3012 return NUMBERFORMAT_ENTRY_NOT_FOUND;
3014 if (eLnge == LANGUAGE_DONTKNOW)
3015 eLnge = IniLnge;
3018 osl::MutexGuard aGuard(&theIndexTable.maMtx);
3019 if (theIndexTable.maData[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND)
3020 return NUMBERFORMAT_ENTRY_NOT_FOUND;
3023 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // create new standard formats if necessary
3026 osl::MutexGuard aGuard(&theIndexTable.maMtx);
3027 return nCLOffset + theIndexTable.maData[nTabOff];
3032 NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const
3034 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relative index
3035 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3037 return NF_INDEX_TABLE_ENTRIES; // not a built-in format
3041 osl::MutexGuard aGuard(&theIndexTable.maMtx);
3042 for ( sal_uInt16 j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
3044 if (theIndexTable.maData[j] == nOffset)
3045 return (NfIndexTableOffset) j;
3048 return NF_INDEX_TABLE_ENTRIES; // bad luck
3051 void SvNumberFormatter::SetEvalDateFormat( NfEvalDateFormat eEDF )
3053 eEvalDateFormat = eEDF;
3056 NfEvalDateFormat SvNumberFormatter::GetEvalDateFormat() const
3058 return eEvalDateFormat;
3061 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal )
3063 pStringScanner->SetYear2000( nVal );
3067 sal_uInt16 SvNumberFormatter::GetYear2000() const
3069 return pStringScanner->GetYear2000();
3073 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear ) const
3075 if ( nYear < 100 )
3076 return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3077 pStringScanner->GetYear2000() );
3078 return nYear;
3082 // static
3083 sal_uInt16 SvNumberFormatter::GetYear2000Default()
3085 return (sal_uInt16) ::utl::MiscCfg().GetYear2000();
3089 // static
3090 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3092 ::osl::MutexGuard aGuard( GetMutex() );
3093 while ( !bCurrencyTableInitialized )
3094 ImpInitCurrencyTable();
3095 return theCurrencyTable::get();
3099 // static
3100 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3102 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3103 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3104 return nSystemCurrencyPosition ? &rTable[nSystemCurrencyPosition] : NULL;
3108 // static
3109 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3111 if ( eLang == LANGUAGE_SYSTEM )
3113 const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3114 return pCurr ? *pCurr : GetTheCurrencyTable()[0];
3116 else
3118 eLang = MsLangId::getRealLanguage( eLang );
3119 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3120 sal_uInt16 nCount = rTable.size();
3121 for ( sal_uInt16 j = 0; j < nCount; j++ )
3123 if ( rTable[j].GetLanguage() == eLang )
3124 return rTable[j];
3126 return rTable[0];
3131 // static
3132 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(const OUString& rAbbrev, LanguageType eLang )
3134 eLang = MsLangId::getRealLanguage( eLang );
3135 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3136 sal_uInt16 nCount = rTable.size();
3137 for ( sal_uInt16 j = 0; j < nCount; j++ )
3139 if ( rTable[j].GetLanguage() == eLang &&
3140 rTable[j].GetBankSymbol() == rAbbrev )
3142 return &rTable[j];
3145 return NULL;
3149 // static
3150 const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( const OUString& rSymbol,
3151 const OUString& rAbbrev )
3153 if (!bCurrencyTableInitialized)
3155 GetTheCurrencyTable(); // just for initialization
3157 const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get();
3158 sal_uInt16 nCount = rTable.size();
3159 for ( sal_uInt16 j = 0; j < nCount; j++ )
3161 if ( rTable[j].GetSymbol() == rSymbol &&
3162 rTable[j].GetBankSymbol() == rAbbrev )
3164 return &rTable[j];
3167 return NULL;
3171 // static
3172 IMPL_STATIC_LINK_NOARG( SvNumberFormatter, CurrencyChangeLink )
3174 ::osl::MutexGuard aGuard( GetMutex() );
3175 OUString aAbbrev;
3176 LanguageType eLang = LANGUAGE_SYSTEM;
3177 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3178 SetDefaultSystemCurrency( aAbbrev, eLang );
3179 return 0;
3183 // static
3184 void SvNumberFormatter::SetDefaultSystemCurrency( const OUString& rAbbrev, LanguageType eLang )
3186 ::osl::MutexGuard aGuard( GetMutex() );
3187 if ( eLang == LANGUAGE_SYSTEM )
3189 eLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3191 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3192 sal_uInt16 nCount = rTable.size();
3193 if ( !rAbbrev.isEmpty() )
3195 for ( sal_uInt16 j = 0; j < nCount; j++ )
3197 if ( rTable[j].GetLanguage() == eLang && rTable[j].GetBankSymbol() == rAbbrev )
3199 nSystemCurrencyPosition = j;
3200 return ;
3204 else
3206 for ( sal_uInt16 j = 0; j < nCount; j++ )
3208 if ( rTable[j].GetLanguage() == eLang )
3210 nSystemCurrencyPosition = j;
3211 return ;
3215 nSystemCurrencyPosition = 0; // not found => simple SYSTEM
3219 void SvNumberFormatter::ResetDefaultSystemCurrency()
3221 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3225 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3227 pStringScanner->InvalidateDateAcceptancePatterns();
3231 sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3233 if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3235 sal_Int32 nCheck;
3236 short nType;
3237 NfWSStringsDtor aCurrList;
3238 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3239 GetCurrencyEntry( LANGUAGE_SYSTEM ), false );
3240 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency System standard format?!?" );
3241 // if already loaded or user defined nDefaultSystemCurrencyFormat
3242 // will be set to the right value
3243 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3244 nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM );
3245 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3246 DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3247 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3249 return nDefaultSystemCurrencyFormat;
3253 sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3255 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3256 DefaultFormatKeysMap::iterator it = aDefaultFormatKeys.find( CLOffset + ZF_STANDARD_CURRENCY );
3257 sal_uInt32 nDefaultCurrencyFormat = (it != aDefaultFormatKeys.end() ?
3258 it->second : NUMBERFORMAT_ENTRY_NOT_FOUND);
3259 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3261 // look for a defined standard
3262 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3263 sal_uInt32 nKey(0);
3264 SvNumberFormatTable::iterator it2 = aFTable.lower_bound( CLOffset );
3265 while ( it2 != aFTable.end() && (nKey = it2->first) >= CLOffset && nKey < nStopKey )
3267 const SvNumberformat* pEntry = it2->second;
3268 if ( pEntry->IsStandard() && (pEntry->GetType() & css::util::NumberFormat::CURRENCY) )
3270 nDefaultCurrencyFormat = nKey;
3271 break; // while
3273 ++it2;
3276 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3277 { // none found, create one
3278 sal_Int32 nCheck;
3279 NfWSStringsDtor aCurrList;
3280 sal_uInt16 nDefault = GetCurrencyFormatStrings( aCurrList,
3281 GetCurrencyEntry( ActLnge ), false );
3282 DBG_ASSERT( aCurrList.size(), "where is the NewCurrency standard format?" );
3283 if ( !aCurrList.empty() )
3285 // if already loaded or user defined nDefaultSystemCurrencyFormat
3286 // will be set to the right value
3287 short nType;
3288 PutEntry( aCurrList[ nDefault ], nCheck, nType,
3289 nDefaultCurrencyFormat, ActLnge );
3290 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3291 DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3292 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3294 // old automatic currency format as a last resort
3295 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3296 nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3297 else
3298 { // mark as standard so that it is found next time
3299 SvNumberformat* pEntry = GetFormatEntry( nDefaultCurrencyFormat );
3300 if ( pEntry )
3301 pEntry->SetStandard();
3304 aDefaultFormatKeys[ CLOffset + ZF_STANDARD_CURRENCY ] = nDefaultCurrencyFormat;
3306 return nDefaultCurrencyFormat;
3310 // static
3311 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
3312 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3313 const NfCurrencyEntry*& pFoundEntry, bool& bFoundBank, const NfCurrencyEntry* pData,
3314 sal_uInt16 nPos, const OUString& rSymbol )
3316 bool bFound;
3317 if ( pData->GetSymbol() == rSymbol )
3319 bFound = true;
3320 bFoundBank = false;
3322 else if ( pData->GetBankSymbol() == rSymbol )
3324 bFound = true;
3325 bFoundBank = true;
3327 else
3328 bFound = false;
3329 if ( bFound )
3331 if ( pFoundEntry && pFoundEntry != pData )
3333 pFoundEntry = NULL;
3334 return false; // break loop, not unique
3336 if ( nPos == 0 )
3337 { // first entry is SYSTEM
3338 pFoundEntry = MatchSystemCurrency();
3339 if ( pFoundEntry )
3341 return false; // break loop
3342 // even if there are more matching entries
3343 // this one is probably the one we are looking for
3345 else
3347 pFoundEntry = pData;
3350 else
3352 pFoundEntry = pData;
3355 return true;
3359 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat, OUString& rStr,
3360 const NfCurrencyEntry** ppEntry /* = NULL */,
3361 bool* pBank /* = NULL */ ) const
3363 if ( ppEntry )
3364 *ppEntry = NULL;
3365 if ( pBank )
3366 *pBank = false;
3368 const SvNumberformat* pFormat = GetFormatEntry(nFormat);
3369 if ( pFormat )
3371 OUStringBuffer sBuff(128); // guess-estimate of a value that will pretty much guarantee no re-alloc
3372 OUString aSymbol, aExtension;
3373 if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3375 if ( ppEntry )
3377 bool bFoundBank = false;
3378 // we definiteley need an entry matching the format code string
3379 const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3380 bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3381 true );
3382 if ( pFoundEntry )
3384 *ppEntry = pFoundEntry;
3385 if ( pBank )
3386 *pBank = bFoundBank;
3387 rStr = pFoundEntry->BuildSymbolString(bFoundBank);
3390 if ( rStr.isEmpty() )
3391 { // analog to BuildSymbolString
3392 sBuff.append("[$");
3393 if ( aSymbol.indexOf( '-' ) != -1 ||
3394 aSymbol.indexOf( ']' ) != -1 )
3396 sBuff.append('"');
3397 sBuff.append( aSymbol);
3398 sBuff.append('"');
3400 else
3402 sBuff.append(aSymbol);
3404 if ( !aExtension.isEmpty() )
3406 sBuff.append(aExtension);
3408 sBuff.append(']');
3410 rStr = sBuff.toString();
3411 return true;
3414 rStr.clear();
3415 return false;
3419 // static
3420 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank,
3421 const OUString& rSymbol,
3422 const OUString& rExtension,
3423 LanguageType eFormatLanguage,
3424 bool bOnlyStringLanguage )
3426 sal_Int32 nExtLen = rExtension.getLength();
3427 LanguageType eExtLang;
3428 if ( nExtLen )
3430 // rExtension should be a 16-bit hex value max FFFF which may contain a
3431 // leading "-" separator (that is not a minus sign, but toInt32 can be
3432 // used to parse it, with post-processing as necessary):
3433 sal_Int32 nExtLang = rExtension.toInt32( 16 );
3434 if ( !nExtLang )
3436 eExtLang = LANGUAGE_DONTKNOW;
3438 else
3440 eExtLang = (LanguageType) ((nExtLang < 0) ? -nExtLang : nExtLang);
3443 else
3445 eExtLang = LANGUAGE_DONTKNOW;
3447 const NfCurrencyEntry* pFoundEntry = NULL;
3448 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3449 sal_uInt16 nCount = rTable.size();
3450 bool bCont = true;
3452 // first try with given extension language/country
3453 if ( nExtLen )
3455 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3457 LanguageType eLang = rTable[j].GetLanguage();
3458 if ( eLang == eExtLang ||
3459 ((eExtLang == LANGUAGE_DONTKNOW) &&
3460 (eLang == LANGUAGE_SYSTEM)))
3462 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3463 &rTable[j], j, rSymbol );
3468 // ok?
3469 if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3471 return pFoundEntry;
3473 if ( !bOnlyStringLanguage )
3475 // now try the language/country of the number format
3476 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3478 LanguageType eLang = rTable[j].GetLanguage();
3479 if ( eLang == eFormatLanguage ||
3480 ((eFormatLanguage == LANGUAGE_DONTKNOW) &&
3481 (eLang == LANGUAGE_SYSTEM)))
3483 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3484 &rTable[j], j, rSymbol );
3488 // ok?
3489 if ( pFoundEntry || !bCont )
3491 return pFoundEntry;
3495 // then try without language/country if no extension specified
3496 if ( !nExtLen )
3498 for ( sal_uInt16 j = 0; j < nCount && bCont; j++ )
3500 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3501 &rTable[j], j, rSymbol );
3505 return pFoundEntry;
3509 void SvNumberFormatter::GetCompatibilityCurrency( OUString& rSymbol, OUString& rAbbrev ) const
3511 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >
3512 xCurrencies( xLocaleData->getAllCurrencies() );
3514 const ::com::sun::star::i18n::Currency2 *pCurrencies = xCurrencies.getConstArray();
3515 sal_Int32 nCurrencies = xCurrencies.getLength();
3517 sal_Int32 j;
3518 for ( j=0; j < nCurrencies; ++j )
3520 if ( pCurrencies[j].UsedInCompatibleFormatCodes )
3522 rSymbol = pCurrencies[j].Symbol;
3523 rAbbrev = pCurrencies[j].BankSymbol;
3524 break;
3527 if ( j >= nCurrencies )
3529 if (LocaleDataWrapper::areChecksEnabled())
3531 LocaleDataWrapper::outputCheckMessage( xLocaleData->
3532 appendLocaleInfo( "GetCompatibilityCurrency: none?"));
3534 rSymbol = xLocaleData->getCurrSymbol();
3535 rAbbrev = xLocaleData->getCurrBankSymbol();
3540 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
3542 switch ( rCurr.GetPositiveFormat() )
3544 case 0: // $1
3545 case 1: // 1$
3546 case 2: // $ 1
3547 case 3: // 1 $
3548 break;
3549 default:
3550 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3551 break;
3553 switch ( rCurr.GetNegativeFormat() )
3555 case 0: // ($1)
3556 case 1: // -$1
3557 case 2: // $-1
3558 case 3: // $1-
3559 case 4: // (1$)
3560 case 5: // -1$
3561 case 6: // 1-$
3562 case 7: // 1$-
3563 case 8: // -1 $
3564 case 9: // -$ 1
3565 case 10: // 1 $-
3566 case 11: // $ -1
3567 case 12 : // $ 1-
3568 case 13 : // 1- $
3569 case 14 : // ($ 1)
3570 case 15 : // (1 $)
3571 break;
3572 default:
3573 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3574 break;
3578 // static
3579 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang )
3581 // The set is initialized as a side effect of the currency table
3582 // created, make sure that exists, which usually is the case unless a
3583 // SvNumberFormatter was never instantiated.
3584 GetTheCurrencyTable();
3585 const NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3586 return rInstalledLocales.find( eLang) != rInstalledLocales.end();
3589 // static
3590 void SvNumberFormatter::ImpInitCurrencyTable()
3592 // Race condition possible:
3593 // ::osl::MutexGuard aGuard( GetMutex() );
3594 // while ( !bCurrencyTableInitialized )
3595 // ImpInitCurrencyTable();
3596 static bool bInitializing = false;
3597 if ( bCurrencyTableInitialized || bInitializing )
3599 return ;
3601 bInitializing = true;
3603 LanguageType eSysLang = SvtSysLocale().GetLanguageTag().getLanguageType();
3604 boost::scoped_ptr<LocaleDataWrapper> pLocaleData(new LocaleDataWrapper(
3605 ::comphelper::getProcessComponentContext(),
3606 SvtSysLocale().GetLanguageTag() ));
3607 // get user configured currency
3608 OUString aConfiguredCurrencyAbbrev;
3609 LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
3610 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3611 aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
3612 sal_uInt16 nSecondarySystemCurrencyPosition = 0;
3613 sal_uInt16 nMatchingSystemCurrencyPosition = 0;
3614 NfCurrencyEntry* pEntry;
3616 // first entry is SYSTEM
3617 pEntry = new NfCurrencyEntry( *pLocaleData, LANGUAGE_SYSTEM );
3618 theCurrencyTable::get().insert( theCurrencyTable::get().begin(), pEntry );
3619 sal_uInt16 nCurrencyPos = 1;
3621 ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc =
3622 LocaleDataWrapper::getInstalledLocaleNames();
3623 sal_Int32 nLocaleCount = xLoc.getLength();
3624 SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount << "\"" );
3625 css::lang::Locale const * const pLocales = xLoc.getConstArray();
3626 NfCurrencyTable &rCurrencyTable = theCurrencyTable::get();
3627 NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get();
3628 NfInstalledLocales &rInstalledLocales = theInstalledLocales::get();
3629 sal_uInt16 nLegacyOnlyCurrencyPos = 0;
3630 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
3632 LanguageType eLang = LanguageTag::convertToLanguageType( pLocales[nLocale], false);
3633 rInstalledLocales.insert( eLang);
3634 pLocaleData->setLanguageTag( LanguageTag( pLocales[nLocale]) );
3635 Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
3636 sal_Int32 nCurrencyCount = aCurrSeq.getLength();
3637 Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
3639 // one default currency for each locale, insert first so it is found first
3640 sal_Int32 nDefault;
3641 for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3643 if ( pCurrencies[nDefault].Default )
3644 break;
3646 if ( nDefault < nCurrencyCount )
3648 pEntry = new NfCurrencyEntry( pCurrencies[nDefault], *pLocaleData, eLang );
3650 else
3652 pEntry = new NfCurrencyEntry( *pLocaleData, eLang ); // first or ShellsAndPebbles
3654 if (LocaleDataWrapper::areChecksEnabled())
3656 lcl_CheckCurrencySymbolPosition( *pEntry );
3658 rCurrencyTable.insert( rCurrencyTable.begin() + nCurrencyPos++, pEntry );
3659 if ( !nSystemCurrencyPosition && !aConfiguredCurrencyAbbrev.isEmpty() &&
3660 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev &&
3661 pEntry->GetLanguage() == eConfiguredCurrencyLanguage )
3663 nSystemCurrencyPosition = nCurrencyPos-1;
3665 if ( !nMatchingSystemCurrencyPosition &&
3666 pEntry->GetLanguage() == eSysLang )
3668 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3670 // all remaining currencies for each locale
3671 if ( nCurrencyCount > 1 )
3673 sal_Int32 nCurrency;
3674 for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
3676 if (pCurrencies[nCurrency].LegacyOnly)
3678 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3679 rLegacyOnlyCurrencyTable.insert( rLegacyOnlyCurrencyTable.begin() + nLegacyOnlyCurrencyPos++, pEntry );
3681 else if ( nCurrency != nDefault )
3683 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3684 // no dupes
3685 bool bInsert = true;
3686 sal_uInt16 n = rCurrencyTable.size();
3687 sal_uInt16 aCurrencyIndex = 1; // skip first SYSTEM entry
3688 for ( sal_uInt16 j=1; j<n; j++ )
3690 if ( rCurrencyTable[aCurrencyIndex++] == *pEntry )
3692 bInsert = false;
3693 break; // for
3696 if ( !bInsert )
3698 delete pEntry;
3700 else
3702 rCurrencyTable.insert( rCurrencyTable.begin() + nCurrencyPos++, pEntry );
3703 if ( !nSecondarySystemCurrencyPosition &&
3704 (!aConfiguredCurrencyAbbrev.isEmpty() ?
3705 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev :
3706 pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
3708 nSecondarySystemCurrencyPosition = nCurrencyPos-1;
3710 if ( !nMatchingSystemCurrencyPosition &&
3711 pEntry->GetLanguage() == eSysLang )
3713 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3720 if ( !nSystemCurrencyPosition )
3722 nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
3724 if ((!aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
3725 LocaleDataWrapper::areChecksEnabled())
3727 LocaleDataWrapper::outputCheckMessage(
3728 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3730 // match SYSTEM if no configured currency found
3731 if ( !nSystemCurrencyPosition )
3733 nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
3735 if ((aConfiguredCurrencyAbbrev.isEmpty() && !nSystemCurrencyPosition) &&
3736 LocaleDataWrapper::areChecksEnabled())
3738 LocaleDataWrapper::outputCheckMessage(
3739 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3741 pLocaleData.reset();
3742 SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( NULL, SvNumberFormatter, CurrencyChangeLink ) );
3743 bInitializing = false;
3744 bCurrencyTableInitialized = true;
3748 sal_uInt16 SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr,
3749 const NfCurrencyEntry& rCurr,
3750 bool bBank ) const
3752 OUString aRed = OUStringBuffer().
3753 append('[').
3754 append(pFormatScanner->GetRedString()).
3755 append(']').makeStringAndClear();
3757 sal_uInt16 nDefault = 0;
3758 if ( bBank )
3760 // Only bank symbols.
3761 OUString aPositiveBank = rCurr.BuildPositiveFormatString(true, *xLocaleData, 1);
3762 OUString aNegativeBank = rCurr.BuildNegativeFormatString(true, *xLocaleData, 1 );
3764 OUStringBuffer format1(aPositiveBank);
3765 format1.append(';');
3766 format1.append(aNegativeBank);
3767 rStrArr.push_back(format1.makeStringAndClear());
3769 OUStringBuffer format2(aPositiveBank);
3770 format2.append(';');
3772 format2.append(aRed);
3774 format2.append(aNegativeBank);
3775 rStrArr.push_back(format2.makeStringAndClear());
3777 nDefault = rStrArr.size() - 1;
3779 else
3781 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
3782 // duplicates if no decimals in currency.
3783 OUString aPositive = rCurr.BuildPositiveFormatString(false, *xLocaleData, 1);
3784 OUString aNegative = rCurr.BuildNegativeFormatString(false, *xLocaleData, 1 );
3785 OUStringBuffer format1;
3786 OUStringBuffer format2;
3787 OUStringBuffer format3;
3788 OUStringBuffer format4;
3789 OUStringBuffer format5;
3790 if (rCurr.GetDigits())
3792 OUString aPositiveNoDec = rCurr.BuildPositiveFormatString(false, *xLocaleData, 0);
3793 OUString aNegativeNoDec = rCurr.BuildNegativeFormatString(false, *xLocaleData, 0 );
3794 OUString aPositiveDashed = rCurr.BuildPositiveFormatString(false, *xLocaleData, 2);
3795 OUString aNegativeDashed = rCurr.BuildNegativeFormatString(false, *xLocaleData, 2);
3797 format1.append(aPositiveNoDec);
3798 format1.append(';');
3799 format1.append(aNegativeNoDec);
3801 format3.append(aPositiveNoDec);
3802 format3.append(';');
3803 format3.append(aRed);
3804 format3.append(aNegativeNoDec);
3806 format5.append(aPositiveDashed);
3807 format5.append(';');
3808 format5.append(aRed);
3809 format5.append(aNegativeDashed);
3812 format2.append(aPositive);
3813 format2.append(';');
3814 format2.append(aNegative);
3816 format4.append(aPositive);
3817 format4.append(';');
3818 format4.append(aRed);
3819 format4.append(aNegative);
3821 if (rCurr.GetDigits())
3823 rStrArr.push_back(format1.makeStringAndClear());
3825 rStrArr.push_back(format2.makeStringAndClear());
3826 if (rCurr.GetDigits())
3828 rStrArr.push_back(format3.makeStringAndClear());
3830 rStrArr.push_back(format4.makeStringAndClear());
3831 nDefault = rStrArr.size() - 1;
3832 if (rCurr.GetDigits())
3834 rStrArr.push_back(format5.makeStringAndClear());
3837 return nDefault;
3840 sal_uInt32 SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt ) const
3842 if (pMergeTable)
3844 SvNumberFormatterIndexTable::iterator it = pMergeTable->find(nOldFmt);
3845 if (it != pMergeTable->end())
3847 return it->second;
3850 return nOldFmt;
3853 bool SvNumberFormatter::HasMergeFormatTable() const
3855 return pMergeTable && !pMergeTable->empty();
3858 // static
3859 sal_uInt16 SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear, sal_uInt16 nTwoDigitYearStart )
3861 if ( nYear < 100 )
3863 if ( nYear < (nTwoDigitYearStart % 100) )
3865 return nYear + (((nTwoDigitYearStart / 100) + 1) * 100);
3867 else
3869 return nYear + ((nTwoDigitYearStart / 100) * 100);
3872 return nYear;
3875 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3877 aSymbol = rLocaleData.getCurrSymbol();
3878 aBankSymbol = rLocaleData.getCurrBankSymbol();
3879 eLanguage = eLang;
3880 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3881 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3882 nDigits = rLocaleData.getCurrDigits();
3883 cZeroChar = rLocaleData.getCurrZeroChar();
3887 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency & rCurr,
3888 const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3890 aSymbol = rCurr.Symbol;
3891 aBankSymbol = rCurr.BankSymbol;
3892 eLanguage = eLang;
3893 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3894 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3895 nDigits = rCurr.DecimalPlaces;
3896 cZeroChar = rLocaleData.getCurrZeroChar();
3899 bool NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
3901 return aSymbol == r.aSymbol
3902 && aBankSymbol == r.aBankSymbol
3903 && eLanguage == r.eLanguage
3907 OUString NfCurrencyEntry::BuildSymbolString(bool bBank,
3908 bool bWithoutExtension) const
3910 OUStringBuffer aBuf("[$");
3911 if (bBank)
3913 aBuf.append(aBankSymbol);
3915 else
3917 if ( aSymbol.indexOf( (sal_Unicode)'-' ) >= 0 ||
3918 aSymbol.indexOf( (sal_Unicode)']' ) >= 0)
3920 aBuf.append('"').append(aSymbol).append('"');
3922 else
3924 aBuf.append(aSymbol);
3926 if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
3928 sal_Int32 nLang = static_cast<sal_Int32>(eLanguage);
3929 aBuf.append('-').append( OUString::number(nLang, 16).toAsciiUpperCase());
3932 aBuf.append(']');
3933 return aBuf.makeStringAndClear();
3936 OUString NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper& rLoc,
3937 sal_uInt16 nDecimalFormat) const
3939 OUStringBuffer aBuf;
3940 aBuf.append('#').append(rLoc.getNumThousandSep()).append("##0");
3941 if (nDecimalFormat && nDigits)
3943 aBuf.append(rLoc.getNumDecimalSep());
3944 sal_Unicode cDecimalChar = nDecimalFormat == 2 ? '-' : cZeroChar;
3945 for (sal_uInt16 i = 0; i < nDigits; ++i)
3947 aBuf.append(cDecimalChar);
3950 return aBuf.makeStringAndClear();
3954 OUString NfCurrencyEntry::BuildPositiveFormatString(bool bBank, const LocaleDataWrapper& rLoc,
3955 sal_uInt16 nDecimalFormat) const
3957 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
3958 sal_uInt16 nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( rLoc.getCurrPositiveFormat(),
3959 nPositiveFormat, bBank );
3960 CompletePositiveFormatString(sBuf, bBank, nPosiForm);
3961 return sBuf.makeStringAndClear();
3965 OUString NfCurrencyEntry::BuildNegativeFormatString(bool bBank,
3966 const LocaleDataWrapper& rLoc, sal_uInt16 nDecimalFormat ) const
3968 OUStringBuffer sBuf(Impl_BuildFormatStringNumChars(rLoc, nDecimalFormat));
3969 sal_uInt16 nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc.getCurrNegativeFormat(),
3970 nNegativeFormat, bBank );
3971 CompleteNegativeFormatString(sBuf, bBank, nNegaForm);
3972 return sBuf.makeStringAndClear();
3976 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, bool bBank,
3977 sal_uInt16 nPosiForm) const
3979 OUString aSymStr = BuildSymbolString(bBank);
3980 NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
3984 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr, bool bBank,
3985 sal_uInt16 nNegaForm) const
3987 OUString aSymStr = BuildSymbolString(bBank);
3988 NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
3992 // static
3993 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer& rStr, const OUString& rSymStr,
3994 sal_uInt16 nPositiveFormat)
3996 switch( nPositiveFormat )
3998 case 0: // $1
3999 rStr.insert(0, rSymStr);
4000 break;
4001 case 1: // 1$
4002 rStr.append(rSymStr);
4003 break;
4004 case 2: // $ 1
4006 rStr.insert(0, ' ');
4007 rStr.insert(0, rSymStr);
4009 break;
4010 case 3: // 1 $
4012 rStr.append(' ');
4013 rStr.append(rSymStr);
4015 break;
4016 default:
4017 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4018 break;
4023 // static
4024 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer& rStr,
4025 const OUString& rSymStr,
4026 sal_uInt16 nNegativeFormat)
4028 switch( nNegativeFormat )
4030 case 0: // ($1)
4032 rStr.insert(0, rSymStr);
4033 rStr.insert(0, '(');
4034 rStr.append(')');
4036 break;
4037 case 1: // -$1
4039 rStr.insert(0, rSymStr);
4040 rStr.insert(0, '-');
4042 break;
4043 case 2: // $-1
4045 rStr.insert(0, '-');
4046 rStr.insert(0, rSymStr);
4048 break;
4049 case 3: // $1-
4051 rStr.insert(0, rSymStr);
4052 rStr.append('-');
4054 break;
4055 case 4: // (1$)
4057 rStr.insert(0, '(');
4058 rStr.append(rSymStr);
4059 rStr.append(')');
4061 break;
4062 case 5: // -1$
4064 rStr.append(rSymStr);
4065 rStr.insert(0, '-');
4067 break;
4068 case 6: // 1-$
4070 rStr.append('-');
4071 rStr.append(rSymStr);
4073 break;
4074 case 7: // 1$-
4076 rStr.append(rSymStr);
4077 rStr.append('-');
4079 break;
4080 case 8: // -1 $
4082 rStr.append(' ');
4083 rStr.append(rSymStr);
4084 rStr.insert(0, '-');
4086 break;
4087 case 9: // -$ 1
4089 rStr.insert(0, ' ');
4090 rStr.insert(0, rSymStr);
4091 rStr.insert(0, '-');
4093 break;
4094 case 10: // 1 $-
4096 rStr.append(' ');
4097 rStr.append(rSymStr);
4098 rStr.append('-');
4100 break;
4101 case 11: // $ -1
4103 rStr.insert(0, " -");
4104 rStr.insert(0, rSymStr);
4106 break;
4107 case 12 : // $ 1-
4109 rStr.insert(0, ' ');
4110 rStr.insert(0, rSymStr);
4111 rStr.append('-');
4113 break;
4114 case 13 : // 1- $
4116 rStr.append('-');
4117 rStr.append(' ');
4118 rStr.append(rSymStr);
4120 break;
4121 case 14 : // ($ 1)
4123 rStr.insert(0, ' ');
4124 rStr.insert(0, rSymStr);
4125 rStr.insert(0, '(');
4126 rStr.append(')');
4128 break;
4129 case 15 : // (1 $)
4131 rStr.insert(0, '(');
4132 rStr.append(' ');
4133 rStr.append(rSymStr);
4134 rStr.append(')');
4136 break;
4137 default:
4138 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4139 break;
4144 // static
4145 sal_uInt16 NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat,
4146 sal_uInt16 nCurrFormat, bool bBank )
4148 if ( bBank )
4150 #if NF_BANKSYMBOL_FIX_POSITION
4151 (void) nIntlFormat; // avoid warnings
4152 return 3;
4153 #else
4154 switch ( nIntlFormat )
4156 case 0: // $1
4157 nIntlFormat = 2; // $ 1
4158 break;
4159 case 1: // 1$
4160 nIntlFormat = 3; // 1 $
4161 break;
4162 case 2: // $ 1
4163 break;
4164 case 3: // 1 $
4165 break;
4166 default:
4167 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4168 break;
4170 return nIntlFormat;
4171 #endif
4173 else
4174 return nCurrFormat;
4178 //! Call this only if nCurrFormat is really with parentheses!
4179 static sal_uInt16 lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat, sal_uInt16 nCurrFormat )
4181 short nSign = 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4182 switch ( nIntlFormat )
4184 case 0: // ($1)
4185 case 4: // (1$)
4186 case 14 : // ($ 1)
4187 case 15 : // (1 $)
4188 return nCurrFormat;
4189 case 1: // -$1
4190 case 5: // -1$
4191 case 8: // -1 $
4192 case 9: // -$ 1
4193 nSign = 0;
4194 break;
4195 case 2: // $-1
4196 case 6: // 1-$
4197 case 11 : // $ -1
4198 case 13 : // 1- $
4199 nSign = 1;
4200 break;
4201 case 3: // $1-
4202 case 7: // 1$-
4203 case 10: // 1 $-
4204 case 12 : // $ 1-
4205 nSign = 2;
4206 break;
4207 default:
4208 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4209 break;
4212 switch ( nCurrFormat )
4214 case 0: // ($1)
4215 switch ( nSign )
4217 case 0:
4218 return 1; // -$1
4219 case 1:
4220 return 2; // $-1
4221 case 2:
4222 return 3; // $1-
4224 break;
4225 case 4: // (1$)
4226 switch ( nSign )
4228 case 0:
4229 return 5; // -1$
4230 case 1:
4231 return 6; // 1-$
4232 case 2:
4233 return 7; // 1$-
4235 break;
4236 case 14 : // ($ 1)
4237 switch ( nSign )
4239 case 0:
4240 return 9; // -$ 1
4241 case 1:
4242 return 11; // $ -1
4243 case 2:
4244 return 12; // $ 1-
4246 break;
4247 case 15 : // (1 $)
4248 switch ( nSign )
4250 case 0:
4251 return 8; // -1 $
4252 case 1:
4253 return 13; // 1- $
4254 case 2:
4255 return 10; // 1 $-
4257 break;
4259 return nCurrFormat;
4263 // static
4264 sal_uInt16 NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat,
4265 sal_uInt16 nCurrFormat, bool bBank )
4267 if ( bBank )
4269 #if NF_BANKSYMBOL_FIX_POSITION
4270 return 8;
4271 #else
4272 switch ( nIntlFormat )
4274 case 0: // ($1)
4275 // nIntlFormat = 14; // ($ 1)
4276 nIntlFormat = 9; // -$ 1
4277 break;
4278 case 1: // -$1
4279 nIntlFormat = 9; // -$ 1
4280 break;
4281 case 2: // $-1
4282 nIntlFormat = 11; // $ -1
4283 break;
4284 case 3: // $1-
4285 nIntlFormat = 12; // $ 1-
4286 break;
4287 case 4: // (1$)
4288 // nIntlFormat = 15; // (1 $)
4289 nIntlFormat = 8; // -1 $
4290 break;
4291 case 5: // -1$
4292 nIntlFormat = 8; // -1 $
4293 break;
4294 case 6: // 1-$
4295 nIntlFormat = 13; // 1- $
4296 break;
4297 case 7: // 1$-
4298 nIntlFormat = 10; // 1 $-
4299 break;
4300 case 8: // -1 $
4301 break;
4302 case 9: // -$ 1
4303 break;
4304 case 10: // 1 $-
4305 break;
4306 case 11: // $ -1
4307 break;
4308 case 12 : // $ 1-
4309 break;
4310 case 13 : // 1- $
4311 break;
4312 case 14 : // ($ 1)
4313 // nIntlFormat = 14; // ($ 1)
4314 nIntlFormat = 9; // -$ 1
4315 break;
4316 case 15 : // (1 $)
4317 // nIntlFormat = 15; // (1 $)
4318 nIntlFormat = 8; // -1 $
4319 break;
4320 default:
4321 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4322 break;
4324 #endif
4326 else if ( nIntlFormat != nCurrFormat )
4328 switch ( nCurrFormat )
4330 case 0: // ($1)
4331 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4332 nIntlFormat, nCurrFormat );
4333 break;
4334 case 1: // -$1
4335 nIntlFormat = nCurrFormat;
4336 break;
4337 case 2: // $-1
4338 nIntlFormat = nCurrFormat;
4339 break;
4340 case 3: // $1-
4341 nIntlFormat = nCurrFormat;
4342 break;
4343 case 4: // (1$)
4344 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4345 nIntlFormat, nCurrFormat );
4346 break;
4347 case 5: // -1$
4348 nIntlFormat = nCurrFormat;
4349 break;
4350 case 6: // 1-$
4351 nIntlFormat = nCurrFormat;
4352 break;
4353 case 7: // 1$-
4354 nIntlFormat = nCurrFormat;
4355 break;
4356 case 8: // -1 $
4357 nIntlFormat = nCurrFormat;
4358 break;
4359 case 9: // -$ 1
4360 nIntlFormat = nCurrFormat;
4361 break;
4362 case 10: // 1 $-
4363 nIntlFormat = nCurrFormat;
4364 break;
4365 case 11: // $ -1
4366 nIntlFormat = nCurrFormat;
4367 break;
4368 case 12 : // $ 1-
4369 nIntlFormat = nCurrFormat;
4370 break;
4371 case 13 : // 1- $
4372 nIntlFormat = nCurrFormat;
4373 break;
4374 case 14 : // ($ 1)
4375 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4376 nIntlFormat, nCurrFormat );
4377 break;
4378 case 15 : // (1 $)
4379 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4380 nIntlFormat, nCurrFormat );
4381 break;
4382 default:
4383 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4384 break;
4387 return nIntlFormat;
4390 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */