1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/string.hxx>
21 #include <tools/debug.hxx>
22 #include <unotools/charclass.hxx>
23 #include <i18nlangtag/mslangid.hxx>
24 #include <unotools/localedatawrapper.hxx>
25 #include <unotools/numberformatcodewrapper.hxx>
26 #include <unotools/calendarwrapper.hxx>
27 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
28 #include <com/sun/star/i18n/KNumberFormatType.hpp>
29 #include <comphelper/processfactory.hxx>
30 #include <unotools/misccfg.hxx>
33 #include <osl/mutex.hxx>
34 #include <svl/zforlist.hxx>
36 #include "zforscan.hxx"
37 #include "zforfind.hxx"
38 #include <svl/zformat.hxx>
39 #include "numhead.hxx"
41 #include <unotools/syslocaleoptions.hxx>
42 #include <unotools/digitgroupingiterator.hxx>
43 #include <rtl/logfile.hxx>
44 #include <rtl/instance.hxx>
45 #include <rtl/strbuf.hxx>
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::i18n
;
53 using namespace ::com::sun::star::lang
;
54 using namespace ::std
;
56 // Constants for type offsets per Country/Language (CL)
58 #define ZF_STANDARD_PERCENT 10
59 #define ZF_STANDARD_CURRENCY 20
60 #define ZF_STANDARD_DATE 30
61 #define ZF_STANDARD_TIME 40
62 #define ZF_STANDARD_DATETIME 50
63 #define ZF_STANDARD_SCIENTIFIC 60
64 #define ZF_STANDARD_FRACTION 70
65 #define ZF_STANDARD_NEWEXTENDED 75
66 #define ZF_STANDARD_NEWEXTENDEDMAX SV_MAX_ANZ_STANDARD_FORMATE-2 // 98
67 #define ZF_STANDARD_LOGICAL SV_MAX_ANZ_STANDARD_FORMATE-1 // 99
68 #define ZF_STANDARD_TEXT SV_MAX_ANZ_STANDARD_FORMATE // 100
70 /* Locale that is set if an unknown locale (from another system) is loaded of
71 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
72 * (old currency) is recognized as a date (#53155#). */
73 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
75 static bool bIndexTableInitialized
= false;
76 static sal_uInt32 theIndexTable
[NF_INDEX_TABLE_ENTRIES
];
79 // ====================================================================
82 instead of every number formatter being a listener we have a registry which
83 also handles one instance of the SysLocale options
86 typedef ::std::vector
< SvNumberFormatter
* > SvNumberFormatterList_impl
;
88 class SvNumberFormatterRegistry_Impl
: public utl::ConfigurationListener
90 SvNumberFormatterList_impl aFormatters
;
91 SvtSysLocaleOptions aSysLocaleOptions
;
92 LanguageType eSysLanguage
;
95 SvNumberFormatterRegistry_Impl();
96 virtual ~SvNumberFormatterRegistry_Impl();
98 void Insert( SvNumberFormatter
* pThis
)
99 { aFormatters
.push_back( pThis
); }
101 SvNumberFormatter
* Remove( SvNumberFormatter
* pThis
);
104 { return aFormatters
.size(); }
106 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster
*, sal_uInt32
);
109 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
111 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
112 aSysLocaleOptions
.AddListener( this );
116 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
118 aSysLocaleOptions
.RemoveListener( this );
122 SvNumberFormatter
* SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter
* pThis
)
124 for (SvNumberFormatterList_impl::iterator it
= aFormatters
.begin();
125 it
!= aFormatters
.end(); ++it
)
129 aFormatters
.erase( it
);
136 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster
*,
139 ::osl::MutexGuard
aGuard( SvNumberFormatter::GetMutex() );
141 if ( nHint
& SYSLOCALEOPTIONS_HINT_LOCALE
)
143 for( size_t i
= 0, n
= aFormatters
.size(); i
< n
; ++i
)
144 aFormatters
[ i
]->ReplaceSystemCL( eSysLanguage
);
145 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
147 if ( nHint
& SYSLOCALEOPTIONS_HINT_CURRENCY
)
149 for( size_t i
= 0, n
= aFormatters
.size(); i
< n
; ++i
)
150 aFormatters
[ i
]->ResetDefaultSystemCurrency();
152 if ( nHint
& SYSLOCALEOPTIONS_HINT_DATEPATTERNS
)
154 for( size_t i
= 0, n
= aFormatters
.size(); i
< n
; ++i
)
155 aFormatters
[ i
]->InvalidateDateAcceptancePatterns();
160 // ====================================================================
162 SvNumberFormatterRegistry_Impl
* SvNumberFormatter::pFormatterRegistry
= NULL
;
163 bool SvNumberFormatter::bCurrencyTableInitialized
= false;
166 struct theCurrencyTable
:
167 public rtl::Static
< NfCurrencyTable
, theCurrencyTable
> {};
169 struct theLegacyOnlyCurrencyTable
:
170 public rtl::Static
< NfCurrencyTable
, theLegacyOnlyCurrencyTable
> {};
172 /** THE set of installed locales. */
173 struct theInstalledLocales
:
174 public rtl::Static
< NfInstalledLocales
, theInstalledLocales
> {};
177 sal_uInt16
SvNumberFormatter::nSystemCurrencyPosition
= 0;
179 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
180 // language dependent.
181 #define NF_BANKSYMBOL_FIX_POSITION 1
184 /***********************Funktionen SvNumberFormatter**************************/
186 const sal_uInt16
SvNumberFormatter::UNLIMITED_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max();
187 const sal_uInt16
SvNumberFormatter::INPUTSTRING_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max()-1;
189 SvNumberFormatter::SvNumberFormatter( const Reference
< XComponentContext
>& rxContext
,
191 : m_xContext( rxContext
)
192 , maLanguageTag( eLang
)
194 ImpConstruct( eLang
);
198 SvNumberFormatter::~SvNumberFormatter()
201 ::osl::MutexGuard
aGuard( GetMutex() );
202 pFormatterRegistry
->Remove( this );
203 if ( !pFormatterRegistry
->Count() )
205 delete pFormatterRegistry
;
206 pFormatterRegistry
= NULL
;
210 for (SvNumberFormatTable::iterator it
= aFTable
.begin(); it
!= aFTable
.end(); ++it
)
214 delete pStringScanner
;
215 delete pFormatScanner
;
221 void SvNumberFormatter::ImpConstruct( LanguageType eLang
)
223 RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog
, "svl", "er93726", "SvNumberFormatter::ImpConstruct" );
225 if ( eLang
== LANGUAGE_DONTKNOW
)
227 eLang
= UNKNOWN_SUBSTITUTE
;
231 eEvalDateFormat
= NF_EVALDATEFORMAT_INTL
;
232 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
234 maLanguageTag
.reset( eLang
);
235 pCharClass
= new CharClass( m_xContext
, maLanguageTag
);
236 xLocaleData
.init( m_xContext
, maLanguageTag
);
237 xCalendar
.init( m_xContext
, maLanguageTag
.getLocale() );
238 xTransliteration
.init( m_xContext
, eLang
,
239 ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE
);
240 xNatNum
.init( m_xContext
);
242 // cached locale data items
243 const LocaleDataWrapper
* pLoc
= GetLocaleData();
244 aDecimalSep
= pLoc
->getNumDecimalSep();
245 aThousandSep
= pLoc
->getNumThousandSep();
246 aDateSep
= pLoc
->getDateSep();
248 pStringScanner
= new ImpSvNumberInputScan( this );
249 pFormatScanner
= new ImpSvNumberformatScan( this );
252 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
256 ::osl::MutexGuard
aGuard( GetMutex() );
257 GetFormatterRegistry().Insert( this );
261 void SvNumberFormatter::ChangeIntl(LanguageType eLnge
)
263 if (ActLnge
!= eLnge
)
267 maLanguageTag
.reset( eLnge
);
268 pCharClass
->setLanguageTag( maLanguageTag
);
269 xLocaleData
.changeLocale( maLanguageTag
);
270 xCalendar
.changeLocale( maLanguageTag
.getLocale() );
271 xTransliteration
.changeLocale( eLnge
);
273 // cached locale data items, initialize BEFORE calling ChangeIntl below
274 const LocaleDataWrapper
* pLoc
= GetLocaleData();
275 aDecimalSep
= pLoc
->getNumDecimalSep();
276 aThousandSep
= pLoc
->getNumThousandSep();
277 aDateSep
= pLoc
->getDateSep();
279 pFormatScanner
->ChangeIntl();
280 pStringScanner
->ChangeIntl();
286 ::osl::Mutex
& SvNumberFormatter::GetMutex()
288 static ::osl::Mutex
* pMutex
= NULL
;
291 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
294 // #i77768# Due to a static reference in the toolkit lib
295 // we need a mutex that lives longer than the svl library.
296 // Otherwise the dtor would use a destructed mutex!!
297 pMutex
= new ::osl::Mutex
;
305 SvNumberFormatterRegistry_Impl
& SvNumberFormatter::GetFormatterRegistry()
307 ::osl::MutexGuard
aGuard( GetMutex() );
308 if ( !pFormatterRegistry
)
310 pFormatterRegistry
= new SvNumberFormatterRegistry_Impl
;
312 return *pFormatterRegistry
;
316 Color
* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex
)
318 if( aColorLink
.IsSet() )
320 return (Color
*) ( aColorLink
.Call( (void*) &nIndex
));
328 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay
,
332 pFormatScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
333 pStringScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
336 Date
* SvNumberFormatter::GetNullDate()
338 return pFormatScanner
->GetNullDate();
341 void SvNumberFormatter::ChangeStandardPrec(short nPrec
)
343 pFormatScanner
->ChangeStandardPrec(nPrec
);
346 sal_uInt16
SvNumberFormatter::GetStandardPrec()
348 return pFormatScanner
->GetStandardPrec();
351 void SvNumberFormatter::ImpChangeSysCL( LanguageType eLnge
, bool bNoAdditionalFormats
)
353 if (eLnge
== LANGUAGE_DONTKNOW
)
355 eLnge
= UNKNOWN_SUBSTITUTE
;
357 if (eLnge
!= IniLnge
)
361 // delete old formats
362 for (SvNumberFormatTable::iterator it
= aFTable
.begin(); it
!= aFTable
.end(); ++it
)
367 ImpGenerateFormats( 0, bNoAdditionalFormats
); // new standard formats
369 else if ( bNoAdditionalFormats
)
371 // delete additional standard formats
373 SvNumberFormatTable::iterator it
= aFTable
.find( SV_MAX_ANZ_STANDARD_FORMATE
+ 1 );
374 while ( it
!= aFTable
.end() &&
375 (nKey
= it
->first
) > SV_MAX_ANZ_STANDARD_FORMATE
&&
376 nKey
< SV_COUNTRY_LANGUAGE_OFFSET
)
379 aFTable
.erase( it
++ );
385 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage
)
387 sal_uInt32 nCLOffset
= ImpGetCLOffset( LANGUAGE_SYSTEM
);
388 if ( nCLOffset
> MaxCLOffset
)
390 return ; // no SYSTEM entries to replace
392 const sal_uInt32 nMaxBuiltin
= nCLOffset
+ SV_MAX_ANZ_STANDARD_FORMATE
;
393 const sal_uInt32 nNextCL
= nCLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
396 // remove old builtin formats
397 SvNumberFormatTable::iterator it
= aFTable
.find( nCLOffset
);
398 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
<= nMaxBuiltin
)
401 aFTable
.erase( it
++ );
404 // move additional and user defined to temporary table
405 SvNumberFormatTable aOldTable
;
406 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
< nNextCL
)
408 aOldTable
[ nKey
] = it
->second
;
409 aFTable
.erase( it
++ );
412 // generate new old builtin formats
413 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
414 ActLnge
= LANGUAGE_DONTKNOW
;
415 ChangeIntl( LANGUAGE_SYSTEM
);
416 ImpGenerateFormats( nCLOffset
, true );
418 // convert additional and user defined from old system to new system
419 SvNumberformat
* pStdFormat
= GetFormatEntry( nCLOffset
+ ZF_STANDARD
);
420 sal_uInt32 nLastKey
= nMaxBuiltin
;
421 pFormatScanner
->SetConvertMode( eOldLanguage
, LANGUAGE_SYSTEM
, true );
422 while ( !aOldTable
.empty() )
424 nKey
= aOldTable
.begin()->first
;
425 if ( nLastKey
< nKey
)
429 SvNumberformat
* pOldEntry
= aOldTable
.begin()->second
;
430 aOldTable
.erase( nKey
);
431 OUString
aString( pOldEntry
->GetFormatstring() );
433 // Same as PutEntry() but assures key position even if format code is
434 // a duplicate. Also won't mix up any LastInsertKey.
435 ChangeIntl( eOldLanguage
);
436 LanguageType eLge
= eOldLanguage
; // ConvertMode changes this
438 sal_Int32 nCheckPos
= -1;
439 SvNumberformat
* pNewEntry
= new SvNumberformat( aString
, pFormatScanner
,
440 pStringScanner
, nCheckPos
, eLge
);
441 if ( nCheckPos
!= 0 )
447 short eCheckType
= pNewEntry
->GetType();
448 if ( eCheckType
!= NUMBERFORMAT_UNDEFINED
)
450 pNewEntry
->SetType( eCheckType
| NUMBERFORMAT_DEFINED
);
454 pNewEntry
->SetType( NUMBERFORMAT_DEFINED
);
457 if ( !aFTable
.insert( make_pair( nKey
, pNewEntry
) ).second
)
466 DBG_ASSERT( bCheck
, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
471 pFormatScanner
->SetConvertMode(false);
472 pStdFormat
->SetLastInsertKey( sal_uInt16(nLastKey
- nCLOffset
) );
474 // append new system additional formats
475 NumberFormatCodeWrapper
aNumberFormatCode( m_xContext
,
476 GetLanguageTag().getLocale() );
477 ImpGenerateAdditionalFormats( nCLOffset
, aNumberFormatCode
, true );
481 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index
) const
483 const SvNumberformat
* pFormat
= GetFormatEntry(F_Index
);
485 return pFormat
? pFormat
->IsTextFormat() : false;
488 bool SvNumberFormatter::PutEntry(OUString
& rString
,
489 sal_Int32
& nCheckPos
,
491 sal_uInt32
& nKey
, // format key
495 if (rString
.isEmpty()) // empty string
497 nCheckPos
= 1; // -> Error
500 if (eLnge
== LANGUAGE_DONTKNOW
)
504 ChangeIntl(eLnge
); // change locale if necessary
505 LanguageType eLge
= eLnge
; // non-const for ConvertMode
507 SvNumberformat
* p_Entry
= new SvNumberformat(rString
,
513 if (nCheckPos
== 0) // Format ok
514 { // Type comparison:
515 short eCheckType
= p_Entry
->GetType();
516 if ( eCheckType
!= NUMBERFORMAT_UNDEFINED
)
518 p_Entry
->SetType(eCheckType
| NUMBERFORMAT_DEFINED
);
523 p_Entry
->SetType(NUMBERFORMAT_DEFINED
);
524 nType
= NUMBERFORMAT_DEFINED
;
527 sal_uInt32 CLOffset
= ImpGenerateCL(eLge
); // create new standard formats if necessary
529 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLge
);
530 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
536 SvNumberformat
* pStdFormat
= GetFormatEntry(CLOffset
+ ZF_STANDARD
);
537 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey();
538 if (nPos
+1 - CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
540 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
543 else if (!aFTable
.insert(make_pair( nPos
+1,p_Entry
)).second
)
545 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
552 pStdFormat
->SetLastInsertKey((sal_uInt16
) (nKey
-CLOffset
));
563 bool SvNumberFormatter::PutandConvertEntry(OUString
& rString
,
564 sal_Int32
& nCheckPos
,
568 LanguageType eNewLnge
)
571 if (eNewLnge
== LANGUAGE_DONTKNOW
)
575 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
);
576 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
577 pFormatScanner
->SetConvertMode(false);
581 bool SvNumberFormatter::PutandConvertEntrySystem(OUString
& rString
,
582 sal_Int32
& nCheckPos
,
586 LanguageType eNewLnge
)
589 if (eNewLnge
== LANGUAGE_DONTKNOW
)
593 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, true);
594 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
595 pFormatScanner
->SetConvertMode(false);
599 sal_uInt32
SvNumberFormatter::GetIndexPuttingAndConverting( String
& rString
, LanguageType eLnge
,
600 LanguageType eSysLnge
, short & rType
,
601 bool & rNewInserted
, xub_StrLen
& rCheckPos
)
604 OUString
sTemp(rString
);
605 sal_Int32 nCheckPos
= (rCheckPos
== (xub_StrLen
)0xFFFF) ? -1 : (sal_Int32
)rCheckPos
;
606 result
= GetIndexPuttingAndConverting(sTemp
, eLnge
, eSysLnge
, rType
, rNewInserted
, nCheckPos
);
607 rCheckPos
= nCheckPos
< 0 ? (xub_StrLen
)0xFFFF : (xub_StrLen
)nCheckPos
;
612 sal_uInt32
SvNumberFormatter::GetIndexPuttingAndConverting( OUString
& rString
, LanguageType eLnge
,
613 LanguageType eSysLnge
, short & rType
,
614 bool & rNewInserted
, sal_Int32
& rCheckPos
)
616 sal_uInt32 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
617 rNewInserted
= false;
620 // #62389# empty format string (of Writer) => General standard format
621 if (rString
.isEmpty())
625 else if (eLnge
== LANGUAGE_SYSTEM
&& eSysLnge
!= SvtSysLocale().GetLanguageTag().getLanguageType())
627 sal_uInt32 nOrig
= GetEntryKey( rString
, eSysLnge
);
628 if (nOrig
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
630 nKey
= nOrig
; // none available, maybe user-defined
634 nKey
= GetFormatForLanguageIfBuiltIn( nOrig
, SvtSysLocale().GetLanguageTag().getLanguageType() );
638 // Not a builtin format, convert.
639 // The format code string may get modified and adapted to the real
640 // language and wouldn't match eSysLnge anymore, do that on a copy.
641 OUString
aTmp( rString
);
642 rNewInserted
= PutandConvertEntrySystem( aTmp
, rCheckPos
, rType
,
643 nKey
, eLnge
, SvtSysLocale().GetLanguageTag().getLanguageType());
646 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
647 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
653 nKey
= GetEntryKey( rString
, eLnge
);
654 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
656 rNewInserted
= PutEntry( rString
, rCheckPos
, rType
, nKey
, eLnge
);
659 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
660 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
664 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
666 nKey
= GetStandardIndex( eLnge
);
668 rType
= GetType( nKey
);
669 // Convert any (!) old "automatic" currency format to new fixed currency
671 if ((rType
& NUMBERFORMAT_CURRENCY
) != 0)
673 const SvNumberformat
* pFormat
= GetEntry( nKey
);
674 if (!pFormat
->HasNewCurrency())
678 DeleteEntry( nKey
); // don't leave trails of rubbish
679 rNewInserted
= false;
681 nKey
= GetStandardFormat( NUMBERFORMAT_CURRENCY
, eLnge
);
688 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey
)
690 delete aFTable
[nKey
];
694 bool SvNumberFormatter::Load( SvStream
& rStream
)
696 LanguageType eSysLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
697 SvNumberFormatter
* pConverter
= NULL
;
699 ImpSvNumMultipleReadHeader
aHdr( rStream
);
702 SvNumberformat
* pEntry
;
704 sal_uInt16 nSysOnStore
, eLge
, eDummy
; // Dummy for compatible format
705 rStream
>> nSysOnStore
>> eLge
; // system language from document
707 SAL_WARN_IF( nVersion
< SV_NUMBERFORMATTER_VERSION_CALENDAR
, "svl.numbers", "SvNumberFormatter::Load: where does this unsupported old data come from?!?");
709 LanguageType eSaveSysLang
= (LanguageType
) nSysOnStore
;
710 LanguageType eLnge
= (LanguageType
) eLge
;
711 ImpChangeSysCL( eLnge
, true );
714 while (nPos
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
716 rStream
>> eDummy
>> eLge
;
717 eLnge
= (LanguageType
) eLge
;
718 ImpGenerateCL( eLnge
, true ); // create new standard formats if necessary
720 sal_uInt32 nOffset
= nPos
% SV_COUNTRY_LANGUAGE_OFFSET
; // relativIndex
721 bool bUserDefined
= (nOffset
> SV_MAX_ANZ_STANDARD_FORMATE
);
723 pEntry
= new SvNumberformat(*pFormatScanner
, eLnge
);
724 pEntry
->Load( rStream
, aHdr
, NULL
, *pStringScanner
);
727 bUserDefined
= (pEntry
->GetNewStandardDefined() > SV_NUMBERFORMATTER_VERSION
);
731 LanguageType eLoadSysLang
= (eLnge
== LANGUAGE_SYSTEM
? eSysLang
: eSaveSysLang
);
732 if ( eSaveSysLang
!= eLoadSysLang
)
734 // different SYSTEM locale
737 pConverter
= new SvNumberFormatter( m_xContext
, eSysLang
);
739 pEntry
->ConvertLanguage( *pConverter
, eSaveSysLang
, eLoadSysLang
, true );
742 if ( nOffset
== 0 ) // Standard/General format
744 SvNumberformat
* pEnt
= GetFormatEntry(nPos
);
747 pEnt
->SetLastInsertKey(pEntry
->GetLastInsertKey());
750 if (!aFTable
.insert(make_pair( nPos
, pEntry
)).second
)
752 SAL_WARN( "svl.numbers", "SvNumberFormatter::Load: dup position");
758 // as of SV_NUMBERFORMATTER_VERSION_YEAR2000
759 if ( nVersion
>= SV_NUMBERFORMATTER_VERSION_YEAR2000
)
762 if ( aHdr
.BytesLeft() >= sizeof(sal_uInt16
) )
766 if ( nVersion
< SV_NUMBERFORMATTER_VERSION_TWODIGITYEAR
&& nY2k
< 100 )
768 nY2k
+= 1901; // was before src513e: 29, now: 1930
780 // generate additional i18n standard formats for all used locales
781 LanguageType eOldLanguage
= ActLnge
;
782 NumberFormatCodeWrapper
aNumberFormatCode( m_xContext
,
783 GetLanguageTag().getLocale() );
784 std::vector
<sal_uInt16
> aList
;
785 GetUsedLanguages( aList
);
786 for ( std::vector
<sal_uInt16
>::const_iterator
it(aList
.begin()); it
!= aList
.end(); ++it
)
788 LanguageType eLang
= *it
;
790 sal_uInt32 CLOffset
= ImpGetCLOffset( eLang
);
791 ImpGenerateAdditionalFormats( CLOffset
, aNumberFormatCode
, true );
793 ChangeIntl( eOldLanguage
);
795 return rStream
.GetError() ? false : true;
798 bool SvNumberFormatter::Save( SvStream
& rStream
) const
800 ImpSvNumMultipleWriteHeader
aHdr( rStream
);
801 // As of 364i we store what SYSTEM locale really was, before it was hard
802 // coded LANGUAGE_SYSTEM.
803 rStream
<< (sal_uInt16
) SV_NUMBERFORMATTER_VERSION
;
804 rStream
<< (sal_uInt16
) SvtSysLocale().GetLanguageTag().getLanguageType() << (sal_uInt16
) IniLnge
;
806 const SvNumberFormatTable
* pTable
= &aFTable
;
807 SvNumberFormatTable::const_iterator it
= pTable
->begin();
808 while (it
!= pTable
->end())
810 SvNumberformat
* pEntry
= it
->second
;
811 // Stored are all marked user defined formats and for each active
812 // (selected) locale the Standard/General format and
813 // NewStandardDefined.
814 if ( pEntry
->GetUsed() || (pEntry
->GetType() & NUMBERFORMAT_DEFINED
) ||
815 pEntry
->GetNewStandardDefined() || (it
->first
% SV_COUNTRY_LANGUAGE_OFFSET
== 0) )
818 << (sal_uInt16
) LANGUAGE_SYSTEM
819 << (sal_uInt16
) pEntry
->GetLanguage();
820 pEntry
->Save(rStream
, aHdr
);
824 rStream
<< NUMBERFORMAT_ENTRY_NOT_FOUND
; // end marker
826 // as of SV_NUMBERFORMATTER_VERSION_YEAR2000
828 rStream
<< (sal_uInt16
) GetYear2000();
831 return rStream
.GetError() ? false : true;
834 void SvNumberFormatter::GetUsedLanguages( std::vector
<sal_uInt16
>& rList
)
838 sal_uInt32 nOffset
= 0;
839 while (nOffset
<= MaxCLOffset
)
841 SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
844 rList
.push_back( pFormat
->GetLanguage() );
846 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
851 void SvNumberFormatter::FillKeywordTable( NfKeywordTable
& rKeywords
,
855 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
856 for ( sal_uInt16 i
= 0; i
< NF_KEYWORD_ENTRIES_COUNT
; ++i
)
858 rKeywords
[i
] = rTable
[i
];
863 OUString
SvNumberFormatter::GetKeyword( LanguageType eLnge
, sal_uInt16 nIndex
)
866 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
867 if ( nIndex
< NF_KEYWORD_ENTRIES_COUNT
)
869 return rTable
[nIndex
];
871 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
876 OUString
SvNumberFormatter::GetStandardName( LanguageType eLnge
)
879 return pFormatScanner
->GetStandardName();
883 sal_uInt32
SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge
) const
885 sal_uInt32 nOffset
= 0;
886 while (nOffset
<= MaxCLOffset
)
888 const SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
889 if (pFormat
&& pFormat
->GetLanguage() == eLnge
)
893 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
898 sal_uInt32
SvNumberFormatter::ImpIsEntry(const OUString
& rString
,
899 sal_uInt32 nCLOffset
,
902 sal_uInt32 res
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
903 SvNumberFormatTable::iterator it
= aFTable
.find( nCLOffset
);
904 while ( res
== NUMBERFORMAT_ENTRY_NOT_FOUND
&&
905 it
!= aFTable
.end() && it
->second
->GetLanguage() == eLnge
)
907 if ( rString
== it
->second
->GetFormatstring() )
920 SvNumberFormatTable
& SvNumberFormatter::GetFirstEntryTable(
925 short eTypetmp
= eType
;
926 if (eType
== NUMBERFORMAT_ALL
) // empty cell or don't care
932 SvNumberformat
* pFormat
= GetFormatEntry(FIndex
);
936 eType
= NUMBERFORMAT_ALL
;
941 rLnge
= pFormat
->GetLanguage();
942 eType
= pFormat
->GetType()&~NUMBERFORMAT_DEFINED
;
945 eType
= NUMBERFORMAT_DEFINED
;
948 else if (eType
== NUMBERFORMAT_DATETIME
)
951 eType
= NUMBERFORMAT_DATE
;
960 return GetEntryTable(eTypetmp
, FIndex
, rLnge
);
963 sal_uInt32
SvNumberFormatter::ImpGenerateCL( LanguageType eLnge
, bool bNoAdditionalFormats
)
966 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
967 if (CLOffset
> MaxCLOffset
)
969 // new CL combination
970 if (LocaleDataWrapper::areChecksEnabled())
972 const LanguageTag
& rLoadedLocale
= xLocaleData
->getLoadedLanguageTag();
973 if ( !rLoadedLocale
.equals( maLanguageTag
, true) )
975 OUString
aMsg("SvNumberFormatter::ImpGenerateCL: locales don't match:");
976 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
978 // test XML locale data FormatElement entries
980 uno::Sequence
< i18n::FormatElement
> xSeq
= xLocaleData
->getAllFormats();
981 // A test for completeness of formatindex="0" ...
982 // formatindex="47" is not needed here since it is done in
983 // ImpGenerateFormats().
985 // Test for dupes of formatindex="..."
986 for ( sal_Int32 j
= 0; j
< xSeq
.getLength(); j
++ )
988 sal_Int16 nIdx
= xSeq
[j
].formatIndex
;
989 OUStringBuffer aDupes
;
990 for ( sal_Int32 i
= 0; i
< xSeq
.getLength(); i
++ )
992 if ( i
!= j
&& xSeq
[i
].formatIndex
== nIdx
)
994 aDupes
.append(OUString::valueOf( i
));
996 aDupes
.append(xSeq
[i
].formatKey
);
997 aDupes
.append( ") ");
1000 if ( aDupes
.getLength() > 0 )
1002 OUStringBuffer
aMsg(aDupes
.getLength() + xSeq
[j
].formatKey
.getLength() + 100);
1003 aMsg
.append("XML locale data FormatElement formatindex dupe: ");
1004 aMsg
.append(OUString::valueOf((sal_Int32
)nIdx
));
1005 aMsg
.append("\nFormatElements: ");
1006 aMsg
.append(OUString::valueOf( j
));
1008 aMsg
.append( xSeq
[j
].formatKey
);
1010 aMsg
.append(aDupes
.makeStringAndClear());
1011 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
.makeStringAndClear() ));
1017 MaxCLOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
1018 ImpGenerateFormats( MaxCLOffset
, bNoAdditionalFormats
);
1019 CLOffset
= MaxCLOffset
;
1024 SvNumberFormatTable
& SvNumberFormatter::ChangeCL(short eType
,
1028 ImpGenerateCL(eLnge
);
1029 return GetEntryTable(eType
, FIndex
, ActLnge
);
1032 SvNumberFormatTable
& SvNumberFormatter::GetEntryTable(
1039 pFormatTable
->clear();
1043 pFormatTable
= new SvNumberFormatTable
;
1046 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
1048 // Might generate and insert a default format for the given type
1049 // (e.g. currency) => has to be done before collecting formats.
1050 sal_uInt32 nDefaultIndex
= GetStandardFormat( eType
, ActLnge
);
1052 SvNumberFormatTable::iterator it
= aFTable
.find( CLOffset
);
1054 if (eType
== NUMBERFORMAT_ALL
)
1056 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
1057 { // copy all entries to output table
1058 (*pFormatTable
)[ it
->first
] = it
->second
;
1064 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
1065 { // copy entries of queried type to output table
1066 if ((it
->second
->GetType()) & eType
)
1067 (*pFormatTable
)[ it
->first
] = it
->second
;
1071 if ( !pFormatTable
->empty() )
1072 { // select default if queried format doesn't exist or queried type or
1073 // language differ from existing format
1074 SvNumberformat
* pEntry
= GetFormatEntry(FIndex
);
1075 if ( !pEntry
|| !(pEntry
->GetType() & eType
) || pEntry
->GetLanguage() != ActLnge
)
1077 FIndex
= nDefaultIndex
;
1080 return *pFormatTable
;
1083 bool SvNumberFormatter::IsNumberFormat(const OUString
& sString
,
1084 sal_uInt32
& F_Index
,
1088 const SvNumberformat
* pFormat
= GetFormatEntry(F_Index
);
1091 ChangeIntl(IniLnge
);
1092 FType
= NUMBERFORMAT_NUMBER
;
1096 FType
= pFormat
->GetType() &~NUMBERFORMAT_DEFINED
;
1099 FType
= NUMBERFORMAT_DEFINED
;
1101 ChangeIntl(pFormat
->GetLanguage());
1105 short RType
= FType
;
1106 if (RType
== NUMBERFORMAT_TEXT
)
1108 res
= false; // type text preset => no conversion to number
1112 res
= pStringScanner
->IsNumberFormat(sString
, RType
, fOutNumber
, pFormat
);
1114 if (res
&& !IsCompatible(FType
, RType
)) // non-matching type
1118 case NUMBERFORMAT_DATE
:
1119 // Preserve ISO 8601 input.
1120 if (pStringScanner
->CanForceToIso8601( DMY
))
1122 F_Index
= GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, ActLnge
);
1126 F_Index
= GetStandardFormat( RType
, ActLnge
);
1129 case NUMBERFORMAT_TIME
:
1130 if ( pStringScanner
->GetDecPos() )
1133 if ( pStringScanner
->GetAnzNums() > 3 || fOutNumber
< 0.0 )
1135 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS00
, ActLnge
);
1139 F_Index
= GetFormatIndex( NF_TIME_MMSS00
, ActLnge
);
1142 else if ( fOutNumber
>= 1.0 || fOutNumber
< 0.0 )
1144 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS
, ActLnge
);
1148 F_Index
= GetStandardFormat( RType
, ActLnge
);
1152 F_Index
= GetStandardFormat( RType
, ActLnge
);
1158 bool SvNumberFormatter::IsCompatible(short eOldType
,
1161 if (eOldType
== eNewType
)
1165 else if (eOldType
== NUMBERFORMAT_DEFINED
)
1173 case NUMBERFORMAT_NUMBER
:
1176 case NUMBERFORMAT_PERCENT
:
1177 case NUMBERFORMAT_CURRENCY
:
1178 case NUMBERFORMAT_SCIENTIFIC
:
1179 case NUMBERFORMAT_FRACTION
:
1180 // case NUMBERFORMAT_LOGICAL:
1181 case NUMBERFORMAT_DEFINED
:
1187 case NUMBERFORMAT_DATE
:
1190 case NUMBERFORMAT_DATETIME
:
1196 case NUMBERFORMAT_TIME
:
1199 case NUMBERFORMAT_DATETIME
:
1205 case NUMBERFORMAT_DATETIME
:
1208 case NUMBERFORMAT_TIME
:
1209 case NUMBERFORMAT_DATE
:
1222 sal_uInt32
SvNumberFormatter::ImpGetDefaultFormat( short nType
)
1224 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
1228 case NUMBERFORMAT_DATE
:
1229 nSearch
= CLOffset
+ ZF_STANDARD_DATE
;
1231 case NUMBERFORMAT_TIME
:
1232 nSearch
= CLOffset
+ ZF_STANDARD_TIME
;
1234 case NUMBERFORMAT_DATETIME
:
1235 nSearch
= CLOffset
+ ZF_STANDARD_DATETIME
;
1237 case NUMBERFORMAT_PERCENT
:
1238 nSearch
= CLOffset
+ ZF_STANDARD_PERCENT
;
1240 case NUMBERFORMAT_SCIENTIFIC
:
1241 nSearch
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1244 nSearch
= CLOffset
+ ZF_STANDARD
;
1247 DefaultFormatKeysMap::iterator it
= aDefaultFormatKeys
.find( nSearch
);
1248 sal_uInt32 nDefaultFormat
= (it
!= aDefaultFormatKeys
.end() ?
1249 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
1250 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1252 // look for a defined standard
1253 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
1255 SvNumberFormatTable::iterator it2
= aFTable
.find( CLOffset
);
1256 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
1258 const SvNumberformat
* pEntry
= it2
->second
;
1259 if ( pEntry
->IsStandard() && ((pEntry
->GetType() &
1260 ~NUMBERFORMAT_DEFINED
) == nType
) )
1262 nDefaultFormat
= nKey
;
1268 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1269 { // none found, use old fixed standards
1272 case NUMBERFORMAT_DATE
:
1273 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATE
;
1275 case NUMBERFORMAT_TIME
:
1276 nDefaultFormat
= CLOffset
+ ZF_STANDARD_TIME
+1;
1278 case NUMBERFORMAT_DATETIME
:
1279 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATETIME
;
1281 case NUMBERFORMAT_PERCENT
:
1282 nDefaultFormat
= CLOffset
+ ZF_STANDARD_PERCENT
+1;
1284 case NUMBERFORMAT_SCIENTIFIC
:
1285 nDefaultFormat
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1288 nDefaultFormat
= CLOffset
+ ZF_STANDARD
;
1291 aDefaultFormatKeys
[ nSearch
] = nDefaultFormat
;
1293 return nDefaultFormat
;
1297 sal_uInt32
SvNumberFormatter::GetStandardFormat( short eType
, LanguageType eLnge
)
1299 if (eLnge
== LANGUAGE_DONTKNOW
)
1303 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1306 case NUMBERFORMAT_CURRENCY
:
1307 return ( eLnge
== LANGUAGE_SYSTEM
) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1308 case NUMBERFORMAT_DATE
:
1309 case NUMBERFORMAT_TIME
:
1310 case NUMBERFORMAT_DATETIME
:
1311 case NUMBERFORMAT_PERCENT
:
1312 case NUMBERFORMAT_SCIENTIFIC
:
1313 return ImpGetDefaultFormat( eType
);
1314 case NUMBERFORMAT_FRACTION
:
1315 return CLOffset
+ ZF_STANDARD_FRACTION
;
1316 case NUMBERFORMAT_LOGICAL
:
1317 return CLOffset
+ ZF_STANDARD_LOGICAL
;
1318 case NUMBERFORMAT_TEXT
:
1319 return CLOffset
+ ZF_STANDARD_TEXT
;
1320 case NUMBERFORMAT_ALL
:
1321 case NUMBERFORMAT_DEFINED
:
1322 case NUMBERFORMAT_NUMBER
:
1323 case NUMBERFORMAT_UNDEFINED
:
1325 return CLOffset
+ ZF_STANDARD
;
1329 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex
,
1330 LanguageType eLnge
)
1333 nFIndex
== GetFormatIndex( NF_TIME_MMSS00
, eLnge
) ||
1334 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
) ||
1335 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
)
1339 sal_uInt32
SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex
, short eType
,
1340 LanguageType eLnge
)
1342 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1345 return GetStandardFormat( eType
, eLnge
);
1348 sal_uInt32
SvNumberFormatter::GetStandardFormat( double fNumber
, sal_uInt32 nFIndex
,
1349 short eType
, LanguageType eLnge
)
1351 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1356 case NUMBERFORMAT_TIME
:
1359 if ( fNumber
< 0.0 )
1366 double fSeconds
= fNumber
* 86400;
1367 if ( floor( fSeconds
+ 0.5 ) * 100 != floor( fSeconds
* 100 + 0.5 ) )
1368 { // with 100th seconds
1369 if ( bSign
|| fSeconds
>= 3600 )
1370 return GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
);
1372 return GetFormatIndex( NF_TIME_MMSS00
, eLnge
);
1376 if ( bSign
|| fNumber
>= 1.0 )
1377 return GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
);
1379 return GetStandardFormat( eType
, eLnge
);
1383 return GetStandardFormat( eType
, eLnge
);
1387 sal_uInt32
SvNumberFormatter::GetEditFormat( double fNumber
, sal_uInt32 nFIndex
,
1388 short eType
, LanguageType eLang
,
1389 SvNumberformat
* pFormat
)
1391 sal_uInt32 nKey
= nFIndex
;
1394 // #61619# always edit using 4-digit year
1395 case NUMBERFORMAT_DATE
:
1396 if (rtl::math::approxFloor( fNumber
) != fNumber
)
1397 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1398 // fdo#34977 preserve time when editing even if only date was
1400 /* FIXME: in case an ISO 8601 format was used, editing should
1401 * also use such. Unfortunately we have no builtin combined
1402 * date+time ISO format defined. Needs also locale data work.
1406 // Preserve ISO 8601 format.
1407 if ( nFIndex
== GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, eLang
) ||
1408 nFIndex
== GetFormatIndex( NF_DATE_DIN_YYMMDD
, eLang
) ||
1409 nFIndex
== GetFormatIndex( NF_DATE_DIN_MMDD
, eLang
) ||
1410 (pFormat
&& pFormat
->IsIso8601( 0 )))
1411 nKey
= GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, eLang
);
1413 nKey
= GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, eLang
);
1416 case NUMBERFORMAT_TIME
:
1417 if (fNumber
< 0.0 || fNumber
>= 1.0)
1419 /* XXX NOTE: this is a purely arbitrary value within the limits
1420 * of a signed 16-bit. 32k hours are 3.7 years ... or
1421 * 1903-09-26 if date. */
1422 if (fabs( fNumber
) * 24 < 0x7fff)
1423 nKey
= GetFormatIndex( NF_TIME_HH_MMSS
, eLang
);
1424 // Preserve duration, use [HH]:MM:SS instead of time.
1426 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1427 // Assume that a large value is a datetime with only time
1431 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1433 case NUMBERFORMAT_DATETIME
:
1434 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1435 /* FIXME: in case an ISO 8601 format was used, editing should
1436 * also use such. Unfortunately we have no builtin combined
1437 * date+time ISO format defined. Needs also locale data work. */
1440 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1445 void SvNumberFormatter::GetInputLineString(const double& fOutNumber
,
1447 OUString
& sOutString
)
1450 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1453 pFormat
= GetFormatEntry(ZF_STANDARD
);
1456 LanguageType eLang
= pFormat
->GetLanguage();
1457 ChangeIntl( eLang
);
1459 short eType
= pFormat
->GetType() & ~NUMBERFORMAT_DEFINED
;
1462 eType
= NUMBERFORMAT_DEFINED
;
1465 sal_uInt16 nOldPrec
= pFormatScanner
->GetStandardPrec();
1466 bool bPrecChanged
= false;
1467 if (eType
== NUMBERFORMAT_NUMBER
||
1468 eType
== NUMBERFORMAT_PERCENT
||
1469 eType
== NUMBERFORMAT_CURRENCY
||
1470 eType
== NUMBERFORMAT_SCIENTIFIC
||
1471 eType
== NUMBERFORMAT_FRACTION
)
1473 if (eType
!= NUMBERFORMAT_PERCENT
) // special treatment of % later
1475 eType
= NUMBERFORMAT_NUMBER
;
1477 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1478 bPrecChanged
= true;
1481 sal_uInt32 nKey
= GetEditFormat( fOutNumber
, nFIndex
, eType
, eLang
, pFormat
);
1482 if ( nKey
!= nFIndex
)
1484 pFormat
= GetFormatEntry( nKey
);
1488 if ( eType
== NUMBERFORMAT_TIME
&& pFormat
->GetFormatPrecision() )
1490 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1491 bPrecChanged
= true;
1493 pFormat
->GetOutputString(fOutNumber
, sOutString
, &pColor
);
1497 ChangeStandardPrec(nOldPrec
);
1501 void SvNumberFormatter::GetInputLineString(const double& fOutNumber
,
1506 GetInputLineString(fOutNumber
, nFIndex
, aTmp
);
1510 void SvNumberFormatter::GetOutputString(const OUString
& sString
,
1512 OUString
& sOutString
,
1514 bool bUseStarFormat
)
1516 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1519 pFormat
= GetFormatEntry(ZF_STANDARD_TEXT
);
1521 if (!pFormat
->IsTextFormat() && !pFormat
->HasTextFormat())
1524 sOutString
= sString
;
1528 ChangeIntl(pFormat
->GetLanguage());
1529 if ( bUseStarFormat
)
1531 pFormat
->SetStarFormatSupport( true );
1533 pFormat
->GetOutputString(sString
, sOutString
, ppColor
);
1534 if ( bUseStarFormat
)
1536 pFormat
->SetStarFormatSupport( false );
1541 void SvNumberFormatter::GetOutputString(const double& fOutNumber
,
1543 OUString
& sOutString
,
1545 bool bUseStarFormat
)
1547 if (bNoZero
&& fOutNumber
== 0.0)
1549 sOutString
= OUString();
1552 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1554 pFormat
= GetFormatEntry(ZF_STANDARD
);
1555 ChangeIntl(pFormat
->GetLanguage());
1556 if ( bUseStarFormat
)
1557 pFormat
->SetStarFormatSupport( true );
1558 pFormat
->GetOutputString(fOutNumber
, sOutString
, ppColor
);
1559 if ( bUseStarFormat
)
1560 pFormat
->SetStarFormatSupport( false );
1563 void SvNumberFormatter::GetOutputString(const double& fOutNumber
,
1567 bool bUseStarFormat
)
1569 OUString
sTemp(sOutString
);
1570 GetOutputString(fOutNumber
, nFIndex
, sTemp
, ppColor
, bUseStarFormat
);
1574 bool SvNumberFormatter::GetPreviewString(const OUString
& sFormatString
,
1575 double fPreviewNumber
,
1576 OUString
& sOutString
,
1579 bool bUseStarFormat
)
1581 if (sFormatString
.isEmpty()) // no empty string
1586 if (eLnge
== LANGUAGE_DONTKNOW
)
1590 ChangeIntl(eLnge
); // change locale if necessary
1592 sal_Int32 nCheckPos
= -1;
1593 OUString sTmpString
= sFormatString
;
1594 SvNumberformat
* p_Entry
= new SvNumberformat(sTmpString
,
1599 if (nCheckPos
== 0) // String ok
1601 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
1602 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLnge
);
1603 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1605 GetOutputString(fPreviewNumber
, nKey
, sOutString
, ppColor
, bUseStarFormat
);
1609 if ( bUseStarFormat
)
1611 p_Entry
->SetStarFormatSupport( true );
1613 p_Entry
->GetOutputString(fPreviewNumber
, sOutString
, ppColor
);
1614 if ( bUseStarFormat
)
1616 p_Entry
->SetStarFormatSupport( false );
1629 bool SvNumberFormatter::GetPreviewStringGuess( const OUString
& sFormatString
,
1630 double fPreviewNumber
,
1631 OUString
& sOutString
,
1633 LanguageType eLnge
)
1635 if (sFormatString
.isEmpty()) // no empty string
1639 if (eLnge
== LANGUAGE_DONTKNOW
)
1643 ChangeIntl( eLnge
);
1645 bool bEnglish
= (eLnge
== LANGUAGE_ENGLISH_US
);
1647 OUString
aFormatStringUpper( pCharClass
->uppercase( sFormatString
) );
1648 sal_uInt32 nCLOffset
= ImpGenerateCL( eLnge
);
1649 sal_uInt32 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, eLnge
);
1650 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1652 // Zielformat vorhanden
1653 GetOutputString( fPreviewNumber
, nKey
, sOutString
, ppColor
);
1657 SvNumberformat
*pEntry
= NULL
;
1658 sal_Int32 nCheckPos
= -1;
1659 OUString sTmpString
;
1663 sTmpString
= sFormatString
;
1664 pEntry
= new SvNumberformat( sTmpString
, pFormatScanner
,
1665 pStringScanner
, nCheckPos
, eLnge
);
1669 nCLOffset
= ImpGenerateCL( LANGUAGE_ENGLISH_US
);
1670 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, LANGUAGE_ENGLISH_US
);
1671 bool bEnglishFormat
= (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
1673 // try english --> other bzw. english nach other konvertieren
1674 LanguageType eFormatLang
= LANGUAGE_ENGLISH_US
;
1675 pFormatScanner
->SetConvertMode( LANGUAGE_ENGLISH_US
, eLnge
);
1676 sTmpString
= sFormatString
;
1677 pEntry
= new SvNumberformat( sTmpString
, pFormatScanner
,
1678 pStringScanner
, nCheckPos
, eFormatLang
);
1679 pFormatScanner
->SetConvertMode( false );
1680 ChangeIntl( eLnge
);
1682 if ( !bEnglishFormat
)
1684 if ( !(nCheckPos
== 0) || xTransliteration
->isEqual( sFormatString
,
1685 pEntry
->GetFormatstring() ) )
1689 sTmpString
= sFormatString
;
1690 pEntry
= new SvNumberformat( sTmpString
, pFormatScanner
,
1691 pStringScanner
, nCheckPos
, eLnge
);
1696 sal_Int32 nCheckPos2
= -1;
1697 // try other --> english
1698 eFormatLang
= eLnge
;
1699 pFormatScanner
->SetConvertMode( eLnge
, LANGUAGE_ENGLISH_US
);
1700 sTmpString
= sFormatString
;
1701 SvNumberformat
* pEntry2
= new SvNumberformat( sTmpString
, pFormatScanner
,
1702 pStringScanner
, nCheckPos2
, eFormatLang
);
1703 pFormatScanner
->SetConvertMode( false );
1704 ChangeIntl( eLnge
);
1705 if ( nCheckPos2
== 0 && !xTransliteration
->isEqual( sFormatString
,
1706 pEntry2
->GetFormatstring() ) )
1710 sTmpString
= sFormatString
;
1711 pEntry
= new SvNumberformat( sTmpString
, pFormatScanner
,
1712 pStringScanner
, nCheckPos
, eLnge
);
1719 if (nCheckPos
== 0) // String ok
1721 ImpGenerateCL( eLnge
); // create new standard formats if necessary
1722 pEntry
->GetOutputString( fPreviewNumber
, sOutString
, ppColor
);
1730 bool SvNumberFormatter::GetPreviewString( const OUString
& sFormatString
,
1731 const OUString
& sPreviewString
,
1732 OUString
& sOutString
,
1734 LanguageType eLnge
)
1736 if (sFormatString
.isEmpty()) // no empty string
1741 if (eLnge
== LANGUAGE_DONTKNOW
)
1745 ChangeIntl(eLnge
); // switch if needed
1747 sal_Int32 nCheckPos
= -1;
1748 OUString sTmpString
= sFormatString
;
1749 SvNumberformat
* p_Entry
= new SvNumberformat( sTmpString
,
1754 if (nCheckPos
== 0) // String ok
1756 // May have to create standard formats for this locale.
1757 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1758 nKey
= ImpIsEntry( p_Entry
->GetFormatstring(), CLOffset
, eLnge
);
1759 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1761 GetOutputString( sPreviewString
, nKey
, sOutString
, ppColor
);
1765 // If the format is valid but not a text format and does not
1766 // include a text subformat, an empty string would result. Same as
1767 // in SvNumberFormatter::GetOutputString()
1768 if (p_Entry
->IsTextFormat() || p_Entry
->HasTextFormat())
1770 p_Entry
->GetOutputString( sPreviewString
, sOutString
, ppColor
);
1775 sOutString
= sPreviewString
;
1788 sal_uInt32
SvNumberFormatter::TestNewString(const OUString
& sFormatString
,
1791 if (sFormatString
.isEmpty()) // no empty string
1793 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
1795 if (eLnge
== LANGUAGE_DONTKNOW
)
1799 ChangeIntl(eLnge
); // change locale if necessary
1802 sal_Int32 nCheckPos
= -1;
1803 OUString sTmpString
= sFormatString
;
1804 SvNumberformat
* pEntry
= new SvNumberformat(sTmpString
,
1809 if (nCheckPos
== 0) // String ok
1811 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
1812 nRes
= ImpIsEntry(pEntry
->GetFormatstring(),CLOffset
, eLnge
);
1817 nRes
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1823 SvNumberformat
* SvNumberFormatter::ImpInsertFormat( const ::com::sun::star::i18n::NumberFormatCode
& rCode
,
1824 sal_uInt32 nPos
, bool bAfterChangingSystemCL
,
1825 sal_Int16 nOrgIndex
)
1827 String
aCodeStr( rCode
.Code
);
1828 if ( rCode
.Index
< NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
&&
1829 rCode
.Usage
== ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY
&&
1830 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
1831 { // strip surrounding [$...] on automatic currency
1832 if ( aCodeStr
.SearchAscii( "[$" ) != STRING_NOTFOUND
)
1833 aCodeStr
= SvNumberformat::StripNewCurrencyDelimiters( aCodeStr
, false );
1836 if (LocaleDataWrapper::areChecksEnabled() &&
1837 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
1839 OUString
aMsg("SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index ");
1840 aMsg
+= OUString::valueOf( sal_Int32(rCode
.Index
) );
1843 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1847 sal_Int32 nCheckPos
= 0;
1848 OUString
sTempIn(aCodeStr
);
1849 SvNumberformat
* pFormat
= new SvNumberformat(sTempIn
,
1855 if ( !pFormat
|| !(nCheckPos
== 0) )
1857 if (LocaleDataWrapper::areChecksEnabled())
1859 OUString
aMsg( "SvNumberFormatter::ImpInsertFormat: bad format code, index " );
1860 aMsg
+= OUString::valueOf( sal_Int32(rCode
.Index
) );
1863 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1868 if ( rCode
.Index
>= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
)
1870 sal_uInt32 nCLOffset
= nPos
- (nPos
% SV_COUNTRY_LANGUAGE_OFFSET
);
1871 sal_uInt32 nKey
= ImpIsEntry( aCodeStr
, nCLOffset
, ActLnge
);
1872 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1874 // If bAfterChangingSystemCL there will definitely be some dups,
1876 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL
)
1878 // Test for duplicate indexes in locale data.
1879 switch ( nOrgIndex
)
1881 // These may be dups of integer versions for locales where
1882 // currencies have no decimals like Italian Lira.
1883 case NF_CURRENCY_1000DEC2
: // NF_CURRENCY_1000INT
1884 case NF_CURRENCY_1000DEC2_RED
: // NF_CURRENCY_1000INT_RED
1885 case NF_CURRENCY_1000DEC2_DASHED
: // NF_CURRENCY_1000INT_RED
1889 OUString
aMsg("SvNumberFormatter::ImpInsertFormat: dup format code, index ");
1890 aMsg
+= OUString::valueOf( sal_Int32(rCode
.Index
) );
1893 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1900 else if ( nPos
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
1902 if (LocaleDataWrapper::areChecksEnabled())
1904 OUString
aMsg( "SvNumberFormatter::ImpInsertFormat: too many format codes, index ");
1905 aMsg
+= OUString::valueOf( sal_Int32(rCode
.Index
) );
1908 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1914 if ( !aFTable
.insert( make_pair( nPos
, pFormat
) ).second
)
1916 if (LocaleDataWrapper::areChecksEnabled())
1918 OUString
aMsg( "ImpInsertFormat: can't insert number format key pos: ");
1919 aMsg
+= OUString::valueOf( sal_Int32( nPos
) );
1920 aMsg
+= ", code index ";
1921 aMsg
+= OUString::valueOf( sal_Int32(rCode
.Index
) );
1924 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1928 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
1933 if ( rCode
.Default
)
1934 pFormat
->SetStandard();
1935 if ( !rCode
.DefaultName
.isEmpty() )
1936 pFormat
->SetComment( rCode
.DefaultName
);
1940 SvNumberformat
* SvNumberFormatter::ImpInsertNewStandardFormat(
1941 const ::com::sun::star::i18n::NumberFormatCode
& rCode
,
1942 sal_uInt32 nPos
, sal_uInt16 nVersion
, bool bAfterChangingSystemCL
,
1943 sal_Int16 nOrgIndex
)
1945 SvNumberformat
* pNewFormat
= ImpInsertFormat( rCode
, nPos
,
1946 bAfterChangingSystemCL
, nOrgIndex
);
1948 pNewFormat
->SetNewStandardDefined( nVersion
);
1949 // so that it gets saved, displayed properly, and converted by old versions
1953 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat
,
1956 sal_uInt16
& nPrecision
,
1957 sal_uInt16
& nAnzLeading
)
1960 SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
1962 pFormat
->GetFormatSpecialInfo(bThousand
, IsRed
,
1963 nPrecision
, nAnzLeading
);
1968 nPrecision
= pFormatScanner
->GetStandardPrec();
1973 sal_uInt16
SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat
) const
1975 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
1977 return pFormat
->GetFormatPrecision();
1979 return pFormatScanner
->GetStandardPrec();
1983 OUString
SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat
) const
1985 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
1986 if ( !pFormat
|| pFormat
->GetLanguage() == ActLnge
)
1988 return GetNumDecimalSep();
1991 LanguageType eSaveLang
= xLocaleData
.getCurrentLanguage();
1992 if ( pFormat
->GetLanguage() == eSaveLang
)
1994 aRet
= xLocaleData
->getNumDecimalSep();
1998 LanguageTag
aSaveLocale( xLocaleData
->getLanguageTag() );
1999 ((SvNumberFormatter
*)this)->xLocaleData
.changeLocale( LanguageTag( pFormat
->GetLanguage()) );
2000 aRet
= xLocaleData
->getNumDecimalSep();
2001 ((SvNumberFormatter
*)this)->xLocaleData
.changeLocale( aSaveLocale
);
2007 sal_uInt32
SvNumberFormatter::GetFormatSpecialInfo( const OUString
& rFormatString
,
2008 bool& bThousand
, bool& IsRed
, sal_uInt16
& nPrecision
,
2009 sal_uInt16
& nAnzLeading
, LanguageType eLnge
)
2012 if (eLnge
== LANGUAGE_DONTKNOW
)
2016 ChangeIntl(eLnge
); // change locale if necessary
2018 OUString
aTmpStr( rFormatString
);
2019 sal_Int32 nCheckPos
= 0;
2020 SvNumberformat
* pFormat
= new SvNumberformat( aTmpStr
, pFormatScanner
,
2021 pStringScanner
, nCheckPos
, eLnge
);
2022 if ( nCheckPos
== 0 )
2024 pFormat
->GetFormatSpecialInfo( bThousand
, IsRed
, nPrecision
, nAnzLeading
);
2030 nPrecision
= pFormatScanner
->GetStandardPrec();
2038 inline sal_uInt32
SetIndexTable( NfIndexTableOffset nTabOff
, sal_uInt32 nIndOff
)
2040 if ( !bIndexTableInitialized
)
2042 DBG_ASSERT( theIndexTable
[nTabOff
] == NUMBERFORMAT_ENTRY_NOT_FOUND
,
2043 "SetIndexTable: theIndexTable[nTabOff] already occupied" );
2044 theIndexTable
[nTabOff
] = nIndOff
;
2050 sal_Int32
SvNumberFormatter::ImpGetFormatCodeIndex(
2051 ::com::sun::star::uno::Sequence
< ::com::sun::star::i18n::NumberFormatCode
>& rSeq
,
2052 const NfIndexTableOffset nTabOff
)
2054 const sal_Int32 nLen
= rSeq
.getLength();
2055 for ( sal_Int32 j
=0; j
<nLen
; j
++ )
2057 if ( rSeq
[j
].Index
== nTabOff
)
2060 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff
< NF_CURRENCY_START
2061 || NF_CURRENCY_END
< nTabOff
|| nTabOff
== NF_CURRENCY_1000INT
2062 || nTabOff
== NF_CURRENCY_1000INT_RED
2063 || nTabOff
== NF_CURRENCY_1000DEC2_CCC
))
2064 { // currency entries with decimals might not exist, e.g. Italian Lira
2065 OUString
aMsg( "SvNumberFormatter::ImpGetFormatCodeIndex: not found: " );
2066 aMsg
+= OUString::valueOf( sal_Int32( nTabOff
) );
2067 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo(aMsg
));
2072 // look for a preset default
2073 for ( j
=0; j
<nLen
; j
++ )
2075 if ( rSeq
[j
].Default
)
2078 // currencies are special, not all format codes must exist, but all
2079 // builtin number format key index positions must have a format assigned
2080 if ( NF_CURRENCY_START
<= nTabOff
&& nTabOff
<= NF_CURRENCY_END
)
2082 // look for a format with decimals
2083 for ( j
=0; j
<nLen
; j
++ )
2085 if ( rSeq
[j
].Index
== NF_CURRENCY_1000DEC2
)
2088 // last resort: look for a format without decimals
2089 for ( j
=0; j
<nLen
; j
++ )
2091 if ( rSeq
[j
].Index
== NF_CURRENCY_1000INT
)
2097 { // we need at least _some_ format
2099 rSeq
[0] = ::com::sun::star::i18n::NumberFormatCode();
2100 rSeq
[0].Code
= OUStringBuffer().
2102 append(GetNumDecimalSep()).
2103 append("############").
2104 makeStringAndClear();
2110 sal_Int32
SvNumberFormatter::ImpAdjustFormatCodeDefault(
2111 ::com::sun::star::i18n::NumberFormatCode
* pFormatArr
,
2112 sal_Int32 nCnt
, bool bCheckCorrectness
)
2114 using namespace ::com::sun::star
;
2118 if (bCheckCorrectness
&& LocaleDataWrapper::areChecksEnabled())
2120 // check the locale data for correctness
2122 sal_Int32 nElem
, nShort
, nMedium
, nLong
, nShortDef
, nMediumDef
, nLongDef
;
2123 nShort
= nMedium
= nLong
= nShortDef
= nMediumDef
= nLongDef
= -1;
2124 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2126 switch ( pFormatArr
[nElem
].Type
)
2128 case i18n::KNumberFormatType::SHORT
:
2131 case i18n::KNumberFormatType::MEDIUM
:
2134 case i18n::KNumberFormatType::LONG
:
2138 aMsg
.append("unknown type");
2140 if ( pFormatArr
[nElem
].Default
)
2142 switch ( pFormatArr
[nElem
].Type
)
2144 case i18n::KNumberFormatType::SHORT
:
2145 if ( nShortDef
!= -1 )
2146 aMsg
.append("dupe short type default");
2149 case i18n::KNumberFormatType::MEDIUM
:
2150 if ( nMediumDef
!= -1 )
2151 aMsg
.append("dupe medium type default");
2154 case i18n::KNumberFormatType::LONG
:
2155 if ( nLongDef
!= -1 )
2156 aMsg
.append("dupe long type default");
2161 if (aMsg
.getLength())
2163 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2164 aMsg
.append("\nXML locale data FormatElement formatindex: ");
2165 aMsg
.append(static_cast<sal_Int32
>(pFormatArr
[nElem
].Index
));
2166 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(),
2167 RTL_TEXTENCODING_ASCII_US
));
2168 LocaleDataWrapper::outputCheckMessage(xLocaleData
->appendLocaleInfo(aUMsg
));
2171 if ( nShort
!= -1 && nShortDef
== -1 )
2172 aMsg
.append("no short type default ");
2173 if ( nMedium
!= -1 && nMediumDef
== -1 )
2174 aMsg
.append("no medium type default ");
2175 if ( nLong
!= -1 && nLongDef
== -1 )
2176 aMsg
.append("no long type default ");
2177 if (aMsg
.getLength())
2179 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2180 aMsg
.append("\nXML locale data FormatElement group of: ");
2181 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
));
2182 LocaleDataWrapper::outputCheckMessage(
2183 xLocaleData
->appendLocaleInfo(aUMsg
+ pFormatArr
[0].NameID
));
2186 // find the default (medium preferred, then long) and reset all other defaults
2187 sal_Int32 nElem
, nDef
, nMedium
;
2188 nDef
= nMedium
= -1;
2189 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2191 if ( pFormatArr
[nElem
].Default
)
2193 switch ( pFormatArr
[nElem
].Type
)
2195 case i18n::KNumberFormatType::MEDIUM
:
2196 nDef
= nMedium
= nElem
;
2198 case i18n::KNumberFormatType::LONG
:
2199 if ( nMedium
== -1 )
2205 pFormatArr
[nElem
].Default
= false;
2211 pFormatArr
[nDef
].Default
= true;
2215 SvNumberformat
* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey
)
2217 SvNumberFormatTable::iterator it
= aFTable
.find( nKey
);
2218 if (it
!= aFTable
.end())
2223 const SvNumberformat
* SvNumberFormatter::GetEntry( sal_uInt32 nKey
) const
2225 SvNumberFormatTable::const_iterator it
= aFTable
.find( nKey
);
2226 if (it
!= aFTable
.end())
2231 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset
, bool bNoAdditionalFormats
)
2233 using namespace ::com::sun::star
;
2235 if ( !bIndexTableInitialized
)
2237 for ( sal_uInt16 j
=0; j
<NF_INDEX_TABLE_ENTRIES
; j
++ )
2239 theIndexTable
[j
] = NUMBERFORMAT_ENTRY_NOT_FOUND
;
2242 bool bOldConvertMode
= pFormatScanner
->GetConvertMode();
2243 if (bOldConvertMode
)
2245 pFormatScanner
->SetConvertMode(false); // switch off for this function
2248 NumberFormatCodeWrapper
aNumberFormatCode( m_xContext
,
2249 GetLanguageTag().getLocale() );
2250 SvNumberformat
* pNewFormat
= NULL
;
2254 // Counter for additional builtin formats not fitting into the first 10
2255 // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2256 // Has to be incremented on each ImpInsertNewStandardformat, new formats
2257 // must be appended, not inserted!
2258 sal_uInt16 nNewExtended
= ZF_STANDARD_NEWEXTENDED
;
2261 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
=
2262 aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER
);
2263 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2266 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_STANDARD
);
2267 SvNumberformat
* pStdFormat
= ImpInsertFormat( aFormatSeq
[nIdx
],
2268 CLOffset
+ SetIndexTable( NF_NUMBER_STANDARD
, ZF_STANDARD
));
2271 // This is _the_ standard format.
2272 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat
->GetType() != NUMBERFORMAT_NUMBER
)
2274 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2275 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2277 pStdFormat
->SetType( NUMBERFORMAT_NUMBER
);
2278 pStdFormat
->SetStandard();
2279 pStdFormat
->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE
);
2283 if (LocaleDataWrapper::areChecksEnabled())
2285 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2286 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2291 OUString aFormatCode
= pFormatScanner
->GetBooleanString();
2292 sal_Int32 nCheckPos
= 0;
2294 pNewFormat
= new SvNumberformat( aFormatCode
, pFormatScanner
,
2295 pStringScanner
, nCheckPos
, ActLnge
);
2296 pNewFormat
->SetType(NUMBERFORMAT_LOGICAL
);
2297 pNewFormat
->SetStandard();
2298 if ( !aFTable
.insert(make_pair(
2299 CLOffset
+ SetIndexTable( NF_BOOLEAN
, ZF_STANDARD_LOGICAL
),
2300 pNewFormat
)).second
)
2302 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2308 pNewFormat
= new SvNumberformat( aFormatCode
, pFormatScanner
,
2309 pStringScanner
, nCheckPos
, ActLnge
);
2310 pNewFormat
->SetType(NUMBERFORMAT_TEXT
);
2311 pNewFormat
->SetStandard();
2312 if ( !aFTable
.insert(make_pair(
2313 CLOffset
+ SetIndexTable( NF_TEXT
, ZF_STANDARD_TEXT
),
2314 pNewFormat
)).second
)
2316 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2323 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_INT
);
2324 ImpInsertFormat( aFormatSeq
[nIdx
],
2325 CLOffset
+ SetIndexTable( NF_NUMBER_INT
, ZF_STANDARD
+1 ));
2328 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_DEC2
);
2329 ImpInsertFormat( aFormatSeq
[nIdx
],
2330 CLOffset
+ SetIndexTable( NF_NUMBER_DEC2
, ZF_STANDARD
+2 ));
2333 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000INT
);
2334 ImpInsertFormat( aFormatSeq
[nIdx
],
2335 CLOffset
+ SetIndexTable( NF_NUMBER_1000INT
, ZF_STANDARD
+3 ));
2338 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000DEC2
);
2339 ImpInsertFormat( aFormatSeq
[nIdx
],
2340 CLOffset
+ SetIndexTable( NF_NUMBER_1000DEC2
, ZF_STANDARD
+4 ));
2342 // #.##0,00 System country/language dependent since number formatter version 6
2343 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_SYSTEM
);
2344 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2345 CLOffset
+ SetIndexTable( NF_NUMBER_SYSTEM
, ZF_STANDARD
+5 ),
2346 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2350 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER
);
2351 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2354 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_INT
);
2355 ImpInsertFormat( aFormatSeq
[nIdx
],
2356 CLOffset
+ SetIndexTable( NF_PERCENT_INT
, ZF_STANDARD_PERCENT
));
2359 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_DEC2
);
2360 ImpInsertFormat( aFormatSeq
[nIdx
],
2361 CLOffset
+ SetIndexTable( NF_PERCENT_DEC2
, ZF_STANDARD_PERCENT
+1 ));
2365 // Currency. NO default standard option! Default is determined of locale
2366 // data default currency and format is generated if needed.
2367 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
);
2368 if (LocaleDataWrapper::areChecksEnabled())
2370 // though no default desired here, test for correctness of locale data
2371 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2375 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT
);
2376 bDefault
= aFormatSeq
[nIdx
].Default
;
2377 aFormatSeq
[nIdx
].Default
= false;
2378 ImpInsertFormat( aFormatSeq
[nIdx
],
2379 CLOffset
+ SetIndexTable( NF_CURRENCY_1000INT
, ZF_STANDARD_CURRENCY
));
2380 aFormatSeq
[nIdx
].Default
= bDefault
;
2383 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2
);
2384 bDefault
= aFormatSeq
[nIdx
].Default
;
2385 aFormatSeq
[nIdx
].Default
= false;
2386 ImpInsertFormat( aFormatSeq
[nIdx
],
2387 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2
, ZF_STANDARD_CURRENCY
+1 ));
2388 aFormatSeq
[nIdx
].Default
= bDefault
;
2390 // #,##0 negative red
2391 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT_RED
);
2392 bDefault
= aFormatSeq
[nIdx
].Default
;
2393 aFormatSeq
[nIdx
].Default
= false;
2394 ImpInsertFormat( aFormatSeq
[nIdx
],
2395 CLOffset
+ SetIndexTable( NF_CURRENCY_1000INT_RED
, ZF_STANDARD_CURRENCY
+2 ));
2396 aFormatSeq
[nIdx
].Default
= bDefault
;
2398 // #,##0.00 negative red
2399 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_RED
);
2400 bDefault
= aFormatSeq
[nIdx
].Default
;
2401 aFormatSeq
[nIdx
].Default
= false;
2402 ImpInsertFormat( aFormatSeq
[nIdx
],
2403 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2_RED
, ZF_STANDARD_CURRENCY
+3 ));
2404 aFormatSeq
[nIdx
].Default
= bDefault
;
2406 // #,##0.00 USD since number formatter version 3
2407 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_CCC
);
2408 bDefault
= aFormatSeq
[nIdx
].Default
;
2409 aFormatSeq
[nIdx
].Default
= false;
2410 pNewFormat
= ImpInsertFormat( aFormatSeq
[nIdx
],
2411 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2_CCC
, ZF_STANDARD_CURRENCY
+4 ));
2413 pNewFormat
->SetUsed(true); // must be saved for older versions
2414 aFormatSeq
[nIdx
].Default
= bDefault
;
2416 // #.##0,-- since number formatter version 6
2417 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_DASHED
);
2418 bDefault
= aFormatSeq
[nIdx
].Default
;
2419 aFormatSeq
[nIdx
].Default
= false;
2420 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2421 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2_DASHED
, ZF_STANDARD_CURRENCY
+5 ),
2422 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2423 aFormatSeq
[nIdx
].Default
= bDefault
;
2428 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::DATE
);
2429 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2432 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_SHORT
);
2433 ImpInsertFormat( aFormatSeq
[nIdx
],
2434 CLOffset
+ SetIndexTable( NF_DATE_SYSTEM_SHORT
, ZF_STANDARD_DATE
));
2437 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DEF_NNDDMMMYY
);
2438 ImpInsertFormat( aFormatSeq
[nIdx
],
2439 CLOffset
+ SetIndexTable( NF_DATE_DEF_NNDDMMMYY
, ZF_STANDARD_DATE
+1 ));
2441 // DD.MM.YY def/System
2442 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_MMYY
);
2443 ImpInsertFormat( aFormatSeq
[nIdx
],
2444 CLOffset
+ SetIndexTable( NF_DATE_SYS_MMYY
, ZF_STANDARD_DATE
+2 ));
2447 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMM
);
2448 ImpInsertFormat( aFormatSeq
[nIdx
],
2449 CLOffset
+ SetIndexTable( NF_DATE_SYS_DDMMM
, ZF_STANDARD_DATE
+3 ));
2452 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_MMMM
);
2453 ImpInsertFormat( aFormatSeq
[nIdx
],
2454 CLOffset
+ SetIndexTable( NF_DATE_MMMM
, ZF_STANDARD_DATE
+4 ));
2457 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_QQJJ
);
2458 ImpInsertFormat( aFormatSeq
[nIdx
],
2459 CLOffset
+ SetIndexTable( NF_DATE_QQJJ
, ZF_STANDARD_DATE
+5 ));
2461 // DD.MM.YYYY since number formatter version 2, was DD.MM.[YY]YY
2462 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYYYY
);
2463 pNewFormat
= ImpInsertFormat( aFormatSeq
[nIdx
],
2464 CLOffset
+ SetIndexTable( NF_DATE_SYS_DDMMYYYY
, ZF_STANDARD_DATE
+6 ));
2467 pNewFormat
->SetUsed(true); // must be saved for older versions
2469 // DD.MM.YY def/System, since number formatter version 6
2470 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYY
);
2471 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2472 CLOffset
+ SetIndexTable( NF_DATE_SYS_DDMMYY
, ZF_STANDARD_DATE
+7 ),
2473 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2475 // NNN, D. MMMM YYYY System
2476 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2477 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_LONG
);
2478 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2479 CLOffset
+ SetIndexTable( NF_DATE_SYSTEM_LONG
, ZF_STANDARD_DATE
+8 ),
2480 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2482 // Hard coded but system (regional settings) delimiters dependent long date formats
2483 // since numberformatter version 6
2485 // D. MMM YY def/System
2486 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYY
);
2487 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2488 CLOffset
+ SetIndexTable( NF_DATE_SYS_DMMMYY
, ZF_STANDARD_DATE
+9 ),
2489 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2491 //! Unfortunally TLOT intended only 10 builtin formats per category, more
2492 //! would overwrite the next category (ZF_STANDARD_TIME) :-((
2493 //! Therefore they are inserted with nNewExtended++ (which is also limited)
2495 // D. MMM YYYY def/System
2496 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYYYY
);
2497 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2498 CLOffset
+ SetIndexTable( NF_DATE_SYS_DMMMYYYY
, nNewExtended
++ ),
2499 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2501 // D. MMMM YYYY def/System
2502 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMMYYYY
);
2503 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2504 CLOffset
+ SetIndexTable( NF_DATE_SYS_DMMMMYYYY
, nNewExtended
++ ),
2505 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2507 // NN, D. MMM YY def/System
2508 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMYY
);
2509 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2510 CLOffset
+ SetIndexTable( NF_DATE_SYS_NNDMMMYY
, nNewExtended
++ ),
2511 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2513 // NN, D. MMMM YYYY def/System
2514 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMMYYYY
);
2515 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2516 CLOffset
+ SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY
, nNewExtended
++ ),
2517 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2519 // NNN, D. MMMM YYYY def/System
2520 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNNNDMMMMYYYY
);
2521 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2522 CLOffset
+ SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY
, nNewExtended
++ ),
2523 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2525 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2527 // D. MMM. YYYY DIN/EN
2528 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMYYYY
);
2529 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2530 CLOffset
+ SetIndexTable( NF_DATE_DIN_DMMMYYYY
, nNewExtended
++ ),
2531 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2533 // D. MMMM YYYY DIN/EN
2534 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMMYYYY
);
2535 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2536 CLOffset
+ SetIndexTable( NF_DATE_DIN_DMMMMYYYY
, nNewExtended
++ ),
2537 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2540 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_MMDD
);
2541 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2542 CLOffset
+ SetIndexTable( NF_DATE_DIN_MMDD
, nNewExtended
++ ),
2543 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2546 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYMMDD
);
2547 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2548 CLOffset
+ SetIndexTable( NF_DATE_DIN_YYMMDD
, nNewExtended
++ ),
2549 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2551 // YYYY-MM-DD DIN/EN
2552 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYYYMMDD
);
2553 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2554 CLOffset
+ SetIndexTable( NF_DATE_DIN_YYYYMMDD
, nNewExtended
++ ),
2555 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
);
2560 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::TIME
);
2561 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2564 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMM
);
2565 ImpInsertFormat( aFormatSeq
[nIdx
],
2566 CLOffset
+ SetIndexTable( NF_TIME_HHMM
, ZF_STANDARD_TIME
));
2569 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSS
);
2570 ImpInsertFormat( aFormatSeq
[nIdx
],
2571 CLOffset
+ SetIndexTable( NF_TIME_HHMMSS
, ZF_STANDARD_TIME
+1 ));
2574 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMAMPM
);
2575 ImpInsertFormat( aFormatSeq
[nIdx
],
2576 CLOffset
+ SetIndexTable( NF_TIME_HHMMAMPM
, ZF_STANDARD_TIME
+2 ));
2579 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSSAMPM
);
2580 ImpInsertFormat( aFormatSeq
[nIdx
],
2581 CLOffset
+ SetIndexTable( NF_TIME_HHMMSSAMPM
, ZF_STANDARD_TIME
+3 ));
2584 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS
);
2585 ImpInsertFormat( aFormatSeq
[nIdx
],
2586 CLOffset
+ SetIndexTable( NF_TIME_HH_MMSS
, ZF_STANDARD_TIME
+4 ));
2589 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_MMSS00
);
2590 ImpInsertFormat( aFormatSeq
[nIdx
],
2591 CLOffset
+ SetIndexTable( NF_TIME_MMSS00
, ZF_STANDARD_TIME
+5 ));
2594 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS00
);
2595 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2596 CLOffset
+ SetIndexTable( NF_TIME_HH_MMSS00
, ZF_STANDARD_TIME
+6 ),
2597 SV_NUMBERFORMATTER_VERSION_NF_TIME_HH_MMSS00
);
2602 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME
);
2603 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2605 // DD.MM.YY HH:MM System
2606 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYSTEM_SHORT_HHMM
);
2607 ImpInsertFormat( aFormatSeq
[nIdx
],
2608 CLOffset
+ SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM
, ZF_STANDARD_DATETIME
));
2610 // DD.MM.YYYY HH:MM:SS System
2611 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
2612 ImpInsertNewStandardFormat( aFormatSeq
[nIdx
],
2613 CLOffset
+ SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, ZF_STANDARD_DATETIME
+1 ),
2614 SV_NUMBERFORMATTER_VERSION_NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
2618 // Scientific number
2619 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER
);
2620 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2623 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E000
);
2624 ImpInsertFormat( aFormatSeq
[nIdx
],
2625 CLOffset
+ SetIndexTable( NF_SCIENTIFIC_000E000
, ZF_STANDARD_SCIENTIFIC
));
2628 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E00
);
2629 ImpInsertFormat( aFormatSeq
[nIdx
],
2630 CLOffset
+ SetIndexTable( NF_SCIENTIFIC_000E00
, ZF_STANDARD_SCIENTIFIC
+1 ));
2634 // Fraction number (no default option)
2635 i18n::NumberFormatCode aSingleFormatCode
;
2636 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::FRACTION_NUMBER
;
2639 aSingleFormatCode
.Code
= "# ?/?";
2640 ImpInsertFormat( aSingleFormatCode
,
2641 CLOffset
+ SetIndexTable( NF_FRACTION_1
, ZF_STANDARD_FRACTION
));
2644 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2645 aSingleFormatCode
.Code
= "# ?\?/?\?";
2646 ImpInsertFormat( aSingleFormatCode
,
2647 CLOffset
+ SetIndexTable( NF_FRACTION_2
, ZF_STANDARD_FRACTION
+1 ));
2650 aSingleFormatCode
.Code
= "# ?/4";
2651 ImpInsertNewStandardFormat( aSingleFormatCode
,
2652 CLOffset
+ SetIndexTable( NF_FRACTION_3
, ZF_STANDARD_FRACTION
+2 ),
2653 SV_NUMBERFORMATTER_VERSION_FIXED_FRACTION
);
2656 aSingleFormatCode
.Code
= "# ?\?/100";
2657 ImpInsertNewStandardFormat( aSingleFormatCode
,
2658 CLOffset
+ SetIndexTable( NF_FRACTION_4
, ZF_STANDARD_FRACTION
+3 ),
2659 SV_NUMBERFORMATTER_VERSION_FIXED_FRACTION
);
2663 // Week of year must be appended here because of nNewExtended
2664 const NfKeywordTable
& rKeyword
= pFormatScanner
->GetKeywords();
2665 aSingleFormatCode
.Code
= rKeyword
[NF_KEY_WW
];
2666 ImpInsertNewStandardFormat( aSingleFormatCode
,
2667 CLOffset
+ SetIndexTable( NF_DATE_WW
, nNewExtended
++ ),
2668 SV_NUMBERFORMATTER_VERSION_NF_DATE_WW
);
2671 bIndexTableInitialized
= true;
2672 SAL_WARN_IF( nNewExtended
> ZF_STANDARD_NEWEXTENDEDMAX
, "svl.numbers",
2673 "ImpGenerateFormats: overflow of nNewExtended standard formats" );
2675 // Now all additional format codes provided by I18N, but only if not
2676 // changing SystemCL, then they are appended last after user defined.
2677 if ( !bNoAdditionalFormats
)
2679 ImpGenerateAdditionalFormats( CLOffset
, aNumberFormatCode
, false );
2681 if (bOldConvertMode
)
2683 pFormatScanner
->SetConvertMode(true);
2688 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset
,
2689 NumberFormatCodeWrapper
& rNumberFormatCode
, bool bAfterChangingSystemCL
)
2691 using namespace ::com::sun::star
;
2693 SvNumberformat
* pStdFormat
= GetFormatEntry( CLOffset
+ ZF_STANDARD
);
2696 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2699 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey();
2700 rNumberFormatCode
.setLocale( GetLanguageTag().getLocale() );
2703 // All currencies, this time with [$...] which was stripped in
2704 // ImpGenerateFormats for old "automatic" currency formats.
2705 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
=
2706 rNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
);
2707 i18n::NumberFormatCode
* pFormatArr
= aFormatSeq
.getArray();
2708 sal_Int32 nCodes
= aFormatSeq
.getLength();
2709 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), nCodes
);
2710 for ( j
= 0; j
< nCodes
; j
++ )
2712 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2714 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2717 if ( pFormatArr
[j
].Index
< NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
&&
2718 pFormatArr
[j
].Index
!= NF_CURRENCY_1000DEC2_CCC
)
2719 { // Insert only if not already inserted, but internal index must be
2720 // above so ImpInsertFormat can distinguish it.
2721 sal_Int16 nOrgIndex
= pFormatArr
[j
].Index
;
2722 pFormatArr
[j
].Index
= sal::static_int_cast
< sal_Int16
>(
2723 pFormatArr
[j
].Index
+ nCodes
+ NF_INDEX_TABLE_ENTRIES
);
2724 //! no default on currency
2725 bool bDefault
= aFormatSeq
[j
].Default
;
2726 aFormatSeq
[j
].Default
= false;
2727 if ( ImpInsertNewStandardFormat( pFormatArr
[j
], nPos
+1,
2728 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS
,
2729 bAfterChangingSystemCL
, nOrgIndex
) )
2731 pFormatArr
[j
].Index
= nOrgIndex
;
2732 aFormatSeq
[j
].Default
= bDefault
;
2736 // all additional format codes provided by I18N that are not old standard index
2737 aFormatSeq
= rNumberFormatCode
.getAllFormatCodes();
2738 nCodes
= aFormatSeq
.getLength();
2741 pFormatArr
= aFormatSeq
.getArray();
2743 sal_Int32 nDef
= ImpAdjustFormatCodeDefault( pFormatArr
, nCodes
, false);
2744 // don't have any defaults here
2745 pFormatArr
[nDef
].Default
= false;
2746 for ( j
= 0; j
< nCodes
; j
++ )
2748 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2750 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2753 if ( pFormatArr
[j
].Index
>= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
)
2754 if ( ImpInsertNewStandardFormat( pFormatArr
[j
], nPos
+1,
2755 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS
,
2756 bAfterChangingSystemCL
) )
2761 pStdFormat
->SetLastInsertKey( (sal_uInt16
)(nPos
- CLOffset
) );
2765 void SvNumberFormatter::ImpGetPosCurrFormat(OUStringBuffer
& sPosStr
, const OUString
& rCurrSymbol
)
2767 NfCurrencyEntry::CompletePositiveFormatString( sPosStr
,
2768 rCurrSymbol
, xLocaleData
->getCurrPositiveFormat() );
2771 void SvNumberFormatter::ImpGetNegCurrFormat(OUStringBuffer
& sNegStr
, const OUString
& rCurrSymbol
)
2773 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
,
2774 rCurrSymbol
, xLocaleData
->getCurrNegativeFormat() );
2777 OUString
SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex
,
2781 sal_uInt16 nPrecision
,
2782 sal_uInt16 nAnzLeading
)
2784 if (eLnge
== LANGUAGE_DONTKNOW
)
2788 short eType
= GetType(nIndex
);
2790 ImpGenerateCL(eLnge
); // create new standard formats if necessary
2792 utl::DigitGroupingIterator
aGrouping( xLocaleData
->getDigitGrouping());
2793 const sal_Int32 nDigitsInFirstGroup
= aGrouping
.get();
2794 const OUString
& rThSep
= GetNumThousandSep();
2796 SvNumberformat
* pFormat
= GetFormatEntry( nIndex
);
2798 OUStringBuffer sString
;
2799 using comphelper::string::padToLength
;
2801 if (nAnzLeading
== 0)
2804 sString
.append('#');
2807 sString
.append('#');
2808 sString
.append(rThSep
);
2809 padToLength(sString
, sString
.getLength() + nDigitsInFirstGroup
, '#');
2814 for (i
= 0; i
< nAnzLeading
; i
++)
2816 if (bThousand
&& i
> 0 && i
== aGrouping
.getPos())
2818 sString
.insert(0, rThSep
);
2819 aGrouping
.advance();
2821 sString
.insert(0, '0');
2823 if (bThousand
&& nAnzLeading
< nDigitsInFirstGroup
+ 1)
2825 for (i
= nAnzLeading
; i
< nDigitsInFirstGroup
+ 1; i
++)
2827 if (bThousand
&& i
% nDigitsInFirstGroup
== 0)
2828 sString
.insert(0, rThSep
);
2829 sString
.insert(0, '#');
2835 sString
.append(GetNumDecimalSep());
2836 padToLength(sString
, sString
.getLength() + nPrecision
, '0');
2838 if (eType
== NUMBERFORMAT_PERCENT
)
2840 sString
.append('%');
2842 else if (eType
== NUMBERFORMAT_CURRENCY
)
2844 OUStringBuffer
sNegStr(sString
);
2846 const NfCurrencyEntry
* pEntry
;
2848 if ( GetNewCurrencySymbolString( nIndex
, aCurr
, &pEntry
, &bBank
) )
2852 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
2853 xLocaleData
->getCurrPositiveFormat(),
2854 pEntry
->GetPositiveFormat(), bBank
);
2855 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
2856 xLocaleData
->getCurrNegativeFormat(),
2857 pEntry
->GetNegativeFormat(), bBank
);
2858 pEntry
->CompletePositiveFormatString( sString
, bBank
, nPosiForm
);
2859 pEntry
->CompleteNegativeFormatString( sNegStr
, bBank
, nNegaForm
);
2862 { // assume currency abbreviation (AKA banking symbol), not symbol
2863 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
2864 xLocaleData
->getCurrPositiveFormat(),
2865 xLocaleData
->getCurrPositiveFormat(), true );
2866 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
2867 xLocaleData
->getCurrNegativeFormat(),
2868 xLocaleData
->getCurrNegativeFormat(), true );
2869 NfCurrencyEntry::CompletePositiveFormatString( sString
, aCurr
, nPosiForm
);
2870 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
, aCurr
, nNegaForm
);
2874 { // "automatic" old style
2875 OUString aSymbol
, aAbbrev
;
2876 GetCompatibilityCurrency( aSymbol
, aAbbrev
);
2877 ImpGetPosCurrFormat( sString
, aSymbol
);
2878 ImpGetNegCurrFormat( sNegStr
, aSymbol
);
2882 sString
.append(';');
2883 sString
.append('[');
2884 sString
.append(pFormatScanner
->GetRedString());
2885 sString
.append(']');
2889 sString
.append(';');
2891 sString
.append(sNegStr
.makeStringAndClear());
2893 if (eType
!= NUMBERFORMAT_CURRENCY
)
2895 bool insertBrackets
= false;
2896 if ( eType
!= NUMBERFORMAT_UNDEFINED
)
2898 insertBrackets
= pFormat
->IsNegativeInBracket();
2900 if (IsRed
|| insertBrackets
)
2902 OUStringBuffer
sTmpStr(sString
);
2904 if ( pFormat
->HasPositiveBracketPlaceholder() )
2906 sTmpStr
.append('_');
2907 sTmpStr
.append(')');
2909 sTmpStr
.append(';');
2913 sTmpStr
.append('[');
2914 sTmpStr
.append(pFormatScanner
->GetRedString());
2915 sTmpStr
.append(']');
2920 sTmpStr
.append('(');
2921 sTmpStr
.append(sString
.toString());
2922 sTmpStr
.append(')');
2926 sTmpStr
.append('-');
2927 sTmpStr
.append(sString
.toString());
2932 return sString
.makeStringAndClear();
2935 bool SvNumberFormatter::IsUserDefined(const OUString
& sStr
,
2938 if (eLnge
== LANGUAGE_DONTKNOW
)
2942 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
2945 sal_uInt32 nKey
= ImpIsEntry(sStr
, CLOffset
, eLnge
);
2946 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
2950 SvNumberformat
* pEntry
= GetFormatEntry( nKey
);
2951 if ( pEntry
&& ((pEntry
->GetType() & NUMBERFORMAT_DEFINED
) != 0) )
2958 sal_uInt32
SvNumberFormatter::GetEntryKey(const OUString
& sStr
,
2961 if (eLnge
== LANGUAGE_DONTKNOW
)
2965 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
2966 return ImpIsEntry(sStr
, CLOffset
, eLnge
);
2969 sal_uInt32
SvNumberFormatter::GetStandardIndex(LanguageType eLnge
)
2971 if (eLnge
== LANGUAGE_DONTKNOW
)
2975 return GetStandardFormat(NUMBERFORMAT_NUMBER
, eLnge
);
2978 short SvNumberFormatter::GetType(sal_uInt32 nFIndex
)
2981 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
2984 eType
= NUMBERFORMAT_UNDEFINED
;
2988 eType
= pFormat
->GetType() &~NUMBERFORMAT_DEFINED
;
2991 eType
= NUMBERFORMAT_DEFINED
;
2997 void SvNumberFormatter::ClearMergeTable()
3001 pMergeTable
->clear();
3005 SvNumberFormatterIndexTable
* SvNumberFormatter::MergeFormatter(SvNumberFormatter
& rTable
)
3013 pMergeTable
= new SvNumberFormatterIndexTable
;
3016 sal_uInt32 nCLOffset
= 0;
3017 sal_uInt32 nOldKey
, nOffset
, nNewKey
;
3018 SvNumberformat
* pNewEntry
;
3020 SvNumberFormatTable::iterator it
= rTable
.aFTable
.begin();
3021 while (it
!= rTable
.aFTable
.end())
3023 SvNumberformat
* pFormat
= it
->second
;
3024 nOldKey
= it
->first
;
3025 nOffset
= nOldKey
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3026 if (nOffset
== 0) // 1st format of CL
3028 nCLOffset
= ImpGenerateCL(pFormat
->GetLanguage());
3030 if (nOffset
<= SV_MAX_ANZ_STANDARD_FORMATE
) // Std.form.
3032 nNewKey
= nCLOffset
+ nOffset
;
3033 if (aFTable
.find( nNewKey
) == aFTable
.end()) // not already present
3035 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
3036 pNewEntry
= new SvNumberformat( *pFormat
, *pFormatScanner
);
3037 if (!aFTable
.insert(make_pair( nNewKey
, pNewEntry
)).second
)
3039 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3043 if (nNewKey
!= nOldKey
) // new index
3045 (*pMergeTable
)[nOldKey
] = nNewKey
;
3048 else // user defined
3050 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
3051 pNewEntry
= new SvNumberformat( *pFormat
, *pFormatScanner
);
3052 nNewKey
= ImpIsEntry(pNewEntry
->GetFormatstring(),
3054 pFormat
->GetLanguage());
3055 if (nNewKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
3061 SvNumberformat
* pStdFormat
= GetFormatEntry(nCLOffset
+ ZF_STANDARD
);
3062 sal_uInt32 nPos
= nCLOffset
+ pStdFormat
->GetLastInsertKey();
3064 if (nNewKey
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
3066 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
3069 else if (!aFTable
.insert(make_pair( nNewKey
, pNewEntry
)).second
)
3071 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
3076 pStdFormat
->SetLastInsertKey((sal_uInt16
) (nNewKey
- nCLOffset
));
3079 if (nNewKey
!= nOldKey
) // new index
3081 (*pMergeTable
)[nOldKey
] = nNewKey
;
3090 SvNumberFormatterMergeMap
SvNumberFormatter::ConvertMergeTableToMap()
3092 if (!HasMergeFmtTbl())
3094 return SvNumberFormatterMergeMap();
3096 SvNumberFormatterMergeMap aMap
;
3097 for (SvNumberFormatterIndexTable::iterator it
= pMergeTable
->begin(); it
!= pMergeTable
->end(); ++it
)
3099 sal_uInt32 nOldKey
= it
->first
;
3100 aMap
[ nOldKey
] = it
->second
;
3107 sal_uInt32
SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat
,
3108 LanguageType eLnge
)
3110 if ( eLnge
== LANGUAGE_DONTKNOW
)
3114 if ( nFormat
< SV_COUNTRY_LANGUAGE_OFFSET
&& eLnge
== IniLnge
)
3116 return nFormat
; // it stays as it is
3118 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3119 if ( nOffset
> SV_MAX_ANZ_STANDARD_FORMATE
)
3121 return nFormat
; // not a built-in format
3123 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3124 return nCLOffset
+ nOffset
;
3128 sal_uInt32
SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff
,
3129 LanguageType eLnge
)
3131 if ( nTabOff
>= NF_INDEX_TABLE_ENTRIES
||
3132 theIndexTable
[nTabOff
] == NUMBERFORMAT_ENTRY_NOT_FOUND
)
3134 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
3136 if ( eLnge
== LANGUAGE_DONTKNOW
)
3140 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3141 return nCLOffset
+ theIndexTable
[nTabOff
];
3145 NfIndexTableOffset
SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat
) const
3147 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3148 if ( nOffset
> SV_MAX_ANZ_STANDARD_FORMATE
)
3150 return NF_INDEX_TABLE_ENTRIES
; // not a built-in format
3152 for ( sal_uInt16 j
= 0; j
< NF_INDEX_TABLE_ENTRIES
; j
++ )
3154 if ( theIndexTable
[j
] == nOffset
)
3156 return (NfIndexTableOffset
) j
;
3159 return NF_INDEX_TABLE_ENTRIES
; // bad luck
3163 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal
)
3165 pStringScanner
->SetYear2000( nVal
);
3169 sal_uInt16
SvNumberFormatter::GetYear2000() const
3171 return pStringScanner
->GetYear2000();
3175 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
) const
3178 return SvNumberFormatter::ExpandTwoDigitYear( nYear
,
3179 pStringScanner
->GetYear2000() );
3185 sal_uInt16
SvNumberFormatter::GetYear2000Default()
3187 return (sal_uInt16
) ::utl::MiscCfg().GetYear2000();
3192 const NfCurrencyTable
& SvNumberFormatter::GetTheCurrencyTable()
3194 ::osl::MutexGuard
aGuard( GetMutex() );
3195 while ( !bCurrencyTableInitialized
)
3196 ImpInitCurrencyTable();
3197 return theCurrencyTable::get();
3202 const NfCurrencyEntry
* SvNumberFormatter::MatchSystemCurrency()
3204 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3205 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3206 return nSystemCurrencyPosition
? &rTable
[nSystemCurrencyPosition
] : NULL
;
3211 const NfCurrencyEntry
& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang
)
3213 if ( eLang
== LANGUAGE_SYSTEM
)
3215 const NfCurrencyEntry
* pCurr
= MatchSystemCurrency();
3216 return pCurr
? *pCurr
: GetTheCurrencyTable()[0];
3220 eLang
= MsLangId::getRealLanguage( eLang
);
3221 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3222 sal_uInt16 nCount
= rTable
.size();
3223 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3225 if ( rTable
[j
].GetLanguage() == eLang
)
3234 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry(const OUString
& rAbbrev
, LanguageType eLang
)
3236 eLang
= MsLangId::getRealLanguage( eLang
);
3237 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3238 sal_uInt16 nCount
= rTable
.size();
3239 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3241 if ( rTable
[j
].GetLanguage() == eLang
&&
3242 rTable
[j
].GetBankSymbol() == rAbbrev
)
3252 const NfCurrencyEntry
* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( const OUString
& rSymbol
,
3253 const OUString
& rAbbrev
)
3255 if (!bCurrencyTableInitialized
)
3257 GetTheCurrencyTable(); // just for initialization
3259 const NfCurrencyTable
& rTable
= theLegacyOnlyCurrencyTable::get();
3260 sal_uInt16 nCount
= rTable
.size();
3261 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3263 if ( rTable
[j
].GetSymbol() == rSymbol
&&
3264 rTable
[j
].GetBankSymbol() == rAbbrev
)
3274 IMPL_STATIC_LINK_NOINSTANCE( SvNumberFormatter
, CurrencyChangeLink
, SAL_UNUSED_PARAMETER
void*, EMPTYARG
)
3276 ::osl::MutexGuard
aGuard( GetMutex() );
3278 LanguageType eLang
= LANGUAGE_SYSTEM
;
3279 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev
, eLang
);
3280 SetDefaultSystemCurrency( aAbbrev
, eLang
);
3286 void SvNumberFormatter::SetDefaultSystemCurrency( const OUString
& rAbbrev
, LanguageType eLang
)
3288 ::osl::MutexGuard
aGuard( GetMutex() );
3289 if ( eLang
== LANGUAGE_SYSTEM
)
3291 eLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
3293 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3294 sal_uInt16 nCount
= rTable
.size();
3295 if ( !rAbbrev
.isEmpty() )
3297 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3299 if ( rTable
[j
].GetLanguage() == eLang
&& rTable
[j
].GetBankSymbol() == rAbbrev
)
3301 nSystemCurrencyPosition
= j
;
3308 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3310 if ( rTable
[j
].GetLanguage() == eLang
)
3312 nSystemCurrencyPosition
= j
;
3317 nSystemCurrencyPosition
= 0; // not found => simple SYSTEM
3321 void SvNumberFormatter::ResetDefaultSystemCurrency()
3323 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
3327 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3329 pStringScanner
->InvalidateDateAcceptancePatterns();
3333 sal_uInt32
SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3335 if ( nDefaultSystemCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3339 NfWSStringsDtor aCurrList
;
3340 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3341 GetCurrencyEntry( LANGUAGE_SYSTEM
), false );
3342 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency System standard format?!?" );
3343 // if already loaded or user defined nDefaultSystemCurrencyFormat
3344 // will be set to the right value
3345 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3346 nDefaultSystemCurrencyFormat
, LANGUAGE_SYSTEM
);
3347 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3348 DBG_ASSERT( nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3349 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3351 return nDefaultSystemCurrencyFormat
;
3355 sal_uInt32
SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3357 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
3358 DefaultFormatKeysMap::iterator it
= aDefaultFormatKeys
.find( CLOffset
+ ZF_STANDARD_CURRENCY
);
3359 sal_uInt32 nDefaultCurrencyFormat
= (it
!= aDefaultFormatKeys
.end() ?
3360 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
3361 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3363 // look for a defined standard
3364 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
3366 SvNumberFormatTable::iterator it2
= aFTable
.lower_bound( CLOffset
);
3367 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
3369 const SvNumberformat
* pEntry
= it2
->second
;
3370 if ( pEntry
->IsStandard() && (pEntry
->GetType() & NUMBERFORMAT_CURRENCY
) )
3372 nDefaultCurrencyFormat
= nKey
;
3378 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3379 { // none found, create one
3381 NfWSStringsDtor aCurrList
;
3382 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3383 GetCurrencyEntry( ActLnge
), false );
3384 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency standard format?" );
3385 if ( !aCurrList
.empty() )
3387 // if already loaded or user defined nDefaultSystemCurrencyFormat
3388 // will be set to the right value
3390 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3391 nDefaultCurrencyFormat
, ActLnge
);
3392 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3393 DBG_ASSERT( nDefaultCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3394 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3396 // old automatic currency format as a last resort
3397 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3398 nDefaultCurrencyFormat
= CLOffset
+ ZF_STANDARD_CURRENCY
+3;
3400 { // mark as standard so that it is found next time
3401 SvNumberformat
* pEntry
= GetFormatEntry( nDefaultCurrencyFormat
);
3403 pEntry
->SetStandard();
3406 aDefaultFormatKeys
[ CLOffset
+ ZF_STANDARD_CURRENCY
] = nDefaultCurrencyFormat
;
3408 return nDefaultCurrencyFormat
;
3413 // try to make it inline if possible since this a loop body
3414 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
3418 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody( const NfCurrencyEntry
*& pFoundEntry
, bool& bFoundBank
,
3419 const NfCurrencyEntry
* pData
, sal_uInt16 nPos
,
3420 const OUString
& rSymbol
)
3423 if ( pData
->GetSymbol() == rSymbol
)
3428 else if ( pData
->GetBankSymbol() == rSymbol
)
3437 if ( pFoundEntry
&& pFoundEntry
!= pData
)
3440 return false; // break loop, not unique
3443 { // first entry is SYSTEM
3444 pFoundEntry
= MatchSystemCurrency();
3447 return false; // break loop
3448 // even if there are more matching entries
3449 // this one is propably the one we are looking for
3453 pFoundEntry
= pData
;
3458 pFoundEntry
= pData
;
3465 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat
, String
& rStr
,
3466 const NfCurrencyEntry
** ppEntry
/* = NULL */,
3467 bool* pBank
/* = NULL */ ) const
3474 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
3477 OUString aSymbol
, aExtension
;
3478 if ( pFormat
->GetNewCurrencySymbol( aSymbol
, aExtension
) )
3482 bool bFoundBank
= false;
3483 // we definiteley need an entry matching the format code string
3484 const NfCurrencyEntry
* pFoundEntry
= GetCurrencyEntry(
3485 bFoundBank
, aSymbol
, aExtension
, pFormat
->GetLanguage(),
3489 *ppEntry
= pFoundEntry
;
3491 *pBank
= bFoundBank
;
3492 rStr
= pFoundEntry
->BuildSymbolString(bFoundBank
);
3496 { // analog to BuildSymbolString
3499 if ( aSymbol
.indexOf( '-' ) != -1 ||
3500 aSymbol
.indexOf( ']' ) != -1 )
3508 if ( aExtension
.getLength() )
3520 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank
,
3521 const OUString
& rSymbol
,
3522 const OUString
& rExtension
,
3523 LanguageType eFormatLanguage
,
3524 bool bOnlyStringLanguage
)
3526 sal_Int32 nExtLen
= rExtension
.getLength();
3527 LanguageType eExtLang
;
3530 sal_Int32 nExtLang
= rExtension
.toInt32( 16 );
3533 eExtLang
= LANGUAGE_DONTKNOW
;
3537 eExtLang
= (LanguageType
) ((nExtLang
< 0) ? -nExtLang
: nExtLang
);
3542 eExtLang
= LANGUAGE_DONTKNOW
;
3544 const NfCurrencyEntry
* pFoundEntry
= NULL
;
3545 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3546 sal_uInt16 nCount
= rTable
.size();
3549 // first try with given extension language/country
3552 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3554 LanguageType eLang
= rTable
[j
].GetLanguage();
3555 if ( eLang
== eExtLang
||
3556 ((eExtLang
== LANGUAGE_DONTKNOW
) &&
3557 (eLang
== LANGUAGE_SYSTEM
)))
3559 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3560 &rTable
[j
], j
, rSymbol
);
3566 if ( pFoundEntry
|| !bCont
|| (bOnlyStringLanguage
&& nExtLen
) )
3570 if ( !bOnlyStringLanguage
)
3572 // now try the language/country of the number format
3573 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3575 LanguageType eLang
= rTable
[j
].GetLanguage();
3576 if ( eLang
== eFormatLanguage
||
3577 ((eFormatLanguage
== LANGUAGE_DONTKNOW
) &&
3578 (eLang
== LANGUAGE_SYSTEM
)))
3580 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3581 &rTable
[j
], j
, rSymbol
);
3586 if ( pFoundEntry
|| !bCont
)
3592 // then try without language/country if no extension specified
3595 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3597 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3598 &rTable
[j
], j
, rSymbol
);
3606 void SvNumberFormatter::GetCompatibilityCurrency( OUString
& rSymbol
, OUString
& rAbbrev
) const
3608 ::com::sun::star::uno::Sequence
< ::com::sun::star::i18n::Currency2
>
3609 xCurrencies( xLocaleData
->getAllCurrencies() );
3611 const ::com::sun::star::i18n::Currency2
*pCurrencies
= xCurrencies
.getConstArray();
3612 sal_Int32 nCurrencies
= xCurrencies
.getLength();
3615 for ( j
=0; j
< nCurrencies
; ++j
)
3617 if ( pCurrencies
[j
].UsedInCompatibleFormatCodes
)
3619 rSymbol
= pCurrencies
[j
].Symbol
;
3620 rAbbrev
= pCurrencies
[j
].BankSymbol
;
3624 if ( j
>= nCurrencies
)
3626 if (LocaleDataWrapper::areChecksEnabled())
3628 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
3629 appendLocaleInfo( "GetCompatibilityCurrency: none?"));
3631 rSymbol
= xLocaleData
->getCurrSymbol();
3632 rAbbrev
= xLocaleData
->getCurrBankSymbol();
3637 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry
& rCurr
)
3639 switch ( rCurr
.GetPositiveFormat() )
3647 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3650 switch ( rCurr
.GetNegativeFormat() )
3670 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3676 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang
)
3678 // The set is initialized as a side effect of the currency table
3679 // created, make sure that exists, which usually is the case unless a
3680 // SvNumberFormatter was never instanciated.
3681 GetTheCurrencyTable();
3682 const NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
3683 return rInstalledLocales
.find( eLang
) != rInstalledLocales
.end();
3687 void SvNumberFormatter::ImpInitCurrencyTable()
3689 // racing condition possible:
3690 // ::osl::MutexGuard aGuard( GetMutex() );
3691 // while ( !bCurrencyTableInitialized )
3692 // ImpInitCurrencyTable();
3693 static bool bInitializing
= false;
3694 if ( bCurrencyTableInitialized
|| bInitializing
)
3698 bInitializing
= true;
3700 RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog
, "svl", "er93726", "SvNumberFormatter::ImpInitCurrencyTable" );
3702 LanguageType eSysLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
3703 LocaleDataWrapper
* pLocaleData
= new LocaleDataWrapper(
3704 ::comphelper::getProcessComponentContext(),
3705 SvtSysLocale().GetLanguageTag() );
3706 // get user configured currency
3707 String aConfiguredCurrencyAbbrev
;
3708 LanguageType eConfiguredCurrencyLanguage
= LANGUAGE_SYSTEM
;
3709 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3710 aConfiguredCurrencyAbbrev
, eConfiguredCurrencyLanguage
);
3711 sal_uInt16 nSecondarySystemCurrencyPosition
= 0;
3712 sal_uInt16 nMatchingSystemCurrencyPosition
= 0;
3713 NfCurrencyEntry
* pEntry
;
3715 // first entry is SYSTEM
3716 pEntry
= new NfCurrencyEntry( *pLocaleData
, LANGUAGE_SYSTEM
);
3717 theCurrencyTable::get().insert( theCurrencyTable::get().begin(), pEntry
);
3718 sal_uInt16 nCurrencyPos
= 1;
3720 ::com::sun::star::uno::Sequence
< ::com::sun::star::lang::Locale
> xLoc
=
3721 LocaleDataWrapper::getInstalledLocaleNames();
3722 sal_Int32 nLocaleCount
= xLoc
.getLength();
3723 RTL_LOGFILE_CONTEXT_TRACE1( aTimeLog
, "number of locales: %ld", nLocaleCount
);
3724 Locale
const * const pLocales
= xLoc
.getConstArray();
3725 NfCurrencyTable
&rCurrencyTable
= theCurrencyTable::get();
3726 NfCurrencyTable
&rLegacyOnlyCurrencyTable
= theLegacyOnlyCurrencyTable::get();
3727 NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
3728 sal_uInt16 nLegacyOnlyCurrencyPos
= 0;
3729 for ( sal_Int32 nLocale
= 0; nLocale
< nLocaleCount
; nLocale
++ )
3731 LanguageType eLang
= LanguageTag( pLocales
[nLocale
]).getLanguageType( false);
3732 rInstalledLocales
.insert( eLang
);
3733 pLocaleData
->setLanguageTag( LanguageTag( pLocales
[nLocale
]) );
3734 Sequence
< Currency2
> aCurrSeq
= pLocaleData
->getAllCurrencies();
3735 sal_Int32 nCurrencyCount
= aCurrSeq
.getLength();
3736 Currency2
const * const pCurrencies
= aCurrSeq
.getConstArray();
3738 // one default currency for each locale, insert first so it is found first
3740 for ( nDefault
= 0; nDefault
< nCurrencyCount
; nDefault
++ )
3742 if ( pCurrencies
[nDefault
].Default
)
3745 if ( nDefault
< nCurrencyCount
)
3747 pEntry
= new NfCurrencyEntry( pCurrencies
[nDefault
], *pLocaleData
, eLang
);
3751 pEntry
= new NfCurrencyEntry( *pLocaleData
, eLang
); // first or ShellsAndPebbles
3753 if (LocaleDataWrapper::areChecksEnabled())
3755 lcl_CheckCurrencySymbolPosition( *pEntry
);
3757 rCurrencyTable
.insert( rCurrencyTable
.begin() + nCurrencyPos
++, pEntry
);
3758 if ( !nSystemCurrencyPosition
&& (aConfiguredCurrencyAbbrev
.Len() ?
3759 pEntry
->GetBankSymbol() == OUString(aConfiguredCurrencyAbbrev
) &&
3760 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
: false) )
3762 nSystemCurrencyPosition
= nCurrencyPos
-1;
3764 if ( !nMatchingSystemCurrencyPosition
&&
3765 pEntry
->GetLanguage() == eSysLang
)
3767 nMatchingSystemCurrencyPosition
= nCurrencyPos
-1;
3769 // all remaining currencies for each locale
3770 if ( nCurrencyCount
> 1 )
3772 sal_Int32 nCurrency
;
3773 for ( nCurrency
= 0; nCurrency
< nCurrencyCount
; nCurrency
++ )
3775 if (pCurrencies
[nCurrency
].LegacyOnly
)
3777 pEntry
= new NfCurrencyEntry( pCurrencies
[nCurrency
], *pLocaleData
, eLang
);
3778 rLegacyOnlyCurrencyTable
.insert( rLegacyOnlyCurrencyTable
.begin() + nLegacyOnlyCurrencyPos
++, pEntry
);
3780 else if ( nCurrency
!= nDefault
)
3782 pEntry
= new NfCurrencyEntry( pCurrencies
[nCurrency
], *pLocaleData
, eLang
);
3784 bool bInsert
= true;
3785 sal_uInt16 n
= rCurrencyTable
.size();
3786 sal_uInt16 aCurrencyIndex
= 1; // skip first SYSTEM entry
3787 for ( sal_uInt16 j
=1; j
<n
; j
++ )
3789 if ( rCurrencyTable
[aCurrencyIndex
++] == *pEntry
)
3801 rCurrencyTable
.insert( rCurrencyTable
.begin() + nCurrencyPos
++, pEntry
);
3802 if ( !nSecondarySystemCurrencyPosition
&&
3803 (aConfiguredCurrencyAbbrev
.Len() ?
3804 pEntry
->GetBankSymbol() == OUString(aConfiguredCurrencyAbbrev
) :
3805 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
) )
3807 nSecondarySystemCurrencyPosition
= nCurrencyPos
-1;
3809 if ( !nMatchingSystemCurrencyPosition
&&
3810 pEntry
->GetLanguage() == eSysLang
)
3812 nMatchingSystemCurrencyPosition
= nCurrencyPos
-1;
3819 if ( !nSystemCurrencyPosition
)
3821 nSystemCurrencyPosition
= nSecondarySystemCurrencyPosition
;
3823 if ((aConfiguredCurrencyAbbrev
.Len() && !nSystemCurrencyPosition
) &&
3824 LocaleDataWrapper::areChecksEnabled())
3826 LocaleDataWrapper::outputCheckMessage(
3827 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3829 // match SYSTEM if no configured currency found
3830 if ( !nSystemCurrencyPosition
)
3832 nSystemCurrencyPosition
= nMatchingSystemCurrencyPosition
;
3834 if ((!aConfiguredCurrencyAbbrev
.Len() && !nSystemCurrencyPosition
) &&
3835 LocaleDataWrapper::areChecksEnabled())
3837 LocaleDataWrapper::outputCheckMessage(
3838 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3841 SvtSysLocaleOptions::SetCurrencyChangeLink( STATIC_LINK( NULL
, SvNumberFormatter
, CurrencyChangeLink
) );
3842 bInitializing
= false;
3843 bCurrencyTableInitialized
= true;
3847 sal_uInt16
SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor
& rStrArr
,
3848 const NfCurrencyEntry
& rCurr
,
3851 OUString aRed
= OUStringBuffer().
3853 append(pFormatScanner
->GetRedString()).
3854 append(']').makeStringAndClear();
3856 sal_uInt16 nDefault
= 0;
3859 // Only bank symbols.
3860 OUString aPositiveBank
= rCurr
.BuildPositiveFormatString(true, *xLocaleData
, 1);
3861 OUString aNegativeBank
= rCurr
.BuildNegativeFormatString(true, *xLocaleData
, 1 );
3863 OUStringBuffer
format1(aPositiveBank
);
3864 format1
.append(';');
3865 format1
.append(aNegativeBank
);
3866 rStrArr
.push_back(format1
.makeStringAndClear());
3868 OUStringBuffer
format2(aPositiveBank
);
3869 format2
.append(';');
3871 format2
.append(aRed
);
3873 format2
.append(aNegativeBank
);
3874 rStrArr
.push_back(format2
.makeStringAndClear());
3876 nDefault
= rStrArr
.size() - 1;
3880 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
3881 // duplicates if no decimals in currency.
3882 OUString aPositive
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 1);
3883 OUString aNegative
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 1 );
3884 OUStringBuffer format1
;
3885 OUStringBuffer format2
;
3886 OUStringBuffer format3
;
3887 OUStringBuffer format4
;
3888 OUStringBuffer format5
;
3889 if (rCurr
.GetDigits())
3891 OUString aPositiveNoDec
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 0);
3892 OUString aNegativeNoDec
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 0 );
3893 OUString aPositiveDashed
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 2);
3894 OUString aNegativeDashed
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 2);
3896 format1
.append(aPositiveNoDec
);
3897 format1
.append(';');
3898 format1
.append(aNegativeNoDec
);
3900 format3
.append(aPositiveNoDec
);
3901 format3
.append(';');
3902 format3
.append(aRed
);
3903 format3
.append(aNegativeNoDec
);
3905 format5
.append(aPositiveDashed
);
3906 format5
.append(';');
3907 format5
.append(aRed
);
3908 format5
.append(aNegativeDashed
);
3911 format2
.append(aPositive
);
3912 format2
.append(';');
3913 format2
.append(aNegative
);
3915 format4
.append(aPositive
);
3916 format4
.append(';');
3917 format4
.append(aRed
);
3918 format4
.append(aNegative
);
3920 if (rCurr
.GetDigits())
3922 rStrArr
.push_back(format1
.makeStringAndClear());
3924 rStrArr
.push_back(format2
.makeStringAndClear());
3925 if (rCurr
.GetDigits())
3927 rStrArr
.push_back(format3
.makeStringAndClear());
3929 rStrArr
.push_back(format4
.makeStringAndClear());
3930 nDefault
= rStrArr
.size() - 1;
3931 if (rCurr
.GetDigits())
3933 rStrArr
.push_back(format5
.makeStringAndClear());
3940 //--- NfCurrencyEntry ----------------------------------------------------
3943 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
3945 aSymbol
= rLocaleData
.getCurrSymbol();
3946 aBankSymbol
= rLocaleData
.getCurrBankSymbol();
3948 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
3949 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
3950 nDigits
= rLocaleData
.getCurrDigits();
3951 cZeroChar
= rLocaleData
.getCurrZeroChar();
3955 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency
& rCurr
,
3956 const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
3958 aSymbol
= rCurr
.Symbol
;
3959 aBankSymbol
= rCurr
.BankSymbol
;
3961 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
3962 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
3963 nDigits
= rCurr
.DecimalPlaces
;
3964 cZeroChar
= rLocaleData
.getCurrZeroChar();
3968 bool NfCurrencyEntry::operator==( const NfCurrencyEntry
& r
) const
3970 return aSymbol
== r
.aSymbol
3971 && aBankSymbol
== r
.aBankSymbol
3972 && eLanguage
== r
.eLanguage
3976 OUString
NfCurrencyEntry::BuildSymbolString(bool bBank
,
3977 bool bWithoutExtension
) const
3979 OUStringBuffer
aBuf("[$");
3982 aBuf
.append(aBankSymbol
);
3986 if ( aSymbol
.indexOf( (sal_Unicode
)'-' ) >= 0 ||
3987 aSymbol
.indexOf( (sal_Unicode
)']' ) >= 0)
3989 aBuf
.append('"').append(aSymbol
).append('"');
3993 aBuf
.append(aSymbol
);
3995 if ( !bWithoutExtension
&& eLanguage
!= LANGUAGE_DONTKNOW
&& eLanguage
!= LANGUAGE_SYSTEM
)
3997 sal_Int32 nLang
= static_cast<sal_Int32
>(eLanguage
);
3998 aBuf
.append('-').append( OUString::valueOf(nLang
, 16).toAsciiUpperCase());
4002 return aBuf
.makeStringAndClear();
4005 OUString
NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper
& rLoc
,
4006 sal_uInt16 nDecimalFormat
) const
4008 OUStringBuffer aBuf
;
4009 aBuf
.append('#').append(rLoc
.getNumThousandSep()).append("##0");
4010 if (nDecimalFormat
&& nDigits
)
4012 aBuf
.append(rLoc
.getNumDecimalSep());
4013 sal_Unicode cDecimalChar
= nDecimalFormat
== 2 ? '-' : cZeroChar
;
4014 for (sal_uInt16 i
= 0; i
< nDigits
; ++i
)
4016 aBuf
.append(cDecimalChar
);
4019 return aBuf
.makeStringAndClear();
4023 OUString
NfCurrencyEntry::BuildPositiveFormatString(bool bBank
, const LocaleDataWrapper
& rLoc
,
4024 sal_uInt16 nDecimalFormat
) const
4026 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
4027 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat( rLoc
.getCurrPositiveFormat(),
4028 nPositiveFormat
, bBank
);
4029 CompletePositiveFormatString(sBuf
, bBank
, nPosiForm
);
4030 return sBuf
.makeStringAndClear();
4034 OUString
NfCurrencyEntry::BuildNegativeFormatString(bool bBank
,
4035 const LocaleDataWrapper
& rLoc
, sal_uInt16 nDecimalFormat
) const
4037 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
4038 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc
.getCurrNegativeFormat(),
4039 nNegativeFormat
, bBank
);
4040 CompleteNegativeFormatString(sBuf
, bBank
, nNegaForm
);
4041 return sBuf
.makeStringAndClear();
4045 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, bool bBank
,
4046 sal_uInt16 nPosiForm
) const
4048 OUString aSymStr
= BuildSymbolString(bBank
);
4049 NfCurrencyEntry::CompletePositiveFormatString( rStr
, aSymStr
, nPosiForm
);
4053 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
, bool bBank
,
4054 sal_uInt16 nNegaForm
) const
4056 OUString aSymStr
= BuildSymbolString(bBank
);
4057 NfCurrencyEntry::CompleteNegativeFormatString( rStr
, aSymStr
, nNegaForm
);
4062 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, const OUString
& rSymStr
,
4063 sal_uInt16 nPositiveFormat
)
4065 switch( nPositiveFormat
)
4068 rStr
.insert(0, rSymStr
);
4071 rStr
.append(rSymStr
);
4075 rStr
.insert(0, ' ');
4076 rStr
.insert(0, rSymStr
);
4082 rStr
.append(rSymStr
);
4086 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4093 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
,
4094 const OUString
& rSymStr
,
4095 sal_uInt16 nNegativeFormat
)
4097 switch( nNegativeFormat
)
4101 rStr
.insert(0, rSymStr
);
4102 rStr
.insert(0, '(');
4108 rStr
.insert(0, rSymStr
);
4109 rStr
.insert(0, '-');
4114 rStr
.insert(0, '-');
4115 rStr
.insert(0, rSymStr
);
4120 rStr
.insert(0, rSymStr
);
4126 rStr
.insert(0, '(');
4127 rStr
.append(rSymStr
);
4133 rStr
.append(rSymStr
);
4134 rStr
.insert(0, '-');
4140 rStr
.append(rSymStr
);
4145 rStr
.append(rSymStr
);
4152 rStr
.append(rSymStr
);
4153 rStr
.insert(0, '-');
4158 rStr
.insert(0, ' ');
4159 rStr
.insert(0, rSymStr
);
4160 rStr
.insert(0, '-');
4166 rStr
.append(rSymStr
);
4172 String
aTmp( rSymStr
);
4175 rStr
.insert(0, aTmp
);
4180 rStr
.insert(0, ' ');
4181 rStr
.insert(0, rSymStr
);
4189 rStr
.append(rSymStr
);
4194 rStr
.insert(0, ' ');
4195 rStr
.insert(0, rSymStr
);
4196 rStr
.insert(0, '(');
4202 rStr
.insert(0, '(');
4204 rStr
.append(rSymStr
);
4209 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4216 sal_uInt16
NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat
,
4217 sal_uInt16 nCurrFormat
, bool bBank
)
4221 #if NF_BANKSYMBOL_FIX_POSITION
4222 (void) nIntlFormat
; // avoid warnings
4225 switch ( nIntlFormat
)
4228 nIntlFormat
= 2; // $ 1
4231 nIntlFormat
= 3; // 1 $
4238 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4249 //! Call this only if nCurrFormat is really with parentheses!
4250 static sal_uInt16
lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat
, sal_uInt16 nCurrFormat
)
4252 short nSign
= 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4253 switch ( nIntlFormat
)
4279 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4283 switch ( nCurrFormat
)
4335 sal_uInt16
NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat
,
4336 sal_uInt16 nCurrFormat
, bool bBank
)
4340 #if NF_BANKSYMBOL_FIX_POSITION
4343 switch ( nIntlFormat
)
4346 // nIntlFormat = 14; // ($ 1)
4347 nIntlFormat
= 9; // -$ 1
4350 nIntlFormat
= 9; // -$ 1
4353 nIntlFormat
= 11; // $ -1
4356 nIntlFormat
= 12; // $ 1-
4359 // nIntlFormat = 15; // (1 $)
4360 nIntlFormat
= 8; // -1 $
4363 nIntlFormat
= 8; // -1 $
4366 nIntlFormat
= 13; // 1- $
4369 nIntlFormat
= 10; // 1 $-
4384 // nIntlFormat = 14; // ($ 1)
4385 nIntlFormat
= 9; // -$ 1
4388 // nIntlFormat = 15; // (1 $)
4389 nIntlFormat
= 8; // -1 $
4392 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4397 else if ( nIntlFormat
!= nCurrFormat
)
4399 switch ( nCurrFormat
)
4402 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4403 nIntlFormat
, nCurrFormat
);
4406 nIntlFormat
= nCurrFormat
;
4409 nIntlFormat
= nCurrFormat
;
4412 nIntlFormat
= nCurrFormat
;
4415 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4416 nIntlFormat
, nCurrFormat
);
4419 nIntlFormat
= nCurrFormat
;
4422 nIntlFormat
= nCurrFormat
;
4425 nIntlFormat
= nCurrFormat
;
4428 nIntlFormat
= nCurrFormat
;
4431 nIntlFormat
= nCurrFormat
;
4434 nIntlFormat
= nCurrFormat
;
4437 nIntlFormat
= nCurrFormat
;
4440 nIntlFormat
= nCurrFormat
;
4443 nIntlFormat
= nCurrFormat
;
4446 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4447 nIntlFormat
, nCurrFormat
);
4450 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4451 nIntlFormat
, nCurrFormat
);
4454 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4462 // we only support default encodings here
4464 sal_Char
NfCurrencyEntry::GetEuroSymbol( rtl_TextEncoding eTextEncoding
)
4466 switch ( eTextEncoding
)
4468 case RTL_TEXTENCODING_MS_1252
: // WNT Ansi
4469 case RTL_TEXTENCODING_ISO_8859_1
: // UNX for use with TrueType fonts
4471 case RTL_TEXTENCODING_ISO_8859_15
: // UNX real
4473 case RTL_TEXTENCODING_IBM_850
: // OS2
4475 case RTL_TEXTENCODING_APPLE_ROMAN
: // MAC
4477 default: // default system
4481 // return '\xA4'; // #56121# 0xA4 would be correct for iso-8859-15
4482 return '\x80'; // but Windows code for the converted TrueType fonts
4484 #error EuroSymbol is what?
4492 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */