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 .
19 #ifndef INCLUDED_SVL_ZFORLIST_HXX
20 #define INCLUDED_SVL_ZFORLIST_HXX
22 #include <config_options.h>
23 #include <svl/svldllapi.h>
24 #include <rtl/ustrbuf.hxx>
25 #include <rtl/ustring.hxx>
26 #include <o3tl/typed_flags_set.hxx>
27 #include <i18nlangtag/lang.h>
28 #include <com/sun/star/util/NumberFormat.hpp>
29 #include <unotools/localedatawrapper.hxx>
32 #include <unordered_map>
34 namespace com::sun::star::i18n
{ struct Currency
; }
38 #define SV_COUNTRY_LANGUAGE_OFFSET 10000 // Max count of formats per country/language
39 #define SV_MAX_COUNT_STANDARD_FORMATS 100 // Max count of builtin default formats per CL
41 constexpr size_t NF_MAX_FORMAT_SYMBOLS
= 100;
43 /// The built-in @ Text format, offset within a locale, key in the locale the
44 /// number formatter was constructed with.
45 constexpr sal_uInt32 NF_STANDARD_FORMAT_TEXT
= SV_MAX_COUNT_STANDARD_FORMATS
;
47 constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND
= 0xffffffff; /// MAX_ULONG
49 enum class SvNumFormatType
: sal_Int16
51 /** selects all number formats.
53 ALL
= css::util::NumberFormat::ALL
, // 0
54 /** selects only user-defined number formats.
56 DEFINED
= css::util::NumberFormat::DEFINED
, // 1
57 /** selects date formats.
59 DATE
= css::util::NumberFormat::DATE
, // 2
60 /** selects time formats.
62 TIME
= css::util::NumberFormat::TIME
, // 4
63 /** selects currency formats.
65 CURRENCY
= css::util::NumberFormat::CURRENCY
, // 8
66 /** selects decimal number formats.
68 NUMBER
= css::util::NumberFormat::NUMBER
, // 16
69 /** selects scientific number formats.
71 SCIENTIFIC
= css::util::NumberFormat::SCIENTIFIC
, // 32
72 /** selects number formats for fractions.
74 FRACTION
= css::util::NumberFormat::FRACTION
, // 64
75 /** selects percentage number formats.
77 PERCENT
= css::util::NumberFormat::PERCENT
, // 128
78 /** selects text number formats.
80 TEXT
= css::util::NumberFormat::TEXT
, // 256
81 /** selects number formats which contain date and time.
83 DATETIME
= DATE
| TIME
, // 6
84 /** selects boolean number formats.
86 LOGICAL
= css::util::NumberFormat::LOGICAL
, // 1024
87 /** is used as a return value if no format exists.
89 UNDEFINED
= css::util::NumberFormat::UNDEFINED
, // 2048
90 /** @internal is used to flag an empty sub format.
91 @since LibreOffice 5.1
93 EMPTY
= css::util::NumberFormat::EMPTY
, // 4096
94 /** @internal selects a time duration format.
96 @since LibreOffice 6.2
98 DURATION
= css::util::NumberFormat::DURATION
, // 8196
101 template<> struct typed_flags
<SvNumFormatType
> : is_typed_flags
<SvNumFormatType
, 0x3dff> {};
104 /** enum values for <method>SvNumberFormatter::GetFormatIndex</method>
107 Builtin standard formats, order should be also the arrangement in the
108 dialog list box representation.</p>
112 <li>SYSTEM: As set in System Regional Settings.
113 <li>SYS: short/long defined, order and separators from System Regional Settings.
114 <li>DEF: short/long and order defined, separators from System Regional Settings.
115 <li>DIN: all settings hard coded as DIN (Deutsche Industrie Norm) and EN (European Norm) require.
116 <li>all other: hard coded
119 Do NOT insert any new values!
120 The values here correspond with those in offapi/com/sun/star/i18n/NumberFormatIndex.idl
121 You may append values though after NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS.
123 enum NfIndexTableOffset
125 NF_NUMERIC_START
= 0,
127 NF_NUMBER_START
= NF_NUMERIC_START
,
128 NF_NUMBER_STANDARD
= NF_NUMBER_START
, // Standard/General
130 NF_NUMBER_DEC2
, // 0.00
131 NF_NUMBER_1000INT
, // #,##0
132 NF_NUMBER_1000DEC2
, // #,##0.00
133 NF_NUMBER_SYSTEM
, // #,##0.00 or whatever is set in System Regional Settings
134 NF_NUMBER_END
= NF_NUMBER_SYSTEM
,
137 NF_SCIENTIFIC_000E000
= NF_SCIENTIFIC_START
, // 0.00E+000
138 NF_SCIENTIFIC_000E00
, // 0.00E+00
139 NF_SCIENTIFIC_END
= NF_SCIENTIFIC_000E00
,
142 NF_PERCENT_INT
= NF_PERCENT_START
, // 0%
143 NF_PERCENT_DEC2
, // 0.00%
144 NF_PERCENT_END
= NF_PERCENT_DEC2
,
147 NF_FRACTION_1D
= NF_FRACTION_START
, // # ?/?
148 NF_FRACTION_2D
, // # ??/??
149 NF_FRACTION_END
= NF_FRACTION_2D
,
151 NF_NUMERIC_END
= NF_FRACTION_END
,
154 NF_CURRENCY_1000INT
= NF_CURRENCY_START
,// #,##0 DM
155 NF_CURRENCY_1000DEC2
, // #,##0.00 DM
156 NF_CURRENCY_1000INT_RED
, // #,##0 DM negative in red
157 NF_CURRENCY_1000DEC2_RED
, // #,##0.00 DM negative in red
158 NF_CURRENCY_1000DEC2_CCC
, // #,##0.00 DEM currency abbreviation
159 NF_CURRENCY_1000DEC2_DASHED
, // #,##0.-- DM
160 NF_CURRENCY_END
= NF_CURRENCY_1000DEC2_DASHED
,
163 NF_DATE_SYSTEM_SHORT
= NF_DATE_START
, // 08.10.97
164 NF_DATE_SYSTEM_LONG
, // Wednesday, 8. October 1997
165 NF_DATE_SYS_DDMMYY
, // 08.10.97
166 NF_DATE_SYS_DDMMYYYY
, // 08.10.1997 THE edit format, formatindex="21"
167 NF_DATE_SYS_DMMMYY
, // 8. Oct 97
168 NF_DATE_SYS_DMMMYYYY
, // 8. Oct 1997
169 NF_DATE_DIN_DMMMYYYY
, // 8. Oct. 1997 DIN
170 NF_DATE_SYS_DMMMMYYYY
, // 8. October 1997
171 NF_DATE_DIN_DMMMMYYYY
, // 8. October 1997 DIN
172 NF_DATE_SYS_NNDMMMYY
, // Wed, 8. Okt 97
173 NF_DATE_DEF_NNDDMMMYY
, // Wed 08.Okt 97
174 NF_DATE_SYS_NNDMMMMYYYY
, // Wed, 8. Oktober 1997
175 NF_DATE_SYS_NNNNDMMMMYYYY
, // Wednesday, 8. Oktober 1997
176 NF_DATE_DIN_MMDD
, // 10-08 DIN
177 NF_DATE_DIN_YYMMDD
, // 97-10-08 DIN
178 NF_DATE_DIN_YYYYMMDD
, // 1997-10-08 DIN
179 NF_DATE_ISO_YYYYMMDD
= NF_DATE_DIN_YYYYMMDD
, // 1997-10-08 ISO clarify with name, formatindex="33"
180 NF_DATE_SYS_MMYY
, // 10.97
181 NF_DATE_SYS_DDMMM
, // 08.Oct
182 NF_DATE_MMMM
, // October
183 NF_DATE_QQJJ
, // 4. Quarter 97
184 NF_DATE_WW
, // week of year
185 NF_DATE_END
= NF_DATE_WW
,
188 NF_TIME_HHMM
= NF_TIME_START
, // HH:MM
189 NF_TIME_HHMMSS
, // HH:MM:SS
190 NF_TIME_HHMMAMPM
, // HH:MM AM/PM
191 NF_TIME_HHMMSSAMPM
, // HH:MM:SS AM/PM
192 NF_TIME_HH_MMSS
, // [HH]:MM:SS formatindex="43"
193 NF_TIME_MMSS00
, // MM:SS,00 formatindex="44"
194 NF_TIME_HH_MMSS00
, // [HH]:MM:SS,00 formatindex="45"
195 NF_TIME_END
= NF_TIME_HH_MMSS00
,
198 NF_DATETIME_SYSTEM_SHORT_HHMM
= NF_DATETIME_START
, // 08.10.97 01:23
199 NF_DATETIME_SYS_DDMMYYYY_HHMMSS
, // 08.10.1997 01:23:45 THE edit format, formatindex="47"
200 NF_DATETIME_END
= NF_DATETIME_SYS_DDMMYYYY_HHMMSS
,
202 NF_BOOLEAN
, // BOOLEAN
205 NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
, // == 50, old number of predefined entries, i18npool locale data additions start after this
207 // From here on are values of new predefined and built-in formats that are
208 // not in the original NumberFormatIndex.idl
210 // XXX Values appended here must also get a corresponding entry in
211 // svl/source/numbers/zforlist.cxx indexTable[] in the same order.
213 // XXX The dialog's number format shell assumes start/end spans
214 // (NF_..._START and NF_..._END above) to fill its categories with builtin
215 // formats, make new formats known to svx/source/items/numfmtsh.cxx
216 // SvxNumberFormatShell::FillEListWithStd_Impl(), otherwise they will not
217 // be listed at all. Yes that is ugly.
218 // DATETIME formats need to be added to
219 // SvxNumberFormatShell::FillEListWithDateTime_Impl().
221 // New predefined format added to i18npool locale data.
222 NF_DATETIME_SYS_DDMMYYYY_HHMM
= NF_INDEX_TABLE_LOCALE_DATA_DEFAULTS
, // 08.10.1997 01:23 formatindex="50"
224 // No i18npool defined locale data between here and NF_INDEX_TABLE_ENTRIES.
225 NF_INDEX_TABLE_RESERVED_START
,
227 NF_FRACTION_3D
= NF_INDEX_TABLE_RESERVED_START
, // # ???/???
228 NF_FRACTION_2
, // # ?/2
229 NF_FRACTION_4
, // # ?/4
230 NF_FRACTION_8
, // # ?/8
231 NF_FRACTION_16
, // # ??/16
232 NF_FRACTION_10
, // # ??/10
233 NF_FRACTION_100
, // # ??/100
235 NF_DATETIME_ISO_YYYYMMDD_HHMMSS
, // 1997-10-08 01:23:45 ISO (with blank instead of T)
236 NF_DATETIME_ISO_YYYYMMDD_HHMMSS000
, // 1997-10-08 01:23:45.678 not quite ISO with locale's separator
237 NF_DATETIME_ISO_YYYYMMDDTHHMMSS
, // 1997-10-08T01:23:45 ISO
238 NF_DATETIME_ISO_YYYYMMDDTHHMMSS000
, // 1997-10-08T01:23:45,678 ISO with milliseconds and ',' or '.'
240 // XXX When adding values here, follow the comment above about
241 // svx/source/items/numfmtsh.cxx
243 NF_INDEX_TABLE_ENTRIES
// == 62, reserved to not be used in i18npool locale data.
245 // XXX Adding values above may increment the reserved area that can't be
246 // used by i18npool's locale data FormatCode definitions, see the
247 // description at i18npool/source/localedata/data/locale.dtd for ELEMENT
248 // FormatCode what the current convention's value is. In that case, the
249 // used formatIndex values in i18npool/source/localedata/data/*.xml will
250 // have to be adjusted.
251 // Overlapping the area will bail out with a check in
252 // SvNumberFormatter::ImpInsertFormat() in debug builds.
256 // #45717# IsNumberFormat( "98-10-24", 30, x ), YMD Format set with DMY
257 // International settings doesn't recognize the string as a date.
258 /** enum values for <method>SvNumberFormatter::SetEvalDateFormat</method>
260 <p>How <method>ImpSvNumberInputScan::GetDateRef</method> shall take the
261 DateFormat order (YMD,DMY,MDY) into account, if called from IsNumberFormat
262 with a date format to match against.
264 enum NfEvalDateFormat
266 /** DateFormat only from International, default. */
267 NF_EVALDATEFORMAT_INTL
,
269 /** DateFormat only from date format passed to function (if any).
270 If no date format is passed then the DateFormat is taken from International. */
271 NF_EVALDATEFORMAT_FORMAT
,
273 /** First try the DateFormat from International. If it doesn't match a
274 valid date try the DateFormat from the date format passed. */
275 NF_EVALDATEFORMAT_INTL_FORMAT
,
277 /** First try the DateFormat from the date format passed. If it doesn't
278 match a valid date try the DateFormat from International. */
279 NF_EVALDATEFORMAT_FORMAT_INTL
283 /// This table is std::map because it needs to preserve insertion order,
284 /// because the formats are roughly ordered from most to least common, and some
285 /// parts of the UI want to show them in that order.
286 typedef std::map
<sal_uInt32
, SvNumberformat
*> SvNumberFormatTable
;
287 typedef std::unordered_map
<sal_uInt16
, sal_uInt32
> SvNumberFormatterIndexTable
;
288 typedef std::unordered_map
< sal_uInt32
, sal_uInt32
> SvNumberFormatterMergeMap
;
291 /** Language/country dependent currency entries
293 class UNLESS_MERGELIBS(SVL_DLLPUBLIC
) NfCurrencyEntry final
295 OUString aSymbol
; /// currency symbol
296 OUString aBankSymbol
; /// currency abbreviation
297 LanguageType eLanguage
; /// language/country value
298 sal_uInt16 nPositiveFormat
; /// position of symbol
299 sal_uInt16 nNegativeFormat
; /// position of symbol and type and position of negative sign
300 sal_uInt16 nDigits
; /// count of decimal digits
301 sal_Unicode cZeroChar
; /// which character is used for zeros as last decimal digits
305 // nDecimalFormat := 0, 1, 2
306 // #,##0 or #,##0.00 or #,##0.-- is returned
307 SVL_DLLPRIVATE OUString
Impl_BuildFormatStringNumChars( const LocaleDataWrapper
&, sal_uInt16 nDecimalFormat
) const;
311 NfCurrencyEntry( const LocaleDataWrapper
& rLocaleData
,
312 LanguageType eLang
);
313 NfCurrencyEntry( const css::i18n::Currency
& rCurr
,
314 const LocaleDataWrapper
& rLocaleData
,
315 LanguageType eLang
);
317 /// Symbols and language identical
318 bool operator==( const NfCurrencyEntry
& r
) const;
320 const OUString
& GetSymbol() const { return aSymbol
; }
321 const OUString
& GetBankSymbol() const { return aBankSymbol
; }
322 LanguageType
GetLanguage() const { return eLanguage
; }
323 sal_uInt16
GetPositiveFormat() const { return nPositiveFormat
; }
324 sal_uInt16
GetNegativeFormat() const { return nNegativeFormat
; }
325 sal_uInt16
GetDigits() const { return nDigits
; }
327 /** Only to resolve system locale for currency list. */
328 void SetLanguage( LanguageType nLang
) { eLanguage
= nLang
; }
330 /** [$DM-407] (bBank==false) or [$DEM] (bBank==true)
331 is returned. If bBank==false and
332 bWithoutExtension==true only [$DM] */
333 OUString
BuildSymbolString(bool bBank
, bool bWithoutExtension
= false) const;
335 /** #,##0.00 [$DM-407] is returned, separators
336 from rLoc, incl. minus sign but without [RED] */
337 OUString
BuildPositiveFormatString(bool bBank
, const LocaleDataWrapper
&,
338 sal_uInt16 nDecimalFormat
= 1) const;
339 OUString
BuildNegativeFormatString(bool bBank
, const LocaleDataWrapper
&,
340 sal_uInt16 nDecimalFormat
= 1) const;
342 /** [$DM-407] (or [$DEM] if bBank==true)
343 is appended/prepended to rStr, incl. minus sign */
344 void CompletePositiveFormatString(OUStringBuffer
& rStr
, bool bBank
,
345 sal_uInt16 nPosiFormat
) const;
346 void CompleteNegativeFormatString(OUStringBuffer
& rStr
, bool bBank
,
347 sal_uInt16 nNegaFormat
) const;
349 /// rSymStr is appended/prepended to rStr, incl. minus sign
350 static void CompletePositiveFormatString(OUStringBuffer
& rStr
,
351 std::u16string_view rSymStr
, sal_uInt16 nPosiFormat
);
352 static void CompleteNegativeFormatString(OUStringBuffer
& rStr
,
353 std::u16string_view rSymStr
, sal_uInt16 nNegaFormat
);
355 /** Representation of a currency (symbol position and
356 negative sign) in other language settings */
357 static sal_uInt16
GetEffectivePositiveFormat( sal_uInt16 nIntlFormat
,
358 sal_uInt16 nCurrFormat
, bool bBank
);
359 static sal_uInt16
GetEffectiveNegativeFormat( sal_uInt16 nIntlFormat
,
360 sal_uInt16 nCurrFormat
, bool bBank
);
362 /// General Unicode Euro symbol
363 static sal_Unicode
GetEuroSymbol() { return u
'\x20AC'; }
366 typedef std::vector
< OUString
> NfWSStringsDtor
;
368 /** Input options to be used with IsNumberFormat() */
369 enum class SvNumInputOptions
: sal_uInt16
372 LAX_TIME
= 1 ///< allow input of minutes or seconds >59
375 template<> struct typed_flags
<SvNumInputOptions
> : is_typed_flags
<SvNumInputOptions
, 0x0001> {};
379 #endif // INCLUDED_SVL_ZFORLIST_HXX
381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */