diff options
Diffstat (limited to 'svl/source/numbers/zforlist.cxx')
-rw-r--r-- | svl/source/numbers/zforlist.cxx | 4348 |
1 files changed, 4348 insertions, 0 deletions
diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx new file mode 100644 index 000000000000..f03ef3f31140 --- /dev/null +++ b/svl/source/numbers/zforlist.cxx @@ -0,0 +1,4348 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: zforlist.cxx,v $ + * $Revision: 1.72.60.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svl.hxx" +#ifndef GCC +#endif + +// #include <math.h> +#include <tools/debug.hxx> +#include <unotools/charclass.hxx> +#include <i18npool/mslangid.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/numberformatcodewrapper.hxx> +#include <unotools/calendarwrapper.hxx> +#include <com/sun/star/i18n/KNumberFormatUsage.hpp> +#include <com/sun/star/i18n/KNumberFormatType.hpp> +#include <comphelper/processfactory.hxx> +#include <unotools/misccfg.hxx> + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> + +#define _ZFORLIST_CXX +#include <osl/mutex.hxx> +#include <svl/zforlist.hxx> +#undef _ZFORLIST_CXX + +#include "zforscan.hxx" +#include "zforfind.hxx" +#include <svl/zformat.hxx> +#include "numhead.hxx" + +#include <unotools/syslocaleoptions.hxx> +#include <unotools/digitgroupingiterator.hxx> +#include <rtl/logfile.hxx> +#include <rtl/instance.hxx> + +#include <math.h> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::lang; + + +// Constants for type offsets per Country/Language (CL) +#define ZF_STANDARD 0 +#define ZF_STANDARD_PERCENT 10 +#define ZF_STANDARD_CURRENCY 20 +#define ZF_STANDARD_DATE 30 +#define ZF_STANDARD_TIME 40 +#define ZF_STANDARD_DATETIME 50 +#define ZF_STANDARD_SCIENTIFIC 60 +#define ZF_STANDARD_FRACTION 70 +#define ZF_STANDARD_NEWEXTENDED 75 +#define ZF_STANDARD_NEWEXTENDEDMAX SV_MAX_ANZ_STANDARD_FORMATE-2 // 98 +#define ZF_STANDARD_LOGICAL SV_MAX_ANZ_STANDARD_FORMATE-1 // 99 +#define ZF_STANDARD_TEXT SV_MAX_ANZ_STANDARD_FORMATE // 100 + +/* Locale that is set if an unknown locale (from another system) is loaded of + * legacy documents. Can not be SYSTEM because else, for example, a German "DM" + * (old currency) is recognized as a date (#53155#). */ +#define UNKNOWN_SUBSTITUTE LANGUAGE_ENGLISH_US + +static BOOL bIndexTableInitialized = FALSE; +static sal_uInt32 __FAR_DATA theIndexTable[NF_INDEX_TABLE_ENTRIES]; + + +// ==================================================================== + +/** + instead of every number formatter being a listener we have a registry which + also handles one instance of the SysLocale options + */ + +class SvNumberFormatterRegistry_Impl : public utl::ConfigurationListener +{ + List aFormatters; + SvtSysLocaleOptions aSysLocaleOptions; + LanguageType eSysLanguage; + +public: + SvNumberFormatterRegistry_Impl(); + virtual ~SvNumberFormatterRegistry_Impl(); + + void Insert( SvNumberFormatter* pThis ) + { aFormatters.Insert( pThis, LIST_APPEND ); } + SvNumberFormatter* Remove( SvNumberFormatter* pThis ) + { return (SvNumberFormatter*)aFormatters.Remove( pThis ); } + sal_uInt32 Count() + { return aFormatters.Count(); } + + virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 ); +}; + + +SvNumberFormatterRegistry_Impl::SvNumberFormatterRegistry_Impl() +{ + eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM ); + aSysLocaleOptions.AddListener( this ); +} + + +SvNumberFormatterRegistry_Impl::~SvNumberFormatterRegistry_Impl() +{ + aSysLocaleOptions.RemoveListener( this ); +} + + +void SvNumberFormatterRegistry_Impl::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 nHint ) +{ + if ( nHint & SYSLOCALEOPTIONS_HINT_LOCALE ) + { + ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() ); + for ( SvNumberFormatter* p = (SvNumberFormatter*)aFormatters.First(); + p; p = (SvNumberFormatter*)aFormatters.Next() ) + { + p->ReplaceSystemCL( eSysLanguage ); + } + eSysLanguage = MsLangId::getRealLanguage( LANGUAGE_SYSTEM ); + } + if ( nHint & SYSLOCALEOPTIONS_HINT_CURRENCY ) + { + ::osl::MutexGuard aGuard( SvNumberFormatter::GetMutex() ); + for ( SvNumberFormatter* p = (SvNumberFormatter*)aFormatters.First(); + p; p = (SvNumberFormatter*)aFormatters.Next() ) + { + p->ResetDefaultSystemCurrency(); + } + } +} + + +// ==================================================================== + +SvNumberFormatterRegistry_Impl* SvNumberFormatter::pFormatterRegistry = NULL; +BOOL SvNumberFormatter::bCurrencyTableInitialized = FALSE; +namespace +{ + struct theCurrencyTable : + public rtl::Static< NfCurrencyTable, theCurrencyTable > {}; + + struct theLegacyOnlyCurrencyTable : + public rtl::Static< NfCurrencyTable, theLegacyOnlyCurrencyTable > {}; +} +USHORT SvNumberFormatter::nSystemCurrencyPosition = 0; +SV_IMPL_PTRARR( NfCurrencyTable, NfCurrencyEntry* ); +SV_IMPL_PTRARR( NfWSStringsDtor, String* ); + +// ob das BankSymbol immer am Ende ist (1 $;-1 $) oder sprachabhaengig +#define NF_BANKSYMBOL_FIX_POSITION 1 + + +/***********************Funktionen SvNumberFormatter**************************/ + +SvNumberFormatter::SvNumberFormatter( + const Reference< XMultiServiceFactory >& xSMgr, + LanguageType eLang ) + : + xServiceManager( xSMgr ) +{ + ImpConstruct( eLang ); +} + + +SvNumberFormatter::SvNumberFormatter( LanguageType eLang ) +{ + ImpConstruct( eLang ); +} + + +SvNumberFormatter::~SvNumberFormatter() +{ + { + ::osl::MutexGuard aGuard( GetMutex() ); + pFormatterRegistry->Remove( this ); + if ( !pFormatterRegistry->Count() ) + { + delete pFormatterRegistry; + pFormatterRegistry = NULL; + } + } + + SvNumberformat* pEntry = aFTable.First(); + while (pEntry) + { + delete pEntry; + pEntry = aFTable.Next(); + } + delete pFormatTable; + delete pCharClass; + delete pStringScanner; + delete pFormatScanner; + ClearMergeTable(); + delete pMergeTable; +} + + +void SvNumberFormatter::ImpConstruct( LanguageType eLang ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svl", "er93726", "SvNumberFormatter::ImpConstruct" ); + + if ( eLang == LANGUAGE_DONTKNOW ) + eLang = UNKNOWN_SUBSTITUTE; + IniLnge = eLang; + ActLnge = eLang; + eEvalDateFormat = NF_EVALDATEFORMAT_INTL; + nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND; + + aLocale = MsLangId::convertLanguageToLocale( eLang ); + pCharClass = new CharClass( xServiceManager, aLocale ); + xLocaleData.init( xServiceManager, aLocale, eLang ); + xCalendar.init( xServiceManager, aLocale ); + xTransliteration.init( xServiceManager, eLang, + ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE ); + xNatNum.init( xServiceManager ); + + // cached locale data items + const LocaleDataWrapper* pLoc = GetLocaleData(); + aDecimalSep = pLoc->getNumDecimalSep(); + aThousandSep = pLoc->getNumThousandSep(); + aDateSep = pLoc->getDateSep(); + + pStringScanner = new ImpSvNumberInputScan( this ); + pFormatScanner = new ImpSvNumberformatScan( this ); + pFormatTable = NULL; + MaxCLOffset = 0; + ImpGenerateFormats( 0, FALSE ); // 0 .. 999 for initialized language formats + pMergeTable = NULL; + bNoZero = FALSE; + + ::osl::MutexGuard aGuard( GetMutex() ); + GetFormatterRegistry().Insert( this ); +} + + +void SvNumberFormatter::ChangeIntl(LanguageType eLnge) +{ + if (ActLnge != eLnge) + { + ActLnge = eLnge; + + aLocale = MsLangId::convertLanguageToLocale( eLnge ); + pCharClass->setLocale( aLocale ); + xLocaleData.changeLocale( aLocale, eLnge ); + xCalendar.changeLocale( aLocale ); + xTransliteration.changeLocale( eLnge ); + + // cached locale data items, initialize BEFORE calling ChangeIntl below + const LocaleDataWrapper* pLoc = GetLocaleData(); + aDecimalSep = pLoc->getNumDecimalSep(); + aThousandSep = pLoc->getNumThousandSep(); + aDateSep = pLoc->getDateSep(); + + pFormatScanner->ChangeIntl(); + pStringScanner->ChangeIntl(); + } +} + + +// static +::osl::Mutex& SvNumberFormatter::GetMutex() +{ + static ::osl::Mutex* pMutex = NULL; + if( !pMutex ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if( !pMutex ) + { + // #i77768# Due to a static reference in the toolkit lib + // we need a mutex that lives longer than the svl library. + // Otherwise the dtor would use a destructed mutex!! + pMutex = new ::osl::Mutex; + } + } + return *pMutex; +} + + +// static +SvNumberFormatterRegistry_Impl& SvNumberFormatter::GetFormatterRegistry() +{ + ::osl::MutexGuard aGuard( GetMutex() ); + if ( !pFormatterRegistry ) + pFormatterRegistry = new SvNumberFormatterRegistry_Impl; + return *pFormatterRegistry; +} + + +Color* SvNumberFormatter::GetUserDefColor(USHORT nIndex) +{ + if( aColorLink.IsSet() ) + return (Color*) ( aColorLink.Call( (void*) &nIndex )); + else + return NULL; +} + +void SvNumberFormatter::ChangeNullDate(USHORT nDay, + USHORT nMonth, + USHORT nYear) +{ + pFormatScanner->ChangeNullDate(nDay, nMonth, nYear); + pStringScanner->ChangeNullDate(nDay, nMonth, nYear); +} + +Date* SvNumberFormatter::GetNullDate() +{ + return pFormatScanner->GetNullDate(); +} + +void SvNumberFormatter::ChangeStandardPrec(short nPrec) +{ + pFormatScanner->ChangeStandardPrec(nPrec); +} + +short SvNumberFormatter::GetStandardPrec() +{ + return pFormatScanner->GetStandardPrec(); +} + +void SvNumberFormatter::ImpChangeSysCL( LanguageType eLnge, BOOL bLoadingSO5 ) +{ + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = UNKNOWN_SUBSTITUTE; + if (eLnge != IniLnge) + { + IniLnge = eLnge; + ChangeIntl(eLnge); + SvNumberformat* pEntry = aFTable.First(); + while (pEntry) // delete old formats + { + pEntry = (SvNumberformat*) aFTable.Remove(aFTable.GetCurKey()); + delete pEntry; + pEntry = (SvNumberformat*) aFTable.First(); + } + ImpGenerateFormats( 0, bLoadingSO5 ); // new standard formats + } + else if ( bLoadingSO5 ) + { // delete additional standard formats + sal_uInt32 nKey; + aFTable.Seek( SV_MAX_ANZ_STANDARD_FORMATE + 1 ); + while ( (nKey = aFTable.GetCurKey()) > SV_MAX_ANZ_STANDARD_FORMATE && + nKey < SV_COUNTRY_LANGUAGE_OFFSET ) + { + SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey ); + delete pEntry; + } + } +} + + +void SvNumberFormatter::ReplaceSystemCL( LanguageType eOldLanguage ) +{ + sal_uInt32 nCLOffset = ImpGetCLOffset( LANGUAGE_SYSTEM ); + if ( nCLOffset > MaxCLOffset ) + return ; // no SYSTEM entries to replace + + const sal_uInt32 nMaxBuiltin = nCLOffset + SV_MAX_ANZ_STANDARD_FORMATE; + const sal_uInt32 nNextCL = nCLOffset + SV_COUNTRY_LANGUAGE_OFFSET; + sal_uInt32 nKey; + + // remove old builtin formats + aFTable.Seek( nCLOffset ); + while ( (nKey = aFTable.GetCurKey()) >= nCLOffset && nKey <= nMaxBuiltin && aFTable.Count() ) + { + SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey ); + delete pEntry; + } + + // move additional and user defined to temporary table + Table aOldTable; + while ( (nKey = aFTable.GetCurKey()) >= nCLOffset && nKey < nNextCL && aFTable.Count() ) + { + SvNumberformat* pEntry = (SvNumberformat*) aFTable.Remove( nKey ); + aOldTable.Insert( nKey, pEntry ); + } + + // generate new old builtin formats + // reset ActLnge otherwise ChangeIntl() wouldn't switch if already LANGUAGE_SYSTEM + ActLnge = LANGUAGE_DONTKNOW; + ChangeIntl( LANGUAGE_SYSTEM ); + ImpGenerateFormats( nCLOffset, TRUE ); + + // convert additional and user defined from old system to new system + SvNumberformat* pStdFormat = (SvNumberformat*) aFTable.Get( nCLOffset + ZF_STANDARD ); + sal_uInt32 nLastKey = nMaxBuiltin; + pFormatScanner->SetConvertMode( eOldLanguage, LANGUAGE_SYSTEM, TRUE ); + aOldTable.First(); + while ( aOldTable.Count() ) + { + nKey = aOldTable.GetCurKey(); + if ( nLastKey < nKey ) + nLastKey = nKey; + SvNumberformat* pOldEntry = (SvNumberformat*) aOldTable.Remove( nKey ); + String aString( pOldEntry->GetFormatstring() ); + xub_StrLen nCheckPos = STRING_NOTFOUND; + + // Same as PutEntry() but assures key position even if format code is + // a duplicate. Also won't mix up any LastInsertKey. + ChangeIntl( eOldLanguage ); + LanguageType eLge = eOldLanguage; // ConvertMode changes this + BOOL bCheck = FALSE; + SvNumberformat* pNewEntry = new SvNumberformat( aString, pFormatScanner, + pStringScanner, nCheckPos, eLge ); + if ( nCheckPos != 0 ) + delete pNewEntry; + else + { + short eCheckType = pNewEntry->GetType(); + if ( eCheckType != NUMBERFORMAT_UNDEFINED ) + pNewEntry->SetType( eCheckType | NUMBERFORMAT_DEFINED ); + else + pNewEntry->SetType( NUMBERFORMAT_DEFINED ); + + if ( !aFTable.Insert( nKey, pNewEntry ) ) + delete pNewEntry; + else + bCheck = TRUE; + } + DBG_ASSERT( bCheck, "SvNumberFormatter::ReplaceSystemCL: couldn't convert" ); + + delete pOldEntry; + } + pFormatScanner->SetConvertMode(FALSE); + pStdFormat->SetLastInsertKey( USHORT(nLastKey - nCLOffset) ); + + // append new system additional formats + NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() ); + ImpGenerateAdditionalFormats( nCLOffset, aNumberFormatCode, TRUE ); +} + + +BOOL SvNumberFormatter::IsTextFormat(sal_uInt32 F_Index) const +{ + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index); + if (!pFormat) + return FALSE; + else + return pFormat->IsTextFormat(); +} + +BOOL SvNumberFormatter::HasTextFormat(sal_uInt32 F_Index) const +{ + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index); + if (!pFormat) + return FALSE; + else + return pFormat->HasTextFormat(); +} + +BOOL SvNumberFormatter::PutEntry(String& rString, + xub_StrLen& nCheckPos, + short& nType, + sal_uInt32& nKey, // Formatnummer + LanguageType eLnge) +{ + nKey = 0; + if (rString.Len() == 0) // keinen Leerstring + { + nCheckPos = 1; // -> Fehler + return FALSE; + } + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + + ChangeIntl(eLnge); // ggfs. austauschen + LanguageType eLge = eLnge; // Umgehung const fuer ConvertMode + BOOL bCheck = FALSE; + SvNumberformat* p_Entry = new SvNumberformat(rString, + pFormatScanner, + pStringScanner, + nCheckPos, + eLge); + if (nCheckPos == 0) // Format ok + { // Typvergleich: + short eCheckType = p_Entry->GetType(); + if ( eCheckType != NUMBERFORMAT_UNDEFINED) + { + p_Entry->SetType(eCheckType | NUMBERFORMAT_DEFINED); + nType = eCheckType; + } + else + { + p_Entry->SetType(NUMBERFORMAT_DEFINED); + nType = NUMBERFORMAT_DEFINED; + } + sal_uInt32 CLOffset = ImpGenerateCL(eLge); // ggfs. neu Standard- + // formate anlegen + nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLge); + if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden + delete p_Entry; + else + { + SvNumberformat* pStdFormat = + (SvNumberformat*) aFTable.Get(CLOffset + ZF_STANDARD); + sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey(); + if (nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET) + { + DBG_ERROR("SvNumberFormatter:: Zu viele Formate pro CL"); + delete p_Entry; + } + else if (!aFTable.Insert(nPos+1,p_Entry)) + delete p_Entry; + else + { + bCheck = TRUE; + nKey = nPos+1; + pStdFormat->SetLastInsertKey((USHORT) (nKey-CLOffset)); + } + } + } + else + delete p_Entry; + return bCheck; +} + +BOOL SvNumberFormatter::PutandConvertEntry(String& rString, + xub_StrLen& nCheckPos, + short& nType, + sal_uInt32& nKey, + LanguageType eLnge, + LanguageType eNewLnge) +{ + BOOL bRes; + if (eNewLnge == LANGUAGE_DONTKNOW) + eNewLnge = IniLnge; + + pFormatScanner->SetConvertMode(eLnge, eNewLnge); + bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge); + pFormatScanner->SetConvertMode(FALSE); + return bRes; +} + + +BOOL SvNumberFormatter::PutandConvertEntrySystem(String& rString, + xub_StrLen& nCheckPos, + short& nType, + sal_uInt32& nKey, + LanguageType eLnge, + LanguageType eNewLnge) +{ + BOOL bRes; + if (eNewLnge == LANGUAGE_DONTKNOW) + eNewLnge = IniLnge; + + pFormatScanner->SetConvertMode(eLnge, eNewLnge, TRUE); + bRes = PutEntry(rString, nCheckPos, nType, nKey, eLnge); + pFormatScanner->SetConvertMode(FALSE); + return bRes; +} + + +sal_uInt32 SvNumberFormatter::GetIndexPuttingAndConverting( String & rString, + LanguageType eLnge, LanguageType eSysLnge, short & rType, + BOOL & rNewInserted, xub_StrLen & rCheckPos ) +{ + sal_uInt32 nKey = NUMBERFORMAT_ENTRY_NOT_FOUND; + rNewInserted = FALSE; + rCheckPos = 0; + + // #62389# empty format string (of Writer) => General standard format + if (!rString.Len()) + ; // nothing + else if (eLnge == LANGUAGE_SYSTEM && eSysLnge != SvtSysLocale().GetLanguage()) + { + sal_uInt32 nOrig = GetEntryKey( rString, eSysLnge ); + if (nOrig == NUMBERFORMAT_ENTRY_NOT_FOUND) + nKey = nOrig; // none avaliable, maybe user-defined + else + nKey = GetFormatForLanguageIfBuiltIn( nOrig, SvtSysLocale().GetLanguage() ); + + if (nKey == nOrig) + { + // Not a builtin format, convert. + // The format code string may get modified and adapted to the real + // language and wouldn't match eSysLnge anymore, do that on a copy. + String aTmp( rString); + rNewInserted = PutandConvertEntrySystem( aTmp, rCheckPos, rType, + nKey, eLnge, SvtSysLocale().GetLanguage()); + if (rCheckPos > 0) + { + DBG_ERRORFILE("SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for current locale"); + nKey = NUMBERFORMAT_ENTRY_NOT_FOUND; + } + } + } + else + { + nKey = GetEntryKey( rString, eLnge); + if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND) + { + rNewInserted = PutEntry( rString, rCheckPos, rType, nKey, eLnge); + if (rCheckPos > 0) + { + DBG_ERRORFILE("SvNumberFormatter::GetIndexPuttingAndConverting: bad format code string for specified locale"); + nKey = NUMBERFORMAT_ENTRY_NOT_FOUND; + } + } + } + if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND) + nKey = GetStandardIndex( eLnge); + rType = GetType( nKey); + // Convert any (!) old "automatic" currency format to new fixed currency + // default format. + if ((rType & NUMBERFORMAT_CURRENCY) != 0) + { + const SvNumberformat* pFormat = GetEntry( nKey); + if (!pFormat->HasNewCurrency()) + { + if (rNewInserted) + { + DeleteEntry( nKey); // don't leave trails of rubbish + rNewInserted = FALSE; + } + nKey = GetStandardFormat( NUMBERFORMAT_CURRENCY, eLnge); + } + } + return nKey; +} + + +void SvNumberFormatter::DeleteEntry(sal_uInt32 nKey) +{ + SvNumberformat* pEntry = aFTable.Remove(nKey); + delete pEntry; +} + +void SvNumberFormatter::PrepareSave() +{ + SvNumberformat* pFormat = aFTable.First(); + while (pFormat) + { + pFormat->SetUsed(FALSE); + pFormat = aFTable.Next(); + } +} + +void SvNumberFormatter::SetFormatUsed(sal_uInt32 nFIndex) +{ + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex); + if (pFormat) + pFormat->SetUsed(TRUE); +} + +BOOL SvNumberFormatter::Load( SvStream& rStream ) +{ + LanguageType eSysLang = SvtSysLocale().GetLanguage(); + SvNumberFormatter* pConverter = NULL; + + ImpSvNumMultipleReadHeader aHdr( rStream ); + USHORT nVersion; + rStream >> nVersion; + SvNumberformat* pEntry; + sal_uInt32 nPos; + LanguageType eSaveSysLang, eLoadSysLang; + USHORT nSysOnStore, eLge, eDummy; // Dummy fuer kompatibles Format + rStream >> nSysOnStore >> eLge; // Systemeinstellung aus + // Dokument + eSaveSysLang = (nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE ? + LANGUAGE_SYSTEM : (LanguageType) nSysOnStore); + LanguageType eLnge = (LanguageType) eLge; + ImpChangeSysCL( eLnge, TRUE ); + + rStream >> nPos; + while (nPos != NUMBERFORMAT_ENTRY_NOT_FOUND) + { + rStream >> eDummy >> eLge; + eLnge = (LanguageType) eLge; + ImpGenerateCL( eLnge, TRUE ); // ggfs. neue Standardformate anlegen + + sal_uInt32 nOffset = nPos % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex + BOOL bUserDefined = (nOffset > SV_MAX_ANZ_STANDARD_FORMATE); + //! HACK! ER 29.07.97 15:15 + // SaveLang wurde bei SYSTEM nicht gespeichert sondern war auch SYSTEM, + // erst ab 364i Unterscheidung moeglich + BOOL bConversionHack; + if ( eLnge == LANGUAGE_SYSTEM ) + { + if ( nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE ) + { + bConversionHack = bUserDefined; + eLoadSysLang = eSaveSysLang; + } + else + { + bConversionHack = FALSE; + eLoadSysLang = eSysLang; + } + } + else + { + bConversionHack = FALSE; + eLoadSysLang = eSaveSysLang; + } + + pEntry = new SvNumberformat(*pFormatScanner, eLnge); + if ( bConversionHack ) + { // SYSTEM + // nVersion < SV_NUMBERFORMATTER_VERSION_SYSTORE + // nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS + if ( !pConverter ) + pConverter = new SvNumberFormatter( xServiceManager, eSysLang ); + NfHackConversion eHackConversion = pEntry->Load( + rStream, aHdr, pConverter, *pStringScanner ); + switch ( eHackConversion ) + { + case NF_CONVERT_GERMAN_ENGLISH : + pEntry->ConvertLanguage( *pConverter, + LANGUAGE_ENGLISH_US, eSysLang, TRUE ); + break; + case NF_CONVERT_ENGLISH_GERMAN : + switch ( eSysLang ) + { + case LANGUAGE_GERMAN: + case LANGUAGE_GERMAN_SWISS: + case LANGUAGE_GERMAN_AUSTRIAN: + case LANGUAGE_GERMAN_LUXEMBOURG: + case LANGUAGE_GERMAN_LIECHTENSTEIN: + // alles beim alten + break; + default: + pEntry->ConvertLanguage( *pConverter, + LANGUAGE_GERMAN, eSysLang, TRUE ); + } + break; + case NF_CONVERT_NONE : + break; // -Wall not handled. + } + + } + else + { + pEntry->Load( rStream, aHdr, NULL, *pStringScanner ); + if ( !bUserDefined ) + bUserDefined = (pEntry->GetNewStandardDefined() > SV_NUMBERFORMATTER_VERSION); + if ( bUserDefined ) + { + if ( eSaveSysLang != eLoadSysLang ) + { // SYSTEM verschieden + if ( !pConverter ) + pConverter = new SvNumberFormatter( xServiceManager, eSysLang ); + if ( nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS ) + { + switch ( eSaveSysLang ) + { + case LANGUAGE_GERMAN: + case LANGUAGE_GERMAN_SWISS: + case LANGUAGE_GERMAN_AUSTRIAN: + case LANGUAGE_GERMAN_LUXEMBOURG: + case LANGUAGE_GERMAN_LIECHTENSTEIN: + // alles beim alten + pEntry->ConvertLanguage( *pConverter, + eSaveSysLang, eLoadSysLang, TRUE ); + break; + default: + // alte english nach neuem anderen + pEntry->ConvertLanguage( *pConverter, + LANGUAGE_ENGLISH_US, eLoadSysLang, TRUE ); + } + } + else + pEntry->ConvertLanguage( *pConverter, + eSaveSysLang, eLoadSysLang, TRUE ); + } + else + { // nicht SYSTEM oder gleiches SYSTEM + if ( nVersion < SV_NUMBERFORMATTER_VERSION_KEYWORDS ) + { + LanguageType eLoadLang; + BOOL bSystem; + if ( eLnge == LANGUAGE_SYSTEM ) + { + eLoadLang = eSysLang; + bSystem = TRUE; + } + else + { + eLoadLang = eLnge; + bSystem = FALSE; + } + switch ( eLoadLang ) + { + case LANGUAGE_GERMAN: + case LANGUAGE_GERMAN_SWISS: + case LANGUAGE_GERMAN_AUSTRIAN: + case LANGUAGE_GERMAN_LUXEMBOURG: + case LANGUAGE_GERMAN_LIECHTENSTEIN: + // alles beim alten + break; + default: + // alte english nach neuem anderen + if ( !pConverter ) + pConverter = new SvNumberFormatter( xServiceManager, eSysLang ); + pEntry->ConvertLanguage( *pConverter, + LANGUAGE_ENGLISH_US, eLoadLang, bSystem ); + } + } + } + } + } + if ( nOffset == 0 ) // StandardFormat + { + SvNumberformat* pEnt = aFTable.Get(nPos); + if (pEnt) + pEnt->SetLastInsertKey(pEntry->GetLastInsertKey()); + } + if (!aFTable.Insert(nPos, pEntry)) + delete pEntry; + rStream >> nPos; + } + + // ab SV_NUMBERFORMATTER_VERSION_YEAR2000 + if ( nVersion >= SV_NUMBERFORMATTER_VERSION_YEAR2000 ) + { + aHdr.StartEntry(); + if ( aHdr.BytesLeft() >= sizeof(UINT16) ) + { + UINT16 nY2k; + rStream >> nY2k; + if ( nVersion < SV_NUMBERFORMATTER_VERSION_TWODIGITYEAR && nY2k < 100 ) + nY2k += 1901; // war vor src513e: 29, jetzt: 1930 + SetYear2000( nY2k ); + } + aHdr.EndEntry(); + } + + if ( pConverter ) + delete pConverter; + + // generate additional i18n standard formats for all used locales + LanguageType eOldLanguage = ActLnge; + NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() ); + SvUShorts aList; + GetUsedLanguages( aList ); + USHORT nCount = aList.Count(); + for ( USHORT j=0; j<nCount; j++ ) + { + LanguageType eLang = aList[j]; + ChangeIntl( eLang ); + sal_uInt32 CLOffset = ImpGetCLOffset( eLang ); + ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, TRUE ); + } + ChangeIntl( eOldLanguage ); + + if (rStream.GetError()) + return FALSE; + else + return TRUE; +} + +BOOL SvNumberFormatter::Save( SvStream& rStream ) const +{ + ImpSvNumMultipleWriteHeader aHdr( rStream ); + // ab 364i wird gespeichert was SYSTEM wirklich war, vorher hart LANGUAGE_SYSTEM + rStream << (USHORT) SV_NUMBERFORMATTER_VERSION; + rStream << (USHORT) SvtSysLocale().GetLanguage() << (USHORT) IniLnge; + SvNumberFormatTable* pTable = (SvNumberFormatTable*) &aFTable; + SvNumberformat* pEntry = (SvNumberformat*) pTable->First(); + while (pEntry) + { + // Gespeichert werden alle markierten, benutzerdefinierten Formate und + // jeweils das Standardformat zu allen angewaehlten CL-Kombinationen + // sowie NewStandardDefined + if ( pEntry->GetUsed() || (pEntry->GetType() & NUMBERFORMAT_DEFINED) || + pEntry->GetNewStandardDefined() || + (pTable->GetCurKey() % SV_COUNTRY_LANGUAGE_OFFSET == 0) ) + { + rStream << static_cast<sal_uInt32>(pTable->GetCurKey()) + << (USHORT) LANGUAGE_SYSTEM + << (USHORT) pEntry->GetLanguage(); + pEntry->Save(rStream, aHdr); + } + pEntry = (SvNumberformat*) pTable->Next(); + } + rStream << NUMBERFORMAT_ENTRY_NOT_FOUND; // EndeKennung + + // ab SV_NUMBERFORMATTER_VERSION_YEAR2000 + aHdr.StartEntry(); + rStream << (UINT16) GetYear2000(); + aHdr.EndEntry(); + + if (rStream.GetError()) + return FALSE; + else + return TRUE; +} + +// static +void SvNumberFormatter::SkipNumberFormatterInStream( SvStream& rStream ) +{ + ImpSvNumMultipleReadHeader::Skip( rStream ); +} + +void SvNumberFormatter::GetUsedLanguages( SvUShorts& rList ) +{ + rList.Remove( 0, rList.Count() ); + + sal_uInt32 nOffset = 0; + while (nOffset <= MaxCLOffset) + { + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nOffset); + if (pFormat) + rList.Insert( pFormat->GetLanguage(), rList.Count() ); + nOffset += SV_COUNTRY_LANGUAGE_OFFSET; + } +} + + +void SvNumberFormatter::FillKeywordTable( NfKeywordTable& rKeywords, + LanguageType eLang ) +{ + ChangeIntl( eLang ); + const String* pTable = pFormatScanner->GetKeywords(); + for ( USHORT i = 0; i < NF_KEYWORD_ENTRIES_COUNT; ++i ) + { + rKeywords[i] = pTable[i]; + } +} + + +String SvNumberFormatter::GetKeyword( LanguageType eLnge, USHORT nIndex ) +{ + ChangeIntl(eLnge); + const String* pTable = pFormatScanner->GetKeywords(); + if ( pTable && nIndex < NF_KEYWORD_ENTRIES_COUNT ) + return pTable[nIndex]; + + DBG_ERROR("GetKeyword: invalid index"); + return String(); +} + + +String SvNumberFormatter::GetStandardName( LanguageType eLnge ) +{ + ChangeIntl( eLnge ); + return pFormatScanner->GetStandardName(); +} + + +sal_uInt32 SvNumberFormatter::ImpGetCLOffset(LanguageType eLnge) const +{ + SvNumberformat* pFormat; + sal_uInt32 nOffset = 0; + while (nOffset <= MaxCLOffset) + { + pFormat = (SvNumberformat*) aFTable.Get(nOffset); + if (pFormat && pFormat->GetLanguage() == eLnge) + return nOffset; + nOffset += SV_COUNTRY_LANGUAGE_OFFSET; + } + return nOffset; +} + +sal_uInt32 SvNumberFormatter::ImpIsEntry(const String& rString, + sal_uInt32 nCLOffset, + LanguageType eLnge) +{ +#ifndef NF_COMMENT_IN_FORMATSTRING +#error NF_COMMENT_IN_FORMATSTRING not defined (zformat.hxx) +#endif +#if NF_COMMENT_IN_FORMATSTRING + String aStr( rString ); + SvNumberformat::EraseComment( aStr ); +#endif + sal_uInt32 res = NUMBERFORMAT_ENTRY_NOT_FOUND; + SvNumberformat* pEntry; + pEntry = (SvNumberformat*) aFTable.Seek(nCLOffset); + while ( res == NUMBERFORMAT_ENTRY_NOT_FOUND && + pEntry && pEntry->GetLanguage() == eLnge ) + { +#if NF_COMMENT_IN_FORMATSTRING + if ( pEntry->GetComment().Len() ) + { + String aFormat( pEntry->GetFormatstring() ); + SvNumberformat::EraseComment( aFormat ); + if ( aStr == aFormat ) + res = aFTable.GetCurKey(); + else + pEntry = (SvNumberformat*) aFTable.Next(); + } + else + { + if ( aStr == pEntry->GetFormatstring() ) + res = aFTable.GetCurKey(); + else + pEntry = (SvNumberformat*) aFTable.Next(); + } +#else + if ( rString == pEntry->GetFormatstring() ) + res = aFTable.GetCurKey(); + else + pEntry = (SvNumberformat*) aFTable.Next(); +#endif + } + return res; +} + + +SvNumberFormatTable& SvNumberFormatter::GetFirstEntryTable( + short& eType, + sal_uInt32& FIndex, + LanguageType& rLnge) +{ + short eTypetmp = eType; + if (eType == NUMBERFORMAT_ALL) // Leere Zelle oder don't care + rLnge = IniLnge; + else + { + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(FIndex); + if (!pFormat) + { +// DBG_ERROR("SvNumberFormatter:: Unbekanntes altes Zahlformat (1)"); + rLnge = IniLnge; + eType = NUMBERFORMAT_ALL; + eTypetmp = eType; + } + else + { + rLnge = pFormat->GetLanguage(); + eType = pFormat->GetType()&~NUMBERFORMAT_DEFINED; + if (eType == 0) + { + eType = NUMBERFORMAT_DEFINED; + eTypetmp = eType; + } + else if (eType == NUMBERFORMAT_DATETIME) + { + eTypetmp = eType; + eType = NUMBERFORMAT_DATE; + } + else + eTypetmp = eType; + } + } + ChangeIntl(rLnge); + return GetEntryTable(eTypetmp, FIndex, rLnge); +} + +sal_uInt32 SvNumberFormatter::ImpGenerateCL( LanguageType eLnge, BOOL bLoadingSO5 ) +{ + ChangeIntl(eLnge); + sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge); + if (CLOffset > MaxCLOffset) + { // new CL combination + if (LocaleDataWrapper::areChecksEnabled()) + { + Locale aLoadedLocale = xLocaleData->getLoadedLocale(); + if ( aLoadedLocale.Language != aLocale.Language || + aLoadedLocale.Country != aLocale.Country ) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumerFormatter::ImpGenerateCL: locales don't match:")); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg )); + } + // test XML locale data FormatElement entries + { + uno::Sequence< i18n::FormatElement > xSeq = + xLocaleData->getAllFormats(); + // A test for completeness of formatindex="0" ... + // formatindex="47" is not needed here since it is done in + // ImpGenerateFormats(). + + // Test for dupes of formatindex="..." + for ( sal_Int32 j = 0; j < xSeq.getLength(); j++ ) + { + sal_Int16 nIdx = xSeq[j].formatIndex; + String aDupes; + for ( sal_Int32 i = 0; i < xSeq.getLength(); i++ ) + { + if ( i != j && xSeq[i].formatIndex == nIdx ) + { + aDupes += String::CreateFromInt32( i ); + aDupes += '('; + aDupes += String( xSeq[i].formatKey ); + aDupes += ')'; + aDupes += ' '; + } + } + if ( aDupes.Len() ) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "XML locale data FormatElement formatindex dupe: ")); + aMsg += String::CreateFromInt32( nIdx ); + aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( + "\nFormatElements: ")); + aMsg += String::CreateFromInt32( j ); + aMsg += '('; + aMsg += String( xSeq[j].formatKey ); + aMsg += ')'; + aMsg += ' '; + aMsg += aDupes; + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg )); + } + } + } + } + + MaxCLOffset += SV_COUNTRY_LANGUAGE_OFFSET; + ImpGenerateFormats( MaxCLOffset, bLoadingSO5 ); + CLOffset = MaxCLOffset; + } + return CLOffset; +} + +SvNumberFormatTable& SvNumberFormatter::ChangeCL(short eType, + sal_uInt32& FIndex, + LanguageType eLnge) +{ + ImpGenerateCL(eLnge); + return GetEntryTable(eType, FIndex, ActLnge); +} + +SvNumberFormatTable& SvNumberFormatter::GetEntryTable( + short eType, + sal_uInt32& FIndex, + LanguageType eLnge) +{ + if ( pFormatTable ) + pFormatTable->Clear(); + else + pFormatTable = new SvNumberFormatTable; + ChangeIntl(eLnge); + sal_uInt32 CLOffset = ImpGetCLOffset(ActLnge); + + // Might generate and insert a default format for the given type + // (e.g. currency) => has to be done before collecting formats. + sal_uInt32 nDefaultIndex = GetStandardFormat( eType, ActLnge ); + + SvNumberformat* pEntry; + pEntry = (SvNumberformat*) aFTable.Seek(CLOffset); + + if (eType == NUMBERFORMAT_ALL) + { + while (pEntry && pEntry->GetLanguage() == ActLnge) + { // copy all entries to output table + pFormatTable->Insert( aFTable.GetCurKey(), pEntry ); + pEntry = (SvNumberformat*) aFTable.Next(); + } + } + else + { + while (pEntry && pEntry->GetLanguage() == ActLnge) + { // copy entries of queried type to output table + if ((pEntry->GetType()) & eType) + pFormatTable->Insert(aFTable.GetCurKey(),pEntry); + pEntry = (SvNumberformat*) aFTable.Next(); + } + } + if ( pFormatTable->Count() > 0 ) + { // select default if queried format doesn't exist or queried type or + // language differ from existing format + pEntry = aFTable.Get(FIndex); + if ( !pEntry || !(pEntry->GetType() & eType) || pEntry->GetLanguage() != ActLnge ) + FIndex = nDefaultIndex; + } + return *pFormatTable; +} + +BOOL SvNumberFormatter::IsNumberFormat(const String& sString, + sal_uInt32& F_Index, + double& fOutNumber) +{ + short FType; + const SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(F_Index); + if (!pFormat) + { +// DBG_ERROR("SvNumberFormatter:: Unbekanntes altes Zahlformat (2)"); + ChangeIntl(IniLnge); + FType = NUMBERFORMAT_NUMBER; + } + else + { + FType = pFormat->GetType() &~NUMBERFORMAT_DEFINED; + if (FType == 0) + FType = NUMBERFORMAT_DEFINED; + ChangeIntl(pFormat->GetLanguage()); + } + BOOL res; + short RType = FType; + // Ergebnistyp + // ohne def-Kennung + if (RType == NUMBERFORMAT_TEXT) // Zahlzelle ->Stringz. + res = FALSE; + else + res = pStringScanner->IsNumberFormat(sString, RType, fOutNumber, pFormat); + + if (res && !IsCompatible(FType, RType)) // unpassender Typ + { + switch ( RType ) + { + case NUMBERFORMAT_TIME : + { + if ( pStringScanner->GetDecPos() ) + { // 100stel Sekunden + if ( pStringScanner->GetAnzNums() > 3 || fOutNumber < 0.0 ) + F_Index = GetFormatIndex( NF_TIME_HH_MMSS00, ActLnge ); + else + F_Index = GetFormatIndex( NF_TIME_MMSS00, ActLnge ); + } + else if ( fOutNumber >= 1.0 || fOutNumber < 0.0 ) + F_Index = GetFormatIndex( NF_TIME_HH_MMSS, ActLnge ); + else + F_Index = GetStandardFormat( RType, ActLnge ); + } + break; + default: + F_Index = GetStandardFormat( RType, ActLnge ); + } + } + return res; +} + +BOOL SvNumberFormatter::IsCompatible(short eOldType, + short eNewType) +{ + if (eOldType == eNewType) + return TRUE; + else if (eOldType == NUMBERFORMAT_DEFINED) + return TRUE; + else + { + switch (eNewType) + { + case NUMBERFORMAT_NUMBER: + { + switch (eOldType) + { + case NUMBERFORMAT_PERCENT: + case NUMBERFORMAT_CURRENCY: + case NUMBERFORMAT_SCIENTIFIC: + case NUMBERFORMAT_FRACTION: +// case NUMBERFORMAT_LOGICAL: + case NUMBERFORMAT_DEFINED: + return TRUE; + default: + return FALSE; + } + } + break; + case NUMBERFORMAT_DATE: + { + switch (eOldType) + { + case NUMBERFORMAT_DATETIME: + return TRUE; + default: + return FALSE; + } + } + break; + case NUMBERFORMAT_TIME: + { + switch (eOldType) + { + case NUMBERFORMAT_DATETIME: + return TRUE; + default: + return FALSE; + } + } + break; + case NUMBERFORMAT_DATETIME: + { + switch (eOldType) + { + case NUMBERFORMAT_TIME: + case NUMBERFORMAT_DATE: + return TRUE; + default: + return FALSE; + } + } + break; + default: + return FALSE; + } + return FALSE; + } +} + + +sal_uInt32 SvNumberFormatter::ImpGetDefaultFormat( short nType ) +{ + sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge ); + sal_uInt32 nSearch; + switch( nType ) + { + case NUMBERFORMAT_DATE : + nSearch = CLOffset + ZF_STANDARD_DATE; + break; + case NUMBERFORMAT_TIME : + nSearch = CLOffset + ZF_STANDARD_TIME; + break; + case NUMBERFORMAT_DATETIME : + nSearch = CLOffset + ZF_STANDARD_DATETIME; + break; + case NUMBERFORMAT_PERCENT : + nSearch = CLOffset + ZF_STANDARD_PERCENT; + break; + case NUMBERFORMAT_SCIENTIFIC: + nSearch = CLOffset + ZF_STANDARD_SCIENTIFIC; + break; + default: + nSearch = CLOffset + ZF_STANDARD; + } + sal_uInt32 nDefaultFormat = (sal_uInt32)(sal_uIntPtr) aDefaultFormatKeys.Get( nSearch ); + if ( !nDefaultFormat ) + nDefaultFormat = NUMBERFORMAT_ENTRY_NOT_FOUND; + if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { // look for a defined standard + sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET; + sal_uInt32 nKey; + aFTable.Seek( CLOffset ); + while ( (nKey = aFTable.GetCurKey()) >= CLOffset && nKey < nStopKey ) + { + const SvNumberformat* pEntry = + (const SvNumberformat*) aFTable.GetCurObject(); + if ( pEntry->IsStandard() && ((pEntry->GetType() & + ~NUMBERFORMAT_DEFINED) == nType) ) + { + nDefaultFormat = nKey; + break; // while + } + aFTable.Next(); + } + + if ( nDefaultFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { // none found, use old fixed standards + switch( nType ) + { + case NUMBERFORMAT_DATE : + nDefaultFormat = CLOffset + ZF_STANDARD_DATE; + break; + case NUMBERFORMAT_TIME : + nDefaultFormat = CLOffset + ZF_STANDARD_TIME+1; + break; + case NUMBERFORMAT_DATETIME : + nDefaultFormat = CLOffset + ZF_STANDARD_DATETIME; + break; + case NUMBERFORMAT_PERCENT : + nDefaultFormat = CLOffset + ZF_STANDARD_PERCENT+1; + break; + case NUMBERFORMAT_SCIENTIFIC: + nDefaultFormat = CLOffset + ZF_STANDARD_SCIENTIFIC; + break; + default: + nDefaultFormat = CLOffset + ZF_STANDARD; + } + } + aDefaultFormatKeys.Insert( nSearch, (void*) nDefaultFormat ); + } + return nDefaultFormat; +} + + +sal_uInt32 SvNumberFormatter::GetStandardFormat( short eType, LanguageType eLnge ) +{ + sal_uInt32 CLOffset = ImpGenerateCL(eLnge); + switch(eType) + { + case NUMBERFORMAT_CURRENCY : + { + if ( eLnge == LANGUAGE_SYSTEM ) + return ImpGetDefaultSystemCurrencyFormat(); + else + return ImpGetDefaultCurrencyFormat(); + } + case NUMBERFORMAT_DATE : + case NUMBERFORMAT_TIME : + case NUMBERFORMAT_DATETIME : + case NUMBERFORMAT_PERCENT : + case NUMBERFORMAT_SCIENTIFIC: + return ImpGetDefaultFormat( eType ); + + case NUMBERFORMAT_FRACTION : return CLOffset + ZF_STANDARD_FRACTION; + case NUMBERFORMAT_LOGICAL : return CLOffset + ZF_STANDARD_LOGICAL; + case NUMBERFORMAT_TEXT : return CLOffset + ZF_STANDARD_TEXT; + case NUMBERFORMAT_ALL : + case NUMBERFORMAT_DEFINED : + case NUMBERFORMAT_NUMBER : + case NUMBERFORMAT_UNDEFINED : + default : return CLOffset + ZF_STANDARD; + } +} + +BOOL SvNumberFormatter::IsSpecialStandardFormat( sal_uInt32 nFIndex, + LanguageType eLnge ) +{ + return + nFIndex == GetFormatIndex( NF_TIME_MMSS00, eLnge ) || + nFIndex == GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ) || + nFIndex == GetFormatIndex( NF_TIME_HH_MMSS, eLnge ) + ; +} + +sal_uInt32 SvNumberFormatter::GetStandardFormat( sal_uInt32 nFIndex, short eType, + LanguageType eLnge ) +{ + if ( IsSpecialStandardFormat( nFIndex, eLnge ) ) + return nFIndex; + else + return GetStandardFormat( eType, eLnge ); +} + +sal_uInt32 SvNumberFormatter::GetStandardFormat( double fNumber, sal_uInt32 nFIndex, + short eType, LanguageType eLnge ) +{ + if ( IsSpecialStandardFormat( nFIndex, eLnge ) ) + return nFIndex; + + switch( eType ) + { + case NUMBERFORMAT_TIME : + { + BOOL bSign; + if ( fNumber < 0.0 ) + { + bSign = TRUE; + fNumber = -fNumber; + } + else + bSign = FALSE; + double fSeconds = fNumber * 86400; + if ( floor( fSeconds + 0.5 ) * 100 != floor( fSeconds * 100 + 0.5 ) ) + { // mit 100stel Sekunden + if ( bSign || fSeconds >= 3600 ) + return GetFormatIndex( NF_TIME_HH_MMSS00, eLnge ); + else + return GetFormatIndex( NF_TIME_MMSS00, eLnge ); + } + else + { + if ( bSign || fNumber >= 1.0 ) + return GetFormatIndex( NF_TIME_HH_MMSS, eLnge ); + else + return GetStandardFormat( eType, eLnge ); + } + } + default: + return GetStandardFormat( eType, eLnge ); + } +} + +void SvNumberFormatter::GetInputLineString(const double& fOutNumber, + sal_uInt32 nFIndex, + String& sOutString) +{ + SvNumberformat* pFormat; + short nOldPrec; + Color* pColor; + pFormat = (SvNumberformat*) aFTable.Get(nFIndex); + if (!pFormat) + pFormat = aFTable.Get(ZF_STANDARD); + LanguageType eLang = pFormat->GetLanguage(); + ChangeIntl( eLang ); + short eType = pFormat->GetType() & ~NUMBERFORMAT_DEFINED; + if (eType == 0) + eType = NUMBERFORMAT_DEFINED; + nOldPrec = -1; + if (eType == NUMBERFORMAT_NUMBER || eType == NUMBERFORMAT_PERCENT + || eType == NUMBERFORMAT_CURRENCY + || eType == NUMBERFORMAT_SCIENTIFIC + || eType == NUMBERFORMAT_FRACTION) + { + if (eType != NUMBERFORMAT_PERCENT) // spaeter Sonderbehandlung % + eType = NUMBERFORMAT_NUMBER; + nOldPrec = pFormatScanner->GetStandardPrec(); + ChangeStandardPrec(300); // Merkwert + } + sal_uInt32 nKey = nFIndex; + switch ( eType ) + { // #61619# immer vierstelliges Jahr editieren + case NUMBERFORMAT_DATE : + nKey = GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang ); + break; + case NUMBERFORMAT_DATETIME : + nKey = GetFormatIndex( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, eLang ); + break; + default: + nKey = GetStandardFormat( fOutNumber, nFIndex, eType, eLang ); + } + if ( nKey != nFIndex ) + pFormat = (SvNumberformat*) aFTable.Get( nKey ); + if (pFormat) + { + if ( eType == NUMBERFORMAT_TIME && pFormat->GetFormatPrecision() ) + { + nOldPrec = pFormatScanner->GetStandardPrec(); + ChangeStandardPrec(300); // Merkwert + } + pFormat->GetOutputString(fOutNumber, sOutString, &pColor); + } + if (nOldPrec != -1) + ChangeStandardPrec(nOldPrec); +} + +void SvNumberFormatter::GetOutputString(const double& fOutNumber, + sal_uInt32 nFIndex, + String& sOutString, + Color** ppColor) +{ + if (bNoZero && fOutNumber == 0.0) + { + sOutString.Erase(); + return; + } + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex); + if (!pFormat) + pFormat = aFTable.Get(ZF_STANDARD); + ChangeIntl(pFormat->GetLanguage()); + pFormat->GetOutputString(fOutNumber, sOutString, ppColor); +} + +void SvNumberFormatter::GetOutputString(String& sString, + sal_uInt32 nFIndex, + String& sOutString, + Color** ppColor) +{ + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex); + if (!pFormat) + pFormat = aFTable.Get(ZF_STANDARD_TEXT); + if (!pFormat->IsTextFormat() && !pFormat->HasTextFormat()) + { + *ppColor = NULL; + sOutString = sString; + } + else + { + ChangeIntl(pFormat->GetLanguage()); + pFormat->GetOutputString(sString, sOutString, ppColor); + } +} + +BOOL SvNumberFormatter::GetPreviewString(const String& sFormatString, + double fPreviewNumber, + String& sOutString, + Color** ppColor, + LanguageType eLnge) +{ + if (sFormatString.Len() == 0) // keinen Leerstring + return FALSE; + + xub_StrLen nCheckPos = STRING_NOTFOUND; + sal_uInt32 nKey; + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + ChangeIntl(eLnge); // ggfs. austauschen + eLnge = ActLnge; + String sTmpString = sFormatString; + SvNumberformat* p_Entry = new SvNumberformat(sTmpString, + pFormatScanner, + pStringScanner, + nCheckPos, + eLnge); + if (nCheckPos == 0) // String ok + { + sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard- + // formate anlegen + nKey = ImpIsEntry(p_Entry->GetFormatstring(),CLOffset, eLnge); + if (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden + GetOutputString(fPreviewNumber,nKey,sOutString,ppColor); + else + p_Entry->GetOutputString(fPreviewNumber,sOutString, ppColor); + delete p_Entry; + return TRUE; + } + else + { + delete p_Entry; + return FALSE; + } +} + +BOOL SvNumberFormatter::GetPreviewStringGuess( const String& sFormatString, + double fPreviewNumber, + String& sOutString, + Color** ppColor, + LanguageType eLnge ) +{ + if (sFormatString.Len() == 0) // keinen Leerstring + return FALSE; + + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + + ChangeIntl( eLnge ); + eLnge = ActLnge; + BOOL bEnglish = (eLnge == LANGUAGE_ENGLISH_US); + + String aFormatStringUpper( pCharClass->upper( sFormatString ) ); + sal_uInt32 nCLOffset = ImpGenerateCL( eLnge ); + sal_uInt32 nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, eLnge ); + if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND ) + { // Zielformat vorhanden + GetOutputString( fPreviewNumber, nKey, sOutString, ppColor ); + return TRUE; + } + + SvNumberformat *pEntry = NULL; + xub_StrLen nCheckPos = STRING_NOTFOUND; + String sTmpString; + + if ( bEnglish ) + { + sTmpString = sFormatString; + pEntry = new SvNumberformat( sTmpString, pFormatScanner, + pStringScanner, nCheckPos, eLnge ); + } + else + { + nCLOffset = ImpGenerateCL( LANGUAGE_ENGLISH_US ); + nKey = ImpIsEntry( aFormatStringUpper, nCLOffset, LANGUAGE_ENGLISH_US ); + BOOL bEnglishFormat = (nKey != NUMBERFORMAT_ENTRY_NOT_FOUND); + + // try english --> other bzw. english nach other konvertieren + LanguageType eFormatLang = LANGUAGE_ENGLISH_US; + pFormatScanner->SetConvertMode( LANGUAGE_ENGLISH_US, eLnge ); + sTmpString = sFormatString; + pEntry = new SvNumberformat( sTmpString, pFormatScanner, + pStringScanner, nCheckPos, eFormatLang ); + pFormatScanner->SetConvertMode( FALSE ); + ChangeIntl( eLnge ); + + if ( !bEnglishFormat ) + { + if ( nCheckPos > 0 || xTransliteration->isEqual( sFormatString, + pEntry->GetFormatstring() ) ) + { // other Format + delete pEntry; + sTmpString = sFormatString; + pEntry = new SvNumberformat( sTmpString, pFormatScanner, + pStringScanner, nCheckPos, eLnge ); + } + else + { // verify english + xub_StrLen nCheckPos2 = STRING_NOTFOUND; + // try other --> english + eFormatLang = eLnge; + pFormatScanner->SetConvertMode( eLnge, LANGUAGE_ENGLISH_US ); + sTmpString = sFormatString; + SvNumberformat* pEntry2 = new SvNumberformat( sTmpString, pFormatScanner, + pStringScanner, nCheckPos2, eFormatLang ); + pFormatScanner->SetConvertMode( FALSE ); + ChangeIntl( eLnge ); + if ( nCheckPos2 == 0 && !xTransliteration->isEqual( sFormatString, + pEntry2->GetFormatstring() ) ) + { // other Format + delete pEntry; + sTmpString = sFormatString; + pEntry = new SvNumberformat( sTmpString, pFormatScanner, + pStringScanner, nCheckPos, eLnge ); + } + delete pEntry2; + } + } + } + + if (nCheckPos == 0) // String ok + { + ImpGenerateCL( eLnge ); // ggfs. neu Standardformate anlegen + pEntry->GetOutputString( fPreviewNumber, sOutString, ppColor ); + delete pEntry; + return TRUE; + } + delete pEntry; + return FALSE; +} + +sal_uInt32 SvNumberFormatter::TestNewString(const String& sFormatString, + LanguageType eLnge) +{ + if (sFormatString.Len() == 0) // keinen Leerstring + return NUMBERFORMAT_ENTRY_NOT_FOUND; + + xub_StrLen nCheckPos = STRING_NOTFOUND; + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + ChangeIntl(eLnge); // ggfs. austauschen + eLnge = ActLnge; + sal_uInt32 nRes; + String sTmpString = sFormatString; + SvNumberformat* pEntry = new SvNumberformat(sTmpString, + pFormatScanner, + pStringScanner, + nCheckPos, + eLnge); + if (nCheckPos == 0) // String ok + { + sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard- + // formate anlegen + nRes = ImpIsEntry(pEntry->GetFormatstring(),CLOffset, eLnge); + // schon vorhanden ? + } + else + nRes = NUMBERFORMAT_ENTRY_NOT_FOUND; + delete pEntry; + return nRes; +} + +SvNumberformat* SvNumberFormatter::ImpInsertFormat( + const ::com::sun::star::i18n::NumberFormatCode& rCode, + sal_uInt32 nPos, BOOL bAfterLoadingSO5, sal_Int16 nOrgIndex ) +{ + String aCodeStr( rCode.Code ); + if ( rCode.Index < NF_INDEX_TABLE_ENTRIES && + rCode.Usage == ::com::sun::star::i18n::KNumberFormatUsage::CURRENCY && + rCode.Index != NF_CURRENCY_1000DEC2_CCC ) + { // strip surrounding [$...] on automatic currency + if ( aCodeStr.SearchAscii( "[$" ) != STRING_NOTFOUND ) + aCodeStr = SvNumberformat::StripNewCurrencyDelimiters( aCodeStr, FALSE ); + else + { + if (LocaleDataWrapper::areChecksEnabled() && + rCode.Index != NF_CURRENCY_1000DEC2_CCC ) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumberFormatter::ImpInsertFormat: no [$...] on currency format code, index ")); + aMsg += String::CreateFromInt32( rCode.Index ); + aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ":\n")); + aMsg += String( rCode.Code ); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + } + } + xub_StrLen nCheckPos = 0; + SvNumberformat* pFormat = new SvNumberformat(aCodeStr, + pFormatScanner, + pStringScanner, + nCheckPos, + ActLnge); + if ( !pFormat || nCheckPos > 0 ) + { + if (LocaleDataWrapper::areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumberFormatter::ImpInsertFormat: bad format code, index ")); + aMsg += String::CreateFromInt32( rCode.Index ); + aMsg += '\n'; + aMsg += String( rCode.Code ); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + delete pFormat; + return NULL; + } + if ( rCode.Index >= NF_INDEX_TABLE_ENTRIES ) + { + sal_uInt32 nCLOffset = nPos - (nPos % SV_COUNTRY_LANGUAGE_OFFSET); + sal_uInt32 nKey = ImpIsEntry( aCodeStr, nCLOffset, ActLnge ); + if ( nKey != NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + if (LocaleDataWrapper::areChecksEnabled()) + { + switch ( nOrgIndex ) + { + // These may be dupes of integer versions for locales where + // currencies have no decimals like Italian Lira. + case NF_CURRENCY_1000DEC2 : // NF_CURRENCY_1000INT + case NF_CURRENCY_1000DEC2_RED : // NF_CURRENCY_1000INT_RED + case NF_CURRENCY_1000DEC2_DASHED : // NF_CURRENCY_1000INT_RED + break; + default: + if ( !bAfterLoadingSO5 ) + { // If bAfterLoadingSO5 there will definitely be some dupes, + // don't cry. But we need this test for verification of locale + // data if not loading old SO5 documents. + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumberFormatter::ImpInsertFormat: dup format code, index ")); + aMsg += String::CreateFromInt32( rCode.Index ); + aMsg += '\n'; + aMsg += String( rCode.Code ); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + } + } + delete pFormat; + return NULL; + } + else if ( nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET ) + { + if (LocaleDataWrapper::areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumberFormatter::ImpInsertFormat: too many format codes, index ")); + aMsg += String::CreateFromInt32( rCode.Index ); + aMsg += '\n'; + aMsg += String( rCode.Code ); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + delete pFormat; + return NULL; + } + } + if ( !aFTable.Insert( nPos, pFormat ) ) + { + if (LocaleDataWrapper::areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "ImpInsertFormat: can't insert number format key pos: ")); + aMsg += String::CreateFromInt32( nPos ); + aMsg.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", code index ")); + aMsg += String::CreateFromInt32( rCode.Index ); + aMsg += '\n'; + aMsg += String( rCode.Code ); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + delete pFormat; + return NULL; + } + if ( rCode.Default ) + pFormat->SetStandard(); + if ( rCode.DefaultName.getLength() ) + pFormat->SetComment( rCode.DefaultName ); + return pFormat; +} + +SvNumberformat* SvNumberFormatter::ImpInsertNewStandardFormat( + const ::com::sun::star::i18n::NumberFormatCode& rCode, + sal_uInt32 nPos, USHORT nVersion, BOOL bAfterLoadingSO5, + sal_Int16 nOrgIndex ) +{ + SvNumberformat* pNewFormat = ImpInsertFormat( rCode, nPos, + bAfterLoadingSO5, nOrgIndex ); + if (pNewFormat) + pNewFormat->SetNewStandardDefined( nVersion ); + // so that it gets saved, displayed properly, and converted by old versions + return pNewFormat; +} + +void SvNumberFormatter::GetFormatSpecialInfo(sal_uInt32 nFormat, + BOOL& bThousand, + BOOL& IsRed, + USHORT& nPrecision, + USHORT& nAnzLeading) + +{ + const SvNumberformat* pFormat = aFTable.Get(nFormat); + if (pFormat) + pFormat->GetFormatSpecialInfo(bThousand, IsRed, + nPrecision, nAnzLeading); + else + { + bThousand = FALSE; + IsRed = FALSE; + nPrecision = pFormatScanner->GetStandardPrec(); + nAnzLeading = 0; + } +} + +USHORT SvNumberFormatter::GetFormatPrecision( sal_uInt32 nFormat ) const +{ + const SvNumberformat* pFormat = aFTable.Get( nFormat ); + if ( pFormat ) + return pFormat->GetFormatPrecision(); + else + return pFormatScanner->GetStandardPrec(); +} + + +String SvNumberFormatter::GetFormatDecimalSep( sal_uInt32 nFormat ) const +{ + const SvNumberformat* pFormat = aFTable.Get( nFormat ); + if ( !pFormat || pFormat->GetLanguage() == ActLnge ) + return GetNumDecimalSep(); + + String aRet; + LanguageType eSaveLang = xLocaleData.getCurrentLanguage(); + if ( pFormat->GetLanguage() == eSaveLang ) + aRet = xLocaleData->getNumDecimalSep(); + else + { + ::com::sun::star::lang::Locale aSaveLocale( xLocaleData->getLocale() ); + ::com::sun::star::lang::Locale aTmpLocale(MsLangId::convertLanguageToLocale(pFormat->GetLanguage())); + ((SvNumberFormatter*)this)->xLocaleData.changeLocale(aTmpLocale, pFormat->GetLanguage() ); + aRet = xLocaleData->getNumDecimalSep(); + ((SvNumberFormatter*)this)->xLocaleData.changeLocale( aSaveLocale, eSaveLang ); + } + return aRet; +} + + +sal_uInt32 SvNumberFormatter::GetFormatSpecialInfo( const String& rFormatString, + BOOL& bThousand, BOOL& IsRed, USHORT& nPrecision, + USHORT& nAnzLeading, LanguageType eLnge ) + +{ + xub_StrLen nCheckPos = 0; + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + ChangeIntl(eLnge); // ggfs. austauschen + eLnge = ActLnge; + String aTmpStr( rFormatString ); + SvNumberformat* pFormat = new SvNumberformat( aTmpStr, + pFormatScanner, pStringScanner, nCheckPos, eLnge ); + if ( nCheckPos == 0 ) + pFormat->GetFormatSpecialInfo( bThousand, IsRed, nPrecision, nAnzLeading ); + else + { + bThousand = FALSE; + IsRed = FALSE; + nPrecision = pFormatScanner->GetStandardPrec(); + nAnzLeading = 0; + } + delete pFormat; + return nCheckPos; +} + + +inline sal_uInt32 SetIndexTable( NfIndexTableOffset nTabOff, sal_uInt32 nIndOff ) +{ + if ( !bIndexTableInitialized ) + { + DBG_ASSERT( theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND, + "SetIndexTable: theIndexTable[nTabOff] already occupied" ); + theIndexTable[nTabOff] = nIndOff; + } + return nIndOff; +} + + +sal_Int32 SvNumberFormatter::ImpGetFormatCodeIndex( + ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::NumberFormatCode >& rSeq, + const NfIndexTableOffset nTabOff ) +{ + const sal_Int32 nLen = rSeq.getLength(); + for ( sal_Int32 j=0; j<nLen; j++ ) + { + if ( rSeq[j].Index == nTabOff ) + return j; + } + if (LocaleDataWrapper::areChecksEnabled() && (nTabOff < NF_CURRENCY_START + || NF_CURRENCY_END < nTabOff || nTabOff == NF_CURRENCY_1000INT + || nTabOff == NF_CURRENCY_1000INT_RED + || nTabOff == NF_CURRENCY_1000DEC2_CCC)) + { // currency entries with decimals might not exist, e.g. Italian Lira + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumberFormatter::ImpGetFormatCodeIndex: not found: ")); + aMsg += String::CreateFromInt32( nTabOff ); + LocaleDataWrapper::outputCheckMessage( xLocaleData->appendLocaleInfo( + aMsg)); + } + if ( nLen ) + { + sal_Int32 j; + // look for a preset default + for ( j=0; j<nLen; j++ ) + { + if ( rSeq[j].Default ) + return j; + } + // currencies are special, not all format codes must exist, but all + // builtin number format key index positions must have a format assigned + if ( NF_CURRENCY_START <= nTabOff && nTabOff <= NF_CURRENCY_END ) + { + // look for a format with decimals + for ( j=0; j<nLen; j++ ) + { + if ( rSeq[j].Index == NF_CURRENCY_1000DEC2 ) + return j; + } + // last resort: look for a format without decimals + for ( j=0; j<nLen; j++ ) + { + if ( rSeq[j].Index == NF_CURRENCY_1000INT ) + return j; + } + } + } + else + { // we need at least _some_ format + rSeq.realloc(1); + rSeq[0] = ::com::sun::star::i18n::NumberFormatCode(); + String aTmp( '0' ); + aTmp += GetNumDecimalSep(); + aTmp.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "############" ) ); + rSeq[0].Code = aTmp; + } + return 0; +} + + +sal_Int32 SvNumberFormatter::ImpAdjustFormatCodeDefault( + ::com::sun::star::i18n::NumberFormatCode * pFormatArr, + sal_Int32 nCnt, BOOL bCheckCorrectness ) +{ + using namespace ::com::sun::star; + + if ( !nCnt ) + return -1; + if (bCheckCorrectness && LocaleDataWrapper::areChecksEnabled()) + { // check the locale data for correctness + ByteString aMsg; + sal_Int32 nElem, nShort, nMedium, nLong, nShortDef, nMediumDef, nLongDef; + nShort = nMedium = nLong = nShortDef = nMediumDef = nLongDef = -1; + for ( nElem = 0; nElem < nCnt; nElem++ ) + { + switch ( pFormatArr[nElem].Type ) + { + case i18n::KNumberFormatType::SHORT : + nShort = nElem; + break; + case i18n::KNumberFormatType::MEDIUM : + nMedium = nElem; + break; + case i18n::KNumberFormatType::LONG : + nLong = nElem; + break; + default: + aMsg = "unknown type"; + } + if ( pFormatArr[nElem].Default ) + { + switch ( pFormatArr[nElem].Type ) + { + case i18n::KNumberFormatType::SHORT : + if ( nShortDef != -1 ) + aMsg = "dupe short type default"; + nShortDef = nElem; + break; + case i18n::KNumberFormatType::MEDIUM : + if ( nMediumDef != -1 ) + aMsg = "dupe medium type default"; + nMediumDef = nElem; + break; + case i18n::KNumberFormatType::LONG : + if ( nLongDef != -1 ) + aMsg = "dupe long type default"; + nLongDef = nElem; + break; + } + } + if ( aMsg.Len() ) + { + aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 ); + aMsg += "\nXML locale data FormatElement formatindex: "; + aMsg += ByteString::CreateFromInt32( pFormatArr[nElem].Index ); + String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aUMsg)); + aMsg.Erase(); + } + } + if ( nShort != -1 && nShortDef == -1 ) + aMsg += "no short type default "; + if ( nMedium != -1 && nMediumDef == -1 ) + aMsg += "no medium type default "; + if ( nLong != -1 && nLongDef == -1 ) + aMsg += "no long type default "; + if ( aMsg.Len() ) + { + aMsg.Insert( "SvNumberFormatter::ImpAdjustFormatCodeDefault: ", 0 ); + aMsg += "\nXML locale data FormatElement group of: "; + String aUMsg( aMsg, RTL_TEXTENCODING_ASCII_US); + aUMsg += String( pFormatArr[0].NameID ); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aUMsg)); + aMsg.Erase(); + } + } + // find the default (medium preferred, then long) and reset all other defaults + sal_Int32 nElem, nDef, nMedium; + nDef = nMedium = -1; + for ( nElem = 0; nElem < nCnt; nElem++ ) + { + if ( pFormatArr[nElem].Default ) + { + switch ( pFormatArr[nElem].Type ) + { + case i18n::KNumberFormatType::MEDIUM : + nDef = nMedium = nElem; + break; + case i18n::KNumberFormatType::LONG : + if ( nMedium == -1 ) + nDef = nElem; + // fallthru + default: + if ( nDef == -1 ) + nDef = nElem; + pFormatArr[nElem].Default = sal_False; + } + } + } + if ( nDef == -1 ) + nDef = 0; + pFormatArr[nDef].Default = sal_True; + return nDef; +} + + +void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, BOOL bLoadingSO5 ) +{ + using namespace ::com::sun::star; + + if ( !bIndexTableInitialized ) + { + for ( USHORT j=0; j<NF_INDEX_TABLE_ENTRIES; j++ ) + { + theIndexTable[j] = NUMBERFORMAT_ENTRY_NOT_FOUND; + } + } + BOOL bOldConvertMode = pFormatScanner->GetConvertMode(); + if (bOldConvertMode) + pFormatScanner->SetConvertMode(FALSE); // switch off for this function + + NumberFormatCodeWrapper aNumberFormatCode( xServiceManager, GetLocale() ); + + xub_StrLen nCheckPos = 0; + SvNumberformat* pNewFormat = NULL; + String aFormatCode; + sal_Int32 nIdx; + sal_Bool bDefault; + + // Counter for additional builtin formats not fitting into the first 10 + // of a category (TLOT:=The Legacy Of Templin), altogether about 20 formats. + // Has to be incremented on each ImpInsertNewStandardformat, new formats + // must be appended, not inserted! + USHORT nNewExtended = ZF_STANDARD_NEWEXTENDED; + + // Number + uno::Sequence< i18n::NumberFormatCode > aFormatSeq + = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::FIXED_NUMBER ); + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() ); + + // General + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_STANDARD ); + SvNumberformat* pStdFormat = ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_NUMBER_STANDARD, ZF_STANDARD )); + if (pStdFormat) + { + // This is _the_ standard format. + if (LocaleDataWrapper::areChecksEnabled() && + pStdFormat->GetType() != NUMBERFORMAT_NUMBER) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumberFormatter::ImpGenerateFormats: General format not NUMBER")); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + pStdFormat->SetType( NUMBERFORMAT_NUMBER ); + pStdFormat->SetStandard(); + pStdFormat->SetLastInsertKey( SV_MAX_ANZ_STANDARD_FORMATE ); + } + else + { + if (LocaleDataWrapper::areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "SvNumberFormatter::ImpGenerateFormats: General format not insertable, nothing will work")); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + } + + // Boolean + aFormatCode = pFormatScanner->GetBooleanString(); + pNewFormat = new SvNumberformat( aFormatCode, + pFormatScanner, pStringScanner, nCheckPos, ActLnge ); + pNewFormat->SetType(NUMBERFORMAT_LOGICAL); + pNewFormat->SetStandard(); + if ( !aFTable.Insert( + CLOffset + SetIndexTable( NF_BOOLEAN, ZF_STANDARD_LOGICAL ), + pNewFormat)) + delete pNewFormat; + + // Text + aFormatCode = '@'; + pNewFormat = new SvNumberformat( aFormatCode, + pFormatScanner, pStringScanner, nCheckPos, ActLnge ); + pNewFormat->SetType(NUMBERFORMAT_TEXT); + pNewFormat->SetStandard(); + if ( !aFTable.Insert( + CLOffset + SetIndexTable( NF_TEXT, ZF_STANDARD_TEXT ), + pNewFormat)) + delete pNewFormat; + + + + // 0 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_INT ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_NUMBER_INT, ZF_STANDARD+1 )); + + // 0.00 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_DEC2 ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_NUMBER_DEC2, ZF_STANDARD+2 )); + + // #,##0 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000INT ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_NUMBER_1000INT, ZF_STANDARD+3 )); + + // #,##0.00 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_1000DEC2 ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_NUMBER_1000DEC2, ZF_STANDARD+4 )); + + // #.##0,00 System country/language dependent since number formatter version 6 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_NUMBER_SYSTEM ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_NUMBER_SYSTEM, ZF_STANDARD+5 ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + + // Percent number + aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::PERCENT_NUMBER ); + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() ); + + // 0% + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_INT ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_PERCENT_INT, ZF_STANDARD_PERCENT )); + + // 0.00% + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_PERCENT_DEC2 ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_PERCENT_DEC2, ZF_STANDARD_PERCENT+1 )); + + + + // Currency. NO default standard option! Default is determined of locale + // data default currency and format is generated if needed. + aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY ); + if (LocaleDataWrapper::areChecksEnabled()) + { + // though no default desired here, test for correctness of locale data + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() ); + } + + // #,##0 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT ); + bDefault = aFormatSeq[nIdx].Default; + aFormatSeq[nIdx].Default = sal_False; + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_CURRENCY_1000INT, ZF_STANDARD_CURRENCY )); + aFormatSeq[nIdx].Default = bDefault; + + // #,##0.00 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2 ); + bDefault = aFormatSeq[nIdx].Default; + aFormatSeq[nIdx].Default = sal_False; + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2, ZF_STANDARD_CURRENCY+1 )); + aFormatSeq[nIdx].Default = bDefault; + + // #,##0 negative red + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000INT_RED ); + bDefault = aFormatSeq[nIdx].Default; + aFormatSeq[nIdx].Default = sal_False; + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_CURRENCY_1000INT_RED, ZF_STANDARD_CURRENCY+2 )); + aFormatSeq[nIdx].Default = bDefault; + + // #,##0.00 negative red + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_RED ); + bDefault = aFormatSeq[nIdx].Default; + aFormatSeq[nIdx].Default = sal_False; + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_RED, ZF_STANDARD_CURRENCY+3 )); + aFormatSeq[nIdx].Default = bDefault; + + // #,##0.00 USD since number formatter version 3 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_CCC ); + bDefault = aFormatSeq[nIdx].Default; + aFormatSeq[nIdx].Default = sal_False; + pNewFormat = ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_CCC, ZF_STANDARD_CURRENCY+4 )); + if ( pNewFormat ) + pNewFormat->SetUsed(TRUE); // must be saved for older versions + aFormatSeq[nIdx].Default = bDefault; + + // #.##0,-- since number formatter version 6 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_CURRENCY_1000DEC2_DASHED ); + bDefault = aFormatSeq[nIdx].Default; + aFormatSeq[nIdx].Default = sal_False; + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_CURRENCY_1000DEC2_DASHED, ZF_STANDARD_CURRENCY+5 ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + aFormatSeq[nIdx].Default = bDefault; + + + + // Date + aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE ); + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() ); + + // DD.MM.YY System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_SHORT ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYSTEM_SHORT, ZF_STANDARD_DATE )); + + // NN DD.MMM YY + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DEF_NNDDMMMYY ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_DEF_NNDDMMMYY, ZF_STANDARD_DATE+1 )); + + // DD.MM.YY def/System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_MMYY ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_MMYY, ZF_STANDARD_DATE+2 )); + + // DD MMM + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMM ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_DDMMM, ZF_STANDARD_DATE+3 )); + + // MMMM + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_MMMM ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_MMMM, ZF_STANDARD_DATE+4 )); + + // QQ YY + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_QQJJ ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_QQJJ, ZF_STANDARD_DATE+5 )); + + // DD.MM.YYYY since number formatter version 2, was DD.MM.[YY]YY + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYYYY ); + pNewFormat = ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYYYY, ZF_STANDARD_DATE+6 )); + if ( pNewFormat ) + pNewFormat->SetUsed(TRUE); // must be saved for older versions + + // DD.MM.YY def/System, since number formatter version 6 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DDMMYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_DDMMYY, ZF_STANDARD_DATE+7 ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // NNN, D. MMMM YYYY System + // Long day of week: "NNNN" instead of "NNN," because of compatibility + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYSTEM_LONG ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYSTEM_LONG, ZF_STANDARD_DATE+8 ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // Hard coded but system (regional settings) delimiters dependent long date formats + // since numberformatter version 6 + + // D. MMM YY def/System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYY, ZF_STANDARD_DATE+9 ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + //! Unfortunally TLOT intended only 10 builtin formats per category, more + //! would overwrite the next category (ZF_STANDARD_TIME) :-(( + //! Therefore they are inserted with nNewExtended++ (which is also limited) + + // D. MMM YYYY def/System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMYYYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_DMMMYYYY, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // D. MMMM YYYY def/System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_DMMMMYYYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_DMMMMYYYY, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // NN, D. MMM YY def/System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMYY, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // NN, D. MMMM YYYY def/System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNDMMMMYYYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_NNDMMMMYYYY, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // NNN, D. MMMM YYYY def/System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_SYS_NNNNDMMMMYYYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_SYS_NNNNDMMMMYYYY, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // Hard coded DIN (Deutsche Industrie Norm) and EN (European Norm) date formats + + // D. MMM. YYYY DIN/EN + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMYYYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_DIN_DMMMYYYY, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // D. MMMM YYYY DIN/EN + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_DMMMMYYYY ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_DIN_DMMMMYYYY, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // MM-DD DIN/EN + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_MMDD ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_DIN_MMDD, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // YY-MM-DD DIN/EN + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYMMDD ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_DIN_YYMMDD, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + // YYYY-MM-DD DIN/EN + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATE_DIN_YYYYMMDD ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATE_DIN_YYYYMMDD, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NEWSTANDARD ); + + + + // Time + aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::TIME ); + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() ); + + // HH:MM + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMM ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_TIME_HHMM, ZF_STANDARD_TIME )); + + // HH:MM:SS + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSS ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_TIME_HHMMSS, ZF_STANDARD_TIME+1 )); + + // HH:MM AM/PM + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMAMPM ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_TIME_HHMMAMPM, ZF_STANDARD_TIME+2 )); + + // HH:MM:SS AM/PM + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HHMMSSAMPM ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_TIME_HHMMSSAMPM, ZF_STANDARD_TIME+3 )); + + // [HH]:MM:SS + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_TIME_HH_MMSS, ZF_STANDARD_TIME+4 )); + + // MM:SS,00 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_MMSS00 ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_TIME_MMSS00, ZF_STANDARD_TIME+5 )); + + // [HH]:MM:SS,00 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_TIME_HH_MMSS00 ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_TIME_HH_MMSS00, ZF_STANDARD_TIME+6 ), + SV_NUMBERFORMATTER_VERSION_NF_TIME_HH_MMSS00 ); + + + + // DateTime + aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::DATE_TIME ); + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() ); + + // DD.MM.YY HH:MM System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYSTEM_SHORT_HHMM ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATETIME_SYSTEM_SHORT_HHMM, ZF_STANDARD_DATETIME )); + + // DD.MM.YYYY HH:MM:SS System + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_DATETIME_SYS_DDMMYYYY_HHMMSS ); + ImpInsertNewStandardFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_DATETIME_SYS_DDMMYYYY_HHMMSS, ZF_STANDARD_DATETIME+1 ), + SV_NUMBERFORMATTER_VERSION_NF_DATETIME_SYS_DDMMYYYY_HHMMSS ); + + + + // Scientific number + aFormatSeq = aNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::SCIENTIFIC_NUMBER ); + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), aFormatSeq.getLength() ); + + // 0.00E+000 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E000 ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_SCIENTIFIC_000E000, ZF_STANDARD_SCIENTIFIC )); + + // 0.00E+00 + nIdx = ImpGetFormatCodeIndex( aFormatSeq, NF_SCIENTIFIC_000E00 ); + ImpInsertFormat( aFormatSeq[nIdx], + CLOffset + SetIndexTable( NF_SCIENTIFIC_000E00, ZF_STANDARD_SCIENTIFIC+1 )); + + + + // Fraction number (no default option) + i18n::NumberFormatCode aSingleFormatCode; + + // # ?/? + aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) ); + String s25( RTL_CONSTASCII_USTRINGPARAM( "# ?/?" ) ); // # ?/? + ImpInsertFormat( aSingleFormatCode, + CLOffset + SetIndexTable( NF_FRACTION_1, ZF_STANDARD_FRACTION )); + + // # ??/?? + //! "??/" would be interpreted by the compiler as a trigraph for '\' + aSingleFormatCode.Code = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "# ?\?/?\?" ) ); + ImpInsertFormat( aSingleFormatCode, + CLOffset + SetIndexTable( NF_FRACTION_2, ZF_STANDARD_FRACTION+1 )); + + // Week of year must be appended here because of nNewExtended + const String* pKeyword = pFormatScanner->GetKeywords(); + aSingleFormatCode.Code = pKeyword[NF_KEY_WW]; + ImpInsertNewStandardFormat( aSingleFormatCode, + CLOffset + SetIndexTable( NF_DATE_WW, nNewExtended++ ), + SV_NUMBERFORMATTER_VERSION_NF_DATE_WW ); + + + + bIndexTableInitialized = TRUE; + DBG_ASSERT( nNewExtended <= ZF_STANDARD_NEWEXTENDEDMAX, + "ImpGenerateFormats: overflow of nNewExtended standard formats" ); + + // Now all additional format codes provided by I18N, but only if not + // loading from old SO5 file format, then they are appended last. + if ( !bLoadingSO5 ) + ImpGenerateAdditionalFormats( CLOffset, aNumberFormatCode, FALSE ); + + if (bOldConvertMode) + pFormatScanner->SetConvertMode(TRUE); +} + + +void SvNumberFormatter::ImpGenerateAdditionalFormats( sal_uInt32 CLOffset, + NumberFormatCodeWrapper& rNumberFormatCode, BOOL bAfterLoadingSO5 ) +{ + using namespace ::com::sun::star; + + SvNumberformat* pStdFormat = + (SvNumberformat*) aFTable.Get( CLOffset + ZF_STANDARD ); + if ( !pStdFormat ) + { + DBG_ERRORFILE( "ImpGenerateAdditionalFormats: no GENERAL format" ); + return ; + } + sal_uInt32 nPos = CLOffset + pStdFormat->GetLastInsertKey(); + rNumberFormatCode.setLocale( GetLocale() ); + sal_Int32 j; + + // All currencies, this time with [$...] which was stripped in + // ImpGenerateFormats for old "automatic" currency formats. + uno::Sequence< i18n::NumberFormatCode > aFormatSeq = + rNumberFormatCode.getAllFormatCode( i18n::KNumberFormatUsage::CURRENCY ); + i18n::NumberFormatCode * pFormatArr = aFormatSeq.getArray(); + sal_Int32 nCodes = aFormatSeq.getLength(); + ImpAdjustFormatCodeDefault( aFormatSeq.getArray(), nCodes ); + for ( j = 0; j < nCodes; j++ ) + { + if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET ) + { + DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" ); + break; // for + } + if ( pFormatArr[j].Index < NF_INDEX_TABLE_ENTRIES && + pFormatArr[j].Index != NF_CURRENCY_1000DEC2_CCC ) + { // Insert only if not already inserted, but internal index must be + // above so ImpInsertFormat can distinguish it. + sal_Int16 nOrgIndex = pFormatArr[j].Index; + pFormatArr[j].Index = sal::static_int_cast< sal_Int16 >( + pFormatArr[j].Index + nCodes + NF_INDEX_TABLE_ENTRIES); + //! no default on currency + sal_Bool bDefault = aFormatSeq[j].Default; + aFormatSeq[j].Default = sal_False; + if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1, + SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS, + bAfterLoadingSO5, nOrgIndex ) ) + nPos++; + pFormatArr[j].Index = nOrgIndex; + aFormatSeq[j].Default = bDefault; + } + } + + // all additional format codes provided by I18N that are not old standard index + aFormatSeq = rNumberFormatCode.getAllFormatCodes(); + nCodes = aFormatSeq.getLength(); + if ( nCodes ) + { + pFormatArr = aFormatSeq.getArray(); + // don't check ALL + sal_Int32 nDef = ImpAdjustFormatCodeDefault( pFormatArr, nCodes, FALSE); + // don't have any defaults here + pFormatArr[nDef].Default = sal_False; + for ( j = 0; j < nCodes; j++ ) + { + if ( nPos - CLOffset >= SV_COUNTRY_LANGUAGE_OFFSET ) + { + DBG_ERRORFILE( "ImpGenerateAdditionalFormats: too many formats" ); + break; // for + } + if ( pFormatArr[j].Index >= NF_INDEX_TABLE_ENTRIES ) + if ( ImpInsertNewStandardFormat( pFormatArr[j], nPos+1, + SV_NUMBERFORMATTER_VERSION_ADDITIONAL_I18N_FORMATS, + bAfterLoadingSO5 ) ) + nPos++; + } + } + + pStdFormat->SetLastInsertKey( (USHORT)(nPos - CLOffset) ); +} + + +void SvNumberFormatter::ImpGetPosCurrFormat( String& sPosStr, const String& rCurrSymbol ) +{ + NfCurrencyEntry::CompletePositiveFormatString( sPosStr, + rCurrSymbol, xLocaleData->getCurrPositiveFormat() ); +} + +void SvNumberFormatter::ImpGetNegCurrFormat( String& sNegStr, const String& rCurrSymbol ) +{ + NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, + rCurrSymbol, xLocaleData->getCurrNegativeFormat() ); +} + +void SvNumberFormatter::GenerateFormat(String& sString, + sal_uInt32 nIndex, + LanguageType eLnge, + BOOL bThousand, + BOOL IsRed, + USHORT nPrecision, + USHORT nAnzLeading) +{ + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + short eType = GetType(nIndex); + USHORT i; + ImpGenerateCL(eLnge); // ggfs. neu Standard- + // formate anlegen + sString.Erase(); + + utl::DigitGroupingIterator aGrouping( xLocaleData->getDigitGrouping()); + const xub_StrLen nDigitsInFirstGroup = static_cast<xub_StrLen>(aGrouping.get()); + const String& rThSep = GetNumThousandSep(); + if (nAnzLeading == 0) + { + if (!bThousand) + sString += '#'; + else + { + sString += '#'; + sString += rThSep; + sString.Expand( sString.Len() + nDigitsInFirstGroup, '#' ); + } + } + else + { + for (i = 0; i < nAnzLeading; i++) + { + if (bThousand && i > 0 && i == aGrouping.getPos()) + { + sString.Insert( rThSep, 0 ); + aGrouping.advance(); + } + sString.Insert('0',0); + } + if (bThousand && nAnzLeading < nDigitsInFirstGroup + 1) + { + for (i = nAnzLeading; i < nDigitsInFirstGroup + 1; i++) + { + if (bThousand && i % nDigitsInFirstGroup == 0) + sString.Insert( rThSep, 0 ); + sString.Insert('#',0); + } + } + } + if (nPrecision > 0) + { + sString += GetNumDecimalSep(); + sString.Expand( sString.Len() + nPrecision, '0' ); + } + if (eType == NUMBERFORMAT_PERCENT) + sString += '%'; + else if (eType == NUMBERFORMAT_CURRENCY) + { + String sNegStr = sString; + String aCurr; + const NfCurrencyEntry* pEntry; + BOOL bBank; + if ( GetNewCurrencySymbolString( nIndex, aCurr, &pEntry, &bBank ) ) + { + if ( pEntry ) + { + USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( + xLocaleData->getCurrPositiveFormat(), + pEntry->GetPositiveFormat(), bBank ); + USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( + xLocaleData->getCurrNegativeFormat(), + pEntry->GetNegativeFormat(), bBank ); + pEntry->CompletePositiveFormatString( sString, bBank, + nPosiForm ); + pEntry->CompleteNegativeFormatString( sNegStr, bBank, + nNegaForm ); + } + else + { // assume currency abbreviation (AKA banking symbol), not symbol + USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( + xLocaleData->getCurrPositiveFormat(), + xLocaleData->getCurrPositiveFormat(), TRUE ); + USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( + xLocaleData->getCurrNegativeFormat(), + xLocaleData->getCurrNegativeFormat(), TRUE ); + NfCurrencyEntry::CompletePositiveFormatString( sString, aCurr, + nPosiForm ); + NfCurrencyEntry::CompleteNegativeFormatString( sNegStr, aCurr, + nNegaForm ); + } + } + else + { // "automatic" old style + String aSymbol, aAbbrev; + GetCompatibilityCurrency( aSymbol, aAbbrev ); + ImpGetPosCurrFormat( sString, aSymbol ); + ImpGetNegCurrFormat( sNegStr, aSymbol ); + } + if (IsRed) + { + sString += ';'; + sString += '['; + sString += pFormatScanner->GetRedString(); + sString += ']'; + } + else + sString += ';'; + sString += sNegStr; + } + if (IsRed && eType != NUMBERFORMAT_CURRENCY) + { + String sTmpStr = sString; + sTmpStr += ';'; + sTmpStr += '['; + sTmpStr += pFormatScanner->GetRedString(); + sTmpStr += ']'; + sTmpStr += '-'; + sTmpStr +=sString; + sString = sTmpStr; + } +} + +BOOL SvNumberFormatter::IsUserDefined(const String& sStr, + LanguageType eLnge) +{ + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard- + // formate anlegen + eLnge = ActLnge; + sal_uInt32 nKey = ImpIsEntry(sStr, CLOffset, eLnge); + if (nKey == NUMBERFORMAT_ENTRY_NOT_FOUND) + return TRUE; + SvNumberformat* pEntry = aFTable.Get(nKey); + if ( pEntry && ((pEntry->GetType() & NUMBERFORMAT_DEFINED) != 0) ) + return TRUE; + return FALSE; +} + +sal_uInt32 SvNumberFormatter::GetEntryKey(const String& sStr, + LanguageType eLnge) +{ + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + sal_uInt32 CLOffset = ImpGenerateCL(eLnge); // ggfs. neu Standard- + // formate anlegen + return ImpIsEntry(sStr, CLOffset, eLnge); +} + +sal_uInt32 SvNumberFormatter::GetStandardIndex(LanguageType eLnge) +{ + if (eLnge == LANGUAGE_DONTKNOW) + eLnge = IniLnge; + return GetStandardFormat(NUMBERFORMAT_NUMBER, eLnge); +} + +short SvNumberFormatter::GetType(sal_uInt32 nFIndex) +{ + short eType; + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get(nFIndex); + if (!pFormat) + eType = NUMBERFORMAT_UNDEFINED; + else + { + eType = pFormat->GetType() &~NUMBERFORMAT_DEFINED; + if (eType == 0) + eType = NUMBERFORMAT_DEFINED; + } + return eType; +} + +void SvNumberFormatter::ClearMergeTable() +{ + if ( pMergeTable ) + { + sal_uInt32* pIndex = (sal_uInt32*) pMergeTable->First(); + while (pIndex) + { + delete pIndex; + pIndex = pMergeTable->Next(); + } + pMergeTable->Clear(); + } +} + +SvNumberFormatterIndexTable* SvNumberFormatter::MergeFormatter(SvNumberFormatter& rTable) +{ + if ( pMergeTable ) + ClearMergeTable(); + else + pMergeTable = new SvNumberFormatterIndexTable; + sal_uInt32 nCLOffset = 0; + sal_uInt32 nOldKey, nOffset, nNewKey; + sal_uInt32* pNewIndex; + SvNumberformat* pNewEntry; + SvNumberformat* pFormat = rTable.aFTable.First(); + while (pFormat) + { + nOldKey = rTable.aFTable.GetCurKey(); + nOffset = nOldKey % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex + if (nOffset == 0) // 1. Format von CL + nCLOffset = ImpGenerateCL(pFormat->GetLanguage()); + + if (nOffset <= SV_MAX_ANZ_STANDARD_FORMATE) // Std.form. + { + nNewKey = nCLOffset + nOffset; + if (!aFTable.Get(nNewKey)) // noch nicht da + { +// pNewEntry = new SvNumberformat(*pFormat); // Copy reicht nicht !!! + pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner ); + if (!aFTable.Insert(nNewKey, pNewEntry)) + delete pNewEntry; + } + if (nNewKey != nOldKey) // neuer Index + { + pNewIndex = new sal_uInt32(nNewKey); + if (!pMergeTable->Insert(nOldKey,pNewIndex)) + delete pNewIndex; + } + } + else // benutzerdef. + { +// pNewEntry = new SvNumberformat(*pFormat); // Copy reicht nicht !!! + pNewEntry = new SvNumberformat( *pFormat, *pFormatScanner ); + nNewKey = ImpIsEntry(pNewEntry->GetFormatstring(), + nCLOffset, + pFormat->GetLanguage()); + if (nNewKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // schon vorhanden + delete pNewEntry; + else + { + SvNumberformat* pStdFormat = + (SvNumberformat*) aFTable.Get(nCLOffset + ZF_STANDARD); + sal_uInt32 nPos = nCLOffset + pStdFormat->GetLastInsertKey(); + nNewKey = nPos+1; + if (nPos - nCLOffset >= SV_COUNTRY_LANGUAGE_OFFSET) + { + DBG_ERROR( + "SvNumberFormatter:: Zu viele Formate pro CL"); + delete pNewEntry; + } + else if (!aFTable.Insert(nNewKey, pNewEntry)) + delete pNewEntry; + else + pStdFormat->SetLastInsertKey((USHORT) (nNewKey - nCLOffset)); + } + if (nNewKey != nOldKey) // neuer Index + { + pNewIndex = new sal_uInt32(nNewKey); + if (!pMergeTable->Insert(nOldKey,pNewIndex)) + delete pNewIndex; + } + } + pFormat = rTable.aFTable.Next(); + } + return pMergeTable; +} + + +SvNumberFormatterMergeMap SvNumberFormatter::ConvertMergeTableToMap() +{ + if (!HasMergeFmtTbl()) + return SvNumberFormatterMergeMap(); + + SvNumberFormatterMergeMap aMap; + for (sal_uInt32* pIndex = pMergeTable->First(); pIndex; pIndex = pMergeTable->Next()) + { + sal_uInt32 nOldKey = pMergeTable->GetCurKey(); + aMap.insert( SvNumberFormatterMergeMap::value_type( nOldKey, *pIndex)); + } + ClearMergeTable(); + return aMap; +} + + +sal_uInt32 SvNumberFormatter::GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat, + LanguageType eLnge ) +{ + if ( eLnge == LANGUAGE_DONTKNOW ) + eLnge = IniLnge; + if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLnge == IniLnge ) + return nFormat; // es bleibt wie es ist + sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex + if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE ) + return nFormat; // kein eingebautes Format + sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // ggbf. generieren + return nCLOffset + nOffset; +} + + +sal_uInt32 SvNumberFormatter::GetFormatIndex( NfIndexTableOffset nTabOff, + LanguageType eLnge ) +{ + if ( nTabOff >= NF_INDEX_TABLE_ENTRIES + || theIndexTable[nTabOff] == NUMBERFORMAT_ENTRY_NOT_FOUND ) + return NUMBERFORMAT_ENTRY_NOT_FOUND; + if ( eLnge == LANGUAGE_DONTKNOW ) + eLnge = IniLnge; + sal_uInt32 nCLOffset = ImpGenerateCL(eLnge); // ggbf. generieren + return nCLOffset + theIndexTable[nTabOff]; +} + + +NfIndexTableOffset SvNumberFormatter::GetIndexTableOffset( sal_uInt32 nFormat ) const +{ + sal_uInt32 nOffset = nFormat % SV_COUNTRY_LANGUAGE_OFFSET; // relativIndex + if ( nOffset > SV_MAX_ANZ_STANDARD_FORMATE ) + return NF_INDEX_TABLE_ENTRIES; // kein eingebautes Format + for ( USHORT j = 0; j < NF_INDEX_TABLE_ENTRIES; j++ ) + { + if ( theIndexTable[j] == nOffset ) + return (NfIndexTableOffset) j; + } + return NF_INDEX_TABLE_ENTRIES; // bad luck +} + + +void SvNumberFormatter::SetYear2000( USHORT nVal ) +{ + pStringScanner->SetYear2000( nVal ); +} + + +USHORT SvNumberFormatter::GetYear2000() const +{ + return pStringScanner->GetYear2000(); +} + + +USHORT SvNumberFormatter::ExpandTwoDigitYear( USHORT nYear ) const +{ + if ( nYear < 100 ) + return SvNumberFormatter::ExpandTwoDigitYear( nYear, + pStringScanner->GetYear2000() ); + return nYear; +} + + +// static +USHORT SvNumberFormatter::GetYear2000Default() +{ + return (USHORT) ::utl::MiscCfg().GetYear2000(); +} + + +// static +const NfCurrencyTable& SvNumberFormatter::GetTheCurrencyTable() +{ + ::osl::MutexGuard aGuard( GetMutex() ); + while ( !bCurrencyTableInitialized ) + ImpInitCurrencyTable(); + return theCurrencyTable::get(); +} + + +// static +const NfCurrencyEntry* SvNumberFormatter::MatchSystemCurrency() +{ + // MUST call GetTheCurrencyTable() before accessing nSystemCurrencyPosition + const NfCurrencyTable& rTable = GetTheCurrencyTable(); + return nSystemCurrencyPosition ? rTable[nSystemCurrencyPosition] : NULL; +} + + +// static +const NfCurrencyEntry& SvNumberFormatter::GetCurrencyEntry( LanguageType eLang ) +{ + if ( eLang == LANGUAGE_SYSTEM ) + { + const NfCurrencyEntry* pCurr = MatchSystemCurrency(); + return pCurr ? *pCurr : *(GetTheCurrencyTable()[0]); + } + else + { + eLang = MsLangId::getRealLanguage( eLang ); + const NfCurrencyTable& rTable = GetTheCurrencyTable(); + USHORT nCount = rTable.Count(); + const NfCurrencyEntryPtr* ppData = rTable.GetData(); + for ( USHORT j = 0; j < nCount; j++, ppData++ ) + { + if ( (*ppData)->GetLanguage() == eLang ) + return **ppData; + } + return *(rTable[0]); + } +} + + +// static +const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( + const String& rAbbrev, LanguageType eLang ) +{ + eLang = MsLangId::getRealLanguage( eLang ); + const NfCurrencyTable& rTable = GetTheCurrencyTable(); + USHORT nCount = rTable.Count(); + const NfCurrencyEntryPtr* ppData = rTable.GetData(); + for ( USHORT j = 0; j < nCount; j++, ppData++ ) + { + if ( (*ppData)->GetLanguage() == eLang && + (*ppData)->GetBankSymbol() == rAbbrev ) + return *ppData; + } + return NULL; +} + + +// static +const NfCurrencyEntry* SvNumberFormatter::GetLegacyOnlyCurrencyEntry( + const String& rSymbol, const String& rAbbrev ) +{ + if (!bCurrencyTableInitialized) + GetTheCurrencyTable(); // just for initialization + const NfCurrencyTable& rTable = theLegacyOnlyCurrencyTable::get(); + USHORT nCount = rTable.Count(); + const NfCurrencyEntryPtr* ppData = rTable.GetData(); + for ( USHORT j = 0; j < nCount; j++, ppData++ ) + { + if ( (*ppData)->GetSymbol() == rSymbol && + (*ppData)->GetBankSymbol() == rAbbrev ) + return *ppData; + } + return NULL; +} + + +// static +IMPL_STATIC_LINK_NOINSTANCE( SvNumberFormatter, CurrencyChangeLink, void*, EMPTYARG ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + String aAbbrev; + LanguageType eLang = LANGUAGE_SYSTEM; + SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( aAbbrev, eLang ); + SetDefaultSystemCurrency( aAbbrev, eLang ); + return 0; +} + + +// static +void SvNumberFormatter::SetDefaultSystemCurrency( const String& rAbbrev, LanguageType eLang ) +{ + ::osl::MutexGuard aGuard( GetMutex() ); + if ( eLang == LANGUAGE_SYSTEM ) + eLang = SvtSysLocale().GetLanguage(); + const NfCurrencyTable& rTable = GetTheCurrencyTable(); + USHORT nCount = rTable.Count(); + const NfCurrencyEntryPtr* ppData = rTable.GetData(); + if ( rAbbrev.Len() ) + { + for ( USHORT j = 0; j < nCount; j++, ppData++ ) + { + if ( (*ppData)->GetLanguage() == eLang && (*ppData)->GetBankSymbol() == rAbbrev ) + { + nSystemCurrencyPosition = j; + return ; + } + } + } + else + { + for ( USHORT j = 0; j < nCount; j++, ppData++ ) + { + if ( (*ppData)->GetLanguage() == eLang ) + { + nSystemCurrencyPosition = j; + return ; + } + } + } + nSystemCurrencyPosition = 0; // not found => simple SYSTEM +} + + +void SvNumberFormatter::ResetDefaultSystemCurrency() +{ + nDefaultSystemCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND; +} + + +sal_uInt32 SvNumberFormatter::ImpGetDefaultSystemCurrencyFormat() +{ + if ( nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + xub_StrLen nCheck; + short nType; + NfWSStringsDtor aCurrList; + USHORT nDefault = GetCurrencyFormatStrings( aCurrList, + GetCurrencyEntry( LANGUAGE_SYSTEM ), FALSE ); + DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency System standard format?!?" ); + // if already loaded or user defined nDefaultSystemCurrencyFormat + // will be set to the right value + PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType, + nDefaultSystemCurrencyFormat, LANGUAGE_SYSTEM ); + DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" ); + DBG_ASSERT( nDefaultSystemCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND, + "nDefaultSystemCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" ); + } + return nDefaultSystemCurrencyFormat; +} + + +sal_uInt32 SvNumberFormatter::ImpGetDefaultCurrencyFormat() +{ + sal_uInt32 CLOffset = ImpGetCLOffset( ActLnge ); + sal_uInt32 nDefaultCurrencyFormat = + (sal_uInt32)(sal_uIntPtr) aDefaultFormatKeys.Get( CLOffset + ZF_STANDARD_CURRENCY ); + if ( !nDefaultCurrencyFormat ) + nDefaultCurrencyFormat = NUMBERFORMAT_ENTRY_NOT_FOUND; + if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + // look for a defined standard + sal_uInt32 nStopKey = CLOffset + SV_COUNTRY_LANGUAGE_OFFSET; + sal_uInt32 nKey; + aFTable.Seek( CLOffset ); + while ( (nKey = aFTable.GetCurKey()) >= CLOffset && nKey < nStopKey ) + { + const SvNumberformat* pEntry = + (const SvNumberformat*) aFTable.GetCurObject(); + if ( pEntry->IsStandard() && (pEntry->GetType() & NUMBERFORMAT_CURRENCY) ) + { + nDefaultCurrencyFormat = nKey; + break; // while + } + aFTable.Next(); + } + + if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { // none found, create one + xub_StrLen nCheck; + short nType; + NfWSStringsDtor aCurrList; + USHORT nDefault = GetCurrencyFormatStrings( aCurrList, + GetCurrencyEntry( ActLnge ), FALSE ); + DBG_ASSERT( aCurrList.Count(), "where is the NewCurrency standard format?" ); + if ( aCurrList.Count() ) + { + // if already loaded or user defined nDefaultSystemCurrencyFormat + // will be set to the right value + PutEntry( *aCurrList.GetObject( nDefault ), nCheck, nType, + nDefaultCurrencyFormat, ActLnge ); + DBG_ASSERT( nCheck == 0, "NewCurrency CheckError" ); + DBG_ASSERT( nDefaultCurrencyFormat != NUMBERFORMAT_ENTRY_NOT_FOUND, + "nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND" ); + } + // old automatic currency format as a last resort + if ( nDefaultCurrencyFormat == NUMBERFORMAT_ENTRY_NOT_FOUND ) + nDefaultCurrencyFormat = CLOffset + ZF_STANDARD_CURRENCY+3; + else + { // mark as standard so that it is found next time + SvNumberformat* pEntry = aFTable.Get( nDefaultCurrencyFormat ); + if ( pEntry ) + pEntry->SetStandard(); + } + } + aDefaultFormatKeys.Insert( CLOffset + ZF_STANDARD_CURRENCY, + (void*) nDefaultCurrencyFormat ); + } + return nDefaultCurrencyFormat; +} + + +// static +// try to make it inline if possible since this a loop body +// TRUE: continue; FALSE: break loop, if pFoundEntry==NULL dupe found +#ifndef DBG_UTIL +inline +#endif + BOOL SvNumberFormatter::ImpLookupCurrencyEntryLoopBody( + const NfCurrencyEntry*& pFoundEntry, BOOL& bFoundBank, + const NfCurrencyEntry* pData, USHORT nPos, const String& rSymbol ) +{ + BOOL bFound; + if ( pData->GetSymbol() == rSymbol ) + { + bFound = TRUE; + bFoundBank = FALSE; + } + else if ( pData->GetBankSymbol() == rSymbol ) + { + bFound = TRUE; + bFoundBank = TRUE; + } + else + bFound = FALSE; + if ( bFound ) + { + if ( pFoundEntry && pFoundEntry != pData ) + { + pFoundEntry = NULL; + return FALSE; // break loop, not unique + } + if ( nPos == 0 ) + { // first entry is SYSTEM + pFoundEntry = MatchSystemCurrency(); + if ( pFoundEntry ) + return FALSE; // break loop + // even if there are more matching entries + // this one is propably the one we are looking for + else + pFoundEntry = pData; + } + else + pFoundEntry = pData; + } + return TRUE; +} + + +BOOL SvNumberFormatter::GetNewCurrencySymbolString( sal_uInt32 nFormat, + String& rStr, const NfCurrencyEntry** ppEntry /* = NULL */, + BOOL* pBank /* = NULL */ ) const +{ + rStr.Erase(); + if ( ppEntry ) + *ppEntry = NULL; + if ( pBank ) + *pBank = FALSE; + SvNumberformat* pFormat = (SvNumberformat*) aFTable.Get( nFormat ); + if ( pFormat ) + { + String aSymbol, aExtension; + if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) ) + { + if ( ppEntry ) + { + BOOL bFoundBank = FALSE; + // we definiteley need an entry matching the format code string + const NfCurrencyEntry* pFoundEntry = GetCurrencyEntry( + bFoundBank, aSymbol, aExtension, pFormat->GetLanguage(), + TRUE ); + if ( pFoundEntry ) + { + *ppEntry = pFoundEntry; + if ( pBank ) + *pBank = bFoundBank; + pFoundEntry->BuildSymbolString( rStr, bFoundBank ); + } + } + if ( !rStr.Len() ) + { // analog zu BuildSymbolString + rStr = '['; + rStr += '$'; + if ( aSymbol.Search( '-' ) != STRING_NOTFOUND || + aSymbol.Search( ']' ) != STRING_NOTFOUND ) + { + rStr += '"'; + rStr += aSymbol; + rStr += '"'; + } + else + rStr += aSymbol; + if ( aExtension.Len() ) + rStr += aExtension; + rStr += ']'; + } + return TRUE; + } + } + return FALSE; +} + + +// static +const NfCurrencyEntry* SvNumberFormatter::GetCurrencyEntry( BOOL & bFoundBank, + const String& rSymbol, const String& rExtension, + LanguageType eFormatLanguage, BOOL bOnlyStringLanguage ) +{ + xub_StrLen nExtLen = rExtension.Len(); + LanguageType eExtLang; + if ( nExtLen ) + { + sal_Int32 nExtLang = ::rtl::OUString( rExtension ).toInt32( 16 ); + if ( !nExtLang ) + eExtLang = LANGUAGE_DONTKNOW; + else + eExtLang = (LanguageType) ((nExtLang < 0) ? + -nExtLang : nExtLang); + } + else + eExtLang = LANGUAGE_DONTKNOW; + const NfCurrencyEntry* pFoundEntry = NULL; + const NfCurrencyTable& rTable = GetTheCurrencyTable(); + USHORT nCount = rTable.Count(); + BOOL bCont = TRUE; + + // first try with given extension language/country + if ( nExtLen ) + { + const NfCurrencyEntryPtr* ppData = rTable.GetData(); + for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ ) + { + LanguageType eLang = (*ppData)->GetLanguage(); + if ( eLang == eExtLang || + ((eExtLang == LANGUAGE_DONTKNOW) && + (eLang == LANGUAGE_SYSTEM)) + ) + { + bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank, + *ppData, j, rSymbol ); + } + } + } + + // ok? + if ( pFoundEntry || !bCont || (bOnlyStringLanguage && nExtLen) ) + return pFoundEntry; + + if ( !bOnlyStringLanguage ) + { + // now try the language/country of the number format + const NfCurrencyEntryPtr* ppData = rTable.GetData(); + for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ ) + { + LanguageType eLang = (*ppData)->GetLanguage(); + if ( eLang == eFormatLanguage || + ((eFormatLanguage == LANGUAGE_DONTKNOW) && + (eLang == LANGUAGE_SYSTEM)) + ) + { + bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank, + *ppData, j, rSymbol ); + } + } + + // ok? + if ( pFoundEntry || !bCont ) + return pFoundEntry; + } + + // then try without language/country if no extension specified + if ( !nExtLen ) + { + const NfCurrencyEntryPtr* ppData = rTable.GetData(); + for ( USHORT j = 0; j < nCount && bCont; j++, ppData++ ) + { + bCont = ImpLookupCurrencyEntryLoopBody( pFoundEntry, bFoundBank, + *ppData, j, rSymbol ); + } + } + + return pFoundEntry; +} + + +void SvNumberFormatter::GetCompatibilityCurrency( String& rSymbol, String& rAbbrev ) const +{ + ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::Currency2 > + xCurrencies = xLocaleData->getAllCurrencies(); + sal_Int32 nCurrencies = xCurrencies.getLength(); + sal_Int32 j; + for ( j=0; j < nCurrencies; ++j ) + { + if ( xCurrencies[j].UsedInCompatibleFormatCodes ) + { + rSymbol = xCurrencies[j].Symbol; + rAbbrev = xCurrencies[j].BankSymbol; + break; + } + } + if ( j >= nCurrencies ) + { + if (LocaleDataWrapper::areChecksEnabled()) + { + String aMsg( RTL_CONSTASCII_USTRINGPARAM( + "GetCompatibilityCurrency: none?")); + LocaleDataWrapper::outputCheckMessage( + xLocaleData->appendLocaleInfo( aMsg)); + } + rSymbol = xLocaleData->getCurrSymbol(); + rAbbrev = xLocaleData->getCurrBankSymbol(); + } +} + + +void lcl_CheckCurrencySymbolPosition( const NfCurrencyEntry& rCurr ) +{ + short nPos = -1; // -1:=unknown, 0:=vorne, 1:=hinten + short nNeg = -1; + switch ( rCurr.GetPositiveFormat() ) + { + case 0: // $1 + nPos = 0; + break; + case 1: // 1$ + nPos = 1; + break; + case 2: // $ 1 + nPos = 0; + break; + case 3: // 1 $ + nPos = 1; + break; + default: + LocaleDataWrapper::outputCheckMessage( + "lcl_CheckCurrencySymbolPosition: unknown PositiveFormat"); + break; + } + switch ( rCurr.GetNegativeFormat() ) + { + case 0: // ($1) + nNeg = 0; + break; + case 1: // -$1 + nNeg = 0; + break; + case 2: // $-1 + nNeg = 0; + break; + case 3: // $1- + nNeg = 0; + break; + case 4: // (1$) + nNeg = 1; + break; + case 5: // -1$ + nNeg = 1; + break; + case 6: // 1-$ + nNeg = 1; + break; + case 7: // 1$- + nNeg = 1; + break; + case 8: // -1 $ + nNeg = 1; + break; + case 9: // -$ 1 + nNeg = 0; + break; + case 10: // 1 $- + nNeg = 1; + break; + case 11: // $ -1 + nNeg = 0; + break; + case 12 : // $ 1- + nNeg = 0; + break; + case 13 : // 1- $ + nNeg = 1; + break; + case 14 : // ($ 1) + nNeg = 0; + break; + case 15 : // (1 $) + nNeg = 1; + break; + default: + LocaleDataWrapper::outputCheckMessage( + "lcl_CheckCurrencySymbolPosition: unknown NegativeFormat"); + break; + } + if ( nPos >= 0 && nNeg >= 0 && nPos != nNeg ) + { + ByteString aStr( "positions of currency symbols differ\nLanguage: " ); + aStr += ByteString::CreateFromInt32( rCurr.GetLanguage() ); + aStr += " <"; + aStr += ByteString( rCurr.GetSymbol(), RTL_TEXTENCODING_UTF8 ); + aStr += "> positive: "; + aStr += ByteString::CreateFromInt32( rCurr.GetPositiveFormat() ); + aStr += ( nPos ? " (postfix)" : " (prefix)" ); + aStr += ", negative: "; + aStr += ByteString::CreateFromInt32( rCurr.GetNegativeFormat() ); + aStr += ( nNeg ? " (postfix)" : " (prefix)" ); +#if 0 +// seems that there really are some currencies which differ, e.g. YugoDinar + DBG_ERRORFILE( aStr.GetBuffer() ); +#endif + } +} + + +// static +void SvNumberFormatter::ImpInitCurrencyTable() +{ + // racing condition possible: + // ::osl::MutexGuard aGuard( GetMutex() ); + // while ( !bCurrencyTableInitialized ) + // ImpInitCurrencyTable(); + static BOOL bInitializing = FALSE; + if ( bCurrencyTableInitialized || bInitializing ) + return ; + bInitializing = TRUE; + + RTL_LOGFILE_CONTEXT_AUTHOR( aTimeLog, "svl", "er93726", "SvNumberFormatter::ImpInitCurrencyTable" ); + + LanguageType eSysLang = SvtSysLocale().GetLanguage(); + LocaleDataWrapper* pLocaleData = new LocaleDataWrapper( + ::comphelper::getProcessServiceFactory(), + MsLangId::convertLanguageToLocale( eSysLang ) ); + // get user configured currency + String aConfiguredCurrencyAbbrev; + LanguageType eConfiguredCurrencyLanguage = LANGUAGE_SYSTEM; + SvtSysLocaleOptions().GetCurrencyAbbrevAndLanguage( + aConfiguredCurrencyAbbrev, eConfiguredCurrencyLanguage ); + USHORT nSecondarySystemCurrencyPosition = 0; + USHORT nMatchingSystemCurrencyPosition = 0; + NfCurrencyEntryPtr pEntry; + + // first entry is SYSTEM + pEntry = new NfCurrencyEntry( *pLocaleData, LANGUAGE_SYSTEM ); + theCurrencyTable::get().Insert( pEntry, 0 ); + USHORT nCurrencyPos = 1; + + ::com::sun::star::uno::Sequence< ::com::sun::star::lang::Locale > xLoc = + LocaleDataWrapper::getInstalledLocaleNames(); + sal_Int32 nLocaleCount = xLoc.getLength(); + RTL_LOGFILE_CONTEXT_TRACE1( aTimeLog, "number of locales: %ld", nLocaleCount ); + Locale const * const pLocales = xLoc.getConstArray(); + NfCurrencyTable &rCurrencyTable = theCurrencyTable::get(); + NfCurrencyTable &rLegacyOnlyCurrencyTable = theLegacyOnlyCurrencyTable::get(); + USHORT nLegacyOnlyCurrencyPos = 0; + for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ ) + { + LanguageType eLang = MsLangId::convertLocaleToLanguage( + pLocales[nLocale]); +#if OSL_DEBUG_LEVEL > 1 + LanguageType eReal = MsLangId::getRealLanguage( eLang ); + if ( eReal != eLang ) { + BOOL bBreak; + bBreak = TRUE; + } +#endif + pLocaleData->setLocale( pLocales[nLocale] ); + Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies(); + sal_Int32 nCurrencyCount = aCurrSeq.getLength(); + Currency2 const * const pCurrencies = aCurrSeq.getConstArray(); + + // one default currency for each locale, insert first so it is found first + sal_Int32 nDefault; + for ( nDefault = 0; nDefault < nCurrencyCount; nDefault++ ) + { + if ( pCurrencies[nDefault].Default ) + break; + } + if ( nDefault < nCurrencyCount ) + pEntry = new NfCurrencyEntry( pCurrencies[nDefault], *pLocaleData, eLang ); + else + pEntry = new NfCurrencyEntry( *pLocaleData, eLang ); // first or ShellsAndPebbles + + if (LocaleDataWrapper::areChecksEnabled()) + lcl_CheckCurrencySymbolPosition( *pEntry ); + + rCurrencyTable.Insert( pEntry, nCurrencyPos++ ); + if ( !nSystemCurrencyPosition && (aConfiguredCurrencyAbbrev.Len() ? + pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev && + pEntry->GetLanguage() == eConfiguredCurrencyLanguage : FALSE) ) + nSystemCurrencyPosition = nCurrencyPos-1; + if ( !nMatchingSystemCurrencyPosition && + pEntry->GetLanguage() == eSysLang ) + nMatchingSystemCurrencyPosition = nCurrencyPos-1; + + // all remaining currencies for each locale + if ( nCurrencyCount > 1 ) + { + sal_Int32 nCurrency; + for ( nCurrency = 0; nCurrency < nCurrencyCount; nCurrency++ ) + { + if (pCurrencies[nCurrency].LegacyOnly) + { + pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang ); + rLegacyOnlyCurrencyTable.Insert( pEntry, nLegacyOnlyCurrencyPos++ ); + } + else if ( nCurrency != nDefault ) + { + pEntry = new NfCurrencyEntry( pCurrencies[nCurrency], *pLocaleData, eLang ); + // no dupes + BOOL bInsert = TRUE; + NfCurrencyEntry const * const * pData = rCurrencyTable.GetData(); + USHORT n = rCurrencyTable.Count(); + pData++; // skip first SYSTEM entry + for ( USHORT j=1; j<n; j++ ) + { + if ( *(*pData++) == *pEntry ) + { + bInsert = FALSE; + break; // for + } + } + if ( !bInsert ) + delete pEntry; + else + { + rCurrencyTable.Insert( pEntry, nCurrencyPos++ ); + if ( !nSecondarySystemCurrencyPosition && + (aConfiguredCurrencyAbbrev.Len() ? + pEntry->GetBankSymbol() == aConfiguredCurrencyAbbrev : + pEntry->GetLanguage() == eConfiguredCurrencyLanguage) ) + nSecondarySystemCurrencyPosition = nCurrencyPos-1; + if ( !nMatchingSystemCurrencyPosition && + pEntry->GetLanguage() == eSysLang ) + nMatchingSystemCurrencyPosition = nCurrencyPos-1; + } + } + } + } + } + if ( !nSystemCurrencyPosition ) + nSystemCurrencyPosition = nSecondarySystemCurrencyPosition; + if ((aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) && + LocaleDataWrapper::areChecksEnabled()) + LocaleDataWrapper::outputCheckMessage( + "SvNumberFormatter::ImpInitCurrencyTable: configured currency not in I18N locale data."); + // match SYSTEM if no configured currency found + if ( !nSystemCurrencyPosition ) + nSystemCurrencyPosition = nMatchingSystemCurrencyPosition; + if ((!aConfiguredCurrencyAbbrev.Len() && !nSystemCurrencyPosition) && + LocaleDataWrapper::areChecksEnabled()) + LocaleDataWrapper::outputCheckMessage( + "SvNumberFormatter::ImpInitCurrencyTable: system currency not in I18N locale data."); + delete pLocaleData; + SvtSysLocaleOptions::SetCurrencyChangeLink( + STATIC_LINK( NULL, SvNumberFormatter, CurrencyChangeLink ) ); + bInitializing = FALSE; + bCurrencyTableInitialized = TRUE; +} + + +USHORT SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr, + const NfCurrencyEntry& rCurr, BOOL bBank ) const +{ + USHORT nDefault = 0; + if ( bBank ) + { // nur Bankensymbole + String aPositiveBank, aNegativeBank; + rCurr.BuildPositiveFormatString( aPositiveBank, TRUE, *xLocaleData, 1 ); + rCurr.BuildNegativeFormatString( aNegativeBank, TRUE, *xLocaleData, 1 ); + + WSStringPtr pFormat1 = new String( aPositiveBank ); + *pFormat1 += ';'; + WSStringPtr pFormat2 = new String( *pFormat1 ); + + String aRed( '[' ); + aRed += pFormatScanner->GetRedString(); + aRed += ']'; + + *pFormat2 += aRed; + + *pFormat1 += aNegativeBank; + *pFormat2 += aNegativeBank; + + rStrArr.Insert( pFormat1, rStrArr.Count() ); + rStrArr.Insert( pFormat2, rStrArr.Count() ); + nDefault = rStrArr.Count() - 1; + } + else + { // gemischte Formate wie in SvNumberFormatter::ImpGenerateFormats + // aber keine doppelten, wenn keine Nachkommastellen in Waehrung + String aPositive, aNegative, aPositiveNoDec, aNegativeNoDec, + aPositiveDashed, aNegativeDashed; + WSStringPtr pFormat1, pFormat2, pFormat3, pFormat4, pFormat5; + + String aRed( '[' ); + aRed += pFormatScanner->GetRedString(); + aRed += ']'; + + rCurr.BuildPositiveFormatString( aPositive, FALSE, *xLocaleData, 1 ); + rCurr.BuildNegativeFormatString( aNegative, FALSE, *xLocaleData, 1 ); + if ( rCurr.GetDigits() ) + { + rCurr.BuildPositiveFormatString( aPositiveNoDec, FALSE, *xLocaleData, 0 ); + rCurr.BuildNegativeFormatString( aNegativeNoDec, FALSE, *xLocaleData, 0 ); + rCurr.BuildPositiveFormatString( aPositiveDashed, FALSE, *xLocaleData, 2 ); + rCurr.BuildNegativeFormatString( aNegativeDashed, FALSE, *xLocaleData, 2 ); + + pFormat1 = new String( aPositiveNoDec ); + *pFormat1 += ';'; + pFormat3 = new String( *pFormat1 ); + pFormat5 = new String( aPositiveDashed ); + *pFormat5 += ';'; + + *pFormat1 += aNegativeNoDec; + + *pFormat3 += aRed; + *pFormat5 += aRed; + + *pFormat3 += aNegativeNoDec; + *pFormat5 += aNegativeDashed; + } + else + { + pFormat1 = NULL; + pFormat3 = NULL; + pFormat5 = NULL; + } + + pFormat2 = new String( aPositive ); + *pFormat2 += ';'; + pFormat4 = new String( *pFormat2 ); + + *pFormat2 += aNegative; + + *pFormat4 += aRed; + *pFormat4 += aNegative; + + if ( pFormat1 ) + rStrArr.Insert( pFormat1, rStrArr.Count() ); + rStrArr.Insert( pFormat2, rStrArr.Count() ); + if ( pFormat3 ) + rStrArr.Insert( pFormat3, rStrArr.Count() ); + rStrArr.Insert( pFormat4, rStrArr.Count() ); + nDefault = rStrArr.Count() - 1; + if ( pFormat5 ) + rStrArr.Insert( pFormat5, rStrArr.Count() ); + } + return nDefault; +} + + +//--- NfCurrencyEntry ---------------------------------------------------- + +NfCurrencyEntry::NfCurrencyEntry() + : eLanguage( LANGUAGE_DONTKNOW ), + nPositiveFormat(3), + nNegativeFormat(8), + nDigits(2), + cZeroChar('0') +{ +} + + +NfCurrencyEntry::NfCurrencyEntry( const LocaleDataWrapper& rLocaleData, LanguageType eLang ) +{ + aSymbol = rLocaleData.getCurrSymbol(); + aBankSymbol = rLocaleData.getCurrBankSymbol(); + eLanguage = eLang; + nPositiveFormat = rLocaleData.getCurrPositiveFormat(); + nNegativeFormat = rLocaleData.getCurrNegativeFormat(); + nDigits = rLocaleData.getCurrDigits(); + cZeroChar = rLocaleData.getCurrZeroChar(); +} + + +NfCurrencyEntry::NfCurrencyEntry( const ::com::sun::star::i18n::Currency & rCurr, + const LocaleDataWrapper& rLocaleData, LanguageType eLang ) +{ + aSymbol = rCurr.Symbol; + aBankSymbol = rCurr.BankSymbol; + eLanguage = eLang; + nPositiveFormat = rLocaleData.getCurrPositiveFormat(); + nNegativeFormat = rLocaleData.getCurrNegativeFormat(); + nDigits = rCurr.DecimalPlaces; + cZeroChar = rLocaleData.getCurrZeroChar(); +} + + +BOOL NfCurrencyEntry::operator==( const NfCurrencyEntry& r ) const +{ + return aSymbol == r.aSymbol + && aBankSymbol == r.aBankSymbol + && eLanguage == r.eLanguage + ; +} + + +void NfCurrencyEntry::SetEuro() +{ + aSymbol = NfCurrencyEntry::GetEuroSymbol(); + aBankSymbol.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "EUR" ) ); + eLanguage = LANGUAGE_DONTKNOW; + nPositiveFormat = 3; + nNegativeFormat = 8; + nDigits = 2; + cZeroChar = '0'; +} + + +BOOL NfCurrencyEntry::IsEuro() const +{ + if ( aBankSymbol.EqualsAscii( "EUR" ) ) + return TRUE; + String aEuro( NfCurrencyEntry::GetEuroSymbol() ); + return aSymbol == aEuro; +} + + +void NfCurrencyEntry::ApplyVariableInformation( const NfCurrencyEntry& r ) +{ + nPositiveFormat = r.nPositiveFormat; + nNegativeFormat = r.nNegativeFormat; + cZeroChar = r.cZeroChar; +} + + +void NfCurrencyEntry::BuildSymbolString( String& rStr, BOOL bBank, + BOOL bWithoutExtension ) const +{ + rStr = '['; + rStr += '$'; + if ( bBank ) + rStr += aBankSymbol; + else + { + if ( aSymbol.Search( '-' ) != STRING_NOTFOUND || aSymbol.Search( ']' ) != STRING_NOTFOUND ) + { + rStr += '"'; + rStr += aSymbol; + rStr += '"'; + } + else + rStr += aSymbol; + if ( !bWithoutExtension && eLanguage != LANGUAGE_DONTKNOW && eLanguage != LANGUAGE_SYSTEM ) + { + rStr += '-'; + rStr += String::CreateFromInt32( sal_Int32( eLanguage ), 16 ).ToUpperAscii(); + } + } + rStr += ']'; +} + + +void NfCurrencyEntry::Impl_BuildFormatStringNumChars( String& rStr, + const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const +{ + rStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###0" ) ); + rStr.Insert( rLoc.getNumThousandSep(), 1 ); + if ( nDecimalFormat && nDigits ) + { + rStr += rLoc.getNumDecimalSep(); + rStr.Expand( rStr.Len() + nDigits, (nDecimalFormat == 2 ? '-' : cZeroChar) ); + } +} + + +void NfCurrencyEntry::BuildPositiveFormatString( String& rStr, BOOL bBank, + const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const +{ + Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat ); + USHORT nPosiForm = NfCurrencyEntry::GetEffectivePositiveFormat( + rLoc.getCurrPositiveFormat(), nPositiveFormat, bBank ); + CompletePositiveFormatString( rStr, bBank, nPosiForm ); +} + + +void NfCurrencyEntry::BuildNegativeFormatString( String& rStr, BOOL bBank, + const LocaleDataWrapper& rLoc, USHORT nDecimalFormat ) const +{ + Impl_BuildFormatStringNumChars( rStr, rLoc, nDecimalFormat ); + USHORT nNegaForm = NfCurrencyEntry::GetEffectiveNegativeFormat( + rLoc.getCurrNegativeFormat(), nNegativeFormat, bBank ); + CompleteNegativeFormatString( rStr, bBank, nNegaForm ); +} + + +void NfCurrencyEntry::CompletePositiveFormatString( String& rStr, BOOL bBank, + USHORT nPosiForm ) const +{ + String aSymStr; + BuildSymbolString( aSymStr, bBank ); + NfCurrencyEntry::CompletePositiveFormatString( rStr, aSymStr, nPosiForm ); +} + + +void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr, BOOL bBank, + USHORT nNegaForm ) const +{ + String aSymStr; + BuildSymbolString( aSymStr, bBank ); + NfCurrencyEntry::CompleteNegativeFormatString( rStr, aSymStr, nNegaForm ); +} + + +// static +void NfCurrencyEntry::CompletePositiveFormatString( String& rStr, + const String& rSymStr, USHORT nPositiveFormat ) +{ + switch( nPositiveFormat ) + { + case 0: // $1 + rStr.Insert( rSymStr , 0 ); + break; + case 1: // 1$ + rStr += rSymStr; + break; + case 2: // $ 1 + { + rStr.Insert( ' ', 0 ); + rStr.Insert( rSymStr, 0 ); + } + break; + case 3: // 1 $ + { + rStr += ' '; + rStr += rSymStr; + } + break; + default: + DBG_ERROR("NfCurrencyEntry::CompletePositiveFormatString: unknown option"); + break; + } +} + + +// static +void NfCurrencyEntry::CompleteNegativeFormatString( String& rStr, + const String& rSymStr, USHORT nNegativeFormat ) +{ + switch( nNegativeFormat ) + { + case 0: // ($1) + { + rStr.Insert( rSymStr, 0); + rStr.Insert('(',0); + rStr += ')'; + } + break; + case 1: // -$1 + { + rStr.Insert( rSymStr, 0); + rStr.Insert('-',0); + } + break; + case 2: // $-1 + { + rStr.Insert('-',0); + rStr.Insert( rSymStr, 0); + } + break; + case 3: // $1- + { + rStr.Insert( rSymStr, 0); + rStr += '-'; + } + break; + case 4: // (1$) + { + rStr.Insert('(',0); + rStr += rSymStr; + rStr += ')'; + } + break; + case 5: // -1$ + { + rStr += rSymStr; + rStr.Insert('-',0); + } + break; + case 6: // 1-$ + { + rStr += '-'; + rStr += rSymStr; + } + break; + case 7: // 1$- + { + rStr += rSymStr; + rStr += '-'; + } + break; + case 8: // -1 $ + { + rStr += ' '; + rStr += rSymStr; + rStr.Insert('-',0); + } + break; + case 9: // -$ 1 + { + rStr.Insert(' ',0); + rStr.Insert( rSymStr, 0); + rStr.Insert('-',0); + } + break; + case 10: // 1 $- + { + rStr += ' '; + rStr += rSymStr; + rStr += '-'; + } + break; + case 11: // $ -1 + { + String aTmp( rSymStr ); + aTmp += ' '; + aTmp += '-'; + rStr.Insert( aTmp, 0 ); + } + break; + case 12 : // $ 1- + { + rStr.Insert(' ', 0); + rStr.Insert( rSymStr, 0); + rStr += '-'; + } + break; + case 13 : // 1- $ + { + rStr += '-'; + rStr += ' '; + rStr += rSymStr; + } + break; + case 14 : // ($ 1) + { + rStr.Insert(' ',0); + rStr.Insert( rSymStr, 0); + rStr.Insert('(',0); + rStr += ')'; + } + break; + case 15 : // (1 $) + { + rStr.Insert('(',0); + rStr += ' '; + rStr += rSymStr; + rStr += ')'; + } + break; + default: + DBG_ERROR("NfCurrencyEntry::CompleteNegativeFormatString: unknown option"); + break; + } +} + + +// static +USHORT NfCurrencyEntry::GetEffectivePositiveFormat( USHORT +#if ! NF_BANKSYMBOL_FIX_POSITION + nIntlFormat +#endif + , USHORT nCurrFormat, BOOL bBank ) +{ + if ( bBank ) + { +#if NF_BANKSYMBOL_FIX_POSITION + return 3; +#else + switch ( nIntlFormat ) + { + case 0: // $1 + nIntlFormat = 2; // $ 1 + break; + case 1: // 1$ + nIntlFormat = 3; // 1 $ + break; + case 2: // $ 1 + break; + case 3: // 1 $ + break; + default: + DBG_ERROR("NfCurrencyEntry::GetEffectivePositiveFormat: unknown option"); + break; + } + return nIntlFormat; +#endif + } + else + return nCurrFormat; +} + + +// nur aufrufen, wenn nCurrFormat wirklich mit Klammern ist +USHORT lcl_MergeNegativeParenthesisFormat( USHORT nIntlFormat, USHORT nCurrFormat ) +{ + short nSign = 0; // -1:=Klammer 0:=links, 1:=mitte, 2:=rechts + switch ( nIntlFormat ) + { + case 0: // ($1) + case 4: // (1$) + case 14 : // ($ 1) + case 15 : // (1 $) + return nCurrFormat; + case 1: // -$1 + case 5: // -1$ + case 8: // -1 $ + case 9: // -$ 1 + nSign = 0; + break; + case 2: // $-1 + case 6: // 1-$ + case 11 : // $ -1 + case 13 : // 1- $ + nSign = 1; + break; + case 3: // $1- + case 7: // 1$- + case 10: // 1 $- + case 12 : // $ 1- + nSign = 2; + break; + default: + DBG_ERROR("lcl_MergeNegativeParenthesisFormat: unknown option"); + break; + } + + switch ( nCurrFormat ) + { + case 0: // ($1) + switch ( nSign ) + { + case 0: + return 1; // -$1 + case 1: + return 2; // $-1 + case 2: + return 3; // $1- + } + break; + case 4: // (1$) + switch ( nSign ) + { + case 0: + return 5; // -1$ + case 1: + return 6; // 1-$ + case 2: + return 7; // 1$- + } + break; + case 14 : // ($ 1) + switch ( nSign ) + { + case 0: + return 9; // -$ 1 + case 1: + return 11; // $ -1 + case 2: + return 12; // $ 1- + } + break; + case 15 : // (1 $) + switch ( nSign ) + { + case 0: + return 8; // -1 $ + case 1: + return 13; // 1- $ + case 2: + return 10; // 1 $- + } + break; + } + return nCurrFormat; +} + + +// static +USHORT NfCurrencyEntry::GetEffectiveNegativeFormat( USHORT nIntlFormat, + USHORT nCurrFormat, BOOL bBank ) +{ + if ( bBank ) + { +#if NF_BANKSYMBOL_FIX_POSITION + return 8; +#else + switch ( nIntlFormat ) + { + case 0: // ($1) +// nIntlFormat = 14; // ($ 1) + nIntlFormat = 9; // -$ 1 + break; + case 1: // -$1 + nIntlFormat = 9; // -$ 1 + break; + case 2: // $-1 + nIntlFormat = 11; // $ -1 + break; + case 3: // $1- + nIntlFormat = 12; // $ 1- + break; + case 4: // (1$) +// nIntlFormat = 15; // (1 $) + nIntlFormat = 8; // -1 $ + break; + case 5: // -1$ + nIntlFormat = 8; // -1 $ + break; + case 6: // 1-$ + nIntlFormat = 13; // 1- $ + break; + case 7: // 1$- + nIntlFormat = 10; // 1 $- + break; + case 8: // -1 $ + break; + case 9: // -$ 1 + break; + case 10: // 1 $- + break; + case 11: // $ -1 + break; + case 12 : // $ 1- + break; + case 13 : // 1- $ + break; + case 14 : // ($ 1) +// nIntlFormat = 14; // ($ 1) + nIntlFormat = 9; // -$ 1 + break; + case 15 : // (1 $) +// nIntlFormat = 15; // (1 $) + nIntlFormat = 8; // -1 $ + break; + default: + DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option"); + break; + } +#endif + } + else if ( nIntlFormat != nCurrFormat ) + { + switch ( nCurrFormat ) + { + case 0: // ($1) + nIntlFormat = lcl_MergeNegativeParenthesisFormat( + nIntlFormat, nCurrFormat ); + break; + case 1: // -$1 + nIntlFormat = nCurrFormat; + break; + case 2: // $-1 + nIntlFormat = nCurrFormat; + break; + case 3: // $1- + nIntlFormat = nCurrFormat; + break; + case 4: // (1$) + nIntlFormat = lcl_MergeNegativeParenthesisFormat( + nIntlFormat, nCurrFormat ); + break; + case 5: // -1$ + nIntlFormat = nCurrFormat; + break; + case 6: // 1-$ + nIntlFormat = nCurrFormat; + break; + case 7: // 1$- + nIntlFormat = nCurrFormat; + break; + case 8: // -1 $ + nIntlFormat = nCurrFormat; + break; + case 9: // -$ 1 + nIntlFormat = nCurrFormat; + break; + case 10: // 1 $- + nIntlFormat = nCurrFormat; + break; + case 11: // $ -1 + nIntlFormat = nCurrFormat; + break; + case 12 : // $ 1- + nIntlFormat = nCurrFormat; + break; + case 13 : // 1- $ + nIntlFormat = nCurrFormat; + break; + case 14 : // ($ 1) + nIntlFormat = lcl_MergeNegativeParenthesisFormat( + nIntlFormat, nCurrFormat ); + break; + case 15 : // (1 $) + nIntlFormat = lcl_MergeNegativeParenthesisFormat( + nIntlFormat, nCurrFormat ); + break; + default: + DBG_ERROR("NfCurrencyEntry::GetEffectiveNegativeFormat: unknown option"); + break; + } + } + return nIntlFormat; +} + + +// we only support default encodings here +// static +sal_Char NfCurrencyEntry::GetEuroSymbol( rtl_TextEncoding eTextEncoding ) +{ + switch ( eTextEncoding ) + { + case RTL_TEXTENCODING_MS_1252 : // WNT Ansi + case RTL_TEXTENCODING_ISO_8859_1 : // UNX for use with TrueType fonts + return '\x80'; + case RTL_TEXTENCODING_ISO_8859_15 : // UNX real + return '\xA4'; + case RTL_TEXTENCODING_IBM_850 : // OS2 + return '\xD5'; + case RTL_TEXTENCODING_APPLE_ROMAN : // MAC + return '\xDB'; + default: // default system +#if WNT + return '\x80'; +#elif OS2 + return '\xD5'; +#elif UNX +// return '\xA4'; // #56121# 0xA4 waere korrekt fuer iso-8859-15 + return '\x80'; // aber Windoze-Code fuer die konvertierten TrueType-Fonts +#else +#error EuroSymbol is what? + return '\x80'; +#endif + } + return '\x80'; +} + + + |