update dev300-m57
[ooovba.git] / svtools / source / numbers / zforlist.cxx
blob4b13774a372f89bfb20c053742ff06a15cdb6295
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: zforlist.cxx,v $
10 * $Revision: 1.72.60.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
33 #ifndef GCC
34 #endif
36 // #include <math.h>
37 #include <tools/debug.hxx>
38 #ifndef _SOUND_HXX //autogen
39 #include <vcl/sound.hxx>
40 #endif
41 #include <vcl/svapp.hxx>
42 #include <vcl/settings.hxx>
43 #include <unotools/charclass.hxx>
44 #include <i18npool/mslangid.hxx>
45 #include <unotools/localedatawrapper.hxx>
46 #include <unotools/numberformatcodewrapper.hxx>
47 #include <unotools/calendarwrapper.hxx>
48 #include <com/sun/star/i18n/KNumberFormatUsage.hpp>
49 #include <com/sun/star/i18n/KNumberFormatType.hpp>
50 #include <comphelper/processfactory.hxx>
52 #define _SVSTDARR_USHORTS
53 #include <svtools/svstdarr.hxx>
55 #define _ZFORLIST_CXX
56 #include <osl/mutex.hxx>
57 #include <svtools/zforlist.hxx>
58 #undef _ZFORLIST_CXX
60 #include "zforscan.hxx"
61 #include "zforfind.hxx"
62 #include <svtools/zformat.hxx>
63 #include "numhead.hxx"
65 #include <svtools/syslocaleoptions.hxx>
66 #include "listener.hxx"
67 #include <svtools/smplhint.hxx>
68 #include <unotools/digitgroupingiterator.hxx>
69 #include <rtl/logfile.hxx>
70 #include <rtl/instance.hxx>
72 #include <math.h>
74 using namespace ::com::sun::star;
75 using namespace ::com::sun::star::uno;
76 using namespace ::com::sun::star::i18n;
77 using namespace ::com::sun::star::lang;
80 // Constants for type offsets per Country/Language (CL)
81 #define ZF_STANDARD 0
82 #define ZF_STANDARD_PERCENT 10
83 #define ZF_STANDARD_CURRENCY 20
84 #define ZF_STANDARD_DATE 30
85 #define ZF_STANDARD_TIME 40
86 #define ZF_STANDARD_DATETIME 50
87 #define ZF_STANDARD_SCIENTIFIC 60
88 #define ZF_STANDARD_FRACTION 70
89 #define ZF_STANDARD_NEWEXTENDED 75
90 #define ZF_STANDARD_NEWEXTENDEDMAX SV_MAX_ANZ_STANDARD_FORMATE-2 // 98
91 #define ZF_STANDARD_LOGICAL SV_MAX_ANZ_STANDARD_FORMATE-1 // 99
92 #define ZF_STANDARD_TEXT SV_MAX_ANZ_STANDARD_FORMATE // 100
94 /* Locale that is set if an unknown locale (from another system) is loaded of
95 * legacy documents. Can not be SYSTEM because else, for example, a German "DM"
96 * (old currency) is recognized as a date (#53155#). */
97 #define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US
99 static BOOL bIndexTableInitialized = FALSE;
100 static sal_uInt32 __FAR_DATA theIndexTable[NF_INDEX_TABLE_ENTRIES];
103 // ====================================================================
106 instead of every number formatter being a listener we have a registry which
107 also handles one instance of the SysLocale options
110 class SvNumberFormatterRegistry_Impl : public SvtListener
112 List aFormatters;
113 SvtSysLocaleOptions aSysLocaleOptions;
114 LanguageType eSysLanguage;
116 public:
117 SvNumberFormatterRegistry_Impl();
118 virtual ~SvNumberFormatterRegistry_Impl();
120 void Insert( SvNumberFormatter* pThis )
121 { aFormatters.Insert( pThis, LIST_APPEND ); }
122 SvNumberFormatter* Remove( SvNumberFormatter* pThis )
123 { return (SvNumberFormatter*)aFormatters.Remove( pThis ); }
124 sal_uInt32 Count()
125 { return aFormatters.Count(); }
127 virtual void Notify( SvtBroadcaster& rBC, const SfxHint& rHint );
132 SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl()
134 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
135 aSysLocaleOptions.AddListener( *this );
139 SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl()
141 aSysLocaleOptions.RemoveListener( *this );
145 void SvNumberFormatterRegistry_Impl::Notify( SvtBroadcaster&, const SfxHint& rHint )
147 const SfxSimpleHint* pHint = PTR_CAST( SfxSimpleHint, &rHint );
148 if( pHint )
150 if ( pHint->GetId() & SYSLOCALEOPTIONS_HINT_LOCALE )
152 ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() );
153 for ( SvNumberFormatter* p = (SvNumberFormatter*)aFormatters.First();
154 p; p = (SvNumberFormatter*)aFormatters.Next() )
156 p->ReplaceSystemCL( eSysLanguage );
158 eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM );
160 if ( pHint->GetId() & SYSLOCALEOPTIONS_HINT_CURRENCY )
162 ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() );
163 for ( SvNumberFormatter* p = (SvNumberFormatter*)aFormatters.First();
164 p; p = (SvNumberFormatter*)aFormatters.Next() )
166 p->ResetDefaultSystemCurrency();
173 // ====================================================================
175 SvNumberFormatterRegistry_Impl* SvNumberFormatter::pFormatterRegistry = NULL;
176 BOOL SvNumberFormatter::bCurrencyTableInitialized = FALSE;
177 namespace
179 struct theCurrencyTable :
180 public rtl::Static< NfCurrencyTable, theCurrencyTable > {};
182 struct theLegacyOnlyCurrencyTable :
183 public rtl::Static< NfCurrencyTable, theLegacyOnlyCurrencyTable > {};
185 USHORT SvNumberFormatter::nSystemCurrencyPosition = 0;
186 SV_IMPL_PTRARR( NfCurrencyTable, NfCurrencyEntry* );
187 SV_IMPL_PTRARR( NfWSStringsDtor, String* );
189 // ob das BankSymbol immer am Ende ist (1 $;-1 $) oder sprachabhaengig
190 #define NF_BANKSYMBOL_FIX_POSITION 1
193 /***********************Funktionen SvNumberFormatter**************************/
195 SvNumberFormatter::SvNumberFormatter(
196 const Reference< XMultiServiceFactory >& xSMgr,
197 LanguageType eLang )
199 xServiceManager( xSMgr )
201 ImpConstruct( eLang );
205 SvNumberFormatter::SvNumberFormatter( LanguageType eLang )
207 ImpConstruct( eLang );
211 SvNumberFormatter::~SvNumberFormatter()
214 ::osl::MutexGuard aGuard( GetMutex() );
215 pFormatterRegistry->Remove( this );
216 if ( !pFormatterRegistry->Count() )
218 delete pFormatterRegistry;
219 pFormatterRegistry = NULL;
223 SvNumberformat* pEntry = aFTable.First();
224 while (pEntry)
226 delete pEntry;
227 pEntry = aFTable.Next();
229 delete pFormatTable;
230 delete pCharClass;
231 delete pStringScanner;
232 delete pFormatScanner;
233 ClearMergeTable();
234 delete pMergeTable;
238 void SvNumberFormatter::ImpConstruct( LanguageType eLang )
240 RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svtools", "er93726", "SvNumberFormatter::ImpConstruct" );
242 if ( eLang == LANGUAGE_DONTKNOW )
243 eLang = UNKNOWN_SUBSTITUTE;
244 IniLnge = eLang;
245 ActLnge = eLang;
246 eEvalDateFormat = NF_EVALDATEFORMAT_INTL;
247 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
249 aLocale = MsLangId::convertLanguageToLocale( eLang );
250 pCharClass = new CharClass( xServiceManager, aLocale );
251 xLocaleData.init( xServiceManager, aLocale, eLang );
252 xCalendar.init( xServiceManager, aLocale );
253 xTransliteration.init( xServiceManager, eLang,
254 ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE );
255 xNatNum.init( xServiceManager );
257 // cached locale data items
258 const LocaleDataWrapper* pLoc = GetLocaleData();
259 aDecimalSep = pLoc->getNumDecimalSep();
260 aThousandSep = pLoc->getNumThousandSep();
261 aDateSep = pLoc->getDateSep();
263 pStringScanner = new ImpSvNumberInputScan( this );
264 pFormatScanner = new ImpSvNumberformatScan( this );
265 pFormatTable = NULL;
266 MaxCLOffset = 0;
267 ImpGenerateFormats( 0, FALSE ); // 0 .. 999 for initialized language formats
268 pMergeTable = NULL;
269 bNoZero = FALSE;
271 ::osl::MutexGuard aGuard( GetMutex() );
272 GetFormatterRegistry().Insert( this );
276 void SvNumberFormatter::ChangeIntl(LanguageType eLnge)
278 if (ActLnge != eLnge)
280 ActLnge = eLnge;
282 aLocale = MsLangId::convertLanguageToLocale( eLnge );
283 pCharClass->setLocale( aLocale );
284 xLocaleData.changeLocale( aLocale, eLnge );
285 xCalendar.changeLocale( aLocale );
286 xTransliteration.changeLocale( eLnge );
288 // cached locale data items, initialize BEFORE calling ChangeIntl below
289 const LocaleDataWrapper* pLoc = GetLocaleData();
290 aDecimalSep = pLoc->getNumDecimalSep();
291 aThousandSep = pLoc->getNumThousandSep();
292 aDateSep = pLoc->getDateSep();
294 pFormatScanner->ChangeIntl();
295 pStringScanner->ChangeIntl();
300 // static
301 ::osl::Mutex& SvNumberFormatter::GetMutex()
303 static ::osl::Mutex* pMutex = NULL;
304 if( !pMutex )
306 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
307 if( !pMutex )
309 // #i77768# Due to a static reference in the toolkit lib
310 // we need a mutex that lives longer than the svtools library.
311 // Otherwise the dtor would use a destructed mutex!!
312 pMutex = new ::osl::Mutex;
315 return *pMutex;
319 // static
320 SvNumberFormatterRegistry_Impl& SvNumberFormatter::GetFormatterRegistry()
322 ::osl::MutexGuard aGuard( GetMutex() );
323 if ( !pFormatterRegistry )
324 pFormatterRegistry = new SvNumberFormatterRegistry_Impl;
325 return *pFormatterRegistry;
329 Color* SvNumberFormatter::GetUserDefColor(USHORT nIndex)
331 if( aColorLink.IsSet() )
332 return (Color*) ( aColorLink.Call( (void*) &nIndex ));
333 else
334 return NULL;
337 void SvNumberFormatter::ChangeNullDate(USHORT nDay,
338 USHORT nMonth,
339 USHORT nYear)
341 pFormatScanner->ChangeNullDate(nDay, nMonth, nYear);
342 pStringScanner->ChangeNullDate(nDay, nMonth, nYear);
345 Date* SvNumberFormatter::GetNullDate()
347 return pFormatScanner->GetNullDate();
350 void SvNumberFormatter::ChangeStandardPrec(short nPrec)
352 pFormatScanner->ChangeStandardPrec(nPrec);
355 short SvNumberFormatter::GetStandardPrec()
357 return pFormatScanner->GetStandardPrec();
360 void SvNumberFormatter::ImpChangeSysCL( LanguageType eLnge, BOOL bLoadingSO5 )
362 if (eLnge == LANGUAGE_DONTKNOW)
363 eLnge = UNKNOWN_SUBSTITUTE;
364 if (eLnge != IniLnge)
366 IniLnge = eLnge;
367 ChangeIntl(eLnge);
368 SvNumberformat* pEntry = aFTable.First();
369 while (pEntry) // delete old formats
371 pEntry = (SvNumberformat*) aFTable.Remove(aFTable.GetCurKey());
372 delete pEntry;
373 pEntry = (SvNumberformat*) aFTable.First();
375 ImpGenerateFormats( 0, bLoadingSO5 ); // new standard formats
377 else if ( bLoadingSO5 )
378 { // delete additional standard formats
379 sal_uInt32 nKey;
380 aFTable.Seek( SV_MAX_ANZ_STANDARD_FORMATE + 1 );
381 while ( (nKey = aFTable.GetCurKey()) > SV_MAX_ANZ_STANDARD_FORMATE &&
382 nKey < SV_COUNTRY_LANGUAGE_OFFSET )
384 SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey );
385 delete pEntry;
391 void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage )
393 sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM );
394 if ( nCLOffset > MaxCLOffset )
395 return ; // no SYSTEM entries to replace
397 const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_ANZ_STANDARD_FORMATE;
398 const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
399 sal_uInt32 nKey;
401 // remove old builtin formats
402 aFTable.Seek( nCLOffset );
403 while ( (nKey = aFTable.GetCurKey()) >= nCLOffset && nKey <= nMaxBuiltin && aFTable.Count() )
405 SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey );
406 delete pEntry;
409 // move additional and user defined to temporary table
410 Table aOldTable;
411 while ( (nKey = aFTable.GetCurKey()) >= nCLOffset && nKey < nNextCL && aFTable.Count() )
413 SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey );
414 aOldTable.Insert( nKey, pEntry );
417 // generate new old builtin formats
418 // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM
419 ActLnge = LANGUAGE_DONTKNOW;
420 ChangeIntl( LANGUAGE_SYSTEM );
421 ImpGenerateFormats( nCLOffset, TRUE );
423 // convert additional and user defined from old system to new system
424 SvNumberformat* pStdFormat = (SvNumberformat*) aFTable.Get( nCLOffset + ZF_STANDARD );
425 sal_uInt32 nLastKey = nMaxBuiltin;
426 pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, TRUE );
427 aOldTable.First();
428 while ( aOldTable.Count() )
430 nKey = aOldTable.GetCurKey();
431 if ( nLastKey < nKey )
432 nLastKey = nKey;
433 SvNumberformat* pOldEntry = (SvNumberformat*) aOldTable.Remove( nKey );
434 String aString( pOldEntry->GetFormatstring() );
435 xub_StrLen nCheckPos = STRING_NOTFOUND;
437 // Same as PutEntry() but assures key position even if format code is
438 // a duplicate. Also won't mix up any LastInsertKey.
439 ChangeIntl( eOldLanguage );
440 LanguageType eLge = eOldLanguage; // ConvertMode changes this
441 BOOL bCheck = FALSE;
442 SvNumberformat* pNewEntry = new SvNumberformat( aString, pFormatScanner,
443 pStringScanner, nCheckPos, eLge );
444 if ( nCheckPos != 0 )
445 delete pNewEntry;
446 else
448 short eCheckType = pNewEntry->GetType();
449 if ( eCheckType != NUMBERFORMAT_UNDEFINED )
450 pNewEntry->SetType( eCheckType | NUMBERFORMAT_DEFINED );
451 else
452 pNewEntry->SetType( NUMBERFORMAT_DEFINED );
454 if ( !aFTable.Insert( nKey, pNewEntry ) )
455 delete pNewEntry;
456 else
457 bCheck = TRUE;
459 DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" );
461 delete pOldEntry;
463 pFormatScanner->SetConvertMode(FALSE);
464 pStdFormat->SetLastInsertKey( USHORT(nLastKey - nCLOffset) );
466 // append new system additional formats
467 NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() );
468 ImpGenerateAdditionalFormats( nCLOffset, aNumberFormatCode, TRUE );
472 BOOL SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const
474 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index);
475 if (!pFormat)
476 return FALSE;
477 else
478 return pFormat->IsTextFormat();
481 BOOL SvNumberFormatter::HasTextFormat(sal_uInt32 F_Index) const
483 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index);
484 if (!pFormat)
485 return FALSE;
486 else
487 return pFormat->HasTextFormat();
490 BOOL SvNumberFormatter::PutEntry(String& rString,
491 xub_StrLen& nCheckPos,
492 short& nType,
493 sal_uInt32& nKey, // Formatnummer
494 LanguageType eLnge)
496 nKey = 0;
497 if (rString.Len() == 0) // keinen Leerstring
499 nCheckPos = 1; // -> Fehler
500 return FALSE;
502 if (eLnge == LANGUAGE_DONTKNOW)
503 eLnge = IniLnge;
505 ChangeIntl(eLnge); // ggfs. austauschen
506 LanguageType eLge = eLnge; // Umgehung const fuer ConvertMode
507 BOOL bCheck = FALSE;
508 SvNumberformat* p_Entry = new SvNumberformat(rString,
509 pFormatScanner,
510 pStringScanner,
511 nCheckPos,
512 eLge);
513 if (nCheckPos == 0) // Format ok
514 { // Typvergleich:
515 short eCheckType = p_Entry->GetType();
516 if ( eCheckType != NUMBERFORMAT_UNDEFINED)
518 p_Entry->SetType(eCheckType | NUMBERFORMAT_DEFINED);
519 nType = eCheckType;
521 else
523 p_Entry->SetType(NUMBERFORMAT_DEFINED);
524 nType = NUMBERFORMAT_DEFINED;
526 sal_uInt32 CLOffset = ImpGenerateCL(eLge); // ggfs. neu Standard-
527 // formate anlegen
528 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge);
529 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden
530 delete p_Entry;
531 else
533 SvNumberformat* pStdFormat =
534 (SvNumberformat*) aFTable.Get(CLOffset + ZF_STANDARD);
535 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
536 if (nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
538 Sound::Beep();
539 DBG_ERROR("SvNumberFormatter:: Zu viele Formate pro CL");
540 delete p_Entry;
542 else if (!aFTable.Insert(nPos+1,p_Entry))
543 delete p_Entry;
544 else
546 bCheck = TRUE;
547 nKey = nPos+1;
548 pStdFormat->SetLastInsertKey((USHORT) (nKey-CLOffset));
552 else
553 delete p_Entry;
554 return bCheck;
557 BOOL SvNumberFormatter::PutandConvertEntry(String& rString,
558 xub_StrLen& nCheckPos,
559 short& nType,
560 sal_uInt32& nKey,
561 LanguageType eLnge,
562 LanguageType eNewLnge)
564 BOOL bRes;
565 if (eNewLnge == LANGUAGE_DONTKNOW)
566 eNewLnge = IniLnge;
568 pFormatScanner->SetConvertMode(eLnge, eNewLnge);
569 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
570 pFormatScanner->SetConvertMode(FALSE);
571 return bRes;
575 BOOL SvNumberFormatter::PutandConvertEntrySystem(String& rString,
576 xub_StrLen& nCheckPos,
577 short& nType,
578 sal_uInt32& nKey,
579 LanguageType eLnge,
580 LanguageType eNewLnge)
582 BOOL bRes;
583 if (eNewLnge == LANGUAGE_DONTKNOW)
584 eNewLnge = IniLnge;
586 pFormatScanner->SetConvertMode(eLnge, eNewLnge, TRUE);
587 bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge);
588 pFormatScanner->SetConvertMode(FALSE);
589 return bRes;
593 sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( String & rString,
594 LanguageType eLnge, LanguageType eSysLnge, short & rType,
595 BOOL & rNewInserted, xub_StrLen & rCheckPos )
597 sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
598 rNewInserted = FALSE;
599 rCheckPos = 0;
601 // #62389# empty format string (of Writer) => General standard format
602 if (!rString.Len())
603 ; // nothing
604 else if (eLnge == LANGUAGE_SYSTEM && eSysLnge !=
605 Application::GetSettings().GetLanguage())
607 sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge );
608 if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND)
609 nKey = nOrig; // none avaliable, maybe user-defined
610 else
611 nKey = GetFormatForLanguageIfBuiltIn( nOrig,
612 Application::GetSettings().GetLanguage());
613 if (nKey == nOrig)
615 // Not a builtin format, convert.
616 // The format code string may get modified and adapted to the real
617 // language and wouldn't match eSysLnge anymore, do that on a copy.
618 String aTmp( rString);
619 rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType,
620 nKey, eLnge, Application::GetSettings().GetLanguage());
621 if (rCheckPos > 0)
623 DBG_ERRORFILE("SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale");
624 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
628 else
630 nKey = GetEntryKey( rString, eLnge);
631 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
633 rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge);
634 if (rCheckPos > 0)
636 DBG_ERRORFILE("SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale");
637 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND;
641 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
642 nKey = GetStandardIndex( eLnge);
643 rType = GetType( nKey);
644 // Convert any (!) old "automatic" currency format to new fixed currency
645 // default format.
646 if ((rType & NUMBERFORMAT_CURRENCY) != 0)
648 const SvNumberformat* pFormat = GetEntry( nKey);
649 if (!pFormat->HasNewCurrency())
651 if (rNewInserted)
653 DeleteEntry( nKey); // don't leave trails of rubbish
654 rNewInserted = FALSE;
656 nKey = GetStandardFormat( NUMBERFORMAT_CURRENCY, eLnge);
659 return nKey;
663 void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey)
665 SvNumberformat* pEntry = aFTable.Remove(nKey);
666 delete pEntry;
669 void SvNumberFormatter::PrepareSave()
671 SvNumberformat* pFormat = aFTable.First();
672 while (pFormat)
674 pFormat->SetUsed(FALSE);
675 pFormat = aFTable.Next();
679 void SvNumberFormatter::SetFormatUsed(sal_uInt32 nFIndex)
681 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
682 if (pFormat)
683 pFormat->SetUsed(TRUE);
686 BOOL SvNumberFormatter::Load( SvStream& rStream )
688 LanguageType eSysLang = Application::GetSettings().GetLanguage();
689 SvNumberFormatter* pConverter = NULL;
691 ImpSvNumMultipleReadHeader aHdr( rStream );
692 USHORT nVersion;
693 rStream >> nVersion;
694 SvNumberformat* pEntry;
695 sal_uInt32 nPos;
696 LanguageType eSaveSysLang, eLoadSysLang;
697 USHORT nSysOnStore, eLge, eDummy; // Dummy fuer kompatibles Format
698 rStream >> nSysOnStore >> eLge; // Systemeinstellung aus
699 // Dokument
700 eSaveSysLang = (nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE ?
701 LANGUAGE_SYSTEM : (LanguageType) nSysOnStore);
702 LanguageType eLnge = (LanguageType) eLge;
703 ImpChangeSysCL( eLnge, TRUE );
705 rStream >> nPos;
706 while (nPos != NUMBERFORMAT_ENTRY_NOT_FOUND)
708 rStream >> eDummy >> eLge;
709 eLnge = (LanguageType) eLge;
710 ImpGenerateCL( eLnge, TRUE ); // ggfs. neue Standardformate anlegen
712 sal_uInt32 nOffset = nPos % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
713 BOOL bUserDefined = (nOffset > SV_MAX_ANZ_STANDARD_FORMATE);
714 //! HACK! ER 29.07.97 15:15
715 // SaveLang wurde bei SYSTEM nicht gespeichert sondern war auch SYSTEM,
716 // erst ab 364i Unterscheidung moeglich
717 BOOL bConversionHack;
718 if ( eLnge == LANGUAGE_SYSTEM )
720 if ( nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE )
722 bConversionHack = bUserDefined;
723 eLoadSysLang = eSaveSysLang;
725 else
727 bConversionHack = FALSE;
728 eLoadSysLang = eSysLang;
731 else
733 bConversionHack = FALSE;
734 eLoadSysLang = eSaveSysLang;
737 pEntry = new SvNumberformat(*pFormatScanner, eLnge);
738 if ( bConversionHack )
739 { // SYSTEM
740 // nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE
741 // nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS
742 if ( !pConverter )
743 pConverter = new SvNumberFormatter( xServiceManager, eSysLang );
744 NfHackConversion eHackConversion = pEntry->Load(
745 rStream, aHdr, pConverter, *pStringScanner );
746 switch ( eHackConversion )
748 case NF_CONVERT_GERMAN_ENGLISH :
749 pEntry->ConvertLanguage( *pConverter,
750 LANGUAGE_ENGLISH_US, eSysLang, TRUE );
751 break;
752 case NF_CONVERT_ENGLISH_GERMAN :
753 switch ( eSysLang )
755 case LANGUAGE_GERMAN:
756 case LANGUAGE_GERMAN_SWISS:
757 case LANGUAGE_GERMAN_AUSTRIAN:
758 case LANGUAGE_GERMAN_LUXEMBOURG:
759 case LANGUAGE_GERMAN_LIECHTENSTEIN:
760 // alles beim alten
761 break;
762 default:
763 pEntry->ConvertLanguage( *pConverter,
764 LANGUAGE_GERMAN, eSysLang, TRUE );
766 break;
767 case NF_CONVERT_NONE :
768 break; // -Wall not handled.
772 else
774 pEntry->Load( rStream, aHdr, NULL, *pStringScanner );
775 if ( !bUserDefined )
776 bUserDefined = (pEntry->GetNewStandardDefined() > SV_NUMBERFORMATTER_VERSION);
777 if ( bUserDefined )
779 if ( eSaveSysLang != eLoadSysLang )
780 { // SYSTEM verschieden
781 if ( !pConverter )
782 pConverter = new SvNumberFormatter( xServiceManager, eSysLang );
783 if ( nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS )
785 switch ( eSaveSysLang )
787 case LANGUAGE_GERMAN:
788 case LANGUAGE_GERMAN_SWISS:
789 case LANGUAGE_GERMAN_AUSTRIAN:
790 case LANGUAGE_GERMAN_LUXEMBOURG:
791 case LANGUAGE_GERMAN_LIECHTENSTEIN:
792 // alles beim alten
793 pEntry->ConvertLanguage( *pConverter,
794 eSaveSysLang, eLoadSysLang, TRUE );
795 break;
796 default:
797 // alte english nach neuem anderen
798 pEntry->ConvertLanguage( *pConverter,
799 LANGUAGE_ENGLISH_US, eLoadSysLang, TRUE );
802 else
803 pEntry->ConvertLanguage( *pConverter,
804 eSaveSysLang, eLoadSysLang, TRUE );
806 else
807 { // nicht SYSTEM oder gleiches SYSTEM
808 if ( nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS )
810 LanguageType eLoadLang;
811 BOOL bSystem;
812 if ( eLnge == LANGUAGE_SYSTEM )
814 eLoadLang = eSysLang;
815 bSystem = TRUE;
817 else
819 eLoadLang = eLnge;
820 bSystem = FALSE;
822 switch ( eLoadLang )
824 case LANGUAGE_GERMAN:
825 case LANGUAGE_GERMAN_SWISS:
826 case LANGUAGE_GERMAN_AUSTRIAN:
827 case LANGUAGE_GERMAN_LUXEMBOURG:
828 case LANGUAGE_GERMAN_LIECHTENSTEIN:
829 // alles beim alten
830 break;
831 default:
832 // alte english nach neuem anderen
833 if ( !pConverter )
834 pConverter = new SvNumberFormatter( xServiceManager, eSysLang );
835 pEntry->ConvertLanguage( *pConverter,
836 LANGUAGE_ENGLISH_US, eLoadLang, bSystem );
842 if ( nOffset == 0 ) // StandardFormat
844 SvNumberformat* pEnt = aFTable.Get(nPos);
845 if (pEnt)
846 pEnt->SetLastInsertKey(pEntry->GetLastInsertKey());
848 if (!aFTable.Insert(nPos, pEntry))
849 delete pEntry;
850 rStream >> nPos;
853 // ab SV_NUMBERFORMATTER_VERSION_YEAR2000
854 if ( nVersion >= SV_NUMBERFORMATTER_VERSION_YEAR2000 )
856 aHdr.StartEntry();
857 if ( aHdr.BytesLeft() >= sizeof(UINT16) )
859 UINT16 nY2k;
860 rStream >> nY2k;
861 if ( nVersion < SV_NUMBERFORMATTER_VERSION_TWODIGITYEAR && nY2k < 100 )
862 nY2k += 1901; // war vor src513e: 29, jetzt: 1930
863 SetYear2000( nY2k );
865 aHdr.EndEntry();
868 if ( pConverter )
869 delete pConverter;
871 // generate additional i18n standard formats for all used locales
872 LanguageType eOldLanguage = ActLnge;
873 NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() );
874 SvUShorts aList;
875 GetUsedLanguages( aList );
876 USHORT nCount = aList.Count();
877 for ( USHORT j=0; j<nCount; j++ )
879 LanguageType eLang = aList[j];
880 ChangeIntl( eLang );
881 sal_uInt32 CLOffset = ImpGetCLOffset( eLang );
882 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, TRUE );
884 ChangeIntl( eOldLanguage );
886 if (rStream.GetError())
887 return FALSE;
888 else
889 return TRUE;
892 BOOL SvNumberFormatter::Save( SvStream& rStream ) const
894 ImpSvNumMultipleWriteHeader aHdr( rStream );
895 // ab 364i wird gespeichert was SYSTEM wirklich war, vorher hart LANGUAGE_SYSTEM
896 rStream << (USHORT) SV_NUMBERFORMATTER_VERSION;
897 rStream << (USHORT) Application::GetSettings().GetLanguage() << (USHORT) IniLnge;
898 SvNumberFormatTable* pTable = (SvNumberFormatTable*) &aFTable;
899 SvNumberformat* pEntry = (SvNumberformat*) pTable->First();
900 while (pEntry)
902 // Gespeichert werden alle markierten, benutzerdefinierten Formate und
903 // jeweils das Standardformat zu allen angewaehlten CL-Kombinationen
904 // sowie NewStandardDefined
905 if ( pEntry->GetUsed() || (pEntry->GetType() & NUMBERFORMAT_DEFINED) ||
906 pEntry->GetNewStandardDefined() ||
907 (pTable->GetCurKey() % SV_COUNTRY_LANGUAGE_OFFSET == 0) )
909 rStream << static_cast<sal_uInt32>(pTable->GetCurKey())
910 << (USHORT) LANGUAGE_SYSTEM
911 << (USHORT) pEntry->GetLanguage();
912 pEntry->Save(rStream, aHdr);
914 pEntry = (SvNumberformat*) pTable->Next();
916 rStream << NUMBERFORMAT_ENTRY_NOT_FOUND; // EndeKennung
918 // ab SV_NUMBERFORMATTER_VERSION_YEAR2000
919 aHdr.StartEntry();
920 rStream << (UINT16) GetYear2000();
921 aHdr.EndEntry();
923 if (rStream.GetError())
924 return FALSE;
925 else
926 return TRUE;
929 // static
930 void SvNumberFormatter::SkipNumberFormatterInStream( SvStream& rStream )
932 ImpSvNumMultipleReadHeader::Skip( rStream );
935 void SvNumberFormatter::GetUsedLanguages( SvUShorts& rList )
937 rList.Remove( 0, rList.Count() );
939 sal_uInt32 nOffset = 0;
940 while (nOffset <= MaxCLOffset)
942 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nOffset);
943 if (pFormat)
944 rList.Insert( pFormat->GetLanguage(), rList.Count() );
945 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
950 void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords,
951 LanguageType eLang )
953 ChangeIntl( eLang );
954 const String* pTable = pFormatScanner->GetKeywords();
955 for ( USHORT i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i )
957 rKeywords[i] = pTable[i];
962 String SvNumberFormatter::GetKeyword( LanguageType eLnge, USHORT nIndex )
964 ChangeIntl(eLnge);
965 const String* pTable = pFormatScanner->GetKeywords();
966 if ( pTable && nIndex < NF_KEYWORD_ENTRIES_COUNT )
967 return pTable[nIndex];
969 DBG_ERROR("GetKeyword: invalid index");
970 return String();
974 String SvNumberFormatter::GetStandardName( LanguageType eLnge )
976 ChangeIntl( eLnge );
977 return pFormatScanner->GetStandardName();
981 sal_uInt32 SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge) const
983 SvNumberformat* pFormat;
984 sal_uInt32 nOffset = 0;
985 while (nOffset <= MaxCLOffset)
987 pFormat = (SvNumberformat*) aFTable.Get(nOffset);
988 if (pFormat && pFormat->GetLanguage() == eLnge)
989 return nOffset;
990 nOffset += SV_COUNTRY_LANGUAGE_OFFSET;
992 return nOffset;
995 sal_uInt32 SvNumberFormatter::ImpIsEntry(const String& rString,
996 sal_uInt32 nCLOffset,
997 LanguageType eLnge)
999 #ifndef NF_COMMENT_IN_FORMATSTRING
1000 #error NF_COMMENT_IN_FORMATSTRING not defined (zformat.hxx)
1001 #endif
1002 #if NF_COMMENT_IN_FORMATSTRING
1003 String aStr( rString );
1004 SvNumberformat::EraseComment( aStr );
1005 #endif
1006 sal_uInt32 res = NUMBERFORMAT_ENTRY_NOT_FOUND;
1007 SvNumberformat* pEntry;
1008 pEntry = (SvNumberformat*) aFTable.Seek(nCLOffset);
1009 while ( res == NUMBERFORMAT_ENTRY_NOT_FOUND &&
1010 pEntry && pEntry->GetLanguage() == eLnge )
1012 #if NF_COMMENT_IN_FORMATSTRING
1013 if ( pEntry->GetComment().Len() )
1015 String aFormat( pEntry->GetFormatstring() );
1016 SvNumberformat::EraseComment( aFormat );
1017 if ( aStr == aFormat )
1018 res = aFTable.GetCurKey();
1019 else
1020 pEntry = (SvNumberformat*) aFTable.Next();
1022 else
1024 if ( aStr == pEntry->GetFormatstring() )
1025 res = aFTable.GetCurKey();
1026 else
1027 pEntry = (SvNumberformat*) aFTable.Next();
1029 #else
1030 if ( rString == pEntry->GetFormatstring() )
1031 res = aFTable.GetCurKey();
1032 else
1033 pEntry = (SvNumberformat*) aFTable.Next();
1034 #endif
1036 return res;
1040 SvNumberFormatTable& SvNumberFormatter::GetFirstEntryTable(
1041 short& eType,
1042 sal_uInt32& FIndex,
1043 LanguageType& rLnge)
1045 short eTypetmp = eType;
1046 if (eType == NUMBERFORMAT_ALL) // Leere Zelle oder don't care
1047 rLnge = IniLnge;
1048 else
1050 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(FIndex);
1051 if (!pFormat)
1053 // DBG_ERROR("SvNumberFormatter:: Unbekanntes altes Zahlformat (1)");
1054 rLnge = IniLnge;
1055 eType = NUMBERFORMAT_ALL;
1056 eTypetmp = eType;
1058 else
1060 rLnge = pFormat->GetLanguage();
1061 eType = pFormat->GetType()&~NUMBERFORMAT_DEFINED;
1062 if (eType == 0)
1064 eType = NUMBERFORMAT_DEFINED;
1065 eTypetmp = eType;
1067 else if (eType == NUMBERFORMAT_DATETIME)
1069 eTypetmp = eType;
1070 eType = NUMBERFORMAT_DATE;
1072 else
1073 eTypetmp = eType;
1076 ChangeIntl(rLnge);
1077 return GetEntryTable(eTypetmp, FIndex, rLnge);
1080 sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge, BOOL bLoadingSO5 )
1082 ChangeIntl(eLnge);
1083 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1084 if (CLOffset > MaxCLOffset)
1085 { // new CL combination
1086 if (LocaleDataWrapper::areChecksEnabled())
1088 Locale aLoadedLocale = xLocaleData->getLoadedLocale();
1089 if ( aLoadedLocale.Language != aLocale.Language ||
1090 aLoadedLocale.Country != aLocale.Country )
1092 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1093 "SvNumerFormatter::ImpGenerateCL: locales don't match:"));
1094 LocaleDataWrapper::outputCheckMessage(
1095 xLocaleData->appendLocaleInfo( aMsg ));
1097 // test XML locale data FormatElement entries
1099 uno::Sequence< i18n::FormatElement > xSeq =
1100 xLocaleData->getAllFormats();
1101 // A test for completeness of formatindex="0" ...
1102 // formatindex="47" is not needed here since it is done in
1103 // ImpGenerateFormats().
1105 // Test for dupes of formatindex="..."
1106 for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ )
1108 sal_Int16 nIdx = xSeq[j].formatIndex;
1109 String aDupes;
1110 for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ )
1112 if ( i != j && xSeq[i].formatIndex == nIdx )
1114 aDupes += String::CreateFromInt32( i );
1115 aDupes += '(';
1116 aDupes += String( xSeq[i].formatKey );
1117 aDupes += ')';
1118 aDupes += ' ';
1121 if ( aDupes.Len() )
1123 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1124 "XML locale data FormatElement formatindex dupe: "));
1125 aMsg += String::CreateFromInt32( nIdx );
1126 aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM(
1127 "\nFormatElements: "));
1128 aMsg += String::CreateFromInt32( j );
1129 aMsg += '(';
1130 aMsg += String( xSeq[j].formatKey );
1131 aMsg += ')';
1132 aMsg += ' ';
1133 aMsg += aDupes;
1134 LocaleDataWrapper::outputCheckMessage(
1135 xLocaleData->appendLocaleInfo( aMsg ));
1141 MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET;
1142 ImpGenerateFormats( MaxCLOffset, bLoadingSO5 );
1143 CLOffset = MaxCLOffset;
1145 return CLOffset;
1148 SvNumberFormatTable& SvNumberFormatter::ChangeCL(short eType,
1149 sal_uInt32& FIndex,
1150 LanguageType eLnge)
1152 ImpGenerateCL(eLnge);
1153 return GetEntryTable(eType, FIndex, ActLnge);
1156 SvNumberFormatTable& SvNumberFormatter::GetEntryTable(
1157 short eType,
1158 sal_uInt32& FIndex,
1159 LanguageType eLnge)
1161 if ( pFormatTable )
1162 pFormatTable->Clear();
1163 else
1164 pFormatTable = new SvNumberFormatTable;
1165 ChangeIntl(eLnge);
1166 sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge);
1168 // Might generate and insert a default format for the given type
1169 // (e.g. currency) => has to be done before collecting formats.
1170 sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge );
1172 SvNumberformat* pEntry;
1173 pEntry = (SvNumberformat*) aFTable.Seek(CLOffset);
1175 if (eType == NUMBERFORMAT_ALL)
1177 while (pEntry && pEntry->GetLanguage() == ActLnge)
1178 { // copy all entries to output table
1179 pFormatTable->Insert( aFTable.GetCurKey(), pEntry );
1180 pEntry = (SvNumberformat*) aFTable.Next();
1183 else
1185 while (pEntry && pEntry->GetLanguage() == ActLnge)
1186 { // copy entries of queried type to output table
1187 if ((pEntry->GetType()) & eType)
1188 pFormatTable->Insert(aFTable.GetCurKey(),pEntry);
1189 pEntry = (SvNumberformat*) aFTable.Next();
1192 if ( pFormatTable->Count() > 0 )
1193 { // select default if queried format doesn't exist or queried type or
1194 // language differ from existing format
1195 pEntry = aFTable.Get(FIndex);
1196 if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge )
1197 FIndex = nDefaultIndex;
1199 return *pFormatTable;
1202 BOOL SvNumberFormatter::IsNumberFormat(const String& sString,
1203 sal_uInt32& F_Index,
1204 double& fOutNumber)
1206 short FType;
1207 const SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index);
1208 if (!pFormat)
1210 // DBG_ERROR("SvNumberFormatter:: Unbekanntes altes Zahlformat (2)");
1211 ChangeIntl(IniLnge);
1212 FType = NUMBERFORMAT_NUMBER;
1214 else
1216 FType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
1217 if (FType == 0)
1218 FType = NUMBERFORMAT_DEFINED;
1219 ChangeIntl(pFormat->GetLanguage());
1221 BOOL res;
1222 short RType = FType;
1223 // Ergebnistyp
1224 // ohne def-Kennung
1225 if (RType == NUMBERFORMAT_TEXT) // Zahlzelle ->Stringz.
1226 res = FALSE;
1227 else
1228 res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat);
1230 if (res && !IsCompatible(FType, RType)) // unpassender Typ
1232 switch ( RType )
1234 case NUMBERFORMAT_TIME :
1236 if ( pStringScanner->GetDecPos() )
1237 { // 100stel Sekunden
1238 if ( pStringScanner->GetAnzNums() > 3 || fOutNumber < 0.0 )
1239 F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge );
1240 else
1241 F_Index = GetFormatIndex( NF_TIME_MMSS00, ActLnge );
1243 else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 )
1244 F_Index = GetFormatIndex( NF_TIME_HH_MMSS, ActLnge );
1245 else
1246 F_Index = GetStandardFormat( RType, ActLnge );
1248 break;
1249 default:
1250 F_Index = GetStandardFormat( RType, ActLnge );
1253 return res;
1256 BOOL SvNumberFormatter::IsCompatible(short eOldType,
1257 short eNewType)
1259 if (eOldType == eNewType)
1260 return TRUE;
1261 else if (eOldType == NUMBERFORMAT_DEFINED)
1262 return TRUE;
1263 else
1265 switch (eNewType)
1267 case NUMBERFORMAT_NUMBER:
1269 switch (eOldType)
1271 case NUMBERFORMAT_PERCENT:
1272 case NUMBERFORMAT_CURRENCY:
1273 case NUMBERFORMAT_SCIENTIFIC:
1274 case NUMBERFORMAT_FRACTION:
1275 // case NUMBERFORMAT_LOGICAL:
1276 case NUMBERFORMAT_DEFINED:
1277 return TRUE;
1278 default:
1279 return FALSE;
1282 break;
1283 case NUMBERFORMAT_DATE:
1285 switch (eOldType)
1287 case NUMBERFORMAT_DATETIME:
1288 return TRUE;
1289 default:
1290 return FALSE;
1293 break;
1294 case NUMBERFORMAT_TIME:
1296 switch (eOldType)
1298 case NUMBERFORMAT_DATETIME:
1299 return TRUE;
1300 default:
1301 return FALSE;
1304 break;
1305 case NUMBERFORMAT_DATETIME:
1307 switch (eOldType)
1309 case NUMBERFORMAT_TIME:
1310 case NUMBERFORMAT_DATE:
1311 return TRUE;
1312 default:
1313 return FALSE;
1316 break;
1317 default:
1318 return FALSE;
1320 return FALSE;
1325 sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( short nType )
1327 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
1328 sal_uInt32 nSearch;
1329 switch( nType )
1331 case NUMBERFORMAT_DATE :
1332 nSearch = CLOffset + ZF_STANDARD_DATE;
1333 break;
1334 case NUMBERFORMAT_TIME :
1335 nSearch = CLOffset + ZF_STANDARD_TIME;
1336 break;
1337 case NUMBERFORMAT_DATETIME :
1338 nSearch = CLOffset + ZF_STANDARD_DATETIME;
1339 break;
1340 case NUMBERFORMAT_PERCENT :
1341 nSearch = CLOffset + ZF_STANDARD_PERCENT;
1342 break;
1343 case NUMBERFORMAT_SCIENTIFIC:
1344 nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC;
1345 break;
1346 default:
1347 nSearch = CLOffset + ZF_STANDARD;
1349 sal_uInt32 nDefaultFormat = (sal_uInt32)(sal_uIntPtr) aDefaultFormatKeys.Get( nSearch );
1350 if ( !nDefaultFormat )
1351 nDefaultFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
1352 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1353 { // look for a defined standard
1354 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
1355 sal_uInt32 nKey;
1356 aFTable.Seek( CLOffset );
1357 while ( (nKey = aFTable.GetCurKey()) >= CLOffset && nKey < nStopKey )
1359 const SvNumberformat* pEntry =
1360 (const SvNumberformat*) aFTable.GetCurObject();
1361 if ( pEntry->IsStandard() && ((pEntry->GetType() &
1362 ~NUMBERFORMAT_DEFINED) == nType) )
1364 nDefaultFormat = nKey;
1365 break; // while
1367 aFTable.Next();
1370 if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
1371 { // none found, use old fixed standards
1372 switch( nType )
1374 case NUMBERFORMAT_DATE :
1375 nDefaultFormat = CLOffset + ZF_STANDARD_DATE;
1376 break;
1377 case NUMBERFORMAT_TIME :
1378 nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1;
1379 break;
1380 case NUMBERFORMAT_DATETIME :
1381 nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME;
1382 break;
1383 case NUMBERFORMAT_PERCENT :
1384 nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1;
1385 break;
1386 case NUMBERFORMAT_SCIENTIFIC:
1387 nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC;
1388 break;
1389 default:
1390 nDefaultFormat = CLOffset + ZF_STANDARD;
1393 aDefaultFormatKeys.Insert( nSearch, (void*) nDefaultFormat );
1395 return nDefaultFormat;
1399 sal_uInt32 SvNumberFormatter::GetStandardFormat( short eType, LanguageType eLnge )
1401 sal_uInt32 CLOffset = ImpGenerateCL(eLnge);
1402 switch(eType)
1404 case NUMBERFORMAT_CURRENCY :
1406 if ( eLnge == LANGUAGE_SYSTEM )
1407 return ImpGetDefaultSystemCurrencyFormat();
1408 else
1409 return ImpGetDefaultCurrencyFormat();
1411 case NUMBERFORMAT_DATE :
1412 case NUMBERFORMAT_TIME :
1413 case NUMBERFORMAT_DATETIME :
1414 case NUMBERFORMAT_PERCENT :
1415 case NUMBERFORMAT_SCIENTIFIC:
1416 return ImpGetDefaultFormat( eType );
1418 case NUMBERFORMAT_FRACTION : return CLOffset + ZF_STANDARD_FRACTION;
1419 case NUMBERFORMAT_LOGICAL : return CLOffset + ZF_STANDARD_LOGICAL;
1420 case NUMBERFORMAT_TEXT : return CLOffset + ZF_STANDARD_TEXT;
1421 case NUMBERFORMAT_ALL :
1422 case NUMBERFORMAT_DEFINED :
1423 case NUMBERFORMAT_NUMBER :
1424 case NUMBERFORMAT_UNDEFINED :
1425 default : return CLOffset + ZF_STANDARD;
1429 BOOL SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex,
1430 LanguageType eLnge )
1432 return
1433 nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) ||
1434 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) ||
1435 nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge )
1439 sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, short eType,
1440 LanguageType eLnge )
1442 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1443 return nFIndex;
1444 else
1445 return GetStandardFormat( eType, eLnge );
1448 sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex,
1449 short eType, LanguageType eLnge )
1451 if ( IsSpecialStandardFormat( nFIndex, eLnge ) )
1452 return nFIndex;
1454 switch( eType )
1456 case NUMBERFORMAT_TIME :
1458 BOOL bSign;
1459 if ( fNumber < 0.0 )
1461 bSign = TRUE;
1462 fNumber = -fNumber;
1464 else
1465 bSign = FALSE;
1466 double fSeconds = fNumber * 86400;
1467 if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) )
1468 { // mit 100stel Sekunden
1469 if ( bSign || fSeconds >= 3600 )
1470 return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge );
1471 else
1472 return GetFormatIndex( NF_TIME_MMSS00, eLnge );
1474 else
1476 if ( bSign || fNumber >= 1.0 )
1477 return GetFormatIndex( NF_TIME_HH_MMSS, eLnge );
1478 else
1479 return GetStandardFormat( eType, eLnge );
1482 default:
1483 return GetStandardFormat( eType, eLnge );
1487 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1488 sal_uInt32 nFIndex,
1489 String& sOutString)
1491 SvNumberformat* pFormat;
1492 short nOldPrec;
1493 Color* pColor;
1494 pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1495 if (!pFormat)
1496 pFormat = aFTable.Get(ZF_STANDARD);
1497 LanguageType eLang = pFormat->GetLanguage();
1498 ChangeIntl( eLang );
1499 short eType = pFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1500 if (eType == 0)
1501 eType = NUMBERFORMAT_DEFINED;
1502 nOldPrec = -1;
1503 if (eType == NUMBERFORMAT_NUMBER || eType == NUMBERFORMAT_PERCENT
1504 || eType == NUMBERFORMAT_CURRENCY
1505 || eType == NUMBERFORMAT_SCIENTIFIC
1506 || eType == NUMBERFORMAT_FRACTION)
1508 if (eType != NUMBERFORMAT_PERCENT) // spaeter Sonderbehandlung %
1509 eType = NUMBERFORMAT_NUMBER;
1510 nOldPrec = pFormatScanner->GetStandardPrec();
1511 ChangeStandardPrec(300); // Merkwert
1513 sal_uInt32 nKey = nFIndex;
1514 switch ( eType )
1515 { // #61619# immer vierstelliges Jahr editieren
1516 case NUMBERFORMAT_DATE :
1517 nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1518 break;
1519 case NUMBERFORMAT_DATETIME :
1520 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1521 break;
1522 default:
1523 nKey = GetStandardFormat( fOutNumber, nFIndex, eType, eLang );
1525 if ( nKey != nFIndex )
1526 pFormat = (SvNumberformat*) aFTable.Get( nKey );
1527 if (pFormat)
1529 if ( eType == NUMBERFORMAT_TIME && pFormat->GetFormatPrecision() )
1531 nOldPrec = pFormatScanner->GetStandardPrec();
1532 ChangeStandardPrec(300); // Merkwert
1534 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1536 if (nOldPrec != -1)
1537 ChangeStandardPrec(nOldPrec);
1540 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1541 sal_uInt32 nFIndex,
1542 String& sOutString,
1543 Color** ppColor)
1545 if (bNoZero && fOutNumber == 0.0)
1547 sOutString.Erase();
1548 return;
1550 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1551 if (!pFormat)
1552 pFormat = aFTable.Get(ZF_STANDARD);
1553 ChangeIntl(pFormat->GetLanguage());
1554 pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1557 void SvNumberFormatter::GetOutputString(String& sString,
1558 sal_uInt32 nFIndex,
1559 String& sOutString,
1560 Color** ppColor)
1562 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1563 if (!pFormat)
1564 pFormat = aFTable.Get(ZF_STANDARD_TEXT);
1565 if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1567 *ppColor = NULL;
1568 sOutString = sString;
1570 else
1572 ChangeIntl(pFormat->GetLanguage());
1573 pFormat->GetOutputString(sString, sOutString, ppColor);
1577 BOOL SvNumberFormatter::GetPreviewString(const String& sFormatString,
1578 double fPreviewNumber,
1579 String& sOutString,
1580 Color** ppColor,
1581 LanguageType eLnge)
1583 if (sFormatString.Len() == 0) // keinen Leerstring
1584 return FALSE;
1586 xub_StrLen nCheckPos = STRING_NOTFOUND;
1587 sal_uInt32 nKey;
1588 if (eLnge == LANGUAGE_DONTKNOW)
1589 eLnge = IniLnge;
1590 ChangeIntl(eLnge); // ggfs. austauschen
1591 eLnge = ActLnge;
1592 String sTmpString = sFormatString;
1593 SvNumberformat* p_Entry = new SvNumberformat(sTmpString,
1594 pFormatScanner,
1595 pStringScanner,
1596 nCheckPos,
1597 eLnge);
1598 if (nCheckPos == 0) // String ok
1600 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
1601 // formate anlegen
1602 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge);
1603 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden
1604 GetOutputString(fPreviewNumber,nKey,sOutString,ppColor);
1605 else
1606 p_Entry->GetOutputString(fPreviewNumber,sOutString, ppColor);
1607 delete p_Entry;
1608 return TRUE;
1610 else
1612 delete p_Entry;
1613 return FALSE;
1617 BOOL SvNumberFormatter::GetPreviewStringGuess( const String& sFormatString,
1618 double fPreviewNumber,
1619 String& sOutString,
1620 Color** ppColor,
1621 LanguageType eLnge )
1623 if (sFormatString.Len() == 0) // keinen Leerstring
1624 return FALSE;
1626 if (eLnge == LANGUAGE_DONTKNOW)
1627 eLnge = IniLnge;
1629 ChangeIntl( eLnge );
1630 eLnge = ActLnge;
1631 BOOL bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1633 String aFormatStringUpper( pCharClass->upper( sFormatString ) );
1634 sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1635 sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1636 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1637 { // Zielformat vorhanden
1638 GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1639 return TRUE;
1642 SvNumberformat *pEntry = NULL;
1643 xub_StrLen nCheckPos = STRING_NOTFOUND;
1644 String sTmpString;
1646 if ( bEnglish )
1648 sTmpString = sFormatString;
1649 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1650 pStringScanner, nCheckPos, eLnge );
1652 else
1654 nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1655 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1656 BOOL bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1658 // try english --> other bzw. english nach other konvertieren
1659 LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1660 pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge );
1661 sTmpString = sFormatString;
1662 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1663 pStringScanner, nCheckPos, eFormatLang );
1664 pFormatScanner->SetConvertMode( FALSE );
1665 ChangeIntl( eLnge );
1667 if ( !bEnglishFormat )
1669 if ( nCheckPos > 0 || xTransliteration->isEqual( sFormatString,
1670 pEntry->GetFormatstring() ) )
1671 { // other Format
1672 delete pEntry;
1673 sTmpString = sFormatString;
1674 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1675 pStringScanner, nCheckPos, eLnge );
1677 else
1678 { // verify english
1679 xub_StrLen nCheckPos2 = STRING_NOTFOUND;
1680 // try other --> english
1681 eFormatLang = eLnge;
1682 pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US );
1683 sTmpString = sFormatString;
1684 SvNumberformat* pEntry2 = new SvNumberformat( sTmpString, pFormatScanner,
1685 pStringScanner, nCheckPos2, eFormatLang );
1686 pFormatScanner->SetConvertMode( FALSE );
1687 ChangeIntl( eLnge );
1688 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1689 pEntry2->GetFormatstring() ) )
1690 { // other Format
1691 delete pEntry;
1692 sTmpString = sFormatString;
1693 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1694 pStringScanner, nCheckPos, eLnge );
1696 delete pEntry2;
1701 if (nCheckPos == 0) // String ok
1703 ImpGenerateCL( eLnge ); // ggfs. neu Standardformate anlegen
1704 pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1705 delete pEntry;
1706 return TRUE;
1708 delete pEntry;
1709 return FALSE;
1712 sal_uInt32 SvNumberFormatter::TestNewString(const String& sFormatString,
1713 LanguageType eLnge)
1715 if (sFormatString.Len() == 0) // keinen Leerstring
1716 return NUMBERFORMAT_ENTRY_NOT_FOUND;
1718 xub_StrLen nCheckPos = STRING_NOTFOUND;
1719 if (eLnge == LANGUAGE_DONTKNOW)
1720 eLnge = IniLnge;
1721 ChangeIntl(eLnge); // ggfs. austauschen
1722 eLnge = ActLnge;
1723 sal_uInt32 nRes;
1724 String sTmpString = sFormatString;
1725 SvNumberformat* pEntry = new SvNumberformat(sTmpString,
1726 pFormatScanner,
1727 pStringScanner,
1728 nCheckPos,
1729 eLnge);
1730 if (nCheckPos == 0) // String ok
1732 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
1733 // formate anlegen
1734 nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge);
1735 // schon vorhanden ?
1737 else
1738 nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1739 delete pEntry;
1740 return nRes;
1743 SvNumberformat* SvNumberFormatter::ImpInsertFormat(
1744 const ::com::sun::star::i18n::NumberFormatCode& rCode,
1745 sal_uInt32 nPos, BOOL bAfterLoadingSO5, sal_Int16 nOrgIndex )
1747 String aCodeStr( rCode.Code );
1748 if ( rCode.Index < NF_INDEX_TABLE_ENTRIES &&
1749 rCode.Usage == ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY &&
1750 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1751 { // strip surrounding [$...] on automatic currency
1752 if ( aCodeStr.SearchAscii( "[$" ) != STRING_NOTFOUND )
1753 aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr, FALSE );
1754 else
1756 if (LocaleDataWrapper::areChecksEnabled() &&
1757 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1759 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1760 "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index "));
1761 aMsg += String::CreateFromInt32( rCode.Index );
1762 aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ":\n"));
1763 aMsg += String( rCode.Code );
1764 LocaleDataWrapper::outputCheckMessage(
1765 xLocaleData->appendLocaleInfo( aMsg));
1769 xub_StrLen nCheckPos = 0;
1770 SvNumberformat* pFormat = new SvNumberformat(aCodeStr,
1771 pFormatScanner,
1772 pStringScanner,
1773 nCheckPos,
1774 ActLnge);
1775 if ( !pFormat || nCheckPos > 0 )
1777 if (LocaleDataWrapper::areChecksEnabled())
1779 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1780 "SvNumberFormatter::ImpInsertFormat: bad format code, index "));
1781 aMsg += String::CreateFromInt32( rCode.Index );
1782 aMsg += '\n';
1783 aMsg += String( rCode.Code );
1784 LocaleDataWrapper::outputCheckMessage(
1785 xLocaleData->appendLocaleInfo( aMsg));
1787 delete pFormat;
1788 return NULL;
1790 if ( rCode.Index >= NF_INDEX_TABLE_ENTRIES )
1792 sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
1793 sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
1794 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1796 if (LocaleDataWrapper::areChecksEnabled())
1798 switch ( nOrgIndex )
1800 // These may be dupes of integer versions for locales where
1801 // currencies have no decimals like Italian Lira.
1802 case NF_CURRENCY_1000DEC2 : // NF_CURRENCY_1000INT
1803 case NF_CURRENCY_1000DEC2_RED : // NF_CURRENCY_1000INT_RED
1804 case NF_CURRENCY_1000DEC2_DASHED : // NF_CURRENCY_1000INT_RED
1805 break;
1806 default:
1807 if ( !bAfterLoadingSO5 )
1808 { // If bAfterLoadingSO5 there will definitely be some dupes,
1809 // don't cry. But we need this test for verification of locale
1810 // data if not loading old SO5 documents.
1811 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1812 "SvNumberFormatter::ImpInsertFormat: dup format code, index "));
1813 aMsg += String::CreateFromInt32( rCode.Index );
1814 aMsg += '\n';
1815 aMsg += String( rCode.Code );
1816 LocaleDataWrapper::outputCheckMessage(
1817 xLocaleData->appendLocaleInfo( aMsg));
1821 delete pFormat;
1822 return NULL;
1824 else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
1826 if (LocaleDataWrapper::areChecksEnabled())
1828 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1829 "SvNumberFormatter::ImpInsertFormat: too many format codes, index "));
1830 aMsg += String::CreateFromInt32( rCode.Index );
1831 aMsg += '\n';
1832 aMsg += String( rCode.Code );
1833 LocaleDataWrapper::outputCheckMessage(
1834 xLocaleData->appendLocaleInfo( aMsg));
1836 delete pFormat;
1837 return NULL;
1840 if ( !aFTable.Insert( nPos, pFormat ) )
1842 if (LocaleDataWrapper::areChecksEnabled())
1844 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1845 "ImpInsertFormat: can't insert number format key pos: "));
1846 aMsg += String::CreateFromInt32( nPos );
1847 aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", code index "));
1848 aMsg += String::CreateFromInt32( rCode.Index );
1849 aMsg += '\n';
1850 aMsg += String( rCode.Code );
1851 LocaleDataWrapper::outputCheckMessage(
1852 xLocaleData->appendLocaleInfo( aMsg));
1854 delete pFormat;
1855 return NULL;
1857 if ( rCode.Default )
1858 pFormat->SetStandard();
1859 if ( rCode.DefaultName.getLength() )
1860 pFormat->SetComment( rCode.DefaultName );
1861 return pFormat;
1864 SvNumberformat* SvNumberFormatter::ImpInsertNewStandardFormat(
1865 const ::com::sun::star::i18n::NumberFormatCode& rCode,
1866 sal_uInt32 nPos, USHORT nVersion, BOOL bAfterLoadingSO5,
1867 sal_Int16 nOrgIndex )
1869 SvNumberformat* pNewFormat = ImpInsertFormat( rCode, nPos,
1870 bAfterLoadingSO5, nOrgIndex );
1871 if (pNewFormat)
1872 pNewFormat->SetNewStandardDefined( nVersion );
1873 // so that it gets saved, displayed properly, and converted by old versions
1874 return pNewFormat;
1877 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
1878 BOOL& bThousand,
1879 BOOL& IsRed,
1880 USHORT& nPrecision,
1881 USHORT& nAnzLeading)
1884 const SvNumberformat* pFormat = aFTable.Get(nFormat);
1885 if (pFormat)
1886 pFormat->GetFormatSpecialInfo(bThousand, IsRed,
1887 nPrecision, nAnzLeading);
1888 else
1890 bThousand = FALSE;
1891 IsRed = FALSE;
1892 nPrecision = pFormatScanner->GetStandardPrec();
1893 nAnzLeading = 0;
1897 USHORT SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
1899 const SvNumberformat* pFormat = aFTable.Get( nFormat );
1900 if ( pFormat )
1901 return pFormat->GetFormatPrecision();
1902 else
1903 return pFormatScanner->GetStandardPrec();
1907 String SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
1909 const SvNumberformat* pFormat = aFTable.Get( nFormat );
1910 if ( !pFormat || pFormat->GetLanguage() == ActLnge )
1911 return GetNumDecimalSep();
1913 String aRet;
1914 LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
1915 if ( pFormat->GetLanguage() == eSaveLang )
1916 aRet = xLocaleData->getNumDecimalSep();
1917 else
1919 ::com::sun::star::lang::Locale aSaveLocale( xLocaleData->getLocale() );
1920 ::com::sun::star::lang::Locale aTmpLocale(MsLangId::convertLanguageToLocale(pFormat->GetLanguage()));
1921 ((SvNumberFormatter*)this)->xLocaleData.changeLocale(aTmpLocale, pFormat->GetLanguage() );
1922 aRet = xLocaleData->getNumDecimalSep();
1923 ((SvNumberFormatter*)this)->xLocaleData.changeLocale( aSaveLocale, eSaveLang );
1925 return aRet;
1929 sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const String& rFormatString,
1930 BOOL& bThousand, BOOL& IsRed, USHORT& nPrecision,
1931 USHORT& nAnzLeading, LanguageType eLnge )
1934 xub_StrLen nCheckPos = 0;
1935 if (eLnge == LANGUAGE_DONTKNOW)
1936 eLnge = IniLnge;
1937 ChangeIntl(eLnge); // ggfs. austauschen
1938 eLnge = ActLnge;
1939 String aTmpStr( rFormatString );
1940 SvNumberformat* pFormat = new SvNumberformat( aTmpStr,
1941 pFormatScanner, pStringScanner, nCheckPos, eLnge );
1942 if ( nCheckPos == 0 )
1943 pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nAnzLeading );
1944 else
1946 bThousand = FALSE;
1947 IsRed = FALSE;
1948 nPrecision = pFormatScanner->GetStandardPrec();
1949 nAnzLeading = 0;
1951 delete pFormat;
1952 return nCheckPos;
1956 inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff )
1958 if ( !bIndexTableInitialized )
1960 DBG_ASSERT( theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
1961 "SetIndexTable: theIndexTable[nTabOff] already occupied" );
1962 theIndexTable[nTabOff] = nIndOff;
1964 return nIndOff;
1968 sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex(
1969 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode >& rSeq,
1970 const NfIndexTableOffset nTabOff )
1972 const sal_Int32 nLen = rSeq.getLength();
1973 for ( sal_Int32 j=0; j<nLen; j++ )
1975 if ( rSeq[j].Index == nTabOff )
1976 return j;
1978 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START
1979 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
1980 || nTabOff == NF_CURRENCY_1000INT_RED
1981 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
1982 { // currency entries with decimals might not exist, e.g. Italian Lira
1983 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1984 "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "));
1985 aMsg += String::CreateFromInt32( nTabOff );
1986 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo(
1987 aMsg));
1989 if ( nLen )
1991 sal_Int32 j;
1992 // look for a preset default
1993 for ( j=0; j<nLen; j++ )
1995 if ( rSeq[j].Default )
1996 return j;
1998 // currencies are special, not all format codes must exist, but all
1999 // builtin number format key index positions must have a format assigned
2000 if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
2002 // look for a format with decimals
2003 for ( j=0; j<nLen; j++ )
2005 if ( rSeq[j].Index == NF_CURRENCY_1000DEC2 )
2006 return j;
2008 // last resort: look for a format without decimals
2009 for ( j=0; j<nLen; j++ )
2011 if ( rSeq[j].Index == NF_CURRENCY_1000INT )
2012 return j;
2016 else
2017 { // we need at least _some_ format
2018 rSeq.realloc(1);
2019 rSeq[0] = ::com::sun::star::i18n::NumberFormatCode();
2020 String aTmp( '0' );
2021 aTmp += GetNumDecimalSep();
2022 aTmp.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "############" ) );
2023 rSeq[0].Code = aTmp;
2025 return 0;
2029 sal_Int32 SvNumberFormatter::ImpAdjustFormatCodeDefault(
2030 ::com::sun::star::i18n::NumberFormatCode * pFormatArr,
2031 sal_Int32 nCnt, BOOL bCheckCorrectness )
2033 using namespace ::com::sun::star;
2035 if ( !nCnt )
2036 return -1;
2037 if (bCheckCorrectness && LocaleDataWrapper::areChecksEnabled())
2038 { // check the locale data for correctness
2039 ByteString aMsg;
2040 sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
2041 nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
2042 for ( nElem = 0; nElem < nCnt; nElem++ )
2044 switch ( pFormatArr[nElem].Type )
2046 case i18n::KNumberFormatType::SHORT :
2047 nShort = nElem;
2048 break;
2049 case i18n::KNumberFormatType::MEDIUM :
2050 nMedium = nElem;
2051 break;
2052 case i18n::KNumberFormatType::LONG :
2053 nLong = nElem;
2054 break;
2055 default:
2056 aMsg = "unknown type";
2058 if ( pFormatArr[nElem].Default )
2060 switch ( pFormatArr[nElem].Type )
2062 case i18n::KNumberFormatType::SHORT :
2063 if ( nShortDef != -1 )
2064 aMsg = "dupe short type default";
2065 nShortDef = nElem;
2066 break;
2067 case i18n::KNumberFormatType::MEDIUM :
2068 if ( nMediumDef != -1 )
2069 aMsg = "dupe medium type default";
2070 nMediumDef = nElem;
2071 break;
2072 case i18n::KNumberFormatType::LONG :
2073 if ( nLongDef != -1 )
2074 aMsg = "dupe long type default";
2075 nLongDef = nElem;
2076 break;
2079 if ( aMsg.Len() )
2081 aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 );
2082 aMsg += "\nXML locale data FormatElement formatindex: ";
2083 aMsg += ByteString::CreateFromInt32( pFormatArr[nElem].Index );
2084 String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US);
2085 LocaleDataWrapper::outputCheckMessage(
2086 xLocaleData->appendLocaleInfo( aUMsg));
2087 aMsg.Erase();
2090 if ( nShort != -1 && nShortDef == -1 )
2091 aMsg += "no short type default ";
2092 if ( nMedium != -1 && nMediumDef == -1 )
2093 aMsg += "no medium type default ";
2094 if ( nLong != -1 && nLongDef == -1 )
2095 aMsg += "no long type default ";
2096 if ( aMsg.Len() )
2098 aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 );
2099 aMsg += "\nXML locale data FormatElement group of: ";
2100 String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US);
2101 aUMsg += String( pFormatArr[0].NameID );
2102 LocaleDataWrapper::outputCheckMessage(
2103 xLocaleData->appendLocaleInfo( aUMsg));
2104 aMsg.Erase();
2107 // find the default (medium preferred, then long) and reset all other defaults
2108 sal_Int32 nElem, nDef, nMedium;
2109 nDef = nMedium = -1;
2110 for ( nElem = 0; nElem < nCnt; nElem++ )
2112 if ( pFormatArr[nElem].Default )
2114 switch ( pFormatArr[nElem].Type )
2116 case i18n::KNumberFormatType::MEDIUM :
2117 nDef = nMedium = nElem;
2118 break;
2119 case i18n::KNumberFormatType::LONG :
2120 if ( nMedium == -1 )
2121 nDef = nElem;
2122 // fallthru
2123 default:
2124 if ( nDef == -1 )
2125 nDef = nElem;
2126 pFormatArr[nElem].Default = sal_False;
2130 if ( nDef == -1 )
2131 nDef = 0;
2132 pFormatArr[nDef].Default = sal_True;
2133 return nDef;
2137 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, BOOL bLoadingSO5 )
2139 using namespace ::com::sun::star;
2141 if ( !bIndexTableInitialized )
2143 for ( USHORT j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
2145 theIndexTable[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
2148 BOOL bOldConvertMode = pFormatScanner->GetConvertMode();
2149 if (bOldConvertMode)
2150 pFormatScanner->SetConvertMode(FALSE); // switch off for this function
2152 NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() );
2154 xub_StrLen nCheckPos = 0;
2155 SvNumberformat* pNewFormat = NULL;
2156 String aFormatCode;
2157 sal_Int32 nIdx;
2158 sal_Bool bDefault;
2160 // Counter for additional builtin formats not fitting into the first 10
2161 // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2162 // Has to be incremented on each ImpInsertNewStandardformat, new formats
2163 // must be appended, not inserted!
2164 USHORT nNewExtended = ZF_STANDARD_NEWEXTENDED;
2166 // Number
2167 uno::Sequence< i18n::NumberFormatCode > aFormatSeq
2168 = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER );
2169 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2171 // General
2172 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2173 SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2174 CLOffset + SetIndexTable( NF_NUMBER_STANDARD, ZF_STANDARD ));
2175 if (pStdFormat)
2177 // This is _the_ standard format.
2178 if (LocaleDataWrapper::areChecksEnabled() &&
2179 pStdFormat->GetType() != NUMBERFORMAT_NUMBER)
2181 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2182 "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2183 LocaleDataWrapper::outputCheckMessage(
2184 xLocaleData->appendLocaleInfo( aMsg));
2186 pStdFormat->SetType( NUMBERFORMAT_NUMBER );
2187 pStdFormat->SetStandard();
2188 pStdFormat->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE );
2190 else
2192 if (LocaleDataWrapper::areChecksEnabled())
2194 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2195 "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2196 LocaleDataWrapper::outputCheckMessage(
2197 xLocaleData->appendLocaleInfo( aMsg));
2201 // Boolean
2202 aFormatCode = pFormatScanner->GetBooleanString();
2203 pNewFormat = new SvNumberformat( aFormatCode,
2204 pFormatScanner, pStringScanner, nCheckPos, ActLnge );
2205 pNewFormat->SetType(NUMBERFORMAT_LOGICAL);
2206 pNewFormat->SetStandard();
2207 if ( !aFTable.Insert(
2208 CLOffset + SetIndexTable( NF_BOOLEAN, ZF_STANDARD_LOGICAL ),
2209 pNewFormat))
2210 delete pNewFormat;
2212 // Text
2213 aFormatCode = '@';
2214 pNewFormat = new SvNumberformat( aFormatCode,
2215 pFormatScanner, pStringScanner, nCheckPos, ActLnge );
2216 pNewFormat->SetType(NUMBERFORMAT_TEXT);
2217 pNewFormat->SetStandard();
2218 if ( !aFTable.Insert(
2219 CLOffset + SetIndexTable( NF_TEXT, ZF_STANDARD_TEXT ),
2220 pNewFormat))
2221 delete pNewFormat;
2225 // 0
2226 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2227 ImpInsertFormat( aFormatSeq[nIdx],
2228 CLOffset + SetIndexTable( NF_NUMBER_INT, ZF_STANDARD+1 ));
2230 // 0.00
2231 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2232 ImpInsertFormat( aFormatSeq[nIdx],
2233 CLOffset + SetIndexTable( NF_NUMBER_DEC2, ZF_STANDARD+2 ));
2235 // #,##0
2236 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2237 ImpInsertFormat( aFormatSeq[nIdx],
2238 CLOffset + SetIndexTable( NF_NUMBER_1000INT, ZF_STANDARD+3 ));
2240 // #,##0.00
2241 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2242 ImpInsertFormat( aFormatSeq[nIdx],
2243 CLOffset + SetIndexTable( NF_NUMBER_1000DEC2, ZF_STANDARD+4 ));
2245 // #.##0,00 System country/language dependent since number formatter version 6
2246 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2247 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2248 CLOffset + SetIndexTable( NF_NUMBER_SYSTEM, ZF_STANDARD+5 ),
2249 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2252 // Percent number
2253 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER );
2254 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2256 // 0%
2257 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2258 ImpInsertFormat( aFormatSeq[nIdx],
2259 CLOffset + SetIndexTable( NF_PERCENT_INT, ZF_STANDARD_PERCENT ));
2261 // 0.00%
2262 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2263 ImpInsertFormat( aFormatSeq[nIdx],
2264 CLOffset + SetIndexTable( NF_PERCENT_DEC2, ZF_STANDARD_PERCENT+1 ));
2268 // Currency. NO default standard option! Default is determined of locale
2269 // data default currency and format is generated if needed.
2270 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2271 if (LocaleDataWrapper::areChecksEnabled())
2273 // though no default desired here, test for correctness of locale data
2274 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2277 // #,##0
2278 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2279 bDefault = aFormatSeq[nIdx].Default;
2280 aFormatSeq[nIdx].Default = sal_False;
2281 ImpInsertFormat( aFormatSeq[nIdx],
2282 CLOffset + SetIndexTable( NF_CURRENCY_1000INT, ZF_STANDARD_CURRENCY ));
2283 aFormatSeq[nIdx].Default = bDefault;
2285 // #,##0.00
2286 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2287 bDefault = aFormatSeq[nIdx].Default;
2288 aFormatSeq[nIdx].Default = sal_False;
2289 ImpInsertFormat( aFormatSeq[nIdx],
2290 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2, ZF_STANDARD_CURRENCY+1 ));
2291 aFormatSeq[nIdx].Default = bDefault;
2293 // #,##0 negative red
2294 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2295 bDefault = aFormatSeq[nIdx].Default;
2296 aFormatSeq[nIdx].Default = sal_False;
2297 ImpInsertFormat( aFormatSeq[nIdx],
2298 CLOffset + SetIndexTable( NF_CURRENCY_1000INT_RED, ZF_STANDARD_CURRENCY+2 ));
2299 aFormatSeq[nIdx].Default = bDefault;
2301 // #,##0.00 negative red
2302 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2303 bDefault = aFormatSeq[nIdx].Default;
2304 aFormatSeq[nIdx].Default = sal_False;
2305 ImpInsertFormat( aFormatSeq[nIdx],
2306 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_RED, ZF_STANDARD_CURRENCY+3 ));
2307 aFormatSeq[nIdx].Default = bDefault;
2309 // #,##0.00 USD since number formatter version 3
2310 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2311 bDefault = aFormatSeq[nIdx].Default;
2312 aFormatSeq[nIdx].Default = sal_False;
2313 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2314 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_CCC, ZF_STANDARD_CURRENCY+4 ));
2315 if ( pNewFormat )
2316 pNewFormat->SetUsed(TRUE); // must be saved for older versions
2317 aFormatSeq[nIdx].Default = bDefault;
2319 // #.##0,-- since number formatter version 6
2320 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED );
2321 bDefault = aFormatSeq[nIdx].Default;
2322 aFormatSeq[nIdx].Default = sal_False;
2323 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2324 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_DASHED, ZF_STANDARD_CURRENCY+5 ),
2325 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2326 aFormatSeq[nIdx].Default = bDefault;
2330 // Date
2331 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE );
2332 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2334 // DD.MM.YY System
2335 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2336 ImpInsertFormat( aFormatSeq[nIdx],
2337 CLOffset + SetIndexTable( NF_DATE_SYSTEM_SHORT, ZF_STANDARD_DATE ));
2339 // NN DD.MMM YY
2340 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2341 ImpInsertFormat( aFormatSeq[nIdx],
2342 CLOffset + SetIndexTable( NF_DATE_DEF_NNDDMMMYY, ZF_STANDARD_DATE+1 ));
2344 // DD.MM.YY def/System
2345 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2346 ImpInsertFormat( aFormatSeq[nIdx],
2347 CLOffset + SetIndexTable( NF_DATE_SYS_MMYY, ZF_STANDARD_DATE+2 ));
2349 // DD MMM
2350 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2351 ImpInsertFormat( aFormatSeq[nIdx],
2352 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMM, ZF_STANDARD_DATE+3 ));
2354 // MMMM
2355 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2356 ImpInsertFormat( aFormatSeq[nIdx],
2357 CLOffset + SetIndexTable( NF_DATE_MMMM, ZF_STANDARD_DATE+4 ));
2359 // QQ YY
2360 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2361 ImpInsertFormat( aFormatSeq[nIdx],
2362 CLOffset + SetIndexTable( NF_DATE_QQJJ, ZF_STANDARD_DATE+5 ));
2364 // DD.MM.YYYY since number formatter version 2, was DD.MM.[YY]YY
2365 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2366 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2367 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYYYY, ZF_STANDARD_DATE+6 ));
2368 if ( pNewFormat )
2369 pNewFormat->SetUsed(TRUE); // must be saved for older versions
2371 // DD.MM.YY def/System, since number formatter version 6
2372 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2373 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2374 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYY, ZF_STANDARD_DATE+7 ),
2375 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2377 // NNN, D. MMMM YYYY System
2378 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2379 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2380 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2381 CLOffset + SetIndexTable( NF_DATE_SYSTEM_LONG, ZF_STANDARD_DATE+8 ),
2382 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2384 // Hard coded but system (regional settings) delimiters dependent long date formats
2385 // since numberformatter version 6
2387 // D. MMM YY def/System
2388 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2389 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2390 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYY, ZF_STANDARD_DATE+9 ),
2391 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2393 //! Unfortunally TLOT intended only 10 builtin formats per category, more
2394 //! would overwrite the next category (ZF_STANDARD_TIME) :-((
2395 //! Therefore they are inserted with nNewExtended++ (which is also limited)
2397 // D. MMM YYYY def/System
2398 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2399 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2400 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYYYY, nNewExtended++ ),
2401 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2403 // D. MMMM YYYY def/System
2404 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2405 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2406 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMMYYYY, nNewExtended++ ),
2407 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2409 // NN, D. MMM YY def/System
2410 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2411 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2412 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMYY, nNewExtended++ ),
2413 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2415 // NN, D. MMMM YYYY def/System
2416 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2417 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2418 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY, nNewExtended++ ),
2419 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2421 // NNN, D. MMMM YYYY def/System
2422 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY );
2423 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2424 CLOffset + SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY, nNewExtended++ ),
2425 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2427 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2429 // D. MMM. YYYY DIN/EN
2430 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2431 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2432 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMYYYY, nNewExtended++ ),
2433 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2435 // D. MMMM YYYY DIN/EN
2436 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2437 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2438 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMMYYYY, nNewExtended++ ),
2439 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2441 // MM-DD DIN/EN
2442 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2443 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2444 CLOffset + SetIndexTable( NF_DATE_DIN_MMDD, nNewExtended++ ),
2445 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2447 // YY-MM-DD DIN/EN
2448 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2449 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2450 CLOffset + SetIndexTable( NF_DATE_DIN_YYMMDD, nNewExtended++ ),
2451 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2453 // YYYY-MM-DD DIN/EN
2454 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2455 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2456 CLOffset + SetIndexTable( NF_DATE_DIN_YYYYMMDD, nNewExtended++ ),
2457 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2461 // Time
2462 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::TIME );
2463 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2465 // HH:MM
2466 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2467 ImpInsertFormat( aFormatSeq[nIdx],
2468 CLOffset + SetIndexTable( NF_TIME_HHMM, ZF_STANDARD_TIME ));
2470 // HH:MM:SS
2471 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2472 ImpInsertFormat( aFormatSeq[nIdx],
2473 CLOffset + SetIndexTable( NF_TIME_HHMMSS, ZF_STANDARD_TIME+1 ));
2475 // HH:MM AM/PM
2476 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2477 ImpInsertFormat( aFormatSeq[nIdx],
2478 CLOffset + SetIndexTable( NF_TIME_HHMMAMPM, ZF_STANDARD_TIME+2 ));
2480 // HH:MM:SS AM/PM
2481 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2482 ImpInsertFormat( aFormatSeq[nIdx],
2483 CLOffset + SetIndexTable( NF_TIME_HHMMSSAMPM, ZF_STANDARD_TIME+3 ));
2485 // [HH]:MM:SS
2486 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2487 ImpInsertFormat( aFormatSeq[nIdx],
2488 CLOffset + SetIndexTable( NF_TIME_HH_MMSS, ZF_STANDARD_TIME+4 ));
2490 // MM:SS,00
2491 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2492 ImpInsertFormat( aFormatSeq[nIdx],
2493 CLOffset + SetIndexTable( NF_TIME_MMSS00, ZF_STANDARD_TIME+5 ));
2495 // [HH]:MM:SS,00
2496 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2497 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2498 CLOffset + SetIndexTable( NF_TIME_HH_MMSS00, ZF_STANDARD_TIME+6 ),
2499 SV_NUMBERFORMATTER_VERSION_NF_TIME_HH_MMSS00 );
2503 // DateTime
2504 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME );
2505 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2507 // DD.MM.YY HH:MM System
2508 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM );
2509 ImpInsertFormat( aFormatSeq[nIdx],
2510 CLOffset + SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM, ZF_STANDARD_DATETIME ));
2512 // DD.MM.YYYY HH:MM:SS System
2513 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2514 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2515 CLOffset + SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, ZF_STANDARD_DATETIME+1 ),
2516 SV_NUMBERFORMATTER_VERSION_NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2520 // Scientific number
2521 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER );
2522 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2524 // 0.00E+000
2525 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2526 ImpInsertFormat( aFormatSeq[nIdx],
2527 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E000, ZF_STANDARD_SCIENTIFIC ));
2529 // 0.00E+00
2530 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2531 ImpInsertFormat( aFormatSeq[nIdx],
2532 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E00, ZF_STANDARD_SCIENTIFIC+1 ));
2536 // Fraction number (no default option)
2537 i18n::NumberFormatCode aSingleFormatCode;
2539 // # ?/?
2540 aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) );
2541 String s25( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) ); // # ?/?
2542 ImpInsertFormat( aSingleFormatCode,
2543 CLOffset + SetIndexTable( NF_FRACTION_1, ZF_STANDARD_FRACTION ));
2545 // # ??/??
2546 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2547 aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?\?/?\?" ) );
2548 ImpInsertFormat( aSingleFormatCode,
2549 CLOffset + SetIndexTable( NF_FRACTION_2, ZF_STANDARD_FRACTION+1 ));
2551 // Week of year must be appended here because of nNewExtended
2552 const String* pKeyword = pFormatScanner->GetKeywords();
2553 aSingleFormatCode.Code = pKeyword[NF_KEY_WW];
2554 ImpInsertNewStandardFormat( aSingleFormatCode,
2555 CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ),
2556 SV_NUMBERFORMATTER_VERSION_NF_DATE_WW );
2560 bIndexTableInitialized = TRUE;
2561 DBG_ASSERT( nNewExtended <= ZF_STANDARD_NEWEXTENDEDMAX,
2562 "ImpGenerateFormats: overflow of nNewExtended standard formats" );
2564 // Now all additional format codes provided by I18N, but only if not
2565 // loading from old SO5 file format, then they are appended last.
2566 if ( !bLoadingSO5 )
2567 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, FALSE );
2569 if (bOldConvertMode)
2570 pFormatScanner->SetConvertMode(TRUE);
2574 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset,
2575 NumberFormatCodeWrapper& rNumberFormatCode, BOOL bAfterLoadingSO5 )
2577 using namespace ::com::sun::star;
2579 SvNumberformat* pStdFormat =
2580 (SvNumberformat*) aFTable.Get( CLOffset + ZF_STANDARD );
2581 if ( !pStdFormat )
2583 DBG_ERRORFILE( "ImpGenerateAdditionalFormats: no GENERAL format" );
2584 return ;
2586 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
2587 rNumberFormatCode.setLocale( GetLocale() );
2588 sal_Int32 j;
2590 // All currencies, this time with [$...] which was stripped in
2591 // ImpGenerateFormats for old "automatic" currency formats.
2592 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2593 rNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2594 i18n::NumberFormatCode * pFormatArr = aFormatSeq.getArray();
2595 sal_Int32 nCodes = aFormatSeq.getLength();
2596 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes );
2597 for ( j = 0; j < nCodes; j++ )
2599 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2601 DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" );
2602 break; // for
2604 if ( pFormatArr[j].Index < NF_INDEX_TABLE_ENTRIES &&
2605 pFormatArr[j].Index != NF_CURRENCY_1000DEC2_CCC )
2606 { // Insert only if not already inserted, but internal index must be
2607 // above so ImpInsertFormat can distinguish it.
2608 sal_Int16 nOrgIndex = pFormatArr[j].Index;
2609 pFormatArr[j].Index = sal::static_int_cast< sal_Int16 >(
2610 pFormatArr[j].Index + nCodes + NF_INDEX_TABLE_ENTRIES);
2611 //! no default on currency
2612 sal_Bool bDefault = aFormatSeq[j].Default;
2613 aFormatSeq[j].Default = sal_False;
2614 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2615 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2616 bAfterLoadingSO5, nOrgIndex ) )
2617 nPos++;
2618 pFormatArr[j].Index = nOrgIndex;
2619 aFormatSeq[j].Default = bDefault;
2623 // all additional format codes provided by I18N that are not old standard index
2624 aFormatSeq = rNumberFormatCode.getAllFormatCodes();
2625 nCodes = aFormatSeq.getLength();
2626 if ( nCodes )
2628 pFormatArr = aFormatSeq.getArray();
2629 // don't check ALL
2630 sal_Int32 nDef = ImpAdjustFormatCodeDefault( pFormatArr, nCodes, FALSE);
2631 // don't have any defaults here
2632 pFormatArr[nDef].Default = sal_False;
2633 for ( j = 0; j < nCodes; j++ )
2635 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2637 DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" );
2638 break; // for
2640 if ( pFormatArr[j].Index >= NF_INDEX_TABLE_ENTRIES )
2641 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2642 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2643 bAfterLoadingSO5 ) )
2644 nPos++;
2648 pStdFormat->SetLastInsertKey( (USHORT)(nPos - CLOffset) );
2652 void SvNumberFormatter::ImpGetPosCurrFormat( String& sPosStr, const String& rCurrSymbol )
2654 NfCurrencyEntry::CompletePositiveFormatString( sPosStr,
2655 rCurrSymbol, xLocaleData->getCurrPositiveFormat() );
2658 void SvNumberFormatter::ImpGetNegCurrFormat( String& sNegStr, const String& rCurrSymbol )
2660 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
2661 rCurrSymbol, xLocaleData->getCurrNegativeFormat() );
2664 void SvNumberFormatter::GenerateFormat(String& sString,
2665 sal_uInt32 nIndex,
2666 LanguageType eLnge,
2667 BOOL bThousand,
2668 BOOL IsRed,
2669 USHORT nPrecision,
2670 USHORT nAnzLeading)
2672 if (eLnge == LANGUAGE_DONTKNOW)
2673 eLnge = IniLnge;
2674 short eType = GetType(nIndex);
2675 USHORT i;
2676 ImpGenerateCL(eLnge); // ggfs. neu Standard-
2677 // formate anlegen
2678 sString.Erase();
2680 utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping());
2681 const xub_StrLen nDigitsInFirstGroup = static_cast<xub_StrLen>(aGrouping.get());
2682 const String& rThSep = GetNumThousandSep();
2683 if (nAnzLeading == 0)
2685 if (!bThousand)
2686 sString += '#';
2687 else
2689 sString += '#';
2690 sString += rThSep;
2691 sString.Expand( sString.Len() + nDigitsInFirstGroup, '#' );
2694 else
2696 for (i = 0; i < nAnzLeading; i++)
2698 if (bThousand && i > 0 && i == aGrouping.getPos())
2700 sString.Insert( rThSep, 0 );
2701 aGrouping.advance();
2703 sString.Insert('0',0);
2705 if (bThousand && nAnzLeading < nDigitsInFirstGroup + 1)
2707 for (i = nAnzLeading; i < nDigitsInFirstGroup + 1; i++)
2709 if (bThousand && i % nDigitsInFirstGroup == 0)
2710 sString.Insert( rThSep, 0 );
2711 sString.Insert('#',0);
2715 if (nPrecision > 0)
2717 sString += GetNumDecimalSep();
2718 sString.Expand( sString.Len() + nPrecision, '0' );
2720 if (eType == NUMBERFORMAT_PERCENT)
2721 sString += '%';
2722 else if (eType == NUMBERFORMAT_CURRENCY)
2724 String sNegStr = sString;
2725 String aCurr;
2726 const NfCurrencyEntry* pEntry;
2727 BOOL bBank;
2728 if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
2730 if ( pEntry )
2732 USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2733 xLocaleData->getCurrPositiveFormat(),
2734 pEntry->GetPositiveFormat(), bBank );
2735 USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2736 xLocaleData->getCurrNegativeFormat(),
2737 pEntry->GetNegativeFormat(), bBank );
2738 pEntry->CompletePositiveFormatString( sString, bBank,
2739 nPosiForm );
2740 pEntry->CompleteNegativeFormatString( sNegStr, bBank,
2741 nNegaForm );
2743 else
2744 { // assume currency abbreviation (AKA banking symbol), not symbol
2745 USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2746 xLocaleData->getCurrPositiveFormat(),
2747 xLocaleData->getCurrPositiveFormat(), TRUE );
2748 USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2749 xLocaleData->getCurrNegativeFormat(),
2750 xLocaleData->getCurrNegativeFormat(), TRUE );
2751 NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr,
2752 nPosiForm );
2753 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr,
2754 nNegaForm );
2757 else
2758 { // "automatic" old style
2759 String aSymbol, aAbbrev;
2760 GetCompatibilityCurrency( aSymbol, aAbbrev );
2761 ImpGetPosCurrFormat( sString, aSymbol );
2762 ImpGetNegCurrFormat( sNegStr, aSymbol );
2764 if (IsRed)
2766 sString += ';';
2767 sString += '[';
2768 sString += pFormatScanner->GetRedString();
2769 sString += ']';
2771 else
2772 sString += ';';
2773 sString += sNegStr;
2775 if (IsRed && eType != NUMBERFORMAT_CURRENCY)
2777 String sTmpStr = sString;
2778 sTmpStr += ';';
2779 sTmpStr += '[';
2780 sTmpStr += pFormatScanner->GetRedString();
2781 sTmpStr += ']';
2782 sTmpStr += '-';
2783 sTmpStr +=sString;
2784 sString = sTmpStr;
2788 BOOL SvNumberFormatter::IsUserDefined(const String& sStr,
2789 LanguageType eLnge)
2791 if (eLnge == LANGUAGE_DONTKNOW)
2792 eLnge = IniLnge;
2793 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
2794 // formate anlegen
2795 eLnge = ActLnge;
2796 sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
2797 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
2798 return TRUE;
2799 SvNumberformat* pEntry = aFTable.Get(nKey);
2800 if ( pEntry && ((pEntry->GetType() & NUMBERFORMAT_DEFINED) != 0) )
2801 return TRUE;
2802 return FALSE;
2805 sal_uInt32 SvNumberFormatter::GetEntryKey(const String& sStr,
2806 LanguageType eLnge)
2808 if (eLnge == LANGUAGE_DONTKNOW)
2809 eLnge = IniLnge;
2810 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
2811 // formate anlegen
2812 return ImpIsEntry(sStr, CLOffset, eLnge);
2815 sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge)
2817 if (eLnge == LANGUAGE_DONTKNOW)
2818 eLnge = IniLnge;
2819 return GetStandardFormat(NUMBERFORMAT_NUMBER, eLnge);
2822 short SvNumberFormatter::GetType(sal_uInt32 nFIndex)
2824 short eType;
2825 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
2826 if (!pFormat)
2827 eType = NUMBERFORMAT_UNDEFINED;
2828 else
2830 eType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
2831 if (eType == 0)
2832 eType = NUMBERFORMAT_DEFINED;
2834 return eType;
2837 void SvNumberFormatter::ClearMergeTable()
2839 if ( pMergeTable )
2841 sal_uInt32* pIndex = (sal_uInt32*) pMergeTable->First();
2842 while (pIndex)
2844 delete pIndex;
2845 pIndex = pMergeTable->Next();
2847 pMergeTable->Clear();
2851 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
2853 if ( pMergeTable )
2854 ClearMergeTable();
2855 else
2856 pMergeTable = new SvNumberFormatterIndexTable;
2857 sal_uInt32 nCLOffset = 0;
2858 sal_uInt32 nOldKey, nOffset, nNewKey;
2859 sal_uInt32* pNewIndex;
2860 SvNumberformat* pNewEntry;
2861 SvNumberformat* pFormat = rTable.aFTable.First();
2862 while (pFormat)
2864 nOldKey = rTable.aFTable.GetCurKey();
2865 nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
2866 if (nOffset == 0) // 1. Format von CL
2867 nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
2869 if (nOffset <= SV_MAX_ANZ_STANDARD_FORMATE) // Std.form.
2871 nNewKey = nCLOffset + nOffset;
2872 if (!aFTable.Get(nNewKey)) // noch nicht da
2874 // pNewEntry = new SvNumberformat(*pFormat); // Copy reicht nicht !!!
2875 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2876 if (!aFTable.Insert(nNewKey, pNewEntry))
2877 delete pNewEntry;
2879 if (nNewKey != nOldKey) // neuer Index
2881 pNewIndex = new sal_uInt32(nNewKey);
2882 if (!pMergeTable->Insert(nOldKey,pNewIndex))
2883 delete pNewIndex;
2886 else // benutzerdef.
2888 // pNewEntry = new SvNumberformat(*pFormat); // Copy reicht nicht !!!
2889 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2890 nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
2891 nCLOffset,
2892 pFormat->GetLanguage());
2893 if (nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden
2894 delete pNewEntry;
2895 else
2897 SvNumberformat* pStdFormat =
2898 (SvNumberformat*) aFTable.Get(nCLOffset + ZF_STANDARD);
2899 sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey();
2900 nNewKey = nPos+1;
2901 if (nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
2903 Sound::Beep();
2904 DBG_ERROR(
2905 "SvNumberFormatter:: Zu viele Formate pro CL");
2906 delete pNewEntry;
2908 else if (!aFTable.Insert(nNewKey, pNewEntry))
2909 delete pNewEntry;
2910 else
2911 pStdFormat->SetLastInsertKey((USHORT) (nNewKey - nCLOffset));
2913 if (nNewKey != nOldKey) // neuer Index
2915 pNewIndex = new sal_uInt32(nNewKey);
2916 if (!pMergeTable->Insert(nOldKey,pNewIndex))
2917 delete pNewIndex;
2920 pFormat = rTable.aFTable.Next();
2922 return pMergeTable;
2926 SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap()
2928 if (!HasMergeFmtTbl())
2929 return SvNumberFormatterMergeMap();
2931 SvNumberFormatterMergeMap aMap;
2932 for (sal_uInt32* pIndex = pMergeTable->First(); pIndex; pIndex = pMergeTable->Next())
2934 sal_uInt32 nOldKey = pMergeTable->GetCurKey();
2935 aMap.insert( SvNumberFormatterMergeMap::value_type( nOldKey, *pIndex));
2937 ClearMergeTable();
2938 return aMap;
2942 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
2943 LanguageType eLnge )
2945 if ( eLnge == LANGUAGE_DONTKNOW )
2946 eLnge = IniLnge;
2947 if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
2948 return nFormat; // es bleibt wie es ist
2949 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
2950 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
2951 return nFormat; // kein eingebautes Format
2952 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // ggbf. generieren
2953 return nCLOffset + nOffset;
2957 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
2958 LanguageType eLnge )
2960 if ( nTabOff >= NF_INDEX_TABLE_ENTRIES
2961 || theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND )
2962 return NUMBERFORMAT_ENTRY_NOT_FOUND;
2963 if ( eLnge == LANGUAGE_DONTKNOW )
2964 eLnge = IniLnge;
2965 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // ggbf. generieren
2966 return nCLOffset + theIndexTable[nTabOff];
2970 NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const
2972 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
2973 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
2974 return NF_INDEX_TABLE_ENTRIES; // kein eingebautes Format
2975 for ( USHORT j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
2977 if ( theIndexTable[j] == nOffset )
2978 return (NfIndexTableOffset) j;
2980 return NF_INDEX_TABLE_ENTRIES; // bad luck
2984 void SvNumberFormatter::SetYear2000( USHORT nVal )
2986 pStringScanner->SetYear2000( nVal );
2990 USHORT SvNumberFormatter::GetYear2000() const
2992 return pStringScanner->GetYear2000();
2996 USHORT SvNumberFormatter::ExpandTwoDigitYear( USHORT nYear ) const
2998 if ( nYear < 100 )
2999 return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3000 pStringScanner->GetYear2000() );
3001 return nYear;
3005 // static
3006 USHORT SvNumberFormatter::GetYear2000Default()
3008 return Application::GetSettings().GetMiscSettings().GetTwoDigitYearStart();
3012 // static
3013 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3015 ::osl::MutexGuard aGuard( GetMutex() );
3016 while ( !bCurrencyTableInitialized )
3017 ImpInitCurrencyTable();
3018 return theCurrencyTable::get();
3022 // static
3023 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3025 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3026 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3027 return nSystemCurrencyPosition ? rTable[nSystemCurrencyPosition] : NULL;
3031 // static
3032 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3034 if ( eLang == LANGUAGE_SYSTEM )
3036 const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3037 return pCurr ? *pCurr : *(GetTheCurrencyTable()[0]);
3039 else
3041 eLang = MsLangId::getRealLanguage( eLang );
3042 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3043 USHORT nCount = rTable.Count();
3044 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3045 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3047 if ( (*ppData)->GetLanguage() == eLang )
3048 return **ppData;
3050 return *(rTable[0]);
3055 // static
3056 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(
3057 const String& rAbbrev, LanguageType eLang )
3059 eLang = MsLangId::getRealLanguage( eLang );
3060 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3061 USHORT nCount = rTable.Count();
3062 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3063 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3065 if ( (*ppData)->GetLanguage() == eLang &&
3066 (*ppData)->GetBankSymbol() == rAbbrev )
3067 return *ppData;
3069 return NULL;
3073 // static
3074 const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry(
3075 const String& rSymbol, const String& rAbbrev )
3077 if (!bCurrencyTableInitialized)
3078 GetTheCurrencyTable(); // just for initialization
3079 const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get();
3080 USHORT nCount = rTable.Count();
3081 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3082 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3084 if ( (*ppData)->GetSymbol() == rSymbol &&
3085 (*ppData)->GetBankSymbol() == rAbbrev )
3086 return *ppData;
3088 return NULL;
3092 // static
3093 IMPL_STATIC_LINK_NOINSTANCE( SvNumberFormatter, CurrencyChangeLink, void*, EMPTYARG )
3095 ::osl::MutexGuard aGuard( GetMutex() );
3096 String aAbbrev;
3097 LanguageType eLang = LANGUAGE_SYSTEM;
3098 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3099 SetDefaultSystemCurrency( aAbbrev, eLang );
3100 return 0;
3104 // static
3105 void SvNumberFormatter::SetDefaultSystemCurrency( const String& rAbbrev, LanguageType eLang )
3107 ::osl::MutexGuard aGuard( GetMutex() );
3108 if ( eLang == LANGUAGE_SYSTEM )
3109 eLang = Application::GetSettings().GetLanguage();
3110 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3111 USHORT nCount = rTable.Count();
3112 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3113 if ( rAbbrev.Len() )
3115 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3117 if ( (*ppData)->GetLanguage() == eLang && (*ppData)->GetBankSymbol() == rAbbrev )
3119 nSystemCurrencyPosition = j;
3120 return ;
3124 else
3126 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3128 if ( (*ppData)->GetLanguage() == eLang )
3130 nSystemCurrencyPosition = j;
3131 return ;
3135 nSystemCurrencyPosition = 0; // not found => simple SYSTEM
3139 void SvNumberFormatter::ResetDefaultSystemCurrency()
3141 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3145 sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3147 if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3149 xub_StrLen nCheck;
3150 short nType;
3151 NfWSStringsDtor aCurrList;
3152 USHORT nDefault = GetCurrencyFormatStrings( aCurrList,
3153 GetCurrencyEntry( LANGUAGE_SYSTEM ), FALSE );
3154 DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency System standard format?!?" );
3155 // if already loaded or user defined nDefaultSystemCurrencyFormat
3156 // will be set to the right value
3157 PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType,
3158 nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM );
3159 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3160 DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3161 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3163 return nDefaultSystemCurrencyFormat;
3167 sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3169 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3170 sal_uInt32 nDefaultCurrencyFormat =
3171 (sal_uInt32)(sal_uIntPtr) aDefaultFormatKeys.Get( CLOffset + ZF_STANDARD_CURRENCY );
3172 if ( !nDefaultCurrencyFormat )
3173 nDefaultCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3174 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3176 // look for a defined standard
3177 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3178 sal_uInt32 nKey;
3179 aFTable.Seek( CLOffset );
3180 while ( (nKey = aFTable.GetCurKey()) >= CLOffset && nKey < nStopKey )
3182 const SvNumberformat* pEntry =
3183 (const SvNumberformat*) aFTable.GetCurObject();
3184 if ( pEntry->IsStandard() && (pEntry->GetType() & NUMBERFORMAT_CURRENCY) )
3186 nDefaultCurrencyFormat = nKey;
3187 break; // while
3189 aFTable.Next();
3192 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3193 { // none found, create one
3194 xub_StrLen nCheck;
3195 short nType;
3196 NfWSStringsDtor aCurrList;
3197 USHORT nDefault = GetCurrencyFormatStrings( aCurrList,
3198 GetCurrencyEntry( ActLnge ), FALSE );
3199 DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency standard format?" );
3200 if ( aCurrList.Count() )
3202 // if already loaded or user defined nDefaultSystemCurrencyFormat
3203 // will be set to the right value
3204 PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType,
3205 nDefaultCurrencyFormat, ActLnge );
3206 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3207 DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3208 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3210 // old automatic currency format as a last resort
3211 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3212 nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3213 else
3214 { // mark as standard so that it is found next time
3215 SvNumberformat* pEntry = aFTable.Get( nDefaultCurrencyFormat );
3216 if ( pEntry )
3217 pEntry->SetStandard();
3220 aDefaultFormatKeys.Insert( CLOffset + ZF_STANDARD_CURRENCY,
3221 (void*) nDefaultCurrencyFormat );
3223 return nDefaultCurrencyFormat;
3227 // static
3228 // try to make it inline if possible since this a loop body
3229 // TRUE: continue; FALSE: break loop, if pFoundEntry==NULL dupe found
3230 #ifdef PRODUCT
3231 inline
3232 #endif
3233 BOOL SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3234 const NfCurrencyEntry*& pFoundEntry, BOOL& bFoundBank,
3235 const NfCurrencyEntry* pData, USHORT nPos, const String& rSymbol )
3237 BOOL bFound;
3238 if ( pData->GetSymbol() == rSymbol )
3240 bFound = TRUE;
3241 bFoundBank = FALSE;
3243 else if ( pData->GetBankSymbol() == rSymbol )
3245 bFound = TRUE;
3246 bFoundBank = TRUE;
3248 else
3249 bFound = FALSE;
3250 if ( bFound )
3252 if ( pFoundEntry && pFoundEntry != pData )
3254 pFoundEntry = NULL;
3255 return FALSE; // break loop, not unique
3257 if ( nPos == 0 )
3258 { // first entry is SYSTEM
3259 pFoundEntry = MatchSystemCurrency();
3260 if ( pFoundEntry )
3261 return FALSE; // break loop
3262 // even if there are more matching entries
3263 // this one is propably the one we are looking for
3264 else
3265 pFoundEntry = pData;
3267 else
3268 pFoundEntry = pData;
3270 return TRUE;
3274 BOOL SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat,
3275 String& rStr, const NfCurrencyEntry** ppEntry /* = NULL */,
3276 BOOL* pBank /* = NULL */ ) const
3278 rStr.Erase();
3279 if ( ppEntry )
3280 *ppEntry = NULL;
3281 if ( pBank )
3282 *pBank = FALSE;
3283 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get( nFormat );
3284 if ( pFormat )
3286 String aSymbol, aExtension;
3287 if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3289 if ( ppEntry )
3291 BOOL bFoundBank = FALSE;
3292 // we definiteley need an entry matching the format code string
3293 const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3294 bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3295 TRUE );
3296 if ( pFoundEntry )
3298 *ppEntry = pFoundEntry;
3299 if ( pBank )
3300 *pBank = bFoundBank;
3301 pFoundEntry->BuildSymbolString( rStr, bFoundBank );
3304 if ( !rStr.Len() )
3305 { // analog zu BuildSymbolString
3306 rStr = '[';
3307 rStr += '$';
3308 if ( aSymbol.Search( '-' ) != STRING_NOTFOUND ||
3309 aSymbol.Search( ']' ) != STRING_NOTFOUND )
3311 rStr += '"';
3312 rStr += aSymbol;
3313 rStr += '"';
3315 else
3316 rStr += aSymbol;
3317 if ( aExtension.Len() )
3318 rStr += aExtension;
3319 rStr += ']';
3321 return TRUE;
3324 return FALSE;
3328 // static
3329 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( BOOL & bFoundBank,
3330 const String& rSymbol, const String& rExtension,
3331 LanguageType eFormatLanguage, BOOL bOnlyStringLanguage )
3333 xub_StrLen nExtLen = rExtension.Len();
3334 LanguageType eExtLang;
3335 if ( nExtLen )
3337 sal_Int32 nExtLang = ::rtl::OUString( rExtension ).toInt32( 16 );
3338 if ( !nExtLang )
3339 eExtLang = LANGUAGE_DONTKNOW;
3340 else
3341 eExtLang = (LanguageType) ((nExtLang < 0) ?
3342 -nExtLang : nExtLang);
3344 else
3345 eExtLang = LANGUAGE_DONTKNOW;
3346 const NfCurrencyEntry* pFoundEntry = NULL;
3347 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3348 USHORT nCount = rTable.Count();
3349 BOOL bCont = TRUE;
3351 // first try with given extension language/country
3352 if ( nExtLen )
3354 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3355 for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ )
3357 LanguageType eLang = (*ppData)->GetLanguage();
3358 if ( eLang == eExtLang ||
3359 ((eExtLang == LANGUAGE_DONTKNOW) &&
3360 (eLang == LANGUAGE_SYSTEM))
3363 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3364 *ppData, j, rSymbol );
3369 // ok?
3370 if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3371 return pFoundEntry;
3373 if ( !bOnlyStringLanguage )
3375 // now try the language/country of the number format
3376 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3377 for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ )
3379 LanguageType eLang = (*ppData)->GetLanguage();
3380 if ( eLang == eFormatLanguage ||
3381 ((eFormatLanguage == LANGUAGE_DONTKNOW) &&
3382 (eLang == LANGUAGE_SYSTEM))
3385 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3386 *ppData, j, rSymbol );
3390 // ok?
3391 if ( pFoundEntry || !bCont )
3392 return pFoundEntry;
3395 // then try without language/country if no extension specified
3396 if ( !nExtLen )
3398 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3399 for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ )
3401 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3402 *ppData, j, rSymbol );
3406 return pFoundEntry;
3410 void SvNumberFormatter::GetCompatibilityCurrency( String& rSymbol, String& rAbbrev ) const
3412 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >
3413 xCurrencies = xLocaleData->getAllCurrencies();
3414 sal_Int32 nCurrencies = xCurrencies.getLength();
3415 sal_Int32 j;
3416 for ( j=0; j < nCurrencies; ++j )
3418 if ( xCurrencies[j].UsedInCompatibleFormatCodes )
3420 rSymbol = xCurrencies[j].Symbol;
3421 rAbbrev = xCurrencies[j].BankSymbol;
3422 break;
3425 if ( j >= nCurrencies )
3427 if (LocaleDataWrapper::areChecksEnabled())
3429 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
3430 "GetCompatibilityCurrency: none?"));
3431 LocaleDataWrapper::outputCheckMessage(
3432 xLocaleData->appendLocaleInfo( aMsg));
3434 rSymbol = xLocaleData->getCurrSymbol();
3435 rAbbrev = xLocaleData->getCurrBankSymbol();
3440 void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
3442 short nPos = -1; // -1:=unknown, 0:=vorne, 1:=hinten
3443 short nNeg = -1;
3444 switch ( rCurr.GetPositiveFormat() )
3446 case 0: // $1
3447 nPos = 0;
3448 break;
3449 case 1: // 1$
3450 nPos = 1;
3451 break;
3452 case 2: // $ 1
3453 nPos = 0;
3454 break;
3455 case 3: // 1 $
3456 nPos = 1;
3457 break;
3458 default:
3459 LocaleDataWrapper::outputCheckMessage(
3460 "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3461 break;
3463 switch ( rCurr.GetNegativeFormat() )
3465 case 0: // ($1)
3466 nNeg = 0;
3467 break;
3468 case 1: // -$1
3469 nNeg = 0;
3470 break;
3471 case 2: // $-1
3472 nNeg = 0;
3473 break;
3474 case 3: // $1-
3475 nNeg = 0;
3476 break;
3477 case 4: // (1$)
3478 nNeg = 1;
3479 break;
3480 case 5: // -1$
3481 nNeg = 1;
3482 break;
3483 case 6: // 1-$
3484 nNeg = 1;
3485 break;
3486 case 7: // 1$-
3487 nNeg = 1;
3488 break;
3489 case 8: // -1 $
3490 nNeg = 1;
3491 break;
3492 case 9: // -$ 1
3493 nNeg = 0;
3494 break;
3495 case 10: // 1 $-
3496 nNeg = 1;
3497 break;
3498 case 11: // $ -1
3499 nNeg = 0;
3500 break;
3501 case 12 : // $ 1-
3502 nNeg = 0;
3503 break;
3504 case 13 : // 1- $
3505 nNeg = 1;
3506 break;
3507 case 14 : // ($ 1)
3508 nNeg = 0;
3509 break;
3510 case 15 : // (1 $)
3511 nNeg = 1;
3512 break;
3513 default:
3514 LocaleDataWrapper::outputCheckMessage(
3515 "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3516 break;
3518 if ( nPos >= 0 && nNeg >= 0 && nPos != nNeg )
3520 ByteString aStr( "positions of currency symbols differ\nLanguage: " );
3521 aStr += ByteString::CreateFromInt32( rCurr.GetLanguage() );
3522 aStr += " <";
3523 aStr += ByteString( rCurr.GetSymbol(), RTL_TEXTENCODING_UTF8 );
3524 aStr += "> positive: ";
3525 aStr += ByteString::CreateFromInt32( rCurr.GetPositiveFormat() );
3526 aStr += ( nPos ? " (postfix)" : " (prefix)" );
3527 aStr += ", negative: ";
3528 aStr += ByteString::CreateFromInt32( rCurr.GetNegativeFormat() );
3529 aStr += ( nNeg ? " (postfix)" : " (prefix)" );
3530 #if 0
3531 // seems that there really are some currencies which differ, e.g. YugoDinar
3532 DBG_ERRORFILE( aStr.GetBuffer() );
3533 #endif
3538 // static
3539 void SvNumberFormatter::ImpInitCurrencyTable()
3541 // racing condition possible:
3542 // ::osl::MutexGuard aGuard( GetMutex() );
3543 // while ( !bCurrencyTableInitialized )
3544 // ImpInitCurrencyTable();
3545 static BOOL bInitializing = FALSE;
3546 if ( bCurrencyTableInitialized || bInitializing )
3547 return ;
3548 bInitializing = TRUE;
3550 RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svtools", "er93726", "SvNumberFormatter::ImpInitCurrencyTable" );
3552 LanguageType eSysLang = Application::GetSettings().GetLanguage();
3553 LocaleDataWrapper* pLocaleData = new LocaleDataWrapper(
3554 ::comphelper::getProcessServiceFactory(),
3555 MsLangId::convertLanguageToLocale( eSysLang ) );
3556 // get user configured currency
3557 String aConfiguredCurrencyAbbrev;
3558 LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
3559 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3560 aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
3561 USHORT nSecondarySystemCurrencyPosition = 0;
3562 USHORT nMatchingSystemCurrencyPosition = 0;
3563 NfCurrencyEntryPtr pEntry;
3565 // first entry is SYSTEM
3566 pEntry = new NfCurrencyEntry( *pLocaleData, LANGUAGE_SYSTEM );
3567 theCurrencyTable::get().Insert( pEntry, 0 );
3568 USHORT nCurrencyPos = 1;
3570 ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc =
3571 LocaleDataWrapper::getInstalledLocaleNames();
3572 sal_Int32 nLocaleCount = xLoc.getLength();
3573 RTL_LOGFILE_CONTEXT_TRACE1( aTimeLog, "number of locales: %ld", nLocaleCount );
3574 Locale const * const pLocales = xLoc.getConstArray();
3575 NfCurrencyTable &rCurrencyTable = theCurrencyTable::get();
3576 NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get();
3577 USHORT nLegacyOnlyCurrencyPos = 0;
3578 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
3580 LanguageType eLang = MsLangId::convertLocaleToLanguage(
3581 pLocales[nLocale]);
3582 #if OSL_DEBUG_LEVEL > 1
3583 LanguageType eReal = MsLangId::getRealLanguage( eLang );
3584 if ( eReal != eLang ) {
3585 BOOL bBreak;
3586 bBreak = TRUE;
3588 #endif
3589 pLocaleData->setLocale( pLocales[nLocale] );
3590 Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
3591 sal_Int32 nCurrencyCount = aCurrSeq.getLength();
3592 Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
3594 // one default currency for each locale, insert first so it is found first
3595 sal_Int32 nDefault;
3596 for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3598 if ( pCurrencies[nDefault].Default )
3599 break;
3601 if ( nDefault < nCurrencyCount )
3602 pEntry = new NfCurrencyEntry( pCurrencies[nDefault], *pLocaleData, eLang );
3603 else
3604 pEntry = new NfCurrencyEntry( *pLocaleData, eLang ); // first or ShellsAndPebbles
3606 if (LocaleDataWrapper::areChecksEnabled())
3607 lcl_CheckCurrencySymbolPosition( *pEntry );
3609 rCurrencyTable.Insert( pEntry, nCurrencyPos++ );
3610 if ( !nSystemCurrencyPosition && (aConfiguredCurrencyAbbrev.Len() ?
3611 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev &&
3612 pEntry->GetLanguage() == eConfiguredCurrencyLanguage : FALSE) )
3613 nSystemCurrencyPosition = nCurrencyPos-1;
3614 if ( !nMatchingSystemCurrencyPosition &&
3615 pEntry->GetLanguage() == eSysLang )
3616 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3618 // all remaining currencies for each locale
3619 if ( nCurrencyCount > 1 )
3621 sal_Int32 nCurrency;
3622 for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
3624 if (pCurrencies[nCurrency].LegacyOnly)
3626 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3627 rLegacyOnlyCurrencyTable.Insert( pEntry, nLegacyOnlyCurrencyPos++ );
3629 else if ( nCurrency != nDefault )
3631 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3632 // no dupes
3633 BOOL bInsert = TRUE;
3634 NfCurrencyEntry const * const * pData = rCurrencyTable.GetData();
3635 USHORT n = rCurrencyTable.Count();
3636 pData++; // skip first SYSTEM entry
3637 for ( USHORT j=1; j<n; j++ )
3639 if ( *(*pData++) == *pEntry )
3641 bInsert = FALSE;
3642 break; // for
3645 if ( !bInsert )
3646 delete pEntry;
3647 else
3649 rCurrencyTable.Insert( pEntry, nCurrencyPos++ );
3650 if ( !nSecondarySystemCurrencyPosition &&
3651 (aConfiguredCurrencyAbbrev.Len() ?
3652 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev :
3653 pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
3654 nSecondarySystemCurrencyPosition = nCurrencyPos-1;
3655 if ( !nMatchingSystemCurrencyPosition &&
3656 pEntry->GetLanguage() == eSysLang )
3657 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3663 if ( !nSystemCurrencyPosition )
3664 nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
3665 if ((aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3666 LocaleDataWrapper::areChecksEnabled())
3667 LocaleDataWrapper::outputCheckMessage(
3668 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3669 // match SYSTEM if no configured currency found
3670 if ( !nSystemCurrencyPosition )
3671 nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
3672 if ((!aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3673 LocaleDataWrapper::areChecksEnabled())
3674 LocaleDataWrapper::outputCheckMessage(
3675 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3676 delete pLocaleData;
3677 SvtSysLocaleOptions::SetCurrencyChangeLink(
3678 STATIC_LINK( NULL, SvNumberFormatter, CurrencyChangeLink ) );
3679 bInitializing = FALSE;
3680 bCurrencyTableInitialized = TRUE;
3684 USHORT SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr,
3685 const NfCurrencyEntry& rCurr, BOOL bBank ) const
3687 USHORT nDefault = 0;
3688 if ( bBank )
3689 { // nur Bankensymbole
3690 String aPositiveBank, aNegativeBank;
3691 rCurr.BuildPositiveFormatString( aPositiveBank, TRUE, *xLocaleData, 1 );
3692 rCurr.BuildNegativeFormatString( aNegativeBank, TRUE, *xLocaleData, 1 );
3694 WSStringPtr pFormat1 = new String( aPositiveBank );
3695 *pFormat1 += ';';
3696 WSStringPtr pFormat2 = new String( *pFormat1 );
3698 String aRed( '[' );
3699 aRed += pFormatScanner->GetRedString();
3700 aRed += ']';
3702 *pFormat2 += aRed;
3704 *pFormat1 += aNegativeBank;
3705 *pFormat2 += aNegativeBank;
3707 rStrArr.Insert( pFormat1, rStrArr.Count() );
3708 rStrArr.Insert( pFormat2, rStrArr.Count() );
3709 nDefault = rStrArr.Count() - 1;
3711 else
3712 { // gemischte Formate wie in SvNumberFormatter::ImpGenerateFormats
3713 // aber keine doppelten, wenn keine Nachkommastellen in Waehrung
3714 String aPositive, aNegative, aPositiveNoDec, aNegativeNoDec,
3715 aPositiveDashed, aNegativeDashed;
3716 WSStringPtr pFormat1, pFormat2, pFormat3, pFormat4, pFormat5;
3718 String aRed( '[' );
3719 aRed += pFormatScanner->GetRedString();
3720 aRed += ']';
3722 rCurr.BuildPositiveFormatString( aPositive, FALSE, *xLocaleData, 1 );
3723 rCurr.BuildNegativeFormatString( aNegative, FALSE, *xLocaleData, 1 );
3724 if ( rCurr.GetDigits() )
3726 rCurr.BuildPositiveFormatString( aPositiveNoDec, FALSE, *xLocaleData, 0 );
3727 rCurr.BuildNegativeFormatString( aNegativeNoDec, FALSE, *xLocaleData, 0 );
3728 rCurr.BuildPositiveFormatString( aPositiveDashed, FALSE, *xLocaleData, 2 );
3729 rCurr.BuildNegativeFormatString( aNegativeDashed, FALSE, *xLocaleData, 2 );
3731 pFormat1 = new String( aPositiveNoDec );
3732 *pFormat1 += ';';
3733 pFormat3 = new String( *pFormat1 );
3734 pFormat5 = new String( aPositiveDashed );
3735 *pFormat5 += ';';
3737 *pFormat1 += aNegativeNoDec;
3739 *pFormat3 += aRed;
3740 *pFormat5 += aRed;
3742 *pFormat3 += aNegativeNoDec;
3743 *pFormat5 += aNegativeDashed;
3745 else
3747 pFormat1 = NULL;
3748 pFormat3 = NULL;
3749 pFormat5 = NULL;
3752 pFormat2 = new String( aPositive );
3753 *pFormat2 += ';';
3754 pFormat4 = new String( *pFormat2 );
3756 *pFormat2 += aNegative;
3758 *pFormat4 += aRed;
3759 *pFormat4 += aNegative;
3761 if ( pFormat1 )
3762 rStrArr.Insert( pFormat1, rStrArr.Count() );
3763 rStrArr.Insert( pFormat2, rStrArr.Count() );
3764 if ( pFormat3 )
3765 rStrArr.Insert( pFormat3, rStrArr.Count() );
3766 rStrArr.Insert( pFormat4, rStrArr.Count() );
3767 nDefault = rStrArr.Count() - 1;
3768 if ( pFormat5 )
3769 rStrArr.Insert( pFormat5, rStrArr.Count() );
3771 return nDefault;
3775 //--- NfCurrencyEntry ----------------------------------------------------
3777 NfCurrencyEntry::NfCurrencyEntry()
3778 : eLanguage( LANGUAGE_DONTKNOW ),
3779 nPositiveFormat(3),
3780 nNegativeFormat(8),
3781 nDigits(2),
3782 cZeroChar('0')
3787 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3789 aSymbol = rLocaleData.getCurrSymbol();
3790 aBankSymbol = rLocaleData.getCurrBankSymbol();
3791 eLanguage = eLang;
3792 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3793 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3794 nDigits = rLocaleData.getCurrDigits();
3795 cZeroChar = rLocaleData.getCurrZeroChar();
3799 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency & rCurr,
3800 const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3802 aSymbol = rCurr.Symbol;
3803 aBankSymbol = rCurr.BankSymbol;
3804 eLanguage = eLang;
3805 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3806 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3807 nDigits = rCurr.DecimalPlaces;
3808 cZeroChar = rLocaleData.getCurrZeroChar();
3812 BOOL NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
3814 return aSymbol == r.aSymbol
3815 && aBankSymbol == r.aBankSymbol
3816 && eLanguage == r.eLanguage
3821 void NfCurrencyEntry::SetEuro()
3823 aSymbol = NfCurrencyEntry::GetEuroSymbol();
3824 aBankSymbol.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "EUR" ) );
3825 eLanguage = LANGUAGE_DONTKNOW;
3826 nPositiveFormat = 3;
3827 nNegativeFormat = 8;
3828 nDigits = 2;
3829 cZeroChar = '0';
3833 BOOL NfCurrencyEntry::IsEuro() const
3835 if ( aBankSymbol.EqualsAscii( "EUR" ) )
3836 return TRUE;
3837 String aEuro( NfCurrencyEntry::GetEuroSymbol() );
3838 return aSymbol == aEuro;
3842 void NfCurrencyEntry::ApplyVariableInformation( const NfCurrencyEntry& r )
3844 nPositiveFormat = r.nPositiveFormat;
3845 nNegativeFormat = r.nNegativeFormat;
3846 cZeroChar = r.cZeroChar;
3850 void NfCurrencyEntry::BuildSymbolString( String& rStr, BOOL bBank,
3851 BOOL bWithoutExtension ) const
3853 rStr = '[';
3854 rStr += '$';
3855 if ( bBank )
3856 rStr += aBankSymbol;
3857 else
3859 if ( aSymbol.Search( '-' ) != STRING_NOTFOUND || aSymbol.Search( ']' ) != STRING_NOTFOUND )
3861 rStr += '"';
3862 rStr += aSymbol;
3863 rStr += '"';
3865 else
3866 rStr += aSymbol;
3867 if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
3869 rStr += '-';
3870 rStr += String::CreateFromInt32( sal_Int32( eLanguage ), 16 ).ToUpperAscii();
3873 rStr += ']';
3877 void NfCurrencyEntry::Impl_BuildFormatStringNumChars( String& rStr,
3878 const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const
3880 rStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###0" ) );
3881 rStr.Insert( rLoc.getNumThousandSep(), 1 );
3882 if ( nDecimalFormat && nDigits )
3884 rStr += rLoc.getNumDecimalSep();
3885 rStr.Expand( rStr.Len() + nDigits, (nDecimalFormat == 2 ? '-' : cZeroChar) );
3890 void NfCurrencyEntry::BuildPositiveFormatString( String& rStr, BOOL bBank,
3891 const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const
3893 Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat );
3894 USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
3895 rLoc.getCurrPositiveFormat(), nPositiveFormat, bBank );
3896 CompletePositiveFormatString( rStr, bBank, nPosiForm );
3900 void NfCurrencyEntry::BuildNegativeFormatString( String& rStr, BOOL bBank,
3901 const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const
3903 Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat );
3904 USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
3905 rLoc.getCurrNegativeFormat(), nNegativeFormat, bBank );
3906 CompleteNegativeFormatString( rStr, bBank, nNegaForm );
3910 void NfCurrencyEntry::CompletePositiveFormatString( String& rStr, BOOL bBank,
3911 USHORT nPosiForm ) const
3913 String aSymStr;
3914 BuildSymbolString( aSymStr, bBank );
3915 NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
3919 void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr, BOOL bBank,
3920 USHORT nNegaForm ) const
3922 String aSymStr;
3923 BuildSymbolString( aSymStr, bBank );
3924 NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
3928 // static
3929 void NfCurrencyEntry::CompletePositiveFormatString( String& rStr,
3930 const String& rSymStr, USHORT nPositiveFormat )
3932 switch( nPositiveFormat )
3934 case 0: // $1
3935 rStr.Insert( rSymStr , 0 );
3936 break;
3937 case 1: // 1$
3938 rStr += rSymStr;
3939 break;
3940 case 2: // $ 1
3942 rStr.Insert( ' ', 0 );
3943 rStr.Insert( rSymStr, 0 );
3945 break;
3946 case 3: // 1 $
3948 rStr += ' ';
3949 rStr += rSymStr;
3951 break;
3952 default:
3953 DBG_ERROR("NfCurrencyEntry::CompletePositiveFormatString: unknown option");
3954 break;
3959 // static
3960 void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr,
3961 const String& rSymStr, USHORT nNegativeFormat )
3963 switch( nNegativeFormat )
3965 case 0: // ($1)
3967 rStr.Insert( rSymStr, 0);
3968 rStr.Insert('(',0);
3969 rStr += ')';
3971 break;
3972 case 1: // -$1
3974 rStr.Insert( rSymStr, 0);
3975 rStr.Insert('-',0);
3977 break;
3978 case 2: // $-1
3980 rStr.Insert('-',0);
3981 rStr.Insert( rSymStr, 0);
3983 break;
3984 case 3: // $1-
3986 rStr.Insert( rSymStr, 0);
3987 rStr += '-';
3989 break;
3990 case 4: // (1$)
3992 rStr.Insert('(',0);
3993 rStr += rSymStr;
3994 rStr += ')';
3996 break;
3997 case 5: // -1$
3999 rStr += rSymStr;
4000 rStr.Insert('-',0);
4002 break;
4003 case 6: // 1-$
4005 rStr += '-';
4006 rStr += rSymStr;
4008 break;
4009 case 7: // 1$-
4011 rStr += rSymStr;
4012 rStr += '-';
4014 break;
4015 case 8: // -1 $
4017 rStr += ' ';
4018 rStr += rSymStr;
4019 rStr.Insert('-',0);
4021 break;
4022 case 9: // -$ 1
4024 rStr.Insert(' ',0);
4025 rStr.Insert( rSymStr, 0);
4026 rStr.Insert('-',0);
4028 break;
4029 case 10: // 1 $-
4031 rStr += ' ';
4032 rStr += rSymStr;
4033 rStr += '-';
4035 break;
4036 case 11: // $ -1
4038 String aTmp( rSymStr );
4039 aTmp += ' ';
4040 aTmp += '-';
4041 rStr.Insert( aTmp, 0 );
4043 break;
4044 case 12 : // $ 1-
4046 rStr.Insert(' ', 0);
4047 rStr.Insert( rSymStr, 0);
4048 rStr += '-';
4050 break;
4051 case 13 : // 1- $
4053 rStr += '-';
4054 rStr += ' ';
4055 rStr += rSymStr;
4057 break;
4058 case 14 : // ($ 1)
4060 rStr.Insert(' ',0);
4061 rStr.Insert( rSymStr, 0);
4062 rStr.Insert('(',0);
4063 rStr += ')';
4065 break;
4066 case 15 : // (1 $)
4068 rStr.Insert('(',0);
4069 rStr += ' ';
4070 rStr += rSymStr;
4071 rStr += ')';
4073 break;
4074 default:
4075 DBG_ERROR("NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4076 break;
4081 // static
4082 USHORT NfCurrencyEntry::GetEffectivePositiveFormat( USHORT
4083 #if ! NF_BANKSYMBOL_FIX_POSITION
4084 nIntlFormat
4085 #endif
4086 , USHORT nCurrFormat, BOOL bBank )
4088 if ( bBank )
4090 #if NF_BANKSYMBOL_FIX_POSITION
4091 return 3;
4092 #else
4093 switch ( nIntlFormat )
4095 case 0: // $1
4096 nIntlFormat = 2; // $ 1
4097 break;
4098 case 1: // 1$
4099 nIntlFormat = 3; // 1 $
4100 break;
4101 case 2: // $ 1
4102 break;
4103 case 3: // 1 $
4104 break;
4105 default:
4106 DBG_ERROR("NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4107 break;
4109 return nIntlFormat;
4110 #endif
4112 else
4113 return nCurrFormat;
4117 // nur aufrufen, wenn nCurrFormat wirklich mit Klammern ist
4118 USHORT lcl_MergeNegativeParenthesisFormat( USHORT nIntlFormat, USHORT nCurrFormat )
4120 short nSign = 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4121 switch ( nIntlFormat )
4123 case 0: // ($1)
4124 case 4: // (1$)
4125 case 14 : // ($ 1)
4126 case 15 : // (1 $)
4127 return nCurrFormat;
4128 case 1: // -$1
4129 case 5: // -1$
4130 case 8: // -1 $
4131 case 9: // -$ 1
4132 nSign = 0;
4133 break;
4134 case 2: // $-1
4135 case 6: // 1-$
4136 case 11 : // $ -1
4137 case 13 : // 1- $
4138 nSign = 1;
4139 break;
4140 case 3: // $1-
4141 case 7: // 1$-
4142 case 10: // 1 $-
4143 case 12 : // $ 1-
4144 nSign = 2;
4145 break;
4146 default:
4147 DBG_ERROR("lcl_MergeNegativeParenthesisFormat: unknown option");
4148 break;
4151 switch ( nCurrFormat )
4153 case 0: // ($1)
4154 switch ( nSign )
4156 case 0:
4157 return 1; // -$1
4158 case 1:
4159 return 2; // $-1
4160 case 2:
4161 return 3; // $1-
4163 break;
4164 case 4: // (1$)
4165 switch ( nSign )
4167 case 0:
4168 return 5; // -1$
4169 case 1:
4170 return 6; // 1-$
4171 case 2:
4172 return 7; // 1$-
4174 break;
4175 case 14 : // ($ 1)
4176 switch ( nSign )
4178 case 0:
4179 return 9; // -$ 1
4180 case 1:
4181 return 11; // $ -1
4182 case 2:
4183 return 12; // $ 1-
4185 break;
4186 case 15 : // (1 $)
4187 switch ( nSign )
4189 case 0:
4190 return 8; // -1 $
4191 case 1:
4192 return 13; // 1- $
4193 case 2:
4194 return 10; // 1 $-
4196 break;
4198 return nCurrFormat;
4202 // static
4203 USHORT NfCurrencyEntry::GetEffectiveNegativeFormat( USHORT nIntlFormat,
4204 USHORT nCurrFormat, BOOL bBank )
4206 if ( bBank )
4208 #if NF_BANKSYMBOL_FIX_POSITION
4209 return 8;
4210 #else
4211 switch ( nIntlFormat )
4213 case 0: // ($1)
4214 // nIntlFormat = 14; // ($ 1)
4215 nIntlFormat = 9; // -$ 1
4216 break;
4217 case 1: // -$1
4218 nIntlFormat = 9; // -$ 1
4219 break;
4220 case 2: // $-1
4221 nIntlFormat = 11; // $ -1
4222 break;
4223 case 3: // $1-
4224 nIntlFormat = 12; // $ 1-
4225 break;
4226 case 4: // (1$)
4227 // nIntlFormat = 15; // (1 $)
4228 nIntlFormat = 8; // -1 $
4229 break;
4230 case 5: // -1$
4231 nIntlFormat = 8; // -1 $
4232 break;
4233 case 6: // 1-$
4234 nIntlFormat = 13; // 1- $
4235 break;
4236 case 7: // 1$-
4237 nIntlFormat = 10; // 1 $-
4238 break;
4239 case 8: // -1 $
4240 break;
4241 case 9: // -$ 1
4242 break;
4243 case 10: // 1 $-
4244 break;
4245 case 11: // $ -1
4246 break;
4247 case 12 : // $ 1-
4248 break;
4249 case 13 : // 1- $
4250 break;
4251 case 14 : // ($ 1)
4252 // nIntlFormat = 14; // ($ 1)
4253 nIntlFormat = 9; // -$ 1
4254 break;
4255 case 15 : // (1 $)
4256 // nIntlFormat = 15; // (1 $)
4257 nIntlFormat = 8; // -1 $
4258 break;
4259 default:
4260 DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4261 break;
4263 #endif
4265 else if ( nIntlFormat != nCurrFormat )
4267 switch ( nCurrFormat )
4269 case 0: // ($1)
4270 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4271 nIntlFormat, nCurrFormat );
4272 break;
4273 case 1: // -$1
4274 nIntlFormat = nCurrFormat;
4275 break;
4276 case 2: // $-1
4277 nIntlFormat = nCurrFormat;
4278 break;
4279 case 3: // $1-
4280 nIntlFormat = nCurrFormat;
4281 break;
4282 case 4: // (1$)
4283 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4284 nIntlFormat, nCurrFormat );
4285 break;
4286 case 5: // -1$
4287 nIntlFormat = nCurrFormat;
4288 break;
4289 case 6: // 1-$
4290 nIntlFormat = nCurrFormat;
4291 break;
4292 case 7: // 1$-
4293 nIntlFormat = nCurrFormat;
4294 break;
4295 case 8: // -1 $
4296 nIntlFormat = nCurrFormat;
4297 break;
4298 case 9: // -$ 1
4299 nIntlFormat = nCurrFormat;
4300 break;
4301 case 10: // 1 $-
4302 nIntlFormat = nCurrFormat;
4303 break;
4304 case 11: // $ -1
4305 nIntlFormat = nCurrFormat;
4306 break;
4307 case 12 : // $ 1-
4308 nIntlFormat = nCurrFormat;
4309 break;
4310 case 13 : // 1- $
4311 nIntlFormat = nCurrFormat;
4312 break;
4313 case 14 : // ($ 1)
4314 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4315 nIntlFormat, nCurrFormat );
4316 break;
4317 case 15 : // (1 $)
4318 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4319 nIntlFormat, nCurrFormat );
4320 break;
4321 default:
4322 DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4323 break;
4326 return nIntlFormat;
4330 // we only support default encodings here
4331 // static
4332 sal_Char NfCurrencyEntry::GetEuroSymbol( rtl_TextEncoding eTextEncoding )
4334 switch ( eTextEncoding )
4336 case RTL_TEXTENCODING_MS_1252 : // WNT Ansi
4337 case RTL_TEXTENCODING_ISO_8859_1 : // UNX for use with TrueType fonts
4338 return '\x80';
4339 case RTL_TEXTENCODING_ISO_8859_15 : // UNX real
4340 return '\xA4';
4341 case RTL_TEXTENCODING_IBM_850 : // OS2
4342 return '\xD5';
4343 case RTL_TEXTENCODING_APPLE_ROMAN : // MAC
4344 return '\xDB';
4345 default: // default system
4346 #if WNT
4347 return '\x80';
4348 #elif OS2
4349 return '\xD5';
4350 #elif UNX
4351 // return '\xA4'; // #56121# 0xA4 waere korrekt fuer iso-8859-15
4352 return '\x80'; // aber Windoze-Code fuer die konvertierten TrueType-Fonts
4353 #else
4354 #error EuroSymbol is what?
4355 return '\x80';
4356 #endif
4358 return '\x80';