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 <sal/config.h>
22 #include <sal/log.hxx>
23 #include <svl/zforlist.hxx>
24 #include <svl/currencytable.hxx>
26 #include <comphelper/string.hxx>
27 #include <tools/debug.hxx>
28 #include <unotools/charclass.hxx>
29 #include <i18nlangtag/mslangid.hxx>
30 #include <unotools/localedatawrapper.hxx>
31 #include <unotools/numberformatcodewrapper.hxx>
32 #include <unotools/calendarwrapper.hxx>
33 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
34 #include <com/sun/star/i18n/KNumberFormatType.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <unotools/misccfg.hxx>
39 #include <osl/mutex.hxx>
41 #include "zforscan.hxx"
42 #include "zforfind.hxx"
43 #include <svl/zformat.hxx>
45 #include <unotools/syslocaleoptions.hxx>
46 #include <unotools/digitgroupingiterator.hxx>
47 #include <rtl/instance.hxx>
48 #include <rtl/strbuf.hxx>
52 #include <boost/scoped_ptr.hpp>
54 using namespace ::com::sun::star
;
55 using namespace ::com::sun::star::uno
;
56 using namespace ::com::sun::star::i18n
;
57 using namespace ::com::sun::star::lang
;
58 using namespace ::std
;
60 // Constants for type offsets per Country/Language (CL)
62 #define ZF_STANDARD_PERCENT 10
63 #define ZF_STANDARD_CURRENCY 20
64 #define ZF_STANDARD_DATE 30
65 #define ZF_STANDARD_TIME 40
66 #define ZF_STANDARD_DATETIME 50
67 #define ZF_STANDARD_SCIENTIFIC 60
68 #define ZF_STANDARD_FRACTION 70
69 #define ZF_STANDARD_NEWEXTENDED 75
70 #define ZF_STANDARD_NEWEXTENDEDMAX SV_MAX_ANZ_STANDARD_FORMATE-2 // 98
71 #define ZF_STANDARD_LOGICAL SV_MAX_ANZ_STANDARD_FORMATE-1 // 99
72 #define ZF_STANDARD_TEXT SV_MAX_ANZ_STANDARD_FORMATE // 100
74 /* Locale that is set if an unknown locale (from another system) is loaded of
75 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
76 * (old currency) is recognized as a date (#53155#). */
77 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
82 sal_uInt32 maData
[NF_INDEX_TABLE_ENTRIES
];
85 IndexTable() : mbInitialized(false) {}
88 static IndexTable theIndexTable
;
93 instead of every number formatter being a listener we have a registry which
94 also handles one instance of the SysLocale options
97 typedef ::std::vector
< SvNumberFormatter
* > SvNumberFormatterList_impl
;
99 class SvNumberFormatterRegistry_Impl
: public utl::ConfigurationListener
101 SvNumberFormatterList_impl aFormatters
;
102 SvtSysLocaleOptions aSysLocaleOptions
;
103 LanguageType eSysLanguage
;
106 SvNumberFormatterRegistry_Impl();
107 virtual ~SvNumberFormatterRegistry_Impl();
109 void Insert( SvNumberFormatter
* pThis
)
110 { aFormatters
.push_back( pThis
); }
112 SvNumberFormatter
* Remove( SvNumberFormatter
* pThis
);
115 { return aFormatters
.size(); }
117 virtual void ConfigurationChanged( utl::ConfigurationBroadcaster
*, sal_uInt32
) SAL_OVERRIDE
;
120 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
122 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
123 aSysLocaleOptions
.AddListener( this );
127 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
129 aSysLocaleOptions
.RemoveListener( this );
133 SvNumberFormatter
* SvNumberFormatterRegistry_Impl::Remove( SvNumberFormatter
* pThis
)
135 for (SvNumberFormatterList_impl::iterator it
= aFormatters
.begin();
136 it
!= aFormatters
.end(); ++it
)
140 aFormatters
.erase( it
);
147 void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster
*,
150 ::osl::MutexGuard
aGuard( SvNumberFormatter::GetMutex() );
152 if ( nHint
& SYSLOCALEOPTIONS_HINT_LOCALE
)
154 for( size_t i
= 0, n
= aFormatters
.size(); i
< n
; ++i
)
155 aFormatters
[ i
]->ReplaceSystemCL( eSysLanguage
);
156 eSysLanguage
= MsLangId::getRealLanguage( LANGUAGE_SYSTEM
);
158 if ( nHint
& SYSLOCALEOPTIONS_HINT_CURRENCY
)
160 for( size_t i
= 0, n
= aFormatters
.size(); i
< n
; ++i
)
161 aFormatters
[ i
]->ResetDefaultSystemCurrency();
163 if ( nHint
& SYSLOCALEOPTIONS_HINT_DATEPATTERNS
)
165 for( size_t i
= 0, n
= aFormatters
.size(); i
< n
; ++i
)
166 aFormatters
[ i
]->InvalidateDateAcceptancePatterns();
173 SvNumberFormatterRegistry_Impl
* SvNumberFormatter::pFormatterRegistry
= NULL
;
174 bool SvNumberFormatter::bCurrencyTableInitialized
= false;
177 struct theCurrencyTable
:
178 public rtl::Static
< NfCurrencyTable
, theCurrencyTable
> {};
180 struct theLegacyOnlyCurrencyTable
:
181 public rtl::Static
< NfCurrencyTable
, theLegacyOnlyCurrencyTable
> {};
183 /** THE set of installed locales. */
184 struct theInstalledLocales
:
185 public rtl::Static
< NfInstalledLocales
, theInstalledLocales
> {};
188 sal_uInt16
SvNumberFormatter::nSystemCurrencyPosition
= 0;
190 // Whether BankSymbol (not CurrencySymbol!) is always at the end (1 $;-1 $) or
191 // language dependent.
192 #define NF_BANKSYMBOL_FIX_POSITION 1
194 const sal_uInt16
SvNumberFormatter::UNLIMITED_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max();
195 const sal_uInt16
SvNumberFormatter::INPUTSTRING_PRECISION
= ::std::numeric_limits
<sal_uInt16
>::max()-1;
197 SvNumberFormatter::SvNumberFormatter( const Reference
< XComponentContext
>& rxContext
,
199 : m_xContext( rxContext
)
200 , maLanguageTag( eLang
)
202 ImpConstruct( eLang
);
205 SvNumberFormatter::~SvNumberFormatter()
208 ::osl::MutexGuard
aGuard( GetMutex() );
209 pFormatterRegistry
->Remove( this );
210 if ( !pFormatterRegistry
->Count() )
212 delete pFormatterRegistry
;
213 pFormatterRegistry
= NULL
;
217 for (SvNumberFormatTable::iterator it
= aFTable
.begin(); it
!= aFTable
.end(); ++it
)
221 delete pStringScanner
;
222 delete pFormatScanner
;
228 void SvNumberFormatter::ImpConstruct( LanguageType eLang
)
230 if ( eLang
== LANGUAGE_DONTKNOW
)
232 eLang
= UNKNOWN_SUBSTITUTE
;
236 eEvalDateFormat
= NF_EVALDATEFORMAT_INTL
;
237 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
239 maLanguageTag
.reset( eLang
);
240 pCharClass
= new CharClass( m_xContext
, maLanguageTag
);
241 xLocaleData
.init( m_xContext
, maLanguageTag
);
242 xCalendar
.init( m_xContext
, maLanguageTag
.getLocale() );
243 xTransliteration
.init( m_xContext
, eLang
,
244 ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE
);
245 xNatNum
.init( m_xContext
);
247 // cached locale data items
248 const LocaleDataWrapper
* pLoc
= GetLocaleData();
249 aDecimalSep
= pLoc
->getNumDecimalSep();
250 aThousandSep
= pLoc
->getNumThousandSep();
251 aDateSep
= pLoc
->getDateSep();
253 pStringScanner
= new ImpSvNumberInputScan( this );
254 pFormatScanner
= new ImpSvNumberformatScan( this );
257 ImpGenerateFormats( 0, false ); // 0 .. 999 for initialized language formats
261 ::osl::MutexGuard
aGuard( GetMutex() );
262 GetFormatterRegistry().Insert( this );
266 void SvNumberFormatter::ChangeIntl(LanguageType eLnge
)
268 if (ActLnge
!= eLnge
)
272 maLanguageTag
.reset( eLnge
);
273 pCharClass
->setLanguageTag( maLanguageTag
);
274 xLocaleData
.changeLocale( maLanguageTag
);
275 xCalendar
.changeLocale( maLanguageTag
.getLocale() );
276 xTransliteration
.changeLocale( eLnge
);
278 // cached locale data items, initialize BEFORE calling ChangeIntl below
279 const LocaleDataWrapper
* pLoc
= GetLocaleData();
280 aDecimalSep
= pLoc
->getNumDecimalSep();
281 aThousandSep
= pLoc
->getNumThousandSep();
282 aDateSep
= pLoc
->getDateSep();
284 pFormatScanner
->ChangeIntl();
285 pStringScanner
->ChangeIntl();
291 ::osl::Mutex
& SvNumberFormatter::GetMutex()
293 static ::osl::Mutex
* pMutex
= NULL
;
296 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
299 // #i77768# Due to a static reference in the toolkit lib
300 // we need a mutex that lives longer than the svl library.
301 // Otherwise the dtor would use a destructed mutex!!
302 pMutex
= new ::osl::Mutex
;
310 SvNumberFormatterRegistry_Impl
& SvNumberFormatter::GetFormatterRegistry()
312 ::osl::MutexGuard
aGuard( GetMutex() );
313 if ( !pFormatterRegistry
)
315 pFormatterRegistry
= new SvNumberFormatterRegistry_Impl
;
317 return *pFormatterRegistry
;
320 void SvNumberFormatter::SetColorLink( const Link
<>& rColorTableCallBack
)
322 aColorLink
= rColorTableCallBack
;
325 Color
* SvNumberFormatter::GetUserDefColor(sal_uInt16 nIndex
)
327 if( aColorLink
.IsSet() )
329 return reinterpret_cast<Color
*>( aColorLink
.Call( (void*) &nIndex
)) ;
337 void SvNumberFormatter::ChangeNullDate(sal_uInt16 nDay
,
341 pFormatScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
342 pStringScanner
->ChangeNullDate(nDay
, nMonth
, nYear
);
345 Date
* SvNumberFormatter::GetNullDate()
347 return pFormatScanner
->GetNullDate();
350 void SvNumberFormatter::ChangeStandardPrec(short nPrec
)
352 pFormatScanner
->ChangeStandardPrec(nPrec
);
355 void SvNumberFormatter::SetNoZero(bool bNZ
)
360 sal_uInt16
SvNumberFormatter::GetStandardPrec()
362 return pFormatScanner
->GetStandardPrec();
365 bool SvNumberFormatter::GetNoZero()
370 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage
)
372 sal_uInt32 nCLOffset
= ImpGetCLOffset( LANGUAGE_SYSTEM
);
373 if ( nCLOffset
> MaxCLOffset
)
375 return ; // no SYSTEM entries to replace
377 const sal_uInt32 nMaxBuiltin
= nCLOffset
+ SV_MAX_ANZ_STANDARD_FORMATE
;
378 const sal_uInt32 nNextCL
= nCLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
381 // remove old builtin formats
382 SvNumberFormatTable::iterator it
= aFTable
.find( nCLOffset
);
383 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
<= nMaxBuiltin
)
386 it
= aFTable
.erase(it
);
389 // move additional and user defined to temporary table
390 SvNumberFormatTable aOldTable
;
391 while ( it
!= aFTable
.end() && (nKey
= it
->first
) >= nCLOffset
&& nKey
< nNextCL
)
393 aOldTable
[ nKey
] = it
->second
;
394 it
= aFTable
.erase(it
);
397 // generate new old builtin formats
398 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
399 ActLnge
= LANGUAGE_DONTKNOW
;
400 ChangeIntl( LANGUAGE_SYSTEM
);
401 ImpGenerateFormats( nCLOffset
, true );
403 // convert additional and user defined from old system to new system
404 SvNumberformat
* pStdFormat
= GetFormatEntry( nCLOffset
+ ZF_STANDARD
);
405 sal_uInt32 nLastKey
= nMaxBuiltin
;
406 pFormatScanner
->SetConvertMode( eOldLanguage
, LANGUAGE_SYSTEM
, true );
407 while ( !aOldTable
.empty() )
409 nKey
= aOldTable
.begin()->first
;
410 if ( nLastKey
< nKey
)
414 SvNumberformat
* pOldEntry
= aOldTable
.begin()->second
;
415 aOldTable
.erase( nKey
);
416 OUString
aString( pOldEntry
->GetFormatstring() );
418 // Same as PutEntry() but assures key position even if format code is
419 // a duplicate. Also won't mix up any LastInsertKey.
420 ChangeIntl( eOldLanguage
);
421 LanguageType eLge
= eOldLanguage
; // ConvertMode changes this
423 sal_Int32 nCheckPos
= -1;
424 SvNumberformat
* pNewEntry
= new SvNumberformat( aString
, pFormatScanner
,
425 pStringScanner
, nCheckPos
, eLge
);
426 if ( nCheckPos
!= 0 )
432 short eCheckType
= pNewEntry
->GetType();
433 if ( eCheckType
!= css::util::NumberFormat::UNDEFINED
)
435 pNewEntry
->SetType( eCheckType
| css::util::NumberFormat::DEFINED
);
439 pNewEntry
->SetType( css::util::NumberFormat::DEFINED
);
442 if ( !aFTable
.insert( make_pair( nKey
, pNewEntry
) ).second
)
451 DBG_ASSERT( bCheck
, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
456 pFormatScanner
->SetConvertMode(false);
457 pStdFormat
->SetLastInsertKey( sal_uInt16(nLastKey
- nCLOffset
) );
459 // append new system additional formats
460 NumberFormatCodeWrapper
aNumberFormatCode( m_xContext
,
461 GetLanguageTag().getLocale() );
462 ImpGenerateAdditionalFormats( nCLOffset
, aNumberFormatCode
, true );
465 css::uno::Reference
<css::uno::XComponentContext
> SvNumberFormatter::GetComponentContext() const
470 const ImpSvNumberformatScan
* SvNumberFormatter::GetFormatScanner() const { return pFormatScanner
; }
472 const LanguageTag
& SvNumberFormatter::GetLanguageTag() const { return maLanguageTag
; }
474 const ::utl::TransliterationWrapper
* SvNumberFormatter::GetTransliteration() const
476 return xTransliteration
.get();
479 const CharClass
* SvNumberFormatter::GetCharClass() const { return pCharClass
; }
481 const LocaleDataWrapper
* SvNumberFormatter::GetLocaleData() const { return xLocaleData
.get(); }
483 CalendarWrapper
* SvNumberFormatter::GetCalendar() const { return xCalendar
.get(); }
485 const NativeNumberWrapper
* SvNumberFormatter::GetNatNum() const { return xNatNum
.get(); }
487 const OUString
& SvNumberFormatter::GetNumDecimalSep() const { return aDecimalSep
; }
489 const OUString
& SvNumberFormatter::GetNumThousandSep() const { return aThousandSep
; }
491 const OUString
& SvNumberFormatter::GetDateSep() const { return aDateSep
; }
493 bool SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index
) const
495 const SvNumberformat
* pFormat
= GetFormatEntry(F_Index
);
497 return pFormat
&& pFormat
->IsTextFormat();
500 bool SvNumberFormatter::PutEntry(OUString
& rString
,
501 sal_Int32
& nCheckPos
,
503 sal_uInt32
& nKey
, // format key
507 if (rString
.isEmpty()) // empty string
509 nCheckPos
= 1; // -> Error
512 if (eLnge
== LANGUAGE_DONTKNOW
)
516 ChangeIntl(eLnge
); // change locale if necessary
517 LanguageType eLge
= eLnge
; // non-const for ConvertMode
519 SvNumberformat
* p_Entry
= new SvNumberformat(rString
,
525 if (nCheckPos
== 0) // Format ok
526 { // Type comparison:
527 short eCheckType
= p_Entry
->GetType();
528 if ( eCheckType
!= css::util::NumberFormat::UNDEFINED
)
530 p_Entry
->SetType(eCheckType
| css::util::NumberFormat::DEFINED
);
535 p_Entry
->SetType(css::util::NumberFormat::DEFINED
);
536 nType
= css::util::NumberFormat::DEFINED
;
539 sal_uInt32 CLOffset
= ImpGenerateCL(eLge
); // create new standard formats if necessary
541 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLge
);
542 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
548 SvNumberformat
* pStdFormat
= GetFormatEntry(CLOffset
+ ZF_STANDARD
);
549 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey();
550 if (nPos
+1 - CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
552 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: too many formats for CL");
555 else if (!aFTable
.insert(make_pair( nPos
+1,p_Entry
)).second
)
557 SAL_WARN( "svl.numbers", "SvNumberFormatter::PutEntry: dup position");
564 pStdFormat
->SetLastInsertKey((sal_uInt16
) (nKey
-CLOffset
));
575 bool SvNumberFormatter::PutandConvertEntry(OUString
& rString
,
576 sal_Int32
& nCheckPos
,
580 LanguageType eNewLnge
)
583 if (eNewLnge
== LANGUAGE_DONTKNOW
)
587 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
);
588 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
589 pFormatScanner
->SetConvertMode(false);
593 bool SvNumberFormatter::PutandConvertEntrySystem(OUString
& rString
,
594 sal_Int32
& nCheckPos
,
598 LanguageType eNewLnge
)
601 if (eNewLnge
== LANGUAGE_DONTKNOW
)
605 pFormatScanner
->SetConvertMode(eLnge
, eNewLnge
, true);
606 bRes
= PutEntry(rString
, nCheckPos
, nType
, nKey
, eLnge
);
607 pFormatScanner
->SetConvertMode(false);
611 sal_uInt32
SvNumberFormatter::GetIndexPuttingAndConverting( OUString
& rString
, LanguageType eLnge
,
612 LanguageType eSysLnge
, short & rType
,
613 bool & rNewInserted
, sal_Int32
& rCheckPos
)
615 sal_uInt32 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
616 rNewInserted
= false;
619 // #62389# empty format string (of Writer) => General standard format
620 if (rString
.isEmpty())
624 else if (eLnge
== LANGUAGE_SYSTEM
&& eSysLnge
!= SvtSysLocale().GetLanguageTag().getLanguageType())
626 sal_uInt32 nOrig
= GetEntryKey( rString
, eSysLnge
);
627 if (nOrig
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
629 nKey
= nOrig
; // none available, maybe user-defined
633 nKey
= GetFormatForLanguageIfBuiltIn( nOrig
, SvtSysLocale().GetLanguageTag().getLanguageType() );
637 // Not a builtin format, convert.
638 // The format code string may get modified and adapted to the real
639 // language and wouldn't match eSysLnge anymore, do that on a copy.
640 OUString
aTmp( rString
);
641 rNewInserted
= PutandConvertEntrySystem( aTmp
, rCheckPos
, rType
,
642 nKey
, eLnge
, SvtSysLocale().GetLanguageTag().getLanguageType());
645 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
646 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
652 nKey
= GetEntryKey( rString
, eLnge
);
653 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
655 rNewInserted
= PutEntry( rString
, rCheckPos
, rType
, nKey
, eLnge
);
658 SAL_WARN( "svl.numbers", "SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
659 nKey
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
663 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
665 nKey
= GetStandardIndex( eLnge
);
667 rType
= GetType( nKey
);
668 // Convert any (!) old "automatic" currency format to new fixed currency
670 if ((rType
& css::util::NumberFormat::CURRENCY
) != 0)
672 const SvNumberformat
* pFormat
= GetEntry( nKey
);
673 if (!pFormat
->HasNewCurrency())
677 DeleteEntry( nKey
); // don't leave trails of rubbish
678 rNewInserted
= false;
680 nKey
= GetStandardFormat( css::util::NumberFormat::CURRENCY
, eLnge
);
686 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey
)
688 delete aFTable
[nKey
];
692 void SvNumberFormatter::GetUsedLanguages( std::vector
<sal_uInt16
>& rList
)
696 sal_uInt32 nOffset
= 0;
697 while (nOffset
<= MaxCLOffset
)
699 SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
702 rList
.push_back( pFormat
->GetLanguage() );
704 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
709 void SvNumberFormatter::FillKeywordTable( NfKeywordTable
& rKeywords
,
713 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
714 for ( sal_uInt16 i
= 0; i
< NF_KEYWORD_ENTRIES_COUNT
; ++i
)
716 rKeywords
[i
] = rTable
[i
];
721 OUString
SvNumberFormatter::GetKeyword( LanguageType eLnge
, sal_uInt16 nIndex
)
724 const NfKeywordTable
& rTable
= pFormatScanner
->GetKeywords();
725 if ( nIndex
< NF_KEYWORD_ENTRIES_COUNT
)
727 return rTable
[nIndex
];
729 SAL_WARN( "svl.numbers", "GetKeyword: invalid index");
734 OUString
SvNumberFormatter::GetStandardName( LanguageType eLnge
)
737 return pFormatScanner
->GetStandardName();
741 sal_uInt32
SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge
) const
743 sal_uInt32 nOffset
= 0;
744 while (nOffset
<= MaxCLOffset
)
746 const SvNumberformat
* pFormat
= GetFormatEntry(nOffset
);
747 if (pFormat
&& pFormat
->GetLanguage() == eLnge
)
751 nOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
756 sal_uInt32
SvNumberFormatter::ImpIsEntry(const OUString
& rString
,
757 sal_uInt32 nCLOffset
,
760 sal_uInt32 res
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
761 SvNumberFormatTable::iterator it
= aFTable
.find( nCLOffset
);
762 while ( res
== NUMBERFORMAT_ENTRY_NOT_FOUND
&&
763 it
!= aFTable
.end() && it
->second
->GetLanguage() == eLnge
)
765 if ( rString
== it
->second
->GetFormatstring() )
778 SvNumberFormatTable
& SvNumberFormatter::GetFirstEntryTable(
783 short eTypetmp
= eType
;
784 if (eType
== css::util::NumberFormat::ALL
) // empty cell or don't care
790 SvNumberformat
* pFormat
= GetFormatEntry(FIndex
);
794 eType
= css::util::NumberFormat::ALL
;
799 rLnge
= pFormat
->GetLanguage();
800 eType
= pFormat
->GetType()&~css::util::NumberFormat::DEFINED
;
803 eType
= css::util::NumberFormat::DEFINED
;
806 else if (eType
== css::util::NumberFormat::DATETIME
)
809 eType
= css::util::NumberFormat::DATE
;
818 return GetEntryTable(eTypetmp
, FIndex
, rLnge
);
821 sal_uInt32
SvNumberFormatter::ImpGenerateCL( LanguageType eLnge
, bool bNoAdditionalFormats
)
824 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
825 if (CLOffset
> MaxCLOffset
)
827 // new CL combination
828 if (LocaleDataWrapper::areChecksEnabled())
830 const LanguageTag
& rLoadedLocale
= xLocaleData
->getLoadedLanguageTag();
831 if ( !rLoadedLocale
.equals( maLanguageTag
, true) )
833 OUString
aMsg("SvNumberFormatter::ImpGenerateCL: locales don't match:");
834 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
836 // test XML locale data FormatElement entries
838 uno::Sequence
< i18n::FormatElement
> xSeq
= xLocaleData
->getAllFormats();
839 // A test for completeness of formatindex="0" ...
840 // formatindex="47" is not needed here since it is done in
841 // ImpGenerateFormats().
843 // Test for dupes of formatindex="..."
844 for ( sal_Int32 j
= 0; j
< xSeq
.getLength(); j
++ )
846 sal_Int16 nIdx
= xSeq
[j
].formatIndex
;
847 OUStringBuffer aDupes
;
848 for ( sal_Int32 i
= 0; i
< xSeq
.getLength(); i
++ )
850 if ( i
!= j
&& xSeq
[i
].formatIndex
== nIdx
)
852 aDupes
.append(OUString::number( i
));
854 aDupes
.append(xSeq
[i
].formatKey
);
855 aDupes
.append( ") ");
858 if ( !aDupes
.isEmpty() )
860 OUStringBuffer
aMsg(aDupes
.getLength() + xSeq
[j
].formatKey
.getLength() + 100);
861 aMsg
.append("XML locale data FormatElement formatindex dupe: ");
862 aMsg
.append(OUString::number(nIdx
));
863 aMsg
.append("\nFormatElements: ");
864 aMsg
.append(OUString::number( j
));
866 aMsg
.append( xSeq
[j
].formatKey
);
868 aMsg
.append(aDupes
.makeStringAndClear());
869 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
.makeStringAndClear() ));
875 MaxCLOffset
+= SV_COUNTRY_LANGUAGE_OFFSET
;
876 ImpGenerateFormats( MaxCLOffset
, bNoAdditionalFormats
);
877 CLOffset
= MaxCLOffset
;
882 SvNumberFormatTable
& SvNumberFormatter::ChangeCL(short eType
,
886 ImpGenerateCL(eLnge
);
887 return GetEntryTable(eType
, FIndex
, ActLnge
);
890 SvNumberFormatTable
& SvNumberFormatter::GetEntryTable(
897 pFormatTable
->clear();
901 pFormatTable
= new SvNumberFormatTable
;
904 sal_uInt32 CLOffset
= ImpGetCLOffset(ActLnge
);
906 // Might generate and insert a default format for the given type
907 // (e.g. currency) => has to be done before collecting formats.
908 sal_uInt32 nDefaultIndex
= GetStandardFormat( eType
, ActLnge
);
910 SvNumberFormatTable::iterator it
= aFTable
.find( CLOffset
);
912 if (eType
== css::util::NumberFormat::ALL
)
914 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
915 { // copy all entries to output table
916 (*pFormatTable
)[ it
->first
] = it
->second
;
922 while (it
!= aFTable
.end() && it
->second
->GetLanguage() == ActLnge
)
923 { // copy entries of queried type to output table
924 if ((it
->second
->GetType()) & eType
)
925 (*pFormatTable
)[ it
->first
] = it
->second
;
929 if ( !pFormatTable
->empty() )
930 { // select default if queried format doesn't exist or queried type or
931 // language differ from existing format
932 SvNumberformat
* pEntry
= GetFormatEntry(FIndex
);
933 if ( !pEntry
|| !(pEntry
->GetType() & eType
) || pEntry
->GetLanguage() != ActLnge
)
935 FIndex
= nDefaultIndex
;
938 return *pFormatTable
;
941 bool SvNumberFormatter::IsNumberFormat(const OUString
& sString
,
946 const SvNumberformat
* pFormat
= GetFormatEntry(F_Index
);
950 FType
= css::util::NumberFormat::NUMBER
;
954 FType
= pFormat
->GetType() &~css::util::NumberFormat::DEFINED
;
957 FType
= css::util::NumberFormat::DEFINED
;
959 ChangeIntl(pFormat
->GetLanguage());
964 if (RType
== css::util::NumberFormat::TEXT
)
966 res
= false; // type text preset => no conversion to number
970 res
= pStringScanner
->IsNumberFormat(sString
, RType
, fOutNumber
, pFormat
);
972 if (res
&& !IsCompatible(FType
, RType
)) // non-matching type
976 case css::util::NumberFormat::DATE
:
977 // Preserve ISO 8601 input.
978 if (pStringScanner
->CanForceToIso8601( DMY
))
980 F_Index
= GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, ActLnge
);
984 F_Index
= GetStandardFormat( RType
, ActLnge
);
987 case css::util::NumberFormat::TIME
:
988 if ( pStringScanner
->GetDecPos() )
991 if ( pStringScanner
->GetAnzNums() > 3 || fOutNumber
< 0.0 )
993 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS00
, ActLnge
);
997 F_Index
= GetFormatIndex( NF_TIME_MMSS00
, ActLnge
);
1000 else if ( fOutNumber
>= 1.0 || fOutNumber
< 0.0 )
1002 F_Index
= GetFormatIndex( NF_TIME_HH_MMSS
, ActLnge
);
1006 F_Index
= GetStandardFormat( RType
, ActLnge
);
1010 F_Index
= GetStandardFormat( RType
, ActLnge
);
1016 LanguageType
SvNumberFormatter::GetLanguage() const
1021 bool SvNumberFormatter::IsCompatible(short eOldType
,
1024 if (eOldType
== eNewType
)
1028 else if (eOldType
== css::util::NumberFormat::DEFINED
)
1036 case css::util::NumberFormat::NUMBER
:
1039 case css::util::NumberFormat::PERCENT
:
1040 case css::util::NumberFormat::CURRENCY
:
1041 case css::util::NumberFormat::SCIENTIFIC
:
1042 case css::util::NumberFormat::FRACTION
:
1043 // case css::util::NumberFormat::LOGICAL:
1044 case css::util::NumberFormat::DEFINED
:
1050 case css::util::NumberFormat::DATE
:
1053 case css::util::NumberFormat::DATETIME
:
1059 case css::util::NumberFormat::TIME
:
1062 case css::util::NumberFormat::DATETIME
:
1068 case css::util::NumberFormat::DATETIME
:
1071 case css::util::NumberFormat::TIME
:
1072 case css::util::NumberFormat::DATE
:
1085 sal_uInt32
SvNumberFormatter::ImpGetDefaultFormat( short nType
)
1087 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
1091 case css::util::NumberFormat::DATE
:
1092 nSearch
= CLOffset
+ ZF_STANDARD_DATE
;
1094 case css::util::NumberFormat::TIME
:
1095 nSearch
= CLOffset
+ ZF_STANDARD_TIME
;
1097 case css::util::NumberFormat::DATETIME
:
1098 nSearch
= CLOffset
+ ZF_STANDARD_DATETIME
;
1100 case css::util::NumberFormat::PERCENT
:
1101 nSearch
= CLOffset
+ ZF_STANDARD_PERCENT
;
1103 case css::util::NumberFormat::SCIENTIFIC
:
1104 nSearch
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1107 nSearch
= CLOffset
+ ZF_STANDARD
;
1110 DefaultFormatKeysMap::iterator it
= aDefaultFormatKeys
.find( nSearch
);
1111 sal_uInt32 nDefaultFormat
= (it
!= aDefaultFormatKeys
.end() ?
1112 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
1113 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1115 // look for a defined standard
1116 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
1118 SvNumberFormatTable::iterator it2
= aFTable
.find( CLOffset
);
1119 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
1121 const SvNumberformat
* pEntry
= it2
->second
;
1122 if ( pEntry
->IsStandard() && ((pEntry
->GetType() &
1123 ~css::util::NumberFormat::DEFINED
) == nType
) )
1125 nDefaultFormat
= nKey
;
1131 if ( nDefaultFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
1132 { // none found, use old fixed standards
1135 case css::util::NumberFormat::DATE
:
1136 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATE
;
1138 case css::util::NumberFormat::TIME
:
1139 nDefaultFormat
= CLOffset
+ ZF_STANDARD_TIME
+1;
1141 case css::util::NumberFormat::DATETIME
:
1142 nDefaultFormat
= CLOffset
+ ZF_STANDARD_DATETIME
;
1144 case css::util::NumberFormat::PERCENT
:
1145 nDefaultFormat
= CLOffset
+ ZF_STANDARD_PERCENT
+1;
1147 case css::util::NumberFormat::SCIENTIFIC
:
1148 nDefaultFormat
= CLOffset
+ ZF_STANDARD_SCIENTIFIC
;
1151 nDefaultFormat
= CLOffset
+ ZF_STANDARD
;
1154 aDefaultFormatKeys
[ nSearch
] = nDefaultFormat
;
1156 return nDefaultFormat
;
1160 sal_uInt32
SvNumberFormatter::GetStandardFormat( short eType
, LanguageType eLnge
)
1162 if (eLnge
== LANGUAGE_DONTKNOW
)
1166 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1169 case css::util::NumberFormat::CURRENCY
:
1170 return ( eLnge
== LANGUAGE_SYSTEM
) ? ImpGetDefaultSystemCurrencyFormat() : ImpGetDefaultCurrencyFormat();
1171 case css::util::NumberFormat::DATE
:
1172 case css::util::NumberFormat::TIME
:
1173 case css::util::NumberFormat::DATETIME
:
1174 case css::util::NumberFormat::PERCENT
:
1175 case css::util::NumberFormat::SCIENTIFIC
:
1176 return ImpGetDefaultFormat( eType
);
1177 case css::util::NumberFormat::FRACTION
:
1178 return CLOffset
+ ZF_STANDARD_FRACTION
;
1179 case css::util::NumberFormat::LOGICAL
:
1180 return CLOffset
+ ZF_STANDARD_LOGICAL
;
1181 case css::util::NumberFormat::TEXT
:
1182 return CLOffset
+ ZF_STANDARD_TEXT
;
1183 case css::util::NumberFormat::ALL
:
1184 case css::util::NumberFormat::DEFINED
:
1185 case css::util::NumberFormat::NUMBER
:
1186 case css::util::NumberFormat::UNDEFINED
:
1188 return CLOffset
+ ZF_STANDARD
;
1192 bool SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex
,
1193 LanguageType eLnge
)
1196 nFIndex
== GetFormatIndex( NF_TIME_MMSS00
, eLnge
) ||
1197 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
) ||
1198 nFIndex
== GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
)
1202 sal_uInt32
SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex
, short eType
,
1203 LanguageType eLnge
)
1205 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1208 return GetStandardFormat( eType
, eLnge
);
1211 sal_uInt32
SvNumberFormatter::GetStandardFormat( double fNumber
, sal_uInt32 nFIndex
,
1212 short eType
, LanguageType eLnge
)
1214 if ( IsSpecialStandardFormat( nFIndex
, eLnge
) )
1219 case css::util::NumberFormat::TIME
:
1222 if ( fNumber
< 0.0 )
1229 double fSeconds
= fNumber
* 86400;
1230 if ( floor( fSeconds
+ 0.5 ) * 100 != floor( fSeconds
* 100 + 0.5 ) )
1231 { // with 100th seconds
1232 if ( bSign
|| fSeconds
>= 3600 )
1233 return GetFormatIndex( NF_TIME_HH_MMSS00
, eLnge
);
1235 return GetFormatIndex( NF_TIME_MMSS00
, eLnge
);
1239 if ( bSign
|| fNumber
>= 1.0 )
1240 return GetFormatIndex( NF_TIME_HH_MMSS
, eLnge
);
1242 return GetStandardFormat( eType
, eLnge
);
1246 return GetStandardFormat( eType
, eLnge
);
1250 sal_uInt32
SvNumberFormatter::GetEditFormat( double fNumber
, sal_uInt32 nFIndex
,
1251 short eType
, LanguageType eLang
,
1252 SvNumberformat
* pFormat
)
1254 sal_uInt32 nKey
= nFIndex
;
1257 // #61619# always edit using 4-digit year
1258 case css::util::NumberFormat::DATE
:
1259 if (rtl::math::approxFloor( fNumber
) != fNumber
)
1260 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1261 // fdo#34977 preserve time when editing even if only date was
1263 /* FIXME: in case an ISO 8601 format was used, editing should
1264 * also use such. Unfortunately we have no builtin combined
1265 * date+time ISO format defined. Needs also locale data work.
1269 // Preserve ISO 8601 format.
1270 if ( nFIndex
== GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, eLang
) ||
1271 nFIndex
== GetFormatIndex( NF_DATE_DIN_YYMMDD
, eLang
) ||
1272 nFIndex
== GetFormatIndex( NF_DATE_DIN_MMDD
, eLang
) ||
1273 (pFormat
&& pFormat
->IsIso8601( 0 )))
1274 nKey
= GetFormatIndex( NF_DATE_DIN_YYYYMMDD
, eLang
);
1276 nKey
= GetFormatIndex( NF_DATE_SYS_DDMMYYYY
, eLang
);
1279 case css::util::NumberFormat::TIME
:
1280 if (fNumber
< 0.0 || fNumber
>= 1.0)
1282 /* XXX NOTE: this is a purely arbitrary value within the limits
1283 * of a signed 16-bit. 32k hours are 3.7 years ... or
1284 * 1903-09-26 if date. */
1285 if (fabs( fNumber
) * 24 < 0x7fff)
1286 nKey
= GetFormatIndex( NF_TIME_HH_MMSS
, eLang
);
1287 // Preserve duration, use [HH]:MM:SS instead of time.
1289 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1290 // Assume that a large value is a datetime with only time
1294 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1296 case css::util::NumberFormat::DATETIME
:
1297 nKey
= GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, eLang
);
1298 /* FIXME: in case an ISO 8601 format was used, editing should
1299 * also use such. Unfortunately we have no builtin combined
1300 * date+time ISO format defined. Needs also locale data work. */
1303 nKey
= GetStandardFormat( fNumber
, nFIndex
, eType
, eLang
);
1308 void SvNumberFormatter::GetInputLineString(const double& fOutNumber
,
1310 OUString
& sOutString
)
1313 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1316 pFormat
= GetFormatEntry(ZF_STANDARD
);
1319 LanguageType eLang
= pFormat
->GetLanguage();
1320 ChangeIntl( eLang
);
1322 short eType
= pFormat
->GetType() & ~css::util::NumberFormat::DEFINED
;
1325 eType
= css::util::NumberFormat::DEFINED
;
1328 sal_uInt16 nOldPrec
= pFormatScanner
->GetStandardPrec();
1329 bool bPrecChanged
= false;
1330 if (eType
== css::util::NumberFormat::NUMBER
||
1331 eType
== css::util::NumberFormat::PERCENT
||
1332 eType
== css::util::NumberFormat::CURRENCY
||
1333 eType
== css::util::NumberFormat::SCIENTIFIC
||
1334 eType
== css::util::NumberFormat::FRACTION
)
1336 if (eType
!= css::util::NumberFormat::PERCENT
) // special treatment of % later
1338 eType
= css::util::NumberFormat::NUMBER
;
1340 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1341 bPrecChanged
= true;
1344 sal_uInt32 nKey
= GetEditFormat( fOutNumber
, nFIndex
, eType
, eLang
, pFormat
);
1345 if ( nKey
!= nFIndex
)
1347 pFormat
= GetFormatEntry( nKey
);
1351 if ( eType
== css::util::NumberFormat::TIME
&& pFormat
->GetFormatPrecision() )
1353 ChangeStandardPrec(INPUTSTRING_PRECISION
);
1354 bPrecChanged
= true;
1356 pFormat
->GetOutputString(fOutNumber
, sOutString
, &pColor
);
1360 ChangeStandardPrec(nOldPrec
);
1364 void SvNumberFormatter::GetOutputString(const OUString
& sString
,
1366 OUString
& sOutString
,
1368 bool bUseStarFormat
)
1370 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1373 pFormat
= GetFormatEntry(ZF_STANDARD_TEXT
);
1375 if (!pFormat
->IsTextFormat() && !pFormat
->HasTextFormat())
1378 sOutString
= sString
;
1382 ChangeIntl(pFormat
->GetLanguage());
1383 if ( bUseStarFormat
)
1385 pFormat
->SetStarFormatSupport( true );
1387 pFormat
->GetOutputString(sString
, sOutString
, ppColor
);
1388 if ( bUseStarFormat
)
1390 pFormat
->SetStarFormatSupport( false );
1395 void SvNumberFormatter::GetOutputString(const double& fOutNumber
,
1397 OUString
& sOutString
,
1399 bool bUseStarFormat
)
1401 if (bNoZero
&& fOutNumber
== 0.0)
1406 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
1408 pFormat
= GetFormatEntry(ZF_STANDARD
);
1409 ChangeIntl(pFormat
->GetLanguage());
1410 if ( bUseStarFormat
)
1411 pFormat
->SetStarFormatSupport( true );
1412 pFormat
->GetOutputString(fOutNumber
, sOutString
, ppColor
);
1413 if ( bUseStarFormat
)
1414 pFormat
->SetStarFormatSupport( false );
1417 bool SvNumberFormatter::GetPreviewString(const OUString
& sFormatString
,
1418 double fPreviewNumber
,
1419 OUString
& sOutString
,
1422 bool bUseStarFormat
)
1424 if (sFormatString
.isEmpty()) // no empty string
1429 if (eLnge
== LANGUAGE_DONTKNOW
)
1433 ChangeIntl(eLnge
); // change locale if necessary
1435 sal_Int32 nCheckPos
= -1;
1436 OUString sTmpString
= sFormatString
;
1437 boost::scoped_ptr
<SvNumberformat
> p_Entry(new SvNumberformat(sTmpString
,
1442 if (nCheckPos
== 0) // String ok
1444 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
1445 nKey
= ImpIsEntry(p_Entry
->GetFormatstring(),CLOffset
, eLnge
);
1446 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1448 GetOutputString(fPreviewNumber
, nKey
, sOutString
, ppColor
, bUseStarFormat
);
1452 if ( bUseStarFormat
)
1454 p_Entry
->SetStarFormatSupport( true );
1456 p_Entry
->GetOutputString(fPreviewNumber
, sOutString
, ppColor
);
1457 if ( bUseStarFormat
)
1459 p_Entry
->SetStarFormatSupport( false );
1470 bool SvNumberFormatter::GetPreviewStringGuess( const OUString
& sFormatString
,
1471 double fPreviewNumber
,
1472 OUString
& sOutString
,
1474 LanguageType eLnge
)
1476 if (sFormatString
.isEmpty()) // no empty string
1480 if (eLnge
== LANGUAGE_DONTKNOW
)
1484 ChangeIntl( eLnge
);
1486 bool bEnglish
= (eLnge
== LANGUAGE_ENGLISH_US
);
1488 OUString
aFormatStringUpper( pCharClass
->uppercase( sFormatString
) );
1489 sal_uInt32 nCLOffset
= ImpGenerateCL( eLnge
);
1490 sal_uInt32 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, eLnge
);
1491 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1493 // Target format present
1494 GetOutputString( fPreviewNumber
, nKey
, sOutString
, ppColor
);
1498 boost::scoped_ptr
<SvNumberformat
> pEntry
;
1499 sal_Int32 nCheckPos
= -1;
1500 OUString sTmpString
;
1504 sTmpString
= sFormatString
;
1505 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
,
1506 pStringScanner
, nCheckPos
, eLnge
));
1510 nCLOffset
= ImpGenerateCL( LANGUAGE_ENGLISH_US
);
1511 nKey
= ImpIsEntry( aFormatStringUpper
, nCLOffset
, LANGUAGE_ENGLISH_US
);
1512 bool bEnglishFormat
= (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
);
1514 // Try English -> other or convert english to other
1515 LanguageType eFormatLang
= LANGUAGE_ENGLISH_US
;
1516 pFormatScanner
->SetConvertMode( LANGUAGE_ENGLISH_US
, eLnge
);
1517 sTmpString
= sFormatString
;
1518 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
,
1519 pStringScanner
, nCheckPos
, eFormatLang
));
1520 pFormatScanner
->SetConvertMode( false );
1521 ChangeIntl( eLnge
);
1523 if ( !bEnglishFormat
)
1525 if ( !(nCheckPos
== 0) || xTransliteration
->isEqual( sFormatString
,
1526 pEntry
->GetFormatstring() ) )
1529 sTmpString
= sFormatString
;
1530 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
,
1531 pStringScanner
, nCheckPos
, eLnge
));
1536 sal_Int32 nCheckPos2
= -1;
1537 // try other --> english
1538 eFormatLang
= eLnge
;
1539 pFormatScanner
->SetConvertMode( eLnge
, LANGUAGE_ENGLISH_US
);
1540 sTmpString
= sFormatString
;
1541 boost::scoped_ptr
<SvNumberformat
> pEntry2(new SvNumberformat( sTmpString
, pFormatScanner
,
1542 pStringScanner
, nCheckPos2
, eFormatLang
));
1543 pFormatScanner
->SetConvertMode( false );
1544 ChangeIntl( eLnge
);
1545 if ( nCheckPos2
== 0 && !xTransliteration
->isEqual( sFormatString
,
1546 pEntry2
->GetFormatstring() ) )
1549 sTmpString
= sFormatString
;
1550 pEntry
.reset(new SvNumberformat( sTmpString
, pFormatScanner
,
1551 pStringScanner
, nCheckPos
, eLnge
));
1557 if (nCheckPos
== 0) // String ok
1559 ImpGenerateCL( eLnge
); // create new standard formats if necessary
1560 pEntry
->GetOutputString( fPreviewNumber
, sOutString
, ppColor
);
1566 bool SvNumberFormatter::GetPreviewString( const OUString
& sFormatString
,
1567 const OUString
& sPreviewString
,
1568 OUString
& sOutString
,
1570 LanguageType eLnge
)
1572 if (sFormatString
.isEmpty()) // no empty string
1577 if (eLnge
== LANGUAGE_DONTKNOW
)
1581 ChangeIntl(eLnge
); // switch if needed
1583 sal_Int32 nCheckPos
= -1;
1584 OUString sTmpString
= sFormatString
;
1585 boost::scoped_ptr
<SvNumberformat
> p_Entry(new SvNumberformat( sTmpString
,
1590 if (nCheckPos
== 0) // String ok
1592 // May have to create standard formats for this locale.
1593 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
);
1594 nKey
= ImpIsEntry( p_Entry
->GetFormatstring(), CLOffset
, eLnge
);
1595 if (nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
1597 GetOutputString( sPreviewString
, nKey
, sOutString
, ppColor
);
1601 // If the format is valid but not a text format and does not
1602 // include a text subformat, an empty string would result. Same as
1603 // in SvNumberFormatter::GetOutputString()
1604 if (p_Entry
->IsTextFormat() || p_Entry
->HasTextFormat())
1606 p_Entry
->GetOutputString( sPreviewString
, sOutString
, ppColor
);
1611 sOutString
= sPreviewString
;
1622 sal_uInt32
SvNumberFormatter::TestNewString(const OUString
& sFormatString
,
1625 if (sFormatString
.isEmpty()) // no empty string
1627 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
1629 if (eLnge
== LANGUAGE_DONTKNOW
)
1633 ChangeIntl(eLnge
); // change locale if necessary
1636 sal_Int32 nCheckPos
= -1;
1637 OUString sTmpString
= sFormatString
;
1638 boost::scoped_ptr
<SvNumberformat
> pEntry(new SvNumberformat(sTmpString
,
1643 if (nCheckPos
== 0) // String ok
1645 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
1646 nRes
= ImpIsEntry(pEntry
->GetFormatstring(),CLOffset
, eLnge
);
1651 nRes
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
1656 SvNumberformat
* SvNumberFormatter::ImpInsertFormat( const ::com::sun::star::i18n::NumberFormatCode
& rCode
,
1657 sal_uInt32 nPos
, bool bAfterChangingSystemCL
,
1658 sal_Int16 nOrgIndex
)
1660 OUString
aCodeStr( rCode
.Code
);
1661 if ( rCode
.Index
< NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
&&
1662 rCode
.Usage
== ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY
&&
1663 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
1664 { // strip surrounding [$...] on automatic currency
1665 if ( aCodeStr
.indexOf( "[$" ) >= 0)
1666 aCodeStr
= SvNumberformat::StripNewCurrencyDelimiters( aCodeStr
, false );
1669 if (LocaleDataWrapper::areChecksEnabled() &&
1670 rCode
.Index
!= NF_CURRENCY_1000DEC2_CCC
)
1672 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index " +
1673 OUString::number( rCode
.Index
) +
1676 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1680 sal_Int32 nCheckPos
= 0;
1681 SvNumberformat
* pFormat
= new SvNumberformat(aCodeStr
,
1688 if (LocaleDataWrapper::areChecksEnabled())
1690 OUString aMsg
= "SvNumberFormatter::ImpInsertFormat: bad format code, index " +
1691 OUString::number( rCode
.Index
) +
1694 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1699 if ( rCode
.Index
>= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
)
1701 sal_uInt32 nCLOffset
= nPos
- (nPos
% SV_COUNTRY_LANGUAGE_OFFSET
);
1702 sal_uInt32 nKey
= ImpIsEntry( aCodeStr
, nCLOffset
, ActLnge
);
1703 if ( nKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
1705 // If bAfterChangingSystemCL there will definitely be some dups,
1707 if (LocaleDataWrapper::areChecksEnabled() && !bAfterChangingSystemCL
)
1709 // Test for duplicate indexes in locale data.
1710 switch ( nOrgIndex
)
1712 // These may be dups of integer versions for locales where
1713 // currencies have no decimals like Italian Lira.
1714 case NF_CURRENCY_1000DEC2
: // NF_CURRENCY_1000INT
1715 case NF_CURRENCY_1000DEC2_RED
: // NF_CURRENCY_1000INT_RED
1716 case NF_CURRENCY_1000DEC2_DASHED
: // NF_CURRENCY_1000INT_RED
1720 OUString
aMsg("SvNumberFormatter::ImpInsertFormat: dup format code, index ");
1721 aMsg
+= OUString::number( rCode
.Index
);
1724 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1731 else if ( nPos
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
1733 if (LocaleDataWrapper::areChecksEnabled())
1735 OUString
aMsg( "SvNumberFormatter::ImpInsertFormat: too many format codes, index ");
1736 aMsg
+= OUString::number( rCode
.Index
);
1739 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1745 if ( !aFTable
.insert( make_pair( nPos
, pFormat
) ).second
)
1747 if (LocaleDataWrapper::areChecksEnabled())
1749 OUString
aMsg( "ImpInsertFormat: can't insert number format key pos: ");
1750 aMsg
+= OUString::number( nPos
);
1751 aMsg
+= ", code index ";
1752 aMsg
+= OUString::number( rCode
.Index
);
1755 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo( aMsg
));
1759 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpInsertFormat: dup position");
1764 if ( rCode
.Default
)
1765 pFormat
->SetStandard();
1766 if ( !rCode
.DefaultName
.isEmpty() )
1767 pFormat
->SetComment( rCode
.DefaultName
);
1771 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat
,
1774 sal_uInt16
& nPrecision
,
1775 sal_uInt16
& nAnzLeading
)
1778 SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
1780 pFormat
->GetFormatSpecialInfo(bThousand
, IsRed
,
1781 nPrecision
, nAnzLeading
);
1786 nPrecision
= pFormatScanner
->GetStandardPrec();
1791 sal_uInt16
SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat
) const
1793 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
1795 return pFormat
->GetFormatPrecision();
1797 return pFormatScanner
->GetStandardPrec();
1800 sal_uInt16
SvNumberFormatter::GetFormatIntegerDigits( sal_uInt32 nFormat
) const
1802 const SvNumberformat
* pFormat
= GetFormatEntry( nFormat
);
1804 return pFormat
->GetFormatIntegerDigits();
1809 sal_Unicode
SvNumberFormatter::GetDecSep() const
1811 return GetNumDecimalSep()[0];
1814 OUString
SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat
) const
1816 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
1817 if ( !pFormat
|| pFormat
->GetLanguage() == ActLnge
)
1819 return GetNumDecimalSep();
1822 LanguageType eSaveLang
= xLocaleData
.getCurrentLanguage();
1823 if ( pFormat
->GetLanguage() == eSaveLang
)
1825 aRet
= xLocaleData
->getNumDecimalSep();
1829 LanguageTag
aSaveLocale( xLocaleData
->getLanguageTag() );
1830 const_cast<SvNumberFormatter
*>(this)->xLocaleData
.changeLocale( LanguageTag( pFormat
->GetLanguage()) );
1831 aRet
= xLocaleData
->getNumDecimalSep();
1832 const_cast<SvNumberFormatter
*>(this)->xLocaleData
.changeLocale( aSaveLocale
);
1838 sal_uInt32
SvNumberFormatter::GetFormatSpecialInfo( const OUString
& rFormatString
,
1839 bool& bThousand
, bool& IsRed
, sal_uInt16
& nPrecision
,
1840 sal_uInt16
& nAnzLeading
, LanguageType eLnge
)
1843 if (eLnge
== LANGUAGE_DONTKNOW
)
1847 ChangeIntl(eLnge
); // change locale if necessary
1849 OUString
aTmpStr( rFormatString
);
1850 sal_Int32 nCheckPos
= 0;
1851 boost::scoped_ptr
<SvNumberformat
> pFormat(new SvNumberformat( aTmpStr
, pFormatScanner
,
1852 pStringScanner
, nCheckPos
, eLnge
));
1853 if ( nCheckPos
== 0 )
1855 pFormat
->GetFormatSpecialInfo( bThousand
, IsRed
, nPrecision
, nAnzLeading
);
1861 nPrecision
= pFormatScanner
->GetStandardPrec();
1868 inline sal_uInt32
SetIndexTable( NfIndexTableOffset nTabOff
, sal_uInt32 nIndOff
)
1870 osl::MutexGuard
aGuard(&theIndexTable
.maMtx
);
1872 if (!theIndexTable
.mbInitialized
)
1874 DBG_ASSERT(theIndexTable
.maData
[nTabOff
] == NUMBERFORMAT_ENTRY_NOT_FOUND
,
1875 "SetIndexTable: theIndexTable[nTabOff] already occupied" );
1876 theIndexTable
.maData
[nTabOff
] = nIndOff
;
1882 sal_Int32
SvNumberFormatter::ImpGetFormatCodeIndex(
1883 ::com::sun::star::uno::Sequence
< ::com::sun::star::i18n::NumberFormatCode
>& rSeq
,
1884 const NfIndexTableOffset nTabOff
)
1886 const sal_Int32 nLen
= rSeq
.getLength();
1887 for ( sal_Int32 j
=0; j
<nLen
; j
++ )
1889 if ( rSeq
[j
].Index
== nTabOff
)
1892 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff
< NF_CURRENCY_START
1893 || NF_CURRENCY_END
< nTabOff
|| nTabOff
== NF_CURRENCY_1000INT
1894 || nTabOff
== NF_CURRENCY_1000INT_RED
1895 || nTabOff
== NF_CURRENCY_1000DEC2_CCC
))
1896 { // currency entries with decimals might not exist, e.g. Italian Lira
1897 OUString
aMsg( "SvNumberFormatter::ImpGetFormatCodeIndex: not found: " );
1898 aMsg
+= OUString::number( nTabOff
);
1899 LocaleDataWrapper::outputCheckMessage( xLocaleData
->appendLocaleInfo(aMsg
));
1904 // look for a preset default
1905 for ( j
=0; j
<nLen
; j
++ )
1907 if ( rSeq
[j
].Default
)
1910 // currencies are special, not all format codes must exist, but all
1911 // builtin number format key index positions must have a format assigned
1912 if ( NF_CURRENCY_START
<= nTabOff
&& nTabOff
<= NF_CURRENCY_END
)
1914 // look for a format with decimals
1915 for ( j
=0; j
<nLen
; j
++ )
1917 if ( rSeq
[j
].Index
== NF_CURRENCY_1000DEC2
)
1920 // last resort: look for a format without decimals
1921 for ( j
=0; j
<nLen
; j
++ )
1923 if ( rSeq
[j
].Index
== NF_CURRENCY_1000INT
)
1929 { // we need at least _some_ format
1931 rSeq
[0] = ::com::sun::star::i18n::NumberFormatCode();
1932 rSeq
[0].Code
= OUStringBuffer().
1934 append(GetNumDecimalSep()).
1935 append("############").
1936 makeStringAndClear();
1942 sal_Int32
SvNumberFormatter::ImpAdjustFormatCodeDefault(
1943 ::com::sun::star::i18n::NumberFormatCode
* pFormatArr
,
1944 sal_Int32 nCnt
, bool bCheckCorrectness
)
1946 using namespace ::com::sun::star
;
1950 if (bCheckCorrectness
&& LocaleDataWrapper::areChecksEnabled())
1952 // check the locale data for correctness
1954 sal_Int32 nElem
, nShort
, nMedium
, nLong
, nShortDef
, nMediumDef
, nLongDef
;
1955 nShort
= nMedium
= nLong
= nShortDef
= nMediumDef
= nLongDef
= -1;
1956 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
1958 switch ( pFormatArr
[nElem
].Type
)
1960 case i18n::KNumberFormatType::SHORT
:
1963 case i18n::KNumberFormatType::MEDIUM
:
1966 case i18n::KNumberFormatType::LONG
:
1970 aMsg
.append("unknown type");
1972 if ( pFormatArr
[nElem
].Default
)
1974 switch ( pFormatArr
[nElem
].Type
)
1976 case i18n::KNumberFormatType::SHORT
:
1977 if ( nShortDef
!= -1 )
1978 aMsg
.append("dupe short type default");
1981 case i18n::KNumberFormatType::MEDIUM
:
1982 if ( nMediumDef
!= -1 )
1983 aMsg
.append("dupe medium type default");
1986 case i18n::KNumberFormatType::LONG
:
1987 if ( nLongDef
!= -1 )
1988 aMsg
.append("dupe long type default");
1993 if (!aMsg
.isEmpty())
1995 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
1996 aMsg
.append("\nXML locale data FormatElement formatindex: ");
1997 aMsg
.append(static_cast<sal_Int32
>(pFormatArr
[nElem
].Index
));
1998 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(),
1999 RTL_TEXTENCODING_ASCII_US
));
2000 LocaleDataWrapper::outputCheckMessage(xLocaleData
->appendLocaleInfo(aUMsg
));
2003 if ( nShort
!= -1 && nShortDef
== -1 )
2004 aMsg
.append("no short type default ");
2005 if ( nMedium
!= -1 && nMediumDef
== -1 )
2006 aMsg
.append("no medium type default ");
2007 if ( nLong
!= -1 && nLongDef
== -1 )
2008 aMsg
.append("no long type default ");
2009 if (!aMsg
.isEmpty())
2011 aMsg
.insert(0, "SvNumberFormatter::ImpAdjustFormatCodeDefault: ");
2012 aMsg
.append("\nXML locale data FormatElement group of: ");
2013 OUString
aUMsg(OStringToOUString(aMsg
.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US
));
2014 LocaleDataWrapper::outputCheckMessage(
2015 xLocaleData
->appendLocaleInfo(aUMsg
+ pFormatArr
[0].NameID
));
2018 // find the default (medium preferred, then long) and reset all other defaults
2019 sal_Int32 nElem
, nDef
, nMedium
;
2020 nDef
= nMedium
= -1;
2021 for ( nElem
= 0; nElem
< nCnt
; nElem
++ )
2023 if ( pFormatArr
[nElem
].Default
)
2025 switch ( pFormatArr
[nElem
].Type
)
2027 case i18n::KNumberFormatType::MEDIUM
:
2028 nDef
= nMedium
= nElem
;
2030 case i18n::KNumberFormatType::LONG
:
2031 if ( nMedium
== -1 )
2037 pFormatArr
[nElem
].Default
= false;
2043 pFormatArr
[nDef
].Default
= true;
2047 SvNumberformat
* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey
)
2049 SvNumberFormatTable::iterator it
= aFTable
.find( nKey
);
2050 if (it
!= aFTable
.end())
2055 const SvNumberformat
* SvNumberFormatter::GetFormatEntry( sal_uInt32 nKey
) const
2057 return GetEntry( nKey
);
2060 const SvNumberformat
* SvNumberFormatter::GetEntry( sal_uInt32 nKey
) const
2062 SvNumberFormatTable::const_iterator it
= aFTable
.find( nKey
);
2063 if (it
!= aFTable
.end())
2068 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset
, bool bNoAdditionalFormats
)
2070 using namespace ::com::sun::star
;
2073 osl::MutexGuard
aGuard(&theIndexTable
.maMtx
);
2074 if (!theIndexTable
.mbInitialized
)
2076 for ( sal_uInt16 j
=0; j
<NF_INDEX_TABLE_ENTRIES
; j
++ )
2078 theIndexTable
.maData
[j
] = NUMBERFORMAT_ENTRY_NOT_FOUND
;
2083 bool bOldConvertMode
= pFormatScanner
->GetConvertMode();
2084 if (bOldConvertMode
)
2086 pFormatScanner
->SetConvertMode(false); // switch off for this function
2089 NumberFormatCodeWrapper
aNumberFormatCode( m_xContext
,
2090 GetLanguageTag().getLocale() );
2091 SvNumberformat
* pNewFormat
= NULL
;
2095 // Counter for additional builtin formats not fitting into the first 10
2096 // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2097 // Has to be incremented on each ImpInsertNewStandardformat, new formats
2098 // must be appended, not inserted!
2099 sal_uInt16 nNewExtended
= ZF_STANDARD_NEWEXTENDED
;
2102 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
=
2103 aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER
);
2104 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2107 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_STANDARD
);
2108 SvNumberformat
* pStdFormat
= ImpInsertFormat( aFormatSeq
[nIdx
],
2109 CLOffset
+ SetIndexTable( NF_NUMBER_STANDARD
, ZF_STANDARD
));
2112 // This is _the_ standard format.
2113 if (LocaleDataWrapper::areChecksEnabled() && pStdFormat
->GetType() != css::util::NumberFormat::NUMBER
)
2115 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2116 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2118 pStdFormat
->SetType( css::util::NumberFormat::NUMBER
);
2119 pStdFormat
->SetStandard();
2120 pStdFormat
->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE
);
2124 if (LocaleDataWrapper::areChecksEnabled())
2126 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
2127 appendLocaleInfo( "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2132 OUString aFormatCode
= pFormatScanner
->GetBooleanString();
2133 sal_Int32 nCheckPos
= 0;
2135 pNewFormat
= new SvNumberformat( aFormatCode
, pFormatScanner
,
2136 pStringScanner
, nCheckPos
, ActLnge
);
2137 pNewFormat
->SetType(css::util::NumberFormat::LOGICAL
);
2138 pNewFormat
->SetStandard();
2139 if ( !aFTable
.insert(make_pair(
2140 CLOffset
+ SetIndexTable( NF_BOOLEAN
, ZF_STANDARD_LOGICAL
),
2141 pNewFormat
)).second
)
2143 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Boolean");
2149 pNewFormat
= new SvNumberformat( aFormatCode
, pFormatScanner
,
2150 pStringScanner
, nCheckPos
, ActLnge
);
2151 pNewFormat
->SetType(css::util::NumberFormat::TEXT
);
2152 pNewFormat
->SetStandard();
2153 if ( !aFTable
.insert(make_pair(
2154 CLOffset
+ SetIndexTable( NF_TEXT
, ZF_STANDARD_TEXT
),
2155 pNewFormat
)).second
)
2157 SAL_WARN( "svl.numbers", "SvNumberFormatter::ImpGenerateFormats: dup position Text");
2164 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_INT
);
2165 ImpInsertFormat( aFormatSeq
[nIdx
],
2166 CLOffset
+ SetIndexTable( NF_NUMBER_INT
, ZF_STANDARD
+1 ));
2169 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_DEC2
);
2170 ImpInsertFormat( aFormatSeq
[nIdx
],
2171 CLOffset
+ SetIndexTable( NF_NUMBER_DEC2
, ZF_STANDARD
+2 ));
2174 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000INT
);
2175 ImpInsertFormat( aFormatSeq
[nIdx
],
2176 CLOffset
+ SetIndexTable( NF_NUMBER_1000INT
, ZF_STANDARD
+3 ));
2179 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_1000DEC2
);
2180 ImpInsertFormat( aFormatSeq
[nIdx
],
2181 CLOffset
+ SetIndexTable( NF_NUMBER_1000DEC2
, ZF_STANDARD
+4 ));
2183 // #.##0,00 System country/language dependent
2184 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_NUMBER_SYSTEM
);
2185 ImpInsertFormat( aFormatSeq
[nIdx
],
2186 CLOffset
+ SetIndexTable( NF_NUMBER_SYSTEM
, ZF_STANDARD
+5 ));
2190 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER
);
2191 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2194 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_INT
);
2195 ImpInsertFormat( aFormatSeq
[nIdx
],
2196 CLOffset
+ SetIndexTable( NF_PERCENT_INT
, ZF_STANDARD_PERCENT
));
2199 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_PERCENT_DEC2
);
2200 ImpInsertFormat( aFormatSeq
[nIdx
],
2201 CLOffset
+ SetIndexTable( NF_PERCENT_DEC2
, ZF_STANDARD_PERCENT
+1 ));
2205 // Currency. NO default standard option! Default is determined of locale
2206 // data default currency and format is generated if needed.
2207 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
);
2208 if (LocaleDataWrapper::areChecksEnabled())
2210 // though no default desired here, test for correctness of locale data
2211 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2215 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT
);
2216 bDefault
= aFormatSeq
[nIdx
].Default
;
2217 aFormatSeq
[nIdx
].Default
= false;
2218 ImpInsertFormat( aFormatSeq
[nIdx
],
2219 CLOffset
+ SetIndexTable( NF_CURRENCY_1000INT
, ZF_STANDARD_CURRENCY
));
2220 aFormatSeq
[nIdx
].Default
= bDefault
;
2223 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2
);
2224 bDefault
= aFormatSeq
[nIdx
].Default
;
2225 aFormatSeq
[nIdx
].Default
= false;
2226 ImpInsertFormat( aFormatSeq
[nIdx
],
2227 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2
, ZF_STANDARD_CURRENCY
+1 ));
2228 aFormatSeq
[nIdx
].Default
= bDefault
;
2230 // #,##0 negative red
2231 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000INT_RED
);
2232 bDefault
= aFormatSeq
[nIdx
].Default
;
2233 aFormatSeq
[nIdx
].Default
= false;
2234 ImpInsertFormat( aFormatSeq
[nIdx
],
2235 CLOffset
+ SetIndexTable( NF_CURRENCY_1000INT_RED
, ZF_STANDARD_CURRENCY
+2 ));
2236 aFormatSeq
[nIdx
].Default
= bDefault
;
2238 // #,##0.00 negative red
2239 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_RED
);
2240 bDefault
= aFormatSeq
[nIdx
].Default
;
2241 aFormatSeq
[nIdx
].Default
= false;
2242 ImpInsertFormat( aFormatSeq
[nIdx
],
2243 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2_RED
, ZF_STANDARD_CURRENCY
+3 ));
2244 aFormatSeq
[nIdx
].Default
= bDefault
;
2247 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_CCC
);
2248 bDefault
= aFormatSeq
[nIdx
].Default
;
2249 aFormatSeq
[nIdx
].Default
= false;
2250 ImpInsertFormat( aFormatSeq
[nIdx
],
2251 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2_CCC
, ZF_STANDARD_CURRENCY
+4 ));
2252 aFormatSeq
[nIdx
].Default
= bDefault
;
2255 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_CURRENCY_1000DEC2_DASHED
);
2256 bDefault
= aFormatSeq
[nIdx
].Default
;
2257 aFormatSeq
[nIdx
].Default
= false;
2258 ImpInsertFormat( aFormatSeq
[nIdx
],
2259 CLOffset
+ SetIndexTable( NF_CURRENCY_1000DEC2_DASHED
, ZF_STANDARD_CURRENCY
+5 ));
2260 aFormatSeq
[nIdx
].Default
= bDefault
;
2265 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::DATE
);
2266 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2269 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_SHORT
);
2270 ImpInsertFormat( aFormatSeq
[nIdx
],
2271 CLOffset
+ SetIndexTable( NF_DATE_SYSTEM_SHORT
, ZF_STANDARD_DATE
));
2274 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DEF_NNDDMMMYY
);
2275 ImpInsertFormat( aFormatSeq
[nIdx
],
2276 CLOffset
+ SetIndexTable( NF_DATE_DEF_NNDDMMMYY
, ZF_STANDARD_DATE
+1 ));
2278 // DD.MM.YY def/System
2279 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_MMYY
);
2280 ImpInsertFormat( aFormatSeq
[nIdx
],
2281 CLOffset
+ SetIndexTable( NF_DATE_SYS_MMYY
, ZF_STANDARD_DATE
+2 ));
2284 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMM
);
2285 ImpInsertFormat( aFormatSeq
[nIdx
],
2286 CLOffset
+ SetIndexTable( NF_DATE_SYS_DDMMM
, ZF_STANDARD_DATE
+3 ));
2289 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_MMMM
);
2290 ImpInsertFormat( aFormatSeq
[nIdx
],
2291 CLOffset
+ SetIndexTable( NF_DATE_MMMM
, ZF_STANDARD_DATE
+4 ));
2294 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_QQJJ
);
2295 ImpInsertFormat( aFormatSeq
[nIdx
],
2296 CLOffset
+ SetIndexTable( NF_DATE_QQJJ
, ZF_STANDARD_DATE
+5 ));
2298 // DD.MM.YYYY was DD.MM.[YY]YY
2299 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYYYY
);
2300 ImpInsertFormat( aFormatSeq
[nIdx
],
2301 CLOffset
+ SetIndexTable( NF_DATE_SYS_DDMMYYYY
, ZF_STANDARD_DATE
+6 ));
2303 // DD.MM.YY def/System
2304 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DDMMYY
);
2305 ImpInsertFormat( aFormatSeq
[nIdx
],
2306 CLOffset
+ SetIndexTable( NF_DATE_SYS_DDMMYY
, ZF_STANDARD_DATE
+7 ));
2308 // NNN, D. MMMM YYYY System
2309 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2310 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYSTEM_LONG
);
2311 ImpInsertFormat( aFormatSeq
[nIdx
],
2312 CLOffset
+ SetIndexTable( NF_DATE_SYSTEM_LONG
, ZF_STANDARD_DATE
+8 ));
2314 // Hard coded but system (regional settings) delimiters dependent long date formats
2316 // D. MMM YY def/System
2317 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYY
);
2318 ImpInsertFormat( aFormatSeq
[nIdx
],
2319 CLOffset
+ SetIndexTable( NF_DATE_SYS_DMMMYY
, ZF_STANDARD_DATE
+9 ));
2321 //! Unfortunately TLOT intended only 10 builtin formats per category, more
2322 //! would overwrite the next category (ZF_STANDARD_TIME) :-((
2323 //! Therefore they are inserted with nNewExtended++ (which is also limited)
2325 // D. MMM YYYY def/System
2326 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMYYYY
);
2327 ImpInsertFormat( aFormatSeq
[nIdx
],
2328 CLOffset
+ SetIndexTable( NF_DATE_SYS_DMMMYYYY
, nNewExtended
++ ));
2330 // D. MMMM YYYY def/System
2331 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_DMMMMYYYY
);
2332 ImpInsertFormat( aFormatSeq
[nIdx
],
2333 CLOffset
+ SetIndexTable( NF_DATE_SYS_DMMMMYYYY
, nNewExtended
++ ));
2335 // NN, D. MMM YY def/System
2336 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMYY
);
2337 ImpInsertFormat( aFormatSeq
[nIdx
],
2338 CLOffset
+ SetIndexTable( NF_DATE_SYS_NNDMMMYY
, nNewExtended
++ ));
2340 // NN, D. MMMM YYYY def/System
2341 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNDMMMMYYYY
);
2342 ImpInsertFormat( aFormatSeq
[nIdx
],
2343 CLOffset
+ SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY
, nNewExtended
++ ));
2345 // NNN, D. MMMM YYYY def/System
2346 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_SYS_NNNNDMMMMYYYY
);
2347 ImpInsertFormat( aFormatSeq
[nIdx
],
2348 CLOffset
+ SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY
, nNewExtended
++ ));
2350 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2352 // D. MMM. YYYY DIN/EN
2353 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMYYYY
);
2354 ImpInsertFormat( aFormatSeq
[nIdx
],
2355 CLOffset
+ SetIndexTable( NF_DATE_DIN_DMMMYYYY
, nNewExtended
++ ));
2357 // D. MMMM YYYY DIN/EN
2358 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_DMMMMYYYY
);
2359 ImpInsertFormat( aFormatSeq
[nIdx
],
2360 CLOffset
+ SetIndexTable( NF_DATE_DIN_DMMMMYYYY
, nNewExtended
++ ));
2363 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_MMDD
);
2364 ImpInsertFormat( aFormatSeq
[nIdx
],
2365 CLOffset
+ SetIndexTable( NF_DATE_DIN_MMDD
, nNewExtended
++ ));
2368 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYMMDD
);
2369 ImpInsertFormat( aFormatSeq
[nIdx
],
2370 CLOffset
+ SetIndexTable( NF_DATE_DIN_YYMMDD
, nNewExtended
++ ));
2372 // YYYY-MM-DD DIN/EN
2373 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATE_DIN_YYYYMMDD
);
2374 ImpInsertFormat( aFormatSeq
[nIdx
],
2375 CLOffset
+ SetIndexTable( NF_DATE_DIN_YYYYMMDD
, nNewExtended
++ ));
2380 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::TIME
);
2381 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2384 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMM
);
2385 ImpInsertFormat( aFormatSeq
[nIdx
],
2386 CLOffset
+ SetIndexTable( NF_TIME_HHMM
, ZF_STANDARD_TIME
));
2389 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSS
);
2390 ImpInsertFormat( aFormatSeq
[nIdx
],
2391 CLOffset
+ SetIndexTable( NF_TIME_HHMMSS
, ZF_STANDARD_TIME
+1 ));
2394 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMAMPM
);
2395 ImpInsertFormat( aFormatSeq
[nIdx
],
2396 CLOffset
+ SetIndexTable( NF_TIME_HHMMAMPM
, ZF_STANDARD_TIME
+2 ));
2399 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HHMMSSAMPM
);
2400 ImpInsertFormat( aFormatSeq
[nIdx
],
2401 CLOffset
+ SetIndexTable( NF_TIME_HHMMSSAMPM
, ZF_STANDARD_TIME
+3 ));
2404 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS
);
2405 ImpInsertFormat( aFormatSeq
[nIdx
],
2406 CLOffset
+ SetIndexTable( NF_TIME_HH_MMSS
, ZF_STANDARD_TIME
+4 ));
2409 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_MMSS00
);
2410 ImpInsertFormat( aFormatSeq
[nIdx
],
2411 CLOffset
+ SetIndexTable( NF_TIME_MMSS00
, ZF_STANDARD_TIME
+5 ));
2414 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_TIME_HH_MMSS00
);
2415 ImpInsertFormat( aFormatSeq
[nIdx
],
2416 CLOffset
+ SetIndexTable( NF_TIME_HH_MMSS00
, ZF_STANDARD_TIME
+6 ));
2421 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME
);
2422 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2424 // DD.MM.YY HH:MM System
2425 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYSTEM_SHORT_HHMM
);
2426 ImpInsertFormat( aFormatSeq
[nIdx
],
2427 CLOffset
+ SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM
, ZF_STANDARD_DATETIME
));
2429 // DD.MM.YYYY HH:MM:SS System
2430 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_DATETIME_SYS_DDMMYYYY_HHMMSS
);
2431 ImpInsertFormat( aFormatSeq
[nIdx
],
2432 CLOffset
+ SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, ZF_STANDARD_DATETIME
+1 ));
2436 // Scientific number
2437 aFormatSeq
= aNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER
);
2438 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), aFormatSeq
.getLength() );
2441 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E000
);
2442 ImpInsertFormat( aFormatSeq
[nIdx
],
2443 CLOffset
+ SetIndexTable( NF_SCIENTIFIC_000E000
, ZF_STANDARD_SCIENTIFIC
));
2446 nIdx
= ImpGetFormatCodeIndex( aFormatSeq
, NF_SCIENTIFIC_000E00
);
2447 ImpInsertFormat( aFormatSeq
[nIdx
],
2448 CLOffset
+ SetIndexTable( NF_SCIENTIFIC_000E00
, ZF_STANDARD_SCIENTIFIC
+1 ));
2452 // Fraction number (no default option)
2453 i18n::NumberFormatCode aSingleFormatCode
;
2454 aSingleFormatCode
.Usage
= i18n::KNumberFormatUsage::FRACTION_NUMBER
;
2457 aSingleFormatCode
.Code
= "# ?/?";
2458 ImpInsertFormat( aSingleFormatCode
,
2459 CLOffset
+ SetIndexTable( NF_FRACTION_1
, ZF_STANDARD_FRACTION
));
2462 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2463 aSingleFormatCode
.Code
= "# ?\?/?\?";
2464 ImpInsertFormat( aSingleFormatCode
,
2465 CLOffset
+ SetIndexTable( NF_FRACTION_2
, ZF_STANDARD_FRACTION
+1 ));
2468 aSingleFormatCode
.Code
= "# ?/4";
2469 ImpInsertFormat( aSingleFormatCode
,
2470 CLOffset
+ SetIndexTable( NF_FRACTION_3
, ZF_STANDARD_FRACTION
+2 ));
2473 aSingleFormatCode
.Code
= "# ?\?/100";
2474 ImpInsertFormat( aSingleFormatCode
,
2475 CLOffset
+ SetIndexTable( NF_FRACTION_4
, ZF_STANDARD_FRACTION
+3 ));
2479 // Week of year must be appended here because of nNewExtended
2480 const NfKeywordTable
& rKeyword
= pFormatScanner
->GetKeywords();
2481 aSingleFormatCode
.Code
= rKeyword
[NF_KEY_WW
];
2482 ImpInsertFormat( aSingleFormatCode
,
2483 CLOffset
+ SetIndexTable( NF_DATE_WW
, nNewExtended
++ ));
2486 osl::MutexGuard
aGuard(&theIndexTable
.maMtx
);
2487 theIndexTable
.mbInitialized
= true;
2489 SAL_WARN_IF( nNewExtended
> ZF_STANDARD_NEWEXTENDEDMAX
, "svl.numbers",
2490 "ImpGenerateFormats: overflow of nNewExtended standard formats" );
2491 assert( nNewExtended
<= ZF_STANDARD_NEWEXTENDEDMAX
);
2493 // Now all additional format codes provided by I18N, but only if not
2494 // changing SystemCL, then they are appended last after user defined.
2495 if ( !bNoAdditionalFormats
)
2497 ImpGenerateAdditionalFormats( CLOffset
, aNumberFormatCode
, false );
2499 if (bOldConvertMode
)
2501 pFormatScanner
->SetConvertMode(true);
2506 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset
,
2507 NumberFormatCodeWrapper
& rNumberFormatCode
, bool bAfterChangingSystemCL
)
2509 using namespace ::com::sun::star
;
2511 SvNumberformat
* pStdFormat
= GetFormatEntry( CLOffset
+ ZF_STANDARD
);
2514 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: no GENERAL format" );
2517 sal_uInt32 nPos
= CLOffset
+ pStdFormat
->GetLastInsertKey();
2518 rNumberFormatCode
.setLocale( GetLanguageTag().getLocale() );
2521 // All currencies, this time with [$...] which was stripped in
2522 // ImpGenerateFormats for old "automatic" currency formats.
2523 uno::Sequence
< i18n::NumberFormatCode
> aFormatSeq
=
2524 rNumberFormatCode
.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY
);
2525 i18n::NumberFormatCode
* pFormatArr
= aFormatSeq
.getArray();
2526 sal_Int32 nCodes
= aFormatSeq
.getLength();
2527 ImpAdjustFormatCodeDefault( aFormatSeq
.getArray(), nCodes
);
2528 for ( j
= 0; j
< nCodes
; j
++ )
2530 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2532 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2535 if ( pFormatArr
[j
].Index
< NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
&&
2536 pFormatArr
[j
].Index
!= NF_CURRENCY_1000DEC2_CCC
)
2537 { // Insert only if not already inserted, but internal index must be
2538 // above so ImpInsertFormat can distinguish it.
2539 sal_Int16 nOrgIndex
= pFormatArr
[j
].Index
;
2540 pFormatArr
[j
].Index
= sal::static_int_cast
< sal_Int16
>(
2541 pFormatArr
[j
].Index
+ nCodes
+ NF_INDEX_TABLE_ENTRIES
);
2542 //! no default on currency
2543 bool bDefault
= aFormatSeq
[j
].Default
;
2544 aFormatSeq
[j
].Default
= false;
2545 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat( pFormatArr
[j
], nPos
+1,
2546 bAfterChangingSystemCL
, nOrgIndex
) )
2548 pNewFormat
->SetAdditionalBuiltin();
2551 pFormatArr
[j
].Index
= nOrgIndex
;
2552 aFormatSeq
[j
].Default
= bDefault
;
2556 // All additional format codes provided by I18N that are not old standard
2557 // index. Additional formats may define defaults, currently there is no
2558 // check if more than one default of a usage/type combination is provided,
2559 // like it is done for usage groups with ImpAdjustFormatCodeDefault().
2560 // There is no harm though, on first invocation ImpGetDefaultFormat() will
2561 // use the first default encountered.
2562 aFormatSeq
= rNumberFormatCode
.getAllFormatCodes();
2563 nCodes
= aFormatSeq
.getLength();
2566 pFormatArr
= aFormatSeq
.getArray();
2567 for ( j
= 0; j
< nCodes
; j
++ )
2569 if ( nPos
- CLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2571 SAL_WARN( "svl.numbers", "ImpGenerateAdditionalFormats: too many formats" );
2574 if ( pFormatArr
[j
].Index
>= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
)
2576 if ( SvNumberformat
* pNewFormat
= ImpInsertFormat( pFormatArr
[j
], nPos
+1,
2577 bAfterChangingSystemCL
) )
2579 pNewFormat
->SetAdditionalBuiltin();
2586 pStdFormat
->SetLastInsertKey( (sal_uInt16
)(nPos
- CLOffset
) );
2590 void SvNumberFormatter::ImpGetPosCurrFormat(OUStringBuffer
& sPosStr
, const OUString
& rCurrSymbol
)
2592 NfCurrencyEntry::CompletePositiveFormatString( sPosStr
,
2593 rCurrSymbol
, xLocaleData
->getCurrPositiveFormat() );
2596 void SvNumberFormatter::ImpGetNegCurrFormat(OUStringBuffer
& sNegStr
, const OUString
& rCurrSymbol
)
2598 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
,
2599 rCurrSymbol
, xLocaleData
->getCurrNegativeFormat() );
2602 sal_Int32
SvNumberFormatter::ImpPosToken ( const OUStringBuffer
& sFormat
, sal_Unicode token
, sal_Int32 nStartPos
/* = 0*/ )
2604 sal_Int32 nLength
= sFormat
.getLength();
2605 for ( sal_Int32 i
=nStartPos
; i
<nLength
&& i
>=0 ; i
++ )
2609 case '\"' : // skip text
2610 i
= sFormat
.indexOf('\"',i
+1);
2612 case '[' : // skip condition
2613 i
= sFormat
.indexOf(']',i
+1);
2615 case '\\' : // skip escaped character
2625 return i
; // if 'E' is outside "" and [] it must be the 'E' exponent
2635 OUString
SvNumberFormatter::GenerateFormat(sal_uInt32 nIndex
,
2639 sal_uInt16 nPrecision
,
2640 sal_uInt16 nLeadingZeros
)
2642 if (eLnge
== LANGUAGE_DONTKNOW
)
2646 short eType
= GetType(nIndex
);
2648 ImpGenerateCL(eLnge
); // create new standard formats if necessary
2650 utl::DigitGroupingIterator
aGrouping( xLocaleData
->getDigitGrouping());
2651 // always group of 3 for Engineering notation
2652 const sal_Int32 nDigitsInFirstGroup
= ( bThousand
&& (eType
== css::util::NumberFormat::SCIENTIFIC
) ) ? 3 : aGrouping
.get();
2653 const OUString
& rThSep
= GetNumThousandSep();
2655 SvNumberformat
* pFormat
= GetFormatEntry( nIndex
);
2657 OUStringBuffer sString
;
2658 using comphelper::string::padToLength
;
2660 if (nLeadingZeros
== 0)
2663 sString
.append('#');
2666 if (eType
== css::util::NumberFormat::SCIENTIFIC
)
2667 { // for scientific, bThousand is used for Engineering notation
2668 sString
.append("###");
2672 sString
.append('#');
2673 sString
.append(rThSep
);
2674 padToLength(sString
, sString
.getLength() + nDigitsInFirstGroup
, '#');
2680 for (i
= 0; i
< nLeadingZeros
; i
++)
2682 if (bThousand
&& i
> 0 && i
== aGrouping
.getPos())
2684 sString
.insert(0, rThSep
);
2685 aGrouping
.advance();
2687 sString
.insert(0, '0');
2691 sal_Int32 nDigits
= (eType
== css::util::NumberFormat::SCIENTIFIC
) ? 3*((nLeadingZeros
-1)/3 + 1) : nDigitsInFirstGroup
+ 1;
2692 for (i
= nLeadingZeros
; i
< nDigits
; i
++)
2694 if ( i
% nDigitsInFirstGroup
== 0 )
2695 sString
.insert(0, rThSep
);
2696 sString
.insert(0, '#');
2702 sString
.append(GetNumDecimalSep());
2703 padToLength(sString
, sString
.getLength() + nPrecision
, '0');
2705 if (eType
== css::util::NumberFormat::PERCENT
)
2707 sString
.append('%');
2709 else if (eType
== css::util::NumberFormat::SCIENTIFIC
)
2711 OUStringBuffer sOldFormatString
= pFormat
->GetFormatstring();
2712 sal_Int32 nIndexE
= ImpPosToken( sOldFormatString
, 'E' );
2715 sal_Int32 nIndexSep
= ImpPosToken( sOldFormatString
, ';', nIndexE
);
2716 if (nIndexSep
> nIndexE
)
2717 sString
.append( sOldFormatString
.copy(nIndexE
, nIndexSep
- nIndexE
) );
2719 sString
.append( sOldFormatString
.copy(nIndexE
) );
2722 else if (eType
== css::util::NumberFormat::CURRENCY
)
2724 OUStringBuffer
sNegStr(sString
);
2726 const NfCurrencyEntry
* pEntry
;
2728 if ( GetNewCurrencySymbolString( nIndex
, aCurr
, &pEntry
, &bBank
) )
2732 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
2733 xLocaleData
->getCurrPositiveFormat(),
2734 pEntry
->GetPositiveFormat(), bBank
);
2735 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
2736 xLocaleData
->getCurrNegativeFormat(),
2737 pEntry
->GetNegativeFormat(), bBank
);
2738 pEntry
->CompletePositiveFormatString( sString
, bBank
, nPosiForm
);
2739 pEntry
->CompleteNegativeFormatString( sNegStr
, bBank
, nNegaForm
);
2742 { // assume currency abbreviation (AKA banking symbol), not symbol
2743 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat(
2744 xLocaleData
->getCurrPositiveFormat(),
2745 xLocaleData
->getCurrPositiveFormat(), true );
2746 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat(
2747 xLocaleData
->getCurrNegativeFormat(),
2748 xLocaleData
->getCurrNegativeFormat(), true );
2749 NfCurrencyEntry::CompletePositiveFormatString( sString
, aCurr
, nPosiForm
);
2750 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr
, aCurr
, nNegaForm
);
2754 { // "automatic" old style
2755 OUString aSymbol
, aAbbrev
;
2756 GetCompatibilityCurrency( aSymbol
, aAbbrev
);
2757 ImpGetPosCurrFormat( sString
, aSymbol
);
2758 ImpGetNegCurrFormat( sNegStr
, aSymbol
);
2762 sString
.append(';');
2763 sString
.append('[');
2764 sString
.append(pFormatScanner
->GetRedString());
2765 sString
.append(']');
2769 sString
.append(';');
2771 sString
.append(sNegStr
.makeStringAndClear());
2773 if (eType
!= css::util::NumberFormat::CURRENCY
)
2775 bool insertBrackets
= false;
2776 if ( eType
!= css::util::NumberFormat::UNDEFINED
)
2778 insertBrackets
= pFormat
->IsNegativeInBracket();
2780 if (IsRed
|| insertBrackets
)
2782 OUStringBuffer
sTmpStr(sString
);
2784 if ( pFormat
->HasPositiveBracketPlaceholder() )
2786 sTmpStr
.append('_');
2787 sTmpStr
.append(')');
2789 sTmpStr
.append(';');
2793 sTmpStr
.append('[');
2794 sTmpStr
.append(pFormatScanner
->GetRedString());
2795 sTmpStr
.append(']');
2800 sTmpStr
.append('(');
2801 sTmpStr
.append(sString
.toString());
2802 sTmpStr
.append(')');
2806 sTmpStr
.append('-');
2807 sTmpStr
.append(sString
.toString());
2812 return sString
.makeStringAndClear();
2815 bool SvNumberFormatter::IsUserDefined(const OUString
& sStr
,
2818 if (eLnge
== LANGUAGE_DONTKNOW
)
2822 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
2825 sal_uInt32 nKey
= ImpIsEntry(sStr
, CLOffset
, eLnge
);
2826 if (nKey
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
2830 SvNumberformat
* pEntry
= GetFormatEntry( nKey
);
2831 if ( pEntry
&& ((pEntry
->GetType() & css::util::NumberFormat::DEFINED
) != 0) )
2838 sal_uInt32
SvNumberFormatter::GetEntryKey(const OUString
& sStr
,
2841 if (eLnge
== LANGUAGE_DONTKNOW
)
2845 sal_uInt32 CLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
2846 return ImpIsEntry(sStr
, CLOffset
, eLnge
);
2849 sal_uInt32
SvNumberFormatter::GetStandardIndex(LanguageType eLnge
)
2851 if (eLnge
== LANGUAGE_DONTKNOW
)
2855 return GetStandardFormat(css::util::NumberFormat::NUMBER
, eLnge
);
2858 short SvNumberFormatter::GetType(sal_uInt32 nFIndex
)
2861 SvNumberformat
* pFormat
= GetFormatEntry( nFIndex
);
2864 eType
= css::util::NumberFormat::UNDEFINED
;
2868 eType
= pFormat
->GetType() &~css::util::NumberFormat::DEFINED
;
2871 eType
= css::util::NumberFormat::DEFINED
;
2877 void SvNumberFormatter::ClearMergeTable()
2881 pMergeTable
->clear();
2885 SvNumberFormatterIndexTable
* SvNumberFormatter::MergeFormatter(SvNumberFormatter
& rTable
)
2893 pMergeTable
= new SvNumberFormatterIndexTable
;
2896 sal_uInt32 nCLOffset
= 0;
2897 sal_uInt32 nOldKey
, nOffset
, nNewKey
;
2898 SvNumberformat
* pNewEntry
;
2900 SvNumberFormatTable::iterator it
= rTable
.aFTable
.begin();
2901 while (it
!= rTable
.aFTable
.end())
2903 SvNumberformat
* pFormat
= it
->second
;
2904 nOldKey
= it
->first
;
2905 nOffset
= nOldKey
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
2906 if (nOffset
== 0) // 1st format of CL
2908 nCLOffset
= ImpGenerateCL(pFormat
->GetLanguage());
2910 if (nOffset
<= SV_MAX_ANZ_STANDARD_FORMATE
) // Std.form.
2912 nNewKey
= nCLOffset
+ nOffset
;
2913 if (aFTable
.find( nNewKey
) == aFTable
.end()) // not already present
2915 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
2916 pNewEntry
= new SvNumberformat( *pFormat
, *pFormatScanner
);
2917 if (!aFTable
.insert(make_pair( nNewKey
, pNewEntry
)).second
)
2919 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
2923 if (nNewKey
!= nOldKey
) // new index
2925 (*pMergeTable
)[nOldKey
] = nNewKey
;
2928 else // user defined
2930 // pNewEntry = new SvNumberformat(*pFormat); // Copy is not sufficient!
2931 pNewEntry
= new SvNumberformat( *pFormat
, *pFormatScanner
);
2932 nNewKey
= ImpIsEntry(pNewEntry
->GetFormatstring(),
2934 pFormat
->GetLanguage());
2935 if (nNewKey
!= NUMBERFORMAT_ENTRY_NOT_FOUND
) // already present
2941 SvNumberformat
* pStdFormat
= GetFormatEntry(nCLOffset
+ ZF_STANDARD
);
2942 sal_uInt32 nPos
= nCLOffset
+ pStdFormat
->GetLastInsertKey();
2944 if (nNewKey
- nCLOffset
>= SV_COUNTRY_LANGUAGE_OFFSET
)
2946 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: too many formats for CL");
2949 else if (!aFTable
.insert(make_pair( nNewKey
, pNewEntry
)).second
)
2951 SAL_WARN( "svl.numbers", "SvNumberFormatter::MergeFormatter: dup position");
2956 pStdFormat
->SetLastInsertKey((sal_uInt16
) (nNewKey
- nCLOffset
));
2959 if (nNewKey
!= nOldKey
) // new index
2961 (*pMergeTable
)[nOldKey
] = nNewKey
;
2970 SvNumberFormatterMergeMap
SvNumberFormatter::ConvertMergeTableToMap()
2972 if (!HasMergeFormatTable())
2974 return SvNumberFormatterMergeMap();
2976 SvNumberFormatterMergeMap aMap
;
2977 for (SvNumberFormatterIndexTable::iterator it
= pMergeTable
->begin(); it
!= pMergeTable
->end(); ++it
)
2979 sal_uInt32 nOldKey
= it
->first
;
2980 aMap
[ nOldKey
] = it
->second
;
2987 sal_uInt32
SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat
,
2988 LanguageType eLnge
)
2990 if ( eLnge
== LANGUAGE_DONTKNOW
)
2994 if ( nFormat
< SV_COUNTRY_LANGUAGE_OFFSET
&& eLnge
== IniLnge
)
2996 return nFormat
; // it stays as it is
2998 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
2999 if ( nOffset
> SV_MAX_ANZ_STANDARD_FORMATE
)
3001 return nFormat
; // not a built-in format
3003 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3004 return nCLOffset
+ nOffset
;
3008 sal_uInt32
SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff
,
3009 LanguageType eLnge
)
3011 if (nTabOff
>= NF_INDEX_TABLE_ENTRIES
)
3012 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
3014 if (eLnge
== LANGUAGE_DONTKNOW
)
3018 osl::MutexGuard
aGuard(&theIndexTable
.maMtx
);
3019 if (theIndexTable
.maData
[nTabOff
] == NUMBERFORMAT_ENTRY_NOT_FOUND
)
3020 return NUMBERFORMAT_ENTRY_NOT_FOUND
;
3023 sal_uInt32 nCLOffset
= ImpGenerateCL(eLnge
); // create new standard formats if necessary
3026 osl::MutexGuard
aGuard(&theIndexTable
.maMtx
);
3027 return nCLOffset
+ theIndexTable
.maData
[nTabOff
];
3032 NfIndexTableOffset
SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat
) const
3034 sal_uInt32 nOffset
= nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
; // relative index
3035 if ( nOffset
> SV_MAX_ANZ_STANDARD_FORMATE
)
3037 return NF_INDEX_TABLE_ENTRIES
; // not a built-in format
3041 osl::MutexGuard
aGuard(&theIndexTable
.maMtx
);
3042 for ( sal_uInt16 j
= 0; j
< NF_INDEX_TABLE_ENTRIES
; j
++ )
3044 if (theIndexTable
.maData
[j
] == nOffset
)
3045 return (NfIndexTableOffset
) j
;
3048 return NF_INDEX_TABLE_ENTRIES
; // bad luck
3051 void SvNumberFormatter::SetEvalDateFormat( NfEvalDateFormat eEDF
)
3053 eEvalDateFormat
= eEDF
;
3056 NfEvalDateFormat
SvNumberFormatter::GetEvalDateFormat() const
3058 return eEvalDateFormat
;
3061 void SvNumberFormatter::SetYear2000( sal_uInt16 nVal
)
3063 pStringScanner
->SetYear2000( nVal
);
3067 sal_uInt16
SvNumberFormatter::GetYear2000() const
3069 return pStringScanner
->GetYear2000();
3073 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
) const
3076 return SvNumberFormatter::ExpandTwoDigitYear( nYear
,
3077 pStringScanner
->GetYear2000() );
3083 sal_uInt16
SvNumberFormatter::GetYear2000Default()
3085 return (sal_uInt16
) ::utl::MiscCfg().GetYear2000();
3090 const NfCurrencyTable
& SvNumberFormatter::GetTheCurrencyTable()
3092 ::osl::MutexGuard
aGuard( GetMutex() );
3093 while ( !bCurrencyTableInitialized
)
3094 ImpInitCurrencyTable();
3095 return theCurrencyTable::get();
3100 const NfCurrencyEntry
* SvNumberFormatter::MatchSystemCurrency()
3102 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3103 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3104 return nSystemCurrencyPosition
? &rTable
[nSystemCurrencyPosition
] : NULL
;
3109 const NfCurrencyEntry
& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang
)
3111 if ( eLang
== LANGUAGE_SYSTEM
)
3113 const NfCurrencyEntry
* pCurr
= MatchSystemCurrency();
3114 return pCurr
? *pCurr
: GetTheCurrencyTable()[0];
3118 eLang
= MsLangId::getRealLanguage( eLang
);
3119 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3120 sal_uInt16 nCount
= rTable
.size();
3121 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3123 if ( rTable
[j
].GetLanguage() == eLang
)
3132 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry(const OUString
& rAbbrev
, LanguageType eLang
)
3134 eLang
= MsLangId::getRealLanguage( eLang
);
3135 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3136 sal_uInt16 nCount
= rTable
.size();
3137 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3139 if ( rTable
[j
].GetLanguage() == eLang
&&
3140 rTable
[j
].GetBankSymbol() == rAbbrev
)
3150 const NfCurrencyEntry
* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( const OUString
& rSymbol
,
3151 const OUString
& rAbbrev
)
3153 if (!bCurrencyTableInitialized
)
3155 GetTheCurrencyTable(); // just for initialization
3157 const NfCurrencyTable
& rTable
= theLegacyOnlyCurrencyTable::get();
3158 sal_uInt16 nCount
= rTable
.size();
3159 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3161 if ( rTable
[j
].GetSymbol() == rSymbol
&&
3162 rTable
[j
].GetBankSymbol() == rAbbrev
)
3172 IMPL_STATIC_LINK_NOARG( SvNumberFormatter
, CurrencyChangeLink
)
3174 ::osl::MutexGuard
aGuard( GetMutex() );
3176 LanguageType eLang
= LANGUAGE_SYSTEM
;
3177 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev
, eLang
);
3178 SetDefaultSystemCurrency( aAbbrev
, eLang
);
3184 void SvNumberFormatter::SetDefaultSystemCurrency( const OUString
& rAbbrev
, LanguageType eLang
)
3186 ::osl::MutexGuard
aGuard( GetMutex() );
3187 if ( eLang
== LANGUAGE_SYSTEM
)
3189 eLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
3191 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3192 sal_uInt16 nCount
= rTable
.size();
3193 if ( !rAbbrev
.isEmpty() )
3195 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3197 if ( rTable
[j
].GetLanguage() == eLang
&& rTable
[j
].GetBankSymbol() == rAbbrev
)
3199 nSystemCurrencyPosition
= j
;
3206 for ( sal_uInt16 j
= 0; j
< nCount
; j
++ )
3208 if ( rTable
[j
].GetLanguage() == eLang
)
3210 nSystemCurrencyPosition
= j
;
3215 nSystemCurrencyPosition
= 0; // not found => simple SYSTEM
3219 void SvNumberFormatter::ResetDefaultSystemCurrency()
3221 nDefaultSystemCurrencyFormat
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
3225 void SvNumberFormatter::InvalidateDateAcceptancePatterns()
3227 pStringScanner
->InvalidateDateAcceptancePatterns();
3231 sal_uInt32
SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3233 if ( nDefaultSystemCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3237 NfWSStringsDtor aCurrList
;
3238 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3239 GetCurrencyEntry( LANGUAGE_SYSTEM
), false );
3240 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency System standard format?!?" );
3241 // if already loaded or user defined nDefaultSystemCurrencyFormat
3242 // will be set to the right value
3243 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3244 nDefaultSystemCurrencyFormat
, LANGUAGE_SYSTEM
);
3245 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3246 DBG_ASSERT( nDefaultSystemCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3247 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3249 return nDefaultSystemCurrencyFormat
;
3253 sal_uInt32
SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3255 sal_uInt32 CLOffset
= ImpGetCLOffset( ActLnge
);
3256 DefaultFormatKeysMap::iterator it
= aDefaultFormatKeys
.find( CLOffset
+ ZF_STANDARD_CURRENCY
);
3257 sal_uInt32 nDefaultCurrencyFormat
= (it
!= aDefaultFormatKeys
.end() ?
3258 it
->second
: NUMBERFORMAT_ENTRY_NOT_FOUND
);
3259 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3261 // look for a defined standard
3262 sal_uInt32 nStopKey
= CLOffset
+ SV_COUNTRY_LANGUAGE_OFFSET
;
3264 SvNumberFormatTable::iterator it2
= aFTable
.lower_bound( CLOffset
);
3265 while ( it2
!= aFTable
.end() && (nKey
= it2
->first
) >= CLOffset
&& nKey
< nStopKey
)
3267 const SvNumberformat
* pEntry
= it2
->second
;
3268 if ( pEntry
->IsStandard() && (pEntry
->GetType() & css::util::NumberFormat::CURRENCY
) )
3270 nDefaultCurrencyFormat
= nKey
;
3276 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3277 { // none found, create one
3279 NfWSStringsDtor aCurrList
;
3280 sal_uInt16 nDefault
= GetCurrencyFormatStrings( aCurrList
,
3281 GetCurrencyEntry( ActLnge
), false );
3282 DBG_ASSERT( aCurrList
.size(), "where is the NewCurrency standard format?" );
3283 if ( !aCurrList
.empty() )
3285 // if already loaded or user defined nDefaultSystemCurrencyFormat
3286 // will be set to the right value
3288 PutEntry( aCurrList
[ nDefault
], nCheck
, nType
,
3289 nDefaultCurrencyFormat
, ActLnge
);
3290 DBG_ASSERT( nCheck
== 0, "NewCurrency CheckError" );
3291 DBG_ASSERT( nDefaultCurrencyFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
,
3292 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3294 // old automatic currency format as a last resort
3295 if ( nDefaultCurrencyFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3296 nDefaultCurrencyFormat
= CLOffset
+ ZF_STANDARD_CURRENCY
+3;
3298 { // mark as standard so that it is found next time
3299 SvNumberformat
* pEntry
= GetFormatEntry( nDefaultCurrencyFormat
);
3301 pEntry
->SetStandard();
3304 aDefaultFormatKeys
[ CLOffset
+ ZF_STANDARD_CURRENCY
] = nDefaultCurrencyFormat
;
3306 return nDefaultCurrencyFormat
;
3311 // true: continue; false: break loop, if pFoundEntry==NULL dupe found
3312 bool SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3313 const NfCurrencyEntry
*& pFoundEntry
, bool& bFoundBank
, const NfCurrencyEntry
* pData
,
3314 sal_uInt16 nPos
, const OUString
& rSymbol
)
3317 if ( pData
->GetSymbol() == rSymbol
)
3322 else if ( pData
->GetBankSymbol() == rSymbol
)
3331 if ( pFoundEntry
&& pFoundEntry
!= pData
)
3334 return false; // break loop, not unique
3337 { // first entry is SYSTEM
3338 pFoundEntry
= MatchSystemCurrency();
3341 return false; // break loop
3342 // even if there are more matching entries
3343 // this one is probably the one we are looking for
3347 pFoundEntry
= pData
;
3352 pFoundEntry
= pData
;
3359 bool SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat
, OUString
& rStr
,
3360 const NfCurrencyEntry
** ppEntry
/* = NULL */,
3361 bool* pBank
/* = NULL */ ) const
3368 const SvNumberformat
* pFormat
= GetFormatEntry(nFormat
);
3371 OUStringBuffer
sBuff(128); // guess-estimate of a value that will pretty much guarantee no re-alloc
3372 OUString aSymbol
, aExtension
;
3373 if ( pFormat
->GetNewCurrencySymbol( aSymbol
, aExtension
) )
3377 bool bFoundBank
= false;
3378 // we definiteley need an entry matching the format code string
3379 const NfCurrencyEntry
* pFoundEntry
= GetCurrencyEntry(
3380 bFoundBank
, aSymbol
, aExtension
, pFormat
->GetLanguage(),
3384 *ppEntry
= pFoundEntry
;
3386 *pBank
= bFoundBank
;
3387 rStr
= pFoundEntry
->BuildSymbolString(bFoundBank
);
3390 if ( rStr
.isEmpty() )
3391 { // analog to BuildSymbolString
3393 if ( aSymbol
.indexOf( '-' ) != -1 ||
3394 aSymbol
.indexOf( ']' ) != -1 )
3397 sBuff
.append( aSymbol
);
3402 sBuff
.append(aSymbol
);
3404 if ( !aExtension
.isEmpty() )
3406 sBuff
.append(aExtension
);
3410 rStr
= sBuff
.toString();
3420 const NfCurrencyEntry
* SvNumberFormatter::GetCurrencyEntry( bool & bFoundBank
,
3421 const OUString
& rSymbol
,
3422 const OUString
& rExtension
,
3423 LanguageType eFormatLanguage
,
3424 bool bOnlyStringLanguage
)
3426 sal_Int32 nExtLen
= rExtension
.getLength();
3427 LanguageType eExtLang
;
3430 // rExtension should be a 16-bit hex value max FFFF which may contain a
3431 // leading "-" separator (that is not a minus sign, but toInt32 can be
3432 // used to parse it, with post-processing as necessary):
3433 sal_Int32 nExtLang
= rExtension
.toInt32( 16 );
3436 eExtLang
= LANGUAGE_DONTKNOW
;
3440 eExtLang
= (LanguageType
) ((nExtLang
< 0) ? -nExtLang
: nExtLang
);
3445 eExtLang
= LANGUAGE_DONTKNOW
;
3447 const NfCurrencyEntry
* pFoundEntry
= NULL
;
3448 const NfCurrencyTable
& rTable
= GetTheCurrencyTable();
3449 sal_uInt16 nCount
= rTable
.size();
3452 // first try with given extension language/country
3455 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3457 LanguageType eLang
= rTable
[j
].GetLanguage();
3458 if ( eLang
== eExtLang
||
3459 ((eExtLang
== LANGUAGE_DONTKNOW
) &&
3460 (eLang
== LANGUAGE_SYSTEM
)))
3462 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3463 &rTable
[j
], j
, rSymbol
);
3469 if ( pFoundEntry
|| !bCont
|| (bOnlyStringLanguage
&& nExtLen
) )
3473 if ( !bOnlyStringLanguage
)
3475 // now try the language/country of the number format
3476 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3478 LanguageType eLang
= rTable
[j
].GetLanguage();
3479 if ( eLang
== eFormatLanguage
||
3480 ((eFormatLanguage
== LANGUAGE_DONTKNOW
) &&
3481 (eLang
== LANGUAGE_SYSTEM
)))
3483 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3484 &rTable
[j
], j
, rSymbol
);
3489 if ( pFoundEntry
|| !bCont
)
3495 // then try without language/country if no extension specified
3498 for ( sal_uInt16 j
= 0; j
< nCount
&& bCont
; j
++ )
3500 bCont
= ImpLookupCurrencyEntryLoopBody( pFoundEntry
, bFoundBank
,
3501 &rTable
[j
], j
, rSymbol
);
3509 void SvNumberFormatter::GetCompatibilityCurrency( OUString
& rSymbol
, OUString
& rAbbrev
) const
3511 ::com::sun::star::uno::Sequence
< ::com::sun::star::i18n::Currency2
>
3512 xCurrencies( xLocaleData
->getAllCurrencies() );
3514 const ::com::sun::star::i18n::Currency2
*pCurrencies
= xCurrencies
.getConstArray();
3515 sal_Int32 nCurrencies
= xCurrencies
.getLength();
3518 for ( j
=0; j
< nCurrencies
; ++j
)
3520 if ( pCurrencies
[j
].UsedInCompatibleFormatCodes
)
3522 rSymbol
= pCurrencies
[j
].Symbol
;
3523 rAbbrev
= pCurrencies
[j
].BankSymbol
;
3527 if ( j
>= nCurrencies
)
3529 if (LocaleDataWrapper::areChecksEnabled())
3531 LocaleDataWrapper::outputCheckMessage( xLocaleData
->
3532 appendLocaleInfo( "GetCompatibilityCurrency: none?"));
3534 rSymbol
= xLocaleData
->getCurrSymbol();
3535 rAbbrev
= xLocaleData
->getCurrBankSymbol();
3540 static void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry
& rCurr
)
3542 switch ( rCurr
.GetPositiveFormat() )
3550 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3553 switch ( rCurr
.GetNegativeFormat() )
3573 LocaleDataWrapper::outputCheckMessage( "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3579 bool SvNumberFormatter::IsLocaleInstalled( LanguageType eLang
)
3581 // The set is initialized as a side effect of the currency table
3582 // created, make sure that exists, which usually is the case unless a
3583 // SvNumberFormatter was never instantiated.
3584 GetTheCurrencyTable();
3585 const NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
3586 return rInstalledLocales
.find( eLang
) != rInstalledLocales
.end();
3590 void SvNumberFormatter::ImpInitCurrencyTable()
3592 // Race condition possible:
3593 // ::osl::MutexGuard aGuard( GetMutex() );
3594 // while ( !bCurrencyTableInitialized )
3595 // ImpInitCurrencyTable();
3596 static bool bInitializing
= false;
3597 if ( bCurrencyTableInitialized
|| bInitializing
)
3601 bInitializing
= true;
3603 LanguageType eSysLang
= SvtSysLocale().GetLanguageTag().getLanguageType();
3604 boost::scoped_ptr
<LocaleDataWrapper
> pLocaleData(new LocaleDataWrapper(
3605 ::comphelper::getProcessComponentContext(),
3606 SvtSysLocale().GetLanguageTag() ));
3607 // get user configured currency
3608 OUString aConfiguredCurrencyAbbrev
;
3609 LanguageType eConfiguredCurrencyLanguage
= LANGUAGE_SYSTEM
;
3610 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3611 aConfiguredCurrencyAbbrev
, eConfiguredCurrencyLanguage
);
3612 sal_uInt16 nSecondarySystemCurrencyPosition
= 0;
3613 sal_uInt16 nMatchingSystemCurrencyPosition
= 0;
3614 NfCurrencyEntry
* pEntry
;
3616 // first entry is SYSTEM
3617 pEntry
= new NfCurrencyEntry( *pLocaleData
, LANGUAGE_SYSTEM
);
3618 theCurrencyTable::get().insert( theCurrencyTable::get().begin(), pEntry
);
3619 sal_uInt16 nCurrencyPos
= 1;
3621 ::com::sun::star::uno::Sequence
< ::com::sun::star::lang::Locale
> xLoc
=
3622 LocaleDataWrapper::getInstalledLocaleNames();
3623 sal_Int32 nLocaleCount
= xLoc
.getLength();
3624 SAL_INFO( "svl.numbers", "number of locales: \"" << nLocaleCount
<< "\"" );
3625 css::lang::Locale
const * const pLocales
= xLoc
.getConstArray();
3626 NfCurrencyTable
&rCurrencyTable
= theCurrencyTable::get();
3627 NfCurrencyTable
&rLegacyOnlyCurrencyTable
= theLegacyOnlyCurrencyTable::get();
3628 NfInstalledLocales
&rInstalledLocales
= theInstalledLocales::get();
3629 sal_uInt16 nLegacyOnlyCurrencyPos
= 0;
3630 for ( sal_Int32 nLocale
= 0; nLocale
< nLocaleCount
; nLocale
++ )
3632 LanguageType eLang
= LanguageTag::convertToLanguageType( pLocales
[nLocale
], false);
3633 rInstalledLocales
.insert( eLang
);
3634 pLocaleData
->setLanguageTag( LanguageTag( pLocales
[nLocale
]) );
3635 Sequence
< Currency2
> aCurrSeq
= pLocaleData
->getAllCurrencies();
3636 sal_Int32 nCurrencyCount
= aCurrSeq
.getLength();
3637 Currency2
const * const pCurrencies
= aCurrSeq
.getConstArray();
3639 // one default currency for each locale, insert first so it is found first
3641 for ( nDefault
= 0; nDefault
< nCurrencyCount
; nDefault
++ )
3643 if ( pCurrencies
[nDefault
].Default
)
3646 if ( nDefault
< nCurrencyCount
)
3648 pEntry
= new NfCurrencyEntry( pCurrencies
[nDefault
], *pLocaleData
, eLang
);
3652 pEntry
= new NfCurrencyEntry( *pLocaleData
, eLang
); // first or ShellsAndPebbles
3654 if (LocaleDataWrapper::areChecksEnabled())
3656 lcl_CheckCurrencySymbolPosition( *pEntry
);
3658 rCurrencyTable
.insert( rCurrencyTable
.begin() + nCurrencyPos
++, pEntry
);
3659 if ( !nSystemCurrencyPosition
&& !aConfiguredCurrencyAbbrev
.isEmpty() &&
3660 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
&&
3661 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
)
3663 nSystemCurrencyPosition
= nCurrencyPos
-1;
3665 if ( !nMatchingSystemCurrencyPosition
&&
3666 pEntry
->GetLanguage() == eSysLang
)
3668 nMatchingSystemCurrencyPosition
= nCurrencyPos
-1;
3670 // all remaining currencies for each locale
3671 if ( nCurrencyCount
> 1 )
3673 sal_Int32 nCurrency
;
3674 for ( nCurrency
= 0; nCurrency
< nCurrencyCount
; nCurrency
++ )
3676 if (pCurrencies
[nCurrency
].LegacyOnly
)
3678 pEntry
= new NfCurrencyEntry( pCurrencies
[nCurrency
], *pLocaleData
, eLang
);
3679 rLegacyOnlyCurrencyTable
.insert( rLegacyOnlyCurrencyTable
.begin() + nLegacyOnlyCurrencyPos
++, pEntry
);
3681 else if ( nCurrency
!= nDefault
)
3683 pEntry
= new NfCurrencyEntry( pCurrencies
[nCurrency
], *pLocaleData
, eLang
);
3685 bool bInsert
= true;
3686 sal_uInt16 n
= rCurrencyTable
.size();
3687 sal_uInt16 aCurrencyIndex
= 1; // skip first SYSTEM entry
3688 for ( sal_uInt16 j
=1; j
<n
; j
++ )
3690 if ( rCurrencyTable
[aCurrencyIndex
++] == *pEntry
)
3702 rCurrencyTable
.insert( rCurrencyTable
.begin() + nCurrencyPos
++, pEntry
);
3703 if ( !nSecondarySystemCurrencyPosition
&&
3704 (!aConfiguredCurrencyAbbrev
.isEmpty() ?
3705 pEntry
->GetBankSymbol() == aConfiguredCurrencyAbbrev
:
3706 pEntry
->GetLanguage() == eConfiguredCurrencyLanguage
) )
3708 nSecondarySystemCurrencyPosition
= nCurrencyPos
-1;
3710 if ( !nMatchingSystemCurrencyPosition
&&
3711 pEntry
->GetLanguage() == eSysLang
)
3713 nMatchingSystemCurrencyPosition
= nCurrencyPos
-1;
3720 if ( !nSystemCurrencyPosition
)
3722 nSystemCurrencyPosition
= nSecondarySystemCurrencyPosition
;
3724 if ((!aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
3725 LocaleDataWrapper::areChecksEnabled())
3727 LocaleDataWrapper::outputCheckMessage(
3728 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3730 // match SYSTEM if no configured currency found
3731 if ( !nSystemCurrencyPosition
)
3733 nSystemCurrencyPosition
= nMatchingSystemCurrencyPosition
;
3735 if ((aConfiguredCurrencyAbbrev
.isEmpty() && !nSystemCurrencyPosition
) &&
3736 LocaleDataWrapper::areChecksEnabled())
3738 LocaleDataWrapper::outputCheckMessage(
3739 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3741 pLocaleData
.reset();
3742 SvtSysLocaleOptions::SetCurrencyChangeLink( LINK( NULL
, SvNumberFormatter
, CurrencyChangeLink
) );
3743 bInitializing
= false;
3744 bCurrencyTableInitialized
= true;
3748 sal_uInt16
SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor
& rStrArr
,
3749 const NfCurrencyEntry
& rCurr
,
3752 OUString aRed
= OUStringBuffer().
3754 append(pFormatScanner
->GetRedString()).
3755 append(']').makeStringAndClear();
3757 sal_uInt16 nDefault
= 0;
3760 // Only bank symbols.
3761 OUString aPositiveBank
= rCurr
.BuildPositiveFormatString(true, *xLocaleData
, 1);
3762 OUString aNegativeBank
= rCurr
.BuildNegativeFormatString(true, *xLocaleData
, 1 );
3764 OUStringBuffer
format1(aPositiveBank
);
3765 format1
.append(';');
3766 format1
.append(aNegativeBank
);
3767 rStrArr
.push_back(format1
.makeStringAndClear());
3769 OUStringBuffer
format2(aPositiveBank
);
3770 format2
.append(';');
3772 format2
.append(aRed
);
3774 format2
.append(aNegativeBank
);
3775 rStrArr
.push_back(format2
.makeStringAndClear());
3777 nDefault
= rStrArr
.size() - 1;
3781 // Mixed formats like in SvNumberFormatter::ImpGenerateFormats() but no
3782 // duplicates if no decimals in currency.
3783 OUString aPositive
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 1);
3784 OUString aNegative
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 1 );
3785 OUStringBuffer format1
;
3786 OUStringBuffer format2
;
3787 OUStringBuffer format3
;
3788 OUStringBuffer format4
;
3789 OUStringBuffer format5
;
3790 if (rCurr
.GetDigits())
3792 OUString aPositiveNoDec
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 0);
3793 OUString aNegativeNoDec
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 0 );
3794 OUString aPositiveDashed
= rCurr
.BuildPositiveFormatString(false, *xLocaleData
, 2);
3795 OUString aNegativeDashed
= rCurr
.BuildNegativeFormatString(false, *xLocaleData
, 2);
3797 format1
.append(aPositiveNoDec
);
3798 format1
.append(';');
3799 format1
.append(aNegativeNoDec
);
3801 format3
.append(aPositiveNoDec
);
3802 format3
.append(';');
3803 format3
.append(aRed
);
3804 format3
.append(aNegativeNoDec
);
3806 format5
.append(aPositiveDashed
);
3807 format5
.append(';');
3808 format5
.append(aRed
);
3809 format5
.append(aNegativeDashed
);
3812 format2
.append(aPositive
);
3813 format2
.append(';');
3814 format2
.append(aNegative
);
3816 format4
.append(aPositive
);
3817 format4
.append(';');
3818 format4
.append(aRed
);
3819 format4
.append(aNegative
);
3821 if (rCurr
.GetDigits())
3823 rStrArr
.push_back(format1
.makeStringAndClear());
3825 rStrArr
.push_back(format2
.makeStringAndClear());
3826 if (rCurr
.GetDigits())
3828 rStrArr
.push_back(format3
.makeStringAndClear());
3830 rStrArr
.push_back(format4
.makeStringAndClear());
3831 nDefault
= rStrArr
.size() - 1;
3832 if (rCurr
.GetDigits())
3834 rStrArr
.push_back(format5
.makeStringAndClear());
3840 sal_uInt32
SvNumberFormatter::GetMergeFormatIndex( sal_uInt32 nOldFmt
) const
3844 SvNumberFormatterIndexTable::iterator it
= pMergeTable
->find(nOldFmt
);
3845 if (it
!= pMergeTable
->end())
3853 bool SvNumberFormatter::HasMergeFormatTable() const
3855 return pMergeTable
&& !pMergeTable
->empty();
3859 sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
, sal_uInt16 nTwoDigitYearStart
)
3863 if ( nYear
< (nTwoDigitYearStart
% 100) )
3865 return nYear
+ (((nTwoDigitYearStart
/ 100) + 1) * 100);
3869 return nYear
+ ((nTwoDigitYearStart
/ 100) * 100);
3875 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
3877 aSymbol
= rLocaleData
.getCurrSymbol();
3878 aBankSymbol
= rLocaleData
.getCurrBankSymbol();
3880 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
3881 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
3882 nDigits
= rLocaleData
.getCurrDigits();
3883 cZeroChar
= rLocaleData
.getCurrZeroChar();
3887 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency
& rCurr
,
3888 const LocaleDataWrapper
& rLocaleData
, LanguageType eLang
)
3890 aSymbol
= rCurr
.Symbol
;
3891 aBankSymbol
= rCurr
.BankSymbol
;
3893 nPositiveFormat
= rLocaleData
.getCurrPositiveFormat();
3894 nNegativeFormat
= rLocaleData
.getCurrNegativeFormat();
3895 nDigits
= rCurr
.DecimalPlaces
;
3896 cZeroChar
= rLocaleData
.getCurrZeroChar();
3899 bool NfCurrencyEntry::operator==( const NfCurrencyEntry
& r
) const
3901 return aSymbol
== r
.aSymbol
3902 && aBankSymbol
== r
.aBankSymbol
3903 && eLanguage
== r
.eLanguage
3907 OUString
NfCurrencyEntry::BuildSymbolString(bool bBank
,
3908 bool bWithoutExtension
) const
3910 OUStringBuffer
aBuf("[$");
3913 aBuf
.append(aBankSymbol
);
3917 if ( aSymbol
.indexOf( (sal_Unicode
)'-' ) >= 0 ||
3918 aSymbol
.indexOf( (sal_Unicode
)']' ) >= 0)
3920 aBuf
.append('"').append(aSymbol
).append('"');
3924 aBuf
.append(aSymbol
);
3926 if ( !bWithoutExtension
&& eLanguage
!= LANGUAGE_DONTKNOW
&& eLanguage
!= LANGUAGE_SYSTEM
)
3928 sal_Int32 nLang
= static_cast<sal_Int32
>(eLanguage
);
3929 aBuf
.append('-').append( OUString::number(nLang
, 16).toAsciiUpperCase());
3933 return aBuf
.makeStringAndClear();
3936 OUString
NfCurrencyEntry::Impl_BuildFormatStringNumChars( const LocaleDataWrapper
& rLoc
,
3937 sal_uInt16 nDecimalFormat
) const
3939 OUStringBuffer aBuf
;
3940 aBuf
.append('#').append(rLoc
.getNumThousandSep()).append("##0");
3941 if (nDecimalFormat
&& nDigits
)
3943 aBuf
.append(rLoc
.getNumDecimalSep());
3944 sal_Unicode cDecimalChar
= nDecimalFormat
== 2 ? '-' : cZeroChar
;
3945 for (sal_uInt16 i
= 0; i
< nDigits
; ++i
)
3947 aBuf
.append(cDecimalChar
);
3950 return aBuf
.makeStringAndClear();
3954 OUString
NfCurrencyEntry::BuildPositiveFormatString(bool bBank
, const LocaleDataWrapper
& rLoc
,
3955 sal_uInt16 nDecimalFormat
) const
3957 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
3958 sal_uInt16 nPosiForm
= NfCurrencyEntry::GetEffectivePositiveFormat( rLoc
.getCurrPositiveFormat(),
3959 nPositiveFormat
, bBank
);
3960 CompletePositiveFormatString(sBuf
, bBank
, nPosiForm
);
3961 return sBuf
.makeStringAndClear();
3965 OUString
NfCurrencyEntry::BuildNegativeFormatString(bool bBank
,
3966 const LocaleDataWrapper
& rLoc
, sal_uInt16 nDecimalFormat
) const
3968 OUStringBuffer
sBuf(Impl_BuildFormatStringNumChars(rLoc
, nDecimalFormat
));
3969 sal_uInt16 nNegaForm
= NfCurrencyEntry::GetEffectiveNegativeFormat( rLoc
.getCurrNegativeFormat(),
3970 nNegativeFormat
, bBank
);
3971 CompleteNegativeFormatString(sBuf
, bBank
, nNegaForm
);
3972 return sBuf
.makeStringAndClear();
3976 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, bool bBank
,
3977 sal_uInt16 nPosiForm
) const
3979 OUString aSymStr
= BuildSymbolString(bBank
);
3980 NfCurrencyEntry::CompletePositiveFormatString( rStr
, aSymStr
, nPosiForm
);
3984 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
, bool bBank
,
3985 sal_uInt16 nNegaForm
) const
3987 OUString aSymStr
= BuildSymbolString(bBank
);
3988 NfCurrencyEntry::CompleteNegativeFormatString( rStr
, aSymStr
, nNegaForm
);
3993 void NfCurrencyEntry::CompletePositiveFormatString(OUStringBuffer
& rStr
, const OUString
& rSymStr
,
3994 sal_uInt16 nPositiveFormat
)
3996 switch( nPositiveFormat
)
3999 rStr
.insert(0, rSymStr
);
4002 rStr
.append(rSymStr
);
4006 rStr
.insert(0, ' ');
4007 rStr
.insert(0, rSymStr
);
4013 rStr
.append(rSymStr
);
4017 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompletePositiveFormatString: unknown option");
4024 void NfCurrencyEntry::CompleteNegativeFormatString(OUStringBuffer
& rStr
,
4025 const OUString
& rSymStr
,
4026 sal_uInt16 nNegativeFormat
)
4028 switch( nNegativeFormat
)
4032 rStr
.insert(0, rSymStr
);
4033 rStr
.insert(0, '(');
4039 rStr
.insert(0, rSymStr
);
4040 rStr
.insert(0, '-');
4045 rStr
.insert(0, '-');
4046 rStr
.insert(0, rSymStr
);
4051 rStr
.insert(0, rSymStr
);
4057 rStr
.insert(0, '(');
4058 rStr
.append(rSymStr
);
4064 rStr
.append(rSymStr
);
4065 rStr
.insert(0, '-');
4071 rStr
.append(rSymStr
);
4076 rStr
.append(rSymStr
);
4083 rStr
.append(rSymStr
);
4084 rStr
.insert(0, '-');
4089 rStr
.insert(0, ' ');
4090 rStr
.insert(0, rSymStr
);
4091 rStr
.insert(0, '-');
4097 rStr
.append(rSymStr
);
4103 rStr
.insert(0, " -");
4104 rStr
.insert(0, rSymStr
);
4109 rStr
.insert(0, ' ');
4110 rStr
.insert(0, rSymStr
);
4118 rStr
.append(rSymStr
);
4123 rStr
.insert(0, ' ');
4124 rStr
.insert(0, rSymStr
);
4125 rStr
.insert(0, '(');
4131 rStr
.insert(0, '(');
4133 rStr
.append(rSymStr
);
4138 SAL_WARN( "svl.numbers", "NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4145 sal_uInt16
NfCurrencyEntry::GetEffectivePositiveFormat( sal_uInt16 nIntlFormat
,
4146 sal_uInt16 nCurrFormat
, bool bBank
)
4150 #if NF_BANKSYMBOL_FIX_POSITION
4151 (void) nIntlFormat
; // avoid warnings
4154 switch ( nIntlFormat
)
4157 nIntlFormat
= 2; // $ 1
4160 nIntlFormat
= 3; // 1 $
4167 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4178 //! Call this only if nCurrFormat is really with parentheses!
4179 static sal_uInt16
lcl_MergeNegativeParenthesisFormat( sal_uInt16 nIntlFormat
, sal_uInt16 nCurrFormat
)
4181 short nSign
= 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4182 switch ( nIntlFormat
)
4208 SAL_WARN( "svl.numbers", "lcl_MergeNegativeParenthesisFormat: unknown option");
4212 switch ( nCurrFormat
)
4264 sal_uInt16
NfCurrencyEntry::GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat
,
4265 sal_uInt16 nCurrFormat
, bool bBank
)
4269 #if NF_BANKSYMBOL_FIX_POSITION
4272 switch ( nIntlFormat
)
4275 // nIntlFormat = 14; // ($ 1)
4276 nIntlFormat
= 9; // -$ 1
4279 nIntlFormat
= 9; // -$ 1
4282 nIntlFormat
= 11; // $ -1
4285 nIntlFormat
= 12; // $ 1-
4288 // nIntlFormat = 15; // (1 $)
4289 nIntlFormat
= 8; // -1 $
4292 nIntlFormat
= 8; // -1 $
4295 nIntlFormat
= 13; // 1- $
4298 nIntlFormat
= 10; // 1 $-
4313 // nIntlFormat = 14; // ($ 1)
4314 nIntlFormat
= 9; // -$ 1
4317 // nIntlFormat = 15; // (1 $)
4318 nIntlFormat
= 8; // -1 $
4321 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4326 else if ( nIntlFormat
!= nCurrFormat
)
4328 switch ( nCurrFormat
)
4331 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4332 nIntlFormat
, nCurrFormat
);
4335 nIntlFormat
= nCurrFormat
;
4338 nIntlFormat
= nCurrFormat
;
4341 nIntlFormat
= nCurrFormat
;
4344 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4345 nIntlFormat
, nCurrFormat
);
4348 nIntlFormat
= nCurrFormat
;
4351 nIntlFormat
= nCurrFormat
;
4354 nIntlFormat
= nCurrFormat
;
4357 nIntlFormat
= nCurrFormat
;
4360 nIntlFormat
= nCurrFormat
;
4363 nIntlFormat
= nCurrFormat
;
4366 nIntlFormat
= nCurrFormat
;
4369 nIntlFormat
= nCurrFormat
;
4372 nIntlFormat
= nCurrFormat
;
4375 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4376 nIntlFormat
, nCurrFormat
);
4379 nIntlFormat
= lcl_MergeNegativeParenthesisFormat(
4380 nIntlFormat
, nCurrFormat
);
4383 SAL_WARN( "svl.numbers", "NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4390 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */