/src/libreoffice/svl/source/numbers/zformat.cxx
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 | | |
20 | | #include <string_view> |
21 | | |
22 | | #include <o3tl/sprintf.hxx> |
23 | | #include <o3tl/string_view.hxx> |
24 | | #include <o3tl/numeric.hxx> |
25 | | #include <comphelper/string.hxx> |
26 | | #include <sal/log.hxx> |
27 | | #include <tools/debug.hxx> |
28 | | #include <tools/long.hxx> |
29 | | #include <i18nlangtag/mslangid.hxx> |
30 | | #include <rtl/math.hxx> |
31 | | #include <unotools/charclass.hxx> |
32 | | #include <unotools/calendarwrapper.hxx> |
33 | | #include <unotools/nativenumberwrapper.hxx> |
34 | | #include <com/sun/star/i18n/CalendarFieldIndex.hpp> |
35 | | #include <com/sun/star/i18n/CalendarDisplayIndex.hpp> |
36 | | #include <com/sun/star/i18n/CalendarDisplayCode.hpp> |
37 | | #include <com/sun/star/i18n/AmPmValue.hpp> |
38 | | #include <com/sun/star/i18n/NativeNumberMode.hpp> |
39 | | #include <com/sun/star/i18n/NativeNumberXmlAttributes2.hpp> |
40 | | |
41 | | #include <svl/zformat.hxx> |
42 | | #include "zforscan.hxx" |
43 | | |
44 | | #include "zforfind.hxx" |
45 | | #include <svl/zforlist.hxx> |
46 | | #include <unotools/digitgroupingiterator.hxx> |
47 | | #include <svl/nfsymbol.hxx> |
48 | | |
49 | | #include <cmath> |
50 | | #include <array> |
51 | | |
52 | | using namespace svt; |
53 | | |
54 | | namespace { |
55 | | |
56 | | constexpr OUString GREGORIAN = u"gregorian"_ustr; |
57 | | |
58 | | const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary... |
59 | | const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value. |
60 | | const double EXP_ABS_UPPER_BOUND = 1.0E15; // use exponential notation above that absolute value. |
61 | | // Back in time was E16 that lead |
62 | | // to display rounding errors, see |
63 | | // also sal/rtl/math.cxx |
64 | | // doubleToString() |
65 | | |
66 | | constexpr sal_Int32 kTimeSignificantRound = 7; // Round (date+)time at 7 decimals |
67 | | // (+5 of 86400 == 12 significant digits). |
68 | | |
69 | | const sal_Unicode cBlankDigit = 0x2007; // tdf#158890 use figure space for '?' |
70 | | } // namespace |
71 | | |
72 | | const double D_MAX_U_INT32 = double(0xffffffff); // 4294967295.0 |
73 | | constexpr double D_MAX_INTEGER = (sal_uInt64(1) << 53) - 1; |
74 | | |
75 | | const double D_MAX_D_BY_100 = 1.7E306; |
76 | | const double D_MIN_M_BY_1000 = 2.3E-305; |
77 | | |
78 | | const sal_uInt8 cCharWidths[ 128-32 ] = { |
79 | | 1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1, |
80 | | 2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2, |
81 | | 3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3, |
82 | | 2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2, |
83 | | 1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2, |
84 | | 2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1 |
85 | | }; |
86 | | |
87 | | // static |
88 | | sal_Int32 SvNumberformat::InsertBlanks( OUStringBuffer& r, sal_Int32 nPos, sal_Unicode c ) |
89 | 21.9k | { |
90 | 21.9k | if( c >= 32 ) |
91 | 21.9k | { |
92 | 21.9k | int n = 2; // Default for chars > 128 (HACK!) |
93 | 21.9k | if( c <= 127 ) |
94 | 20.1k | { |
95 | 20.1k | n = static_cast<int>(cCharWidths[ c - 32 ]); |
96 | 20.1k | } |
97 | 56.4k | while( n-- ) |
98 | 34.5k | { |
99 | 34.5k | r.insert( nPos++, ' '); |
100 | 34.5k | } |
101 | 21.9k | } |
102 | 21.9k | return nPos; |
103 | 21.9k | } |
104 | | |
105 | | static tools::Long GetPrecExp( double fAbsVal ) |
106 | 64.1k | { |
107 | 64.1k | DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" ); |
108 | 64.1k | if ( fAbsVal < 1e-7 || fAbsVal > 1e7 ) |
109 | 8.63k | { |
110 | | // Shear: whether it's faster or not, falls in between 1e6 and 1e7 |
111 | 8.63k | return static_cast<tools::Long>(floor( log10( fAbsVal ) )) + 1; |
112 | 8.63k | } |
113 | 55.4k | else |
114 | 55.4k | { |
115 | 55.4k | tools::Long nPrecExp = 1; |
116 | 62.5k | while( fAbsVal < 1 ) |
117 | 7.04k | { |
118 | 7.04k | fAbsVal *= 10; |
119 | 7.04k | nPrecExp--; |
120 | 7.04k | } |
121 | 140k | while( fAbsVal >= 10 ) |
122 | 84.8k | { |
123 | 84.8k | fAbsVal /= 10; |
124 | 84.8k | nPrecExp++; |
125 | 84.8k | } |
126 | 55.4k | return nPrecExp; |
127 | 55.4k | } |
128 | 64.1k | } |
129 | | |
130 | | /** |
131 | | * SvNumberformatInfo |
132 | | * */ |
133 | | |
134 | | void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nCnt ) |
135 | 4.60k | { |
136 | 10.3k | for (sal_uInt16 i = 0; i < nCnt; ++i) |
137 | 5.76k | { |
138 | 5.76k | sStrArray[i] = rNumFor.sStrArray[i]; |
139 | 5.76k | nTypeArray[i] = rNumFor.nTypeArray[i]; |
140 | 5.76k | } |
141 | 4.60k | eScannedType = rNumFor.eScannedType; |
142 | 4.60k | bThousand = rNumFor.bThousand; |
143 | 4.60k | nThousand = rNumFor.nThousand; |
144 | 4.60k | nCntPre = rNumFor.nCntPre; |
145 | 4.60k | nCntPost = rNumFor.nCntPost; |
146 | 4.60k | nCntExp = rNumFor.nCntExp; |
147 | 4.60k | } |
148 | | |
149 | | const std::map<LanguageType, std::array<sal_uInt8, 4>> tblDBNumToNatNum |
150 | | = { { primary(LANGUAGE_CHINESE), { 4, 5, 3, 0 } }, |
151 | | { primary(LANGUAGE_JAPANESE), { 4, 5, 3, 0 } }, |
152 | | { primary(LANGUAGE_KOREAN), { 4, 5, 6, 10 } } }; |
153 | | |
154 | | // static |
155 | | sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, bool bDate ) |
156 | 0 | { |
157 | 0 | sal_uInt8 nNatNum = 0; |
158 | 0 | eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc. |
159 | 0 | eLang = primary(eLang); // 10 bit primary language |
160 | 0 | if ( bDate ) |
161 | 0 | { |
162 | 0 | if ( nDBNum == 4 && eLang == primary(LANGUAGE_KOREAN) ) |
163 | 0 | { |
164 | 0 | nNatNum = 10; |
165 | 0 | } |
166 | 0 | else if ( nDBNum <= 3 ) |
167 | 0 | { |
168 | 0 | nNatNum = nDBNum; // known to be good for: zh,ja,ko / 1,2,3 |
169 | 0 | } |
170 | 0 | } |
171 | 0 | else |
172 | 0 | { |
173 | 0 | if (1 <= nDBNum && nDBNum <= 4) |
174 | 0 | { |
175 | 0 | auto const it = tblDBNumToNatNum.find(eLang); |
176 | 0 | if (it != tblDBNumToNatNum.end()) |
177 | 0 | nNatNum = it->second[nDBNum - 1]; |
178 | |
|
179 | 0 | } |
180 | 0 | } |
181 | 0 | return nNatNum; |
182 | 0 | } |
183 | | |
184 | | const std::map<LanguageType, std::array<sal_uInt8, 9>> tblNatNumToDBNum |
185 | | = { { primary(LANGUAGE_CHINESE), { 1, 0, 0, 1, 2, 3, 0, 0, 0 } }, |
186 | | { primary(LANGUAGE_JAPANESE), { 1, 2, 3, 1, 2, 3, 1, 2, 0 } }, |
187 | | { primary(LANGUAGE_KOREAN), { 1, 2, 3, 1, 2, 3, 1, 2, 4 } } }; |
188 | | |
189 | | // static |
190 | | sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, bool bDate ) |
191 | 0 | { |
192 | 0 | sal_uInt8 nDBNum = 0; |
193 | 0 | eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc. |
194 | 0 | eLang = primary(eLang); // 10 bit primary language |
195 | 0 | if ( bDate ) |
196 | 0 | { |
197 | 0 | if ( nNatNum == 10 && eLang == primary(LANGUAGE_KOREAN) ) |
198 | 0 | { |
199 | 0 | nDBNum = 4; |
200 | 0 | } |
201 | 0 | else if ( nNatNum <= 3 ) |
202 | 0 | { |
203 | 0 | nDBNum = nNatNum; // known to be good for: zh,ja,ko / 1,2,3 |
204 | 0 | } |
205 | 0 | } |
206 | 0 | else |
207 | 0 | { |
208 | 0 | if (1 <= nNatNum && nNatNum <= 9) |
209 | 0 | { |
210 | 0 | auto const it = tblNatNumToDBNum.find(eLang); |
211 | 0 | if (it != tblNatNumToDBNum.end()) |
212 | 0 | nDBNum = it->second[nNatNum - 1]; |
213 | 0 | } |
214 | 0 | } |
215 | 0 | return nDBNum; |
216 | 0 | } |
217 | | |
218 | | /** |
219 | | * SvNumFor |
220 | | */ |
221 | | |
222 | | ImpSvNumFor::ImpSvNumFor() |
223 | 100M | { |
224 | 100M | nStringsCnt = 0; |
225 | 100M | aI.eScannedType = SvNumFormatType::UNDEFINED; |
226 | 100M | aI.bThousand = false; |
227 | 100M | aI.nThousand = 0; |
228 | 100M | aI.nCntPre = 0; |
229 | 100M | aI.nCntPost = 0; |
230 | 100M | aI.nCntExp = 0; |
231 | 100M | pColor = nullptr; |
232 | 100M | } |
233 | | |
234 | | ImpSvNumFor::~ImpSvNumFor() |
235 | 100M | { |
236 | 100M | } |
237 | | |
238 | | void ImpSvNumFor::Enlarge(sal_uInt16 nCnt) |
239 | 29.0M | { |
240 | 29.0M | if ( nStringsCnt != nCnt ) |
241 | 29.0M | { |
242 | 29.0M | nStringsCnt = nCnt; |
243 | 29.0M | aI.nTypeArray.resize(nCnt); |
244 | 29.0M | aI.sStrArray.resize(nCnt); |
245 | 29.0M | } |
246 | 29.0M | } |
247 | | |
248 | | void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, const ImpSvNumberformatScan* pSc ) |
249 | 4.60k | { |
250 | 4.60k | Enlarge( rNumFor.nStringsCnt ); |
251 | 4.60k | aI.Copy( rNumFor.aI, nStringsCnt ); |
252 | 4.60k | sColorName = rNumFor.sColorName; |
253 | 4.60k | if ( pSc ) |
254 | 0 | { |
255 | 0 | pColor = pSc->GetColor( sColorName ); // #121103# don't copy pointer between documents |
256 | 0 | } |
257 | 4.60k | else |
258 | 4.60k | { |
259 | 4.60k | pColor = rNumFor.pColor; |
260 | 4.60k | } |
261 | 4.60k | aNatNum = rNumFor.aNatNum; |
262 | 4.60k | } |
263 | | |
264 | | bool ImpSvNumFor::HasNewCurrency() const |
265 | 0 | { |
266 | 0 | for ( sal_uInt16 j=0; j<nStringsCnt; j++ ) |
267 | 0 | { |
268 | 0 | if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY ) |
269 | 0 | { |
270 | 0 | return true; |
271 | 0 | } |
272 | 0 | } |
273 | 0 | return false; |
274 | 0 | } |
275 | | |
276 | | bool ImpSvNumFor::GetNewCurrencySymbol( OUString& rSymbol, |
277 | | OUString& rExtension ) const |
278 | 535k | { |
279 | 1.05M | for ( sal_uInt16 j=0; j<nStringsCnt; j++ ) |
280 | 540k | { |
281 | 540k | if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY ) |
282 | 16.2k | { |
283 | 16.2k | rSymbol = aI.sStrArray[j]; |
284 | 16.2k | if ( j < nStringsCnt-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT ) |
285 | 10.6k | { |
286 | 10.6k | rExtension = aI.sStrArray[j+1]; |
287 | 10.6k | } |
288 | 5.59k | else |
289 | 5.59k | { |
290 | 5.59k | rExtension.clear(); |
291 | 5.59k | } |
292 | 16.2k | return true; |
293 | 16.2k | } |
294 | 540k | } |
295 | | //! No Erase at rSymbol, rExtension |
296 | 519k | return false; |
297 | 535k | } |
298 | | |
299 | | /** |
300 | | * SvNumberformat |
301 | | */ |
302 | | |
303 | | namespace { |
304 | | |
305 | | enum BracketFormatSymbolType |
306 | | { |
307 | | BRACKET_SYMBOLTYPE_FORMAT = -1, // subformat string |
308 | | BRACKET_SYMBOLTYPE_COLOR = -2, // color |
309 | | BRACKET_SYMBOLTYPE_ERROR = -3, // error |
310 | | BRACKET_SYMBOLTYPE_DBNUM1 = -4, // DoubleByteNumber, represent numbers |
311 | | BRACKET_SYMBOLTYPE_DBNUM2 = -5, // using CJK characters, Excel compatible |
312 | | BRACKET_SYMBOLTYPE_DBNUM3 = -6, |
313 | | BRACKET_SYMBOLTYPE_DBNUM4 = -7, |
314 | | BRACKET_SYMBOLTYPE_DBNUM5 = -8, |
315 | | BRACKET_SYMBOLTYPE_DBNUM6 = -9, |
316 | | BRACKET_SYMBOLTYPE_DBNUM7 = -10, |
317 | | BRACKET_SYMBOLTYPE_DBNUM8 = -11, |
318 | | BRACKET_SYMBOLTYPE_DBNUM9 = -12, |
319 | | BRACKET_SYMBOLTYPE_LOCALE = -13, |
320 | | BRACKET_SYMBOLTYPE_NATNUM0 = -14, // Our NativeNumber support, ASCII |
321 | | BRACKET_SYMBOLTYPE_NATNUM1 = -15, // Our NativeNumber support, represent |
322 | | BRACKET_SYMBOLTYPE_NATNUM2 = -16, // numbers using CJK, CTL, ... |
323 | | BRACKET_SYMBOLTYPE_NATNUM3 = -17, |
324 | | BRACKET_SYMBOLTYPE_NATNUM4 = -18, |
325 | | BRACKET_SYMBOLTYPE_NATNUM5 = -19, |
326 | | BRACKET_SYMBOLTYPE_NATNUM6 = -20, |
327 | | BRACKET_SYMBOLTYPE_NATNUM7 = -21, |
328 | | BRACKET_SYMBOLTYPE_NATNUM8 = -22, |
329 | | BRACKET_SYMBOLTYPE_NATNUM9 = -23, |
330 | | BRACKET_SYMBOLTYPE_NATNUM10 = -24, |
331 | | BRACKET_SYMBOLTYPE_NATNUM11 = -25, |
332 | | BRACKET_SYMBOLTYPE_NATNUM12 = -26, |
333 | | BRACKET_SYMBOLTYPE_NATNUM13 = -27, |
334 | | BRACKET_SYMBOLTYPE_NATNUM14 = -28, |
335 | | BRACKET_SYMBOLTYPE_NATNUM15 = -29, |
336 | | BRACKET_SYMBOLTYPE_NATNUM16 = -30, |
337 | | BRACKET_SYMBOLTYPE_NATNUM17 = -31, |
338 | | BRACKET_SYMBOLTYPE_NATNUM18 = -32, |
339 | | BRACKET_SYMBOLTYPE_NATNUM19 = -33 |
340 | | }; |
341 | | |
342 | | } |
343 | | |
344 | | void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat ) |
345 | 1.15k | { |
346 | 1.15k | sFormatstring = rFormat.sFormatstring; |
347 | 1.15k | eType = rFormat.eType; |
348 | 1.15k | maLocale = rFormat.maLocale; |
349 | 1.15k | fLimit1 = rFormat.fLimit1; |
350 | 1.15k | fLimit2 = rFormat.fLimit2; |
351 | 1.15k | eOp1 = rFormat.eOp1; |
352 | 1.15k | eOp2 = rFormat.eOp2; |
353 | 1.15k | bStandard = rFormat.bStandard; |
354 | 1.15k | bIsUsed = rFormat.bIsUsed; |
355 | 1.15k | sComment = rFormat.sComment; |
356 | 1.15k | bAdditionalBuiltin = rFormat.bAdditionalBuiltin; |
357 | | |
358 | | // #121103# when copying between documents, get color pointers from own scanner |
359 | 1.15k | ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : nullptr; |
360 | | |
361 | 5.76k | for (sal_uInt16 i = 0; i < 4; i++) |
362 | 4.60k | { |
363 | 4.60k | NumFor[i].Copy(rFormat.NumFor[i], pColorSc); |
364 | 4.60k | } |
365 | 1.15k | } |
366 | | |
367 | | SvNumberformat::SvNumberformat( SvNumberformat const & rFormat ) |
368 | 576 | : rScan(rFormat.rScan) |
369 | 576 | { |
370 | 576 | ImpCopyNumberformat( rFormat ); |
371 | 576 | } |
372 | | |
373 | | SvNumberformat::SvNumberformat( SvNumberformat const & rFormat, ImpSvNumberformatScan& rSc ) |
374 | 0 | : rScan(rSc) |
375 | 0 | { |
376 | 0 | ImpCopyNumberformat( rFormat ); |
377 | 0 | } |
378 | | |
379 | | static bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType ) |
380 | 66.5M | { |
381 | 66.5M | if ( nSymbolType > 0 ) |
382 | 10.6k | { |
383 | 10.6k | return true; // conditions |
384 | 10.6k | } |
385 | 66.5M | switch ( nSymbolType ) |
386 | 66.5M | { |
387 | 3.43M | case BRACKET_SYMBOLTYPE_COLOR : |
388 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM1 : |
389 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM2 : |
390 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM3 : |
391 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM4 : |
392 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM5 : |
393 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM6 : |
394 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM7 : |
395 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM8 : |
396 | 3.43M | case BRACKET_SYMBOLTYPE_DBNUM9 : |
397 | 3.77M | case BRACKET_SYMBOLTYPE_LOCALE : |
398 | 3.77M | case BRACKET_SYMBOLTYPE_NATNUM0 : |
399 | 3.84M | case BRACKET_SYMBOLTYPE_NATNUM1 : |
400 | 3.85M | case BRACKET_SYMBOLTYPE_NATNUM2 : |
401 | 3.86M | case BRACKET_SYMBOLTYPE_NATNUM3 : |
402 | 3.86M | case BRACKET_SYMBOLTYPE_NATNUM4 : |
403 | 3.86M | case BRACKET_SYMBOLTYPE_NATNUM5 : |
404 | 3.86M | case BRACKET_SYMBOLTYPE_NATNUM6 : |
405 | 3.86M | case BRACKET_SYMBOLTYPE_NATNUM7 : |
406 | 3.86M | case BRACKET_SYMBOLTYPE_NATNUM8 : |
407 | 3.87M | case BRACKET_SYMBOLTYPE_NATNUM9 : |
408 | 3.87M | case BRACKET_SYMBOLTYPE_NATNUM10 : |
409 | 3.87M | case BRACKET_SYMBOLTYPE_NATNUM11 : |
410 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM12 : |
411 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM13 : |
412 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM14 : |
413 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM15 : |
414 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM16 : |
415 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM17 : |
416 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM18 : |
417 | 8.18M | case BRACKET_SYMBOLTYPE_NATNUM19 : |
418 | 8.18M | return true; |
419 | 66.5M | } |
420 | 58.3M | return false; |
421 | 66.5M | } |
422 | | |
423 | | /** Import extended LCID from Excel |
424 | | */ |
425 | | OUString SvNumberformat::ImpObtainCalendarAndNumerals( OUStringBuffer& rString, sal_Int32 nPos, |
426 | | LanguageType& nLang, const LocaleType& aTmpLocale ) |
427 | 120k | { |
428 | 120k | OUString sCalendar; |
429 | 120k | sal_uInt16 nNatNum = 0; |
430 | 120k | LanguageType nLocaleLang = MsLangId::getRealLanguage( maLocale.meLanguage ); |
431 | 120k | LanguageType nTmpLocaleLang = MsLangId::getRealLanguage( aTmpLocale.meLanguage ); |
432 | | /* NOTE: enhancement to allow other possible locale dependent |
433 | | * calendars and numerals. BUT only if our locale data allows it! For LCID |
434 | | * numerals and calendars see |
435 | | * http://office.microsoft.com/en-us/excel/HA010346351033.aspx |
436 | | * Calendar is inserted after |
437 | | * all prefixes have been consumed as it is actually a format modifier |
438 | | * and not a prefix. |
439 | | * Currently calendars are tied to the locale of the entire number |
440 | | * format, e.g. [~buddhist] in en_US doesn't work. |
441 | | * => Having different locales in sub formats does not work! |
442 | | * */ |
443 | | /* TODO: calendars could be tied to a sub format's NatNum info |
444 | | * instead, or even better be available for any locale. Needs a |
445 | | * different implementation of GetCal() and locale data calendars. |
446 | | * */ |
447 | 120k | switch ( aTmpLocale.mnCalendarType & 0x7F ) |
448 | 120k | { |
449 | 4.15k | case 0x03 : // Gengou calendar |
450 | | // Only Japanese language support Gengou calendar. |
451 | | // It is an implicit "other" calendar where E, EE, R and RR |
452 | | // automatically switch to and YY and YYYY switch to Gregorian. Do |
453 | | // not add the "[~gengou]" modifier. |
454 | 4.15k | if ( nLocaleLang != LANGUAGE_JAPANESE ) |
455 | 3.39k | { |
456 | 3.39k | nLang = maLocale.meLanguage = LANGUAGE_JAPANESE; |
457 | 3.39k | } |
458 | 4.15k | break; |
459 | 5.03k | case 0x05 : // Korean Dangi calendar |
460 | 5.03k | sCalendar = "[~dangi]"; |
461 | | // Only Korean language support dangi calendar |
462 | 5.03k | if ( nLocaleLang != LANGUAGE_KOREAN ) |
463 | 4.72k | { |
464 | 4.72k | nLang = maLocale.meLanguage = LANGUAGE_KOREAN; |
465 | 4.72k | } |
466 | 5.03k | break; |
467 | 3.80k | case 0x06 : // Hijri calendar |
468 | 6.21k | case 0x17 : // same? |
469 | 6.21k | sCalendar = "[~hijri]"; |
470 | | // Only Arabic or Farsi languages support Hijri calendar |
471 | 6.21k | if ( ( primary( nLocaleLang ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) |
472 | 5.94k | && nLocaleLang != LANGUAGE_FARSI ) |
473 | 5.94k | { |
474 | 5.94k | if ( ( primary( nTmpLocaleLang ) == LANGUAGE_ARABIC_PRIMARY_ONLY ) |
475 | 2.97k | || nTmpLocaleLang == LANGUAGE_FARSI ) |
476 | 2.96k | { |
477 | 2.96k | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
478 | 2.96k | } |
479 | 2.97k | else |
480 | 2.97k | { |
481 | 2.97k | nLang = maLocale.meLanguage = LANGUAGE_ARABIC_SAUDI_ARABIA; |
482 | 2.97k | } |
483 | 5.94k | } |
484 | 6.21k | break; |
485 | 4.28k | case 0x07 : // Buddhist calendar |
486 | 4.28k | sCalendar="[~buddhist]"; |
487 | | // Only Thai or Lao languages support Buddhist calendar |
488 | 4.28k | if ( nLocaleLang != LANGUAGE_THAI && nLocaleLang != LANGUAGE_LAO ) |
489 | 3.46k | { |
490 | 3.46k | if ( nTmpLocaleLang == LANGUAGE_THAI || nTmpLocaleLang == LANGUAGE_LAO ) |
491 | 194 | { |
492 | 194 | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
493 | 194 | } |
494 | 3.27k | else |
495 | 3.27k | { |
496 | 3.27k | nLang = maLocale.meLanguage = LANGUAGE_THAI; |
497 | 3.27k | } |
498 | 3.46k | } |
499 | 4.28k | break; |
500 | 3.00k | case 0x08 : // Hebrew calendar |
501 | 3.00k | sCalendar = "[~jewish]"; |
502 | | // Many languages (but not all) support Jewish calendar |
503 | | // Unable to find any logic => keep same language |
504 | 3.00k | break; |
505 | 1.18k | case 0x0E : // unknown calendar |
506 | 2.03k | case 0x0F : // unknown calendar |
507 | 4.42k | case 0x10 : // Indian calendar (unsupported) |
508 | 6.03k | case 0x11 : // unknown calendar |
509 | 7.45k | case 0x12 : // unknown calendar |
510 | 8.81k | case 0x13 : // unknown calendar |
511 | 98.0k | default : // other calendars (see tdf#36038) are not handle by LibO |
512 | 98.0k | break; |
513 | 120k | } |
514 | | /** Reference language for each numeral ID */ |
515 | 120k | static const LanguageType aNumeralIDtoLanguage []= |
516 | 120k | { |
517 | 120k | LANGUAGE_DONTKNOW, // 0x00 |
518 | 120k | LANGUAGE_ENGLISH_US, // 0x01 |
519 | 120k | LANGUAGE_ARABIC_SAUDI_ARABIA, // 0x02 + all Arabic |
520 | 120k | LANGUAGE_FARSI, // 0x03 |
521 | 120k | LANGUAGE_HINDI, // 0x04 + Devanagari |
522 | 120k | LANGUAGE_BENGALI, // 0x05 |
523 | 120k | LANGUAGE_PUNJABI, // 0x06 |
524 | 120k | LANGUAGE_GUJARATI, // 0x07 |
525 | 120k | LANGUAGE_ODIA, // 0x08 |
526 | 120k | LANGUAGE_TAMIL, // 0x09 |
527 | 120k | LANGUAGE_TELUGU, // 0x0A |
528 | 120k | LANGUAGE_KANNADA, // 0x0B |
529 | 120k | LANGUAGE_MALAYALAM, // 0x0C |
530 | 120k | LANGUAGE_THAI, // 0x0D |
531 | 120k | LANGUAGE_LAO, // 0x0E |
532 | 120k | LANGUAGE_TIBETAN, // 0x0F |
533 | 120k | LANGUAGE_BURMESE, // 0x10 |
534 | 120k | LANGUAGE_TIGRIGNA_ETHIOPIA, // 0x11 |
535 | 120k | LANGUAGE_KHMER, // 0x12 |
536 | 120k | LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA, // 0x13 |
537 | 120k | LANGUAGE_DONTKNOW, // 0x14 |
538 | 120k | LANGUAGE_DONTKNOW, // 0x15 |
539 | 120k | LANGUAGE_DONTKNOW, // 0x16 |
540 | 120k | LANGUAGE_DONTKNOW, // 0x17 |
541 | 120k | LANGUAGE_DONTKNOW, // 0x18 |
542 | 120k | LANGUAGE_DONTKNOW, // 0x19 |
543 | 120k | LANGUAGE_DONTKNOW, // 0x1A |
544 | 120k | LANGUAGE_JAPANESE, // 0x1B |
545 | 120k | LANGUAGE_JAPANESE, // 0x1C |
546 | 120k | LANGUAGE_JAPANESE, // 0x1D |
547 | 120k | LANGUAGE_CHINESE_SIMPLIFIED, // 0x1E |
548 | 120k | LANGUAGE_CHINESE_SIMPLIFIED, // 0x1F |
549 | 120k | LANGUAGE_CHINESE_SIMPLIFIED, // 0x20 |
550 | 120k | LANGUAGE_CHINESE_TRADITIONAL, // 0x21 |
551 | 120k | LANGUAGE_CHINESE_TRADITIONAL, // 0x22 |
552 | 120k | LANGUAGE_CHINESE_TRADITIONAL, // 0x23 |
553 | 120k | LANGUAGE_KOREAN, // 0x24 |
554 | 120k | LANGUAGE_KOREAN, // 0x25 |
555 | 120k | LANGUAGE_KOREAN, // 0x26 |
556 | 120k | LANGUAGE_KOREAN // 0x27 |
557 | 120k | }; |
558 | | |
559 | 120k | sal_uInt16 nNumeralID = aTmpLocale.mnNumeralShape & 0x7F; |
560 | 120k | LanguageType nReferenceLanguage = nNumeralID <= 0x27 ? aNumeralIDtoLanguage[nNumeralID] : LANGUAGE_DONTKNOW; |
561 | | |
562 | 120k | switch ( nNumeralID ) |
563 | 120k | { |
564 | | // Regular cases: all languages with same primary mask use same numerals |
565 | 1.12k | case 0x03 : // Perso-Arabic (Farsi) numerals |
566 | 2.35k | case 0x05 : // Bengali numerals |
567 | 4.10k | case 0x06 : // Punjabi numerals |
568 | 5.20k | case 0x07 : // Gujarati numerals |
569 | 6.25k | case 0x08 : // Odia (Orya) numerals |
570 | 7.48k | case 0x09 : // Tamil numerals |
571 | 8.14k | case 0x0A : // Telugu numerals |
572 | 8.57k | case 0x0B : // Kannada numerals |
573 | 9.11k | case 0x0C : // Malayalam numerals |
574 | 10.5k | case 0x0D : // Thai numerals |
575 | 11.1k | case 0x0E : // Lao numerals |
576 | 12.2k | case 0x0F : // Tibetan numerals |
577 | 12.9k | case 0x10 : // Burmese (Myanmar) numerals |
578 | 13.6k | case 0x11 : // Tigrigna (Ethiopia) numerals |
579 | 14.3k | case 0x12 : // Khmer numerals |
580 | 14.3k | if ( primary( nLocaleLang ) != primary( nReferenceLanguage ) ) |
581 | 13.2k | { |
582 | 13.2k | if ( primary( nTmpLocaleLang ) == primary( nReferenceLanguage ) ) |
583 | 289 | { |
584 | 289 | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
585 | 289 | } |
586 | 12.9k | else |
587 | 12.9k | { |
588 | 12.9k | nLang = maLocale.meLanguage = nReferenceLanguage; |
589 | 12.9k | } |
590 | 13.2k | } |
591 | 14.3k | break; |
592 | | // Special cases |
593 | 2.91k | case 0x04 : // Devanagari (Hindi) numerals |
594 | | // same numerals (Devanagari) for languages with different primary masks |
595 | 2.91k | if ( nLocaleLang != LANGUAGE_HINDI && nLocaleLang != LANGUAGE_MARATHI |
596 | 2.44k | && primary( nLocaleLang ) != primary( LANGUAGE_NEPALI ) ) |
597 | 2.44k | { |
598 | 2.44k | if ( nTmpLocaleLang == LANGUAGE_HINDI || nTmpLocaleLang == LANGUAGE_MARATHI |
599 | 2.24k | || primary( nTmpLocaleLang ) == primary( LANGUAGE_NEPALI ) ) |
600 | 374 | { |
601 | 374 | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
602 | 374 | } |
603 | 2.06k | else |
604 | 2.06k | { |
605 | 2.06k | nLang = maLocale.meLanguage = LANGUAGE_HINDI; |
606 | 2.06k | } |
607 | 2.44k | } |
608 | 2.91k | break; |
609 | 1.86k | case 0x13 : // Mongolian numerals |
610 | | // not all Mongolian languages use Mongolian numerals |
611 | 1.86k | if ( nLocaleLang != LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA |
612 | 1.20k | && nLocaleLang != LANGUAGE_MONGOLIAN_MONGOLIAN_CHINA |
613 | 1.20k | && nLocaleLang != LANGUAGE_MONGOLIAN_MONGOLIAN_LSO ) |
614 | 1.20k | { |
615 | 1.20k | if ( nTmpLocaleLang == LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA |
616 | 1.20k | || nTmpLocaleLang == LANGUAGE_MONGOLIAN_MONGOLIAN_CHINA |
617 | 1.20k | || nTmpLocaleLang == LANGUAGE_MONGOLIAN_MONGOLIAN_LSO ) |
618 | 0 | { |
619 | 0 | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
620 | 0 | } |
621 | 1.20k | else |
622 | 1.20k | { |
623 | 1.20k | nLang = maLocale.meLanguage = LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA; |
624 | 1.20k | } |
625 | 1.20k | } |
626 | 1.86k | break; |
627 | 12.8k | case 0x02 : // Eastern-Arabic numerals |
628 | | // all arabic primary mask + LANGUAGE_PUNJABI_ARABIC_LSO |
629 | 12.8k | if ( primary( nLocaleLang ) != LANGUAGE_ARABIC_PRIMARY_ONLY |
630 | 12.5k | && nLocaleLang != LANGUAGE_PUNJABI_ARABIC_LSO ) |
631 | 12.5k | { |
632 | 12.5k | if ( primary( nTmpLocaleLang ) == LANGUAGE_ARABIC_PRIMARY_ONLY |
633 | 12.2k | || nTmpLocaleLang != LANGUAGE_PUNJABI_ARABIC_LSO ) |
634 | 12.3k | { |
635 | 12.3k | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
636 | 12.3k | } |
637 | 197 | else |
638 | 197 | { |
639 | 197 | nLang = maLocale.meLanguage = nReferenceLanguage; |
640 | 197 | } |
641 | 12.5k | } |
642 | 12.8k | break; |
643 | | // CJK numerals |
644 | 407 | case 0x1B : // simple Asian numerals, Japanese |
645 | 761 | case 0x1C : // financial Asian numerals, Japanese |
646 | 1.10k | case 0x1D : // Arabic fullwidth numerals, Japanese |
647 | 1.78k | case 0x24 : // simple Asian numerals, Korean |
648 | 2.35k | case 0x25 : // financial Asian numerals, Korean |
649 | 2.59k | case 0x26 : // Arabic fullwidth numerals, Korean |
650 | 4.04k | case 0x27 : // Korean Hangul numerals |
651 | | // Japanese and Korean are regular |
652 | 4.04k | if ( primary( nLocaleLang ) != primary( nReferenceLanguage ) ) |
653 | 3.60k | { |
654 | 3.60k | if ( primary( nTmpLocaleLang ) == primary( nReferenceLanguage ) ) |
655 | 446 | { |
656 | 446 | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
657 | 446 | } |
658 | 3.15k | else |
659 | 3.15k | { |
660 | 3.15k | nLang = maLocale.meLanguage = nReferenceLanguage; |
661 | 3.15k | } |
662 | 3.60k | } |
663 | 4.04k | [[fallthrough]]; |
664 | 4.88k | case 0x1E : // simple Asian numerals, Chinese-PRC |
665 | 5.24k | case 0x1F : // financial Asian numerals, Chinese-PRC |
666 | 7.82k | case 0x20 : // Arabic fullwidth numerals, Chinese-PRC |
667 | 9.12k | case 0x21 : // simple Asian numerals, Chinese-Taiwan |
668 | 10.6k | case 0x22 : // financial Asian numerals, Chinese-Taiwan |
669 | 12.3k | case 0x23 : // Arabic fullwidth numerals, Chinese-Taiwan |
670 | 12.3k | nNatNum = nNumeralID == 0x27 ? 9 : ( ( nNumeralID - 0x1B ) % 3 ) + 1; |
671 | | // [NatNum1] simple numerals |
672 | | // [natNum2] financial numerals |
673 | | // [NatNum3] Arabic fullwidth numerals |
674 | | // Chinese simplified and Chinese traditional have same primary mask |
675 | | // Chinese-PRC |
676 | 12.3k | if ( nReferenceLanguage == LANGUAGE_CHINESE_SIMPLIFIED |
677 | 3.78k | && nLocaleLang != LANGUAGE_CHINESE_SIMPLIFIED |
678 | 3.38k | && nLocaleLang != LANGUAGE_CHINESE_SINGAPORE |
679 | 3.18k | && nLocaleLang != LANGUAGE_CHINESE_LSO ) |
680 | 3.18k | { |
681 | 3.18k | if ( nTmpLocaleLang == LANGUAGE_CHINESE_SIMPLIFIED |
682 | 2.83k | || nTmpLocaleLang == LANGUAGE_CHINESE_SINGAPORE |
683 | 2.38k | || nTmpLocaleLang == LANGUAGE_CHINESE_LSO ) |
684 | 808 | { |
685 | 808 | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
686 | 808 | } |
687 | 2.38k | else |
688 | 2.38k | { |
689 | 2.38k | nLang = maLocale.meLanguage = LANGUAGE_CHINESE_SIMPLIFIED; |
690 | 2.38k | } |
691 | 3.18k | } |
692 | | // Chinese-Taiwan |
693 | 9.12k | else if ( nReferenceLanguage == LANGUAGE_CHINESE_TRADITIONAL |
694 | 4.48k | && nLocaleLang != LANGUAGE_CHINESE_TRADITIONAL |
695 | 3.89k | && nLocaleLang != LANGUAGE_CHINESE_HONGKONG |
696 | 3.64k | && nLocaleLang != LANGUAGE_CHINESE_MACAU ) |
697 | 3.64k | { |
698 | 3.64k | if ( nTmpLocaleLang == LANGUAGE_CHINESE_TRADITIONAL |
699 | 3.43k | || nTmpLocaleLang == LANGUAGE_CHINESE_HONGKONG |
700 | 2.99k | || nTmpLocaleLang == LANGUAGE_CHINESE_MACAU ) |
701 | 650 | { |
702 | 650 | nLang = maLocale.meLanguage = aTmpLocale.meLanguage; |
703 | 650 | } |
704 | 2.99k | else |
705 | 2.99k | { |
706 | 2.99k | nLang = maLocale.meLanguage = LANGUAGE_CHINESE_TRADITIONAL; |
707 | 2.99k | } |
708 | 3.64k | } |
709 | 12.3k | break; |
710 | 120k | } |
711 | 120k | if ( nNumeralID >= 0x02 && nNumeralID <= 0x13 ) |
712 | 31.9k | nNatNum = 1; |
713 | 120k | if ( nNatNum ) |
714 | 44.2k | rString.insert(nPos, "[NatNum" + OUString::number(nNatNum) + "]"); |
715 | 120k | return sCalendar; |
716 | 120k | } |
717 | | |
718 | | namespace |
719 | | { |
720 | | bool NatNumTakesParameters(sal_Int16 nNum) |
721 | 2.50M | { |
722 | 2.50M | return (nNum == css::i18n::NativeNumberMode::NATNUM12); |
723 | 2.50M | } |
724 | | } |
725 | | |
726 | | // is there a 3-letter bank code in NatNum12 param (but not |
727 | | // followed by an equal mark, like in the date code "NNN=")? |
728 | | static bool lcl_isNatNum12Currency( std::u16string_view sParam ) |
729 | 2.15M | { |
730 | 2.15M | sal_Int32 nUpper = 0; |
731 | 2.15M | sal_Int32 nLen = sParam.size(); |
732 | 26.6M | for (sal_Int32 n = 0; n < nLen; ++n) |
733 | 24.5M | { |
734 | 24.5M | sal_Unicode c = sParam[n]; |
735 | 24.5M | if ( 'A' <= c && c <= 'Z' ) |
736 | 3.23M | { |
737 | 3.23M | ++nUpper; |
738 | 3.23M | } |
739 | 21.2M | else if ( c == ' ' && nUpper == 3 && (n == 3 || sParam[n - 4] == ' ') ) |
740 | 157 | { |
741 | 157 | return true; |
742 | 157 | } |
743 | 21.2M | else |
744 | 21.2M | { |
745 | 21.2M | nUpper = 0; |
746 | 21.2M | } |
747 | 24.5M | } |
748 | | |
749 | 2.15M | return nUpper == 3 && (nLen == 3 || sParam[nLen - 4] == ' '); |
750 | 2.15M | } |
751 | | |
752 | | SvNumberformat::SvNumberformat(OUString& rString, |
753 | | ImpSvNumberformatScan* pSc, |
754 | | ImpSvNumberInputScan* pISc, |
755 | | const NativeNumberWrapper& rNatNum, |
756 | | sal_Int32& nCheckPos, |
757 | | LanguageType& eLan, |
758 | | bool bReplaceBooleanEquivalent) |
759 | 25.1M | : rScan(*pSc) |
760 | 25.1M | , bAdditionalBuiltin( false ) |
761 | 25.1M | { |
762 | 25.1M | if (bReplaceBooleanEquivalent) |
763 | 25.1M | rScan.ReplaceBooleanEquivalent( rString); |
764 | | |
765 | 25.1M | OUStringBuffer sBuff(rString); |
766 | | |
767 | | // If the group (AKA thousand) separator is a No-Break Space (French) |
768 | | // replace all occurrences by a simple space. |
769 | | // The same for Narrow No-Break Space just in case some locale uses it. |
770 | | // The tokens will be changed to the LocaleData separator again later on. |
771 | 25.1M | const OUString& rThSep = GetCurrentLanguageData().GetNumThousandSep(); |
772 | 25.1M | if ( rThSep.getLength() == 1) |
773 | 25.1M | { |
774 | 25.1M | const sal_Unicode cNBSp = 0xA0; |
775 | 25.1M | const sal_Unicode cNNBSp = 0x202F; |
776 | 25.1M | if (rThSep[0] == cNBSp ) |
777 | 0 | sBuff.replace( cNBSp, ' '); |
778 | 25.1M | else if (rThSep[0] == cNNBSp ) |
779 | 0 | sBuff.replace( cNNBSp, ' '); |
780 | 25.1M | } |
781 | | |
782 | 25.1M | OUString aConvertFromDecSep; |
783 | 25.1M | OUString aConvertToDecSep; |
784 | 25.1M | if (rScan.GetConvertMode()) |
785 | 641k | { |
786 | 641k | aConvertFromDecSep = GetCurrentLanguageData().GetNumDecimalSep(); |
787 | 641k | maLocale.meLanguage = rScan.GetNewLnge(); |
788 | 641k | eLan = maLocale.meLanguage; // Make sure to return switch |
789 | 641k | } |
790 | 24.4M | else |
791 | 24.4M | { |
792 | 24.4M | maLocale.meLanguage = eLan; |
793 | 24.4M | } |
794 | 25.1M | bStandard = false; |
795 | 25.1M | bIsUsed = false; |
796 | 25.1M | fLimit1 = 0.0; |
797 | 25.1M | fLimit2 = 0.0; |
798 | 25.1M | eOp1 = NUMBERFORMAT_OP_NO; |
799 | 25.1M | eOp2 = NUMBERFORMAT_OP_NO; |
800 | 25.1M | eType = SvNumFormatType::DEFINED; |
801 | | |
802 | 25.1M | bool bCancel = false; |
803 | 25.1M | bool bCondition = false; |
804 | 25.1M | short eSymbolType; |
805 | 25.1M | sal_Int32 nPos = 0; |
806 | 25.1M | sal_Int32 nPosOld; |
807 | 25.1M | nCheckPos = 0; |
808 | | |
809 | | // Split into 4 sub formats |
810 | 25.1M | sal_uInt16 nIndex; |
811 | 54.3M | for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ ) |
812 | 29.2M | { |
813 | | // Original language/country may have to be reestablished |
814 | 29.2M | if (rScan.GetConvertMode()) |
815 | 845k | { |
816 | 845k | rScan.GetCurrentLanguageData().ChangeIntl(rScan.GetTmpLnge()); |
817 | 845k | } |
818 | 29.2M | OUString sInsertCalendar; // a calendar resulting from parsing LCID |
819 | 29.2M | OUString sStr; |
820 | 29.2M | nPosOld = nPos; // Start position of substring |
821 | | // first get bracketed prefixes; e.g. conditions, color |
822 | 29.2M | do |
823 | 33.2M | { |
824 | 33.2M | eSymbolType = ImpNextSymbol(sBuff, nPos, sStr); |
825 | 33.2M | if (eSymbolType > 0) // condition |
826 | 21.3k | { |
827 | 21.3k | if ( nIndex == 0 && !bCondition ) |
828 | 17.3k | { |
829 | 17.3k | bCondition = true; |
830 | 17.3k | eOp1 = static_cast<SvNumberformatLimitOps>(eSymbolType); |
831 | 17.3k | } |
832 | 4.01k | else if ( nIndex == 1 && bCondition ) |
833 | 2.57k | { |
834 | 2.57k | eOp2 = static_cast<SvNumberformatLimitOps>(eSymbolType); |
835 | 2.57k | } |
836 | 1.44k | else // error |
837 | 1.44k | { |
838 | 1.44k | bCancel = true; // break for |
839 | 1.44k | nCheckPos = nPosOld; |
840 | 1.44k | } |
841 | 21.3k | if (!bCancel) |
842 | 19.9k | { |
843 | 19.9k | double fNumber; |
844 | 19.9k | sal_Int32 nCntChars = ImpGetNumber(sBuff, nPos, sStr); |
845 | 19.9k | if (nCntChars > 0) |
846 | 14.8k | { |
847 | 14.8k | sal_Int32 nDecPos; |
848 | 14.8k | SvNumFormatType F_Type = SvNumFormatType::UNDEFINED; |
849 | 14.8k | if (!pISc->IsNumberFormat(sStr, F_Type, fNumber, nullptr, rNatNum, SvNumInputOptions::NONE) || |
850 | 6.45k | ( F_Type != SvNumFormatType::NUMBER && |
851 | 988 | F_Type != SvNumFormatType::SCIENTIFIC) ) |
852 | 9.27k | { |
853 | 9.27k | fNumber = 0.0; |
854 | 9.27k | nPos = nPos - nCntChars; |
855 | 9.27k | sBuff.remove(nPos, nCntChars); |
856 | 9.27k | sBuff.insert(nPos, '0'); |
857 | 9.27k | nPos++; |
858 | 9.27k | } |
859 | 5.59k | else if (rScan.GetConvertMode() && ((nDecPos = sStr.indexOf( aConvertFromDecSep)) >= 0)) |
860 | 3.14k | { |
861 | 3.14k | if (aConvertToDecSep.isEmpty()) |
862 | 2.84k | aConvertToDecSep = rScan.GetCurrentLanguageData().GetLangDecimalSep( rScan.GetNewLnge()); |
863 | 3.14k | if (aConvertToDecSep != aConvertFromDecSep) |
864 | 211 | { |
865 | 211 | const OUString aStr( sStr.replaceAt( nDecPos, |
866 | 211 | aConvertFromDecSep.getLength(), aConvertToDecSep)); |
867 | 211 | nPos = nPos - nCntChars; |
868 | 211 | sBuff.remove(nPos, nCntChars); |
869 | 211 | sBuff.insert(nPos, aStr); |
870 | 211 | nPos += aStr.getLength(); |
871 | 211 | } |
872 | 3.14k | } |
873 | 14.8k | } |
874 | 5.07k | else |
875 | 5.07k | { |
876 | 5.07k | fNumber = 0.0; |
877 | 5.07k | sBuff.insert(nPos++, '0'); |
878 | 5.07k | } |
879 | 19.9k | if (nIndex == 0) |
880 | 17.3k | { |
881 | 17.3k | fLimit1 = fNumber; |
882 | 17.3k | } |
883 | 2.57k | else |
884 | 2.57k | { |
885 | 2.57k | fLimit2 = fNumber; |
886 | 2.57k | } |
887 | 19.9k | if ( nPos < sBuff.getLength() && sBuff[nPos] == ']' ) |
888 | 10.6k | { |
889 | 10.6k | nPos++; |
890 | 10.6k | } |
891 | 9.31k | else |
892 | 9.31k | { |
893 | 9.31k | bCancel = true; // break for |
894 | 9.31k | nCheckPos = nPos; |
895 | 9.31k | } |
896 | 19.9k | } |
897 | 21.3k | nPosOld = nPos; // position before string |
898 | 21.3k | } |
899 | 33.2M | else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) |
900 | 4.10M | { |
901 | 4.10M | OUString sSymbol( sStr); |
902 | 4.10M | switch ( eSymbolType ) |
903 | 4.10M | { |
904 | 1.72M | case BRACKET_SYMBOLTYPE_COLOR : |
905 | 1.72M | if ( NumFor[nIndex].GetColor() != nullptr ) |
906 | 185 | { // error, more than one color |
907 | 185 | bCancel = true; // break for |
908 | 185 | nCheckPos = nPosOld; |
909 | 185 | } |
910 | 1.72M | else |
911 | 1.72M | { |
912 | 1.72M | const Color* pColor = pSc->GetColor( sStr); |
913 | 1.72M | NumFor[nIndex].SetColor( pColor, sStr); |
914 | 1.72M | if (pColor == nullptr) |
915 | 8.68k | { // error |
916 | 8.68k | bCancel = true; // break for |
917 | 8.68k | nCheckPos = nPosOld; |
918 | 8.68k | } |
919 | 1.72M | } |
920 | 1.72M | break; |
921 | 1.37k | case BRACKET_SYMBOLTYPE_NATNUM0 : |
922 | 36.6k | case BRACKET_SYMBOLTYPE_NATNUM1 : |
923 | 41.0k | case BRACKET_SYMBOLTYPE_NATNUM2 : |
924 | 45.9k | case BRACKET_SYMBOLTYPE_NATNUM3 : |
925 | 45.9k | case BRACKET_SYMBOLTYPE_NATNUM4 : |
926 | 46.0k | case BRACKET_SYMBOLTYPE_NATNUM5 : |
927 | 46.0k | case BRACKET_SYMBOLTYPE_NATNUM6 : |
928 | 46.1k | case BRACKET_SYMBOLTYPE_NATNUM7 : |
929 | 46.2k | case BRACKET_SYMBOLTYPE_NATNUM8 : |
930 | 47.6k | case BRACKET_SYMBOLTYPE_NATNUM9 : |
931 | 47.7k | case BRACKET_SYMBOLTYPE_NATNUM10 : |
932 | 47.8k | case BRACKET_SYMBOLTYPE_NATNUM11 : |
933 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM12 : |
934 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM13 : |
935 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM14 : |
936 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM15 : |
937 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM16 : |
938 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM17 : |
939 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM18 : |
940 | 2.20M | case BRACKET_SYMBOLTYPE_NATNUM19 : |
941 | 2.20M | if ( NumFor[nIndex].GetNatNum().IsSet() ) |
942 | 44 | { |
943 | 44 | bCancel = true; // break for |
944 | 44 | nCheckPos = nPosOld; |
945 | 44 | } |
946 | 2.20M | else |
947 | 2.20M | { |
948 | 2.20M | OUString sParams; |
949 | 2.20M | sal_Int32 nSpacePos = sStr.indexOf(' '); |
950 | 2.20M | if (nSpacePos >= 0) |
951 | 2.15M | { |
952 | 2.15M | sParams = o3tl::trim(sStr.subView(nSpacePos+1)); |
953 | 2.15M | } |
954 | | //! eSymbolType is negative |
955 | 2.20M | sal_uInt8 nNum = static_cast<sal_uInt8>(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0)); |
956 | 2.20M | if (!sParams.isEmpty() && !NatNumTakesParameters(nNum)) |
957 | 854 | { |
958 | 854 | bCancel = true; // break for |
959 | 854 | nCheckPos = nPosOld; |
960 | 854 | break; |
961 | 854 | } |
962 | 2.20M | sStr = "NatNum" + OUString::number(nNum); |
963 | 2.20M | NumFor[nIndex].SetNatNumNum( nNum, false ); |
964 | | // NatNum12 supports arguments |
965 | 2.20M | if (nNum == 12) |
966 | 2.15M | { |
967 | 2.15M | if (sParams.isEmpty()) |
968 | 85 | sParams = "cardinal"; // default NatNum12 format is "cardinal" |
969 | 2.15M | else if (sParams.indexOf("CURRENCY") >= 0) |
970 | 1.07M | sParams = sParams.replaceAll("CURRENCY", |
971 | 1.07M | rLoc().getCurrBankSymbol()); |
972 | 2.15M | NumFor[nIndex].SetNatNumParams(sParams); |
973 | 2.15M | sStr += " " + sParams; |
974 | 2.15M | } |
975 | 2.20M | } |
976 | 2.20M | break; |
977 | 2.20M | case BRACKET_SYMBOLTYPE_DBNUM1 : |
978 | 0 | case BRACKET_SYMBOLTYPE_DBNUM2 : |
979 | 0 | case BRACKET_SYMBOLTYPE_DBNUM3 : |
980 | 0 | case BRACKET_SYMBOLTYPE_DBNUM4 : |
981 | 0 | case BRACKET_SYMBOLTYPE_DBNUM5 : |
982 | 0 | case BRACKET_SYMBOLTYPE_DBNUM6 : |
983 | 0 | case BRACKET_SYMBOLTYPE_DBNUM7 : |
984 | 0 | case BRACKET_SYMBOLTYPE_DBNUM8 : |
985 | 0 | case BRACKET_SYMBOLTYPE_DBNUM9 : |
986 | 0 | if ( NumFor[nIndex].GetNatNum().IsSet() ) |
987 | 0 | { |
988 | 0 | bCancel = true; // break for |
989 | 0 | nCheckPos = nPosOld; |
990 | 0 | } |
991 | 0 | else |
992 | 0 | { |
993 | | //! eSymbolType is negative |
994 | 0 | sal_uInt8 nNum = static_cast<sal_uInt8>(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1)); |
995 | 0 | sStr = "DBNum" + OUStringChar(sal_Unicode('0' + nNum)); |
996 | 0 | NumFor[nIndex].SetNatNumNum( nNum, true ); |
997 | 0 | } |
998 | 0 | break; |
999 | 175k | case BRACKET_SYMBOLTYPE_LOCALE : |
1000 | 175k | if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW || |
1001 | 175k | sBuff[nPos-1] != ']' ) |
1002 | | // Check also for ']' to avoid pulling in |
1003 | | // locale data for the preview string for not |
1004 | | // yet completed LCIDs in the dialog. |
1005 | 4.59k | { |
1006 | 4.59k | bCancel = true; // break for |
1007 | 4.59k | nCheckPos = nPosOld; |
1008 | 4.59k | } |
1009 | 171k | else |
1010 | 171k | { |
1011 | 171k | sal_Int32 nTmp = 2; |
1012 | 171k | LocaleType aTmpLocale( ImpGetLocaleType( sStr, nTmp)); |
1013 | 171k | if (aTmpLocale.meLanguage == LANGUAGE_DONTKNOW) |
1014 | 6.51k | { |
1015 | 6.51k | bCancel = true; // break for |
1016 | 6.51k | nCheckPos = nPosOld; |
1017 | 6.51k | } |
1018 | 164k | else |
1019 | 164k | { |
1020 | | // Only the first sub format's locale will be |
1021 | | // used as the format's overall locale. |
1022 | | // Sorts this also under the corresponding |
1023 | | // locale for the dialog. |
1024 | | // If we don't support the locale this would |
1025 | | // result in an unknown (empty) language |
1026 | | // listbox entry and the user would never see |
1027 | | // this format. |
1028 | 164k | if (nIndex == 0 && (aTmpLocale.meLanguage == LANGUAGE_SYSTEM || |
1029 | 149k | SvNumberFormatter::IsLocaleInstalled( aTmpLocale.meLanguage))) |
1030 | 59.8k | { |
1031 | 59.8k | maLocale = aTmpLocale; |
1032 | 59.8k | eLan = aTmpLocale.meLanguage; // return to caller |
1033 | | |
1034 | | // Set new target locale also at scanner. |
1035 | | // We have to do this because switching locale |
1036 | | // may make replacing keywords and separators |
1037 | | // necessary. |
1038 | | // We can do this because it's the first |
1039 | | // subformat and we're still at parsing the |
1040 | | // modifiers, not keywords. |
1041 | 59.8k | rScan.SetNewLnge( eLan); |
1042 | | // We can not force conversion though because |
1043 | | // the caller may have explicitly not set it. |
1044 | | // In the usual case the target locale is the |
1045 | | // originating locale the conversion is not |
1046 | | // necessary, when reading alien documents |
1047 | | // conversion is enabled anyway. |
1048 | | |
1049 | | /* TODO: fiddle with scanner to make this |
1050 | | * known? A change in the locale may affect |
1051 | | * separators and keywords. On the other |
1052 | | * hand they may have been entered as used |
1053 | | * in the originating locale, there's no |
1054 | | * way to predict other than analyzing the |
1055 | | * format code, we assume here the current |
1056 | | * context is used, which is most likely |
1057 | | * the case. |
1058 | | * */ |
1059 | | |
1060 | | // Strip a plain locale identifier if locale |
1061 | | // data is available to avoid duplicated |
1062 | | // formats with and without LCID for the same |
1063 | | // locale. Besides it looks ugly and confusing |
1064 | | // and is unnecessary as the format will be |
1065 | | // listed for the resulting locale. |
1066 | 59.8k | if (aTmpLocale.isPlainLocale()) |
1067 | 41.7k | sStr.clear(); |
1068 | 18.0k | else |
1069 | 18.0k | sStr = "$-" + aTmpLocale.generateCode(); |
1070 | 59.8k | } |
1071 | 104k | else |
1072 | 104k | { |
1073 | 104k | if (nIndex == 0) |
1074 | | // Locale data not available, remember. |
1075 | 96.1k | maLocale.meLanguageWithoutLocaleData = aTmpLocale.meLanguage; |
1076 | | |
1077 | 104k | sStr = "$-" + aTmpLocale.generateCode(); |
1078 | 104k | } |
1079 | 164k | NumFor[nIndex].SetNatNumLang( MsLangId::getRealLanguage( aTmpLocale.meLanguage)); |
1080 | | |
1081 | | // "$-NNCCLLLL" Numerals and Calendar |
1082 | 164k | if (sSymbol.getLength() > 6) |
1083 | 120k | { |
1084 | 120k | sInsertCalendar = ImpObtainCalendarAndNumerals( sBuff, nPos, eLan, aTmpLocale); |
1085 | 120k | } |
1086 | | /* NOTE: there can be only one calendar |
1087 | | * inserted so the last one wins, though |
1088 | | * our own calendar modifiers support |
1089 | | * multiple calendars within one sub format |
1090 | | * code if at different positions. */ |
1091 | 164k | } |
1092 | 171k | } |
1093 | 175k | break; |
1094 | 4.10M | } |
1095 | 4.10M | if ( !bCancel ) |
1096 | 4.08M | { |
1097 | 4.08M | if (sStr == sSymbol) |
1098 | 2.82M | { |
1099 | 2.82M | nPosOld = nPos; |
1100 | 2.82M | } |
1101 | 1.25M | else |
1102 | 1.25M | { |
1103 | 1.25M | sBuff.remove(nPosOld, nPos - nPosOld); |
1104 | 1.25M | if (!sStr.isEmpty()) |
1105 | 1.21M | { |
1106 | 1.21M | sBuff.insert(nPosOld, "[" + sStr + "]"); |
1107 | 1.21M | nPos = nPosOld + sStr.getLength() + 2; |
1108 | 1.21M | nPosOld = nPos; // position before string |
1109 | 1.21M | } |
1110 | 41.7k | else |
1111 | 41.7k | { |
1112 | 41.7k | nPos = nPosOld; // prefix removed for whatever reason |
1113 | 41.7k | } |
1114 | 1.25M | } |
1115 | 4.08M | } |
1116 | 4.10M | } |
1117 | 33.2M | } |
1118 | 33.2M | while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ); |
1119 | | |
1120 | | // The remaining format code string |
1121 | 29.2M | if ( !bCancel ) |
1122 | 29.1M | { |
1123 | 29.1M | if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT) |
1124 | 29.1M | { |
1125 | 29.1M | if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO) |
1126 | 3.99M | { |
1127 | 3.99M | eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0 |
1128 | 3.99M | } |
1129 | 25.1M | else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO) |
1130 | 52.8k | { |
1131 | 52.8k | eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0 |
1132 | 52.8k | } |
1133 | 29.1M | if (sStr.isEmpty()) |
1134 | 41.7k | { |
1135 | | // Empty sub format. |
1136 | 41.7k | NumFor[nIndex].Info().eScannedType = SvNumFormatType::EMPTY; |
1137 | 41.7k | } |
1138 | 29.1M | else |
1139 | 29.1M | { |
1140 | 29.1M | if (!sInsertCalendar.isEmpty()) |
1141 | 16.9k | { |
1142 | 16.9k | sStr = sInsertCalendar + sStr; |
1143 | 16.9k | } |
1144 | 29.1M | sal_Int32 nStrPos = pSc->ScanFormat( sStr); |
1145 | 29.1M | sal_uInt16 nCnt = pSc->GetResultStringsCnt(); |
1146 | 29.1M | if (nCnt == 0 && nStrPos == 0) // error |
1147 | 0 | { |
1148 | 0 | nStrPos = 1; |
1149 | 0 | } |
1150 | 29.1M | if (nStrPos == 0) // ok |
1151 | 29.0M | { |
1152 | | // e.g. Thai T speciality |
1153 | 29.0M | if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet()) |
1154 | 0 | { |
1155 | 0 | sStr = "[NatNum" + OUString::number( pSc->GetNatNumModifier()) + "]" + sStr; |
1156 | 0 | NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), false ); |
1157 | 0 | } |
1158 | | // #i53826# #i42727# For the Thai T speciality we need |
1159 | | // to freeze the locale and immunize it against |
1160 | | // conversions during exports, just in case we want to |
1161 | | // save to Xcl. This disables the feature of being able |
1162 | | // to convert a NatNum to another locale. You can't |
1163 | | // have both. |
1164 | | // FIXME: implement a specialized export conversion |
1165 | | // that works on tokens (have to tokenize all first) |
1166 | | // and doesn't use the format string and |
1167 | | // PutandConvertEntry() to LANGUAGE_ENGLISH_US in |
1168 | | // sc/source/filter/excel/xestyle.cxx |
1169 | | // XclExpNumFmtBuffer::WriteFormatRecord(). |
1170 | 29.0M | LanguageType eLanguage; |
1171 | 29.0M | if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 && |
1172 | 20.4k | ((eLanguage = MsLangId::getRealLanguage( eLan)) == LANGUAGE_THAI) && |
1173 | 1.12k | NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW) |
1174 | 0 | { |
1175 | 0 | sStr = "[$-" + OUString::number( sal_uInt16(eLanguage), 16 ).toAsciiUpperCase() + "]" + sStr; |
1176 | 0 | NumFor[nIndex].SetNatNumLang( eLanguage); |
1177 | 0 | } |
1178 | 29.0M | sBuff.remove(nPosOld, nPos - nPosOld); |
1179 | 29.0M | sBuff.insert(nPosOld, sStr); |
1180 | 29.0M | nPos = nPosOld + sStr.getLength(); |
1181 | 29.0M | if (nPos < sBuff.getLength()) |
1182 | 4.07M | { |
1183 | 4.07M | sBuff.insert(nPos, ";"); |
1184 | 4.07M | nPos++; |
1185 | 4.07M | } |
1186 | 24.9M | else if (nIndex > 0) |
1187 | 3.97M | { |
1188 | | // The last subformat. If it is a trailing text |
1189 | | // format the omitted subformats act like they were |
1190 | | // not specified and "inherited" the first format, |
1191 | | // e.g. 0;@ behaves like 0;-0;0;@ |
1192 | 3.97M | if (pSc->GetScannedType() == SvNumFormatType::TEXT) |
1193 | 16.6k | { |
1194 | | // Reset conditions, reverting any set above. |
1195 | 16.6k | if (nIndex == 1) |
1196 | 1.57k | eOp1 = NUMBERFORMAT_OP_NO; |
1197 | 15.0k | else if (nIndex == 2) |
1198 | 617 | eOp2 = NUMBERFORMAT_OP_NO; |
1199 | 16.6k | nIndex = 3; |
1200 | 16.6k | } |
1201 | 3.97M | } |
1202 | 29.0M | NumFor[nIndex].Enlarge(nCnt); |
1203 | 29.0M | pSc->CopyInfo(&(NumFor[nIndex].Info()), nCnt); |
1204 | | // type check |
1205 | 29.0M | if (nIndex == 0) |
1206 | 25.0M | { |
1207 | 25.0M | if ( NumFor[nIndex].GetNatNum().GetNatNum() == 12 && |
1208 | 2.15M | lcl_isNatNum12Currency(NumFor[nIndex].GetNatNum().GetParams()) ) |
1209 | 1.07M | eType = SvNumFormatType::CURRENCY; |
1210 | 23.9M | else |
1211 | 23.9M | eType = NumFor[nIndex].Info().eScannedType; |
1212 | 25.0M | } |
1213 | 4.05M | else if (nIndex == 3) |
1214 | 29.6k | { // #77026# Everything recognized IS text |
1215 | 29.6k | NumFor[nIndex].Info().eScannedType = SvNumFormatType::TEXT; |
1216 | 29.6k | } |
1217 | 4.02M | else if ( NumFor[nIndex].Info().eScannedType != eType) |
1218 | 88.9k | { |
1219 | 88.9k | eType = SvNumFormatType::DEFINED; |
1220 | 88.9k | } |
1221 | 29.0M | } |
1222 | 68.1k | else |
1223 | 68.1k | { |
1224 | 68.1k | nCheckPos = nPosOld + nStrPos; // error in string |
1225 | 68.1k | bCancel = true; // break for |
1226 | 68.1k | } |
1227 | 29.1M | } |
1228 | 29.1M | } |
1229 | 2.41k | else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error |
1230 | 2.41k | { |
1231 | 2.41k | nCheckPos = nPosOld; |
1232 | 2.41k | bCancel = true; |
1233 | 2.41k | } |
1234 | 0 | else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) |
1235 | 0 | { |
1236 | 0 | nCheckPos = nPosOld + 1; // error, prefix in string |
1237 | 0 | bCancel = true; // break for |
1238 | 0 | } |
1239 | 29.1M | } |
1240 | 29.2M | if ( bCancel && !nCheckPos ) |
1241 | 19.9k | { |
1242 | 19.9k | nCheckPos = 1; // nCheckPos is used as an error condition |
1243 | 19.9k | } |
1244 | 29.2M | if ( !bCancel ) |
1245 | 29.1M | { |
1246 | 29.1M | if ( NumFor[nIndex].GetNatNum().IsSet() && |
1247 | 2.20M | NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW ) |
1248 | 2.15M | { |
1249 | 2.15M | NumFor[nIndex].SetNatNumLang( eLan ); |
1250 | 2.15M | } |
1251 | 29.1M | } |
1252 | 29.2M | if (sBuff.getLength() == nPos) |
1253 | 25.1M | { |
1254 | 25.1M | if (nIndex < 3 && rString[rString.getLength()-1] == ';') |
1255 | 7.60k | { |
1256 | | // A trailing ';' is significant and specifies the following |
1257 | | // subformat to be empty. We don't enter the scanning loop |
1258 | | // above again though. |
1259 | | // Note that the operators apply to the current last scanned |
1260 | | // subformat. |
1261 | 7.60k | if (nIndex == 0 && eOp1 == NUMBERFORMAT_OP_NO) |
1262 | 4.06k | { |
1263 | 4.06k | eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0 |
1264 | 4.06k | } |
1265 | 3.54k | else if (nIndex == 1 && eOp2 == NUMBERFORMAT_OP_NO) |
1266 | 2.04k | { |
1267 | 2.04k | eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0 |
1268 | 2.04k | } |
1269 | 7.60k | NumFor[nIndex+1].Info().eScannedType = SvNumFormatType::EMPTY; |
1270 | 7.60k | if (sBuff[nPos-1] != ';') |
1271 | 5.19k | sBuff.insert( nPos++, ';'); |
1272 | 7.60k | } |
1273 | 25.1M | if (nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT && sBuff[nPos-1] == ';') |
1274 | 591 | { |
1275 | | // #83510# A 4th subformat explicitly specified to be empty |
1276 | | // hides any text. Need the type here for HasTextFormat() |
1277 | 591 | NumFor[3].Info().eScannedType = SvNumFormatType::TEXT; |
1278 | 591 | } |
1279 | 25.1M | bCancel = true; |
1280 | 25.1M | } |
1281 | 29.2M | if ( NumFor[nIndex].GetNatNum().IsSet() ) |
1282 | 2.20M | { |
1283 | 2.20M | NumFor[nIndex].SetNatNumDate( bool(NumFor[nIndex].Info().eScannedType & SvNumFormatType::DATE) ); |
1284 | 2.20M | } |
1285 | 29.2M | } |
1286 | | |
1287 | 25.1M | if (!nCheckPos && IsSubstituted()) |
1288 | 1.38k | { |
1289 | | // For to be substituted formats the scanned type must match the |
1290 | | // substitute type. |
1291 | 1.38k | if (IsSystemTimeFormat()) |
1292 | 511 | { |
1293 | 511 | if ((eType & ~SvNumFormatType::DEFINED) != SvNumFormatType::TIME) |
1294 | 147 | nCheckPos = std::max<sal_Int32>( sBuff.indexOf(']') + 1, 1); |
1295 | 511 | } |
1296 | 869 | else if (IsSystemLongDateFormat()) |
1297 | 415 | { |
1298 | 415 | if ((eType & ~SvNumFormatType::DEFINED) != SvNumFormatType::DATE) |
1299 | 198 | nCheckPos = std::max<sal_Int32>( sBuff.indexOf(']') + 1, 1); |
1300 | 415 | } |
1301 | 454 | else |
1302 | 869 | assert(!"unhandled substitute"); |
1303 | 1.38k | } |
1304 | | |
1305 | 25.1M | if ( bCondition && !nCheckPos ) |
1306 | 6.43k | { |
1307 | 6.43k | if ( nIndex == 1 && NumFor[0].GetCount() == 0 && |
1308 | 1.81k | sBuff[sBuff.getLength() - 1] != ';' ) |
1309 | 1.57k | { |
1310 | | // No format code => GENERAL but not if specified empty |
1311 | 1.57k | OUString aAdd( pSc->GetStandardName() ); |
1312 | 1.57k | if ( !pSc->ScanFormat( aAdd ) ) |
1313 | 1.57k | { |
1314 | 1.57k | sal_uInt16 nCnt = pSc->GetResultStringsCnt(); |
1315 | 1.57k | if ( nCnt ) |
1316 | 1.57k | { |
1317 | 1.57k | NumFor[0].Enlarge(nCnt); |
1318 | 1.57k | pSc->CopyInfo( &(NumFor[0].Info()), nCnt ); |
1319 | 1.57k | sBuff.append(aAdd); |
1320 | 1.57k | } |
1321 | 1.57k | } |
1322 | 1.57k | } |
1323 | 4.86k | else if ( nIndex == 1 && NumFor[nIndex].GetCount() == 0 && |
1324 | 2.56k | sBuff[sBuff.getLength() - 1] != ';' && |
1325 | 2.11k | (NumFor[0].GetCount() > 1 || |
1326 | 1.63k | (NumFor[0].GetCount() == 1 && |
1327 | 1.63k | NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) ) |
1328 | 1.91k | { |
1329 | | // No trailing second subformat => GENERAL but not if specified empty |
1330 | | // and not if first subformat is GENERAL |
1331 | 1.91k | OUString aAdd( pSc->GetStandardName() ); |
1332 | 1.91k | if ( !pSc->ScanFormat( aAdd ) ) |
1333 | 1.91k | { |
1334 | 1.91k | sal_uInt16 nCnt = pSc->GetResultStringsCnt(); |
1335 | 1.91k | if ( nCnt ) |
1336 | 1.91k | { |
1337 | 1.91k | NumFor[nIndex].Enlarge(nCnt); |
1338 | 1.91k | pSc->CopyInfo( &(NumFor[nIndex].Info()), nCnt ); |
1339 | 1.91k | sBuff.append(";" + aAdd); |
1340 | 1.91k | } |
1341 | 1.91k | } |
1342 | 1.91k | } |
1343 | 2.94k | else if ( nIndex == 2 && NumFor[nIndex].GetCount() == 0 && |
1344 | 1.23k | sBuff[sBuff.getLength() - 1] != ';' && |
1345 | 972 | eOp2 != NUMBERFORMAT_OP_NO ) |
1346 | 451 | { |
1347 | | // No trailing third subformat => GENERAL but not if specified empty |
1348 | 451 | OUString aAdd( pSc->GetStandardName() ); |
1349 | 451 | if ( !pSc->ScanFormat( aAdd ) ) |
1350 | 451 | { |
1351 | 451 | sal_uInt16 nCnt = pSc->GetResultStringsCnt(); |
1352 | 451 | if ( nCnt ) |
1353 | 451 | { |
1354 | 451 | NumFor[nIndex].Enlarge(nCnt); |
1355 | 451 | pSc->CopyInfo( &(NumFor[nIndex].Info()), nCnt ); |
1356 | 451 | sBuff.append(";" + aAdd); |
1357 | 451 | } |
1358 | 451 | } |
1359 | 451 | } |
1360 | 6.43k | } |
1361 | 25.1M | rString = sBuff.makeStringAndClear(); |
1362 | 25.1M | sFormatstring = rString; |
1363 | | |
1364 | 25.1M | if (NumFor[2].GetCount() == 0 && // No third partial string |
1365 | 25.0M | eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO && |
1366 | 3.94M | fLimit1 == 0.0 && fLimit2 == 0.0) |
1367 | 3.94M | { |
1368 | 3.94M | eOp1 = NUMBERFORMAT_OP_GE; // Add 0 to the first format |
1369 | 3.94M | } |
1370 | | |
1371 | 25.1M | } |
1372 | | |
1373 | | SvNumberformat::~SvNumberformat() |
1374 | 25.1M | { |
1375 | 25.1M | } |
1376 | | |
1377 | | /** |
1378 | | * Next_Symbol |
1379 | | * |
1380 | | * Splits up the symbols for further processing (by the Turing machine) |
1381 | | * |
1382 | | * Start state = SsStart, * = Special state |
1383 | | * ---------------+-------------------+----------------------------+--------------- |
1384 | | * Old State | Symbol read | Event | New state |
1385 | | * ---------------+-------------------+----------------------------+--------------- |
1386 | | * SsStart | " | Symbol += Character | SsGetQuoted |
1387 | | * | ; | Pos-- | SsGetString |
1388 | | * | [ | Symbol += Character | SsGetBracketed |
1389 | | * | ] | Error | SsStop |
1390 | | * | BLANK | | |
1391 | | * | Else | Symbol += Character | SsGetString |
1392 | | * ---------------+-------------------+----------------------------+--------------- |
1393 | | * SsGetString | " | Symbol += Character | SsGetQuoted |
1394 | | * | ; | | SsStop |
1395 | | * | Else | Symbol += Character | |
1396 | | * ---------------+-------------------+----------------------------+--------------- |
1397 | | * SsGetQuoted | " | Symbol += Character | SsGetString |
1398 | | * | Else | Symbol += Character | |
1399 | | * ---------------+-------------------+----------------------------+--------------- |
1400 | | * SsGetBracketed | <, > = | del [ | |
1401 | | * | | Symbol += Character | SsGetCon |
1402 | | * | BLANK | | |
1403 | | * | h, H, m, M, s, S | Symbol += Character | SsGetTime |
1404 | | * | Else | del [ | |
1405 | | * | | Symbol += Character | SsGetPrefix |
1406 | | * ---------------+-------------------+----------------------------+--------------- |
1407 | | * SsGetTime | ] | Symbol += Character | SsGetString |
1408 | | * | h, H, m, M, s, S | Symbol += Character, * | SsGetString |
1409 | | * | Else | del [; Symbol += Character | SsGetPrefix |
1410 | | * ---------------+-------------------+----------------------------+--------------- |
1411 | | * SsGetPrefix | ] | | SsStop |
1412 | | * | Else | Symbol += Character | |
1413 | | * ---------------+-------------------+----------------------------+--------------- |
1414 | | * SsGetCon | >, = | Symbol += Character | |
1415 | | * | ] | | SsStop |
1416 | | * | Else | Error | SsStop |
1417 | | * ---------------+-------------------+----------------------------+--------------- |
1418 | | */ |
1419 | | |
1420 | | namespace { |
1421 | | |
1422 | | enum ScanState |
1423 | | { |
1424 | | SsStop, |
1425 | | SsStart, |
1426 | | SsGetCon, // condition |
1427 | | SsGetString, // format string |
1428 | | SsGetPrefix, // color or NatNumN |
1429 | | SsGetTime, // [HH] for time |
1430 | | SsGetBracketed, // any [...] not decided yet |
1431 | | SsGetQuoted // quoted text |
1432 | | }; |
1433 | | |
1434 | | } |
1435 | | |
1436 | | // read a string until ']' and delete spaces in input |
1437 | | // static |
1438 | | sal_Int32 SvNumberformat::ImpGetNumber(OUStringBuffer& rString, |
1439 | | sal_Int32& nPos, |
1440 | | OUString& sSymbol) |
1441 | 19.9k | { |
1442 | 19.9k | sal_Int32 nStartPos = nPos; |
1443 | 19.9k | sal_Unicode cToken; |
1444 | 19.9k | sal_Int32 nLen = rString.getLength(); |
1445 | 19.9k | OUStringBuffer sBuffSymbol; |
1446 | 189k | while ( nPos < nLen ) |
1447 | 180k | { |
1448 | 180k | cToken = rString[nPos]; |
1449 | 180k | if (cToken == ']') |
1450 | 10.6k | break; |
1451 | 169k | if (cToken == ' ') |
1452 | 3.93k | { // delete spaces |
1453 | 3.93k | rString.remove(nPos,1); |
1454 | 3.93k | nLen--; |
1455 | 3.93k | } |
1456 | 166k | else |
1457 | 166k | { |
1458 | 166k | nPos++; |
1459 | 166k | sBuffSymbol.append(cToken); |
1460 | 166k | } |
1461 | 169k | } |
1462 | 19.9k | sSymbol = sBuffSymbol.makeStringAndClear(); |
1463 | 19.9k | return nPos - nStartPos; |
1464 | 19.9k | } |
1465 | | |
1466 | | namespace { |
1467 | | |
1468 | | sal_Unicode toUniChar(sal_uInt8 n) |
1469 | 417k | { |
1470 | 417k | if (n < 10) |
1471 | 311k | return static_cast<sal_Unicode>('0' + n); |
1472 | 106k | else |
1473 | 106k | return static_cast<sal_Unicode>('A' + n - 10); |
1474 | 417k | } |
1475 | | |
1476 | | bool IsCombiningSymbol( OUStringBuffer& rStringBuffer, sal_Int32 nPos ) |
1477 | 4.09M | { |
1478 | 4.09M | bool bRet = false; |
1479 | 4.10M | while (nPos >= 0) |
1480 | 4.10M | { |
1481 | 4.10M | switch (rStringBuffer[nPos]) |
1482 | 4.10M | { |
1483 | 1.46k | case '*': |
1484 | 4.17k | case '\\': |
1485 | 6.09k | case '_': |
1486 | 6.09k | bRet = !bRet; |
1487 | 6.09k | --nPos; |
1488 | 6.09k | break; |
1489 | 4.09M | default: |
1490 | 4.09M | return bRet; |
1491 | 4.10M | } |
1492 | 4.10M | } |
1493 | 514 | return bRet; |
1494 | 4.09M | } |
1495 | | |
1496 | | } // namespace |
1497 | | |
1498 | | OUString SvNumberformat::LocaleType::generateCode() const |
1499 | 122k | { |
1500 | 122k | OUStringBuffer aBuf; |
1501 | | #if 0 |
1502 | | // TODO: We may re-enable this later. Don't remove it! --Kohei |
1503 | | if (mnNumeralShape) |
1504 | | { |
1505 | | sal_uInt8 nVal = mnNumeralShape; |
1506 | | for (sal_uInt8 i = 0; i < 2; ++i) |
1507 | | { |
1508 | | sal_uInt8 n = (nVal & 0xF0) >> 4; |
1509 | | if (n || aBuf.getLength()) |
1510 | | { |
1511 | | aBuf.append(toUniChar(n)); |
1512 | | } |
1513 | | nVal = nVal << 4; |
1514 | | } |
1515 | | } |
1516 | | |
1517 | | if (mnNumeralShape || mnCalendarType) |
1518 | | { |
1519 | | sal_uInt8 nVal = mnCalendarType; |
1520 | | for (sal_uInt8 i = 0; i < 2; ++i) |
1521 | | { |
1522 | | sal_uInt8 n = (nVal & 0xF0) >> 4; |
1523 | | if (n || aBuf.getLength()) |
1524 | | { |
1525 | | aBuf.append(toUniChar(n)); |
1526 | | } |
1527 | | nVal = nVal << 4; |
1528 | | } |
1529 | | } |
1530 | | #endif |
1531 | | |
1532 | 122k | sal_uInt16 n16 = static_cast<sal_uInt16>( |
1533 | 122k | (meLanguageWithoutLocaleData == LANGUAGE_DONTKNOW) ? meLanguage : |
1534 | 122k | meLanguageWithoutLocaleData); |
1535 | 122k | if (meLanguage == LANGUAGE_SYSTEM) |
1536 | 3.93k | { |
1537 | 3.93k | switch (meSubstitute) |
1538 | 3.93k | { |
1539 | 2.51k | case Substitute::NONE: |
1540 | 2.51k | ; // nothing |
1541 | 2.51k | break; |
1542 | 737 | case Substitute::TIME: |
1543 | 737 | n16 = static_cast<sal_uInt16>(LANGUAGE_NF_SYSTEM_TIME); |
1544 | 737 | break; |
1545 | 683 | case Substitute::LONGDATE: |
1546 | 683 | n16 = static_cast<sal_uInt16>(LANGUAGE_NF_SYSTEM_DATE); |
1547 | 683 | break; |
1548 | 3.93k | } |
1549 | 3.93k | } |
1550 | 614k | for (sal_uInt8 i = 0; i < 4; ++i) |
1551 | 491k | { |
1552 | 491k | sal_uInt8 n = static_cast<sal_uInt8>((n16 & 0xF000) >> 12); |
1553 | | // Omit leading zeros for consistency. |
1554 | 491k | if (n || !aBuf.isEmpty() || i == 3) |
1555 | 417k | { |
1556 | 417k | aBuf.append(toUniChar(n)); |
1557 | 417k | } |
1558 | 491k | n16 = (n16 << 4) & 0xFFFF; |
1559 | 491k | } |
1560 | | |
1561 | 122k | return aBuf.makeStringAndClear(); |
1562 | 122k | } |
1563 | | |
1564 | | SvNumberformat::LocaleType::LocaleType() |
1565 | 25.1M | : meLanguage(LANGUAGE_DONTKNOW) |
1566 | 25.1M | , meLanguageWithoutLocaleData(LANGUAGE_DONTKNOW) |
1567 | 25.1M | , meSubstitute(Substitute::NONE) |
1568 | 25.1M | , mnNumeralShape(0) |
1569 | 25.1M | , mnCalendarType(0) |
1570 | 25.1M | { |
1571 | 25.1M | } |
1572 | | |
1573 | | SvNumberformat::LocaleType::LocaleType(sal_uInt32 nRawNum) |
1574 | 164k | : meLanguage(LANGUAGE_DONTKNOW) |
1575 | 164k | , meLanguageWithoutLocaleData(LANGUAGE_DONTKNOW) |
1576 | 164k | , meSubstitute(Substitute::NONE) |
1577 | 164k | , mnNumeralShape(0) |
1578 | 164k | , mnCalendarType(0) |
1579 | 164k | { |
1580 | 164k | meLanguage = static_cast<LanguageType>(nRawNum & 0x0000FFFF); |
1581 | 164k | if (meLanguage == LANGUAGE_NF_SYSTEM_TIME) |
1582 | 737 | { |
1583 | 737 | meSubstitute = Substitute::TIME; |
1584 | 737 | meLanguage = LANGUAGE_SYSTEM; |
1585 | 737 | } |
1586 | 163k | else if (meLanguage == LANGUAGE_NF_SYSTEM_DATE) |
1587 | 683 | { |
1588 | 683 | meSubstitute = Substitute::LONGDATE; |
1589 | 683 | meLanguage = LANGUAGE_SYSTEM; |
1590 | 683 | } |
1591 | 164k | nRawNum = (nRawNum >> 16); |
1592 | 164k | mnCalendarType = static_cast<sal_uInt8>(nRawNum & 0xFF); |
1593 | 164k | nRawNum = (nRawNum >> 8); |
1594 | 164k | mnNumeralShape = static_cast<sal_uInt8>(nRawNum & 0xFF); |
1595 | 164k | } |
1596 | | |
1597 | | bool SvNumberformat::LocaleType::isPlainLocale() const |
1598 | 59.8k | { |
1599 | 59.8k | return meSubstitute == Substitute::NONE && !mnCalendarType && !mnNumeralShape; |
1600 | 59.8k | } |
1601 | | |
1602 | | // static |
1603 | | SvNumberformat::LocaleType SvNumberformat::ImpGetLocaleType(std::u16string_view rString, sal_Int32& nPos ) |
1604 | 171k | { |
1605 | 171k | sal_uInt32 nNum = 0; |
1606 | 171k | sal_Unicode cToken = 0; |
1607 | 171k | sal_Int32 nStart = nPos; |
1608 | 171k | sal_Int32 nLen = rString.size(); |
1609 | 1.19M | while ( nPos < nLen && (nPos - nStart < 8) ) |
1610 | 1.02M | { |
1611 | 1.02M | cToken = rString[nPos]; |
1612 | 1.02M | if (cToken == ']') |
1613 | 0 | break; |
1614 | | |
1615 | 1.02M | int nValue = o3tl::convertToHex<int>(cToken); |
1616 | | |
1617 | 1.02M | if (nValue == -1) |
1618 | 5.19k | return LocaleType(); // LANGUAGE_DONTKNOW; |
1619 | | |
1620 | 1.02M | nNum *= 16; |
1621 | 1.02M | nNum += nValue; |
1622 | | |
1623 | 1.02M | ++nPos; |
1624 | 1.02M | } |
1625 | | |
1626 | 166k | return (cToken == ']' || nPos == nLen) ? LocaleType(nNum) : LocaleType(); |
1627 | 171k | } |
1628 | | |
1629 | | static bool lcl_matchKeywordAndGetNumber( std::u16string_view rString, const sal_Int32 nPos, |
1630 | | std::u16string_view rKeyword, sal_Int32 & nNumber ) |
1631 | 6.76M | { |
1632 | 6.76M | if (0 <= nPos && nPos + static_cast<sal_Int32>(rKeyword.size()) < static_cast<sal_Int32>(rString.size()) && o3tl::matchIgnoreAsciiCase( rString, rKeyword, nPos)) |
1633 | 2.20M | { |
1634 | 2.20M | nNumber = o3tl::toInt32(rString.substr( nPos + rKeyword.size())); |
1635 | 2.20M | return true; |
1636 | 2.20M | } |
1637 | 4.55M | else |
1638 | 4.55M | { |
1639 | 4.55M | nNumber = 0; |
1640 | 4.55M | return false; |
1641 | 4.55M | } |
1642 | 6.76M | } |
1643 | | |
1644 | | short SvNumberformat::ImpNextSymbol(OUStringBuffer& rString, |
1645 | | sal_Int32& nPos, |
1646 | | OUString& sSymbol) const |
1647 | 33.2M | { |
1648 | 33.2M | short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; |
1649 | 33.2M | sal_Unicode cToken; |
1650 | 33.2M | sal_Unicode cLetter = ' '; // Preliminary result |
1651 | 33.2M | sal_Int32 nLen = rString.getLength(); |
1652 | 33.2M | ScanState eState = SsStart; |
1653 | 33.2M | OUStringBuffer sBuffSymbol(128); |
1654 | | |
1655 | 33.2M | const NfKeywordTable & rKeywords = rScan.GetKeywords(); |
1656 | 401M | while (nPos < nLen && eState != SsStop) |
1657 | 367M | { |
1658 | 367M | cToken = rString[nPos]; |
1659 | 367M | nPos++; |
1660 | 367M | switch (eState) |
1661 | 367M | { |
1662 | 33.2M | case SsStart: |
1663 | 33.2M | if (cToken == '\"') |
1664 | 7.37k | { |
1665 | 7.37k | eState = SsGetQuoted; |
1666 | 7.37k | sBuffSymbol.append(cToken); |
1667 | 7.37k | } |
1668 | 33.2M | else if (cToken == '[') |
1669 | 9.34M | { |
1670 | 9.34M | eState = SsGetBracketed; |
1671 | 9.34M | sBuffSymbol.append(cToken); |
1672 | 9.34M | } |
1673 | 23.9M | else if (cToken == ';') |
1674 | 14.9k | { |
1675 | 14.9k | eState = SsGetString; |
1676 | 14.9k | nPos--; |
1677 | 14.9k | eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; |
1678 | 14.9k | } |
1679 | 23.9M | else if (cToken == ']') |
1680 | 1.39k | { |
1681 | 1.39k | eState = SsStop; |
1682 | 1.39k | eSymbolType = BRACKET_SYMBOLTYPE_ERROR; |
1683 | 1.39k | } |
1684 | 23.9M | else if (cToken == ' ') // Skip Blanks |
1685 | 6.48k | { |
1686 | 6.48k | nPos--; |
1687 | 6.48k | rString.remove(nPos, 1); |
1688 | 6.48k | nLen--; |
1689 | 6.48k | } |
1690 | 23.8M | else |
1691 | 23.8M | { |
1692 | 23.8M | sBuffSymbol.append(cToken); |
1693 | 23.8M | eState = SsGetString; |
1694 | 23.8M | eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; |
1695 | 23.8M | } |
1696 | 33.2M | break; |
1697 | 9.35M | case SsGetBracketed: |
1698 | 9.35M | switch (cToken) |
1699 | 9.35M | { |
1700 | 9.38k | case '<': |
1701 | 15.5k | case '>': |
1702 | 22.4k | case '=': |
1703 | 22.4k | sBuffSymbol.stripStart('['); |
1704 | 22.4k | sBuffSymbol.append(cToken); |
1705 | 22.4k | cLetter = cToken; |
1706 | 22.4k | eState = SsGetCon; |
1707 | 22.4k | switch (cToken) |
1708 | 22.4k | { |
1709 | 9.38k | case '<': |
1710 | 9.38k | eSymbolType = NUMBERFORMAT_OP_LT; |
1711 | 9.38k | break; |
1712 | 6.13k | case '>': |
1713 | 6.13k | eSymbolType = NUMBERFORMAT_OP_GT; |
1714 | 6.13k | break; |
1715 | 6.89k | case '=': |
1716 | 6.89k | eSymbolType = NUMBERFORMAT_OP_EQ; |
1717 | 6.89k | break; |
1718 | 22.4k | } |
1719 | 22.4k | break; |
1720 | 22.4k | case ' ': |
1721 | 6.28k | nPos--; |
1722 | 6.28k | rString.remove(nPos, 1); |
1723 | 6.28k | nLen--; |
1724 | 6.28k | break; |
1725 | 2.14M | case '$' : |
1726 | 2.14M | if ( nPos < nLen && rString[nPos] == '-' ) |
1727 | 175k | { |
1728 | | // [$-xxx] locale |
1729 | 175k | sBuffSymbol.stripStart('['); |
1730 | 175k | eSymbolType = BRACKET_SYMBOLTYPE_LOCALE; |
1731 | 175k | eState = SsGetPrefix; |
1732 | 175k | } |
1733 | 1.96M | else |
1734 | 1.96M | { // currency |
1735 | 1.96M | eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; |
1736 | 1.96M | eState = SsGetString; |
1737 | 1.96M | } |
1738 | 2.14M | sBuffSymbol.append(cToken); |
1739 | 2.14M | break; |
1740 | 2.69M | case '~' : |
1741 | | // calendarID |
1742 | 2.69M | eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; |
1743 | 2.69M | sBuffSymbol.append(cToken); |
1744 | 2.69M | eState = SsGetString; |
1745 | 2.69M | break; |
1746 | 4.48M | default: |
1747 | 4.48M | { |
1748 | 4.48M | static constexpr OUString aNatNum(u"NATNUM"_ustr); |
1749 | 4.48M | static constexpr OUString aDBNum(u"DBNUM"_ustr); |
1750 | 4.48M | const OUString aBufStr( rString.toString()); |
1751 | 4.48M | sal_Int32 nNatNumNum; |
1752 | 4.48M | sal_Int32 nDBNum; |
1753 | 4.48M | if ( lcl_matchKeywordAndGetNumber( aBufStr, nPos-1, aNatNum, nNatNumNum) && |
1754 | 2.20M | 0 <= nNatNumNum && nNatNumNum <= 19 ) |
1755 | 2.20M | { |
1756 | 2.20M | sBuffSymbol.stripStart('['); |
1757 | 2.20M | sBuffSymbol.append( aBufStr.subView(--nPos, aNatNum.getLength()+1) ); |
1758 | 2.20M | nPos += aNatNum.getLength()+1; |
1759 | | //! SymbolType is negative |
1760 | 2.20M | eSymbolType = static_cast<short>(BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum); |
1761 | 2.20M | eState = SsGetPrefix; |
1762 | 2.20M | } |
1763 | 2.27M | else if ( lcl_matchKeywordAndGetNumber( aBufStr, nPos-1, aDBNum, nDBNum) && |
1764 | 0 | 1 <= nDBNum && nDBNum <= 9 ) |
1765 | 0 | { |
1766 | 0 | sBuffSymbol.stripStart('['); |
1767 | 0 | sBuffSymbol.append( aBufStr.subView(--nPos, aDBNum.getLength()+1) ); |
1768 | 0 | nPos += aDBNum.getLength()+1; |
1769 | | //! SymbolType is negative |
1770 | 0 | eSymbolType = sal::static_int_cast< short >( BRACKET_SYMBOLTYPE_DBNUM1 - (nDBNum - 1) ); |
1771 | 0 | eState = SsGetPrefix; |
1772 | 0 | } |
1773 | 2.27M | else |
1774 | 2.27M | { |
1775 | 2.27M | sal_Unicode cUpper = rChrCls().uppercase( aBufStr, nPos-1, 1)[0]; |
1776 | 2.27M | if ( cUpper == rKeywords[NF_KEY_H][0] || // H |
1777 | 1.72M | cUpper == rKeywords[NF_KEY_MI][0] || // M |
1778 | 1.72M | cUpper == rKeywords[NF_KEY_S][0] ) // S |
1779 | 557k | { |
1780 | 557k | sBuffSymbol.append(cToken); |
1781 | 557k | eState = SsGetTime; |
1782 | 557k | cLetter = cToken; |
1783 | 557k | } |
1784 | 1.72M | else |
1785 | 1.72M | { |
1786 | 1.72M | sBuffSymbol.stripStart('['); |
1787 | 1.72M | sBuffSymbol.append(cToken); |
1788 | 1.72M | eSymbolType = BRACKET_SYMBOLTYPE_COLOR; |
1789 | 1.72M | eState = SsGetPrefix; |
1790 | 1.72M | } |
1791 | 2.27M | } |
1792 | 4.48M | } |
1793 | 9.35M | } |
1794 | 9.35M | break; |
1795 | 279M | case SsGetString: |
1796 | 279M | if (cToken == '\"') |
1797 | 598k | { |
1798 | 598k | eState = SsGetQuoted; |
1799 | 598k | sBuffSymbol.append(cToken); |
1800 | 598k | } |
1801 | 278M | else if (cToken == ';' && (nPos < 2 || !IsCombiningSymbol( rString, nPos-2))) |
1802 | 4.10M | { |
1803 | 4.10M | eState = SsStop; |
1804 | 4.10M | } |
1805 | 274M | else |
1806 | 274M | { |
1807 | 274M | sBuffSymbol.append(cToken); |
1808 | 274M | } |
1809 | 279M | break; |
1810 | 1.30M | case SsGetQuoted: |
1811 | 1.30M | if (cToken == '\"') |
1812 | 593k | { |
1813 | 593k | eState = SsGetString; |
1814 | 593k | sBuffSymbol.append(cToken); |
1815 | 593k | } |
1816 | 711k | else |
1817 | 711k | { |
1818 | 711k | sBuffSymbol.append(cToken); |
1819 | 711k | } |
1820 | 1.30M | break; |
1821 | 1.09M | case SsGetTime: |
1822 | 1.09M | if (cToken == ']') |
1823 | 550k | { |
1824 | 550k | sBuffSymbol.append(cToken); |
1825 | 550k | eState = SsGetString; |
1826 | 550k | eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; |
1827 | 550k | } |
1828 | 547k | else |
1829 | 547k | { |
1830 | 547k | sal_Unicode cUpper = rChrCls().uppercase(rString.toString(), nPos-1, 1)[0]; |
1831 | 547k | if (cUpper == rKeywords[NF_KEY_H][0] || // H |
1832 | 8.14k | cUpper == rKeywords[NF_KEY_MI][0] || // M |
1833 | 3.90k | cUpper == rKeywords[NF_KEY_S][0] ) // S |
1834 | 546k | { |
1835 | 546k | if (cLetter == cToken) |
1836 | 542k | { |
1837 | 542k | sBuffSymbol.append(cToken); |
1838 | 542k | cLetter = ' '; |
1839 | 542k | } |
1840 | 3.81k | else |
1841 | 3.81k | { |
1842 | 3.81k | sBuffSymbol.stripStart('['); |
1843 | 3.81k | sBuffSymbol.append(cToken); |
1844 | 3.81k | eState = SsGetPrefix; |
1845 | 3.81k | } |
1846 | 546k | } |
1847 | 1.02k | else |
1848 | 1.02k | { |
1849 | 1.02k | sBuffSymbol.stripStart('['); |
1850 | 1.02k | sBuffSymbol.append(cToken); |
1851 | 1.02k | eSymbolType = BRACKET_SYMBOLTYPE_COLOR; |
1852 | 1.02k | eState = SsGetPrefix; |
1853 | 1.02k | } |
1854 | 547k | } |
1855 | 1.09M | break; |
1856 | 23.6k | case SsGetCon: |
1857 | 23.6k | switch (cToken) |
1858 | 23.6k | { |
1859 | 316 | case '<': |
1860 | 316 | eState = SsStop; |
1861 | 316 | eSymbolType = BRACKET_SYMBOLTYPE_ERROR; |
1862 | 316 | break; |
1863 | 932 | case '>': |
1864 | 932 | if (cLetter == '<') |
1865 | 523 | { |
1866 | 523 | sBuffSymbol.append(cToken); |
1867 | 523 | cLetter = ' '; |
1868 | 523 | eState = SsStop; |
1869 | 523 | eSymbolType = NUMBERFORMAT_OP_NE; |
1870 | 523 | } |
1871 | 409 | else |
1872 | 409 | { |
1873 | 409 | eState = SsStop; |
1874 | 409 | eSymbolType = BRACKET_SYMBOLTYPE_ERROR; |
1875 | 409 | } |
1876 | 932 | break; |
1877 | 1.20k | case '=': |
1878 | 1.20k | if (cLetter == '<') |
1879 | 425 | { |
1880 | 425 | sBuffSymbol.append(cToken); |
1881 | 425 | cLetter = ' '; |
1882 | 425 | eSymbolType = NUMBERFORMAT_OP_LE; |
1883 | 425 | } |
1884 | 781 | else if (cLetter == '>') |
1885 | 478 | { |
1886 | 478 | sBuffSymbol.append(cToken); |
1887 | 478 | cLetter = ' '; |
1888 | 478 | eSymbolType = NUMBERFORMAT_OP_GE; |
1889 | 478 | } |
1890 | 303 | else |
1891 | 303 | { |
1892 | 303 | eState = SsStop; |
1893 | 303 | eSymbolType = BRACKET_SYMBOLTYPE_ERROR; |
1894 | 303 | } |
1895 | 1.20k | break; |
1896 | 1.55k | case ' ': |
1897 | 1.55k | nPos--; |
1898 | 1.55k | rString.remove(nPos,1); |
1899 | 1.55k | nLen--; |
1900 | 1.55k | break; |
1901 | 19.6k | default: |
1902 | 19.6k | eState = SsStop; |
1903 | 19.6k | nPos--; |
1904 | 19.6k | break; |
1905 | 23.6k | } |
1906 | 23.6k | break; |
1907 | 43.2M | case SsGetPrefix: |
1908 | 43.2M | if (cToken == ']') |
1909 | 4.09M | { |
1910 | 4.09M | eState = SsStop; |
1911 | 4.09M | } |
1912 | 39.1M | else |
1913 | 39.1M | { |
1914 | 39.1M | sBuffSymbol.append(cToken); |
1915 | 39.1M | } |
1916 | 43.2M | break; |
1917 | 0 | default: |
1918 | 0 | break; |
1919 | 367M | } // of switch |
1920 | 367M | } // of while |
1921 | 33.2M | sSymbol = sBuffSymbol.makeStringAndClear(); |
1922 | 33.2M | return eSymbolType; |
1923 | 33.2M | } |
1924 | | |
1925 | | void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter, |
1926 | | LanguageType eConvertFrom, |
1927 | | LanguageType eConvertTo ) |
1928 | 576 | { |
1929 | 576 | sal_Int32 nCheckPos; |
1930 | 576 | sal_uInt32 nKey; |
1931 | 576 | SvNumFormatType nType = eType; |
1932 | 576 | OUString aFormatString( sFormatstring ); |
1933 | 576 | rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType, |
1934 | 576 | nKey, eConvertFrom, eConvertTo, false); |
1935 | 576 | const SvNumberformat* pFormat = rConverter.GetEntry( nKey ); |
1936 | 576 | DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion without format" ); |
1937 | 576 | if ( pFormat ) |
1938 | 576 | { |
1939 | 576 | ImpCopyNumberformat( *pFormat ); |
1940 | | // Reset values taken over from Formatter/Scanner |
1941 | | // pColor still points to table in temporary Formatter/Scanner |
1942 | 576 | for (ImpSvNumFor & rFormatter : NumFor) |
1943 | 2.30k | { |
1944 | 2.30k | OUString aColorName = rFormatter.GetColorName(); |
1945 | 2.30k | const Color* pColor = rScan.GetColor( aColorName ); |
1946 | 2.30k | rFormatter.SetColor( pColor, aColorName ); |
1947 | 2.30k | } |
1948 | 576 | } |
1949 | 576 | } |
1950 | | |
1951 | | bool SvNumberformat::HasNewCurrency() const |
1952 | 0 | { |
1953 | 0 | for (const auto & j : NumFor) |
1954 | 0 | { |
1955 | 0 | if ( j.HasNewCurrency() ) |
1956 | 0 | { |
1957 | 0 | return true; |
1958 | 0 | } |
1959 | 0 | } |
1960 | 0 | return false; |
1961 | 0 | } |
1962 | | |
1963 | | bool SvNumberformat::GetNewCurrencySymbol( OUString& rSymbol, |
1964 | | OUString& rExtension ) const |
1965 | 143k | { |
1966 | 143k | for (const auto & j : NumFor) |
1967 | 535k | { |
1968 | 535k | if ( j.GetNewCurrencySymbol( rSymbol, rExtension ) ) |
1969 | 16.2k | { |
1970 | 16.2k | return true; |
1971 | 16.2k | } |
1972 | 535k | } |
1973 | 127k | rSymbol.clear(); |
1974 | 127k | rExtension.clear(); |
1975 | 127k | return false; |
1976 | 143k | } |
1977 | | |
1978 | | // static |
1979 | | OUString SvNumberformat::StripNewCurrencyDelimiters( const OUString& rStr ) |
1980 | 1.34M | { |
1981 | 1.34M | OUStringBuffer aTmp(rStr.getLength()); |
1982 | 1.34M | sal_Int32 nStartPos, nPos, nLen; |
1983 | 1.34M | nLen = rStr.getLength(); |
1984 | 1.34M | nStartPos = 0; |
1985 | 4.04M | while ( (nPos = rStr.indexOf( "[$", nStartPos )) >= 0 ) |
1986 | 2.69M | { |
1987 | 2.69M | sal_Int32 nEnd; |
1988 | 2.69M | if ( (nEnd = GetQuoteEnd( rStr, nPos )) >= 0 ) |
1989 | 0 | { |
1990 | 0 | aTmp.append(rStr.subView( nStartPos, ++nEnd - nStartPos )); |
1991 | 0 | nStartPos = nEnd; |
1992 | 0 | } |
1993 | 2.69M | else |
1994 | 2.69M | { |
1995 | 2.69M | aTmp.append(rStr.subView(nStartPos, nPos - nStartPos) ); |
1996 | 2.69M | nStartPos = nPos + 2; |
1997 | 2.69M | sal_Int32 nDash; |
1998 | 2.69M | nEnd = nStartPos - 1; |
1999 | 2.69M | do |
2000 | 2.69M | { |
2001 | 2.69M | nDash = rStr.indexOf( '-', ++nEnd ); |
2002 | 2.69M | nEnd = GetQuoteEnd( rStr, nDash ); |
2003 | 2.69M | } |
2004 | 2.69M | while ( nEnd >= 0 ); |
2005 | 2.69M | sal_Int32 nClose; |
2006 | 2.69M | nEnd = nStartPos - 1; |
2007 | 2.69M | do |
2008 | 2.69M | { |
2009 | 2.69M | nClose = rStr.indexOf( ']', ++nEnd ); |
2010 | 2.69M | nEnd = GetQuoteEnd( rStr, nClose ); |
2011 | 2.69M | } |
2012 | 2.69M | while ( nEnd >= 0 ); |
2013 | | |
2014 | 2.69M | if(nClose < 0) |
2015 | 0 | { |
2016 | | /* there should always be a closing ] |
2017 | | * but the old String class would have hidden |
2018 | | * that. so be conservative too |
2019 | | */ |
2020 | 0 | nClose = nLen; |
2021 | 0 | } |
2022 | | |
2023 | 2.69M | nPos = nClose; |
2024 | 2.69M | if(nDash >= 0 && nDash < nClose) |
2025 | 2.69M | { |
2026 | 2.69M | nPos = nDash; |
2027 | 2.69M | } |
2028 | 2.69M | aTmp.append(rStr.subView(nStartPos, nPos - nStartPos) ); |
2029 | 2.69M | nStartPos = nClose + 1; |
2030 | 2.69M | } |
2031 | 2.69M | } |
2032 | 1.34M | if ( nLen > nStartPos ) |
2033 | 1.34M | { |
2034 | 1.34M | aTmp.append(rStr.subView(nStartPos, nLen - nStartPos) ); |
2035 | 1.34M | } |
2036 | 1.34M | return aTmp.makeStringAndClear(); |
2037 | 1.34M | } |
2038 | | |
2039 | | void SvNumberformat::ImpGetOutputStandard(double& fNumber, OUStringBuffer& rOutString, |
2040 | | const NativeNumberWrapper& rNatNum) const |
2041 | 14.5k | { |
2042 | 14.5k | OUString sTemp; |
2043 | 14.5k | ImpGetOutputStandard(fNumber, sTemp, rNatNum); |
2044 | 14.5k | rOutString = sTemp; |
2045 | 14.5k | } |
2046 | | |
2047 | | void SvNumberformat::ImpGetOutputStandard(double& fNumber, OUString& rOutString, |
2048 | | const NativeNumberWrapper& rNatNum) const |
2049 | 14.5k | { |
2050 | 14.5k | sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); |
2051 | | |
2052 | 14.5k | if ( fabs(fNumber) > EXP_ABS_UPPER_BOUND ) |
2053 | 18 | { |
2054 | 18 | nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals |
2055 | 18 | rOutString = ::rtl::math::doubleToUString( fNumber, |
2056 | 18 | rtl_math_StringFormat_E2, nStandardPrec /*2*/, |
2057 | 18 | GetCurrentLanguageData().GetNumDecimalSep()[0]); |
2058 | 18 | } |
2059 | 14.4k | else |
2060 | 14.4k | { |
2061 | 14.4k | ImpGetOutputStdToPrecision(fNumber, rOutString, nStandardPrec, rNatNum); |
2062 | 14.4k | } |
2063 | 14.5k | } |
2064 | | |
2065 | | namespace |
2066 | | { |
2067 | | |
2068 | | template<typename T> |
2069 | | bool checkForAll0s(const T& rString, sal_Int32 nIdx=0) |
2070 | 1.15k | { |
2071 | 1.15k | if (nIdx>=rString.getLength()) |
2072 | 0 | return false; |
2073 | | |
2074 | 1.15k | do |
2075 | 1.23k | { |
2076 | 1.23k | if (rString[nIdx]!='0') |
2077 | 1.13k | return false; |
2078 | 1.23k | } |
2079 | 1.15k | while (++nIdx<rString.getLength()); |
2080 | | |
2081 | 20 | return true; |
2082 | 1.15k | } zformat.cxx:bool (anonymous namespace)::checkForAll0s<rtl::OUString>(rtl::OUString const&, int) Line | Count | Source | 2070 | 634 | { | 2071 | 634 | if (nIdx>=rString.getLength()) | 2072 | 0 | return false; | 2073 | | | 2074 | 634 | do | 2075 | 692 | { | 2076 | 692 | if (rString[nIdx]!='0') | 2077 | 624 | return false; | 2078 | 692 | } | 2079 | 634 | while (++nIdx<rString.getLength()); | 2080 | | | 2081 | 10 | return true; | 2082 | 634 | } |
zformat.cxx:bool (anonymous namespace)::checkForAll0s<rtl::OUStringBuffer>(rtl::OUStringBuffer const&, int) Line | Count | Source | 2070 | 525 | { | 2071 | 525 | if (nIdx>=rString.getLength()) | 2072 | 0 | return false; | 2073 | | | 2074 | 525 | do | 2075 | 541 | { | 2076 | 541 | if (rString[nIdx]!='0') | 2077 | 515 | return false; | 2078 | 541 | } | 2079 | 525 | while (++nIdx<rString.getLength()); | 2080 | | | 2081 | 10 | return true; | 2082 | 525 | } |
|
2083 | | |
2084 | | OUString impTransliterateImpl(const OUString& rStr, |
2085 | | const SvNumberNatNum& rNum, |
2086 | | const NativeNumberWrapper& rNatNum) |
2087 | 127 | { |
2088 | 127 | css::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() ); |
2089 | 127 | return rNatNum.getNativeNumberStringParams(rStr, aLocale, rNum.GetNatNum(), rNum.GetParams()); |
2090 | 127 | } |
2091 | | |
2092 | | void impTransliterateImpl(OUStringBuffer& rStr, |
2093 | | const SvNumberNatNum& rNum, |
2094 | | const NativeNumberWrapper& rNatNum) |
2095 | 690 | { |
2096 | 690 | css::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() ); |
2097 | | |
2098 | 690 | rStr = rNatNum.getNativeNumberStringParams( |
2099 | 690 | OUString::unacquired(rStr), aLocale, rNum.GetNatNum(), rNum.GetParams()); |
2100 | 690 | } |
2101 | | |
2102 | | OUString impTransliterate(const OUString& rStr, const SvNumberNatNum& rNum, const NativeNumberWrapper& rNatNum) |
2103 | 34.6k | { |
2104 | 34.6k | return rNum.IsComplete() ? impTransliterateImpl(rStr, rNum, rNatNum) : rStr; |
2105 | 34.6k | } |
2106 | | |
2107 | | void impTransliterate(OUStringBuffer& rStr, const SvNumberNatNum& rNum, const NativeNumberWrapper& rNatNum) |
2108 | 75.8k | { |
2109 | 75.8k | if(rNum.IsComplete()) |
2110 | 690 | { |
2111 | 690 | impTransliterateImpl(rStr, rNum, rNatNum); |
2112 | 690 | } |
2113 | 75.8k | } |
2114 | | |
2115 | | } |
2116 | | |
2117 | | void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, OUString& rOutString, sal_uInt16 nPrecision, |
2118 | | const NativeNumberWrapper& rNatNum) const |
2119 | 14.4k | { |
2120 | | // Make sure the precision doesn't go over the maximum allowable precision. |
2121 | 14.4k | nPrecision = ::std::min(UPPER_PRECISION, nPrecision); |
2122 | | |
2123 | | // We decided to strip trailing zeros unconditionally, since binary |
2124 | | // double-precision rounding error makes it impossible to determine e.g. |
2125 | | // whether 844.10000000000002273737 is what the user has typed, or the |
2126 | | // user has typed 844.1 but IEEE 754 represents it that way internally. |
2127 | | |
2128 | 14.4k | rOutString = ::rtl::math::doubleToUString( rNumber, |
2129 | 14.4k | rtl_math_StringFormat_F, nPrecision /*2*/, |
2130 | 14.4k | GetCurrentLanguageData().GetNumDecimalSep()[0], true ); |
2131 | 14.4k | if (rOutString[0] == '-' && checkForAll0s(rOutString, 1)) |
2132 | 10 | { |
2133 | 10 | rOutString = comphelper::string::stripStart(rOutString, '-'); // not -0 |
2134 | 10 | } |
2135 | 14.4k | rOutString = ::impTransliterate(rOutString, NumFor[0].GetNatNum(), rNatNum); |
2136 | 14.4k | } |
2137 | | |
2138 | | void SvNumberformat::ImpGetOutputInputLine(double fNumber, OUString& OutString) const |
2139 | 43.1k | { |
2140 | 43.1k | bool bModified = false; |
2141 | 43.1k | if ( (eType & SvNumFormatType::PERCENT) && (fabs(fNumber) < D_MAX_D_BY_100)) |
2142 | 0 | { |
2143 | 0 | if (fNumber == 0.0) |
2144 | 0 | { |
2145 | 0 | OutString = "0%"; |
2146 | 0 | return; |
2147 | 0 | } |
2148 | 0 | fNumber *= 100; |
2149 | 0 | bModified = true; |
2150 | 0 | } |
2151 | | |
2152 | 43.1k | if (fNumber == 0.0) |
2153 | 37.5k | { |
2154 | 37.5k | OutString = "0"; |
2155 | 37.5k | return; |
2156 | 37.5k | } |
2157 | | |
2158 | 5.58k | OutString = ::rtl::math::doubleToUString( fNumber, |
2159 | 5.58k | rtl_math_StringFormat_Automatic, |
2160 | 5.58k | rtl_math_DecimalPlaces_Max, |
2161 | 5.58k | GetCurrentLanguageData().GetNumDecimalSep()[0], true ); |
2162 | | |
2163 | 5.58k | if ( eType & SvNumFormatType::PERCENT && bModified) |
2164 | 0 | { |
2165 | 0 | OutString += "%"; |
2166 | 0 | } |
2167 | 5.58k | } |
2168 | | |
2169 | | short SvNumberformat::ImpCheckCondition(double fNumber, |
2170 | | double fLimit, |
2171 | | SvNumberformatLimitOps eOp) |
2172 | 431k | { |
2173 | 431k | switch(eOp) |
2174 | 431k | { |
2175 | 410k | case NUMBERFORMAT_OP_NO: |
2176 | 410k | return -1; |
2177 | 0 | case NUMBERFORMAT_OP_EQ: |
2178 | 0 | return static_cast<short>(fNumber == fLimit); |
2179 | 0 | case NUMBERFORMAT_OP_NE: |
2180 | 0 | return static_cast<short>(fNumber != fLimit); |
2181 | 2.95k | case NUMBERFORMAT_OP_LT: |
2182 | 2.95k | return static_cast<short>(fNumber < fLimit); |
2183 | 0 | case NUMBERFORMAT_OP_LE: |
2184 | 0 | return static_cast<short>(fNumber <= fLimit); |
2185 | 8.35k | case NUMBERFORMAT_OP_GT: |
2186 | 8.35k | return static_cast<short>(fNumber > fLimit); |
2187 | 9.49k | case NUMBERFORMAT_OP_GE: |
2188 | 9.49k | return static_cast<short>(fNumber >= fLimit); |
2189 | 0 | default: |
2190 | 0 | return -1; |
2191 | 431k | } |
2192 | 431k | } |
2193 | | |
2194 | | static bool lcl_appendStarFillChar( OUStringBuffer& rBuf, std::u16string_view rStr ) |
2195 | 0 | { |
2196 | | // Right during user input the star symbol is the very |
2197 | | // last character before the user enters another one. |
2198 | 0 | if (rStr.size() > 1) |
2199 | 0 | { |
2200 | 0 | rBuf.append(u'\x001B'); |
2201 | 0 | rBuf.append(rStr[1]); |
2202 | 0 | return true; |
2203 | 0 | } |
2204 | 0 | return false; |
2205 | 0 | } |
2206 | | |
2207 | | static bool lcl_insertStarFillChar( OUStringBuffer& rBuf, sal_Int32 nPos, std::u16string_view rStr ) |
2208 | 0 | { |
2209 | 0 | if (rStr.size() > 1) |
2210 | 0 | { |
2211 | 0 | rBuf.insert( nPos, rStr[1]); |
2212 | 0 | rBuf.insert( nPos, u'\x001B'); |
2213 | 0 | return true; |
2214 | 0 | } |
2215 | 0 | return false; |
2216 | 0 | } |
2217 | | |
2218 | | void SvNumberformat::GetOutputString(std::u16string_view sString, |
2219 | | OUString& OutString, |
2220 | | const Color** ppColor, |
2221 | | bool bStarFlag) const |
2222 | 2.93k | { |
2223 | 2.93k | OUStringBuffer sOutBuff; |
2224 | 2.93k | sal_uInt16 nIx; |
2225 | 2.93k | if (eType & SvNumFormatType::TEXT) |
2226 | 2.54k | { |
2227 | 2.54k | nIx = 0; |
2228 | 2.54k | } |
2229 | 391 | else if (NumFor[3].GetCount() > 0) |
2230 | 391 | { |
2231 | 391 | nIx = 3; |
2232 | 391 | } |
2233 | 0 | else |
2234 | 0 | { |
2235 | 0 | *ppColor = nullptr; // no change of color |
2236 | 0 | return; |
2237 | 0 | } |
2238 | 2.93k | *ppColor = NumFor[nIx].GetColor(); |
2239 | 2.93k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
2240 | 2.93k | if (rInfo.eScannedType == SvNumFormatType::TEXT) |
2241 | 2.93k | { |
2242 | 2.93k | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
2243 | 6.75k | for (sal_uInt16 i = 0; i < nCnt; i++) |
2244 | 3.82k | { |
2245 | 3.82k | switch (rInfo.nTypeArray[i]) |
2246 | 3.82k | { |
2247 | 0 | case NF_SYMBOLTYPE_STAR: |
2248 | 0 | if( bStarFlag ) |
2249 | 0 | { |
2250 | 0 | lcl_appendStarFillChar( sOutBuff, rInfo.sStrArray[i]); |
2251 | 0 | } |
2252 | 0 | break; |
2253 | 552 | case NF_SYMBOLTYPE_BLANK: |
2254 | 552 | if (rInfo.sStrArray[i].getLength() >= 2) |
2255 | 552 | InsertBlanks( sOutBuff, sOutBuff.getLength(), rInfo.sStrArray[i][1] ); |
2256 | 552 | break; |
2257 | 0 | case NF_KEY_GENERAL : // #77026# "General" is the same as "@" |
2258 | 2.93k | case NF_SYMBOLTYPE_DEL : |
2259 | 2.93k | sOutBuff.append(sString); |
2260 | 2.93k | break; |
2261 | 336 | default: |
2262 | 336 | sOutBuff.append(rInfo.sStrArray[i]); |
2263 | 3.82k | } |
2264 | 3.82k | } |
2265 | 2.93k | } |
2266 | 2.93k | OutString = sOutBuff.makeStringAndClear(); |
2267 | 2.93k | } |
2268 | | |
2269 | | namespace { |
2270 | | |
2271 | | void lcl_GetOutputStringScientific(double fNumber, sal_uInt16 nCharCount, |
2272 | | const SvNFLanguageData& rLanguageData, OUString& rOutString) |
2273 | 0 | { |
2274 | 0 | bool bSign = std::signbit(fNumber); |
2275 | | |
2276 | | // 1.000E+015 (one digit and the decimal point, and the two chars + |
2277 | | // nExpDigit for the exponential part, totalling 6 or 7). |
2278 | 0 | double fExp = log10( fabs(fNumber) ); |
2279 | 0 | if( fExp < 0.0 ) |
2280 | 0 | fExp = 1.0 - fExp; |
2281 | 0 | sal_uInt16 nCharFormat = 6 + (fExp >= 100.0 ? 1 : 0); |
2282 | 0 | sal_uInt16 nPrec = nCharCount > nCharFormat ? nCharCount - nCharFormat : 0; |
2283 | 0 | if (nPrec && bSign) |
2284 | 0 | { |
2285 | | // Make room for the negative sign. |
2286 | 0 | --nPrec; |
2287 | 0 | } |
2288 | 0 | nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals. |
2289 | |
|
2290 | 0 | rOutString = ::rtl::math::doubleToUString(fNumber, rtl_math_StringFormat_E2, |
2291 | 0 | nPrec, rLanguageData.GetNumDecimalSep()[0], true ); |
2292 | 0 | } |
2293 | | |
2294 | | OUString lcl_GetPercentString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nCnt) |
2295 | 2.52k | { |
2296 | 2.52k | sal_Int32 i; |
2297 | 2.52k | OUStringBuffer aPercentString; |
2298 | 12.6k | for( i = 0; i < nCnt; i++ ) |
2299 | 10.0k | { |
2300 | 10.0k | if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_PERCENT ) |
2301 | 2.52k | { |
2302 | 2.52k | aPercentString.append( rInfo.sStrArray[i] ); |
2303 | 2.52k | bool bStringFound = false; |
2304 | 2.52k | for( i--; i >= 0 && rInfo.nTypeArray[i] == NF_SYMBOLTYPE_STRING ; i-- ) |
2305 | 0 | { |
2306 | 0 | if( !bStringFound ) |
2307 | 0 | { |
2308 | 0 | bStringFound = true; |
2309 | 0 | aPercentString.insert( 0, "\"" ); |
2310 | 0 | } |
2311 | 0 | aPercentString.insert( 0, rInfo.sStrArray[i] ); |
2312 | 0 | } |
2313 | 2.52k | i = nCnt; |
2314 | 2.52k | if( bStringFound ) |
2315 | 0 | aPercentString.insert( 0, "\"" ); |
2316 | 2.52k | } |
2317 | 10.0k | } |
2318 | 2.52k | return aPercentString.makeStringAndClear(); |
2319 | 2.52k | } |
2320 | | |
2321 | | OUString lcl_GetDenominatorString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nCnt) |
2322 | 3.38k | { |
2323 | 3.38k | sal_Int32 i; |
2324 | 3.38k | OUStringBuffer aDenominatorString; |
2325 | 13.9k | for( i = 0; i < nCnt; i++ ) |
2326 | 10.6k | { |
2327 | 10.6k | if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRAC ) |
2328 | 3.38k | { |
2329 | 4.75k | while ( ( ++i < nCnt ) && rInfo.nTypeArray[i] != NF_SYMBOLTYPE_FRAC_FDIV |
2330 | 3.74k | && rInfo.nTypeArray[i] != NF_SYMBOLTYPE_DIGIT ); |
2331 | 17.7k | for( ; i < nCnt; i++ ) |
2332 | 14.3k | { |
2333 | 14.3k | if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRAC_FDIV || rInfo.nTypeArray[i] == NF_SYMBOLTYPE_DIGIT ) |
2334 | 11.4k | aDenominatorString.append( rInfo.sStrArray[i] ); |
2335 | 2.91k | else |
2336 | 2.91k | i = nCnt; |
2337 | 14.3k | } |
2338 | 3.38k | } |
2339 | 10.6k | } |
2340 | 3.38k | return aDenominatorString.makeStringAndClear(); |
2341 | 3.38k | } |
2342 | | |
2343 | | OUString lcl_GetNumeratorString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nCnt) |
2344 | 1.94k | { |
2345 | 1.94k | sal_Int32 i; |
2346 | 1.94k | OUStringBuffer aNumeratorString; |
2347 | 8.00k | for( i = 0; i < nCnt; i++ ) |
2348 | 6.05k | { |
2349 | 6.05k | if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRAC ) |
2350 | 1.94k | { |
2351 | 5.21k | for( i--; i >= 0 && rInfo.nTypeArray[i] == NF_SYMBOLTYPE_DIGIT ; i-- ) |
2352 | 3.27k | { |
2353 | 3.27k | aNumeratorString.insert( 0, rInfo.sStrArray[i] ); |
2354 | 3.27k | } |
2355 | 1.94k | i = nCnt; |
2356 | 1.94k | } |
2357 | 6.05k | } |
2358 | 1.94k | return aNumeratorString.makeStringAndClear(); |
2359 | 1.94k | } |
2360 | | |
2361 | | OUString lcl_GetFractionIntegerString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nCnt) |
2362 | 1.94k | { |
2363 | 1.94k | sal_Int32 i; |
2364 | 1.94k | OUStringBuffer aIntegerString; |
2365 | 23.8k | for( i = 0; i < nCnt; i++ ) |
2366 | 21.8k | { |
2367 | 21.8k | if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRACBLANK ) |
2368 | 740 | { |
2369 | 1.13k | for( i--; i >= 0 && ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_DIGIT |
2370 | 399 | || rInfo.nTypeArray[i] == NF_SYMBOLTYPE_THSEP ); i-- ) |
2371 | 399 | { |
2372 | 399 | aIntegerString.insert( 0, rInfo.sStrArray[i] ); |
2373 | 399 | } |
2374 | 740 | i = nCnt; |
2375 | 740 | } |
2376 | 21.8k | } |
2377 | 1.94k | return aIntegerString.makeStringAndClear(); |
2378 | 1.94k | } |
2379 | | |
2380 | | OUString lcl_GetIntegerFractionDelimiterString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nCnt) |
2381 | 0 | { |
2382 | 0 | sal_uInt16 i; |
2383 | 0 | for( i = 0; i < nCnt; i++ ) |
2384 | 0 | { |
2385 | 0 | if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRACBLANK ) |
2386 | 0 | { |
2387 | 0 | return rInfo.sStrArray[i]; |
2388 | 0 | } |
2389 | 0 | } |
2390 | 0 | return OUString(); |
2391 | 0 | } |
2392 | | |
2393 | | } |
2394 | | |
2395 | | OUString SvNumberformat::GetPercentString( sal_uInt16 nNumFor ) const |
2396 | 2.52k | { |
2397 | 2.52k | const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); |
2398 | 2.52k | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
2399 | 2.52k | return lcl_GetPercentString( rInfo, nCnt ); |
2400 | 2.52k | } |
2401 | | |
2402 | | OUString SvNumberformat::GetDenominatorString( sal_uInt16 nNumFor ) const |
2403 | 0 | { |
2404 | 0 | const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); |
2405 | 0 | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
2406 | 0 | return lcl_GetDenominatorString( rInfo, nCnt ); |
2407 | 0 | } |
2408 | | |
2409 | | OUString SvNumberformat::GetNumeratorString( sal_uInt16 nNumFor ) const |
2410 | 0 | { |
2411 | 0 | const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); |
2412 | 0 | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
2413 | 0 | return lcl_GetNumeratorString( rInfo, nCnt ); |
2414 | 0 | } |
2415 | | |
2416 | | OUString SvNumberformat::GetIntegerFractionDelimiterString( sal_uInt16 nNumFor ) const |
2417 | 0 | { |
2418 | 0 | const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); |
2419 | 0 | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
2420 | 0 | return lcl_GetIntegerFractionDelimiterString( rInfo, nCnt ); |
2421 | 0 | } |
2422 | | |
2423 | | bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, OUString& rOutString, const NativeNumberWrapper& rNatNum) const |
2424 | 0 | { |
2425 | 0 | if (eType != SvNumFormatType::NUMBER) |
2426 | 0 | { |
2427 | 0 | return false; |
2428 | 0 | } |
2429 | 0 | double fTestNum = fNumber; |
2430 | 0 | bool bSign = std::signbit(fTestNum); |
2431 | 0 | if (bSign) |
2432 | 0 | { |
2433 | 0 | fTestNum = -fTestNum; |
2434 | 0 | } |
2435 | 0 | if (fTestNum < EXP_LOWER_BOUND) |
2436 | 0 | { |
2437 | 0 | lcl_GetOutputStringScientific(fNumber, nCharCount, GetCurrentLanguageData(), rOutString); |
2438 | 0 | return true; |
2439 | 0 | } |
2440 | | |
2441 | 0 | double fExp = log10(fTestNum); |
2442 | | // Values < 1.0 always have one digit before the decimal point. |
2443 | 0 | sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1; |
2444 | |
|
2445 | 0 | if (nDigitPre > 15) |
2446 | 0 | { |
2447 | 0 | lcl_GetOutputStringScientific(fNumber, nCharCount, GetCurrentLanguageData(), rOutString); |
2448 | 0 | return true; |
2449 | 0 | } |
2450 | | |
2451 | 0 | sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0; |
2452 | 0 | if (nPrec && bSign) |
2453 | 0 | { |
2454 | | // Subtract the negative sign. |
2455 | 0 | --nPrec; |
2456 | 0 | } |
2457 | 0 | if (nPrec) |
2458 | 0 | { |
2459 | | // Subtract the decimal point. |
2460 | 0 | --nPrec; |
2461 | 0 | } |
2462 | 0 | ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec, rNatNum); |
2463 | 0 | if (rOutString.getLength() > nCharCount) |
2464 | 0 | { |
2465 | | // String still wider than desired. Switch to scientific notation. |
2466 | 0 | lcl_GetOutputStringScientific(fNumber, nCharCount, GetCurrentLanguageData(), rOutString); |
2467 | 0 | } |
2468 | 0 | return true; |
2469 | 0 | } |
2470 | | |
2471 | | sal_uInt16 SvNumberformat::GetSubformatIndex (double fNumber ) const |
2472 | 426k | { |
2473 | 426k | sal_uInt16 nIx; // Index of the partial format |
2474 | 426k | double fLimit_1 = fLimit1; |
2475 | 426k | short nCheck = ImpCheckCondition(fNumber, fLimit_1, eOp1); |
2476 | 426k | if (nCheck == -1 || nCheck == 1) // Only 1 String or True |
2477 | 421k | { |
2478 | 421k | nIx = 0; |
2479 | 421k | } |
2480 | 4.77k | else |
2481 | 4.77k | { |
2482 | 4.77k | double fLimit_2 = fLimit2; |
2483 | 4.77k | nCheck = ImpCheckCondition(fNumber, fLimit_2, eOp2); |
2484 | 4.77k | if (nCheck == -1 || nCheck == 1) |
2485 | 2.83k | { |
2486 | 2.83k | nIx = 1; |
2487 | 2.83k | } |
2488 | 1.94k | else |
2489 | 1.94k | { |
2490 | 1.94k | nIx = 2; |
2491 | 1.94k | } |
2492 | 4.77k | } |
2493 | 426k | return nIx; |
2494 | 426k | } |
2495 | | |
2496 | | bool SvNumberformat::GetOutputString(double fNumber, |
2497 | | OUString& OutString, |
2498 | | const Color** ppColor, |
2499 | | const NativeNumberWrapper& rNatNum, |
2500 | | const SvNFLanguageData& rCurrentLang, |
2501 | | bool bStarFlag) const |
2502 | 755k | { |
2503 | 755k | bool bRes = false; |
2504 | 755k | OutString.clear(); |
2505 | 755k | *ppColor = nullptr; // No color change |
2506 | 755k | if (eType & SvNumFormatType::LOGICAL && sFormatstring == rScan.GetKeywords()[NF_KEY_BOOLEAN]) |
2507 | 6.64k | { |
2508 | 6.64k | if (fNumber) |
2509 | 4.89k | { |
2510 | 4.89k | OutString = rScan.GetTrueString(); |
2511 | 4.89k | } |
2512 | 1.74k | else |
2513 | 1.74k | { |
2514 | 1.74k | OutString = rScan.GetFalseString(); |
2515 | 1.74k | } |
2516 | 6.64k | return false; |
2517 | 6.64k | } |
2518 | 748k | OUStringBuffer sBuff(64); |
2519 | 748k | if (eType & SvNumFormatType::TEXT) |
2520 | 3 | { |
2521 | 3 | ImpGetOutputStandard(fNumber, sBuff, rNatNum); |
2522 | 3 | OutString = sBuff.makeStringAndClear(); |
2523 | 3 | return false; |
2524 | 3 | } |
2525 | 748k | bool bHadStandard = false; |
2526 | 748k | if (bStandard) // Individual standard formats |
2527 | 322k | { |
2528 | 322k | if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // All number format InputLine |
2529 | 43.1k | { |
2530 | 43.1k | ImpGetOutputInputLine(fNumber, OutString); |
2531 | 43.1k | return false; |
2532 | 43.1k | } |
2533 | 279k | switch (eType) |
2534 | 279k | { |
2535 | 263k | case SvNumFormatType::NUMBER: // Standard number format |
2536 | 263k | if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION) |
2537 | 248k | { |
2538 | 248k | if (std::signbit(fNumber)) |
2539 | 6.35k | { |
2540 | 6.35k | if (!(fNumber < 0.0)) |
2541 | 158 | fNumber = -fNumber; // do not display -0.0 |
2542 | 6.35k | } |
2543 | 248k | if (fNumber == 0.0) |
2544 | 52.3k | { |
2545 | 52.3k | OutString = "0"; |
2546 | 52.3k | } |
2547 | 196k | else if (fNumber < 1.0 && fNumber > -1.0) |
2548 | 7.89k | { |
2549 | | // Decide whether to display as 0.000000123... or 1.23...e-07 |
2550 | 7.89k | bool bFix = (fNumber < -EXP_LOWER_BOUND || EXP_LOWER_BOUND < fNumber); |
2551 | 7.89k | if (!bFix) |
2552 | 450 | { |
2553 | | // Arbitrary, not too many 0s visually, start E2 at 1E-10. |
2554 | 450 | constexpr sal_Int32 kMaxExp = 9; |
2555 | 450 | const sal_Int32 nExp = static_cast<sal_Int32>(ceil( -log10( fabs( fNumber)))); |
2556 | 450 | if (nExp <= kMaxExp && rtl::math::approxEqual( |
2557 | 368 | rtl::math::round( fNumber, 16), rtl::math::round( fNumber, nExp + 16))) |
2558 | 228 | { |
2559 | | // Not too many significant digits or accuracy |
2560 | | // artefacts, otherwise leave everything to E2 |
2561 | | // format. |
2562 | 228 | bFix = true; |
2563 | 228 | } |
2564 | 450 | } |
2565 | 7.89k | if (bFix) |
2566 | 7.67k | OutString = ::rtl::math::doubleToUString( fNumber, |
2567 | 7.67k | rtl_math_StringFormat_F, |
2568 | 7.67k | rtl_math_DecimalPlaces_Max, |
2569 | 7.67k | GetCurrentLanguageData().GetNumDecimalSep()[0], true); |
2570 | 222 | else |
2571 | 222 | OutString = ::rtl::math::doubleToUString( fNumber, |
2572 | 222 | rtl_math_StringFormat_E2, |
2573 | 222 | rtl_math_DecimalPlaces_Max, |
2574 | 222 | GetCurrentLanguageData().GetNumDecimalSep()[0], true); |
2575 | 7.89k | } |
2576 | 188k | else |
2577 | 188k | { |
2578 | 188k | OutString = ::rtl::math::doubleToUString( fNumber, |
2579 | 188k | rtl_math_StringFormat_Automatic, |
2580 | 188k | rtl_math_DecimalPlaces_Max, |
2581 | 188k | GetCurrentLanguageData().GetNumDecimalSep()[0], true); |
2582 | 188k | } |
2583 | 248k | return false; |
2584 | 248k | } |
2585 | 14.4k | ImpGetOutputStandard(fNumber, sBuff, rNatNum); |
2586 | 14.4k | bHadStandard = true; |
2587 | 14.4k | break; |
2588 | 15.6k | case SvNumFormatType::DATE: |
2589 | 15.6k | bRes |= ImpGetDateOutput(fNumber, 0, bStarFlag, rNatNum, rCurrentLang, sBuff); |
2590 | 15.6k | bHadStandard = true; |
2591 | 15.6k | break; |
2592 | 25 | case SvNumFormatType::TIME: |
2593 | 25 | bRes |= ImpGetTimeOutput(fNumber, 0, bStarFlag, rNatNum, rCurrentLang, sBuff); |
2594 | 25 | bHadStandard = true; |
2595 | 25 | break; |
2596 | 19 | case SvNumFormatType::DATETIME: |
2597 | 19 | bRes |= ImpGetDateTimeOutput(fNumber, 0, bStarFlag, rNatNum, rCurrentLang, sBuff); |
2598 | 19 | bHadStandard = true; |
2599 | 19 | break; |
2600 | 481 | default: break; |
2601 | 279k | } |
2602 | 279k | } |
2603 | 456k | if ( !bHadStandard ) |
2604 | 426k | { |
2605 | 426k | sal_uInt16 nIx = GetSubformatIndex ( fNumber ); // Index of the partial format |
2606 | 426k | if (fNumber < 0.0 && |
2607 | 3.62k | ((nIx == 0 && IsFirstSubformatRealNegative()) || // 1st, usually positive subformat |
2608 | 3.59k | (nIx == 1 && IsSecondSubformatRealNegative()))) // 2nd, usually negative subformat |
2609 | 2.84k | { |
2610 | 2.84k | fNumber = -fNumber; // eliminate sign |
2611 | 2.84k | } |
2612 | 426k | *ppColor = NumFor[nIx].GetColor(); |
2613 | 426k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
2614 | 426k | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
2615 | 426k | if (nCnt == 0 && rInfo.eScannedType == SvNumFormatType::EMPTY) |
2616 | 337 | { |
2617 | 337 | return false; // Empty => nothing |
2618 | 337 | } |
2619 | 426k | else if (nCnt == 0) // Else Standard Format |
2620 | 0 | { |
2621 | 0 | ImpGetOutputStandard(fNumber, sBuff, rNatNum); |
2622 | 0 | OutString = sBuff.makeStringAndClear(); |
2623 | 0 | return false; |
2624 | 0 | } |
2625 | 426k | switch (rInfo.eScannedType) |
2626 | 426k | { |
2627 | 149 | case SvNumFormatType::TEXT: |
2628 | 485 | case SvNumFormatType::DEFINED: |
2629 | 1.61k | for (sal_uInt16 i = 0; i < nCnt; i++) |
2630 | 1.13k | { |
2631 | 1.13k | switch (rInfo.nTypeArray[i]) |
2632 | 1.13k | { |
2633 | 178 | case NF_SYMBOLTYPE_STAR: |
2634 | 178 | if( bStarFlag ) |
2635 | 0 | { |
2636 | 0 | bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]); |
2637 | 0 | } |
2638 | 178 | break; |
2639 | 18 | case NF_SYMBOLTYPE_BLANK: |
2640 | 18 | if (rInfo.sStrArray[i].getLength() >= 2) |
2641 | 10 | InsertBlanks(sBuff, sBuff.getLength(), rInfo.sStrArray[i][1] ); |
2642 | 18 | break; |
2643 | 786 | case NF_SYMBOLTYPE_STRING: |
2644 | 786 | case NF_SYMBOLTYPE_CURRENCY: |
2645 | 786 | sBuff.append(rInfo.sStrArray[i]); |
2646 | 786 | break; |
2647 | 0 | case NF_SYMBOLTYPE_THSEP: |
2648 | 0 | if (rInfo.nThousand == 0) |
2649 | 0 | { |
2650 | 0 | sBuff.append(rInfo.sStrArray[i]); |
2651 | 0 | } |
2652 | 0 | break; |
2653 | 149 | default: |
2654 | 149 | break; |
2655 | 1.13k | } |
2656 | 1.13k | } |
2657 | 485 | break; |
2658 | 330k | case SvNumFormatType::DATE: |
2659 | 330k | bRes |= ImpGetDateOutput(fNumber, nIx, bStarFlag, rNatNum, rCurrentLang, sBuff); |
2660 | 330k | break; |
2661 | 7.35k | case SvNumFormatType::TIME: |
2662 | 7.35k | bRes |= ImpGetTimeOutput(fNumber, nIx, bStarFlag, rNatNum, rCurrentLang, sBuff); |
2663 | 7.35k | break; |
2664 | 6.69k | case SvNumFormatType::DATETIME: |
2665 | 6.69k | bRes |= ImpGetDateTimeOutput(fNumber, nIx, bStarFlag, rNatNum, rCurrentLang, sBuff); |
2666 | 6.69k | break; |
2667 | 65.7k | case SvNumFormatType::NUMBER: |
2668 | 69.9k | case SvNumFormatType::PERCENT: |
2669 | 74.7k | case SvNumFormatType::CURRENCY: |
2670 | 74.7k | bRes |= ImpGetNumberOutput(fNumber, nIx, bStarFlag, rNatNum, sBuff); |
2671 | 74.7k | break; |
2672 | 31 | case SvNumFormatType::LOGICAL: |
2673 | 31 | bRes |= ImpGetLogicalOutput(fNumber, nIx, rNatNum, sBuff); |
2674 | 31 | break; |
2675 | 1.94k | case SvNumFormatType::FRACTION: |
2676 | 1.94k | bRes |= ImpGetFractionOutput(fNumber, nIx, bStarFlag, rNatNum, sBuff); |
2677 | 1.94k | break; |
2678 | 5.00k | case SvNumFormatType::SCIENTIFIC: |
2679 | 5.00k | bRes |= ImpGetScientificOutput(fNumber, nIx, bStarFlag, rNatNum, sBuff); |
2680 | 5.00k | break; |
2681 | 1 | default: break; |
2682 | 426k | } |
2683 | 426k | } |
2684 | 456k | OutString = sBuff.makeStringAndClear(); |
2685 | 456k | return bRes; |
2686 | 456k | } |
2687 | | |
2688 | | bool SvNumberformat::ImpGetScientificOutput(double fNumber, |
2689 | | sal_uInt16 nIx, |
2690 | | bool bStarFlag, |
2691 | | const NativeNumberWrapper& rNatNum, |
2692 | | OUStringBuffer& sStr) const |
2693 | 5.00k | { |
2694 | 5.00k | bool bRes = false; |
2695 | 5.00k | bool bSign = false; |
2696 | | |
2697 | 5.00k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
2698 | 5.00k | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
2699 | | |
2700 | 5.00k | if (fNumber < 0) |
2701 | 182 | { |
2702 | 182 | if (nIx == 0) // Not in the ones at the end |
2703 | 182 | { |
2704 | 182 | bSign = true; // Formats |
2705 | 182 | } |
2706 | 182 | fNumber = -fNumber; |
2707 | 182 | } |
2708 | | |
2709 | 5.00k | sStr = ::rtl::math::doubleToUString( fNumber, |
2710 | 5.00k | rtl_math_StringFormat_E, |
2711 | 5.00k | rInfo.nCntPre + rInfo.nCntPost - 1, '.' ); |
2712 | 5.00k | OUStringBuffer ExpStr; |
2713 | 5.00k | short nExpSign = 1; |
2714 | 5.00k | sal_Int32 nExPos = sStr.indexOf('E'); |
2715 | 5.00k | sal_Int32 nDecPos = -1; |
2716 | | |
2717 | 5.00k | if ( nExPos >= 0 ) |
2718 | 5.00k | { |
2719 | | // split into mantissa and exponent and get rid of "E+" or "E-" |
2720 | 5.00k | sal_Int32 nExpStart = nExPos + 1; |
2721 | | |
2722 | 5.00k | switch ( sStr[ nExpStart ] ) |
2723 | 5.00k | { |
2724 | 398 | case '-' : |
2725 | 398 | nExpSign = -1; |
2726 | 398 | [[fallthrough]]; |
2727 | 5.00k | case '+' : |
2728 | 5.00k | ++nExpStart; |
2729 | 5.00k | break; |
2730 | 5.00k | } |
2731 | 5.00k | ExpStr = sStr.subView( nExpStart ); // part following the "E+" |
2732 | 5.00k | sStr.truncate( nExPos ); |
2733 | | |
2734 | 5.00k | if ( rInfo.nCntPre != 1 ) // rescale Exp |
2735 | 219 | { |
2736 | 219 | sal_Int32 nExp = OUString::unacquired(ExpStr).toInt32() * nExpSign; |
2737 | 219 | sal_Int32 nRescale = (rInfo.nCntPre != 0) ? nExp % static_cast<sal_Int32>(rInfo.nCntPre) : -1; |
2738 | 219 | if( nRescale < 0 && rInfo.nCntPre != 0 ) |
2739 | 76 | nRescale += static_cast<sal_Int32>(rInfo.nCntPre); |
2740 | 219 | nExp -= nRescale; |
2741 | 219 | if ( nExp < 0 ) |
2742 | 94 | { |
2743 | 94 | nExpSign = -1; |
2744 | 94 | nExp = -nExp; |
2745 | 94 | } |
2746 | 125 | else |
2747 | 125 | { |
2748 | 125 | nExpSign = 1; |
2749 | 125 | } |
2750 | 219 | ExpStr = OUString::number( nExp ); |
2751 | 219 | const sal_Unicode cFirstDigit = sStr[0]; |
2752 | | // rescale mantissa |
2753 | 219 | sStr = ::rtl::math::doubleToUString( fNumber, |
2754 | 219 | rtl_math_StringFormat_E, |
2755 | 219 | nRescale + rInfo.nCntPost, '.' ); |
2756 | | |
2757 | | // sStr now may contain a rounded-up value shifted into the next |
2758 | | // magnitude, for example 1.000E+02 (4 digits) for fNumber 99.995 |
2759 | | // (9.9995E+02 rounded to 3 decimals) but we want the final result |
2760 | | // to be 100.00E+00 (5 digits), so for the following fill routines |
2761 | | // below to work correctly append a zero decimal. |
2762 | | /* TODO: this is awkward, could an engineering notation mode be |
2763 | | * introduced to rtl_math_doubleToUString()? */ |
2764 | 219 | sStr.truncate( sStr.indexOf('E') ); |
2765 | 219 | if (sStr[0] == '1' && cFirstDigit != '1') |
2766 | 0 | sStr.append('0'); |
2767 | 219 | } |
2768 | | |
2769 | | // cut any decimal delimiter |
2770 | 5.00k | sal_Int32 index = 0; |
2771 | | |
2772 | 5.62k | while((index = sStr.indexOf('.', index)) >= 0) |
2773 | 619 | { |
2774 | 619 | if (nDecPos < 0) |
2775 | 619 | nDecPos = index; |
2776 | 619 | sStr.remove(index, 1); |
2777 | 619 | } |
2778 | 5.00k | } |
2779 | | |
2780 | 5.00k | sal_uInt16 j = nCnt-1; // Last symbol |
2781 | 5.00k | sal_Int32 k = ExpStr.getLength() - 1; // Position in ExpStr |
2782 | 5.00k | sal_Int32 nZeros = 0; // Erase leading zeros |
2783 | | |
2784 | | // erase all leading zeros except last one |
2785 | 14.4k | while (nZeros < k && ExpStr[nZeros] == '0') |
2786 | 9.47k | { |
2787 | 9.47k | ++nZeros; |
2788 | 9.47k | } |
2789 | 5.00k | if (nZeros) |
2790 | 4.76k | { |
2791 | 4.76k | ExpStr.remove( 0, nZeros); |
2792 | 4.76k | } |
2793 | | |
2794 | | // restore leading zeros or blanks according to format '0' or '?' tdf#156449 |
2795 | 5.00k | bRes |= ImpNumberFill(rNatNum, ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP, bStarFlag); |
2796 | | |
2797 | 5.00k | bool bCont = true; |
2798 | | |
2799 | 5.00k | if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP) |
2800 | 5.00k | { |
2801 | 5.00k | const OUString& rStr = rInfo.sStrArray[j]; |
2802 | 5.00k | if (nExpSign == -1) |
2803 | 398 | { |
2804 | 398 | ExpStr.insert(0, '-'); |
2805 | 398 | } |
2806 | 4.60k | else if (rStr.getLength() > 1 && rStr[1] == '+') |
2807 | 482 | { |
2808 | 482 | ExpStr.insert(0, '+'); |
2809 | 482 | } |
2810 | 5.00k | ExpStr.insert(0, rStr[0]); |
2811 | 5.00k | if ( j ) |
2812 | 776 | { |
2813 | 776 | j--; |
2814 | 776 | } |
2815 | 4.22k | else |
2816 | 4.22k | { |
2817 | 4.22k | bCont = false; |
2818 | 4.22k | } |
2819 | 5.00k | } |
2820 | | // Continue main number: |
2821 | 5.00k | if ( !bCont ) |
2822 | 4.22k | { |
2823 | 4.22k | sStr.truncate(); |
2824 | 4.22k | } |
2825 | 776 | else |
2826 | 776 | { |
2827 | 776 | bRes |= ImpDecimalFill(rNatNum, sStr, fNumber, nDecPos, j, nIx, false, bStarFlag); |
2828 | 776 | } |
2829 | | |
2830 | 5.00k | if (bSign) |
2831 | 182 | { |
2832 | 182 | sStr.insert(0, '-'); |
2833 | 182 | } |
2834 | 5.00k | sStr.append(ExpStr); |
2835 | | |
2836 | 5.00k | return bRes; |
2837 | 5.00k | } |
2838 | | |
2839 | | double SvNumberformat::GetRoundFractionValue ( double fNumber ) const |
2840 | 0 | { |
2841 | 0 | sal_uInt16 nIx = GetSubformatIndex ( fNumber ); |
2842 | 0 | double fIntPart = 0.0; // integer part of fraction |
2843 | 0 | sal_Int64 nFrac = 0, nDiv = 1; // numerator and denominator |
2844 | 0 | double fSign = (fNumber < 0.0) ? -1.0 : 1.0; |
2845 | | // fNumber is modified in ImpGetFractionElements to absolute fractional part |
2846 | 0 | ImpGetFractionElements ( fNumber, nIx, fIntPart, nFrac, nDiv ); |
2847 | 0 | if ( nDiv > 0 ) |
2848 | 0 | return fSign * ( fIntPart + static_cast<double>(nFrac) / static_cast<double>(nDiv) ); |
2849 | 0 | else |
2850 | 0 | return fSign * fIntPart; |
2851 | 0 | } |
2852 | | |
2853 | | void SvNumberformat::ImpGetFractionElements ( double& fNumber, sal_uInt16 nIx, |
2854 | | double& fIntPart, sal_Int64& nFrac, sal_Int64& nDiv ) const |
2855 | 1.44k | { |
2856 | 1.44k | if ( fNumber < 0.0 ) |
2857 | 0 | fNumber = -fNumber; |
2858 | 1.44k | fIntPart = floor(fNumber); // Integral part |
2859 | 1.44k | fNumber -= fIntPart; // Fractional part |
2860 | 1.44k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
2861 | 1.44k | sal_Int64 nForcedDiv = lcl_GetDenominatorString( rInfo, NumFor[nIx].GetCount() ).toInt32(); |
2862 | 1.44k | if( nForcedDiv > 0 ) |
2863 | 506 | { // Forced Denominator |
2864 | 506 | nDiv = nForcedDiv; |
2865 | 506 | nFrac = static_cast<sal_Int64>(floor ( fNumber * nDiv )); |
2866 | 506 | double fFracNew = static_cast<double>(nFrac) / static_cast<double>(nDiv); |
2867 | 506 | double fFracNew1 = static_cast<double>(nFrac + 1) / static_cast<double>(nDiv); |
2868 | 506 | double fDiff = fNumber - fFracNew; |
2869 | 506 | if( fDiff > ( fFracNew1 - fNumber ) ) |
2870 | 18 | { |
2871 | 18 | nFrac++; |
2872 | 18 | } |
2873 | 506 | } |
2874 | 937 | else // Calculated Denominator |
2875 | 937 | { |
2876 | 937 | nDiv = 1; |
2877 | 937 | sal_Int64 nBasis = static_cast<sal_Int64>(floor( pow(10.0,rInfo.nCntExp))) - 1; // 9, 99, 999 ,... |
2878 | 937 | sal_Int64 nFracPrev = 1, nDivPrev = 0, nFracNext, nDivNext, nPartialDenom; |
2879 | 937 | double fRemainder = fNumber; |
2880 | | |
2881 | | // Use continued fraction representation of fNumber |
2882 | | // See https://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximations |
2883 | 1.11k | while ( fRemainder > 0.0 ) |
2884 | 180 | { |
2885 | 180 | double fTemp = 1.0 / fRemainder; // 64bits precision required when fRemainder is very weak |
2886 | 180 | nPartialDenom = static_cast<sal_Int64>(floor(fTemp)); // due to floating point notation with double precision |
2887 | 180 | fRemainder = fTemp - static_cast<double>(nPartialDenom); |
2888 | 180 | nDivNext = nPartialDenom * nDiv + nDivPrev; |
2889 | 180 | if ( nDivNext <= nBasis ) // continue loop |
2890 | 144 | { |
2891 | 144 | nFracNext = nPartialDenom * nFrac + nFracPrev; |
2892 | 144 | nFracPrev = nFrac; |
2893 | 144 | nFrac = nFracNext; |
2894 | 144 | nDivPrev = nDiv; |
2895 | 144 | nDiv = nDivNext; |
2896 | 144 | } |
2897 | 36 | else // calculate collateral fraction and exit |
2898 | 36 | { |
2899 | 36 | sal_Int64 nCollat = (nBasis - nDivPrev) / nDiv; |
2900 | 36 | if ( 2 * nCollat >= nPartialDenom ) |
2901 | 3 | { |
2902 | 3 | sal_Int64 nFracTest = nCollat * nFrac + nFracPrev; |
2903 | 3 | sal_Int64 nDivTest = nCollat * nDiv + nDivPrev; |
2904 | 3 | double fSign = (static_cast<double>(nFrac) > fNumber * static_cast<double>(nDiv))?1.0:-1.0; |
2905 | 3 | if ( fSign * ( double(nFrac * nDivTest + nDiv * nFracTest) - 2.0 * double(nDiv * nDivTest) * fNumber ) > 0.0 ) |
2906 | 3 | { |
2907 | 3 | nFrac = nFracTest; |
2908 | 3 | nDiv = nDivTest; |
2909 | 3 | } |
2910 | 3 | } |
2911 | 36 | fRemainder = 0.0; // exit while loop |
2912 | 36 | } |
2913 | 180 | } |
2914 | 937 | } |
2915 | 1.44k | if (nFrac >= nDiv) |
2916 | 0 | { |
2917 | 0 | ++fIntPart; |
2918 | 0 | nFrac = 0; |
2919 | 0 | nDiv = ( nForcedDiv > 0 ) ? nForcedDiv : 1; |
2920 | 0 | } |
2921 | 1.44k | } |
2922 | | |
2923 | | bool SvNumberformat::ImpGetFractionOutput(double fNumber, |
2924 | | sal_uInt16 nIx, |
2925 | | bool bStarFlag, |
2926 | | const NativeNumberWrapper& rNatNum, |
2927 | | OUStringBuffer& sBuff) const |
2928 | 1.94k | { |
2929 | 1.94k | bool bRes = false; |
2930 | 1.94k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
2931 | 1.94k | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
2932 | 1.94k | OUStringBuffer sStr, sFrac, sDiv; // Strings, value for Integral part Numerator and denominator |
2933 | 1.94k | bool bSign = ( (fNumber < 0) && (nIx == 0) ); // sign Not in the ones at the end |
2934 | 1.94k | const OUString sIntegerFormat = lcl_GetFractionIntegerString(rInfo, nCnt); |
2935 | 1.94k | const OUString sNumeratorFormat = lcl_GetNumeratorString(rInfo, nCnt); |
2936 | 1.94k | const OUString sDenominatorFormat = lcl_GetDenominatorString(rInfo, nCnt); |
2937 | | |
2938 | 1.94k | sal_Int64 nFrac = 0, nDiv = 1; |
2939 | 1.94k | double fNum = floor(fNumber); // Integral part |
2940 | | |
2941 | 1.94k | if (fNum > D_MAX_U_INT32 || rInfo.nCntExp > 9) // Too large |
2942 | 502 | { |
2943 | 502 | sBuff = ImpSvNumberformatScan::sErrStr; |
2944 | 502 | return false; |
2945 | 502 | } |
2946 | 1.44k | if (rInfo.nCntExp == 0) |
2947 | 0 | { |
2948 | 0 | SAL_WARN( "svl.numbers", "SvNumberformat:: Fraction, nCntExp == 0"); |
2949 | 0 | sBuff.truncate(); |
2950 | 0 | return false; |
2951 | 0 | } |
2952 | | |
2953 | 1.44k | ImpGetFractionElements( fNumber, nIx, fNum, nFrac, nDiv); |
2954 | | |
2955 | 1.44k | if (rInfo.nCntPre == 0) // Improper fraction |
2956 | 1.04k | { |
2957 | 1.04k | double fNum1 = fNum * static_cast<double>(nDiv) + static_cast<double>(nFrac); |
2958 | | |
2959 | 1.04k | if (fNum1 > D_MAX_INTEGER) |
2960 | 3 | { |
2961 | 3 | sBuff = ImpSvNumberformatScan::sErrStr; |
2962 | 3 | return false; |
2963 | 3 | } |
2964 | 1.04k | nFrac = static_cast<sal_Int64>(floor(fNum1)); |
2965 | 1.04k | } |
2966 | 398 | else if (fNum == 0.0 && nFrac != 0) |
2967 | 8 | { |
2968 | 8 | } |
2969 | 390 | else |
2970 | 390 | { |
2971 | 390 | char aBuf[100]; |
2972 | 390 | o3tl::sprintf( aBuf, "%.f", fNum ); // simple rounded integer |
2973 | 390 | sStr.appendAscii( aBuf ); |
2974 | 390 | ::impTransliterate(sStr, NumFor[nIx].GetNatNum(), rNatNum); |
2975 | 390 | } |
2976 | 1.44k | bool bHideFraction = (rInfo.nCntPre > 0 && nFrac == 0 |
2977 | 340 | && (sNumeratorFormat.indexOf('0') < 0) |
2978 | 328 | && (sDenominatorFormat.indexOf('0') < 0 |
2979 | 274 | || sDenominatorFormat.toInt32() > 0) ); |
2980 | 1.44k | if ( bHideFraction ) |
2981 | 267 | { |
2982 | 267 | sDiv.truncate(); |
2983 | 267 | } |
2984 | 1.17k | else // if there are some '0' in format, force display of fraction |
2985 | 1.17k | { |
2986 | 1.17k | sFrac = ImpIntToString(rNatNum, nIx, nFrac); |
2987 | 1.17k | sDiv = ImpIntToString(rNatNum, nIx, nDiv); |
2988 | 1.17k | } |
2989 | | |
2990 | 1.44k | sal_uInt16 j = nCnt-1; // Last symbol -> backwards |
2991 | 1.44k | sal_Int32 k; // Denominator |
2992 | | |
2993 | 1.44k | bRes |= ImpNumberFill(rNatNum, sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC, bStarFlag, true); |
2994 | | |
2995 | 1.44k | bool bCont = true; |
2996 | 1.44k | if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC) |
2997 | 1.44k | { |
2998 | 1.44k | if ( bHideFraction ) |
2999 | 267 | { // do not insert blank for fraction if there is no '?' |
3000 | 267 | if ( sNumeratorFormat.indexOf('?') >= 0 |
3001 | 248 | || sDenominatorFormat.indexOf('?') >= 0 ) |
3002 | 57 | sDiv.insert(0, ' '); |
3003 | 267 | } |
3004 | 1.17k | else |
3005 | 1.17k | { |
3006 | 1.17k | sDiv.insert(0, rInfo.sStrArray[j][0]); |
3007 | 1.17k | } |
3008 | 1.44k | if ( j ) |
3009 | 1.44k | { |
3010 | 1.44k | j--; |
3011 | 1.44k | } |
3012 | 0 | else |
3013 | 0 | { |
3014 | 0 | bCont = false; |
3015 | 0 | } |
3016 | 1.44k | } |
3017 | | // Further numerators: |
3018 | 1.44k | if ( !bCont ) |
3019 | 0 | { |
3020 | 0 | sFrac.truncate(); |
3021 | 0 | } |
3022 | 1.44k | else |
3023 | 1.44k | { |
3024 | 1.44k | bRes |= ImpNumberFill(rNatNum, sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK, bStarFlag); |
3025 | 1.44k | bCont = false; // there is no integer part? |
3026 | 1.44k | if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK) |
3027 | 399 | { |
3028 | 399 | if ( j ) |
3029 | 399 | { |
3030 | 399 | if ( bHideFraction ) |
3031 | 267 | { // '?' in any format force display of blank as delimiter |
3032 | 267 | if ( sIntegerFormat.indexOf('?') >= 0 |
3033 | 254 | || sNumeratorFormat.indexOf('?') >= 0 |
3034 | 235 | || sDenominatorFormat.indexOf('?') >= 0 ) |
3035 | 63 | { |
3036 | 362 | for (sal_Int32 i = 0; i < rInfo.sStrArray[j].getLength(); i++) |
3037 | 299 | sFrac.insert(0, ' '); |
3038 | 63 | } |
3039 | 267 | } |
3040 | 132 | else |
3041 | 132 | { |
3042 | 132 | if ( fNum != 0.0 || sIntegerFormat.indexOf('0') >= 0 ) |
3043 | 99 | sFrac.insert(0, rInfo.sStrArray[j]); // insert Blank string only if there are both integer and fraction |
3044 | 33 | else |
3045 | 33 | { |
3046 | 33 | if ( sIntegerFormat.indexOf('?') >= 0 |
3047 | 32 | || sNumeratorFormat.indexOf('?') >= 0 ) |
3048 | 29 | { |
3049 | 178 | for (sal_Int32 i = 0; i < rInfo.sStrArray[j].getLength(); i++) |
3050 | 149 | sFrac.insert(0, ' '); |
3051 | 29 | } |
3052 | 33 | } |
3053 | 132 | } |
3054 | 399 | j--; |
3055 | 399 | bCont = true; // Yes, there is an integer |
3056 | 399 | } |
3057 | 0 | else |
3058 | 0 | sFrac.insert(0, rInfo.sStrArray[j]); |
3059 | 399 | } |
3060 | 1.44k | } |
3061 | | // Continue integer part |
3062 | 1.44k | if ( !bCont ) |
3063 | 1.04k | { |
3064 | 1.04k | sStr.truncate(); |
3065 | 1.04k | } |
3066 | 399 | else |
3067 | 399 | { |
3068 | 399 | k = sStr.getLength(); // After last figure |
3069 | 399 | bRes |= ImpNumberFillWithThousands(rNatNum, sStr, fNumber, k, j, nIx, |
3070 | 399 | rInfo.nCntPre, bStarFlag); |
3071 | 399 | } |
3072 | 1.44k | if (bSign && (nFrac != 0 || fNum != 0.0)) |
3073 | 0 | { |
3074 | 0 | sBuff.insert(0, '-'); // Not -0 |
3075 | 0 | } |
3076 | 1.44k | sBuff.append(sStr); |
3077 | 1.44k | sBuff.append(sFrac); |
3078 | 1.44k | sBuff.append(sDiv); |
3079 | 1.44k | return bRes; |
3080 | 1.44k | } |
3081 | | |
3082 | | sal_uInt16 SvNumberformat::ImpGetFractionOfSecondString( OUStringBuffer& rBuf, double fFractionOfSecond, |
3083 | | int nFractionDecimals, bool bAddOneRoundingDecimal, sal_uInt16 nIx, sal_uInt16 nMinimumInputLineDecimals, |
3084 | | const NativeNumberWrapper& rNatNum) const |
3085 | 14.0k | { |
3086 | 14.0k | if (!nFractionDecimals) |
3087 | 13.4k | return 0; |
3088 | | |
3089 | | // nFractionDecimals+1 to not round up what Time::GetClock() carefully |
3090 | | // truncated. |
3091 | 658 | rBuf.append( rtl::math::doubleToUString( fFractionOfSecond, rtl_math_StringFormat_F, |
3092 | 658 | (bAddOneRoundingDecimal ? nFractionDecimals + 1 : nFractionDecimals), '.')); |
3093 | 658 | rBuf.stripStart('0'); |
3094 | 658 | rBuf.stripStart('.'); |
3095 | 658 | if (bAddOneRoundingDecimal && rBuf.getLength() > nFractionDecimals) |
3096 | 658 | rBuf.truncate( nFractionDecimals); // the digit appended because of nFractionDecimals+1 |
3097 | 658 | if (nMinimumInputLineDecimals) |
3098 | 0 | { |
3099 | 0 | rBuf.stripEnd('0'); |
3100 | 0 | for (sal_Int32 index = rBuf.getLength(); index < nMinimumInputLineDecimals; ++index) |
3101 | 0 | { |
3102 | 0 | rBuf.append('0'); |
3103 | 0 | } |
3104 | 0 | ::impTransliterate(rBuf, NumFor[nIx].GetNatNum(), rNatNum); |
3105 | 0 | nFractionDecimals = rBuf.getLength(); |
3106 | 0 | } |
3107 | 658 | else |
3108 | 658 | { |
3109 | 658 | ::impTransliterate(rBuf, NumFor[nIx].GetNatNum(), rNatNum); |
3110 | 658 | } |
3111 | 658 | return static_cast<sal_uInt16>(nFractionDecimals); |
3112 | 14.0k | } |
3113 | | |
3114 | | bool SvNumberformat::ImpGetTimeOutput(double fNumber, |
3115 | | sal_uInt16 nIx, |
3116 | | bool bStarFlag, |
3117 | | const NativeNumberWrapper& rNatNum, |
3118 | | const SvNFLanguageData& rCurrentLang, |
3119 | | OUStringBuffer& sBuff) const |
3120 | 7.37k | { |
3121 | 7.37k | using namespace ::com::sun::star::i18n; |
3122 | 7.37k | bool bCalendarSet = false; |
3123 | 7.37k | const double fNumberOrig = fNumber; |
3124 | 7.37k | bool bRes = false; |
3125 | 7.37k | bool bSign = false; |
3126 | 7.37k | if (fNumber < 0.0) |
3127 | 18 | { |
3128 | 18 | fNumber = -fNumber; |
3129 | 18 | if (nIx == 0) |
3130 | 18 | { |
3131 | 18 | bSign = true; |
3132 | 18 | } |
3133 | 18 | } |
3134 | 7.37k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
3135 | 7.37k | bool bInputLine; |
3136 | 7.37k | sal_Int32 nCntPost; |
3137 | 7.37k | if ( rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION && |
3138 | 0 | 0 < rInfo.nCntPost && rInfo.nCntPost < kTimeSignificantRound ) |
3139 | 0 | { |
3140 | 0 | bInputLine = true; |
3141 | 0 | nCntPost = kTimeSignificantRound; |
3142 | 0 | } |
3143 | 7.37k | else |
3144 | 7.37k | { |
3145 | 7.37k | bInputLine = false; |
3146 | 7.37k | nCntPost = rInfo.nCntPost; |
3147 | 7.37k | } |
3148 | | |
3149 | 7.37k | OUStringBuffer sSecStr; |
3150 | 7.37k | sal_Int32 nSecPos = 0; // For figure by figure processing |
3151 | 7.37k | sal_uInt32 nHour, nMin, nSec; |
3152 | 7.37k | if (!rInfo.bThousand) // No [] format |
3153 | 5.70k | { |
3154 | 5.70k | sal_uInt16 nCHour, nCMinute, nCSecond; |
3155 | 5.70k | double fFractionOfSecond; |
3156 | 5.70k | tools::Time::GetClock( fNumberOrig, nCHour, nCMinute, nCSecond, fFractionOfSecond, nCntPost); |
3157 | 5.70k | nHour = nCHour; |
3158 | 5.70k | nMin = nCMinute; |
3159 | 5.70k | nSec = nCSecond; |
3160 | 5.70k | nCntPost = ImpGetFractionOfSecondString( sSecStr, fFractionOfSecond, nCntPost, true, nIx, |
3161 | 5.70k | (bInputLine ? rInfo.nCntPost : 0), rNatNum ); |
3162 | 5.70k | } |
3163 | 1.67k | else |
3164 | 1.67k | { |
3165 | 1.67k | const double fTime = rtl::math::round( fNumber * 86400.0, int(nCntPost)); |
3166 | 1.67k | if (bSign && fTime == 0.0) |
3167 | 0 | { |
3168 | 0 | bSign = false; // Not -00:00:00 |
3169 | 0 | } |
3170 | 1.67k | if (fTime > D_MAX_U_INT32) |
3171 | 0 | { |
3172 | 0 | sBuff = ImpSvNumberformatScan::sErrStr; |
3173 | 0 | return false; |
3174 | 0 | } |
3175 | 1.67k | sal_uInt32 nSeconds = static_cast<sal_uInt32>(fTime); |
3176 | | |
3177 | 1.67k | nCntPost = ImpGetFractionOfSecondString( sSecStr, fTime - nSeconds, nCntPost, false, nIx, |
3178 | 1.67k | (bInputLine ? rInfo.nCntPost : 0), rNatNum ); |
3179 | | |
3180 | 1.67k | if (rInfo.nThousand == 3) // [ss] |
3181 | 0 | { |
3182 | 0 | nHour = 0; |
3183 | 0 | nMin = 0; |
3184 | 0 | nSec = nSeconds; |
3185 | 0 | } |
3186 | 1.67k | else if (rInfo.nThousand == 2) // [mm]:ss |
3187 | 3 | { |
3188 | 3 | nHour = 0; |
3189 | 3 | nMin = nSeconds / 60; |
3190 | 3 | nSec = nSeconds % 60; |
3191 | 3 | } |
3192 | 1.67k | else if (rInfo.nThousand == 1) // [hh]:mm:ss |
3193 | 1.67k | { |
3194 | 1.67k | nHour = nSeconds / 3600; |
3195 | 1.67k | nMin = (nSeconds%3600) / 60; |
3196 | 1.67k | nSec = nSeconds%60; |
3197 | 1.67k | } |
3198 | 1 | else |
3199 | 1 | { |
3200 | | // TODO What should these be set to? |
3201 | 1 | nHour = 0; |
3202 | 1 | nMin = 0; |
3203 | 1 | nSec = 0; |
3204 | 1 | } |
3205 | 1.67k | } |
3206 | | |
3207 | 7.37k | sal_Unicode cAmPm = ' '; // a or p |
3208 | 7.37k | if (rInfo.nCntExp) // AM/PM |
3209 | 63 | { |
3210 | 63 | if (nHour == 0) |
3211 | 3 | { |
3212 | 3 | nHour = 12; |
3213 | 3 | cAmPm = 'a'; |
3214 | 3 | } |
3215 | 60 | else if (nHour < 12) |
3216 | 50 | { |
3217 | 50 | cAmPm = 'a'; |
3218 | 50 | } |
3219 | 10 | else |
3220 | 10 | { |
3221 | 10 | cAmPm = 'p'; |
3222 | 10 | if (nHour > 12) |
3223 | 6 | { |
3224 | 6 | nHour -= 12; |
3225 | 6 | } |
3226 | 10 | } |
3227 | 63 | } |
3228 | 7.37k | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
3229 | 56.8k | for (sal_uInt16 i = 0; i < nCnt; i++) |
3230 | 49.5k | { |
3231 | 49.5k | sal_Int32 nLen; |
3232 | 49.5k | switch (rInfo.nTypeArray[i]) |
3233 | 49.5k | { |
3234 | 136 | case NF_SYMBOLTYPE_STAR: |
3235 | 136 | if( bStarFlag ) |
3236 | 0 | { |
3237 | 0 | bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]); |
3238 | 0 | } |
3239 | 136 | break; |
3240 | 66 | case NF_SYMBOLTYPE_BLANK: |
3241 | 66 | if (rInfo.sStrArray[i].getLength() >= 2) |
3242 | 65 | InsertBlanks(sBuff, sBuff.getLength(), rInfo.sStrArray[i][1] ); |
3243 | 66 | break; |
3244 | 2.79k | case NF_SYMBOLTYPE_STRING: |
3245 | 2.79k | case NF_SYMBOLTYPE_CURRENCY: |
3246 | 2.79k | case NF_SYMBOLTYPE_DATESEP: |
3247 | 26.6k | case NF_SYMBOLTYPE_TIMESEP: |
3248 | 26.6k | case NF_SYMBOLTYPE_TIME100SECSEP: |
3249 | 26.6k | sBuff.append(rInfo.sStrArray[i]); |
3250 | 26.6k | break; |
3251 | 608 | case NF_SYMBOLTYPE_DIGIT: |
3252 | 608 | nLen = ( bInputLine && i > 0 && |
3253 | 0 | (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || |
3254 | 0 | rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? |
3255 | 608 | nCntPost : rInfo.sStrArray[i].getLength() ); |
3256 | 1.29k | for (sal_Int32 j = 0; j < nLen && nSecPos < nCntPost && nSecPos < sSecStr.getLength(); ++j) |
3257 | 683 | { |
3258 | 683 | sBuff.append(sSecStr[nSecPos]); |
3259 | 683 | nSecPos++; |
3260 | 683 | } |
3261 | 608 | break; |
3262 | 63 | case NF_KEY_AMPM: // AM/PM |
3263 | 63 | { |
3264 | 63 | CalendarWrapper& rCal = *rCurrentLang.GetCalendar(); |
3265 | 63 | if ( !bCalendarSet ) |
3266 | 63 | { |
3267 | 63 | double fDiff = DateTime::Sub( DateTime(rScan.GetNullDate()), rCal.getEpochStart()); |
3268 | 63 | fDiff += fNumberOrig; |
3269 | 63 | rCal.setLocalDateTime( fDiff ); |
3270 | 63 | bCalendarSet = true; |
3271 | 63 | } |
3272 | 63 | if (cAmPm == 'a') |
3273 | 53 | { |
3274 | 53 | sBuff.append(rCal.getDisplayName( |
3275 | 53 | CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 )); |
3276 | 53 | } |
3277 | 10 | else |
3278 | 10 | { |
3279 | 10 | sBuff.append(rCal.getDisplayName( |
3280 | 10 | CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 )); |
3281 | 10 | } |
3282 | 63 | break; |
3283 | 26.6k | } |
3284 | 0 | case NF_KEY_AP: // A/P |
3285 | 0 | if (cAmPm == 'a') |
3286 | 0 | { |
3287 | 0 | sBuff.append('a'); |
3288 | 0 | } |
3289 | 0 | else |
3290 | 0 | { |
3291 | 0 | sBuff.append('p'); |
3292 | 0 | } |
3293 | 0 | break; |
3294 | 434 | case NF_KEY_MI: // M |
3295 | 434 | sBuff.append(ImpIntToString(rNatNum, nIx, nMin )); |
3296 | 434 | break; |
3297 | 6.53k | case NF_KEY_MMI: // MM |
3298 | 6.53k | sBuff.append(ImpIntToString(rNatNum, nIx, nMin, 2 )); |
3299 | 6.53k | break; |
3300 | 645 | case NF_KEY_H: // H |
3301 | 645 | sBuff.append(ImpIntToString(rNatNum, nIx, nHour )); |
3302 | 645 | break; |
3303 | 6.01k | case NF_KEY_HH: // HH |
3304 | 6.01k | sBuff.append(ImpIntToString(rNatNum, nIx, nHour, 2 )); |
3305 | 6.01k | break; |
3306 | 662 | case NF_KEY_S: // S |
3307 | 662 | sBuff.append(ImpIntToString(rNatNum, nIx, nSec )); |
3308 | 662 | break; |
3309 | 4.29k | case NF_KEY_SS: // SS |
3310 | 4.29k | sBuff.append(ImpIntToString(rNatNum, nIx, nSec, 2 )); |
3311 | 4.29k | break; |
3312 | 3.36k | default: |
3313 | 3.36k | break; |
3314 | 49.5k | } |
3315 | 49.5k | } |
3316 | 7.37k | if (bSign && rInfo.bThousand) |
3317 | 0 | { |
3318 | 0 | sBuff.insert(0, '-'); |
3319 | 0 | } |
3320 | 7.37k | return bRes; |
3321 | 7.37k | } |
3322 | | |
3323 | | |
3324 | | /** If a day of month occurs within the format, the month name is in possessive |
3325 | | genitive case if the day follows the month, and partitive case if the day |
3326 | | precedes the month. If there is no day of month the nominative case (noun) |
3327 | | is returned. Also if the month is immediately preceded or followed by a |
3328 | | literal string other than space and not followed by a comma, the nominative |
3329 | | name is used, this prevents duplicated casing for MMMM\t\a and such in |
3330 | | documents imported from (e.g. Finnish) Excel or older LibO/OOo releases. |
3331 | | */ |
3332 | | |
3333 | | // IDEA: instead of eCodeType pass the index to nTypeArray and restrict |
3334 | | // inspection of month name around that one, that would enable different month |
3335 | | // cases in one format. Though probably the most rare use case ever... |
3336 | | |
3337 | | sal_Int32 SvNumberformat::ImpUseMonthCase( int & io_nState, const ImpSvNumFor& rNumFor, NfKeywordIndex eCodeType ) |
3338 | 6.41k | { |
3339 | 6.41k | using namespace ::com::sun::star::i18n; |
3340 | 6.41k | if (!io_nState) |
3341 | 3.46k | { |
3342 | 3.46k | bool bMonthSeen = false; |
3343 | 3.46k | bool bDaySeen = false; |
3344 | 3.46k | const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); |
3345 | 3.46k | const sal_uInt16 nCount = rNumFor.GetCount(); |
3346 | 23.6k | for (sal_uInt16 i = 0; i < nCount && io_nState == 0; ++i) |
3347 | 20.2k | { |
3348 | 20.2k | sal_Int32 nLen; |
3349 | 20.2k | switch (rInfo.nTypeArray[i]) |
3350 | 20.2k | { |
3351 | 1.21k | case NF_KEY_D : |
3352 | 2.78k | case NF_KEY_DD : |
3353 | 2.78k | if (bMonthSeen) |
3354 | 359 | { |
3355 | 359 | io_nState = 2; |
3356 | 359 | } |
3357 | 2.42k | else |
3358 | 2.42k | { |
3359 | 2.42k | bDaySeen = true; |
3360 | 2.42k | } |
3361 | 2.78k | break; |
3362 | 1.21k | case NF_KEY_MMM: |
3363 | 2.87k | case NF_KEY_MMMM: |
3364 | 4.25k | case NF_KEY_MMMMM: |
3365 | 4.25k | if ((i < nCount-1 && |
3366 | 4.23k | rInfo.nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && |
3367 | | // Literal following, not empty, space nor comma. |
3368 | 2.76k | !rInfo.sStrArray[i+1].isEmpty() && |
3369 | 2.76k | rInfo.sStrArray[i+1][0] != ' ' && rInfo.sStrArray[i+1][0] != ',') || |
3370 | 3.90k | (i > 0 && rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING && |
3371 | 2.59k | ((nLen = rInfo.sStrArray[i-1].getLength()) > 0) && |
3372 | | // Literal preceding, not space. |
3373 | 2.59k | rInfo.sStrArray[i-1][nLen-1] != ' ')) |
3374 | 807 | { |
3375 | 807 | io_nState = 1; |
3376 | 807 | } |
3377 | 3.45k | else if (bDaySeen) |
3378 | 2.21k | { |
3379 | 2.21k | io_nState = 3; |
3380 | 2.21k | } |
3381 | 1.23k | else |
3382 | 1.23k | { |
3383 | 1.23k | bMonthSeen = true; |
3384 | 1.23k | } |
3385 | 4.25k | break; |
3386 | 20.2k | } |
3387 | 20.2k | } |
3388 | 3.46k | if (io_nState == 0) |
3389 | 88 | { |
3390 | 88 | io_nState = 1; // No day of month |
3391 | 88 | } |
3392 | 3.46k | } |
3393 | 6.41k | switch (io_nState) |
3394 | 6.41k | { |
3395 | 3.45k | case 1: |
3396 | | // No day of month or forced nominative |
3397 | 3.45k | switch (eCodeType) |
3398 | 3.45k | { |
3399 | 706 | case NF_KEY_MMM: |
3400 | 706 | return CalendarDisplayCode::SHORT_MONTH_NAME; |
3401 | 26 | case NF_KEY_MMMM: |
3402 | 26 | return CalendarDisplayCode::LONG_MONTH_NAME; |
3403 | 2.71k | case NF_KEY_MMMMM: |
3404 | 2.71k | return CalendarDisplayCode::NARROW_MONTH_NAME; |
3405 | 0 | default: |
3406 | 0 | ; // nothing |
3407 | 3.45k | } |
3408 | 0 | break; |
3409 | 688 | case 2: |
3410 | | // Day of month follows month (the month's 17th) |
3411 | 688 | switch (eCodeType) |
3412 | 688 | { |
3413 | 259 | case NF_KEY_MMM: |
3414 | 259 | return CalendarDisplayCode::SHORT_GENITIVE_MONTH_NAME; |
3415 | 48 | case NF_KEY_MMMM: |
3416 | 48 | return CalendarDisplayCode::LONG_GENITIVE_MONTH_NAME; |
3417 | 381 | case NF_KEY_MMMMM: |
3418 | 381 | return CalendarDisplayCode::NARROW_GENITIVE_MONTH_NAME; |
3419 | 0 | default: |
3420 | 0 | ; // Nothing |
3421 | 688 | } |
3422 | 0 | break; |
3423 | 2.27k | case 3: |
3424 | | // Day of month precedes month (17 of month) |
3425 | 2.27k | switch (eCodeType) |
3426 | 2.27k | { |
3427 | 614 | case NF_KEY_MMM: |
3428 | 614 | return CalendarDisplayCode::SHORT_PARTITIVE_MONTH_NAME; |
3429 | 1.59k | case NF_KEY_MMMM: |
3430 | 1.59k | return CalendarDisplayCode::LONG_PARTITIVE_MONTH_NAME; |
3431 | 69 | case NF_KEY_MMMMM: |
3432 | 69 | return CalendarDisplayCode::NARROW_PARTITIVE_MONTH_NAME; |
3433 | 0 | default: |
3434 | 0 | ; // nothing |
3435 | 2.27k | } |
3436 | 0 | break; |
3437 | 6.41k | } |
3438 | 0 | SAL_WARN( "svl.numbers", "ImpUseMonthCase: unhandled keyword index eCodeType"); |
3439 | 0 | return CalendarDisplayCode::LONG_MONTH_NAME; |
3440 | 0 | } |
3441 | | |
3442 | | namespace { |
3443 | | |
3444 | | bool ImpIsOtherCalendar( const ImpSvNumFor& rNumFor, const CalendarWrapper& rCal ) |
3445 | 352k | { |
3446 | 352k | if ( rCal.getUniqueID() != GREGORIAN ) |
3447 | 0 | { |
3448 | 0 | return false; |
3449 | 0 | } |
3450 | 352k | const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); |
3451 | 352k | const sal_uInt16 nCnt = rNumFor.GetCount(); |
3452 | 352k | sal_uInt16 i; |
3453 | 2.07M | for ( i = 0; i < nCnt; i++ ) |
3454 | 1.75M | { |
3455 | 1.75M | switch ( rInfo.nTypeArray[i] ) |
3456 | 1.75M | { |
3457 | 3.86k | case NF_SYMBOLTYPE_CALENDAR : |
3458 | 3.86k | return false; |
3459 | 905 | case NF_KEY_EC : |
3460 | 6.98k | case NF_KEY_EEC : |
3461 | 10.1k | case NF_KEY_R : |
3462 | 10.1k | case NF_KEY_RR : |
3463 | 10.1k | case NF_KEY_AAA : |
3464 | 25.9k | case NF_KEY_AAAA : |
3465 | 27.2k | case NF_KEY_G : |
3466 | 27.2k | case NF_KEY_GG : |
3467 | 27.5k | case NF_KEY_GGG : |
3468 | 27.5k | return true; |
3469 | 1.75M | } |
3470 | 1.75M | } |
3471 | 321k | return false; |
3472 | 352k | } |
3473 | | |
3474 | | } |
3475 | | |
3476 | | void SvNumberformat::SwitchToOtherCalendar( OUString& rOrgCalendar, |
3477 | | double& fOrgDateTime, |
3478 | | CalendarWrapper& rCal ) const |
3479 | 49.9k | { |
3480 | 49.9k | if ( rCal.getUniqueID() != GREGORIAN ) |
3481 | 0 | return; |
3482 | | |
3483 | 49.9k | using namespace ::com::sun::star::i18n; |
3484 | 49.9k | const css::uno::Sequence< OUString > xCals = rCal.getAllCalendars( |
3485 | 49.9k | rLoc().getLanguageTag().getLocale() ); |
3486 | 49.9k | sal_Int32 nCnt = xCals.getLength(); |
3487 | 49.9k | if ( nCnt <= 1 ) |
3488 | 0 | return; |
3489 | | |
3490 | 49.9k | auto pCal = std::find_if(xCals.begin(), xCals.end(), |
3491 | 99.9k | [](const OUString& rCalName) { return rCalName != GREGORIAN; }); |
3492 | 49.9k | if (pCal == xCals.end()) |
3493 | 0 | return; |
3494 | | |
3495 | 49.9k | if ( !rOrgCalendar.getLength() ) |
3496 | 27.5k | { |
3497 | 27.5k | rOrgCalendar = rCal.getUniqueID(); |
3498 | 27.5k | fOrgDateTime = rCal.getDateTime(); |
3499 | 27.5k | } |
3500 | 49.9k | rCal.loadCalendar( *pCal, rLoc().getLanguageTag().getLocale() ); |
3501 | 49.9k | rCal.setDateTime( fOrgDateTime ); |
3502 | 49.9k | } |
3503 | | |
3504 | | void SvNumberformat::SwitchToGregorianCalendar( std::u16string_view rOrgCalendar, |
3505 | | double fOrgDateTime, |
3506 | | CalendarWrapper& rCal ) const |
3507 | 22.4k | { |
3508 | 22.4k | if ( rOrgCalendar.size() && rCal.getUniqueID() != GREGORIAN ) |
3509 | 22.4k | { |
3510 | 22.4k | rCal.loadCalendar( GREGORIAN, rLoc().getLanguageTag().getLocale() ); |
3511 | 22.4k | rCal.setDateTime( fOrgDateTime ); |
3512 | 22.4k | } |
3513 | 22.4k | } |
3514 | | |
3515 | | bool SvNumberformat::ImpFallBackToGregorianCalendar( OUString& rOrgCalendar, |
3516 | | double& fOrgDateTime, |
3517 | | CalendarWrapper& rCal ) const |
3518 | 356k | { |
3519 | 356k | using namespace ::com::sun::star::i18n; |
3520 | 356k | if ( rCal.getUniqueID() != GREGORIAN ) |
3521 | 29.5k | { |
3522 | 29.5k | sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); |
3523 | 29.5k | if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID == "Dummy" ) |
3524 | 0 | { |
3525 | 0 | if ( !rOrgCalendar.getLength() ) |
3526 | 0 | { |
3527 | 0 | rOrgCalendar = rCal.getUniqueID(); |
3528 | 0 | fOrgDateTime = rCal.getDateTime(); |
3529 | 0 | } |
3530 | 0 | else if ( rOrgCalendar == GREGORIAN ) |
3531 | 0 | { |
3532 | 0 | rOrgCalendar.clear(); |
3533 | 0 | } |
3534 | 0 | rCal.loadCalendar( GREGORIAN, rLoc().getLanguageTag().getLocale() ); |
3535 | 0 | rCal.setDateTime( fOrgDateTime ); |
3536 | 0 | return true; |
3537 | 0 | } |
3538 | 29.5k | } |
3539 | 356k | return false; |
3540 | 356k | } |
3541 | | |
3542 | | |
3543 | | #ifdef THE_FUTURE |
3544 | | /* XXX NOTE: even if the ImpSwitchToSpecifiedCalendar method is currently |
3545 | | * unused please don't remove it, it would be needed by |
3546 | | * SwitchToSpecifiedCalendar(), see comment in |
3547 | | * ImpSvNumberInputScan::GetDateRef() */ |
3548 | | |
3549 | | bool SvNumberformat::ImpSwitchToSpecifiedCalendar( OUString& rOrgCalendar, |
3550 | | double& fOrgDateTime, |
3551 | | const ImpSvNumFor& rNumFor ) const |
3552 | | { |
3553 | | const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); |
3554 | | const sal_uInt16 nCnt = rNumFor.GetCount(); |
3555 | | for ( sal_uInt16 i = 0; i < nCnt; i++ ) |
3556 | | { |
3557 | | if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR ) |
3558 | | { |
3559 | | CalendarWrapper& rCal = GetCal(); |
3560 | | if ( !rOrgCalendar.getLength() ) |
3561 | | { |
3562 | | rOrgCalendar = rCal.getUniqueID(); |
3563 | | fOrgDateTime = rCal.getDateTime(); |
3564 | | } |
3565 | | rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); |
3566 | | rCal.setDateTime( fOrgDateTime ); |
3567 | | return true; |
3568 | | } |
3569 | | } |
3570 | | return false; |
3571 | | } |
3572 | | #endif |
3573 | | |
3574 | | // static |
3575 | | void SvNumberformat::ImpAppendEraG( OUStringBuffer& OutString, |
3576 | | const CalendarWrapper& rCal, |
3577 | | sal_Int16 nNatNum ) |
3578 | 3.58k | { |
3579 | 3.58k | using namespace ::com::sun::star::i18n; |
3580 | 3.58k | if ( rCal.getUniqueID() == "gengou" ) |
3581 | 0 | { |
3582 | 0 | sal_Unicode cEra; |
3583 | 0 | sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); |
3584 | 0 | switch ( nVal ) |
3585 | 0 | { |
3586 | 0 | case 1: |
3587 | 0 | cEra = 'M'; |
3588 | 0 | break; |
3589 | 0 | case 2: |
3590 | 0 | cEra = 'T'; |
3591 | 0 | break; |
3592 | 0 | case 3: |
3593 | 0 | cEra = 'S'; |
3594 | 0 | break; |
3595 | 0 | case 4: |
3596 | 0 | cEra = 'H'; |
3597 | 0 | break; |
3598 | 0 | case 5: |
3599 | 0 | cEra = 'R'; |
3600 | 0 | break; |
3601 | 0 | default: |
3602 | 0 | cEra = '?'; |
3603 | 0 | break; |
3604 | 0 | } |
3605 | 0 | OutString.append(cEra); |
3606 | 0 | } |
3607 | 3.58k | else |
3608 | 3.58k | { |
3609 | 3.58k | OutString.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum )); |
3610 | 3.58k | } |
3611 | 3.58k | } |
3612 | | |
3613 | | bool SvNumberformat::ImpIsIso8601( const ImpSvNumFor& rNumFor ) const |
3614 | 912 | { |
3615 | 912 | bool bIsIso = false; |
3616 | 912 | if (eType & SvNumFormatType::DATE) |
3617 | 912 | { |
3618 | 912 | enum State |
3619 | 912 | { |
3620 | 912 | eNone, |
3621 | 912 | eAtYear, |
3622 | 912 | eAtSep1, |
3623 | 912 | eAtMonth, |
3624 | 912 | eAtSep2, |
3625 | 912 | eNotIso |
3626 | 912 | }; |
3627 | 912 | State eState = eNone; |
3628 | 912 | auto & rTypeArray = rNumFor.Info().nTypeArray; |
3629 | 912 | sal_uInt16 nCnt = rNumFor.GetCount(); |
3630 | 1.84k | for (sal_uInt16 i=0; i < nCnt && !bIsIso && eState != eNotIso; ++i) |
3631 | 936 | { |
3632 | 936 | switch ( rTypeArray[i] ) |
3633 | 936 | { |
3634 | 17 | case NF_KEY_YY: // two digits not strictly ISO 8601 |
3635 | 27 | case NF_KEY_YYYY: |
3636 | 27 | if (eState != eNone) |
3637 | 0 | { |
3638 | 0 | eState = eNotIso; |
3639 | 0 | } |
3640 | 27 | else |
3641 | 27 | { |
3642 | 27 | eState = eAtYear; |
3643 | 27 | } |
3644 | 27 | break; |
3645 | 18 | case NF_KEY_M: // single digit not strictly ISO 8601 |
3646 | 141 | case NF_KEY_MM: |
3647 | 141 | if (eState != eAtSep1) |
3648 | 138 | { |
3649 | 138 | eState = eNotIso; |
3650 | 138 | } |
3651 | 3 | else |
3652 | 3 | { |
3653 | 3 | eState = eAtMonth; |
3654 | 3 | } |
3655 | 141 | break; |
3656 | 149 | case NF_KEY_D: // single digit not strictly ISO 8601 |
3657 | 378 | case NF_KEY_DD: |
3658 | 378 | if (eState != eAtSep2) |
3659 | 375 | { |
3660 | 375 | eState = eNotIso; |
3661 | 375 | } |
3662 | 3 | else |
3663 | 3 | { |
3664 | 3 | bIsIso = true; |
3665 | 3 | } |
3666 | 378 | break; |
3667 | 296 | case NF_SYMBOLTYPE_STRING: |
3668 | 299 | case NF_SYMBOLTYPE_DATESEP: |
3669 | 299 | if (rNumFor.Info().sStrArray[i] == "-") |
3670 | 11 | { |
3671 | 11 | if (eState == eAtYear) |
3672 | 5 | { |
3673 | 5 | eState = eAtSep1; |
3674 | 5 | } |
3675 | 6 | else if (eState == eAtMonth) |
3676 | 3 | { |
3677 | 3 | eState = eAtSep2; |
3678 | 3 | } |
3679 | 3 | else |
3680 | 3 | { |
3681 | 3 | eState = eNotIso; |
3682 | 3 | } |
3683 | 11 | } |
3684 | 288 | else |
3685 | 288 | { |
3686 | 288 | eState = eNotIso; |
3687 | 288 | } |
3688 | 299 | break; |
3689 | 91 | default: |
3690 | 91 | eState = eNotIso; |
3691 | 936 | } |
3692 | 936 | } |
3693 | 912 | } |
3694 | 0 | else |
3695 | 0 | { |
3696 | 0 | SAL_WARN( "svl.numbers", "SvNumberformat::ImpIsIso8601: no date" ); |
3697 | 0 | } |
3698 | 912 | return bIsIso; |
3699 | 912 | } |
3700 | | |
3701 | | static bool lcl_hasEra( const ImpSvNumFor& rNumFor ) |
3702 | 1 | { |
3703 | 1 | const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); |
3704 | 1 | const sal_uInt16 nCnt = rNumFor.GetCount(); |
3705 | 6 | for ( sal_uInt16 i = 0; i < nCnt; i++ ) |
3706 | 5 | { |
3707 | 5 | switch ( rInfo.nTypeArray[i] ) |
3708 | 5 | { |
3709 | 0 | case NF_KEY_RR : |
3710 | 0 | case NF_KEY_G : |
3711 | 0 | case NF_KEY_GG : |
3712 | 0 | case NF_KEY_GGG : |
3713 | 0 | return true; |
3714 | 5 | } |
3715 | 5 | } |
3716 | 1 | return false; |
3717 | 1 | } |
3718 | | |
3719 | | static bool lcl_isSignedYear( const CalendarWrapper& rCal, const ImpSvNumFor& rNumFor ) |
3720 | 341k | { |
3721 | 341k | return rCal.getValue( css::i18n::CalendarFieldIndex::ERA ) == 0 && |
3722 | 1 | rCal.getUniqueID() == GREGORIAN && !lcl_hasEra( rNumFor ); |
3723 | 341k | } |
3724 | | |
3725 | | /* XXX: if needed this could be stripped from rEpochStart and diff adding and |
3726 | | * moved to tools' DateTime to be reused elsewhere. */ |
3727 | | static bool lcl_getValidDate( const DateTime& rNullDate, const DateTime& rEpochStart, double& fNumber ) |
3728 | 352k | { |
3729 | 352k | static const DateTime aCE( Date(1,1,1)); |
3730 | 352k | static const DateTime aMin( Date(1,1, SAL_MIN_INT16)); |
3731 | 352k | static const DateTime aMax( Date(31,12, SAL_MAX_INT16), tools::Time(23,59,59, tools::Time::nanoSecPerSec - 1)); |
3732 | 352k | static const double fMin = DateTime::Sub( aMin, aCE); |
3733 | 352k | static const double fMax = DateTime::Sub( aMax, aCE); |
3734 | | // Value must be representable in our tools::Date proleptic Gregorian |
3735 | | // calendar as well. |
3736 | 352k | const double fOff = DateTime::Sub( rNullDate, aCE) + fNumber; |
3737 | | // Add diff between epochs to serial date number. |
3738 | 352k | const double fDiff = DateTime::Sub( rNullDate, rEpochStart); |
3739 | 352k | fNumber += fDiff; |
3740 | 352k | return fMin <= fOff && fOff <= fMax; |
3741 | 352k | } |
3742 | | |
3743 | | bool SvNumberformat::ImpGetDateOutput(double fNumber, |
3744 | | sal_uInt16 nIx, |
3745 | | bool bStarFlag, |
3746 | | const NativeNumberWrapper& rNatNum, |
3747 | | const SvNFLanguageData& rCurrentLang, |
3748 | | OUStringBuffer& sBuff) const |
3749 | 345k | { |
3750 | 345k | using namespace ::com::sun::star::i18n; |
3751 | 345k | bool bRes = false; |
3752 | | |
3753 | 345k | CalendarWrapper& rCal = *rCurrentLang.GetCalendar(); |
3754 | 345k | if (!lcl_getValidDate( DateTime( rScan.GetNullDate() ), rCal.getEpochStart(), fNumber)) |
3755 | 4 | { |
3756 | 4 | sBuff = ImpSvNumberformatScan::sErrStr; |
3757 | 4 | return false; |
3758 | 4 | } |
3759 | 345k | rCal.setLocalDateTime( fNumber ); |
3760 | 345k | int nUseMonthCase = 0; // Not decided yet |
3761 | 345k | OUString aOrgCalendar; // empty => not changed yet |
3762 | | |
3763 | 345k | double fOrgDateTime(0.0); |
3764 | 345k | bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx], *rCurrentLang.GetCalendar() ); |
3765 | 345k | if ( bOtherCalendar ) |
3766 | 22.9k | { |
3767 | 22.9k | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3768 | 22.9k | } |
3769 | 345k | if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ) ) |
3770 | 0 | { |
3771 | 0 | bOtherCalendar = false; |
3772 | 0 | } |
3773 | 345k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
3774 | 345k | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
3775 | 345k | sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); |
3776 | 345k | OUString aStr; |
3777 | | |
3778 | | // NatNum12: if the date format contains more than a date |
3779 | | // field, it needs to specify in NatNum12 argument |
3780 | | // which date element needs special formatting: |
3781 | | // |
3782 | | // '[NatNum12 ordinal-number]D' -> "1st" |
3783 | | // '[NatNum12 D=ordinal-number]D" of "MMMM' -> "1st of April" |
3784 | | // '[NatNum12 D=ordinal]D" of "MMMM' -> "first of April" |
3785 | | // '[NatNum12 YYYY=year,D=ordinal]D" of "MMMM", "YYYY' -> "first of April, nineteen ninety" |
3786 | | // |
3787 | | // Note: set only for YYYY, MMMM, M, DDDD, D and NNN/AAAA in date formats. |
3788 | | // Additionally for MMMMM, MMM, DDD and NN/AA to support at least |
3789 | | // capitalize, upper, lower, title. |
3790 | | // XXX It's possible to extend this for other keywords and date + time |
3791 | | // combinations, as required. |
3792 | | |
3793 | 345k | bool bUseSpellout = NatNumTakesParameters(nNatNum) && |
3794 | 0 | (nCnt == 1 || NumFor[nIx].GetNatNum().GetParams().indexOf('=') > -1); |
3795 | | |
3796 | 2.08M | for (sal_uInt16 i = 0; i < nCnt; i++) |
3797 | 1.73M | { |
3798 | 1.73M | switch (rInfo.nTypeArray[i]) |
3799 | 1.73M | { |
3800 | 3.88k | case NF_SYMBOLTYPE_CALENDAR : |
3801 | 3.88k | if ( !aOrgCalendar.getLength() ) |
3802 | 3.85k | { |
3803 | 3.85k | aOrgCalendar = rCal.getUniqueID(); |
3804 | 3.85k | fOrgDateTime = rCal.getDateTime(); |
3805 | 3.85k | } |
3806 | 3.88k | rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLanguageTag().getLocale() ); |
3807 | 3.88k | rCal.setDateTime( fOrgDateTime ); |
3808 | 3.88k | ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3809 | 3.88k | break; |
3810 | 97 | case NF_SYMBOLTYPE_STAR: |
3811 | 97 | if( bStarFlag ) |
3812 | 0 | { |
3813 | 0 | bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]); |
3814 | 0 | } |
3815 | 97 | break; |
3816 | 1.70k | case NF_SYMBOLTYPE_BLANK: |
3817 | 1.70k | if (rInfo.sStrArray[i].getLength() >= 2) |
3818 | 1.70k | InsertBlanks( sBuff, sBuff.getLength(), rInfo.sStrArray[i][1] ); |
3819 | 1.70k | break; |
3820 | 66.4k | case NF_SYMBOLTYPE_STRING: |
3821 | 66.4k | case NF_SYMBOLTYPE_CURRENCY: |
3822 | 698k | case NF_SYMBOLTYPE_DATESEP: |
3823 | 698k | case NF_SYMBOLTYPE_TIMESEP: |
3824 | 698k | case NF_SYMBOLTYPE_TIME100SECSEP: |
3825 | 698k | sBuff.append(rInfo.sStrArray[i]); |
3826 | 698k | break; |
3827 | 299k | case NF_KEY_M: // M |
3828 | 299k | aStr = rCal.getDisplayString( CalendarDisplayCode::SHORT_MONTH, nNatNum ); |
3829 | | // NatNum12: support variants of preposition, suffixation or article |
3830 | | // for example, Catalan "de març", but "d'abril" etc. |
3831 | 299k | if ( bUseSpellout ) |
3832 | 0 | { |
3833 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3834 | 0 | } |
3835 | 299k | sBuff.append(aStr); |
3836 | 299k | break; |
3837 | 39.5k | case NF_KEY_MM: // MM |
3838 | 39.5k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_MONTH, nNatNum )); |
3839 | 39.5k | break; |
3840 | 1.40k | case NF_KEY_MMM: // MMM |
3841 | 3.04k | case NF_KEY_MMMM: // MMMM |
3842 | 4.33k | case NF_KEY_MMMMM: // MMMMM |
3843 | | // NatNum12: support variants of preposition, suffixation or |
3844 | | // article, or capitalize, upper, lower, title. |
3845 | | // Note: result of the "spell out" conversion can depend from the optional |
3846 | | // PartitiveMonths or GenitiveMonths defined in the locale data, |
3847 | | // see description of ImpUseMonthCase(), and locale data in |
3848 | | // i18npool/source/localedata/data/ and libnumbertext |
3849 | 4.33k | aStr = rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx], |
3850 | 4.33k | static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])), |
3851 | 4.33k | nNatNum); |
3852 | 4.33k | if ( bUseSpellout ) |
3853 | 0 | { |
3854 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3855 | 0 | } |
3856 | 4.33k | sBuff.append(aStr); |
3857 | 4.33k | break; |
3858 | 1.91k | case NF_KEY_Q: // Q |
3859 | 1.91k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_QUARTER, nNatNum )); |
3860 | 1.91k | break; |
3861 | 515 | case NF_KEY_QQ: // QQ |
3862 | 515 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_QUARTER, nNatNum )); |
3863 | 515 | break; |
3864 | 297k | case NF_KEY_D: // D |
3865 | 297k | aStr = rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum ); |
3866 | | // NatNum12: support variants of preposition, suffixation or article |
3867 | 297k | if ( bUseSpellout ) |
3868 | 0 | { |
3869 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3870 | 0 | } |
3871 | 297k | sBuff.append(aStr); |
3872 | 297k | break; |
3873 | 23.3k | case NF_KEY_DD: // DD |
3874 | 23.3k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY, nNatNum )); |
3875 | 23.3k | break; |
3876 | 355 | case NF_KEY_DDD: // DDD |
3877 | 355 | if ( bOtherCalendar ) |
3878 | 243 | { |
3879 | 243 | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3880 | 243 | } |
3881 | 355 | aStr = rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); |
3882 | | // NatNum12: support at least capitalize, upper, lower, title |
3883 | 355 | if ( bUseSpellout ) |
3884 | 0 | { |
3885 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3886 | 0 | } |
3887 | 355 | sBuff.append(aStr); |
3888 | 355 | if ( bOtherCalendar ) |
3889 | 243 | { |
3890 | 243 | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3891 | 243 | } |
3892 | 355 | break; |
3893 | 1.10k | case NF_KEY_DDDD: // DDDD |
3894 | 1.10k | if ( bOtherCalendar ) |
3895 | 373 | { |
3896 | 373 | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3897 | 373 | } |
3898 | 1.10k | aStr = rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); |
3899 | | // NatNum12: support variants of preposition, suffixation or article |
3900 | 1.10k | if ( bUseSpellout ) |
3901 | 0 | { |
3902 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3903 | 0 | } |
3904 | 1.10k | sBuff.append(aStr); |
3905 | 1.10k | if ( bOtherCalendar ) |
3906 | 373 | { |
3907 | 373 | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3908 | 373 | } |
3909 | 1.10k | break; |
3910 | 313k | case NF_KEY_YY: // YY |
3911 | 313k | if ( bOtherCalendar ) |
3912 | 424 | { |
3913 | 424 | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3914 | 424 | } |
3915 | | // Prepend a minus sign if Gregorian BCE and era is not displayed. |
3916 | 313k | if (lcl_isSignedYear( rCal, NumFor[nIx] )) |
3917 | 1 | { |
3918 | 1 | sBuff.append('-'); |
3919 | 1 | } |
3920 | 313k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum )); |
3921 | 313k | if ( bOtherCalendar ) |
3922 | 424 | { |
3923 | 424 | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3924 | 424 | } |
3925 | 313k | break; |
3926 | 9.23k | case NF_KEY_YYYY: // YYYY |
3927 | 9.23k | if ( bOtherCalendar ) |
3928 | 2.29k | { |
3929 | 2.29k | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3930 | 2.29k | } |
3931 | | // Prepend a minus sign if Gregorian BCE and era is not displayed. |
3932 | 9.23k | if (lcl_isSignedYear( rCal, NumFor[nIx] )) |
3933 | 0 | { |
3934 | 0 | sBuff.append('-'); |
3935 | 0 | } |
3936 | 9.23k | aStr = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum ); |
3937 | 9.23k | if (aStr.getLength() < 4 && !lcl_hasEra(NumFor[nIx])) |
3938 | 0 | { |
3939 | 0 | using namespace comphelper::string; |
3940 | | // Ensure that year consists of at least 4 digits, so it |
3941 | | // can be distinguished from 2 digits display and edited |
3942 | | // without suddenly being hit by the 2-digit year magic. |
3943 | 0 | OUStringBuffer aBuf; |
3944 | 0 | padToLength(aBuf, 4 - aStr.getLength(), '0'); |
3945 | 0 | ::impTransliterate(aBuf, NumFor[nIx].GetNatNum(), rNatNum); |
3946 | 0 | aBuf.append(aStr); |
3947 | 0 | aStr = aBuf.makeStringAndClear(); |
3948 | 0 | } |
3949 | | // NatNum12: support variants of preposition, suffixation or article |
3950 | 9.23k | if ( bUseSpellout ) |
3951 | 0 | { |
3952 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3953 | 0 | } |
3954 | 9.23k | sBuff.append(aStr); |
3955 | 9.23k | if ( bOtherCalendar ) |
3956 | 2.29k | { |
3957 | 2.29k | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
3958 | 2.29k | } |
3959 | 9.23k | break; |
3960 | 1.24k | case NF_KEY_EC: // E |
3961 | 1.24k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum )); |
3962 | 1.24k | break; |
3963 | 7.93k | case NF_KEY_EEC: // EE |
3964 | 10.3k | case NF_KEY_R: // R |
3965 | 10.3k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum )); |
3966 | 10.3k | break; |
3967 | 1.60k | case NF_KEY_NN: // NN |
3968 | 1.62k | case NF_KEY_AAA: // AAA |
3969 | 1.62k | aStr = rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); |
3970 | | // NatNum12: support at least capitalize, upper, lower, title |
3971 | 1.62k | if ( bUseSpellout ) |
3972 | 0 | { |
3973 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3974 | 0 | } |
3975 | 1.62k | sBuff.append(aStr); |
3976 | 1.62k | break; |
3977 | 136 | case NF_KEY_NNN: // NNN |
3978 | 18.3k | case NF_KEY_AAAA: // AAAA |
3979 | 18.3k | aStr = rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); |
3980 | | // NatNum12: support variants of preposition, suffixation or article |
3981 | 18.3k | if ( bUseSpellout ) |
3982 | 0 | { |
3983 | 0 | aStr = impTransliterate(aStr, NumFor[nIx].GetNatNum(), rInfo.nTypeArray[i], rNatNum); |
3984 | 0 | } |
3985 | 18.3k | sBuff.append(aStr); |
3986 | 18.3k | break; |
3987 | 98 | case NF_KEY_NNNN: // NNNN |
3988 | 98 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum )); |
3989 | 98 | sBuff.append(rLoc().getLongDateDayOfWeekSep()); |
3990 | 98 | break; |
3991 | 133 | case NF_KEY_WW : // WW |
3992 | 133 | sBuff.append(ImpIntToString(rNatNum, nIx, |
3993 | 133 | rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ))); |
3994 | 133 | break; |
3995 | 256 | case NF_KEY_G: // G |
3996 | 256 | ImpAppendEraG(sBuff, rCal, nNatNum ); |
3997 | 256 | break; |
3998 | 269 | case NF_KEY_GG: // GG |
3999 | 269 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum )); |
4000 | 269 | break; |
4001 | 1.33k | case NF_KEY_GGG: // GGG |
4002 | 1.33k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_ERA, nNatNum )); |
4003 | 1.33k | break; |
4004 | 1.04k | case NF_KEY_RR: // RR => GGGEE |
4005 | 1.04k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum )); |
4006 | 1.04k | break; |
4007 | 1.73M | } |
4008 | 1.73M | } |
4009 | 345k | if ( aOrgCalendar.getLength() ) |
4010 | 26.8k | { |
4011 | 26.8k | rCal.loadCalendar( aOrgCalendar, rLoc().getLanguageTag().getLocale() ); // restore calendar |
4012 | 26.8k | } |
4013 | 345k | return bRes; |
4014 | 345k | } |
4015 | | |
4016 | | bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, |
4017 | | sal_uInt16 nIx, |
4018 | | bool bStarFlag, |
4019 | | const NativeNumberWrapper& rNatNum, |
4020 | | const SvNFLanguageData& rCurrentLang, |
4021 | | OUStringBuffer& sBuff) const |
4022 | 6.71k | { |
4023 | 6.71k | using namespace ::com::sun::star::i18n; |
4024 | 6.71k | bool bRes = false; |
4025 | | |
4026 | 6.71k | CalendarWrapper& rCal = *rCurrentLang.GetCalendar(); |
4027 | 6.71k | if (!lcl_getValidDate( DateTime( rScan.GetNullDate() ), rCal.getEpochStart(), fNumber)) |
4028 | 7 | { |
4029 | 7 | sBuff = ImpSvNumberformatScan::sErrStr; |
4030 | 7 | return false; |
4031 | 7 | } |
4032 | | |
4033 | 6.70k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
4034 | 6.70k | bool bInputLine; |
4035 | 6.70k | sal_Int32 nCntPost, nFirstRounding; |
4036 | 6.70k | if ( rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION && |
4037 | 0 | 0 < rInfo.nCntPost && rInfo.nCntPost < kTimeSignificantRound ) |
4038 | 0 | { |
4039 | 0 | bInputLine = true; |
4040 | 0 | nCntPost = nFirstRounding = kTimeSignificantRound; |
4041 | 0 | } |
4042 | 6.70k | else |
4043 | 6.70k | { |
4044 | 6.70k | bInputLine = false; |
4045 | 6.70k | nCntPost = rInfo.nCntPost; |
4046 | | // For clock format (not []) do not round up to seconds and thus days. |
4047 | 6.70k | nFirstRounding = (rInfo.bThousand ? nCntPost : kTimeSignificantRound); |
4048 | 6.70k | } |
4049 | 6.70k | double fTime = (fNumber - floor( fNumber )) * 86400.0; |
4050 | 6.70k | fTime = ::rtl::math::round( fTime, int(nFirstRounding) ); |
4051 | 6.70k | if (fTime >= 86400.0) |
4052 | 0 | { |
4053 | | // result of fNumber==x.999999999... rounded up, use correct date/time |
4054 | 0 | fTime -= 86400.0; |
4055 | 0 | fNumber = floor( fNumber + 0.5) + fTime; |
4056 | 0 | } |
4057 | 6.70k | rCal.setLocalDateTime( fNumber ); |
4058 | | |
4059 | 6.70k | int nUseMonthCase = 0; // Not decided yet |
4060 | 6.70k | OUString aOrgCalendar; // empty => not changed yet |
4061 | 6.70k | double fOrgDateTime(0.0); |
4062 | 6.70k | bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx], *rCurrentLang.GetCalendar() ); |
4063 | 6.70k | if ( bOtherCalendar ) |
4064 | 4.60k | { |
4065 | 4.60k | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4066 | 4.60k | } |
4067 | 6.70k | if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ) ) |
4068 | 0 | { |
4069 | 0 | bOtherCalendar = false; |
4070 | 0 | } |
4071 | 6.70k | sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); |
4072 | | |
4073 | 6.70k | OUStringBuffer sSecStr; |
4074 | 6.70k | sal_Int32 nSecPos = 0; // For figure by figure processing |
4075 | 6.70k | sal_uInt32 nHour, nMin, nSec; |
4076 | 6.70k | if (!rInfo.bThousand) // No [] format |
4077 | 6.70k | { |
4078 | 6.70k | sal_uInt16 nCHour, nCMinute, nCSecond; |
4079 | 6.70k | double fFractionOfSecond; |
4080 | 6.70k | tools::Time::GetClock( fNumber, nCHour, nCMinute, nCSecond, fFractionOfSecond, nCntPost); |
4081 | 6.70k | nHour = nCHour; |
4082 | 6.70k | nMin = nCMinute; |
4083 | 6.70k | nSec = nCSecond; |
4084 | 6.70k | nCntPost = ImpGetFractionOfSecondString( sSecStr, fFractionOfSecond, nCntPost, true, nIx, |
4085 | 6.70k | (bInputLine ? rInfo.nCntPost : 0), rNatNum ); |
4086 | 6.70k | } |
4087 | 0 | else |
4088 | 0 | { |
4089 | 0 | sal_uInt32 nSeconds = static_cast<sal_uInt32>(floor( fTime )); |
4090 | |
|
4091 | 0 | nCntPost = ImpGetFractionOfSecondString( sSecStr, fTime - nSeconds, nCntPost, false, nIx, |
4092 | 0 | (bInputLine ? rInfo.nCntPost : 0), rNatNum ); |
4093 | |
|
4094 | 0 | if (rInfo.nThousand == 3) // [ss] |
4095 | 0 | { |
4096 | 0 | nHour = 0; |
4097 | 0 | nMin = 0; |
4098 | 0 | nSec = nSeconds; |
4099 | 0 | } |
4100 | 0 | else if (rInfo.nThousand == 2) // [mm]:ss |
4101 | 0 | { |
4102 | 0 | nHour = 0; |
4103 | 0 | nMin = nSeconds / 60; |
4104 | 0 | nSec = nSeconds % 60; |
4105 | 0 | } |
4106 | 0 | else if (rInfo.nThousand == 1) // [hh]:mm:ss |
4107 | 0 | { |
4108 | 0 | nHour = nSeconds / 3600; |
4109 | 0 | nMin = (nSeconds%3600) / 60; |
4110 | 0 | nSec = nSeconds%60; |
4111 | 0 | } |
4112 | 0 | else |
4113 | 0 | { |
4114 | 0 | nHour = 0; // TODO What should these values be? |
4115 | 0 | nMin = 0; |
4116 | 0 | nSec = 0; |
4117 | 0 | } |
4118 | 0 | } |
4119 | 6.70k | sal_Unicode cAmPm = ' '; // a or p |
4120 | 6.70k | if (rInfo.nCntExp) // AM/PM |
4121 | 917 | { |
4122 | 917 | if (nHour == 0) |
4123 | 4 | { |
4124 | 4 | nHour = 12; |
4125 | 4 | cAmPm = 'a'; |
4126 | 4 | } |
4127 | 913 | else if (nHour < 12) |
4128 | 236 | { |
4129 | 236 | cAmPm = 'a'; |
4130 | 236 | } |
4131 | 677 | else |
4132 | 677 | { |
4133 | 677 | cAmPm = 'p'; |
4134 | 677 | if (nHour > 12) |
4135 | 677 | { |
4136 | 677 | nHour -= 12; |
4137 | 677 | } |
4138 | 677 | } |
4139 | 917 | } |
4140 | 6.70k | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
4141 | 6.70k | sal_Int32 nLen; |
4142 | 6.70k | OUString aYear; |
4143 | 136k | for (sal_uInt16 i = 0; i < nCnt; i++) |
4144 | 129k | { |
4145 | 129k | switch (rInfo.nTypeArray[i]) |
4146 | 129k | { |
4147 | 7 | case NF_SYMBOLTYPE_CALENDAR : |
4148 | 7 | if ( !aOrgCalendar.getLength() ) |
4149 | 7 | { |
4150 | 7 | aOrgCalendar = rCal.getUniqueID(); |
4151 | 7 | fOrgDateTime = rCal.getDateTime(); |
4152 | 7 | } |
4153 | 7 | rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLanguageTag().getLocale() ); |
4154 | 7 | rCal.setDateTime( fOrgDateTime ); |
4155 | 7 | ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4156 | 7 | break; |
4157 | 3.12k | case NF_SYMBOLTYPE_STAR: |
4158 | 3.12k | if( bStarFlag ) |
4159 | 0 | { |
4160 | 0 | bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]); |
4161 | 0 | } |
4162 | 3.12k | break; |
4163 | 9.95k | case NF_SYMBOLTYPE_BLANK: |
4164 | 9.95k | if (rInfo.sStrArray[i].getLength() >= 2) |
4165 | 9.95k | InsertBlanks( sBuff, sBuff.getLength(), rInfo.sStrArray[i][1] ); |
4166 | 9.95k | break; |
4167 | 40.6k | case NF_SYMBOLTYPE_STRING: |
4168 | 40.6k | case NF_SYMBOLTYPE_CURRENCY: |
4169 | 44.0k | case NF_SYMBOLTYPE_DATESEP: |
4170 | 46.1k | case NF_SYMBOLTYPE_TIMESEP: |
4171 | 46.1k | case NF_SYMBOLTYPE_TIME100SECSEP: |
4172 | 46.1k | sBuff.append(rInfo.sStrArray[i]); |
4173 | 46.1k | break; |
4174 | 230 | case NF_SYMBOLTYPE_DIGIT: |
4175 | 230 | nLen = ( bInputLine && i > 0 && |
4176 | 0 | (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || |
4177 | 0 | rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? |
4178 | 230 | nCntPost : rInfo.sStrArray[i].getLength() ); |
4179 | 484 | for (sal_Int32 j = 0; j < nLen && nSecPos < nCntPost && nSecPos < sSecStr.getLength(); ++j) |
4180 | 254 | { |
4181 | 254 | sBuff.append(sSecStr[ nSecPos ]); |
4182 | 254 | nSecPos++; |
4183 | 254 | } |
4184 | 230 | break; |
4185 | 917 | case NF_KEY_AMPM: // AM/PM |
4186 | 917 | if (cAmPm == 'a') |
4187 | 240 | { |
4188 | 240 | sBuff.append(rCal.getDisplayName( CalendarDisplayIndex::AM_PM, |
4189 | 240 | AmPmValue::AM, 0 )); |
4190 | 240 | } |
4191 | 677 | else |
4192 | 677 | { |
4193 | 677 | sBuff.append(rCal.getDisplayName( CalendarDisplayIndex::AM_PM, |
4194 | 677 | AmPmValue::PM, 0 )); |
4195 | 677 | } |
4196 | 917 | break; |
4197 | 0 | case NF_KEY_AP: // A/P |
4198 | 0 | if (cAmPm == 'a') |
4199 | 0 | { |
4200 | 0 | sBuff.append('a'); |
4201 | 0 | } |
4202 | 0 | else |
4203 | 0 | { |
4204 | 0 | sBuff.append('p'); |
4205 | 0 | } |
4206 | 0 | break; |
4207 | 1.77k | case NF_KEY_MI: // M |
4208 | 1.77k | sBuff.append(ImpIntToString(rNatNum, nIx, nMin )); |
4209 | 1.77k | break; |
4210 | 999 | case NF_KEY_MMI: // MM |
4211 | 999 | sBuff.append(ImpIntToString(rNatNum, nIx, nMin, 2 )); |
4212 | 999 | break; |
4213 | 1.24k | case NF_KEY_H: // H |
4214 | 1.24k | sBuff.append(ImpIntToString(rNatNum, nIx, nHour )); |
4215 | 1.24k | break; |
4216 | 1.09k | case NF_KEY_HH: // HH |
4217 | 1.09k | sBuff.append(ImpIntToString(rNatNum, nIx, nHour, 2 )); |
4218 | 1.09k | break; |
4219 | 6.50k | case NF_KEY_S: // S |
4220 | 6.50k | sBuff.append(ImpIntToString(rNatNum, nIx, nSec )); |
4221 | 6.50k | break; |
4222 | 1.12k | case NF_KEY_SS: // SS |
4223 | 1.12k | sBuff.append(ImpIntToString(rNatNum, nIx, nSec, 2 )); |
4224 | 1.12k | break; |
4225 | 5.33k | case NF_KEY_M: // M |
4226 | 5.33k | sBuff.append(rCal.getDisplayString( |
4227 | 5.33k | CalendarDisplayCode::SHORT_MONTH, nNatNum )); |
4228 | 5.33k | break; |
4229 | 256 | case NF_KEY_MM: // MM |
4230 | 256 | sBuff.append(rCal.getDisplayString( |
4231 | 256 | CalendarDisplayCode::LONG_MONTH, nNatNum )); |
4232 | 256 | break; |
4233 | 178 | case NF_KEY_MMM: // MMM |
4234 | 178 | sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx], |
4235 | 178 | static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])), |
4236 | 178 | nNatNum)); |
4237 | 178 | break; |
4238 | 25 | case NF_KEY_MMMM: // MMMM |
4239 | 25 | sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx], |
4240 | 25 | static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])), |
4241 | 25 | nNatNum)); |
4242 | 25 | break; |
4243 | 1.88k | case NF_KEY_MMMMM: // MMMMM |
4244 | 1.88k | sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx], |
4245 | 1.88k | static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])), |
4246 | 1.88k | nNatNum)); |
4247 | 1.88k | break; |
4248 | 1.42k | case NF_KEY_Q: // Q |
4249 | 1.42k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_QUARTER, nNatNum )); |
4250 | 1.42k | break; |
4251 | 182 | case NF_KEY_QQ: // QQ |
4252 | 182 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_QUARTER, nNatNum )); |
4253 | 182 | break; |
4254 | 4.35k | case NF_KEY_D: // D |
4255 | 4.35k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum )); |
4256 | 4.35k | break; |
4257 | 352 | case NF_KEY_DD: // DD |
4258 | 352 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY, nNatNum )); |
4259 | 352 | break; |
4260 | 285 | case NF_KEY_DDD: // DDD |
4261 | 285 | if ( bOtherCalendar ) |
4262 | 223 | { |
4263 | 223 | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4264 | 223 | } |
4265 | 285 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum )); |
4266 | 285 | if ( bOtherCalendar ) |
4267 | 223 | { |
4268 | 223 | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4269 | 223 | } |
4270 | 285 | break; |
4271 | 3.36k | case NF_KEY_DDDD: // DDDD |
4272 | 3.36k | if ( bOtherCalendar ) |
4273 | 2.80k | { |
4274 | 2.80k | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4275 | 2.80k | } |
4276 | 3.36k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum )); |
4277 | 3.36k | if ( bOtherCalendar ) |
4278 | 2.80k | { |
4279 | 2.80k | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4280 | 2.80k | } |
4281 | 3.36k | break; |
4282 | 2.10k | case NF_KEY_YY: // YY |
4283 | 2.10k | if ( bOtherCalendar ) |
4284 | 1.90k | { |
4285 | 1.90k | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4286 | 1.90k | } |
4287 | | // Prepend a minus sign if Gregorian BCE and era is not displayed. |
4288 | 2.10k | if (lcl_isSignedYear( rCal, NumFor[nIx] )) |
4289 | 0 | { |
4290 | 0 | sBuff.append('-'); |
4291 | 0 | } |
4292 | 2.10k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum )); |
4293 | 2.10k | if ( bOtherCalendar ) |
4294 | 1.90k | { |
4295 | 1.90k | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4296 | 1.90k | } |
4297 | 2.10k | break; |
4298 | 17.4k | case NF_KEY_YYYY: // YYYY |
4299 | 17.4k | if ( bOtherCalendar ) |
4300 | 14.1k | { |
4301 | 14.1k | SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4302 | 14.1k | } |
4303 | | // Prepend a minus sign if Gregorian BCE and era is not displayed. |
4304 | 17.4k | if (lcl_isSignedYear( rCal, NumFor[nIx] )) |
4305 | 0 | { |
4306 | 0 | sBuff.append('-'); |
4307 | 0 | } |
4308 | 17.4k | aYear = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum ); |
4309 | 17.4k | if (aYear.getLength() < 4 && !lcl_hasEra(NumFor[nIx])) |
4310 | 0 | { |
4311 | 0 | using namespace comphelper::string; |
4312 | | // Ensure that year consists of at least 4 digits, so it |
4313 | | // can be distinguished from 2 digits display and edited |
4314 | | // without suddenly being hit by the 2-digit year magic. |
4315 | 0 | OUStringBuffer aBuf; |
4316 | 0 | padToLength(aBuf, 4 - aYear.getLength(), '0'); |
4317 | 0 | ::impTransliterate(aBuf, NumFor[nIx].GetNatNum(), rNatNum); |
4318 | 0 | aBuf.append(aYear); |
4319 | 0 | sBuff.append(aBuf); |
4320 | 0 | } |
4321 | 17.4k | else |
4322 | 17.4k | { |
4323 | 17.4k | sBuff.append(aYear); |
4324 | 17.4k | } |
4325 | 17.4k | if ( bOtherCalendar ) |
4326 | 14.1k | { |
4327 | 14.1k | SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime, *rCurrentLang.GetCalendar() ); |
4328 | 14.1k | } |
4329 | 17.4k | break; |
4330 | 2.35k | case NF_KEY_EC: // E |
4331 | 2.35k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum )); |
4332 | 2.35k | break; |
4333 | 1.07k | case NF_KEY_EEC: // EE |
4334 | 7.73k | case NF_KEY_R: // R |
4335 | 7.73k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum )); |
4336 | 7.73k | break; |
4337 | 14 | case NF_KEY_NN: // NN |
4338 | 129 | case NF_KEY_AAA: // AAA |
4339 | 129 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum )); |
4340 | 129 | break; |
4341 | 57 | case NF_KEY_NNN: // NNN |
4342 | 433 | case NF_KEY_AAAA: // AAAA |
4343 | 433 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum )); |
4344 | 433 | break; |
4345 | 57 | case NF_KEY_NNNN: // NNNN |
4346 | 57 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum )); |
4347 | 57 | sBuff.append(rLoc().getLongDateDayOfWeekSep()); |
4348 | 57 | break; |
4349 | 362 | case NF_KEY_WW : // WW |
4350 | 362 | sBuff.append(ImpIntToString(rNatNum, nIx, rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ))); |
4351 | 362 | break; |
4352 | 3.32k | case NF_KEY_G: // G |
4353 | 3.32k | ImpAppendEraG( sBuff, rCal, nNatNum ); |
4354 | 3.32k | break; |
4355 | 253 | case NF_KEY_GG: // GG |
4356 | 253 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum )); |
4357 | 253 | break; |
4358 | 872 | case NF_KEY_GGG: // GGG |
4359 | 872 | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_ERA, nNatNum )); |
4360 | 872 | break; |
4361 | 3.54k | case NF_KEY_RR: // RR => GGGEE |
4362 | 3.54k | sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum )); |
4363 | 3.54k | break; |
4364 | 129k | } |
4365 | 129k | } |
4366 | 6.70k | if ( aOrgCalendar.getLength() ) |
4367 | 4.61k | { |
4368 | 4.61k | rCal.loadCalendar( aOrgCalendar, rLoc().getLanguageTag().getLocale() ); // restore calendar |
4369 | 4.61k | } |
4370 | 6.70k | return bRes; |
4371 | 6.70k | } |
4372 | | |
4373 | | bool SvNumberformat::ImpGetLogicalOutput(double fNumber, |
4374 | | sal_uInt16 nIx, |
4375 | | const NativeNumberWrapper& rNatNum, |
4376 | | OUStringBuffer& sStr) const |
4377 | 31 | { |
4378 | 31 | bool bRes = false; |
4379 | 31 | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
4380 | 31 | const sal_uInt16 nCnt = NumFor[nIx].GetCount(); |
4381 | 2.35k | for (sal_uInt16 j = 0; j < nCnt; ++j) |
4382 | 2.32k | { |
4383 | 2.32k | switch (rInfo.nTypeArray[j]) |
4384 | 2.32k | { |
4385 | 31 | case NF_KEY_BOOLEAN: |
4386 | 31 | sStr.append( fNumber ? rScan.GetTrueString() : rScan.GetFalseString()); |
4387 | 31 | break; |
4388 | 894 | case NF_SYMBOLTYPE_STRING: |
4389 | 894 | sStr.append( rInfo.sStrArray[j]); |
4390 | 894 | break; |
4391 | 2.32k | } |
4392 | 2.32k | } |
4393 | 31 | ::impTransliterate(sStr, NumFor[nIx].GetNatNum(), rNatNum); |
4394 | 31 | return bRes; |
4395 | 31 | } |
4396 | | |
4397 | | bool SvNumberformat::ImpGetNumberOutput(double fNumber, |
4398 | | sal_uInt16 nIx, |
4399 | | bool bStarFlag, |
4400 | | const NativeNumberWrapper& rNatNum, |
4401 | | OUStringBuffer& sStr) const |
4402 | 74.7k | { |
4403 | 74.7k | bool bRes = false; |
4404 | 74.7k | bool bSign; |
4405 | 74.7k | if (fNumber < 0.0) |
4406 | 558 | { |
4407 | 558 | bSign = (nIx == 0); // Not in the ones at the back; |
4408 | 558 | fNumber = -fNumber; |
4409 | 558 | } |
4410 | 74.1k | else |
4411 | 74.1k | { |
4412 | 74.1k | bSign = false; |
4413 | 74.1k | if ( std::signbit( fNumber ) ) |
4414 | 7 | { |
4415 | 7 | fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-' |
4416 | 7 | } |
4417 | 74.1k | } |
4418 | 74.7k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
4419 | 74.7k | if (rInfo.eScannedType == SvNumFormatType::PERCENT) |
4420 | 4.26k | { |
4421 | 4.26k | if (fNumber < D_MAX_D_BY_100) |
4422 | 4.26k | { |
4423 | 4.26k | fNumber *= 100.0; |
4424 | 4.26k | } |
4425 | 0 | else |
4426 | 0 | { |
4427 | 0 | sStr = ImpSvNumberformatScan::sErrStr; |
4428 | 0 | return false; |
4429 | 0 | } |
4430 | 4.26k | } |
4431 | 74.7k | sal_uInt16 i, j; |
4432 | 74.7k | sal_Int32 nDecPos = -1; |
4433 | 74.7k | bool bInteger = false; |
4434 | 74.7k | if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT ) |
4435 | 74.7k | { |
4436 | | // Special formatting only if no GENERAL keyword in format code |
4437 | 74.7k | const sal_uInt16 nThousand = rInfo.nThousand; |
4438 | 74.7k | tools::Long nPrecExp; |
4439 | 76.0k | for (i = 0; i < nThousand; i++) |
4440 | 1.27k | { |
4441 | 1.27k | if (fNumber > D_MIN_M_BY_1000) |
4442 | 1.25k | { |
4443 | 1.25k | fNumber /= 1000.0; |
4444 | 1.25k | } |
4445 | 19 | else |
4446 | 19 | { |
4447 | 19 | fNumber = 0.0; |
4448 | 19 | } |
4449 | 1.27k | } |
4450 | 74.7k | if (fNumber > 0.0) |
4451 | 64.1k | { |
4452 | 64.1k | nPrecExp = GetPrecExp( fNumber ); |
4453 | 64.1k | } |
4454 | 10.6k | else |
4455 | 10.6k | { |
4456 | 10.6k | nPrecExp = 0; |
4457 | 10.6k | } |
4458 | | // Make sure that Calc's ROUND and formatted output agree |
4459 | 74.7k | fNumber = rtl_math_round(fNumber, rInfo.nCntPost, rtl_math_RoundingMode_Corrected); |
4460 | 74.7k | if (rInfo.nCntPost) // Decimal places |
4461 | 36.6k | { |
4462 | 36.6k | if ((rInfo.nCntPost + nPrecExp) > 15 && nPrecExp < 15) |
4463 | 8.71k | { |
4464 | 8.71k | sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, 15-nPrecExp, '.'); |
4465 | 68.6k | for (tools::Long l = 15-nPrecExp; l < static_cast<tools::Long>(rInfo.nCntPost); l++) |
4466 | 59.9k | { |
4467 | 59.9k | sStr.append('0'); |
4468 | 59.9k | } |
4469 | 8.71k | } |
4470 | 27.9k | else |
4471 | 27.9k | { |
4472 | 27.9k | sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, rInfo.nCntPost, '.' ); |
4473 | 27.9k | } |
4474 | 36.6k | sStr.stripStart('0'); // Strip leading zeros |
4475 | 36.6k | } |
4476 | 38.0k | else if (fNumber == 0.0) // Null |
4477 | 8.59k | { |
4478 | | // Nothing to be done here, keep empty string sStr, |
4479 | | // ImpNumberFillWithThousands does the rest |
4480 | 8.59k | } |
4481 | 29.4k | else // Integer |
4482 | 29.4k | { |
4483 | 29.4k | sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, 0, '.'); |
4484 | 29.4k | sStr.stripStart('0'); // Strip leading zeros |
4485 | 29.4k | } |
4486 | 74.7k | nDecPos = sStr.indexOf('.' ); |
4487 | 74.7k | if ( nDecPos >= 0) |
4488 | 36.6k | { |
4489 | 36.6k | const sal_Unicode* p = sStr.getStr() + nDecPos; |
4490 | 230k | while ( *++p == '0' ) |
4491 | 193k | ; |
4492 | 36.6k | if ( !*p ) |
4493 | 23.9k | { |
4494 | 23.9k | bInteger = true; |
4495 | 23.9k | } |
4496 | 36.6k | sStr.remove( nDecPos, 1 ); // Remove . |
4497 | 36.6k | } |
4498 | 74.7k | if (bSign && (sStr.isEmpty() || checkForAll0s(sStr))) // Only 00000 |
4499 | 40 | { |
4500 | 40 | bSign = false; // Not -0.00 |
4501 | 40 | } |
4502 | 74.7k | } // End of != FLAG_STANDARD_IN_FORMAT |
4503 | | |
4504 | | // Edit backwards: |
4505 | 74.7k | j = NumFor[nIx].GetCount()-1; // Last symbol |
4506 | | // Decimal places: |
4507 | 74.7k | bRes |= ImpDecimalFill(rNatNum, sStr, fNumber, nDecPos, j, nIx, bInteger, bStarFlag); |
4508 | 74.7k | if (bSign) |
4509 | 515 | { |
4510 | 515 | sStr.insert(0, '-'); |
4511 | 515 | } |
4512 | 74.7k | ::impTransliterate(sStr, NumFor[nIx].GetNatNum(), rNatNum); |
4513 | 74.7k | return bRes; |
4514 | 74.7k | } |
4515 | | |
4516 | | bool SvNumberformat::ImpDecimalFill(const NativeNumberWrapper& rNatNum, |
4517 | | OUStringBuffer& sStr, // number string |
4518 | | double& rNumber, // number |
4519 | | sal_Int32 nDecPos, // decimals start |
4520 | | sal_uInt16 j, // symbol index within format code |
4521 | | sal_uInt16 nIx, // subformat index |
4522 | | bool bInteger, // is integer |
4523 | | bool bStarFlag) const |
4524 | 75.5k | { |
4525 | 75.5k | bool bRes = false; |
4526 | 75.5k | bool bFilled = false; // Was filled? |
4527 | 75.5k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
4528 | 75.5k | sal_Int32 k = sStr.getLength(); // After last figure |
4529 | | // Decimal places: |
4530 | 75.5k | if (rInfo.nCntPost > 0) |
4531 | 37.2k | { |
4532 | 37.2k | bool bTrailing = true; // Trailing zeros? |
4533 | 37.2k | short nType; |
4534 | 90.4k | while (j > 0 && // Backwards |
4535 | 89.9k | (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP) |
4536 | 53.2k | { |
4537 | 53.2k | switch ( nType ) |
4538 | 53.2k | { |
4539 | 120 | case NF_SYMBOLTYPE_STAR: |
4540 | 120 | if( bStarFlag ) |
4541 | 0 | { |
4542 | 0 | bRes = lcl_insertStarFillChar( sStr, k, rInfo.sStrArray[j]); |
4543 | 0 | } |
4544 | 120 | break; |
4545 | 1.33k | case NF_SYMBOLTYPE_BLANK: |
4546 | 1.33k | if (rInfo.sStrArray[j].getLength() >= 2) |
4547 | 1.33k | /*k = */ InsertBlanks(sStr, k, rInfo.sStrArray[j][1] ); |
4548 | 1.33k | break; |
4549 | 3.32k | case NF_SYMBOLTYPE_STRING: |
4550 | 4.31k | case NF_SYMBOLTYPE_CURRENCY: |
4551 | 6.57k | case NF_SYMBOLTYPE_PERCENT: |
4552 | 6.57k | sStr.insert(k, rInfo.sStrArray[j]); |
4553 | 6.57k | break; |
4554 | 770 | case NF_SYMBOLTYPE_THSEP: |
4555 | 770 | if (rInfo.nThousand == 0) |
4556 | 0 | { |
4557 | 0 | sStr.insert(k, rInfo.sStrArray[j]); |
4558 | 0 | } |
4559 | 770 | break; |
4560 | 37.8k | case NF_SYMBOLTYPE_DIGIT: |
4561 | 37.8k | { |
4562 | 37.8k | const OUString& rStr = rInfo.sStrArray[j]; |
4563 | 37.8k | const sal_Unicode* p1 = rStr.getStr(); |
4564 | 37.8k | const sal_Unicode* p = p1 + rStr.getLength(); |
4565 | | // In case the number of decimals passed are less than the |
4566 | | // "digits" given, append trailing '0' characters, which here |
4567 | | // means insert them because literal strings may have been |
4568 | | // appended already. If they weren't to be '0' characters |
4569 | | // they'll be changed below, as if decimals with trailing zeros |
4570 | | // were passed. |
4571 | 37.8k | if (nDecPos >= 0 && nDecPos <= k) |
4572 | 37.8k | { |
4573 | 37.8k | sal_Int32 nAppend = rStr.getLength() - (k - nDecPos); |
4574 | 38.3k | while (nAppend-- > 0) |
4575 | 429 | { |
4576 | 429 | sStr.insert( k++, '0'); |
4577 | 429 | } |
4578 | 37.8k | } |
4579 | 268k | while (k && p1 < p--) |
4580 | 230k | { |
4581 | 230k | const sal_Unicode c = *p; |
4582 | 230k | k--; |
4583 | 230k | if ( sStr[k] != '0' ) |
4584 | 31.2k | { |
4585 | 31.2k | bTrailing = false; |
4586 | 31.2k | bFilled = true; |
4587 | 31.2k | } |
4588 | 230k | if (bTrailing) |
4589 | 194k | { |
4590 | 194k | if ( c == '0' ) |
4591 | 192k | { |
4592 | 192k | bFilled = true; |
4593 | 192k | } |
4594 | 2.35k | else if ( c == '-' ) |
4595 | 338 | { |
4596 | 338 | if ( bInteger ) |
4597 | 271 | { |
4598 | 271 | sStr[ k ] = '-'; |
4599 | 271 | } |
4600 | 338 | bFilled = true; |
4601 | 338 | } |
4602 | 2.01k | else if ( c == '?' ) |
4603 | 221 | { |
4604 | 221 | sStr[ k ] = cBlankDigit; |
4605 | 221 | bFilled = true; |
4606 | 221 | } |
4607 | 1.79k | else if ( !bFilled ) // # |
4608 | 1.66k | { |
4609 | 1.66k | sStr.remove(k,1); |
4610 | 1.66k | } |
4611 | 194k | } |
4612 | 230k | } // of for |
4613 | 37.8k | break; |
4614 | 4.31k | } // of case digi |
4615 | 204 | case NF_KEY_CCC: // CCC currency |
4616 | 204 | sStr.insert(k, rScan.GetCurAbbrev()); |
4617 | 204 | break; |
4618 | 0 | case NF_KEY_GENERAL: // Standard in the String |
4619 | 0 | { |
4620 | 0 | OUStringBuffer sNum; |
4621 | 0 | ImpGetOutputStandard(rNumber, sNum, rNatNum); |
4622 | 0 | sNum.stripStart('-'); |
4623 | 0 | sStr.insert(k, sNum); |
4624 | 0 | break; |
4625 | 4.31k | } |
4626 | 6.30k | default: |
4627 | 6.30k | break; |
4628 | 53.2k | } // of switch |
4629 | 53.2k | j--; |
4630 | 53.2k | } // of while |
4631 | 37.2k | } // of decimal places |
4632 | | |
4633 | 75.5k | bRes |= ImpNumberFillWithThousands(rNatNum, sStr, rNumber, k, j, nIx, // Fill with . if needed |
4634 | 75.5k | rInfo.nCntPre, bStarFlag, bFilled ); |
4635 | | |
4636 | 75.5k | return bRes; |
4637 | 75.5k | } |
4638 | | |
4639 | | bool SvNumberformat::ImpNumberFillWithThousands( const NativeNumberWrapper& rNatNum, |
4640 | | OUStringBuffer& sBuff, // number string |
4641 | | double& rNumber, // number |
4642 | | sal_Int32 k, // position within string |
4643 | | sal_uInt16 j, // symbol index within format code |
4644 | | sal_uInt16 nIx, // subformat index |
4645 | | sal_Int32 nDigCnt, // count of integer digits in format |
4646 | | bool bStarFlag, |
4647 | | bool bAddDecSep) const // add decimal separator if necessary |
4648 | 75.9k | { |
4649 | 75.9k | bool bRes = false; |
4650 | 75.9k | sal_Int32 nLeadingStringChars = 0; // inserted StringChars before number |
4651 | 75.9k | sal_Int32 nDigitCount = 0; // count of integer digits from the right |
4652 | 75.9k | bool bStop = false; |
4653 | 75.9k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
4654 | | // no normal thousands separators if number divided by thousands |
4655 | 75.9k | bool bDoThousands = (rInfo.nThousand == 0); |
4656 | 75.9k | utl::DigitGroupingIterator aGrouping( GetCurrentLanguageData().GetLocaleData()->getDigitGrouping()); |
4657 | | |
4658 | 273k | while (!bStop) // backwards |
4659 | 197k | { |
4660 | 197k | if (j == 0) |
4661 | 75.9k | { |
4662 | 75.9k | bStop = true; |
4663 | 75.9k | } |
4664 | 197k | switch (rInfo.nTypeArray[j]) |
4665 | 197k | { |
4666 | 37.2k | case NF_SYMBOLTYPE_DECSEP: |
4667 | 37.2k | aGrouping.reset(); |
4668 | 37.2k | [[fallthrough]]; |
4669 | 49.4k | case NF_SYMBOLTYPE_STRING: |
4670 | 49.4k | if ( rInfo.nTypeArray[j] == NF_SYMBOLTYPE_STRING && nDigCnt == 0 ) |
4671 | 203 | { |
4672 | | // tdf#159930 no integer in format ".###" |
4673 | 203 | k = 0; // insert string at the beginning |
4674 | 203 | } |
4675 | 49.4k | [[fallthrough]]; |
4676 | 52.9k | case NF_SYMBOLTYPE_CURRENCY: |
4677 | 54.9k | case NF_SYMBOLTYPE_PERCENT: |
4678 | 54.9k | if ( rInfo.nTypeArray[j] != NF_SYMBOLTYPE_DECSEP || bAddDecSep ) |
4679 | 54.3k | sBuff.insert(k, rInfo.sStrArray[j]); |
4680 | 54.9k | if ( k == 0 ) |
4681 | 20.4k | { |
4682 | 20.4k | nLeadingStringChars = nLeadingStringChars + rInfo.sStrArray[j].getLength(); |
4683 | 20.4k | } |
4684 | 54.9k | break; |
4685 | 4.08k | case NF_SYMBOLTYPE_STAR: |
4686 | 4.08k | if( bStarFlag ) |
4687 | 0 | { |
4688 | 0 | bRes = lcl_insertStarFillChar( sBuff, k, rInfo.sStrArray[j]); |
4689 | 0 | } |
4690 | 4.08k | break; |
4691 | 8.19k | case NF_SYMBOLTYPE_BLANK: |
4692 | 8.19k | if (rInfo.sStrArray[j].getLength() >= 2) |
4693 | 8.18k | /*k = */ InsertBlanks(sBuff, k, rInfo.sStrArray[j][1] ); |
4694 | 8.19k | break; |
4695 | 18.8k | case NF_SYMBOLTYPE_THSEP: |
4696 | | // #i7284# #102685# Insert separator also if number is divided |
4697 | | // by thousands and the separator is specified somewhere in |
4698 | | // between and not only at the end. |
4699 | | // #i12596# But do not insert if it's a parenthesized negative |
4700 | | // format like (#,) |
4701 | | // In fact, do not insert if divided and regex [0#,],[^0#] and |
4702 | | // no other digit symbol follows (which was already detected |
4703 | | // during scan of format code, otherwise there would be no |
4704 | | // division), else do insert. Same in ImpNumberFill() below. |
4705 | 18.8k | if ( !bDoThousands && j < NumFor[nIx].GetCount()-1 ) |
4706 | 1.10k | { |
4707 | 1.10k | bDoThousands = ((j == 0) || |
4708 | 1.10k | (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && |
4709 | 0 | rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || |
4710 | 1.10k | (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); |
4711 | 1.10k | } |
4712 | 18.8k | if ( bDoThousands ) |
4713 | 18.3k | { |
4714 | 18.3k | if (k > 0) |
4715 | 7.02k | { |
4716 | 7.02k | sBuff.insert(k, rInfo.sStrArray[j]); |
4717 | 7.02k | } |
4718 | 11.3k | else if (nDigitCount < nDigCnt) |
4719 | 11.3k | { |
4720 | | // Leading '#' displays nothing (e.g. no leading |
4721 | | // separator for numbers <1000 with #,##0 format). |
4722 | | // Leading '?' displays blank. |
4723 | | // Everything else, including nothing, displays the |
4724 | | // separator. |
4725 | 11.3k | sal_Unicode cLeader = 0; |
4726 | 11.3k | if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT) |
4727 | 11.3k | { |
4728 | 11.3k | const OUString& rStr = rInfo.sStrArray[j-1]; |
4729 | 11.3k | sal_Int32 nLen = rStr.getLength(); |
4730 | 11.3k | if (nLen) |
4731 | 11.3k | { |
4732 | 11.3k | cLeader = rStr[ nLen - 1 ]; |
4733 | 11.3k | } |
4734 | 11.3k | } |
4735 | 11.3k | switch (cLeader) |
4736 | 11.3k | { |
4737 | 11.2k | case '#': |
4738 | 11.2k | ; // nothing |
4739 | 11.2k | break; |
4740 | 47 | case '?': |
4741 | | // replace thousand separator with blank |
4742 | 47 | sBuff.insert(k, ' '); |
4743 | 47 | break; |
4744 | 17 | default: |
4745 | 17 | sBuff.insert(k, rInfo.sStrArray[j]); |
4746 | 11.3k | } |
4747 | 11.3k | } |
4748 | 18.3k | aGrouping.advance(); |
4749 | 18.3k | } |
4750 | 18.8k | break; |
4751 | 94.4k | case NF_SYMBOLTYPE_DIGIT: |
4752 | 94.4k | { |
4753 | 94.4k | const OUString& rStr = rInfo.sStrArray[j]; |
4754 | 94.4k | const sal_Unicode* p1 = rStr.getStr(); |
4755 | 94.4k | const sal_Unicode* p = p1 + rStr.getLength(); |
4756 | 243k | while ( p1 < p-- ) |
4757 | 148k | { |
4758 | 148k | nDigitCount++; |
4759 | 148k | if (k > 0) |
4760 | 96.8k | { |
4761 | 96.8k | k--; |
4762 | 96.8k | } |
4763 | 52.1k | else |
4764 | 52.1k | { |
4765 | 52.1k | switch (*p) |
4766 | 52.1k | { |
4767 | 16.5k | case '0': |
4768 | 16.5k | sBuff.insert(0, '0'); |
4769 | 16.5k | break; |
4770 | 2.43k | case '?': |
4771 | 2.43k | sBuff.insert(0, cBlankDigit); |
4772 | 2.43k | break; |
4773 | 52.1k | } |
4774 | 52.1k | } |
4775 | 148k | if (nDigitCount == nDigCnt && k > 0) |
4776 | 29.4k | { |
4777 | | // more digits than specified |
4778 | 29.4k | ImpDigitFill(sBuff, 0, k, nIx, nDigitCount, aGrouping); |
4779 | 29.4k | } |
4780 | 148k | } |
4781 | 94.4k | break; |
4782 | 94.4k | } |
4783 | 94.4k | case NF_KEY_CCC: // CCC currency |
4784 | 193 | sBuff.insert(k, rScan.GetCurAbbrev()); |
4785 | 193 | break; |
4786 | 20 | case NF_KEY_GENERAL: // "General" in string |
4787 | 20 | { |
4788 | 20 | OUStringBuffer sNum; |
4789 | 20 | ImpGetOutputStandard(rNumber, sNum, rNatNum); |
4790 | 20 | sNum.stripStart('-'); |
4791 | 20 | sBuff.insert(k, sNum); |
4792 | 20 | break; |
4793 | 94.4k | } |
4794 | 16.7k | default: |
4795 | 16.7k | break; |
4796 | 197k | } // switch |
4797 | 197k | j--; // next format code string |
4798 | 197k | } // while |
4799 | | |
4800 | 75.9k | k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ... |
4801 | 75.9k | if (k > nLeadingStringChars) |
4802 | 396 | { |
4803 | 396 | ImpDigitFill(sBuff, nLeadingStringChars, k, nIx, nDigitCount, aGrouping); |
4804 | 396 | } |
4805 | 75.9k | return bRes; |
4806 | 75.9k | } |
4807 | | |
4808 | | void SvNumberformat::ImpDigitFill(OUStringBuffer& sStr, // number string |
4809 | | sal_Int32 nStart, // start of digits |
4810 | | sal_Int32 & k, // position within string |
4811 | | sal_uInt16 nIx, // subformat index |
4812 | | sal_Int32 & nDigitCount, // count of integer digits from the right so far |
4813 | | utl::DigitGroupingIterator & rGrouping ) const // current grouping |
4814 | 29.8k | { |
4815 | 29.8k | if (NumFor[nIx].Info().bThousand) // Only if grouping fill in separators |
4816 | 3.77k | { |
4817 | 3.77k | const OUString& rThousandSep = GetCurrentLanguageData().GetNumThousandSep(); |
4818 | 15.0k | while (k > nStart) |
4819 | 11.2k | { |
4820 | 11.2k | if (nDigitCount == rGrouping.getPos()) |
4821 | 2.36k | { |
4822 | 2.36k | sStr.insert( k, rThousandSep ); |
4823 | 2.36k | rGrouping.advance(); |
4824 | 2.36k | } |
4825 | 11.2k | nDigitCount++; |
4826 | 11.2k | k--; |
4827 | 11.2k | } |
4828 | 3.77k | } |
4829 | 26.0k | else // simply skip |
4830 | 26.0k | { |
4831 | 26.0k | k = nStart; |
4832 | 26.0k | } |
4833 | 29.8k | } |
4834 | | |
4835 | | bool SvNumberformat::ImpNumberFill( const NativeNumberWrapper& rNatNum, |
4836 | | OUStringBuffer& sBuff, // number string |
4837 | | double& rNumber, // number for "General" format |
4838 | | sal_Int32& k, // position within string |
4839 | | sal_uInt16& j, // symbol index within format code |
4840 | | sal_uInt16 nIx, // subformat index |
4841 | | short eSymbolType, // type of stop condition |
4842 | | bool bStarFlag, |
4843 | | bool bInsertRightBlank) const // insert blank on right for denominator (default = false) |
4844 | 7.88k | { |
4845 | 7.88k | bool bRes = false; |
4846 | 7.88k | bool bStop = false; |
4847 | 7.88k | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
4848 | | // no normal thousands separators if number divided by thousands |
4849 | 7.88k | bool bDoThousands = (rInfo.nThousand == 0); |
4850 | 7.88k | bool bFoundNumber = false; |
4851 | 7.88k | short nType; |
4852 | | |
4853 | 7.88k | k = sBuff.getLength(); // behind last digit |
4854 | | |
4855 | 97.7k | while (!bStop && (nType = rInfo.nTypeArray[j]) != eSymbolType ) // Backwards |
4856 | 89.9k | { |
4857 | 89.9k | switch ( nType ) |
4858 | 89.9k | { |
4859 | 1 | case NF_SYMBOLTYPE_STAR: |
4860 | 1 | if( bStarFlag ) |
4861 | 0 | { |
4862 | 0 | if ( bFoundNumber && eSymbolType != NF_SYMBOLTYPE_EXP ) |
4863 | 0 | k = 0; // tdf#100842 jump to beginning of number before inserting something else |
4864 | 0 | bRes = lcl_insertStarFillChar( sBuff, k, rInfo.sStrArray[j]); |
4865 | 0 | } |
4866 | 1 | break; |
4867 | 124 | case NF_SYMBOLTYPE_BLANK: |
4868 | 124 | if (rInfo.sStrArray[j].getLength() >= 2) |
4869 | 124 | { |
4870 | 124 | if ( bFoundNumber && eSymbolType != NF_SYMBOLTYPE_EXP ) |
4871 | 0 | k = 0; // tdf#100842 jump to beginning of number before inserting something else |
4872 | 124 | k = InsertBlanks(sBuff, k, rInfo.sStrArray[j][1] ); |
4873 | 124 | } |
4874 | 124 | break; |
4875 | 0 | case NF_SYMBOLTYPE_THSEP: |
4876 | | // Same as in ImpNumberFillWithThousands() above, do not insert |
4877 | | // if divided and regex [0#,],[^0#] and no other digit symbol |
4878 | | // follows (which was already detected during scan of format |
4879 | | // code, otherwise there would be no division), else do insert. |
4880 | 0 | if ( !bDoThousands && j < NumFor[nIx].GetCount()-1 ) |
4881 | 0 | { |
4882 | 0 | bDoThousands = ((j == 0) || |
4883 | 0 | (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && |
4884 | 0 | rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || |
4885 | 0 | (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); |
4886 | 0 | } |
4887 | 0 | if ( bDoThousands && k > 0 ) |
4888 | 0 | { |
4889 | 0 | sBuff.insert(k, rInfo.sStrArray[j]); |
4890 | 0 | } |
4891 | 0 | break; |
4892 | 10.2k | case NF_SYMBOLTYPE_DIGIT: |
4893 | 10.2k | { |
4894 | 10.2k | bFoundNumber = true; |
4895 | 10.2k | sal_uInt16 nPosInsertBlank = bInsertRightBlank ? k : 0; // left alignment of denominator |
4896 | 10.2k | const OUString& rStr = rInfo.sStrArray[j]; |
4897 | 10.2k | const sal_Unicode* p1 = rStr.getStr(); |
4898 | 10.2k | const sal_Unicode* p = p1 + rStr.getLength(); |
4899 | 24.0k | while ( p1 < p-- ) |
4900 | 13.7k | { |
4901 | 13.7k | if (k > 0) |
4902 | 3.98k | { |
4903 | 3.98k | k--; |
4904 | 3.98k | } |
4905 | 9.75k | else |
4906 | 9.75k | { |
4907 | 9.75k | switch (*p) |
4908 | 9.75k | { |
4909 | 7.66k | case '0': |
4910 | 7.66k | sBuff.insert(0, '0'); |
4911 | 7.66k | break; |
4912 | 620 | case '?': |
4913 | 620 | sBuff.insert(nPosInsertBlank, cBlankDigit); |
4914 | 620 | break; |
4915 | 9.75k | } |
4916 | 9.75k | } |
4917 | 13.7k | } |
4918 | 10.2k | } |
4919 | 10.2k | break; |
4920 | 10.2k | case NF_KEY_CCC: // CCC currency |
4921 | 0 | sBuff.insert(k, rScan.GetCurAbbrev()); |
4922 | 0 | break; |
4923 | 0 | case NF_KEY_GENERAL: // Standard in the String |
4924 | 0 | { |
4925 | 0 | OUStringBuffer sNum; |
4926 | 0 | bFoundNumber = true; |
4927 | 0 | ImpGetOutputStandard(rNumber, sNum, rNatNum); |
4928 | 0 | sNum.stripStart('-'); |
4929 | 0 | sBuff.insert(k, sNum); |
4930 | 0 | } |
4931 | 0 | break; |
4932 | 64.4k | case NF_SYMBOLTYPE_FRAC_FDIV: // Do Nothing |
4933 | 64.4k | if (k > 0) |
4934 | 7.08k | { |
4935 | 7.08k | k--; |
4936 | 7.08k | } |
4937 | 64.4k | break; |
4938 | | |
4939 | 15.0k | default: |
4940 | 15.0k | if ( bFoundNumber && eSymbolType != NF_SYMBOLTYPE_EXP ) |
4941 | 1.56k | k = 0; // tdf#100842 jump to beginning of number before inserting something else |
4942 | 15.0k | sBuff.insert(k, rInfo.sStrArray[j]); |
4943 | 15.0k | break; |
4944 | 89.9k | } // of switch |
4945 | 89.9k | if ( j ) |
4946 | 88.8k | j--; // Next String |
4947 | 1.04k | else |
4948 | 1.04k | bStop = true; |
4949 | 89.9k | } // of while |
4950 | 7.88k | return bRes; |
4951 | 7.88k | } |
4952 | | |
4953 | | void SvNumberformat::GetFormatSpecialInfo(bool& bThousand, |
4954 | | bool& IsRed, |
4955 | | sal_uInt16& nPrecision, |
4956 | | sal_uInt16& nLeadingCnt) const |
4957 | 22.4k | { |
4958 | | // as before: take info from nNumFor=0 for whole format (for dialog etc.) |
4959 | | |
4960 | 22.4k | SvNumFormatType nDummyType; |
4961 | 22.4k | GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nLeadingCnt ); |
4962 | | |
4963 | | // "negative in red" is only useful for the whole format |
4964 | | |
4965 | 22.4k | const Color* pColor = NumFor[1].GetColor(); |
4966 | 22.4k | IsRed = fLimit1 == 0.0 && fLimit2 == 0.0 && pColor |
4967 | 0 | && (*pColor == ImpSvNumberformatScan::GetRedColor()); |
4968 | 22.4k | } |
4969 | | |
4970 | | void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, SvNumFormatType& rScannedType, |
4971 | | bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nLeadingCnt ) const |
4972 | 22.4k | { |
4973 | | // take info from a specified sub-format (for XML export) |
4974 | | |
4975 | 22.4k | if ( nNumFor > 3 ) |
4976 | 0 | { |
4977 | 0 | return; // invalid |
4978 | 0 | } |
4979 | | |
4980 | 22.4k | const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); |
4981 | 22.4k | rScannedType = rInfo.eScannedType; |
4982 | 22.4k | bThousand = rInfo.bThousand; |
4983 | 22.4k | nPrecision = (rInfo.eScannedType == SvNumFormatType::FRACTION) |
4984 | 22.4k | ? rInfo.nCntExp // number of denominator digits for fraction |
4985 | 22.4k | : rInfo.nCntPost; |
4986 | 22.4k | sal_Int32 nPosHash = 1; |
4987 | 22.4k | if ( rInfo.eScannedType == SvNumFormatType::FRACTION && |
4988 | 0 | ( (nPosHash += GetDenominatorString(nNumFor).indexOf('#')) > 0 ) ) |
4989 | 0 | nPrecision -= nPosHash; |
4990 | 22.4k | if (bStandard && rInfo.eScannedType == SvNumFormatType::NUMBER) |
4991 | 22.4k | { |
4992 | | // StandardFormat |
4993 | 22.4k | nLeadingCnt = 1; |
4994 | 22.4k | } |
4995 | 0 | else |
4996 | 0 | { |
4997 | 0 | nLeadingCnt = 0; |
4998 | 0 | bool bStop = false; |
4999 | 0 | sal_uInt16 i = 0; |
5000 | 0 | const sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
5001 | 0 | while (!bStop && i < nCnt) |
5002 | 0 | { |
5003 | 0 | short nType = rInfo.nTypeArray[i]; |
5004 | 0 | if ( nType == NF_SYMBOLTYPE_DIGIT) |
5005 | 0 | { |
5006 | 0 | const sal_Unicode* p = rInfo.sStrArray[i].getStr(); |
5007 | 0 | while ( *p == '#' ) |
5008 | 0 | { |
5009 | 0 | p++; |
5010 | 0 | } |
5011 | 0 | while ( *p == '0' || *p == '?' ) |
5012 | 0 | { |
5013 | 0 | nLeadingCnt++; |
5014 | 0 | p++; |
5015 | 0 | } |
5016 | 0 | } |
5017 | 0 | else if (nType == NF_SYMBOLTYPE_DECSEP |
5018 | 0 | || nType == NF_SYMBOLTYPE_EXP |
5019 | 0 | || nType == NF_SYMBOLTYPE_FRACBLANK) // Fraction: stop after integer part, |
5020 | 0 | { // do not count '0' of fraction |
5021 | 0 | bStop = true; |
5022 | 0 | } |
5023 | 0 | i++; |
5024 | 0 | } |
5025 | 0 | } |
5026 | 22.4k | } |
5027 | | |
5028 | | const OUString* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos, |
5029 | | bool bString /* = false */ ) const |
5030 | 1.36M | { |
5031 | 1.36M | if ( nNumFor > 3 ) |
5032 | 0 | { |
5033 | 0 | return nullptr; |
5034 | 0 | } |
5035 | 1.36M | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
5036 | 1.36M | if ( !nCnt ) |
5037 | 685k | { |
5038 | 685k | return nullptr; |
5039 | 685k | } |
5040 | 677k | if ( nPos == 0xFFFF ) |
5041 | 122k | { |
5042 | 122k | nPos = nCnt - 1; |
5043 | 122k | if ( bString ) |
5044 | 122k | { // Backwards |
5045 | 122k | short const * pType = NumFor[nNumFor].Info().nTypeArray.data() + nPos; |
5046 | 255k | while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && |
5047 | 149k | (*pType != NF_SYMBOLTYPE_CURRENCY) ) |
5048 | 132k | { |
5049 | 132k | pType--; |
5050 | 132k | nPos--; |
5051 | 132k | } |
5052 | 122k | if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) |
5053 | 13.1k | { |
5054 | 13.1k | return nullptr; |
5055 | 13.1k | } |
5056 | 122k | } |
5057 | 122k | } |
5058 | 554k | else if ( nPos > nCnt - 1 ) |
5059 | 17.7k | { |
5060 | 17.7k | return nullptr; |
5061 | 17.7k | } |
5062 | 537k | else if ( bString ) |
5063 | 531k | { |
5064 | | // forward |
5065 | 531k | short const * pType = NumFor[nNumFor].Info().nTypeArray.data() + nPos; |
5066 | 1.02M | while ( nPos < nCnt && (*pType != NF_SYMBOLTYPE_STRING) && |
5067 | 527k | (*pType != NF_SYMBOLTYPE_CURRENCY) ) |
5068 | 489k | { |
5069 | 489k | pType++; |
5070 | 489k | nPos++; |
5071 | 489k | } |
5072 | 531k | if ( nPos >= nCnt || ((*pType != NF_SYMBOLTYPE_STRING) && |
5073 | 38.1k | (*pType != NF_SYMBOLTYPE_CURRENCY)) ) |
5074 | 110k | { |
5075 | 110k | return nullptr; |
5076 | 110k | } |
5077 | 531k | } |
5078 | 535k | return &NumFor[nNumFor].Info().sStrArray[nPos]; |
5079 | 677k | } |
5080 | | |
5081 | | short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos ) const |
5082 | 0 | { |
5083 | 0 | if ( nNumFor > 3 ) |
5084 | 0 | { |
5085 | 0 | return 0; |
5086 | 0 | } |
5087 | 0 | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
5088 | 0 | if ( !nCnt ) |
5089 | 0 | { |
5090 | 0 | return 0; |
5091 | 0 | } |
5092 | 0 | if ( nPos == 0xFFFF ) |
5093 | 0 | { |
5094 | 0 | nPos = nCnt - 1; |
5095 | 0 | } |
5096 | 0 | else if ( nPos > nCnt - 1 ) |
5097 | 0 | { |
5098 | 0 | return 0; |
5099 | 0 | } |
5100 | 0 | return NumFor[nNumFor].Info().nTypeArray[nPos]; |
5101 | 0 | } |
5102 | | |
5103 | | bool SvNumberformat::IsNegativeWithoutSign() const |
5104 | 6.18k | { |
5105 | 6.18k | if ( IsSecondSubformatRealNegative() ) |
5106 | 6.18k | { |
5107 | 6.18k | const OUString* pStr = GetNumForString( 1, 0, true ); |
5108 | 6.18k | if ( pStr ) |
5109 | 6.18k | { |
5110 | 6.18k | return !HasStringNegativeSign( *pStr ); |
5111 | 6.18k | } |
5112 | 6.18k | } |
5113 | 0 | return false; |
5114 | 6.18k | } |
5115 | | |
5116 | | bool SvNumberformat::IsNegativeInBracket() const |
5117 | 51.5k | { |
5118 | 51.5k | sal_uInt16 nCnt = NumFor[1].GetCount(); |
5119 | 51.5k | if (!nCnt) |
5120 | 51.5k | { |
5121 | 51.5k | return false; |
5122 | 51.5k | } |
5123 | 0 | auto& tmp = NumFor[1].Info().sStrArray; |
5124 | 0 | return tmp[0] == "(" && tmp[nCnt-1] == ")"; |
5125 | 51.5k | } |
5126 | | |
5127 | | bool SvNumberformat::HasPositiveBracketPlaceholder() const |
5128 | 486 | { |
5129 | 486 | sal_uInt16 nCnt = NumFor[0].GetCount(); |
5130 | 486 | return NumFor[0].Info().sStrArray[nCnt-1] == "_)"; |
5131 | 486 | } |
5132 | | |
5133 | | DateOrder SvNumberformat::GetDateOrder() const |
5134 | 44.4k | { |
5135 | 44.4k | if ( eType & SvNumFormatType::DATE ) |
5136 | 44.4k | { |
5137 | 44.4k | auto& rTypeArray = NumFor[0].Info().nTypeArray; |
5138 | 44.4k | sal_uInt16 nCnt = NumFor[0].GetCount(); |
5139 | 62.5k | for ( sal_uInt16 j=0; j<nCnt; j++ ) |
5140 | 61.5k | { |
5141 | 61.5k | switch ( rTypeArray[j] ) |
5142 | 61.5k | { |
5143 | 5.27k | case NF_KEY_D : |
5144 | 22.9k | case NF_KEY_DD : |
5145 | 22.9k | return DateOrder::DMY; |
5146 | 2.17k | case NF_KEY_M : |
5147 | 6.71k | case NF_KEY_MM : |
5148 | 7.56k | case NF_KEY_MMM : |
5149 | 8.22k | case NF_KEY_MMMM : |
5150 | 8.66k | case NF_KEY_MMMMM : |
5151 | 8.66k | return DateOrder::MDY; |
5152 | 1.94k | case NF_KEY_YY : |
5153 | 2.87k | case NF_KEY_YYYY : |
5154 | 3.26k | case NF_KEY_EC : |
5155 | 3.81k | case NF_KEY_EEC : |
5156 | 11.1k | case NF_KEY_R : |
5157 | 11.8k | case NF_KEY_RR : |
5158 | 11.8k | return DateOrder::YMD; |
5159 | 61.5k | } |
5160 | 61.5k | } |
5161 | 44.4k | } |
5162 | 0 | else |
5163 | 0 | { |
5164 | 0 | SAL_WARN( "svl.numbers", "SvNumberformat::GetDateOrder: no date" ); |
5165 | 0 | } |
5166 | 1.00k | return rLoc().getDateOrder(); |
5167 | 44.4k | } |
5168 | | |
5169 | | sal_uInt32 SvNumberformat::GetExactDateOrder() const |
5170 | 52.7k | { |
5171 | 52.7k | sal_uInt32 nRet = 0; |
5172 | 52.7k | if ( !(eType & SvNumFormatType::DATE) ) |
5173 | 0 | { |
5174 | 0 | SAL_WARN( "svl.numbers", "SvNumberformat::GetExactDateOrder: no date" ); |
5175 | 0 | return nRet; |
5176 | 0 | } |
5177 | 52.7k | auto& rTypeArray = NumFor[0].Info().nTypeArray; |
5178 | 52.7k | sal_uInt16 nCnt = NumFor[0].GetCount(); |
5179 | 52.7k | int nShift = 0; |
5180 | 257k | for ( sal_uInt16 j=0; j<nCnt && nShift < 3; j++ ) |
5181 | 205k | { |
5182 | 205k | switch ( rTypeArray[j] ) |
5183 | 205k | { |
5184 | 16.1k | case NF_KEY_D : |
5185 | 39.1k | case NF_KEY_DD : |
5186 | 39.1k | nRet = (nRet << 8) | 'D'; |
5187 | 39.1k | ++nShift; |
5188 | 39.1k | break; |
5189 | 9.63k | case NF_KEY_M : |
5190 | 16.1k | case NF_KEY_MM : |
5191 | 16.6k | case NF_KEY_MMM : |
5192 | 31.6k | case NF_KEY_MMMM : |
5193 | 32.3k | case NF_KEY_MMMMM : |
5194 | 32.3k | nRet = (nRet << 8) | 'M'; |
5195 | 32.3k | ++nShift; |
5196 | 32.3k | break; |
5197 | 6.60k | case NF_KEY_YY : |
5198 | 11.9k | case NF_KEY_YYYY : |
5199 | 16.7k | case NF_KEY_EC : |
5200 | 18.6k | case NF_KEY_EEC : |
5201 | 34.1k | case NF_KEY_R : |
5202 | 35.8k | case NF_KEY_RR : |
5203 | 35.8k | nRet = (nRet << 8) | 'Y'; |
5204 | 35.8k | ++nShift; |
5205 | 35.8k | break; |
5206 | 205k | } |
5207 | 205k | } |
5208 | 52.7k | return nRet; |
5209 | 52.7k | } |
5210 | | |
5211 | | void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1, |
5212 | | SvNumberformatLimitOps& rOper2, double& rVal2 ) const |
5213 | 0 | { |
5214 | 0 | rOper1 = eOp1; |
5215 | 0 | rOper2 = eOp2; |
5216 | 0 | rVal1 = fLimit1; |
5217 | 0 | rVal2 = fLimit2; |
5218 | 0 | } |
5219 | | |
5220 | | const Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const |
5221 | 0 | { |
5222 | 0 | if ( nNumFor > 3 ) |
5223 | 0 | { |
5224 | 0 | return nullptr; |
5225 | 0 | } |
5226 | 0 | return NumFor[nNumFor].GetColor(); |
5227 | 0 | } |
5228 | | |
5229 | | static void lcl_SvNumberformat_AddLimitStringImpl( OUString& rStr, |
5230 | | SvNumberformatLimitOps eOp, |
5231 | | double fLimit, std::u16string_view rDecSep ) |
5232 | 0 | { |
5233 | 0 | if ( eOp == NUMBERFORMAT_OP_NO ) |
5234 | 0 | return; |
5235 | | |
5236 | 0 | switch ( eOp ) |
5237 | 0 | { |
5238 | 0 | case NUMBERFORMAT_OP_EQ : |
5239 | 0 | rStr = "[="; |
5240 | 0 | break; |
5241 | 0 | case NUMBERFORMAT_OP_NE : |
5242 | 0 | rStr = "[<>"; |
5243 | 0 | break; |
5244 | 0 | case NUMBERFORMAT_OP_LT : |
5245 | 0 | rStr = "[<"; |
5246 | 0 | break; |
5247 | 0 | case NUMBERFORMAT_OP_LE : |
5248 | 0 | rStr = "[<="; |
5249 | 0 | break; |
5250 | 0 | case NUMBERFORMAT_OP_GT : |
5251 | 0 | rStr = "[>"; |
5252 | 0 | break; |
5253 | 0 | case NUMBERFORMAT_OP_GE : |
5254 | 0 | rStr = "[>="; |
5255 | 0 | break; |
5256 | 0 | default: |
5257 | 0 | SAL_WARN( "svl.numbers", "unsupported number format" ); |
5258 | 0 | break; |
5259 | 0 | } |
5260 | 0 | rStr += ::rtl::math::doubleToUString( fLimit, |
5261 | 0 | rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, |
5262 | 0 | rDecSep[0], true); |
5263 | 0 | rStr += "]"; |
5264 | 0 | } |
5265 | | |
5266 | | static void lcl_insertLCID( OUStringBuffer& rFormatStr, sal_uInt32 nLCID, sal_Int32 nPosInsertLCID, bool bDBNumInserted ) |
5267 | 0 | { |
5268 | 0 | if ( nLCID == 0 ) |
5269 | 0 | return; |
5270 | 0 | if (nPosInsertLCID == rFormatStr.getLength() && !bDBNumInserted) |
5271 | | // No format code, no locale. |
5272 | 0 | return; |
5273 | | |
5274 | 0 | auto aLCIDString = OUString::number( nLCID , 16 ).toAsciiUpperCase(); |
5275 | | // Search for only last DBNum which is the last element before insertion position |
5276 | 0 | if ( bDBNumInserted && nPosInsertLCID >= 8 |
5277 | 0 | && aLCIDString.length > 4 |
5278 | 0 | && OUString::unacquired(rFormatStr).match( "[DBNum", nPosInsertLCID-8) ) |
5279 | 0 | { // remove DBNumX code if long LCID |
5280 | 0 | nPosInsertLCID -= 8; |
5281 | 0 | rFormatStr.remove( nPosInsertLCID, 8 ); |
5282 | 0 | } |
5283 | 0 | rFormatStr.insert( nPosInsertLCID, "[$-" + aLCIDString + "]" ); |
5284 | 0 | } |
5285 | | |
5286 | | /** Increment nAlphabetID for CJK numerals |
5287 | | * +1 for financial numerals [NatNum2] |
5288 | | * +2 for Arabic fullwidth numerals [NatNum3] |
5289 | | * */ |
5290 | | static void lcl_incrementAlphabetWithNatNum ( sal_uInt32& nAlphabetID, sal_uInt32 nNatNum ) |
5291 | 0 | { |
5292 | 0 | if ( nNatNum == 2) // financial |
5293 | 0 | nAlphabetID += 1; |
5294 | 0 | else if ( nNatNum == 3) |
5295 | 0 | nAlphabetID += 2; |
5296 | 0 | nAlphabetID = nAlphabetID << 24; |
5297 | 0 | } |
5298 | | |
5299 | | OUString SvNumberformat::GetMappedFormatstring( const NfKeywordTable& rKeywords, |
5300 | | const LocaleDataWrapper& rLocWrp, |
5301 | | LanguageType nOriginalLang /* =LANGUAGE_DONTKNOW */, |
5302 | | bool bSystemLanguage /* =false */ ) const |
5303 | 0 | { |
5304 | 0 | OUStringBuffer aStr; |
5305 | 0 | if (maLocale.meSubstitute != LocaleType::Substitute::NONE) |
5306 | 0 | { |
5307 | | // XXX: theoretically this could clash with the first subformat's |
5308 | | // lcl_insertLCID() below, in practice as long as it is used for system |
5309 | | // time and date modifiers it shouldn't (i.e. there is no calendar or |
5310 | | // numeral specified as well). |
5311 | 0 | aStr.append("[$-" + maLocale.generateCode() + "]"); |
5312 | 0 | } |
5313 | 0 | bool bDefault[4]; |
5314 | | // 1 subformat matches all if no condition specified, |
5315 | 0 | bDefault[0] = ( NumFor[1].GetCount() == 0 && eOp1 == NUMBERFORMAT_OP_NO ); |
5316 | | // with 2 subformats [>=0];[<0] is implied if no condition specified |
5317 | 0 | bDefault[1] = ( !bDefault[0] && NumFor[2].GetCount() == 0 && |
5318 | 0 | eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 && |
5319 | 0 | eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 ); |
5320 | | // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified, |
5321 | | // note that subformats may be empty (;;;) and NumFor[2].GetCount()>0 is not checked. |
5322 | 0 | bDefault[2] = ( !bDefault[0] && !bDefault[1] && |
5323 | 0 | eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 && |
5324 | 0 | eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 ); |
5325 | 0 | bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2]; |
5326 | | // from now on bDefault[] values are used to append empty subformats at the end |
5327 | 0 | bDefault[3] = false; |
5328 | 0 | if ( !bDefaults ) |
5329 | 0 | { |
5330 | | // conditions specified |
5331 | 0 | if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO ) |
5332 | 0 | { |
5333 | 0 | bDefault[0] = bDefault[1] = true; // [];x |
5334 | 0 | } |
5335 | 0 | else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO && |
5336 | 0 | NumFor[2].GetCount() == 0 ) |
5337 | 0 | { |
5338 | 0 | bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = true; // [];[];; |
5339 | 0 | } |
5340 | | // nothing to do if conditions specified for every subformat |
5341 | 0 | } |
5342 | 0 | else if ( bDefault[0] ) |
5343 | 0 | { |
5344 | 0 | bDefault[0] = false; // a single unconditional subformat is never delimited |
5345 | 0 | } |
5346 | 0 | else |
5347 | 0 | { |
5348 | 0 | if ( bDefault[2] && NumFor[2].GetCount() == 0 && NumFor[1].GetCount() > 0 ) |
5349 | 0 | { |
5350 | 0 | bDefault[3] = true; // special cases x;x;; and ;x;; |
5351 | 0 | } |
5352 | 0 | for ( int i=0; i<3 && !bDefault[i]; ++i ) |
5353 | 0 | { |
5354 | 0 | bDefault[i] = true; |
5355 | 0 | } |
5356 | 0 | } |
5357 | 0 | int nSem = 0; // needed ';' delimiters |
5358 | 0 | int nSub = 0; // subformats delimited so far |
5359 | 0 | for ( int n=0; n<4; n++ ) |
5360 | 0 | { |
5361 | 0 | if ( n > 0 && NumFor[n].Info().eScannedType != SvNumFormatType::UNDEFINED ) |
5362 | 0 | { |
5363 | 0 | nSem++; |
5364 | 0 | } |
5365 | 0 | OUString aPrefix; |
5366 | |
|
5367 | 0 | if ( !bDefaults ) |
5368 | 0 | { |
5369 | 0 | switch ( n ) |
5370 | 0 | { |
5371 | 0 | case 0 : |
5372 | 0 | lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1, |
5373 | 0 | fLimit1, rLocWrp.getNumDecimalSep() ); |
5374 | 0 | break; |
5375 | 0 | case 1 : |
5376 | 0 | lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2, |
5377 | 0 | fLimit2, rLocWrp.getNumDecimalSep() ); |
5378 | 0 | break; |
5379 | 0 | } |
5380 | 0 | } |
5381 | | |
5382 | 0 | const OUString& rColorName = NumFor[n].GetColorName(); |
5383 | 0 | if ( !rColorName.isEmpty() ) |
5384 | 0 | { |
5385 | 0 | const NfKeywordTable & rKey = rScan.GetKeywords(); |
5386 | 0 | for ( int j = NF_KEY_FIRSTCOLOR; j <= NF_KEY_LASTCOLOR; j++ ) |
5387 | 0 | { |
5388 | 0 | if ( rKey[j] == rColorName ) |
5389 | 0 | { |
5390 | 0 | aPrefix += "[" + rKeywords[j] + "]"; |
5391 | 0 | break; // for |
5392 | 0 | } |
5393 | 0 | } |
5394 | 0 | } |
5395 | |
|
5396 | 0 | SvNumberNatNum aNatNum = NumFor[n].GetNatNum(); |
5397 | 0 | bool bDBNumInserted = false; |
5398 | 0 | if (aNatNum.IsComplete() && (aNatNum.GetDBNum() > 0 || nOriginalLang != LANGUAGE_DONTKNOW)) |
5399 | 0 | { // GetFormatStringForExcel() may have changed language to en_US |
5400 | 0 | if (aNatNum.GetLang() == LANGUAGE_ENGLISH_US && nOriginalLang != LANGUAGE_DONTKNOW) |
5401 | 0 | aNatNum.SetLang( nOriginalLang ); |
5402 | 0 | if ( aNatNum.GetDBNum() > 0 ) |
5403 | 0 | { |
5404 | 0 | aPrefix += "[DBNum" + OUString::number( aNatNum.GetDBNum() ) + "]"; |
5405 | 0 | bDBNumInserted = true; |
5406 | 0 | } |
5407 | 0 | } |
5408 | |
|
5409 | 0 | sal_uInt16 nCnt = NumFor[n].GetCount(); |
5410 | 0 | if ( nSem && (nCnt || !aPrefix.isEmpty()) ) |
5411 | 0 | { |
5412 | 0 | for ( ; nSem; --nSem ) |
5413 | 0 | { |
5414 | 0 | aStr.append( ';' ); |
5415 | 0 | } |
5416 | 0 | for ( ; nSub <= n; ++nSub ) |
5417 | 0 | { |
5418 | 0 | bDefault[nSub] = false; |
5419 | 0 | } |
5420 | 0 | } |
5421 | |
|
5422 | 0 | if ( !aPrefix.isEmpty() ) |
5423 | 0 | { |
5424 | 0 | aStr.append( aPrefix ); |
5425 | 0 | } |
5426 | 0 | sal_Int32 nPosHaveLCID = -1; |
5427 | 0 | sal_Int32 nPosInsertLCID = aStr.getLength(); |
5428 | 0 | sal_uInt32 nCalendarID = 0x0000000; // Excel ID of calendar used in sub-format see tdf#36038 |
5429 | 0 | constexpr sal_uInt32 kCalGengou = 0x0030000; |
5430 | 0 | if ( nCnt ) |
5431 | 0 | { |
5432 | 0 | auto& rTypeArray = NumFor[n].Info().nTypeArray; |
5433 | 0 | auto& rStrArray = NumFor[n].Info().sStrArray; |
5434 | 0 | for ( sal_uInt16 j=0; j<nCnt; j++ ) |
5435 | 0 | { |
5436 | 0 | if ( 0 <= rTypeArray[j] && rTypeArray[j] < NF_KEYWORD_ENTRIES_COUNT ) |
5437 | 0 | { |
5438 | 0 | aStr.append( rKeywords[rTypeArray[j]] ); |
5439 | 0 | if( NF_KEY_NNNN == rTypeArray[j] ) |
5440 | 0 | { |
5441 | 0 | aStr.append( rLocWrp.getLongDateDayOfWeekSep() ); |
5442 | 0 | } |
5443 | 0 | switch (rTypeArray[j]) |
5444 | 0 | { |
5445 | 0 | case NF_KEY_EC: |
5446 | 0 | case NF_KEY_EEC: |
5447 | 0 | case NF_KEY_R: |
5448 | 0 | case NF_KEY_RR: |
5449 | | // Implicit secondary (non-gregorian) calendar. |
5450 | | // Currently only for ja-JP. |
5451 | | /* TODO: same for all locales in |
5452 | | * LocaleDataWrapper::doesSecondaryCalendarUseEC() ? |
5453 | | * Should split the locales off that then. */ |
5454 | 0 | if (!nCalendarID) |
5455 | 0 | { |
5456 | 0 | const LanguageType nLang = MsLangId::getRealLanguage( nOriginalLang); |
5457 | 0 | if (nLang == LANGUAGE_JAPANESE) |
5458 | 0 | nCalendarID = kCalGengou; |
5459 | 0 | } |
5460 | 0 | break; |
5461 | 0 | default: |
5462 | 0 | ; // nothing |
5463 | 0 | } |
5464 | 0 | } |
5465 | 0 | else |
5466 | 0 | { |
5467 | 0 | switch ( rTypeArray[j] ) |
5468 | 0 | { |
5469 | 0 | case NF_SYMBOLTYPE_DECSEP : |
5470 | 0 | aStr.append( rLocWrp.getNumDecimalSep() ); |
5471 | 0 | break; |
5472 | 0 | case NF_SYMBOLTYPE_THSEP : |
5473 | 0 | aStr.append( rLocWrp.getNumThousandSep() ); |
5474 | 0 | break; |
5475 | 0 | case NF_SYMBOLTYPE_EXP : |
5476 | 0 | aStr.append( rKeywords[NF_KEY_E] ); |
5477 | 0 | if ( rStrArray[j].getLength() > 1 && rStrArray[j][1] == '+' ) |
5478 | 0 | aStr.append( "+" ); |
5479 | 0 | else |
5480 | | // tdf#102370: Excel code for exponent without sign |
5481 | 0 | aStr.append( "-" ); |
5482 | 0 | break; |
5483 | 0 | case NF_SYMBOLTYPE_DATESEP : |
5484 | 0 | aStr.append( rLocWrp.getDateSep() ); |
5485 | 0 | break; |
5486 | 0 | case NF_SYMBOLTYPE_TIMESEP : |
5487 | 0 | aStr.append( rLocWrp.getTimeSep() ); |
5488 | 0 | break; |
5489 | 0 | case NF_SYMBOLTYPE_TIME100SECSEP : |
5490 | 0 | aStr.append( rLocWrp.getTime100SecSep() ); |
5491 | 0 | break; |
5492 | 0 | case NF_SYMBOLTYPE_FRACBLANK : |
5493 | 0 | case NF_SYMBOLTYPE_STRING : |
5494 | 0 | if ( rStrArray[j].getLength() == 1 ) |
5495 | 0 | { |
5496 | 0 | if ( rTypeArray[j] == NF_SYMBOLTYPE_STRING ) |
5497 | 0 | aStr.append( '\\' ); |
5498 | 0 | aStr.append( rStrArray[j] ); |
5499 | 0 | } |
5500 | 0 | else |
5501 | 0 | { |
5502 | 0 | aStr.append( "\"" + rStrArray[j] + "\"" ); |
5503 | 0 | } |
5504 | 0 | break; |
5505 | 0 | case NF_SYMBOLTYPE_CALDEL : |
5506 | 0 | if (j + 1 >= nCnt) |
5507 | 0 | break; |
5508 | 0 | if ( rStrArray[j+1] == "gengou" ) |
5509 | 0 | { |
5510 | 0 | nCalendarID = kCalGengou; |
5511 | 0 | } |
5512 | 0 | else if ( rStrArray[j+1] == "hijri" ) |
5513 | 0 | { |
5514 | 0 | nCalendarID = 0x0060000; |
5515 | 0 | } |
5516 | 0 | else if ( rStrArray[j+1] == "buddhist" ) |
5517 | 0 | { |
5518 | 0 | nCalendarID = 0x0070000; |
5519 | 0 | } |
5520 | 0 | else if ( rStrArray[j+1] == "jewish" ) |
5521 | 0 | { |
5522 | 0 | nCalendarID = 0x0080000; |
5523 | 0 | } |
5524 | | // Other calendars (see tdf#36038) not corresponding between LibO and XL. |
5525 | | // However, skip any calendar modifier and don't write |
5526 | | // as format code (if not as literal string). |
5527 | 0 | j += 2; |
5528 | 0 | break; |
5529 | 0 | case NF_SYMBOLTYPE_CURREXT : |
5530 | 0 | nPosHaveLCID = aStr.getLength(); |
5531 | 0 | aStr.append( rStrArray[j] ); |
5532 | 0 | break; |
5533 | 0 | default: |
5534 | 0 | aStr.append( rStrArray[j] ); |
5535 | 0 | } |
5536 | 0 | } |
5537 | 0 | } |
5538 | 0 | } |
5539 | 0 | sal_uInt32 nAlphabetID = 0x0000000; // Excel ID of alphabet used for numerals see tdf#36038 |
5540 | 0 | LanguageType nLanguageID = LANGUAGE_SYSTEM; |
5541 | 0 | if ( aNatNum.IsComplete() ) |
5542 | 0 | { |
5543 | 0 | nLanguageID = MsLangId::getRealLanguage( aNatNum.GetLang()); |
5544 | 0 | if ( aNatNum.GetNatNum() == 0 ) |
5545 | 0 | { |
5546 | 0 | nAlphabetID = 0x01000000; // Arabic-european numerals |
5547 | 0 | } |
5548 | 0 | else if ( nCalendarID > 0 || aNatNum.GetDBNum() == 0 || aNatNum.GetDBNum() == aNatNum.GetNatNum() ) |
5549 | 0 | { // if no DBNum code then use long LCID |
5550 | | // if DBNum value != NatNum value, use DBNum and not extended LCID |
5551 | | // if calendar, then DBNum will be removed |
5552 | 0 | LanguageType pri = primary(nLanguageID); |
5553 | 0 | if ( pri == LANGUAGE_ARABIC_PRIMARY_ONLY ) |
5554 | 0 | nAlphabetID = 0x02000000; // Arabic-indic numerals |
5555 | 0 | else if ( pri == primary(LANGUAGE_FARSI) ) |
5556 | 0 | nAlphabetID = 0x03000000; // Farsi numerals |
5557 | 0 | else if ( pri.anyOf( |
5558 | 0 | primary(LANGUAGE_HINDI), |
5559 | 0 | primary(LANGUAGE_MARATHI), |
5560 | 0 | primary(LANGUAGE_NEPALI) )) |
5561 | 0 | nAlphabetID = 0x04000000; // Devanagari numerals |
5562 | 0 | else if ( pri == primary(LANGUAGE_BENGALI) ) |
5563 | 0 | nAlphabetID = 0x05000000; // Bengali numerals |
5564 | 0 | else if ( pri == primary(LANGUAGE_PUNJABI) ) |
5565 | 0 | { |
5566 | 0 | if ( nLanguageID == LANGUAGE_PUNJABI_ARABIC_LSO ) |
5567 | 0 | nAlphabetID = 0x02000000; // Arabic-indic numerals |
5568 | 0 | else |
5569 | 0 | nAlphabetID = 0x06000000; // Punjabi numerals |
5570 | 0 | } |
5571 | 0 | else if ( pri == primary(LANGUAGE_GUJARATI) ) |
5572 | 0 | nAlphabetID = 0x07000000; // Gujarati numerals |
5573 | 0 | else if ( pri == primary(LANGUAGE_ODIA)) |
5574 | 0 | nAlphabetID = 0x08000000; // Odia (Oriya) numerals |
5575 | 0 | else if ( pri == primary(LANGUAGE_TAMIL)) |
5576 | 0 | nAlphabetID = 0x09000000; // Tamil numerals |
5577 | 0 | else if ( pri == primary(LANGUAGE_TELUGU)) |
5578 | 0 | nAlphabetID = 0x0A000000; // Telugu numerals |
5579 | 0 | else if ( pri == primary(LANGUAGE_KANNADA)) |
5580 | 0 | nAlphabetID = 0x0B000000; // Kannada numerals |
5581 | 0 | else if ( pri == primary(LANGUAGE_MALAYALAM)) |
5582 | 0 | nAlphabetID = 0x0C000000; // Malayalam numerals |
5583 | 0 | else if ( pri == primary(LANGUAGE_THAI)) |
5584 | 0 | { |
5585 | | // The Thai T NatNum modifier during Xcl export. |
5586 | 0 | if ( rKeywords[NF_KEY_THAI_T] == "T" ) |
5587 | 0 | nAlphabetID = 0x0D000000; // Thai numerals |
5588 | 0 | } |
5589 | 0 | else if ( pri == primary(LANGUAGE_LAO)) |
5590 | 0 | nAlphabetID = 0x0E000000; // Lao numerals |
5591 | 0 | else if ( pri == primary(LANGUAGE_TIBETAN)) |
5592 | 0 | nAlphabetID = 0x0F000000; // Tibetan numerals |
5593 | 0 | else if ( pri == primary(LANGUAGE_BURMESE)) |
5594 | 0 | nAlphabetID = 0x10000000; // Burmese numerals |
5595 | 0 | else if ( pri == primary(LANGUAGE_TIGRIGNA_ETHIOPIA)) |
5596 | 0 | nAlphabetID = 0x11000000; // Tigrigna numerals |
5597 | 0 | else if ( pri == primary(LANGUAGE_KHMER)) |
5598 | 0 | nAlphabetID = 0x12000000; // Khmer numerals |
5599 | 0 | else if ( pri == primary(LANGUAGE_MONGOLIAN_MONGOLIAN_MONGOLIA)) |
5600 | 0 | { |
5601 | 0 | if ( nLanguageID != LANGUAGE_MONGOLIAN_CYRILLIC_MONGOLIA |
5602 | 0 | && nLanguageID != LANGUAGE_MONGOLIAN_CYRILLIC_LSO ) |
5603 | 0 | nAlphabetID = 0x13000000; // Mongolian numerals |
5604 | 0 | } |
5605 | | // CJK numerals |
5606 | 0 | else if ( pri == primary(LANGUAGE_JAPANESE)) |
5607 | 0 | { |
5608 | 0 | nAlphabetID = 0x1B; |
5609 | 0 | lcl_incrementAlphabetWithNatNum ( nAlphabetID, aNatNum.GetNatNum() ); |
5610 | 0 | } |
5611 | 0 | else if ( pri == primary(LANGUAGE_CHINESE)) |
5612 | 0 | { |
5613 | 0 | if ( nLanguageID == LANGUAGE_CHINESE_TRADITIONAL |
5614 | 0 | || nLanguageID == LANGUAGE_CHINESE_HONGKONG |
5615 | 0 | || nLanguageID == LANGUAGE_CHINESE_MACAU ) |
5616 | 0 | { |
5617 | 0 | nAlphabetID = 0x21; |
5618 | 0 | lcl_incrementAlphabetWithNatNum ( nAlphabetID, aNatNum.GetNatNum() ); |
5619 | 0 | } |
5620 | 0 | else // LANGUAGE_CHINESE_SIMPLIFIED |
5621 | 0 | { |
5622 | 0 | nAlphabetID = 0x1E; |
5623 | 0 | lcl_incrementAlphabetWithNatNum ( nAlphabetID, aNatNum.GetNatNum() ); |
5624 | 0 | } |
5625 | 0 | } |
5626 | 0 | else if ( pri == primary(LANGUAGE_KOREAN)) |
5627 | 0 | { |
5628 | 0 | if ( aNatNum.GetNatNum() == 9 ) // Hangul |
5629 | 0 | { |
5630 | 0 | nAlphabetID = 0x27000000; |
5631 | 0 | } |
5632 | 0 | else |
5633 | 0 | { |
5634 | 0 | nAlphabetID = 0x24; |
5635 | 0 | lcl_incrementAlphabetWithNatNum ( nAlphabetID, aNatNum.GetNatNum() ); |
5636 | 0 | } |
5637 | 0 | } |
5638 | 0 | } |
5639 | | // Add LCID to DBNum |
5640 | 0 | if ( aNatNum.GetDBNum() > 0 && nLanguageID == LANGUAGE_SYSTEM ) |
5641 | 0 | nLanguageID = MsLangId::getRealLanguage( aNatNum.GetLang()); |
5642 | 0 | } |
5643 | 0 | else if (nPosHaveLCID < 0) |
5644 | 0 | { |
5645 | | // Do not insert a duplicated LCID that was already given with a |
5646 | | // currency format as [$R-1C09] |
5647 | 0 | if (!bSystemLanguage && nOriginalLang != LANGUAGE_DONTKNOW) |
5648 | 0 | { |
5649 | | // Explicit locale, write only to the first subformat. |
5650 | 0 | if (n == 0) |
5651 | 0 | nLanguageID = MsLangId::getRealLanguage( nOriginalLang); |
5652 | 0 | } |
5653 | 0 | else if (bSystemLanguage && maLocale.meLanguageWithoutLocaleData != LANGUAGE_DONTKNOW) |
5654 | 0 | { |
5655 | | // Explicit locale but no locale data thus assigned to system |
5656 | | // locale, preserve for roundtrip, write only to the first |
5657 | | // subformat. |
5658 | 0 | if (n == 0) |
5659 | 0 | nLanguageID = maLocale.meLanguageWithoutLocaleData; |
5660 | 0 | } |
5661 | 0 | } |
5662 | 0 | if ( nCalendarID > 0 ) |
5663 | 0 | { // Add alphabet and language to calendar |
5664 | 0 | if ( nAlphabetID == 0 ) |
5665 | 0 | nAlphabetID = 0x01000000; |
5666 | 0 | if ( nLanguageID == LANGUAGE_SYSTEM && nOriginalLang != LANGUAGE_DONTKNOW ) |
5667 | 0 | nLanguageID = nOriginalLang; |
5668 | 0 | } |
5669 | 0 | lcl_insertLCID( aStr, nAlphabetID + nCalendarID + static_cast<sal_uInt16>(nLanguageID), nPosInsertLCID, |
5670 | 0 | bDBNumInserted); |
5671 | 0 | } |
5672 | 0 | for ( ; nSub<4 && bDefault[nSub]; ++nSub ) |
5673 | 0 | { // append empty subformats |
5674 | 0 | aStr.append( ';' ); |
5675 | 0 | } |
5676 | 0 | return aStr.makeStringAndClear(); |
5677 | 0 | } |
5678 | | |
5679 | | // static |
5680 | | OUString SvNumberformat::ImpGetNatNumString(const SvNumberNatNum& rNum, |
5681 | | sal_Int64 nVal, sal_uInt16 nMinDigits, |
5682 | | const NativeNumberWrapper& rNatNum) |
5683 | 20.1k | { |
5684 | 20.1k | OUString aStr; |
5685 | 20.1k | if ( nMinDigits ) |
5686 | 20.0k | { |
5687 | 20.0k | if ( nMinDigits == 2 ) |
5688 | 20.0k | { |
5689 | | // speed up the most common case |
5690 | 20.0k | if ( 0 <= nVal && nVal < 10 ) |
5691 | 10.1k | { |
5692 | 10.1k | sal_Unicode aBuf[2]; |
5693 | 10.1k | aBuf[0] = '0'; |
5694 | 10.1k | aBuf[1] = '0' + nVal; |
5695 | 10.1k | aStr = OUString(aBuf, SAL_N_ELEMENTS(aBuf)); |
5696 | 10.1k | } |
5697 | 9.92k | else |
5698 | 9.92k | { |
5699 | 9.92k | aStr = OUString::number( nVal ); |
5700 | 9.92k | } |
5701 | 20.0k | } |
5702 | 0 | else |
5703 | 0 | { |
5704 | 0 | OUString aValStr( OUString::number( nVal ) ); |
5705 | 0 | if ( aValStr.getLength() >= nMinDigits ) |
5706 | 0 | { |
5707 | 0 | aStr = aValStr; |
5708 | 0 | } |
5709 | 0 | else |
5710 | 0 | { |
5711 | 0 | OUStringBuffer aBuf; |
5712 | 0 | for(sal_Int32 index = 0; index < nMinDigits - aValStr.getLength(); ++index) |
5713 | 0 | { |
5714 | 0 | aBuf.append('0'); |
5715 | 0 | } |
5716 | 0 | aBuf.append(aValStr); |
5717 | 0 | aStr = aBuf.makeStringAndClear(); |
5718 | 0 | } |
5719 | 0 | } |
5720 | 20.0k | } |
5721 | 111 | else |
5722 | 111 | { |
5723 | 111 | aStr = OUString::number( nVal ); |
5724 | 111 | } |
5725 | 20.1k | return ::impTransliterate(aStr, rNum, rNatNum); |
5726 | 20.1k | } |
5727 | | |
5728 | | OUString SvNumberformat::impTransliterateImpl(const OUString& rStr, |
5729 | | const SvNumberNatNum& rNum, |
5730 | | const sal_uInt16 nDateKey, |
5731 | | const NativeNumberWrapper& rNatNum) const |
5732 | 0 | { |
5733 | | // no KEYWORD=argument list in NatNum12 |
5734 | 0 | if (rNum.GetParams().indexOf('=') == -1) |
5735 | 0 | return ::impTransliterateImpl( rStr, rNum, rNatNum); |
5736 | | |
5737 | 0 | const NfKeywordTable & rKeywords = rScan.GetKeywords(); |
5738 | | |
5739 | | // Format: KEYWORD=numbertext_prefix, ..., for example: |
5740 | | // [NatNum12 YYYY=title ordinal,MMMM=article, D=ordinal-number] |
5741 | 0 | sal_Int32 nField = -1; |
5742 | 0 | do |
5743 | 0 | { |
5744 | 0 | nField = rNum.GetParams().indexOf(Concat2View(rKeywords[nDateKey] + "="), ++nField); |
5745 | 0 | } |
5746 | 0 | while (nField != -1 && nField != 0 && |
5747 | 0 | (rNum.GetParams()[nField - 1] != ',' && |
5748 | 0 | rNum.GetParams()[nField - 1] != ' ')); |
5749 | | |
5750 | | // no format specified for actual keyword |
5751 | 0 | if (nField == -1) |
5752 | 0 | return rStr; |
5753 | | |
5754 | 0 | sal_Int32 nKeywordLen = rKeywords[nDateKey].getLength() + 1; |
5755 | 0 | sal_Int32 nFieldEnd = rNum.GetParams().indexOf(',', nField); |
5756 | |
|
5757 | 0 | if (nFieldEnd == -1) |
5758 | 0 | nFieldEnd = rNum.GetParams().getLength(); |
5759 | |
|
5760 | 0 | css::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() ); |
5761 | |
|
5762 | 0 | return rNatNum.getNativeNumberStringParams( |
5763 | 0 | rStr, aLocale, rNum.GetNatNum(), |
5764 | 0 | rNum.GetParams().copy(nField + nKeywordLen, nFieldEnd - nField - nKeywordLen)); |
5765 | 0 | } |
5766 | | |
5767 | | void SvNumberformat::GetNatNumXml( css::i18n::NativeNumberXmlAttributes2& rAttr, |
5768 | | sal_uInt16 nNumFor, const NativeNumberWrapper& rNatNum ) const |
5769 | 0 | { |
5770 | 0 | if ( nNumFor <= 3 ) |
5771 | 0 | { |
5772 | 0 | const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum(); |
5773 | 0 | if ( rNum.IsSet() ) |
5774 | 0 | { |
5775 | 0 | css::lang::Locale aLocale( |
5776 | 0 | LanguageTag( rNum.GetLang() ).getLocale() ); |
5777 | | |
5778 | | /* TODO: a new XNativeNumberSupplier2::convertToXmlAttributes() |
5779 | | * should rather return NativeNumberXmlAttributes2 and places |
5780 | | * adapted, and whether to fill Spellout or something different |
5781 | | * should be internal there. */ |
5782 | 0 | css::i18n::NativeNumberXmlAttributes aTmp( |
5783 | 0 | rNatNum.convertToXmlAttributes( |
5784 | 0 | aLocale, rNum.GetNatNum())); |
5785 | 0 | rAttr.Locale = aTmp.Locale; |
5786 | 0 | rAttr.Format = aTmp.Format; |
5787 | 0 | rAttr.Style = aTmp.Style; |
5788 | 0 | if ( NatNumTakesParameters(rNum.GetNatNum()) ) |
5789 | 0 | { |
5790 | | // NatNum12 spell out numbers, dates and money amounts |
5791 | 0 | rAttr.Spellout = rNum.GetParams(); |
5792 | | // Mutually exclusive. |
5793 | 0 | rAttr.Format.clear(); |
5794 | 0 | rAttr.Style.clear(); |
5795 | 0 | } |
5796 | 0 | else |
5797 | 0 | { |
5798 | 0 | rAttr.Spellout.clear(); |
5799 | 0 | } |
5800 | 0 | } |
5801 | 0 | else |
5802 | 0 | { |
5803 | 0 | rAttr = css::i18n::NativeNumberXmlAttributes2(); |
5804 | 0 | } |
5805 | 0 | } |
5806 | 0 | else |
5807 | 0 | { |
5808 | 0 | rAttr = css::i18n::NativeNumberXmlAttributes2(); |
5809 | 0 | } |
5810 | 0 | } |
5811 | | |
5812 | | OUString SvNumberformat::GetNatNumModifierString( sal_uInt16 nNumFor ) const |
5813 | 62.7k | { |
5814 | 62.7k | if ( nNumFor > 3 ) |
5815 | 0 | return u""_ustr; |
5816 | 62.7k | const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum(); |
5817 | 62.7k | if ( !rNum.IsSet() ) |
5818 | 62.7k | return u""_ustr; |
5819 | 0 | const sal_Int32 nNum = rNum.GetNatNum(); |
5820 | 0 | OUStringBuffer sNatNumModifier = "[NatNum" + OUString::number( nNum ); |
5821 | 0 | if ( NatNumTakesParameters( nNum ) ) |
5822 | 0 | { |
5823 | 0 | sNatNumModifier.append( " " + rNum.GetParams() ); |
5824 | 0 | } |
5825 | 0 | sNatNumModifier.append( "]" ); |
5826 | |
|
5827 | 0 | return sNatNumModifier.makeStringAndClear(); |
5828 | 62.7k | } |
5829 | | |
5830 | | // static |
5831 | | bool SvNumberformat::HasStringNegativeSign( const OUString& rStr ) |
5832 | 10.1k | { |
5833 | | // For Sign '-' needs to be at the start or at the end of the string (blanks ignored) |
5834 | 10.1k | sal_Int32 nLen = rStr.getLength(); |
5835 | 10.1k | if ( !nLen ) |
5836 | 0 | { |
5837 | 0 | return false; |
5838 | 0 | } |
5839 | 10.1k | const sal_Unicode* const pBeg = rStr.getStr(); |
5840 | 10.1k | const sal_Unicode* const pEnd = pBeg + nLen; |
5841 | 10.1k | const sal_Unicode* p = pBeg; |
5842 | 10.1k | do |
5843 | 10.4k | { // Start |
5844 | 10.4k | if ( *p == '-' ) |
5845 | 2.85k | { |
5846 | 2.85k | return true; |
5847 | 2.85k | } |
5848 | 10.4k | } |
5849 | 10.1k | while ( *p == ' ' && ++p < pEnd ); |
5850 | | |
5851 | 7.30k | p = pEnd - 1; |
5852 | | |
5853 | 7.30k | do |
5854 | 7.94k | { // End |
5855 | 7.94k | if ( *p == '-' ) |
5856 | 348 | { |
5857 | 348 | return true; |
5858 | 348 | } |
5859 | 7.94k | } |
5860 | 7.59k | while ( *p == ' ' && pBeg < --p ); |
5861 | 6.95k | return false; |
5862 | 7.30k | } |
5863 | | |
5864 | | // static |
5865 | | bool SvNumberformat::IsInQuote( const OUString& rStr, sal_Int32 nPos, |
5866 | | sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) |
5867 | 14.7M | { |
5868 | 14.7M | sal_Int32 nLen = rStr.getLength(); |
5869 | 14.7M | if ( nPos >= nLen ) |
5870 | 0 | { |
5871 | 0 | return false; |
5872 | 0 | } |
5873 | 14.7M | const sal_Unicode* p0 = rStr.getStr(); |
5874 | 14.7M | const sal_Unicode* p = p0; |
5875 | 14.7M | const sal_Unicode* p1 = p0 + nPos; |
5876 | 14.7M | bool bQuoted = false; |
5877 | 145M | while ( p <= p1 ) |
5878 | 130M | { |
5879 | 130M | if ( *p == cQuote ) |
5880 | 96.4k | { |
5881 | 96.4k | if ( p == p0 ) |
5882 | 3.36k | { |
5883 | 3.36k | bQuoted = true; |
5884 | 3.36k | } |
5885 | 93.0k | else if ( bQuoted ) |
5886 | 42.7k | { |
5887 | 42.7k | if ( *(p-1) != cEscIn ) |
5888 | 42.7k | { |
5889 | 42.7k | bQuoted = false; |
5890 | 42.7k | } |
5891 | 42.7k | } |
5892 | 50.2k | else |
5893 | 50.2k | { |
5894 | 50.2k | if ( *(p-1) != cEscOut ) |
5895 | 48.4k | { |
5896 | 48.4k | bQuoted = true; |
5897 | 48.4k | } |
5898 | 50.2k | } |
5899 | 96.4k | } |
5900 | 130M | p++; |
5901 | 130M | } |
5902 | 14.7M | return bQuoted; |
5903 | 14.7M | } |
5904 | | |
5905 | | // static |
5906 | | sal_Int32 SvNumberformat::GetQuoteEnd( const OUString& rStr, sal_Int32 nPos, |
5907 | | sal_Unicode cQuote, sal_Unicode cEscIn ) |
5908 | 14.7M | { |
5909 | 14.7M | if ( nPos < 0 ) |
5910 | 0 | { |
5911 | 0 | return -1; |
5912 | 0 | } |
5913 | 14.7M | sal_Int32 nLen = rStr.getLength(); |
5914 | 14.7M | if ( nPos >= nLen ) |
5915 | 0 | { |
5916 | 0 | return -1; |
5917 | 0 | } |
5918 | 14.7M | if ( !IsInQuote( rStr, nPos, cQuote, cEscIn ) ) |
5919 | 14.7M | { |
5920 | 14.7M | if ( rStr[ nPos ] == cQuote ) |
5921 | 0 | { |
5922 | 0 | return nPos; // Closing cQuote |
5923 | 0 | } |
5924 | 14.7M | return -1; |
5925 | 14.7M | } |
5926 | 9.01k | const sal_Unicode* p0 = rStr.getStr(); |
5927 | 9.01k | const sal_Unicode* p = p0 + nPos; |
5928 | 9.01k | const sal_Unicode* p1 = p0 + nLen; |
5929 | 30.9k | while ( p < p1 ) |
5930 | 30.3k | { |
5931 | 30.3k | if ( *p == cQuote && p > p0 && *(p-1) != cEscIn ) |
5932 | 8.40k | { |
5933 | 8.40k | return sal::static_int_cast< sal_Int32 >(p - p0); |
5934 | 8.40k | } |
5935 | 21.9k | p++; |
5936 | 21.9k | } |
5937 | 610 | return nLen; // End of String |
5938 | 9.01k | } |
5939 | | |
5940 | | sal_uInt16 SvNumberformat::GetNumForNumberElementCount( sal_uInt16 nNumFor ) const |
5941 | 0 | { |
5942 | 0 | if ( nNumFor < 4 ) |
5943 | 0 | { |
5944 | 0 | sal_uInt16 nCnt = NumFor[nNumFor].GetCount(); |
5945 | 0 | return nCnt - ImpGetNumForStringElementCount( nNumFor ); |
5946 | 0 | } |
5947 | 0 | return 0; |
5948 | 0 | } |
5949 | | |
5950 | | sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const |
5951 | 16.6k | { |
5952 | 16.6k | sal_uInt16 nCnt = 0; |
5953 | 16.6k | sal_uInt16 nNumForCnt = NumFor[nNumFor].GetCount(); |
5954 | 16.6k | auto& rTypeArray = NumFor[nNumFor].Info().nTypeArray; |
5955 | 112k | for ( sal_uInt16 j=0; j<nNumForCnt; ++j ) |
5956 | 95.7k | { |
5957 | 95.7k | switch ( rTypeArray[j] ) |
5958 | 95.7k | { |
5959 | 22.5k | case NF_SYMBOLTYPE_STRING: |
5960 | 23.1k | case NF_SYMBOLTYPE_CURRENCY: |
5961 | 23.9k | case NF_SYMBOLTYPE_DATESEP: |
5962 | 24.3k | case NF_SYMBOLTYPE_TIMESEP: |
5963 | 25.2k | case NF_SYMBOLTYPE_TIME100SECSEP: |
5964 | 25.6k | case NF_SYMBOLTYPE_PERCENT: |
5965 | 25.6k | ++nCnt; |
5966 | 25.6k | break; |
5967 | 95.7k | } |
5968 | 95.7k | } |
5969 | 16.6k | return nCnt; |
5970 | 16.6k | } |
5971 | | |
5972 | | bool SvNumberformat::IsMinuteSecondFormat() const |
5973 | 7.82k | { |
5974 | 7.82k | if (GetMaskedType() != SvNumFormatType::TIME) |
5975 | 2.78k | return false; |
5976 | | |
5977 | 5.03k | constexpr sal_uInt16 k00 = 0x00; // Nada, Nilch |
5978 | 5.03k | constexpr sal_uInt16 kLB = 0x01; // '[' Left Bracket |
5979 | 5.03k | constexpr sal_uInt16 kRB = 0x02; // ']' Right Bracket |
5980 | 5.03k | constexpr sal_uInt16 kMM = 0x04; // M or MM |
5981 | 5.03k | constexpr sal_uInt16 kTS = 0x08; // Time Separator |
5982 | 5.03k | constexpr sal_uInt16 kSS = 0x10; // S or SS |
5983 | 5.03k | #define HAS_MINUTE_SECOND(state) ((state) == (kMM|kTS|kSS) || (state) == (kLB|kMM|kRB|kTS|kSS)) |
5984 | | // Also (kMM|kTS|kLB|kSS|kRB) but those are the same bits. |
5985 | | |
5986 | 5.03k | sal_uInt16 nState = k00; |
5987 | 5.03k | bool bSep = false; |
5988 | 5.03k | sal_uInt16 nNumForCnt = NumFor[0].GetCount(); |
5989 | 5.03k | auto const & rTypeArray = NumFor[0].Info().nTypeArray; |
5990 | 22.1k | for (sal_uInt16 j=0; j < nNumForCnt; ++j) |
5991 | 20.0k | { |
5992 | 20.0k | switch (rTypeArray[j]) |
5993 | 20.0k | { |
5994 | 2.66k | case NF_SYMBOLTYPE_DEL: |
5995 | 2.66k | { |
5996 | | // '[' or ']' before/after MM or SS |
5997 | 2.66k | const OUString& rStr = NumFor[0].Info().sStrArray[j]; |
5998 | 2.66k | if (rStr == "[") |
5999 | 1.57k | { |
6000 | 1.57k | if (nState != k00 && nState != (kMM|kTS)) |
6001 | 204 | return false; |
6002 | 1.36k | nState |= kLB; |
6003 | 1.36k | } |
6004 | 1.09k | else if (rStr == "]") |
6005 | 862 | { |
6006 | 862 | if (nState != (kLB|kMM) && nState != (kMM|kTS|kLB|kSS)) |
6007 | 307 | return false; |
6008 | 555 | nState |= kRB; |
6009 | 555 | } |
6010 | 232 | else |
6011 | 232 | return false; |
6012 | 2.66k | } |
6013 | 1.92k | break; |
6014 | 1.96k | case NF_KEY_MI: |
6015 | 3.92k | case NF_KEY_MMI: |
6016 | 3.92k | if (nState != k00 && nState != kLB) |
6017 | 327 | return false; |
6018 | 3.59k | nState |= kMM; |
6019 | 3.59k | break; |
6020 | 2.70k | case NF_SYMBOLTYPE_TIMESEP: |
6021 | 2.70k | if (nState != kMM && nState != (kLB|kMM|kRB)) |
6022 | 247 | return false; |
6023 | 2.45k | nState |= kTS; |
6024 | 2.45k | break; |
6025 | 1.86k | case NF_KEY_S: |
6026 | 2.67k | case NF_KEY_SS: |
6027 | 2.67k | if (nState != (kMM|kTS) && nState != (kLB|kMM|kRB|kTS) && nState != (kMM|kTS|kLB)) |
6028 | 433 | return false; |
6029 | 2.23k | nState |= kSS; |
6030 | 2.23k | break; |
6031 | 1.03k | case NF_SYMBOLTYPE_TIME100SECSEP: |
6032 | | // Trailing fraction of seconds allowed. |
6033 | 1.03k | if (!HAS_MINUTE_SECOND(nState)) |
6034 | 229 | return false; |
6035 | 805 | bSep = true; |
6036 | 805 | break; |
6037 | 838 | case NF_SYMBOLTYPE_DIGIT: |
6038 | 838 | if (!bSep) |
6039 | 210 | return false; |
6040 | 628 | break; |
6041 | 5.45k | case NF_SYMBOLTYPE_STRING: |
6042 | | // nothing, display literal |
6043 | 5.45k | break; |
6044 | 757 | default: |
6045 | 757 | return false; |
6046 | 20.0k | } |
6047 | 20.0k | } |
6048 | 2.08k | return HAS_MINUTE_SECOND(nState); |
6049 | 5.03k | #undef HAS_MINUTE_SECOND |
6050 | 5.03k | } |
6051 | | |
6052 | | OUString SvNumberformat::GetFormatStringForTimePrecision( int nPrecision ) const |
6053 | 0 | { |
6054 | 0 | OUStringBuffer sString; |
6055 | |
|
6056 | 0 | sal_uInt16 nNumForCnt = NumFor[0].GetCount(); |
6057 | 0 | auto const & rTypeArray = NumFor[0].Info().nTypeArray; |
6058 | 0 | for (sal_uInt16 j=0; j < nNumForCnt; ++j) |
6059 | 0 | { |
6060 | 0 | switch (rTypeArray[j]) |
6061 | 0 | { |
6062 | 0 | case NF_KEY_S : |
6063 | 0 | case NF_KEY_SS: |
6064 | 0 | sString.append( NumFor[0].Info().sStrArray[j] ); |
6065 | 0 | if ( j > 0 && rTypeArray[j-1] == NF_SYMBOLTYPE_DEL && j < nNumForCnt-1 ) |
6066 | 0 | { |
6067 | 0 | j++; |
6068 | 0 | sString.append( NumFor[0].Info().sStrArray[j] ); |
6069 | 0 | } |
6070 | 0 | if (nPrecision > 0) |
6071 | 0 | { |
6072 | 0 | sString.append(rLoc().getTime100SecSep() + RepeatedUChar('0', nPrecision)); |
6073 | 0 | } |
6074 | 0 | break; |
6075 | 0 | case NF_SYMBOLTYPE_TIME100SECSEP: |
6076 | 0 | case NF_SYMBOLTYPE_DIGIT: |
6077 | 0 | break; |
6078 | 0 | case NF_SYMBOLTYPE_STRING: |
6079 | 0 | sString.append( "\"" ); |
6080 | 0 | [[fallthrough]]; |
6081 | 0 | default: |
6082 | 0 | sString.append( NumFor[0].Info().sStrArray[j] ); |
6083 | 0 | if (rTypeArray[j] == NF_SYMBOLTYPE_STRING) |
6084 | 0 | { |
6085 | 0 | sString.append( "\"" ); |
6086 | 0 | } |
6087 | 0 | } |
6088 | 0 | } |
6089 | | |
6090 | 0 | return sString.makeStringAndClear(); |
6091 | 0 | } |
6092 | | |
6093 | | sal_uInt16 SvNumberformat::GetThousandDivisorPrecision( sal_uInt16 nIx ) const |
6094 | 0 | { |
6095 | 0 | if (nIx >= 4) |
6096 | 0 | return 0; |
6097 | | |
6098 | 0 | const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); |
6099 | |
|
6100 | 0 | if (rInfo.eScannedType != SvNumFormatType::NUMBER && rInfo.eScannedType != SvNumFormatType::CURRENCY) |
6101 | 0 | return 0; |
6102 | | |
6103 | 0 | if (rInfo.nThousand == FLAG_STANDARD_IN_FORMAT) |
6104 | 0 | return SvNumberFormatter::UNLIMITED_PRECISION; |
6105 | | |
6106 | 0 | return rInfo.nThousand * 3; |
6107 | 0 | } |
6108 | | |
6109 | | const CharClass& SvNumberformat::rChrCls() const |
6110 | 2.82M | { |
6111 | 2.82M | return rScan.GetChrCls(); |
6112 | 2.82M | } |
6113 | | |
6114 | | const LocaleDataWrapper& SvNumberformat::rLoc() const |
6115 | 1.23M | { |
6116 | 1.23M | return rScan.GetLoc(); |
6117 | 1.23M | } |
6118 | | |
6119 | | const SvNFLanguageData& SvNumberformat::GetCurrentLanguageData() const |
6120 | 26.0M | { |
6121 | 26.0M | return rScan.GetCurrentLanguageData(); |
6122 | 26.0M | } |
6123 | | |
6124 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |