summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <ooo@erack.de>2011-08-04 23:43:19 +0200
committerEike Rathke <ooo@erack.de>2011-08-05 12:35:58 +0200
commitfbe916fd7dc7ba22b8652bc0c5b8a0d9cb15cc9d (patch)
tree1580098b93376bff484ae80cdfa3e361459a6be0
parent7d20dd760a1c9a67f3f0b34a4689323b1200a5f6 (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.
-rw-r--r--svl/inc/svl/zforlist.hxx20
-rw-r--r--svl/inc/svl/zformat.hxx16
-rw-r--r--svl/source/numbers/zforlist.cxx2
-rw-r--r--svl/source/numbers/zformat.cxx152
4 files changed, 152 insertions, 38 deletions
diff --git a/svl/inc/svl/zforlist.hxx b/svl/inc/svl/zforlist.hxx
index 6b07356219..d1519ea3de 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,6 +804,20 @@ 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;
::com::sun::star::lang::Locale aLocale;
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 1ed6b7597a..59bbe8737a 100644
--- a/svl/source/numbers/zforlist.cxx
+++ b/svl/source/numbers/zforlist.cxx
@@ -195,6 +195,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,
@@ -3627,6 +3628,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 b567c20699..69b3e1762f 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,
@@ -636,7 +676,6 @@ SvNumberformat::SvNumberformat(String& rString,
sal_Bool bCancel = sal_False;
sal_Bool bCondition = sal_False;
- sal_Bool bHasValidBracketPrefix = sal_False;
short eSymbolType;
xub_StrLen nPos = 0;
xub_StrLen nPosOld;
@@ -651,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
@@ -710,6 +750,7 @@ SvNumberformat::SvNumberformat(String& rString,
}
else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
{
+ String sSymbol( sStr);
switch ( eSymbolType )
{
case BRACKET_SYMBOLTYPE_COLOR :
@@ -728,8 +769,6 @@ SvNumberformat::SvNumberformat(String& rString,
bCancel = sal_True; // break for
nCheckPos = nPosOld;
}
- else
- bHasValidBracketPrefix = sal_True;
}
}
break;
@@ -766,7 +805,6 @@ SvNumberformat::SvNumberformat(String& rString,
sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0));
sStr += String::CreateFromInt32( nNum );
NumFor[nIndex].SetNatNumNum( nNum, sal_False );
- bHasValidBracketPrefix = sal_True;
}
}
break;
@@ -792,13 +830,16 @@ SvNumberformat::SvNumberformat(String& rString,
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 );
- bHasValidBracketPrefix = sal_True;
}
}
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;
@@ -806,18 +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);
- bHasValidBracketPrefix = sal_True;
+ 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. */
}
}
}
@@ -825,19 +898,24 @@ SvNumberformat::SvNumberformat(String& rString,
}
if ( !bCancel )
{
- rString.Erase(nPosOld,nPos-nPosOld);
- if ( bHasValidBracketPrefix )
- {
- 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
+ }
}
}
}
@@ -857,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
@@ -1136,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;
}
}
@@ -1147,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;
}
}
@@ -1157,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;
}
@@ -1189,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' )
{
@@ -1212,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,
@@ -1296,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;