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