summaryrefslogtreecommitdiff
path: root/svl/source/numbers
diff options
context:
space:
mode:
authorthb <thb@openoffice.org>2010-01-18 01:10:42 +0100
committerthb <thb@openoffice.org>2010-01-18 01:10:42 +0100
commitea48c18b848fed4d6504c956adeb3f24f05938ca (patch)
tree1eccf884707ec16e4dd74f8e83c74563e1539b34 /svl/source/numbers
parent1737f4d2fdba50a590f76631cd7ca7e762d18c35 (diff)
parent8765a3bf9f2926a50d0f644e4263782269abe023 (diff)
thbfixes10: merge with DEV300 m69
Diffstat (limited to 'svl/source/numbers')
-rw-r--r--svl/source/numbers/makefile.mk78
-rw-r--r--svl/source/numbers/nbdll.cxx82
-rw-r--r--svl/source/numbers/numfmuno.cxx1143
-rw-r--r--svl/source/numbers/numfmuno.hxx324
-rw-r--r--svl/source/numbers/numhead.cxx252
-rw-r--r--svl/source/numbers/numhead.hxx109
-rw-r--r--svl/source/numbers/numuno.cxx170
-rw-r--r--svl/source/numbers/supservs.cxx232
-rw-r--r--svl/source/numbers/supservs.hxx105
-rw-r--r--svl/source/numbers/zforfind.cxx2819
-rw-r--r--svl/source/numbers/zforfind.hxx291
-rw-r--r--svl/source/numbers/zforlist.cxx4348
-rw-r--r--svl/source/numbers/zformat.cxx4480
-rw-r--r--svl/source/numbers/zforscan.cxx2812
-rw-r--r--svl/source/numbers/zforscan.hxx278
15 files changed, 17523 insertions, 0 deletions
diff --git a/svl/source/numbers/makefile.mk b/svl/source/numbers/makefile.mk
new file mode 100644
index 000000000000..db4b30070ce8
--- /dev/null
+++ b/svl/source/numbers/makefile.mk
@@ -0,0 +1,78 @@
+#*************************************************************************
+#
+# 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: makefile.mk,v $
+#
+# $Revision: 1.12.148.1 $
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+PRJNAME=svl
+TARGET=numbers
+LIBTARGET=NO
+
+PROJECTPCH=
+PROJECTPCHSOURCE=
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/svl.pmk
+
+# --- Files --------------------------------------------------------
+
+EXCEPTIONSFILES= \
+ $(SLO)$/numuno.obj \
+ $(SLO)$/numfmuno.obj \
+ $(SLO)$/supservs.obj \
+ $(SLO)$/zforlist.obj
+
+SLOFILES = \
+ $(EXCEPTIONSFILES) \
+ $(SLO)$/zforfind.obj \
+ $(SLO)$/zformat.obj \
+ $(SLO)$/zforscan.obj \
+ $(SLO)$/numhead.obj
+
+LIB1TARGET= $(SLB)$/$(TARGET).uno.lib
+LIB1OBJFILES= \
+ $(SLO)$/numfmuno.obj \
+ $(SLO)$/supservs.obj
+
+LIB2TARGET= $(SLB)$/$(TARGET).lib
+LIB2OBJFILES= \
+ $(SLO)$/zforfind.obj \
+ $(SLO)$/zforlist.obj \
+ $(SLO)$/zformat.obj \
+ $(SLO)$/zforscan.obj \
+ $(SLO)$/numuno.obj \
+ $(SLO)$/numhead.obj
+
+# --- Targets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/svl/source/numbers/nbdll.cxx b/svl/source/numbers/nbdll.cxx
new file mode 100644
index 000000000000..2bc5121e18fd
--- /dev/null
+++ b/svl/source/numbers/nbdll.cxx
@@ -0,0 +1,82 @@
+/*************************************************************************
+ *
+ * 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: nbdll.cxx,v $
+ * $Revision: 1.4 $
+ *
+ * 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"
+
+#ifdef WIN
+#include <svwin.h>
+
+#ifndef _SYSDEP_HXX
+#include <sysdep.hxx>
+#endif
+
+// Statische DLL-Verwaltungs-Variablen
+static HINSTANCE hDLLInst = 0; // HANDLE der DLL
+
+
+/***************************************************************************
+|*
+|* LibMain()
+|*
+|* Beschreibung Initialisierungsfunktion der DLL
+|* Ersterstellung TH 05.05.93
+|* Letzte Aenderung TH 05.05.93
+|*
+***************************************************************************/
+
+extern "C" int CALLBACK LibMain( HINSTANCE hDLL, WORD, WORD nHeap, LPSTR )
+{
+#ifndef WNT
+ if ( nHeap )
+ UnlockData( 0 );
+#endif
+
+ hDLLInst = hDLL;
+
+ return TRUE;
+}
+
+/***************************************************************************
+|*
+|* WEP()
+|*
+|* Beschreibung DLL-Deinitialisierung
+|* Ersterstellung TH 05.05.93
+|* Letzte Aenderung TH 05.05.93
+|*
+***************************************************************************/
+
+extern "C" int CALLBACK WEP( int )
+{
+ return 1;
+}
+
+#endif
diff --git a/svl/source/numbers/numfmuno.cxx b/svl/source/numbers/numfmuno.cxx
new file mode 100644
index 000000000000..23f627834955
--- /dev/null
+++ b/svl/source/numbers/numfmuno.cxx
@@ -0,0 +1,1143 @@
+/*************************************************************************
+ *
+ * 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: numfmuno.cxx,v $
+ * $Revision: 1.15 $
+ *
+ * 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 <tools/color.hxx>
+#include <tools/debug.hxx>
+#include <i18npool/mslangid.hxx>
+#include <vos/mutex.hxx>
+#include <rtl/ustring.hxx>
+
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include "numfmuno.hxx"
+#include "numuno.hxx"
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <svl/itemprop.hxx>
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+#define SERVICENAME_NUMBERFORMATTER "com.sun.star.util.NumberFormatter"
+#define SERVICENAME_NUMBERSETTINGS "com.sun.star.util.NumberFormatSettings"
+#define SERVICENAME_NUMBERFORMATS "com.sun.star.util.NumberFormats"
+#define SERVICENAME_NUMBERFORMAT "com.sun.star.util.NumberFormatProperties"
+
+//------------------------------------------------------------------------
+
+#define PROPERTYNAME_FMTSTR "FormatString"
+#define PROPERTYNAME_LOCALE "Locale"
+#define PROPERTYNAME_TYPE "Type"
+#define PROPERTYNAME_COMMENT "Comment"
+#define PROPERTYNAME_CURREXT "CurrencyExtension"
+#define PROPERTYNAME_CURRSYM "CurrencySymbol"
+#define PROPERTYNAME_CURRABB "CurrencyAbbreviation"
+#define PROPERTYNAME_DECIMALS "Decimals"
+#define PROPERTYNAME_LEADING "LeadingZeros"
+#define PROPERTYNAME_NEGRED "NegativeRed"
+#define PROPERTYNAME_STDFORM "StandardFormat"
+#define PROPERTYNAME_THOUS "ThousandsSeparator"
+#define PROPERTYNAME_USERDEF "UserDefined"
+
+#define PROPERTYNAME_NOZERO "NoZero"
+#define PROPERTYNAME_NULLDATE "NullDate"
+#define PROPERTYNAME_STDDEC "StandardDecimals"
+#define PROPERTYNAME_TWODIGIT "TwoDigitDateStart"
+
+//------------------------------------------------------------------------
+
+// alles ohne Which-ID, Map nur fuer PropertySetInfo
+
+const SfxItemPropertyMapEntry* lcl_GetNumberFormatPropertyMap()
+{
+ static SfxItemPropertyMapEntry aNumberFormatPropertyMap_Impl[] =
+ {
+ {MAP_CHAR_LEN(PROPERTYNAME_FMTSTR), 0, &getCppuType((rtl::OUString*)0),beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_LOCALE), 0, &getCppuType((lang::Locale*)0),beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_TYPE), 0, &getCppuType((sal_Int16*)0), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_COMMENT), 0, &getCppuType((rtl::OUString*)0),beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_CURREXT), 0, &getCppuType((rtl::OUString*)0),beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_CURRSYM), 0, &getCppuType((rtl::OUString*)0),beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_DECIMALS), 0, &getCppuType((sal_Int16*)0), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_LEADING), 0, &getCppuType((sal_Int16*)0), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_NEGRED), 0, &getBooleanCppuType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_STDFORM), 0, &getBooleanCppuType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_THOUS), 0, &getBooleanCppuType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_USERDEF), 0, &getBooleanCppuType(), beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_CURRABB), 0, &getCppuType((rtl::OUString*)0),beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY, 0},
+ {0,0,0,0,0,0}
+ };
+ return aNumberFormatPropertyMap_Impl;
+}
+
+const SfxItemPropertyMapEntry* lcl_GetNumberSettingsPropertyMap()
+{
+ static SfxItemPropertyMapEntry aNumberSettingsPropertyMap_Impl[] =
+ {
+ {MAP_CHAR_LEN(PROPERTYNAME_NOZERO), 0, &getBooleanCppuType(), beans::PropertyAttribute::BOUND, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_NULLDATE), 0, &getCppuType((util::Date*)0), beans::PropertyAttribute::BOUND, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_STDDEC), 0, &getCppuType((sal_Int16*)0), beans::PropertyAttribute::BOUND, 0},
+ {MAP_CHAR_LEN(PROPERTYNAME_TWODIGIT), 0, &getCppuType((sal_Int16*)0), beans::PropertyAttribute::BOUND, 0},
+ {0,0,0,0,0,0}
+ };
+ return aNumberSettingsPropertyMap_Impl;
+}
+
+//----------------------------------------------------------------------------------------
+
+LanguageType lcl_GetLanguage( const lang::Locale& rLocale )
+{
+ // empty language -> LANGUAGE_SYSTEM
+ if ( rLocale.Language.getLength() == 0 )
+ return LANGUAGE_SYSTEM;
+
+ LanguageType eRet = MsLangId::convertLocaleToLanguage( rLocale );
+ if ( eRet == LANGUAGE_NONE )
+ eRet = LANGUAGE_SYSTEM; //! or throw an exception?
+
+ return eRet;
+}
+
+//----------------------------------------------------------------------------------------
+
+SvNumberFormatterServiceObj::SvNumberFormatterServiceObj()
+ :m_aMutex()
+{
+}
+
+SvNumberFormatterServiceObj::~SvNumberFormatterServiceObj()
+{
+}
+
+com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SvNumberFormatterServiceObj_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& )
+{
+ return ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface >( ( ::cppu::OWeakObject* ) new SvNumberFormatterServiceObj );
+}
+
+// XNumberFormatter
+
+void SAL_CALL SvNumberFormatterServiceObj::attachNumberFormatsSupplier(
+ const uno::Reference<util::XNumberFormatsSupplier>& _xSupplier )
+ throw(uno::RuntimeException)
+{
+ ::rtl::Reference< SvNumberFormatsSupplierObj > xAutoReleaseOld;
+
+ // SYNCHRONIZED ->
+ {
+ ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
+
+ SvNumberFormatsSupplierObj* pNew = SvNumberFormatsSupplierObj::getImplementation( _xSupplier );
+ if (!pNew)
+ throw uno::RuntimeException(); // wrong object
+
+ xAutoReleaseOld = xSupplier;
+
+ xSupplier = pNew;
+ m_aMutex = xSupplier->getSharedMutex();
+ }
+ // <- SYNCHRONIZED
+}
+
+uno::Reference<util::XNumberFormatsSupplier> SAL_CALL
+ SvNumberFormatterServiceObj::getNumberFormatsSupplier()
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return xSupplier.get();
+}
+
+sal_Int32 SAL_CALL SvNumberFormatterServiceObj::detectNumberFormat(
+ sal_Int32 nKey, const rtl::OUString& aString )
+ throw(util::NotNumericException, uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ String aTemp = aString;
+ sal_uInt32 nUKey = nKey;
+ double fValue = 0.0;
+ if ( pFormatter->IsNumberFormat(aTemp, nUKey, fValue) )
+ nRet = nUKey;
+ else
+ throw util::NotNumericException();
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+double SAL_CALL SvNumberFormatterServiceObj::convertStringToNumber(
+ sal_Int32 nKey, const rtl::OUString& aString )
+ throw(util::NotNumericException, uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ double fRet = 0.0;
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ String aTemp = aString;
+ sal_uInt32 nUKey = nKey;
+ double fValue = 0.0;
+ if ( pFormatter->IsNumberFormat(aTemp, nUKey, fValue) )
+ fRet = fValue;
+ else
+ throw util::NotNumericException();
+ }
+ else
+ throw uno::RuntimeException();
+
+ return fRet;
+}
+
+rtl::OUString SAL_CALL SvNumberFormatterServiceObj::convertNumberToString(
+ sal_Int32 nKey, double fValue ) throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ String aRet;
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ Color* pColor = NULL;
+ pFormatter->GetOutputString(fValue, nKey, aRet, &pColor);
+ }
+ else
+ throw uno::RuntimeException();
+
+ return aRet;
+}
+
+util::Color SAL_CALL SvNumberFormatterServiceObj::queryColorForNumber( sal_Int32 nKey,
+ double fValue, util::Color aDefaultColor )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ util::Color nRet = aDefaultColor; // color = INT32
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ String aStr;
+ Color* pColor = NULL;
+ pFormatter->GetOutputString(fValue, nKey, aStr, &pColor);
+ if (pColor)
+ nRet = pColor->GetColor();
+ // sonst Default behalten
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+rtl::OUString SAL_CALL SvNumberFormatterServiceObj::formatString( sal_Int32 nKey,
+ const rtl::OUString& aString ) throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ String aRet;
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ String aTemp = aString;
+ Color* pColor = NULL;
+ pFormatter->GetOutputString(aTemp, nKey, aRet, &pColor);
+ }
+ else
+ throw uno::RuntimeException();
+
+ return aRet;
+}
+
+util::Color SAL_CALL SvNumberFormatterServiceObj::queryColorForString( sal_Int32 nKey,
+ const rtl::OUString& aString,util::Color aDefaultColor )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ util::Color nRet = aDefaultColor; // color = INT32
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ String aTemp = aString;
+ String aStr;
+ Color* pColor = NULL;
+ pFormatter->GetOutputString(aTemp, nKey, aStr, &pColor);
+ if (pColor)
+ nRet = pColor->GetColor();
+ // sonst Default behalten
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+rtl::OUString SAL_CALL SvNumberFormatterServiceObj::getInputString( sal_Int32 nKey, double fValue )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ String aRet;
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ pFormatter->GetInputLineString(fValue, nKey, aRet);
+ else
+ throw uno::RuntimeException();
+
+ return aRet;
+}
+
+// XNumberFormatPreviewer
+
+rtl::OUString SAL_CALL SvNumberFormatterServiceObj::convertNumberToPreviewString(
+ const rtl::OUString& aFormat, double fValue,
+ const lang::Locale& nLocale, sal_Bool bAllowEnglish )
+ throw(util::MalformedNumberFormatException, uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ String aRet;
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ String aOutString;
+ String aFormString = aFormat;
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ Color* pColor = NULL;
+
+ BOOL bOk;
+ if ( bAllowEnglish )
+ bOk = pFormatter->GetPreviewStringGuess(
+ aFormString, fValue, aOutString, &pColor, eLang );
+ else
+ bOk = pFormatter->GetPreviewString(
+ aFormString, fValue, aOutString, &pColor, eLang );
+
+ if (bOk)
+ aRet = aOutString;
+ else
+ throw util::MalformedNumberFormatException();
+ }
+ else
+ throw uno::RuntimeException();
+
+ return aRet;
+}
+
+util::Color SAL_CALL SvNumberFormatterServiceObj::queryPreviewColorForNumber(
+ const rtl::OUString& aFormat, double fValue,
+ const lang::Locale& nLocale, sal_Bool bAllowEnglish,
+ util::Color aDefaultColor )
+ throw(util::MalformedNumberFormatException, uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ util::Color nRet = aDefaultColor; // color = INT32
+ SvNumberFormatter* pFormatter = xSupplier.is() ? xSupplier->GetNumberFormatter() : NULL;
+ if (pFormatter)
+ {
+ String aOutString;
+ String aFormString = aFormat;
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ Color* pColor = NULL;
+
+ BOOL bOk;
+ if ( bAllowEnglish )
+ bOk = pFormatter->GetPreviewStringGuess(
+ aFormString, fValue, aOutString, &pColor, eLang );
+ else
+ bOk = pFormatter->GetPreviewString(
+ aFormString, fValue, aOutString, &pColor, eLang );
+
+ if (bOk)
+ {
+ if (pColor)
+ nRet = pColor->GetColor();
+ // sonst Default behalten
+ }
+ else
+ throw util::MalformedNumberFormatException();
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+// XServiceInfo
+
+rtl::OUString SAL_CALL SvNumberFormatterServiceObj::getImplementationName()
+ throw(uno::RuntimeException)
+{
+ return rtl::OUString::createFromAscii("com.sun.star.uno.util.numbers.SvNumberFormatterServiceObject");
+}
+
+sal_Bool SAL_CALL SvNumberFormatterServiceObj::supportsService( const rtl::OUString& ServiceName )
+ throw(uno::RuntimeException)
+{
+ return ( ServiceName.compareToAscii(SERVICENAME_NUMBERFORMATTER) == 0 );
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL SvNumberFormatterServiceObj::getSupportedServiceNames()
+ throw(uno::RuntimeException)
+{
+ uno::Sequence<rtl::OUString> aRet(1);
+ rtl::OUString* pArray = aRet.getArray();
+ pArray[0] = rtl::OUString::createFromAscii(SERVICENAME_NUMBERFORMATTER);
+ return aRet;
+}
+
+//------------------------------------------------------------------------
+
+SvNumberFormatsObj::SvNumberFormatsObj( SvNumberFormatsSupplierObj& _rParent, ::comphelper::SharedMutex& _rMutex )
+ :rSupplier( _rParent )
+ ,m_aMutex( _rMutex )
+{
+ rSupplier.acquire();
+}
+
+SvNumberFormatsObj::~SvNumberFormatsObj()
+{
+ rSupplier.release();
+}
+
+// XNumberFormats
+
+uno::Reference<beans::XPropertySet> SAL_CALL SvNumberFormatsObj::getByKey( sal_Int32 nKey )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ const SvNumberformat* pFormat = pFormatter ? pFormatter->GetEntry(nKey) : NULL;
+ if (pFormat)
+ return new SvNumberFormatObj( rSupplier, nKey, m_aMutex );
+ else
+ throw uno::RuntimeException();
+}
+
+uno::Sequence<sal_Int32> SAL_CALL SvNumberFormatsObj::queryKeys( sal_Int16 nType,
+ const lang::Locale& nLocale, sal_Bool bCreate )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if ( pFormatter )
+ {
+ sal_uInt32 nIndex = 0;
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ SvNumberFormatTable& rTable = bCreate ?
+ pFormatter->ChangeCL( nType, nIndex, eLang ) :
+ pFormatter->GetEntryTable( nType, nIndex, eLang );
+ sal_uInt32 nCount = rTable.Count();
+ uno::Sequence<sal_Int32> aSeq(nCount);
+ sal_Int32* pAry = aSeq.getArray();
+ for (sal_uInt32 i=0; i<nCount; i++)
+ pAry[i] = rTable.GetObjectKey( i );
+
+ return aSeq;
+ }
+ else
+ throw uno::RuntimeException();
+}
+
+sal_Int32 SAL_CALL SvNumberFormatsObj::queryKey( const rtl::OUString& aFormat,
+ const lang::Locale& nLocale, sal_Bool bScan )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ String aFormStr = aFormat;
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ if (bScan)
+ {
+ //! irgendwas muss hier noch passieren...
+ }
+ nRet = pFormatter->GetEntryKey( aFormat, eLang );
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+sal_Int32 SAL_CALL SvNumberFormatsObj::addNew( const rtl::OUString& aFormat,
+ const lang::Locale& nLocale )
+ throw(util::MalformedNumberFormatException, uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ String aFormStr = aFormat;
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ sal_uInt32 nKey = 0;
+ xub_StrLen nCheckPos = 0;
+ short nType = 0;
+ BOOL bOk = pFormatter->PutEntry( aFormStr, nCheckPos, nType, nKey, eLang );
+ if (bOk)
+ nRet = nKey;
+ else if (nCheckPos)
+ {
+ throw util::MalformedNumberFormatException(); // ungueltiges Format
+ }
+ else
+ throw uno::RuntimeException(); // anderer Fehler (z.B. schon vorhanden)
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+sal_Int32 SAL_CALL SvNumberFormatsObj::addNewConverted( const rtl::OUString& aFormat,
+ const lang::Locale& nLocale, const lang::Locale& nNewLocale )
+ throw(util::MalformedNumberFormatException, uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ String aFormStr = aFormat;
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ LanguageType eNewLang = lcl_GetLanguage( nNewLocale );
+ sal_uInt32 nKey = 0;
+ xub_StrLen nCheckPos = 0;
+ short nType = 0;
+ BOOL bOk = pFormatter->PutandConvertEntry( aFormStr, nCheckPos, nType, nKey, eLang, eNewLang );
+ if (bOk || nKey > 0)
+ nRet = nKey;
+ else if (nCheckPos)
+ {
+ throw util::MalformedNumberFormatException(); // ungueltiges Format
+ }
+ else
+ throw uno::RuntimeException(); // anderer Fehler (z.B. schon vorhanden)
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+void SAL_CALL SvNumberFormatsObj::removeByKey( sal_Int32 nKey ) throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+
+ if (pFormatter)
+ {
+ pFormatter->DeleteEntry(nKey);
+ rSupplier.NumberFormatDeleted(nKey); // Benachrichtigung fuers Dokument
+ }
+}
+
+rtl::OUString SAL_CALL SvNumberFormatsObj::generateFormat( sal_Int32 nBaseKey,
+ const lang::Locale& nLocale, sal_Bool bThousands,
+ sal_Bool bRed, sal_Int16 nDecimals, sal_Int16 nLeading )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ String aRet;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ pFormatter->GenerateFormat( aRet, nBaseKey, eLang, bThousands, bRed, nDecimals, nLeading );
+ }
+ else
+ throw uno::RuntimeException();
+
+ return aRet;
+}
+
+// XNumberFormatTypes
+
+sal_Int32 SAL_CALL SvNumberFormatsObj::getStandardIndex( const lang::Locale& nLocale )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ nRet = pFormatter->GetStandardIndex(eLang);
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+sal_Int32 SAL_CALL SvNumberFormatsObj::getStandardFormat( sal_Int16 nType, const lang::Locale& nLocale )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ // mask out "defined" bit, so type from an existing number format
+ // can directly be used for getStandardFormat
+ nType &= ~NUMBERFORMAT_DEFINED;
+ nRet = pFormatter->GetStandardFormat(nType, eLang);
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+sal_Int32 SAL_CALL SvNumberFormatsObj::getFormatIndex( sal_Int16 nIndex, const lang::Locale& nLocale )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ nRet = pFormatter->GetFormatIndex( (NfIndexTableOffset)nIndex, eLang );
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+sal_Bool SAL_CALL SvNumberFormatsObj::isTypeCompatible( sal_Int16 nOldType, sal_Int16 nNewType )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ BOOL bRet = FALSE;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ bRet = pFormatter->IsCompatible( nOldType, nNewType );
+ else
+ throw uno::RuntimeException();
+
+ return bRet;
+}
+
+sal_Int32 SAL_CALL SvNumberFormatsObj::getFormatForLocale( sal_Int32 nKey, const lang::Locale& nLocale )
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ INT32 nRet = 0;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ LanguageType eLang = lcl_GetLanguage( nLocale );
+ nRet = pFormatter->GetFormatForLanguageIfBuiltIn(nKey, eLang);
+ }
+ else
+ throw uno::RuntimeException();
+
+ return nRet;
+}
+
+// XServiceInfo
+
+rtl::OUString SAL_CALL SvNumberFormatsObj::getImplementationName()
+ throw(uno::RuntimeException)
+{
+ return rtl::OUString::createFromAscii("SvNumberFormatsObj");
+}
+
+sal_Bool SAL_CALL SvNumberFormatsObj::supportsService( const rtl::OUString& ServiceName )
+ throw(uno::RuntimeException)
+{
+ return ( ServiceName.compareToAscii(SERVICENAME_NUMBERFORMATS) == 0 );
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL SvNumberFormatsObj::getSupportedServiceNames()
+ throw(uno::RuntimeException)
+{
+ uno::Sequence<rtl::OUString> aRet(1);
+ rtl::OUString* pArray = aRet.getArray();
+ pArray[0] = rtl::OUString::createFromAscii(SERVICENAME_NUMBERFORMATS);
+ return aRet;
+}
+
+//------------------------------------------------------------------------
+
+SvNumberFormatObj::SvNumberFormatObj( SvNumberFormatsSupplierObj& rParent, ULONG nK, const ::comphelper::SharedMutex& _rMutex )
+ :rSupplier( rParent )
+ ,nKey( nK )
+ ,m_aMutex( _rMutex )
+{
+ rSupplier.acquire();
+}
+
+SvNumberFormatObj::~SvNumberFormatObj()
+{
+ rSupplier.release();
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL SvNumberFormatObj::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( lcl_GetNumberFormatPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL SvNumberFormatObj::setPropertyValue( const rtl::OUString&,
+ const uno::Any& )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ throw beans::UnknownPropertyException(); // everything is read-only
+}
+
+uno::Any SAL_CALL SvNumberFormatObj::getPropertyValue( const rtl::OUString& aPropertyName )
+ throw(beans::UnknownPropertyException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ uno::Any aRet;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ const SvNumberformat* pFormat = pFormatter ? pFormatter->GetEntry(nKey) : NULL;
+ if (pFormat)
+ {
+ BOOL bThousand, bRed;
+ USHORT nDecimals, nLeading;
+
+ String aString = aPropertyName;
+ if (aString.EqualsAscii( PROPERTYNAME_FMTSTR ))
+ {
+ aRet <<= rtl::OUString( pFormat->GetFormatstring() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_LOCALE ))
+ {
+ lang::Locale aLocale( MsLangId::convertLanguageToLocale(
+ pFormat->GetLanguage()));
+ aRet <<= aLocale;
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_TYPE ))
+ {
+ aRet <<= (sal_Int16)( pFormat->GetType() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_COMMENT ))
+ {
+ aRet <<= rtl::OUString( pFormat->GetComment() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_STDFORM ))
+ {
+ //! SvNumberformat Member bStandard rausreichen?
+ BOOL bStandard = ( ( nKey % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 );
+ aRet.setValue( &bStandard, getBooleanCppuType() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_USERDEF ))
+ {
+ BOOL bUserDef = ( ( pFormat->GetType() & NUMBERFORMAT_DEFINED ) != 0 );
+ aRet.setValue( &bUserDef, getBooleanCppuType() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_DECIMALS ))
+ {
+ pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
+ aRet <<= (sal_Int16)( nDecimals );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_LEADING ))
+ {
+ pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
+ aRet <<= (sal_Int16)( nLeading );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_NEGRED ))
+ {
+ pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
+ aRet.setValue( &bRed, getBooleanCppuType() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_THOUS ))
+ {
+ pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
+ aRet.setValue( &bThousand, getBooleanCppuType() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_CURRSYM ))
+ {
+ String aSymbol, aExt;
+ pFormat->GetNewCurrencySymbol( aSymbol, aExt );
+ aRet <<= rtl::OUString( aSymbol );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_CURREXT ))
+ {
+ String aSymbol, aExt;
+ pFormat->GetNewCurrencySymbol( aSymbol, aExt );
+ aRet <<= rtl::OUString( aExt );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_CURRABB ))
+ {
+ String aSymbol, aExt;
+ BOOL bBank = FALSE;
+ pFormat->GetNewCurrencySymbol( aSymbol, aExt );
+ const NfCurrencyEntry* pCurr = pFormatter->GetCurrencyEntry( bBank,
+ aSymbol, aExt, pFormat->GetLanguage() );
+ if ( pCurr )
+ aRet <<= rtl::OUString( pCurr->GetBankSymbol() );
+ else
+ aRet <<= rtl::OUString();
+ }
+ else
+ throw beans::UnknownPropertyException();
+ }
+ else
+ throw uno::RuntimeException();
+
+ return aRet;
+}
+
+void SAL_CALL SvNumberFormatObj::addPropertyChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XPropertyChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+void SAL_CALL SvNumberFormatObj::removePropertyChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XPropertyChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+void SAL_CALL SvNumberFormatObj::addVetoableChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+void SAL_CALL SvNumberFormatObj::removeVetoableChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+// XPropertyAccess
+
+uno::Sequence<beans::PropertyValue> SAL_CALL SvNumberFormatObj::getPropertyValues()
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ const SvNumberformat* pFormat = pFormatter ? pFormatter->GetEntry(nKey) : NULL;
+ if (pFormat)
+ {
+ String aSymbol, aExt, aAbb;
+ BOOL bBank = FALSE;
+ pFormat->GetNewCurrencySymbol( aSymbol, aExt );
+ const NfCurrencyEntry* pCurr = pFormatter->GetCurrencyEntry( bBank,
+ aSymbol, aExt, pFormat->GetLanguage() );
+ if ( pCurr )
+ aAbb = pCurr->GetBankSymbol();
+
+ String aFmtStr = pFormat->GetFormatstring();
+ String aComment = pFormat->GetComment();
+ BOOL bStandard = ( ( nKey % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 );
+ //! SvNumberformat Member bStandard rausreichen?
+ BOOL bUserDef = ( ( pFormat->GetType() & NUMBERFORMAT_DEFINED ) != 0 );
+ BOOL bThousand, bRed;
+ USHORT nDecimals, nLeading;
+ pFormat->GetFormatSpecialInfo( bThousand, bRed, nDecimals, nLeading );
+ lang::Locale aLocale( MsLangId::convertLanguageToLocale(
+ pFormat->GetLanguage()));
+
+ uno::Sequence<beans::PropertyValue> aSeq(13);
+ beans::PropertyValue* pArray = aSeq.getArray();
+
+ pArray[0].Name = rtl::OUString::createFromAscii( PROPERTYNAME_FMTSTR );
+ pArray[0].Value <<= rtl::OUString( aFmtStr );
+ pArray[1].Name = rtl::OUString::createFromAscii( PROPERTYNAME_LOCALE );
+ pArray[1].Value <<= aLocale;
+ pArray[2].Name = rtl::OUString::createFromAscii( PROPERTYNAME_TYPE );
+ pArray[2].Value <<= (sal_Int16)( pFormat->GetType() );
+ pArray[3].Name = rtl::OUString::createFromAscii( PROPERTYNAME_COMMENT );
+ pArray[3].Value <<= rtl::OUString( aComment );
+ pArray[4].Name = rtl::OUString::createFromAscii( PROPERTYNAME_STDFORM );
+ pArray[4].Value.setValue( &bStandard, getBooleanCppuType() );
+ pArray[5].Name = rtl::OUString::createFromAscii( PROPERTYNAME_USERDEF );
+ pArray[5].Value.setValue( &bUserDef, getBooleanCppuType() );
+ pArray[6].Name = rtl::OUString::createFromAscii( PROPERTYNAME_DECIMALS );
+ pArray[6].Value <<= (sal_Int16)( nDecimals );
+ pArray[7].Name = rtl::OUString::createFromAscii( PROPERTYNAME_LEADING );
+ pArray[7].Value <<= (sal_Int16)( nLeading );
+ pArray[8].Name = rtl::OUString::createFromAscii( PROPERTYNAME_NEGRED );
+ pArray[8].Value.setValue( &bRed, getBooleanCppuType() );
+ pArray[9].Name = rtl::OUString::createFromAscii( PROPERTYNAME_THOUS );
+ pArray[9].Value.setValue( &bThousand, getBooleanCppuType() );
+ pArray[10].Name = rtl::OUString::createFromAscii( PROPERTYNAME_CURRSYM );
+ pArray[10].Value <<= rtl::OUString( aSymbol );
+ pArray[11].Name = rtl::OUString::createFromAscii( PROPERTYNAME_CURREXT );
+ pArray[11].Value <<= rtl::OUString( aExt );
+ pArray[12].Name = rtl::OUString::createFromAscii( PROPERTYNAME_CURRABB );
+ pArray[12].Value <<= rtl::OUString( aAbb );
+
+ return aSeq;
+ }
+ else
+ throw uno::RuntimeException();
+}
+
+void SAL_CALL SvNumberFormatObj::setPropertyValues( const uno::Sequence<beans::PropertyValue>& )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ throw beans::UnknownPropertyException(); // everything is read-only
+}
+
+// XServiceInfo
+
+rtl::OUString SAL_CALL SvNumberFormatObj::getImplementationName()
+ throw(uno::RuntimeException)
+{
+ return rtl::OUString::createFromAscii("SvNumberFormatObj");
+}
+
+sal_Bool SAL_CALL SvNumberFormatObj::supportsService( const rtl::OUString& ServiceName )
+ throw(uno::RuntimeException)
+{
+ return ( ServiceName.compareToAscii(SERVICENAME_NUMBERFORMAT) == 0 );
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL SvNumberFormatObj::getSupportedServiceNames()
+ throw(uno::RuntimeException)
+{
+ uno::Sequence<rtl::OUString> aRet(1);
+ rtl::OUString* pArray = aRet.getArray();
+ pArray[0] = rtl::OUString::createFromAscii(SERVICENAME_NUMBERFORMAT);
+ return aRet;
+}
+
+//------------------------------------------------------------------------
+
+SvNumberFormatSettingsObj::SvNumberFormatSettingsObj( SvNumberFormatsSupplierObj& rParent, const ::comphelper::SharedMutex& _rMutex )
+ :rSupplier( rParent )
+ ,m_aMutex( _rMutex )
+{
+ rSupplier.acquire();
+}
+
+SvNumberFormatSettingsObj::~SvNumberFormatSettingsObj()
+{
+ rSupplier.release();
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL SvNumberFormatSettingsObj::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( lcl_GetNumberSettingsPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL SvNumberFormatSettingsObj::setPropertyValue( const rtl::OUString& aPropertyName,
+ const uno::Any& aValue )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ String aString = aPropertyName;
+ if (aString.EqualsAscii( PROPERTYNAME_NOZERO ))
+ {
+ // operator >>= shouldn't be used for bool (?)
+ if ( aValue.getValueTypeClass() == uno::TypeClass_BOOLEAN )
+ pFormatter->SetNoZero( *(sal_Bool*)aValue.getValue() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_NULLDATE ))
+ {
+ util::Date aDate;
+ if ( aValue >>= aDate )
+ pFormatter->ChangeNullDate( aDate.Day, aDate.Month, aDate.Year );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_STDDEC ))
+ {
+ sal_Int16 nInt16 = sal_Int16();
+ if ( aValue >>= nInt16 )
+ pFormatter->ChangeStandardPrec( nInt16 );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_TWODIGIT ))
+ {
+ sal_Int16 nInt16 = sal_Int16();
+ if ( aValue >>= nInt16 )
+ pFormatter->SetYear2000( nInt16 );
+ }
+ else
+ throw beans::UnknownPropertyException();
+
+ rSupplier.SettingsChanged();
+ }
+ else
+ throw uno::RuntimeException();
+}
+
+uno::Any SAL_CALL SvNumberFormatSettingsObj::getPropertyValue( const rtl::OUString& aPropertyName )
+ throw(beans::UnknownPropertyException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ uno::Any aRet;
+ SvNumberFormatter* pFormatter = rSupplier.GetNumberFormatter();
+ if (pFormatter)
+ {
+ String aString = aPropertyName;
+ if (aString.EqualsAscii( PROPERTYNAME_NOZERO ))
+ {
+ BOOL bNoZero = pFormatter->GetNoZero();
+ aRet.setValue( &bNoZero, getBooleanCppuType() );
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_NULLDATE ))
+ {
+ Date* pDate = pFormatter->GetNullDate();
+ if (pDate)
+ {
+ util::Date aUnoDate( pDate->GetDay(), pDate->GetMonth(), pDate->GetYear() );
+ aRet <<= aUnoDate;
+ }
+ }
+ else if (aString.EqualsAscii( PROPERTYNAME_STDDEC ))
+ aRet <<= (sal_Int16)( pFormatter->GetStandardPrec() );
+ else if (aString.EqualsAscii( PROPERTYNAME_TWODIGIT ))
+ aRet <<= (sal_Int16)( pFormatter->GetYear2000() );
+ else
+ throw beans::UnknownPropertyException();
+ }
+ else
+ throw uno::RuntimeException();
+
+ return aRet;
+}
+
+void SAL_CALL SvNumberFormatSettingsObj::addPropertyChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XPropertyChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+void SAL_CALL SvNumberFormatSettingsObj::removePropertyChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XPropertyChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+void SAL_CALL SvNumberFormatSettingsObj::addVetoableChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+void SAL_CALL SvNumberFormatSettingsObj::removeVetoableChangeListener( const rtl::OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+ throw(beans::UnknownPropertyException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ DBG_ERROR("not implemented");
+}
+
+// XServiceInfo
+
+rtl::OUString SAL_CALL SvNumberFormatSettingsObj::getImplementationName()
+ throw(uno::RuntimeException)
+{
+ return rtl::OUString::createFromAscii("SvNumberFormatSettingsObj");
+}
+
+sal_Bool SAL_CALL SvNumberFormatSettingsObj::supportsService( const rtl::OUString& ServiceName )
+ throw(uno::RuntimeException)
+{
+ return ( ServiceName.compareToAscii(SERVICENAME_NUMBERSETTINGS) == 0 );
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL SvNumberFormatSettingsObj::getSupportedServiceNames()
+ throw(uno::RuntimeException)
+{
+ uno::Sequence<rtl::OUString> aRet(1);
+ rtl::OUString* pArray = aRet.getArray();
+ pArray[0] = rtl::OUString::createFromAscii(SERVICENAME_NUMBERSETTINGS);
+ return aRet;
+}
+
+
diff --git a/svl/source/numbers/numfmuno.hxx b/svl/source/numbers/numfmuno.hxx
new file mode 100644
index 000000000000..4148069fb37e
--- /dev/null
+++ b/svl/source/numbers/numfmuno.hxx
@@ -0,0 +1,324 @@
+/*************************************************************************
+ *
+ * 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: numfmuno.hxx,v $
+ * $Revision: 1.4 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _NUMFMUNO_HXX
+#define _NUMFMUNO_HXX
+
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatPreviewer.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <comphelper/sharedmutex.hxx>
+#include <rtl/ref.hxx>
+
+class SvNumberformat;
+class SvNumberFormatter;
+class SvNumberFormatsSupplierObj;
+
+
+// SvNumberFormatterServiceObj wird global als Service angemeldet
+
+class SvNumberFormatterServiceObj : public cppu::WeakImplHelper3<
+ com::sun::star::util::XNumberFormatter,
+ com::sun::star::util::XNumberFormatPreviewer,
+ com::sun::star::lang::XServiceInfo>
+{
+private:
+ ::rtl::Reference< SvNumberFormatsSupplierObj > xSupplier;
+ mutable ::comphelper::SharedMutex m_aMutex;
+
+public:
+ SvNumberFormatterServiceObj();
+ virtual ~SvNumberFormatterServiceObj();
+
+ // XNumberFormatter
+ virtual void SAL_CALL attachNumberFormatsSupplier(
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::util::XNumberFormatsSupplier >& xSupplier )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatsSupplier >
+ SAL_CALL getNumberFormatsSupplier()
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL detectNumberFormat( sal_Int32 nKey, const ::rtl::OUString& aString )
+ throw(::com::sun::star::util::NotNumericException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual double SAL_CALL convertStringToNumber( sal_Int32 nKey, const ::rtl::OUString& aString )
+ throw(::com::sun::star::util::NotNumericException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL convertNumberToString( sal_Int32 nKey, double fValue )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::util::Color SAL_CALL queryColorForNumber( sal_Int32 nKey,
+ double fValue, ::com::sun::star::util::Color aDefaultColor )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL formatString( sal_Int32 nKey, const ::rtl::OUString& aString )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::util::Color SAL_CALL queryColorForString( sal_Int32 nKey,
+ const ::rtl::OUString& aString,
+ ::com::sun::star::util::Color aDefaultColor )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getInputString( sal_Int32 nKey, double fValue )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XNumberFormatPreviewer
+ virtual ::rtl::OUString SAL_CALL convertNumberToPreviewString(
+ const ::rtl::OUString& aFormat, double fValue,
+ const ::com::sun::star::lang::Locale& nLocale, sal_Bool bAllowEnglish )
+ throw(::com::sun::star::util::MalformedNumberFormatException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::util::Color SAL_CALL queryPreviewColorForNumber(
+ const ::rtl::OUString& aFormat, double fValue,
+ const ::com::sun::star::lang::Locale& nLocale, sal_Bool bAllowEnglish,
+ ::com::sun::star::util::Color aDefaultColor )
+ throw(::com::sun::star::util::MalformedNumberFormatException,
+ ::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
+ throw(::com::sun::star::uno::RuntimeException);
+};
+
+
+class SvNumberFormatsObj : public cppu::WeakImplHelper3<
+ com::sun::star::util::XNumberFormats,
+ com::sun::star::util::XNumberFormatTypes,
+ com::sun::star::lang::XServiceInfo>
+{
+private:
+ SvNumberFormatsSupplierObj& rSupplier;
+ mutable ::comphelper::SharedMutex m_aMutex;
+
+public:
+ SvNumberFormatsObj(SvNumberFormatsSupplierObj& pParent, ::comphelper::SharedMutex& _rMutex);
+ virtual ~SvNumberFormatsObj();
+
+
+ // XNumberFormats
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > SAL_CALL
+ getByKey( sal_Int32 nKey ) throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< sal_Int32 > SAL_CALL queryKeys( sal_Int16 nType,
+ const ::com::sun::star::lang::Locale& nLocale, sal_Bool bCreate )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL queryKey( const ::rtl::OUString& aFormat,
+ const ::com::sun::star::lang::Locale& nLocale, sal_Bool bScan )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL addNew( const ::rtl::OUString& aFormat,
+ const ::com::sun::star::lang::Locale& nLocale )
+ throw(::com::sun::star::util::MalformedNumberFormatException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL addNewConverted( const ::rtl::OUString& aFormat,
+ const ::com::sun::star::lang::Locale& nLocale,
+ const ::com::sun::star::lang::Locale& nNewLocale )
+ throw(::com::sun::star::util::MalformedNumberFormatException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeByKey( sal_Int32 nKey ) throw(::com::sun::star::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL generateFormat( sal_Int32 nBaseKey,
+ const ::com::sun::star::lang::Locale& nLocale, sal_Bool bThousands,
+ sal_Bool bRed, sal_Int16 nDecimals, sal_Int16 nLeading )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XNumberFormatTypes
+ virtual sal_Int32 SAL_CALL getStandardIndex( const ::com::sun::star::lang::Locale& nLocale )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL getStandardFormat( sal_Int16 nType,
+ const ::com::sun::star::lang::Locale& nLocale )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL getFormatIndex( sal_Int16 nIndex,
+ const ::com::sun::star::lang::Locale& nLocale )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL isTypeCompatible( sal_Int16 nOldType, sal_Int16 nNewType )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Int32 SAL_CALL getFormatForLocale( sal_Int32 nKey,
+ const ::com::sun::star::lang::Locale& nLocale )
+ throw(::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
+ throw(::com::sun::star::uno::RuntimeException);
+
+private:
+ SvNumberFormatsObj(); // never implemented
+};
+
+
+class SvNumberFormatObj : public cppu::WeakImplHelper3<
+ com::sun::star::beans::XPropertySet,
+ com::sun::star::beans::XPropertyAccess,
+ com::sun::star::lang::XServiceInfo>
+{
+private:
+ SvNumberFormatsSupplierObj& rSupplier;
+ ULONG nKey;
+ mutable ::comphelper::SharedMutex m_aMutex;
+
+public:
+ SvNumberFormatObj( SvNumberFormatsSupplierObj& rParent, ULONG nK, const ::comphelper::SharedMutex& _rMutex );
+ virtual ~SvNumberFormatObj();
+
+ // XPropertySet
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo >
+ SAL_CALL getPropertySetInfo( )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName,
+ const ::com::sun::star::uno::Any& aValue )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::beans::PropertyVetoException,
+ ::com::sun::star::lang::IllegalArgumentException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue(
+ const ::rtl::OUString& PropertyName )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertyChangeListener >& xListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertyChangeListener >& aListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XVetoableChangeListener >& aListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XVetoableChangeListener >& aListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+
+ // XPropertyAccess
+ virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL
+ getPropertyValues() throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setPropertyValues( const ::com::sun::star::uno::Sequence<
+ ::com::sun::star::beans::PropertyValue >& aProps )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::beans::PropertyVetoException,
+ ::com::sun::star::lang::IllegalArgumentException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
+ throw(::com::sun::star::uno::RuntimeException);
+};
+
+
+class SvNumberFormatSettingsObj : public cppu::WeakImplHelper2<
+ com::sun::star::beans::XPropertySet,
+ com::sun::star::lang::XServiceInfo>
+{
+private:
+ SvNumberFormatsSupplierObj& rSupplier;
+ mutable ::comphelper::SharedMutex m_aMutex;
+
+public:
+ SvNumberFormatSettingsObj( SvNumberFormatsSupplierObj& rParent, const ::comphelper::SharedMutex& _rMutex);
+ virtual ~SvNumberFormatSettingsObj();
+
+
+ // XPropertySet
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo >
+ SAL_CALL getPropertySetInfo( )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName,
+ const ::com::sun::star::uno::Any& aValue )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::beans::PropertyVetoException,
+ ::com::sun::star::lang::IllegalArgumentException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue(
+ const ::rtl::OUString& PropertyName )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertyChangeListener >& xListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XPropertyChangeListener >& aListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XVetoableChangeListener >& aListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName,
+ const ::com::sun::star::uno::Reference<
+ ::com::sun::star::beans::XVetoableChangeListener >& aListener )
+ throw(::com::sun::star::beans::UnknownPropertyException,
+ ::com::sun::star::lang::WrappedTargetException,
+ ::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
+ throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
+ throw(::com::sun::star::uno::RuntimeException);
+};
+
+
+
+#endif
+
diff --git a/svl/source/numbers/numhead.cxx b/svl/source/numbers/numhead.cxx
new file mode 100644
index 000000000000..99ff33433de3
--- /dev/null
+++ b/svl/source/numbers/numhead.cxx
@@ -0,0 +1,252 @@
+/*************************************************************************
+ *
+ * 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: numhead.cxx,v $
+ * $Revision: 1.9 $
+ *
+ * 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 <tools/debug.hxx>
+
+#include "numhead.hxx"
+
+// ID's fuer Dateien:
+#define SV_NUMID_SIZES 0x4200
+
+// STATIC DATA -----------------------------------------------------------
+
+//SEG_EOFGLOBALS()
+
+// =======================================================================
+/* wird fuer SvNumberformatter nicht gebraucht
+//#pragma SEG_FUNCDEF(numhead_01)
+
+SvNumReadHeader::SvNumReadHeader(SvStream& rNewStream) :
+ rStream( rNewStream )
+{
+ ULONG nDataSize;
+ rStream >> nDataSize;
+ nDataEnd = rStream.Tell() + nDataSize;
+}
+
+//#pragma SEG_FUNCDEF(numhead_02)
+
+SvNumReadHeader::~SvNumReadHeader()
+{
+ ULONG nReadEnd = rStream.Tell();
+ DBG_ASSERT( nReadEnd <= nDataEnd, "zuviele Bytes gelesen" );
+ if ( nReadEnd != nDataEnd )
+ rStream.Seek(nDataEnd); // Rest ueberspringen
+}
+
+//#pragma SEG_FUNCDEF(numhead_03)
+
+ULONG SvNumReadHeader::BytesLeft() const
+{
+ ULONG nReadEnd = rStream.Tell();
+ if (nReadEnd <= nDataEnd)
+ return nDataEnd-nReadEnd;
+
+ DBG_ERROR("Fehler bei SvNumReadHeader::BytesLeft");
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+//#pragma SEG_FUNCDEF(numhead_04)
+
+SvNumWriteHeader::SvNumWriteHeader(SvStream& rNewStream, ULONG nDefault) :
+ rStream( rNewStream )
+{
+ nDataSize = nDefault;
+ rStream << nDataSize;
+ nDataPos = rStream.Tell();
+}
+
+//#pragma SEG_FUNCDEF(numhead_05)
+
+SvNumWriteHeader::~SvNumWriteHeader()
+{
+ ULONG nPos = rStream.Tell();
+
+ if ( nPos - nDataPos != nDataSize ) // Default getroffen?
+ {
+ nDataSize = nPos - nDataPos;
+ rStream.Seek(nDataPos - sizeof(sal_uInt32));
+ rStream << nDataSize; // Groesse am Anfang eintragen
+ rStream.Seek(nPos);
+ }
+}
+*/
+
+// =======================================================================
+
+//#pragma SEG_FUNCDEF(numhead_06)
+
+//! mit Skip() synchron
+ImpSvNumMultipleReadHeader::ImpSvNumMultipleReadHeader(SvStream& rNewStream) :
+ rStream( rNewStream )
+{
+ sal_uInt32 nDataSize;
+ rStream >> nDataSize;
+ ULONG nDataPos = rStream.Tell();
+ nEntryEnd = nDataPos;
+
+ rStream.SeekRel(nDataSize);
+ USHORT nID;
+ rStream >> nID;
+ if (nID != SV_NUMID_SIZES)
+ {
+ DBG_ERROR("SV_NUMID_SIZES nicht gefunden");
+ }
+ sal_uInt32 nSizeTableLen;
+ rStream >> nSizeTableLen;
+ pBuf = new char[nSizeTableLen];
+ rStream.Read( pBuf, nSizeTableLen );
+ pMemStream = new SvMemoryStream( pBuf, nSizeTableLen, STREAM_READ );
+
+ nEndPos = rStream.Tell();
+ rStream.Seek( nDataPos );
+}
+
+//#pragma SEG_FUNCDEF(numhead_07)
+
+ImpSvNumMultipleReadHeader::~ImpSvNumMultipleReadHeader()
+{
+ DBG_ASSERT( pMemStream->Tell() == pMemStream->GetSize(),
+ "Sizes nicht vollstaendig gelesen" );
+ delete pMemStream;
+ delete [] pBuf;
+
+ rStream.Seek(nEndPos);
+}
+
+//! mit ctor synchron
+// static
+void ImpSvNumMultipleReadHeader::Skip( SvStream& rStream )
+{
+ sal_uInt32 nDataSize;
+ rStream >> nDataSize;
+ rStream.SeekRel( nDataSize );
+ USHORT nID;
+ rStream >> nID;
+ if ( nID != SV_NUMID_SIZES )
+ {
+ DBG_ERROR("SV_NUMID_SIZES nicht gefunden");
+ }
+ sal_uInt32 nSizeTableLen;
+ rStream >> nSizeTableLen;
+ rStream.SeekRel( nSizeTableLen );
+}
+
+//#pragma SEG_FUNCDEF(numhead_08)
+
+void ImpSvNumMultipleReadHeader::EndEntry()
+{
+ ULONG nPos = rStream.Tell();
+ DBG_ASSERT( nPos <= nEntryEnd, "zuviel gelesen" );
+ if ( nPos != nEntryEnd )
+ rStream.Seek( nEntryEnd ); // Rest ueberspringen
+}
+
+//#pragma SEG_FUNCDEF(numhead_0d)
+
+void ImpSvNumMultipleReadHeader::StartEntry()
+{
+ ULONG nPos = rStream.Tell();
+ sal_uInt32 nEntrySize;
+ (*pMemStream) >> nEntrySize;
+
+ nEntryEnd = nPos + nEntrySize;
+}
+
+//#pragma SEG_FUNCDEF(numhead_09)
+
+ULONG ImpSvNumMultipleReadHeader::BytesLeft() const
+{
+ ULONG nReadEnd = rStream.Tell();
+ if (nReadEnd <= nEntryEnd)
+ return nEntryEnd-nReadEnd;
+
+ DBG_ERROR("Fehler bei ImpSvNumMultipleReadHeader::BytesLeft");
+ return 0;
+}
+
+// -----------------------------------------------------------------------
+
+//#pragma SEG_FUNCDEF(numhead_0a)
+
+ImpSvNumMultipleWriteHeader::ImpSvNumMultipleWriteHeader(SvStream& rNewStream,
+ ULONG nDefault) :
+ rStream( rNewStream ),
+ aMemStream( 4096, 4096 )
+{
+ nDataSize = nDefault;
+ rStream << nDataSize;
+
+ nDataPos = rStream.Tell();
+ nEntryStart = nDataPos;
+}
+
+//#pragma SEG_FUNCDEF(numhead_0b)
+
+ImpSvNumMultipleWriteHeader::~ImpSvNumMultipleWriteHeader()
+{
+ ULONG nDataEnd = rStream.Tell();
+
+ rStream << (USHORT) SV_NUMID_SIZES;
+ rStream << static_cast<sal_uInt32>(aMemStream.Tell());
+ rStream.Write( aMemStream.GetData(), aMemStream.Tell() );
+
+ if ( nDataEnd - nDataPos != nDataSize ) // Default getroffen?
+ {
+ nDataSize = nDataEnd - nDataPos;
+ ULONG nPos = rStream.Tell();
+ rStream.Seek(nDataPos-sizeof(sal_uInt32));
+ rStream << nDataSize; // Groesse am Anfang eintragen
+ rStream.Seek(nPos);
+ }
+}
+
+//#pragma SEG_FUNCDEF(numhead_0c)
+
+void ImpSvNumMultipleWriteHeader::EndEntry()
+{
+ ULONG nPos = rStream.Tell();
+ aMemStream << static_cast<sal_uInt32>(nPos - nEntryStart);
+}
+
+//#pragma SEG_FUNCDEF(numhead_0e)
+
+void ImpSvNumMultipleWriteHeader::StartEntry()
+{
+ ULONG nPos = rStream.Tell();
+ nEntryStart = nPos;
+}
+
diff --git a/svl/source/numbers/numhead.hxx b/svl/source/numbers/numhead.hxx
new file mode 100644
index 000000000000..de23b3cbccf4
--- /dev/null
+++ b/svl/source/numbers/numhead.hxx
@@ -0,0 +1,109 @@
+/*************************************************************************
+ *
+ * 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: numhead.hxx,v $
+ * $Revision: 1.4 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef NF_NUMHEAD_HXX
+#define NF_NUMHEAD_HXX
+
+#include <tools/stream.hxx>
+
+// -----------------------------------------------------------------------
+
+ // "Automatischer" Record-Header mit Groessenangabe
+
+/* wird fuer SvNumberFormatter nicht gebraucht
+class SvNumReadHeader
+{
+private:
+ SvStream& rStream;
+ ULONG nDataEnd;
+
+public:
+ SvNumReadHeader(SvStream& rNewStream);
+ ~SvNumReadHeader();
+
+ ULONG BytesLeft() const;
+};
+
+class SvNumWriteHeader
+{
+private:
+ SvStream& rStream;
+ ULONG nDataPos;
+ ULONG nDataSize;
+
+public:
+ SvNumWriteHeader(SvStream& rNewStream, ULONG nDefault = 0);
+ ~SvNumWriteHeader();
+};
+
+*/
+
+ // Header mit Groessenangaben fuer mehrere Objekte
+
+class ImpSvNumMultipleReadHeader
+{
+private:
+ SvStream& rStream;
+ char* pBuf;
+ SvMemoryStream* pMemStream;
+ ULONG nEndPos;
+ ULONG nEntryEnd;
+
+public:
+ ImpSvNumMultipleReadHeader(SvStream& rNewStream);
+ ~ImpSvNumMultipleReadHeader();
+
+ void StartEntry();
+ void EndEntry();
+ ULONG BytesLeft() const;
+
+ static void Skip( SvStream& ); // komplett ueberspringen
+};
+
+class ImpSvNumMultipleWriteHeader
+{
+private:
+ SvStream& rStream;
+ SvMemoryStream aMemStream;
+ ULONG nDataPos;
+ sal_uInt32 nDataSize;
+ ULONG nEntryStart;
+
+public:
+ ImpSvNumMultipleWriteHeader(SvStream& rNewStream, ULONG nDefault = 0);
+ ~ImpSvNumMultipleWriteHeader();
+
+ void StartEntry();
+ void EndEntry();
+};
+
+#endif
+
+
diff --git a/svl/source/numbers/numuno.cxx b/svl/source/numbers/numuno.cxx
new file mode 100644
index 000000000000..3cc90998e2dc
--- /dev/null
+++ b/svl/source/numbers/numuno.cxx
@@ -0,0 +1,170 @@
+/*************************************************************************
+ *
+ * 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: numuno.cxx,v $
+ * $Revision: 1.9 $
+ *
+ * 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
+
+#define _ZFORLIST_DECLARE_TABLE
+
+#include <tools/color.hxx>
+#include <tools/debug.hxx>
+#include <vos/mutex.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/uuid.h>
+
+#include "numuno.hxx"
+#include "numfmuno.hxx"
+#include <svl/zforlist.hxx>
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+class SvNumFmtSuppl_Impl
+{
+public:
+ SvNumberFormatter* pFormatter;
+ mutable ::comphelper::SharedMutex aMutex;
+
+ SvNumFmtSuppl_Impl(SvNumberFormatter* p) :
+ pFormatter(p) {}
+};
+
+//------------------------------------------------------------------------
+
+// Default-ctor fuer getReflection
+SvNumberFormatsSupplierObj::SvNumberFormatsSupplierObj()
+{
+ pImpl = new SvNumFmtSuppl_Impl(NULL);
+}
+
+SvNumberFormatsSupplierObj::SvNumberFormatsSupplierObj(SvNumberFormatter* pForm)
+{
+ pImpl = new SvNumFmtSuppl_Impl(pForm);
+}
+
+SvNumberFormatsSupplierObj::~SvNumberFormatsSupplierObj()
+{
+ delete pImpl;
+}
+
+::comphelper::SharedMutex& SvNumberFormatsSupplierObj::getSharedMutex() const
+{
+ return pImpl->aMutex;
+}
+
+SvNumberFormatter* SvNumberFormatsSupplierObj::GetNumberFormatter() const
+{
+ return pImpl->pFormatter;
+}
+
+void SvNumberFormatsSupplierObj::SetNumberFormatter(SvNumberFormatter* pNew)
+{
+ // der alte Numberformatter ist ungueltig geworden, nicht mehr darauf zugreifen!
+ pImpl->pFormatter = pNew;
+}
+
+void SvNumberFormatsSupplierObj::NumberFormatDeleted(sal_uInt32)
+{
+ // Basis-Implementierung tut nix...
+}
+
+void SvNumberFormatsSupplierObj::SettingsChanged()
+{
+ // Basis-Implementierung tut nix...
+}
+
+// XNumberFormatsSupplier
+
+uno::Reference<beans::XPropertySet> SAL_CALL SvNumberFormatsSupplierObj::getNumberFormatSettings()
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( pImpl->aMutex );
+
+ return new SvNumberFormatSettingsObj( *this, pImpl->aMutex );
+}
+
+uno::Reference<util::XNumberFormats> SAL_CALL SvNumberFormatsSupplierObj::getNumberFormats()
+ throw(uno::RuntimeException)
+{
+ ::osl::MutexGuard aGuard( pImpl->aMutex );
+
+ return new SvNumberFormatsObj( *this, pImpl->aMutex );
+}
+
+// XUnoTunnel
+
+sal_Int64 SAL_CALL SvNumberFormatsSupplierObj::getSomething(
+ const uno::Sequence<sal_Int8 >& rId ) throw(uno::RuntimeException)
+{
+ if ( rId.getLength() == 16 &&
+ 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(),
+ rId.getConstArray(), 16 ) )
+ {
+ return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
+ }
+ return 0;
+}
+
+// static
+const uno::Sequence<sal_Int8>& SvNumberFormatsSupplierObj::getUnoTunnelId()
+{
+ static uno::Sequence<sal_Int8> * pSeq = 0;
+ if( !pSeq )
+ {
+ osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
+ if( !pSeq )
+ {
+ static uno::Sequence< sal_Int8 > aSeq( 16 );
+ rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True );
+ pSeq = &aSeq;
+ }
+ }
+ return *pSeq;
+}
+
+// static
+SvNumberFormatsSupplierObj* SvNumberFormatsSupplierObj::getImplementation(
+ const uno::Reference<util::XNumberFormatsSupplier> xObj )
+{
+ SvNumberFormatsSupplierObj* pRet = NULL;
+ uno::Reference<lang::XUnoTunnel> xUT( xObj, uno::UNO_QUERY );
+ if (xUT.is())
+ pRet = reinterpret_cast<SvNumberFormatsSupplierObj*>(sal::static_int_cast<sal_IntPtr>(xUT->getSomething( getUnoTunnelId() )));
+ return pRet;
+}
+
+
+//------------------------------------------------------------------------
+
+
+
diff --git a/svl/source/numbers/supservs.cxx b/svl/source/numbers/supservs.cxx
new file mode 100644
index 000000000000..7e4d8560dae7
--- /dev/null
+++ b/svl/source/numbers/supservs.cxx
@@ -0,0 +1,232 @@
+/*************************************************************************
+ *
+ * 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: supservs.cxx,v $
+ * $Revision: 1.10 $
+ *
+ * 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"
+#include "supservs.hxx"
+#include <com/sun/star/lang/Locale.hpp>
+#include <comphelper/sharedmutex.hxx>
+#include <i18npool/mslangid.hxx>
+#include <tools/debug.hxx>
+#include <vos/mutex.hxx>
+#include <tools/stream.hxx>
+#include <strmadpt.hxx>
+#include "instrm.hxx"
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::util;
+using namespace ::vos;
+using namespace ::utl;
+
+#define PERSISTENT_SERVICE_NAME ::rtl::OUString::createFromAscii("com.sun.star.util.NumberFormatsSupplier");
+
+//-------------------------------------------------------------------------
+Reference< XInterface > SAL_CALL SvNumberFormatsSupplierServiceObject_CreateInstance(const Reference< XMultiServiceFactory >& _rxFactory)
+{
+ return static_cast< ::cppu::OWeakObject* >(new SvNumberFormatsSupplierServiceObject(_rxFactory));
+}
+
+//-------------------------------------------------------------------------
+SvNumberFormatsSupplierServiceObject::SvNumberFormatsSupplierServiceObject(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB)
+ :m_pOwnFormatter(NULL)
+ ,m_xORB(_rxORB)
+{
+}
+
+//-------------------------------------------------------------------------
+SvNumberFormatsSupplierServiceObject::~SvNumberFormatsSupplierServiceObject()
+{
+ if (m_pOwnFormatter)
+ {
+ delete m_pOwnFormatter;
+ m_pOwnFormatter = NULL;
+ }
+}
+
+//-------------------------------------------------------------------------
+Any SAL_CALL SvNumberFormatsSupplierServiceObject::queryAggregation( const Type& _rType ) throw (RuntimeException)
+{
+ Any aReturn = ::cppu::queryInterface(_rType,
+ static_cast< XInitialization* >(this),
+ static_cast< XPersistObject* >(this),
+ static_cast< XServiceInfo* >(this)
+ );
+
+ if (!aReturn.hasValue())
+ aReturn = SvNumberFormatsSupplierObj::queryAggregation(_rType);
+
+ return aReturn;
+}
+
+//-------------------------------------------------------------------------
+void SAL_CALL SvNumberFormatsSupplierServiceObject::initialize( const Sequence< Any >& _rArguments ) throw(Exception, RuntimeException)
+{
+ ::osl::MutexGuard aGuard( getSharedMutex() );
+
+ DBG_ASSERT(m_pOwnFormatter == NULL,
+ "SvNumberFormatsSupplierServiceObject::initialize : already initialized !");
+ // maybe you already called a method which needed the formatter
+ // you should use XMultiServiceFactory::createInstanceWithArguments to avoid that
+ if (m_pOwnFormatter)
+ { // !!! this is only a emergency handling, normally this should not occur !!!
+ delete m_pOwnFormatter;
+ m_pOwnFormatter = NULL;
+ SetNumberFormatter(m_pOwnFormatter);
+ }
+
+ Type aExpectedArgType = ::getCppuType(static_cast<Locale*>(NULL));
+ LanguageType eNewFormatterLanguage = LANGUAGE_ENGLISH_US;
+ // the default
+
+ const Any* pArgs = _rArguments.getConstArray();
+ for (sal_Int32 i=0; i<_rArguments.getLength(); ++i, ++pArgs)
+ {
+ if (pArgs->getValueType().equals(aExpectedArgType))
+ {
+ Locale aLocale;
+ *pArgs >>= aLocale;
+ eNewFormatterLanguage = MsLangId::convertLocaleToLanguage( aLocale);
+ }
+#ifdef DBG_UTIL
+ else
+ {
+ DBG_ERROR("SvNumberFormatsSupplierServiceObject::initialize : unknown argument !");
+ }
+#endif
+ }
+
+ m_pOwnFormatter = new SvNumberFormatter(m_xORB, eNewFormatterLanguage);
+ m_pOwnFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL );
+ SetNumberFormatter(m_pOwnFormatter);
+}
+
+//-------------------------------------------------------------------------
+::rtl::OUString SAL_CALL SvNumberFormatsSupplierServiceObject::getImplementationName( ) throw(RuntimeException)
+{
+ return ::rtl::OUString::createFromAscii("com.sun.star.uno.util.numbers.SvNumberFormatsSupplierServiceObject");
+}
+
+//-------------------------------------------------------------------------
+sal_Bool SAL_CALL SvNumberFormatsSupplierServiceObject::supportsService( const ::rtl::OUString& _rServiceName ) throw(RuntimeException)
+{
+ Sequence< ::rtl::OUString > aServices = getSupportedServiceNames();
+ const ::rtl::OUString* pServices = aServices.getConstArray();
+ for (sal_Int32 i=0; i<aServices.getLength(); ++i, ++pServices)
+ if (pServices->equals(_rServiceName))
+ return sal_True;
+
+ return sal_False;
+}
+
+//-------------------------------------------------------------------------
+Sequence< ::rtl::OUString > SAL_CALL SvNumberFormatsSupplierServiceObject::getSupportedServiceNames( ) throw(RuntimeException)
+{
+ Sequence< ::rtl::OUString > aSupported(1);
+ aSupported.getArray()[0] = PERSISTENT_SERVICE_NAME;
+ return aSupported;
+}
+
+//-------------------------------------------------------------------------
+::rtl::OUString SAL_CALL SvNumberFormatsSupplierServiceObject::getServiceName( ) throw(RuntimeException)
+{
+ return PERSISTENT_SERVICE_NAME;
+}
+
+//-------------------------------------------------------------------------
+void SAL_CALL SvNumberFormatsSupplierServiceObject::write( const Reference< XObjectOutputStream >& _rxOutStream ) throw(IOException, RuntimeException)
+{
+ ::osl::MutexGuard aGuard( getSharedMutex() );
+ implEnsureFormatter();
+
+ Reference< XOutputStream > xStream(_rxOutStream.get());
+ SvLockBytesRef aLockBytes = new SvOutputStreamOpenLockBytes(xStream);
+ SvStream aSvOutputSteam(aLockBytes);
+
+ m_pOwnFormatter->Save(aSvOutputSteam);
+}
+
+//-------------------------------------------------------------------------
+void SAL_CALL SvNumberFormatsSupplierServiceObject::read( const Reference< XObjectInputStream >& _rxInStream ) throw(IOException, RuntimeException)
+{
+ ::osl::MutexGuard aGuard( getSharedMutex() );
+ implEnsureFormatter();
+
+ Reference< XInputStream > xStream(_rxInStream.get());
+ SvInputStream aSvInputSteam(xStream);
+
+ m_pOwnFormatter->Load(aSvInputSteam);
+}
+
+//-------------------------------------------------------------------------
+Reference< XPropertySet > SAL_CALL SvNumberFormatsSupplierServiceObject::getNumberFormatSettings() throw(RuntimeException)
+{
+ ::osl::MutexGuard aGuard( getSharedMutex() );
+ implEnsureFormatter();
+ return SvNumberFormatsSupplierObj::getNumberFormatSettings();
+}
+
+//-------------------------------------------------------------------------
+Reference< XNumberFormats > SAL_CALL SvNumberFormatsSupplierServiceObject::getNumberFormats() throw(RuntimeException)
+{
+ ::osl::MutexGuard aGuard( getSharedMutex() );
+ implEnsureFormatter();
+ return SvNumberFormatsSupplierObj::getNumberFormats();
+}
+
+//-------------------------------------------------------------------------
+sal_Int64 SAL_CALL SvNumberFormatsSupplierServiceObject::getSomething( const Sequence< sal_Int8 >& aIdentifier ) throw (RuntimeException)
+{
+ sal_Int64 nReturn = SvNumberFormatsSupplierObj::getSomething( aIdentifier );
+ if ( nReturn )
+ // if somebody accesses internals then we should have the formatter
+ implEnsureFormatter();
+ return nReturn;
+}
+
+//-------------------------------------------------------------------------
+void SvNumberFormatsSupplierServiceObject::implEnsureFormatter()
+{
+ if (!m_pOwnFormatter)
+ {
+ // get the office's UI locale
+ SvtSysLocale aSysLocale;
+ Locale aOfficeLocale = aSysLocale.GetLocaleData().getLocale();
+
+ // initi with this locale
+ Sequence< Any > aFakedInitProps( 1 );
+ aFakedInitProps[0] <<= aOfficeLocale;
+
+ initialize( aFakedInitProps );
+ }
+}
+
diff --git a/svl/source/numbers/supservs.hxx b/svl/source/numbers/supservs.hxx
new file mode 100644
index 000000000000..7dbbfe27177d
--- /dev/null
+++ b/svl/source/numbers/supservs.hxx
@@ -0,0 +1,105 @@
+/*************************************************************************
+ *
+ * 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: supservs.hxx,v $
+ * $Revision: 1.7 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _SVTOOLS_NUMBERS_SUPPLIERSERVICE_HXX_
+#define _SVTOOLS_NUMBERS_SUPPLIERSERVICE_HXX_
+
+#include "numuno.hxx"
+#include <svl/zforlist.hxx>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/io/XPersistObject.hpp>
+
+//=========================================================================
+//= SvNumberFormatsSupplierServiceObject - a number formats supplier which
+//= - can be instantiated as an service
+//= - supports the ::com::sun::star::io::XPersistObject interface
+//= - works with it's own SvNumberFormatter instance
+//= - can be initialized (::com::sun::star::lang::XInitialization)
+//= with a specific language (i.e. ::com::sun::star::lang::Locale)
+//=========================================================================
+class SvNumberFormatsSupplierServiceObject
+ :protected SvNumberFormatsSupplierObj
+ ,public ::com::sun::star::lang::XInitialization
+ ,public ::com::sun::star::io::XPersistObject
+ ,public ::com::sun::star::lang::XServiceInfo
+{ // don't want the Set-/GetNumberFormatter to be accessable from outside
+
+ friend ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >
+ SAL_CALL SvNumberFormatsSupplierServiceObject_CreateInstance(
+ const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >&);
+
+protected:
+ SvNumberFormatter* m_pOwnFormatter;
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
+ m_xORB;
+
+public:
+ SvNumberFormatsSupplierServiceObject(const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& _rxORB);
+ ~SvNumberFormatsSupplierServiceObject();
+
+ // XInterface
+ virtual void SAL_CALL acquire() throw() { SvNumberFormatsSupplierObj::acquire(); }
+ virtual void SAL_CALL release() throw() { SvNumberFormatsSupplierObj::release(); }
+ virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& _rType ) throw(::com::sun::star::uno::RuntimeException)
+ { return SvNumberFormatsSupplierObj::queryInterface(_rType); }
+
+ // XAggregation
+ virtual ::com::sun::star::uno::Any SAL_CALL queryAggregation( const ::com::sun::star::uno::Type& _rType ) throw(::com::sun::star::uno::RuntimeException);
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments ) throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException);
+
+ // XServiceInfo
+ virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw(::com::sun::star::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw(::com::sun::star::uno::RuntimeException);
+
+ // XPersistObject
+ virtual ::rtl::OUString SAL_CALL getServiceName( ) throw(::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL write( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectOutputStream >& OutStream ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
+ virtual void SAL_CALL read( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XObjectInputStream >& InStream ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
+
+ // XNumberFormatsSupplier
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > SAL_CALL
+ getNumberFormatSettings() throw(::com::sun::star::uno::RuntimeException);
+ virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormats > SAL_CALL
+ getNumberFormats() throw(::com::sun::star::uno::RuntimeException);
+
+ // XUnoTunnler
+ virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw (::com::sun::star::uno::RuntimeException);
+
+protected:
+ void implEnsureFormatter();
+};
+
+
+#endif // _SVTOOLS_NUMBERS_SUPPLIERSERVICE_HXX_
+
diff --git a/svl/source/numbers/zforfind.cxx b/svl/source/numbers/zforfind.cxx
new file mode 100644
index 000000000000..372ae2b15abf
--- /dev/null
+++ b/svl/source/numbers/zforfind.cxx
@@ -0,0 +1,2819 @@
+/*************************************************************************
+ *
+ * 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: zforfind.cxx,v $
+ * $Revision: 1.51.96.1 $
+ *
+ * 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"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <float.h>
+#include <errno.h>
+#include <tools/date.hxx>
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <com/sun/star/i18n/CalendarFieldIndex.hpp>
+#include <unotools/digitgroupingiterator.hxx>
+
+#include <svl/zforlist.hxx> // NUMBERFORMAT_XXX
+#include "zforscan.hxx"
+#include <svl/zformat.hxx>
+
+#define _ZFORFIND_CXX
+#include "zforfind.hxx"
+#undef _ZFORFIND_CXX
+
+
+#ifndef DBG_UTIL
+#define NF_TEST_CALENDAR 0
+#else
+#define NF_TEST_CALENDAR 0
+#endif
+#if NF_TEST_CALENDAR
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/i18n/XExtendedCalendar.hpp>
+#endif
+
+
+const BYTE ImpSvNumberInputScan::nMatchedEndString = 0x01;
+const BYTE ImpSvNumberInputScan::nMatchedMidString = 0x02;
+const BYTE ImpSvNumberInputScan::nMatchedStartString = 0x04;
+const BYTE ImpSvNumberInputScan::nMatchedVirgin = 0x08;
+const BYTE ImpSvNumberInputScan::nMatchedUsedAsReturn = 0x10;
+
+/* It is not clear how we want timezones to be handled. Convert them to local
+ * time isn't wanted, as it isn't done in any other place and timezone
+ * information isn't stored anywhere. Ignoring them and pretending local time
+ * may be wrong too and might not be what the user expects. Keep the input as
+ * string so that no information is lost.
+ * Anyway, defining NF_RECOGNIZE_ISO8601_TIMEZONES to 1 would be the way how it
+ * would work, together with the nTimezonePos handling in GetTimeRef(). */
+#define NF_RECOGNIZE_ISO8601_TIMEZONES 0
+
+//---------------------------------------------------------------------------
+// Konstruktor
+
+ImpSvNumberInputScan::ImpSvNumberInputScan( SvNumberFormatter* pFormatterP )
+ :
+ pUpperMonthText( NULL ),
+ pUpperAbbrevMonthText( NULL ),
+ pUpperDayText( NULL ),
+ pUpperAbbrevDayText( NULL )
+{
+ pFormatter = pFormatterP;
+ pNullDate = new Date(30,12,1899);
+ nYear2000 = SvNumberFormatter::GetYear2000Default();
+ Reset();
+ ChangeIntl();
+}
+
+
+//---------------------------------------------------------------------------
+// Destruktor
+
+ImpSvNumberInputScan::~ImpSvNumberInputScan()
+{
+ Reset();
+ delete pNullDate;
+ delete [] pUpperMonthText;
+ delete [] pUpperAbbrevMonthText;
+ delete [] pUpperDayText;
+ delete [] pUpperAbbrevDayText;
+}
+
+
+//---------------------------------------------------------------------------
+// Reset
+
+void ImpSvNumberInputScan::Reset()
+{
+#if 0
+// ER 16.06.97 18:56 Vorbelegung erfolgt jetzt in NumberStringDivision,
+// wozu immer alles loeschen wenn einiges wieder benutzt oder gar nicht
+// gebraucht wird..
+ for (USHORT i = 0; i < SV_MAX_ANZ_INPUT_STRINGS; i++)
+ {
+ sStrArray[i].Erase();
+ nNums[i] = SV_MAX_ANZ_INPUT_STRINGS-1;
+ IsNum[i] = FALSE;
+ }
+#endif
+ nMonth = 0;
+ nMonthPos = 0;
+ nTimePos = 0;
+ nSign = 0;
+ nESign = 0;
+ nDecPos = 0;
+ nNegCheck = 0;
+ nAnzStrings = 0;
+ nAnzNums = 0;
+ nThousand = 0;
+ eScannedType = NUMBERFORMAT_UNDEFINED;
+ nAmPm = 0;
+ nPosThousandString = 0;
+ nLogical = 0;
+ nStringScanNumFor = 0;
+ nStringScanSign = 0;
+ nMatchedAllStrings = nMatchedVirgin;
+ nMayBeIso8601 = 0;
+ nTimezonePos = 0;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// static
+inline BOOL ImpSvNumberInputScan::MyIsdigit( sal_Unicode c )
+{
+ // If the input string wouldn't be converted using TransformInput() we'd
+ // to use something similar to the following and to adapt many places.
+#if 0
+ // use faster isdigit() if possible
+ if ( c < 128 )
+ return isdigit( (unsigned char) c ) != 0;
+ if ( c < 256 )
+ return FALSE;
+ String aTmp( c );
+ return pFormatter->GetCharClass()->isDigit( aTmp, 0 );
+#else
+ return c < 128 && isdigit( (unsigned char) c );
+#endif
+}
+
+
+//---------------------------------------------------------------------------
+//
+void ImpSvNumberInputScan::TransformInput( String& rStr )
+{
+ xub_StrLen nPos, nLen;
+ for ( nPos = 0, nLen = rStr.Len(); nPos < nLen; ++nPos )
+ {
+ if ( 256 <= rStr.GetChar( nPos ) &&
+ pFormatter->GetCharClass()->isDigit( rStr, nPos ) )
+ break;
+ }
+ if ( nPos < nLen )
+ rStr = pFormatter->GetNatNum()->getNativeNumberString( rStr,
+ pFormatter->GetLocale(), 0 );
+}
+
+
+//---------------------------------------------------------------------------
+// StringToDouble
+//
+// Only simple unsigned floating point values without any error detection,
+// decimal separator has to be '.'
+
+double ImpSvNumberInputScan::StringToDouble( const String& rStr, BOOL bForceFraction )
+{
+ double fNum = 0.0;
+ double fFrac = 0.0;
+ int nExp = 0;
+ xub_StrLen nPos = 0;
+ xub_StrLen nLen = rStr.Len();
+ BOOL bPreSep = !bForceFraction;
+
+ while (nPos < nLen)
+ {
+ if (rStr.GetChar(nPos) == '.')
+ bPreSep = FALSE;
+ else if (bPreSep)
+ fNum = fNum * 10.0 + (double) (rStr.GetChar(nPos) - '0');
+ else
+ {
+ fFrac = fFrac * 10.0 + (double) (rStr.GetChar(nPos) - '0');
+ --nExp;
+ }
+ nPos++;
+ }
+ if ( fFrac )
+ return fNum + ::rtl::math::pow10Exp( fFrac, nExp );
+ return fNum;
+}
+
+
+//---------------------------------------------------------------------------
+// NextNumberStringSymbol
+//
+// Zerlegt die Eingabe in Zahlen und Strings fuer die weitere
+// Verarbeitung (Turing-Maschine).
+//---------------------------------------------------------------------------
+// Ausgangs Zustand = GetChar
+//---------------+-------------------+-----------------------+---------------
+// Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
+//---------------+-------------------+-----------------------+---------------
+// GetChar | Ziffer | Symbol=Zeichen | GetValue
+// | Sonst | Symbol=Zeichen | GetString
+//---------------|-------------------+-----------------------+---------------
+// GetValue | Ziffer | Symbol=Symbol+Zeichen | GetValue
+// | Sonst | Dec(CharPos) | Stop
+//---------------+-------------------+-----------------------+---------------
+// GetString | Ziffer | Dec(CharPos) | Stop
+// | Sonst | Symbol=Symbol+Zeichen | GetString
+//---------------+-------------------+-----------------------+---------------
+
+enum ScanState // States der Turing-Maschine
+{
+ SsStop = 0,
+ SsStart = 1,
+ SsGetValue = 2,
+ SsGetString = 3
+};
+
+BOOL ImpSvNumberInputScan::NextNumberStringSymbol(
+ const sal_Unicode*& pStr,
+ String& rSymbol )
+{
+ BOOL isNumber = FALSE;
+ sal_Unicode cToken;
+ ScanState eState = SsStart;
+ register const sal_Unicode* pHere = pStr;
+ register xub_StrLen nChars = 0;
+
+ while ( ((cToken = *pHere) != 0) && eState != SsStop)
+ {
+ pHere++;
+ switch (eState)
+ {
+ case SsStart:
+ if ( MyIsdigit( cToken ) )
+ {
+ eState = SsGetValue;
+ isNumber = TRUE;
+ }
+ else
+ eState = SsGetString;
+ nChars++;
+ break;
+ case SsGetValue:
+ if ( MyIsdigit( cToken ) )
+ nChars++;
+ else
+ {
+ eState = SsStop;
+ pHere--;
+ }
+ break;
+ case SsGetString:
+ if ( !MyIsdigit( cToken ) )
+ nChars++;
+ else
+ {
+ eState = SsStop;
+ pHere--;
+ }
+ break;
+ default:
+ break;
+ } // switch
+ } // while
+
+ if ( nChars )
+ rSymbol.Assign( pStr, nChars );
+ else
+ rSymbol.Erase();
+
+ pStr = pHere;
+
+ return isNumber;
+}
+
+
+//---------------------------------------------------------------------------
+// SkipThousands
+
+// FIXME: should be grouping; it is only used though in case nAnzStrings is
+// near SV_MAX_ANZ_INPUT_STRINGS, in NumberStringDivision().
+
+BOOL ImpSvNumberInputScan::SkipThousands(
+ const sal_Unicode*& pStr,
+ String& rSymbol )
+{
+ BOOL res = FALSE;
+ sal_Unicode cToken;
+ const String& rThSep = pFormatter->GetNumThousandSep();
+ register const sal_Unicode* pHere = pStr;
+ ScanState eState = SsStart;
+ xub_StrLen nCounter = 0; // counts 3 digits
+
+ while ( ((cToken = *pHere) != 0) && eState != SsStop)
+ {
+ pHere++;
+ switch (eState)
+ {
+ case SsStart:
+ if ( StringPtrContains( rThSep, pHere-1, 0 ) )
+ {
+ nCounter = 0;
+ eState = SsGetValue;
+ pHere += rThSep.Len()-1;
+ }
+ else
+ {
+ eState = SsStop;
+ pHere--;
+ }
+ break;
+ case SsGetValue:
+ if ( MyIsdigit( cToken ) )
+ {
+ rSymbol += cToken;
+ nCounter++;
+ if (nCounter == 3)
+ {
+ eState = SsStart;
+ res = TRUE; // .000 combination found
+ }
+ }
+ else
+ {
+ eState = SsStop;
+ pHere--;
+ }
+ break;
+ default:
+ break;
+ } // switch
+ } // while
+
+ if (eState == SsGetValue) // break witth less than 3 digits
+ {
+ if ( nCounter )
+ rSymbol.Erase( rSymbol.Len() - nCounter, nCounter );
+ pHere -= nCounter + rThSep.Len(); // put back ThSep also
+ }
+ pStr = pHere;
+
+ return res;
+}
+
+
+//---------------------------------------------------------------------------
+// NumberStringDivision
+
+void ImpSvNumberInputScan::NumberStringDivision( const String& rString )
+{
+ const sal_Unicode* pStr = rString.GetBuffer();
+ const sal_Unicode* const pEnd = pStr + rString.Len();
+ while ( pStr < pEnd && nAnzStrings < SV_MAX_ANZ_INPUT_STRINGS )
+ {
+ if ( NextNumberStringSymbol( pStr, sStrArray[nAnzStrings] ) )
+ { // Zahl
+ IsNum[nAnzStrings] = TRUE;
+ nNums[nAnzNums] = nAnzStrings;
+ nAnzNums++;
+ if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS - 7 &&
+ nPosThousandString == 0) // nur einmal
+ if ( SkipThousands( pStr, sStrArray[nAnzStrings] ) )
+ nPosThousandString = nAnzStrings;
+ }
+ else
+ {
+ IsNum[nAnzStrings] = FALSE;
+ }
+ nAnzStrings++;
+ }
+}
+
+
+//---------------------------------------------------------------------------
+// Whether rString contains rWhat at nPos
+
+BOOL ImpSvNumberInputScan::StringContainsImpl( const String& rWhat,
+ const String& rString, xub_StrLen nPos )
+{
+ if ( nPos + rWhat.Len() <= rString.Len() )
+ return StringPtrContainsImpl( rWhat, rString.GetBuffer(), nPos );
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// Whether pString contains rWhat at nPos
+
+BOOL ImpSvNumberInputScan::StringPtrContainsImpl( const String& rWhat,
+ const sal_Unicode* pString, xub_StrLen nPos )
+{
+ if ( rWhat.Len() == 0 )
+ return FALSE;
+ register const sal_Unicode* pWhat = rWhat.GetBuffer();
+ register const sal_Unicode* const pEnd = pWhat + rWhat.Len();
+ register const sal_Unicode* pStr = pString + nPos;
+ while ( pWhat < pEnd )
+ {
+ if ( *pWhat != *pStr )
+ return FALSE;
+ pWhat++;
+ pStr++;
+ }
+ return TRUE;
+}
+
+
+//---------------------------------------------------------------------------
+// SkipChar
+//
+// ueberspringt genau das angegebene Zeichen
+
+inline BOOL ImpSvNumberInputScan::SkipChar( sal_Unicode c, const String& rString,
+ xub_StrLen& nPos )
+{
+ if ((nPos < rString.Len()) && (rString.GetChar(nPos) == c))
+ {
+ nPos++;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// SkipBlanks
+//
+// Ueberspringt Leerzeichen
+
+inline void ImpSvNumberInputScan::SkipBlanks( const String& rString,
+ xub_StrLen& nPos )
+{
+ if ( nPos < rString.Len() )
+ {
+ register const sal_Unicode* p = rString.GetBuffer() + nPos;
+ while ( *p == ' ' )
+ {
+ nPos++;
+ p++;
+ }
+ }
+}
+
+
+//---------------------------------------------------------------------------
+// SkipString
+//
+// jump over rWhat in rString at nPos
+
+inline BOOL ImpSvNumberInputScan::SkipString( const String& rWhat,
+ const String& rString, xub_StrLen& nPos )
+{
+ if ( StringContains( rWhat, rString, nPos ) )
+ {
+ nPos = nPos + rWhat.Len();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// GetThousandSep
+//
+// recognizes exactly ,111 in {3} and {3,2} or ,11 in {3,2} grouping
+
+inline BOOL ImpSvNumberInputScan::GetThousandSep(
+ const String& rString,
+ xub_StrLen& nPos,
+ USHORT nStringPos )
+{
+ const String& rSep = pFormatter->GetNumThousandSep();
+ // Is it an ordinary space instead of a non-breaking space?
+ bool bSpaceBreak = rSep.GetChar(0) == 0xa0 && rString.GetChar(0) == 0x20 &&
+ rSep.Len() == 1 && rString.Len() == 1;
+ if (!( (rString == rSep || bSpaceBreak) // nothing else
+ && nStringPos < nAnzStrings - 1 // safety first!
+ && IsNum[nStringPos+1] )) // number follows
+ return FALSE; // no? => out
+
+ utl::DigitGroupingIterator aGrouping(
+ pFormatter->GetLocaleData()->getDigitGrouping());
+ // Match ,### in {3} or ,## in {3,2}
+ /* FIXME: this could be refined to match ,## in {3,2} only if ,##,## or
+ * ,##,### and to match ,### in {3,2} only if it's the last. However,
+ * currently there is no track kept where group separators occur. In {3,2}
+ * #,###,### and #,##,## would be valid input, which maybe isn't even bad
+ * for #,###,###. Other combinations such as #,###,## maybe not. */
+ xub_StrLen nLen = sStrArray[nStringPos+1].Len();
+ if (nLen == aGrouping.get() // with 3 (or so) digits
+ || nLen == aGrouping.advance().get() // or with 2 (or 3 or so) digits
+ || nPosThousandString == nStringPos+1 // or concatenated
+ )
+ {
+ nPos = nPos + rSep.Len();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// GetLogical
+//
+// Conversion of text to logial value
+// "TRUE" => 1:
+// "FALSE"=> -1:
+// else => 0:
+
+short ImpSvNumberInputScan::GetLogical( const String& rString )
+{
+ short res;
+
+ const ImpSvNumberformatScan* pFS = pFormatter->GetFormatScanner();
+ if ( rString == pFS->GetTrueString() )
+ res = 1;
+ else if ( rString == pFS->GetFalseString() )
+ res = -1;
+ else
+ res = 0;
+
+ return res;
+}
+
+
+//---------------------------------------------------------------------------
+// GetMonth
+//
+// Converts a string containing a month name (JAN, January) at nPos into the
+// month number (negative if abbreviated), returns 0 if nothing found
+
+short ImpSvNumberInputScan::GetMonth( const String& rString, xub_StrLen& nPos )
+{
+ // #102136# The correct English form of month September abbreviated is
+ // SEPT, but almost every data contains SEP instead.
+ static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
+ static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
+
+ short res = 0; // no month found
+
+ if (rString.Len() > nPos) // only if needed
+ {
+ if ( !bTextInitialized )
+ InitText();
+ sal_Int16 nMonths = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
+ for ( sal_Int16 i = 0; i < nMonths; i++ )
+ {
+ if ( StringContains( pUpperMonthText[i], rString, nPos ) )
+ { // full names first
+ nPos = nPos + pUpperMonthText[i].Len();
+ res = i+1;
+ break; // for
+ }
+ else if ( StringContains( pUpperAbbrevMonthText[i], rString, nPos ) )
+ { // abbreviated
+ nPos = nPos + pUpperAbbrevMonthText[i].Len();
+ res = sal::static_int_cast< short >(-(i+1)); // negative
+ break; // for
+ }
+ else if ( i == 8 && pUpperAbbrevMonthText[i] == aSeptCorrect &&
+ StringContains( aSepShortened, rString, nPos ) )
+ { // #102136# SEPT/SEP
+ nPos = nPos + aSepShortened.Len();
+ res = sal::static_int_cast< short >(-(i+1)); // negative
+ break; // for
+ }
+ }
+ }
+
+ return res;
+}
+
+
+//---------------------------------------------------------------------------
+// GetDayOfWeek
+//
+// Converts a string containing a DayOfWeek name (Mon, Monday) at nPos into the
+// DayOfWeek number + 1 (negative if abbreviated), returns 0 if nothing found
+
+int ImpSvNumberInputScan::GetDayOfWeek( const String& rString, xub_StrLen& nPos )
+{
+ int res = 0; // no day found
+
+ if (rString.Len() > nPos) // only if needed
+ {
+ if ( !bTextInitialized )
+ InitText();
+ sal_Int16 nDays = pFormatter->GetCalendar()->getNumberOfDaysInWeek();
+ for ( sal_Int16 i = 0; i < nDays; i++ )
+ {
+ if ( StringContains( pUpperDayText[i], rString, nPos ) )
+ { // full names first
+ nPos = nPos + pUpperDayText[i].Len();
+ res = i + 1;
+ break; // for
+ }
+ if ( StringContains( pUpperAbbrevDayText[i], rString, nPos ) )
+ { // abbreviated
+ nPos = nPos + pUpperAbbrevDayText[i].Len();
+ res = -(i + 1); // negative
+ break; // for
+ }
+ }
+ }
+
+ return res;
+}
+
+
+//---------------------------------------------------------------------------
+// GetCurrency
+//
+// Lesen eines Waehrungssysmbols
+// '$' => TRUE
+// sonst => FALSE
+
+BOOL ImpSvNumberInputScan::GetCurrency( const String& rString, xub_StrLen& nPos,
+ const SvNumberformat* pFormat )
+{
+ if ( rString.Len() > nPos )
+ {
+ if ( !aUpperCurrSymbol.Len() )
+ { // if no format specified the currency of the initialized formatter
+ LanguageType eLang = (pFormat ? pFormat->GetLanguage() :
+ pFormatter->GetLanguage());
+ aUpperCurrSymbol = pFormatter->GetCharClass()->upper(
+ SvNumberFormatter::GetCurrencyEntry( eLang ).GetSymbol() );
+ }
+ if ( StringContains( aUpperCurrSymbol, rString, nPos ) )
+ {
+ nPos = nPos + aUpperCurrSymbol.Len();
+ return TRUE;
+ }
+ if ( pFormat )
+ {
+ String aSymbol, aExtension;
+ if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
+ {
+ if ( aSymbol.Len() <= rString.Len() - nPos )
+ {
+ pFormatter->GetCharClass()->toUpper( aSymbol );
+ if ( StringContains( aSymbol, rString, nPos ) )
+ {
+ nPos = nPos + aSymbol.Len();
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// GetTimeAmPm
+//
+// Lesen des Zeitsymbols (AM od. PM) f. kurze Zeitangabe
+//
+// Rueckgabe:
+// "AM" od. "PM" => TRUE
+// sonst => FALSE
+//
+// nAmPos:
+// "AM" => 1
+// "PM" => -1
+// sonst => 0
+
+BOOL ImpSvNumberInputScan::GetTimeAmPm( const String& rString, xub_StrLen& nPos )
+{
+
+ if ( rString.Len() > nPos )
+ {
+ const CharClass* pChr = pFormatter->GetCharClass();
+ const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
+ if ( StringContains( pChr->upper( pLoc->getTimeAM() ), rString, nPos ) )
+ {
+ nAmPm = 1;
+ nPos = nPos + pLoc->getTimeAM().Len();
+ return TRUE;
+ }
+ else if ( StringContains( pChr->upper( pLoc->getTimePM() ), rString, nPos ) )
+ {
+ nAmPm = -1;
+ nPos = nPos + pLoc->getTimePM().Len();
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// GetDecSep
+//
+// Lesen eines Dezimaltrenners (',')
+// ',' => TRUE
+// sonst => FALSE
+
+inline BOOL ImpSvNumberInputScan::GetDecSep( const String& rString, xub_StrLen& nPos )
+{
+ if ( rString.Len() > nPos )
+ {
+ const String& rSep = pFormatter->GetNumDecimalSep();
+ if ( rString.Equals( rSep, nPos, rSep.Len() ) )
+ {
+ nPos = nPos + rSep.Len();
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// read a hundredth seconds separator
+
+inline BOOL ImpSvNumberInputScan::GetTime100SecSep( const String& rString, xub_StrLen& nPos )
+{
+ if ( rString.Len() > nPos )
+ {
+ const String& rSep = pFormatter->GetLocaleData()->getTime100SecSep();
+ if ( rString.Equals( rSep, nPos, rSep.Len() ) )
+ {
+ nPos = nPos + rSep.Len();
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// GetSign
+//
+// Lesen eines Vorzeichens, auch Klammer !?!
+// '+' => 1
+// '-' => -1
+// '(' => -1, nNegCheck = 1
+// sonst => 0
+
+int ImpSvNumberInputScan::GetSign( const String& rString, xub_StrLen& nPos )
+{
+ if (rString.Len() > nPos)
+ switch (rString.GetChar(nPos))
+ {
+ case '+':
+ nPos++;
+ return 1;
+ case '(': // '(' aehnlich wie '-' ?!?
+ nNegCheck = 1;
+ //! fallthru
+ case '-':
+ nPos++;
+ return -1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+//---------------------------------------------------------------------------
+// GetESign
+//
+// Lesen eines Vorzeichens, gedacht fuer Exponent ?!?
+// '+' => 1
+// '-' => -1
+// sonst => 0
+
+short ImpSvNumberInputScan::GetESign( const String& rString, xub_StrLen& nPos )
+{
+ if (rString.Len() > nPos)
+ switch (rString.GetChar(nPos))
+ {
+ case '+':
+ nPos++;
+ return 1;
+ case '-':
+ nPos++;
+ return -1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+//---------------------------------------------------------------------------
+// GetNextNumber
+//
+// i counts string portions, j counts numbers thereof.
+// It should had been called SkipNumber instead.
+
+inline BOOL ImpSvNumberInputScan::GetNextNumber( USHORT& i, USHORT& j )
+{
+ if ( i < nAnzStrings && IsNum[i] )
+ {
+ j++;
+ i++;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// GetTimeRef
+
+void ImpSvNumberInputScan::GetTimeRef(
+ double& fOutNumber,
+ USHORT nIndex, // j-value of the first numeric time part of input, default 0
+ USHORT nAnz ) // count of numeric time parts
+{
+ USHORT nHour;
+ USHORT nMinute = 0;
+ USHORT nSecond = 0;
+ double fSecond100 = 0.0;
+ USHORT nStartIndex = nIndex;
+
+ if (nTimezonePos)
+ {
+ // find first timezone number index and adjust count
+ for (USHORT j=0; j<nAnzNums; ++j)
+ {
+ if (nNums[j] == nTimezonePos)
+ {
+ // nAnz is not total count, but count of time relevant strings.
+ if (nStartIndex < j && j - nStartIndex < nAnz)
+ nAnz = j - nStartIndex;
+ break; // for
+ }
+ }
+ }
+
+ if (nDecPos == 2 && (nAnz == 3 || nAnz == 2)) // 20:45.5 or 45.5
+ nHour = 0;
+ else if (nIndex - nStartIndex < nAnz)
+ nHour = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
+ else
+ {
+ nHour = 0;
+ DBG_ERRORFILE( "ImpSvNumberInputScan::GetTimeRef: bad number index");
+ }
+ if (nDecPos == 2 && nAnz == 2) // 45.5
+ nMinute = 0;
+ else if (nIndex - nStartIndex < nAnz)
+ nMinute = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
+ if (nIndex - nStartIndex < nAnz)
+ nSecond = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
+ if (nIndex - nStartIndex < nAnz)
+ fSecond100 = StringToDouble( sStrArray[nNums[nIndex]], TRUE );
+ if (nAmPm == -1 && nHour != 12) // PM
+ nHour += 12;
+ else if (nAmPm == 1 && nHour == 12) // 12 AM
+ nHour = 0;
+
+ fOutNumber = ((double)nHour*3600 +
+ (double)nMinute*60 +
+ (double)nSecond +
+ fSecond100)/86400.0;
+}
+
+
+//---------------------------------------------------------------------------
+// ImplGetDay
+
+USHORT ImpSvNumberInputScan::ImplGetDay( USHORT nIndex )
+{
+ USHORT nRes = 0;
+
+ if (sStrArray[nNums[nIndex]].Len() <= 2)
+ {
+ USHORT nNum = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
+ if (nNum <= 31)
+ nRes = nNum;
+ }
+
+ return nRes;
+}
+
+
+//---------------------------------------------------------------------------
+// ImplGetMonth
+
+USHORT ImpSvNumberInputScan::ImplGetMonth( USHORT nIndex )
+{
+ // preset invalid month number
+ USHORT nRes = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
+
+ if (sStrArray[nNums[nIndex]].Len() <= 2)
+ {
+ USHORT nNum = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
+ if ( 0 < nNum && nNum <= nRes )
+ nRes = nNum - 1; // zero based for CalendarFieldIndex::MONTH
+ }
+
+ return nRes;
+}
+
+
+//---------------------------------------------------------------------------
+// ImplGetYear
+//
+// 30 -> 1930, 29 -> 2029, oder 56 -> 1756, 55 -> 1855, ...
+
+USHORT ImpSvNumberInputScan::ImplGetYear( USHORT nIndex )
+{
+ USHORT nYear = 0;
+
+ if (sStrArray[nNums[nIndex]].Len() <= 4)
+ {
+ nYear = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
+ nYear = SvNumberFormatter::ExpandTwoDigitYear( nYear, nYear2000 );
+ }
+
+ return nYear;
+}
+
+//---------------------------------------------------------------------------
+
+bool ImpSvNumberInputScan::MayBeIso8601()
+{
+ if (nMayBeIso8601 == 0)
+ {
+ if (nAnzNums >= 3 && nNums[0] < nAnzStrings &&
+ sStrArray[nNums[0]].ToInt32() > 31)
+ nMayBeIso8601 = 1;
+ else
+ nMayBeIso8601 = 2;
+ }
+ return nMayBeIso8601 == 1;
+}
+
+//---------------------------------------------------------------------------
+// GetDateRef
+
+BOOL ImpSvNumberInputScan::GetDateRef( double& fDays, USHORT& nCounter,
+ const SvNumberformat* pFormat )
+{
+ using namespace ::com::sun::star::i18n;
+ NfEvalDateFormat eEDF;
+ int nFormatOrder;
+ if ( pFormat && ((pFormat->GetType() & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE) )
+ {
+ eEDF = pFormatter->GetEvalDateFormat();
+ switch ( eEDF )
+ {
+ case NF_EVALDATEFORMAT_INTL :
+ case NF_EVALDATEFORMAT_FORMAT :
+ nFormatOrder = 1; // only one loop
+ break;
+ default:
+ nFormatOrder = 2;
+ if ( nMatchedAllStrings )
+ eEDF = NF_EVALDATEFORMAT_FORMAT_INTL;
+ // we have a complete match, use it
+ }
+ }
+ else
+ {
+ eEDF = NF_EVALDATEFORMAT_INTL;
+ nFormatOrder = 1;
+ }
+ BOOL res = TRUE;
+
+ const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
+ CalendarWrapper* pCal = pFormatter->GetCalendar();
+ for ( int nTryOrder = 1; nTryOrder <= nFormatOrder; nTryOrder++ )
+ {
+ pCal->setGregorianDateTime( Date() ); // today
+ String aOrgCalendar; // empty => not changed yet
+ DateFormat DateFmt;
+ BOOL bFormatTurn;
+ switch ( eEDF )
+ {
+ case NF_EVALDATEFORMAT_INTL :
+ bFormatTurn = FALSE;
+ DateFmt = pLoc->getDateFormat();
+ break;
+ case NF_EVALDATEFORMAT_FORMAT :
+ bFormatTurn = TRUE;
+ DateFmt = pFormat->GetDateOrder();
+ break;
+ case NF_EVALDATEFORMAT_INTL_FORMAT :
+ if ( nTryOrder == 1 )
+ {
+ bFormatTurn = FALSE;
+ DateFmt = pLoc->getDateFormat();
+ }
+ else
+ {
+ bFormatTurn = TRUE;
+ DateFmt = pFormat->GetDateOrder();
+ }
+ break;
+ case NF_EVALDATEFORMAT_FORMAT_INTL :
+ if ( nTryOrder == 2 )
+ {
+ bFormatTurn = FALSE;
+ DateFmt = pLoc->getDateFormat();
+ }
+ else
+ {
+ bFormatTurn = TRUE;
+ DateFmt = pFormat->GetDateOrder();
+ }
+ break;
+ default:
+ DBG_ERROR( "ImpSvNumberInputScan::GetDateRef: unknown NfEvalDateFormat" );
+ DateFmt = YMD;
+ bFormatTurn = FALSE;
+ }
+ if ( bFormatTurn )
+ {
+#if 0
+/* TODO:
+We are currently not able to fully support a switch to another calendar during
+input for the following reasons:
+1. We do have a problem if both (locale's default and format's) calendars
+ define the same YMD order and use the same date separator, there is no way
+ to distinguish between them if the input results in valid calendar input for
+ both calendars. How to solve? Would NfEvalDateFormat be sufficient? Should
+ it always be set to NF_EVALDATEFORMAT_FORMAT_INTL and thus the format's
+ calendar be preferred? This could be confusing if a Calc cell was formatted
+ different to the locale's default and has no content yet, then the user has
+ no clue about the format or calendar being set.
+2. In Calc cell edit mode a date is always displayed and edited using the
+ default edit format of the default calendar (normally being Gregorian). If
+ input was ambiguous due to issue #1 we'd need a mechanism to tell that a
+ date was edited and not newly entered. Not feasible. Otherwise we'd need a
+ mechanism to use a specific edit format with a specific calendar according
+ to the format set.
+3. For some calendars like Japanese Gengou we'd need era input, which isn't
+ implemented at all. Though this is a rare and special case, forcing a
+ calendar dependent edit format as suggested in item #2 might require era
+ input, if it shouldn't result in a fallback to Gregorian calendar.
+4. Last and least: the GetMonth() method currently only matches month names of
+ the default calendar. Alternating month names of the actual format's
+ calendar would have to be implemented. No problem.
+
+*/
+ if ( pFormat->IsOtherCalendar( nStringScanNumFor ) )
+ pFormat->SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ else
+ pFormat->SwitchToSpecifiedCalendar( aOrgCalendar, fOrgDateTime,
+ nStringScanNumFor );
+#endif
+ }
+
+ res = TRUE;
+ nCounter = 0;
+ // For incomplete dates, always assume first day of month if not specified.
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
+
+ switch (nAnzNums) // count of numbers in string
+ {
+ case 0: // none
+ if (nMonthPos) // only month (Jan)
+ pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
+ else
+ res = FALSE;
+ break;
+
+ case 1: // only one number
+ nCounter = 1;
+ switch (nMonthPos) // where is the month
+ {
+ case 0: // not found => only day entered
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ break;
+ case 1: // month at the beginning (Jan 01)
+ pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
+ switch (DateFmt)
+ {
+ case MDY:
+ case YMD:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ break;
+ case DMY:
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ case 3: // month at the end (10 Jan)
+ pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
+ switch (DateFmt)
+ {
+ case DMY:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ break;
+ case YMD:
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ default:
+ res = FALSE;
+ break;
+ } // switch (nMonthPos)
+ break;
+
+ case 2: // 2 numbers
+ nCounter = 2;
+ switch (nMonthPos) // where is the month
+ {
+ case 0: // not found
+ {
+ bool bHadExact;
+ sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
+ if ( 0xff < nExactDateOrder && nExactDateOrder <= 0xffff )
+ { // formatted as date and exactly 2 parts
+ bHadExact = true;
+ switch ( (nExactDateOrder >> 8) & 0xff )
+ {
+ case 'Y':
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ break;
+ case 'M':
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
+ break;
+ case 'D':
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ break;
+ default:
+ bHadExact = false;
+ }
+ switch ( nExactDateOrder & 0xff )
+ {
+ case 'Y':
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
+ break;
+ case 'M':
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
+ break;
+ case 'D':
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
+ break;
+ default:
+ bHadExact = false;
+ }
+ }
+ else
+ bHadExact = false;
+ if ( !bHadExact || !pCal->isValid() )
+ {
+ if ( !bHadExact && nExactDateOrder )
+ pCal->setGregorianDateTime( Date() ); // reset today
+ switch (DateFmt)
+ {
+ case MDY:
+ // M D
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
+ if ( !pCal->isValid() ) // 2nd try
+ { // M Y
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
+ }
+ break;
+ case DMY:
+ // D M
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
+ if ( !pCal->isValid() ) // 2nd try
+ { // M Y
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
+ }
+ break;
+ case YMD:
+ // M D
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
+ if ( !pCal->isValid() ) // 2nd try
+ { // Y M
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ }
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ }
+ }
+ break;
+ case 1: // month at the beginning (Jan 01 01)
+ {
+ // The input is valid as MDY in almost any
+ // constellation, there is no date order (M)YD except if
+ // set in a format applied.
+ pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
+ sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
+ if ((((nExactDateOrder >> 8) & 0xff) == 'Y') && ((nExactDateOrder & 0xff) == 'D'))
+ {
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ }
+ else
+ {
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
+ }
+ }
+ break;
+ case 2: // month in the middle (10 Jan 94)
+ pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
+ switch (DateFmt)
+ {
+ case MDY: // yes, "10-Jan-94" is valid
+ case DMY:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
+ break;
+ case YMD:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ default: // else, e.g. month at the end (94 10 Jan)
+ res = FALSE;
+ break;
+ } // switch (nMonthPos)
+ break;
+
+ default: // more than two numbers (31.12.94 8:23) (31.12. 8:23)
+ switch (nMonthPos) // where is the month
+ {
+ case 0: // not found
+ {
+ nCounter = 3;
+ if ( nTimePos > 1 )
+ { // find first time number index (should only be 3 or 2 anyway)
+ for ( USHORT j = 0; j < nAnzNums; j++ )
+ {
+ if ( nNums[j] == nTimePos - 2 )
+ {
+ nCounter = j;
+ break; // for
+ }
+ }
+ }
+ // ISO 8601 yyyy-mm-dd forced recognition
+ DateFormat eDF = (MayBeIso8601() ? YMD : DateFmt);
+ switch (eDF)
+ {
+ case MDY:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
+ if ( nCounter > 2 )
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
+ break;
+ case DMY:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
+ if ( nCounter > 2 )
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
+ break;
+ case YMD:
+ if ( nCounter > 2 )
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(2) );
+ pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ }
+ break;
+ case 1: // month at the beginning (Jan 01 01 8:23)
+ nCounter = 2;
+ switch (DateFmt)
+ {
+ case MDY:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ case 2: // month in the middle (10 Jan 94 8:23)
+ nCounter = 2;
+ pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
+ switch (DateFmt)
+ {
+ case DMY:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
+ break;
+ case YMD:
+ pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
+ pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
+ break;
+ default:
+ res = FALSE;
+ break;
+ }
+ break;
+ default: // else, e.g. month at the end (94 10 Jan 8:23)
+ nCounter = 2;
+ res = FALSE;
+ break;
+ } // switch (nMonthPos)
+ break;
+ } // switch (nAnzNums)
+
+ if ( res && pCal->isValid() )
+ {
+ double fDiff = DateTime(*pNullDate) - pCal->getEpochStart();
+ fDays = ::rtl::math::approxFloor( pCal->getLocalDateTime() );
+ fDays -= fDiff;
+ nTryOrder = nFormatOrder; // break for
+ }
+ else
+ res = FALSE;
+
+ if ( aOrgCalendar.Len() )
+ pCal->loadCalendar( aOrgCalendar, pLoc->getLocale() ); // restore calendar
+
+#if NF_TEST_CALENDAR
+{
+ using namespace ::com::sun::star;
+ struct entry { const char* lan; const char* cou; const char* cal; };
+ const entry cals[] = {
+ { "en", "US", "gregorian" },
+ { "ar", "TN", "hijri" },
+ { "he", "IL", "jewish" },
+ { "ja", "JP", "gengou" },
+ { "ko", "KR", "hanja_yoil" },
+ { "th", "TH", "buddhist" },
+ { "zh", "TW", "ROC" },
+ {0,0,0}
+ };
+ lang::Locale aLocale;
+ sal_Bool bValid;
+ sal_Int16 nDay, nMyMonth, nYear, nHour, nMinute, nSecond;
+ sal_Int16 nDaySet, nMonthSet, nYearSet, nHourSet, nMinuteSet, nSecondSet;
+ sal_Int16 nZO, nDST1, nDST2, nDST, nZOmillis, nDST1millis, nDST2millis, nDSTmillis;
+ sal_Int32 nZoneInMillis, nDST1InMillis, nDST2InMillis;
+ uno::Reference< lang::XMultiServiceFactory > xSMgr =
+ ::comphelper::getProcessServiceFactory();
+ uno::Reference< ::com::sun::star::i18n::XExtendedCalendar > xCal(
+ xSMgr->createInstance( ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.i18n.LocaleCalendar" ) ) ),
+ uno::UNO_QUERY );
+ for ( const entry* p = cals; p->lan; ++p )
+ {
+ aLocale.Language = ::rtl::OUString::createFromAscii( p->lan );
+ aLocale.Country = ::rtl::OUString::createFromAscii( p->cou );
+ xCal->loadCalendar( ::rtl::OUString::createFromAscii( p->cal ),
+ aLocale );
+ double nDateTime = 0.0; // 1-Jan-1970 00:00:00
+ nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
+ nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
+ nZoneInMillis = static_cast<sal_Int32>(nZO) * 60000 +
+ (nZO < 0 ? -1 : 1) * static_cast<sal_uInt16>(nZOmillis);
+ nDST1 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
+ nDST1millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
+ nDST1InMillis = static_cast<sal_Int32>(nDST1) * 60000 +
+ (nDST1 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST1millis);
+ nDateTime -= (double)(nZoneInMillis + nDST1InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
+ xCal->setDateTime( nDateTime );
+ nDST2 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
+ nDST2millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
+ nDST2InMillis = static_cast<sal_Int32>(nDST2) * 60000 +
+ (nDST2 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST2millis);
+ if ( nDST1InMillis != nDST2InMillis )
+ {
+ nDateTime = 0.0 - (double)(nZoneInMillis + nDST2InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
+ xCal->setDateTime( nDateTime );
+ }
+ nDaySet = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
+ nMonthSet = xCal->getValue( i18n::CalendarFieldIndex::MONTH );
+ nYearSet = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
+ nHourSet = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
+ nMinuteSet = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
+ nSecondSet = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
+ nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
+ nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
+ nDST = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
+ nDSTmillis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
+ xCal->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDaySet );
+ xCal->setValue( i18n::CalendarFieldIndex::MONTH, nMonthSet );
+ xCal->setValue( i18n::CalendarFieldIndex::YEAR, nYearSet );
+ xCal->setValue( i18n::CalendarFieldIndex::HOUR, nHourSet );
+ xCal->setValue( i18n::CalendarFieldIndex::MINUTE, nMinuteSet );
+ xCal->setValue( i18n::CalendarFieldIndex::SECOND, nSecondSet );
+ bValid = xCal->isValid();
+ nDay = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
+ nMyMonth= xCal->getValue( i18n::CalendarFieldIndex::MONTH );
+ nYear = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
+ nHour = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
+ nMinute = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
+ nSecond = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
+ bValid = bValid && nDay == nDaySet && nMyMonth == nMonthSet && nYear ==
+ nYearSet && nHour == nHourSet && nMinute == nMinuteSet && nSecond
+ == nSecondSet;
+ }
+}
+#endif // NF_TEST_CALENDAR
+
+ }
+
+ return res;
+}
+
+
+//---------------------------------------------------------------------------
+// ScanStartString
+//
+// ersten String analysieren
+// Alles weg => TRUE
+// sonst => FALSE
+
+BOOL ImpSvNumberInputScan::ScanStartString( const String& rString,
+ const SvNumberformat* pFormat )
+{
+ xub_StrLen nPos = 0;
+ int nDayOfWeek;
+
+ // First of all, eat leading blanks
+ SkipBlanks(rString, nPos);
+
+ // Yes, nMatchedAllStrings should know about the sign position
+ nSign = GetSign(rString, nPos);
+ if ( nSign ) // sign?
+ SkipBlanks(rString, nPos);
+
+ // #102371# match against format string only if start string is not a sign character
+ if ( nMatchedAllStrings && !(nSign && rString.Len() == 1) )
+ { // Match against format in any case, so later on for a "x1-2-3" input
+ // we may distinguish between a xy-m-d (or similar) date and a x0-0-0
+ // format. No sign detection here!
+ if ( ScanStringNumFor( rString, nPos, pFormat, 0, TRUE ) )
+ nMatchedAllStrings |= nMatchedStartString;
+ else
+ nMatchedAllStrings = 0;
+ }
+
+ if ( GetDecSep(rString, nPos) ) // decimal separator in start string
+ {
+ nDecPos = 1;
+ SkipBlanks(rString, nPos);
+ }
+ else if ( GetCurrency(rString, nPos, pFormat) ) // currency (DM 1)?
+ {
+ eScannedType = NUMBERFORMAT_CURRENCY; // !!! it IS currency !!!
+ SkipBlanks(rString, nPos);
+ if (nSign == 0) // no sign yet
+ {
+ nSign = GetSign(rString, nPos);
+ if ( nSign ) // DM -1
+ SkipBlanks(rString, nPos);
+ }
+ }
+ else
+ {
+ nMonth = GetMonth(rString, nPos);
+ if ( nMonth ) // month (Jan 1)?
+ {
+ eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!!
+ nMonthPos = 1; // month at the beginning
+ if ( nMonth < 0 )
+ SkipChar( '.', rString, nPos ); // abbreviated
+ SkipBlanks(rString, nPos);
+ }
+ else
+ {
+ nDayOfWeek = GetDayOfWeek( rString, nPos );
+ if ( nDayOfWeek )
+ { // day of week is just parsed away
+ eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!!
+ if ( nPos < rString.Len() )
+ {
+ if ( nDayOfWeek < 0 )
+ { // abbreviated
+ if ( rString.GetChar( nPos ) == '.' )
+ ++nPos;
+ }
+ else
+ { // full long name
+ SkipBlanks(rString, nPos);
+ SkipString( pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(), rString, nPos );
+ }
+ SkipBlanks(rString, nPos);
+ nMonth = GetMonth(rString, nPos);
+ if ( nMonth ) // month (Jan 1)?
+ {
+ nMonthPos = 1; // month a the beginning
+ if ( nMonth < 0 )
+ SkipChar( '.', rString, nPos ); // abbreviated
+ SkipBlanks(rString, nPos);
+ }
+ }
+ }
+ }
+ }
+
+ if (nPos < rString.Len()) // not everything consumed
+ {
+ // Does input StartString equal StartString of format?
+ // This time with sign detection!
+ if ( !ScanStringNumFor( rString, nPos, pFormat, 0 ) )
+ return MatchedReturn();
+ }
+
+ return TRUE;
+}
+
+
+//---------------------------------------------------------------------------
+// ScanMidString
+//
+// String in der Mitte analysieren
+// Alles weg => TRUE
+// sonst => FALSE
+
+BOOL ImpSvNumberInputScan::ScanMidString( const String& rString,
+ USHORT nStringPos, const SvNumberformat* pFormat )
+{
+ xub_StrLen nPos = 0;
+ short eOldScannedType = eScannedType;
+
+ if ( nMatchedAllStrings )
+ { // Match against format in any case, so later on for a "1-2-3-4" input
+ // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
+ // format.
+ if ( ScanStringNumFor( rString, 0, pFormat, nStringPos ) )
+ nMatchedAllStrings |= nMatchedMidString;
+ else
+ nMatchedAllStrings = 0;
+ }
+
+ SkipBlanks(rString, nPos);
+ if (GetDecSep(rString, nPos)) // decimal separator?
+ {
+ if (nDecPos == 1 || nDecPos == 3) // .12.4 or 1.E2.1
+ return MatchedReturn();
+ else if (nDecPos == 2) // . dup: 12.4.
+ {
+ if (bDecSepInDateSeps) // . also date separator
+ {
+ if ( eScannedType != NUMBERFORMAT_UNDEFINED &&
+ eScannedType != NUMBERFORMAT_DATE &&
+ eScannedType != NUMBERFORMAT_DATETIME) // already another type
+ return MatchedReturn();
+ if (eScannedType == NUMBERFORMAT_UNDEFINED)
+ eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
+ SkipBlanks(rString, nPos);
+ }
+ else
+ return MatchedReturn();
+ }
+ else
+ {
+ nDecPos = 2; // . in mid string
+ SkipBlanks(rString, nPos);
+ }
+ }
+ else if ( ((eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME)
+ && GetTime100SecSep( rString, nPos ) )
+ { // hundredth seconds separator
+ if ( nDecPos )
+ return MatchedReturn();
+ nDecPos = 2; // . in mid string
+ SkipBlanks(rString, nPos);
+ }
+
+ if (SkipChar('/', rString, nPos)) // fraction?
+ {
+ if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
+ && eScannedType != NUMBERFORMAT_DATE) // except date
+ return MatchedReturn(); // => jan/31/1994
+ else if ( eScannedType != NUMBERFORMAT_DATE // analyzed date until now
+ && ( eSetType == NUMBERFORMAT_FRACTION // and preset was fraction
+ || (nAnzNums == 3 // or 3 numbers
+ && nStringPos > 2) ) ) // and what ???
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_FRACTION; // !!! it IS a fraction
+ }
+ else
+ nPos--; // put '/' back
+ }
+
+ if (GetThousandSep(rString, nPos, nStringPos)) // 1,000
+ {
+ if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
+ && eScannedType != NUMBERFORMAT_CURRENCY) // except currency
+ return MatchedReturn();
+ nThousand++;
+ }
+
+ const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
+ const String& rDate = pFormatter->GetDateSep();
+ const String& rTime = pLoc->getTimeSep();
+ sal_Unicode cTime = rTime.GetChar(0);
+ SkipBlanks(rString, nPos);
+ if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/
+ || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY:
+ || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean
+ || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation!
+ {
+ if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
+ && eScannedType != NUMBERFORMAT_DATE) // except date
+ return MatchedReturn();
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
+ short nTmpMonth = GetMonth(rString, nPos); // 10. Jan 94
+ if (nMonth && nTmpMonth) // month dup
+ return MatchedReturn();
+ if (nTmpMonth)
+ {
+ nMonth = nTmpMonth;
+ nMonthPos = 2; // month in the middle
+ if ( nMonth < 0 && SkipChar( '.', rString, nPos ) )
+ ; // short month may be abbreviated Jan.
+ else if ( SkipChar( '-', rString, nPos ) )
+ ; // #79632# recognize 17-Jan-2001 to be a date
+ // #99065# short and long month name
+ else
+ SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
+ SkipBlanks(rString, nPos);
+ }
+ }
+
+ short nTempMonth = GetMonth(rString, nPos); // month in the middle (10 Jan 94)
+ if (nTempMonth)
+ {
+ if (nMonth != 0) // month dup
+ return MatchedReturn();
+ if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
+ && eScannedType != NUMBERFORMAT_DATE) // except date
+ return MatchedReturn();
+ eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
+ nMonth = nTempMonth;
+ nMonthPos = 2; // month in the middle
+ if ( nMonth < 0 )
+ SkipChar( '.', rString, nPos ); // abbreviated
+ SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
+ SkipBlanks(rString, nPos);
+ }
+
+ if ( SkipChar('E', rString, nPos) // 10E, 10e, 10,Ee
+ || SkipChar('e', rString, nPos) )
+ {
+ if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
+ return MatchedReturn();
+ else
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_SCIENTIFIC; // !!! it IS scientific
+ if ( nThousand+2 == nAnzNums // special case 1.E2
+ && nDecPos == 2 )
+ nDecPos = 3; // 1,100.E2 1,100,100.E3
+ }
+ nESign = GetESign(rString, nPos); // signed exponent?
+ SkipBlanks(rString, nPos);
+ }
+
+ if ( SkipString(rTime, rString, nPos) ) // time separator?
+ {
+ if (nDecPos) // already . => maybe error
+ {
+ if (bDecSepInDateSeps) // . also date sep
+ {
+ if ( eScannedType != NUMBERFORMAT_DATE && // already another type than date
+ eScannedType != NUMBERFORMAT_DATETIME) // or date time
+ return MatchedReturn();
+ if (eScannedType == NUMBERFORMAT_DATE)
+ nDecPos = 0; // reset for time transition
+ }
+ else
+ return MatchedReturn();
+ }
+ if ( ( eScannedType == NUMBERFORMAT_DATE // already date type
+ || eScannedType == NUMBERFORMAT_DATETIME) // or date time
+ && nAnzNums > 3) // and more than 3 numbers? (31.Dez.94 8:23)
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_DATETIME; // !!! it IS date with time
+ }
+ else if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
+ && eScannedType != NUMBERFORMAT_TIME) // except time
+ return MatchedReturn();
+ else
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_TIME; // !!! it IS a time
+ }
+ if ( !nTimePos )
+ nTimePos = nStringPos + 1;
+ }
+
+ if (nPos < rString.Len())
+ {
+ switch (eScannedType)
+ {
+ case NUMBERFORMAT_DATE:
+ if (nMonthPos == 1 && pLoc->getLongDateFormat() == MDY)
+ {
+ // #68232# recognize long date separators like ", " in "September 5, 1999"
+ if (SkipString( pLoc->getLongDateDaySep(), rString, nPos ))
+ SkipBlanks( rString, nPos );
+ }
+ else if (nStringPos == 5 && nPos == 0 && rString.Len() == 1 &&
+ rString.GetChar(0) == 'T' && MayBeIso8601())
+ {
+ // ISO 8601 combined date and time, yyyy-mm-ddThh:mm
+ ++nPos;
+ }
+ break;
+#if NF_RECOGNIZE_ISO8601_TIMEZONES
+ case NUMBERFORMAT_DATETIME:
+ if (nPos == 0 && rString.Len() == 1 && nStringPos >= 9 &&
+ MayBeIso8601())
+ {
+ // ISO 8601 timezone offset
+ switch (rString.GetChar(0))
+ {
+ case '+':
+ case '-':
+ if (nStringPos == nAnzStrings-2 ||
+ nStringPos == nAnzStrings-4)
+ {
+ ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx[[:]yy]
+ // nTimezonePos needed for GetTimeRef()
+ if (!nTimezonePos)
+ nTimezonePos = nStringPos + 1;
+ }
+ break;
+ case ':':
+ if (nTimezonePos && nStringPos >= 11 &&
+ nStringPos == nAnzStrings-2)
+ ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx:yy
+ break;
+ }
+ }
+ break;
+#endif
+ }
+ }
+
+ if (nPos < rString.Len()) // not everything consumed?
+ {
+ if ( nMatchedAllStrings & ~nMatchedVirgin )
+ eScannedType = eOldScannedType;
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+//---------------------------------------------------------------------------
+// ScanEndString
+//
+// Schlussteil analysieren
+// Alles weg => TRUE
+// sonst => FALSE
+
+BOOL ImpSvNumberInputScan::ScanEndString( const String& rString,
+ const SvNumberformat* pFormat )
+{
+ xub_StrLen nPos = 0;
+
+ if ( nMatchedAllStrings )
+ { // Match against format in any case, so later on for a "1-2-3-4" input
+ // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
+ // format.
+ if ( ScanStringNumFor( rString, 0, pFormat, 0xFFFF ) )
+ nMatchedAllStrings |= nMatchedEndString;
+ else
+ nMatchedAllStrings = 0;
+ }
+
+ SkipBlanks(rString, nPos);
+ if (GetDecSep(rString, nPos)) // decimal separator?
+ {
+ if (nDecPos == 1 || nDecPos == 3) // .12.4 or 12.E4.
+ return MatchedReturn();
+ else if (nDecPos == 2) // . dup: 12.4.
+ {
+ if (bDecSepInDateSeps) // . also date sep
+ {
+ if ( eScannedType != NUMBERFORMAT_UNDEFINED &&
+ eScannedType != NUMBERFORMAT_DATE &&
+ eScannedType != NUMBERFORMAT_DATETIME) // already another type
+ return MatchedReturn();
+ if (eScannedType == NUMBERFORMAT_UNDEFINED)
+ eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
+ SkipBlanks(rString, nPos);
+ }
+ else
+ return MatchedReturn();
+ }
+ else
+ {
+ nDecPos = 3; // . in end string
+ SkipBlanks(rString, nPos);
+ }
+ }
+
+ if ( nSign == 0 // conflict - not signed
+ && eScannedType != NUMBERFORMAT_DATE) // and not date
+//!? catch time too?
+ { // not signed yet
+ nSign = GetSign(rString, nPos); // 1- DM
+ if (nNegCheck) // '(' as sign
+ return MatchedReturn();
+ }
+
+ SkipBlanks(rString, nPos);
+ if (nNegCheck && SkipChar(')', rString, nPos)) // skip ')' if appropriate
+ {
+ nNegCheck = 0;
+ SkipBlanks(rString, nPos);
+ }
+
+ if ( GetCurrency(rString, nPos, pFormat) ) // currency symbol?
+ {
+ if (eScannedType != NUMBERFORMAT_UNDEFINED) // currency dup
+ return MatchedReturn();
+ else
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_CURRENCY;
+ } // behind currency a '-' is allowed
+ if (nSign == 0) // not signed yet
+ {
+ nSign = GetSign(rString, nPos); // DM -
+ SkipBlanks(rString, nPos);
+ if (nNegCheck) // 3 DM (
+ return MatchedReturn();
+ }
+ if ( nNegCheck && eScannedType == NUMBERFORMAT_CURRENCY
+ && SkipChar(')', rString, nPos) )
+ {
+ nNegCheck = 0; // ')' skipped
+ SkipBlanks(rString, nPos); // only if currency
+ }
+ }
+
+ if ( SkipChar('%', rString, nPos) ) // 1 %
+ {
+ if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
+ return MatchedReturn();
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_PERCENT;
+ }
+
+ const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
+ const String& rDate = pFormatter->GetDateSep();
+ const String& rTime = pLoc->getTimeSep();
+ if ( SkipString(rTime, rString, nPos) ) // 10:
+ {
+ if (nDecPos) // already , => error
+ return MatchedReturn();
+ if (eScannedType == NUMBERFORMAT_DATE && nAnzNums > 2) // 31.Dez.94 8:
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_DATETIME;
+ }
+ else if (eScannedType != NUMBERFORMAT_UNDEFINED &&
+ eScannedType != NUMBERFORMAT_TIME) // already another type
+ return MatchedReturn();
+ else
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_TIME;
+ }
+ if ( !nTimePos )
+ nTimePos = nAnzStrings;
+ }
+
+ sal_Unicode cTime = rTime.GetChar(0);
+ if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/
+ || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY:
+ || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean
+ || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation!
+ {
+ if (eScannedType != NUMBERFORMAT_UNDEFINED &&
+ eScannedType != NUMBERFORMAT_DATE) // already another type
+ return MatchedReturn();
+ else
+ {
+ SkipBlanks(rString, nPos);
+ eScannedType = NUMBERFORMAT_DATE;
+ }
+ short nTmpMonth = GetMonth(rString, nPos); // 10. Jan
+ if (nMonth && nTmpMonth) // month dup
+ return MatchedReturn();
+ if (nTmpMonth)
+ {
+ nMonth = nTmpMonth;
+ nMonthPos = 3; // month at end
+ if ( nMonth < 0 )
+ SkipChar( '.', rString, nPos ); // abbreviated
+ SkipBlanks(rString, nPos);
+ }
+ }
+
+ short nTempMonth = GetMonth(rString, nPos); // 10 Jan
+ if (nTempMonth)
+ {
+ if (nMonth) // month dup
+ return MatchedReturn();
+ if (eScannedType != NUMBERFORMAT_UNDEFINED &&
+ eScannedType != NUMBERFORMAT_DATE) // already another type
+ return MatchedReturn();
+ eScannedType = NUMBERFORMAT_DATE;
+ nMonth = nTempMonth;
+ nMonthPos = 3; // month at end
+ if ( nMonth < 0 )
+ SkipChar( '.', rString, nPos ); // abbreviated
+ SkipBlanks(rString, nPos);
+ }
+
+ xub_StrLen nOrigPos = nPos;
+ if (GetTimeAmPm(rString, nPos))
+ {
+ if (eScannedType != NUMBERFORMAT_UNDEFINED &&
+ eScannedType != NUMBERFORMAT_TIME &&
+ eScannedType != NUMBERFORMAT_DATETIME) // already another type
+ return MatchedReturn();
+ else
+ {
+ // If not already scanned as time, 6.78am does not result in 6
+ // seconds and 78 hundredths in the morning. Keep as suffix.
+ if (eScannedType != NUMBERFORMAT_TIME && nDecPos == 2 && nAnzNums == 2)
+ nPos = nOrigPos; // rewind am/pm
+ else
+ {
+ SkipBlanks(rString, nPos);
+ if ( eScannedType != NUMBERFORMAT_DATETIME )
+ eScannedType = NUMBERFORMAT_TIME;
+ }
+ }
+ }
+
+ if ( nNegCheck && SkipChar(')', rString, nPos) )
+ {
+ if (eScannedType == NUMBERFORMAT_CURRENCY) // only if currency
+ {
+ nNegCheck = 0; // skip ')'
+ SkipBlanks(rString, nPos);
+ }
+ else
+ return MatchedReturn();
+ }
+
+ if ( nPos < rString.Len() &&
+ (eScannedType == NUMBERFORMAT_DATE
+ || eScannedType == NUMBERFORMAT_DATETIME) )
+ { // day of week is just parsed away
+ xub_StrLen nOldPos = nPos;
+ const String& rSep = pFormatter->GetLocaleData()->getLongDateDayOfWeekSep();
+ if ( StringContains( rSep, rString, nPos ) )
+ {
+ nPos = nPos + rSep.Len();
+ SkipBlanks(rString, nPos);
+ }
+ int nDayOfWeek = GetDayOfWeek( rString, nPos );
+ if ( nDayOfWeek )
+ {
+ if ( nPos < rString.Len() )
+ {
+ if ( nDayOfWeek < 0 )
+ { // short
+ if ( rString.GetChar( nPos ) == '.' )
+ ++nPos;
+ }
+ SkipBlanks(rString, nPos);
+ }
+ }
+ else
+ nPos = nOldPos;
+ }
+
+#if NF_RECOGNIZE_ISO8601_TIMEZONES
+ if (nPos == 0 && eScannedType == NUMBERFORMAT_DATETIME &&
+ rString.Len() == 1 && rString.GetChar(0) == 'Z' && MayBeIso8601())
+ {
+ // ISO 8601 timezone UTC yyyy-mm-ddThh:mmZ
+ ++nPos;
+ }
+#endif
+
+ if (nPos < rString.Len()) // everything consumed?
+ {
+ // does input EndString equal EndString in Format?
+ if ( !ScanStringNumFor( rString, nPos, pFormat, 0xFFFF ) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOL ImpSvNumberInputScan::ScanStringNumFor(
+ const String& rString, // String to scan
+ xub_StrLen nPos, // Position until which was consumed
+ const SvNumberformat* pFormat, // The format to match
+ USHORT nString, // Substring of format, 0xFFFF => last
+ BOOL bDontDetectNegation // Suppress sign detection
+ )
+{
+ if ( !pFormat )
+ return FALSE;
+ const ::utl::TransliterationWrapper* pTransliteration = pFormatter->GetTransliteration();
+ const String* pStr;
+ String aString( rString );
+ BOOL bFound = FALSE;
+ BOOL bFirst = TRUE;
+ BOOL bContinue = TRUE;
+ USHORT nSub;
+ do
+ {
+ // Don't try "lower" subformats ff the very first match was the second
+ // or third subformat.
+ nSub = nStringScanNumFor;
+ do
+ { // Step through subformats, first positive, then negative, then
+ // other, but not the last (text) subformat.
+ pStr = pFormat->GetNumForString( nSub, nString, TRUE );
+ if ( pStr && pTransliteration->isEqual( aString, *pStr ) )
+ {
+ bFound = TRUE;
+ bContinue = FALSE;
+ }
+ else if ( nSub < 2 )
+ ++nSub;
+ else
+ bContinue = FALSE;
+ } while ( bContinue );
+ if ( !bFound && bFirst && nPos )
+ { // try remaining substring
+ bFirst = FALSE;
+ aString.Erase( 0, nPos );
+ bContinue = TRUE;
+ }
+ } while ( bContinue );
+
+ if ( !bFound )
+ {
+ if ( !bDontDetectNegation && (nString == 0) && !bFirst && (nSign < 0)
+ && pFormat->IsNegativeRealNegative() )
+ { // simply negated twice? --1
+ aString.EraseAllChars( ' ' );
+ if ( (aString.Len() == 1) && (aString.GetChar(0) == '-') )
+ {
+ bFound = TRUE;
+ nStringScanSign = -1;
+ nSub = 0; //! not 1
+ }
+ }
+ if ( !bFound )
+ return FALSE;
+ }
+ else if ( !bDontDetectNegation && (nSub == 1) &&
+ pFormat->IsNegativeRealNegative() )
+ { // negative
+ if ( nStringScanSign < 0 )
+ {
+ if ( (nSign < 0) && (nStringScanNumFor != 1) )
+ nStringScanSign = 1; // triple negated --1 yyy
+ }
+ else if ( nStringScanSign == 0 )
+ {
+ if ( nSign < 0 )
+ { // nSign and nStringScanSign will be combined later,
+ // flip sign if doubly negated
+ if ( (nString == 0) && !bFirst
+ && SvNumberformat::HasStringNegativeSign( aString ) )
+ nStringScanSign = -1; // direct double negation
+ else if ( pFormat->IsNegativeWithoutSign() )
+ nStringScanSign = -1; // indirect double negation
+ }
+ else
+ nStringScanSign = -1;
+ }
+ else // > 0
+ nStringScanSign = -1;
+ }
+ nStringScanNumFor = nSub;
+ return TRUE;
+}
+
+
+//---------------------------------------------------------------------------
+// IsNumberFormatMain
+//
+// Recognizes types of number, exponential, fraction, percent, currency, date, time.
+// Else text => return FALSE
+
+BOOL ImpSvNumberInputScan::IsNumberFormatMain(
+ const String& rString, // string to be analyzed
+ double& , // OUT: result as number, if possible
+ const SvNumberformat* pFormat ) // maybe number format set to match against
+{
+ Reset();
+ NumberStringDivision( rString ); // breakdown into strings and numbers
+ if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS) // too many elements
+ return FALSE; // Njet, Nope, ...
+
+ if (nAnzNums == 0) // no number in input
+ {
+ if ( nAnzStrings > 0 )
+ {
+ // Here we may change the original, we don't need it anymore.
+ // This saves copies and ToUpper() in GetLogical() and is faster.
+ String& rStrArray = sStrArray[0];
+ rStrArray.EraseTrailingChars( ' ' );
+ rStrArray.EraseLeadingChars( ' ' );
+ nLogical = GetLogical( rStrArray );
+ if ( nLogical )
+ {
+ eScannedType = NUMBERFORMAT_LOGICAL; // !!! it's a BOOLEAN
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ return TRUE;
+ }
+ else
+ return FALSE; // simple text
+ }
+ else
+ return FALSE; // simple text
+ }
+
+ USHORT i = 0; // mark any symbol
+ USHORT j = 0; // mark only numbers
+
+ switch ( nAnzNums )
+ {
+ case 1 : // Exactly 1 number in input
+ { // nAnzStrings >= 1
+ if (GetNextNumber(i,j)) // i=1,0
+ { // Number at start
+ if (eSetType == NUMBERFORMAT_FRACTION) // Fraction 1 = 1/1
+ {
+ if (i >= nAnzStrings || // no end string nor decimal separator
+ sStrArray[i] == pFormatter->GetNumDecimalSep())
+ {
+ eScannedType = NUMBERFORMAT_FRACTION;
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ return TRUE;
+ }
+ }
+ }
+ else
+ { // Analyze start string
+ if (!ScanStartString( sStrArray[i], pFormat )) // i=0
+ return FALSE; // already an error
+ i++; // next symbol, i=1
+ }
+ GetNextNumber(i,j); // i=1,2
+ if (eSetType == NUMBERFORMAT_FRACTION) // Fraction -1 = -1/1
+ {
+ if (nSign && !nNegCheck && // Sign +, -
+ eScannedType == NUMBERFORMAT_UNDEFINED && // not date or currency
+ nDecPos == 0 && // no previous decimal separator
+ (i >= nAnzStrings || // no end string nor decimal separator
+ sStrArray[i] == pFormatter->GetNumDecimalSep())
+ )
+ {
+ eScannedType = NUMBERFORMAT_FRACTION;
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ return TRUE;
+ }
+ }
+ if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
+ return FALSE;
+ }
+ break;
+ case 2 : // Exactly 2 numbers in input
+ { // nAnzStrings >= 3
+ if (!GetNextNumber(i,j)) // i=1,0
+ { // Analyze start string
+ if (!ScanStartString( sStrArray[i], pFormat ))
+ return FALSE; // already an error
+ i++; // i=1
+ }
+ GetNextNumber(i,j); // i=1,2
+ if ( !ScanMidString( sStrArray[i], i, pFormat ) )
+ return FALSE;
+ i++; // next symbol, i=2,3
+ GetNextNumber(i,j); // i=3,4
+ if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
+ return FALSE;
+ if (eSetType == NUMBERFORMAT_FRACTION) // -1,200. as fraction
+ {
+ if (!nNegCheck && // no sign '('
+ eScannedType == NUMBERFORMAT_UNDEFINED &&
+ (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
+ )
+ {
+ eScannedType = NUMBERFORMAT_FRACTION;
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ return TRUE;
+ }
+ }
+ }
+ break;
+ case 3 : // Exactly 3 numbers in input
+ { // nAnzStrings >= 5
+ if (!GetNextNumber(i,j)) // i=1,0
+ { // Analyze start string
+ if (!ScanStartString( sStrArray[i], pFormat ))
+ return FALSE; // already an error
+ i++; // i=1
+ if (nDecPos == 1) // decimal separator at start => error
+ return FALSE;
+ }
+ GetNextNumber(i,j); // i=1,2
+ if ( !ScanMidString( sStrArray[i], i, pFormat ) )
+ return FALSE;
+ i++; // i=2,3
+ if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end
+ return FALSE;
+ GetNextNumber(i,j); // i=3,4
+ if ( !ScanMidString( sStrArray[i], i, pFormat ) )
+ return FALSE;
+ i++; // i=4,5
+ GetNextNumber(i,j); // i=5,6
+ if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
+ return FALSE;
+ if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction
+ {
+ if (!nNegCheck && // no sign '('
+ eScannedType == NUMBERFORMAT_UNDEFINED &&
+ (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
+ )
+ {
+ eScannedType = NUMBERFORMAT_FRACTION;
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ return TRUE;
+ }
+ }
+ if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
+ return FALSE; // #36857# not a real fraction
+ }
+ break;
+ default: // More than 3 numbers in input
+ { // nAnzStrings >= 7
+ if (!GetNextNumber(i,j)) // i=1,0
+ { // Analyze startstring
+ if (!ScanStartString( sStrArray[i], pFormat ))
+ return FALSE; // already an error
+ i++; // i=1
+ if (nDecPos == 1) // decimal separator at start => error
+ return FALSE;
+ }
+ GetNextNumber(i,j); // i=1,2
+ if ( !ScanMidString( sStrArray[i], i, pFormat ) )
+ return FALSE;
+ i++; // i=2,3
+ USHORT nThOld = 10; // just not 0 or 1
+ while (nThOld != nThousand && j < nAnzNums-1)
+ // Execute at least one time
+ // but leave one number.
+ { // Loop over group separators
+ nThOld = nThousand;
+ if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end
+ return FALSE;
+ GetNextNumber(i,j);
+ if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
+ return FALSE;
+ i++;
+ }
+ if (eScannedType == NUMBERFORMAT_DATE || // long date or
+ eScannedType == NUMBERFORMAT_TIME || // long time or
+ eScannedType == NUMBERFORMAT_UNDEFINED) // long number
+ {
+ for (USHORT k = j; k < nAnzNums-1; k++)
+ {
+ if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at endd
+ return FALSE;
+ GetNextNumber(i,j);
+ if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
+ return FALSE;
+ i++;
+ }
+ }
+ GetNextNumber(i,j);
+ if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
+ return FALSE;
+ if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction
+ {
+ if (!nNegCheck && // no sign '('
+ eScannedType == NUMBERFORMAT_UNDEFINED &&
+ (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
+ )
+ {
+ eScannedType = NUMBERFORMAT_FRACTION;
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ return TRUE;
+ }
+ }
+ if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
+ return FALSE; // #36857# not a real fraction
+ }
+ }
+
+ if (eScannedType == NUMBERFORMAT_UNDEFINED)
+ {
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ // did match including nMatchedUsedAsReturn
+ BOOL bDidMatch = (nMatchedAllStrings != 0);
+ if ( nMatchedAllStrings )
+ {
+ BOOL bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
+ nStringScanNumFor, nAnzStrings, nAnzNums ) : FALSE);
+ if ( !bMatch )
+ nMatchedAllStrings = 0;
+ }
+ if ( nMatchedAllStrings )
+ eScannedType = eSetType;
+ else if ( bDidMatch )
+ return FALSE;
+ else
+ eScannedType = NUMBERFORMAT_NUMBER;
+ // everything else should have been recognized by now
+ }
+ else if ( eScannedType == NUMBERFORMAT_DATE )
+ { // the very relaxed date input checks may interfere with a preset format
+ nMatchedAllStrings &= ~nMatchedVirgin;
+ BOOL bWasReturn = ((nMatchedAllStrings & nMatchedUsedAsReturn) != 0);
+ if ( nMatchedAllStrings )
+ {
+ BOOL bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
+ nStringScanNumFor, nAnzStrings, nAnzNums ) : FALSE);
+ if ( !bMatch )
+ nMatchedAllStrings = 0;
+ }
+ if ( nMatchedAllStrings )
+ eScannedType = eSetType;
+ else if ( bWasReturn )
+ return FALSE;
+ }
+ else
+ nMatchedAllStrings = 0; // reset flag to no substrings matched
+
+ return TRUE;
+}
+
+
+//---------------------------------------------------------------------------
+// return TRUE or FALSE depending on the nMatched... state and remember usage
+BOOL ImpSvNumberInputScan::MatchedReturn()
+{
+ if ( nMatchedAllStrings & ~nMatchedVirgin )
+ {
+ nMatchedAllStrings |= nMatchedUsedAsReturn;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//---------------------------------------------------------------------------
+// Initialize uppercase months and weekdays
+
+void ImpSvNumberInputScan::InitText()
+{
+ sal_Int32 j, nElems;
+ const CharClass* pChrCls = pFormatter->GetCharClass();
+ const CalendarWrapper* pCal = pFormatter->GetCalendar();
+ delete [] pUpperMonthText;
+ delete [] pUpperAbbrevMonthText;
+ ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > xElems
+ = pCal->getMonths();
+ nElems = xElems.getLength();
+ pUpperMonthText = new String[nElems];
+ pUpperAbbrevMonthText = new String[nElems];
+ for ( j=0; j<nElems; j++ )
+ {
+ pUpperMonthText[j] = pChrCls->upper( xElems[j].FullName );
+ pUpperAbbrevMonthText[j] = pChrCls->upper( xElems[j].AbbrevName );
+ }
+ delete [] pUpperDayText;
+ delete [] pUpperAbbrevDayText;
+ xElems = pCal->getDays();
+ nElems = xElems.getLength();
+ pUpperDayText = new String[nElems];
+ pUpperAbbrevDayText = new String[nElems];
+ for ( j=0; j<nElems; j++ )
+ {
+ pUpperDayText[j] = pChrCls->upper( xElems[j].FullName );
+ pUpperAbbrevDayText[j] = pChrCls->upper( xElems[j].AbbrevName );
+ }
+ bTextInitialized = TRUE;
+}
+
+
+//===========================================================================
+// P U B L I C
+
+//---------------------------------------------------------------------------
+// ChangeIntl
+//
+// MUST be called if International/Locale is changed
+
+void ImpSvNumberInputScan::ChangeIntl()
+{
+ sal_Unicode cDecSep = pFormatter->GetNumDecimalSep().GetChar(0);
+ bDecSepInDateSeps = ( cDecSep == '-' ||
+ cDecSep == '/' ||
+ cDecSep == '.' ||
+ cDecSep == pFormatter->GetDateSep().GetChar(0) );
+ bTextInitialized = FALSE;
+ aUpperCurrSymbol.Erase();
+}
+
+
+//---------------------------------------------------------------------------
+// ChangeNullDate
+
+void ImpSvNumberInputScan::ChangeNullDate(
+ const USHORT Day,
+ const USHORT Month,
+ const USHORT Year )
+{
+ if ( pNullDate )
+ *pNullDate = Date(Day, Month, Year);
+ else
+ pNullDate = new Date(Day, Month, Year);
+}
+
+
+//---------------------------------------------------------------------------
+// IsNumberFormat
+//
+// => does rString represent a number (also date, time et al)
+
+BOOL ImpSvNumberInputScan::IsNumberFormat(
+ const String& rString, // string to be analyzed
+ short& F_Type, // IN: old type, OUT: new type
+ double& fOutNumber, // OUT: number if convertable
+ const SvNumberformat* pFormat ) // maybe a number format to match against
+{
+ String sResString;
+ String aString;
+ BOOL res; // return value
+ eSetType = F_Type; // old type set
+
+ if ( !rString.Len() )
+ res = FALSE;
+ else if (rString.Len() > 308) // arbitrary
+ res = FALSE;
+ else
+ {
+ // NoMoreUpperNeeded, all comparisons on UpperCase
+ aString = pFormatter->GetCharClass()->upper( rString );
+ // convert native number to ASCII if necessary
+ TransformInput( aString );
+ res = IsNumberFormatMain( aString, fOutNumber, pFormat );
+ }
+
+ if (res)
+ {
+ if ( nNegCheck // ')' not found for '('
+ || (nSign && (eScannedType == NUMBERFORMAT_DATE
+ || eScannedType == NUMBERFORMAT_DATETIME))
+ ) // signed date/datetime
+ res = FALSE;
+ else
+ { // check count of partial number strings
+ switch (eScannedType)
+ {
+ case NUMBERFORMAT_PERCENT:
+ case NUMBERFORMAT_CURRENCY:
+ case NUMBERFORMAT_NUMBER:
+ if (nDecPos == 1) // .05
+ {
+ // matched MidStrings function like group separators
+ if ( nMatchedAllStrings )
+ nThousand = nAnzNums - 1;
+ else if ( nAnzNums != 1 )
+ res = FALSE;
+ }
+ else if (nDecPos == 2) // 1.05
+ {
+ // matched MidStrings function like group separators
+ if ( nMatchedAllStrings )
+ nThousand = nAnzNums - 1;
+ else if ( nAnzNums != nThousand+2 )
+ res = FALSE;
+ }
+ else // 1,100 or 1,100.
+ {
+ // matched MidStrings function like group separators
+ if ( nMatchedAllStrings )
+ nThousand = nAnzNums - 1;
+ else if ( nAnzNums != nThousand+1 )
+ res = FALSE;
+ }
+ break;
+
+ case NUMBERFORMAT_SCIENTIFIC: // 1.0e-2
+ if (nDecPos == 1) // .05
+ {
+ if (nAnzNums != 2)
+ res = FALSE;
+ }
+ else if (nDecPos == 2) // 1.05
+ {
+ if (nAnzNums != nThousand+3)
+ res = FALSE;
+ }
+ else // 1,100 or 1,100.
+ {
+ if (nAnzNums != nThousand+2)
+ res = FALSE;
+ }
+ break;
+
+ case NUMBERFORMAT_DATE:
+ if (nMonth)
+ { // month name and numbers
+ if (nAnzNums > 2)
+ res = FALSE;
+ }
+ else
+ {
+ if (nAnzNums > 3)
+ res = FALSE;
+ }
+ break;
+
+ case NUMBERFORMAT_TIME:
+ if (nDecPos)
+ { // hundredth seconds included
+ if (nAnzNums > 4)
+ res = FALSE;
+ }
+ else
+ {
+ if (nAnzNums > 3)
+ res = FALSE;
+ }
+ break;
+
+ case NUMBERFORMAT_DATETIME:
+ if (nMonth)
+ { // month name and numbers
+ if (nDecPos)
+ { // hundredth seconds included
+ if (nAnzNums > 6)
+ res = FALSE;
+ }
+ else
+ {
+ if (nAnzNums > 5)
+ res = FALSE;
+ }
+ }
+ else
+ {
+ if (nDecPos)
+ { // hundredth seconds included
+ if (nAnzNums > 7)
+ res = FALSE;
+ }
+ else
+ {
+ if (nAnzNums > 6)
+ res = FALSE;
+ }
+ }
+ break;
+
+ default:
+ break;
+ } // switch
+ } // else
+ } // if (res)
+
+ if (res)
+ { // we finally have a number
+ switch (eScannedType)
+ {
+ case NUMBERFORMAT_LOGICAL:
+ if (nLogical == 1)
+ fOutNumber = 1.0; // True
+ else if (nLogical == -1)
+ fOutNumber = 0.0; // False
+ else
+ res = FALSE; // Oops
+ break;
+
+ case NUMBERFORMAT_PERCENT:
+ case NUMBERFORMAT_CURRENCY:
+ case NUMBERFORMAT_NUMBER:
+ case NUMBERFORMAT_SCIENTIFIC:
+ case NUMBERFORMAT_DEFINED: // if no category detected handle as number
+ {
+ if ( nDecPos == 1 ) // . at start
+ sResString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0." ) );
+ else
+ sResString.Erase();
+ USHORT k;
+ for ( k = 0; k <= nThousand; k++)
+ sResString += sStrArray[nNums[k]]; // integer part
+ if ( nDecPos == 2 && k < nAnzNums ) // . somewhere
+ {
+ sResString += '.';
+ USHORT nStop = (eScannedType == NUMBERFORMAT_SCIENTIFIC ?
+ nAnzNums-1 : nAnzNums);
+ for ( ; k < nStop; k++)
+ sResString += sStrArray[nNums[k]]; // fractional part
+ }
+
+ if (eScannedType != NUMBERFORMAT_SCIENTIFIC)
+ fOutNumber = StringToDouble(sResString);
+ else
+ { // append exponent
+ sResString += 'E';
+ if ( nESign == -1 )
+ sResString += '-';
+ sResString += sStrArray[nNums[nAnzNums-1]];
+ rtl_math_ConversionStatus eStatus;
+ fOutNumber = ::rtl::math::stringToDouble(
+ sResString, '.', ',', &eStatus, NULL );
+ if ( eStatus == rtl_math_ConversionStatus_OutOfRange )
+ {
+ F_Type = NUMBERFORMAT_TEXT; // overflow/underflow -> Text
+ if (nESign == -1)
+ fOutNumber = 0.0;
+ else
+ fOutNumber = DBL_MAX;
+/*!*/ return TRUE;
+ }
+ }
+
+ if ( nStringScanSign )
+ {
+ if ( nSign )
+ nSign *= nStringScanSign;
+ else
+ nSign = nStringScanSign;
+ }
+ if ( nSign < 0 )
+ fOutNumber = -fOutNumber;
+
+ if (eScannedType == NUMBERFORMAT_PERCENT)
+ fOutNumber/= 100.0;
+ }
+ break;
+
+ case NUMBERFORMAT_FRACTION:
+ if (nAnzNums == 1)
+ fOutNumber = StringToDouble(sStrArray[nNums[0]]);
+ else if (nAnzNums == 2)
+ {
+ if (nThousand == 1)
+ {
+ sResString = sStrArray[nNums[0]];
+ sResString += sStrArray[nNums[1]]; // integer part
+ fOutNumber = StringToDouble(sResString);
+ }
+ else
+ {
+ double fZaehler = StringToDouble(sStrArray[nNums[0]]);
+ double fNenner = StringToDouble(sStrArray[nNums[1]]);
+ if (fNenner != 0.0)
+ fOutNumber = fZaehler/fNenner;
+ else
+ res = FALSE;
+ }
+ }
+ else // nAnzNums > 2
+ {
+ USHORT k = 1;
+ sResString = sStrArray[nNums[0]];
+ if (nThousand > 0)
+ for (k = 1; k <= nThousand; k++)
+ sResString += sStrArray[nNums[k]];
+ fOutNumber = StringToDouble(sResString);
+
+ if (k == nAnzNums-2)
+ {
+ double fZaehler = StringToDouble(sStrArray[nNums[k]]);
+ double fNenner = StringToDouble(sStrArray[nNums[k+1]]);
+ if (fNenner != 0.0)
+ fOutNumber += fZaehler/fNenner;
+ else
+ res = FALSE;
+ }
+ }
+
+ if ( nStringScanSign )
+ {
+ if ( nSign )
+ nSign *= nStringScanSign;
+ else
+ nSign = nStringScanSign;
+ }
+ if ( nSign < 0 )
+ fOutNumber = -fOutNumber;
+ break;
+
+ case NUMBERFORMAT_TIME:
+ GetTimeRef(fOutNumber, 0, nAnzNums);
+ if ( nSign < 0 )
+ fOutNumber = -fOutNumber;
+ break;
+
+ case NUMBERFORMAT_DATE:
+ {
+ USHORT nCounter = 0; // dummy here
+ res = GetDateRef( fOutNumber, nCounter, pFormat );
+ }
+ break;
+
+ case NUMBERFORMAT_DATETIME:
+ {
+ USHORT nCounter = 0; // needed here
+ res = GetDateRef( fOutNumber, nCounter, pFormat );
+ if ( res )
+ {
+ double fTime;
+ GetTimeRef( fTime, nCounter, nAnzNums - nCounter );
+ fOutNumber += fTime;
+ }
+ }
+ break;
+
+ default:
+ DBG_ERRORFILE( "Some number recognized but what's it?" );
+ fOutNumber = 0.0;
+ break;
+ }
+ }
+
+ if (res) // overflow/underflow -> Text
+ {
+ if (fOutNumber < -DBL_MAX) // -1.7E308
+ {
+ F_Type = NUMBERFORMAT_TEXT;
+ fOutNumber = -DBL_MAX;
+ return TRUE;
+ }
+ else if (fOutNumber > DBL_MAX) // 1.7E308
+ {
+ F_Type = NUMBERFORMAT_TEXT;
+ fOutNumber = DBL_MAX;
+ return TRUE;
+ }
+ }
+
+ if (res == FALSE)
+ {
+ eScannedType = NUMBERFORMAT_TEXT;
+ fOutNumber = 0.0;
+ }
+
+ F_Type = eScannedType;
+ return res;
+}
+
+
+
diff --git a/svl/source/numbers/zforfind.hxx b/svl/source/numbers/zforfind.hxx
new file mode 100644
index 000000000000..049925f2034f
--- /dev/null
+++ b/svl/source/numbers/zforfind.hxx
@@ -0,0 +1,291 @@
+/*************************************************************************
+ *
+ * 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: zforfind.hxx,v $
+ * $Revision: 1.13 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef _ZFORFIND_HXX
+#define _ZFORFIND_HXX
+
+#include <tools/string.hxx>
+
+class Date;
+class SvNumberformat;
+class SvNumberFormatter;
+
+#define SV_MAX_ANZ_INPUT_STRINGS 20 // max count of substrings in input scanner
+
+class ImpSvNumberInputScan
+{
+public:
+ ImpSvNumberInputScan( SvNumberFormatter* pFormatter );
+ ~ImpSvNumberInputScan();
+
+/*!*/ void ChangeIntl(); // MUST be called if language changes
+
+ /// set reference date for offset calculation
+ void ChangeNullDate(
+ const USHORT nDay,
+ const USHORT nMonth,
+ const USHORT nYear );
+
+ /// convert input string to number
+ BOOL IsNumberFormat(
+ const String& rString, /// input string
+ short& F_Type, /// format type (in + out)
+ double& fOutNumber, /// value determined (out)
+ const SvNumberformat* pFormat = NULL /// optional a number format to which compare against
+ );
+
+ /// after IsNumberFormat: get decimal position
+ short GetDecPos() const { return nDecPos; }
+ /// after IsNumberFormat: get count of numeric substrings in input string
+ USHORT GetAnzNums() const { return nAnzNums; }
+
+ /// set threshold of two-digit year input
+ void SetYear2000( USHORT nVal ) { nYear2000 = nVal; }
+ /// get threshold of two-digit year input
+ USHORT GetYear2000() const { return nYear2000; }
+
+private:
+ SvNumberFormatter* pFormatter;
+ String* pUpperMonthText; // Array of month names, uppercase
+ String* pUpperAbbrevMonthText; // Array of month names, abbreviated, uppercase
+ String* pUpperDayText; // Array of day of week names, uppercase
+ String* pUpperAbbrevDayText; // Array of day of week names, abbreviated, uppercase
+ String aUpperCurrSymbol; // Currency symbol, uppercase
+ BOOL bTextInitialized; // Whether days and months are initialized
+ Date* pNullDate; // 30Dec1899
+ // Variables for provisional results:
+ String sStrArray[SV_MAX_ANZ_INPUT_STRINGS]; // Array of scanned substrings
+ BOOL IsNum[SV_MAX_ANZ_INPUT_STRINGS]; // Whether a substring is numeric
+ USHORT nNums[SV_MAX_ANZ_INPUT_STRINGS]; // Sequence of offsets to numeric strings
+ USHORT nAnzStrings; // Total count of scanned substrings
+ USHORT nAnzNums; // Count of numeric substrings
+ BOOL bDecSepInDateSeps; // True <=> DecSep in {.,-,/,DateSep}
+ BYTE nMatchedAllStrings; // Scan...String() matched all substrings,
+ // bit mask of nMatched... constants
+
+ static const BYTE nMatchedEndString; // 0x01
+ static const BYTE nMatchedMidString; // 0x02
+ static const BYTE nMatchedStartString; // 0x04
+ static const BYTE nMatchedVirgin; // 0x08
+ static const BYTE nMatchedUsedAsReturn; // 0x10
+
+ int nSign; // Sign of number
+ short nMonth; // Month (1..x) if date
+ // negative => short format
+ short nMonthPos; // 1 = front, 2 = middle
+ // 3 = end
+ USHORT nTimePos; // Index of first time separator (+1)
+ short nDecPos; // Index of substring containing "," (+1)
+ short nNegCheck; // '( )' for negative
+ short nESign; // Sign of exponent
+ short nAmPm; // +1 AM, -1 PM, 0 if none
+ short nLogical; // -1 => False, 1 => True
+ USHORT nThousand; // Count of group (AKA thousand) separators
+ USHORT nPosThousandString; // Position of concatenaded 000,000,000 string
+ short eScannedType; // Scanned type
+ short eSetType; // Preset Type
+
+ USHORT nStringScanNumFor; // Fixed strings recognized in
+ // pFormat->NumFor[nNumForStringScan]
+ short nStringScanSign; // Sign resulting of FixString
+ USHORT nYear2000; // Two-digit threshold
+ // Year as 20xx
+ // default 18
+ // number <= nYear2000 => 20xx
+ // number > nYear2000 => 19xx
+ USHORT nTimezonePos; // Index of timezone separator (+1)
+ BYTE nMayBeIso8601; // 0:=dontknowyet, 1:=yes, 2:=no
+
+#ifdef _ZFORFIND_CXX // methods private to implementation
+ void Reset(); // Reset all variables before start of analysis
+
+ void InitText(); // Init of months and days of week
+
+ // Convert string to double.
+ // Only simple unsigned floating point values without any error detection,
+ // decimal separator has to be '.'
+ // If bForceFraction==TRUE the string is taken to be the fractional part
+ // of 0.1234 without the leading 0. (thus being just "1234").
+ double StringToDouble(
+ const String& rStr,
+ BOOL bForceFraction = FALSE );
+
+ BOOL NextNumberStringSymbol( // Next number/string symbol
+ const sal_Unicode*& pStr,
+ String& rSymbol );
+
+ BOOL SkipThousands( // Concatenate ,000,23 blocks
+ const sal_Unicode*& pStr, // in input to 000123
+ String& rSymbol );
+
+ void NumberStringDivision( // Divide numbers/strings into
+ const String& rString ); // arrays and variables above.
+ // Leading blanks and blanks
+ // after numbers are thrown away
+
+
+ // optimized substring versions
+
+ static inline BOOL StringContains( // Whether rString contains rWhat at nPos
+ const String& rWhat,
+ const String& rString,
+ xub_StrLen nPos )
+ { // mostly used with one character
+ if ( rWhat.GetChar(0) != rString.GetChar(nPos) )
+ return FALSE;
+ return StringContainsImpl( rWhat, rString, nPos );
+ }
+ static inline BOOL StringPtrContains( // Whether pString contains rWhat at nPos
+ const String& rWhat,
+ const sal_Unicode* pString,
+ xub_StrLen nPos ) // nPos MUST be a valid offset from pString
+ { // mostly used with one character
+ if ( rWhat.GetChar(0) != *(pString+nPos) )
+ return FALSE;
+ return StringPtrContainsImpl( rWhat, pString, nPos );
+ }
+ static BOOL StringContainsImpl( //! DO NOT use directly
+ const String& rWhat,
+ const String& rString,
+ xub_StrLen nPos );
+ static BOOL StringPtrContainsImpl( //! DO NOT use directly
+ const String& rWhat,
+ const sal_Unicode* pString,
+ xub_StrLen nPos );
+
+
+ static inline BOOL SkipChar( // Skip a special character
+ sal_Unicode c,
+ const String& rString,
+ xub_StrLen& nPos );
+ static inline void SkipBlanks( // Skip blank
+ const String& rString,
+ xub_StrLen& nPos );
+ static inline BOOL SkipString( // Jump over rWhat in rString at nPos
+ const String& rWhat,
+ const String& rString,
+ xub_StrLen& nPos );
+
+ inline BOOL GetThousandSep( // Recognizes exactly ,111 as group separator
+ const String& rString,
+ xub_StrLen& nPos,
+ USHORT nStringPos );
+ short GetLogical( // Get boolean value
+ const String& rString );
+ short GetMonth( // Get month and advance string position
+ const String& rString,
+ xub_StrLen& nPos );
+ int GetDayOfWeek( // Get day of week and advance string position
+ const String& rString,
+ xub_StrLen& nPos );
+ BOOL GetCurrency( // Get currency symbol and advance string position
+ const String& rString,
+ xub_StrLen& nPos,
+ const SvNumberformat* pFormat = NULL ); // optional number format to match against
+ BOOL GetTimeAmPm( // Get symbol AM or PM and advance string position
+ const String& rString,
+ xub_StrLen& nPos );
+ inline BOOL GetDecSep( // Get decimal separator and advance string position
+ const String& rString,
+ xub_StrLen& nPos );
+ inline BOOL GetTime100SecSep( // Get hundredth seconds separator and advance string position
+ const String& rString,
+ xub_StrLen& nPos );
+ int GetSign( // Get sign and advance string position
+ const String& rString, // Including special case '('
+ xub_StrLen& nPos );
+ short GetESign( // Get sign of exponent and advance string position
+ const String& rString,
+ xub_StrLen& nPos );
+
+ inline BOOL GetNextNumber( // Get next number as array offset
+ USHORT& i,
+ USHORT& j );
+
+ void GetTimeRef( // Converts time -> double (only decimals)
+ double& fOutNumber, // result as double
+ USHORT nIndex, // Index of hour in input
+ USHORT nAnz ); // Count of time substrings in input
+ USHORT ImplGetDay ( USHORT nIndex ); // Day input, 0 if no match
+ USHORT ImplGetMonth( USHORT nIndex ); // Month input, zero based return, NumberOfMonths if no match
+ USHORT ImplGetYear ( USHORT nIndex ); // Year input, 0 if no match
+ BOOL GetDateRef( // Conversion of date to number
+ double& fDays, // OUT: days diff to null date
+ USHORT& nCounter, // Count of date substrings
+ const SvNumberformat* pFormat = NULL ); // optional number format to match against
+
+ BOOL ScanStartString( // Analyze start of string
+ const String& rString,
+ const SvNumberformat* pFormat = NULL );
+ BOOL ScanMidString( // Analyze middle substring
+ const String& rString,
+ USHORT nStringPos,
+ const SvNumberformat* pFormat = NULL );
+ BOOL ScanEndString( // Analyze end of string
+ const String& rString,
+ const SvNumberformat* pFormat = NULL );
+
+ // Whether input may be a ISO 8601 date format, yyyy-mm-dd...
+ // checks if at least 3 numbers and first number>31
+ bool MayBeIso8601();
+
+ // Compare rString to substring of array indexed by nString
+ // nString == 0xFFFF => last substring
+ BOOL ScanStringNumFor(
+ const String& rString,
+ xub_StrLen nPos,
+ const SvNumberformat* pFormat,
+ USHORT nString,
+ BOOL bDontDetectNegation = FALSE );
+
+ // if nMatchedAllStrings set nMatchedUsedAsReturn and return TRUE,
+ // else do nothing and return FALSE
+ BOOL MatchedReturn();
+
+ //! Be sure that the string to be analyzed is already converted to upper
+ //! case and if it contained native humber digits that they are already
+ //! converted to ASCII.
+ BOOL IsNumberFormatMain( // Main anlyzing function
+ const String& rString,
+ double& fOutNumber, // return value if string is numeric
+ const SvNumberformat* pFormat = NULL // optional number format to match against
+ );
+
+ static inline BOOL MyIsdigit( sal_Unicode c );
+
+ // native number transliteration if necessary
+ void TransformInput( String& rString );
+
+#endif // _ZFORFIND_CXX
+};
+
+
+
+#endif // _ZFORFIND_HXX
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';
+}
+
+
+
diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
new file mode 100644
index 000000000000..52d37b9cd26f
--- /dev/null
+++ b/svl/source/numbers/zformat.cxx
@@ -0,0 +1,4480 @@
+/*************************************************************************
+ *
+ * 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: zformat.cxx,v $
+ * $Revision: 1.78.138.1 $
+ *
+ * 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"
+#include <stdio.h>
+#include <ctype.h>
+#include <float.h>
+// #include <math.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <tools/debug.hxx>
+#include <i18npool/mslangid.hxx>
+#include <rtl/math.hxx>
+#include <rtl/instance.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <unotools/nativenumberwrapper.hxx>
+#include <com/sun/star/i18n/CalendarFieldIndex.hpp>
+#include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
+#include <com/sun/star/i18n/CalendarDisplayCode.hpp>
+#include <com/sun/star/i18n/AmPmValue.hpp>
+
+#define _ZFORMAT_CXX
+#include <svl/zformat.hxx>
+#include "zforscan.hxx"
+
+#include "zforfind.hxx"
+#include <svl/zforlist.hxx>
+#include "numhead.hxx"
+#include <unotools/digitgroupingiterator.hxx>
+#include "nfsymbol.hxx"
+using namespace svt;
+
+namespace {
+struct Gregorian
+ : public rtl::StaticWithInit<const ::rtl::OUString, Gregorian> {
+ const ::rtl::OUString operator () () {
+ return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian"));
+ }
+};
+}
+
+const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0
+const double _D_MAX_LONG_ = (double) 0x7fffffff; // 2147483647.0
+const USHORT _MAX_FRACTION_PREC = 3;
+const double D_EPS = 1.0E-2;
+
+const double _D_MAX_D_BY_100 = 1.7E306;
+const double _D_MIN_M_BY_1000 = 2.3E-305;
+
+static BYTE cCharWidths[ 128-32 ] = {
+ 1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,
+ 3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3,
+ 2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2,
+ 1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2,
+ 2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1
+};
+
+// static
+xub_StrLen SvNumberformat::InsertBlanks( String& r, xub_StrLen nPos, sal_Unicode c )
+{
+ if( c >= 32 )
+ {
+ USHORT n = 2; // Default fuer Zeichen > 128 (HACK!)
+ if( c <= 127 )
+ n = cCharWidths[ c - 32 ];
+ while( n-- )
+ r.Insert( ' ', nPos++ );
+ }
+ return nPos;
+}
+
+static long GetPrecExp( double fAbsVal )
+{
+ DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" );
+ if ( fAbsVal < 1e-7 || fAbsVal > 1e7 )
+ { // die Schere, ob's schneller ist oder nicht, liegt zwischen 1e6 und 1e7
+ return (long) floor( log10( fAbsVal ) ) + 1;
+ }
+ else
+ {
+ long nPrecExp = 1;
+ while( fAbsVal < 1 )
+ {
+ fAbsVal *= 10;
+ nPrecExp--;
+ }
+ while( fAbsVal >= 10 )
+ {
+ fAbsVal /= 10;
+ nPrecExp++;
+ }
+ return nPrecExp;
+ }
+}
+
+const USHORT nNewCurrencyVersionId = 0x434E; // "NC"
+const sal_Unicode cNewCurrencyMagic = 0x01; // Magic for format code in comment
+const USHORT nNewStandardFlagVersionId = 0x4653; // "SF"
+
+/***********************Funktion SvNumberformatInfo******************************/
+
+void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, USHORT nAnz )
+{
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ sStrArray[i] = rNumFor.sStrArray[i];
+ nTypeArray[i] = rNumFor.nTypeArray[i];
+ }
+ eScannedType = rNumFor.eScannedType;
+ bThousand = rNumFor.bThousand;
+ nThousand = rNumFor.nThousand;
+ nCntPre = rNumFor.nCntPre;
+ nCntPost = rNumFor.nCntPost;
+ nCntExp = rNumFor.nCntExp;
+}
+
+void ImpSvNumberformatInfo::Save(SvStream& rStream, USHORT nAnz) const
+{
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ rStream.WriteByteString( sStrArray[i], rStream.GetStreamCharSet() );
+ short nType = nTypeArray[i];
+ switch ( nType )
+ { // der Krampf fuer Versionen vor SV_NUMBERFORMATTER_VERSION_NEW_CURR
+ case NF_SYMBOLTYPE_CURRENCY :
+ rStream << short( NF_SYMBOLTYPE_STRING );
+ break;
+ case NF_SYMBOLTYPE_CURRDEL :
+ case NF_SYMBOLTYPE_CURREXT :
+ rStream << short(0); // werden ignoriert (hoffentlich..)
+ break;
+ default:
+ if ( nType > NF_KEY_LASTKEYWORD_SO5 )
+ rStream << short( NF_SYMBOLTYPE_STRING ); // all new keywords are string
+ else
+ rStream << nType;
+ }
+
+ }
+ rStream << eScannedType << bThousand << nThousand
+ << nCntPre << nCntPost << nCntExp;
+}
+
+void ImpSvNumberformatInfo::Load(SvStream& rStream, USHORT nAnz)
+{
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ SvNumberformat::LoadString( rStream, sStrArray[i] );
+ rStream >> nTypeArray[i];
+ }
+ rStream >> eScannedType >> bThousand >> nThousand
+ >> nCntPre >> nCntPost >> nCntExp;
+}
+
+
+//============================================================================
+
+// static
+BYTE SvNumberNatNum::MapDBNumToNatNum( BYTE nDBNum, LanguageType eLang, BOOL bDate )
+{
+ BYTE nNatNum = 0;
+ eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
+ eLang &= 0x03FF; // 10 bit primary language
+ if ( bDate )
+ {
+ if ( nDBNum == 4 && eLang == LANGUAGE_KOREAN )
+ nNatNum = 9;
+ else if ( nDBNum <= 3 )
+ nNatNum = nDBNum; // known to be good for: zh,ja,ko / 1,2,3
+ }
+ else
+ {
+ switch ( nDBNum )
+ {
+ case 1:
+ switch ( eLang )
+ {
+ case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 4; break;
+ case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 1; break;
+ case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 1; break;
+ }
+ break;
+ case 2:
+ switch ( eLang )
+ {
+ case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 5; break;
+ case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 4; break;
+ case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 2; break;
+ }
+ break;
+ case 3:
+ switch ( eLang )
+ {
+ case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 6; break;
+ case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 5; break;
+ case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 3; break;
+ }
+ break;
+ case 4:
+ switch ( eLang )
+ {
+ case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 7; break;
+ case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 9; break;
+ }
+ break;
+ }
+ }
+ return nNatNum;
+}
+
+
+// static
+BYTE SvNumberNatNum::MapNatNumToDBNum( BYTE nNatNum, LanguageType eLang, BOOL bDate )
+{
+ BYTE nDBNum = 0;
+ eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
+ eLang &= 0x03FF; // 10 bit primary language
+ if ( bDate )
+ {
+ if ( nNatNum == 9 && eLang == LANGUAGE_KOREAN )
+ nDBNum = 4;
+ else if ( nNatNum <= 3 )
+ nDBNum = nNatNum; // known to be good for: zh,ja,ko / 1,2,3
+ }
+ else
+ {
+ switch ( nNatNum )
+ {
+ case 1:
+ switch ( eLang )
+ {
+ case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 1; break;
+ case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 1; break;
+ }
+ break;
+ case 2:
+ switch ( eLang )
+ {
+ case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 2; break;
+ }
+ break;
+ case 3:
+ switch ( eLang )
+ {
+ case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 3; break;
+ }
+ break;
+ case 4:
+ switch ( eLang )
+ {
+ case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 1; break;
+ case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 2; break;
+ }
+ break;
+ case 5:
+ switch ( eLang )
+ {
+ case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 2; break;
+ case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 3; break;
+ }
+ break;
+ case 6:
+ switch ( eLang )
+ {
+ case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 3; break;
+ }
+ break;
+ case 7:
+ switch ( eLang )
+ {
+ case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 4; break;
+ }
+ break;
+ case 8:
+ break;
+ case 9:
+ switch ( eLang )
+ {
+ case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 4; break;
+ }
+ break;
+ case 10:
+ break;
+ case 11:
+ break;
+ }
+ }
+ return nDBNum;
+}
+
+/***********************Funktionen SvNumFor******************************/
+
+ImpSvNumFor::ImpSvNumFor()
+{
+ nAnzStrings = 0;
+ aI.nTypeArray = NULL;
+ aI.sStrArray = NULL;
+ aI.eScannedType = NUMBERFORMAT_UNDEFINED;
+ aI.bThousand = FALSE;
+ aI.nThousand = 0;
+ aI.nCntPre = 0;
+ aI.nCntPost = 0;
+ aI.nCntExp = 0;
+ pColor = NULL;
+}
+
+ImpSvNumFor::~ImpSvNumFor()
+{
+ for (USHORT i = 0; i < nAnzStrings; i++)
+ aI.sStrArray[i].Erase();
+ delete [] aI.sStrArray;
+ delete [] aI.nTypeArray;
+}
+
+void ImpSvNumFor::Enlarge(USHORT nAnz)
+{
+ if ( nAnzStrings != nAnz )
+ {
+ if ( aI.nTypeArray )
+ delete [] aI.nTypeArray;
+ if ( aI.sStrArray )
+ delete [] aI.sStrArray;
+ nAnzStrings = nAnz;
+ if ( nAnz )
+ {
+ aI.nTypeArray = new short[nAnz];
+ aI.sStrArray = new String[nAnz];
+ }
+ else
+ {
+ aI.nTypeArray = NULL;
+ aI.sStrArray = NULL;
+ }
+ }
+}
+
+void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc )
+{
+ Enlarge( rNumFor.nAnzStrings );
+ aI.Copy( rNumFor.aI, nAnzStrings );
+ sColorName = rNumFor.sColorName;
+ if ( pSc )
+ pColor = pSc->GetColor( sColorName ); // #121103# don't copy pointer between documents
+ else
+ pColor = rNumFor.pColor;
+ aNatNum = rNumFor.aNatNum;
+}
+
+void ImpSvNumFor::Save(SvStream& rStream) const
+{
+ rStream << nAnzStrings;
+ aI.Save(rStream, nAnzStrings);
+ rStream.WriteByteString( sColorName, rStream.GetStreamCharSet() );
+}
+
+void ImpSvNumFor::Load(SvStream& rStream, ImpSvNumberformatScan& rSc,
+ String& rLoadedColorName )
+{
+ USHORT nAnz;
+ rStream >> nAnz; //! noch nicht direkt nAnzStrings wg. Enlarge
+ Enlarge( nAnz );
+ aI.Load( rStream, nAnz );
+ rStream.ReadByteString( sColorName, rStream.GetStreamCharSet() );
+ rLoadedColorName = sColorName;
+ pColor = rSc.GetColor(sColorName);
+}
+
+
+BOOL ImpSvNumFor::HasNewCurrency() const
+{
+ for ( USHORT j=0; j<nAnzStrings; j++ )
+ {
+ if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+BOOL ImpSvNumFor::GetNewCurrencySymbol( String& rSymbol,
+ String& rExtension ) const
+{
+ for ( USHORT j=0; j<nAnzStrings; j++ )
+ {
+ if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
+ {
+ rSymbol = aI.sStrArray[j];
+ if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT )
+ rExtension = aI.sStrArray[j+1];
+ else
+ rExtension.Erase();
+ return TRUE;
+ }
+ }
+ //! kein Erase an rSymbol, rExtension
+ return FALSE;
+}
+
+
+void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const
+{
+ USHORT j;
+ USHORT nCnt = 0;
+ for ( j=0; j<nAnzStrings; j++ )
+ {
+ switch ( aI.nTypeArray[j] )
+ {
+ case NF_SYMBOLTYPE_CURRENCY :
+ case NF_SYMBOLTYPE_CURRDEL :
+ case NF_SYMBOLTYPE_CURREXT :
+ nCnt++;
+ break;
+ }
+ }
+ rStream << nCnt;
+ for ( j=0; j<nAnzStrings; j++ )
+ {
+ switch ( aI.nTypeArray[j] )
+ {
+ case NF_SYMBOLTYPE_CURRENCY :
+ case NF_SYMBOLTYPE_CURRDEL :
+ case NF_SYMBOLTYPE_CURREXT :
+ rStream << j << aI.nTypeArray[j];
+ break;
+ }
+ }
+}
+
+
+void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream )
+{
+ USHORT nCnt;
+ rStream >> nCnt;
+ for ( USHORT j=0; j<nCnt; j++ )
+ {
+ USHORT nPos;
+ short nType;
+ rStream >> nPos >> nType;
+ if ( nPos < nAnzStrings )
+ aI.nTypeArray[nPos] = nType;
+ }
+}
+
+
+/***********************Funktionen SvNumberformat************************/
+
+enum BracketFormatSymbolType
+{
+ BRACKET_SYMBOLTYPE_FORMAT = -1, // subformat string
+ BRACKET_SYMBOLTYPE_COLOR = -2, // color
+ BRACKET_SYMBOLTYPE_ERROR = -3, // error
+ BRACKET_SYMBOLTYPE_DBNUM1 = -4, // DoubleByteNumber, represent numbers
+ BRACKET_SYMBOLTYPE_DBNUM2 = -5, // using CJK characters, Excel compatible.
+ BRACKET_SYMBOLTYPE_DBNUM3 = -6,
+ BRACKET_SYMBOLTYPE_DBNUM4 = -7,
+ BRACKET_SYMBOLTYPE_DBNUM5 = -8,
+ BRACKET_SYMBOLTYPE_DBNUM6 = -9,
+ BRACKET_SYMBOLTYPE_DBNUM7 = -10,
+ BRACKET_SYMBOLTYPE_DBNUM8 = -11,
+ BRACKET_SYMBOLTYPE_DBNUM9 = -12,
+ BRACKET_SYMBOLTYPE_LOCALE = -13,
+ BRACKET_SYMBOLTYPE_NATNUM0 = -14, // Our NativeNumber support, ASCII
+ BRACKET_SYMBOLTYPE_NATNUM1 = -15, // Our NativeNumber support, represent
+ BRACKET_SYMBOLTYPE_NATNUM2 = -16, // numbers using CJK, CTL, ...
+ BRACKET_SYMBOLTYPE_NATNUM3 = -17,
+ BRACKET_SYMBOLTYPE_NATNUM4 = -18,
+ BRACKET_SYMBOLTYPE_NATNUM5 = -19,
+ BRACKET_SYMBOLTYPE_NATNUM6 = -20,
+ BRACKET_SYMBOLTYPE_NATNUM7 = -21,
+ BRACKET_SYMBOLTYPE_NATNUM8 = -22,
+ BRACKET_SYMBOLTYPE_NATNUM9 = -23,
+ BRACKET_SYMBOLTYPE_NATNUM10 = -24,
+ BRACKET_SYMBOLTYPE_NATNUM11 = -25,
+ BRACKET_SYMBOLTYPE_NATNUM12 = -26,
+ BRACKET_SYMBOLTYPE_NATNUM13 = -27,
+ BRACKET_SYMBOLTYPE_NATNUM14 = -28,
+ BRACKET_SYMBOLTYPE_NATNUM15 = -29,
+ BRACKET_SYMBOLTYPE_NATNUM16 = -30,
+ BRACKET_SYMBOLTYPE_NATNUM17 = -31,
+ BRACKET_SYMBOLTYPE_NATNUM18 = -32,
+ BRACKET_SYMBOLTYPE_NATNUM19 = -33
+};
+
+SvNumberformat::SvNumberformat( ImpSvNumberformatScan& rSc, LanguageType eLge )
+ :
+ rScan(rSc),
+ eLnge(eLge),
+ nNewStandardDefined(0),
+ bStarFlag( FALSE )
+{
+}
+
+void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat )
+{
+ sFormatstring = rFormat.sFormatstring;
+ eType = rFormat.eType;
+ eLnge = rFormat.eLnge;
+ fLimit1 = rFormat.fLimit1;
+ fLimit2 = rFormat.fLimit2;
+ eOp1 = rFormat.eOp1;
+ eOp2 = rFormat.eOp2;
+ bStandard = rFormat.bStandard;
+ bIsUsed = rFormat.bIsUsed;
+ sComment = rFormat.sComment;
+ nNewStandardDefined = rFormat.nNewStandardDefined;
+
+ // #121103# when copying between documents, get color pointers from own scanner
+ ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : NULL;
+
+ for (USHORT i = 0; i < 4; i++)
+ NumFor[i].Copy(rFormat.NumFor[i], pColorSc);
+}
+
+SvNumberformat::SvNumberformat( SvNumberformat& rFormat )
+ : rScan(rFormat.rScan), bStarFlag( rFormat.bStarFlag )
+{
+ ImpCopyNumberformat( rFormat );
+}
+
+SvNumberformat::SvNumberformat( SvNumberformat& rFormat, ImpSvNumberformatScan& rSc )
+ : rScan(rSc), bStarFlag( rFormat.bStarFlag )
+{
+ ImpCopyNumberformat( rFormat );
+}
+
+
+BOOL lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType )
+{
+ if ( nSymbolType > 0 )
+ return TRUE; // conditions
+ switch ( nSymbolType )
+ {
+ case BRACKET_SYMBOLTYPE_COLOR :
+ case BRACKET_SYMBOLTYPE_DBNUM1 :
+ case BRACKET_SYMBOLTYPE_DBNUM2 :
+ case BRACKET_SYMBOLTYPE_DBNUM3 :
+ case BRACKET_SYMBOLTYPE_DBNUM4 :
+ case BRACKET_SYMBOLTYPE_DBNUM5 :
+ case BRACKET_SYMBOLTYPE_DBNUM6 :
+ case BRACKET_SYMBOLTYPE_DBNUM7 :
+ case BRACKET_SYMBOLTYPE_DBNUM8 :
+ case BRACKET_SYMBOLTYPE_DBNUM9 :
+ case BRACKET_SYMBOLTYPE_LOCALE :
+ case BRACKET_SYMBOLTYPE_NATNUM0 :
+ case BRACKET_SYMBOLTYPE_NATNUM1 :
+ case BRACKET_SYMBOLTYPE_NATNUM2 :
+ case BRACKET_SYMBOLTYPE_NATNUM3 :
+ case BRACKET_SYMBOLTYPE_NATNUM4 :
+ case BRACKET_SYMBOLTYPE_NATNUM5 :
+ case BRACKET_SYMBOLTYPE_NATNUM6 :
+ case BRACKET_SYMBOLTYPE_NATNUM7 :
+ case BRACKET_SYMBOLTYPE_NATNUM8 :
+ case BRACKET_SYMBOLTYPE_NATNUM9 :
+ case BRACKET_SYMBOLTYPE_NATNUM10 :
+ case BRACKET_SYMBOLTYPE_NATNUM11 :
+ case BRACKET_SYMBOLTYPE_NATNUM12 :
+ case BRACKET_SYMBOLTYPE_NATNUM13 :
+ case BRACKET_SYMBOLTYPE_NATNUM14 :
+ case BRACKET_SYMBOLTYPE_NATNUM15 :
+ case BRACKET_SYMBOLTYPE_NATNUM16 :
+ case BRACKET_SYMBOLTYPE_NATNUM17 :
+ case BRACKET_SYMBOLTYPE_NATNUM18 :
+ case BRACKET_SYMBOLTYPE_NATNUM19 :
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+SvNumberformat::SvNumberformat(String& rString,
+ ImpSvNumberformatScan* pSc,
+ ImpSvNumberInputScan* pISc,
+ xub_StrLen& nCheckPos,
+ LanguageType& eLan,
+ BOOL bStan)
+ :
+ rScan(*pSc),
+ nNewStandardDefined(0),
+ bStarFlag( FALSE )
+{
+ // If the group (AKA thousand) separator is a Non-Breaking Space (French)
+ // replace all occurences by a simple space.
+ // The tokens will be changed to the LocaleData separator again later on.
+ const sal_Unicode cNBSp = 0xA0;
+ const String& rThSep = GetFormatter().GetNumThousandSep();
+ if ( rThSep.GetChar(0) == cNBSp && rThSep.Len() == 1 )
+ {
+ xub_StrLen nIndex = 0;
+ do
+ nIndex = rString.SearchAndReplace( cNBSp, ' ', nIndex );
+ while ( nIndex != STRING_NOTFOUND );
+ }
+
+ if (rScan.GetConvertMode())
+ {
+ eLnge = rScan.GetNewLnge();
+ eLan = eLnge; // Wechsel auch zurueckgeben
+ }
+ else
+ eLnge = eLan;
+ bStandard = bStan;
+ bIsUsed = FALSE;
+ fLimit1 = 0.0;
+ fLimit2 = 0.0;
+ eOp1 = NUMBERFORMAT_OP_NO;
+ eOp2 = NUMBERFORMAT_OP_NO;
+ eType = NUMBERFORMAT_DEFINED;
+
+ BOOL bCancel = FALSE;
+ BOOL bCondition = FALSE;
+ short eSymbolType;
+ xub_StrLen nPos = 0;
+ xub_StrLen nPosOld;
+ nCheckPos = 0;
+ String aComment;
+
+ // Split into 4 sub formats
+ USHORT nIndex;
+ for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ )
+ {
+ // Original language/country may have to be reestablished
+ if (rScan.GetConvertMode())
+ (rScan.GetNumberformatter())->ChangeIntl(rScan.GetTmpLnge());
+
+ String sStr;
+ nPosOld = nPos; // Start position of substring
+ // first get bracketed prefixes; e.g. conditions, color
+ do
+ {
+ eSymbolType = ImpNextSymbol(rString, nPos, sStr);
+ if (eSymbolType > 0) // condition
+ {
+ if ( nIndex == 0 && !bCondition )
+ {
+ bCondition = TRUE;
+ eOp1 = (SvNumberformatLimitOps) eSymbolType;
+ }
+ else if ( nIndex == 1 && bCondition )
+ eOp2 = (SvNumberformatLimitOps) eSymbolType;
+ else // error
+ {
+ bCancel = TRUE; // break for
+ nCheckPos = nPosOld;
+ }
+ if (!bCancel)
+ {
+ double fNumber;
+ xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr);
+ if (nAnzChars > 0)
+ {
+ short F_Type;
+ if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) ||
+ ( F_Type != NUMBERFORMAT_NUMBER &&
+ F_Type != NUMBERFORMAT_SCIENTIFIC) )
+ {
+ fNumber = 0.0;
+ nPos = nPos - nAnzChars;
+ rString.Erase(nPos, nAnzChars);
+ rString.Insert('0',nPos);
+ nPos++;
+ }
+ }
+ else
+ {
+ fNumber = 0.0;
+ rString.Insert('0',nPos++);
+ }
+ if (nIndex == 0)
+ fLimit1 = fNumber;
+ else
+ fLimit2 = fNumber;
+ if ( rString.GetChar(nPos) == ']' )
+ nPos++;
+ else
+ {
+ bCancel = TRUE; // break for
+ nCheckPos = nPos;
+ }
+ }
+ nPosOld = nPos; // position before string
+ }
+ else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
+ {
+ switch ( eSymbolType )
+ {
+ case BRACKET_SYMBOLTYPE_COLOR :
+ {
+ if ( NumFor[nIndex].GetColor() != NULL )
+ { // error, more than one color
+ bCancel = TRUE; // break for
+ nCheckPos = nPosOld;
+ }
+ else
+ {
+ Color* pColor = pSc->GetColor( sStr);
+ NumFor[nIndex].SetColor( pColor, sStr);
+ if (pColor == NULL)
+ { // error
+ bCancel = TRUE; // break for
+ nCheckPos = nPosOld;
+ }
+ }
+ }
+ break;
+ case BRACKET_SYMBOLTYPE_NATNUM0 :
+ case BRACKET_SYMBOLTYPE_NATNUM1 :
+ case BRACKET_SYMBOLTYPE_NATNUM2 :
+ case BRACKET_SYMBOLTYPE_NATNUM3 :
+ case BRACKET_SYMBOLTYPE_NATNUM4 :
+ case BRACKET_SYMBOLTYPE_NATNUM5 :
+ case BRACKET_SYMBOLTYPE_NATNUM6 :
+ case BRACKET_SYMBOLTYPE_NATNUM7 :
+ case BRACKET_SYMBOLTYPE_NATNUM8 :
+ case BRACKET_SYMBOLTYPE_NATNUM9 :
+ case BRACKET_SYMBOLTYPE_NATNUM10 :
+ case BRACKET_SYMBOLTYPE_NATNUM11 :
+ case BRACKET_SYMBOLTYPE_NATNUM12 :
+ case BRACKET_SYMBOLTYPE_NATNUM13 :
+ case BRACKET_SYMBOLTYPE_NATNUM14 :
+ case BRACKET_SYMBOLTYPE_NATNUM15 :
+ case BRACKET_SYMBOLTYPE_NATNUM16 :
+ case BRACKET_SYMBOLTYPE_NATNUM17 :
+ case BRACKET_SYMBOLTYPE_NATNUM18 :
+ case BRACKET_SYMBOLTYPE_NATNUM19 :
+ {
+ if ( NumFor[nIndex].GetNatNum().IsSet() )
+ {
+ bCancel = TRUE; // break for
+ nCheckPos = nPosOld;
+ }
+ else
+ {
+ sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) );
+ //! eSymbolType is negative
+ BYTE nNum = sal::static_int_cast< BYTE >(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0));
+ sStr += String::CreateFromInt32( nNum );
+ NumFor[nIndex].SetNatNumNum( nNum, FALSE );
+ }
+ }
+ break;
+ case BRACKET_SYMBOLTYPE_DBNUM1 :
+ case BRACKET_SYMBOLTYPE_DBNUM2 :
+ case BRACKET_SYMBOLTYPE_DBNUM3 :
+ case BRACKET_SYMBOLTYPE_DBNUM4 :
+ case BRACKET_SYMBOLTYPE_DBNUM5 :
+ case BRACKET_SYMBOLTYPE_DBNUM6 :
+ case BRACKET_SYMBOLTYPE_DBNUM7 :
+ case BRACKET_SYMBOLTYPE_DBNUM8 :
+ case BRACKET_SYMBOLTYPE_DBNUM9 :
+ {
+ if ( NumFor[nIndex].GetNatNum().IsSet() )
+ {
+ bCancel = TRUE; // break for
+ nCheckPos = nPosOld;
+ }
+ else
+ {
+ sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) );
+ //! eSymbolType is negative
+ BYTE nNum = sal::static_int_cast< BYTE >(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1));
+ sStr += static_cast< sal_Unicode >('0' + nNum);
+ NumFor[nIndex].SetNatNumNum( nNum, TRUE );
+ }
+ }
+ break;
+ case BRACKET_SYMBOLTYPE_LOCALE :
+ {
+ if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW )
+ {
+ bCancel = TRUE; // break for
+ nCheckPos = nPosOld;
+ }
+ else
+ {
+ xub_StrLen nTmp = 2;
+ LanguageType eLang = ImpGetLanguageType( sStr, nTmp );
+ if ( eLang == LANGUAGE_DONTKNOW )
+ {
+ bCancel = TRUE; // break for
+ nCheckPos = nPosOld;
+ }
+ else
+ {
+ sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "$-" ) );
+ sStr += String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii();
+ NumFor[nIndex].SetNatNumLang( eLang );
+ }
+ }
+ }
+ break;
+ }
+ if ( !bCancel )
+ {
+ rString.Erase(nPosOld,nPos-nPosOld);
+ rString.Insert(sStr,nPosOld);
+ nPos = nPosOld + sStr.Len();
+ rString.Insert(']', nPos);
+ rString.Insert('[', nPosOld);
+ nPos += 2;
+ nPosOld = nPos; // position before string
+ }
+ }
+ } while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) );
+
+ // The remaining format code string
+ if ( !bCancel )
+ {
+ if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT)
+ {
+ if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO)
+ eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0
+ else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO)
+ eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0
+ if (sStr.Len() == 0)
+ { // empty sub format
+ }
+ else
+ {
+ xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment );
+ USHORT nAnz = pSc->GetAnzResStrings();
+ if (nAnz == 0) // error
+ nStrPos = 1;
+ if (nStrPos == 0) // ok
+ {
+ // e.g. Thai T speciality
+ if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet())
+ {
+ String aNat( RTL_CONSTASCII_USTRINGPARAM( "[NatNum"));
+ aNat += String::CreateFromInt32( pSc->GetNatNumModifier());
+ aNat += ']';
+ sStr.Insert( aNat, 0);
+ NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), FALSE );
+ }
+ // #i53826# #i42727# For the Thai T speciality we need
+ // to freeze the locale and immunize it against
+ // conversions during exports, just in case we want to
+ // save to Xcl. This disables the feature of being able
+ // to convert a NatNum to another locale. You can't
+ // have both.
+ // FIXME: implement a specialized export conversion
+ // that works on tokens (have to tokenize all first)
+ // and doesn't use the format string and
+ // PutandConvertEntry() to LANGUAGE_ENGLISH_US in
+ // sc/source/filter/excel/xestyle.cxx
+ // XclExpNumFmtBuffer::WriteFormatRecord().
+ LanguageType eLanguage;
+ if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 &&
+ ((eLanguage =
+ MsLangId::getRealLanguage( eLan))
+ == LANGUAGE_THAI) &&
+ NumFor[nIndex].GetNatNum().GetLang() ==
+ LANGUAGE_DONTKNOW)
+ {
+ String aLID( RTL_CONSTASCII_USTRINGPARAM( "[$-"));
+ aLID += String::CreateFromInt32( sal_Int32(
+ eLanguage), 16 ).ToUpperAscii();
+ aLID += ']';
+ sStr.Insert( aLID, 0);
+ NumFor[nIndex].SetNatNumLang( eLanguage);
+ }
+ rString.Erase(nPosOld,nPos-nPosOld);
+ rString.Insert(sStr,nPosOld);
+ nPos = nPosOld + sStr.Len();
+ if (nPos < rString.Len())
+ {
+ rString.Insert(';',nPos);
+ nPos++;
+ }
+ NumFor[nIndex].Enlarge(nAnz);
+ pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz);
+ // type check
+ if (nIndex == 0)
+ eType = (short) NumFor[nIndex].Info().eScannedType;
+ else if (nIndex == 3)
+ { // #77026# Everything recognized IS text
+ NumFor[nIndex].Info().eScannedType = NUMBERFORMAT_TEXT;
+ }
+ else if ( (short) NumFor[nIndex].Info().eScannedType !=
+ eType)
+ eType = NUMBERFORMAT_DEFINED;
+ }
+ else
+ {
+ nCheckPos = nPosOld + nStrPos; // error in string
+ bCancel = TRUE; // break for
+ }
+ }
+ }
+ else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error
+ {
+ nCheckPos = nPosOld;
+ bCancel = TRUE;
+ }
+ else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
+ {
+ nCheckPos = nPosOld+1; // error, prefix in string
+ bCancel = TRUE; // break for
+ }
+ }
+ if ( bCancel && !nCheckPos )
+ nCheckPos = 1; // nCheckPos is used as an error condition
+ if ( !bCancel )
+ {
+ if ( NumFor[nIndex].GetNatNum().IsSet() &&
+ NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW )
+ NumFor[nIndex].SetNatNumLang( eLan );
+ }
+ if (rString.Len() == nPos)
+ {
+ if ( nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT &&
+ rString.GetChar(nPos-1) == ';' )
+ { // #83510# A 4th subformat explicitly specified to be empty
+ // hides any text. Need the type here for HasTextFormat()
+ NumFor[3].Info().eScannedType = NUMBERFORMAT_TEXT;
+ }
+ bCancel = TRUE;
+ }
+ if ( NumFor[nIndex].GetNatNum().IsSet() )
+ NumFor[nIndex].SetNatNumDate(
+ (NumFor[nIndex].Info().eScannedType & NUMBERFORMAT_DATE) != 0 );
+ }
+
+ if ( bCondition && !nCheckPos )
+ {
+ if ( nIndex == 1 && NumFor[0].GetnAnz() == 0 &&
+ rString.GetChar(rString.Len()-1) != ';' )
+ { // No format code => GENERAL but not if specified empty
+ String aAdd( pSc->GetStandardName() );
+ String aTmp;
+ if ( !pSc->ScanFormat( aAdd, aTmp ) )
+ {
+ USHORT nAnz = pSc->GetAnzResStrings();
+ if ( nAnz )
+ {
+ NumFor[0].Enlarge(nAnz);
+ pSc->CopyInfo( &(NumFor[0].Info()), nAnz );
+ rString += aAdd;
+ }
+ }
+ }
+ else if ( nIndex == 1 && NumFor[nIndex].GetnAnz() == 0 &&
+ rString.GetChar(rString.Len()-1) != ';' &&
+ (NumFor[0].GetnAnz() > 1 || (NumFor[0].GetnAnz() == 1 &&
+ NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) )
+ { // No trailing second subformat => GENERAL but not if specified empty
+ // and not if first subformat is GENERAL
+ String aAdd( pSc->GetStandardName() );
+ String aTmp;
+ if ( !pSc->ScanFormat( aAdd, aTmp ) )
+ {
+ USHORT nAnz = pSc->GetAnzResStrings();
+ if ( nAnz )
+ {
+ NumFor[nIndex].Enlarge(nAnz);
+ pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
+ rString += ';';
+ rString += aAdd;
+ }
+ }
+ }
+ else if ( nIndex == 2 && NumFor[nIndex].GetnAnz() == 0 &&
+ rString.GetChar(rString.Len()-1) != ';' &&
+ eOp2 != NUMBERFORMAT_OP_NO )
+ { // No trailing third subformat => GENERAL but not if specified empty
+ String aAdd( pSc->GetStandardName() );
+ String aTmp;
+ if ( !pSc->ScanFormat( aAdd, aTmp ) )
+ {
+ USHORT nAnz = pSc->GetAnzResStrings();
+ if ( nAnz )
+ {
+ NumFor[nIndex].Enlarge(nAnz);
+ pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
+ rString += ';';
+ rString += aAdd;
+ }
+ }
+ }
+ }
+ sFormatstring = rString;
+ if ( aComment.Len() )
+ {
+ SetComment( aComment ); // setzt sComment und sFormatstring
+ rString = sFormatstring; // geaenderten sFormatstring uebernehmen
+ }
+ if (NumFor[2].GetnAnz() == 0 && // kein 3. Teilstring
+ eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO &&
+ fLimit1 == 0.0 && fLimit2 == 0.0)
+ eOp1 = NUMBERFORMAT_OP_GE; // 0 zum ersten Format dazu
+
+}
+
+SvNumberformat::~SvNumberformat()
+{
+}
+
+//---------------------------------------------------------------------------
+// Next_Symbol
+//---------------------------------------------------------------------------
+// Zerlegt die Eingabe in Symbole fuer die weitere
+// Verarbeitung (Turing-Maschine).
+//---------------------------------------------------------------------------
+// Ausgangs Zustand = SsStart
+//---------------+-------------------+-----------------------+---------------
+// Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
+//---------------+-------------------+-----------------------+---------------
+// SsStart | ; | Pos-- | SsGetString
+// | [ | Symbol += Zeichen | SsGetBracketed
+// | ] | Fehler | SsStop
+// | BLANK | |
+// | Sonst | Symbol += Zeichen | SsGetString
+//---------------+-------------------+-----------------------+---------------
+// SsGetString | ; | | SsStop
+// | Sonst | Symbol+=Zeichen |
+//---------------+-------------------+-----------------------+---------------
+// SsGetBracketed| <, > = | del [ |
+// | | Symbol += Zeichen | SsGetCon
+// | BLANK | |
+// | h, H, m, M, s, S | Symbol += Zeichen | SsGetTime
+// | sonst | del [ |
+// | | Symbol += Zeichen | SsGetPrefix
+//---------------+-------------------+-----------------------+---------------
+// SsGetTime | ] | Symbol += Zeichen | SsGetString
+// | h, H, m, M, s, S | Symbol += Zeichen, * | SsGetString
+// | sonst | del [; Symbol+=Zeichen| SsGetPrefix
+//---------------+-------------------+-----------------------+---------------
+// SsGetPrefix | ] | | SsStop
+// | sonst | Symbol += Zeichen |
+//---------------+-------------------+-----------------------+---------------
+// SsGetCon | >, = | Symbol+=Zeichen |
+// | ] | | SsStop
+// | sonst | Fehler | SsStop
+//---------------+-------------------+-----------------------+---------------
+// * : Sonderbedingung
+
+enum ScanState
+{
+ SsStop,
+ SsStart,
+ SsGetCon, // condition
+ SsGetString, // format string
+ SsGetPrefix, // color or NatNumN
+ SsGetTime, // [HH] for time
+ SsGetBracketed // any [...] not decided yet
+};
+
+
+// read a string until ']' and delete spaces in input
+// static
+xub_StrLen SvNumberformat::ImpGetNumber(String& rString,
+ xub_StrLen& nPos,
+ String& sSymbol)
+{
+ xub_StrLen nStartPos = nPos;
+ sal_Unicode cToken;
+ xub_StrLen nLen = rString.Len();
+ sSymbol.Erase();
+ while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') )
+ {
+ if (cToken == ' ')
+ { // delete spaces
+ rString.Erase(nPos,1);
+ nLen--;
+ }
+ else
+ {
+ nPos++;
+ sSymbol += cToken;
+ }
+ }
+ return nPos - nStartPos;
+}
+
+
+// static
+LanguageType SvNumberformat::ImpGetLanguageType( const String& rString,
+ xub_StrLen& nPos )
+{
+ sal_Int32 nNum = 0;
+ sal_Unicode cToken = 0;
+ xub_StrLen nLen = rString.Len();
+ while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') )
+ {
+ if ( '0' <= cToken && cToken <= '9' )
+ {
+ nNum *= 16;
+ nNum += cToken - '0';
+ }
+ else if ( 'a' <= cToken && cToken <= 'f' )
+ {
+ nNum *= 16;
+ nNum += cToken - 'a' + 10;
+ }
+ else if ( 'A' <= cToken && cToken <= 'F' )
+ {
+ nNum *= 16;
+ nNum += cToken - 'A' + 10;
+ }
+ else
+ return LANGUAGE_DONTKNOW;
+ ++nPos;
+ }
+ return (nNum && (cToken == ']' || nPos == nLen)) ? (LanguageType)nNum :
+ LANGUAGE_DONTKNOW;
+}
+
+
+short SvNumberformat::ImpNextSymbol(String& rString,
+ xub_StrLen& nPos,
+ String& sSymbol)
+{
+ short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
+ sal_Unicode cToken;
+ sal_Unicode cLetter = ' '; // Zwischenergebnis
+ xub_StrLen nLen = rString.Len();
+ ScanState eState = SsStart;
+ sSymbol.Erase();
+ const String* pKeywords = rScan.GetKeywords();
+ while (nPos < nLen && eState != SsStop)
+ {
+ cToken = rString.GetChar(nPos);
+ nPos++;
+ switch (eState)
+ {
+ case SsStart:
+ {
+ if (cToken == '[')
+ {
+ eState = SsGetBracketed;
+ sSymbol += cToken;
+ }
+ else if (cToken == ';')
+ {
+ eState = SsGetString;
+ nPos--;
+ eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
+ }
+ else if (cToken == ']')
+ {
+ eState = SsStop;
+ eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
+ }
+ else if (cToken == ' ') // Skip Blanks
+ {
+ rString.Erase(nPos-1,1);
+ nPos--;
+ nLen--;
+ }
+ else
+ {
+ sSymbol += cToken;
+ eState = SsGetString;
+ eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
+ }
+ }
+ break;
+ case SsGetBracketed:
+ {
+ switch (cToken)
+ {
+ case '<':
+ case '>':
+ case '=':
+ {
+ sSymbol.EraseAllChars('[');
+ sSymbol += cToken;
+ cLetter = cToken;
+ eState = SsGetCon;
+ switch (cToken)
+ {
+ case '<': eSymbolType = NUMBERFORMAT_OP_LT; break;
+ case '>': eSymbolType = NUMBERFORMAT_OP_GT; break;
+ case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break;
+ default: break;
+ }
+ }
+ break;
+ case ' ':
+ {
+ rString.Erase(nPos-1,1);
+ nPos--;
+ nLen--;
+ }
+ break;
+ case '$' :
+ {
+ if ( rString.GetChar(nPos) == '-' )
+ { // [$-xxx] locale
+ sSymbol.EraseAllChars('[');
+ eSymbolType = BRACKET_SYMBOLTYPE_LOCALE;
+ eState = SsGetPrefix;
+ }
+ else
+ { // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
+ eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
+ eState = SsGetString;
+ }
+ sSymbol += cToken;
+ }
+ break;
+ case '~' :
+ { // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR
+ eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
+ sSymbol += cToken;
+ eState = SsGetString;
+ }
+ break;
+ default:
+ {
+ static const String aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) );
+ static const String aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) );
+ String aUpperNatNum( rChrCls().toUpper( rString, nPos-1, aNatNum.Len() ) );
+ String aUpperDBNum( rChrCls().toUpper( rString, nPos-1, aDBNum.Len() ) );
+ sal_Unicode cUpper = aUpperNatNum.GetChar(0);
+ sal_Int32 nNatNumNum = rString.Copy( nPos-1+aNatNum.Len() ).ToInt32();
+ sal_Unicode cDBNum = rString.GetChar( nPos-1+aDBNum.Len() );
+ if ( aUpperNatNum == aNatNum && 0 <= nNatNumNum && nNatNumNum <= 19 )
+ {
+ sSymbol.EraseAllChars('[');
+ sSymbol += rString.Copy( --nPos, aNatNum.Len()+1 );
+ nPos += aNatNum.Len()+1;
+ //! SymbolType is negative
+ eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum);
+ eState = SsGetPrefix;
+ }
+ else if ( aUpperDBNum == aDBNum && '1' <= cDBNum && cDBNum <= '9' )
+ {
+ sSymbol.EraseAllChars('[');
+ sSymbol += rString.Copy( --nPos, aDBNum.Len()+1 );
+ nPos += aDBNum.Len()+1;
+ //! SymbolType is negative
+ eSymbolType = sal::static_int_cast< short >(
+ BRACKET_SYMBOLTYPE_DBNUM1 - (cDBNum - '1'));
+ eState = SsGetPrefix;
+ }
+ else if (cUpper == pKeywords[NF_KEY_H].GetChar(0) || // H
+ cUpper == pKeywords[NF_KEY_MI].GetChar(0) || // M
+ cUpper == pKeywords[NF_KEY_S].GetChar(0) ) // S
+ {
+ sSymbol += cToken;
+ eState = SsGetTime;
+ cLetter = cToken;
+ }
+ else
+ {
+ sSymbol.EraseAllChars('[');
+ sSymbol += cToken;
+ eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
+ eState = SsGetPrefix;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case SsGetString:
+ {
+ if (cToken == ';')
+ eState = SsStop;
+ else
+ sSymbol += cToken;
+ }
+ break;
+ case SsGetTime:
+ {
+ if (cToken == ']')
+ {
+ sSymbol += cToken;
+ eState = SsGetString;
+ eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
+ }
+ else
+ {
+ sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0);
+ if (cUpper == pKeywords[NF_KEY_H].GetChar(0) || // H
+ cUpper == pKeywords[NF_KEY_MI].GetChar(0) || // M
+ cUpper == pKeywords[NF_KEY_S].GetChar(0) ) // S
+ {
+ if (cLetter == cToken)
+ {
+ sSymbol += cToken;
+ cLetter = ' ';
+ }
+ else
+ {
+ sSymbol.EraseAllChars('[');
+ sSymbol += cToken;
+ eState = SsGetPrefix;
+ }
+ }
+ else
+ {
+ sSymbol.EraseAllChars('[');
+ sSymbol += cToken;
+ eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
+ eState = SsGetPrefix;
+ }
+ }
+ }
+ break;
+ case SsGetCon:
+ {
+ switch (cToken)
+ {
+ case '<':
+ {
+ eState = SsStop;
+ eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
+ }
+ break;
+ case '>':
+ {
+ if (cLetter == '<')
+ {
+ sSymbol += cToken;
+ cLetter = ' ';
+ eState = SsStop;
+ eSymbolType = NUMBERFORMAT_OP_NE;
+ }
+ else
+ {
+ eState = SsStop;
+ eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
+ }
+ }
+ break;
+ case '=':
+ {
+ if (cLetter == '<')
+ {
+ sSymbol += cToken;
+ cLetter = ' ';
+ eSymbolType = NUMBERFORMAT_OP_LE;
+ }
+ else if (cLetter == '>')
+ {
+ sSymbol += cToken;
+ cLetter = ' ';
+ eSymbolType = NUMBERFORMAT_OP_GE;
+ }
+ else
+ {
+ eState = SsStop;
+ eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
+ }
+ }
+ break;
+ case ' ':
+ {
+ rString.Erase(nPos-1,1);
+ nPos--;
+ nLen--;
+ }
+ break;
+ default:
+ {
+ eState = SsStop;
+ nPos--;
+ }
+ break;
+ }
+ }
+ break;
+ case SsGetPrefix:
+ {
+ if (cToken == ']')
+ eState = SsStop;
+ else
+ sSymbol += cToken;
+ }
+ break;
+ default:
+ break;
+ } // of switch
+ } // of while
+
+ return eSymbolType;
+}
+
+NfHackConversion SvNumberformat::Load( SvStream& rStream,
+ ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter,
+ ImpSvNumberInputScan& rISc )
+{
+ rHdr.StartEntry();
+ USHORT nOp1, nOp2;
+ SvNumberformat::LoadString( rStream, sFormatstring );
+ rStream >> eType >> fLimit1 >> fLimit2
+ >> nOp1 >> nOp2 >> bStandard >> bIsUsed;
+ NfHackConversion eHackConversion = NF_CONVERT_NONE;
+ BOOL bOldConvert = FALSE;
+ LanguageType eOldTmpLang = 0;
+ LanguageType eOldNewLang = 0;
+ if ( pHackConverter )
+ { // werden nur hierbei gebraucht
+ bOldConvert = rScan.GetConvertMode();
+ eOldTmpLang = rScan.GetTmpLnge();
+ eOldNewLang = rScan.GetNewLnge();
+ }
+ String aLoadedColorName;
+ for (USHORT i = 0; i < 4; i++)
+ {
+ NumFor[i].Load( rStream, rScan, aLoadedColorName );
+ if ( pHackConverter && eHackConversion == NF_CONVERT_NONE )
+ {
+ //! HACK! ER 29.07.97 13:52
+ // leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/
+ // aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert..
+ // System-German FARBE nach System-xxx COLOR umsetzen und vice versa,
+ //! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in
+ //! ImpSvNumberformatScan existierten
+ if ( aLoadedColorName.Len() && !NumFor[i].GetColor()
+ && aLoadedColorName != rScan.GetColorString() )
+ {
+ if ( rScan.GetColorString().EqualsAscii( "FARBE" ) )
+ { // English -> German
+ eHackConversion = NF_CONVERT_ENGLISH_GERMAN;
+ rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US );
+ rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN );
+ }
+ else
+ { // German -> English
+ eHackConversion = NF_CONVERT_GERMAN_ENGLISH;
+ rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN );
+ rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US );
+ }
+ String aColorName = NumFor[i].GetColorName();
+ const Color* pColor = rScan.GetColor( aColorName );
+ if ( !pColor && aLoadedColorName == aColorName )
+ eHackConversion = NF_CONVERT_NONE;
+ rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM );
+ rScan.SetConvertMode( eOldTmpLang, eOldNewLang );
+ rScan.SetConvertMode( bOldConvert );
+ }
+ }
+ }
+ eOp1 = (SvNumberformatLimitOps) nOp1;
+ eOp2 = (SvNumberformatLimitOps) nOp2;
+ String aComment; // wird nach dem NewCurrency-Geraffel richtig gesetzt
+ if ( rHdr.BytesLeft() )
+ { // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
+ SvNumberformat::LoadString( rStream, aComment );
+ rStream >> nNewStandardDefined;
+ }
+
+ xub_StrLen nNewCurrencyEnd = STRING_NOTFOUND;
+ BOOL bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic &&
+ (nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND );
+ BOOL bNewCurrencyLoaded = FALSE;
+ BOOL bNewCurrency = FALSE;
+
+ BOOL bGoOn = TRUE;
+ while ( rHdr.BytesLeft() && bGoOn )
+ { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
+ USHORT nId;
+ rStream >> nId;
+ switch ( nId )
+ {
+ case nNewCurrencyVersionId :
+ {
+ bNewCurrencyLoaded = TRUE;
+ rStream >> bNewCurrency;
+ if ( bNewCurrency )
+ {
+ for ( USHORT j=0; j<4; j++ )
+ {
+ NumFor[j].LoadNewCurrencyMap( rStream );
+ }
+ }
+ }
+ break;
+ case nNewStandardFlagVersionId :
+ rStream >> bStandard; // the real standard flag
+ break;
+ default:
+ DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" );
+ bGoOn = FALSE; // stop reading unknown stream left over of newer versions
+ // Would be nice to have multiple read/write headers instead
+ // but old versions wouldn't know it, TLOT.
+ }
+ }
+ rHdr.EndEntry();
+
+ if ( bNewCurrencyLoaded )
+ {
+ if ( bNewCurrency && bNewCurrencyComment )
+ { // original Formatstring und Kommentar wiederherstellen
+ sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
+ aComment.Erase( 0, nNewCurrencyEnd+1 );
+ }
+ }
+ else if ( bNewCurrencyComment )
+ { // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert
+ // original Formatstring und Kommentar wiederherstellen
+ sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 );
+ aComment.Erase( 0, nNewCurrencyEnd+1 );
+ // Zustaende merken
+ short nDefined = ( eType & NUMBERFORMAT_DEFINED );
+ USHORT nNewStandard = nNewStandardDefined;
+ // neu parsen etc.
+ String aStr( sFormatstring );
+ xub_StrLen nCheckPos = 0;
+ SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc,
+ nCheckPos, eLnge, bStandard );
+ DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" );
+ ImpCopyNumberformat( *pFormat );
+ delete pFormat;
+ // Zustaende wiederherstellen
+ eType |= nDefined;
+ if ( nNewStandard )
+ SetNewStandardDefined( nNewStandard );
+ }
+ SetComment( aComment );
+
+ if ( eHackConversion != NF_CONVERT_NONE )
+ { //! und weiter mit dem HACK!
+ switch ( eHackConversion )
+ {
+ case NF_CONVERT_ENGLISH_GERMAN :
+ ConvertLanguage( *pHackConverter,
+ LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, TRUE );
+ break;
+ case NF_CONVERT_GERMAN_ENGLISH :
+ ConvertLanguage( *pHackConverter,
+ LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, TRUE );
+ break;
+ default:
+ DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" );
+ }
+ }
+ return eHackConversion;
+}
+
+void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter,
+ LanguageType eConvertFrom, LanguageType eConvertTo, BOOL bSystem )
+{
+ xub_StrLen nCheckPos;
+ sal_uInt32 nKey;
+ short nType = eType;
+ String aFormatString( sFormatstring );
+ if ( bSystem )
+ rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType,
+ nKey, eConvertFrom, eConvertTo );
+ else
+ rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType,
+ nKey, eConvertFrom, eConvertTo );
+ const SvNumberformat* pFormat = rConverter.GetEntry( nKey );
+ DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
+ if ( pFormat )
+ {
+ ImpCopyNumberformat( *pFormat );
+ // aus Formatter/Scanner uebernommene Werte zuruecksetzen
+ if ( bSystem )
+ eLnge = LANGUAGE_SYSTEM;
+ // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner
+ for ( USHORT i = 0; i < 4; i++ )
+ {
+ String aColorName = NumFor[i].GetColorName();
+ Color* pColor = rScan.GetColor( aColorName );
+ NumFor[i].SetColor( pColor, aColorName );
+ }
+ }
+}
+
+
+// static
+void SvNumberformat::LoadString( SvStream& rStream, String& rStr )
+{
+ CharSet eStream = rStream.GetStreamCharSet();
+ ByteString aStr;
+ rStream.ReadByteString( aStr );
+ sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream );
+ if ( aStr.Search( cStream ) == STRING_NOTFOUND )
+ { // simple conversion to unicode
+ rStr = UniString( aStr, eStream );
+ }
+ else
+ {
+ sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol();
+ register const sal_Char* p = aStr.GetBuffer();
+ register const sal_Char* const pEnd = p + aStr.Len();
+ register sal_Unicode* pUni = rStr.AllocBuffer( aStr.Len() );
+ while ( p < pEnd )
+ {
+ if ( *p == cStream )
+ *pUni = cTarget;
+ else
+ *pUni = ByteString::ConvertToUnicode( *p, eStream );
+ p++;
+ pUni++;
+ }
+ *pUni = 0;
+ }
+}
+
+
+void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const
+{
+ String aFormatstring( sFormatstring );
+ String aComment( sComment );
+#if NF_COMMENT_IN_FORMATSTRING
+ // der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen
+ // nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung
+ // (z.B. im Dialog) zu ermoeglichen
+ SetComment( "", aFormatstring, aComment );
+#endif
+
+ BOOL bNewCurrency = HasNewCurrency();
+ if ( bNewCurrency )
+ { // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern
+ aComment.Insert( cNewCurrencyMagic, 0 );
+ aComment.Insert( cNewCurrencyMagic, 0 );
+ aComment.Insert( aFormatstring, 1 );
+ Build50Formatstring( aFormatstring ); // alten Formatstring generieren
+ }
+
+ // old SO5 versions do behave strange (no output) if standard flag is set
+ // on formats not prepared for it (not having the following exact types)
+ BOOL bOldStandard = bStandard;
+ if ( bOldStandard )
+ {
+ switch ( eType )
+ {
+ case NUMBERFORMAT_NUMBER :
+ case NUMBERFORMAT_DATE :
+ case NUMBERFORMAT_TIME :
+ case NUMBERFORMAT_DATETIME :
+ case NUMBERFORMAT_PERCENT :
+ case NUMBERFORMAT_SCIENTIFIC :
+ // ok to save
+ break;
+ default:
+ bOldStandard = FALSE;
+ }
+ }
+
+ rHdr.StartEntry();
+ rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() );
+ rStream << eType << fLimit1 << fLimit2 << (USHORT) eOp1 << (USHORT) eOp2
+ << bOldStandard << bIsUsed;
+ for (USHORT i = 0; i < 4; i++)
+ NumFor[i].Save(rStream);
+ // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD
+ rStream.WriteByteString( aComment, rStream.GetStreamCharSet() );
+ rStream << nNewStandardDefined;
+ // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
+ rStream << nNewCurrencyVersionId;
+ rStream << bNewCurrency;
+ if ( bNewCurrency )
+ {
+ for ( USHORT j=0; j<4; j++ )
+ {
+ NumFor[j].SaveNewCurrencyMap( rStream );
+ }
+ }
+
+ // the real standard flag to load with versions >638 if different
+ if ( bStandard != bOldStandard )
+ {
+ rStream << nNewStandardFlagVersionId;
+ rStream << bStandard;
+ }
+
+ rHdr.EndEntry();
+}
+
+
+BOOL SvNumberformat::HasNewCurrency() const
+{
+ for ( USHORT j=0; j<4; j++ )
+ {
+ if ( NumFor[j].HasNewCurrency() )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+BOOL SvNumberformat::GetNewCurrencySymbol( String& rSymbol,
+ String& rExtension ) const
+{
+ for ( USHORT j=0; j<4; j++ )
+ {
+ if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) )
+ return TRUE;
+ }
+ rSymbol.Erase();
+ rExtension.Erase();
+ return FALSE;
+}
+
+
+// static
+String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr,
+ BOOL bQuoteSymbol )
+{
+ String aTmp;
+ xub_StrLen nStartPos, nPos, nLen;
+ nLen = rStr.Len();
+ nStartPos = 0;
+ while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND )
+ {
+ xub_StrLen nEnd;
+ if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen )
+ {
+ aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos );
+ nStartPos = nEnd;
+ }
+ else
+ {
+ aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
+ nStartPos = nPos + 2;
+ xub_StrLen nDash;
+ nEnd = nStartPos - 1;
+ do
+ {
+ nDash = rStr.Search( '-', ++nEnd );
+ } while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen );
+ xub_StrLen nClose;
+ nEnd = nStartPos - 1;
+ do
+ {
+ nClose = rStr.Search( ']', ++nEnd );
+ } while ( (nEnd = GetQuoteEnd( rStr, nClose )) < nLen );
+ nPos = ( nDash < nClose ? nDash : nClose );
+ if ( !bQuoteSymbol || rStr.GetChar( nStartPos ) == '"' )
+ aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
+ else
+ {
+ aTmp += '"';
+ aTmp += rStr.Copy( nStartPos, nPos - nStartPos );
+ aTmp += '"';
+ }
+ nStartPos = nClose + 1;
+ }
+ }
+ if ( nLen > nStartPos )
+ aTmp += rStr.Copy( nStartPos, nLen - nStartPos );
+ return aTmp;
+}
+
+
+void SvNumberformat::Build50Formatstring( String& rStr ) const
+{
+ rStr = StripNewCurrencyDelimiters( sFormatstring, TRUE );
+}
+
+
+void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString)
+{
+ USHORT nStandardPrec = rScan.GetStandardPrec();
+ if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16
+ OutString = ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_E, nStandardPrec /*2*/,
+ GetFormatter().GetNumDecimalSep().GetChar(0));
+ else
+ {
+#if 0
+{
+ // debugger test case for ANSI standard correctness
+ ::rtl::OUString aTest;
+ // expect 0.00123 OK
+ aTest = ::rtl::math::doubleToUString( 0.001234567,
+ rtl_math_StringFormat_G, 3, '.', sal_True );
+ // expect 123 OK
+ aTest = ::rtl::math::doubleToUString( 123.4567,
+ rtl_math_StringFormat_G, 3, '.', sal_True );
+ // expect 123.5 OK
+ aTest = ::rtl::math::doubleToUString( 123.4567,
+ rtl_math_StringFormat_G, 4, '.', sal_True );
+ // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
+ // 1000 with an exponent equal to significant digits)
+ // Currently (24-Jan-2003) we do fail in this case and output 1000
+ // instead, negligible.
+ aTest = ::rtl::math::doubleToUString( 999.6,
+ rtl_math_StringFormat_G, 3, '.', sal_True );
+ // expect what? result is 1.2e+004
+ aTest = ::rtl::math::doubleToUString( 12345.6789,
+ rtl_math_StringFormat_G, -3, '.', sal_True );
+}
+#endif
+
+ OutString = ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_F, nStandardPrec /*2*/,
+ GetFormatter().GetNumDecimalSep().GetChar(0), sal_True );
+ if (OutString.GetChar(0) == '-' &&
+ OutString.GetTokenCount('0') == OutString.Len())
+ OutString.EraseLeadingChars('-'); // nicht -0
+ }
+ ImpTransliterate( OutString, NumFor[0].GetNatNum() );
+ return;
+}
+
+void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString)
+{
+ BOOL bModified = FALSE;
+ if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100))
+ {
+ if (fNumber == 0.0)
+ {
+ OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) );
+ return;
+ }
+ fNumber *= 100;
+ bModified = TRUE;
+ }
+
+ if (fNumber == 0.0)
+ {
+ OutString = '0';
+ return;
+ }
+
+ OutString = ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ GetFormatter().GetNumDecimalSep().GetChar(0), sal_True );
+
+ if ( eType & NUMBERFORMAT_PERCENT && bModified)
+ OutString += '%';
+ return;
+}
+
+short SvNumberformat::ImpCheckCondition(double& fNumber,
+ double& fLimit,
+ SvNumberformatLimitOps eOp)
+{
+ switch(eOp)
+ {
+ case NUMBERFORMAT_OP_NO: return -1;
+ case NUMBERFORMAT_OP_EQ: return (short) (fNumber == fLimit);
+ case NUMBERFORMAT_OP_NE: return (short) (fNumber != fLimit);
+ case NUMBERFORMAT_OP_LT: return (short) (fNumber < fLimit);
+ case NUMBERFORMAT_OP_LE: return (short) (fNumber <= fLimit);
+ case NUMBERFORMAT_OP_GT: return (short) (fNumber > fLimit);
+ case NUMBERFORMAT_OP_GE: return (short) (fNumber >= fLimit);
+ default: return -1;
+ }
+}
+
+BOOL SvNumberformat::GetOutputString(String& sString,
+ String& OutString,
+ Color** ppColor)
+{
+ OutString.Erase();
+ USHORT nIx;
+ if (eType & NUMBERFORMAT_TEXT)
+ nIx = 0;
+ else if (NumFor[3].GetnAnz() > 0)
+ nIx = 3;
+ else
+ {
+ *ppColor = NULL; // no change of color
+ return FALSE;
+ }
+ *ppColor = NumFor[nIx].GetColor();
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ if (rInfo.eScannedType == NUMBERFORMAT_TEXT)
+ {
+ BOOL bRes = FALSE;
+ const USHORT nAnz = NumFor[nIx].GetnAnz();
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ switch (rInfo.nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ OutString += (sal_Unicode) 0x1B;
+ OutString += rInfo.sStrArray[i].GetChar(1);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ InsertBlanks( OutString, OutString.Len(),
+ rInfo.sStrArray[i].GetChar(1) );
+ break;
+ case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
+ case NF_SYMBOLTYPE_DEL :
+ OutString += sString;
+ break;
+ default:
+ OutString += rInfo.sStrArray[i];
+ }
+ }
+ return bRes;
+ }
+ return FALSE;
+}
+/*
+void SvNumberformat::GetNextFareyNumber(ULONG nPrec, ULONG x0, ULONG x1,
+ ULONG y0, ULONG y1,
+ ULONG& x2,ULONG& y2)
+{
+ x2 = ((y0+nPrec)/y1)*x1 - x0;
+ y2 = ((y0+nPrec)/y1)*y1 - y0;
+}
+*/
+ULONG SvNumberformat::ImpGGT(ULONG x, ULONG y)
+{
+ if (y == 0)
+ return x;
+ else
+ {
+ ULONG z = x%y;
+ while (z)
+ {
+ x = y;
+ y = z;
+ z = x%y;
+ }
+ return y;
+ }
+}
+
+ULONG SvNumberformat::ImpGGTRound(ULONG x, ULONG y)
+{
+ if (y == 0)
+ return x;
+ else
+ {
+ ULONG z = x%y;
+ while ((double)z/(double)y > D_EPS)
+ {
+ x = y;
+ y = z;
+ z = x%y;
+ }
+ return y;
+ }
+}
+
+BOOL SvNumberformat::GetOutputString(double fNumber,
+ String& OutString,
+ Color** ppColor)
+{
+ BOOL bRes = FALSE;
+ OutString.Erase(); // alles loeschen
+ *ppColor = NULL; // keine Farbaenderung
+ if (eType & NUMBERFORMAT_LOGICAL)
+ {
+ if (fNumber)
+ OutString = rScan.GetTrueString();
+ else
+ OutString = rScan.GetFalseString();
+ return FALSE;
+ }
+ if (eType & NUMBERFORMAT_TEXT && bStandard)
+ {
+ ImpGetOutputStandard(fNumber, OutString);
+ return FALSE;
+ }
+ BOOL bHadStandard = FALSE;
+ if (bStandard) // einzelne Standardformate
+ {
+ if (rScan.GetStandardPrec() == 300) // alle Zahlformate InputLine
+ {
+ ImpGetOutputInputLine(fNumber, OutString);
+ return FALSE;
+ }
+ switch (eType)
+ {
+ case NUMBERFORMAT_NUMBER: // Standardzahlformat
+ ImpGetOutputStandard(fNumber, OutString);
+ bHadStandard = TRUE;
+ break;
+ case NUMBERFORMAT_DATE:
+ bRes |= ImpGetDateOutput(fNumber, 0, OutString);
+ bHadStandard = TRUE;
+ break;
+ case NUMBERFORMAT_TIME:
+ bRes |= ImpGetTimeOutput(fNumber, 0, OutString);
+ bHadStandard = TRUE;
+ break;
+ case NUMBERFORMAT_DATETIME:
+ bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString);
+ bHadStandard = TRUE;
+ break;
+ }
+ }
+ if ( !bHadStandard )
+ {
+ USHORT nIx; // Index des Teilformats
+ short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
+ if (nCheck == -1 || nCheck == 1) // nur 1 String oder True
+ nIx = 0;
+ else
+ {
+ nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
+ if (nCheck == -1 || nCheck == 1)
+ nIx = 1;
+ else
+ nIx = 2;
+ }
+ if (nIx == 1 && fNumber < 0.0 && // negatives Format
+ IsNegativeRealNegative() ) // ohne Vorzeichen
+ fNumber = -fNumber; // Vorzeichen eliminieren
+ *ppColor = NumFor[nIx].GetColor();
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ const USHORT nAnz = NumFor[nIx].GetnAnz();
+ if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED)
+ return FALSE; // leer => nichts
+ else if (nAnz == 0) // sonst Standard-Format
+ {
+ ImpGetOutputStandard(fNumber, OutString);
+ return FALSE;
+ }
+ switch (rInfo.eScannedType)
+ {
+ case NUMBERFORMAT_TEXT:
+ case NUMBERFORMAT_DEFINED:
+ {
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ switch (rInfo.nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ OutString += (sal_Unicode) 0x1B;
+ OutString += rInfo.sStrArray[i].GetChar(1);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ InsertBlanks( OutString, OutString.Len(),
+ rInfo.sStrArray[i].GetChar(1) );
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_CURRENCY:
+ OutString += rInfo.sStrArray[i];
+ break;
+ case NF_SYMBOLTYPE_THSEP:
+ if (rInfo.nThousand == 0)
+ OutString += rInfo.sStrArray[i];
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case NUMBERFORMAT_DATE:
+ bRes |= ImpGetDateOutput(fNumber, nIx, OutString);
+ break;
+ case NUMBERFORMAT_TIME:
+ bRes |= ImpGetTimeOutput(fNumber, nIx, OutString);
+ break;
+ case NUMBERFORMAT_DATETIME:
+ bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString);
+ break;
+ case NUMBERFORMAT_NUMBER:
+ case NUMBERFORMAT_PERCENT:
+ case NUMBERFORMAT_CURRENCY:
+ bRes |= ImpGetNumberOutput(fNumber, nIx, OutString);
+ break;
+ case NUMBERFORMAT_FRACTION:
+ {
+ String sStr, sFrac, sDiv; // Strings, Wert fuer
+ ULONG nFrac, nDiv; // Vorkommaanteil
+ // Zaehler und Nenner
+ BOOL bSign = FALSE;
+ if (fNumber < 0)
+ {
+ if (nIx == 0) // nicht in hinteren
+ bSign = TRUE; // Formaten
+ fNumber = -fNumber;
+ }
+ double fNum = floor(fNumber); // Vorkommateil
+ fNumber -= fNum; // Nachkommateil
+ if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9)
+ // zu gross
+ {
+ OutString = rScan.GetErrorString();
+ return FALSE;
+ }
+ if (rInfo.nCntExp == 0)
+ {
+ DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0");
+ return FALSE;
+ }
+ ULONG nBasis = ((ULONG)floor( // 9, 99, 999 ,...
+ pow(10.0,rInfo.nCntExp))) - 1;
+ ULONG x0, y0, x1, y1;
+
+ if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
+ {
+ BOOL bUpperHalf;
+ if (fNumber > 0.5)
+ {
+ bUpperHalf = TRUE;
+ fNumber -= (fNumber - 0.5) * 2.0;
+ }
+ else
+ bUpperHalf = FALSE;
+ // Einstieg in Farey-Serie
+ // finden:
+ x0 = (ULONG) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9
+ if (x0 == 0) // => x0 = 2
+ {
+ y0 = 1;
+ x1 = 1;
+ y1 = nBasis;
+ }
+ else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2
+ { // geht (nBasis ungerade)
+ y0 = nBasis;
+ x1 = 1;
+ y1 = 2;
+ }
+ else if (x0 == 1)
+ {
+ y0 = nBasis; // 1/n; 1/(n-1)
+ x1 = 1;
+ y1 = nBasis - 1;
+ }
+ else
+ {
+ y0 = nBasis; // z.B. 2/9 2/8
+ x1 = x0;
+ y1 = nBasis - 1;
+ double fUg = (double) x0 / (double) y0;
+ double fOg = (double) x1 / (double) y1;
+ ULONG nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen
+ x0 /= nGgt;
+ y0 /= nGgt; // Einschachteln:
+ ULONG x2 = 0;
+ ULONG y2 = 0;
+ BOOL bStop = FALSE;
+ while (!bStop)
+ {
+#ifdef GCC
+ // #i21648# GCC over-optimizes something resulting
+ // in wrong fTest values throughout the loops.
+ volatile
+#endif
+ double fTest = (double)x1/(double)y1;
+ while (!bStop)
+ {
+ while (fTest > fOg)
+ {
+ x1--;
+ fTest = (double)x1/(double)y1;
+ }
+ while (fTest < fUg && y1 > 1)
+ {
+ y1--;
+ fTest = (double)x1/(double)y1;
+ }
+ if (fTest <= fOg)
+ {
+ fOg = fTest;
+ bStop = TRUE;
+ }
+ else if (y1 == 1)
+ bStop = TRUE;
+ } // of while
+ nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen
+ x2 = x1 / nGgt;
+ y2 = y1 / nGgt;
+ if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2
+ bStop = TRUE; // naechste Farey-Zahl
+ else
+ {
+ y1--;
+ bStop = FALSE;
+ }
+ } // of while
+ x1 = x2;
+ y1 = y2;
+ } // of else
+ double fup, flow;
+ flow = (double)x0/(double)y0;
+ fup = (double)x1/(double)y1;
+ while (fNumber > fup)
+ {
+ ULONG x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl
+ ULONG y2 = ((y0+nBasis)/y1)*y1 - y0;
+// GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2);
+ x0 = x1;
+ y0 = y1;
+ x1 = x2;
+ y1 = y2;
+ flow = fup;
+ fup = (double)x1/(double)y1;
+ }
+ if (fNumber - flow < fup - fNumber)
+ {
+ nFrac = x0;
+ nDiv = y0;
+ }
+ else
+ {
+ nFrac = x1;
+ nDiv = y1;
+ }
+ if (bUpperHalf) // Original restaur.
+ {
+ if (nFrac == 0 && nDiv == 1) // 1/1
+ fNum += 1.0;
+ else
+ nFrac = nDiv - nFrac;
+ }
+ }
+ else // grosse Nenner
+ { // 0,1234->123/1000
+ ULONG nGgt;
+/*
+ nDiv = nBasis+1;
+ nFrac = ((ULONG)floor(0.5 + fNumber *
+ pow(10.0,rInfo.nCntExp)));
+*/
+ nDiv = 10000000;
+ nFrac = ((ULONG)floor(0.5 + fNumber * 10000000.0));
+ nGgt = ImpGGT(nDiv, nFrac);
+ if (nGgt > 1)
+ {
+ nDiv /= nGgt;
+ nFrac /= nGgt;
+ }
+ if (nDiv > nBasis)
+ {
+ nGgt = ImpGGTRound(nDiv, nFrac);
+ if (nGgt > 1)
+ {
+ nDiv /= nGgt;
+ nFrac /= nGgt;
+ }
+ }
+ if (nDiv > nBasis)
+ {
+ nDiv = nBasis;
+ nFrac = ((ULONG)floor(0.5 + fNumber *
+ pow(10.0,rInfo.nCntExp)));
+ nGgt = ImpGGTRound(nDiv, nFrac);
+ if (nGgt > 1)
+ {
+ nDiv /= nGgt;
+ nFrac /= nGgt;
+ }
+ }
+ }
+
+ if (rInfo.nCntPre == 0) // unechter Bruch
+ {
+ double fNum1 = fNum * (double)nDiv + (double)nFrac;
+ if (fNum1 > _D_MAX_U_LONG_)
+ {
+ OutString = rScan.GetErrorString();
+ return FALSE;
+ }
+ nFrac = (ULONG) floor(fNum1);
+ sStr.Erase();
+ }
+ else if (fNum == 0.0 && nFrac != 0)
+ sStr.Erase();
+ else
+ {
+ char aBuf[100];
+ sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked)
+ sStr.AssignAscii( aBuf );
+ ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
+ }
+ if (rInfo.nCntPre > 0 && nFrac == 0)
+ {
+ sFrac.Erase();
+ sDiv.Erase();
+ }
+ else
+ {
+ sFrac = ImpIntToString( nIx, nFrac );
+ sDiv = ImpIntToString( nIx, nDiv );
+ }
+
+ USHORT j = nAnz-1; // letztes Symbol->rueckw.
+ xub_StrLen k; // Nenner:
+ bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
+ BOOL bCont = TRUE;
+ if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
+ {
+ if (rInfo.nCntPre > 0 && nFrac == 0)
+ sDiv.Insert(' ',0);
+ else
+ sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 );
+ if ( j )
+ j--;
+ else
+ bCont = FALSE;
+ }
+ // weiter Zaehler:
+ if ( !bCont )
+ sFrac.Erase();
+ else
+ {
+ bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
+ if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
+ {
+ sFrac.Insert(rInfo.sStrArray[j],0);
+ if ( j )
+ j--;
+ else
+ bCont = FALSE;
+ }
+ }
+ // weiter Hauptzahl
+ if ( !bCont )
+ sStr.Erase();
+ else
+ {
+ k = sStr.Len(); // hinter letzter Ziffer
+ bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
+ rInfo.nCntPre);
+ }
+ if (bSign && !(nFrac == 0 && fNum == 0.0))
+ OutString.Insert('-',0); // nicht -0
+ OutString += sStr;
+ OutString += sFrac;
+ OutString += sDiv;
+ }
+ break;
+ case NUMBERFORMAT_SCIENTIFIC:
+ {
+ BOOL bSign = FALSE;
+ if (fNumber < 0)
+ {
+ if (nIx == 0) // nicht in hinteren
+ bSign = TRUE; // Formaten
+ fNumber = -fNumber;
+ }
+ String sStr( ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_E,
+ rInfo.nCntPre + rInfo.nCntPost - 1, '.' ));
+
+ String ExpStr;
+ short nExpSign = 1;
+ xub_StrLen nExPos = sStr.Search('E');
+ if ( nExPos != STRING_NOTFOUND )
+ {
+ // split into mantisse and exponent and get rid of "E+" or "E-"
+ xub_StrLen nExpStart = nExPos + 1;
+ switch ( sStr.GetChar( nExpStart ) )
+ {
+ case '-' :
+ nExpSign = -1;
+ // fallthru
+ case '+' :
+ ++nExpStart;
+ break;
+ }
+ ExpStr = sStr.Copy( nExpStart ); // part following the "E+"
+ sStr.Erase( nExPos );
+ sStr.EraseAllChars('.'); // cut any decimal delimiter
+ if ( rInfo.nCntPre != 1 ) // rescale Exp
+ {
+ sal_Int32 nExp = ExpStr.ToInt32() * nExpSign;
+ nExp -= sal_Int32(rInfo.nCntPre)-1;
+ if ( nExp < 0 )
+ {
+ nExpSign = -1;
+ nExp = -nExp;
+ }
+ else
+ nExpSign = 1;
+ ExpStr = String::CreateFromInt32( nExp );
+ }
+ }
+ USHORT j = nAnz-1; // last symbol
+ xub_StrLen k; // position in ExpStr
+ bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
+
+ xub_StrLen nZeros = 0; // erase leading zeros
+ while (nZeros < k && ExpStr.GetChar(nZeros) == '0')
+ ++nZeros;
+ if (nZeros)
+ ExpStr.Erase( 0, nZeros);
+
+ BOOL bCont = TRUE;
+ if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
+ {
+ const String& rStr = rInfo.sStrArray[j];
+ if (nExpSign == -1)
+ ExpStr.Insert('-',0);
+ else if (rStr.Len() > 1 && rStr.GetChar(1) == '+')
+ ExpStr.Insert('+',0);
+ ExpStr.Insert(rStr.GetChar(0),0);
+ if ( j )
+ j--;
+ else
+ bCont = FALSE;
+ }
+ // weiter Hauptzahl:
+ if ( !bCont )
+ sStr.Erase();
+ else
+ {
+ k = sStr.Len(); // hinter letzter Ziffer
+ bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx,
+ rInfo.nCntPre +
+ rInfo.nCntPost);
+ }
+ if (bSign)
+ sStr.Insert('-',0);
+ OutString = sStr;
+ OutString += ExpStr;
+ }
+ break;
+ }
+ }
+ return bRes;
+}
+
+BOOL SvNumberformat::ImpGetTimeOutput(double fNumber,
+ USHORT nIx,
+ String& OutString)
+{
+ using namespace ::com::sun::star::i18n;
+ BOOL bCalendarSet = FALSE;
+ double fNumberOrig = fNumber;
+ BOOL bRes = FALSE;
+ BOOL bSign = FALSE;
+ if (fNumber < 0.0)
+ {
+ fNumber = -fNumber;
+ if (nIx == 0)
+ bSign = TRUE;
+ }
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ if (rInfo.bThousand) // []-Format
+ {
+ if (fNumber > 1.0E10) // zu gross
+ {
+ OutString = rScan.GetErrorString();
+ return FALSE;
+ }
+ }
+ else
+ fNumber -= floor(fNumber); // sonst Datum abtrennen
+ BOOL bInputLine;
+ xub_StrLen nCntPost;
+ if ( rScan.GetStandardPrec() == 300 &&
+ 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
+ { // round at 7 decimals (+5 of 86400 == 12 significant digits)
+ bInputLine = TRUE;
+ nCntPost = 7;
+ }
+ else
+ {
+ bInputLine = FALSE;
+ nCntPost = xub_StrLen(rInfo.nCntPost);
+ }
+ if (bSign && !rInfo.bThousand) // kein []-Format
+ fNumber = 1.0 - fNumber; // "Kehrwert"
+ double fTime = fNumber * 86400.0;
+ fTime = ::rtl::math::round( fTime, int(nCntPost) );
+ if (bSign && fTime == 0.0)
+ bSign = FALSE; // nicht -00:00:00
+
+ if( floor( fTime ) > _D_MAX_U_LONG_ )
+ {
+ OutString = rScan.GetErrorString();
+ return FALSE;
+ }
+ ULONG nSeconds = (ULONG)floor( fTime );
+
+ String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
+ rtl_math_StringFormat_F, int(nCntPost), '.'));
+ sSecStr.EraseLeadingChars('0');
+ sSecStr.EraseLeadingChars('.');
+ if ( bInputLine )
+ {
+ sSecStr.EraseTrailingChars('0');
+ if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
+ sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
+ ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
+ nCntPost = sSecStr.Len();
+ }
+ else
+ ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
+
+ xub_StrLen nSecPos = 0; // Zum Ziffernweisen
+ // abarbeiten
+ ULONG nHour, nMin, nSec;
+ if (!rInfo.bThousand) // kein [] Format
+ {
+ nHour = (nSeconds/3600) % 24;
+ nMin = (nSeconds%3600) / 60;
+ nSec = nSeconds%60;
+ }
+ else if (rInfo.nThousand == 3) // [ss]
+ {
+ nHour = 0;
+ nMin = 0;
+ nSec = nSeconds;
+ }
+ else if (rInfo.nThousand == 2) // [mm]:ss
+ {
+ nHour = 0;
+ nMin = nSeconds / 60;
+ nSec = nSeconds % 60;
+ }
+ else if (rInfo.nThousand == 1) // [hh]:mm:ss
+ {
+ nHour = nSeconds / 3600;
+ nMin = (nSeconds%3600) / 60;
+ nSec = nSeconds%60;
+ }
+ else {
+ // TODO What should these be set to?
+ nHour = 0;
+ nMin = 0;
+ nSec = 0;
+ }
+
+ sal_Unicode cAmPm = ' '; // a oder p
+ if (rInfo.nCntExp) // AM/PM
+ {
+ if (nHour == 0)
+ {
+ nHour = 12;
+ cAmPm = 'a';
+ }
+ else if (nHour < 12)
+ cAmPm = 'a';
+ else
+ {
+ cAmPm = 'p';
+ if (nHour > 12)
+ nHour -= 12;
+ }
+ }
+ const USHORT nAnz = NumFor[nIx].GetnAnz();
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ switch (rInfo.nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ OutString += (sal_Unicode) 0x1B;
+ OutString += rInfo.sStrArray[i].GetChar(1);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ InsertBlanks( OutString, OutString.Len(),
+ rInfo.sStrArray[i].GetChar(1) );
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_CURRENCY:
+ case NF_SYMBOLTYPE_DATESEP:
+ case NF_SYMBOLTYPE_TIMESEP:
+ case NF_SYMBOLTYPE_TIME100SECSEP:
+ OutString += rInfo.sStrArray[i];
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ {
+ xub_StrLen nLen = ( bInputLine && i > 0 &&
+ (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
+ rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
+ nCntPost : rInfo.sStrArray[i].Len() );
+ for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
+ {
+ OutString += sSecStr.GetChar(nSecPos);
+ nSecPos++;
+ }
+ }
+ break;
+ case NF_KEY_AMPM: // AM/PM
+ {
+ if ( !bCalendarSet )
+ {
+ double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
+ fDiff += fNumberOrig;
+ GetCal().setLocalDateTime( fDiff );
+ bCalendarSet = TRUE;
+ }
+ if (cAmPm == 'a')
+ OutString += GetCal().getDisplayName(
+ CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 );
+ else
+ OutString += GetCal().getDisplayName(
+ CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 );
+ }
+ break;
+ case NF_KEY_AP: // A/P
+ {
+ if (cAmPm == 'a')
+ OutString += 'a';
+ else
+ OutString += 'p';
+ }
+ break;
+ case NF_KEY_MI: // M
+ OutString += ImpIntToString( nIx, nMin );
+ break;
+ case NF_KEY_MMI: // MM
+ OutString += ImpIntToString( nIx, nMin, 2 );
+ break;
+ case NF_KEY_H: // H
+ OutString += ImpIntToString( nIx, nHour );
+ break;
+ case NF_KEY_HH: // HH
+ OutString += ImpIntToString( nIx, nHour, 2 );
+ break;
+ case NF_KEY_S: // S
+ OutString += ImpIntToString( nIx, nSec );
+ break;
+ case NF_KEY_SS: // SS
+ OutString += ImpIntToString( nIx, nSec, 2 );
+ break;
+ default:
+ break;
+ }
+ }
+ if (bSign && rInfo.bThousand)
+ OutString.Insert('-',0);
+ return bRes;
+}
+
+
+BOOL SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
+{
+ if ( GetCal().getUniqueID() != Gregorian::get() )
+ return FALSE;
+ const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
+ const USHORT nAnz = rNumFor.GetnAnz();
+ USHORT i;
+ for ( i = 0; i < nAnz; i++ )
+ {
+ switch ( rInfo.nTypeArray[i] )
+ {
+ case NF_SYMBOLTYPE_CALENDAR :
+ return FALSE;
+ case NF_KEY_EC :
+ case NF_KEY_EEC :
+ case NF_KEY_R :
+ case NF_KEY_RR :
+ case NF_KEY_AAA :
+ case NF_KEY_AAAA :
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar,
+ double& fOrgDateTime ) const
+{
+ CalendarWrapper& rCal = GetCal();
+ const rtl::OUString &rGregorian = Gregorian::get();
+ if ( rCal.getUniqueID() == rGregorian )
+ {
+ using namespace ::com::sun::star::i18n;
+ ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals
+ = rCal.getAllCalendars( rLoc().getLocale() );
+ sal_Int32 nCnt = xCals.getLength();
+ if ( nCnt > 1 )
+ {
+ for ( sal_Int32 j=0; j < nCnt; j++ )
+ {
+ if ( xCals[j] != rGregorian )
+ {
+ if ( !rOrgCalendar.Len() )
+ {
+ rOrgCalendar = rCal.getUniqueID();
+ fOrgDateTime = rCal.getDateTime();
+ }
+ rCal.loadCalendar( xCals[j], rLoc().getLocale() );
+ rCal.setDateTime( fOrgDateTime );
+ break; // for
+ }
+ }
+ }
+ }
+}
+
+
+void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar,
+ double fOrgDateTime ) const
+{
+ CalendarWrapper& rCal = GetCal();
+ const rtl::OUString &rGregorian = Gregorian::get();
+ if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian )
+ {
+ rCal.loadCalendar( rGregorian, rLoc().getLocale() );
+ rCal.setDateTime( fOrgDateTime );
+ }
+}
+
+
+BOOL SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime )
+{
+ using namespace ::com::sun::star::i18n;
+ CalendarWrapper& rCal = GetCal();
+ const rtl::OUString &rGregorian = Gregorian::get();
+ if ( rCal.getUniqueID() != rGregorian )
+ {
+ sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
+ if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL(
+ RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) )
+ {
+ if ( !rOrgCalendar.Len() )
+ {
+ rOrgCalendar = rCal.getUniqueID();
+ fOrgDateTime = rCal.getDateTime();
+ }
+ else if ( rOrgCalendar == String(rGregorian) )
+ rOrgCalendar.Erase();
+ rCal.loadCalendar( rGregorian, rLoc().getLocale() );
+ rCal.setDateTime( fOrgDateTime );
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+BOOL SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar,
+ double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const
+{
+ const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
+ const USHORT nAnz = rNumFor.GetnAnz();
+ for ( USHORT i = 0; i < nAnz; i++ )
+ {
+ if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
+ {
+ CalendarWrapper& rCal = GetCal();
+ if ( !rOrgCalendar.Len() )
+ {
+ rOrgCalendar = rCal.getUniqueID();
+ fOrgDateTime = rCal.getDateTime();
+ }
+ rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
+ rCal.setDateTime( fOrgDateTime );
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+// static
+void SvNumberformat::ImpAppendEraG( String& OutString,
+ const CalendarWrapper& rCal, sal_Int16 nNatNum )
+{
+ using namespace ::com::sun::star::i18n;
+ if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) )
+ {
+ sal_Unicode cEra;
+ sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
+ switch ( nVal )
+ {
+ case 1 : cEra = 'M'; break;
+ case 2 : cEra = 'T'; break;
+ case 3 : cEra = 'S'; break;
+ case 4 : cEra = 'H'; break;
+ default:
+ cEra = '?';
+ }
+ OutString += cEra;
+ }
+ else
+ OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum );
+}
+
+
+BOOL SvNumberformat::ImpGetDateOutput(double fNumber,
+ USHORT nIx,
+ String& OutString)
+{
+ using namespace ::com::sun::star::i18n;
+ BOOL bRes = FALSE;
+ CalendarWrapper& rCal = GetCal();
+ double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
+ fNumber += fDiff;
+ rCal.setLocalDateTime( fNumber );
+ String aOrgCalendar; // empty => not changed yet
+ double fOrgDateTime;
+ BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
+ bOtherCalendar = FALSE;
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ const USHORT nAnz = NumFor[nIx].GetnAnz();
+ sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ switch (rInfo.nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_CALENDAR :
+ if ( !aOrgCalendar.Len() )
+ {
+ aOrgCalendar = rCal.getUniqueID();
+ fOrgDateTime = rCal.getDateTime();
+ }
+ rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
+ rCal.setDateTime( fOrgDateTime );
+ ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ break;
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ OutString += (sal_Unicode) 0x1B;
+ OutString += rInfo.sStrArray[i].GetChar(1);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ InsertBlanks( OutString, OutString.Len(),
+ rInfo.sStrArray[i].GetChar(1) );
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_CURRENCY:
+ case NF_SYMBOLTYPE_DATESEP:
+ case NF_SYMBOLTYPE_TIMESEP:
+ case NF_SYMBOLTYPE_TIME100SECSEP:
+ OutString += rInfo.sStrArray[i];
+ break;
+ case NF_KEY_M: // M
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_MONTH, nNatNum );
+ break;
+ case NF_KEY_MM: // MM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_MONTH, nNatNum );
+ break;
+ case NF_KEY_MMM: // MMM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
+ break;
+ case NF_KEY_MMMM: // MMMM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
+ break;
+ case NF_KEY_MMMMM: // MMMMM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
+ break;
+ case NF_KEY_Q: // Q
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_QUARTER, nNatNum );
+ break;
+ case NF_KEY_QQ: // QQ
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_QUARTER, nNatNum );
+ break;
+ case NF_KEY_D: // D
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_DAY, nNatNum );
+ break;
+ case NF_KEY_DD: // DD
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY, nNatNum );
+ break;
+ case NF_KEY_DDD: // DDD
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_DDDD: // DDDD
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_YY: // YY
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_YEAR, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_YYYY: // YYYY
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_YEAR, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_EC: // E
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_YEAR, nNatNum );
+ break;
+ case NF_KEY_EEC: // EE
+ case NF_KEY_R: // R
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_YEAR, nNatNum );
+ break;
+ case NF_KEY_NN: // NN
+ case NF_KEY_AAA: // AAA
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
+ break;
+ case NF_KEY_NNN: // NNN
+ case NF_KEY_AAAA: // AAAA
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ break;
+ case NF_KEY_NNNN: // NNNN
+ {
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ OutString += rLoc().getLongDateDayOfWeekSep();
+ }
+ break;
+ case NF_KEY_WW : // WW
+ {
+ sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
+ OutString += ImpIntToString( nIx, nVal );
+ }
+ break;
+ case NF_KEY_G: // G
+ ImpAppendEraG( OutString, rCal, nNatNum );
+ break;
+ case NF_KEY_GG: // GG
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_ERA, nNatNum );
+ break;
+ case NF_KEY_GGG: // GGG
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_ERA, nNatNum );
+ break;
+ case NF_KEY_RR: // RR => GGGEE
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
+ break;
+ }
+ }
+ if ( aOrgCalendar.Len() )
+ rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
+ return bRes;
+}
+
+BOOL SvNumberformat::ImpGetDateTimeOutput(double fNumber,
+ USHORT nIx,
+ String& OutString)
+{
+ using namespace ::com::sun::star::i18n;
+ BOOL bRes = FALSE;
+
+ CalendarWrapper& rCal = GetCal();
+ double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
+ fNumber += fDiff;
+
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ BOOL bInputLine;
+ xub_StrLen nCntPost;
+ if ( rScan.GetStandardPrec() == 300 &&
+ 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
+ { // round at 7 decimals (+5 of 86400 == 12 significant digits)
+ bInputLine = TRUE;
+ nCntPost = 7;
+ }
+ else
+ {
+ bInputLine = FALSE;
+ nCntPost = xub_StrLen(rInfo.nCntPost);
+ }
+ double fTime = (fNumber - floor( fNumber )) * 86400.0;
+ fTime = ::rtl::math::round( fTime, int(nCntPost) );
+ if (fTime >= 86400.0)
+ {
+ // result of fNumber==x.999999999... rounded up, use correct date/time
+ fTime -= 86400.0;
+ fNumber = floor( fNumber + 0.5) + fTime;
+ }
+ rCal.setLocalDateTime( fNumber );
+
+ String aOrgCalendar; // empty => not changed yet
+ double fOrgDateTime;
+ BOOL bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
+ bOtherCalendar = FALSE;
+ sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
+
+ ULONG nSeconds = (ULONG)floor( fTime );
+ String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
+ rtl_math_StringFormat_F, int(nCntPost), '.'));
+ sSecStr.EraseLeadingChars('0');
+ sSecStr.EraseLeadingChars('.');
+ if ( bInputLine )
+ {
+ sSecStr.EraseTrailingChars('0');
+ if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) )
+ sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' );
+ ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
+ nCntPost = sSecStr.Len();
+ }
+ else
+ ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() );
+
+ xub_StrLen nSecPos = 0; // Zum Ziffernweisen
+ // abarbeiten
+ ULONG nHour, nMin, nSec;
+ if (!rInfo.bThousand) // [] Format
+ {
+ nHour = (nSeconds/3600) % 24;
+ nMin = (nSeconds%3600) / 60;
+ nSec = nSeconds%60;
+ }
+ else if (rInfo.nThousand == 3) // [ss]
+ {
+ nHour = 0;
+ nMin = 0;
+ nSec = nSeconds;
+ }
+ else if (rInfo.nThousand == 2) // [mm]:ss
+ {
+ nHour = 0;
+ nMin = nSeconds / 60;
+ nSec = nSeconds % 60;
+ }
+ else if (rInfo.nThousand == 1) // [hh]:mm:ss
+ {
+ nHour = nSeconds / 3600;
+ nMin = (nSeconds%3600) / 60;
+ nSec = nSeconds%60;
+ }
+ else {
+ nHour = 0; // TODO What should these values be?
+ nMin = 0;
+ nSec = 0;
+ }
+ sal_Unicode cAmPm = ' '; // a oder p
+ if (rInfo.nCntExp) // AM/PM
+ {
+ if (nHour == 0)
+ {
+ nHour = 12;
+ cAmPm = 'a';
+ }
+ else if (nHour < 12)
+ cAmPm = 'a';
+ else
+ {
+ cAmPm = 'p';
+ if (nHour > 12)
+ nHour -= 12;
+ }
+ }
+ const USHORT nAnz = NumFor[nIx].GetnAnz();
+ for (USHORT i = 0; i < nAnz; i++)
+ {
+ switch (rInfo.nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_CALENDAR :
+ if ( !aOrgCalendar.Len() )
+ {
+ aOrgCalendar = rCal.getUniqueID();
+ fOrgDateTime = rCal.getDateTime();
+ }
+ rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
+ rCal.setDateTime( fOrgDateTime );
+ ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ break;
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ OutString += (sal_Unicode) 0x1B;
+ OutString += rInfo.sStrArray[i].GetChar(1);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ InsertBlanks( OutString, OutString.Len(),
+ rInfo.sStrArray[i].GetChar(1) );
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_CURRENCY:
+ case NF_SYMBOLTYPE_DATESEP:
+ case NF_SYMBOLTYPE_TIMESEP:
+ case NF_SYMBOLTYPE_TIME100SECSEP:
+ OutString += rInfo.sStrArray[i];
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ {
+ xub_StrLen nLen = ( bInputLine && i > 0 &&
+ (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
+ rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
+ nCntPost : rInfo.sStrArray[i].Len() );
+ for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++)
+ {
+ OutString += sSecStr.GetChar(nSecPos);
+ nSecPos++;
+ }
+ }
+ break;
+ case NF_KEY_AMPM: // AM/PM
+ {
+ if (cAmPm == 'a')
+ OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
+ AmPmValue::AM, 0 );
+ else
+ OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
+ AmPmValue::PM, 0 );
+ }
+ break;
+ case NF_KEY_AP: // A/P
+ {
+ if (cAmPm == 'a')
+ OutString += 'a';
+ else
+ OutString += 'p';
+ }
+ break;
+ case NF_KEY_MI: // M
+ OutString += ImpIntToString( nIx, nMin );
+ break;
+ case NF_KEY_MMI: // MM
+ OutString += ImpIntToString( nIx, nMin, 2 );
+ break;
+ case NF_KEY_H: // H
+ OutString += ImpIntToString( nIx, nHour );
+ break;
+ case NF_KEY_HH: // HH
+ OutString += ImpIntToString( nIx, nHour, 2 );
+ break;
+ case NF_KEY_S: // S
+ OutString += ImpIntToString( nIx, nSec );
+ break;
+ case NF_KEY_SS: // SS
+ OutString += ImpIntToString( nIx, nSec, 2 );
+ break;
+ case NF_KEY_M: // M
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_MONTH, nNatNum );
+ break;
+ case NF_KEY_MM: // MM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_MONTH, nNatNum );
+ break;
+ case NF_KEY_MMM: // MMM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum );
+ break;
+ case NF_KEY_MMMM: // MMMM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_MONTH_NAME, nNatNum );
+ break;
+ case NF_KEY_MMMMM: // MMMMM
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0);
+ break;
+ case NF_KEY_Q: // Q
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_QUARTER, nNatNum );
+ break;
+ case NF_KEY_QQ: // QQ
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_QUARTER, nNatNum );
+ break;
+ case NF_KEY_D: // D
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_DAY, nNatNum );
+ break;
+ case NF_KEY_DD: // DD
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY, nNatNum );
+ break;
+ case NF_KEY_DDD: // DDD
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_DDDD: // DDDD
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_YY: // YY
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_YEAR, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_YYYY: // YYYY
+ {
+ if ( bOtherCalendar )
+ SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_YEAR, nNatNum );
+ if ( bOtherCalendar )
+ SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
+ }
+ break;
+ case NF_KEY_EC: // E
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_YEAR, nNatNum );
+ break;
+ case NF_KEY_EEC: // EE
+ case NF_KEY_R: // R
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_YEAR, nNatNum );
+ break;
+ case NF_KEY_NN: // NN
+ case NF_KEY_AAA: // AAA
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_DAY_NAME, nNatNum );
+ break;
+ case NF_KEY_NNN: // NNN
+ case NF_KEY_AAAA: // AAAA
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ break;
+ case NF_KEY_NNNN: // NNNN
+ {
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_DAY_NAME, nNatNum );
+ OutString += rLoc().getLongDateDayOfWeekSep();
+ }
+ break;
+ case NF_KEY_WW : // WW
+ {
+ sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR );
+ OutString += ImpIntToString( nIx, nVal );
+ }
+ break;
+ case NF_KEY_G: // G
+ ImpAppendEraG( OutString, rCal, nNatNum );
+ break;
+ case NF_KEY_GG: // GG
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::SHORT_ERA, nNatNum );
+ break;
+ case NF_KEY_GGG: // GGG
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_ERA, nNatNum );
+ break;
+ case NF_KEY_RR: // RR => GGGEE
+ OutString += rCal.getDisplayString(
+ CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum );
+ break;
+ }
+ }
+ if ( aOrgCalendar.Len() )
+ rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar
+ return bRes;
+}
+
+BOOL SvNumberformat::ImpGetNumberOutput(double fNumber,
+ USHORT nIx,
+ String& OutString)
+{
+ BOOL bRes = FALSE;
+ BOOL bSign;
+ if (fNumber < 0.0)
+ {
+ if (nIx == 0) // nicht in hinteren
+ bSign = TRUE; // Formaten
+ else
+ bSign = FALSE;
+ fNumber = -fNumber;
+ }
+ else
+ {
+ bSign = FALSE;
+ if ( ::rtl::math::isSignBitSet( fNumber ) )
+ fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-'
+ }
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ if (rInfo.eScannedType == NUMBERFORMAT_PERCENT)
+ {
+ if (fNumber < _D_MAX_D_BY_100)
+ fNumber *= 100.0;
+ else
+ {
+ OutString = rScan.GetErrorString();
+ return FALSE;
+ }
+ }
+ USHORT i, j;
+ xub_StrLen k;
+ String sStr;
+ long nPrecExp;
+ BOOL bInteger = FALSE;
+ if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
+ { // special formatting only if no GENERAL keyword in format code
+ const USHORT nThousand = rInfo.nThousand;
+ for (i = 0; i < nThousand; i++)
+ {
+ if (fNumber > _D_MIN_M_BY_1000)
+ fNumber /= 1000.0;
+ else
+ fNumber = 0.0;
+ }
+ if (fNumber > 0.0)
+ nPrecExp = GetPrecExp( fNumber );
+ else
+ nPrecExp = 0;
+ if (rInfo.nCntPost) // NachkommaStellen
+ {
+ if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15)
+ {
+ sStr = ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_F, 15-nPrecExp, '.');
+ for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
+ sStr += '0';
+ }
+ else
+ sStr = ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
+ sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
+ }
+ else if (fNumber == 0.0) // Null
+ {
+ // nothing to be done here, keep empty string sStr,
+ // ImpNumberFillWithThousands does the rest
+ }
+ else // Integer
+ {
+ sStr = ::rtl::math::doubleToUString( fNumber,
+ rtl_math_StringFormat_F, 0, '.');
+ sStr.EraseLeadingChars('0'); // fuehrende Nullen weg
+ }
+ xub_StrLen nPoint = sStr.Search( '.' );
+ if ( nPoint != STRING_NOTFOUND )
+ {
+ register const sal_Unicode* p = sStr.GetBuffer() + nPoint;
+ while ( *++p == '0' )
+ ;
+ if ( !*p )
+ bInteger = TRUE;
+ sStr.Erase( nPoint, 1 ); // . herausnehmen
+ }
+ if (bSign &&
+ (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000
+ bSign = FALSE; // nicht -0.00
+ } // End of != FLAG_STANDARD_IN_FORMAT
+
+ // von hinten nach vorn
+ // editieren:
+ k = sStr.Len(); // hinter letzter Ziffer
+ j = NumFor[nIx].GetnAnz()-1; // letztes Symbol
+ // Nachkommastellen:
+ if (rInfo.nCntPost > 0)
+ {
+ BOOL bTrailing = TRUE; // ob Endnullen?
+ BOOL bFilled = FALSE; // ob aufgefuellt wurde ?
+ short nType;
+ while (j > 0 && // rueckwaerts
+ (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
+ {
+ switch ( nType )
+ {
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ );
+ sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_CURRENCY:
+ case NF_SYMBOLTYPE_PERCENT:
+ sStr.Insert(rInfo.sStrArray[j],k);
+ break;
+ case NF_SYMBOLTYPE_THSEP:
+ if (rInfo.nThousand == 0)
+ sStr.Insert(rInfo.sStrArray[j],k);
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ {
+ const String& rStr = rInfo.sStrArray[j];
+ const sal_Unicode* p1 = rStr.GetBuffer();
+ register const sal_Unicode* p = p1 + rStr.Len();
+ while ( p1 < p-- )
+ {
+ const sal_Unicode c = *p;
+ k--;
+ if ( sStr.GetChar(k) != '0' )
+ bTrailing = FALSE;
+ if (bTrailing)
+ {
+ if ( c == '0' )
+ bFilled = TRUE;
+ else if ( c == '-' )
+ {
+ if ( bInteger )
+ sStr.SetChar( k, '-' );
+ bFilled = TRUE;
+ }
+ else if ( c == '?' )
+ {
+ sStr.SetChar( k, ' ' );
+ bFilled = TRUE;
+ }
+ else if ( !bFilled ) // #
+ sStr.Erase(k,1);
+ }
+ } // of for
+ } // of case digi
+ break;
+ case NF_KEY_CCC: // CCC-Waehrung
+ sStr.Insert(rScan.GetCurAbbrev(), k);
+ break;
+ case NF_KEY_GENERAL: // Standard im String
+ {
+ String sNum;
+ ImpGetOutputStandard(fNumber, sNum);
+ sNum.EraseLeadingChars('-');
+ sStr.Insert(sNum, k);
+ }
+ break;
+ default:
+ break;
+ } // of switch
+ j--;
+ } // of while
+ } // of Nachkomma
+
+ bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit .
+ rInfo.nCntPre);
+ if ( rInfo.nCntPost > 0 )
+ {
+ const String& rDecSep = GetFormatter().GetNumDecimalSep();
+ xub_StrLen nLen = rDecSep.Len();
+ if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) )
+ sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep
+ }
+ if (bSign)
+ sStr.Insert('-',0);
+ ImpTransliterate( sStr, NumFor[nIx].GetNatNum() );
+ OutString = sStr;
+ return bRes;
+}
+
+BOOL SvNumberformat::ImpNumberFillWithThousands(
+ String& sStr, // number string
+ double& rNumber, // number
+ xub_StrLen k, // position within string
+ USHORT j, // symbol index within format code
+ USHORT nIx, // subformat index
+ USHORT nDigCnt) // count of integer digits in format
+{
+ BOOL bRes = FALSE;
+ xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number
+ xub_StrLen nDigitCount = 0; // count of integer digits from the right
+ BOOL bStop = FALSE;
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ // no normal thousands separators if number divided by thousands
+ BOOL bDoThousands = (rInfo.nThousand == 0);
+ utl::DigitGroupingIterator aGrouping(
+ GetFormatter().GetLocaleData()->getDigitGrouping());
+ while (!bStop) // backwards
+ {
+ if (j == 0)
+ bStop = TRUE;
+ switch (rInfo.nTypeArray[j])
+ {
+ case NF_SYMBOLTYPE_DECSEP:
+ aGrouping.reset();
+ // fall thru
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_CURRENCY:
+ case NF_SYMBOLTYPE_PERCENT:
+ sStr.Insert(rInfo.sStrArray[j],k);
+ if ( k == 0 )
+ nLeadingStringChars =
+ nLeadingStringChars + rInfo.sStrArray[j].Len();
+ break;
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ );
+ sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
+ break;
+ case NF_SYMBOLTYPE_THSEP:
+ {
+ // #i7284# #102685# Insert separator also if number is divided
+ // by thousands and the separator is specified somewhere in
+ // between and not only at the end.
+ // #i12596# But do not insert if it's a parenthesized negative
+ // format like (#,)
+ // In fact, do not insert if divided and regex [0#,],[^0#] and
+ // no other digit symbol follows (which was already detected
+ // during scan of format code, otherwise there would be no
+ // division), else do insert. Same in ImpNumberFill() below.
+ if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
+ bDoThousands = ((j == 0) ||
+ (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
+ rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
+ (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
+ if ( bDoThousands )
+ {
+ if (k > 0)
+ sStr.Insert(rInfo.sStrArray[j],k);
+ else if (nDigitCount < nDigCnt)
+ {
+ // Leading '#' displays nothing (e.g. no leading
+ // separator for numbers <1000 with #,##0 format).
+ // Leading '?' displays blank.
+ // Everything else, including nothing, displays the
+ // separator.
+ sal_Unicode cLeader = 0;
+ if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
+ {
+ const String& rStr = rInfo.sStrArray[j-1];
+ xub_StrLen nLen = rStr.Len();
+ if (nLen)
+ cLeader = rStr.GetChar(nLen-1);
+ }
+ switch (cLeader)
+ {
+ case '#':
+ ; // nothing
+ break;
+ case '?':
+ // erAck: 2008-04-03T16:24+0200
+ // Actually this currently isn't executed
+ // because the format scanner in the context of
+ // "?," doesn't generate a group separator but
+ // a literal ',' character instead that is
+ // inserted unconditionally. Should be changed
+ // on some occasion.
+ sStr.Insert(' ',k);
+ break;
+ default:
+ sStr.Insert(rInfo.sStrArray[j],k);
+ }
+ }
+ aGrouping.advance();
+ }
+ }
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ {
+ const String& rStr = rInfo.sStrArray[j];
+ const sal_Unicode* p1 = rStr.GetBuffer();
+ register const sal_Unicode* p = p1 + rStr.Len();
+ while ( p1 < p-- )
+ {
+ nDigitCount++;
+ if (k > 0)
+ k--;
+ else
+ {
+ switch (*p)
+ {
+ case '0':
+ sStr.Insert('0',0);
+ break;
+ case '?':
+ sStr.Insert(' ',0);
+ break;
+ }
+ }
+ if (nDigitCount == nDigCnt && k > 0)
+ { // more digits than specified
+ ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping);
+ }
+ }
+ }
+ break;
+ case NF_KEY_CCC: // CCC currency
+ sStr.Insert(rScan.GetCurAbbrev(), k);
+ break;
+ case NF_KEY_GENERAL: // "General" in string
+ {
+ String sNum;
+ ImpGetOutputStandard(rNumber, sNum);
+ sNum.EraseLeadingChars('-');
+ sStr.Insert(sNum, k);
+ }
+ break;
+
+ default:
+ break;
+ } // switch
+ j--; // next format code string
+ } // while
+ k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ...
+ if (k > nLeadingStringChars)
+ ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
+ return bRes;
+}
+
+void SvNumberformat::ImpDigitFill(
+ String& sStr, // number string
+ xub_StrLen nStart, // start of digits
+ xub_StrLen& k, // position within string
+ USHORT nIx, // subformat index
+ xub_StrLen & nDigitCount, // count of integer digits from the right so far
+ utl::DigitGroupingIterator & rGrouping ) // current grouping
+{
+ if (NumFor[nIx].Info().bThousand) // only if grouping
+ { // fill in separators
+ const String& rThousandSep = GetFormatter().GetNumThousandSep();
+ while (k > nStart)
+ {
+ if (nDigitCount == rGrouping.getPos())
+ {
+ sStr.Insert( rThousandSep, k );
+ rGrouping.advance();
+ }
+ nDigitCount++;
+ k--;
+ }
+ }
+ else // simply skip
+ k = nStart;
+}
+
+BOOL SvNumberformat::ImpNumberFill( String& sStr, // number string
+ double& rNumber, // number for "General" format
+ xub_StrLen& k, // position within string
+ USHORT& j, // symbol index within format code
+ USHORT nIx, // subformat index
+ short eSymbolType ) // type of stop condition
+{
+ BOOL bRes = FALSE;
+ k = sStr.Len(); // behind last digit
+ const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
+ // no normal thousands separators if number divided by thousands
+ BOOL bDoThousands = (rInfo.nThousand == 0);
+ short nType;
+ while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType )
+ { // rueckwaerts:
+ switch ( nType )
+ {
+ case NF_SYMBOLTYPE_STAR:
+ if( bStarFlag )
+ {
+ sStr.Insert( sal_Unicode(0x1B), k++ );
+ sStr.Insert(rInfo.sStrArray[j].GetChar(1),k);
+ bRes = TRUE;
+ }
+ break;
+ case NF_SYMBOLTYPE_BLANK:
+ k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) );
+ break;
+ case NF_SYMBOLTYPE_THSEP:
+ {
+ // Same as in ImpNumberFillWithThousands() above, do not insert
+ // if divided and regex [0#,],[^0#] and no other digit symbol
+ // follows (which was already detected during scan of format
+ // code, otherwise there would be no division), else do insert.
+ if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 )
+ bDoThousands = ((j == 0) ||
+ (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
+ rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
+ (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
+ if ( bDoThousands && k > 0 )
+ {
+ sStr.Insert(rInfo.sStrArray[j],k);
+ }
+ }
+ break;
+ case NF_SYMBOLTYPE_DIGIT:
+ {
+ const String& rStr = rInfo.sStrArray[j];
+ const sal_Unicode* p1 = rStr.GetBuffer();
+ register const sal_Unicode* p = p1 + rStr.Len();
+ while ( p1 < p-- )
+ {
+ if (k > 0)
+ k--;
+ else
+ {
+ switch (*p)
+ {
+ case '0':
+ sStr.Insert('0',0);
+ break;
+ case '?':
+ sStr.Insert(' ',0);
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case NF_KEY_CCC: // CCC-Waehrung
+ sStr.Insert(rScan.GetCurAbbrev(), k);
+ break;
+ case NF_KEY_GENERAL: // Standard im String
+ {
+ String sNum;
+ ImpGetOutputStandard(rNumber, sNum);
+ sNum.EraseLeadingChars('-'); // Vorzeichen weg!!
+ sStr.Insert(sNum, k);
+ }
+ break;
+
+ default:
+ sStr.Insert(rInfo.sStrArray[j],k);
+ break;
+ } // of switch
+ j--; // naechster String
+ } // of while
+ return bRes;
+}
+
+void SvNumberformat::GetFormatSpecialInfo(BOOL& bThousand,
+ BOOL& IsRed,
+ USHORT& nPrecision,
+ USHORT& nAnzLeading) const
+{
+ // as before: take info from nNumFor=0 for whole format (for dialog etc.)
+
+ short nDummyType;
+ GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
+
+ // "negative in red" is only useful for the whole format
+
+ const Color* pColor = NumFor[1].GetColor();
+ if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
+ && (*pColor == rScan.GetRedColor()))
+ IsRed = TRUE;
+ else
+ IsRed = FALSE;
+}
+
+void SvNumberformat::GetNumForInfo( USHORT nNumFor, short& rScannedType,
+ BOOL& bThousand, USHORT& nPrecision, USHORT& nAnzLeading ) const
+{
+ // take info from a specified sub-format (for XML export)
+
+ if ( nNumFor > 3 )
+ return; // invalid
+
+ const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
+ rScannedType = rInfo.eScannedType;
+ bThousand = rInfo.bThousand;
+ nPrecision = rInfo.nCntPost;
+ if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER)
+ // StandardFormat
+ nAnzLeading = 1;
+ else
+ {
+ nAnzLeading = 0;
+ BOOL bStop = FALSE;
+ USHORT i = 0;
+ const USHORT nAnz = NumFor[nNumFor].GetnAnz();
+ while (!bStop && i < nAnz)
+ {
+ short nType = rInfo.nTypeArray[i];
+ if ( nType == NF_SYMBOLTYPE_DIGIT)
+ {
+ register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer();
+ while ( *p == '#' )
+ p++;
+ while ( *p++ == '0' )
+ nAnzLeading++;
+ }
+ else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
+ bStop = TRUE;
+ i++;
+ }
+ }
+}
+
+const String* SvNumberformat::GetNumForString( USHORT nNumFor, USHORT nPos,
+ BOOL bString /* = FALSE */ ) const
+{
+ if ( nNumFor > 3 )
+ return NULL;
+ USHORT nAnz = NumFor[nNumFor].GetnAnz();
+ if ( !nAnz )
+ return NULL;
+ if ( nPos == 0xFFFF )
+ {
+ nPos = nAnz - 1;
+ if ( bString )
+ { // rueckwaerts
+ short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
+ while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
+ (*pType != NF_SYMBOLTYPE_CURRENCY) )
+ {
+ pType--;
+ nPos--;
+ }
+ if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
+ return NULL;
+ }
+ }
+ else if ( nPos > nAnz - 1 )
+ return NULL;
+ else if ( bString )
+ { // vorwaerts
+ short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
+ while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
+ (*pType != NF_SYMBOLTYPE_CURRENCY) )
+ {
+ pType++;
+ nPos++;
+ }
+ if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
+ (*pType != NF_SYMBOLTYPE_CURRENCY)) )
+ return NULL;
+ }
+ return &NumFor[nNumFor].Info().sStrArray[nPos];
+}
+
+
+short SvNumberformat::GetNumForType( USHORT nNumFor, USHORT nPos,
+ BOOL bString /* = FALSE */ ) const
+{
+ if ( nNumFor > 3 )
+ return 0;
+ USHORT nAnz = NumFor[nNumFor].GetnAnz();
+ if ( !nAnz )
+ return 0;
+ if ( nPos == 0xFFFF )
+ {
+ nPos = nAnz - 1;
+ if ( bString )
+ { // rueckwaerts
+ short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
+ while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
+ (*pType != NF_SYMBOLTYPE_CURRENCY) )
+ {
+ pType--;
+ nPos--;
+ }
+ if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
+ return 0;
+ }
+ }
+ else if ( nPos > nAnz - 1 )
+ return 0;
+ else if ( bString )
+ { // vorwaerts
+ short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
+ while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
+ (*pType != NF_SYMBOLTYPE_CURRENCY) )
+ {
+ pType++;
+ nPos++;
+ }
+ if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
+ return 0;
+ }
+ return NumFor[nNumFor].Info().nTypeArray[nPos];
+}
+
+
+BOOL SvNumberformat::IsNegativeWithoutSign() const
+{
+ if ( IsNegativeRealNegative() )
+ {
+ const String* pStr = GetNumForString( 1, 0, TRUE );
+ if ( pStr )
+ return !HasStringNegativeSign( *pStr );
+ }
+ return FALSE;
+}
+
+
+DateFormat SvNumberformat::GetDateOrder() const
+{
+ if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE )
+ {
+ short const * const pType = NumFor[0].Info().nTypeArray;
+ USHORT nAnz = NumFor[0].GetnAnz();
+ for ( USHORT j=0; j<nAnz; j++ )
+ {
+ switch ( pType[j] )
+ {
+ case NF_KEY_D :
+ case NF_KEY_DD :
+ return DMY;
+ case NF_KEY_M :
+ case NF_KEY_MM :
+ case NF_KEY_MMM :
+ case NF_KEY_MMMM :
+ case NF_KEY_MMMMM :
+ return MDY;
+ case NF_KEY_YY :
+ case NF_KEY_YYYY :
+ case NF_KEY_EC :
+ case NF_KEY_EEC :
+ case NF_KEY_R :
+ case NF_KEY_RR :
+ return YMD;
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR( "SvNumberformat::GetDateOrder: no date" );
+ }
+ return rLoc().getDateFormat();
+}
+
+
+sal_uInt32 SvNumberformat::GetExactDateOrder() const
+{
+ sal_uInt32 nRet = 0;
+ if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE )
+ {
+ DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" );
+ return nRet;
+ }
+ short const * const pType = NumFor[0].Info().nTypeArray;
+ USHORT nAnz = NumFor[0].GetnAnz();
+ int nShift = 0;
+ for ( USHORT j=0; j<nAnz && nShift < 3; j++ )
+ {
+ switch ( pType[j] )
+ {
+ case NF_KEY_D :
+ case NF_KEY_DD :
+ nRet = (nRet << 8) | 'D';
+ ++nShift;
+ break;
+ case NF_KEY_M :
+ case NF_KEY_MM :
+ case NF_KEY_MMM :
+ case NF_KEY_MMMM :
+ case NF_KEY_MMMMM :
+ nRet = (nRet << 8) | 'M';
+ ++nShift;
+ break;
+ case NF_KEY_YY :
+ case NF_KEY_YYYY :
+ case NF_KEY_EC :
+ case NF_KEY_EEC :
+ case NF_KEY_R :
+ case NF_KEY_RR :
+ nRet = (nRet << 8) | 'Y';
+ ++nShift;
+ break;
+ }
+ }
+ return nRet;
+}
+
+
+void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
+ SvNumberformatLimitOps& rOper2, double& rVal2 ) const
+{
+ rOper1 = eOp1;
+ rOper2 = eOp2;
+ rVal1 = fLimit1;
+ rVal2 = fLimit2;
+}
+
+
+Color* SvNumberformat::GetColor( USHORT nNumFor ) const
+{
+ if ( nNumFor > 3 )
+ return NULL;
+
+ return NumFor[nNumFor].GetColor();
+}
+
+
+void lcl_SvNumberformat_AddLimitStringImpl( String& rStr,
+ SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep )
+{
+ if ( eOp != NUMBERFORMAT_OP_NO )
+ {
+ switch ( eOp )
+ {
+ case NUMBERFORMAT_OP_EQ :
+ rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) );
+ break;
+ case NUMBERFORMAT_OP_NE :
+ rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) );
+ break;
+ case NUMBERFORMAT_OP_LT :
+ rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) );
+ break;
+ case NUMBERFORMAT_OP_LE :
+ rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) );
+ break;
+ case NUMBERFORMAT_OP_GT :
+ rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) );
+ break;
+ case NUMBERFORMAT_OP_GE :
+ rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) );
+ break;
+ default:
+ OSL_ASSERT( "unsupported number format" );
+ break;
+ }
+ rStr += String( ::rtl::math::doubleToUString( fLimit,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ rDecSep.GetChar(0), sal_True));
+ rStr += ']';
+ }
+}
+
+
+String SvNumberformat::GetMappedFormatstring(
+ const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp,
+ BOOL bDontQuote ) const
+{
+ String aStr;
+ BOOL bDefault[4];
+ // 1 subformat matches all if no condition specified,
+ bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
+ // with 2 subformats [>=0];[<0] is implied if no condition specified
+ bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 &&
+ eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
+ eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
+ // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
+ // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
+ bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
+ eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
+ eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
+ BOOL bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
+ // from now on bDefault[] values are used to append empty subformats at the end
+ bDefault[3] = FALSE;
+ if ( !bDefaults )
+ { // conditions specified
+ if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
+ bDefault[0] = bDefault[1] = TRUE; // [];x
+ else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
+ NumFor[2].GetnAnz() == 0 )
+ bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = TRUE; // [];[];;
+ // nothing to do if conditions specified for every subformat
+ }
+ else if ( bDefault[0] )
+ bDefault[0] = FALSE; // a single unconditional subformat is never delimited
+ else
+ {
+ if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 )
+ bDefault[3] = TRUE; // special cases x;x;; and ;x;;
+ for ( int i=0; i<3 && !bDefault[i]; ++i )
+ bDefault[i] = TRUE;
+ }
+ int nSem = 0; // needed ';' delimiters
+ int nSub = 0; // subformats delimited so far
+ for ( int n=0; n<4; n++ )
+ {
+ if ( n > 0 )
+ nSem++;
+
+ String aPrefix;
+
+ if ( !bDefaults )
+ {
+ switch ( n )
+ {
+ case 0 :
+ lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
+ fLimit1, rLocWrp.getNumDecimalSep() );
+ break;
+ case 1 :
+ lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
+ fLimit2, rLocWrp.getNumDecimalSep() );
+ break;
+ }
+ }
+
+ const String& rColorName = NumFor[n].GetColorName();
+ if ( rColorName.Len() )
+ {
+ const String* pKey = rScan.GetKeywords() + NF_KEY_FIRSTCOLOR;
+ for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++, pKey++ )
+ {
+ if ( *pKey == rColorName )
+ {
+ aPrefix += '[';
+ aPrefix += rKeywords[j];
+ aPrefix += ']';
+ break; // for
+ }
+ }
+ }
+
+ const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
+ // The Thai T NatNum modifier during Xcl export.
+ if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
+ rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") &&
+ MsLangId::getRealLanguage( rNum.GetLang()) ==
+ LANGUAGE_THAI)
+ {
+ aPrefix += 't'; // must be lowercase, otherwise taken as literal
+ }
+
+ USHORT nAnz = NumFor[n].GetnAnz();
+ if ( nSem && (nAnz || aPrefix.Len()) )
+ {
+ for ( ; nSem; --nSem )
+ aStr += ';';
+ for ( ; nSub <= n; ++nSub )
+ bDefault[nSub] = FALSE;
+ }
+
+ if ( aPrefix.Len() )
+ aStr += aPrefix;
+
+ if ( nAnz )
+ {
+ const short* pType = NumFor[n].Info().nTypeArray;
+ const String* pStr = NumFor[n].Info().sStrArray;
+ for ( USHORT j=0; j<nAnz; j++ )
+ {
+ if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
+ {
+ aStr += rKeywords[pType[j]];
+ if( NF_KEY_NNNN == pType[j] )
+ aStr += rLocWrp.getLongDateDayOfWeekSep();
+ }
+ else
+ {
+ switch ( pType[j] )
+ {
+ case NF_SYMBOLTYPE_DECSEP :
+ aStr += rLocWrp.getNumDecimalSep();
+ break;
+ case NF_SYMBOLTYPE_THSEP :
+ aStr += rLocWrp.getNumThousandSep();
+ break;
+ case NF_SYMBOLTYPE_DATESEP :
+ aStr += rLocWrp.getDateSep();
+ break;
+ case NF_SYMBOLTYPE_TIMESEP :
+ aStr += rLocWrp.getTimeSep();
+ break;
+ case NF_SYMBOLTYPE_TIME100SECSEP :
+ aStr += rLocWrp.getTime100SecSep();
+ break;
+ case NF_SYMBOLTYPE_STRING :
+ if( bDontQuote )
+ aStr += pStr[j];
+ else if ( pStr[j].Len() == 1 )
+ {
+ aStr += '\\';
+ aStr += pStr[j];
+ }
+ else
+ {
+ aStr += '"';
+ aStr += pStr[j];
+ aStr += '"';
+ }
+ break;
+ default:
+ aStr += pStr[j];
+ }
+
+ }
+ }
+ }
+ }
+ for ( ; nSub<4 && bDefault[nSub]; ++nSub )
+ { // append empty subformats
+ aStr += ';';
+ }
+ return aStr;
+}
+
+
+String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
+ sal_Int32 nVal, USHORT nMinDigits ) const
+{
+ String aStr;
+ if ( nMinDigits )
+ {
+ if ( nMinDigits == 2 )
+ { // speed up the most common case
+ if ( 0 <= nVal && nVal < 10 )
+ {
+ sal_Unicode* p = aStr.AllocBuffer( 2 );
+ *p++ = '0';
+ *p = sal_Unicode( '0' + nVal );
+ }
+ else
+ aStr = String::CreateFromInt32( nVal );
+ }
+ else
+ {
+ String aValStr( String::CreateFromInt32( nVal ) );
+ if ( aValStr.Len() >= nMinDigits )
+ aStr = aValStr;
+ else
+ {
+ aStr.Fill( nMinDigits - aValStr.Len(), '0' );
+ aStr += aValStr;
+ }
+ }
+ }
+ else
+ aStr = String::CreateFromInt32( nVal );
+ ImpTransliterate( aStr, rNum );
+ return aStr;
+}
+
+
+void SvNumberformat::ImpTransliterateImpl( String& rStr,
+ const SvNumberNatNum& rNum ) const
+{
+ com::sun::star::lang::Locale aLocale(
+ MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
+ rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr,
+ aLocale, rNum.GetNatNum() );
+}
+
+
+void SvNumberformat::GetNatNumXml(
+ com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
+ USHORT nNumFor ) const
+{
+ if ( nNumFor <= 3 )
+ {
+ const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
+ if ( rNum.IsSet() )
+ {
+ com::sun::star::lang::Locale aLocale(
+ MsLangId::convertLanguageToLocale( rNum.GetLang() ) );
+ rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
+ aLocale, rNum.GetNatNum() );
+ }
+ else
+ rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
+ }
+ else
+ rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
+}
+
+// static
+BOOL SvNumberformat::HasStringNegativeSign( const String& rStr )
+{
+ // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored)
+ xub_StrLen nLen = rStr.Len();
+ if ( !nLen )
+ return FALSE;
+ const sal_Unicode* const pBeg = rStr.GetBuffer();
+ const sal_Unicode* const pEnd = pBeg + nLen;
+ register const sal_Unicode* p = pBeg;
+ do
+ { // Anfang
+ if ( *p == '-' )
+ return TRUE;
+ } while ( *p == ' ' && ++p < pEnd );
+ p = pEnd - 1;
+ do
+ { // Ende
+ if ( *p == '-' )
+ return TRUE;
+ } while ( *p == ' ' && pBeg < --p );
+ return FALSE;
+}
+
+
+// static
+void SvNumberformat::SetComment( const String& rStr, String& rFormat,
+ String& rComment )
+{
+ if ( rComment.Len() )
+ { // alten Kommentar aus Formatstring loeschen
+ //! nicht per EraseComment, der Kommentar muss matchen
+ String aTmp( '{' );
+ aTmp += ' ';
+ aTmp += rComment;
+ aTmp += ' ';
+ aTmp += '}';
+ xub_StrLen nCom = 0;
+ do
+ {
+ nCom = rFormat.Search( aTmp, nCom );
+ } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) );
+ if ( nCom != STRING_NOTFOUND )
+ rFormat.Erase( nCom );
+ }
+ if ( rStr.Len() )
+ { // neuen Kommentar setzen
+ rFormat += '{';
+ rFormat += ' ';
+ rFormat += rStr;
+ rFormat += ' ';
+ rFormat += '}';
+ rComment = rStr;
+ }
+}
+
+
+// static
+void SvNumberformat::EraseCommentBraces( String& rStr )
+{
+ xub_StrLen nLen = rStr.Len();
+ if ( nLen && rStr.GetChar(0) == '{' )
+ {
+ rStr.Erase( 0, 1 );
+ --nLen;
+ }
+ if ( nLen && rStr.GetChar(0) == ' ' )
+ {
+ rStr.Erase( 0, 1 );
+ --nLen;
+ }
+ if ( nLen && rStr.GetChar( nLen-1 ) == '}' )
+ rStr.Erase( --nLen, 1 );
+ if ( nLen && rStr.GetChar( nLen-1 ) == ' ' )
+ rStr.Erase( --nLen, 1 );
+}
+
+
+// static
+void SvNumberformat::EraseComment( String& rStr )
+{
+ register const sal_Unicode* p = rStr.GetBuffer();
+ BOOL bInString = FALSE;
+ BOOL bEscaped = FALSE;
+ BOOL bFound = FALSE;
+ xub_StrLen nPos = 0;
+ while ( !bFound && *p )
+ {
+ switch ( *p )
+ {
+ case '\\' :
+ bEscaped = !bEscaped;
+ break;
+ case '\"' :
+ if ( !bEscaped )
+ bInString = !bInString;
+ break;
+ case '{' :
+ if ( !bEscaped && !bInString )
+ {
+ bFound = TRUE;
+ nPos = sal::static_int_cast< xub_StrLen >(
+ p - rStr.GetBuffer());
+ }
+ break;
+ }
+ if ( bEscaped && *p != '\\' )
+ bEscaped = FALSE;
+ ++p;
+ }
+ if ( bFound )
+ rStr.Erase( nPos );
+}
+
+
+// static
+BOOL SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos,
+ sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
+{
+ xub_StrLen nLen = rStr.Len();
+ if ( nPos >= nLen )
+ return FALSE;
+ register const sal_Unicode* p0 = rStr.GetBuffer();
+ register const sal_Unicode* p = p0;
+ register const sal_Unicode* p1 = p0 + nPos;
+ BOOL bQuoted = FALSE;
+ while ( p <= p1 )
+ {
+ if ( *p == cQuote )
+ {
+ if ( p == p0 )
+ bQuoted = TRUE;
+ else if ( bQuoted )
+ {
+ if ( *(p-1) != cEscIn )
+ bQuoted = FALSE;
+ }
+ else
+ {
+ if ( *(p-1) != cEscOut )
+ bQuoted = TRUE;
+ }
+ }
+ p++;
+ }
+ return bQuoted;
+}
+
+
+// static
+xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos,
+ sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
+{
+ xub_StrLen nLen = rStr.Len();
+ if ( nPos >= nLen )
+ return STRING_NOTFOUND;
+ if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
+ {
+ if ( rStr.GetChar( nPos ) == cQuote )
+ return nPos; // schliessendes cQuote
+ return STRING_NOTFOUND;
+ }
+ register const sal_Unicode* p0 = rStr.GetBuffer();
+ register const sal_Unicode* p = p0 + nPos;
+ register const sal_Unicode* p1 = p0 + nLen;
+ while ( p < p1 )
+ {
+ if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
+ return sal::static_int_cast< xub_StrLen >(p - p0);
+ p++;
+ }
+ return nLen; // String Ende
+}
+
+
+USHORT SvNumberformat::ImpGetNumForStringElementCount( USHORT nNumFor ) const
+{
+ USHORT nCnt = 0;
+ USHORT nAnz = NumFor[nNumFor].GetnAnz();
+ short const * const pType = NumFor[nNumFor].Info().nTypeArray;
+ for ( USHORT j=0; j<nAnz; ++j )
+ {
+ switch ( pType[j] )
+ {
+ case NF_SYMBOLTYPE_STRING:
+ case NF_SYMBOLTYPE_CURRENCY:
+ case NF_SYMBOLTYPE_DATESEP:
+ case NF_SYMBOLTYPE_TIMESEP:
+ case NF_SYMBOLTYPE_TIME100SECSEP:
+ case NF_SYMBOLTYPE_PERCENT:
+ ++nCnt;
+ break;
+ }
+ }
+ return nCnt;
+}
+
diff --git a/svl/source/numbers/zforscan.cxx b/svl/source/numbers/zforscan.cxx
new file mode 100644
index 000000000000..5c0d45a53ed2
--- /dev/null
+++ b/svl/source/numbers/zforscan.cxx
@@ -0,0 +1,2812 @@
+/*************************************************************************
+ *
+ * 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: zforscan.cxx,v $
+ * $Revision: 1.49.140.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 <stdlib.h>
+#include <tools/debug.hxx>
+#include <i18npool/mslangid.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/numberformatcodewrapper.hxx>
+#include <rtl/instance.hxx>
+
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <unotools/digitgroupingiterator.hxx>
+
+#define _ZFORSCAN_CXX
+#include "zforscan.hxx"
+#undef _ZFORSCAN_CXX
+#include "nfsymbol.hxx"
+using namespace svt;
+
+const sal_Unicode cNonBreakingSpace = 0xA0;
+
+namespace
+{
+ struct ImplEnglishColors
+ {
+ const String* operator()()
+ {
+ static const String aEnglishColors[NF_MAX_DEFAULT_COLORS] =
+ {
+ String( RTL_CONSTASCII_USTRINGPARAM( "BLACK" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "BLUE" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "GREEN" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "CYAN" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "RED" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "MAGENTA" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "BROWN" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "GREY" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "YELLOW" ) ),
+ String( RTL_CONSTASCII_USTRINGPARAM( "WHITE" ) )
+ };
+ return &aEnglishColors[0];
+ }
+ };
+
+ struct theEnglishColors
+ : public rtl::StaticAggregate< const String, ImplEnglishColors> {};
+
+}
+
+ImpSvNumberformatScan::ImpSvNumberformatScan( SvNumberFormatter* pFormatterP )
+{
+ pFormatter = pFormatterP;
+ bConvertMode = FALSE;
+ //! All keywords MUST be UPPERCASE!
+ sKeyword[NF_KEY_E].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "E" ) ); // Exponent
+ sKeyword[NF_KEY_AMPM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AM/PM" ) ); // AM/PM
+ sKeyword[NF_KEY_AP].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "A/P" ) ); // AM/PM short
+ sKeyword[NF_KEY_MI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) ); // Minute
+ sKeyword[NF_KEY_MMI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) ); // Minute 02
+ sKeyword[NF_KEY_S].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "S" ) ); // Second
+ sKeyword[NF_KEY_SS].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "SS" ) ); // Second 02
+ sKeyword[NF_KEY_Q].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Q" ) ); // Quarter short 'Q'
+ sKeyword[NF_KEY_QQ].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "QQ" ) ); // Quarter long
+ sKeyword[NF_KEY_NN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NN" ) ); // Day of week short
+ sKeyword[NF_KEY_NNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NNN" ) ); // Day of week long
+ sKeyword[NF_KEY_NNNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NNNN" ) ); // Day of week long incl. separator
+ sKeyword[NF_KEY_WW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WW" ) ); // Week of year
+ sKeyword[NF_KEY_CCC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CCC" ) ); // Currency abbreviation
+ bKeywordsNeedInit = TRUE; // locale dependent keywords
+ bCompatCurNeedInit = TRUE; // locale dependent compatibility currency strings
+
+ StandardColor[0] = Color(COL_BLACK);
+ StandardColor[1] = Color(COL_LIGHTBLUE);
+ StandardColor[2] = Color(COL_LIGHTGREEN);
+ StandardColor[3] = Color(COL_LIGHTCYAN);
+ StandardColor[4] = Color(COL_LIGHTRED);
+ StandardColor[5] = Color(COL_LIGHTMAGENTA);
+ StandardColor[6] = Color(COL_BROWN);
+ StandardColor[7] = Color(COL_GRAY);
+ StandardColor[8] = Color(COL_YELLOW);
+ StandardColor[9] = Color(COL_WHITE);
+
+ pNullDate = new Date(30,12,1899);
+ nStandardPrec = 2;
+
+ sErrStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###" ) );
+ Reset();
+}
+
+ImpSvNumberformatScan::~ImpSvNumberformatScan()
+{
+ delete pNullDate;
+ Reset();
+}
+
+
+void ImpSvNumberformatScan::ChangeIntl()
+{
+ bKeywordsNeedInit = TRUE;
+ bCompatCurNeedInit = TRUE;
+ // may be initialized by InitSpecialKeyword()
+ sKeyword[NF_KEY_TRUE].Erase();
+ sKeyword[NF_KEY_FALSE].Erase();
+}
+
+
+void ImpSvNumberformatScan::InitSpecialKeyword( NfKeywordIndex eIdx ) const
+{
+ switch ( eIdx )
+ {
+ case NF_KEY_TRUE :
+ ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE] =
+ pFormatter->GetCharClass()->upper(
+ pFormatter->GetLocaleData()->getTrueWord() );
+ if ( !sKeyword[NF_KEY_TRUE].Len() )
+ {
+ DBG_ERRORFILE( "InitSpecialKeyword: TRUE_WORD?" );
+ ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TRUE" ) );
+ }
+ break;
+ case NF_KEY_FALSE :
+ ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE] =
+ pFormatter->GetCharClass()->upper(
+ pFormatter->GetLocaleData()->getFalseWord() );
+ if ( !sKeyword[NF_KEY_FALSE].Len() )
+ {
+ DBG_ERRORFILE( "InitSpecialKeyword: FALSE_WORD?" );
+ ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "FALSE" ) );
+ }
+ break;
+ default:
+ DBG_ERRORFILE( "InitSpecialKeyword: unknown request" );
+ }
+}
+
+
+void ImpSvNumberformatScan::InitCompatCur() const
+{
+ ImpSvNumberformatScan* pThis = (ImpSvNumberformatScan*)this;
+ // currency symbol for old style ("automatic") compatibility format codes
+ pFormatter->GetCompatibilityCurrency( pThis->sCurSymbol, pThis->sCurAbbrev );
+ // currency symbol upper case
+ pThis->sCurString = pFormatter->GetCharClass()->upper( sCurSymbol );
+ bCompatCurNeedInit = FALSE;
+}
+
+
+void ImpSvNumberformatScan::InitKeywords() const
+{
+ if ( !bKeywordsNeedInit )
+ return ;
+ ((ImpSvNumberformatScan*)this)->SetDependentKeywords();
+ bKeywordsNeedInit = FALSE;
+}
+
+
+/** Extract the name of General, Standard, Whatever, ignoring leading modifiers
+ such as [NatNum1]. */
+static String lcl_extractStandardGeneralName( const ::rtl::OUString & rCode )
+{
+ String aStr;
+ const sal_Unicode* p = rCode.getStr();
+ const sal_Unicode* const pStop = p + rCode.getLength();
+ const sal_Unicode* pBeg = p; // name begins here
+ bool bMod = false;
+ bool bDone = false;
+ while (p < pStop && !bDone)
+ {
+ switch (*p)
+ {
+ case '[':
+ bMod = true;
+ break;
+ case ']':
+ if (bMod)
+ {
+ bMod = false;
+ pBeg = p+1;
+ }
+ // else: would be a locale data error, easily to be spotted in
+ // UI dialog
+ break;
+ case ';':
+ if (!bMod)
+ {
+ bDone = true;
+ --p; // put back, increment by one follows
+ }
+ break;
+ }
+ ++p;
+ if (bMod)
+ pBeg = p;
+ }
+ if (pBeg < p)
+ aStr = rCode.copy( pBeg - rCode.getStr(), p - pBeg);
+ return aStr;
+}
+
+
+void ImpSvNumberformatScan::SetDependentKeywords()
+{
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+
+ const CharClass* pCharClass = pFormatter->GetCharClass();
+ const LocaleDataWrapper* pLocaleData = pFormatter->GetLocaleData();
+ // #80023# be sure to generate keywords for the loaded Locale, not for the
+ // requested Locale, otherwise number format codes might not match
+ lang::Locale aLoadedLocale = pLocaleData->getLoadedLocale();
+ LanguageType eLang = MsLangId::convertLocaleToLanguage( aLoadedLocale );
+ NumberFormatCodeWrapper aNumberFormatCode( pFormatter->GetServiceManager(), aLoadedLocale );
+
+ i18n::NumberFormatCode aFormat = aNumberFormatCode.getFormatCode( NF_NUMBER_STANDARD );
+ sNameStandardFormat = lcl_extractStandardGeneralName( aFormat.Code);
+ sKeyword[NF_KEY_GENERAL] = pCharClass->upper( sNameStandardFormat );
+
+ // preset new calendar keywords
+ sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAA" ) );
+ sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAAA" ) );
+ sKeyword[NF_KEY_EC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "E" ) );
+ sKeyword[NF_KEY_EEC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "EE" ) );
+ sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "G" ) );
+ sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GG" ) );
+ sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGG" ) );
+ sKeyword[NF_KEY_R].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "R" ) );
+ sKeyword[NF_KEY_RR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "RR" ) );
+
+ // Thai T NatNum special. Other locale's small letter 't' results in upper
+ // case comparison not matching but length does in conversion mode. Ugly.
+ if (eLang == LANGUAGE_THAI)
+ sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T"));
+ else
+ sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "t"));
+
+ switch ( eLang )
+ {
+ case LANGUAGE_GERMAN:
+ case LANGUAGE_GERMAN_SWISS:
+ case LANGUAGE_GERMAN_AUSTRIAN:
+ case LANGUAGE_GERMAN_LUXEMBOURG:
+ case LANGUAGE_GERMAN_LIECHTENSTEIN:
+ {
+ //! all capital letters
+ sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) ); // month 1
+ sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) ); // month 01
+ sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMM" ) ); // month Jan
+ sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMM" ) ); // month Januar
+ sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMMM" ) );// month J
+ sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "H" ) ); // hour 2
+ sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "HH" ) ); // hour 02
+ sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T" ) );
+ sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TT" ) );
+ sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TTT" ) );
+ sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TTTT" ) );
+ sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
+ sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
+ sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "LOGISCH" ) );
+ sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "FARBE" ) );
+ sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "SCHWARZ" ) );
+ sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLAU" ) );
+ sKeyword[NF_KEY_GREEN] = UniString( "GR" "\xDC" "N", RTL_TEXTENCODING_ISO_8859_1 );
+ sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CYAN" ) );
+ sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "ROT" ) );
+ sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MAGENTA" ) );
+ sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BRAUN" ) );
+ sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GRAU" ) );
+ sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GELB" ) );
+ sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WEISS" ) );
+ }
+ break;
+ default:
+ {
+ // day
+ switch ( eLang )
+ {
+ case LANGUAGE_ITALIAN :
+ case LANGUAGE_ITALIAN_SWISS :
+ sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "G" ) );
+ sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GG" ) );
+ sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGG" ) );
+ sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGGG" ) );
+ // must exchange the era code, same as Xcl
+ sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "X" ) );
+ sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XX" ) );
+ sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XXX" ) );
+ break;
+ case LANGUAGE_FRENCH :
+ case LANGUAGE_FRENCH_BELGIAN :
+ case LANGUAGE_FRENCH_CANADIAN :
+ case LANGUAGE_FRENCH_SWISS :
+ case LANGUAGE_FRENCH_LUXEMBOURG :
+ case LANGUAGE_FRENCH_MONACO :
+ sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "J" ) );
+ sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
+ sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJ" ) );
+ sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
+ break;
+ case LANGUAGE_FINNISH :
+ sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "P" ) );
+ sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PP" ) );
+ sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPP" ) );
+ sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPPP" ) );
+ break;
+ default:
+ sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D" ) );
+ sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DD" ) );
+ sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDD" ) );
+ sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDDD" ) );
+ }
+ // month
+ switch ( eLang )
+ {
+ case LANGUAGE_FINNISH :
+ sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "K" ) );
+ sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KK" ) );
+ sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKK" ) );
+ sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKK" ) );
+ sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKKK" ) );
+ break;
+ default:
+ sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) );
+ sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) );
+ sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMM" ) );
+ sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMM" ) );
+ sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMMM" ) );
+ }
+ // year
+ switch ( eLang )
+ {
+ case LANGUAGE_ITALIAN :
+ case LANGUAGE_ITALIAN_SWISS :
+ case LANGUAGE_FRENCH :
+ case LANGUAGE_FRENCH_BELGIAN :
+ case LANGUAGE_FRENCH_CANADIAN :
+ case LANGUAGE_FRENCH_SWISS :
+ case LANGUAGE_FRENCH_LUXEMBOURG :
+ case LANGUAGE_FRENCH_MONACO :
+ case LANGUAGE_PORTUGUESE :
+ case LANGUAGE_PORTUGUESE_BRAZILIAN :
+ case LANGUAGE_SPANISH_MODERN :
+ case LANGUAGE_SPANISH_DATED :
+ case LANGUAGE_SPANISH_MEXICAN :
+ case LANGUAGE_SPANISH_GUATEMALA :
+ case LANGUAGE_SPANISH_COSTARICA :
+ case LANGUAGE_SPANISH_PANAMA :
+ case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC :
+ case LANGUAGE_SPANISH_VENEZUELA :
+ case LANGUAGE_SPANISH_COLOMBIA :
+ case LANGUAGE_SPANISH_PERU :
+ case LANGUAGE_SPANISH_ARGENTINA :
+ case LANGUAGE_SPANISH_ECUADOR :
+ case LANGUAGE_SPANISH_CHILE :
+ case LANGUAGE_SPANISH_URUGUAY :
+ case LANGUAGE_SPANISH_PARAGUAY :
+ case LANGUAGE_SPANISH_BOLIVIA :
+ case LANGUAGE_SPANISH_EL_SALVADOR :
+ case LANGUAGE_SPANISH_HONDURAS :
+ case LANGUAGE_SPANISH_NICARAGUA :
+ case LANGUAGE_SPANISH_PUERTO_RICO :
+ sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AA" ) );
+ sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAAA" ) );
+ // must exchange the day of week name code, same as Xcl
+ sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OOO" ) );
+ sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OOOO" ) );
+ break;
+ case LANGUAGE_DUTCH :
+ case LANGUAGE_DUTCH_BELGIAN :
+ sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
+ sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
+ break;
+ case LANGUAGE_FINNISH :
+ sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VV" ) );
+ sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VVVV" ) );
+ break;
+ default:
+ sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YY" ) );
+ sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YYYY" ) );
+ }
+ // hour
+ switch ( eLang )
+ {
+ case LANGUAGE_DUTCH :
+ case LANGUAGE_DUTCH_BELGIAN :
+ sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "U" ) );
+ sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "UU" ) );
+ break;
+ case LANGUAGE_FINNISH :
+ case LANGUAGE_SWEDISH :
+ case LANGUAGE_SWEDISH_FINLAND :
+ case LANGUAGE_DANISH :
+ case LANGUAGE_NORWEGIAN :
+ case LANGUAGE_NORWEGIAN_BOKMAL :
+ case LANGUAGE_NORWEGIAN_NYNORSK :
+ sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T" ) );
+ sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TT" ) );
+ break;
+ default:
+ sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "H" ) );
+ sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "HH" ) );
+ }
+ // boolean
+ sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BOOLEAN" ) );
+ // colours
+ sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "COLOR" ) );
+ sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLACK" ) );
+ sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLUE" ) );
+ sKeyword[NF_KEY_GREEN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GREEN" ) );
+ sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CYAN" ) );
+ sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "RED" ) );
+ sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MAGENTA" ) );
+ sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BROWN" ) );
+ sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GREY" ) );
+ sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YELLOW" ) );
+ sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WHITE" ) );
+ }
+ break;
+ }
+
+ // boolean keyords
+ InitSpecialKeyword( NF_KEY_TRUE );
+ InitSpecialKeyword( NF_KEY_FALSE );
+
+ // compatibility currency strings
+ InitCompatCur();
+}
+
+
+void ImpSvNumberformatScan::ChangeNullDate(USHORT nDay, USHORT nMonth, USHORT nYear)
+{
+ if ( pNullDate )
+ *pNullDate = Date(nDay, nMonth, nYear);
+ else
+ pNullDate = new Date(nDay, nMonth, nYear);
+}
+
+void ImpSvNumberformatScan::ChangeStandardPrec(short nPrec)
+{
+ nStandardPrec = nPrec;
+}
+
+Color* ImpSvNumberformatScan::GetColor(String& sStr)
+{
+ String sString = pFormatter->GetCharClass()->upper(sStr);
+ const String* pKeyword = GetKeywords();
+ size_t i = 0;
+ while (i < NF_MAX_DEFAULT_COLORS &&
+ sString != pKeyword[NF_KEY_FIRSTCOLOR+i] )
+ i++;
+ if ( i >= NF_MAX_DEFAULT_COLORS )
+ {
+ const String* pEnglishColors = theEnglishColors::get();
+ size_t j = 0;
+ while ( j < NF_MAX_DEFAULT_COLORS &&
+ sString != pEnglishColors[j] )
+ ++j;
+ if ( j < NF_MAX_DEFAULT_COLORS )
+ i = j;
+ }
+
+ Color* pResult = NULL;
+ if (i >= NF_MAX_DEFAULT_COLORS)
+ {
+ const String& rColorWord = pKeyword[NF_KEY_COLOR];
+ xub_StrLen nPos = sString.Match(rColorWord);
+ if (nPos > 0)
+ {
+ sStr.Erase(0, nPos);
+ sStr.EraseLeadingChars();
+ sStr.EraseTrailingChars();
+ if (bConvertMode)
+ {
+ pFormatter->ChangeIntl(eNewLnge);
+ sStr.Insert( GetKeywords()[NF_KEY_COLOR], 0 ); // Color -> FARBE
+ pFormatter->ChangeIntl(eTmpLnge);
+ }
+ else
+ sStr.Insert(rColorWord,0);
+ sString.Erase(0, nPos);
+ sString.EraseLeadingChars();
+ sString.EraseTrailingChars();
+
+ if ( CharClass::isAsciiNumeric( sString ) )
+ {
+ long nIndex = sString.ToInt32();
+ if (nIndex > 0 && nIndex <= 64)
+ pResult = pFormatter->GetUserDefColor((USHORT)nIndex-1);
+ }
+ }
+ }
+ else
+ {
+ sStr.Erase();
+ if (bConvertMode)
+ {
+ pFormatter->ChangeIntl(eNewLnge);
+ sStr = GetKeywords()[NF_KEY_FIRSTCOLOR+i]; // red -> rot
+ pFormatter->ChangeIntl(eTmpLnge);
+ }
+ else
+ sStr = pKeyword[NF_KEY_FIRSTCOLOR+i];
+
+ pResult = &(StandardColor[i]);
+ }
+ return pResult;
+}
+
+
+short ImpSvNumberformatScan::GetKeyWord( const String& sSymbol, xub_StrLen nPos )
+{
+ String sString = pFormatter->GetCharClass()->toUpper( sSymbol, nPos, sSymbol.Len() - nPos );
+ const String* pKeyword = GetKeywords();
+ // #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere
+ if ( sString.Search( pKeyword[NF_KEY_GENERAL] ) == 0 )
+ return NF_KEY_GENERAL;
+ //! MUST be a reverse search to find longer strings first
+ short i = NF_KEYWORD_ENTRIES_COUNT-1;
+ BOOL bFound = FALSE;
+ for ( ; i > NF_KEY_LASTKEYWORD_SO5; --i )
+ {
+ bFound = sString.Search(pKeyword[i]) == 0;
+ if ( bFound )
+ {
+ break;
+ }
+ }
+ // new keywords take precedence over old keywords
+ if ( !bFound )
+ { // skip the gap of colors et al between new and old keywords and search on
+ i = NF_KEY_LASTKEYWORD;
+ while ( i > 0 && sString.Search(pKeyword[i]) != 0 )
+ i--;
+ if ( i > NF_KEY_LASTOLDKEYWORD && sString != pKeyword[i] )
+ { // found something, but maybe it's something else?
+ // e.g. new NNN is found in NNNN, for NNNN we must search on
+ short j = i - 1;
+ while ( j > 0 && sString.Search(pKeyword[j]) != 0 )
+ j--;
+ if ( j && pKeyword[j].Len() > pKeyword[i].Len() )
+ return j;
+ }
+ }
+ // The Thai T NatNum modifier during Xcl import.
+ if (i == 0 && bConvertMode && sString.GetChar(0) == 'T' && eTmpLnge ==
+ LANGUAGE_ENGLISH_US && MsLangId::getRealLanguage( eNewLnge) ==
+ LANGUAGE_THAI)
+ i = NF_KEY_THAI_T;
+ return i; // 0 => not found
+}
+
+//---------------------------------------------------------------------------
+// Next_Symbol
+//---------------------------------------------------------------------------
+// Zerlegt die Eingabe in Symbole fuer die weitere
+// Verarbeitung (Turing-Maschine).
+//---------------------------------------------------------------------------
+// Ausgangs Zustand = SsStart
+//---------------+-------------------+-----------------------+---------------
+// Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
+//---------------+-------------------+-----------------------+---------------
+// SsStart | Buchstabe | Symbol=Zeichen | SsGetWord
+// | " | Typ = String | SsGetString
+// | \ | Typ = String | SsGetChar
+// | * | Typ = Star | SsGetStar
+// | _ | Typ = Blank | SsGetBlank
+// | @ # 0 ? / . , % [ | Symbol = Zeichen; |
+// | ] ' Blank | Typ = Steuerzeichen | SsStop
+// | $ - + ( ) : | Typ = String; |
+// | | | Typ = Comment | SsStop
+// | Sonst | Symbol = Zeichen | SsStop
+//---------------|-------------------+-----------------------+---------------
+// SsGetChar | Sonst | Symbol=Zeichen | SsStop
+//---------------+-------------------+-----------------------+---------------
+// GetString | " | | SsStop
+// | Sonst | Symbol+=Zeichen | GetString
+//---------------+-------------------+-----------------------+---------------
+// SsGetWord | Buchstabe | Symbol += Zeichen |
+// | + - (E+ E-)| Symbol += Zeichen | SsStop
+// | / (AM/PM)| Symbol += Zeichen |
+// | Sonst | Pos--, if Key Typ=Word| SsStop
+//---------------+-------------------+-----------------------+---------------
+// SsGetStar | Sonst | Symbol+=Zeichen | SsStop
+// | | markiere Sonderfall * |
+//---------------+-------------------+-----------------------+---------------
+// SsGetBlank | Sonst | Symbol+=Zeichen | SsStop
+// | | markiere Sonderfall _ |
+//---------------+-------------------+-----------------------+---------------
+// Wurde im State SsGetWord ein Schluesselwort erkannt (auch als
+// Anfangsteilwort des Symbols)
+// so werden die restlichen Buchstaben zurueckgeschrieben !!
+
+enum ScanState
+{
+ SsStop = 0,
+ SsStart = 1,
+ SsGetChar = 2,
+ SsGetString = 3,
+ SsGetWord = 4,
+ SsGetStar = 5,
+ SsGetBlank = 6
+};
+
+short ImpSvNumberformatScan::Next_Symbol( const String& rStr,
+ xub_StrLen& nPos, String& sSymbol )
+{
+ if ( bKeywordsNeedInit )
+ InitKeywords();
+ const CharClass* pChrCls = pFormatter->GetCharClass();
+ const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
+ const xub_StrLen nStart = nPos;
+ short eType = 0;
+ ScanState eState = SsStart;
+ sSymbol.Erase();
+ while ( nPos < rStr.Len() && eState != SsStop )
+ {
+ sal_Unicode cToken = rStr.GetChar( nPos++ );
+ switch (eState)
+ {
+ case SsStart:
+ {
+ // Fetch any currency longer than one character and don't get
+ // confused later on by "E/" or other combinations of letters
+ // and meaningful symbols. Necessary for old automatic currency.
+ // #96158# But don't do it if we're starting a "[...]" section,
+ // for example a "[$...]" new currency symbol to not parse away
+ // "$U" (symbol) of "[$UYU]" (abbreviation).
+ if ( nCurrPos != STRING_NOTFOUND && sCurString.Len() > 1 &&
+ nPos-1 + sCurString.Len() <= rStr.Len() &&
+ !(nPos > 1 && rStr.GetChar( nPos-2 ) == '[') )
+ {
+ String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
+ pChrCls->toUpper( aTest );
+ if ( aTest == sCurString )
+ {
+ sSymbol = rStr.Copy( --nPos, sCurString.Len() );
+ nPos = nPos + sSymbol.Len();
+ eState = SsStop;
+ eType = NF_SYMBOLTYPE_STRING;
+ return eType;
+ }
+ }
+ switch (cToken)
+ {
+ case '#':
+ case '0':
+ case '?':
+ case '%':
+ case '@':
+ case '[':
+ case ']':
+ case ',':
+ case '.':
+ case '/':
+ case '\'':
+ case ' ':
+ case ':':
+ case '-':
+ {
+ eType = NF_SYMBOLTYPE_DEL;
+ sSymbol += cToken;
+ eState = SsStop;
+ }
+ break;
+ case '*':
+ {
+ eType = NF_SYMBOLTYPE_STAR;
+ sSymbol += cToken;
+ eState = SsGetStar;
+ }
+ break;
+ case '_':
+ {
+ eType = NF_SYMBOLTYPE_BLANK;
+ sSymbol += cToken;
+ eState = SsGetBlank;
+ }
+ break;
+#if NF_COMMENT_IN_FORMATSTRING
+ case '{':
+ eType = NF_SYMBOLTYPE_COMMENT;
+ eState = SsStop;
+ sSymbol.Append( rStr.GetBuffer() + (nPos-1), rStr.Len() - (nPos-1) );
+ nPos = rStr.Len();
+ break;
+#endif
+ case '"':
+ eType = NF_SYMBOLTYPE_STRING;
+ eState = SsGetString;
+ sSymbol += cToken;
+ break;
+ case '\\':
+ eType = NF_SYMBOLTYPE_STRING;
+ eState = SsGetChar;
+ sSymbol += cToken;
+ break;
+ case '$':
+ case '+':
+ case '(':
+ case ')':
+ eType = NF_SYMBOLTYPE_STRING;
+ eState = SsStop;
+ sSymbol += cToken;
+ break;
+ default :
+ {
+ if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cToken) ||
+ StringEqualsChar( pFormatter->GetNumThousandSep(), cToken) ||
+ StringEqualsChar( pFormatter->GetDateSep(), cToken) ||
+ StringEqualsChar( pLoc->getTimeSep(), cToken) ||
+ StringEqualsChar( pLoc->getTime100SecSep(), cToken))
+ {
+ // Another separator than pre-known ASCII
+ eType = NF_SYMBOLTYPE_DEL;
+ sSymbol += cToken;
+ eState = SsStop;
+ }
+ else if ( pChrCls->isLetter( rStr, nPos-1 ) )
+ {
+ short nTmpType = GetKeyWord( rStr, nPos-1 );
+ if ( nTmpType )
+ {
+ BOOL bCurrency = FALSE;
+ // "Automatic" currency may start with keyword,
+ // like "R" (Rand) and 'R' (era)
+ if ( nCurrPos != STRING_NOTFOUND &&
+ nPos-1 + sCurString.Len() <= rStr.Len() &&
+ sCurString.Search( sKeyword[nTmpType] ) == 0 )
+ {
+ String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
+ pChrCls->toUpper( aTest );
+ if ( aTest == sCurString )
+ bCurrency = TRUE;
+ }
+ if ( bCurrency )
+ {
+ eState = SsGetWord;
+ sSymbol += cToken;
+ }
+ else
+ {
+ eType = nTmpType;
+ xub_StrLen nLen = sKeyword[eType].Len();
+ sSymbol = rStr.Copy( nPos-1, nLen );
+ if ( eType == NF_KEY_E || IsAmbiguousE( eType ) )
+ {
+ sal_Unicode cNext = rStr.GetChar(nPos);
+ switch ( cNext )
+ {
+ case '+' :
+ case '-' : // E+ E- combine to one symbol
+ sSymbol += cNext;
+ eType = NF_KEY_E;
+ nPos++;
+ break;
+ case '0' :
+ case '#' : // scientific E without sign
+ eType = NF_KEY_E;
+ break;
+ }
+ }
+ nPos--;
+ nPos = nPos + nLen;
+ eState = SsStop;
+ }
+ }
+ else
+ {
+ eState = SsGetWord;
+ sSymbol += cToken;
+ }
+ }
+ else
+ {
+ eType = NF_SYMBOLTYPE_STRING;
+ eState = SsStop;
+ sSymbol += cToken;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case SsGetChar:
+ {
+ sSymbol += cToken;
+ eState = SsStop;
+ }
+ break;
+ case SsGetString:
+ {
+ if (cToken == '"')
+ eState = SsStop;
+ sSymbol += cToken;
+ }
+ break;
+ case SsGetWord:
+ {
+ if ( pChrCls->isLetter( rStr, nPos-1 ) )
+ {
+ short nTmpType = GetKeyWord( rStr, nPos-1 );
+ if ( nTmpType )
+ { // beginning of keyword, stop scan and put back
+ eType = NF_SYMBOLTYPE_STRING;
+ eState = SsStop;
+ nPos--;
+ }
+ else
+ sSymbol += cToken;
+ }
+ else
+ {
+ BOOL bDontStop = FALSE;
+ switch (cToken)
+ {
+ case '/': // AM/PM, A/P
+ {
+ sal_Unicode cNext = rStr.GetChar(nPos);
+ if ( cNext == 'P' || cNext == 'p' )
+ {
+ xub_StrLen nLen = sSymbol.Len();
+ if ( 1 <= nLen
+ && (sSymbol.GetChar(0) == 'A' || sSymbol.GetChar(0) == 'a')
+ && (nLen == 1 || (nLen == 2
+ && (sSymbol.GetChar(1) == 'M' || sSymbol.GetChar(1) == 'm')
+ && (rStr.GetChar(nPos+1) == 'M' || rStr.GetChar(nPos+1) == 'm'))) )
+ {
+ sSymbol += cToken;
+ bDontStop = TRUE;
+ }
+ }
+ }
+ break;
+ }
+ // anything not recognized will stop the scan
+ if ( eState != SsStop && !bDontStop )
+ {
+ eState = SsStop;
+ nPos--;
+ eType = NF_SYMBOLTYPE_STRING;
+ }
+ }
+ }
+ break;
+ case SsGetStar:
+ {
+ eState = SsStop;
+ sSymbol += cToken;
+ nRepPos = (nPos - nStart) - 1; // everytime > 0!!
+ }
+ break;
+ case SsGetBlank:
+ {
+ eState = SsStop;
+ sSymbol += cToken;
+ }
+ break;
+ default:
+ break;
+ } // of switch
+ } // of while
+ if (eState == SsGetWord)
+ eType = NF_SYMBOLTYPE_STRING;
+ return eType;
+}
+
+xub_StrLen ImpSvNumberformatScan::Symbol_Division(const String& rString)
+{
+ nCurrPos = STRING_NOTFOUND;
+ // Ist Waehrung im Spiel?
+ String sString = pFormatter->GetCharClass()->upper(rString);
+ xub_StrLen nCPos = 0;
+ while (nCPos != STRING_NOTFOUND)
+ {
+ nCPos = sString.Search(GetCurString(),nCPos);
+ if (nCPos != STRING_NOTFOUND)
+ {
+ // in Quotes?
+ xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sString, nCPos );
+ if ( nQ == STRING_NOTFOUND )
+ {
+ sal_Unicode c;
+ if ( nCPos == 0 ||
+ ((c = sString.GetChar(xub_StrLen(nCPos-1))) != '"'
+ && c != '\\') ) // dm kann durch "dm
+ { // \d geschuetzt werden
+ nCurrPos = nCPos;
+ nCPos = STRING_NOTFOUND; // Abbruch
+ }
+ else
+ nCPos++; // weitersuchen
+ }
+ else
+ nCPos = nQ + 1; // weitersuchen
+ }
+ }
+ nAnzStrings = 0;
+ BOOL bStar = FALSE; // wird bei '*'Detektion gesetzt
+ Reset();
+
+ xub_StrLen nPos = 0;
+ const xub_StrLen nLen = rString.Len();
+ while (nPos < nLen && nAnzStrings < NF_MAX_FORMAT_SYMBOLS)
+ {
+ nTypeArray[nAnzStrings] = Next_Symbol(rString, nPos, sStrArray[nAnzStrings]);
+ if (nTypeArray[nAnzStrings] == NF_SYMBOLTYPE_STAR)
+ { // Ueberwachung des '*'
+ if (bStar)
+ return nPos; // Fehler: doppelter '*'
+ else
+ bStar = TRUE;
+ }
+ nAnzStrings++;
+ }
+
+ return 0; // 0 => ok
+}
+
+void ImpSvNumberformatScan::SkipStrings(USHORT& i, xub_StrLen& nPos)
+{
+ while (i < nAnzStrings && ( nTypeArray[i] == NF_SYMBOLTYPE_STRING
+ || nTypeArray[i] == NF_SYMBOLTYPE_BLANK
+ || nTypeArray[i] == NF_SYMBOLTYPE_STAR) )
+ {
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+}
+
+
+USHORT ImpSvNumberformatScan::PreviousKeyword(USHORT i)
+{
+ short res = 0;
+ if (i > 0 && i < nAnzStrings)
+ {
+ i--;
+ while (i > 0 && nTypeArray[i] <= 0)
+ i--;
+ if (nTypeArray[i] > 0)
+ res = nTypeArray[i];
+ }
+ return res;
+}
+
+USHORT ImpSvNumberformatScan::NextKeyword(USHORT i)
+{
+ short res = 0;
+ if (i < nAnzStrings-1)
+ {
+ i++;
+ while (i < nAnzStrings-1 && nTypeArray[i] <= 0)
+ i++;
+ if (nTypeArray[i] > 0)
+ res = nTypeArray[i];
+ }
+ return res;
+}
+
+short ImpSvNumberformatScan::PreviousType( USHORT i )
+{
+ if ( i > 0 && i < nAnzStrings )
+ {
+ do
+ {
+ i--;
+ } while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY );
+ return nTypeArray[i];
+ }
+ return 0;
+}
+
+sal_Unicode ImpSvNumberformatScan::PreviousChar(USHORT i)
+{
+ sal_Unicode res = ' ';
+ if (i > 0 && i < nAnzStrings)
+ {
+ i--;
+ while (i > 0 && ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
+ || nTypeArray[i] == NF_SYMBOLTYPE_STRING
+ || nTypeArray[i] == NF_SYMBOLTYPE_STAR
+ || nTypeArray[i] == NF_SYMBOLTYPE_BLANK ) )
+ i--;
+ if (sStrArray[i].Len() > 0)
+ res = sStrArray[i].GetChar(xub_StrLen(sStrArray[i].Len()-1));
+ }
+ return res;
+}
+
+sal_Unicode ImpSvNumberformatScan::NextChar(USHORT i)
+{
+ sal_Unicode res = ' ';
+ if (i < nAnzStrings-1)
+ {
+ i++;
+ while (i < nAnzStrings-1 &&
+ ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
+ || nTypeArray[i] == NF_SYMBOLTYPE_STRING
+ || nTypeArray[i] == NF_SYMBOLTYPE_STAR
+ || nTypeArray[i] == NF_SYMBOLTYPE_BLANK))
+ i++;
+ if (sStrArray[i].Len() > 0)
+ res = sStrArray[i].GetChar(0);
+ }
+ return res;
+}
+
+BOOL ImpSvNumberformatScan::IsLastBlankBeforeFrac(USHORT i)
+{
+ BOOL res = TRUE;
+ if (i < nAnzStrings-1)
+ {
+ BOOL bStop = FALSE;
+ i++;
+ while (i < nAnzStrings-1 && !bStop)
+ {
+ i++;
+ if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
+ sStrArray[i].GetChar(0) == '/')
+ bStop = TRUE;
+ else if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
+ sStrArray[i].GetChar(0) == ' ')
+ res = FALSE;
+ }
+ if (!bStop) // kein '/'
+ res = FALSE;
+ }
+ else
+ res = FALSE; // kein '/' mehr
+
+ return res;
+}
+
+void ImpSvNumberformatScan::Reset()
+{
+ nAnzStrings = 0;
+ nAnzResStrings = 0;
+#if 0
+// ER 20.06.97 14:05 nicht noetig, wenn nAnzStrings beachtet wird
+ for (size_t i = 0; i < NF_MAX_FORMAT_SYMBOLS; i++)
+ {
+ sStrArray[i].Erase();
+ nTypeArray[i] = 0;
+ }
+#endif
+ eScannedType = NUMBERFORMAT_UNDEFINED;
+ nRepPos = 0;
+ bExp = FALSE;
+ bThousand = FALSE;
+ nThousand = 0;
+ bDecSep = FALSE;
+ nDecPos = -1;
+ nExpPos = (USHORT) -1;
+ nBlankPos = (USHORT) -1;
+ nCntPre = 0;
+ nCntPost = 0;
+ nCntExp = 0;
+ bFrac = FALSE;
+ bBlank = FALSE;
+ nNatNumModifier = 0;
+}
+
+
+BOOL ImpSvNumberformatScan::Is100SecZero( USHORT i, BOOL bHadDecSep )
+{
+ USHORT nIndexPre = PreviousKeyword( i );
+ return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS)
+ && (bHadDecSep // S, SS ','
+ || (i>0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING));
+ // SS"any"00 take "any" as a valid decimal separator
+}
+
+
+xub_StrLen ImpSvNumberformatScan::ScanType(const String&)
+{
+ const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
+
+ xub_StrLen nPos = 0;
+ USHORT i = 0;
+ short eNewType;
+ BOOL bMatchBracket = FALSE;
+ bool bHaveGeneral = false; // if General/Standard encountered
+
+ SkipStrings(i, nPos);
+ while (i < nAnzStrings)
+ {
+ if (nTypeArray[i] > 0)
+ { // keyword
+ switch (nTypeArray[i])
+ {
+ case NF_KEY_E: // E
+ eNewType = NUMBERFORMAT_SCIENTIFIC;
+ break;
+ case NF_KEY_AMPM: // AM,A,PM,P
+ case NF_KEY_AP:
+ case NF_KEY_H: // H
+ case NF_KEY_HH: // HH
+ case NF_KEY_S: // S
+ case NF_KEY_SS: // SS
+ eNewType = NUMBERFORMAT_TIME;
+ break;
+ case NF_KEY_M: // M
+ case NF_KEY_MM: // MM
+ { // minute or month
+ USHORT nIndexPre = PreviousKeyword(i);
+ USHORT nIndexNex = NextKeyword(i);
+ sal_Unicode cChar = PreviousChar(i);
+ if (nIndexPre == NF_KEY_H || // H
+ nIndexPre == NF_KEY_HH || // HH
+ nIndexNex == NF_KEY_S || // S
+ nIndexNex == NF_KEY_SS || // SS
+ cChar == '[' ) // [M
+ {
+ eNewType = NUMBERFORMAT_TIME;
+ nTypeArray[i] -= 2; // 6 -> 4, 7 -> 5
+ }
+ else
+ eNewType = NUMBERFORMAT_DATE;
+ }
+ break;
+ case NF_KEY_MMM: // MMM
+ case NF_KEY_MMMM: // MMMM
+ case NF_KEY_MMMMM: // MMMMM
+ case NF_KEY_Q: // Q
+ case NF_KEY_QQ: // QQ
+ case NF_KEY_D: // D
+ case NF_KEY_DD: // DD
+ case NF_KEY_DDD: // DDD
+ case NF_KEY_DDDD: // DDDD
+ case NF_KEY_YY: // YY
+ case NF_KEY_YYYY: // YYYY
+ case NF_KEY_NN: // NN
+ case NF_KEY_NNN: // NNN
+ case NF_KEY_NNNN: // NNNN
+ case NF_KEY_WW : // WW
+ case NF_KEY_AAA : // AAA
+ case NF_KEY_AAAA : // AAAA
+ case NF_KEY_EC : // E
+ case NF_KEY_EEC : // EE
+ case NF_KEY_G : // G
+ case NF_KEY_GG : // GG
+ case NF_KEY_GGG : // GGG
+ case NF_KEY_R : // R
+ case NF_KEY_RR : // RR
+ eNewType = NUMBERFORMAT_DATE;
+ break;
+ case NF_KEY_CCC: // CCC
+ eNewType = NUMBERFORMAT_CURRENCY;
+ break;
+ case NF_KEY_GENERAL: // Standard
+ eNewType = NUMBERFORMAT_NUMBER;
+ bHaveGeneral = true;
+ break;
+ default:
+ eNewType = NUMBERFORMAT_UNDEFINED;
+ break;
+ }
+ }
+ else
+ { // control character
+ switch ( sStrArray[i].GetChar(0) )
+ {
+ case '#':
+ case '?':
+ eNewType = NUMBERFORMAT_NUMBER;
+ break;
+ case '0':
+ {
+ if ( (eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME )
+ {
+ if ( Is100SecZero( i, bDecSep ) )
+ {
+ bDecSep = TRUE; // subsequent 0's
+ eNewType = NUMBERFORMAT_TIME;
+ }
+ else
+ return nPos; // Error
+ }
+ else
+ eNewType = NUMBERFORMAT_NUMBER;
+ }
+ break;
+ case '%':
+ eNewType = NUMBERFORMAT_PERCENT;
+ break;
+ case '/':
+ eNewType = NUMBERFORMAT_FRACTION;
+ break;
+ case '[':
+ {
+ if ( i < nAnzStrings-1 &&
+ nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
+ sStrArray[i+1].GetChar(0) == '$' )
+ { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
+ eNewType = NUMBERFORMAT_CURRENCY;
+ bMatchBracket = TRUE;
+ }
+ else if ( i < nAnzStrings-1 &&
+ nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
+ sStrArray[i+1].GetChar(0) == '~' )
+ { // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
+ eNewType = NUMBERFORMAT_DATE;
+ bMatchBracket = TRUE;
+ }
+ else
+ {
+ USHORT nIndexNex = NextKeyword(i);
+ if (nIndexNex == NF_KEY_H || // H
+ nIndexNex == NF_KEY_HH || // HH
+ nIndexNex == NF_KEY_M || // M
+ nIndexNex == NF_KEY_MM || // MM
+ nIndexNex == NF_KEY_S || // S
+ nIndexNex == NF_KEY_SS ) // SS
+ eNewType = NUMBERFORMAT_TIME;
+ else
+ return nPos; // Error
+ }
+ }
+ break;
+ case '@':
+ eNewType = NUMBERFORMAT_TEXT;
+ break;
+ default:
+ if ( sStrArray[i] == pLoc->getTime100SecSep() )
+ bDecSep = TRUE; // for SS,0
+ eNewType = NUMBERFORMAT_UNDEFINED;
+ break;
+ }
+ }
+ if (eScannedType == NUMBERFORMAT_UNDEFINED)
+ eScannedType = eNewType;
+ else if (eScannedType == NUMBERFORMAT_TEXT || eNewType == NUMBERFORMAT_TEXT)
+ eScannedType = NUMBERFORMAT_TEXT; // Text bleibt immer Text
+ else if (eNewType == NUMBERFORMAT_UNDEFINED)
+ { // bleibt wie bisher
+ }
+ else if (eScannedType != eNewType)
+ {
+ switch (eScannedType)
+ {
+ case NUMBERFORMAT_DATE:
+ {
+ switch (eNewType)
+ {
+ case NUMBERFORMAT_TIME:
+ eScannedType = NUMBERFORMAT_DATETIME;
+ break;
+ case NUMBERFORMAT_FRACTION: // DD/MM
+ break;
+ default:
+ {
+ if (nCurrPos != STRING_NOTFOUND)
+ eScannedType = NUMBERFORMAT_UNDEFINED;
+ else if ( sStrArray[i] != pFormatter->GetDateSep() )
+ return nPos;
+ }
+ }
+ }
+ break;
+ case NUMBERFORMAT_TIME:
+ {
+ switch (eNewType)
+ {
+ case NUMBERFORMAT_DATE:
+ eScannedType = NUMBERFORMAT_DATETIME;
+ break;
+ case NUMBERFORMAT_FRACTION: // MM/SS
+ break;
+ default:
+ {
+ if (nCurrPos != STRING_NOTFOUND)
+ eScannedType = NUMBERFORMAT_UNDEFINED;
+ else if ( sStrArray[i] != pLoc->getTimeSep() )
+ return nPos;
+ }
+ }
+ }
+ break;
+ case NUMBERFORMAT_DATETIME:
+ {
+ switch (eNewType)
+ {
+ case NUMBERFORMAT_TIME:
+ case NUMBERFORMAT_DATE:
+ break;
+ case NUMBERFORMAT_FRACTION: // DD/MM
+ break;
+ default:
+ {
+ if (nCurrPos != STRING_NOTFOUND)
+ eScannedType = NUMBERFORMAT_UNDEFINED;
+ else if ( sStrArray[i] != pFormatter->GetDateSep()
+ && sStrArray[i] != pLoc->getTimeSep() )
+ return nPos;
+ }
+ }
+ }
+ break;
+ case NUMBERFORMAT_PERCENT:
+ {
+ switch (eNewType)
+ {
+ case NUMBERFORMAT_NUMBER: // nur Zahl nach Prozent
+ break;
+ default:
+ return nPos;
+ }
+ }
+ break;
+ case NUMBERFORMAT_SCIENTIFIC:
+ {
+ switch (eNewType)
+ {
+ case NUMBERFORMAT_NUMBER: // nur Zahl nach E
+ break;
+ default:
+ return nPos;
+ }
+ }
+ break;
+ case NUMBERFORMAT_NUMBER:
+ {
+ switch (eNewType)
+ {
+ case NUMBERFORMAT_SCIENTIFIC:
+ case NUMBERFORMAT_PERCENT:
+ case NUMBERFORMAT_FRACTION:
+ case NUMBERFORMAT_CURRENCY:
+ eScannedType = eNewType;
+ break;
+ default:
+ if (nCurrPos != STRING_NOTFOUND)
+ eScannedType = NUMBERFORMAT_UNDEFINED;
+ else
+ return nPos;
+ }
+ }
+ break;
+ case NUMBERFORMAT_FRACTION:
+ {
+ switch (eNewType)
+ {
+ case NUMBERFORMAT_NUMBER: // nur Zahl nach Bruch
+ break;
+ default:
+ return nPos;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ nPos = nPos + sStrArray[i].Len(); // Korrekturposition
+ i++;
+ if ( bMatchBracket )
+ { // no type detection inside of matching brackets if [$...], [~...]
+ while ( bMatchBracket && i < nAnzStrings )
+ {
+ if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL
+ && sStrArray[i].GetChar(0) == ']' )
+ bMatchBracket = FALSE;
+ else
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ if ( bMatchBracket )
+ return nPos; // missing closing bracket at end of code
+ }
+ SkipStrings(i, nPos);
+ }
+
+ if ((eScannedType == NUMBERFORMAT_NUMBER || eScannedType == NUMBERFORMAT_UNDEFINED)
+ && nCurrPos != STRING_NOTFOUND && !bHaveGeneral)
+ eScannedType = NUMBERFORMAT_CURRENCY; // old "automatic" currency
+ if (eScannedType == NUMBERFORMAT_UNDEFINED)
+ eScannedType = NUMBERFORMAT_DEFINED;
+ return 0; // Alles ok
+}
+
+
+bool ImpSvNumberformatScan::InsertSymbol( USHORT & nPos, svt::NfSymbolType eType, const String& rStr )
+{
+ if (nAnzStrings >= NF_MAX_FORMAT_SYMBOLS || nPos > nAnzStrings)
+ return false;
+ ++nAnzResStrings;
+ if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY)
+ --nPos; // reuse position
+ else
+ {
+ ++nAnzStrings;
+ for (size_t i = nAnzStrings; i > nPos; --i)
+ {
+ nTypeArray[i] = nTypeArray[i-1];
+ sStrArray[i] = sStrArray[i-1];
+ }
+ }
+ nTypeArray[nPos] = static_cast<short>(eType);
+ sStrArray[nPos] = rStr;
+ return true;
+}
+
+
+int ImpSvNumberformatScan::FinalScanGetCalendar( xub_StrLen& nPos, USHORT& i,
+ USHORT& rAnzResStrings )
+{
+ if ( sStrArray[i].GetChar(0) == '[' &&
+ i < nAnzStrings-1 &&
+ nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
+ sStrArray[i+1].GetChar(0) == '~' )
+ { // [~calendarID]
+ // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
+ nPos = nPos + sStrArray[i].Len(); // [
+ nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
+ nPos = nPos + sStrArray[++i].Len(); // ~
+ sStrArray[i-1] += sStrArray[i]; // [~
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ rAnzResStrings--;
+ if ( ++i >= nAnzStrings )
+ return -1; // error
+ nPos = nPos + sStrArray[i].Len(); // calendarID
+ String& rStr = sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR; // convert
+ i++;
+ while ( i < nAnzStrings &&
+ sStrArray[i].GetChar(0) != ']' )
+ {
+ nPos = nPos + sStrArray[i].Len();
+ rStr += sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ rAnzResStrings--;
+ i++;
+ }
+ if ( rStr.Len() && i < nAnzStrings &&
+ sStrArray[i].GetChar(0) == ']' )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ else
+ return -1; // error
+ return 1;
+ }
+ return 0;
+}
+
+xub_StrLen ImpSvNumberformatScan::FinalScan( String& rString, String& rComment )
+{
+ const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
+
+ // save values for convert mode
+ String sOldDecSep = pFormatter->GetNumDecimalSep();
+ String sOldThousandSep = pFormatter->GetNumThousandSep();
+ String sOldDateSep = pFormatter->GetDateSep();
+ String sOldTimeSep = pLoc->getTimeSep();
+ String sOldTime100SecSep= pLoc->getTime100SecSep();
+ String sOldCurSymbol = GetCurSymbol();
+ String sOldCurString = GetCurString();
+ sal_Unicode cOldKeyH = sKeyword[NF_KEY_H].GetChar(0);
+ sal_Unicode cOldKeyMI = sKeyword[NF_KEY_MI].GetChar(0);
+ sal_Unicode cOldKeyS = sKeyword[NF_KEY_S].GetChar(0);
+
+ // If the group separator is a Non-Breaking Space (French) continue with a
+ // normal space instead so queries on space work correctly.
+ // The format string is adjusted to allow both.
+ // For output of the format code string the LocaleData characters are used.
+ if ( sOldThousandSep.GetChar(0) == cNonBreakingSpace && sOldThousandSep.Len() == 1 )
+ sOldThousandSep = ' ';
+
+ // change locale data et al
+ if (bConvertMode)
+ {
+ pFormatter->ChangeIntl(eNewLnge);
+ //! pointer may have changed
+ pLoc = pFormatter->GetLocaleData();
+ //! init new keywords
+ InitKeywords();
+ }
+ const CharClass* pChrCls = pFormatter->GetCharClass();
+
+ xub_StrLen nPos = 0; // error correction position
+ USHORT i = 0; // symbol loop counter
+ USHORT nCounter = 0; // counts digits
+ nAnzResStrings = nAnzStrings; // counts remaining symbols
+ bDecSep = FALSE; // reset in case already used in TypeCheck
+ bool bThaiT = false; // Thai T NatNum modifier present
+
+ switch (eScannedType)
+ {
+ case NUMBERFORMAT_TEXT:
+ case NUMBERFORMAT_DEFINED:
+ {
+ while (i < nAnzStrings)
+ {
+ switch (nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_BLANK:
+ case NF_SYMBOLTYPE_STAR:
+ break;
+ case NF_SYMBOLTYPE_COMMENT:
+ {
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ SvNumberformat::EraseCommentBraces( rStr );
+ rComment += rStr;
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ break;
+ case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
+ break;
+ default:
+ {
+ if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL ||
+ sStrArray[i].GetChar(0) != '@' )
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ }
+ break;
+ }
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ } // of while
+ }
+ break;
+ case NUMBERFORMAT_NUMBER:
+ case NUMBERFORMAT_PERCENT:
+ case NUMBERFORMAT_CURRENCY:
+ case NUMBERFORMAT_SCIENTIFIC:
+ case NUMBERFORMAT_FRACTION:
+ {
+ sal_Unicode cThousandFill = ' ';
+ while (i < nAnzStrings)
+ {
+ if (eScannedType == NUMBERFORMAT_FRACTION && // special case
+ nTypeArray[i] == NF_SYMBOLTYPE_DEL && // # ### #/#
+ StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden
+ StringEqualsChar( sStrArray[i], ' ' ) &&
+ !bFrac &&
+ IsLastBlankBeforeFrac(i) )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING; // del->string
+ } // kein Taus.p.
+
+
+ if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK ||
+ nTypeArray[i] == NF_SYMBOLTYPE_STAR ||
+ nTypeArray[i] == NF_KEY_CCC || // CCC
+ nTypeArray[i] == NF_KEY_GENERAL ) // Standard
+ {
+ if (nTypeArray[i] == NF_KEY_GENERAL)
+ {
+ nThousand = FLAG_STANDARD_IN_FORMAT;
+ if ( bConvertMode )
+ sStrArray[i] = sNameStandardFormat;
+ }
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING || // Strings oder
+ nTypeArray[i] > 0) // Keywords
+ {
+ if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
+ nTypeArray[i] == NF_KEY_E) // E+
+ {
+ if (bExp) // doppelt
+ return nPos;
+ bExp = TRUE;
+ nExpPos = i;
+ if (bDecSep)
+ nCntPost = nCounter;
+ else
+ nCntPre = nCounter;
+ nCounter = 0;
+ nTypeArray[i] = NF_SYMBOLTYPE_EXP;
+ }
+ else if (eScannedType == NUMBERFORMAT_FRACTION &&
+ sStrArray[i].GetChar(0) == ' ')
+ {
+ if (!bBlank && !bFrac) // nicht doppelt oder hinter /
+ {
+ if (bDecSep && nCounter > 0) // Nachkommastellen
+ return nPos; // Fehler
+ bBlank = TRUE;
+ nBlankPos = i;
+ nCntPre = nCounter;
+ nCounter = 0;
+ }
+ nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK;
+ }
+ else if (nTypeArray[i] == NF_KEY_THAI_T)
+ {
+ bThaiT = true;
+ sStrArray[i] = sKeyword[nTypeArray[i]];
+ }
+ else
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL)
+ {
+ sal_Unicode cHere = sStrArray[i].GetChar(0);
+ // Handle not pre-known separators in switch.
+ sal_Unicode cSimplified;
+ if (StringEqualsChar( pFormatter->GetNumThousandSep(), cHere))
+ cSimplified = ',';
+ else if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cHere))
+ cSimplified = '.';
+ else
+ cSimplified = cHere;
+ switch ( cSimplified )
+ {
+ case '#':
+ case '0':
+ case '?':
+ {
+ if (nThousand > 0) // #... #
+ return nPos; // Fehler
+ else if (bFrac && cHere == '0')
+ return nPos; // 0 im Nenner
+ nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ i++;
+ nCounter++;
+ while (i < nAnzStrings &&
+ (sStrArray[i].GetChar(0) == '#' ||
+ sStrArray[i].GetChar(0) == '0' ||
+ sStrArray[i].GetChar(0) == '?')
+ )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
+ nPos = nPos + sStrArray[i].Len();
+ nCounter++;
+ i++;
+ }
+ }
+ break;
+ case '-':
+ {
+ if ( bDecSep && nDecPos+1 == i &&
+ nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP )
+ { // "0.--"
+ nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ i++;
+ nCounter++;
+ while (i < nAnzStrings &&
+ (sStrArray[i].GetChar(0) == '-') )
+ {
+ // If more than two dashes are present in
+ // currency formats the last dash will be
+ // interpreted literally as a minus sign.
+ // Has to be this ugly. Period.
+ if ( eScannedType == NUMBERFORMAT_CURRENCY
+ && rStr.Len() >= 2 &&
+ (i == nAnzStrings-1 ||
+ sStrArray[i+1].GetChar(0) != '-') )
+ break;
+ rStr += sStrArray[i];
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ nCounter++;
+ i++;
+ }
+ }
+ else
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ }
+ break;
+ case '.':
+ case ',':
+ case '\'':
+ case ' ':
+ {
+ sal_Unicode cSep = cHere; // remember
+ if ( StringEqualsChar( sOldThousandSep, cSep ) )
+ {
+ // previous char with skip empty
+ sal_Unicode cPre = PreviousChar(i);
+ sal_Unicode cNext;
+ if (bExp || bBlank || bFrac)
+ { // after E, / or ' '
+ if ( !StringEqualsChar( sOldThousandSep, ' ' ) )
+ {
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++; // eat it
+ }
+ else
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ }
+ else if (i > 0 && i < nAnzStrings-1 &&
+ (cPre == '#' || cPre == '0') &&
+ ((cNext = NextChar(i)) == '#' || cNext == '0')
+ ) // #,#
+ {
+ nPos = nPos + sStrArray[i].Len();
+ if (!bThousand) // only once
+ {
+ bThousand = TRUE;
+ cThousandFill = sStrArray[i+1].GetChar(0);
+ }
+ // Eat it, will be reinserted at proper
+ // grouping positions further down.
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ else if (i > 0 && (cPre == '#' || cPre == '0')
+ && PreviousType(i) == NF_SYMBOLTYPE_DIGIT
+ && nThousand < FLAG_STANDARD_IN_FORMAT )
+ { // #,,,,
+ if ( StringEqualsChar( sOldThousandSep, ' ' ) )
+ { // strange, those French..
+ BOOL bFirst = TRUE;
+ String& rStr = sStrArray[i];
+ // set a hard Non-Breaking Space or ConvertMode
+ const String& rSepF = pFormatter->GetNumThousandSep();
+ while ( i < nAnzStrings
+ && sStrArray[i] == sOldThousandSep
+ && StringEqualsChar( sOldThousandSep, NextChar(i) ) )
+ { // last was a space or another space
+ // is following => separator
+ nPos = nPos + sStrArray[i].Len();
+ if ( bFirst )
+ {
+ bFirst = FALSE;
+ rStr = rSepF;
+ nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
+ }
+ else
+ {
+ rStr += rSepF;
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ nThousand++;
+ i++;
+ }
+ if ( i < nAnzStrings-1
+ && sStrArray[i] == sOldThousandSep )
+ { // something following last space
+ // => space if currency contained,
+ // else separator
+ nPos = nPos + sStrArray[i].Len();
+ if ( (nPos <= nCurrPos &&
+ nCurrPos < nPos + sStrArray[i+1].Len())
+ || nTypeArray[i+1] == NF_KEY_CCC
+ || (i < nAnzStrings-2 &&
+ sStrArray[i+1].GetChar(0) == '[' &&
+ sStrArray[i+2].GetChar(0) == '$') )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ }
+ else
+ {
+ if ( bFirst )
+ {
+ bFirst = FALSE;
+ rStr = rSepF;
+ nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
+ }
+ else
+ {
+ rStr += rSepF;
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ nThousand++;
+ }
+ i++;
+ }
+ }
+ else
+ {
+ do
+ {
+ nThousand++;
+ nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
+ nPos = nPos + sStrArray[i].Len();
+ sStrArray[i] = pFormatter->GetNumThousandSep();
+ i++;
+ } while (i < nAnzStrings &&
+ sStrArray[i] == sOldThousandSep);
+ }
+ }
+ else // any grsep
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ i++;
+ while ( i < nAnzStrings &&
+ sStrArray[i] == sOldThousandSep )
+ {
+ rStr += sStrArray[i];
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ }
+ }
+ else if ( StringEqualsChar( sOldDecSep, cSep ) )
+ {
+ if (bBlank || bFrac) // . behind / or ' '
+ return nPos; // error
+ else if (bExp) // behind E
+ {
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++; // eat it
+ }
+ else if (bDecSep) // any .
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ i++;
+ while ( i < nAnzStrings &&
+ sStrArray[i] == sOldDecSep )
+ {
+ rStr += sStrArray[i];
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ }
+ else
+ {
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_DECSEP;
+ sStrArray[i] = pFormatter->GetNumDecimalSep();
+ bDecSep = TRUE;
+ nDecPos = i;
+ nCntPre = nCounter;
+ nCounter = 0;
+
+ i++;
+ }
+ } // of else = DecSep
+ else // . without meaning
+ {
+ if (cSep == ' ' &&
+ eScannedType == NUMBERFORMAT_FRACTION &&
+ StringEqualsChar( sStrArray[i], ' ' ) )
+ {
+ if (!bBlank && !bFrac) // no dups
+ { // or behind /
+ if (bDecSep && nCounter > 0)// dec.
+ return nPos; // error
+ bBlank = TRUE;
+ nBlankPos = i;
+ nCntPre = nCounter;
+ nCounter = 0;
+ }
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ }
+ else
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ i++;
+ while (i < nAnzStrings &&
+ StringEqualsChar( sStrArray[i], cSep ) )
+ {
+ rStr += sStrArray[i];
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ }
+ }
+ }
+ break;
+ case '/':
+ {
+ if (eScannedType == NUMBERFORMAT_FRACTION)
+ {
+ if ( i == 0 ||
+ (nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT &&
+ nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) )
+ return nPos ? nPos : 1; // /? not allowed
+ else if (!bFrac || (bDecSep && nCounter > 0))
+ {
+ bFrac = TRUE;
+ nCntPost = nCounter;
+ nCounter = 0;
+ nTypeArray[i] = NF_SYMBOLTYPE_FRAC;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ else // / doppelt od. , imZaehl
+ return nPos; // Fehler
+ }
+ else
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ }
+ break;
+ case '[' :
+ {
+ if ( eScannedType == NUMBERFORMAT_CURRENCY &&
+ i < nAnzStrings-1 &&
+ nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
+ sStrArray[i+1].GetChar(0) == '$' )
+ { // [$DM-xxx]
+ // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
+ nPos = nPos + sStrArray[i].Len(); // [
+ nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
+ nPos = nPos + sStrArray[++i].Len(); // $
+ sStrArray[i-1] += sStrArray[i]; // [$
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ if ( ++i >= nAnzStrings )
+ return nPos; // Fehler
+ nPos = nPos + sStrArray[i].Len(); // DM
+ String& rStr = sStrArray[i];
+ String* pStr = &sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY; // wandeln
+ BOOL bHadDash = FALSE;
+ i++;
+ while ( i < nAnzStrings &&
+ sStrArray[i].GetChar(0) != ']' )
+ {
+ nPos = nPos + sStrArray[i].Len();
+ if ( bHadDash )
+ {
+ *pStr += sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ else
+ {
+ if ( sStrArray[i].GetChar(0) == '-' )
+ {
+ bHadDash = TRUE;
+ pStr = &sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_CURREXT;
+ }
+ else
+ {
+ *pStr += sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ }
+ i++;
+ }
+ if ( rStr.Len() && i < nAnzStrings &&
+ sStrArray[i].GetChar(0) == ']' )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ else
+ return nPos; // Fehler
+ }
+ else
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ }
+ break;
+ default: // andere Dels
+ {
+ if (eScannedType == NUMBERFORMAT_PERCENT &&
+ cHere == '%')
+ nTypeArray[i] = NF_SYMBOLTYPE_PERCENT;
+ else
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ } // of switch (Del)
+ } // of else Del
+ else if ( nTypeArray[i] == NF_SYMBOLTYPE_COMMENT )
+ {
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ SvNumberformat::EraseCommentBraces( rStr );
+ rComment += rStr;
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ else
+ {
+ DBG_ERRORFILE( "unknown NF_SYMBOLTYPE_..." );
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ } // of while
+ if (eScannedType == NUMBERFORMAT_FRACTION)
+ {
+ if (bFrac)
+ nCntExp = nCounter;
+ else if (bBlank)
+ nCntPost = nCounter;
+ else
+ nCntPre = nCounter;
+ }
+ else
+ {
+ if (bExp)
+ nCntExp = nCounter;
+ else if (bDecSep)
+ nCntPost = nCounter;
+ else
+ nCntPre = nCounter;
+ }
+ if (bThousand) // Expansion of grouping separators
+ {
+ USHORT nMaxPos;
+ if (bFrac)
+ {
+ if (bBlank)
+ nMaxPos = nBlankPos;
+ else
+ nMaxPos = 0; // no grouping
+ }
+ else if (bDecSep) // decimal separator present
+ nMaxPos = nDecPos;
+ else if (bExp) // 'E' exponent present
+ nMaxPos = nExpPos;
+ else // up to end
+ nMaxPos = i;
+ // Insert separators at proper positions.
+ xub_StrLen nCount = 0;
+ utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping());
+ size_t nFirstDigitSymbol = nMaxPos;
+ size_t nFirstGroupingSymbol = nMaxPos;
+ i = nMaxPos;
+ while (i-- > 0)
+ {
+ if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
+ {
+ nFirstDigitSymbol = i;
+ nCount = nCount + sStrArray[i].Len(); // MSC converts += to int and then warns, so ...
+ // Insert separator only if not leftmost symbol.
+ if (i > 0 && nCount >= aGrouping.getPos())
+ {
+ DBG_ASSERT( sStrArray[i].Len() == 1,
+ "ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion");
+ if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP,
+ pFormatter->GetNumThousandSep()))
+ // nPos isn't correct here, but signals error
+ return nPos;
+ // i may have been decremented by 1
+ nFirstDigitSymbol = i + 1;
+ nFirstGroupingSymbol = i;
+ aGrouping.advance();
+ }
+ }
+ }
+ // Generated something like "string",000; remove separator again.
+ if (nFirstGroupingSymbol < nFirstDigitSymbol)
+ {
+ nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ }
+ // Combine digits into groups to save memory (Info will be copied
+ // later, taking only non-empty symbols).
+ for (i = 0; i < nAnzStrings; ++i)
+ {
+ if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
+ {
+ String& rStr = sStrArray[i];
+ while (++i < nAnzStrings &&
+ nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
+ {
+ rStr += sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ }
+ }
+ }
+ break; // of NUMBERFORMAT_NUMBER
+ case NUMBERFORMAT_DATE:
+ {
+ while (i < nAnzStrings)
+ {
+ switch (nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_BLANK:
+ case NF_SYMBOLTYPE_STAR:
+ case NF_SYMBOLTYPE_STRING:
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ case NF_SYMBOLTYPE_COMMENT:
+ {
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ SvNumberformat::EraseCommentBraces( rStr );
+ rComment += rStr;
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ break;
+ case NF_SYMBOLTYPE_DEL:
+ {
+ int nCalRet;
+ if (sStrArray[i] == sOldDateSep)
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
+ nPos = nPos + sStrArray[i].Len();
+ if (bConvertMode)
+ sStrArray[i] = pFormatter->GetDateSep();
+ i++;
+ }
+ else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
+ {
+ if ( nCalRet < 0 )
+ return nPos; // error
+ }
+ else
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ }
+ break;
+ case NF_KEY_THAI_T :
+ bThaiT = true;
+ // fall thru
+ case NF_KEY_M: // M
+ case NF_KEY_MM: // MM
+ case NF_KEY_MMM: // MMM
+ case NF_KEY_MMMM: // MMMM
+ case NF_KEY_MMMMM: // MMMMM
+ case NF_KEY_Q: // Q
+ case NF_KEY_QQ: // QQ
+ case NF_KEY_D: // D
+ case NF_KEY_DD: // DD
+ case NF_KEY_DDD: // DDD
+ case NF_KEY_DDDD: // DDDD
+ case NF_KEY_YY: // YY
+ case NF_KEY_YYYY: // YYYY
+ case NF_KEY_NN: // NN
+ case NF_KEY_NNN: // NNN
+ case NF_KEY_NNNN: // NNNN
+ case NF_KEY_WW : // WW
+ case NF_KEY_AAA : // AAA
+ case NF_KEY_AAAA : // AAAA
+ case NF_KEY_EC : // E
+ case NF_KEY_EEC : // EE
+ case NF_KEY_G : // G
+ case NF_KEY_GG : // GG
+ case NF_KEY_GGG : // GGG
+ case NF_KEY_R : // R
+ case NF_KEY_RR : // RR
+ sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ default: // andere Keywords
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ }
+ } // of while
+ }
+ break; // of NUMBERFORMAT_DATE
+ case NUMBERFORMAT_TIME:
+ {
+ while (i < nAnzStrings)
+ {
+ switch (nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_BLANK:
+ case NF_SYMBOLTYPE_STAR:
+ {
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ case NF_SYMBOLTYPE_DEL:
+ {
+ switch( sStrArray[i].GetChar(0) )
+ {
+ case '0':
+ {
+ if ( Is100SecZero( i, bDecSep ) )
+ {
+ bDecSep = TRUE;
+ nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
+ String& rStr = sStrArray[i];
+ i++;
+ nPos = nPos + sStrArray[i].Len();
+ nCounter++;
+ while (i < nAnzStrings &&
+ sStrArray[i].GetChar(0) == '0')
+ {
+ rStr += sStrArray[i];
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ nCounter++;
+ i++;
+ }
+ }
+ else
+ return nPos;
+ }
+ break;
+ case '#':
+ case '?':
+ return nPos;
+ case '[':
+ {
+ if (bThousand) // doppelt
+ return nPos;
+ bThousand = TRUE; // bei Time frei
+ sal_Unicode cChar = pChrCls->upper( NextChar(i) ).GetChar(0);
+ if ( cChar == cOldKeyH )
+ nThousand = 1; // H
+ else if ( cChar == cOldKeyMI )
+ nThousand = 2; // M
+ else if ( cChar == cOldKeyS )
+ nThousand = 3; // S
+ else
+ return nPos;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ case ']':
+ {
+ if (!bThousand) // kein [ vorher
+ return nPos;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ default:
+ {
+ nPos = nPos + sStrArray[i].Len();
+ if ( sStrArray[i] == sOldTimeSep )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
+ if ( bConvertMode )
+ sStrArray[i] = pLoc->getTimeSep();
+ }
+ else if ( sStrArray[i] == sOldTime100SecSep )
+ {
+ bDecSep = TRUE;
+ nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
+ if ( bConvertMode )
+ sStrArray[i] = pLoc->getTime100SecSep();
+ }
+ else
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ i++;
+ }
+ break;
+ }
+ }
+ break;
+ case NF_SYMBOLTYPE_STRING:
+ {
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ case NF_SYMBOLTYPE_COMMENT:
+ {
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ SvNumberformat::EraseCommentBraces( rStr );
+ rComment += rStr;
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ break;
+ case NF_KEY_AMPM: // AM/PM
+ case NF_KEY_AP: // A/P
+ {
+ bExp = TRUE; // missbraucht fuer A/P
+ sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ case NF_KEY_THAI_T :
+ bThaiT = true;
+ // fall thru
+ case NF_KEY_MI: // M
+ case NF_KEY_MMI: // MM
+ case NF_KEY_H: // H
+ case NF_KEY_HH: // HH
+ case NF_KEY_S: // S
+ case NF_KEY_SS: // SS
+ {
+ sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ default: // andere Keywords
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ }
+ } // of while
+ nCntPost = nCounter; // Zaehler der Nullen
+ if (bExp)
+ nCntExp = 1; // merkt AM/PM
+ }
+ break; // of NUMBERFORMAT_TIME
+ case NUMBERFORMAT_DATETIME:
+ {
+ BOOL bTimePart = FALSE;
+ while (i < nAnzStrings)
+ {
+ switch (nTypeArray[i])
+ {
+ case NF_SYMBOLTYPE_BLANK:
+ case NF_SYMBOLTYPE_STAR:
+ case NF_SYMBOLTYPE_STRING:
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ case NF_SYMBOLTYPE_COMMENT:
+ {
+ String& rStr = sStrArray[i];
+ nPos = nPos + rStr.Len();
+ SvNumberformat::EraseCommentBraces( rStr );
+ rComment += rStr;
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ i++;
+ }
+ break;
+ case NF_SYMBOLTYPE_DEL:
+ {
+ int nCalRet;
+ if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
+ {
+ if ( nCalRet < 0 )
+ return nPos; // error
+ }
+ else
+ {
+ switch( sStrArray[i].GetChar(0) )
+ {
+ case '0':
+ {
+ if ( bTimePart && Is100SecZero( i, bDecSep ) )
+ {
+ bDecSep = TRUE;
+ nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
+ String& rStr = sStrArray[i];
+ i++;
+ nPos = nPos + sStrArray[i].Len();
+ nCounter++;
+ while (i < nAnzStrings &&
+ sStrArray[i].GetChar(0) == '0')
+ {
+ rStr += sStrArray[i];
+ nPos = nPos + sStrArray[i].Len();
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ nCounter++;
+ i++;
+ }
+ }
+ else
+ return nPos;
+ }
+ break;
+ case '#':
+ case '?':
+ return nPos;
+ default:
+ {
+ nPos = nPos + sStrArray[i].Len();
+ if (bTimePart)
+ {
+ if ( sStrArray[i] == sOldTimeSep )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
+ if ( bConvertMode )
+ sStrArray[i] = pLoc->getTimeSep();
+ }
+ else if ( sStrArray[i] == sOldTime100SecSep )
+ {
+ bDecSep = TRUE;
+ nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
+ if ( bConvertMode )
+ sStrArray[i] = pLoc->getTime100SecSep();
+ }
+ else
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ }
+ else
+ {
+ if ( sStrArray[i] == sOldDateSep )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
+ if (bConvertMode)
+ sStrArray[i] = pFormatter->GetDateSep();
+ }
+ else
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ }
+ i++;
+ }
+ }
+ }
+ }
+ break;
+ case NF_KEY_AMPM: // AM/PM
+ case NF_KEY_AP: // A/P
+ {
+ bTimePart = TRUE;
+ bExp = TRUE; // missbraucht fuer A/P
+ sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ }
+ break;
+ case NF_KEY_MI: // M
+ case NF_KEY_MMI: // MM
+ case NF_KEY_H: // H
+ case NF_KEY_HH: // HH
+ case NF_KEY_S: // S
+ case NF_KEY_SS: // SS
+ bTimePart = TRUE;
+ sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ case NF_KEY_M: // M
+ case NF_KEY_MM: // MM
+ case NF_KEY_MMM: // MMM
+ case NF_KEY_MMMM: // MMMM
+ case NF_KEY_MMMMM: // MMMMM
+ case NF_KEY_Q: // Q
+ case NF_KEY_QQ: // QQ
+ case NF_KEY_D: // D
+ case NF_KEY_DD: // DD
+ case NF_KEY_DDD: // DDD
+ case NF_KEY_DDDD: // DDDD
+ case NF_KEY_YY: // YY
+ case NF_KEY_YYYY: // YYYY
+ case NF_KEY_NN: // NN
+ case NF_KEY_NNN: // NNN
+ case NF_KEY_NNNN: // NNNN
+ case NF_KEY_WW : // WW
+ case NF_KEY_AAA : // AAA
+ case NF_KEY_AAAA : // AAAA
+ case NF_KEY_EC : // E
+ case NF_KEY_EEC : // EE
+ case NF_KEY_G : // G
+ case NF_KEY_GG : // GG
+ case NF_KEY_GGG : // GGG
+ case NF_KEY_R : // R
+ case NF_KEY_RR : // RR
+ bTimePart = FALSE;
+ sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ case NF_KEY_THAI_T :
+ bThaiT = true;
+ sStrArray[i] = sKeyword[nTypeArray[i]];
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ default: // andere Keywords
+ nTypeArray[i] = NF_SYMBOLTYPE_STRING;
+ nPos = nPos + sStrArray[i].Len();
+ i++;
+ break;
+ }
+ } // of while
+ nCntPost = nCounter; // decimals (100th seconds)
+ if (bExp)
+ nCntExp = 1; // merkt AM/PM
+ }
+ break; // of NUMBERFORMAT_DATETIME
+ default:
+ break;
+ }
+ if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
+ (nCntPre + nCntPost == 0 || nCntExp == 0))
+ return nPos;
+ else if (eScannedType == NUMBERFORMAT_FRACTION && (nCntExp > 8 || nCntExp == 0))
+ return nPos;
+
+ if (bThaiT && !GetNatNumModifier())
+ SetNatNumModifier(1);
+
+ if ( bConvertMode )
+ { // strings containing keywords of the target locale must be quoted, so
+ // the user sees the difference and is able to edit the format string
+ for ( i=0; i < nAnzStrings; i++ )
+ {
+ if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING &&
+ sStrArray[i].GetChar(0) != '\"' )
+ {
+ if ( bConvertSystemToSystem && eScannedType == NUMBERFORMAT_CURRENCY )
+ { // don't stringize automatic currency, will be converted
+ if ( sStrArray[i] == sOldCurSymbol )
+ continue; // for
+ // DM might be splitted into D and M
+ if ( sStrArray[i].Len() < sOldCurSymbol.Len() &&
+ pChrCls->toUpper( sStrArray[i], 0, 1 ).GetChar(0) ==
+ sOldCurString.GetChar(0) )
+ {
+ String aTmp( sStrArray[i] );
+ USHORT j = i + 1;
+ while ( aTmp.Len() < sOldCurSymbol.Len() &&
+ j < nAnzStrings &&
+ nTypeArray[j] == NF_SYMBOLTYPE_STRING )
+ {
+ aTmp += sStrArray[j++];
+ }
+ if ( pChrCls->upper( aTmp ) == sOldCurString )
+ {
+ sStrArray[i++] = aTmp;
+ for ( ; i<j; i++ )
+ {
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ i = j - 1;
+ continue; // for
+ }
+ }
+ }
+ String& rStr = sStrArray[i];
+ xub_StrLen nLen = rStr.Len();
+ for ( xub_StrLen j=0; j<nLen; j++ )
+ {
+ if ( (j == 0 || rStr.GetChar(j-1) != '\\') && GetKeyWord( rStr, j ) )
+ {
+ rStr.Insert( '\"', 0 );
+ rStr += '\"';
+ break; // for
+ }
+ }
+ }
+ }
+ }
+ // concatenate strings, remove quotes for output, and rebuild the format string
+ rString.Erase();
+ i = 0;
+ while (i < nAnzStrings)
+ {
+ switch ( nTypeArray[i] )
+ {
+ case NF_SYMBOLTYPE_STRING :
+ {
+ xub_StrLen nStringPos = rString.Len();
+ xub_StrLen nArrPos = 0;
+ USHORT iPos = i;
+ do
+ {
+ if (sStrArray[i].Len() == 2 &&
+ sStrArray[i].GetChar(0) == '\\')
+ {
+ // Unescape some simple forms of symbols even in the UI
+ // visible string to prevent duplicates that differ
+ // only in notation, originating from import.
+ // e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical,
+ // but 0\ 000 0 and 0 000 0 in a French locale are not.
+ sal_Unicode c = sStrArray[i].GetChar(1);
+ switch (c)
+ {
+ case '+':
+ case '-':
+ rString += c;
+ break;
+ case ' ':
+ case '.':
+ case '/':
+ if (((eScannedType & NUMBERFORMAT_DATE) == 0)
+ && (StringEqualsChar(
+ pFormatter->GetNumThousandSep(),
+ c) || StringEqualsChar(
+ pFormatter->GetNumDecimalSep(),
+ c) || (c == ' ' &&
+ StringEqualsChar(
+ pFormatter->GetNumThousandSep(),
+ cNonBreakingSpace))))
+ rString += sStrArray[i];
+ else if ((eScannedType & NUMBERFORMAT_DATE) &&
+ StringEqualsChar(
+ pFormatter->GetDateSep(), c))
+ rString += sStrArray[i];
+ else if ((eScannedType & NUMBERFORMAT_TIME) &&
+ (StringEqualsChar( pLoc->getTimeSep(),
+ c) ||
+ StringEqualsChar(
+ pLoc->getTime100SecSep(), c)))
+ rString += sStrArray[i];
+ else if (eScannedType & NUMBERFORMAT_FRACTION)
+ rString += sStrArray[i];
+ else
+ rString += c;
+ break;
+ default:
+ rString += sStrArray[i];
+ }
+ }
+ else
+ rString += sStrArray[i];
+ if ( RemoveQuotes( sStrArray[i] ) > 0 )
+ { // update currency up to quoted string
+ if ( eScannedType == NUMBERFORMAT_CURRENCY )
+ { // dM -> DM or DM -> $ in old automatic
+ // currency formats, oh my ..., why did we ever
+ // introduce them?
+ String aTmp( pChrCls->toUpper(
+ sStrArray[iPos], nArrPos,
+ sStrArray[iPos].Len()-nArrPos ) );
+ xub_StrLen nCPos = aTmp.Search( sOldCurString );
+ if ( nCPos != STRING_NOTFOUND )
+ {
+ const String& rCur =
+ bConvertMode && bConvertSystemToSystem ?
+ GetCurSymbol() : sOldCurSymbol;
+ sStrArray[iPos].Replace( nArrPos+nCPos,
+ sOldCurString.Len(), rCur );
+ rString.Replace( nStringPos+nCPos,
+ sOldCurString.Len(), rCur );
+ }
+ nStringPos = rString.Len();
+ if ( iPos == i )
+ nArrPos = sStrArray[iPos].Len();
+ else
+ nArrPos = sStrArray[iPos].Len() + sStrArray[i].Len();
+ }
+ }
+ if ( iPos != i )
+ {
+ sStrArray[iPos] += sStrArray[i];
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ i++;
+ } while ( i < nAnzStrings && nTypeArray[i] == NF_SYMBOLTYPE_STRING );
+ if ( i < nAnzStrings )
+ i--; // enter switch on next symbol again
+ if ( eScannedType == NUMBERFORMAT_CURRENCY && nStringPos < rString.Len() )
+ { // same as above, since last RemoveQuotes
+ String aTmp( pChrCls->toUpper(
+ sStrArray[iPos], nArrPos,
+ sStrArray[iPos].Len()-nArrPos ) );
+ xub_StrLen nCPos = aTmp.Search( sOldCurString );
+ if ( nCPos != STRING_NOTFOUND )
+ {
+ const String& rCur =
+ bConvertMode && bConvertSystemToSystem ?
+ GetCurSymbol() : sOldCurSymbol;
+ sStrArray[iPos].Replace( nArrPos+nCPos,
+ sOldCurString.Len(), rCur );
+ rString.Replace( nStringPos+nCPos,
+ sOldCurString.Len(), rCur );
+ }
+ }
+ }
+ break;
+ case NF_SYMBOLTYPE_CURRENCY :
+ {
+ rString += sStrArray[i];
+ RemoveQuotes( sStrArray[i] );
+ }
+ break;
+ case NF_KEY_THAI_T:
+ if (bThaiT && GetNatNumModifier() == 1)
+ { // Remove T from format code, will be replaced with a [NatNum1] prefix.
+ nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
+ nAnzResStrings--;
+ }
+ else
+ rString += sStrArray[i];
+ break;
+ case NF_SYMBOLTYPE_EMPTY :
+ // nothing
+ break;
+ default:
+ rString += sStrArray[i];
+ }
+ i++;
+ }
+ return 0;
+}
+
+
+xub_StrLen ImpSvNumberformatScan::RemoveQuotes( String& rStr )
+{
+ if ( rStr.Len() > 1 )
+ {
+ sal_Unicode c = rStr.GetChar(0);
+ xub_StrLen n;
+ if ( c == '"' && rStr.GetChar( (n = xub_StrLen(rStr.Len()-1)) ) == '"' )
+ {
+ rStr.Erase(n,1);
+ rStr.Erase(0,1);
+ return 2;
+ }
+ else if ( c == '\\' )
+ {
+ rStr.Erase(0,1);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+xub_StrLen ImpSvNumberformatScan::ScanFormat( String& rString, String& rComment )
+{
+ xub_StrLen res = Symbol_Division(rString); //lexikalische Analyse
+ if (!res)
+ res = ScanType(rString); // Erkennung des Formattyps
+ if (!res)
+ res = FinalScan( rString, rComment ); // Typabhaengige Endanalyse
+ return res; // res = Kontrollposition
+ // res = 0 => Format ok
+}
+
+void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, USHORT nAnz)
+{
+ size_t i,j;
+ j = 0;
+ i = 0;
+ while (i < nAnz && j < NF_MAX_FORMAT_SYMBOLS)
+ {
+ if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY)
+ {
+ pInfo->sStrArray[i] = sStrArray[j];
+ pInfo->nTypeArray[i] = nTypeArray[j];
+ i++;
+ }
+ j++;
+ }
+ pInfo->eScannedType = eScannedType;
+ pInfo->bThousand = bThousand;
+ pInfo->nThousand = nThousand;
+ pInfo->nCntPre = nCntPre;
+ pInfo->nCntPost = nCntPost;
+ pInfo->nCntExp = nCntExp;
+}
+
+
diff --git a/svl/source/numbers/zforscan.hxx b/svl/source/numbers/zforscan.hxx
new file mode 100644
index 000000000000..300715dfeaa5
--- /dev/null
+++ b/svl/source/numbers/zforscan.hxx
@@ -0,0 +1,278 @@
+/*************************************************************************
+ *
+ * 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: zforscan.hxx,v $
+ * $Revision: 1.24.136.1 $
+ *
+ * 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.
+ *
+ ************************************************************************/
+#ifndef _ZFORSCAN_HXX
+#define _ZFORSCAN_HXX
+
+#include <tools/string.hxx>
+#include <tools/date.hxx>
+#include <i18npool/lang.h>
+#include <tools/color.hxx>
+#include <svl/nfkeytab.hxx>
+#include "nfsymbol.hxx"
+
+class SvNumberFormatter;
+struct ImpSvNumberformatInfo;
+
+
+const size_t NF_MAX_FORMAT_SYMBOLS = 100;
+const size_t NF_MAX_DEFAULT_COLORS = 10;
+
+// Hack: nThousand==1000 => "Default" occurs in format string
+const USHORT FLAG_STANDARD_IN_FORMAT = 1000;
+
+class ImpSvNumberformatScan
+{
+public:
+
+ ImpSvNumberformatScan( SvNumberFormatter* pFormatter );
+ ~ImpSvNumberformatScan();
+ void ChangeIntl(); // tauscht Keywords aus
+
+ void ChangeNullDate(USHORT nDay, USHORT nMonth, USHORT nYear);
+ // tauscht Referenzdatum aus
+ void ChangeStandardPrec(short nPrec); // tauscht Standardprecision aus
+
+ xub_StrLen ScanFormat( String& rString, String& rComment ); // Aufruf der Scan-Analyse
+
+ void CopyInfo(ImpSvNumberformatInfo* pInfo,
+ USHORT nAnz); // Kopiert die FormatInfo
+ USHORT GetAnzResStrings() const { return nAnzResStrings; }
+
+ const CharClass& GetChrCls() const { return *pFormatter->GetCharClass(); }
+ const LocaleDataWrapper& GetLoc() const { return *pFormatter->GetLocaleData(); }
+ CalendarWrapper& GetCal() const { return *pFormatter->GetCalendar(); }
+
+ const String* GetKeywords() const
+ {
+ if ( bKeywordsNeedInit )
+ InitKeywords();
+ return sKeyword;
+ }
+ // Keywords used in output like TRUE and FALSE
+ const String& GetSpecialKeyword( NfKeywordIndex eIdx ) const
+ {
+ if ( !sKeyword[eIdx].Len() )
+ InitSpecialKeyword( eIdx );
+ return sKeyword[eIdx];
+ }
+ const String& GetTrueString() const { return GetSpecialKeyword( NF_KEY_TRUE ); }
+ const String& GetFalseString() const { return GetSpecialKeyword( NF_KEY_FALSE ); }
+ const String& GetColorString() const { return GetKeywords()[NF_KEY_COLOR]; }
+ const String& GetRedString() const { return GetKeywords()[NF_KEY_RED]; }
+ const String& GetBooleanString() const { return GetKeywords()[NF_KEY_BOOLEAN]; }
+ const String& GetErrorString() const { return sErrStr; }
+
+ Date* GetNullDate() const { return pNullDate; }
+ const String& GetStandardName() const
+ {
+ if ( bKeywordsNeedInit )
+ InitKeywords();
+ return sNameStandardFormat;
+ }
+ short GetStandardPrec() const { return nStandardPrec; }
+ const Color& GetRedColor() const { return StandardColor[4]; }
+ Color* GetColor(String& sStr); // Setzt Hauptfarben oder
+ // definierte Farben
+
+ // the compatibility currency symbol for old automatic currency formats
+ const String& GetCurSymbol() const
+ {
+ if ( bCompatCurNeedInit )
+ InitCompatCur();
+ return sCurSymbol;
+ }
+
+ // the compatibility currency abbreviation for CCC format code
+ const String& GetCurAbbrev() const
+ {
+ if ( bCompatCurNeedInit )
+ InitCompatCur();
+ return sCurAbbrev;
+ }
+
+ // the compatibility currency symbol upper case for old automatic currency formats
+ const String& GetCurString() const
+ {
+ if ( bCompatCurNeedInit )
+ InitCompatCur();
+ return sCurString;
+ }
+
+ void SetConvertMode(LanguageType eTmpLge, LanguageType eNewLge,
+ BOOL bSystemToSystem = FALSE )
+ {
+ bConvertMode = TRUE;
+ eNewLnge = eNewLge;
+ eTmpLnge = eTmpLge;
+ bConvertSystemToSystem = bSystemToSystem;
+ }
+ void SetConvertMode(BOOL bMode) { bConvertMode = bMode; }
+ // Veraendert nur die Bool-Variable
+ // (zum temporaeren Unterbrechen des
+ // Convert-Modus)
+ BOOL GetConvertMode() const { return bConvertMode; }
+ LanguageType GetNewLnge() const { return eNewLnge; }
+ // Lesezugriff auf ConvertMode
+ // und Konvertierungsland/Spr.
+ LanguageType GetTmpLnge() const { return eTmpLnge; }
+ // Lesezugriff auf
+ // und Ausgangsland/Spr.
+
+ /// get Thai T speciality
+ BYTE GetNatNumModifier() const { return nNatNumModifier; }
+ /// set Thai T speciality
+ void SetNatNumModifier( BYTE n ) { nNatNumModifier = n; }
+
+ SvNumberFormatter* GetNumberformatter() { return pFormatter; }
+ // Zugriff auf Formatierer
+ // (fuer zformat.cxx)
+
+
+private: // ---- privater Teil
+ NfKeywordTable sKeyword; // Schluesselworte der Syntax
+ Color StandardColor[NF_MAX_DEFAULT_COLORS];
+ // Array der Standardfarben
+ Date* pNullDate; // 30Dec1899
+ String sNameStandardFormat; // "Standard"
+ short nStandardPrec; // default Precision fuer Standardformat (2)
+ SvNumberFormatter* pFormatter; // Pointer auf die Formatliste
+
+ String sStrArray[NF_MAX_FORMAT_SYMBOLS]; // Array der Symbole
+ short nTypeArray[NF_MAX_FORMAT_SYMBOLS]; // Array der Infos
+ // externe Infos:
+ USHORT nAnzResStrings; // Anzahl der Ergebnissymbole
+#if !(defined SOLARIS && defined X86)
+ short eScannedType; // Typ gemaess Scan
+#else
+ int eScannedType; // wg. Optimierung
+#endif
+ BOOL bThousand; // Mit Tausenderpunkt
+ USHORT nThousand; // Zaehlt ....-Folgen
+ USHORT nCntPre; // Zaehlt Vorkommastellen
+ USHORT nCntPost; // Zaehlt Nachkommastellen
+ USHORT nCntExp; // Zaehlt Exp.Stellen, AM/PM
+ // interne Infos:
+ USHORT nAnzStrings; // Anzahl der Symbole
+ USHORT nRepPos; // Position eines '*'
+ USHORT nExpPos; // interne Position des E
+ USHORT nBlankPos; // interne Position des Blank
+ short nDecPos; // interne Pos. des ,
+ BOOL bExp; // wird bei Lesen des E gesetzt
+ BOOL bFrac; // wird bei Lesen des / gesetzt
+ BOOL bBlank; // wird bei ' '(Fraction) ges.
+ BOOL bDecSep; // Wird beim ersten , gesetzt
+ mutable BOOL bKeywordsNeedInit; // Locale dependent keywords need to be initialized
+ mutable BOOL bCompatCurNeedInit; // Locale dependent compatibility currency need to be initialized
+ String sCurSymbol; // Currency symbol for compatibility format codes
+ String sCurString; // Currency symbol in upper case
+ String sCurAbbrev; // Currency abbreviation
+ String sErrStr; // String fuer Fehlerausgaben
+
+ BOOL bConvertMode; // Wird im Convert-Mode gesetzt
+ // Land/Sprache, in die der
+ LanguageType eNewLnge; // gescannte String konvertiert
+ // wird (fuer Excel Filter)
+ // Land/Sprache, aus der der
+ LanguageType eTmpLnge; // gescannte String konvertiert
+ // wird (fuer Excel Filter)
+ BOOL bConvertSystemToSystem; // Whether the conversion is
+ // from one system locale to
+ // another system locale (in
+ // this case the automatic
+ // currency symbol is converted
+ // too).
+
+ xub_StrLen nCurrPos; // Position des Waehrungssymbols
+
+ BYTE nNatNumModifier; // Thai T speciality
+
+ void InitKeywords() const;
+ void InitSpecialKeyword( NfKeywordIndex eIdx ) const;
+ void InitCompatCur() const;
+
+#ifdef _ZFORSCAN_CXX // ----- private Methoden -----
+ void SetDependentKeywords();
+ // Setzt die Sprachabh. Keyw.
+ void SkipStrings(USHORT& i,xub_StrLen& nPos);// Ueberspringt StringSymbole
+ USHORT PreviousKeyword(USHORT i); // Gibt Index des vorangeh.
+ // Schluesselworts oder 0
+ USHORT NextKeyword(USHORT i); // Gibt Index des naechsten
+ // Schluesselworts oder 0
+ sal_Unicode PreviousChar(USHORT i); // Gibt letzten Buchstaben
+ // vor der Position,
+ // skipt EMPTY, STRING, STAR, BLANK
+ sal_Unicode NextChar(USHORT i); // Gibt ersten Buchst. danach
+ short PreviousType( USHORT i ); // Gibt Typ vor Position,
+ // skipt EMPTY
+ BOOL IsLastBlankBeforeFrac(USHORT i); // True <=> es kommt kein ' '
+ // mehr bis zum '/'
+ void Reset(); // Reset aller Variablen
+ // vor Analysestart
+ short GetKeyWord( const String& sSymbol, // determine keyword at nPos
+ xub_StrLen nPos ); // return 0 <=> not found
+
+ inline BOOL IsAmbiguousE( short nKey ) // whether nKey is ambiguous E of NF_KEY_E/NF_KEY_EC
+ {
+ return (nKey == NF_KEY_EC || nKey == NF_KEY_E) &&
+ (GetKeywords()[NF_KEY_EC] == GetKeywords()[NF_KEY_E]);
+ }
+
+ // if 0 at strArray[i] is of S,00 or SS,00 or SS"any"00 in ScanType() or FinalScan()
+ BOOL Is100SecZero( USHORT i, BOOL bHadDecSep );
+
+ short Next_Symbol(const String& rStr,
+ xub_StrLen& nPos,
+ String& sSymbol); // Naechstes Symbol
+ xub_StrLen Symbol_Division(const String& rString);// lexikalische Voranalyse
+ xub_StrLen ScanType(const String& rString); // Analyse des Formattyps
+ xub_StrLen FinalScan( String& rString, String& rComment ); // Endanalyse mit Vorgabe
+ // des Typs
+ // -1:= error, return nPos in FinalScan; 0:= no calendar, 1:= calendar found
+ int FinalScanGetCalendar( xub_StrLen& nPos, USHORT& i, USHORT& nAnzResStrings );
+
+ /** Insert symbol into nTypeArray and sStrArray, e.g. grouping separator.
+ If at nPos-1 a symbol type NF_SYMBOLTYPE_EMPTY is present, that is
+ reused instead of shifting all one up and nPos is decremented! */
+ bool InsertSymbol( USHORT & nPos, svt::NfSymbolType eType, const String& rStr );
+
+ static inline BOOL StringEqualsChar( const String& rStr, sal_Unicode ch )
+ { return rStr.GetChar(0) == ch && rStr.Len() == 1; }
+ // Yes, for efficiency get the character first and then compare length
+ // because in most places where this is used the string is one char.
+
+ // remove "..." and \... quotes from rStr, return how many chars removed
+ static xub_StrLen RemoveQuotes( String& rStr );
+
+#endif //_ZFORSCAN_CXX
+};
+
+
+
+#endif // _ZFORSCAN_HXX