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 <tools/color.hxx>
21
22 #include <tools/debug.hxx>
23 #include <i18nlangtag/mslangid.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <svl/numformat.hxx>
26 #include <svl/zforlist.hxx>
27 #include <svl/zformat.hxx>
28 #include <svl/currencytable.hxx>
29
30 #include <svx/numfmtsh.hxx>
31 #include <svx/flagsdef.hxx>
32 #include <svx/tbcontrl.hxx>
33 #include <sfx2/IDocumentModelAccessor.hxx>
34
35 #include <limits>
36
37 namespace
38 {
GetDefaultValNum(const SvNumFormatType nType)39 double GetDefaultValNum(const SvNumFormatType nType)
40 {
41 switch (nType)
42 {
43 case SvNumFormatType::NUMBER:
44 return fSvxNumValConst[SvxNumValCategory::Standard];
45 case SvNumFormatType::CURRENCY:
46 return fSvxNumValConst[SvxNumValCategory::Currency];
47 case SvNumFormatType::PERCENT:
48 return fSvxNumValConst[SvxNumValCategory::Percent];
49 case SvNumFormatType::DATE:
50 case SvNumFormatType::DATETIME:
51 return fSvxNumValConst[SvxNumValCategory::Date];
52 case SvNumFormatType::TIME:
53 return fSvxNumValConst[SvxNumValCategory::Time];
54 case SvNumFormatType::SCIENTIFIC:
55 return fSvxNumValConst[SvxNumValCategory::Scientific];
56 case SvNumFormatType::FRACTION:
57 return fSvxNumValConst[SvxNumValCategory::Fraction];
58 case SvNumFormatType::LOGICAL:
59 return fSvxNumValConst[SvxNumValCategory::Boolean];
60 default:
61 break;
62 }
63 return fSvxNumValConst[SvxNumValCategory::NoValue];
64 }
65 }
66
Create(SvNumberFormatter * pNumFormatter,sal_uInt32 nFormatKey,SvxNumberValueType eNumValType,const OUString & rNumStr)67 SvxNumberFormatShell* SvxNumberFormatShell::Create(SvNumberFormatter* pNumFormatter,
68 sal_uInt32 nFormatKey,
69 SvxNumberValueType eNumValType,
70 const OUString& rNumStr)
71 {
72 return new SvxNumberFormatShell(pNumFormatter, nFormatKey, eNumValType, rNumStr);
73 }
74
Create(SvNumberFormatter * pNumFormatter,sal_uInt32 nFormatKey,SvxNumberValueType eNumValType,double nNumVal,const OUString * pNumStr)75 SvxNumberFormatShell* SvxNumberFormatShell::Create(SvNumberFormatter* pNumFormatter,
76 sal_uInt32 nFormatKey,
77 SvxNumberValueType eNumValType, double nNumVal,
78 const OUString* pNumStr)
79 {
80 return new SvxNumberFormatShell(pNumFormatter, nFormatKey, eNumValType, nNumVal, pNumStr);
81 }
82
SvxNumberFormatShell(SvNumberFormatter * pNumFormatter,sal_uInt32 nFormatKey,SvxNumberValueType eNumValType,const OUString & rNumStr)83 SvxNumberFormatShell::SvxNumberFormatShell(SvNumberFormatter* pNumFormatter, sal_uInt32 nFormatKey,
84 SvxNumberValueType eNumValType, const OUString& rNumStr)
85 : pFormatter(pNumFormatter)
86 , pCurFmtTable(nullptr)
87 , eValType(eNumValType)
88 , bUndoAddList(true)
89 , nCurFormatKey(nFormatKey)
90 , nCurCategory(SvNumFormatType::ALL)
91 , eCurLanguage(LANGUAGE_NONE)
92 , pCurCurrencyEntry(nullptr)
93 , bBankingSymbol(false)
94 , nCurCurrencyEntryPos(sal_uInt16(SELPOS_NONE))
95 , bUseStarFormat(false)
96 , bIsDefaultValNum(true)
97 {
98 nValNum = 0;
99
100 switch (eValType)
101 {
102 case SvxNumberValueType::String:
103 aValStr = rNumStr;
104 break;
105 case SvxNumberValueType::Number:
106 if (pFormatter)
107 {
108 nValNum = GetDefaultValNum(pFormatter->GetType(nCurFormatKey));
109 }
110 [[fallthrough]];
111 case SvxNumberValueType::Undefined:
112 default:
113 aValStr.clear();
114 }
115 }
116
SvxNumberFormatShell(SvNumberFormatter * pNumFormatter,sal_uInt32 nFormatKey,SvxNumberValueType eNumValType,double nNumVal,const OUString * pNumStr)117 SvxNumberFormatShell::SvxNumberFormatShell(SvNumberFormatter* pNumFormatter, sal_uInt32 nFormatKey,
118 SvxNumberValueType eNumValType, double nNumVal,
119 const OUString* pNumStr)
120 : pFormatter(pNumFormatter)
121 , pCurFmtTable(nullptr)
122 , eValType(eNumValType)
123 , bUndoAddList(true)
124 , nCurFormatKey(nFormatKey)
125 , nCurCategory(SvNumFormatType::ALL)
126 , eCurLanguage(LANGUAGE_NONE)
127 , pCurCurrencyEntry(nullptr)
128 , bBankingSymbol(false)
129 , nCurCurrencyEntryPos(sal_uInt16(SELPOS_NONE))
130 , bUseStarFormat(false)
131 , bIsDefaultValNum(false)
132 {
133 // #50441# When used in Writer, the SvxNumberInfoItem contains the
134 // original string in addition to the value
135
136 if (pNumStr)
137 aValStr = *pNumStr;
138
139 switch (eValType)
140 {
141 case SvxNumberValueType::Number:
142 nValNum = nNumVal;
143 break;
144 case SvxNumberValueType::String:
145 case SvxNumberValueType::Undefined:
146 default:
147 nValNum = 0;
148 bIsDefaultValNum = true;
149 }
150 }
151
~SvxNumberFormatShell()152 SvxNumberFormatShell::~SvxNumberFormatShell()
153 {
154 /*
155 * At this point, depending on whether the added user-defined were
156 * validated (ValidateNewEntries()), the add list is removed from
157 * the number formatter again.
158 *
159 * Deleting formats from the formatter happens for Undo reasons
160 * only in the calling instance.
161 */
162
163 if (bUndoAddList)
164 {
165 // Added formats are invalid => remove them
166
167 for (const auto& rItem : aAddList)
168 pFormatter->DeleteEntry(rItem);
169 }
170 }
171
GetUpdateData() const172 std::vector<sal_uInt32> const& SvxNumberFormatShell::GetUpdateData() const { return aDelList; }
173
CategoryChanged(sal_uInt16 nCatLbPos,short & rFmtSelPos,std::vector<OUString> & rFmtEntries)174 void SvxNumberFormatShell::CategoryChanged(sal_uInt16 nCatLbPos, short& rFmtSelPos,
175 std::vector<OUString>& rFmtEntries)
176 {
177 SvNumFormatType nOldCategory = nCurCategory;
178 PosToCategory_Impl(nCatLbPos, nCurCategory);
179 pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
180 // reinitialize currency if category newly entered
181 if (nCurCategory == SvNumFormatType::CURRENCY && nOldCategory != nCurCategory)
182 pCurCurrencyEntry = nullptr;
183 rFmtSelPos = FillEntryList_Impl(rFmtEntries);
184 }
185
LanguageChanged(LanguageType eLangType,short & rFmtSelPos,std::vector<OUString> & rFmtEntries)186 void SvxNumberFormatShell::LanguageChanged(LanguageType eLangType, short& rFmtSelPos,
187 std::vector<OUString>& rFmtEntries)
188 {
189 eCurLanguage = eLangType;
190 pCurFmtTable = &(pFormatter->ChangeCL(nCurCategory, nCurFormatKey, eCurLanguage));
191 rFmtSelPos = FillEntryList_Impl(rFmtEntries);
192 }
193
FormatChanged(sal_uInt16 nFmtLbPos,OUString & rPreviewStr,const Color * & rpFontColor)194 void SvxNumberFormatShell::FormatChanged(sal_uInt16 nFmtLbPos, OUString& rPreviewStr,
195 const Color*& rpFontColor)
196 {
197 if (static_cast<size_t>(nFmtLbPos) >= aCurEntryList.size())
198 return;
199
200 nCurFormatKey = aCurEntryList[nFmtLbPos];
201
202 if (nCurFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
203 {
204 GetPreviewString_Impl(rPreviewStr, rpFontColor);
205 }
206 else if (nCurCategory == SvNumFormatType::CURRENCY)
207 {
208 if (static_cast<size_t>(nFmtLbPos) < aCurrencyFormatList.size())
209 {
210 MakePrevStringFromVal(aCurrencyFormatList[nFmtLbPos], rPreviewStr, rpFontColor,
211 nValNum);
212 }
213 }
214 }
215
AddFormat(OUString & rFormat,sal_Int32 & rErrPos,sal_uInt16 & rCatLbSelPos,short & rFmtSelPos,std::vector<OUString> & rFmtEntries)216 bool SvxNumberFormatShell::AddFormat(OUString& rFormat, sal_Int32& rErrPos,
217 sal_uInt16& rCatLbSelPos, short& rFmtSelPos,
218 std::vector<OUString>& rFmtEntries)
219 {
220 bool bInserted = false;
221 sal_uInt32 nAddKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
222
223 if (nAddKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // exists already?
224 {
225 ::std::vector<sal_uInt32>::iterator nAt = GetRemoved_Impl(nAddKey);
226 if (nAt != aDelList.end())
227 {
228 aDelList.erase(nAt);
229 bInserted = true;
230 }
231 else
232 {
233 OSL_FAIL("duplicate format!");
234 }
235 }
236 else // new format
237 {
238 sal_Int32 nPos;
239 bInserted = pFormatter->PutEntry(rFormat, nPos, nCurCategory, nAddKey, eCurLanguage);
240 rErrPos = (nPos >= 0) ? nPos : -1;
241
242 if (bInserted)
243 {
244 // May be sorted under a different locale if LCID was parsed.
245 const SvNumberformat* pEntry = pFormatter->GetEntry(nAddKey);
246 if (pEntry)
247 {
248 LanguageType nLang = pEntry->GetLanguage();
249 if (eCurLanguage != nLang)
250 {
251 // Current language's list would not show entry, adapt.
252 eCurLanguage = nLang;
253 }
254 }
255 }
256 }
257
258 if (bInserted)
259 {
260 nCurFormatKey = nAddKey;
261 DBG_ASSERT(GetAdded_Impl(nCurFormatKey) == aAddList.end(), "duplicate format!");
262 aAddList.push_back(nCurFormatKey);
263
264 // get current table
265 pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
266 nCurCategory = pFormatter->GetType(nAddKey);
267 CategoryToPos_Impl(nCurCategory, rCatLbSelPos);
268 rFmtSelPos = FillEntryList_Impl(rFmtEntries);
269 }
270 else if (rErrPos != 0) // syntax error
271 {
272 ;
273 }
274 else // insert twice not possible
275 {
276 OSL_FAIL("duplicate format!");
277 }
278
279 return bInserted;
280 }
281
RemoveFormat(std::u16string_view rFormat,sal_uInt16 & rCatLbSelPos,short & rFmtSelPos,std::vector<OUString> & rFmtEntries)282 void SvxNumberFormatShell::RemoveFormat(std::u16string_view rFormat, sal_uInt16& rCatLbSelPos,
283 short& rFmtSelPos, std::vector<OUString>& rFmtEntries)
284 {
285 sal_uInt32 nDelKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
286
287 DBG_ASSERT(nDelKey != NUMBERFORMAT_ENTRY_NOT_FOUND, "entry not found!");
288 DBG_ASSERT(!IsRemoved_Impl(nDelKey), "entry already removed!");
289
290 if ((nDelKey == NUMBERFORMAT_ENTRY_NOT_FOUND) || IsRemoved_Impl(nDelKey))
291 return;
292
293 aDelList.push_back(nDelKey);
294
295 ::std::vector<sal_uInt32>::iterator nAt = GetAdded_Impl(nDelKey);
296 if (nAt != aAddList.end())
297 {
298 aAddList.erase(nAt);
299 }
300
301 nCurCategory = pFormatter->GetType(nDelKey);
302 pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
303
304 nCurFormatKey = pFormatter->GetStandardFormat(nCurCategory, eCurLanguage);
305
306 CategoryToPos_Impl(nCurCategory, rCatLbSelPos);
307 rFmtSelPos = FillEntryList_Impl(rFmtEntries);
308 }
309
MakeFormat(OUString & rFormat,bool bThousand,bool bNegRed,sal_uInt16 nPrecision,sal_uInt16 nLeadingZeroes,sal_uInt16 nCurrencyPos)310 void SvxNumberFormatShell::MakeFormat(OUString& rFormat, bool bThousand, bool bNegRed,
311 sal_uInt16 nPrecision, sal_uInt16 nLeadingZeroes,
312 sal_uInt16 nCurrencyPos)
313 {
314 if (aCurrencyFormatList.size() > static_cast<size_t>(nCurrencyPos))
315 {
316 sal_Int32 rErrPos = 0;
317 std::vector<OUString> aFmtEList;
318
319 sal_uInt32 nFound
320 = pFormatter->TestNewString(aCurrencyFormatList[nCurrencyPos], eCurLanguage);
321
322 if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
323 {
324 sal_uInt16 rCatLbSelPos = 0;
325 short rFmtSelPos = 0;
326 AddFormat(aCurrencyFormatList[nCurrencyPos], rErrPos, rCatLbSelPos, rFmtSelPos,
327 aFmtEList);
328 }
329
330 if (rErrPos == 0)
331 {
332 rFormat = pFormatter->GenerateFormat(nCurFormatKey, eCurLanguage, bThousand, bNegRed,
333 nPrecision, nLeadingZeroes);
334 }
335 }
336 else
337 {
338 rFormat = pFormatter->GenerateFormat(nCurFormatKey, eCurLanguage, bThousand, bNegRed,
339 nPrecision, nLeadingZeroes);
340 }
341 }
342
GetFormatIntegerDigits(std::u16string_view rFormat) const343 sal_uInt16 SvxNumberFormatShell::GetFormatIntegerDigits(std::u16string_view rFormat) const
344 {
345 sal_uInt32 nFmtKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
346
347 return pFormatter->GetFormatIntegerDigits(nFmtKey);
348 }
349
IsNatNum12(std::u16string_view rFormat) const350 bool SvxNumberFormatShell::IsNatNum12(std::u16string_view rFormat) const
351 {
352 sal_uInt32 nFmtKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
353
354 return pFormatter->IsNatNum12(nFmtKey);
355 }
356
GetOptions(const OUString & rFormat,bool & rThousand,bool & rNegRed,sal_uInt16 & rPrecision,sal_uInt16 & rLeadingZeroes,sal_uInt16 & rCatLbPos)357 void SvxNumberFormatShell::GetOptions(const OUString& rFormat, bool& rThousand, bool& rNegRed,
358 sal_uInt16& rPrecision, sal_uInt16& rLeadingZeroes,
359 sal_uInt16& rCatLbPos)
360 {
361 sal_uInt32 nFmtKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
362
363 if (nFmtKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
364 {
365 pFormatter->GetFormatSpecialInfo(nFmtKey, rThousand, rNegRed, rPrecision, rLeadingZeroes);
366
367 CategoryToPos_Impl(pFormatter->GetType(nFmtKey), rCatLbPos);
368 }
369 else
370 {
371 bool bTestBanking = false;
372 sal_uInt16 nPos = FindCurrencyTableEntry(rFormat, bTestBanking);
373
374 if (IsInTable(nPos, bTestBanking, rFormat)
375 && pFormatter->GetFormatSpecialInfo(rFormat, rThousand, rNegRed, rPrecision,
376 rLeadingZeroes, eCurLanguage)
377 == 0)
378 {
379 rCatLbPos = CAT_CURRENCY;
380 }
381 else
382 rCatLbPos = CAT_USERDEFINED;
383 }
384 }
385
MakePreviewString(const OUString & rFormatStr,OUString & rPreviewStr,const Color * & rpFontColor)386 void SvxNumberFormatShell::MakePreviewString(const OUString& rFormatStr, OUString& rPreviewStr,
387 const Color*& rpFontColor)
388 {
389 rpFontColor = nullptr;
390
391 sal_uInt32 nExistingFormat = pFormatter->GetEntryKey(rFormatStr, eCurLanguage);
392 if (nExistingFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
393 {
394 // real preview - not implemented in NumberFormatter for text formats
395 pFormatter->GetPreviewString(rFormatStr, nValNum, rPreviewStr, &rpFontColor, eCurLanguage,
396 bUseStarFormat);
397 }
398 else
399 {
400 // format exists
401
402 // #50441# if a string was set in addition to the value, use it for text formats
403 bool bUseText = (eValType == SvxNumberValueType::String
404 || (!aValStr.isEmpty()
405 && (pFormatter->GetType(nExistingFormat) & SvNumFormatType::TEXT)));
406
407 if (bUseText)
408 {
409 pFormatter->GetOutputString(aValStr, nExistingFormat, rPreviewStr, &rpFontColor);
410 }
411 else
412 {
413 if (bIsDefaultValNum)
414 nValNum = GetDefaultValNum(pFormatter->GetType(nExistingFormat));
415 pFormatter->GetOutputString(nValNum, nExistingFormat, rPreviewStr, &rpFontColor,
416 bUseStarFormat);
417 }
418 }
419 }
420
IsUserDefined(const OUString & rFmtString)421 bool SvxNumberFormatShell::IsUserDefined(const OUString& rFmtString)
422 {
423 sal_uInt32 nFound = pFormatter->GetEntryKey(rFmtString, eCurLanguage);
424
425 bool bFlag = false;
426 if (nFound != NUMBERFORMAT_ENTRY_NOT_FOUND)
427 {
428 bFlag = pFormatter->IsUserDefined(rFmtString, eCurLanguage);
429
430 if (bFlag)
431 {
432 const SvNumberformat* pNumEntry = pFormatter->GetEntry(nFound);
433
434 if (pNumEntry != nullptr && pNumEntry->HasNewCurrency())
435 {
436 bool bTestBanking;
437 sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
438 bFlag = !IsInTable(nPos, bTestBanking, rFmtString);
439 }
440 }
441 }
442 return bFlag;
443 }
444
FindEntry(const OUString & rFmtString,sal_uInt32 * pAt)445 bool SvxNumberFormatShell::FindEntry(const OUString& rFmtString, sal_uInt32* pAt /* = NULL */)
446 {
447 bool bRes = false;
448
449 sal_uInt32 nFound = NUMBERFORMAT_ENTRY_NOT_FOUND;
450 // There may be multiple builtin entries with the same format code, first
451 // try if the current key matches.
452 const SvNumberformat* pEntry = pFormatter->GetEntry(nCurFormatKey);
453 if (pEntry && pEntry->GetLanguage() == eCurLanguage && pEntry->GetFormatstring() == rFmtString)
454 nFound = nCurFormatKey;
455
456 if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
457 // Find the first matching format code.
458 nFound = pFormatter->TestNewString(rFmtString, eCurLanguage);
459
460 if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
461 {
462 bool bTestBanking = false;
463 sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
464
465 if (IsInTable(nPos, bTestBanking, rFmtString))
466 {
467 nFound = NUMBERFORMAT_ENTRY_NEW_CURRENCY;
468 bRes = true;
469 }
470 }
471 else
472 {
473 bRes = !IsRemoved_Impl(nFound);
474 }
475
476 if (pAt)
477 *pAt = nFound;
478
479 return bRes;
480 }
481
GetInitSettings(sal_uInt16 & nCatLbPos,LanguageType & rLangType,sal_uInt16 & nFmtLbSelPos,std::vector<OUString> & rFmtEntries,OUString & rPrevString,const Color * & rpPrevColor)482 void SvxNumberFormatShell::GetInitSettings(sal_uInt16& nCatLbPos, LanguageType& rLangType,
483 sal_uInt16& nFmtLbSelPos,
484 std::vector<OUString>& rFmtEntries,
485 OUString& rPrevString, const Color*& rpPrevColor)
486 {
487 // precondition: number formater found
488 DBG_ASSERT(pFormatter != nullptr, "Number formatter not found!");
489
490 short nSelPos = SELPOS_NONE;
491
492 // special treatment for undefined number format:
493 if ((eValType == SvxNumberValueType::Undefined) && (nCurFormatKey == 0))
494 PosToCategory_Impl(CAT_ALL, nCurCategory); // category = all
495 else
496 nCurCategory = SvNumFormatType::UNDEFINED; // category = undefined
497
498 pCurFmtTable = &(pFormatter->GetFirstEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
499
500 CategoryToPos_Impl(nCurCategory, nCatLbPos);
501 rLangType = eCurLanguage;
502
503 nSelPos = FillEntryList_Impl(rFmtEntries);
504
505 DBG_ASSERT(nSelPos != SELPOS_NONE, "Leere Formatliste!");
506
507 nFmtLbSelPos = (nSelPos != SELPOS_NONE) ? static_cast<sal_uInt16>(nSelPos) : 0;
508 GetPreviewString_Impl(rPrevString, rpPrevColor);
509 }
510
FillEntryList_Impl(std::vector<OUString> & rList)511 short SvxNumberFormatShell::FillEntryList_Impl(std::vector<OUString>& rList)
512 {
513 /* Create a current list of format entries. The return value is
514 * the list position of the current format. If the list is empty
515 * or if there is no current format, SELPOS_NONE is delivered.
516 */
517 short nSelPos = SELPOS_NONE;
518
519 aCurEntryList.clear();
520
521 if (nCurCategory == SvNumFormatType::ALL)
522 {
523 FillEListWithStd_Impl(rList, SvNumFormatType::NUMBER, nSelPos);
524 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::NUMBER, nSelPos);
525
526 FillEListWithStd_Impl(rList, SvNumFormatType::PERCENT, nSelPos);
527 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::PERCENT, nSelPos);
528
529 FillEListWithStd_Impl(rList, SvNumFormatType::CURRENCY, nSelPos);
530 // No FillEListWithUsD_Impl() here, user defined currency formats
531 // were already added.
532
533 FillEListWithStd_Impl(rList, SvNumFormatType::DATE, nSelPos);
534 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::DATE, nSelPos);
535
536 FillEListWithStd_Impl(rList, SvNumFormatType::TIME, nSelPos);
537 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::TIME, nSelPos);
538
539 nSelPos = FillEListWithDateTime_Impl(rList, nSelPos, false);
540 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::DATETIME, nSelPos);
541
542 FillEListWithStd_Impl(rList, SvNumFormatType::SCIENTIFIC, nSelPos);
543 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::SCIENTIFIC, nSelPos);
544
545 FillEListWithStd_Impl(rList, SvNumFormatType::FRACTION, nSelPos);
546 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::FRACTION, nSelPos);
547
548 FillEListWithStd_Impl(rList, SvNumFormatType::LOGICAL, nSelPos);
549 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::LOGICAL, nSelPos);
550
551 FillEListWithStd_Impl(rList, SvNumFormatType::TEXT, nSelPos);
552 nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::TEXT, nSelPos);
553 }
554 else
555 {
556 FillEListWithStd_Impl(rList, nCurCategory, nSelPos, true);
557 nSelPos = FillEListWithUsD_Impl(rList, nCurCategory, nSelPos);
558 if (nCurCategory == SvNumFormatType::DATE || nCurCategory == SvNumFormatType::TIME)
559 nSelPos = FillEListWithDateTime_Impl(rList, nSelPos, true);
560 }
561
562 return nSelPos;
563 }
564
FillEListWithStd_Impl(std::vector<OUString> & rList,SvNumFormatType eCategory,short & nSelPos,bool bSuppressDuplicates)565 void SvxNumberFormatShell::FillEListWithStd_Impl(std::vector<OUString>& rList,
566 SvNumFormatType eCategory, short& nSelPos,
567 bool bSuppressDuplicates)
568 {
569 /* Create a current list of format entries. The return value is
570 * the list position of the current format. If the list is empty
571 * or if there is no current format, SELPOS_NONE is delivered.
572 */
573
574 assert(pCurFmtTable != nullptr);
575
576 aCurrencyFormatList.clear();
577
578 NfIndexTableOffset eOffsetStart;
579 NfIndexTableOffset eOffsetEnd;
580
581 switch (eCategory)
582 {
583 case SvNumFormatType::NUMBER:
584 eOffsetStart = NF_NUMBER_START;
585 eOffsetEnd = NF_NUMBER_END;
586 break;
587 case SvNumFormatType::PERCENT:
588 eOffsetStart = NF_PERCENT_START;
589 eOffsetEnd = NF_PERCENT_END;
590 break;
591 case SvNumFormatType::CURRENCY:
592 // Currency entries are generated and assembled, ignore
593 // bSuppressDuplicates.
594 nSelPos = FillEListWithCurrency_Impl(rList, nSelPos);
595 return;
596 case SvNumFormatType::DATE:
597 eOffsetStart = NF_DATE_START;
598 eOffsetEnd = NF_DATE_END;
599 break;
600 case SvNumFormatType::TIME:
601 eOffsetStart = NF_TIME_START;
602 eOffsetEnd = NF_TIME_END;
603 break;
604 case SvNumFormatType::SCIENTIFIC:
605 eOffsetStart = NF_SCIENTIFIC_START;
606 eOffsetEnd = NF_SCIENTIFIC_END;
607 break;
608 case SvNumFormatType::FRACTION:
609 eOffsetStart = NF_FRACTION_START;
610 eOffsetEnd = NF_FRACTION_END;
611 // Fraction formats are internally generated by the number
612 // formatter and are not supposed to contain duplicates anyway.
613 nSelPos = FillEListWithFormats_Impl(rList, nSelPos, eOffsetStart, eOffsetEnd, false);
614 nSelPos
615 = FillEListWithFormats_Impl(rList, nSelPos, NF_FRACTION_3D, NF_FRACTION_100, false);
616 return;
617 case SvNumFormatType::LOGICAL:
618 eOffsetStart = NF_BOOLEAN;
619 eOffsetEnd = NF_BOOLEAN;
620 break;
621 case SvNumFormatType::TEXT:
622 eOffsetStart = NF_TEXT;
623 eOffsetEnd = NF_TEXT;
624 break;
625 default:
626 return;
627 }
628
629 nSelPos
630 = FillEListWithFormats_Impl(rList, nSelPos, eOffsetStart, eOffsetEnd, bSuppressDuplicates);
631 }
632
FillEListWithFormats_Impl(std::vector<OUString> & rList,short nSelPos,NfIndexTableOffset eOffsetStart,NfIndexTableOffset eOffsetEnd,bool bSuppressDuplicates)633 short SvxNumberFormatShell::FillEListWithFormats_Impl(std::vector<OUString>& rList, short nSelPos,
634 NfIndexTableOffset eOffsetStart,
635 NfIndexTableOffset eOffsetEnd,
636 bool bSuppressDuplicates)
637 {
638 /* Create a current list of format entries. The return value is
639 * the list position of the current format. If the list is empty
640 * or if there is no current format, SELPOS_NONE is delivered.
641 */
642 for (tools::Long nIndex = eOffsetStart; nIndex <= eOffsetEnd; ++nIndex)
643 {
644 FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates,
645 static_cast<NfIndexTableOffset>(nIndex), false);
646 }
647
648 return nSelPos;
649 }
650
FillEListWithDateTime_Impl(std::vector<OUString> & rList,short nSelPos,bool bSuppressDuplicates)651 short SvxNumberFormatShell::FillEListWithDateTime_Impl(std::vector<OUString>& rList, short nSelPos,
652 bool bSuppressDuplicates)
653 {
654 // Append a list of date+time formats.
655
656 // Add first, so a NF_DATETIME_SYSTEM_SHORT_HHMM may be suppressed in
657 // locales that do not use 2-digit years there and this here is the
658 // default.
659 FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates, NF_DATETIME_SYS_DDMMYYYY_HHMM,
660 true);
661
662 for (tools::Long nIndex = NF_DATETIME_START; nIndex <= NF_DATETIME_END; ++nIndex)
663 {
664 FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates,
665 static_cast<NfIndexTableOffset>(nIndex), true);
666 }
667
668 // Always add the internally generated ISO formats.
669 nSelPos = FillEListWithFormats_Impl(rList, nSelPos, NF_DATETIME_ISO_YYYYMMDD_HHMMSS,
670 NF_DATETIME_ISO_YYYYMMDDTHHMMSS000, false);
671
672 return nSelPos;
673 }
674
FillEListWithOneFormat_Impl(std::vector<OUString> & rList,short & nSelPos,bool bSuppressDuplicates,NfIndexTableOffset nOffset,bool bSuppressIsoDateTime)675 void SvxNumberFormatShell::FillEListWithOneFormat_Impl(std::vector<OUString>& rList, short& nSelPos,
676 bool bSuppressDuplicates,
677 NfIndexTableOffset nOffset,
678 bool bSuppressIsoDateTime)
679 {
680 sal_uInt32 nNFEntry = pFormatter->GetFormatIndex(nOffset, eCurLanguage);
681
682 const SvNumberformat* pNumEntry = pFormatter->GetEntry(nNFEntry);
683 if (pNumEntry == nullptr)
684 return;
685
686 SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
687 sal_uInt16 nMyType;
688 CategoryToPos_Impl(nMyCat, nMyType);
689 OUString aNewFormNInfo = pNumEntry->GetFormatstring();
690
691 if (nNFEntry == nCurFormatKey)
692 {
693 nSelPos = (!IsRemoved_Impl(nNFEntry)) ? aCurEntryList.size() : SELPOS_NONE;
694 }
695
696 // Ugly hack to suppress an ISO date+time format that is the default
697 // date+time format of the locale and identical to the internally generated
698 // one always to be added after/below.
699 const bool bSupIso
700 = bSuppressIsoDateTime && bSuppressDuplicates
701 && (aNewFormNInfo == "YYYY-MM-DD HH:MM:SS" || aNewFormNInfo == "YYYY-MM-DD\"T\"HH:MM:SS");
702
703 if (!bSupIso
704 && (!bSuppressDuplicates || IsEssentialFormat_Impl(nMyCat, nNFEntry)
705 || std::find(rList.begin(), rList.end(), aNewFormNInfo) == rList.end()))
706 {
707 rList.push_back(aNewFormNInfo);
708 aCurEntryList.push_back(nNFEntry);
709 }
710 }
711
IsEssentialFormat_Impl(SvNumFormatType eType,sal_uInt32 nKey)712 bool SvxNumberFormatShell::IsEssentialFormat_Impl(SvNumFormatType eType, sal_uInt32 nKey)
713 {
714 if (nKey == nCurFormatKey)
715 return true;
716
717 const NfIndexTableOffset nIndex = SvNumberFormatter::GetIndexTableOffset(nKey);
718 switch (nIndex)
719 {
720 // These are preferred or edit formats.
721 case NF_DATE_SYS_DDMMYYYY:
722 case NF_DATE_ISO_YYYYMMDD:
723 case NF_TIME_HH_MMSS:
724 case NF_TIME_MMSS00:
725 case NF_TIME_HH_MMSS00:
726 case NF_DATETIME_SYS_DDMMYYYY_HHMM:
727 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
728 case NF_DATETIME_ISO_YYYYMMDD_HHMMSS:
729 case NF_DATETIME_ISO_YYYYMMDD_HHMMSS000:
730 case NF_DATETIME_ISO_YYYYMMDDTHHMMSS:
731 case NF_DATETIME_ISO_YYYYMMDDTHHMMSS000:
732 return true;
733 default:
734 break;
735 }
736
737 return nKey == pFormatter->GetStandardFormat(eType, eCurLanguage);
738 }
739
FillEListWithCurrency_Impl(std::vector<OUString> & rList,short nSelPos)740 short SvxNumberFormatShell::FillEListWithCurrency_Impl(std::vector<OUString>& rList, short nSelPos)
741 {
742 /* Create a current list of format entries. The return value is
743 * the list position of the current format. If the list is empty
744 * or if there is no current format, SELPOS_NONE is delivered.
745 */
746 DBG_ASSERT(pCurFmtTable != nullptr, "unknown NumberFormat");
747
748 const NfCurrencyEntry* pTmpCurrencyEntry;
749 bool bTmpBanking;
750 OUString rSymbol;
751
752 bool bFlag = pFormatter->GetNewCurrencySymbolString(nCurFormatKey, rSymbol, &pTmpCurrencyEntry,
753 &bTmpBanking);
754
755 if ((!bFlag && pCurCurrencyEntry == nullptr)
756 || (bFlag && pTmpCurrencyEntry == nullptr && rSymbol.isEmpty())
757 || (nCurCategory == SvNumFormatType::ALL))
758 {
759 if (nCurCategory == SvNumFormatType::ALL)
760 FillEListWithUserCurrencys(rList, nSelPos);
761 nSelPos = FillEListWithSysCurrencys(rList, nSelPos);
762 }
763 else
764 {
765 nSelPos = FillEListWithUserCurrencys(rList, nSelPos);
766 }
767
768 return nSelPos;
769 }
770
FillEListWithSysCurrencys(std::vector<OUString> & rList,short nSelPos)771 short SvxNumberFormatShell::FillEListWithSysCurrencys(std::vector<OUString>& rList, short nSelPos)
772 {
773 /* Create a current list of format entries. The return value is
774 * the list position of the current format. If the list is empty
775 * or if there is no current format, SELPOS_NONE is delivered.
776 */
777 sal_uInt16 nMyType;
778
779 sal_uInt32 nNFEntry;
780 OUString aNewFormNInfo;
781
782 nCurCurrencyEntryPos = 0;
783
784 for (tools::Long nIndex = NF_CURRENCY_START; nIndex <= NF_CURRENCY_END; nIndex++)
785 {
786 nNFEntry
787 = pFormatter->GetFormatIndex(static_cast<NfIndexTableOffset>(nIndex), eCurLanguage);
788
789 if (nCurCategory == SvNumFormatType::ALL && nNFEntry != nCurFormatKey)
790 // Deprecated old currency entries, for ALL add only if used as
791 // current format key.
792 continue;
793
794 const SvNumberformat* pNumEntry = pFormatter->GetEntry(nNFEntry);
795
796 if (pNumEntry == nullptr)
797 continue;
798
799 SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
800 CategoryToPos_Impl(nMyCat, nMyType);
801 aNewFormNInfo = pNumEntry->GetFormatstring();
802
803 if (nNFEntry == nCurFormatKey)
804 {
805 nSelPos = (!IsRemoved_Impl(nNFEntry)) ? aCurEntryList.size() : SELPOS_NONE;
806 }
807
808 rList.push_back(aNewFormNInfo);
809 aCurEntryList.push_back(nNFEntry);
810 }
811
812 if (nCurCategory != SvNumFormatType::ALL)
813 {
814 assert(pCurFmtTable != nullptr && "unknown NumberFormat");
815 for (const auto& rEntry : *pCurFmtTable)
816 {
817 sal_uInt32 nKey = rEntry.first;
818 const SvNumberformat* pNumEntry = rEntry.second;
819
820 if (!IsRemoved_Impl(nKey))
821 {
822 bool bUserNewCurrency = false;
823 if (pNumEntry->HasNewCurrency())
824 {
825 const NfCurrencyEntry* pTmpCurrencyEntry;
826 bool bTmpBanking;
827 OUString rSymbol;
828
829 pFormatter->GetNewCurrencySymbolString(nKey, rSymbol, &pTmpCurrencyEntry,
830 &bTmpBanking);
831
832 bUserNewCurrency = (pTmpCurrencyEntry != nullptr);
833 }
834
835 if (!bUserNewCurrency && (pNumEntry->GetType() & SvNumFormatType::DEFINED))
836 {
837 SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
838 CategoryToPos_Impl(nMyCat, nMyType);
839 aNewFormNInfo = pNumEntry->GetFormatstring();
840
841 if (nKey == nCurFormatKey)
842 nSelPos = aCurEntryList.size();
843 rList.push_back(aNewFormNInfo);
844 aCurEntryList.push_back(nKey);
845 }
846 }
847 }
848 }
849 return nSelPos;
850 }
851
FillEListWithUserCurrencys(std::vector<OUString> & rList,short nSelPos)852 short SvxNumberFormatShell::FillEListWithUserCurrencys(std::vector<OUString>& rList, short nSelPos)
853 {
854 /* Create a current list of format entries. The return value is
855 * the list position of the current format. If the list is empty
856 * or if there is no current format, SELPOS_NONE is delivered.
857 */
858 sal_uInt16 nMyType;
859
860 OUString aNewFormNInfo;
861
862 const NfCurrencyEntry* pTmpCurrencyEntry;
863 bool bTmpBanking, bAdaptSelPos;
864 OUString rSymbol;
865 OUString rBankSymbol;
866
867 std::vector<OUString> aList;
868 std::vector<sal_uInt32> aKeyList;
869
870 pFormatter->GetNewCurrencySymbolString(nCurFormatKey, rSymbol, &pTmpCurrencyEntry,
871 &bTmpBanking);
872
873 OUString rShortSymbol;
874
875 if (pCurCurrencyEntry == nullptr)
876 {
877 // #110398# If no currency format was previously selected (we're not
878 // about to add another currency), try to select the initial currency
879 // format (nCurFormatKey) that was set in FormatChanged() after
880 // matching the format string entered in the dialog.
881 bAdaptSelPos = true;
882 pCurCurrencyEntry = const_cast<NfCurrencyEntry*>(pTmpCurrencyEntry);
883 bBankingSymbol = bTmpBanking;
884 nCurCurrencyEntryPos = FindCurrencyFormat(pTmpCurrencyEntry, bTmpBanking);
885 }
886 else
887 {
888 if (pTmpCurrencyEntry == pCurCurrencyEntry)
889 bAdaptSelPos = true;
890 else
891 {
892 bAdaptSelPos = false;
893 pTmpCurrencyEntry = pCurCurrencyEntry;
894 }
895 bTmpBanking = bBankingSymbol;
896 }
897
898 if (pTmpCurrencyEntry != nullptr)
899 {
900 rSymbol = pTmpCurrencyEntry->BuildSymbolString(false);
901 rBankSymbol = pTmpCurrencyEntry->BuildSymbolString(true);
902 rShortSymbol = pTmpCurrencyEntry->BuildSymbolString(bTmpBanking, true);
903 }
904
905 assert(pCurFmtTable != nullptr && "unknown NumberFormat");
906 for (const auto& rEntry : *pCurFmtTable)
907 {
908 sal_uInt32 nKey = rEntry.first;
909 const SvNumberformat* pNumEntry = rEntry.second;
910
911 if (!IsRemoved_Impl(nKey))
912 {
913 if (pNumEntry->GetType() & SvNumFormatType::DEFINED || pNumEntry->IsAdditionalBuiltin())
914 {
915 SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
916 CategoryToPos_Impl(nMyCat, nMyType);
917 aNewFormNInfo = pNumEntry->GetFormatstring();
918
919 bool bInsFlag = false;
920 if (pNumEntry->HasNewCurrency())
921 {
922 bInsFlag = true; // merge locale formats into currency selection
923 }
924 else if ((!bTmpBanking && aNewFormNInfo.indexOf(rSymbol) >= 0)
925 || (bTmpBanking && aNewFormNInfo.indexOf(rBankSymbol) >= 0))
926 {
927 bInsFlag = true;
928 }
929 else if (aNewFormNInfo.indexOf(rShortSymbol) >= 0)
930 {
931 OUString rTstSymbol;
932 const NfCurrencyEntry* pTstCurrencyEntry;
933 bool bTstBanking;
934
935 pFormatter->GetNewCurrencySymbolString(nKey, rTstSymbol, &pTstCurrencyEntry,
936 &bTstBanking);
937
938 if (pTmpCurrencyEntry == pTstCurrencyEntry && bTstBanking == bTmpBanking)
939 {
940 bInsFlag = true;
941 }
942 }
943
944 if (bInsFlag)
945 {
946 aList.push_back(aNewFormNInfo);
947 aKeyList.push_back(nKey);
948 }
949 }
950 }
951 }
952
953 NfWSStringsDtor aWSStringsDtor;
954 sal_uInt16 nDefault;
955 if (pTmpCurrencyEntry && nCurCategory != SvNumFormatType::ALL)
956 {
957 nDefault
958 = pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pTmpCurrencyEntry, bTmpBanking);
959 if (!bTmpBanking)
960 pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pTmpCurrencyEntry, true);
961 }
962 else
963 nDefault = 0;
964 if (!bTmpBanking && nCurCategory != SvNumFormatType::ALL)
965 {
966 // append formats for all currencies defined in the current I18N locale
967 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
968 sal_uInt16 nCurrCount = rCurrencyTable.size();
969 LanguageType eLang = MsLangId::getRealLanguage(eCurLanguage);
970 for (sal_uInt16 i = 0; i < nCurrCount; ++i)
971 {
972 const NfCurrencyEntry* pCurr = &rCurrencyTable[i];
973 if (pCurr->GetLanguage() == eLang && pTmpCurrencyEntry != pCurr)
974 {
975 pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pCurr, false);
976 pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pCurr, true);
977 }
978 }
979 }
980
981 size_t nOldListCount = rList.size();
982 for (size_t i = 0, nPos = nOldListCount; i < aWSStringsDtor.size(); ++i)
983 {
984 bool bFlag = true;
985 OUString aInsStr(aWSStringsDtor[i]);
986 size_t j;
987 for (j = 0; j < aList.size(); ++j)
988 {
989 if (aList[j] == aInsStr)
990 {
991 bFlag = false;
992 break;
993 }
994 }
995 if (bFlag)
996 {
997 rList.push_back(aInsStr);
998 aCurEntryList.insert(aCurEntryList.begin() + (nPos++), NUMBERFORMAT_ENTRY_NOT_FOUND);
999 }
1000 else
1001 {
1002 rList.push_back(aList[j]);
1003 aList.erase(aList.begin() + j);
1004 aCurEntryList.insert(aCurEntryList.begin() + (nPos++), aKeyList[j]);
1005 aKeyList.erase(aKeyList.begin() + j);
1006 }
1007 }
1008
1009 for (size_t i = 0; i < aKeyList.size(); ++i)
1010 {
1011 if (aKeyList[i] != NUMBERFORMAT_ENTRY_NOT_FOUND)
1012 {
1013 rList.push_back(aList[i]);
1014 aCurEntryList.push_back(aKeyList[i]);
1015 }
1016 }
1017
1018 for (size_t i = nOldListCount; i < rList.size(); ++i)
1019 {
1020 aCurrencyFormatList.push_back(rList[i]);
1021
1022 if (nSelPos == SELPOS_NONE && bAdaptSelPos && aCurEntryList[i] == nCurFormatKey)
1023 nSelPos = i;
1024 }
1025
1026 if (nSelPos == SELPOS_NONE && nCurCategory != SvNumFormatType::ALL)
1027 nSelPos = nDefault;
1028
1029 return nSelPos;
1030 }
1031
FillEListWithUsD_Impl(std::vector<OUString> & rList,SvNumFormatType eCategory,short nSelPos)1032 short SvxNumberFormatShell::FillEListWithUsD_Impl(std::vector<OUString>& rList,
1033 SvNumFormatType eCategory, short nSelPos)
1034 {
1035 /* Create a current list of format entries. The return value is
1036 * the list position of the current format. If the list is empty
1037 * or if there is no current format, SELPOS_NONE is delivered.
1038 */
1039
1040 assert(pCurFmtTable != nullptr);
1041
1042 OUString aNewFormNInfo;
1043
1044 const bool bCatDefined = (eCategory == SvNumFormatType::DEFINED);
1045 const bool bCategoryMatch = (eCategory != SvNumFormatType::ALL && !bCatDefined);
1046 const bool bNatNumCurrency = (eCategory == SvNumFormatType::CURRENCY);
1047
1048 for (const auto& rEntry : *pCurFmtTable)
1049 {
1050 const SvNumberformat* pNumEntry = rEntry.second;
1051
1052 if (bCategoryMatch && (pNumEntry->GetMaskedType() & eCategory) != eCategory)
1053 continue; // for; type does not match category if not ALL
1054
1055 const bool bUserDefined = bool(pNumEntry->GetType() & SvNumFormatType::DEFINED);
1056 if (!bUserDefined && bCatDefined)
1057 continue; // for; not user defined in DEFINED category
1058
1059 if (!(bUserDefined || (!bCatDefined && pNumEntry->IsAdditionalBuiltin())))
1060 continue; // for; does not match criteria at all
1061
1062 const sal_uInt32 nKey = rEntry.first;
1063 if (!IsRemoved_Impl(nKey))
1064 {
1065 aNewFormNInfo = pNumEntry->GetFormatstring();
1066
1067 if (bNatNumCurrency && (aNewFormNInfo.indexOf("NatNum12") < 0 || bUserDefined))
1068 continue; // for; extra CURRENCY must be not user-defined NatNum12 type
1069
1070 bool bAdd = true;
1071 if (pNumEntry->HasNewCurrency())
1072 {
1073 bool bTestBanking;
1074 sal_uInt16 nPos = FindCurrencyTableEntry(aNewFormNInfo, bTestBanking);
1075 bAdd = !IsInTable(nPos, bTestBanking, aNewFormNInfo);
1076 }
1077 if (bAdd)
1078 {
1079 if (nKey == nCurFormatKey)
1080 nSelPos = aCurEntryList.size();
1081 rList.push_back(aNewFormNInfo);
1082 aCurEntryList.push_back(nKey);
1083 }
1084 }
1085 }
1086 return nSelPos;
1087 }
1088
GetPreviewString_Impl(OUString & rString,const Color * & rpColor)1089 void SvxNumberFormatShell::GetPreviewString_Impl(OUString& rString, const Color*& rpColor)
1090 {
1091 rpColor = nullptr;
1092
1093 // #50441# if a string was set in addition to the value, use it for text formats
1094 bool bUseText
1095 = (eValType == SvxNumberValueType::String
1096 || (!aValStr.isEmpty() && (pFormatter->GetType(nCurFormatKey) & SvNumFormatType::TEXT)));
1097
1098 if (bUseText)
1099 {
1100 pFormatter->GetOutputString(aValStr, nCurFormatKey, rString, &rpColor);
1101 }
1102 else
1103 {
1104 pFormatter->GetOutputString(nValNum, nCurFormatKey, rString, &rpColor, bUseStarFormat);
1105 }
1106 }
1107
GetRemoved_Impl(size_t nKey)1108 ::std::vector<sal_uInt32>::iterator SvxNumberFormatShell::GetRemoved_Impl(size_t nKey)
1109 {
1110 return ::std::find(aDelList.begin(), aDelList.end(), nKey);
1111 }
1112
IsRemoved_Impl(size_t nKey)1113 bool SvxNumberFormatShell::IsRemoved_Impl(size_t nKey)
1114 {
1115 return GetRemoved_Impl(nKey) != aDelList.end();
1116 }
1117
GetAdded_Impl(size_t nKey)1118 ::std::vector<sal_uInt32>::iterator SvxNumberFormatShell::GetAdded_Impl(size_t nKey)
1119 {
1120 return ::std::find(aAddList.begin(), aAddList.end(), nKey);
1121 }
1122
1123 // Conversion routines:
PosToCategory_Impl(sal_uInt16 nPos,SvNumFormatType & rCategory)1124 void SvxNumberFormatShell::PosToCategory_Impl(sal_uInt16 nPos, SvNumFormatType& rCategory)
1125 {
1126 // map category css::form positions (->resource)
1127 switch (nPos)
1128 {
1129 case CAT_USERDEFINED:
1130 rCategory = SvNumFormatType::DEFINED;
1131 break;
1132 case CAT_NUMBER:
1133 rCategory = SvNumFormatType::NUMBER;
1134 break;
1135 case CAT_PERCENT:
1136 rCategory = SvNumFormatType::PERCENT;
1137 break;
1138 case CAT_CURRENCY:
1139 rCategory = SvNumFormatType::CURRENCY;
1140 break;
1141 case CAT_DATE:
1142 rCategory = SvNumFormatType::DATE;
1143 break;
1144 case CAT_TIME:
1145 rCategory = SvNumFormatType::TIME;
1146 break;
1147 case CAT_SCIENTIFIC:
1148 rCategory = SvNumFormatType::SCIENTIFIC;
1149 break;
1150 case CAT_FRACTION:
1151 rCategory = SvNumFormatType::FRACTION;
1152 break;
1153 case CAT_BOOLEAN:
1154 rCategory = SvNumFormatType::LOGICAL;
1155 break;
1156 case CAT_TEXT:
1157 rCategory = SvNumFormatType::TEXT;
1158 break;
1159 case CAT_ALL:
1160 default:
1161 rCategory = SvNumFormatType::ALL;
1162 break;
1163 }
1164 }
1165
CategoryToPos_Impl(SvNumFormatType nCategory,sal_uInt16 & rPos)1166 void SvxNumberFormatShell::CategoryToPos_Impl(SvNumFormatType nCategory, sal_uInt16& rPos)
1167 {
1168 // map category to css::form positions (->resource)
1169 switch (nCategory)
1170 {
1171 case SvNumFormatType::DEFINED:
1172 rPos = CAT_USERDEFINED;
1173 break;
1174 case SvNumFormatType::NUMBER:
1175 rPos = CAT_NUMBER;
1176 break;
1177 case SvNumFormatType::PERCENT:
1178 rPos = CAT_PERCENT;
1179 break;
1180 case SvNumFormatType::CURRENCY:
1181 rPos = CAT_CURRENCY;
1182 break;
1183 case SvNumFormatType::DATETIME:
1184 case SvNumFormatType::DATE:
1185 rPos = CAT_DATE;
1186 break;
1187 case SvNumFormatType::TIME:
1188 rPos = CAT_TIME;
1189 break;
1190 case SvNumFormatType::SCIENTIFIC:
1191 rPos = CAT_SCIENTIFIC;
1192 break;
1193 case SvNumFormatType::FRACTION:
1194 rPos = CAT_FRACTION;
1195 break;
1196 case SvNumFormatType::LOGICAL:
1197 rPos = CAT_BOOLEAN;
1198 break;
1199 case SvNumFormatType::TEXT:
1200 rPos = CAT_TEXT;
1201 break;
1202 case SvNumFormatType::ALL:
1203 default:
1204 rPos = CAT_ALL;
1205 }
1206 }
1207
1208 /*
1209 * Function: Formats the number nValue dependent on rFormatStr
1210 * and stores the result in rPreviewStr.
1211 * Input: FormatString, color, number to format
1212 * Output: Output string rPreviewStr
1213 */
MakePrevStringFromVal(const OUString & rFormatStr,OUString & rPreviewStr,const Color * & rpFontColor,double nValue)1214 void SvxNumberFormatShell::MakePrevStringFromVal(const OUString& rFormatStr, OUString& rPreviewStr,
1215 const Color*& rpFontColor, double nValue)
1216 {
1217 rpFontColor = nullptr;
1218 pFormatter->GetPreviewString(rFormatStr, nValue, rPreviewStr, &rpFontColor, eCurLanguage);
1219 }
1220
1221 /*
1222 * Function: Returns the comment for a given entry.
1223 * Input: Number of the entry
1224 * Output: Comment string
1225 */
SetComment4Entry(short nEntry,const OUString & aEntStr)1226 void SvxNumberFormatShell::SetComment4Entry(short nEntry, const OUString& aEntStr)
1227 {
1228 SvNumberformat* pNumEntry;
1229 if (nEntry < 0)
1230 return;
1231 sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
1232 pNumEntry = const_cast<SvNumberformat*>(pFormatter->GetEntry(nMyNfEntry));
1233 if (pNumEntry != nullptr)
1234 pNumEntry->SetComment(aEntStr);
1235 }
1236
1237 /*
1238 * Function: Returns the comment for a given entry.
1239 * Input: Number of the entry
1240 * Output: Comment string
1241 */
GetComment4Entry(short nEntry)1242 OUString SvxNumberFormatShell::GetComment4Entry(short nEntry)
1243 {
1244 if (nEntry < 0)
1245 return OUString();
1246
1247 if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
1248 {
1249 sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
1250 const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
1251 if (pNumEntry != nullptr)
1252 return pNumEntry->GetComment();
1253 }
1254
1255 return OUString();
1256 }
1257
1258 /*
1259 * Function: Returns the category number for a given entry.
1260 * Input: Number of the entry
1261 * Output: Category number
1262 */
GetCategory4Entry(short nEntry) const1263 short SvxNumberFormatShell::GetCategory4Entry(short nEntry) const
1264 {
1265 if (nEntry < 0)
1266 return 0;
1267 if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
1268 {
1269 sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
1270
1271 if (nMyNfEntry != NUMBERFORMAT_ENTRY_NOT_FOUND)
1272 {
1273 const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
1274 if (pNumEntry != nullptr)
1275 {
1276 SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
1277 sal_uInt16 nMyType;
1278 CategoryToPos_Impl(nMyCat, nMyType);
1279
1280 return static_cast<short>(nMyType);
1281 }
1282 return 0;
1283 }
1284 else if (!aCurrencyFormatList.empty())
1285 {
1286 return CAT_CURRENCY;
1287 }
1288 }
1289 return 0;
1290 }
1291
1292 /*
1293 * Function: Returns the information about whether an entry is user-specific.
1294 * Input: Number of the entry
1295 * Output: User-specific?
1296 */
GetUserDefined4Entry(short nEntry)1297 bool SvxNumberFormatShell::GetUserDefined4Entry(short nEntry)
1298 {
1299 if (nEntry < 0)
1300 return false;
1301 if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
1302 {
1303 sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
1304 const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
1305
1306 if (pNumEntry != nullptr)
1307 {
1308 if (pNumEntry->GetType() & SvNumFormatType::DEFINED)
1309 {
1310 return true;
1311 }
1312 }
1313 }
1314 return false;
1315 }
1316
1317 /*
1318 * Function: Returns the format string for a given entry.
1319 * Input: Number of the entry
1320 * Output: Format string
1321 */
GetFormat4Entry(short nEntry)1322 OUString SvxNumberFormatShell::GetFormat4Entry(short nEntry)
1323 {
1324 if (nEntry < 0)
1325 return OUString();
1326
1327 if (!aCurrencyFormatList.empty()
1328 && (!pFormatter->GetEntry(aCurEntryList[nEntry])
1329 || pFormatter->GetEntry(aCurEntryList[nEntry])->GetFormatstring().indexOf("NatNum12")
1330 < 0))
1331 {
1332 if (aCurrencyFormatList.size() > o3tl::make_unsigned(nEntry))
1333 return aCurrencyFormatList[nEntry];
1334 }
1335 else
1336 {
1337 sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
1338 const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
1339
1340 if (pNumEntry != nullptr)
1341 return pNumEntry->GetFormatstring();
1342 }
1343 return OUString();
1344 }
1345
1346 /*
1347 * Function: Returns the list number for a given format index.
1348 * Input: Number of the entry
1349 * Output: Category number
1350 */
GetListPos4Entry(sal_uInt32 nIdx,std::u16string_view rFmtString)1351 short SvxNumberFormatShell::GetListPos4Entry(sal_uInt32 nIdx, std::u16string_view rFmtString)
1352 {
1353 short nSelP = SELPOS_NONE;
1354 if (nIdx != NUMBERFORMAT_ENTRY_NEW_CURRENCY)
1355 {
1356 // Check list size against return type limit.
1357 if (aCurEntryList.size() <= o3tl::make_unsigned(::std::numeric_limits<short>::max()))
1358 {
1359 for (size_t i = 0; i < aCurEntryList.size(); ++i)
1360 {
1361 if (aCurEntryList[i] == nIdx)
1362 {
1363 nSelP = i;
1364 break;
1365 }
1366 }
1367 }
1368 else
1369 {
1370 OSL_FAIL("svx::SvxNumberFormatShell::GetListPos4Entry(), list got too large!");
1371 }
1372 }
1373 else
1374 {
1375 // A second list holds the generated currency formats.
1376 for (size_t i = 0; i < aCurrencyFormatList.size(); ++i)
1377 {
1378 if (rFmtString == aCurrencyFormatList[i])
1379 {
1380 nSelP = static_cast<short>(i);
1381 break;
1382 }
1383 }
1384 }
1385 return nSelP;
1386 }
1387
GetStandardName() const1388 OUString SvxNumberFormatShell::GetStandardName() const
1389 {
1390 return pFormatter->GetStandardName(eCurLanguage);
1391 }
1392
GetCurrencySymbols(std::vector<OUString> & rList,sal_uInt16 * pPos)1393 void SvxNumberFormatShell::GetCurrencySymbols(std::vector<OUString>& rList, sal_uInt16* pPos)
1394 {
1395 const NfCurrencyEntry* pTmpCurrencyEntry = SvNumberFormatter::MatchSystemCurrency();
1396
1397 bool bFlag = (pTmpCurrencyEntry == nullptr);
1398
1399 std::vector<sfx::CurrencyID> aDocumentCurrencyIDs;
1400 SvxCurrencyToolBoxControl::GetCurrencySymbols(rList, bFlag, aCurCurrencyList,
1401 aDocumentCurrencyIDs);
1402
1403 if (pPos == nullptr)
1404 return;
1405
1406 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
1407 sal_uInt16 nTableCount = rCurrencyTable.size();
1408
1409 *pPos = 0;
1410 size_t nCount = aCurCurrencyList.size();
1411
1412 if (bFlag)
1413 {
1414 *pPos = 1;
1415 nCurCurrencyEntryPos = 1;
1416 }
1417 else
1418 {
1419 for (size_t i = 1; i < nCount; i++)
1420 {
1421 const sal_uInt16 j = aCurCurrencyList[i];
1422 if (j != sal_uInt16(-1) && j < nTableCount && pTmpCurrencyEntry == &rCurrencyTable[j])
1423 {
1424 *pPos = static_cast<sal_uInt16>(i);
1425 nCurCurrencyEntryPos = static_cast<sal_uInt16>(i);
1426 break;
1427 }
1428 }
1429 }
1430 }
1431
SetCurrencySymbol(sal_uInt32 nPos)1432 void SvxNumberFormatShell::SetCurrencySymbol(sal_uInt32 nPos)
1433 {
1434 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
1435 sal_uInt16 nCount = rCurrencyTable.size();
1436
1437 bBankingSymbol = (nPos >= nCount);
1438
1439 if (nPos >= aCurCurrencyList.size())
1440 return;
1441
1442 sal_uInt16 nCurrencyPos = aCurCurrencyList[nPos];
1443 if (nCurrencyPos != sal_uInt16(-1))
1444 {
1445 pCurCurrencyEntry = const_cast<NfCurrencyEntry*>(&rCurrencyTable[nCurrencyPos]);
1446 nCurCurrencyEntryPos = nPos;
1447 }
1448 else
1449 {
1450 pCurCurrencyEntry = nullptr;
1451 nCurCurrencyEntryPos = 0;
1452 nCurFormatKey = pFormatter->GetFormatIndex(NF_CURRENCY_1000DEC2_RED, eCurLanguage);
1453 }
1454 }
1455
SetCurCurrencyEntry(NfCurrencyEntry * pCEntry)1456 void SvxNumberFormatShell::SetCurCurrencyEntry(NfCurrencyEntry* pCEntry)
1457 {
1458 pCurCurrencyEntry = pCEntry;
1459 }
1460
IsTmpCurrencyFormat(const OUString & rFmtString)1461 bool SvxNumberFormatShell::IsTmpCurrencyFormat(const OUString& rFmtString)
1462 {
1463 sal_uInt32 nFound;
1464 FindEntry(rFmtString, &nFound);
1465 return nFound == NUMBERFORMAT_ENTRY_NEW_CURRENCY;
1466 }
1467
FindCurrencyFormat(const OUString & rFmtString)1468 sal_uInt16 SvxNumberFormatShell::FindCurrencyFormat(const OUString& rFmtString)
1469 {
1470 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
1471 sal_uInt16 nCount = rCurrencyTable.size();
1472
1473 bool bTestBanking = false;
1474
1475 sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
1476
1477 if (nPos != sal_uInt16(-1))
1478 {
1479 sal_uInt16 nStart = 0;
1480 if (bTestBanking && aCurCurrencyList.size() > nPos)
1481 {
1482 nStart = nCount;
1483 }
1484 for (size_t j = nStart; j < aCurCurrencyList.size(); j++)
1485 {
1486 if (aCurCurrencyList[j] == nPos)
1487 return j;
1488 }
1489 }
1490 return sal_uInt16(-1);
1491 }
1492
FindCurrencyTableEntry(const OUString & rFmtString,bool & bTestBanking)1493 sal_uInt16 SvxNumberFormatShell::FindCurrencyTableEntry(const OUString& rFmtString,
1494 bool& bTestBanking)
1495 {
1496 sal_uInt16 nPos = sal_uInt16(-1);
1497
1498 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
1499 sal_uInt16 nCount = rCurrencyTable.size();
1500
1501 const SvNumberformat* pFormat;
1502 OUString aSymbol, aExtension;
1503 sal_uInt32 nFound = pFormatter->TestNewString(rFmtString, eCurLanguage);
1504 if (nFound != NUMBERFORMAT_ENTRY_NOT_FOUND
1505 && ((pFormat = pFormatter->GetEntry(nFound)) != nullptr)
1506 && pFormat->GetNewCurrencySymbol(aSymbol, aExtension))
1507 {
1508 // eventually match with format locale
1509 const NfCurrencyEntry* pTmpCurrencyEntry = SvNumberFormatter::GetCurrencyEntry(
1510 bTestBanking, aSymbol, aExtension, pFormat->GetLanguage());
1511 if (pTmpCurrencyEntry)
1512 {
1513 for (sal_uInt16 i = 0; i < nCount; i++)
1514 {
1515 if (pTmpCurrencyEntry == &rCurrencyTable[i])
1516 {
1517 nPos = i;
1518 break;
1519 }
1520 }
1521 }
1522 }
1523 else
1524 {
1525 // search symbol string only
1526 for (sal_uInt16 i = 0; i < nCount; i++)
1527 {
1528 const NfCurrencyEntry* pTmpCurrencyEntry = &rCurrencyTable[i];
1529 OUString _aSymbol = pTmpCurrencyEntry->BuildSymbolString(false);
1530 OUString aBankSymbol = pTmpCurrencyEntry->BuildSymbolString(true);
1531
1532 if (rFmtString.indexOf(_aSymbol) != -1)
1533 {
1534 bTestBanking = false;
1535 nPos = i;
1536 break;
1537 }
1538 else if (rFmtString.indexOf(aBankSymbol) != -1)
1539 {
1540 bTestBanking = true;
1541 nPos = i;
1542 break;
1543 }
1544 }
1545 }
1546
1547 return nPos;
1548 }
1549
FindCurrencyFormat(const NfCurrencyEntry * pTmpCurrencyEntry,bool bTmpBanking)1550 sal_uInt16 SvxNumberFormatShell::FindCurrencyFormat(const NfCurrencyEntry* pTmpCurrencyEntry,
1551 bool bTmpBanking)
1552 {
1553 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
1554 sal_uInt16 nCount = rCurrencyTable.size();
1555
1556 sal_uInt16 nPos = 0;
1557 for (sal_uInt16 i = 0; i < nCount; i++)
1558 {
1559 if (pTmpCurrencyEntry == &rCurrencyTable[i])
1560 {
1561 nPos = i;
1562 break;
1563 }
1564 }
1565
1566 sal_uInt16 nStart = 0;
1567 if (bTmpBanking && aCurCurrencyList.size() > nPos)
1568 {
1569 nStart = nCount;
1570 }
1571 for (size_t j = nStart; j < aCurCurrencyList.size(); j++)
1572 {
1573 if (aCurCurrencyList[j] == nPos)
1574 return j;
1575 }
1576 return sal_uInt16(-1);
1577 }
1578
IsInTable(sal_uInt16 const nPos,bool const bTmpBanking,std::u16string_view rFmtString) const1579 bool SvxNumberFormatShell::IsInTable(sal_uInt16 const nPos, bool const bTmpBanking,
1580 std::u16string_view rFmtString) const
1581 {
1582 bool bFlag = false;
1583
1584 if (nPos != sal_uInt16(-1))
1585 {
1586 const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
1587
1588 if (nPos < rCurrencyTable.size())
1589 {
1590 NfWSStringsDtor aWSStringsDtor;
1591 pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, rCurrencyTable[nPos], bTmpBanking);
1592
1593 for (const OUString& s : aWSStringsDtor)
1594 {
1595 if (s == rFmtString)
1596 {
1597 bFlag = true;
1598 break;
1599 }
1600 }
1601 }
1602 }
1603
1604 return bFlag;
1605 }
1606
1607 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1608