/src/libreoffice/include/svl/zformat.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | #ifndef INCLUDED_SVL_ZFORMAT_HXX |
20 | | #define INCLUDED_SVL_ZFORMAT_HXX |
21 | | |
22 | | #include <svl/svldllapi.h> |
23 | | #include <svl/zforlist.hxx> |
24 | | #include <svl/nfkeytab.hxx> |
25 | | #include <vector> |
26 | | |
27 | | namespace utl { |
28 | | class DigitGroupingIterator; |
29 | | } |
30 | | |
31 | | namespace com::sun::star::i18n { struct NativeNumberXmlAttributes2; } |
32 | | |
33 | | class Color; |
34 | | class CalendarWrapper; |
35 | | class LocaleDataWrapper; |
36 | | enum class DateOrder; |
37 | | |
38 | | class SvNFLanguageData; |
39 | | |
40 | | class ImpSvNumberformatScan; // format code string scanner |
41 | | class ImpSvNumberInputScan; // input string scanner |
42 | | class NativeNumberWrapper; |
43 | | class SvNFFormatData; |
44 | | class SvNumberFormatter; |
45 | | |
46 | | enum SvNumberformatLimitOps |
47 | | { |
48 | | NUMBERFORMAT_OP_NO = 0, // Undefined, no OP |
49 | | NUMBERFORMAT_OP_EQ = 1, // Operator = |
50 | | NUMBERFORMAT_OP_NE = 2, // Operator <> |
51 | | NUMBERFORMAT_OP_LT = 3, // Operator < |
52 | | NUMBERFORMAT_OP_LE = 4, // Operator <= |
53 | | NUMBERFORMAT_OP_GT = 5, // Operator > |
54 | | NUMBERFORMAT_OP_GE = 6 // Operator >= |
55 | | }; |
56 | | |
57 | | struct ImpSvNumberformatInfo // Struct for FormatInfo |
58 | | { |
59 | | std::vector<OUString> sStrArray; // Array of symbols |
60 | | std::vector<short> nTypeArray; // Array of infos |
61 | | sal_uInt16 nThousand; // Count of group separator sequences |
62 | | sal_uInt16 nCntPre; // Count of digits before decimal point |
63 | | sal_uInt16 nCntPost; // Count of digits after decimal point |
64 | | sal_uInt16 nCntExp; // Count of exponent digits, or AM/PM |
65 | | SvNumFormatType eScannedType; // Type determined by scan |
66 | | bool bThousand; // Has group (AKA thousand) separator |
67 | | |
68 | | void Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nCount ); |
69 | | }; |
70 | | |
71 | | // NativeNumber, represent numbers using CJK or other digits if nNum>0, |
72 | | // eLang specifies the Locale to use. |
73 | | class SvNumberNatNum |
74 | | { |
75 | | OUString sParams; // For [NatNum12 ordinal-number]-like syntax |
76 | | LanguageType eLang; |
77 | | sal_uInt8 nNum; |
78 | | bool bDBNum :1; // DBNum, to be converted to NatNum |
79 | | bool bDate :1; // Used in date? (needed for DBNum/NatNum mapping) |
80 | | bool bSet :1; // If set, since NatNum0 is possible |
81 | | |
82 | | public: |
83 | | |
84 | | static sal_uInt8 MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, bool bDate ); |
85 | | static sal_uInt8 MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, bool bDate ); |
86 | | |
87 | 90.1M | SvNumberNatNum() : eLang( LANGUAGE_DONTKNOW ), nNum(0), |
88 | 90.1M | bDBNum(false), bDate(false), bSet(false) {} |
89 | 98.8k | bool IsComplete() const { return bSet && eLang != LANGUAGE_DONTKNOW; } |
90 | 48.7M | sal_uInt8 GetNatNum() const { return bDBNum ? MapDBNumToNatNum( nNum, eLang, bDate ) : nNum; } |
91 | 0 | sal_uInt8 GetDBNum() const { return bDBNum ? nNum : MapNatNumToDBNum( nNum, eLang, bDate ); } |
92 | 2.16M | LanguageType GetLang() const { return eLang; } |
93 | 2.10M | void SetLang( LanguageType e ) { eLang = e; } |
94 | | void SetNum( sal_uInt8 nNumber, bool bDBNumber ) |
95 | 1.97M | { |
96 | 1.97M | nNum = nNumber; |
97 | 1.97M | bDBNum = bDBNumber; |
98 | 1.97M | bSet = true; |
99 | 1.97M | } |
100 | 54.3M | bool IsSet() const { return bSet; } |
101 | 1.97M | void SetDate( bool bDateP ) { bDate = bDateP; } |
102 | 1.92M | void SetParams(const OUString& s) { sParams = s; } |
103 | 1.93M | OUString const & GetParams() const { return sParams; } |
104 | | }; |
105 | | |
106 | | class CharClass; |
107 | | |
108 | | class ImpSvNumFor // One of four subformats of the format code string |
109 | | { |
110 | | public: |
111 | | ImpSvNumFor(); // Ctor without filling the Info |
112 | | ~ImpSvNumFor(); |
113 | | |
114 | | void Enlarge(sal_uInt16 nCount); // Init of arrays to the right size |
115 | | |
116 | | // if pSc is set, it is used to get the Color pointer |
117 | | void Copy( const ImpSvNumFor& rNumFor, const ImpSvNumberformatScan* pSc ); |
118 | | |
119 | | // Access to Info; call Enlarge before! |
120 | 53.8M | ImpSvNumberformatInfo& Info() { return aI;} |
121 | 2.99M | const ImpSvNumberformatInfo& Info() const { return aI; } |
122 | | |
123 | | // Get count of substrings (symbols) |
124 | 25.1M | sal_uInt16 GetCount() const { return nStringsCnt;} |
125 | | |
126 | 1.86M | const Color* GetColor() const { return pColor; } |
127 | | void SetColor(const Color* pCol, OUString const& rName) |
128 | 1.54M | { pColor = pCol; sColorName = rName; } |
129 | 2.17k | const OUString& GetColorName() const { return sColorName; } |
130 | | |
131 | | // new SYMBOLTYPE_CURRENCY in subformat? |
132 | | bool HasNewCurrency() const; |
133 | | bool GetNewCurrencySymbol( OUString& rSymbol, OUString& rExtension ) const; |
134 | | |
135 | | // [NatNum1], [NatNum2], ... |
136 | 1.97M | void SetNatNumNum( sal_uInt8 nNum, bool bDBNum ) { aNatNum.SetNum( nNum, bDBNum ); } |
137 | 2.10M | void SetNatNumLang( LanguageType eLang ) { aNatNum.SetLang( eLang ); } |
138 | 1.97M | void SetNatNumDate( bool bDate ) { aNatNum.SetDate( bDate ); } |
139 | 1.92M | void SetNatNumParams(const OUString& sParams) { aNatNum.SetParams(sParams); } |
140 | 107M | const SvNumberNatNum& GetNatNum() const { return aNatNum; } |
141 | | |
142 | | private: |
143 | | ImpSvNumberformatInfo aI; // helper struct for remaining information |
144 | | OUString sColorName; // color name |
145 | | const Color* pColor; // pointer to color of subformat |
146 | | sal_uInt16 nStringsCnt; // count of symbols |
147 | | SvNumberNatNum aNatNum; // DoubleByteNumber |
148 | | |
149 | | }; |
150 | | |
151 | | class SVL_DLLPUBLIC SvNumberformat |
152 | | { |
153 | | struct SAL_DLLPRIVATE LocaleType |
154 | | { |
155 | | enum class Substitute : sal_uInt8 |
156 | | { |
157 | | NONE, |
158 | | TIME, |
159 | | LONGDATE |
160 | | }; |
161 | | |
162 | | LanguageType meLanguage; |
163 | | LanguageType meLanguageWithoutLocaleData; |
164 | | Substitute meSubstitute; |
165 | | sal_uInt8 mnNumeralShape; |
166 | | sal_uInt8 mnCalendarType; |
167 | | |
168 | | OUString generateCode() const; |
169 | | |
170 | | LocaleType(); |
171 | | LocaleType(sal_uInt32 nRawCode); |
172 | | |
173 | | bool isPlainLocale() const; |
174 | | }; |
175 | | |
176 | | public: |
177 | | // Normal ctor |
178 | | SvNumberformat( OUString& rString, |
179 | | ImpSvNumberformatScan* pSc, |
180 | | ImpSvNumberInputScan* pISc, |
181 | | const NativeNumberWrapper& rNatNum, |
182 | | sal_Int32& nCheckPos, |
183 | | LanguageType& eLan, |
184 | | bool bReplaceBooleanEquivalent = true ); |
185 | | |
186 | | // Copy ctor |
187 | | SvNumberformat( SvNumberformat const & rFormat ); |
188 | | |
189 | | // Copy ctor with exchange of format code string scanner (used in merge) |
190 | | SvNumberformat( SvNumberformat const & rFormat, ImpSvNumberformatScan& rSc ); |
191 | | |
192 | | ~SvNumberformat(); |
193 | | |
194 | | /// Get type of format, may include css::util::NumberFormat::DEFINED bit |
195 | 846k | SvNumFormatType GetType() const { return eType; } |
196 | | |
197 | | /// Get type of format, does not include css::util::NumberFormat::DEFINED |
198 | 6.37M | SvNumFormatType GetMaskedType() const { return eType & ~SvNumFormatType::DEFINED; } |
199 | | |
200 | 1.36M | void SetType(SvNumFormatType eSetType) { eType = eSetType; } |
201 | | // Standard means the I18N defined standard format of this type |
202 | 2.17M | void SetStandard() { bStandard = true; } |
203 | 92.0M | bool IsStandard() const { return bStandard; } |
204 | | |
205 | | // If this format is an additional built-in format defined by i18n. |
206 | 6.74M | void SetAdditionalBuiltin() { bAdditionalBuiltin = true; } |
207 | 0 | bool IsAdditionalBuiltin() const { return bAdditionalBuiltin; } |
208 | | |
209 | 679M | LanguageType GetLanguage() const { return maLocale.meLanguage;} |
210 | | |
211 | | /** If the format is a placeholder and needs to be substituted. */ |
212 | | bool IsSubstituted() const |
213 | 25.8M | { |
214 | 25.8M | return maLocale.meSubstitute != LocaleType::Substitute::NONE; |
215 | 25.8M | } |
216 | | |
217 | | /** If the format is a placeholder for the system time format and needs to |
218 | | be substituted during formatting time. |
219 | | */ |
220 | | bool IsSystemTimeFormat() const |
221 | 4.11k | { |
222 | 4.11k | return maLocale.meSubstitute == LocaleType::Substitute::TIME && maLocale.meLanguage == LANGUAGE_SYSTEM; |
223 | 4.11k | } |
224 | | |
225 | | /** If the format is a placeholder for the system long date format and needs |
226 | | to be substituted during formatting time. |
227 | | */ |
228 | | bool IsSystemLongDateFormat() const |
229 | 2.54k | { |
230 | 2.54k | return maLocale.meSubstitute == LocaleType::Substitute::LONGDATE && maLocale.meLanguage == LANGUAGE_SYSTEM; |
231 | 2.54k | } |
232 | | |
233 | | /** If the format is a MM:SS or [MM]:SS format, or MM:[SS] (sic!) or even |
234 | | MM:SS.00 or [MM]:SS.00 or MM:[SS].00 |
235 | | */ |
236 | | bool IsMinuteSecondFormat() const; |
237 | | |
238 | 574M | const OUString& GetFormatstring() const { return sFormatstring; } |
239 | | |
240 | | // Build a format string of application defined keywords |
241 | | OUString GetMappedFormatstring( const NfKeywordTable& rKeywords, |
242 | | const LocaleDataWrapper& rLoc, |
243 | | LanguageType nOriginalLang = LANGUAGE_DONTKNOW, |
244 | | bool bSystemLanguage = false ) const; |
245 | | |
246 | | /** |
247 | | * Get output string from a numeric value that fits the number of |
248 | | * characters specified. |
249 | | */ |
250 | | bool GetOutputString( double fNumber, sal_uInt16 nCharCount, OUString& rOutString, |
251 | | const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang ) const; |
252 | | |
253 | | // bStarFlag: Take *n format as ESC n |
254 | | bool GetOutputString( double fNumber, OUString& OutString, const Color** ppColor, const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang, bool bStarFlag = false) const; |
255 | | void GetOutputString( std::u16string_view sString, OUString& OutString, const Color** ppColor, bool bStarFlag = false) const; |
256 | | |
257 | | // True if type text |
258 | 642k | bool IsTextFormat() const { return bool(eType & SvNumFormatType::TEXT); } |
259 | | // True if 4th subformat present |
260 | | bool HasTextFormat() const |
261 | 493k | { |
262 | 493k | return (NumFor[3].GetCount() > 0) || |
263 | 493k | (NumFor[3].Info().eScannedType == SvNumFormatType::TEXT); |
264 | 493k | } |
265 | | |
266 | | void GetFormatSpecialInfo(bool& bThousand, |
267 | | bool& IsRed, |
268 | | sal_uInt16& nPrecision, |
269 | | sal_uInt16& nLeadingCnt) const; |
270 | | |
271 | | /// Get index of subformat (0..3) according to conditions and fNumber value |
272 | | sal_uInt16 GetSubformatIndex( double fNumber ) const; |
273 | | |
274 | | /// Count of decimal precision |
275 | | sal_uInt16 GetFormatPrecision( sal_uInt16 nIx = 0 ) const |
276 | 0 | { return NumFor[nIx].Info().nCntPost; } |
277 | | |
278 | | /// Count of integer digits |
279 | | sal_uInt16 GetFormatIntegerDigits( sal_uInt16 nIx = 0 ) const |
280 | 0 | { return NumFor[nIx].Info().nCntPre; } |
281 | | |
282 | | /** Count of hidden integer digits with thousands divisor: |
283 | | formats like "0," to show only thousands. |
284 | | |
285 | | Works only with SvNumFormatType::NUMBER and SvNumFormatType::CURRENCY, |
286 | | returns 0 otherwise. |
287 | | |
288 | | Returns SvNumberFormatter::UNLIMITED_PRECISION for formats that contain |
289 | | the General keyword. |
290 | | */ |
291 | | sal_uInt16 GetThousandDivisorPrecision( sal_uInt16 nIx = 0 ) const; |
292 | | |
293 | | //! Read/write access on a special sal_uInt16 component, may only be used on the |
294 | | //! standard format 0, 10000, ... and only by the number formatter! |
295 | 1.08M | struct FormatterPrivateAccess { friend SvNumberFormatter; friend SvNFFormatData; private: FormatterPrivateAccess() {} }; |
296 | | sal_uInt16 GetLastInsertKey( const FormatterPrivateAccess& ) const |
297 | 421k | { return NumFor[0].Info().nThousand; } |
298 | | void SetLastInsertKey( sal_uInt16 nKey, const FormatterPrivateAccess& ) |
299 | 662k | { NumFor[0].Info().nThousand = nKey; } |
300 | | |
301 | | //! Only onLoad: convert from stored to current system language/country |
302 | | void ConvertLanguage( SvNumberFormatter& rConverter, |
303 | | LanguageType eConvertFrom, LanguageType eConvertTo ); |
304 | | |
305 | | // Substring of a subformat code nNumFor (0..3) |
306 | | // nPos == 0xFFFF => last substring |
307 | | // bString==true: first/last SYMBOLTYPE_STRING or SYMBOLTYPE_CURRENCY |
308 | | const OUString* GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos, |
309 | | bool bString = false ) const; |
310 | | |
311 | | // Subtype of a subformat code nNumFor (0..3) |
312 | | // nPos == 0xFFFF => last substring |
313 | | short GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos ) const; |
314 | | |
315 | | OUString GetPercentString( sal_uInt16 nNumFor = 0 ) const; |
316 | | |
317 | | OUString GetDenominatorString( sal_uInt16 nNumFor ) const; |
318 | | OUString GetNumeratorString( sal_uInt16 nNumFor ) const; |
319 | | OUString GetIntegerFractionDelimiterString( sal_uInt16 nNumFor ) const; |
320 | | /// Round fNumber to its fraction representation |
321 | | double GetRoundFractionValue ( double fNumber ) const; |
322 | | |
323 | | /// Create a format string for time with a new precision |
324 | | OUString GetFormatStringForTimePrecision( int nPrecision ) const; |
325 | | |
326 | | |
327 | | /** If the count of string elements (substrings, ignoring [modifiers] and |
328 | | so on) in a subformat code nNumFor (0..3) is equal to the given number. |
329 | | Used by ImpSvNumberInputScan::IsNumberFormatMain() to detect a matched |
330 | | format. */ |
331 | | bool IsNumForStringElementCountEqual( sal_uInt16 nNumFor, sal_uInt16 nAllCount, |
332 | | sal_uInt16 nNumCount ) const |
333 | 22.4k | { |
334 | 22.4k | if ( nNumFor < 4 ) |
335 | 22.4k | { |
336 | | // First try a simple approach. Note that this is called only |
337 | | // if all MidStrings did match so far, to verify that all |
338 | | // strings of the format were matched and not just the starting |
339 | | // sequence, so we don't have to check if GetCount() includes |
340 | | // [modifiers] or anything else if both counts are equal. |
341 | 22.4k | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
342 | 22.4k | if ( nAllCount == nCnt ) |
343 | 8.48k | return true; |
344 | 13.9k | if ( nAllCount < nCnt ) // check ignoring [modifiers] and so on |
345 | 13.3k | return ImpGetNumForStringElementCount( nNumFor ) == |
346 | 13.3k | (nAllCount - nNumCount); |
347 | 13.9k | } |
348 | 562 | return false; |
349 | 22.4k | } |
350 | | /** Get the count of numbers among string elements **/ |
351 | | sal_uInt16 GetNumForNumberElementCount( sal_uInt16 nNumFor ) const; |
352 | | |
353 | | /** Get the scanned type of the specified subformat. */ |
354 | | SvNumFormatType GetNumForInfoScannedType( sal_uInt16 nNumFor ) const |
355 | 2.50k | { |
356 | 2.50k | return (nNumFor < 4) ? NumFor[nNumFor].Info().eScannedType : SvNumFormatType::UNDEFINED; |
357 | 2.50k | } |
358 | | |
359 | | // Whether the second subformat code is really for negative numbers |
360 | | // or another limit set. |
361 | | bool IsSecondSubformatRealNegative() const |
362 | 51.9k | { |
363 | 51.9k | return fLimit1 == 0.0 && fLimit2 == 0.0 && |
364 | 51.0k | ( (eOp1 == NUMBERFORMAT_OP_GE && eOp2 == NUMBERFORMAT_OP_NO) || |
365 | 23.3k | (eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT) || |
366 | 13.6k | (eOp1 == NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO) ); |
367 | 51.9k | } |
368 | | |
369 | | // Whether the first subformat code is really for negative numbers |
370 | | // or another limit set. |
371 | | bool IsFirstSubformatRealNegative() const |
372 | 702 | { |
373 | 702 | return fLimit1 == 0.0 && fLimit2 == 0.0 && |
374 | 702 | ((eOp1 == NUMBERFORMAT_OP_LT && |
375 | 28 | (eOp2 == NUMBERFORMAT_OP_GT || eOp2 == NUMBERFORMAT_OP_EQ || |
376 | 28 | eOp2 == NUMBERFORMAT_OP_GE || eOp2 == NUMBERFORMAT_OP_NO)) || |
377 | 674 | (eOp1 == NUMBERFORMAT_OP_LE && |
378 | 0 | (eOp2 == NUMBERFORMAT_OP_NO || eOp2 == NUMBERFORMAT_OP_GT))); |
379 | 702 | } |
380 | | |
381 | | // Whether the negative format is without a sign or not |
382 | | bool IsNegativeWithoutSign() const; |
383 | | |
384 | | bool IsNegativeInBracket() const; |
385 | | |
386 | | bool HasPositiveBracketPlaceholder() const; |
387 | | |
388 | | // Whether a new SYMBOLTYPE_CURRENCY is contained in the format |
389 | | bool HasNewCurrency() const; |
390 | | |
391 | | // strip [$-yyy] from all [$xxx-yyy] leaving only xxx's, |
392 | | static OUString StripNewCurrencyDelimiters( const OUString& rStr ); |
393 | | |
394 | | // If a new SYMBOLTYPE_CURRENCY is contained if the format is of type |
395 | | // css::util::NumberFormat::CURRENCY, and if so the symbol xxx and the extension nnn |
396 | | // of [$xxx-nnn] are returned |
397 | | bool GetNewCurrencySymbol( OUString& rSymbol, OUString& rExtension ) const; |
398 | | |
399 | | static bool HasStringNegativeSign( const OUString& rStr ); |
400 | | |
401 | | /** |
402 | | Whether a character at position nPos is somewhere between two matching |
403 | | cQuote or not. |
404 | | If nPos points to a cQuote, a true is returned on an opening cQuote, |
405 | | a false is returned on a closing cQuote. |
406 | | A cQuote between quotes may be escaped by a cEscIn, a cQuote outside of |
407 | | quotes may be escaped by a cEscOut. |
408 | | The default '\0' results in no escapement possible. |
409 | | Defaults are set right according to the "unlogic" of the Numberformatter |
410 | | */ |
411 | | static bool IsInQuote( const OUString& rString, sal_Int32 nPos, |
412 | | sal_Unicode cQuote = '"', |
413 | | sal_Unicode cEscIn = '\0', sal_Unicode cEscOut = '\\' ); |
414 | | |
415 | | /** |
416 | | Return the position of a matching closing cQuote if the character at |
417 | | position nPos is between two matching cQuote, otherwise return -1. |
418 | | If nPos points to an opening cQuote the position of the matching |
419 | | closing cQuote is returned. |
420 | | If nPos points to a closing cQuote nPos is returned. |
421 | | If nPos points into a part which starts with an opening cQuote but has |
422 | | no closing cQuote, rString.Len() is returned. |
423 | | Uses <method>IsInQuote</method> internally, so you don't have to call |
424 | | that prior to a call of this method. |
425 | | */ |
426 | | static sal_Int32 GetQuoteEnd( const OUString& rString, sal_Int32 nPos, |
427 | | sal_Unicode cQuote = '"', |
428 | | sal_Unicode cEscIn = '\0' ); |
429 | | |
430 | | void SetComment( const OUString& rStr ) |
431 | 723k | { sComment = rStr; } |
432 | 0 | const OUString& GetComment() const { return sComment; } |
433 | | |
434 | | /** Insert the number of blanks into the string that is needed to simulate |
435 | | the width of character c for underscore formats */ |
436 | | static sal_Int32 InsertBlanks( OUString& r, sal_Int32 nPos, sal_Unicode c ) |
437 | 0 | { |
438 | 0 | sal_Int32 result; |
439 | 0 | OUStringBuffer sBuff(r); |
440 | 0 |
|
441 | 0 | result = InsertBlanks(sBuff, nPos, c); |
442 | 0 | r = sBuff.makeStringAndClear(); |
443 | 0 |
|
444 | 0 | return result; |
445 | 0 | } |
446 | | |
447 | | /** Insert the number of blanks into the string that is needed to simulate |
448 | | the width of character c for underscore formats */ |
449 | | static sal_Int32 InsertBlanks( OUStringBuffer& r, sal_Int32 nPos, sal_Unicode c ); |
450 | | |
451 | | /// One of YMD,DMY,MDY if date format |
452 | | DateOrder GetDateOrder() const; |
453 | | |
454 | | /** A coded value of the exact YMD combination used, if date format. |
455 | | For example: YYYY-MM-DD => ('Y' << 16) | ('M' << 8) | 'D' |
456 | | or: MM/YY => ('M' << 8) | 'Y' */ |
457 | | sal_uInt32 GetExactDateOrder() const; |
458 | | |
459 | | // used in XML export |
460 | | void GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1, |
461 | | SvNumberformatLimitOps& rOper2, double& rVal2 ) const; |
462 | | const Color* GetColor( sal_uInt16 nNumFor ) const; |
463 | | void GetNumForInfo( sal_uInt16 nNumFor, SvNumFormatType& rScannedType, |
464 | | bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nLeadingCnt ) const; |
465 | | |
466 | | // rAttr.Number not empty if NatNum attributes are to be stored |
467 | | void GetNatNumXml( |
468 | | css::i18n::NativeNumberXmlAttributes2& rAttr, |
469 | | sal_uInt16 nNumFor, |
470 | | const NativeNumberWrapper& rNatNum ) const; |
471 | | /** Return empty string if no NatNum modifier or invalid nNumFor |
472 | | otherwise return "[NatNum1]" or "[NatNum12 ...]" */ |
473 | | OUString GetNatNumModifierString( sal_uInt16 nNumFor = 0 ) const; |
474 | | |
475 | | /** Switches to the first non-"gregorian" calendar, but only if the current |
476 | | calendar is "gregorian"; original calendar name and date/time returned, |
477 | | but only if calendar switched and rOrgCalendar was empty. */ |
478 | | static void SwitchToOtherCalendar( const SvNFLanguageData& rCurrentLang, OUString& rOrgCalendar, double& fOrgDateTime, CalendarWrapper& rCal ); |
479 | | |
480 | | /** Switches to the "gregorian" calendar, but only if the current calendar |
481 | | is non-"gregorian" and rOrgCalendar is not empty. Thus a preceding |
482 | | ImpSwitchToOtherCalendar() call should have been placed prior to |
483 | | calling this method. */ |
484 | | static void SwitchToGregorianCalendar( const SvNFLanguageData& rCurrentLang, std::u16string_view rOrgCalendar, double fOrgDateTime, CalendarWrapper& rCal ); |
485 | | |
486 | | #ifdef THE_FUTURE |
487 | | /** Switches to the first specified calendar, if any, in subformat nNumFor |
488 | | (0..3). Original calendar name and date/time returned, but only if |
489 | | calendar switched and rOrgCalendar was empty. |
490 | | |
491 | | @return |
492 | | <TRUE/> if a calendar was specified and switched to, |
493 | | <FALSE/> else. |
494 | | */ |
495 | | bool SwitchToSpecifiedCalendar( const SvNFLanguageData& rCurrentLang, OUString& rOrgCalendar, double& fOrgDateTime, |
496 | | sal_uInt16 nNumFor ) const |
497 | | { |
498 | | if ( nNumFor < 4 ) |
499 | | return ImpSwitchToSpecifiedCalendar( rCurrentLang, rOrgCalendar, |
500 | | fOrgDateTime, NumFor[nNumFor] ); |
501 | | return false; |
502 | | } |
503 | | #endif |
504 | | |
505 | | /// Whether it's a (YY)YY-M(M)-D(D) format. |
506 | | bool IsIso8601( sal_uInt16 nNumFor ) const |
507 | 710 | { |
508 | 710 | if ( nNumFor < 4 ) |
509 | 710 | return ImpIsIso8601( NumFor[nNumFor]); |
510 | 0 | return false; |
511 | 710 | } |
512 | | |
513 | | private: |
514 | | ImpSvNumFor NumFor[4]; // Array for the 4 subformats |
515 | | OUString sFormatstring; // The format code string |
516 | | OUString sComment; // Comment, since number formatter version 6 |
517 | | double fLimit1; // Value for first condition |
518 | | double fLimit2; // Value for second condition |
519 | | ImpSvNumberformatScan& rScan; // Format code scanner |
520 | | LocaleType maLocale; // Language/country of the format, numeral shape and calendar type from Excel. |
521 | | SvNumberformatLimitOps eOp1; // Operator for first condition |
522 | | SvNumberformatLimitOps eOp2; // Operator for second condition |
523 | | SvNumFormatType eType; // Type of format |
524 | | bool bAdditionalBuiltin; // If this is an additional built-in format defined by i18n |
525 | | bool bStandard; // If this is a default standard format |
526 | | bool bIsUsed; // Flag as used for storing |
527 | | |
528 | | SVL_DLLPRIVATE sal_uInt16 ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const; |
529 | | |
530 | | #ifdef THE_FUTURE |
531 | | SVL_DLLPRIVATE bool ImpSwitchToSpecifiedCalendar( const SvNFLanguageData& rCurrentLang, |
532 | | OUString& rOrgCalendar, |
533 | | double& fOrgDateTime, |
534 | | const ImpSvNumFor& rNumFor ) const; |
535 | | #endif |
536 | | |
537 | | /** Whether to use possessive genitive case month name, or partitive case |
538 | | month name, instead of nominative name (noun). |
539 | | |
540 | | @param io_nState |
541 | | 0: execute check <br> |
542 | | set to 1 if nominative case is returned, <br> |
543 | | set to 2 if genitive case is returned, <br> |
544 | | set to 3 if partitive case is returned <br> |
545 | | 1: don't execute check, return nominative case <br> |
546 | | 2: don't execute check, return genitive case <br> |
547 | | 3: don't execute check, return partitive case <br> |
548 | | |
549 | | @param eCodeType |
550 | | a NfKeywordIndex, must designate a month type code |
551 | | |
552 | | @returns one of css::i18n::CalendarDisplayCode values |
553 | | according to eCodeType and the check executed (or passed). |
554 | | */ |
555 | | SVL_DLLPRIVATE static sal_Int32 ImpUseMonthCase( int & io_nState, const ImpSvNumFor& rNumFor, NfKeywordIndex eCodeType ); |
556 | | |
557 | | /// Whether it's a (YY)YY-M(M)-D(D) format. |
558 | | SVL_DLLPRIVATE bool ImpIsIso8601( const ImpSvNumFor& rNumFor ) const; |
559 | | |
560 | | const CharClass& rChrCls() const; |
561 | | const LocaleDataWrapper& rLoc() const; |
562 | | |
563 | | // divide in substrings and color conditions |
564 | | SVL_DLLPRIVATE short ImpNextSymbol( OUStringBuffer& rString, |
565 | | sal_Int32& nPos, |
566 | | OUString& sSymbol ) const; |
567 | | |
568 | | // read string until ']' and strip blanks (after condition) |
569 | | SVL_DLLPRIVATE static sal_Int32 ImpGetNumber( OUStringBuffer& rString, |
570 | | sal_Int32& nPos, |
571 | | OUString& sSymbol ); |
572 | | |
573 | | /** |
574 | | * Parse the content of '[$-xxx] or '[$-xxxxxxxx]' and extract the locale |
575 | | * type from it. Given the string, start parsing at position specified by |
576 | | * nPos, and store the end position with nPos when the parsing is |
577 | | * complete. The nPos should point to the '$' before the parsing, and to |
578 | | * the closing bracket after the parsing. When the content is [$-xxx], |
579 | | * the xxx part represents the language type (aka LCID) in hex numerals. |
580 | | * When the content is [$-xxxxxxxx] the last 4 digits represent the LCID |
581 | | * (again in hex), the next 2 digits represent the calendar type, and the |
582 | | * 2 highest digits (if exists) is the numeral shape. |
583 | | * |
584 | | * @reference |
585 | | * http://office.microsoft.com/en-us/excel-help/creating-international-number-formats-HA001034635.aspx |
586 | | * |
587 | | * @param rString input string |
588 | | * @param nPos position (see above). |
589 | | * |
590 | | * @return struct containing numeral shape, calendar type, and LCID that |
591 | | * specifies language type. See i18nlangtag/lang.h for a complete |
592 | | * list of language types. These numbers also correspond with the |
593 | | * numbers used by Microsoft Office. |
594 | | */ |
595 | | SVL_DLLPRIVATE static LocaleType ImpGetLocaleType( std::u16string_view rString, sal_Int32& nPos ); |
596 | | |
597 | | /** Obtain calendar and numerals from a LocaleType that was parsed from a |
598 | | LCID with ImpGetLocaleType(). |
599 | | |
600 | | Inserts a NatNum modifier to rString at nPos if needed as determined |
601 | | from the numeral code. |
602 | | |
603 | | @ATTENTION: may modify <member>maLocale</member> to make it follow |
604 | | aTmpLocale, in which case also nLang is adapted. |
605 | | |
606 | | @returns a string with the calendar if one was determined from the |
607 | | calendar code, else an empty string. The calendar string needs to be |
608 | | inserted at a proper position to rString after all bracketed prefixes. |
609 | | */ |
610 | | SVL_DLLPRIVATE OUString ImpObtainCalendarAndNumerals( OUStringBuffer & rString, |
611 | | sal_Int32 nPos, |
612 | | LanguageType & nLang, |
613 | | const LocaleType & aTmpLocale ); |
614 | | |
615 | | // standard number output |
616 | | SVL_DLLPRIVATE void ImpGetOutputStandard(double& fNumber, OUString& OutString, |
617 | | const NativeNumberWrapper& rNatNum, |
618 | | const SvNFLanguageData& rCurrentLang) const; |
619 | | SVL_DLLPRIVATE void ImpGetOutputStandard(double& fNumber, OUStringBuffer& OutString, |
620 | | const NativeNumberWrapper& rNatNum, |
621 | | const SvNFLanguageData& rCurrentLang) const; |
622 | | SVL_DLLPRIVATE void ImpGetOutputStdToPrecision(double& rNumber, OUString& rOutString, sal_uInt16 nPrecision, |
623 | | const NativeNumberWrapper& rNatNum, |
624 | | const SvNFLanguageData& rCurrentLang) const; |
625 | | // numbers in input line |
626 | | SVL_DLLPRIVATE void ImpGetOutputInputLine( double fNumber, OUString& OutString, |
627 | | const SvNFLanguageData& rCurrentLang ) const; |
628 | | |
629 | | // check subcondition |
630 | | // OP undefined => -1 |
631 | | // else 0 or 1 |
632 | | SVL_DLLPRIVATE static short ImpCheckCondition(double fNumber, |
633 | | double fLimit, |
634 | | SvNumberformatLimitOps eOp); |
635 | | |
636 | | // Helper function for number strings |
637 | | // append string symbols, insert leading 0 or ' ', or ... |
638 | | SVL_DLLPRIVATE bool ImpNumberFill( |
639 | | const NativeNumberWrapper& rNatNum, |
640 | | const SvNFLanguageData& rCurrentLang, |
641 | | OUStringBuffer& sStr, |
642 | | double& rNumber, |
643 | | sal_Int32& k, |
644 | | sal_uInt16& j, |
645 | | sal_uInt16 nIx, |
646 | | short eSymbolType, |
647 | | bool bStarFlag, |
648 | | bool bInsertRightBlank = false ) const; |
649 | | |
650 | | // Helper function to fill in the integer part and the group (AKA thousand) separators |
651 | | SVL_DLLPRIVATE bool ImpNumberFillWithThousands( |
652 | | const NativeNumberWrapper& rNatNum, |
653 | | const SvNFLanguageData& rCurrentLang, |
654 | | OUStringBuffer& sStr, |
655 | | double& rNumber, |
656 | | sal_Int32 k, |
657 | | sal_uInt16 j, |
658 | | sal_uInt16 nIx, |
659 | | sal_Int32 nDigCnt, |
660 | | bool bStarFlag, |
661 | | bool bAddDecSep = true ) const; |
662 | | |
663 | | // Helper function to fill in the group (AKA thousand) separators |
664 | | // or to skip additional digits |
665 | | SVL_DLLPRIVATE void ImpDigitFill( const SvNFLanguageData& rCurrentLang, |
666 | | OUStringBuffer& sStr, |
667 | | sal_Int32 nStart, |
668 | | sal_Int32& k, |
669 | | sal_uInt16 nIx, |
670 | | sal_Int32 & nDigitCount, |
671 | | utl::DigitGroupingIterator & ) const; |
672 | | |
673 | | SVL_DLLPRIVATE bool ImpDecimalFill(const NativeNumberWrapper& rNatNum, |
674 | | const SvNFLanguageData& rCurrentLang, |
675 | | OUStringBuffer& sStr, |
676 | | double& rNumber, |
677 | | sal_Int32 nDecPos, |
678 | | sal_uInt16 j, |
679 | | sal_uInt16 nIx, |
680 | | bool bInteger, |
681 | | bool bStarFlag) const; |
682 | | |
683 | | /** Calculate each element of fraction: |
684 | | * integer part, numerator part, denominator part |
685 | | * @param fNumber value to be represented as fraction. Will contain absolute fractional part |
686 | | * @param nIx subformat number 0..3 |
687 | | * @param fIntPart integral part of fraction |
688 | | * @param nFrac numerator of fraction |
689 | | * @param nDic denominator of fraction |
690 | | */ |
691 | | SVL_DLLPRIVATE void ImpGetFractionElements( double& fNumber, |
692 | | sal_uInt16 nIx, |
693 | | double& fIntPart, |
694 | | sal_Int64& nFrac, |
695 | | sal_Int64& nDiv ) const; |
696 | | SVL_DLLPRIVATE bool ImpGetFractionOutput(double fNumber, |
697 | | sal_uInt16 nIx, |
698 | | bool bStarFlag, |
699 | | const NativeNumberWrapper& rNatNum, |
700 | | const SvNFLanguageData& rCurrentLang, |
701 | | OUStringBuffer& OutString) const; |
702 | | SVL_DLLPRIVATE bool ImpGetScientificOutput(double fNumber, |
703 | | sal_uInt16 nIx, |
704 | | bool bStarFlag, |
705 | | const NativeNumberWrapper& rNatNum, |
706 | | const SvNFLanguageData& rCurrentLang, |
707 | | OUStringBuffer& OutString) const; |
708 | | |
709 | | SVL_DLLPRIVATE bool ImpGetDateOutput( double fNumber, |
710 | | sal_uInt16 nIx, |
711 | | bool bStarFlag, |
712 | | const NativeNumberWrapper& rNatNum, |
713 | | const SvNFLanguageData& rCurrentLang, |
714 | | OUStringBuffer& OutString ) const; |
715 | | SVL_DLLPRIVATE bool ImpGetTimeOutput( double fNumber, |
716 | | sal_uInt16 nIx, |
717 | | bool bStarFlag, |
718 | | const NativeNumberWrapper& rNatNum, |
719 | | const SvNFLanguageData& rCurrentLang, |
720 | | OUStringBuffer& OutString ) const; |
721 | | SVL_DLLPRIVATE bool ImpGetDateTimeOutput( double fNumber, |
722 | | sal_uInt16 nIx, |
723 | | bool bStarFlag, |
724 | | const NativeNumberWrapper& rNatNum, |
725 | | const SvNFLanguageData& rCurrentLang, |
726 | | OUStringBuffer& OutString ) const; |
727 | | |
728 | | // Switches to the "gregorian" calendar if the current calendar is |
729 | | // non-"gregorian" and the era is a "Dummy" era of a calendar which doesn't |
730 | | // know a "before" era (like zh_TW ROC or ja_JP Gengou). If switched and |
731 | | // rOrgCalendar was "gregorian" the string is emptied. If rOrgCalendar was |
732 | | // empty the previous calendar name and date/time are returned. |
733 | | SVL_DLLPRIVATE static bool ImpFallBackToGregorianCalendar(const SvNFLanguageData& rCurrentLang, |
734 | | OUString& rOrgCalendar, |
735 | | double& fOrgDateTime, |
736 | | CalendarWrapper& rCal); |
737 | | |
738 | | // Append a "G" short era string of the given calendar. In the case of a |
739 | | // Gengou calendar this is a one character abbreviation, for other |
740 | | // calendars the XExtendedCalendar::getDisplayString() method is called. |
741 | | SVL_DLLPRIVATE static void ImpAppendEraG( OUStringBuffer& OutStringBuffer, const CalendarWrapper& rCal, |
742 | | sal_Int16 nNatNum ); |
743 | | |
744 | | SVL_DLLPRIVATE bool ImpGetLogicalOutput( double fNumber, |
745 | | sal_uInt16 nIx, |
746 | | const NativeNumberWrapper& rNatNum, |
747 | | const SvNFLanguageData& rCurrentLang, |
748 | | OUStringBuffer& OutString) const; |
749 | | |
750 | | SVL_DLLPRIVATE bool ImpGetNumberOutput( double fNumber, |
751 | | sal_uInt16 nIx, |
752 | | bool bStarFlag, |
753 | | const NativeNumberWrapper& rNatNum, |
754 | | const SvNFLanguageData& rCurrentLang, |
755 | | OUStringBuffer& OutString) const; |
756 | | |
757 | | SVL_DLLPRIVATE void ImpCopyNumberformat( const SvNumberformat& rFormat ); |
758 | | |
759 | | // normal digits or other digits, depending on ImpSvNumFor.aNatNum, |
760 | | // [NatNum1], [NatNum2], ... |
761 | | SVL_DLLPRIVATE static OUString ImpGetNatNumString(const SvNumberNatNum& rNum, sal_Int64 nVal, |
762 | | sal_uInt16 nMinDigits, const NativeNumberWrapper& rNatNum); |
763 | | |
764 | | OUString ImpIntToString(const NativeNumberWrapper& rNatNum, sal_uInt16 nIx, sal_Int64 nVal, sal_uInt16 nMinDigits = 0 ) const |
765 | 22.4k | { |
766 | 22.4k | const SvNumberNatNum& rNum = NumFor[nIx].GetNatNum(); |
767 | 22.4k | if ( nMinDigits || rNum.IsComplete() ) |
768 | 11.5k | { |
769 | 11.5k | return ImpGetNatNumString( rNum, nVal, nMinDigits, rNatNum ); |
770 | 11.5k | } |
771 | 10.8k | return OUString::number(nVal); |
772 | 22.4k | } |
773 | | |
774 | | // Obtain the string of the fraction of second, without leading "0.", |
775 | | // rounded to nFractionDecimals (or nFractionDecimals+1 if |
776 | | // bAddOneRoundingDecimal==true but then truncated at nFractionDecimals, |
777 | | // for use with the result of tools::Time::GetClock()) with the length of |
778 | | // nFractionDecimals, unless nMinimumInputLineDecimals>0 is given for input |
779 | | // line string where extra trailing "0" are discarded. |
780 | | SVL_DLLPRIVATE sal_uInt16 ImpGetFractionOfSecondString( OUStringBuffer& rBuf, double fFractionOfSecond, |
781 | | int nFractionDecimals, bool bAddOneRoundingDecimal, sal_uInt16 nIx, sal_uInt16 nMinimumInputLineDecimals, |
782 | | const NativeNumberWrapper& rNatNum) const; |
783 | | |
784 | | // transliterate according to NativeNumber |
785 | | SVL_DLLPRIVATE static OUString impTransliterateImpl(const OUString& rStr, const SvNumberNatNum& rNum, sal_uInt16 nDateKey, |
786 | | const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang); |
787 | | |
788 | | OUString static impTransliterate(const OUString& rStr, const SvNumberNatNum& rNum, sal_uInt16 nDateKey, |
789 | | const NativeNumberWrapper& rNatNum, const SvNFLanguageData& rCurrentLang) |
790 | 0 | { |
791 | 0 | return rNum.IsComplete() ? impTransliterateImpl(rStr, rNum, nDateKey, rNatNum, rCurrentLang) : rStr; |
792 | 0 | } |
793 | | |
794 | | }; |
795 | | |
796 | | #endif // INCLUDED_SVL_ZFORMAT_HXX |
797 | | |
798 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |