diff options
author | Eike Rathke <ooo@erack.de> | 2011-08-04 23:43:19 +0200 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2011-08-05 12:18:42 +0100 |
commit | 14a83b892ead65acf16d566e2b69c2e8dd75d617 (patch) | |
tree | 32b43109e7b6e28cec18ce42a8ea56c07406c017 | |
parent | 9ee1d8454294375954c8407943ce64b09b573789 (diff) |
Fix fdo#38956 discarding bracketed prefixes in number formats, such as [RED]
* Fixed discarding of prefixes.
* Fixed the broken handling of Thai calendar and numerals speciality.
* Added bits to actually display a format with embedded LCID in the dialog if
the LCID doesn't match the currently viewed locale.
(cherry picked from commit fbe916fd7dc7ba22b8652bc0c5b8a0d9cb15cc9d)
Conflicts:
svl/inc/svl/zforlist.hxx
svl/source/numbers/zformat.cxx
-rw-r--r-- | svl/inc/svl/zforlist.hxx | 18 | ||||
-rw-r--r-- | svl/inc/svl/zformat.hxx | 16 | ||||
-rw-r--r-- | svl/source/numbers/zforlist.cxx | 2 | ||||
-rw-r--r-- | svl/source/numbers/zformat.cxx | 146 |
4 files changed, 147 insertions, 35 deletions
diff --git a/svl/inc/svl/zforlist.hxx b/svl/inc/svl/zforlist.hxx index eef1904424..303b55ef33 100644 --- a/svl/inc/svl/zforlist.hxx +++ b/svl/inc/svl/zforlist.hxx @@ -42,6 +42,7 @@ #include <svl/nfkeytab.hxx> #include <map> +#include <set> class Date; class SvStream; @@ -225,6 +226,8 @@ typedef Table SvNumberFormatterIndexTable; typedef ::std::map< sal_uInt32, sal_uInt32 > SvNumberFormatterMergeMap; +typedef ::std::set< LanguageType > NfInstalledLocales; + /** Language/country dependent currency entries */ @@ -343,6 +346,9 @@ public: */ static const sal_uInt16 INPUTSTRING_PRECISION; + /** THE set of installed locales. */ + static NfInstalledLocales theInstalledLocales; + /// Preferred ctor with service manager and language/country enum SvNumberFormatter( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xSMgr, @@ -798,9 +804,15 @@ public: language/country, used in XML import */ String GetStandardName( LanguageType eLnge ); - /// Skip a NumberFormatter in stream, Chart needs this - static void SkipNumberFormatterInStream( SvStream& ); - + /** Check if a specific locale has supported locale data. */ + static bool IsLocaleInstalled( LanguageType eLang ) + { + // The set is initialized as a side effect of the currency table + // created, make sure that exists, which usually is the case unless a + // SvNumberFormatter was never instanciated. + GetTheCurrencyTable(); + return theInstalledLocales.find( eLang) != theInstalledLocales.end(); + } private: ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager; diff --git a/svl/inc/svl/zformat.hxx b/svl/inc/svl/zformat.hxx index bb43932731..82a6046796 100644 --- a/svl/inc/svl/zformat.hxx +++ b/svl/inc/svl/zformat.hxx @@ -529,6 +529,22 @@ private: */ SVL_DLLPRIVATE static LocaleType ImpGetLocaleType( const String& rString, xub_StrLen& nPos ); + /** Obtain calendar and numerals from a LocaleType that was parsed from a + LCID with ImpGetLocaleType(). + + Inserts a NatNum modifier to rString at nPos if needed as determined + from the numeral code. + + @ATTENTION: may modify <member>maLocale</member> to make it follow + aTmpLocale, in which case also nLang is adapted. + + @returns a string with the calendar if one was determined from the + calendar code, else an empty string. The calendar string needs to be + inserted at a proper positon to rString after all bracketed prefixes. + */ + SVL_DLLPRIVATE String ImpObtainCalendarAndNumerals( String & rString, + xub_StrLen & nPos, LanguageType & nLang, const LocaleType & aTmpLocale ); + // standard number output SVL_DLLPRIVATE void ImpGetOutputStandard( double& fNumber, String& OutString ); SVL_DLLPRIVATE void ImpGetOutputStdToPrecision( double& rNumber, String& rOutString, sal_uInt16 nPrecision ) const; diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx index 2a62b2bdd7..88e50084ae 100644 --- a/svl/source/numbers/zforlist.cxx +++ b/svl/source/numbers/zforlist.cxx @@ -181,6 +181,7 @@ SV_IMPL_PTRARR( NfWSStringsDtor, String* ); const sal_uInt16 SvNumberFormatter::UNLIMITED_PRECISION = ::std::numeric_limits<sal_uInt16>::max(); const sal_uInt16 SvNumberFormatter::INPUTSTRING_PRECISION = ::std::numeric_limits<sal_uInt16>::max()-1; +NfInstalledLocales SvNumberFormatter::theInstalledLocales; SvNumberFormatter::SvNumberFormatter( const Reference< XMultiServiceFactory >& xSMgr, @@ -3678,6 +3679,7 @@ void SvNumberFormatter::ImpInitCurrencyTable() { LanguageType eLang = MsLangId::convertLocaleToLanguage( pLocales[nLocale]); + theInstalledLocales.insert( eLang); pLocaleData->setLocale( pLocales[nLocale] ); Sequence< Currency2 > aCurrSeq = pLocaleData->getAllCurrencies(); sal_Int32 nCurrencyCount = aCurrSeq.getLength(); diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx index eff1a1c72a..a0570eeb11 100644 --- a/svl/source/numbers/zformat.cxx +++ b/svl/source/numbers/zformat.cxx @@ -595,6 +595,46 @@ sal_Bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType ) 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, @@ -650,6 +690,7 @@ SvNumberformat::SvNumberformat(String& rString, 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 @@ -709,6 +750,7 @@ SvNumberformat::SvNumberformat(String& rString, } else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) { + String sSymbol( sStr); switch ( eSymbolType ) { case BRACKET_SYMBOLTYPE_COLOR : @@ -793,7 +835,11 @@ SvNumberformat::SvNumberformat(String& rString, break; case BRACKET_SYMBOLTYPE_LOCALE : { - if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW ) + 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; @@ -801,17 +847,50 @@ SvNumberformat::SvNumberformat(String& rString, else { xub_StrLen nTmp = 2; - maLocale = ImpGetLocaleType( sStr, nTmp ); - if (maLocale.meLanguage == LANGUAGE_DONTKNOW) + LocaleType aTmpLocale( ImpGetLocaleType( sStr, nTmp)); + if (aTmpLocale.meLanguage == LANGUAGE_DONTKNOW) { bCancel = sal_True; // break for nCheckPos = nPosOld; } - else if (maLocale.meLanguage != 0) + 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 = sStr + maLocale.generateCode(); - NumFor[nIndex].SetNatNumLang(maLocale.meLanguage); + 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. */ } } } @@ -819,19 +898,24 @@ SvNumberformat::SvNumberformat(String& rString, } if ( !bCancel ) { - rString.Erase(nPosOld,nPos-nPosOld); - if (maLocale.meLanguage != 0) - { - rString.Insert(sStr,nPosOld); - nPos = nPosOld + sStr.Len(); - rString.Insert(']', nPos); - rString.Insert('[', nPosOld); - nPos += 2; - nPosOld = nPos; // position before string - } + if (sStr == sSymbol) + nPosOld = nPos; else { - nPos = nPosOld; // Excel LCID removed + 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 + } } } } @@ -851,6 +935,9 @@ SvNumberformat::SvNumberformat(String& rString, } else { + if (sInsertCalendar.Len()) + sStr.Insert( sInsertCalendar, 0); + xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment ); sal_uInt16 nAnz = pSc->GetAnzResStrings(); if (nAnz == 0) // error @@ -1130,7 +1217,8 @@ OUString SvNumberformat::LocaleType::generateCode() const for (sal_uInt8 i = 0; i < 2; ++i) { sal_uInt8 n = (nVal & 0xF0) >> 4; - aBuf.append(toUniChar(n)); + if (n || aBuf.getLength()) + aBuf.append(toUniChar(n)); nVal = nVal << 4; } } @@ -1141,7 +1229,8 @@ OUString SvNumberformat::LocaleType::generateCode() const for (sal_uInt8 i = 0; i < 2; ++i) { sal_uInt8 n = (nVal & 0xF0) >> 4; - aBuf.append(toUniChar(n)); + if (n || aBuf.getLength()) + aBuf.append(toUniChar(n)); nVal = nVal << 4; } } @@ -1151,7 +1240,9 @@ OUString SvNumberformat::LocaleType::generateCode() const for (sal_uInt8 i = 0; i < 4; ++i) { sal_uInt8 n = static_cast<sal_uInt8>((n16 & 0xF000) >> 12); - aBuf.append(toUniChar(n)); + // Omit leading zeros for consistency. + if (n || aBuf.getLength() || i == 3) + aBuf.append(toUniChar(n)); n16 = n16 << 4; } @@ -1183,8 +1274,9 @@ SvNumberformat::LocaleType SvNumberformat::ImpGetLocaleType( { sal_uInt32 nNum = 0; sal_Unicode cToken = 0; + xub_StrLen nStart = nPos; xub_StrLen nLen = rString.Len(); - while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') ) + while ( nPos < nLen && (nPos - nStart < 8) && ((cToken = rString.GetChar(nPos)) != ']') ) { if ( '0' <= cToken && cToken <= '9' ) { @@ -1206,7 +1298,7 @@ SvNumberformat::LocaleType SvNumberformat::ImpGetLocaleType( ++nPos; } - return (nNum && (cToken == ']' || nPos == nLen)) ? LocaleType(nNum) : LocaleType(); + return (cToken == ']' || nPos == nLen) ? LocaleType(nNum) : LocaleType(); } short SvNumberformat::ImpNextSymbol(String& rString, @@ -1290,16 +1382,6 @@ short SvNumberformat::ImpNextSymbol(String& rString, { if ( rString.GetChar(nPos) == '-' ) { // [$-xxx] locale - if ( rString.GetChar(nPos+2) == '0' && rString.GetChar(nPos+3) == '7' ) // calendar type code "07" = Thai - { - rString.InsertAscii( "[~buddhist]", nPos+9 ); - nLen += 11; - } - if ( rString.GetChar(nPos+1) == 'D' ) // numeral shape code "D" = Thai digits - { - rString.InsertAscii( "[NatNum1]", nPos+9 ); - nLen += 9; - } sSymbol.EraseAllChars('['); eSymbolType = BRACKET_SYMBOLTYPE_LOCALE; eState = SsGetPrefix; |