1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "svl/svldllapi.h"
23 #include <rtl/ustrbuf.hxx>
24 #include <rtl/ustring.hxx>
25 #include <tools/string.hxx>
26 #include <i18nlangtag/lang.h>
27 #include <com/sun/star/uno/Reference.hxx>
28 #include <com/sun/star/lang/Locale.hpp>
29 #include <com/sun/star/i18n/NumberFormatCode.hpp>
30 #include <unotools/localedatawrapper.hxx>
31 #include <unotools/numberformatcodewrapper.hxx>
32 #include <tools/link.hxx>
33 #include <svl/ondemand.hxx>
34 #include <svl/nfkeytab.hxx>
38 #include <boost/ptr_container/ptr_vector.hpp>
44 class CalendarWrapper
;
46 class ImpSvNumberformatScan
;
47 class ImpSvNumberInputScan
;
50 namespace com
{ namespace sun
{ namespace star
{
52 class XComponentContext
;
56 #define SV_COUNTRY_LANGUAGE_OFFSET 10000 // Max count of formats per country/language
57 #define SV_MAX_ANZ_STANDARD_FORMATE 100 // Max count of builtin default formats per CL
60 #ifndef NUMBERFORMAT_ALL
61 // also defined in com/sun/star/util/NumberFormat.hpp
62 //! => put in single .idl file and include here
63 #define NUMBERFORMAT_ALL 0x000 /// Just for Output of total list, not a real format type
64 #define NUMBERFORMAT_DEFINED 0x001 /// Format defined by user
65 #define NUMBERFORMAT_DATE 0x002 /// Number as date
66 #define NUMBERFORMAT_TIME 0x004 /// Number as time
67 #define NUMBERFORMAT_CURRENCY 0x008 /// Number as currency
68 #define NUMBERFORMAT_NUMBER 0x010 /// Any "normal" number format
69 #define NUMBERFORMAT_SCIENTIFIC 0x020 /// Number as scientific
70 #define NUMBERFORMAT_FRACTION 0x040 /// Number as fraction
71 #define NUMBERFORMAT_PERCENT 0x080 /// Number as percent
72 #define NUMBERFORMAT_TEXT 0x100 /// Text format
73 #define NUMBERFORMAT_DATETIME 0x006 /// Number as date and time
74 #define NUMBERFORMAT_LOGICAL 0x400 /// Number as boolean value
75 #define NUMBERFORMAT_UNDEFINED 0x800 /// Format undefined yet in analyzing
77 #define NUMBERFORMAT_ENTRY_NOT_FOUND (sal_uInt32)(0xffffffff) /// MAX_ULONG
80 /** enum values for <method>SvNumberFormatter::GetFormatIndex</method>
83 Builtin standard formats, order should be also the arrangement in the
84 dialog list box representation.</p>
88 <li>SYSTEM: As set in System Regional Settings.
89 <li>SYS: short/long defined, order and separators from System Regional Settings.
90 <li>DEF: short/long and order defined, separators from System Regional Settings.
91 <li>DIN: all settings hard coded as DIN (Deutsche Industrie Norm) and EN (European Norm) require.
92 <li>all other: hard coded
95 Do NOT insert any new values!
96 The values here correspond with those in offapi/com/sun/star/i18n/NumberFormatIndex.idl
98 enum NfIndexTableOffset
100 NF_NUMERIC_START
= 0,
102 NF_NUMBER_START
= NF_NUMERIC_START
,
103 NF_NUMBER_STANDARD
= NF_NUMBER_START
, // Standard/General
105 NF_NUMBER_DEC2
, // 0.00
106 NF_NUMBER_1000INT
, // #,##0
107 NF_NUMBER_1000DEC2
, // #,##0.00
108 NF_NUMBER_SYSTEM
, // #,##0.00 or whatever is set in System Regional Settings
109 NF_NUMBER_END
= NF_NUMBER_SYSTEM
,
112 NF_SCIENTIFIC_000E000
= NF_SCIENTIFIC_START
, // 0.00E+000
113 NF_SCIENTIFIC_000E00
, // 0.00E+00
114 NF_SCIENTIFIC_END
= NF_SCIENTIFIC_000E00
,
117 NF_PERCENT_INT
= NF_PERCENT_START
, // 0%
118 NF_PERCENT_DEC2
, // 0.00%
119 NF_PERCENT_END
= NF_PERCENT_DEC2
,
122 NF_FRACTION_1
= NF_FRACTION_START
, // # ?/?
123 NF_FRACTION_2
, // # ??/??
124 NF_FRACTION_END
= NF_FRACTION_2
,
126 NF_NUMERIC_END
= NF_FRACTION_END
,
129 NF_CURRENCY_1000INT
= NF_CURRENCY_START
,// #,##0 DM
130 NF_CURRENCY_1000DEC2
, // #,##0.00 DM
131 NF_CURRENCY_1000INT_RED
, // #,##0 DM negative in red
132 NF_CURRENCY_1000DEC2_RED
, // #,##0.00 DM negative in red
133 NF_CURRENCY_1000DEC2_CCC
, // #,##0.00 DEM currency abbreviation
134 NF_CURRENCY_1000DEC2_DASHED
, // #,##0.-- DM
135 NF_CURRENCY_END
= NF_CURRENCY_1000DEC2_DASHED
,
138 NF_DATE_SYSTEM_SHORT
= NF_DATE_START
, // 08.10.97
139 NF_DATE_SYSTEM_LONG
, // Wednesday, 8. October 1997
140 NF_DATE_SYS_DDMMYY
, // 08.10.97
141 NF_DATE_SYS_DDMMYYYY
, // 08.10.1997
142 NF_DATE_SYS_DMMMYY
, // 8. Oct 97
143 NF_DATE_SYS_DMMMYYYY
, // 8. Oct 1997
144 NF_DATE_DIN_DMMMYYYY
, // 8. Oct. 1997 DIN
145 NF_DATE_SYS_DMMMMYYYY
, // 8. October 1997
146 NF_DATE_DIN_DMMMMYYYY
, // 8. October 1997 DIN
147 NF_DATE_SYS_NNDMMMYY
, // Wed, 8. Okt 97
148 NF_DATE_DEF_NNDDMMMYY
, // Wed 08.Okt 97
149 NF_DATE_SYS_NNDMMMMYYYY
, // Wed, 8. Oktober 1997
150 NF_DATE_SYS_NNNNDMMMMYYYY
, // Wednesday, 8. Oktober 1997
151 NF_DATE_DIN_MMDD
, // 10-08 DIN
152 NF_DATE_DIN_YYMMDD
, // 97-10-08 DIN
153 NF_DATE_DIN_YYYYMMDD
, // 1997-10-08 DIN
154 NF_DATE_SYS_MMYY
, // 10.97
155 NF_DATE_SYS_DDMMM
, // 08.Oct
156 NF_DATE_MMMM
, // October
157 NF_DATE_QQJJ
, // 4. Quarter 97
158 NF_DATE_WW
, // week of year
159 NF_DATE_END
= NF_DATE_WW
,
162 NF_TIME_HHMM
= NF_TIME_START
, // HH:MM
163 NF_TIME_HHMMSS
, // HH:MM:SS
164 NF_TIME_HHMMAMPM
, // HH:MM AM/PM
165 NF_TIME_HHMMSSAMPM
, // HH:MM:SS AM/PM
166 NF_TIME_HH_MMSS
, // [HH]:MM:SS
167 NF_TIME_MMSS00
, // MM:SS,00
168 NF_TIME_HH_MMSS00
, // [HH]:MM:SS,00
169 NF_TIME_END
= NF_TIME_HH_MMSS00
,
172 NF_DATETIME_SYSTEM_SHORT_HHMM
= NF_DATETIME_START
, // 08.10.97 01:23
173 NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, // 08.10.1997 01:23:45
174 NF_DATETIME_END
= NF_DATETIME_SYS_DDMMYYYY_HHMMSS
,
176 NF_BOOLEAN
, // BOOLEAN
179 NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
, // old number of predefined entries, locale data additions start after this
181 // From here on are values of new built-in formats that are not in the
182 // original NumberFormatIndex.idl
184 NF_FRACTION_3
= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
, // # ?/4
185 NF_FRACTION_4
, // # ?/100
187 NF_INDEX_TABLE_ENTRIES
191 // #45717# IsNumberFormat( "98-10-24", 30, x ), YMD Format set with DMY
192 // International settings doesn't recognize the string as a date.
193 /** enum values for <method>SvNumberFormatter::SetEvalDateFormat</method>
195 <p>How <method>ImpSvNumberInputScan::GetDateRef</method> shall take the
196 DateFormat order (YMD,DMY,MDY) into account, if called from IsNumberFormat
197 with a date format to match against.
199 enum NfEvalDateFormat
201 /** DateFormat only from International, default. */
202 NF_EVALDATEFORMAT_INTL
,
204 /** DateFormat only from date format passed to function (if any).
205 If no date format is passed then the DateFormat is taken from International. */
206 NF_EVALDATEFORMAT_FORMAT
,
208 /** First try the DateFormat from International. If it doesn't match a
209 valid date try the DateFormat from the date format passed. */
210 NF_EVALDATEFORMAT_INTL_FORMAT
,
212 /** First try the DateFormat from the date format passed. If it doesn't
213 match a valid date try the DateFormat from International. */
214 NF_EVALDATEFORMAT_FORMAT_INTL
218 typedef std::map
<sal_uInt32
, SvNumberformat
*> SvNumberFormatTable
;
219 typedef std::map
<sal_uInt16
, sal_uInt32
> SvNumberFormatterIndexTable
;
221 typedef ::std::map
< sal_uInt32
, sal_uInt32
> SvNumberFormatterMergeMap
;
223 typedef ::std::set
< LanguageType
> NfInstalledLocales
;
226 /** Language/country dependent currency entries
228 class SVL_DLLPUBLIC NfCurrencyEntry
230 OUString aSymbol
; /// currency symbol
231 OUString aBankSymbol
; /// currency abbreviation
232 LanguageType eLanguage
; /// language/country value
233 sal_uInt16 nPositiveFormat
; /// position of symbol
234 sal_uInt16 nNegativeFormat
; /// position of symbol and type and position of negative sign
235 sal_uInt16 nDigits
; /// count of decimal digits
236 sal_Unicode cZeroChar
; /// which character is used for zeros as last decimal digits
238 /// not implemented, prevent usage
239 NfCurrencyEntry( const NfCurrencyEntry
& );
240 /// not implemented, prevent usage
241 NfCurrencyEntry
& operator=( const NfCurrencyEntry
& );
245 // nDecimalFormat := 0, 1, 2
246 // #,##0 or #,##0.00 or #,##0.-- is returned
247 SVL_DLLPRIVATE OUString
Impl_BuildFormatStringNumChars( const LocaleDataWrapper
&, sal_uInt16 nDecimalFormat
) const;
251 NfCurrencyEntry( const LocaleDataWrapper
& rLocaleData
,
252 LanguageType eLang
);
253 NfCurrencyEntry( const ::com::sun::star::i18n::Currency
& rCurr
,
254 const LocaleDataWrapper
& rLocaleData
,
255 LanguageType eLang
);
256 ~NfCurrencyEntry() {}
258 /// Symbols and language identical
259 bool operator==( const NfCurrencyEntry
& r
) const;
261 const OUString
& GetSymbol() const { return aSymbol
; }
262 const OUString
& GetBankSymbol() const { return aBankSymbol
; }
263 LanguageType
GetLanguage() const { return eLanguage
; }
264 sal_uInt16
GetPositiveFormat() const { return nPositiveFormat
; }
265 sal_uInt16
GetNegativeFormat() const { return nNegativeFormat
; }
266 sal_uInt16
GetDigits() const { return nDigits
; }
267 sal_Unicode
GetZeroChar() const { return cZeroChar
; }
269 /** [$DM-407] (bBank==false) or [$DEM] (bBank==true)
270 is returned. If bBank==false and
271 bWithoutExtension==true only [$DM] */
272 OUString
BuildSymbolString(bool bBank
, bool bWithoutExtension
= false) const;
274 /** #,##0.00 [$DM-407] is returned, separators
275 from rLoc, incl. minus sign but without [RED] */
276 OUString
BuildPositiveFormatString(bool bBank
, const LocaleDataWrapper
&,
277 sal_uInt16 nDecimalFormat
= 1) const;
278 OUString
BuildNegativeFormatString(bool bBank
, const LocaleDataWrapper
&,
279 sal_uInt16 nDecimalFormat
= 1) const;
281 /** [$DM-407] (or [$DEM] if bBank==true)
282 is appended/prepended to rStr, incl. minus sign */
283 void CompletePositiveFormatString(OUStringBuffer
& rStr
, bool bBank
,
284 sal_uInt16 nPosiFormat
) const;
285 void CompleteNegativeFormatString(OUStringBuffer
& rStr
, bool bBank
,
286 sal_uInt16 nNegaFormat
) const;
288 /// rSymStr is appended/prepended to rStr, incl. minus sign
289 static void CompletePositiveFormatString(OUStringBuffer
& rStr
,
290 const OUString
& rSymStr
, sal_uInt16 nPosiFormat
);
291 static void CompleteNegativeFormatString(OUStringBuffer
& rStr
,
292 const OUString
& rSymStr
, sal_uInt16 nNegaFormat
);
294 /** Representation of a currency (symbol position and
295 negative sign) in other language settings */
296 static sal_uInt16
GetEffectivePositiveFormat( sal_uInt16 nIntlFormat
,
297 sal_uInt16 nCurrFormat
, bool bBank
);
298 static sal_uInt16
GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat
,
299 sal_uInt16 nCurrFormat
, bool bBank
);
301 /// General Unicode Euro symbol
302 static inline sal_Unicode
GetEuroSymbol() { return sal_Unicode(0x20AC); }
303 /** Platform and CharSet dependent Euro symbol,
304 needed for import/export */
305 static sal_Char
GetEuroSymbol( rtl_TextEncoding eTextEncoding
);
308 typedef boost::ptr_vector
<NfCurrencyEntry
> NfCurrencyTable
;
310 typedef std::vector
< OUString
> NfWSStringsDtor
;
312 class SvNumberFormatterRegistry_Impl
;
314 class SVL_DLLPUBLIC SvNumberFormatter
318 * We can't technically have an "infinite" value, so we use an arbitrary
319 * upper precision threshold to represent the "unlimited" precision.
321 static const sal_uInt16 UNLIMITED_PRECISION
;
324 * Precision suitable for numbers displayed in input bar, for instance
325 * Calc's formula input bar.
327 static const sal_uInt16 INPUTSTRING_PRECISION
;
329 /// Preferred ctor with service manager and language/country enum
331 const ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XComponentContext
>& rxContext
,
335 ~SvNumberFormatter();
337 /// Set CallBack to ColorTable
338 void SetColorLink( const Link
& rColorTableCallBack
) { aColorLink
= rColorTableCallBack
; }
339 /// Do the CallBack to ColorTable
340 Color
* GetUserDefColor(sal_uInt16 nIndex
);
342 /// Change language/country, also input and format scanner
343 void ChangeIntl( LanguageType eLnge
);
344 /// Change the reference null date
345 void ChangeNullDate(sal_uInt16 nDay
, sal_uInt16 nMonth
, sal_uInt16 nYear
);
346 /// Change standard precision
347 void ChangeStandardPrec(short nPrec
);
348 /// Set zero value suppression
349 void SetNoZero(bool bNZ
) { bNoZero
= bNZ
; }
351 /** The language with which the formatter was initialized (system setting),
352 NOT the current language after a ChangeIntl() */
353 LanguageType
GetLanguage() const { return IniLnge
; }
355 // Determine whether two format types are input compatible or not
356 bool IsCompatible(short eOldType
, short eNewType
);
358 /** Get table of formats of a specific type of a locale. A format FIndex is
359 tested whether it has the type and locale requested, if it doesn't
360 match FIndex returns the default format for the type/locale. If no
361 specific format is to be selected FIndex may be initialized to 0. */
362 SvNumberFormatTable
& GetEntryTable(short eType
,
366 /** Get table of formats of a specific type of a language/country.
367 FIndex returns the default format of that type.
368 If the language/country was never touched before new entries are generated */
369 SvNumberFormatTable
& ChangeCL(short eType
,
373 /** Get table of formats of the same type as FIndex; eType and rLnge are
374 set accordingly. An unknown format is set to Standard/General */
375 SvNumberFormatTable
& GetFirstEntryTable(short& eType
,
377 LanguageType
& rLnge
);
379 /// Delete an entry including the format it is refering to
380 void DeleteEntry(sal_uInt32 nKey
);
382 /** Create new entry of a format code string for language/country.
384 <TRUE/> if string new and ok and inserted.
385 <FALSE/> if string already exists or an unresolvable parse error
386 occurred, in which case nCheckPos is the error position within rString.
387 If the error occurs at position 0 or rString is empty nCheckPos
388 will be 1, so an error in the string is always indicated by
389 nCheckPos not being zero.
390 The content of the rString variable can be changed and corrected
392 nType contains the type of the format.
393 nKey contains the index key of the format.
395 bool PutEntry( OUString
& rString
, sal_Int32
& nCheckPos
, short& nType
, sal_uInt32
& nKey
,
396 LanguageType eLnge
= LANGUAGE_DONTKNOW
);
398 /** Same as <method>PutEntry</method> but the format code string is
399 considered to be of language/country eLnge and is converted to
400 language/country eNewLnge */
401 bool PutandConvertEntry( OUString
& rString
, sal_Int32
& nCheckPos
,
402 short& nType
, sal_uInt32
& nKey
,
403 LanguageType eLnge
, LanguageType eNewLnge
);
405 /** Same as <method>PutandConvertEntry</method> but the format code string
406 is considered to be of the System language/country eLnge and is
407 converted to another System language/country eNewLnge. In this case
408 the automatic currency is converted too. */
409 bool PutandConvertEntrySystem( OUString
& rString
, sal_Int32
& nCheckPos
,
410 short& nType
, sal_uInt32
& nKey
,
411 LanguageType eLnge
, LanguageType eNewLnge
);
413 /** Similar to <method>PutEntry</method> and
414 <method>PutandConvertEntry</method> or
415 <method>PutandConvertEntrySystem</method>, the format code string
416 passed is considered to be of language/country eLnge. If
417 eLnge==LANGUAGE_SYSTEM the format code has to match eSysLnge, and if
418 eSysLnge is not the current application locale the format code is
419 converted to the current locale. Additionally, if the format code
420 represents an old "automatic" currency format, it is converted to the
421 new default currency format of the eLnge locale. The rString format
422 code passed as an argument may get adapted in case eLnge was used (or
423 is LANGUAGE_SYSTEM and eSysLnge is identical); in case it wasn't the
424 method works on a copy instead, otherwise the resulting string would
425 not match eSysLnge anymore.
427 <p> This method was introduced to handle the legacy currency formats of
428 the "autotbl.fmt" file used by Calc and Writer and convert them to
429 fixed currency codes of the actual currency. Note that in the case of
430 legacy currency formats no special attribution is converted, only the
431 default currency format of the locale is chosen, and that new fixed
432 currency codes are of course not converted to other currencies. The
433 method may also be used as a general method taking, converting and
434 inserting almost arbitrary format codes. To insert or use, for example,
435 the default currency format code matching the current locale, the
436 method could be called with<br/>
439 GetIndexPuttingAndConverting( "0 $", LANGUAGE_SYSTEM, LANGUAGE_ENGLISH_US, ...);
443 The index key of the resulting number format. If the format code
444 was empty, could not be converted or has errors, the eLnge locale's
445 standard number format is chosen instead. The index key is
446 guaranteed to represent some valid number format. If
447 rNewInserted==false and rCheckPos>0 the format code has errors
448 and/or could not be converted.
450 sal_uInt32
GetIndexPuttingAndConverting( String
& rString
, LanguageType eLnge
,
451 LanguageType eSysLnge
, short & rType
,
453 xub_StrLen
& rCheckPos
);
455 sal_uInt32
GetIndexPuttingAndConverting( OUString
& rString
, LanguageType eLnge
,
456 LanguageType eSysLnge
, short & rType
,
457 bool & rNewInserted
, sal_Int32
& rCheckPos
);
459 /** Create a format code string using format nIndex as a template and
460 applying other settings (passed from the dialog) */
461 OUString
GenerateFormat(sal_uInt32 nIndex
,
462 LanguageType eLnge
= LANGUAGE_DONTKNOW
,
463 bool bThousand
= false, bool IsRed
= false,
464 sal_uInt16 nPrecision
= 0, sal_uInt16 nAnzLeading
= 1);
466 /** Analyze an input string
468 <TRUE/> if input is a number or is matching a format F_Index
469 F_Index is set to a matching format if number, the value is
470 returned in fOutNumber
471 <FALSE/> if input is not a number
473 bool IsNumberFormat( const OUString
& sString
, sal_uInt32
& F_Index
, double& fOutNumber
);
475 /// Format a number according to a format index, return string and color
476 void GetOutputString( const double& fOutNumber
, sal_uInt32 nFIndex
,
477 String
& sOutString
, Color
** ppColor
, bool bUseStarFormat
= false );
479 /// Format a number according to a format index, return string and color
480 void GetOutputString( const double& fOutNumber
, sal_uInt32 nFIndex
,
481 OUString
& sOutString
, Color
** ppColor
, bool bUseStarFormat
= false );
483 /** Format a string according to a format index, return string and color.
484 Formats only if the format code is of type text or the 4th subcode
485 of a format code is specified, otherwise sOutString will be == "" */
486 void GetOutputString( const OUString
& sString
, sal_uInt32 nFIndex
,
487 OUString
& sOutString
, Color
** ppColor
, bool bUseStarFormat
= false );
489 /** Format a number according to the standard default format matching
490 the given format index */
491 void GetInputLineString( const double& fOutNumber
,
492 sal_uInt32 nFIndex
, String
& sOutString
);
494 void GetInputLineString( const double& fOutNumber
,
495 sal_uInt32 nFIndex
, OUString
& rOutString
);
497 /** Format a number according to a format code string to be scanned.
499 <FALSE/> if format code contains an error
500 <TRUE/> else, in which case the string and color are returned.
502 bool GetPreviewString(const OUString
& sFormatString
,
503 double fPreviewNumber
,
504 OUString
& sOutString
,
507 bool bUseStarFormat
= false );
509 /** Same as <method>GetPreviewString</method> but the format code string
510 may be either language/country eLnge or en_US english US */
511 bool GetPreviewStringGuess( const OUString
& sFormatString
, double fPreviewNumber
,
512 OUString
& sOutString
, Color
** ppColor
,
513 LanguageType eLnge
= LANGUAGE_DONTKNOW
);
515 /** Format a string according to a format code string to be scanned.
517 <FALSE/> if format code contains an error
518 <TRUE/> else, in which case the string and color are returned.
520 bool GetPreviewString( const OUString
& sFormatString
, const OUString
& sPreviewString
,
521 OUString
& sOutString
, Color
** ppColor
,
522 LanguageType eLnge
= LANGUAGE_DONTKNOW
);
524 /** Test whether the format code string is already present in container
526 NUMBERFORMAT_ENTRY_NOT_FOUND if not found, else the format index.
528 sal_uInt32
TestNewString( const OUString
& sFormatString
,
529 LanguageType eLnge
= LANGUAGE_DONTKNOW
);
531 /// Whether format index nFIndex is of type text or not
532 bool IsTextFormat(sal_uInt32 nFIndex
) const;
534 /// Load all formats from a stream
535 bool Load( SvStream
& rStream
);
536 /// Save all formats to a stream
537 bool Save( SvStream
& rStream
) const;
539 /// Get additional info of a format index, e.g. for dialog box
540 void GetFormatSpecialInfo(sal_uInt32 nFormat
, bool& bThousand
, bool& IsRed
,
541 sal_uInt16
& nPrecision
, sal_uInt16
& nAnzLeading
);
543 /// Count of decimals
544 sal_uInt16
GetFormatPrecision( sal_uInt32 nFormat
) const;
546 /** Get additional info of a format code string, e.g. for dialog box.
547 Uses a temporary parse, if possible use only if format code is not
548 present in container yet, otherwise ineffective.
550 0 if format code string parsed without errors, otherwise error
551 position (like nCheckPos on <method>PutEntry</method>)
553 sal_uInt32
GetFormatSpecialInfo( const OUString
&, bool& bThousand
, bool& IsRed
,
554 sal_uInt16
& nPrecision
, sal_uInt16
& nAnzLeading
,
555 LanguageType eLnge
= LANGUAGE_DONTKNOW
);
557 /// Check if format code string may be deleted by user
558 bool IsUserDefined( const OUString
& sStr
, LanguageType eLnge
= LANGUAGE_DONTKNOW
);
560 /** Return the format index of the format code string for language/country,
561 or NUMBERFORMAT_ENTRY_NOT_FOUND */
562 sal_uInt32
GetEntryKey( const OUString
& sStr
, LanguageType eLnge
= LANGUAGE_DONTKNOW
);
564 /// Return the format for a format index
565 const SvNumberformat
* GetEntry( sal_uInt32 nKey
) const;
567 /// Return the format index of the standard default number format for language/country
568 sal_uInt32
GetStandardIndex(LanguageType eLnge
= LANGUAGE_DONTKNOW
);
570 /// Return the format index of the default format of a type for language/country
571 sal_uInt32
GetStandardFormat(short eType
, LanguageType eLnge
= LANGUAGE_DONTKNOW
);
573 /** Return the format index of the default format of a type for language/country.
574 Maybe not the default format but a special builtin format, e.g. for
575 NF_TIME_HH_MMSS00, if that format is passed in nFIndex. */
576 sal_uInt32
GetStandardFormat( sal_uInt32 nFIndex
, short eType
, LanguageType eLnge
);
578 /** Return the format index of the default format of a type for language/country.
579 Maybe not the default format but a special builtin format, e.g. for
580 NF_TIME_HH_MMSS00, or NF_TIME_HH_MMSS if fNumber >= 1.0 */
581 sal_uInt32
GetStandardFormat( double fNumber
, sal_uInt32 nFIndex
, short eType
,
582 LanguageType eLnge
);
584 /// Whether nFIndex is a special builtin format
585 bool IsSpecialStandardFormat( sal_uInt32 nFIndex
, LanguageType eLnge
);
587 /** Return the corresponding edit format of a format. */
588 sal_uInt32
GetEditFormat( double fNumber
, sal_uInt32 nFIndex
, short eType
,
589 LanguageType eLnge
, SvNumberformat
* pFormat
);
591 /// Return the reference date
593 /// Return the standard decimal precision
594 sal_uInt16
GetStandardPrec();
595 /// Return whether zero suppression is switched on
596 bool GetNoZero() { return bNoZero
; }
597 /** Get the type of a format (or NUMBERFORMAT_UNDEFINED if no entry),
598 but with NUMBERFORMAT_DEFINED masked out */
599 short GetType(sal_uInt32 nFIndex
);
602 void ClearMergeTable();
603 /// Merge in all new entries from rNewTable and return a table of resulting new format indices
604 SvNumberFormatterIndexTable
* MergeFormatter(SvNumberFormatter
& rNewTable
);
606 /// Whether a merge table is present or not
607 inline bool HasMergeFmtTbl() const;
608 /// Return the new format index for an old format index, if a merge table exists
609 inline sal_uInt32
GetMergeFmtIndex( sal_uInt32 nOldFmt
) const;
611 /** Convert the ugly old tools' Table type bloated with new'ed sal_uInt32
612 entries merge table to ::std::map with old index key and new index key.
613 @ATTENTION! Also clears the old table using ClearMergeTable() */
614 SvNumberFormatterMergeMap
ConvertMergeTableToMap();
616 /// Return the last used position ever of a language/country combination
617 sal_uInt16
GetLastInsertKey(sal_uInt32 CLOffset
);
619 /** Return the format index of a builtin format for a specific language/country.
620 If nFormat is not a builtin format nFormat is returned. */
621 sal_uInt32
GetFormatForLanguageIfBuiltIn( sal_uInt32 nFormat
,
622 LanguageType eLnge
= LANGUAGE_DONTKNOW
);
624 /** Return the format index for a builtin format of a specific language
625 @see NfIndexTableOffset
627 sal_uInt32
GetFormatIndex( NfIndexTableOffset
, LanguageType eLnge
= LANGUAGE_DONTKNOW
);
629 /** Return enum index of a format index of a builtin format,
630 NF_INDEX_TABLE_ENTRIES if it's not a builtin format.
631 @see NfIndexTableOffset
633 NfIndexTableOffset
GetIndexTableOffset( sal_uInt32 nFormat
) const;
635 /** Set evaluation type and order of input date strings
636 @see NfEvalDateFormat
638 void SetEvalDateFormat( NfEvalDateFormat eEDF
) { eEvalDateFormat
= eEDF
; }
639 NfEvalDateFormat
GetEvalDateFormat() const { return eEvalDateFormat
; }
641 /** Set TwoDigitYearStart, how the input string scanner handles a two digit year.
642 Default from VCL: 1930, 30-99 19xx, 00-29 20xx
644 <p> Historically (prior to src513e) it was a two digit number determing
645 until which number the string scanner recognizes a year to be 20xx,
646 default <= 29 is used by SFX/OfaMiscCfg.
647 The name Year2000 is kept although the actual functionality is now a
648 TwoDigitYearStart which might be in any century.
650 void SetYear2000( sal_uInt16 nVal
);
651 sal_uInt16
GetYear2000() const;
652 static sal_uInt16
GetYear2000Default();
654 sal_uInt16
ExpandTwoDigitYear( sal_uInt16 nYear
) const;
655 inline static sal_uInt16
ExpandTwoDigitYear( sal_uInt16 nYear
, sal_uInt16 nTwoDigitYearStart
);
657 /// DEPRICATED: Return first character of the decimal separator of the current language/country
658 sal_Unicode
GetDecSep() const { return GetNumDecimalSep()[0]; }
659 /// Return the decimal separator of the current language/country
660 OUString
GetDecimalSep() const { return GetNumDecimalSep(); }
662 /// Return the decimal separator matching the locale of the given format
663 OUString
GetFormatDecimalSep( sal_uInt32 nFormat
) const;
665 /// Return a <type>NfCurrencyTable</type> with pointers to <type>NfCurrencyEntry</type> entries
666 static const NfCurrencyTable
& GetTheCurrencyTable();
668 /** Searches, according to the default locale currency, an entry of the
669 CurrencyTable which is <bold>not</bold> the first (LANGUAGE_SYSTEM) entry.
672 else pointer to <type>NfCurrencyEntry</type>
674 static const NfCurrencyEntry
* MatchSystemCurrency();
676 /** Return a <type>NfCurrencyEntry</type> matching a language/country.
677 If language/country is LANGUAGE_SYSTEM a <method>MatchSystemCurrency</method>
678 call is tried to get an entry. If that fails or the corresponding
679 language/country is not present the entry for LANGUAGE_SYSTEM is returned.
681 static const NfCurrencyEntry
& GetCurrencyEntry( LanguageType
);
683 /** Return a <type>NfCurrencyEntry</type> pointer matching a language/country
684 and currency abbreviation (AKA banking symbol).
685 This method is meant for the configuration of the default currency.
688 else pointer to <type>NfCurrencyEntry</type>
690 static const NfCurrencyEntry
* GetCurrencyEntry( const OUString
& rAbbrev
,
691 LanguageType eLang
);
693 /** Return a <type>NfCurrencyEntry</type> pointer matching the symbol
694 combination of a LegacyOnly currency. Note that this means only that
695 the currency matching both symbols was once used in the Office, but is
696 not offered in dialogs anymore. It doesn't even mean that the currency
697 symbol combination is valid, since the reason for removing it may have
698 been just that. #i61657#
700 A matching entry, or else <NULL/>.
702 static const NfCurrencyEntry
* GetLegacyOnlyCurrencyEntry( const OUString
& rSymbol
, const OUString
& rAbbrev
);
704 /** Set the default system currency. The combination of abbreviation and
705 language must match an existent element of theCurrencyTable. If not,
706 the SYSTEM (current locale) entry becomes the default.
707 This method is meant for the configuration of the default currency.
709 static void SetDefaultSystemCurrency( const OUString
& rAbbrev
, LanguageType eLang
);
711 /** Get all standard formats for a specific currency, formats are
712 appended to the <type>NfWSStringsDtor</type> list.
714 <TRUE/>: generate only format strings with currency abbreviation
715 <FALSE/>: mixed format strings
717 position of default format
719 sal_uInt16
GetCurrencyFormatStrings( NfWSStringsDtor
&, const NfCurrencyEntry
&,
722 /** Whether nFormat is of type NUMBERFORMAT_CURRENCY and the format code
723 contains a new SYMBOLTYPE_CURRENCY and if so which one [$xxx-nnn].
724 If ppEntry is not NULL and exactly one entry is found, a [$xxx-nnn] is
725 returned, even if the format code only contains [$xxx] !
727 bool GetNewCurrencySymbolString( sal_uInt32 nFormat
, String
& rSymbol
,
728 const NfCurrencyEntry
** ppEntry
= NULL
,
729 bool* pBank
= NULL
) const;
731 /** Look up the corresponding <type>NfCurrencyEntry</type> matching
732 rSymbol (may be CurrencySymbol or CurrencyAbbreviation) and possibly
733 a rExtension (being yyy of [$xxx-yyy]) or a given language/country
734 value. Tries to match a rSymbol with rExtension first, then with
735 eFormatLanguage, then rSymbol only. This is because a currency entry
736 might have been constructed using I18N locale data where a used locale
737 of a currrency format code must not necessarily match the locale of
738 the locale data itself, e.g. [$HK$-40C] (being "zh_HK" locale) in
739 zh_CN locale data. Here the rExtension would have the value 0x40c but
740 eFormatLanguage of the number format would have the value of zh_CN
741 locale, the value with which the corresponding CurrencyEntry is
745 Only used for output.
746 If the return value is not <NULL/> this value is set to <TRUE/> if
747 the matching entry was found by comparing rSymbol against the
748 CurrencyAbbreviation (AKA BankSymbol).
749 If the return value is <NULL/> the value of bFoundBank is undefined.
751 Currency symbol, preferably obtained of a format by a call to
752 <method>SvNumberformat::GetNewCurrencySymbol()</method>
754 Currency extension, preferably obtained of a format by a call to
755 <method>SvNumberformat::GetNewCurrencySymbol()</method>
756 @param eFormatLanguage
757 The language/country value of the format of which rSymbol and
758 rExtension are obtained (<method>SvNumberformat::GetLanguage()</method>).
759 @param bOnlyStringLanguage
760 If <TRUE/> only entries with language/country of rExtension are
761 checked, no match on eFormatLanguage. If rExtension is empty all
764 The matching entry if unique (in which case bFoundBank is set),
767 static const NfCurrencyEntry
* GetCurrencyEntry( bool & bFoundBank
,
768 const OUString
& rSymbol
,
769 const OUString
& rExtension
,
770 LanguageType eFormatLanguage
,
771 bool bOnlyStringLanguage
= false );
773 /// Get compatibility ("automatic" old style) currency from I18N locale data
774 void GetCompatibilityCurrency( OUString
& rSymbol
, OUString
& rAbbrev
) const;
776 /// Fill rList with the language/country codes that have been allocated
777 void GetUsedLanguages( std::vector
<sal_uInt16
>& rList
);
779 /// Fill a <type>NfKeywordIndex</type> table with keywords of a language/country
780 void FillKeywordTable( NfKeywordTable
& rKeywords
, LanguageType eLang
);
782 /** Return a keyword for a language/country and <type>NfKeywordIndex</type>
783 for XML import, to generate number format strings. */
784 OUString
GetKeyword( LanguageType eLnge
, sal_uInt16 nIndex
);
786 /** Return the GENERAL keyword in proper case ("General") for a
787 language/country, used in XML import */
788 OUString
GetStandardName( LanguageType eLnge
);
790 /** Check if a specific locale has supported locale data. */
791 static bool IsLocaleInstalled( LanguageType eLang
);
794 ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XComponentContext
> m_xContext
;
795 LanguageTag maLanguageTag
;
796 SvNumberFormatTable aFTable
; // Table of format keys to format entries
797 typedef std::map
<sal_uInt32
, sal_uInt32
> DefaultFormatKeysMap
;
798 DefaultFormatKeysMap aDefaultFormatKeys
; // Table of default standard to format keys
799 SvNumberFormatTable
* pFormatTable
; // For the UI dialog
800 SvNumberFormatterIndexTable
* pMergeTable
; // List of indices for merging two formatters
801 CharClass
* pCharClass
; // CharacterClassification
802 OnDemandLocaleDataWrapper xLocaleData
; // LocaleData switched between SYSTEM, ENGLISH and other
803 OnDemandTransliterationWrapper xTransliteration
; // Transliteration loaded on demand
804 OnDemandCalendarWrapper xCalendar
; // Calendar loaded on demand
805 OnDemandNativeNumberWrapper xNatNum
; // Native number service loaded on demand
806 ImpSvNumberInputScan
* pStringScanner
; // Input string scanner
807 ImpSvNumberformatScan
* pFormatScanner
; // Format code string scanner
808 Link aColorLink
; // User defined color table CallBack
809 sal_uInt32 MaxCLOffset
; // Max language/country offset used
810 sal_uInt32 nDefaultSystemCurrencyFormat
; // NewCurrency matching SYSTEM locale
811 LanguageType IniLnge
; // Initialized setting language/country
812 LanguageType ActLnge
; // Current setting language/country
813 NfEvalDateFormat eEvalDateFormat
; // DateFormat evaluation
814 bool bNoZero
; // Zero value suppression
816 // cached locale data items needed almost any time
817 OUString aDecimalSep
;
818 OUString aThousandSep
;
821 SVL_DLLPRIVATE
static bool bCurrencyTableInitialized
;
822 SVL_DLLPRIVATE
static sal_uInt16 nSystemCurrencyPosition
;
823 SVL_DLLPRIVATE
static SvNumberFormatterRegistry_Impl
* pFormatterRegistry
;
825 // get the registry, create one if none exists
826 SVL_DLLPRIVATE
static SvNumberFormatterRegistry_Impl
& GetFormatterRegistry();
829 SVL_DLLPRIVATE
void ImpConstruct( LanguageType eLang
);
831 // Changes initialized language/country, clears the entries and generates
832 // new ones, may ONLY be called by the binary file format load
833 SVL_DLLPRIVATE
void ImpChangeSysCL( LanguageType eLnge
, bool bNoAdditionalFormats
);
835 // Generate builtin formats provided by i18n behind CLOffset,
836 // if bNoAdditionalFormats==false also generate additional i18n formats.
837 SVL_DLLPRIVATE
void ImpGenerateFormats( sal_uInt32 CLOffset
, bool bNoAdditionalFormats
);
839 // Generate additional formats provided by i18n
840 SVL_DLLPRIVATE
void ImpGenerateAdditionalFormats( sal_uInt32 CLOffset
,
841 NumberFormatCodeWrapper
& rNumberFormatCode
,
842 bool bAfterChangingSystemCL
);
844 SVL_DLLPRIVATE SvNumberformat
* ImpInsertFormat( const ::com::sun::star::i18n::NumberFormatCode
& rCode
,
846 bool bAfterChangingSystemCL
= false,
847 sal_Int16 nOrgIndex
= 0 );
848 // ImpInsertNewStandardFormat for new (since version ...) builtin formats
849 SVL_DLLPRIVATE SvNumberformat
* ImpInsertNewStandardFormat( const ::com::sun::star::i18n::NumberFormatCode
& rCode
,
852 bool bAfterChangingSystemCL
= false,
853 sal_Int16 nOrgIndex
= 0 );
855 // Return CLOffset or (MaxCLOffset + SV_COUNTRY_LANGUAGE_OFFSET) if new language/country
856 SVL_DLLPRIVATE sal_uInt32
ImpGetCLOffset(LanguageType eLnge
) const;
858 // Test whether format code already exists, then return index key,
859 // otherwise NUMBERFORMAT_ENTRY_NOT_FOUND
860 SVL_DLLPRIVATE sal_uInt32
ImpIsEntry( const OUString
& rString
,
862 LanguageType eLnge
);
864 // Create builtin formats for language/country if necessary, return CLOffset
865 SVL_DLLPRIVATE sal_uInt32
ImpGenerateCL( LanguageType eLnge
, bool bNoAdditionalFormats
= false );
867 // Build negative currency format, old compatibility style
868 SVL_DLLPRIVATE
void ImpGetNegCurrFormat(OUStringBuffer
& sNegStr
, const OUString
& rCurrSymbol
);
869 // Build positive currency format, old compatibility style
870 SVL_DLLPRIVATE
void ImpGetPosCurrFormat(OUStringBuffer
& sPosStr
, const OUString
& rCurrSymbol
);
872 // Create <type>theCurrencyTable</type> with all <type>NfCurrencyEntry</type>
873 SVL_DLLPRIVATE
static void ImpInitCurrencyTable();
875 // Return the format index of the currency format of the system locale.
876 // Format is created if not already present.
877 SVL_DLLPRIVATE sal_uInt32
ImpGetDefaultSystemCurrencyFormat();
879 // Return the format index of the currency format of the current locale.
880 // Format is created if not already present.
881 SVL_DLLPRIVATE sal_uInt32
ImpGetDefaultCurrencyFormat();
883 // Return the default format for a given type and current locale.
884 // May ONLY be called from within GetStandardFormat().
885 SVL_DLLPRIVATE sal_uInt32
ImpGetDefaultFormat( short nType
);
887 // Return the index in a sequence of format codes matching an enum of
888 // NfIndexTableOffset. If not found 0 is returned. If the sequence doesn't
889 // contain any format code elements a default element is created and inserted.
890 SVL_DLLPRIVATE sal_Int32
ImpGetFormatCodeIndex( ::com::sun::star::uno::Sequence
< ::com::sun::star::i18n::NumberFormatCode
>& rSeq
,
891 const NfIndexTableOffset nTabOff
);
893 // Adjust a sequence of format codes to contain only one (THE) default
894 // instead of multiple defaults for short/medium/long types.
895 // If there is no medium but a short and a long default the long is taken.
896 // Return the default index in the sequence.
897 // Non-PRODUCT version may check locale data for matching defaults in one
898 // FormatElement group.
899 SVL_DLLPRIVATE sal_Int32
ImpAdjustFormatCodeDefault( ::com::sun::star::i18n::NumberFormatCode
* pFormatArr
,
900 sal_Int32 nCount
, bool bCheckCorrectness
= true );
902 // Obtain the format entry for a given key index.
903 SVL_DLLPRIVATE SvNumberformat
* GetFormatEntry( sal_uInt32 nKey
);
904 SVL_DLLPRIVATE
const SvNumberformat
* GetFormatEntry( sal_uInt32 nKey
) const
906 return GetEntry( nKey
);
909 // used as a loop body inside of GetNewCurrencySymbolString() and GetCurrencyEntry()
913 static bool ImpLookupCurrencyEntryLoopBody( const NfCurrencyEntry
*& pFoundEntry
,
914 bool& bFoundBank
, const NfCurrencyEntry
* pData
,
915 sal_uInt16 nPos
, const OUString
& rSymbol
);
917 // link to be set at <method>SvtSysLocaleOptions::SetCurrencyChangeLink()</method>
918 DECL_DLLPRIVATE_STATIC_LINK( SvNumberFormatter
, CurrencyChangeLink
, void* );
922 // own static mutex, may also be used by internal class SvNumberFormatterRegistry_Impl
923 static ::osl::Mutex
& GetMutex();
925 // called by SvNumberFormatterRegistry_Impl::Notify if the default system currency changes
926 void ResetDefaultSystemCurrency();
928 // Called by SvNumberFormatterRegistry_Impl::Notify if the system locale's
929 // date acceptence patterns change.
930 void InvalidateDateAcceptancePatterns();
932 // Replace the SYSTEM language/country format codes. Called upon change of
933 // the user configurable locale.
934 // Old compatibility codes are replaced, user defined are converted, and
935 // new format codes are appended.
936 void ReplaceSystemCL( LanguageType eOldLanguage
);
938 inline ::com::sun::star::uno::Reference
< ::com::sun::star::uno::XComponentContext
> GetComponentContext() const
945 //! The following method is not to be used from outside but must be
946 //! public for the InputScanner.
947 // return the current FormatScanner
948 inline const ImpSvNumberformatScan
* GetFormatScanner() const { return pFormatScanner
; }
951 //! The following methods are not to be used from outside but must be
952 //! public for the InputScanner and FormatScanner.
954 // return current (!) Locale
955 inline const LanguageTag
& GetLanguageTag() const { return maLanguageTag
; }
957 // return corresponding Transliteration wrapper
958 inline const ::utl::TransliterationWrapper
* GetTransliteration() const
960 return xTransliteration
.get();
963 // return corresponding Transliteration wrapper with loadModuleByImplName()
964 inline const ::utl::TransliterationWrapper
* GetTransliterationForModule( const OUString
& rModule
,
965 LanguageType eLang
) const
967 return xTransliteration
.getForModule( rModule
, eLang
);
970 // return the corresponding CharacterClassification wrapper
971 inline const CharClass
* GetCharClass() const { return pCharClass
; }
973 // return the corresponding LocaleData wrapper
974 inline const LocaleDataWrapper
* GetLocaleData() const { return xLocaleData
.get(); }
976 // return the corresponding Calendar wrapper
977 inline CalendarWrapper
* GetCalendar() const { return xCalendar
.get(); }
979 // return the corresponding NativeNumberSupplier wrapper
980 inline const NativeNumberWrapper
* GetNatNum() const { return xNatNum
.get(); }
982 // cached locale data items
984 // return the corresponding decimal separator
985 inline const OUString
& GetNumDecimalSep() const { return aDecimalSep
; }
987 // return the corresponding group (AKA thousand) separator
988 inline const OUString
& GetNumThousandSep() const { return aThousandSep
; }
990 // return the corresponding date separator
991 inline const OUString
& GetDateSep() const { return aDateSep
; }
996 // --------------------------- inline --------------------------------------
998 inline sal_uInt32
SvNumberFormatter::GetMergeFmtIndex( sal_uInt32 nOldFmt
) const
1002 SvNumberFormatterIndexTable::iterator it
= pMergeTable
->find(nOldFmt
);
1003 if (it
!= pMergeTable
->end())
1011 inline bool SvNumberFormatter::HasMergeFmtTbl() const
1013 return pMergeTable
&& !pMergeTable
->empty();
1018 inline sal_uInt16
SvNumberFormatter::ExpandTwoDigitYear( sal_uInt16 nYear
, sal_uInt16 nTwoDigitYearStart
)
1022 if ( nYear
< (nTwoDigitYearStart
% 100) )
1024 return nYear
+ (((nTwoDigitYearStart
/ 100) + 1) * 100);
1028 return nYear
+ ((nTwoDigitYearStart
/ 100) * 100);
1034 #endif // _ZFORLIST_HXX
1036 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */