xref: /core/svx/source/items/numfmtsh.cxx (revision 41590e7d)
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