/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary... constdouble EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value. constdouble EXP_ABS_UPPER_BOUND = 1.0E15; // use exponential notation above that absolute value. // Back in time was E16 that lead // to display rounding errors, see // also sal/rtl/math.cxx // doubleToString()
constexpr sal_Int32 kTimeSignificantRound = 7; // Round (date+)time at 7 decimals // (+5 of 86400 == 12 significant digits).
const sal_Unicode cBlankDigit = 0x2007; // tdf#158890 use figure space for '?'
} // namespace
// #121103# when copying between documents, get color pointers from own scanner
ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : nullptr;
for (sal_uInt16 i = 0; i < 4; i++)
{
NumFor[i].Copy(rFormat.NumFor[i], pColorSc);
}
}
staticbool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType )
{ if ( nSymbolType > 0 )
{ returntrue; // 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 : returntrue;
} returnfalse;
}
/** Import extended LCID from Excel
*/
OUString SvNumberformat::ImpObtainCalendarAndNumerals( OUStringBuffer& rString, sal_Int32 nPos,
LanguageType& nLang, const LocaleType& aTmpLocale )
{
OUString sCalendar;
sal_uInt16 nNatNum = 0;
LanguageType nLocaleLang = MsLangId::getRealLanguage( maLocale.meLanguage );
LanguageType nTmpLocaleLang = MsLangId::getRealLanguage( aTmpLocale.meLanguage ); /* NOTE: enhancement 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 * Calendar is inserted after * all prefixes have been consumed as it is actually a format modifier * and not a prefix. * 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.
* */ switch ( aTmpLocale.mnCalendarType & 0x7F )
{ case 0x03 : // Gengou calendar // Only Japanese language support Gengou calendar. // It is an implicit "other" calendar where E, EE, R and RR // automatically switch to and YY and YYYY switch to Gregorian. Do // not add the "[~gengou]" modifier. if ( nLocaleLang != LANGUAGE_JAPANESE )
{
nLang = maLocale.meLanguage = LANGUAGE_JAPANESE;
} break; case 0x05 : // Korean Dangi calendar
sCalendar = "[~dangi]"; // Only Korean language support dangi calendar if ( nLocaleLang != LANGUAGE_KOREAN )
{
nLang = maLocale.meLanguage = LANGUAGE_KOREAN;
} break; case 0x06 : // Hijri calendar case 0x17 : // same?
sCalendar = "[~hijri]"; // Only Arabic or Farsi languages support Hijri calendar if ( ( primary( nLocaleLang ) != LANGUAGE_ARABIC_PRIMARY_ONLY )
&& nLocaleLang != LANGUAGE_FARSI )
{ if ( ( primary( nTmpLocaleLang ) == LANGUAGE_ARABIC_PRIMARY_ONLY )
|| nTmpLocaleLang == LANGUAGE_FARSI )
{
nLang = maLocale.meLanguage = aTmpLocale.meLanguage;
} else
{
nLang = maLocale.meLanguage = LANGUAGE_ARABIC_SAUDI_ARABIA;
}
} break; case 0x07 : // Buddhist calendar
sCalendar="[~buddhist]"; // Only Thai or Lao languages support Buddhist calendar if ( nLocaleLang != LANGUAGE_THAI && nLocaleLang != LANGUAGE_LAO )
{ if ( nTmpLocaleLang == LANGUAGE_THAI || nTmpLocaleLang == LANGUAGE_LAO )
{
nLang = maLocale.meLanguage = aTmpLocale.meLanguage;
} else
{
nLang = maLocale.meLanguage = LANGUAGE_THAI;
}
} break; case 0x08 : // Hebrew calendar
sCalendar = "[~jewish]"; // Many languages (but not all) support Jewish calendar // Unable to find any logic => keep same language break; case 0x0E : // unknown calendar case 0x0F : // unknown calendar case 0x10 : // Indian calendar (unsupported) case 0x11 : // unknown calendar case 0x12 : // unknown calendar case 0x13 : // unknown calendar default : // other calendars (see tdf#36038) are not handle by LibO break;
} /** Reference language for each numeral ID */ staticconst LanguageType aNumeralIDtoLanguage []=
{
LANGUAGE_DONTKNOW, // 0x00
LANGUAGE_ENGLISH_US, // 0x01
LANGUAGE_ARABIC_SAUDI_ARABIA, // 0x02 + all Arabic
LANGUAGE_FARSI, // 0x03
LANGUAGE_HINDI, // 0x04 + Devanagari
LANGUAGE_BENGALI, // 0x05
LANGUAGE_PUNJABI, // 0x06
LANGUAGE_GUJARATI, // 0x07
LANGUAGE_ODIA, // 0x08
LANGUAGE_TAMIL, // 0x09
LANGUAGE_TELUGU, // 0x0A
LANGUAGE_KANNADA, // 0x0B
LANGUAGE_MALAYALAM, // 0x0C
LANGUAGE_THAI, // 0x0D
LANGUAGE_LAO, // 0x0E
LANGUAGE_TIBETAN, // 0x0F
LANGUAGE_BURMESE, // 0x10
LANGUAGE_TIGRIGNA_ETHIOPIA, // 0x11
LANGUAGE_KHMER, // 0x12
LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA, // 0x13
LANGUAGE_DONTKNOW, // 0x14
LANGUAGE_DONTKNOW, // 0x15
LANGUAGE_DONTKNOW, // 0x16
LANGUAGE_DONTKNOW, // 0x17
LANGUAGE_DONTKNOW, // 0x18
LANGUAGE_DONTKNOW, // 0x19
LANGUAGE_DONTKNOW, // 0x1A
LANGUAGE_JAPANESE, // 0x1B
LANGUAGE_JAPANESE, // 0x1C
LANGUAGE_JAPANESE, // 0x1D
LANGUAGE_CHINESE_SIMPLIFIED, // 0x1E
LANGUAGE_CHINESE_SIMPLIFIED, // 0x1F
LANGUAGE_CHINESE_SIMPLIFIED, // 0x20
LANGUAGE_CHINESE_TRADITIONAL, // 0x21
LANGUAGE_CHINESE_TRADITIONAL, // 0x22
LANGUAGE_CHINESE_TRADITIONAL, // 0x23
LANGUAGE_KOREAN, // 0x24
LANGUAGE_KOREAN, // 0x25
LANGUAGE_KOREAN, // 0x26
LANGUAGE_KOREAN // 0x27
};
// is there a 3-letter bank code in NatNum12 param (but not // followed by an equal mark, like in the date code "NNN=")? staticbool lcl_isNatNum12Currency( std::u16string_view sParam )
{
sal_Int32 nUpper = 0;
sal_Int32 nLen = sParam.size(); for (sal_Int32 n = 0; n < nLen; ++n)
{
sal_Unicode c = sParam[n]; if ( 'A' <= c && c <= 'Z' )
{
++nUpper;
} elseif ( c == ' ' && nUpper == 3 && (n == 3 || sParam[n - 4] == ' ') )
{ returntrue;
} else
{
nUpper = 0;
}
}
// If the group (AKA thousand) separator is a No-Break Space (French) // replace all occurrences by a simple space. // The same for Narrow No-Break Space just in case some locale uses it. // The tokens will be changed to the LocaleData separator again later on. const OUString& rThSep = GetCurrentLanguageData().GetNumThousandSep(); if ( rThSep.getLength() == 1)
{ const sal_Unicode cNBSp = 0xA0; const sal_Unicode cNNBSp = 0x202F; if (rThSep[0] == cNBSp )
sBuff.replace( cNBSp, ' '); elseif (rThSep[0] == cNNBSp )
sBuff.replace( cNNBSp, ' ');
}
// 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.GetCurrentLanguageData().ChangeIntl(rScan.GetTmpLnge());
}
OUString sInsertCalendar; // a calendar resulting from parsing LCID
OUString sStr;
nPosOld = nPos; // Start position of substring // first get bracketed prefixes; e.g. conditions, color do
{
eSymbolType = ImpNextSymbol(sBuff, nPos, sStr); if (eSymbolType > 0) // condition
{ if ( nIndex == 0 && !bCondition )
{
bCondition = true;
eOp1 = static_cast<SvNumberformatLimitOps>(eSymbolType);
} elseif ( nIndex == 1 && bCondition )
{
eOp2 = static_cast<SvNumberformatLimitOps>(eSymbolType);
} else// error
{
bCancel = true; // break for
nCheckPos = nPosOld;
} if (!bCancel)
{ double fNumber;
sal_Int32 nCntChars = ImpGetNumber(sBuff, nPos, sStr); if (nCntChars > 0)
{
sal_Int32 nDecPos;
SvNumFormatType F_Type = SvNumFormatType::UNDEFINED; if (!pISc->IsNumberFormat(sStr, F_Type, fNumber, nullptr, rNatNum, SvNumInputOptions::NONE) ||
( F_Type != SvNumFormatType::NUMBER &&
F_Type != SvNumFormatType::SCIENTIFIC) )
{
fNumber = 0.0;
nPos = nPos - nCntChars;
sBuff.remove(nPos, nCntChars);
sBuff.insert(nPos, '0');
nPos++;
} elseif (rScan.GetConvertMode() && ((nDecPos = sStr.indexOf( aConvertFromDecSep)) >= 0))
{ if (aConvertToDecSep.isEmpty())
aConvertToDecSep = rScan.GetCurrentLanguageData().GetLangDecimalSep( rScan.GetNewLnge()); if (aConvertToDecSep != aConvertFromDecSep)
{ const OUString aStr( sStr.replaceAt( nDecPos,
aConvertFromDecSep.getLength(), aConvertToDecSep));
nPos = nPos - nCntChars;
sBuff.remove(nPos, nCntChars);
sBuff.insert(nPos, aStr);
nPos += aStr.getLength();
}
}
} else
{
fNumber = 0.0;
sBuff.insert(nPos++, '0');
} if (nIndex == 0)
{
fLimit1 = fNumber;
} else
{
fLimit2 = fNumber;
} if ( nPos < sBuff.getLength() && sBuff[nPos] == ']' )
{
nPos++;
} else
{
bCancel = true; // break for
nCheckPos = nPos;
}
}
nPosOld = nPos; // position before string
} elseif ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
{
OUString sSymbol( sStr); switch ( eSymbolType )
{ case BRACKET_SYMBOLTYPE_COLOR : if ( NumFor[nIndex].GetColor() != nullptr )
{ // error, more than one color
bCancel = true; // break for
nCheckPos = nPosOld;
} else
{ const Color* pColor = pSc->GetColor( sStr);
NumFor[nIndex].SetColor( pColor, sStr); if (pColor == nullptr)
{ // error
bCancel = true; // break for
nCheckPos = nPosOld;
}
} break; case BRACKET_SYMBOLTYPE_NATNUM0 : case BRACKET_SYMBOLTYPE_NATNUM1 : case BRACKET_SYMBOLTYPE_NATNUM2 : case BRACKET_SYMBOLTYPE_NATNUM3 : case BRACKET_SYMBOLTYPE_NATNUM4 : case BRACKET_SYMBOLTYPE_NATNUM5 : case BRACKET_SYMBOLTYPE_NATNUM6 : case BRACKET_SYMBOLTYPE_NATNUM7 : case BRACKET_SYMBOLTYPE_NATNUM8 : case BRACKET_SYMBOLTYPE_NATNUM9 : case BRACKET_SYMBOLTYPE_NATNUM10 : case BRACKET_SYMBOLTYPE_NATNUM11 : case BRACKET_SYMBOLTYPE_NATNUM12 : case BRACKET_SYMBOLTYPE_NATNUM13 : case BRACKET_SYMBOLTYPE_NATNUM14 : case BRACKET_SYMBOLTYPE_NATNUM15 : case BRACKET_SYMBOLTYPE_NATNUM16 : case BRACKET_SYMBOLTYPE_NATNUM17 : case BRACKET_SYMBOLTYPE_NATNUM18 : case BRACKET_SYMBOLTYPE_NATNUM19 : if ( NumFor[nIndex].GetNatNum().IsSet() )
{
bCancel = true; // break for
nCheckPos = nPosOld;
} else
{
OUString sParams;
sal_Int32 nSpacePos = sStr.indexOf(' '); if (nSpacePos >= 0)
{
sParams = o3tl::trim(sStr.subView(nSpacePos+1));
} //! eSymbolType is negative
sal_uInt8 nNum = static_cast<sal_uInt8>(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0)); if (!sParams.isEmpty() && !NatNumTakesParameters(nNum))
{
bCancel = true; // break for
nCheckPos = nPosOld; break;
}
sStr = "NatNum" + OUString::number(nNum);
NumFor[nIndex].SetNatNumNum( nNum, false ); // NatNum12 supports arguments if (nNum == 12)
{ if (sParams.isEmpty())
sParams = "cardinal"; // default NatNum12 format is "cardinal" elseif (sParams.indexOf("CURRENCY") >= 0)
sParams = sParams.replaceAll("CURRENCY",
rLoc().getCurrBankSymbol());
NumFor[nIndex].SetNatNumParams(sParams);
sStr += " " + sParams;
}
} break; case BRACKET_SYMBOLTYPE_DBNUM1 : case BRACKET_SYMBOLTYPE_DBNUM2 : case BRACKET_SYMBOLTYPE_DBNUM3 : case BRACKET_SYMBOLTYPE_DBNUM4 : case BRACKET_SYMBOLTYPE_DBNUM5 : case BRACKET_SYMBOLTYPE_DBNUM6 : case BRACKET_SYMBOLTYPE_DBNUM7 : case BRACKET_SYMBOLTYPE_DBNUM8 : case BRACKET_SYMBOLTYPE_DBNUM9 : if ( NumFor[nIndex].GetNatNum().IsSet() )
{
bCancel = true; // break for
nCheckPos = nPosOld;
} else
{ //! eSymbolType is negative
sal_uInt8 nNum = static_cast<sal_uInt8>(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1));
sStr = "DBNum" + OUStringChar(sal_Unicode('0' + nNum));
NumFor[nIndex].SetNatNumNum( nNum, true );
} break; case BRACKET_SYMBOLTYPE_LOCALE : if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW ||
sBuff[nPos-1] != ']' ) // Check also for ']' to avoid pulling in // locale data for the preview string for not // yet completed LCIDs in the dialog.
{
bCancel = true; // break for
nCheckPos = nPosOld;
} else
{
sal_Int32 nTmp = 2;
LocaleType aTmpLocale( ImpGetLocaleType( sStr, nTmp)); if (aTmpLocale.meLanguage == LANGUAGE_DONTKNOW)
{
bCancel = 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 == LANGUAGE_SYSTEM ||
SvNumberFormatter::IsLocaleInstalled( aTmpLocale.meLanguage)))
{
maLocale = aTmpLocale;
eLan = aTmpLocale.meLanguage; // return to caller
// Set new target locale also at scanner. // We have to do this because switching locale // may make replacing keywords and separators // necessary. // We can do this because it's the first // subformat and we're still at parsing the // modifiers, not keywords.
rScan.SetNewLnge( eLan); // We can not force conversion though because // the caller may have explicitly not set it. // In the usual case the target locale is the // originating locale the conversion is not // necessary, when reading alien documents // conversion is enabled anyway.
/* 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.
* */
// Strip a plain locale identifier if locale // data is available to avoid duplicated // formats with and without LCID for the same // locale. Besides it looks ugly and confusing // and is unnecessary as the format will be // listed for the resulting locale. if (aTmpLocale.isPlainLocale())
sStr.clear(); else
sStr = "$-" + aTmpLocale.generateCode();
} else
{ if (nIndex == 0) // Locale data not available, remember.
maLocale.meLanguageWithoutLocaleData = aTmpLocale.meLanguage;
// "$-NNCCLLLL" Numerals and Calendar if (sSymbol.getLength() > 6)
{
sInsertCalendar = ImpObtainCalendarAndNumerals( sBuff, 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
{
sBuff.remove(nPosOld, nPos - nPosOld); if (!sStr.isEmpty())
{
sBuff.insert(nPosOld, "[" + sStr + "]");
nPos = nPosOld + sStr.getLength() + 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
} elseif (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO)
{
eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0
} if (sStr.isEmpty())
{ // Empty sub format.
NumFor[nIndex].Info().eScannedType = SvNumFormatType::EMPTY;
} else
{ if (!sInsertCalendar.isEmpty())
{
sStr = sInsertCalendar + sStr;
}
sal_Int32 nStrPos = pSc->ScanFormat( sStr);
sal_uInt16 nCnt = pSc->GetResultStringsCnt(); if (nCnt == 0 && nStrPos == 0) // error
{
nStrPos = 1;
} if (nStrPos == 0) // ok
{ // e.g. Thai T speciality if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet())
{
sStr = "[NatNum" + OUString::number( pSc->GetNatNumModifier()) + "]" + sStr;
NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), false );
} // #i53826# #i42727# For the Thai T speciality we need // to freeze the locale and immunize it against // conversions during exports, just in case we want to // save to Xcl. This disables the feature of being able // to convert a NatNum to another locale. You can't // have both. // FIXME: implement a specialized export conversion // that works on tokens (have to tokenize all first) // and doesn't use the format string and // PutandConvertEntry() to LANGUAGE_ENGLISH_US in // sc/source/filter/excel/xestyle.cxx // XclExpNumFmtBuffer::WriteFormatRecord().
LanguageType eLanguage; if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 &&
((eLanguage = MsLangId::getRealLanguage( eLan)) == LANGUAGE_THAI) &&
NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW)
{
sStr = "[$-" + OUString::number( sal_uInt16(eLanguage), 16 ).toAsciiUpperCase() + "]" + sStr;
NumFor[nIndex].SetNatNumLang( eLanguage);
}
sBuff.remove(nPosOld, nPos - nPosOld);
sBuff.insert(nPosOld, sStr);
nPos = nPosOld + sStr.getLength(); if (nPos < sBuff.getLength())
{
sBuff.insert(nPos, ";");
nPos++;
} elseif (nIndex > 0)
{ // The last subformat. If it is a trailing text // format the omitted subformats act like they were // not specified and "inherited" the first format, // e.g. 0;@ behaves like 0;-0;0;@ if (pSc->GetScannedType() == SvNumFormatType::TEXT)
{ // Reset conditions, reverting any set above. if (nIndex == 1)
eOp1 = NUMBERFORMAT_OP_NO; elseif (nIndex == 2)
eOp2 = NUMBERFORMAT_OP_NO;
nIndex = 3;
}
}
NumFor[nIndex].Enlarge(nCnt);
pSc->CopyInfo(&(NumFor[nIndex].Info()), nCnt); // type check if (nIndex == 0)
{ if ( NumFor[nIndex].GetNatNum().GetNatNum() == 12 &&
lcl_isNatNum12Currency(NumFor[nIndex].GetNatNum().GetParams()) )
eType = SvNumFormatType::CURRENCY; else
eType = NumFor[nIndex].Info().eScannedType;
} elseif (nIndex == 3)
{ // #77026# Everything recognized IS text
NumFor[nIndex].Info().eScannedType = SvNumFormatType::TEXT;
} elseif ( NumFor[nIndex].Info().eScannedType != eType)
{
eType = SvNumFormatType::DEFINED;
}
} else
{
nCheckPos = nPosOld + nStrPos; // error in string
bCancel = true; // break for
}
}
} elseif (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error
{
nCheckPos = nPosOld;
bCancel = true;
} elseif ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
{
nCheckPos = nPosOld + 1; // error, prefix in string
bCancel = true; // break for
}
} if ( bCancel && !nCheckPos )
{
nCheckPos = 1; // nCheckPos is used as an error condition
} if ( !bCancel )
{ if ( NumFor[nIndex].GetNatNum().IsSet() &&
NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW )
{
NumFor[nIndex].SetNatNumLang( eLan );
}
} if (sBuff.getLength() == nPos)
{ if (nIndex < 3 && rString[rString.getLength()-1] == ';')
{ // A trailing ';' is significant and specifies the following // subformat to be empty. We don't enter the scanning loop // above again though. // Note that the operators apply to the current last scanned // subformat. if (nIndex == 0 && eOp1 == NUMBERFORMAT_OP_NO)
{
eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0
} elseif (nIndex == 1 && eOp2 == NUMBERFORMAT_OP_NO)
{
eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0
}
NumFor[nIndex+1].Info().eScannedType = SvNumFormatType::EMPTY; if (sBuff[nPos-1] != ';')
sBuff.insert( nPos++, ';');
} if (nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT && sBuff[nPos-1] == ';')
{ // #83510# A 4th subformat explicitly specified to be empty // hides any text. Need the type here for HasTextFormat()
NumFor[3].Info().eScannedType = SvNumFormatType::TEXT;
}
bCancel = true;
} if ( NumFor[nIndex].GetNatNum().IsSet() )
{
NumFor[nIndex].SetNatNumDate( bool(NumFor[nIndex].Info().eScannedType & SvNumFormatType::DATE) );
}
}
if (!nCheckPos && IsSubstituted())
{ // For to be substituted formats the scanned type must match the // substitute type. if (IsSystemTimeFormat())
{ if ((eType & ~SvNumFormatType::DEFINED) != SvNumFormatType::TIME)
nCheckPos = std::max<sal_Int32>( sBuff.indexOf(']') + 1, 1);
} elseif (IsSystemLongDateFormat())
{ if ((eType & ~SvNumFormatType::DEFINED) != SvNumFormatType::DATE)
nCheckPos = std::max<sal_Int32>( sBuff.indexOf(']') + 1, 1);
} else
assert(!"unhandled substitute");
}
if ( bCondition && !nCheckPos )
{ if ( nIndex == 1 && NumFor[0].GetCount() == 0 &&
sBuff[sBuff.getLength() - 1] != ';' )
{ // No format code => GENERAL but not if specified empty
OUString aAdd( pSc->GetStandardName() ); if ( !pSc->ScanFormat( aAdd ) )
{
sal_uInt16 nCnt = pSc->GetResultStringsCnt(); if ( nCnt )
{
NumFor[0].Enlarge(nCnt);
pSc->CopyInfo( &(NumFor[0].Info()), nCnt );
sBuff.append(aAdd);
}
}
} elseif ( nIndex == 1 && NumFor[nIndex].GetCount() == 0 &&
sBuff[sBuff.getLength() - 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
OUString aAdd( pSc->GetStandardName() ); if ( !pSc->ScanFormat( aAdd ) )
{
sal_uInt16 nCnt = pSc->GetResultStringsCnt(); if ( nCnt )
{
NumFor[nIndex].Enlarge(nCnt);
pSc->CopyInfo( &(NumFor[nIndex].Info()), nCnt );
sBuff.append(";" + aAdd);
}
}
} elseif ( nIndex == 2 && NumFor[nIndex].GetCount() == 0 &&
sBuff[sBuff.getLength() - 1] != ';' &&
eOp2 != NUMBERFORMAT_OP_NO )
{ // No trailing third subformat => GENERAL but not if specified empty
OUString aAdd( pSc->GetStandardName() ); if ( !pSc->ScanFormat( aAdd ) )
{
sal_uInt16 nCnt = pSc->GetResultStringsCnt(); if ( nCnt )
{
NumFor[nIndex].Enlarge(nCnt);
pSc->CopyInfo( &(NumFor[nIndex].Info()), nCnt );
sBuff.append(";" + aAdd);
}
}
}
}
rString = sBuff.makeStringAndClear();
sFormatstring = rString;
if (NumFor[2].GetCount() == 0 && // No third partial string
eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO &&
fLimit1 == 0.0 && fLimit2 == 0.0)
{
eOp1 = NUMBERFORMAT_OP_GE; // Add 0 to the first format
}
}
SvNumberformat::~SvNumberformat()
{
}
/** * Next_Symbol * * Splits up the symbols for further processing (by the Turing machine) * * Start state = SsStart, * = Special state * ---------------+-------------------+----------------------------+--------------- * Old State | Symbol read | Event | New state * ---------------+-------------------+----------------------------+--------------- * SsStart | " | Symbol += Character | SsGetQuoted * | ; | Pos-- | SsGetString * | [ | Symbol += Character | SsGetBracketed * | ] | Error | SsStop * | BLANK | | * | Else | Symbol += Character | SsGetString * ---------------+-------------------+----------------------------+--------------- * SsGetString | " | Symbol += Character | SsGetQuoted * | ; | | SsStop * | Else | Symbol += Character | * ---------------+-------------------+----------------------------+--------------- * SsGetQuoted | " | Symbol += Character | SsGetString * | Else | Symbol += Character | * ---------------+-------------------+----------------------------+--------------- * SsGetBracketed | <, > = | del [ | * | | Symbol += Character | SsGetCon * | BLANK | | * | h, H, m, M, s, S | Symbol += Character | SsGetTime * | Else | del [ | * | | Symbol += Character | SsGetPrefix * ---------------+-------------------+----------------------------+--------------- * SsGetTime | ] | Symbol += Character | SsGetString * | h, H, m, M, s, S | Symbol += Character, * | SsGetString * | Else | del [; Symbol += Character | SsGetPrefix * ---------------+-------------------+----------------------------+--------------- * SsGetPrefix | ] | | SsStop * | Else | Symbol += Character | * ---------------+-------------------+----------------------------+--------------- * SsGetCon | >, = | Symbol += Character | * | ] | | SsStop * | Else | Error | SsStop * ---------------+-------------------+----------------------------+---------------
*/
namespace {
enum ScanState
{
SsStop,
SsStart,
SsGetCon, // condition
SsGetString, // format string
SsGetPrefix, // color or NatNumN
SsGetTime, // [HH] for time
SsGetBracketed, // any [...] not decided yet
SsGetQuoted // quoted text
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.