diff options
Diffstat (limited to 'svl/source/numbers/zformat.cxx')
-rw-r--r-- | svl/source/numbers/zformat.cxx | 4787 |
1 files changed, 0 insertions, 4787 deletions
diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx deleted file mode 100644 index 69b3e1762f..0000000000 --- a/svl/source/numbers/zformat.cxx +++ /dev/null @@ -1,4787 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * 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 <errno.h> -#include <stdlib.h> -#include <tools/debug.hxx> -#include <osl/diagnose.h> -#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 <svl/nfsymbol.hxx> - -#include <cmath> - -using namespace svt; -using ::rtl::OUString; -using ::rtl::OUStringBuffer; - -namespace { -struct Gregorian - : public rtl::StaticWithInit<const ::rtl::OUString, Gregorian> { - const ::rtl::OUString operator () () { - return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian")); - } -}; - -const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary... -const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value. - -} - -const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0 -const double _D_MAX_LONG_ = (double) 0x7fffffff; // 2147483647.0 -const sal_uInt16 _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 sal_uInt8 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 ) - { - sal_uInt16 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 sal_uInt16 nNewCurrencyVersionId = 0x434E; // "NC" -const sal_Unicode cNewCurrencyMagic = 0x01; // Magic for format code in comment -const sal_uInt16 nNewStandardFlagVersionId = 0x4653; // "SF" - -/***********************Funktion SvNumberformatInfo******************************/ - -void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nAnz ) -{ - for (sal_uInt16 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, sal_uInt16 nAnz) const -{ - for (sal_uInt16 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, sal_uInt16 nAnz) -{ - for (sal_uInt16 i = 0; i < nAnz; i++) - { - SvNumberformat::LoadString( rStream, sStrArray[i] ); - rStream >> nTypeArray[i]; - } - rStream >> eScannedType >> bThousand >> nThousand - >> nCntPre >> nCntPost >> nCntExp; -} - -//============================================================================ - -// static -sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, sal_Bool bDate ) -{ - sal_uInt8 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 -sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, sal_Bool bDate ) -{ - sal_uInt8 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 = sal_False; - aI.nThousand = 0; - aI.nCntPre = 0; - aI.nCntPost = 0; - aI.nCntExp = 0; - pColor = NULL; -} - -ImpSvNumFor::~ImpSvNumFor() -{ - for (sal_uInt16 i = 0; i < nAnzStrings; i++) - aI.sStrArray[i].Erase(); - delete [] aI.sStrArray; - delete [] aI.nTypeArray; -} - -void ImpSvNumFor::Enlarge(sal_uInt16 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 ) -{ - sal_uInt16 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); -} - -sal_Bool ImpSvNumFor::HasNewCurrency() const -{ - for ( sal_uInt16 j=0; j<nAnzStrings; j++ ) - { - if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY ) - return sal_True; - } - return sal_False; -} - -sal_Bool ImpSvNumFor::GetNewCurrencySymbol( String& rSymbol, - String& rExtension ) const -{ - for ( sal_uInt16 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 sal_True; - } - } - //! kein Erase an rSymbol, rExtension - return sal_False; -} - -void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const -{ - sal_uInt16 j; - sal_uInt16 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 ) -{ - sal_uInt16 nCnt; - rStream >> nCnt; - for ( sal_uInt16 j=0; j<nCnt; j++ ) - { - sal_uInt16 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), - nNewStandardDefined(0), - bStarFlag( sal_False ) -{ - maLocale.meLanguage = eLge; -} - -void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat ) -{ - sFormatstring = rFormat.sFormatstring; - eType = rFormat.eType; - maLocale = rFormat.maLocale; - 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 (sal_uInt16 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 ); -} - -sal_Bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType ) -{ - if ( nSymbolType > 0 ) - return sal_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 sal_True; - } - return sal_False; -} - - -String SvNumberformat::ImpObtainCalendarAndNumerals( String & rString, - xub_StrLen & nPos, LanguageType & nLang, const LocaleType & aTmpLocale ) -{ - String sCalendar; - /* TODO: this could be enhanced to allow other possible locale dependent - * calendars and numerals. BUT only if our locale data allows it! For LCID - * numerals and calendars see - * http://office.microsoft.com/en-us/excel/HA010346351033.aspx */ - if (MsLangId::getRealLanguage( aTmpLocale.meLanguage) == LANGUAGE_THAI) - { - // Numeral shape code "D" = Thai digits. - if (aTmpLocale.mnNumeralShape == 0xD) - rString.InsertAscii( "[NatNum1]", nPos); - - // Calendar type code "07" = Thai Buddhist calendar, insert this after - // all prefixes have been consumed as it is actually a format modifier - // and not a prefix. - if (aTmpLocale.mnCalendarType == 0x07) - { - // Currently calendars are tied to the locale of the entire number - // format, e.g. [~buddhist] in en_US doesn't work. - // => Having different locales in sub formats does not work! - /* TODO: calendars could be tied to a sub format's NatNum info - * instead, or even better be available for any locale. Needs a - * different implementation of GetCal() and locale data calendars. - * */ - // If this is not Thai yet, make it so. - if (MsLangId::getRealLanguage( maLocale.meLanguage) != LANGUAGE_THAI) - { - maLocale = aTmpLocale; - nLang = maLocale.meLanguage = LANGUAGE_THAI; - } - sCalendar.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "[~buddhist]")); - } - } - return sCalendar; -} - - -SvNumberformat::SvNumberformat(String& rString, - ImpSvNumberformatScan* pSc, - ImpSvNumberInputScan* pISc, - xub_StrLen& nCheckPos, - LanguageType& eLan, - sal_Bool bStan) - : - rScan(*pSc), - nNewStandardDefined(0), - bStarFlag( sal_False ) -{ - // If the group (AKA thousand) separator is a Non-Breaking Space (French) - // replace all occurrences 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()) - { - maLocale.meLanguage = rScan.GetNewLnge(); - eLan = maLocale.meLanguage; // Wechsel auch zurueckgeben - } - else - maLocale.meLanguage = eLan; - bStandard = bStan; - bIsUsed = sal_False; - fLimit1 = 0.0; - fLimit2 = 0.0; - eOp1 = NUMBERFORMAT_OP_NO; - eOp2 = NUMBERFORMAT_OP_NO; - eType = NUMBERFORMAT_DEFINED; - - sal_Bool bCancel = sal_False; - sal_Bool bCondition = sal_False; - short eSymbolType; - xub_StrLen nPos = 0; - xub_StrLen nPosOld; - nCheckPos = 0; - String aComment; - - // Split into 4 sub formats - sal_uInt16 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 sInsertCalendar; // a calendar resulting from parsing LCID - 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 = sal_True; - eOp1 = (SvNumberformatLimitOps) eSymbolType; - } - else if ( nIndex == 1 && bCondition ) - eOp2 = (SvNumberformatLimitOps) eSymbolType; - else // error - { - bCancel = sal_True; // break for - nCheckPos = nPosOld; - } - if (!bCancel) - { - double fNumber; - xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr); - if (nAnzChars > 0) - { - short F_Type = NUMBERFORMAT_UNDEFINED; - 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 = sal_True; // break for - nCheckPos = nPos; - } - } - nPosOld = nPos; // position before string - } - else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) - { - String sSymbol( sStr); - switch ( eSymbolType ) - { - case BRACKET_SYMBOLTYPE_COLOR : - { - if ( NumFor[nIndex].GetColor() != NULL ) - { // error, more than one color - bCancel = sal_True; // break for - nCheckPos = nPosOld; - } - else - { - Color* pColor = pSc->GetColor( sStr); - NumFor[nIndex].SetColor( pColor, sStr); - if (pColor == NULL) - { // error - bCancel = sal_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 = sal_True; // break for - nCheckPos = nPosOld; - } - else - { - sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) ); - //! eSymbolType is negative - sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0)); - sStr += String::CreateFromInt32( nNum ); - NumFor[nIndex].SetNatNumNum( nNum, sal_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 = sal_True; // break for - nCheckPos = nPosOld; - } - else - { - sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) ); - //! eSymbolType is negative - sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1)); - sStr += static_cast< sal_Unicode >('0' + nNum); - NumFor[nIndex].SetNatNumNum( nNum, sal_True ); - } - } - break; - case BRACKET_SYMBOLTYPE_LOCALE : - { - if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW || - rString.GetChar(nPos-1) != ']' ) - // Check also for ']' to avoid pulling in - // locale data for the preview string for not - // yet completed LCIDs in the dialog. - { - bCancel = sal_True; // break for - nCheckPos = nPosOld; - } - else - { - xub_StrLen nTmp = 2; - LocaleType aTmpLocale( ImpGetLocaleType( sStr, nTmp)); - if (aTmpLocale.meLanguage == LANGUAGE_DONTKNOW) - { - bCancel = sal_True; // break for - nCheckPos = nPosOld; - } - else - { - // Only the first sub format's locale will be - // used as the format's overall locale. - // Sorts this also under the corresponding - // locale for the dialog. - // If we don't support the locale this would - // result in an unknown (empty) language - // listbox entry and the user would never see - // this format. - if (nIndex == 0 && (aTmpLocale.meLanguage == 0 || - SvNumberFormatter::IsLocaleInstalled( aTmpLocale.meLanguage))) - { - maLocale = aTmpLocale; - eLan = aTmpLocale.meLanguage; // return to caller - /* TODO: fiddle with scanner to make this - * known? A change in the locale may affect - * separators and keywords. On the other - * hand they may have been entered as used - * in the originating locale, there's no - * way to predict other than analyzing the - * format code, we assume here the current - * context is used, which is most likely - * the case. - * */ - } - sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM("$-") ); - sStr += String( aTmpLocale.generateCode()); - NumFor[nIndex].SetNatNumLang( MsLangId::getRealLanguage( aTmpLocale.meLanguage)); - - // "$-NNCCLLLL" Numerals and Calendar - if (sSymbol.Len() > 6) - sInsertCalendar = ImpObtainCalendarAndNumerals( rString, nPos, eLan, aTmpLocale); - /* NOTE: there can be only one calendar - * inserted so the last one wins, though - * our own calendar modifiers support - * multiple calendars within one sub format - * code if at different positions. */ - } - } - } - break; - } - if ( !bCancel ) - { - if (sStr == sSymbol) - nPosOld = nPos; - else - { - rString.Erase(nPosOld,nPos-nPosOld); - if (sStr.Len()) - { - rString.Insert(sStr,nPosOld); - nPos = nPosOld + sStr.Len(); - rString.Insert(']', nPos); - rString.Insert('[', nPosOld); - nPos += 2; - nPosOld = nPos; // position before string - } - else - { - nPos = nPosOld; // prefix removed for whatever reason - } - } - } - } - } 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 - { - if (sInsertCalendar.Len()) - sStr.Insert( sInsertCalendar, 0); - - xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment ); - sal_uInt16 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(), sal_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 = sal_True; // break for - } - } - } - else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error - { - nCheckPos = nPosOld; - bCancel = sal_True; - } - else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) - { - nCheckPos = nPosOld+1; // error, prefix in string - bCancel = sal_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 = sal_True; - } - if ( NumFor[nIndex].GetNatNum().IsSet() ) - NumFor[nIndex].SetNatNumDate( - (NumFor[nIndex].Info().eScannedType & NUMBERFORMAT_DATE) != 0 ); - } - - if ( bCondition && !nCheckPos ) - { - if ( nIndex == 1 && NumFor[0].GetCount() == 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 ) ) - { - sal_uInt16 nAnz = pSc->GetAnzResStrings(); - if ( nAnz ) - { - NumFor[0].Enlarge(nAnz); - pSc->CopyInfo( &(NumFor[0].Info()), nAnz ); - rString += aAdd; - } - } - } - else if ( nIndex == 1 && NumFor[nIndex].GetCount() == 0 && - rString.GetChar(rString.Len()-1) != ';' && - (NumFor[0].GetCount() > 1 || (NumFor[0].GetCount() == 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 ) ) - { - sal_uInt16 nAnz = pSc->GetAnzResStrings(); - if ( nAnz ) - { - NumFor[nIndex].Enlarge(nAnz); - pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz ); - rString += ';'; - rString += aAdd; - } - } - } - else if ( nIndex == 2 && NumFor[nIndex].GetCount() == 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 ) ) - { - sal_uInt16 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].GetCount() == 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; -} - -namespace { - -sal_Unicode toUniChar(sal_uInt8 n) -{ - sal_Char c; - if (n < 10) - c = '0' + n; - else - c = 'A' + n - 10; - return sal_Unicode(c); -} - -} - -OUString SvNumberformat::LocaleType::generateCode() const -{ - OUStringBuffer aBuf; -#if 0 - // TODO: We may re-enable this later. Don't remove it! --Kohei - if (mnNumeralShape) - { - sal_uInt8 nVal = mnNumeralShape; - for (sal_uInt8 i = 0; i < 2; ++i) - { - sal_uInt8 n = (nVal & 0xF0) >> 4; - if (n || aBuf.getLength()) - aBuf.append(toUniChar(n)); - nVal = nVal << 4; - } - } - - if (mnNumeralShape || mnCalendarType) - { - sal_uInt8 nVal = mnCalendarType; - for (sal_uInt8 i = 0; i < 2; ++i) - { - sal_uInt8 n = (nVal & 0xF0) >> 4; - if (n || aBuf.getLength()) - aBuf.append(toUniChar(n)); - nVal = nVal << 4; - } - } -#endif - - sal_uInt16 n16 = static_cast<sal_uInt16>(meLanguage); - for (sal_uInt8 i = 0; i < 4; ++i) - { - sal_uInt8 n = static_cast<sal_uInt8>((n16 & 0xF000) >> 12); - // Omit leading zeros for consistency. - if (n || aBuf.getLength() || i == 3) - aBuf.append(toUniChar(n)); - n16 = n16 << 4; - } - - return aBuf.makeStringAndClear(); -} - -SvNumberformat::LocaleType::LocaleType() : - mnNumeralShape(0), - mnCalendarType(0), - meLanguage(LANGUAGE_DONTKNOW) -{ -} - -SvNumberformat::LocaleType::LocaleType(sal_uInt32 nRawNum) : - mnNumeralShape(0), - mnCalendarType(0), - meLanguage(LANGUAGE_DONTKNOW) -{ - meLanguage = static_cast<LanguageType>(nRawNum & 0x0000FFFF); - nRawNum = (nRawNum >> 16); - mnCalendarType = static_cast<sal_uInt8>(nRawNum & 0xFF); - nRawNum = (nRawNum >> 8); - mnNumeralShape = static_cast<sal_uInt8>(nRawNum & 0xFF); -} - -// static -SvNumberformat::LocaleType SvNumberformat::ImpGetLocaleType( - const String& rString, xub_StrLen& nPos ) -{ - sal_uInt32 nNum = 0; - sal_Unicode cToken = 0; - xub_StrLen nStart = nPos; - xub_StrLen nLen = rString.Len(); - while ( nPos < nLen && (nPos - nStart < 8) && ((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 (cToken == ']' || nPos == nLen) ? LocaleType(nNum) : LocaleType(); -} - -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 NfKeywordTable & rKeywords = 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: - { - const String aNatNum(RTL_CONSTASCII_USTRINGPARAM("NATNUM")); - 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 == rKeywords[NF_KEY_H].GetChar(0) || // H - cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M - cUpper == rKeywords[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 == rKeywords[NF_KEY_H].GetChar(0) || // H - cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M - cUpper == rKeywords[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(); - sal_uInt16 nOp1, nOp2; - SvNumberformat::LoadString( rStream, sFormatstring ); - rStream >> eType >> fLimit1 >> fLimit2 - >> nOp1 >> nOp2 >> bStandard >> bIsUsed; - NfHackConversion eHackConversion = NF_CONVERT_NONE; - sal_Bool bOldConvert = sal_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 (sal_uInt16 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; - sal_Bool bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic && - (nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND ); - sal_Bool bNewCurrencyLoaded = sal_False; - sal_Bool bNewCurrency = sal_False; - - sal_Bool bGoOn = sal_True; - while ( rHdr.BytesLeft() && bGoOn ) - { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR - sal_uInt16 nId; - rStream >> nId; - switch ( nId ) - { - case nNewCurrencyVersionId : - { - bNewCurrencyLoaded = sal_True; - rStream >> bNewCurrency; - if ( bNewCurrency ) - { - for ( sal_uInt16 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 = sal_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 ); - sal_uInt16 nNewStandard = nNewStandardDefined; - // neu parsen etc. - String aStr( sFormatstring ); - xub_StrLen nCheckPos = 0; - SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc, - nCheckPos, maLocale.meLanguage, 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, sal_True ); - break; - case NF_CONVERT_GERMAN_ENGLISH : - ConvertLanguage( *pHackConverter, - LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, sal_True ); - break; - default: - DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" ); - } - } - return eHackConversion; -} - -void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter, - LanguageType eConvertFrom, LanguageType eConvertTo, sal_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 ) - maLocale.meLanguage = LANGUAGE_SYSTEM; - // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner - for ( sal_uInt16 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 - - sal_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) - sal_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 = sal_False; - } - } - - rHdr.StartEntry(); - rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() ); - rStream << eType << fLimit1 << fLimit2 << (sal_uInt16) eOp1 << (sal_uInt16) eOp2 - << bOldStandard << bIsUsed; - for (sal_uInt16 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 ( sal_uInt16 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(); -} - -sal_Bool SvNumberformat::HasNewCurrency() const -{ - for ( sal_uInt16 j=0; j<4; j++ ) - { - if ( NumFor[j].HasNewCurrency() ) - return sal_True; - } - return sal_False; -} - -sal_Bool SvNumberformat::GetNewCurrencySymbol( String& rSymbol, - String& rExtension ) const -{ - for ( sal_uInt16 j=0; j<4; j++ ) - { - if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) ) - return sal_True; - } - rSymbol.Erase(); - rExtension.Erase(); - return sal_False; -} - -// static -String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr, - sal_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, sal_True ); -} - -void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString) -{ - sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); - - if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16 - { - nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals - OutString = ::rtl::math::doubleToUString( fNumber, - rtl_math_StringFormat_E, nStandardPrec /*2*/, - GetFormatter().GetNumDecimalSep().GetChar(0)); - } - else - ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec); -} - -void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const -{ - // Make sure the precision doesn't go over the maximum allowable precision. - nPrecision = ::std::min(UPPER_PRECISION, nPrecision); - -#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 - - // We decided to strip trailing zeros unconditionally, since binary - // double-precision rounding error makes it impossible to determine e.g. - // whether 844.10000000000002273737 is what the user has typed, or the - // user has typed 844.1 but IEEE 754 represents it that way internally. - - rOutString = ::rtl::math::doubleToUString( rNumber, - rtl_math_StringFormat_F, nPrecision /*2*/, - GetFormatter().GetNumDecimalSep().GetChar(0), true ); - if (rOutString.GetChar(0) == '-' && - rOutString.GetTokenCount('0') == rOutString.Len()) - rOutString.EraseLeadingChars('-'); // nicht -0 - - ImpTransliterate( rOutString, NumFor[0].GetNatNum() ); -} - -void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString) -{ - sal_Bool bModified = sal_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 = sal_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; - } -} - -sal_Bool SvNumberformat::GetOutputString(String& sString, - String& OutString, - Color** ppColor) -{ - OutString.Erase(); - sal_uInt16 nIx; - if (eType & NUMBERFORMAT_TEXT) - nIx = 0; - else if (NumFor[3].GetCount() > 0) - nIx = 3; - else - { - *ppColor = NULL; // no change of color - return sal_False; - } - *ppColor = NumFor[nIx].GetColor(); - const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); - if (rInfo.eScannedType == NUMBERFORMAT_TEXT) - { - sal_Bool bRes = sal_False; - const sal_uInt16 nAnz = NumFor[nIx].GetCount(); - for (sal_uInt16 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 = sal_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 sal_False; -} - -sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y) -{ - if (y == 0) - return x; - else - { - sal_uLong z = x%y; - while (z) - { - x = y; - y = z; - z = x%y; - } - return y; - } -} - -sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y) -{ - if (y == 0) - return x; - else - { - sal_uLong z = x%y; - while ((double)z/(double)y > D_EPS) - { - x = y; - y = z; - z = x%y; - } - return y; - } -} - -namespace { - -void lcl_GetOutputStringScientific( - double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString) -{ - bool bSign = ::rtl::math::isSignBitSet(fNumber); - - // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7). - sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0; - if (nPrec && bSign) - // Make room for the negative sign. - --nPrec; - - nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals. - - rOutString = ::rtl::math::doubleToUString( - fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0)); -} - -sal_Int32 lcl_GetForcedDenominator(ImpSvNumberformatInfo &rInfo, sal_uInt16 nAnz) -{ - sal_uInt16 i; - rtl::OUString aDiv; - for( i = 0; i < nAnz; i++ ) - { - if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRAC_FDIV ) - aDiv += rInfo.sStrArray[i]; - } - return aDiv.toInt32(); -} - -// TODO: More optimizations? -void lcl_ForcedDenominator(sal_uLong &nFrac, sal_uLong &nDiv, sal_uLong nForcedDiv) -{ - double fFrac = (double)nFrac / (double)nDiv; - double fMultiplier = (double)nForcedDiv / (double)nDiv; - nFrac = (sal_uLong)( (double)nFrac * fMultiplier ); - - double fFracNew = (double)nFrac / (double)nForcedDiv; - double fFracNew1 = (double)(nFrac + 1) / (double)nForcedDiv; - double fDiff = fFrac - fFracNew; - if( fDiff > ( fFracNew1 - fFrac ) ) - nFrac++; - nDiv = nForcedDiv; -} - -} - -bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const -{ - using namespace std; - - if (eType != NUMBERFORMAT_NUMBER) - return false; - - double fTestNum = fNumber; - bool bSign = ::rtl::math::isSignBitSet(fTestNum); - if (bSign) - fTestNum = -fTestNum; - - if (fTestNum < EXP_LOWER_BOUND) - { - lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); - return true; - } - - double fExp = log10(fTestNum); - // Values < 1.0 always have one digit before the decimal point. - sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1; - - if (nDigitPre > 15) - { - lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); - return true; - } - - sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0; - if (nPrec && bSign) - // Subtract the negative sign. - --nPrec; - if (nPrec) - // Subtract the decimal point. - --nPrec; - - ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec); - if (rOutString.Len() > nCharCount) - // String still wider than desired. Switch to scientific notation. - lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); - - return true; -} - -sal_Bool SvNumberformat::GetOutputString(double fNumber, - String& OutString, - Color** ppColor) -{ - sal_Bool bRes = sal_False; - OutString.Erase(); // alles loeschen - *ppColor = NULL; // keine Farbaenderung - if (eType & NUMBERFORMAT_LOGICAL) - { - if (fNumber) - OutString = rScan.GetTrueString(); - else - OutString = rScan.GetFalseString(); - return sal_False; - } - if (eType & NUMBERFORMAT_TEXT) - { - ImpGetOutputStandard(fNumber, OutString); - return sal_False; - } - sal_Bool bHadStandard = sal_False; - if (bStandard) // einzelne Standardformate - { - if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // alle Zahlformate InputLine - { - ImpGetOutputInputLine(fNumber, OutString); - return false; - } - switch (eType) - { - case NUMBERFORMAT_NUMBER: // Standardzahlformat - { - if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION) - { - bool bSign = ::rtl::math::isSignBitSet(fNumber); - if (bSign) - fNumber = -fNumber; - ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format. - if (fNumber < EXP_LOWER_BOUND) - { - xub_StrLen nLen = OutString.Len(); - if (!nLen) - return false; - - // #i112250# With the 10-decimal limit, small numbers are formatted as "0". - // Switch to scientific in that case, too: - if (nLen > 11 || (OutString.EqualsAscii("0") && fNumber != 0.0)) - { - sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); - nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals - OutString = ::rtl::math::doubleToUString( fNumber, - rtl_math_StringFormat_E, nStandardPrec /*2*/, - GetFormatter().GetNumDecimalSep().GetChar(0), true); - } - } - if (bSign) - OutString.Insert('-', 0); - return false; - } - ImpGetOutputStandard(fNumber, OutString); - bHadStandard = sal_True; - } - break; - case NUMBERFORMAT_DATE: - bRes |= ImpGetDateOutput(fNumber, 0, OutString); - bHadStandard = sal_True; - break; - case NUMBERFORMAT_TIME: - bRes |= ImpGetTimeOutput(fNumber, 0, OutString); - bHadStandard = sal_True; - break; - case NUMBERFORMAT_DATETIME: - bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString); - bHadStandard = sal_True; - break; - } - } - if ( !bHadStandard ) - { - sal_uInt16 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 sal_uInt16 nAnz = NumFor[nIx].GetCount(); - if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED) - return sal_False; // leer => nichts - else if (nAnz == 0) // sonst Standard-Format - { - ImpGetOutputStandard(fNumber, OutString); - return sal_False; - } - switch (rInfo.eScannedType) - { - case NUMBERFORMAT_TEXT: - case NUMBERFORMAT_DEFINED: - { - for (sal_uInt16 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 = sal_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 - sal_uLong nFrac, nDiv; // Vorkommaanteil - // Zaehler und Nenner - sal_Bool bSign = sal_False; - if (fNumber < 0) - { - if (nIx == 0) // nicht in hinteren - bSign = sal_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 sal_False; - } - if (rInfo.nCntExp == 0) - { - OSL_FAIL("SvNumberformat:: Bruch, nCntExp == 0"); - return sal_False; - } - sal_uLong nBasis = ((sal_uLong)floor( // 9, 99, 999 ,... - pow(10.0,rInfo.nCntExp))) - 1; - sal_uLong x0, y0, x1, y1; - - if (rInfo.nCntExp <= _MAX_FRACTION_PREC) - { - sal_Bool bUpperHalf; - if (fNumber > 0.5) - { - bUpperHalf = sal_True; - fNumber -= (fNumber - 0.5) * 2.0; - } - else - bUpperHalf = sal_False; - // Einstieg in Farey-Serie - // finden: - x0 = (sal_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; - sal_uLong nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen - x0 /= nGgt; - y0 /= nGgt; // Einschachteln: - sal_uLong x2 = 0; - sal_uLong y2 = 0; - sal_Bool bStop = sal_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 = sal_True; - } - else if (y1 == 1) - bStop = sal_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 = sal_True; // naechste Farey-Zahl - else - { - y1--; - bStop = sal_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) - { - sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl - sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0; - 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 - sal_uLong nGgt; - nDiv = 10000000; - nFrac = ((sal_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 = ((sal_uLong)floor(0.5 + fNumber * - pow(10.0,rInfo.nCntExp))); - nGgt = ImpGGTRound(nDiv, nFrac); - if (nGgt > 1) - { - nDiv /= nGgt; - nFrac /= nGgt; - } - } - } - - if( sal_Int32 nForcedDiv = lcl_GetForcedDenominator(NumFor[nIx].Info(), nAnz) ) - { - lcl_ForcedDenominator(nFrac, nDiv, nForcedDiv); - if( nFrac >= nDiv ) - { - nFrac = nDiv = 0; - fNum = fNum + 1.0; - } - } - - if (rInfo.nCntPre == 0) // unechter Bruch - { - double fNum1 = fNum * (double)nDiv + (double)nFrac; - if (fNum1 > _D_MAX_U_LONG_) - { - OutString = rScan.GetErrorString(); - return sal_False; - } - nFrac = (sal_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 ); - } - - sal_uInt16 j = nAnz-1; // letztes Symbol->rueckw. - xub_StrLen k; // Nenner: - bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC); - sal_Bool bCont = sal_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 = sal_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 = sal_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: - { - sal_Bool bSign = sal_False; - if (fNumber < 0) - { - if (nIx == 0) // nicht in hinteren - bSign = sal_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 ); - } - } - sal_uInt16 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); - - sal_Bool bCont = sal_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 = sal_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; -} - -sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber, - sal_uInt16 nIx, - String& OutString) -{ - using namespace ::com::sun::star::i18n; - sal_Bool bCalendarSet = sal_False; - double fNumberOrig = fNumber; - sal_Bool bRes = sal_False; - sal_Bool bSign = sal_False; - if (fNumber < 0.0) - { - fNumber = -fNumber; - if (nIx == 0) - bSign = sal_True; - } - const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); - if (rInfo.bThousand) // []-Format - { - if (fNumber > 1.0E10) // zu gross - { - OutString = rScan.GetErrorString(); - return sal_False; - } - } - else - fNumber -= floor(fNumber); // sonst Datum abtrennen - sal_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 = sal_True; - nCntPost = 7; - } - else - { - bInputLine = sal_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 = sal_False; // nicht -00:00:00 - - if( floor( fTime ) > _D_MAX_U_LONG_ ) - { - OutString = rScan.GetErrorString(); - return sal_False; - } - sal_uLong nSeconds = (sal_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 - sal_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 sal_uInt16 nAnz = NumFor[nIx].GetCount(); - for (sal_uInt16 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 = sal_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 = sal_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; -} - -sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const -{ - if ( GetCal().getUniqueID() != Gregorian::get() ) - return sal_False; - const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); - const sal_uInt16 nAnz = rNumFor.GetCount(); - sal_uInt16 i; - for ( i = 0; i < nAnz; i++ ) - { - switch ( rInfo.nTypeArray[i] ) - { - case NF_SYMBOLTYPE_CALENDAR : - return sal_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 sal_True; - } - } - return sal_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 ); - } -} - -sal_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 sal_True; - } - } - return sal_False; -} - -sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar, - double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const -{ - const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); - const sal_uInt16 nAnz = rNumFor.GetCount(); - for ( sal_uInt16 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 sal_True; - } - } - return sal_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 ); -} - -sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber, - sal_uInt16 nIx, - String& OutString) -{ - using namespace ::com::sun::star::i18n; - sal_Bool bRes = sal_False; - CalendarWrapper& rCal = GetCal(); - double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); - fNumber += fDiff; - rCal.setLocalDateTime( fNumber ); - String aOrgCalendar; // empty => not changed yet - double fOrgDateTime; - sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); - if ( bOtherCalendar ) - SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); - if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) - bOtherCalendar = sal_False; - const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); - const sal_uInt16 nAnz = NumFor[nIx].GetCount(); - sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); - for (sal_uInt16 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 = sal_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; -} - -sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, - sal_uInt16 nIx, - String& OutString) -{ - using namespace ::com::sun::star::i18n; - sal_Bool bRes = sal_False; - - CalendarWrapper& rCal = GetCal(); - double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); - fNumber += fDiff; - - const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); - sal_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 = sal_True; - nCntPost = 7; - } - else - { - bInputLine = sal_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; - sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); - if ( bOtherCalendar ) - SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); - if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) - bOtherCalendar = sal_False; - sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); - - sal_uLong nSeconds = (sal_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 - sal_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 sal_uInt16 nAnz = NumFor[nIx].GetCount(); - for (sal_uInt16 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 = sal_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; -} - -sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber, - sal_uInt16 nIx, - String& OutString) -{ - sal_Bool bRes = sal_False; - sal_Bool bSign; - if (fNumber < 0.0) - { - if (nIx == 0) // nicht in hinteren - bSign = sal_True; // Formaten - else - bSign = sal_False; - fNumber = -fNumber; - } - else - { - bSign = sal_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 sal_False; - } - } - sal_uInt16 i, j; - xub_StrLen k; - String sStr; - sal_Bool bInteger = sal_False; - if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT ) - { // special formatting only if no GENERAL keyword in format code - const sal_uInt16 nThousand = rInfo.nThousand; - long nPrecExp; - 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 = sal_True; - sStr.Erase( nPoint, 1 ); // . herausnehmen - } - if (bSign && - (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000 - bSign = sal_False; // nicht -0.00 - } // End of != FLAG_STANDARD_IN_FORMAT - - // von hinten nach vorn - // editieren: - k = sStr.Len(); // hinter letzter Ziffer - j = NumFor[nIx].GetCount()-1; // letztes Symbol - // Nachkommastellen: - if (rInfo.nCntPost > 0) - { - sal_Bool bTrailing = sal_True; // ob Endnullen? - sal_Bool bFilled = sal_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 = sal_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 = sal_False; - if (bTrailing) - { - if ( c == '0' ) - bFilled = sal_True; - else if ( c == '-' ) - { - if ( bInteger ) - sStr.SetChar( k, '-' ); - bFilled = sal_True; - } - else if ( c == '?' ) - { - sStr.SetChar( k, ' ' ); - bFilled = sal_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; -} - -sal_Bool SvNumberformat::ImpNumberFillWithThousands( - String& sStr, // number string - double& rNumber, // number - xub_StrLen k, // position within string - sal_uInt16 j, // symbol index within format code - sal_uInt16 nIx, // subformat index - sal_uInt16 nDigCnt) // count of integer digits in format -{ - sal_Bool bRes = sal_False; - xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number - xub_StrLen nDigitCount = 0; // count of integer digits from the right - sal_Bool bStop = sal_False; - const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); - // no normal thousands separators if number divided by thousands - sal_Bool bDoThousands = (rInfo.nThousand == 0); - utl::DigitGroupingIterator aGrouping( - GetFormatter().GetLocaleData()->getDigitGrouping()); - while (!bStop) // backwards - { - if (j == 0) - bStop = sal_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 = sal_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].GetCount()-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 - sal_uInt16 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; -} - -sal_Bool SvNumberformat::ImpNumberFill( String& sStr, // number string - double& rNumber, // number for "General" format - xub_StrLen& k, // position within string - sal_uInt16& j, // symbol index within format code - sal_uInt16 nIx, // subformat index - short eSymbolType ) // type of stop condition -{ - sal_Bool bRes = sal_False; - k = sStr.Len(); // behind last digit - const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); - // no normal thousands separators if number divided by thousands - sal_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 = sal_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].GetCount()-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; - case NF_SYMBOLTYPE_FRAC_FDIV: // Do Nothing - break; - - default: - sStr.Insert(rInfo.sStrArray[j],k); - break; - } // of switch - j--; // naechster String - } // of while - return bRes; -} - -void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand, - sal_Bool& IsRed, - sal_uInt16& nPrecision, - sal_uInt16& 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 = sal_True; - else - IsRed = sal_False; -} - -void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType, - sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& 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; - sal_Bool bStop = sal_False; - sal_uInt16 i = 0; - const sal_uInt16 nAnz = NumFor[nNumFor].GetCount(); - 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 = sal_True; - i++; - } - } -} - -const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos, - sal_Bool bString /* = sal_False */ ) const -{ - if ( nNumFor > 3 ) - return NULL; - sal_uInt16 nAnz = NumFor[nNumFor].GetCount(); - 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( sal_uInt16 nNumFor, sal_uInt16 nPos, - sal_Bool bString /* = sal_False */ ) const -{ - if ( nNumFor > 3 ) - return 0; - sal_uInt16 nAnz = NumFor[nNumFor].GetCount(); - 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]; -} - -sal_Bool SvNumberformat::IsNegativeWithoutSign() const -{ - if ( IsNegativeRealNegative() ) - { - const String* pStr = GetNumForString( 1, 0, sal_True ); - if ( pStr ) - return !HasStringNegativeSign( *pStr ); - } - return sal_False; -} - -sal_Bool SvNumberformat::IsNegativeInBracket() const -{ - sal_uInt16 nAnz = NumFor[1].GetCount(); - if (!nAnz) - return sal_False; - - String *tmpStr = NumFor[1].Info().sStrArray; - return (tmpStr[0] == '(' && tmpStr[nAnz-1] == ')' ); -} - -sal_Bool SvNumberformat::HasPositiveBracketPlaceholder() const -{ - sal_uInt16 nAnz = NumFor[0].GetCount(); - String *tmpStr = NumFor[0].Info().sStrArray; - return (tmpStr[nAnz-1].EqualsAscii( "_)" )); -} - -DateFormat SvNumberformat::GetDateOrder() const -{ - if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE ) - { - short const * const pType = NumFor[0].Info().nTypeArray; - sal_uInt16 nAnz = NumFor[0].GetCount(); - for ( sal_uInt16 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 - { - OSL_FAIL( "SvNumberformat::GetDateOrder: no date" ); - } - return rLoc().getDateFormat(); -} - -sal_uInt32 SvNumberformat::GetExactDateOrder() const -{ - sal_uInt32 nRet = 0; - if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE ) - { - OSL_FAIL( "SvNumberformat::GetExactDateOrder: no date" ); - return nRet; - } - short const * const pType = NumFor[0].Info().nTypeArray; - sal_uInt16 nAnz = NumFor[0].GetCount(); - int nShift = 0; - for ( sal_uInt16 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( sal_uInt16 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_FAIL( "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, - sal_Bool bDontQuote ) const -{ - String aStr; - sal_Bool bDefault[4]; - // 1 subformat matches all if no condition specified, - bDefault[0] = ( NumFor[1].GetCount() == 0 && eOp1 == NUMBERFORMAT_OP_NO ); - // with 2 subformats [>=0];[<0] is implied if no condition specified - bDefault[1] = ( !bDefault[0] && NumFor[2].GetCount() == 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 ); - sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2]; - // from now on bDefault[] values are used to append empty subformats at the end - bDefault[3] = sal_False; - if ( !bDefaults ) - { // conditions specified - if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO ) - bDefault[0] = bDefault[1] = sal_True; // [];x - else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO && - NumFor[2].GetCount() == 0 ) - bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True; // [];[];; - // nothing to do if conditions specified for every subformat - } - else if ( bDefault[0] ) - bDefault[0] = sal_False; // a single unconditional subformat is never delimited - else - { - if ( bDefault[2] && NumFor[2].GetCount() == 0 && NumFor[1].GetCount() > 0 ) - bDefault[3] = sal_True; // special cases x;x;; and ;x;; - for ( int i=0; i<3 && !bDefault[i]; ++i ) - bDefault[i] = sal_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; - bool LCIDInserted = false; - - 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 NfKeywordTable & rKey = rScan.GetKeywords(); - for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ ) - { - if ( rKey[j] == rColorName ) - { - aPrefix += '['; - aPrefix += rKeywords[j]; - aPrefix += ']'; - break; // for - } - } - } - - const SvNumberNatNum& rNum = NumFor[n].GetNatNum(); - - sal_uInt16 nAnz = NumFor[n].GetCount(); - if ( nSem && (nAnz || aPrefix.Len()) ) - { - for ( ; nSem; --nSem ) - aStr += ';'; - for ( ; nSub <= n; ++nSub ) - bDefault[nSub] = sal_False; - } - - if ( aPrefix.Len() ) - aStr += aPrefix; - - if ( nAnz ) - { - const short* pType = NumFor[n].Info().nTypeArray; - const String* pStr = NumFor[n].Info().sStrArray; - for ( sal_uInt16 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; - case NF_SYMBOLTYPE_CALDEL : - if ( pStr[j+1].EqualsAscii("buddhist") ) - { - aStr.InsertAscii( "[$-", 0 ); - if ( rNum.IsSet() && rNum.GetNatNum() == 1 && - MsLangId::getRealLanguage( rNum.GetLang() ) == - LANGUAGE_THAI ) - { - aStr.InsertAscii( "D07041E]", 3 ); // date in Thai digit, Buddhist era - } - else - { - aStr.InsertAscii( "107041E]", 3 ); // date in Arabic digit, Buddhist era - } - j = j+2; - } - LCIDInserted = true; - break; - default: - aStr += pStr[j]; - } - - } - } - } - // 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 && !LCIDInserted ) - { - - aStr.InsertAscii( "[$-D00041E]", 0 ); // number in Thai digit - } - } - for ( ; nSub<4 && bDefault[nSub]; ++nSub ) - { // append empty subformats - aStr += ';'; - } - return aStr; -} - -String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum, - sal_Int32 nVal, sal_uInt16 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, - sal_uInt16 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 -sal_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 sal_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 sal_True; - } while ( *p == ' ' && ++p < pEnd ); - p = pEnd - 1; - do - { // Ende - if ( *p == '-' ) - return sal_True; - } while ( *p == ' ' && pBeg < --p ); - return sal_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(); - sal_Bool bInString = sal_False; - sal_Bool bEscaped = sal_False; - sal_Bool bFound = sal_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 = sal_True; - nPos = sal::static_int_cast< xub_StrLen >( - p - rStr.GetBuffer()); - } - break; - } - if ( bEscaped && *p != '\\' ) - bEscaped = sal_False; - ++p; - } - if ( bFound ) - rStr.Erase( nPos ); -} - -// static -sal_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 sal_False; - register const sal_Unicode* p0 = rStr.GetBuffer(); - register const sal_Unicode* p = p0; - register const sal_Unicode* p1 = p0 + nPos; - sal_Bool bQuoted = sal_False; - while ( p <= p1 ) - { - if ( *p == cQuote ) - { - if ( p == p0 ) - bQuoted = sal_True; - else if ( bQuoted ) - { - if ( *(p-1) != cEscIn ) - bQuoted = sal_False; - } - else - { - if ( *(p-1) != cEscOut ) - bQuoted = sal_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 -} - -sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const -{ - sal_uInt16 nCnt = 0; - sal_uInt16 nAnz = NumFor[nNumFor].GetCount(); - short const * const pType = NumFor[nNumFor].Info().nTypeArray; - for ( sal_uInt16 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; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |