Update ooo320-m1
[ooovba.git] / svtools / source / numbers / zforlist.cxx
blobceedb05f6bb9fc42f2f7a03e619b613c08c62809
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 Color* pColor;
1492 GetInputLineString(fOutNumber, nFIndex, sOutString, &pColor);
1495 void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
1496 sal_uInt32 nFIndex,
1497 String& sOutString, Color** ppColor)
1499 SvNumberformat* pFormat;
1500 short nOldPrec;
1501 pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1502 if (!pFormat)
1503 pFormat = aFTable.Get(ZF_STANDARD);
1504 LanguageType eLang = pFormat->GetLanguage();
1505 ChangeIntl( eLang );
1506 short eType = pFormat->GetType() & ~NUMBERFORMAT_DEFINED;
1507 if (eType == 0)
1508 eType = NUMBERFORMAT_DEFINED;
1509 nOldPrec = -1;
1510 if (eType == NUMBERFORMAT_NUMBER || eType == NUMBERFORMAT_PERCENT
1511 || eType == NUMBERFORMAT_CURRENCY
1512 || eType == NUMBERFORMAT_SCIENTIFIC
1513 || eType == NUMBERFORMAT_FRACTION)
1515 if (eType != NUMBERFORMAT_PERCENT) // spaeter Sonderbehandlung %
1516 eType = NUMBERFORMAT_NUMBER;
1517 nOldPrec = pFormatScanner->GetStandardPrec();
1518 ChangeStandardPrec(300); // Merkwert
1520 sal_uInt32 nKey = nFIndex;
1521 switch ( eType )
1522 { // #61619# immer vierstelliges Jahr editieren
1523 case NUMBERFORMAT_DATE :
1524 nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang );
1525 break;
1526 case NUMBERFORMAT_DATETIME :
1527 nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang );
1528 break;
1529 default:
1530 nKey = GetStandardFormat( fOutNumber, nFIndex, eType, eLang );
1532 if ( nKey != nFIndex )
1533 pFormat = (SvNumberformat*) aFTable.Get( nKey );
1534 if (pFormat)
1536 if ( eType == NUMBERFORMAT_TIME && pFormat->GetFormatPrecision() )
1538 nOldPrec = pFormatScanner->GetStandardPrec();
1539 ChangeStandardPrec(300); // Merkwert
1541 if (ppColor)
1542 pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1543 else
1545 Color* pColor; // throw away the color info.
1546 pFormat->GetOutputString(fOutNumber, sOutString, &pColor);
1549 if (nOldPrec != -1)
1550 ChangeStandardPrec(nOldPrec);
1553 void SvNumberFormatter::GetOutputString(const double& fOutNumber,
1554 sal_uInt32 nFIndex,
1555 String& sOutString,
1556 Color** ppColor)
1558 if (bNoZero && fOutNumber == 0.0)
1560 sOutString.Erase();
1561 return;
1563 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1564 if (!pFormat)
1565 pFormat = aFTable.Get(ZF_STANDARD);
1566 ChangeIntl(pFormat->GetLanguage());
1567 pFormat->GetOutputString(fOutNumber, sOutString, ppColor);
1570 void SvNumberFormatter::GetOutputString(String& sString,
1571 sal_uInt32 nFIndex,
1572 String& sOutString,
1573 Color** ppColor)
1575 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1576 if (!pFormat)
1577 pFormat = aFTable.Get(ZF_STANDARD_TEXT);
1578 if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat())
1580 *ppColor = NULL;
1581 sOutString = sString;
1583 else
1585 ChangeIntl(pFormat->GetLanguage());
1586 pFormat->GetOutputString(sString, sOutString, ppColor);
1590 void SvNumberFormatter::GetStringColor( sal_uInt32 nFIndex, Color** ppColor)
1592 if (!ppColor)
1593 return;
1595 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
1596 if (!pFormat)
1597 pFormat = aFTable.Get(ZF_STANDARD_TEXT);
1599 if (pFormat->IsTextFormat() || pFormat->HasTextFormat())
1600 pFormat->GetStringColor(ppColor);
1601 else
1602 *ppColor = NULL;
1605 BOOL SvNumberFormatter::GetPreviewString(const String& sFormatString,
1606 double fPreviewNumber,
1607 String& sOutString,
1608 Color** ppColor,
1609 LanguageType eLnge)
1611 if (sFormatString.Len() == 0) // keinen Leerstring
1612 return FALSE;
1614 xub_StrLen nCheckPos = STRING_NOTFOUND;
1615 sal_uInt32 nKey;
1616 if (eLnge == LANGUAGE_DONTKNOW)
1617 eLnge = IniLnge;
1618 ChangeIntl(eLnge); // ggfs. austauschen
1619 eLnge = ActLnge;
1620 String sTmpString = sFormatString;
1621 SvNumberformat* p_Entry = new SvNumberformat(sTmpString,
1622 pFormatScanner,
1623 pStringScanner,
1624 nCheckPos,
1625 eLnge);
1626 if (nCheckPos == 0) // String ok
1628 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
1629 // formate anlegen
1630 nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge);
1631 if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden
1632 GetOutputString(fPreviewNumber,nKey,sOutString,ppColor);
1633 else
1634 p_Entry->GetOutputString(fPreviewNumber,sOutString, ppColor);
1635 delete p_Entry;
1636 return TRUE;
1638 else
1640 delete p_Entry;
1641 return FALSE;
1645 BOOL SvNumberFormatter::GetPreviewStringGuess( const String& sFormatString,
1646 double fPreviewNumber,
1647 String& sOutString,
1648 Color** ppColor,
1649 LanguageType eLnge )
1651 if (sFormatString.Len() == 0) // keinen Leerstring
1652 return FALSE;
1654 if (eLnge == LANGUAGE_DONTKNOW)
1655 eLnge = IniLnge;
1657 ChangeIntl( eLnge );
1658 eLnge = ActLnge;
1659 BOOL bEnglish = (eLnge == LANGUAGE_ENGLISH_US);
1661 String aFormatStringUpper( pCharClass->upper( sFormatString ) );
1662 sal_uInt32 nCLOffset = ImpGenerateCL( eLnge );
1663 sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge );
1664 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1665 { // Zielformat vorhanden
1666 GetOutputString( fPreviewNumber, nKey, sOutString, ppColor );
1667 return TRUE;
1670 SvNumberformat *pEntry = NULL;
1671 xub_StrLen nCheckPos = STRING_NOTFOUND;
1672 String sTmpString;
1674 if ( bEnglish )
1676 sTmpString = sFormatString;
1677 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1678 pStringScanner, nCheckPos, eLnge );
1680 else
1682 nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US );
1683 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US );
1684 BOOL bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND);
1686 // try english --> other bzw. english nach other konvertieren
1687 LanguageType eFormatLang = LANGUAGE_ENGLISH_US;
1688 pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge );
1689 sTmpString = sFormatString;
1690 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1691 pStringScanner, nCheckPos, eFormatLang );
1692 pFormatScanner->SetConvertMode( FALSE );
1693 ChangeIntl( eLnge );
1695 if ( !bEnglishFormat )
1697 if ( nCheckPos > 0 || xTransliteration->isEqual( sFormatString,
1698 pEntry->GetFormatstring() ) )
1699 { // other Format
1700 delete pEntry;
1701 sTmpString = sFormatString;
1702 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1703 pStringScanner, nCheckPos, eLnge );
1705 else
1706 { // verify english
1707 xub_StrLen nCheckPos2 = STRING_NOTFOUND;
1708 // try other --> english
1709 eFormatLang = eLnge;
1710 pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US );
1711 sTmpString = sFormatString;
1712 SvNumberformat* pEntry2 = new SvNumberformat( sTmpString, pFormatScanner,
1713 pStringScanner, nCheckPos2, eFormatLang );
1714 pFormatScanner->SetConvertMode( FALSE );
1715 ChangeIntl( eLnge );
1716 if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString,
1717 pEntry2->GetFormatstring() ) )
1718 { // other Format
1719 delete pEntry;
1720 sTmpString = sFormatString;
1721 pEntry = new SvNumberformat( sTmpString, pFormatScanner,
1722 pStringScanner, nCheckPos, eLnge );
1724 delete pEntry2;
1729 if (nCheckPos == 0) // String ok
1731 ImpGenerateCL( eLnge ); // ggfs. neu Standardformate anlegen
1732 pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor );
1733 delete pEntry;
1734 return TRUE;
1736 delete pEntry;
1737 return FALSE;
1740 sal_uInt32 SvNumberFormatter::TestNewString(const String& sFormatString,
1741 LanguageType eLnge)
1743 if (sFormatString.Len() == 0) // keinen Leerstring
1744 return NUMBERFORMAT_ENTRY_NOT_FOUND;
1746 xub_StrLen nCheckPos = STRING_NOTFOUND;
1747 if (eLnge == LANGUAGE_DONTKNOW)
1748 eLnge = IniLnge;
1749 ChangeIntl(eLnge); // ggfs. austauschen
1750 eLnge = ActLnge;
1751 sal_uInt32 nRes;
1752 String sTmpString = sFormatString;
1753 SvNumberformat* pEntry = new SvNumberformat(sTmpString,
1754 pFormatScanner,
1755 pStringScanner,
1756 nCheckPos,
1757 eLnge);
1758 if (nCheckPos == 0) // String ok
1760 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
1761 // formate anlegen
1762 nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge);
1763 // schon vorhanden ?
1765 else
1766 nRes = NUMBERFORMAT_ENTRY_NOT_FOUND;
1767 delete pEntry;
1768 return nRes;
1771 SvNumberformat* SvNumberFormatter::ImpInsertFormat(
1772 const ::com::sun::star::i18n::NumberFormatCode& rCode,
1773 sal_uInt32 nPos, BOOL bAfterLoadingSO5, sal_Int16 nOrgIndex )
1775 String aCodeStr( rCode.Code );
1776 if ( rCode.Index < NF_INDEX_TABLE_ENTRIES &&
1777 rCode.Usage == ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY &&
1778 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1779 { // strip surrounding [$...] on automatic currency
1780 if ( aCodeStr.SearchAscii( "[$" ) != STRING_NOTFOUND )
1781 aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr, FALSE );
1782 else
1784 if (LocaleDataWrapper::areChecksEnabled() &&
1785 rCode.Index != NF_CURRENCY_1000DEC2_CCC )
1787 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1788 "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index "));
1789 aMsg += String::CreateFromInt32( rCode.Index );
1790 aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ":\n"));
1791 aMsg += String( rCode.Code );
1792 LocaleDataWrapper::outputCheckMessage(
1793 xLocaleData->appendLocaleInfo( aMsg));
1797 xub_StrLen nCheckPos = 0;
1798 SvNumberformat* pFormat = new SvNumberformat(aCodeStr,
1799 pFormatScanner,
1800 pStringScanner,
1801 nCheckPos,
1802 ActLnge);
1803 if ( !pFormat || nCheckPos > 0 )
1805 if (LocaleDataWrapper::areChecksEnabled())
1807 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1808 "SvNumberFormatter::ImpInsertFormat: bad format code, index "));
1809 aMsg += String::CreateFromInt32( rCode.Index );
1810 aMsg += '\n';
1811 aMsg += String( rCode.Code );
1812 LocaleDataWrapper::outputCheckMessage(
1813 xLocaleData->appendLocaleInfo( aMsg));
1815 delete pFormat;
1816 return NULL;
1818 if ( rCode.Index >= NF_INDEX_TABLE_ENTRIES )
1820 sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET);
1821 sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge );
1822 if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND )
1824 if (LocaleDataWrapper::areChecksEnabled())
1826 switch ( nOrgIndex )
1828 // These may be dupes of integer versions for locales where
1829 // currencies have no decimals like Italian Lira.
1830 case NF_CURRENCY_1000DEC2 : // NF_CURRENCY_1000INT
1831 case NF_CURRENCY_1000DEC2_RED : // NF_CURRENCY_1000INT_RED
1832 case NF_CURRENCY_1000DEC2_DASHED : // NF_CURRENCY_1000INT_RED
1833 break;
1834 default:
1835 if ( !bAfterLoadingSO5 )
1836 { // If bAfterLoadingSO5 there will definitely be some dupes,
1837 // don't cry. But we need this test for verification of locale
1838 // data if not loading old SO5 documents.
1839 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1840 "SvNumberFormatter::ImpInsertFormat: dup format code, index "));
1841 aMsg += String::CreateFromInt32( rCode.Index );
1842 aMsg += '\n';
1843 aMsg += String( rCode.Code );
1844 LocaleDataWrapper::outputCheckMessage(
1845 xLocaleData->appendLocaleInfo( aMsg));
1849 delete pFormat;
1850 return NULL;
1852 else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
1854 if (LocaleDataWrapper::areChecksEnabled())
1856 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1857 "SvNumberFormatter::ImpInsertFormat: too many format codes, index "));
1858 aMsg += String::CreateFromInt32( rCode.Index );
1859 aMsg += '\n';
1860 aMsg += String( rCode.Code );
1861 LocaleDataWrapper::outputCheckMessage(
1862 xLocaleData->appendLocaleInfo( aMsg));
1864 delete pFormat;
1865 return NULL;
1868 if ( !aFTable.Insert( nPos, pFormat ) )
1870 if (LocaleDataWrapper::areChecksEnabled())
1872 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
1873 "ImpInsertFormat: can't insert number format key pos: "));
1874 aMsg += String::CreateFromInt32( nPos );
1875 aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", code index "));
1876 aMsg += String::CreateFromInt32( rCode.Index );
1877 aMsg += '\n';
1878 aMsg += String( rCode.Code );
1879 LocaleDataWrapper::outputCheckMessage(
1880 xLocaleData->appendLocaleInfo( aMsg));
1882 delete pFormat;
1883 return NULL;
1885 if ( rCode.Default )
1886 pFormat->SetStandard();
1887 if ( rCode.DefaultName.getLength() )
1888 pFormat->SetComment( rCode.DefaultName );
1889 return pFormat;
1892 SvNumberformat* SvNumberFormatter::ImpInsertNewStandardFormat(
1893 const ::com::sun::star::i18n::NumberFormatCode& rCode,
1894 sal_uInt32 nPos, USHORT nVersion, BOOL bAfterLoadingSO5,
1895 sal_Int16 nOrgIndex )
1897 SvNumberformat* pNewFormat = ImpInsertFormat( rCode, nPos,
1898 bAfterLoadingSO5, nOrgIndex );
1899 if (pNewFormat)
1900 pNewFormat->SetNewStandardDefined( nVersion );
1901 // so that it gets saved, displayed properly, and converted by old versions
1902 return pNewFormat;
1905 void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat,
1906 BOOL& bThousand,
1907 BOOL& IsRed,
1908 USHORT& nPrecision,
1909 USHORT& nAnzLeading)
1912 const SvNumberformat* pFormat = aFTable.Get(nFormat);
1913 if (pFormat)
1914 pFormat->GetFormatSpecialInfo(bThousand, IsRed,
1915 nPrecision, nAnzLeading);
1916 else
1918 bThousand = FALSE;
1919 IsRed = FALSE;
1920 nPrecision = pFormatScanner->GetStandardPrec();
1921 nAnzLeading = 0;
1925 USHORT SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const
1927 const SvNumberformat* pFormat = aFTable.Get( nFormat );
1928 if ( pFormat )
1929 return pFormat->GetFormatPrecision();
1930 else
1931 return pFormatScanner->GetStandardPrec();
1935 String SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const
1937 const SvNumberformat* pFormat = aFTable.Get( nFormat );
1938 if ( !pFormat || pFormat->GetLanguage() == ActLnge )
1939 return GetNumDecimalSep();
1941 String aRet;
1942 LanguageType eSaveLang = xLocaleData.getCurrentLanguage();
1943 if ( pFormat->GetLanguage() == eSaveLang )
1944 aRet = xLocaleData->getNumDecimalSep();
1945 else
1947 ::com::sun::star::lang::Locale aSaveLocale( xLocaleData->getLocale() );
1948 ::com::sun::star::lang::Locale aTmpLocale(MsLangId::convertLanguageToLocale(pFormat->GetLanguage()));
1949 ((SvNumberFormatter*)this)->xLocaleData.changeLocale(aTmpLocale, pFormat->GetLanguage() );
1950 aRet = xLocaleData->getNumDecimalSep();
1951 ((SvNumberFormatter*)this)->xLocaleData.changeLocale( aSaveLocale, eSaveLang );
1953 return aRet;
1957 sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const String& rFormatString,
1958 BOOL& bThousand, BOOL& IsRed, USHORT& nPrecision,
1959 USHORT& nAnzLeading, LanguageType eLnge )
1962 xub_StrLen nCheckPos = 0;
1963 if (eLnge == LANGUAGE_DONTKNOW)
1964 eLnge = IniLnge;
1965 ChangeIntl(eLnge); // ggfs. austauschen
1966 eLnge = ActLnge;
1967 String aTmpStr( rFormatString );
1968 SvNumberformat* pFormat = new SvNumberformat( aTmpStr,
1969 pFormatScanner, pStringScanner, nCheckPos, eLnge );
1970 if ( nCheckPos == 0 )
1971 pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nAnzLeading );
1972 else
1974 bThousand = FALSE;
1975 IsRed = FALSE;
1976 nPrecision = pFormatScanner->GetStandardPrec();
1977 nAnzLeading = 0;
1979 delete pFormat;
1980 return nCheckPos;
1984 inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff )
1986 if ( !bIndexTableInitialized )
1988 DBG_ASSERT( theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND,
1989 "SetIndexTable: theIndexTable[nTabOff] already occupied" );
1990 theIndexTable[nTabOff] = nIndOff;
1992 return nIndOff;
1996 sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex(
1997 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode >& rSeq,
1998 const NfIndexTableOffset nTabOff )
2000 const sal_Int32 nLen = rSeq.getLength();
2001 for ( sal_Int32 j=0; j<nLen; j++ )
2003 if ( rSeq[j].Index == nTabOff )
2004 return j;
2006 if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START
2007 || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT
2008 || nTabOff == NF_CURRENCY_1000INT_RED
2009 || nTabOff == NF_CURRENCY_1000DEC2_CCC))
2010 { // currency entries with decimals might not exist, e.g. Italian Lira
2011 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2012 "SvNumberFormatter::ImpGetFormatCodeIndex: not found: "));
2013 aMsg += String::CreateFromInt32( nTabOff );
2014 LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo(
2015 aMsg));
2017 if ( nLen )
2019 sal_Int32 j;
2020 // look for a preset default
2021 for ( j=0; j<nLen; j++ )
2023 if ( rSeq[j].Default )
2024 return j;
2026 // currencies are special, not all format codes must exist, but all
2027 // builtin number format key index positions must have a format assigned
2028 if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END )
2030 // look for a format with decimals
2031 for ( j=0; j<nLen; j++ )
2033 if ( rSeq[j].Index == NF_CURRENCY_1000DEC2 )
2034 return j;
2036 // last resort: look for a format without decimals
2037 for ( j=0; j<nLen; j++ )
2039 if ( rSeq[j].Index == NF_CURRENCY_1000INT )
2040 return j;
2044 else
2045 { // we need at least _some_ format
2046 rSeq.realloc(1);
2047 rSeq[0] = ::com::sun::star::i18n::NumberFormatCode();
2048 String aTmp( '0' );
2049 aTmp += GetNumDecimalSep();
2050 aTmp.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "############" ) );
2051 rSeq[0].Code = aTmp;
2053 return 0;
2057 sal_Int32 SvNumberFormatter::ImpAdjustFormatCodeDefault(
2058 ::com::sun::star::i18n::NumberFormatCode * pFormatArr,
2059 sal_Int32 nCnt, BOOL bCheckCorrectness )
2061 using namespace ::com::sun::star;
2063 if ( !nCnt )
2064 return -1;
2065 if (bCheckCorrectness && LocaleDataWrapper::areChecksEnabled())
2066 { // check the locale data for correctness
2067 ByteString aMsg;
2068 sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef;
2069 nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1;
2070 for ( nElem = 0; nElem < nCnt; nElem++ )
2072 switch ( pFormatArr[nElem].Type )
2074 case i18n::KNumberFormatType::SHORT :
2075 nShort = nElem;
2076 break;
2077 case i18n::KNumberFormatType::MEDIUM :
2078 nMedium = nElem;
2079 break;
2080 case i18n::KNumberFormatType::LONG :
2081 nLong = nElem;
2082 break;
2083 default:
2084 aMsg = "unknown type";
2086 if ( pFormatArr[nElem].Default )
2088 switch ( pFormatArr[nElem].Type )
2090 case i18n::KNumberFormatType::SHORT :
2091 if ( nShortDef != -1 )
2092 aMsg = "dupe short type default";
2093 nShortDef = nElem;
2094 break;
2095 case i18n::KNumberFormatType::MEDIUM :
2096 if ( nMediumDef != -1 )
2097 aMsg = "dupe medium type default";
2098 nMediumDef = nElem;
2099 break;
2100 case i18n::KNumberFormatType::LONG :
2101 if ( nLongDef != -1 )
2102 aMsg = "dupe long type default";
2103 nLongDef = nElem;
2104 break;
2107 if ( aMsg.Len() )
2109 aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 );
2110 aMsg += "\nXML locale data FormatElement formatindex: ";
2111 aMsg += ByteString::CreateFromInt32( pFormatArr[nElem].Index );
2112 String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US);
2113 LocaleDataWrapper::outputCheckMessage(
2114 xLocaleData->appendLocaleInfo( aUMsg));
2115 aMsg.Erase();
2118 if ( nShort != -1 && nShortDef == -1 )
2119 aMsg += "no short type default ";
2120 if ( nMedium != -1 && nMediumDef == -1 )
2121 aMsg += "no medium type default ";
2122 if ( nLong != -1 && nLongDef == -1 )
2123 aMsg += "no long type default ";
2124 if ( aMsg.Len() )
2126 aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 );
2127 aMsg += "\nXML locale data FormatElement group of: ";
2128 String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US);
2129 aUMsg += String( pFormatArr[0].NameID );
2130 LocaleDataWrapper::outputCheckMessage(
2131 xLocaleData->appendLocaleInfo( aUMsg));
2132 aMsg.Erase();
2135 // find the default (medium preferred, then long) and reset all other defaults
2136 sal_Int32 nElem, nDef, nMedium;
2137 nDef = nMedium = -1;
2138 for ( nElem = 0; nElem < nCnt; nElem++ )
2140 if ( pFormatArr[nElem].Default )
2142 switch ( pFormatArr[nElem].Type )
2144 case i18n::KNumberFormatType::MEDIUM :
2145 nDef = nMedium = nElem;
2146 break;
2147 case i18n::KNumberFormatType::LONG :
2148 if ( nMedium == -1 )
2149 nDef = nElem;
2150 // fallthru
2151 default:
2152 if ( nDef == -1 )
2153 nDef = nElem;
2154 pFormatArr[nElem].Default = sal_False;
2158 if ( nDef == -1 )
2159 nDef = 0;
2160 pFormatArr[nDef].Default = sal_True;
2161 return nDef;
2165 void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, BOOL bLoadingSO5 )
2167 using namespace ::com::sun::star;
2169 if ( !bIndexTableInitialized )
2171 for ( USHORT j=0; j<NF_INDEX_TABLE_ENTRIES; j++ )
2173 theIndexTable[j] = NUMBERFORMAT_ENTRY_NOT_FOUND;
2176 BOOL bOldConvertMode = pFormatScanner->GetConvertMode();
2177 if (bOldConvertMode)
2178 pFormatScanner->SetConvertMode(FALSE); // switch off for this function
2180 NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() );
2182 xub_StrLen nCheckPos = 0;
2183 SvNumberformat* pNewFormat = NULL;
2184 String aFormatCode;
2185 sal_Int32 nIdx;
2186 sal_Bool bDefault;
2188 // Counter for additional builtin formats not fitting into the first 10
2189 // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats.
2190 // Has to be incremented on each ImpInsertNewStandardformat, new formats
2191 // must be appended, not inserted!
2192 USHORT nNewExtended = ZF_STANDARD_NEWEXTENDED;
2194 // Number
2195 uno::Sequence< i18n::NumberFormatCode > aFormatSeq
2196 = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER );
2197 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2199 // General
2200 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD );
2201 SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx],
2202 CLOffset + SetIndexTable( NF_NUMBER_STANDARD, ZF_STANDARD ));
2203 if (pStdFormat)
2205 // This is _the_ standard format.
2206 if (LocaleDataWrapper::areChecksEnabled() &&
2207 pStdFormat->GetType() != NUMBERFORMAT_NUMBER)
2209 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2210 "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER"));
2211 LocaleDataWrapper::outputCheckMessage(
2212 xLocaleData->appendLocaleInfo( aMsg));
2214 pStdFormat->SetType( NUMBERFORMAT_NUMBER );
2215 pStdFormat->SetStandard();
2216 pStdFormat->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE );
2218 else
2220 if (LocaleDataWrapper::areChecksEnabled())
2222 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
2223 "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work"));
2224 LocaleDataWrapper::outputCheckMessage(
2225 xLocaleData->appendLocaleInfo( aMsg));
2229 // Boolean
2230 aFormatCode = pFormatScanner->GetBooleanString();
2231 pNewFormat = new SvNumberformat( aFormatCode,
2232 pFormatScanner, pStringScanner, nCheckPos, ActLnge );
2233 pNewFormat->SetType(NUMBERFORMAT_LOGICAL);
2234 pNewFormat->SetStandard();
2235 if ( !aFTable.Insert(
2236 CLOffset + SetIndexTable( NF_BOOLEAN, ZF_STANDARD_LOGICAL ),
2237 pNewFormat))
2238 delete pNewFormat;
2240 // Text
2241 aFormatCode = '@';
2242 pNewFormat = new SvNumberformat( aFormatCode,
2243 pFormatScanner, pStringScanner, nCheckPos, ActLnge );
2244 pNewFormat->SetType(NUMBERFORMAT_TEXT);
2245 pNewFormat->SetStandard();
2246 if ( !aFTable.Insert(
2247 CLOffset + SetIndexTable( NF_TEXT, ZF_STANDARD_TEXT ),
2248 pNewFormat))
2249 delete pNewFormat;
2253 // 0
2254 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT );
2255 ImpInsertFormat( aFormatSeq[nIdx],
2256 CLOffset + SetIndexTable( NF_NUMBER_INT, ZF_STANDARD+1 ));
2258 // 0.00
2259 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 );
2260 ImpInsertFormat( aFormatSeq[nIdx],
2261 CLOffset + SetIndexTable( NF_NUMBER_DEC2, ZF_STANDARD+2 ));
2263 // #,##0
2264 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT );
2265 ImpInsertFormat( aFormatSeq[nIdx],
2266 CLOffset + SetIndexTable( NF_NUMBER_1000INT, ZF_STANDARD+3 ));
2268 // #,##0.00
2269 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 );
2270 ImpInsertFormat( aFormatSeq[nIdx],
2271 CLOffset + SetIndexTable( NF_NUMBER_1000DEC2, ZF_STANDARD+4 ));
2273 // #.##0,00 System country/language dependent since number formatter version 6
2274 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM );
2275 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2276 CLOffset + SetIndexTable( NF_NUMBER_SYSTEM, ZF_STANDARD+5 ),
2277 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2280 // Percent number
2281 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER );
2282 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2284 // 0%
2285 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT );
2286 ImpInsertFormat( aFormatSeq[nIdx],
2287 CLOffset + SetIndexTable( NF_PERCENT_INT, ZF_STANDARD_PERCENT ));
2289 // 0.00%
2290 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 );
2291 ImpInsertFormat( aFormatSeq[nIdx],
2292 CLOffset + SetIndexTable( NF_PERCENT_DEC2, ZF_STANDARD_PERCENT+1 ));
2296 // Currency. NO default standard option! Default is determined of locale
2297 // data default currency and format is generated if needed.
2298 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2299 if (LocaleDataWrapper::areChecksEnabled())
2301 // though no default desired here, test for correctness of locale data
2302 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2305 // #,##0
2306 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT );
2307 bDefault = aFormatSeq[nIdx].Default;
2308 aFormatSeq[nIdx].Default = sal_False;
2309 ImpInsertFormat( aFormatSeq[nIdx],
2310 CLOffset + SetIndexTable( NF_CURRENCY_1000INT, ZF_STANDARD_CURRENCY ));
2311 aFormatSeq[nIdx].Default = bDefault;
2313 // #,##0.00
2314 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 );
2315 bDefault = aFormatSeq[nIdx].Default;
2316 aFormatSeq[nIdx].Default = sal_False;
2317 ImpInsertFormat( aFormatSeq[nIdx],
2318 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2, ZF_STANDARD_CURRENCY+1 ));
2319 aFormatSeq[nIdx].Default = bDefault;
2321 // #,##0 negative red
2322 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED );
2323 bDefault = aFormatSeq[nIdx].Default;
2324 aFormatSeq[nIdx].Default = sal_False;
2325 ImpInsertFormat( aFormatSeq[nIdx],
2326 CLOffset + SetIndexTable( NF_CURRENCY_1000INT_RED, ZF_STANDARD_CURRENCY+2 ));
2327 aFormatSeq[nIdx].Default = bDefault;
2329 // #,##0.00 negative red
2330 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED );
2331 bDefault = aFormatSeq[nIdx].Default;
2332 aFormatSeq[nIdx].Default = sal_False;
2333 ImpInsertFormat( aFormatSeq[nIdx],
2334 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_RED, ZF_STANDARD_CURRENCY+3 ));
2335 aFormatSeq[nIdx].Default = bDefault;
2337 // #,##0.00 USD since number formatter version 3
2338 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC );
2339 bDefault = aFormatSeq[nIdx].Default;
2340 aFormatSeq[nIdx].Default = sal_False;
2341 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2342 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_CCC, ZF_STANDARD_CURRENCY+4 ));
2343 if ( pNewFormat )
2344 pNewFormat->SetUsed(TRUE); // must be saved for older versions
2345 aFormatSeq[nIdx].Default = bDefault;
2347 // #.##0,-- since number formatter version 6
2348 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED );
2349 bDefault = aFormatSeq[nIdx].Default;
2350 aFormatSeq[nIdx].Default = sal_False;
2351 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2352 CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_DASHED, ZF_STANDARD_CURRENCY+5 ),
2353 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2354 aFormatSeq[nIdx].Default = bDefault;
2358 // Date
2359 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE );
2360 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2362 // DD.MM.YY System
2363 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT );
2364 ImpInsertFormat( aFormatSeq[nIdx],
2365 CLOffset + SetIndexTable( NF_DATE_SYSTEM_SHORT, ZF_STANDARD_DATE ));
2367 // NN DD.MMM YY
2368 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY );
2369 ImpInsertFormat( aFormatSeq[nIdx],
2370 CLOffset + SetIndexTable( NF_DATE_DEF_NNDDMMMYY, ZF_STANDARD_DATE+1 ));
2372 // DD.MM.YY def/System
2373 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY );
2374 ImpInsertFormat( aFormatSeq[nIdx],
2375 CLOffset + SetIndexTable( NF_DATE_SYS_MMYY, ZF_STANDARD_DATE+2 ));
2377 // DD MMM
2378 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM );
2379 ImpInsertFormat( aFormatSeq[nIdx],
2380 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMM, ZF_STANDARD_DATE+3 ));
2382 // MMMM
2383 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM );
2384 ImpInsertFormat( aFormatSeq[nIdx],
2385 CLOffset + SetIndexTable( NF_DATE_MMMM, ZF_STANDARD_DATE+4 ));
2387 // QQ YY
2388 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ );
2389 ImpInsertFormat( aFormatSeq[nIdx],
2390 CLOffset + SetIndexTable( NF_DATE_QQJJ, ZF_STANDARD_DATE+5 ));
2392 // DD.MM.YYYY since number formatter version 2, was DD.MM.[YY]YY
2393 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY );
2394 pNewFormat = ImpInsertFormat( aFormatSeq[nIdx],
2395 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYYYY, ZF_STANDARD_DATE+6 ));
2396 if ( pNewFormat )
2397 pNewFormat->SetUsed(TRUE); // must be saved for older versions
2399 // DD.MM.YY def/System, since number formatter version 6
2400 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY );
2401 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2402 CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYY, ZF_STANDARD_DATE+7 ),
2403 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2405 // NNN, D. MMMM YYYY System
2406 // Long day of week: "NNNN" instead of "NNN," because of compatibility
2407 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG );
2408 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2409 CLOffset + SetIndexTable( NF_DATE_SYSTEM_LONG, ZF_STANDARD_DATE+8 ),
2410 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2412 // Hard coded but system (regional settings) delimiters dependent long date formats
2413 // since numberformatter version 6
2415 // D. MMM YY def/System
2416 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY );
2417 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2418 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYY, ZF_STANDARD_DATE+9 ),
2419 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2421 //! Unfortunally TLOT intended only 10 builtin formats per category, more
2422 //! would overwrite the next category (ZF_STANDARD_TIME) :-((
2423 //! Therefore they are inserted with nNewExtended++ (which is also limited)
2425 // D. MMM YYYY def/System
2426 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY );
2427 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2428 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYYYY, nNewExtended++ ),
2429 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2431 // D. MMMM YYYY def/System
2432 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY );
2433 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2434 CLOffset + SetIndexTable( NF_DATE_SYS_DMMMMYYYY, nNewExtended++ ),
2435 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2437 // NN, D. MMM YY def/System
2438 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY );
2439 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2440 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMYY, nNewExtended++ ),
2441 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2443 // NN, D. MMMM YYYY def/System
2444 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY );
2445 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2446 CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY, nNewExtended++ ),
2447 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2449 // NNN, D. MMMM YYYY def/System
2450 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY );
2451 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2452 CLOffset + SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY, nNewExtended++ ),
2453 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2455 // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats
2457 // D. MMM. YYYY DIN/EN
2458 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY );
2459 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2460 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMYYYY, nNewExtended++ ),
2461 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2463 // D. MMMM YYYY DIN/EN
2464 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY );
2465 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2466 CLOffset + SetIndexTable( NF_DATE_DIN_DMMMMYYYY, nNewExtended++ ),
2467 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2469 // MM-DD DIN/EN
2470 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD );
2471 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2472 CLOffset + SetIndexTable( NF_DATE_DIN_MMDD, nNewExtended++ ),
2473 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2475 // YY-MM-DD DIN/EN
2476 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD );
2477 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2478 CLOffset + SetIndexTable( NF_DATE_DIN_YYMMDD, nNewExtended++ ),
2479 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2481 // YYYY-MM-DD DIN/EN
2482 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD );
2483 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2484 CLOffset + SetIndexTable( NF_DATE_DIN_YYYYMMDD, nNewExtended++ ),
2485 SV_NUMBERFORMATTER_VERSION_NEWSTANDARD );
2489 // Time
2490 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::TIME );
2491 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2493 // HH:MM
2494 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM );
2495 ImpInsertFormat( aFormatSeq[nIdx],
2496 CLOffset + SetIndexTable( NF_TIME_HHMM, ZF_STANDARD_TIME ));
2498 // HH:MM:SS
2499 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS );
2500 ImpInsertFormat( aFormatSeq[nIdx],
2501 CLOffset + SetIndexTable( NF_TIME_HHMMSS, ZF_STANDARD_TIME+1 ));
2503 // HH:MM AM/PM
2504 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM );
2505 ImpInsertFormat( aFormatSeq[nIdx],
2506 CLOffset + SetIndexTable( NF_TIME_HHMMAMPM, ZF_STANDARD_TIME+2 ));
2508 // HH:MM:SS AM/PM
2509 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM );
2510 ImpInsertFormat( aFormatSeq[nIdx],
2511 CLOffset + SetIndexTable( NF_TIME_HHMMSSAMPM, ZF_STANDARD_TIME+3 ));
2513 // [HH]:MM:SS
2514 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS );
2515 ImpInsertFormat( aFormatSeq[nIdx],
2516 CLOffset + SetIndexTable( NF_TIME_HH_MMSS, ZF_STANDARD_TIME+4 ));
2518 // MM:SS,00
2519 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 );
2520 ImpInsertFormat( aFormatSeq[nIdx],
2521 CLOffset + SetIndexTable( NF_TIME_MMSS00, ZF_STANDARD_TIME+5 ));
2523 // [HH]:MM:SS,00
2524 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 );
2525 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2526 CLOffset + SetIndexTable( NF_TIME_HH_MMSS00, ZF_STANDARD_TIME+6 ),
2527 SV_NUMBERFORMATTER_VERSION_NF_TIME_HH_MMSS00 );
2531 // DateTime
2532 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME );
2533 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2535 // DD.MM.YY HH:MM System
2536 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM );
2537 ImpInsertFormat( aFormatSeq[nIdx],
2538 CLOffset + SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM, ZF_STANDARD_DATETIME ));
2540 // DD.MM.YYYY HH:MM:SS System
2541 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2542 ImpInsertNewStandardFormat( aFormatSeq[nIdx],
2543 CLOffset + SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, ZF_STANDARD_DATETIME+1 ),
2544 SV_NUMBERFORMATTER_VERSION_NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
2548 // Scientific number
2549 aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER );
2550 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() );
2552 // 0.00E+000
2553 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 );
2554 ImpInsertFormat( aFormatSeq[nIdx],
2555 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E000, ZF_STANDARD_SCIENTIFIC ));
2557 // 0.00E+00
2558 nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 );
2559 ImpInsertFormat( aFormatSeq[nIdx],
2560 CLOffset + SetIndexTable( NF_SCIENTIFIC_000E00, ZF_STANDARD_SCIENTIFIC+1 ));
2564 // Fraction number (no default option)
2565 i18n::NumberFormatCode aSingleFormatCode;
2567 // # ?/?
2568 aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) );
2569 String s25( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) ); // # ?/?
2570 ImpInsertFormat( aSingleFormatCode,
2571 CLOffset + SetIndexTable( NF_FRACTION_1, ZF_STANDARD_FRACTION ));
2573 // # ??/??
2574 //! "??/" would be interpreted by the compiler as a trigraph for '\'
2575 aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?\?/?\?" ) );
2576 ImpInsertFormat( aSingleFormatCode,
2577 CLOffset + SetIndexTable( NF_FRACTION_2, ZF_STANDARD_FRACTION+1 ));
2579 // Week of year must be appended here because of nNewExtended
2580 const String* pKeyword = pFormatScanner->GetKeywords();
2581 aSingleFormatCode.Code = pKeyword[NF_KEY_WW];
2582 ImpInsertNewStandardFormat( aSingleFormatCode,
2583 CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ),
2584 SV_NUMBERFORMATTER_VERSION_NF_DATE_WW );
2588 bIndexTableInitialized = TRUE;
2589 DBG_ASSERT( nNewExtended <= ZF_STANDARD_NEWEXTENDEDMAX,
2590 "ImpGenerateFormats: overflow of nNewExtended standard formats" );
2592 // Now all additional format codes provided by I18N, but only if not
2593 // loading from old SO5 file format, then they are appended last.
2594 if ( !bLoadingSO5 )
2595 ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, FALSE );
2597 if (bOldConvertMode)
2598 pFormatScanner->SetConvertMode(TRUE);
2602 void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset,
2603 NumberFormatCodeWrapper& rNumberFormatCode, BOOL bAfterLoadingSO5 )
2605 using namespace ::com::sun::star;
2607 SvNumberformat* pStdFormat =
2608 (SvNumberformat*) aFTable.Get( CLOffset + ZF_STANDARD );
2609 if ( !pStdFormat )
2611 DBG_ERRORFILE( "ImpGenerateAdditionalFormats: no GENERAL format" );
2612 return ;
2614 sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey();
2615 rNumberFormatCode.setLocale( GetLocale() );
2616 sal_Int32 j;
2618 // All currencies, this time with [$...] which was stripped in
2619 // ImpGenerateFormats for old "automatic" currency formats.
2620 uno::Sequence< i18n::NumberFormatCode > aFormatSeq =
2621 rNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY );
2622 i18n::NumberFormatCode * pFormatArr = aFormatSeq.getArray();
2623 sal_Int32 nCodes = aFormatSeq.getLength();
2624 ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes );
2625 for ( j = 0; j < nCodes; j++ )
2627 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2629 DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" );
2630 break; // for
2632 if ( pFormatArr[j].Index < NF_INDEX_TABLE_ENTRIES &&
2633 pFormatArr[j].Index != NF_CURRENCY_1000DEC2_CCC )
2634 { // Insert only if not already inserted, but internal index must be
2635 // above so ImpInsertFormat can distinguish it.
2636 sal_Int16 nOrgIndex = pFormatArr[j].Index;
2637 pFormatArr[j].Index = sal::static_int_cast< sal_Int16 >(
2638 pFormatArr[j].Index + nCodes + NF_INDEX_TABLE_ENTRIES);
2639 //! no default on currency
2640 sal_Bool bDefault = aFormatSeq[j].Default;
2641 aFormatSeq[j].Default = sal_False;
2642 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2643 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2644 bAfterLoadingSO5, nOrgIndex ) )
2645 nPos++;
2646 pFormatArr[j].Index = nOrgIndex;
2647 aFormatSeq[j].Default = bDefault;
2651 // all additional format codes provided by I18N that are not old standard index
2652 aFormatSeq = rNumberFormatCode.getAllFormatCodes();
2653 nCodes = aFormatSeq.getLength();
2654 if ( nCodes )
2656 pFormatArr = aFormatSeq.getArray();
2657 // don't check ALL
2658 sal_Int32 nDef = ImpAdjustFormatCodeDefault( pFormatArr, nCodes, FALSE);
2659 // don't have any defaults here
2660 pFormatArr[nDef].Default = sal_False;
2661 for ( j = 0; j < nCodes; j++ )
2663 if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET )
2665 DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" );
2666 break; // for
2668 if ( pFormatArr[j].Index >= NF_INDEX_TABLE_ENTRIES )
2669 if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1,
2670 SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS,
2671 bAfterLoadingSO5 ) )
2672 nPos++;
2676 pStdFormat->SetLastInsertKey( (USHORT)(nPos - CLOffset) );
2680 void SvNumberFormatter::ImpGetPosCurrFormat( String& sPosStr, const String& rCurrSymbol )
2682 NfCurrencyEntry::CompletePositiveFormatString( sPosStr,
2683 rCurrSymbol, xLocaleData->getCurrPositiveFormat() );
2686 void SvNumberFormatter::ImpGetNegCurrFormat( String& sNegStr, const String& rCurrSymbol )
2688 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr,
2689 rCurrSymbol, xLocaleData->getCurrNegativeFormat() );
2692 void SvNumberFormatter::GenerateFormat(String& sString,
2693 sal_uInt32 nIndex,
2694 LanguageType eLnge,
2695 BOOL bThousand,
2696 BOOL IsRed,
2697 USHORT nPrecision,
2698 USHORT nAnzLeading)
2700 if (eLnge == LANGUAGE_DONTKNOW)
2701 eLnge = IniLnge;
2702 short eType = GetType(nIndex);
2703 USHORT i;
2704 ImpGenerateCL(eLnge); // ggfs. neu Standard-
2705 // formate anlegen
2706 sString.Erase();
2708 utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping());
2709 const xub_StrLen nDigitsInFirstGroup = static_cast<xub_StrLen>(aGrouping.get());
2710 const String& rThSep = GetNumThousandSep();
2711 if (nAnzLeading == 0)
2713 if (!bThousand)
2714 sString += '#';
2715 else
2717 sString += '#';
2718 sString += rThSep;
2719 sString.Expand( sString.Len() + nDigitsInFirstGroup, '#' );
2722 else
2724 for (i = 0; i < nAnzLeading; i++)
2726 if (bThousand && i > 0 && i == aGrouping.getPos())
2728 sString.Insert( rThSep, 0 );
2729 aGrouping.advance();
2731 sString.Insert('0',0);
2733 if (bThousand && nAnzLeading < nDigitsInFirstGroup + 1)
2735 for (i = nAnzLeading; i < nDigitsInFirstGroup + 1; i++)
2737 if (bThousand && i % nDigitsInFirstGroup == 0)
2738 sString.Insert( rThSep, 0 );
2739 sString.Insert('#',0);
2743 if (nPrecision > 0)
2745 sString += GetNumDecimalSep();
2746 sString.Expand( sString.Len() + nPrecision, '0' );
2748 if (eType == NUMBERFORMAT_PERCENT)
2749 sString += '%';
2750 else if (eType == NUMBERFORMAT_CURRENCY)
2752 String sNegStr = sString;
2753 String aCurr;
2754 const NfCurrencyEntry* pEntry;
2755 BOOL bBank;
2756 if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) )
2758 if ( pEntry )
2760 USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2761 xLocaleData->getCurrPositiveFormat(),
2762 pEntry->GetPositiveFormat(), bBank );
2763 USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2764 xLocaleData->getCurrNegativeFormat(),
2765 pEntry->GetNegativeFormat(), bBank );
2766 pEntry->CompletePositiveFormatString( sString, bBank,
2767 nPosiForm );
2768 pEntry->CompleteNegativeFormatString( sNegStr, bBank,
2769 nNegaForm );
2771 else
2772 { // assume currency abbreviation (AKA banking symbol), not symbol
2773 USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
2774 xLocaleData->getCurrPositiveFormat(),
2775 xLocaleData->getCurrPositiveFormat(), TRUE );
2776 USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
2777 xLocaleData->getCurrNegativeFormat(),
2778 xLocaleData->getCurrNegativeFormat(), TRUE );
2779 NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr,
2780 nPosiForm );
2781 NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr,
2782 nNegaForm );
2785 else
2786 { // "automatic" old style
2787 String aSymbol, aAbbrev;
2788 GetCompatibilityCurrency( aSymbol, aAbbrev );
2789 ImpGetPosCurrFormat( sString, aSymbol );
2790 ImpGetNegCurrFormat( sNegStr, aSymbol );
2792 if (IsRed)
2794 sString += ';';
2795 sString += '[';
2796 sString += pFormatScanner->GetRedString();
2797 sString += ']';
2799 else
2800 sString += ';';
2801 sString += sNegStr;
2803 if (IsRed && eType != NUMBERFORMAT_CURRENCY)
2805 String sTmpStr = sString;
2806 sTmpStr += ';';
2807 sTmpStr += '[';
2808 sTmpStr += pFormatScanner->GetRedString();
2809 sTmpStr += ']';
2810 sTmpStr += '-';
2811 sTmpStr +=sString;
2812 sString = sTmpStr;
2816 BOOL SvNumberFormatter::IsUserDefined(const String& sStr,
2817 LanguageType eLnge)
2819 if (eLnge == LANGUAGE_DONTKNOW)
2820 eLnge = IniLnge;
2821 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
2822 // formate anlegen
2823 eLnge = ActLnge;
2824 sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge);
2825 if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND)
2826 return TRUE;
2827 SvNumberformat* pEntry = aFTable.Get(nKey);
2828 if ( pEntry && ((pEntry->GetType() & NUMBERFORMAT_DEFINED) != 0) )
2829 return TRUE;
2830 return FALSE;
2833 sal_uInt32 SvNumberFormatter::GetEntryKey(const String& sStr,
2834 LanguageType eLnge)
2836 if (eLnge == LANGUAGE_DONTKNOW)
2837 eLnge = IniLnge;
2838 sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard-
2839 // formate anlegen
2840 return ImpIsEntry(sStr, CLOffset, eLnge);
2843 sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge)
2845 if (eLnge == LANGUAGE_DONTKNOW)
2846 eLnge = IniLnge;
2847 return GetStandardFormat(NUMBERFORMAT_NUMBER, eLnge);
2850 short SvNumberFormatter::GetType(sal_uInt32 nFIndex)
2852 short eType;
2853 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex);
2854 if (!pFormat)
2855 eType = NUMBERFORMAT_UNDEFINED;
2856 else
2858 eType = pFormat->GetType() &~NUMBERFORMAT_DEFINED;
2859 if (eType == 0)
2860 eType = NUMBERFORMAT_DEFINED;
2862 return eType;
2865 void SvNumberFormatter::ClearMergeTable()
2867 if ( pMergeTable )
2869 sal_uInt32* pIndex = (sal_uInt32*) pMergeTable->First();
2870 while (pIndex)
2872 delete pIndex;
2873 pIndex = pMergeTable->Next();
2875 pMergeTable->Clear();
2879 SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable)
2881 if ( pMergeTable )
2882 ClearMergeTable();
2883 else
2884 pMergeTable = new SvNumberFormatterIndexTable;
2885 sal_uInt32 nCLOffset = 0;
2886 sal_uInt32 nOldKey, nOffset, nNewKey;
2887 sal_uInt32* pNewIndex;
2888 SvNumberformat* pNewEntry;
2889 SvNumberformat* pFormat = rTable.aFTable.First();
2890 while (pFormat)
2892 nOldKey = rTable.aFTable.GetCurKey();
2893 nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
2894 if (nOffset == 0) // 1. Format von CL
2895 nCLOffset = ImpGenerateCL(pFormat->GetLanguage());
2897 if (nOffset <= SV_MAX_ANZ_STANDARD_FORMATE) // Std.form.
2899 nNewKey = nCLOffset + nOffset;
2900 if (!aFTable.Get(nNewKey)) // noch nicht da
2902 // pNewEntry = new SvNumberformat(*pFormat); // Copy reicht nicht !!!
2903 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2904 if (!aFTable.Insert(nNewKey, pNewEntry))
2905 delete pNewEntry;
2907 if (nNewKey != nOldKey) // neuer Index
2909 pNewIndex = new sal_uInt32(nNewKey);
2910 if (!pMergeTable->Insert(nOldKey,pNewIndex))
2911 delete pNewIndex;
2914 else // benutzerdef.
2916 // pNewEntry = new SvNumberformat(*pFormat); // Copy reicht nicht !!!
2917 pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner );
2918 nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(),
2919 nCLOffset,
2920 pFormat->GetLanguage());
2921 if (nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden
2922 delete pNewEntry;
2923 else
2925 SvNumberformat* pStdFormat =
2926 (SvNumberformat*) aFTable.Get(nCLOffset + ZF_STANDARD);
2927 sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey();
2928 nNewKey = nPos+1;
2929 if (nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET)
2931 Sound::Beep();
2932 DBG_ERROR(
2933 "SvNumberFormatter:: Zu viele Formate pro CL");
2934 delete pNewEntry;
2936 else if (!aFTable.Insert(nNewKey, pNewEntry))
2937 delete pNewEntry;
2938 else
2939 pStdFormat->SetLastInsertKey((USHORT) (nNewKey - nCLOffset));
2941 if (nNewKey != nOldKey) // neuer Index
2943 pNewIndex = new sal_uInt32(nNewKey);
2944 if (!pMergeTable->Insert(nOldKey,pNewIndex))
2945 delete pNewIndex;
2948 pFormat = rTable.aFTable.Next();
2950 return pMergeTable;
2954 SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap()
2956 if (!HasMergeFmtTbl())
2957 return SvNumberFormatterMergeMap();
2959 SvNumberFormatterMergeMap aMap;
2960 for (sal_uInt32* pIndex = pMergeTable->First(); pIndex; pIndex = pMergeTable->Next())
2962 sal_uInt32 nOldKey = pMergeTable->GetCurKey();
2963 aMap.insert( SvNumberFormatterMergeMap::value_type( nOldKey, *pIndex));
2965 ClearMergeTable();
2966 return aMap;
2970 sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat,
2971 LanguageType eLnge )
2973 if ( eLnge == LANGUAGE_DONTKNOW )
2974 eLnge = IniLnge;
2975 if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge )
2976 return nFormat; // es bleibt wie es ist
2977 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
2978 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
2979 return nFormat; // kein eingebautes Format
2980 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // ggbf. generieren
2981 return nCLOffset + nOffset;
2985 sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff,
2986 LanguageType eLnge )
2988 if ( nTabOff >= NF_INDEX_TABLE_ENTRIES
2989 || theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND )
2990 return NUMBERFORMAT_ENTRY_NOT_FOUND;
2991 if ( eLnge == LANGUAGE_DONTKNOW )
2992 eLnge = IniLnge;
2993 sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // ggbf. generieren
2994 return nCLOffset + theIndexTable[nTabOff];
2998 NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const
3000 sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex
3001 if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE )
3002 return NF_INDEX_TABLE_ENTRIES; // kein eingebautes Format
3003 for ( USHORT j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ )
3005 if ( theIndexTable[j] == nOffset )
3006 return (NfIndexTableOffset) j;
3008 return NF_INDEX_TABLE_ENTRIES; // bad luck
3012 void SvNumberFormatter::SetYear2000( USHORT nVal )
3014 pStringScanner->SetYear2000( nVal );
3018 USHORT SvNumberFormatter::GetYear2000() const
3020 return pStringScanner->GetYear2000();
3024 USHORT SvNumberFormatter::ExpandTwoDigitYear( USHORT nYear ) const
3026 if ( nYear < 100 )
3027 return SvNumberFormatter::ExpandTwoDigitYear( nYear,
3028 pStringScanner->GetYear2000() );
3029 return nYear;
3033 // static
3034 USHORT SvNumberFormatter::GetYear2000Default()
3036 return Application::GetSettings().GetMiscSettings().GetTwoDigitYearStart();
3040 // static
3041 const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable()
3043 ::osl::MutexGuard aGuard( GetMutex() );
3044 while ( !bCurrencyTableInitialized )
3045 ImpInitCurrencyTable();
3046 return theCurrencyTable::get();
3050 // static
3051 const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency()
3053 // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition
3054 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3055 return nSystemCurrencyPosition ? rTable[nSystemCurrencyPosition] : NULL;
3059 // static
3060 const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang )
3062 if ( eLang == LANGUAGE_SYSTEM )
3064 const NfCurrencyEntry* pCurr = MatchSystemCurrency();
3065 return pCurr ? *pCurr : *(GetTheCurrencyTable()[0]);
3067 else
3069 eLang = MsLangId::getRealLanguage( eLang );
3070 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3071 USHORT nCount = rTable.Count();
3072 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3073 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3075 if ( (*ppData)->GetLanguage() == eLang )
3076 return **ppData;
3078 return *(rTable[0]);
3083 // static
3084 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry(
3085 const String& rAbbrev, LanguageType eLang )
3087 eLang = MsLangId::getRealLanguage( eLang );
3088 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3089 USHORT nCount = rTable.Count();
3090 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3091 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3093 if ( (*ppData)->GetLanguage() == eLang &&
3094 (*ppData)->GetBankSymbol() == rAbbrev )
3095 return *ppData;
3097 return NULL;
3101 // static
3102 const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry(
3103 const String& rSymbol, const String& rAbbrev )
3105 if (!bCurrencyTableInitialized)
3106 GetTheCurrencyTable(); // just for initialization
3107 const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get();
3108 USHORT nCount = rTable.Count();
3109 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3110 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3112 if ( (*ppData)->GetSymbol() == rSymbol &&
3113 (*ppData)->GetBankSymbol() == rAbbrev )
3114 return *ppData;
3116 return NULL;
3120 // static
3121 IMPL_STATIC_LINK_NOINSTANCE( SvNumberFormatter, CurrencyChangeLink, void*, EMPTYARG )
3123 ::osl::MutexGuard aGuard( GetMutex() );
3124 String aAbbrev;
3125 LanguageType eLang = LANGUAGE_SYSTEM;
3126 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang );
3127 SetDefaultSystemCurrency( aAbbrev, eLang );
3128 return 0;
3132 // static
3133 void SvNumberFormatter::SetDefaultSystemCurrency( const String& rAbbrev, LanguageType eLang )
3135 ::osl::MutexGuard aGuard( GetMutex() );
3136 if ( eLang == LANGUAGE_SYSTEM )
3137 eLang = Application::GetSettings().GetLanguage();
3138 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3139 USHORT nCount = rTable.Count();
3140 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3141 if ( rAbbrev.Len() )
3143 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3145 if ( (*ppData)->GetLanguage() == eLang && (*ppData)->GetBankSymbol() == rAbbrev )
3147 nSystemCurrencyPosition = j;
3148 return ;
3152 else
3154 for ( USHORT j = 0; j < nCount; j++, ppData++ )
3156 if ( (*ppData)->GetLanguage() == eLang )
3158 nSystemCurrencyPosition = j;
3159 return ;
3163 nSystemCurrencyPosition = 0; // not found => simple SYSTEM
3167 void SvNumberFormatter::ResetDefaultSystemCurrency()
3169 nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3173 sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat()
3175 if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3177 xub_StrLen nCheck;
3178 short nType;
3179 NfWSStringsDtor aCurrList;
3180 USHORT nDefault = GetCurrencyFormatStrings( aCurrList,
3181 GetCurrencyEntry( LANGUAGE_SYSTEM ), FALSE );
3182 DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency System standard format?!?" );
3183 // if already loaded or user defined nDefaultSystemCurrencyFormat
3184 // will be set to the right value
3185 PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType,
3186 nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM );
3187 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3188 DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3189 "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3191 return nDefaultSystemCurrencyFormat;
3195 sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat()
3197 sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge );
3198 sal_uInt32 nDefaultCurrencyFormat =
3199 (sal_uInt32)(sal_uIntPtr) aDefaultFormatKeys.Get( CLOffset + ZF_STANDARD_CURRENCY );
3200 if ( !nDefaultCurrencyFormat )
3201 nDefaultCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND;
3202 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3204 // look for a defined standard
3205 sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET;
3206 sal_uInt32 nKey;
3207 aFTable.Seek( CLOffset );
3208 while ( (nKey = aFTable.GetCurKey()) >= CLOffset && nKey < nStopKey )
3210 const SvNumberformat* pEntry =
3211 (const SvNumberformat*) aFTable.GetCurObject();
3212 if ( pEntry->IsStandard() && (pEntry->GetType() & NUMBERFORMAT_CURRENCY) )
3214 nDefaultCurrencyFormat = nKey;
3215 break; // while
3217 aFTable.Next();
3220 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3221 { // none found, create one
3222 xub_StrLen nCheck;
3223 short nType;
3224 NfWSStringsDtor aCurrList;
3225 USHORT nDefault = GetCurrencyFormatStrings( aCurrList,
3226 GetCurrencyEntry( ActLnge ), FALSE );
3227 DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency standard format?" );
3228 if ( aCurrList.Count() )
3230 // if already loaded or user defined nDefaultSystemCurrencyFormat
3231 // will be set to the right value
3232 PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType,
3233 nDefaultCurrencyFormat, ActLnge );
3234 DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" );
3235 DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND,
3236 "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" );
3238 // old automatic currency format as a last resort
3239 if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
3240 nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3;
3241 else
3242 { // mark as standard so that it is found next time
3243 SvNumberformat* pEntry = aFTable.Get( nDefaultCurrencyFormat );
3244 if ( pEntry )
3245 pEntry->SetStandard();
3248 aDefaultFormatKeys.Insert( CLOffset + ZF_STANDARD_CURRENCY,
3249 (void*) nDefaultCurrencyFormat );
3251 return nDefaultCurrencyFormat;
3255 // static
3256 // try to make it inline if possible since this a loop body
3257 // TRUE: continue; FALSE: break loop, if pFoundEntry==NULL dupe found
3258 #ifdef PRODUCT
3259 inline
3260 #endif
3261 BOOL SvNumberFormatter::ImpLookupCurrencyEntryLoopBody(
3262 const NfCurrencyEntry*& pFoundEntry, BOOL& bFoundBank,
3263 const NfCurrencyEntry* pData, USHORT nPos, const String& rSymbol )
3265 BOOL bFound;
3266 if ( pData->GetSymbol() == rSymbol )
3268 bFound = TRUE;
3269 bFoundBank = FALSE;
3271 else if ( pData->GetBankSymbol() == rSymbol )
3273 bFound = TRUE;
3274 bFoundBank = TRUE;
3276 else
3277 bFound = FALSE;
3278 if ( bFound )
3280 if ( pFoundEntry && pFoundEntry != pData )
3282 pFoundEntry = NULL;
3283 return FALSE; // break loop, not unique
3285 if ( nPos == 0 )
3286 { // first entry is SYSTEM
3287 pFoundEntry = MatchSystemCurrency();
3288 if ( pFoundEntry )
3289 return FALSE; // break loop
3290 // even if there are more matching entries
3291 // this one is propably the one we are looking for
3292 else
3293 pFoundEntry = pData;
3295 else
3296 pFoundEntry = pData;
3298 return TRUE;
3302 BOOL SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat,
3303 String& rStr, const NfCurrencyEntry** ppEntry /* = NULL */,
3304 BOOL* pBank /* = NULL */ ) const
3306 rStr.Erase();
3307 if ( ppEntry )
3308 *ppEntry = NULL;
3309 if ( pBank )
3310 *pBank = FALSE;
3311 SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get( nFormat );
3312 if ( pFormat )
3314 String aSymbol, aExtension;
3315 if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
3317 if ( ppEntry )
3319 BOOL bFoundBank = FALSE;
3320 // we definiteley need an entry matching the format code string
3321 const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry(
3322 bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(),
3323 TRUE );
3324 if ( pFoundEntry )
3326 *ppEntry = pFoundEntry;
3327 if ( pBank )
3328 *pBank = bFoundBank;
3329 pFoundEntry->BuildSymbolString( rStr, bFoundBank );
3332 if ( !rStr.Len() )
3333 { // analog zu BuildSymbolString
3334 rStr = '[';
3335 rStr += '$';
3336 if ( aSymbol.Search( '-' ) != STRING_NOTFOUND ||
3337 aSymbol.Search( ']' ) != STRING_NOTFOUND )
3339 rStr += '"';
3340 rStr += aSymbol;
3341 rStr += '"';
3343 else
3344 rStr += aSymbol;
3345 if ( aExtension.Len() )
3346 rStr += aExtension;
3347 rStr += ']';
3349 return TRUE;
3352 return FALSE;
3356 // static
3357 const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( BOOL & bFoundBank,
3358 const String& rSymbol, const String& rExtension,
3359 LanguageType eFormatLanguage, BOOL bOnlyStringLanguage )
3361 xub_StrLen nExtLen = rExtension.Len();
3362 LanguageType eExtLang;
3363 if ( nExtLen )
3365 sal_Int32 nExtLang = ::rtl::OUString( rExtension ).toInt32( 16 );
3366 if ( !nExtLang )
3367 eExtLang = LANGUAGE_DONTKNOW;
3368 else
3369 eExtLang = (LanguageType) ((nExtLang < 0) ?
3370 -nExtLang : nExtLang);
3372 else
3373 eExtLang = LANGUAGE_DONTKNOW;
3374 const NfCurrencyEntry* pFoundEntry = NULL;
3375 const NfCurrencyTable& rTable = GetTheCurrencyTable();
3376 USHORT nCount = rTable.Count();
3377 BOOL bCont = TRUE;
3379 // first try with given extension language/country
3380 if ( nExtLen )
3382 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3383 for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ )
3385 LanguageType eLang = (*ppData)->GetLanguage();
3386 if ( eLang == eExtLang ||
3387 ((eExtLang == LANGUAGE_DONTKNOW) &&
3388 (eLang == LANGUAGE_SYSTEM))
3391 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3392 *ppData, j, rSymbol );
3397 // ok?
3398 if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) )
3399 return pFoundEntry;
3401 if ( !bOnlyStringLanguage )
3403 // now try the language/country of the number format
3404 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3405 for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ )
3407 LanguageType eLang = (*ppData)->GetLanguage();
3408 if ( eLang == eFormatLanguage ||
3409 ((eFormatLanguage == LANGUAGE_DONTKNOW) &&
3410 (eLang == LANGUAGE_SYSTEM))
3413 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3414 *ppData, j, rSymbol );
3418 // ok?
3419 if ( pFoundEntry || !bCont )
3420 return pFoundEntry;
3423 // then try without language/country if no extension specified
3424 if ( !nExtLen )
3426 const NfCurrencyEntryPtr* ppData = rTable.GetData();
3427 for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ )
3429 bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank,
3430 *ppData, j, rSymbol );
3434 return pFoundEntry;
3438 void SvNumberFormatter::GetCompatibilityCurrency( String& rSymbol, String& rAbbrev ) const
3440 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 >
3441 xCurrencies = xLocaleData->getAllCurrencies();
3442 sal_Int32 nCurrencies = xCurrencies.getLength();
3443 sal_Int32 j;
3444 for ( j=0; j < nCurrencies; ++j )
3446 if ( xCurrencies[j].UsedInCompatibleFormatCodes )
3448 rSymbol = xCurrencies[j].Symbol;
3449 rAbbrev = xCurrencies[j].BankSymbol;
3450 break;
3453 if ( j >= nCurrencies )
3455 if (LocaleDataWrapper::areChecksEnabled())
3457 String aMsg( RTL_CONSTASCII_USTRINGPARAM(
3458 "GetCompatibilityCurrency: none?"));
3459 LocaleDataWrapper::outputCheckMessage(
3460 xLocaleData->appendLocaleInfo( aMsg));
3462 rSymbol = xLocaleData->getCurrSymbol();
3463 rAbbrev = xLocaleData->getCurrBankSymbol();
3468 void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr )
3470 short nPos = -1; // -1:=unknown, 0:=vorne, 1:=hinten
3471 short nNeg = -1;
3472 switch ( rCurr.GetPositiveFormat() )
3474 case 0: // $1
3475 nPos = 0;
3476 break;
3477 case 1: // 1$
3478 nPos = 1;
3479 break;
3480 case 2: // $ 1
3481 nPos = 0;
3482 break;
3483 case 3: // 1 $
3484 nPos = 1;
3485 break;
3486 default:
3487 LocaleDataWrapper::outputCheckMessage(
3488 "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat");
3489 break;
3491 switch ( rCurr.GetNegativeFormat() )
3493 case 0: // ($1)
3494 nNeg = 0;
3495 break;
3496 case 1: // -$1
3497 nNeg = 0;
3498 break;
3499 case 2: // $-1
3500 nNeg = 0;
3501 break;
3502 case 3: // $1-
3503 nNeg = 0;
3504 break;
3505 case 4: // (1$)
3506 nNeg = 1;
3507 break;
3508 case 5: // -1$
3509 nNeg = 1;
3510 break;
3511 case 6: // 1-$
3512 nNeg = 1;
3513 break;
3514 case 7: // 1$-
3515 nNeg = 1;
3516 break;
3517 case 8: // -1 $
3518 nNeg = 1;
3519 break;
3520 case 9: // -$ 1
3521 nNeg = 0;
3522 break;
3523 case 10: // 1 $-
3524 nNeg = 1;
3525 break;
3526 case 11: // $ -1
3527 nNeg = 0;
3528 break;
3529 case 12 : // $ 1-
3530 nNeg = 0;
3531 break;
3532 case 13 : // 1- $
3533 nNeg = 1;
3534 break;
3535 case 14 : // ($ 1)
3536 nNeg = 0;
3537 break;
3538 case 15 : // (1 $)
3539 nNeg = 1;
3540 break;
3541 default:
3542 LocaleDataWrapper::outputCheckMessage(
3543 "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat");
3544 break;
3546 if ( nPos >= 0 && nNeg >= 0 && nPos != nNeg )
3548 ByteString aStr( "positions of currency symbols differ\nLanguage: " );
3549 aStr += ByteString::CreateFromInt32( rCurr.GetLanguage() );
3550 aStr += " <";
3551 aStr += ByteString( rCurr.GetSymbol(), RTL_TEXTENCODING_UTF8 );
3552 aStr += "> positive: ";
3553 aStr += ByteString::CreateFromInt32( rCurr.GetPositiveFormat() );
3554 aStr += ( nPos ? " (postfix)" : " (prefix)" );
3555 aStr += ", negative: ";
3556 aStr += ByteString::CreateFromInt32( rCurr.GetNegativeFormat() );
3557 aStr += ( nNeg ? " (postfix)" : " (prefix)" );
3558 #if 0
3559 // seems that there really are some currencies which differ, e.g. YugoDinar
3560 DBG_ERRORFILE( aStr.GetBuffer() );
3561 #endif
3566 // static
3567 void SvNumberFormatter::ImpInitCurrencyTable()
3569 // racing condition possible:
3570 // ::osl::MutexGuard aGuard( GetMutex() );
3571 // while ( !bCurrencyTableInitialized )
3572 // ImpInitCurrencyTable();
3573 static BOOL bInitializing = FALSE;
3574 if ( bCurrencyTableInitialized || bInitializing )
3575 return ;
3576 bInitializing = TRUE;
3578 RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svtools", "er93726", "SvNumberFormatter::ImpInitCurrencyTable" );
3580 LanguageType eSysLang = Application::GetSettings().GetLanguage();
3581 LocaleDataWrapper* pLocaleData = new LocaleDataWrapper(
3582 ::comphelper::getProcessServiceFactory(),
3583 MsLangId::convertLanguageToLocale( eSysLang ) );
3584 // get user configured currency
3585 String aConfiguredCurrencyAbbrev;
3586 LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM;
3587 SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage(
3588 aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage );
3589 USHORT nSecondarySystemCurrencyPosition = 0;
3590 USHORT nMatchingSystemCurrencyPosition = 0;
3591 NfCurrencyEntryPtr pEntry;
3593 // first entry is SYSTEM
3594 pEntry = new NfCurrencyEntry( *pLocaleData, LANGUAGE_SYSTEM );
3595 theCurrencyTable::get().Insert( pEntry, 0 );
3596 USHORT nCurrencyPos = 1;
3598 ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc =
3599 LocaleDataWrapper::getInstalledLocaleNames();
3600 sal_Int32 nLocaleCount = xLoc.getLength();
3601 RTL_LOGFILE_CONTEXT_TRACE1( aTimeLog, "number of locales: %ld", nLocaleCount );
3602 Locale const * const pLocales = xLoc.getConstArray();
3603 NfCurrencyTable &rCurrencyTable = theCurrencyTable::get();
3604 NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get();
3605 USHORT nLegacyOnlyCurrencyPos = 0;
3606 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
3608 LanguageType eLang = MsLangId::convertLocaleToLanguage(
3609 pLocales[nLocale]);
3610 #if OSL_DEBUG_LEVEL > 1
3611 LanguageType eReal = MsLangId::getRealLanguage( eLang );
3612 if ( eReal != eLang ) {
3613 BOOL bBreak;
3614 bBreak = TRUE;
3616 #endif
3617 pLocaleData->setLocale( pLocales[nLocale] );
3618 Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies();
3619 sal_Int32 nCurrencyCount = aCurrSeq.getLength();
3620 Currency2 const * const pCurrencies = aCurrSeq.getConstArray();
3622 // one default currency for each locale, insert first so it is found first
3623 sal_Int32 nDefault;
3624 for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ )
3626 if ( pCurrencies[nDefault].Default )
3627 break;
3629 if ( nDefault < nCurrencyCount )
3630 pEntry = new NfCurrencyEntry( pCurrencies[nDefault], *pLocaleData, eLang );
3631 else
3632 pEntry = new NfCurrencyEntry( *pLocaleData, eLang ); // first or ShellsAndPebbles
3634 if (LocaleDataWrapper::areChecksEnabled())
3635 lcl_CheckCurrencySymbolPosition( *pEntry );
3637 rCurrencyTable.Insert( pEntry, nCurrencyPos++ );
3638 if ( !nSystemCurrencyPosition && (aConfiguredCurrencyAbbrev.Len() ?
3639 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev &&
3640 pEntry->GetLanguage() == eConfiguredCurrencyLanguage : FALSE) )
3641 nSystemCurrencyPosition = nCurrencyPos-1;
3642 if ( !nMatchingSystemCurrencyPosition &&
3643 pEntry->GetLanguage() == eSysLang )
3644 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3646 // all remaining currencies for each locale
3647 if ( nCurrencyCount > 1 )
3649 sal_Int32 nCurrency;
3650 for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ )
3652 if (pCurrencies[nCurrency].LegacyOnly)
3654 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3655 rLegacyOnlyCurrencyTable.Insert( pEntry, nLegacyOnlyCurrencyPos++ );
3657 else if ( nCurrency != nDefault )
3659 pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang );
3660 // no dupes
3661 BOOL bInsert = TRUE;
3662 NfCurrencyEntry const * const * pData = rCurrencyTable.GetData();
3663 USHORT n = rCurrencyTable.Count();
3664 pData++; // skip first SYSTEM entry
3665 for ( USHORT j=1; j<n; j++ )
3667 if ( *(*pData++) == *pEntry )
3669 bInsert = FALSE;
3670 break; // for
3673 if ( !bInsert )
3674 delete pEntry;
3675 else
3677 rCurrencyTable.Insert( pEntry, nCurrencyPos++ );
3678 if ( !nSecondarySystemCurrencyPosition &&
3679 (aConfiguredCurrencyAbbrev.Len() ?
3680 pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev :
3681 pEntry->GetLanguage() == eConfiguredCurrencyLanguage) )
3682 nSecondarySystemCurrencyPosition = nCurrencyPos-1;
3683 if ( !nMatchingSystemCurrencyPosition &&
3684 pEntry->GetLanguage() == eSysLang )
3685 nMatchingSystemCurrencyPosition = nCurrencyPos-1;
3691 if ( !nSystemCurrencyPosition )
3692 nSystemCurrencyPosition = nSecondarySystemCurrencyPosition;
3693 if ((aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3694 LocaleDataWrapper::areChecksEnabled())
3695 LocaleDataWrapper::outputCheckMessage(
3696 "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data.");
3697 // match SYSTEM if no configured currency found
3698 if ( !nSystemCurrencyPosition )
3699 nSystemCurrencyPosition = nMatchingSystemCurrencyPosition;
3700 if ((!aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) &&
3701 LocaleDataWrapper::areChecksEnabled())
3702 LocaleDataWrapper::outputCheckMessage(
3703 "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data.");
3704 delete pLocaleData;
3705 SvtSysLocaleOptions::SetCurrencyChangeLink(
3706 STATIC_LINK( NULL, SvNumberFormatter, CurrencyChangeLink ) );
3707 bInitializing = FALSE;
3708 bCurrencyTableInitialized = TRUE;
3712 USHORT SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr,
3713 const NfCurrencyEntry& rCurr, BOOL bBank ) const
3715 USHORT nDefault = 0;
3716 if ( bBank )
3717 { // nur Bankensymbole
3718 String aPositiveBank, aNegativeBank;
3719 rCurr.BuildPositiveFormatString( aPositiveBank, TRUE, *xLocaleData, 1 );
3720 rCurr.BuildNegativeFormatString( aNegativeBank, TRUE, *xLocaleData, 1 );
3722 WSStringPtr pFormat1 = new String( aPositiveBank );
3723 *pFormat1 += ';';
3724 WSStringPtr pFormat2 = new String( *pFormat1 );
3726 String aRed( '[' );
3727 aRed += pFormatScanner->GetRedString();
3728 aRed += ']';
3730 *pFormat2 += aRed;
3732 *pFormat1 += aNegativeBank;
3733 *pFormat2 += aNegativeBank;
3735 rStrArr.Insert( pFormat1, rStrArr.Count() );
3736 rStrArr.Insert( pFormat2, rStrArr.Count() );
3737 nDefault = rStrArr.Count() - 1;
3739 else
3740 { // gemischte Formate wie in SvNumberFormatter::ImpGenerateFormats
3741 // aber keine doppelten, wenn keine Nachkommastellen in Waehrung
3742 String aPositive, aNegative, aPositiveNoDec, aNegativeNoDec,
3743 aPositiveDashed, aNegativeDashed;
3744 WSStringPtr pFormat1, pFormat2, pFormat3, pFormat4, pFormat5;
3746 String aRed( '[' );
3747 aRed += pFormatScanner->GetRedString();
3748 aRed += ']';
3750 rCurr.BuildPositiveFormatString( aPositive, FALSE, *xLocaleData, 1 );
3751 rCurr.BuildNegativeFormatString( aNegative, FALSE, *xLocaleData, 1 );
3752 if ( rCurr.GetDigits() )
3754 rCurr.BuildPositiveFormatString( aPositiveNoDec, FALSE, *xLocaleData, 0 );
3755 rCurr.BuildNegativeFormatString( aNegativeNoDec, FALSE, *xLocaleData, 0 );
3756 rCurr.BuildPositiveFormatString( aPositiveDashed, FALSE, *xLocaleData, 2 );
3757 rCurr.BuildNegativeFormatString( aNegativeDashed, FALSE, *xLocaleData, 2 );
3759 pFormat1 = new String( aPositiveNoDec );
3760 *pFormat1 += ';';
3761 pFormat3 = new String( *pFormat1 );
3762 pFormat5 = new String( aPositiveDashed );
3763 *pFormat5 += ';';
3765 *pFormat1 += aNegativeNoDec;
3767 *pFormat3 += aRed;
3768 *pFormat5 += aRed;
3770 *pFormat3 += aNegativeNoDec;
3771 *pFormat5 += aNegativeDashed;
3773 else
3775 pFormat1 = NULL;
3776 pFormat3 = NULL;
3777 pFormat5 = NULL;
3780 pFormat2 = new String( aPositive );
3781 *pFormat2 += ';';
3782 pFormat4 = new String( *pFormat2 );
3784 *pFormat2 += aNegative;
3786 *pFormat4 += aRed;
3787 *pFormat4 += aNegative;
3789 if ( pFormat1 )
3790 rStrArr.Insert( pFormat1, rStrArr.Count() );
3791 rStrArr.Insert( pFormat2, rStrArr.Count() );
3792 if ( pFormat3 )
3793 rStrArr.Insert( pFormat3, rStrArr.Count() );
3794 rStrArr.Insert( pFormat4, rStrArr.Count() );
3795 nDefault = rStrArr.Count() - 1;
3796 if ( pFormat5 )
3797 rStrArr.Insert( pFormat5, rStrArr.Count() );
3799 return nDefault;
3803 //--- NfCurrencyEntry ----------------------------------------------------
3805 NfCurrencyEntry::NfCurrencyEntry()
3806 : eLanguage( LANGUAGE_DONTKNOW ),
3807 nPositiveFormat(3),
3808 nNegativeFormat(8),
3809 nDigits(2),
3810 cZeroChar('0')
3815 NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3817 aSymbol = rLocaleData.getCurrSymbol();
3818 aBankSymbol = rLocaleData.getCurrBankSymbol();
3819 eLanguage = eLang;
3820 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3821 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3822 nDigits = rLocaleData.getCurrDigits();
3823 cZeroChar = rLocaleData.getCurrZeroChar();
3827 NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency & rCurr,
3828 const LocaleDataWrapper& rLocaleData, LanguageType eLang )
3830 aSymbol = rCurr.Symbol;
3831 aBankSymbol = rCurr.BankSymbol;
3832 eLanguage = eLang;
3833 nPositiveFormat = rLocaleData.getCurrPositiveFormat();
3834 nNegativeFormat = rLocaleData.getCurrNegativeFormat();
3835 nDigits = rCurr.DecimalPlaces;
3836 cZeroChar = rLocaleData.getCurrZeroChar();
3840 BOOL NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const
3842 return aSymbol == r.aSymbol
3843 && aBankSymbol == r.aBankSymbol
3844 && eLanguage == r.eLanguage
3849 void NfCurrencyEntry::SetEuro()
3851 aSymbol = NfCurrencyEntry::GetEuroSymbol();
3852 aBankSymbol.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "EUR" ) );
3853 eLanguage = LANGUAGE_DONTKNOW;
3854 nPositiveFormat = 3;
3855 nNegativeFormat = 8;
3856 nDigits = 2;
3857 cZeroChar = '0';
3861 BOOL NfCurrencyEntry::IsEuro() const
3863 if ( aBankSymbol.EqualsAscii( "EUR" ) )
3864 return TRUE;
3865 String aEuro( NfCurrencyEntry::GetEuroSymbol() );
3866 return aSymbol == aEuro;
3870 void NfCurrencyEntry::ApplyVariableInformation( const NfCurrencyEntry& r )
3872 nPositiveFormat = r.nPositiveFormat;
3873 nNegativeFormat = r.nNegativeFormat;
3874 cZeroChar = r.cZeroChar;
3878 void NfCurrencyEntry::BuildSymbolString( String& rStr, BOOL bBank,
3879 BOOL bWithoutExtension ) const
3881 rStr = '[';
3882 rStr += '$';
3883 if ( bBank )
3884 rStr += aBankSymbol;
3885 else
3887 if ( aSymbol.Search( '-' ) != STRING_NOTFOUND || aSymbol.Search( ']' ) != STRING_NOTFOUND )
3889 rStr += '"';
3890 rStr += aSymbol;
3891 rStr += '"';
3893 else
3894 rStr += aSymbol;
3895 if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM )
3897 rStr += '-';
3898 rStr += String::CreateFromInt32( sal_Int32( eLanguage ), 16 ).ToUpperAscii();
3901 rStr += ']';
3905 void NfCurrencyEntry::Impl_BuildFormatStringNumChars( String& rStr,
3906 const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const
3908 rStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###0" ) );
3909 rStr.Insert( rLoc.getNumThousandSep(), 1 );
3910 if ( nDecimalFormat && nDigits )
3912 rStr += rLoc.getNumDecimalSep();
3913 rStr.Expand( rStr.Len() + nDigits, (nDecimalFormat == 2 ? '-' : cZeroChar) );
3918 void NfCurrencyEntry::BuildPositiveFormatString( String& rStr, BOOL bBank,
3919 const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const
3921 Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat );
3922 USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat(
3923 rLoc.getCurrPositiveFormat(), nPositiveFormat, bBank );
3924 CompletePositiveFormatString( rStr, bBank, nPosiForm );
3928 void NfCurrencyEntry::BuildNegativeFormatString( String& rStr, BOOL bBank,
3929 const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const
3931 Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat );
3932 USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat(
3933 rLoc.getCurrNegativeFormat(), nNegativeFormat, bBank );
3934 CompleteNegativeFormatString( rStr, bBank, nNegaForm );
3938 void NfCurrencyEntry::CompletePositiveFormatString( String& rStr, BOOL bBank,
3939 USHORT nPosiForm ) const
3941 String aSymStr;
3942 BuildSymbolString( aSymStr, bBank );
3943 NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm );
3947 void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr, BOOL bBank,
3948 USHORT nNegaForm ) const
3950 String aSymStr;
3951 BuildSymbolString( aSymStr, bBank );
3952 NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm );
3956 // static
3957 void NfCurrencyEntry::CompletePositiveFormatString( String& rStr,
3958 const String& rSymStr, USHORT nPositiveFormat )
3960 switch( nPositiveFormat )
3962 case 0: // $1
3963 rStr.Insert( rSymStr , 0 );
3964 break;
3965 case 1: // 1$
3966 rStr += rSymStr;
3967 break;
3968 case 2: // $ 1
3970 rStr.Insert( ' ', 0 );
3971 rStr.Insert( rSymStr, 0 );
3973 break;
3974 case 3: // 1 $
3976 rStr += ' ';
3977 rStr += rSymStr;
3979 break;
3980 default:
3981 DBG_ERROR("NfCurrencyEntry::CompletePositiveFormatString: unknown option");
3982 break;
3987 // static
3988 void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr,
3989 const String& rSymStr, USHORT nNegativeFormat )
3991 switch( nNegativeFormat )
3993 case 0: // ($1)
3995 rStr.Insert( rSymStr, 0);
3996 rStr.Insert('(',0);
3997 rStr += ')';
3999 break;
4000 case 1: // -$1
4002 rStr.Insert( rSymStr, 0);
4003 rStr.Insert('-',0);
4005 break;
4006 case 2: // $-1
4008 rStr.Insert('-',0);
4009 rStr.Insert( rSymStr, 0);
4011 break;
4012 case 3: // $1-
4014 rStr.Insert( rSymStr, 0);
4015 rStr += '-';
4017 break;
4018 case 4: // (1$)
4020 rStr.Insert('(',0);
4021 rStr += rSymStr;
4022 rStr += ')';
4024 break;
4025 case 5: // -1$
4027 rStr += rSymStr;
4028 rStr.Insert('-',0);
4030 break;
4031 case 6: // 1-$
4033 rStr += '-';
4034 rStr += rSymStr;
4036 break;
4037 case 7: // 1$-
4039 rStr += rSymStr;
4040 rStr += '-';
4042 break;
4043 case 8: // -1 $
4045 rStr += ' ';
4046 rStr += rSymStr;
4047 rStr.Insert('-',0);
4049 break;
4050 case 9: // -$ 1
4052 rStr.Insert(' ',0);
4053 rStr.Insert( rSymStr, 0);
4054 rStr.Insert('-',0);
4056 break;
4057 case 10: // 1 $-
4059 rStr += ' ';
4060 rStr += rSymStr;
4061 rStr += '-';
4063 break;
4064 case 11: // $ -1
4066 String aTmp( rSymStr );
4067 aTmp += ' ';
4068 aTmp += '-';
4069 rStr.Insert( aTmp, 0 );
4071 break;
4072 case 12 : // $ 1-
4074 rStr.Insert(' ', 0);
4075 rStr.Insert( rSymStr, 0);
4076 rStr += '-';
4078 break;
4079 case 13 : // 1- $
4081 rStr += '-';
4082 rStr += ' ';
4083 rStr += rSymStr;
4085 break;
4086 case 14 : // ($ 1)
4088 rStr.Insert(' ',0);
4089 rStr.Insert( rSymStr, 0);
4090 rStr.Insert('(',0);
4091 rStr += ')';
4093 break;
4094 case 15 : // (1 $)
4096 rStr.Insert('(',0);
4097 rStr += ' ';
4098 rStr += rSymStr;
4099 rStr += ')';
4101 break;
4102 default:
4103 DBG_ERROR("NfCurrencyEntry::CompleteNegativeFormatString: unknown option");
4104 break;
4109 // static
4110 USHORT NfCurrencyEntry::GetEffectivePositiveFormat( USHORT
4111 #if ! NF_BANKSYMBOL_FIX_POSITION
4112 nIntlFormat
4113 #endif
4114 , USHORT nCurrFormat, BOOL bBank )
4116 if ( bBank )
4118 #if NF_BANKSYMBOL_FIX_POSITION
4119 return 3;
4120 #else
4121 switch ( nIntlFormat )
4123 case 0: // $1
4124 nIntlFormat = 2; // $ 1
4125 break;
4126 case 1: // 1$
4127 nIntlFormat = 3; // 1 $
4128 break;
4129 case 2: // $ 1
4130 break;
4131 case 3: // 1 $
4132 break;
4133 default:
4134 DBG_ERROR("NfCurrencyEntry::GetEffectivePositiveFormat: unknown option");
4135 break;
4137 return nIntlFormat;
4138 #endif
4140 else
4141 return nCurrFormat;
4145 // nur aufrufen, wenn nCurrFormat wirklich mit Klammern ist
4146 USHORT lcl_MergeNegativeParenthesisFormat( USHORT nIntlFormat, USHORT nCurrFormat )
4148 short nSign = 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts
4149 switch ( nIntlFormat )
4151 case 0: // ($1)
4152 case 4: // (1$)
4153 case 14 : // ($ 1)
4154 case 15 : // (1 $)
4155 return nCurrFormat;
4156 case 1: // -$1
4157 case 5: // -1$
4158 case 8: // -1 $
4159 case 9: // -$ 1
4160 nSign = 0;
4161 break;
4162 case 2: // $-1
4163 case 6: // 1-$
4164 case 11 : // $ -1
4165 case 13 : // 1- $
4166 nSign = 1;
4167 break;
4168 case 3: // $1-
4169 case 7: // 1$-
4170 case 10: // 1 $-
4171 case 12 : // $ 1-
4172 nSign = 2;
4173 break;
4174 default:
4175 DBG_ERROR("lcl_MergeNegativeParenthesisFormat: unknown option");
4176 break;
4179 switch ( nCurrFormat )
4181 case 0: // ($1)
4182 switch ( nSign )
4184 case 0:
4185 return 1; // -$1
4186 case 1:
4187 return 2; // $-1
4188 case 2:
4189 return 3; // $1-
4191 break;
4192 case 4: // (1$)
4193 switch ( nSign )
4195 case 0:
4196 return 5; // -1$
4197 case 1:
4198 return 6; // 1-$
4199 case 2:
4200 return 7; // 1$-
4202 break;
4203 case 14 : // ($ 1)
4204 switch ( nSign )
4206 case 0:
4207 return 9; // -$ 1
4208 case 1:
4209 return 11; // $ -1
4210 case 2:
4211 return 12; // $ 1-
4213 break;
4214 case 15 : // (1 $)
4215 switch ( nSign )
4217 case 0:
4218 return 8; // -1 $
4219 case 1:
4220 return 13; // 1- $
4221 case 2:
4222 return 10; // 1 $-
4224 break;
4226 return nCurrFormat;
4230 // static
4231 USHORT NfCurrencyEntry::GetEffectiveNegativeFormat( USHORT nIntlFormat,
4232 USHORT nCurrFormat, BOOL bBank )
4234 if ( bBank )
4236 #if NF_BANKSYMBOL_FIX_POSITION
4237 return 8;
4238 #else
4239 switch ( nIntlFormat )
4241 case 0: // ($1)
4242 // nIntlFormat = 14; // ($ 1)
4243 nIntlFormat = 9; // -$ 1
4244 break;
4245 case 1: // -$1
4246 nIntlFormat = 9; // -$ 1
4247 break;
4248 case 2: // $-1
4249 nIntlFormat = 11; // $ -1
4250 break;
4251 case 3: // $1-
4252 nIntlFormat = 12; // $ 1-
4253 break;
4254 case 4: // (1$)
4255 // nIntlFormat = 15; // (1 $)
4256 nIntlFormat = 8; // -1 $
4257 break;
4258 case 5: // -1$
4259 nIntlFormat = 8; // -1 $
4260 break;
4261 case 6: // 1-$
4262 nIntlFormat = 13; // 1- $
4263 break;
4264 case 7: // 1$-
4265 nIntlFormat = 10; // 1 $-
4266 break;
4267 case 8: // -1 $
4268 break;
4269 case 9: // -$ 1
4270 break;
4271 case 10: // 1 $-
4272 break;
4273 case 11: // $ -1
4274 break;
4275 case 12 : // $ 1-
4276 break;
4277 case 13 : // 1- $
4278 break;
4279 case 14 : // ($ 1)
4280 // nIntlFormat = 14; // ($ 1)
4281 nIntlFormat = 9; // -$ 1
4282 break;
4283 case 15 : // (1 $)
4284 // nIntlFormat = 15; // (1 $)
4285 nIntlFormat = 8; // -1 $
4286 break;
4287 default:
4288 DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4289 break;
4291 #endif
4293 else if ( nIntlFormat != nCurrFormat )
4295 switch ( nCurrFormat )
4297 case 0: // ($1)
4298 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4299 nIntlFormat, nCurrFormat );
4300 break;
4301 case 1: // -$1
4302 nIntlFormat = nCurrFormat;
4303 break;
4304 case 2: // $-1
4305 nIntlFormat = nCurrFormat;
4306 break;
4307 case 3: // $1-
4308 nIntlFormat = nCurrFormat;
4309 break;
4310 case 4: // (1$)
4311 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4312 nIntlFormat, nCurrFormat );
4313 break;
4314 case 5: // -1$
4315 nIntlFormat = nCurrFormat;
4316 break;
4317 case 6: // 1-$
4318 nIntlFormat = nCurrFormat;
4319 break;
4320 case 7: // 1$-
4321 nIntlFormat = nCurrFormat;
4322 break;
4323 case 8: // -1 $
4324 nIntlFormat = nCurrFormat;
4325 break;
4326 case 9: // -$ 1
4327 nIntlFormat = nCurrFormat;
4328 break;
4329 case 10: // 1 $-
4330 nIntlFormat = nCurrFormat;
4331 break;
4332 case 11: // $ -1
4333 nIntlFormat = nCurrFormat;
4334 break;
4335 case 12 : // $ 1-
4336 nIntlFormat = nCurrFormat;
4337 break;
4338 case 13 : // 1- $
4339 nIntlFormat = nCurrFormat;
4340 break;
4341 case 14 : // ($ 1)
4342 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4343 nIntlFormat, nCurrFormat );
4344 break;
4345 case 15 : // (1 $)
4346 nIntlFormat = lcl_MergeNegativeParenthesisFormat(
4347 nIntlFormat, nCurrFormat );
4348 break;
4349 default:
4350 DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option");
4351 break;
4354 return nIntlFormat;
4358 // we only support default encodings here
4359 // static
4360 sal_Char NfCurrencyEntry::GetEuroSymbol( rtl_TextEncoding eTextEncoding )
4362 switch ( eTextEncoding )
4364 case RTL_TEXTENCODING_MS_1252 : // WNT Ansi
4365 case RTL_TEXTENCODING_ISO_8859_1 : // UNX for use with TrueType fonts
4366 return '\x80';
4367 case RTL_TEXTENCODING_ISO_8859_15 : // UNX real
4368 return '\xA4';
4369 case RTL_TEXTENCODING_IBM_850 : // OS2
4370 return '\xD5';
4371 case RTL_TEXTENCODING_APPLE_ROMAN : // MAC
4372 return '\xDB';
4373 default: // default system
4374 #if WNT
4375 return '\x80';
4376 #elif OS2
4377 return '\xD5';
4378 #elif UNX
4379 // return '\xA4'; // #56121# 0xA4 waere korrekt fuer iso-8859-15
4380 return '\x80'; // aber Windoze-Code fuer die konvertierten TrueType-Fonts
4381 #else
4382 #error EuroSymbol is what?
4383 return '\x80';
4384 #endif
4386 return '\x80';