office-gobmx/svx/source/items/numfmtsh.cxx
László Németh 2a1d2d42af tdf#115007 add NatNum12 number format list items, fix title case
Add NumberText NatNum12 number formats, e.g. "One Hundred",
and currency formats, e.g. "One U.S. Dollar and Twenty Cents"
to number formatting dialog windows, i.e. Format Cells->Numbers
in Calc and Format Numbers in Writer (Edit Fields->Format->
Additional formats...).

Fix also bad English title case:

"One Euro *and* *Twenty-Two* cents" (not *And* and *Twenty-two*)

Details:

– svl: list NatNum12 NumberText currency codes in Currency
  formats (i.e. after choosing Currency category).

– svx: Recognize bank symbol "CURRENCY" in NatNum12 parameters
  defined in locale resource files. For example,
  "[NatNum12 CURRENCY]" is converted to "[NatNum12 USD]" in
  the number format dialog windows, using bank symbol of
  the current locale settings.

  Recognize compatible (old) bank symbol "CCC" in NatNum12
  parameters defined in locale resource files. For example,
  "[NatNum12 CCC]" is converted to "[NatNum12 DEM]" in
  the number format dialog windows, using bank symbol of
  the compatible currency of the German locale settings.

  User-defined formats with arbitrary bank codes are
  recognized as currency formats, e.g. modifying
  "[NatNum12 USD]" to "[NatNum12 EUR]" in the dialog window
  results a new currency format item.

– i18npool/*en_US.xml: define four Standard NatNum12 formats
  (lower case, sentence case, title case, upper case) and
  four Currency NatNum12 formats (title case, title case with
  digits, upper case, upper case with digits).

– cui: use lower sample numbers for spell out formats:

  – 100 for Standard:

  One Hundred
  one hundred
  One hundred
  ONE HUNDRED

  – 1.2 for Currency:

  One U.S. Dollar
  ONE U.S. DOLLAR
  One U.S. Dollar and Twenty Cents
  ONE U.S. DOLLAR AND TWENTY CENTS

– i18npool: fix English title casing of NatNum12 conversions:

  – Don't apply casing on "and", according to the title
    case rules, for example:

    "One Euro and One Cent" instead of
    "One Euro And One Cent".

  – Apply casing on the second element of the hyphenated
    compound words:

    "Twenty-One" instead of the bad "Twenty-one".

– add unit test for extended Number and Currency categories.

Note: according to the changes, update user-defined number format id in
chart2/qa/extras/chart2dump/reference/chartdatatest/simple_chart.txt

Change-Id: Ieaf9a8f75a4f197b858eaf67f83484df70295834
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141994
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
2022-11-03 22:20:36 +01:00

1599 lines
53 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <tools/color.hxx>
#include <tools/debug.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <o3tl/safeint.hxx>
#include <svl/numformat.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
#include <svl/currencytable.hxx>
#include <svx/numfmtsh.hxx>
#include <svx/flagsdef.hxx>
#include <svx/tbcontrl.hxx>
#include <limits>
namespace
{
double GetDefaultValNum(const SvNumFormatType nType)
{
switch (nType)
{
case SvNumFormatType::NUMBER:
return fSvxNumValConst[SvxNumValCategory::Standard];
case SvNumFormatType::CURRENCY:
return fSvxNumValConst[SvxNumValCategory::Currency];
case SvNumFormatType::PERCENT:
return fSvxNumValConst[SvxNumValCategory::Percent];
case SvNumFormatType::DATE:
case SvNumFormatType::DATETIME:
return fSvxNumValConst[SvxNumValCategory::Date];
case SvNumFormatType::TIME:
return fSvxNumValConst[SvxNumValCategory::Time];
case SvNumFormatType::SCIENTIFIC:
return fSvxNumValConst[SvxNumValCategory::Scientific];
case SvNumFormatType::FRACTION:
return fSvxNumValConst[SvxNumValCategory::Fraction];
case SvNumFormatType::LOGICAL:
return fSvxNumValConst[SvxNumValCategory::Boolean];
default:
break;
}
return fSvxNumValConst[SvxNumValCategory::NoValue];
}
}
SvxNumberFormatShell* SvxNumberFormatShell::Create(SvNumberFormatter* pNumFormatter,
sal_uInt32 nFormatKey,
SvxNumberValueType eNumValType,
const OUString& rNumStr)
{
return new SvxNumberFormatShell(pNumFormatter, nFormatKey, eNumValType, rNumStr);
}
SvxNumberFormatShell* SvxNumberFormatShell::Create(SvNumberFormatter* pNumFormatter,
sal_uInt32 nFormatKey,
SvxNumberValueType eNumValType, double nNumVal,
const OUString* pNumStr)
{
return new SvxNumberFormatShell(pNumFormatter, nFormatKey, eNumValType, nNumVal, pNumStr);
}
SvxNumberFormatShell::SvxNumberFormatShell(SvNumberFormatter* pNumFormatter, sal_uInt32 nFormatKey,
SvxNumberValueType eNumValType, const OUString& rNumStr)
: pFormatter(pNumFormatter)
, pCurFmtTable(nullptr)
, eValType(eNumValType)
, bUndoAddList(true)
, nCurFormatKey(nFormatKey)
, nCurCategory(SvNumFormatType::ALL)
, eCurLanguage(LANGUAGE_NONE)
, pCurCurrencyEntry(nullptr)
, bBankingSymbol(false)
, nCurCurrencyEntryPos(sal_uInt16(SELPOS_NONE))
, bUseStarFormat(false)
, bIsDefaultValNum(true)
{
nValNum = 0;
switch (eValType)
{
case SvxNumberValueType::String:
aValStr = rNumStr;
break;
case SvxNumberValueType::Number:
if (pFormatter)
{
nValNum = GetDefaultValNum(pFormatter->GetType(nCurFormatKey));
}
[[fallthrough]];
case SvxNumberValueType::Undefined:
default:
aValStr.clear();
}
}
SvxNumberFormatShell::SvxNumberFormatShell(SvNumberFormatter* pNumFormatter, sal_uInt32 nFormatKey,
SvxNumberValueType eNumValType, double nNumVal,
const OUString* pNumStr)
: pFormatter(pNumFormatter)
, pCurFmtTable(nullptr)
, eValType(eNumValType)
, bUndoAddList(true)
, nCurFormatKey(nFormatKey)
, nCurCategory(SvNumFormatType::ALL)
, eCurLanguage(LANGUAGE_NONE)
, pCurCurrencyEntry(nullptr)
, bBankingSymbol(false)
, nCurCurrencyEntryPos(sal_uInt16(SELPOS_NONE))
, bUseStarFormat(false)
, bIsDefaultValNum(false)
{
// #50441# When used in Writer, the SvxNumberInfoItem contains the
// original string in addition to the value
if (pNumStr)
aValStr = *pNumStr;
switch (eValType)
{
case SvxNumberValueType::Number:
nValNum = nNumVal;
break;
case SvxNumberValueType::String:
case SvxNumberValueType::Undefined:
default:
nValNum = 0;
bIsDefaultValNum = true;
}
}
SvxNumberFormatShell::~SvxNumberFormatShell()
{
/*
* At this point, depending on whether the added user-defined were
* validated (ValidateNewEntries()), the add list is removed from
* the number formatter again.
*
* Deleting formats from the formatter happens for Undo reasons
* only in the calling instance.
*/
if (bUndoAddList)
{
// Added formats are invalid => remove them
for (const auto& rItem : aAddList)
pFormatter->DeleteEntry(rItem);
}
}
std::vector<sal_uInt32> const& SvxNumberFormatShell::GetUpdateData() const { return aDelList; }
void SvxNumberFormatShell::CategoryChanged(sal_uInt16 nCatLbPos, short& rFmtSelPos,
std::vector<OUString>& rFmtEntries)
{
SvNumFormatType nOldCategory = nCurCategory;
PosToCategory_Impl(nCatLbPos, nCurCategory);
pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
// reinitialize currency if category newly entered
if (nCurCategory == SvNumFormatType::CURRENCY && nOldCategory != nCurCategory)
pCurCurrencyEntry = nullptr;
rFmtSelPos = FillEntryList_Impl(rFmtEntries);
}
void SvxNumberFormatShell::LanguageChanged(LanguageType eLangType, short& rFmtSelPos,
std::vector<OUString>& rFmtEntries)
{
eCurLanguage = eLangType;
pCurFmtTable = &(pFormatter->ChangeCL(nCurCategory, nCurFormatKey, eCurLanguage));
rFmtSelPos = FillEntryList_Impl(rFmtEntries);
}
void SvxNumberFormatShell::FormatChanged(sal_uInt16 nFmtLbPos, OUString& rPreviewStr,
const Color*& rpFontColor)
{
if (static_cast<size_t>(nFmtLbPos) >= aCurEntryList.size())
return;
nCurFormatKey = aCurEntryList[nFmtLbPos];
if (nCurFormatKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
{
GetPreviewString_Impl(rPreviewStr, rpFontColor);
}
else if (nCurCategory == SvNumFormatType::CURRENCY)
{
if (static_cast<size_t>(nFmtLbPos) < aCurrencyFormatList.size())
{
MakePrevStringFromVal(aCurrencyFormatList[nFmtLbPos], rPreviewStr, rpFontColor,
nValNum);
}
}
}
bool SvxNumberFormatShell::AddFormat(OUString& rFormat, sal_Int32& rErrPos,
sal_uInt16& rCatLbSelPos, short& rFmtSelPos,
std::vector<OUString>& rFmtEntries)
{
bool bInserted = false;
sal_uInt32 nAddKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
if (nAddKey != NUMBERFORMAT_ENTRY_NOT_FOUND) // exists already?
{
::std::vector<sal_uInt32>::iterator nAt = GetRemoved_Impl(nAddKey);
if (nAt != aDelList.end())
{
aDelList.erase(nAt);
bInserted = true;
}
else
{
OSL_FAIL("duplicate format!");
}
}
else // new format
{
sal_Int32 nPos;
bInserted = pFormatter->PutEntry(rFormat, nPos, nCurCategory, nAddKey, eCurLanguage);
rErrPos = (nPos >= 0) ? nPos : -1;
if (bInserted)
{
// May be sorted under a different locale if LCID was parsed.
const SvNumberformat* pEntry = pFormatter->GetEntry(nAddKey);
if (pEntry)
{
LanguageType nLang = pEntry->GetLanguage();
if (eCurLanguage != nLang)
{
// Current language's list would not show entry, adapt.
eCurLanguage = nLang;
}
}
}
}
if (bInserted)
{
nCurFormatKey = nAddKey;
DBG_ASSERT(GetAdded_Impl(nCurFormatKey) == aAddList.end(), "duplicate format!");
aAddList.push_back(nCurFormatKey);
// get current table
pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
nCurCategory = pFormatter->GetType(nAddKey);
CategoryToPos_Impl(nCurCategory, rCatLbSelPos);
rFmtSelPos = FillEntryList_Impl(rFmtEntries);
}
else if (rErrPos != 0) // syntax error
{
;
}
else // insert twice not possible
{
OSL_FAIL("duplicate format!");
}
return bInserted;
}
void SvxNumberFormatShell::RemoveFormat(std::u16string_view rFormat, sal_uInt16& rCatLbSelPos,
short& rFmtSelPos, std::vector<OUString>& rFmtEntries)
{
sal_uInt32 nDelKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
DBG_ASSERT(nDelKey != NUMBERFORMAT_ENTRY_NOT_FOUND, "entry not found!");
DBG_ASSERT(!IsRemoved_Impl(nDelKey), "entry already removed!");
if ((nDelKey == NUMBERFORMAT_ENTRY_NOT_FOUND) || IsRemoved_Impl(nDelKey))
return;
aDelList.push_back(nDelKey);
::std::vector<sal_uInt32>::iterator nAt = GetAdded_Impl(nDelKey);
if (nAt != aAddList.end())
{
aAddList.erase(nAt);
}
nCurCategory = pFormatter->GetType(nDelKey);
pCurFmtTable = &(pFormatter->GetEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
nCurFormatKey = pFormatter->GetStandardFormat(nCurCategory, eCurLanguage);
CategoryToPos_Impl(nCurCategory, rCatLbSelPos);
rFmtSelPos = FillEntryList_Impl(rFmtEntries);
}
void SvxNumberFormatShell::MakeFormat(OUString& rFormat, bool bThousand, bool bNegRed,
sal_uInt16 nPrecision, sal_uInt16 nLeadingZeroes,
sal_uInt16 nCurrencyPos)
{
if (aCurrencyFormatList.size() > static_cast<size_t>(nCurrencyPos))
{
sal_Int32 rErrPos = 0;
std::vector<OUString> aFmtEList;
sal_uInt32 nFound
= pFormatter->TestNewString(aCurrencyFormatList[nCurrencyPos], eCurLanguage);
if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
{
sal_uInt16 rCatLbSelPos = 0;
short rFmtSelPos = 0;
AddFormat(aCurrencyFormatList[nCurrencyPos], rErrPos, rCatLbSelPos, rFmtSelPos,
aFmtEList);
}
if (rErrPos == 0)
{
rFormat = pFormatter->GenerateFormat(nCurFormatKey, eCurLanguage, bThousand, bNegRed,
nPrecision, nLeadingZeroes);
}
}
else
{
rFormat = pFormatter->GenerateFormat(nCurFormatKey, eCurLanguage, bThousand, bNegRed,
nPrecision, nLeadingZeroes);
}
}
sal_uInt16 SvxNumberFormatShell::GetFormatIntegerDigits(std::u16string_view rFormat) const
{
sal_uInt32 nFmtKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
return pFormatter->GetFormatIntegerDigits(nFmtKey);
}
void SvxNumberFormatShell::GetOptions(const OUString& rFormat, bool& rThousand, bool& rNegRed,
sal_uInt16& rPrecision, sal_uInt16& rLeadingZeroes,
sal_uInt16& rCatLbPos)
{
sal_uInt32 nFmtKey = pFormatter->GetEntryKey(rFormat, eCurLanguage);
if (nFmtKey != NUMBERFORMAT_ENTRY_NOT_FOUND)
{
pFormatter->GetFormatSpecialInfo(nFmtKey, rThousand, rNegRed, rPrecision, rLeadingZeroes);
CategoryToPos_Impl(pFormatter->GetType(nFmtKey), rCatLbPos);
}
else
{
bool bTestBanking = false;
sal_uInt16 nPos = FindCurrencyTableEntry(rFormat, bTestBanking);
if (IsInTable(nPos, bTestBanking, rFormat)
&& pFormatter->GetFormatSpecialInfo(rFormat, rThousand, rNegRed, rPrecision,
rLeadingZeroes, eCurLanguage)
== 0)
{
rCatLbPos = CAT_CURRENCY;
}
else
rCatLbPos = CAT_USERDEFINED;
}
}
void SvxNumberFormatShell::MakePreviewString(const OUString& rFormatStr, OUString& rPreviewStr,
const Color*& rpFontColor)
{
rpFontColor = nullptr;
sal_uInt32 nExistingFormat = pFormatter->GetEntryKey(rFormatStr, eCurLanguage);
if (nExistingFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
{
// real preview - not implemented in NumberFormatter for text formats
pFormatter->GetPreviewString(rFormatStr, nValNum, rPreviewStr, &rpFontColor, eCurLanguage,
bUseStarFormat);
}
else
{
// format exists
// #50441# if a string was set in addition to the value, use it for text formats
bool bUseText = (eValType == SvxNumberValueType::String
|| (!aValStr.isEmpty()
&& (pFormatter->GetType(nExistingFormat) & SvNumFormatType::TEXT)));
if (bUseText)
{
pFormatter->GetOutputString(aValStr, nExistingFormat, rPreviewStr, &rpFontColor);
}
else
{
if (bIsDefaultValNum)
nValNum = GetDefaultValNum(pFormatter->GetType(nExistingFormat));
pFormatter->GetOutputString(nValNum, nExistingFormat, rPreviewStr, &rpFontColor,
bUseStarFormat);
}
}
}
bool SvxNumberFormatShell::IsUserDefined(const OUString& rFmtString)
{
sal_uInt32 nFound = pFormatter->GetEntryKey(rFmtString, eCurLanguage);
bool bFlag = false;
if (nFound != NUMBERFORMAT_ENTRY_NOT_FOUND)
{
bFlag = pFormatter->IsUserDefined(rFmtString, eCurLanguage);
if (bFlag)
{
const SvNumberformat* pNumEntry = pFormatter->GetEntry(nFound);
if (pNumEntry != nullptr && pNumEntry->HasNewCurrency())
{
bool bTestBanking;
sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
bFlag = !IsInTable(nPos, bTestBanking, rFmtString);
}
}
}
return bFlag;
}
bool SvxNumberFormatShell::FindEntry(const OUString& rFmtString, sal_uInt32* pAt /* = NULL */)
{
bool bRes = false;
sal_uInt32 nFound = NUMBERFORMAT_ENTRY_NOT_FOUND;
// There may be multiple builtin entries with the same format code, first
// try if the current key matches.
const SvNumberformat* pEntry = pFormatter->GetEntry(nCurFormatKey);
if (pEntry && pEntry->GetLanguage() == eCurLanguage && pEntry->GetFormatstring() == rFmtString)
nFound = nCurFormatKey;
if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
// Find the first matching format code.
nFound = pFormatter->TestNewString(rFmtString, eCurLanguage);
if (nFound == NUMBERFORMAT_ENTRY_NOT_FOUND)
{
bool bTestBanking = false;
sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
if (IsInTable(nPos, bTestBanking, rFmtString))
{
nFound = NUMBERFORMAT_ENTRY_NEW_CURRENCY;
bRes = true;
}
}
else
{
bRes = !IsRemoved_Impl(nFound);
}
if (pAt)
*pAt = nFound;
return bRes;
}
void SvxNumberFormatShell::GetInitSettings(sal_uInt16& nCatLbPos, LanguageType& rLangType,
sal_uInt16& nFmtLbSelPos,
std::vector<OUString>& rFmtEntries,
OUString& rPrevString, const Color*& rpPrevColor)
{
// precondition: number formater found
DBG_ASSERT(pFormatter != nullptr, "Number formatter not found!");
short nSelPos = SELPOS_NONE;
// special treatment for undefined number format:
if ((eValType == SvxNumberValueType::Undefined) && (nCurFormatKey == 0))
PosToCategory_Impl(CAT_ALL, nCurCategory); // category = all
else
nCurCategory = SvNumFormatType::UNDEFINED; // category = undefined
pCurFmtTable = &(pFormatter->GetFirstEntryTable(nCurCategory, nCurFormatKey, eCurLanguage));
CategoryToPos_Impl(nCurCategory, nCatLbPos);
rLangType = eCurLanguage;
nSelPos = FillEntryList_Impl(rFmtEntries);
DBG_ASSERT(nSelPos != SELPOS_NONE, "Leere Formatliste!");
nFmtLbSelPos = (nSelPos != SELPOS_NONE) ? static_cast<sal_uInt16>(nSelPos) : 0;
GetPreviewString_Impl(rPrevString, rpPrevColor);
}
short SvxNumberFormatShell::FillEntryList_Impl(std::vector<OUString>& rList)
{
/* Create a current list of format entries. The return value is
* the list position of the current format. If the list is empty
* or if there is no current format, SELPOS_NONE is delivered.
*/
short nSelPos = SELPOS_NONE;
aCurEntryList.clear();
if (nCurCategory == SvNumFormatType::ALL)
{
FillEListWithStd_Impl(rList, SvNumFormatType::NUMBER, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::NUMBER, nSelPos);
FillEListWithStd_Impl(rList, SvNumFormatType::PERCENT, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::PERCENT, nSelPos);
FillEListWithStd_Impl(rList, SvNumFormatType::CURRENCY, nSelPos);
// No FillEListWithUsD_Impl() here, user defined currency formats
// were already added.
FillEListWithStd_Impl(rList, SvNumFormatType::DATE, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::DATE, nSelPos);
FillEListWithStd_Impl(rList, SvNumFormatType::TIME, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::TIME, nSelPos);
nSelPos = FillEListWithDateTime_Impl(rList, nSelPos, false);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::DATETIME, nSelPos);
FillEListWithStd_Impl(rList, SvNumFormatType::SCIENTIFIC, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::SCIENTIFIC, nSelPos);
FillEListWithStd_Impl(rList, SvNumFormatType::FRACTION, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::FRACTION, nSelPos);
FillEListWithStd_Impl(rList, SvNumFormatType::LOGICAL, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::LOGICAL, nSelPos);
FillEListWithStd_Impl(rList, SvNumFormatType::TEXT, nSelPos);
nSelPos = FillEListWithUsD_Impl(rList, SvNumFormatType::TEXT, nSelPos);
}
else
{
FillEListWithStd_Impl(rList, nCurCategory, nSelPos, true);
nSelPos = FillEListWithUsD_Impl(rList, nCurCategory, nSelPos);
if (nCurCategory == SvNumFormatType::DATE || nCurCategory == SvNumFormatType::TIME)
nSelPos = FillEListWithDateTime_Impl(rList, nSelPos, true);
}
return nSelPos;
}
void SvxNumberFormatShell::FillEListWithStd_Impl(std::vector<OUString>& rList,
SvNumFormatType eCategory, short& nSelPos,
bool bSuppressDuplicates)
{
/* Create a current list of format entries. The return value is
* the list position of the current format. If the list is empty
* or if there is no current format, SELPOS_NONE is delivered.
*/
assert(pCurFmtTable != nullptr);
aCurrencyFormatList.clear();
NfIndexTableOffset eOffsetStart;
NfIndexTableOffset eOffsetEnd;
switch (eCategory)
{
case SvNumFormatType::NUMBER:
eOffsetStart = NF_NUMBER_START;
eOffsetEnd = NF_NUMBER_END;
break;
case SvNumFormatType::PERCENT:
eOffsetStart = NF_PERCENT_START;
eOffsetEnd = NF_PERCENT_END;
break;
case SvNumFormatType::CURRENCY:
// Currency entries are generated and assembled, ignore
// bSuppressDuplicates.
nSelPos = FillEListWithCurrency_Impl(rList, nSelPos);
return;
case SvNumFormatType::DATE:
eOffsetStart = NF_DATE_START;
eOffsetEnd = NF_DATE_END;
break;
case SvNumFormatType::TIME:
eOffsetStart = NF_TIME_START;
eOffsetEnd = NF_TIME_END;
break;
case SvNumFormatType::SCIENTIFIC:
eOffsetStart = NF_SCIENTIFIC_START;
eOffsetEnd = NF_SCIENTIFIC_END;
break;
case SvNumFormatType::FRACTION:
eOffsetStart = NF_FRACTION_START;
eOffsetEnd = NF_FRACTION_END;
// Fraction formats are internally generated by the number
// formatter and are not supposed to contain duplicates anyway.
nSelPos = FillEListWithFormats_Impl(rList, nSelPos, eOffsetStart, eOffsetEnd, false);
nSelPos
= FillEListWithFormats_Impl(rList, nSelPos, NF_FRACTION_3D, NF_FRACTION_100, false);
return;
case SvNumFormatType::LOGICAL:
eOffsetStart = NF_BOOLEAN;
eOffsetEnd = NF_BOOLEAN;
break;
case SvNumFormatType::TEXT:
eOffsetStart = NF_TEXT;
eOffsetEnd = NF_TEXT;
break;
default:
return;
}
nSelPos
= FillEListWithFormats_Impl(rList, nSelPos, eOffsetStart, eOffsetEnd, bSuppressDuplicates);
}
short SvxNumberFormatShell::FillEListWithFormats_Impl(std::vector<OUString>& rList, short nSelPos,
NfIndexTableOffset eOffsetStart,
NfIndexTableOffset eOffsetEnd,
bool bSuppressDuplicates)
{
/* Create a current list of format entries. The return value is
* the list position of the current format. If the list is empty
* or if there is no current format, SELPOS_NONE is delivered.
*/
for (tools::Long nIndex = eOffsetStart; nIndex <= eOffsetEnd; ++nIndex)
{
FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates,
static_cast<NfIndexTableOffset>(nIndex), false);
}
return nSelPos;
}
short SvxNumberFormatShell::FillEListWithDateTime_Impl(std::vector<OUString>& rList, short nSelPos,
bool bSuppressDuplicates)
{
// Append a list of date+time formats.
// Add first, so a NF_DATETIME_SYSTEM_SHORT_HHMM may be suppressed in
// locales that do not use 2-digit years there and this here is the
// default.
FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates, NF_DATETIME_SYS_DDMMYYYY_HHMM,
true);
for (tools::Long nIndex = NF_DATETIME_START; nIndex <= NF_DATETIME_END; ++nIndex)
{
FillEListWithOneFormat_Impl(rList, nSelPos, bSuppressDuplicates,
static_cast<NfIndexTableOffset>(nIndex), true);
}
// Always add the internally generated ISO formats.
nSelPos = FillEListWithFormats_Impl(rList, nSelPos, NF_DATETIME_ISO_YYYYMMDD_HHMMSS,
NF_DATETIME_ISO_YYYYMMDDTHHMMSS000, false);
return nSelPos;
}
void SvxNumberFormatShell::FillEListWithOneFormat_Impl(std::vector<OUString>& rList, short& nSelPos,
bool bSuppressDuplicates,
NfIndexTableOffset nOffset,
bool bSuppressIsoDateTime)
{
sal_uInt32 nNFEntry = pFormatter->GetFormatIndex(nOffset, eCurLanguage);
const SvNumberformat* pNumEntry = pFormatter->GetEntry(nNFEntry);
if (pNumEntry == nullptr)
return;
SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
sal_uInt16 nMyType;
CategoryToPos_Impl(nMyCat, nMyType);
OUString aNewFormNInfo = pNumEntry->GetFormatstring();
if (nNFEntry == nCurFormatKey)
{
nSelPos = (!IsRemoved_Impl(nNFEntry)) ? aCurEntryList.size() : SELPOS_NONE;
}
// Ugly hack to suppress an ISO date+time format that is the default
// date+time format of the locale and identical to the internally generated
// one always to be added after/below.
const bool bSupIso
= bSuppressIsoDateTime && bSuppressDuplicates
&& (aNewFormNInfo == "YYYY-MM-DD HH:MM:SS" || aNewFormNInfo == "YYYY-MM-DD\"T\"HH:MM:SS");
if (!bSupIso
&& (!bSuppressDuplicates || IsEssentialFormat_Impl(nMyCat, nNFEntry)
|| std::find(rList.begin(), rList.end(), aNewFormNInfo) == rList.end()))
{
rList.push_back(aNewFormNInfo);
aCurEntryList.push_back(nNFEntry);
}
}
bool SvxNumberFormatShell::IsEssentialFormat_Impl(SvNumFormatType eType, sal_uInt32 nKey)
{
if (nKey == nCurFormatKey)
return true;
const NfIndexTableOffset nIndex = pFormatter->GetIndexTableOffset(nKey);
switch (nIndex)
{
// These are preferred or edit formats.
case NF_DATE_SYS_DDMMYYYY:
case NF_DATE_ISO_YYYYMMDD:
case NF_TIME_HH_MMSS:
case NF_TIME_MMSS00:
case NF_TIME_HH_MMSS00:
case NF_DATETIME_SYS_DDMMYYYY_HHMM:
case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
case NF_DATETIME_ISO_YYYYMMDD_HHMMSS:
case NF_DATETIME_ISO_YYYYMMDD_HHMMSS000:
case NF_DATETIME_ISO_YYYYMMDDTHHMMSS:
case NF_DATETIME_ISO_YYYYMMDDTHHMMSS000:
return true;
default:
break;
}
return nKey == pFormatter->GetStandardFormat(eType, eCurLanguage);
}
short SvxNumberFormatShell::FillEListWithCurrency_Impl(std::vector<OUString>& rList, short nSelPos)
{
/* Create a current list of format entries. The return value is
* the list position of the current format. If the list is empty
* or if there is no current format, SELPOS_NONE is delivered.
*/
DBG_ASSERT(pCurFmtTable != nullptr, "unknown NumberFormat");
const NfCurrencyEntry* pTmpCurrencyEntry;
bool bTmpBanking;
OUString rSymbol;
bool bFlag = pFormatter->GetNewCurrencySymbolString(nCurFormatKey, rSymbol, &pTmpCurrencyEntry,
&bTmpBanking);
if ((!bFlag && pCurCurrencyEntry == nullptr)
|| (bFlag && pTmpCurrencyEntry == nullptr && rSymbol.isEmpty())
|| (nCurCategory == SvNumFormatType::ALL))
{
if (nCurCategory == SvNumFormatType::ALL)
FillEListWithUserCurrencys(rList, nSelPos);
nSelPos = FillEListWithSysCurrencys(rList, nSelPos);
}
else
{
nSelPos = FillEListWithUserCurrencys(rList, nSelPos);
}
return nSelPos;
}
short SvxNumberFormatShell::FillEListWithSysCurrencys(std::vector<OUString>& rList, short nSelPos)
{
/* Create a current list of format entries. The return value is
* the list position of the current format. If the list is empty
* or if there is no current format, SELPOS_NONE is delivered.
*/
sal_uInt16 nMyType;
DBG_ASSERT(pCurFmtTable != nullptr, "unknown NumberFormat");
sal_uInt32 nNFEntry;
OUString aNewFormNInfo;
nCurCurrencyEntryPos = 0;
for (tools::Long nIndex = NF_CURRENCY_START; nIndex <= NF_CURRENCY_END; nIndex++)
{
nNFEntry
= pFormatter->GetFormatIndex(static_cast<NfIndexTableOffset>(nIndex), eCurLanguage);
if (nCurCategory == SvNumFormatType::ALL && nNFEntry != nCurFormatKey)
// Deprecated old currency entries, for ALL add only if used as
// current format key.
continue;
const SvNumberformat* pNumEntry = pFormatter->GetEntry(nNFEntry);
if (pNumEntry == nullptr)
continue;
SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
CategoryToPos_Impl(nMyCat, nMyType);
aNewFormNInfo = pNumEntry->GetFormatstring();
if (nNFEntry == nCurFormatKey)
{
nSelPos = (!IsRemoved_Impl(nNFEntry)) ? aCurEntryList.size() : SELPOS_NONE;
}
rList.push_back(aNewFormNInfo);
aCurEntryList.push_back(nNFEntry);
}
if (nCurCategory != SvNumFormatType::ALL)
{
for (const auto& rEntry : *pCurFmtTable)
{
sal_uInt32 nKey = rEntry.first;
const SvNumberformat* pNumEntry = rEntry.second;
if (!IsRemoved_Impl(nKey))
{
bool bUserNewCurrency = false;
if (pNumEntry->HasNewCurrency())
{
const NfCurrencyEntry* pTmpCurrencyEntry;
bool bTmpBanking;
OUString rSymbol;
pFormatter->GetNewCurrencySymbolString(nKey, rSymbol, &pTmpCurrencyEntry,
&bTmpBanking);
bUserNewCurrency = (pTmpCurrencyEntry != nullptr);
}
if (!bUserNewCurrency && (pNumEntry->GetType() & SvNumFormatType::DEFINED))
{
SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
CategoryToPos_Impl(nMyCat, nMyType);
aNewFormNInfo = pNumEntry->GetFormatstring();
if (nKey == nCurFormatKey)
nSelPos = aCurEntryList.size();
rList.push_back(aNewFormNInfo);
aCurEntryList.push_back(nKey);
}
}
}
}
return nSelPos;
}
short SvxNumberFormatShell::FillEListWithUserCurrencys(std::vector<OUString>& rList, short nSelPos)
{
/* Create a current list of format entries. The return value is
* the list position of the current format. If the list is empty
* or if there is no current format, SELPOS_NONE is delivered.
*/
sal_uInt16 nMyType;
DBG_ASSERT(pCurFmtTable != nullptr, "unknown NumberFormat");
OUString aNewFormNInfo;
const NfCurrencyEntry* pTmpCurrencyEntry;
bool bTmpBanking, bAdaptSelPos;
OUString rSymbol;
OUString rBankSymbol;
std::vector<OUString> aList;
std::vector<sal_uInt32> aKeyList;
pFormatter->GetNewCurrencySymbolString(nCurFormatKey, rSymbol, &pTmpCurrencyEntry,
&bTmpBanking);
OUString rShortSymbol;
if (pCurCurrencyEntry == nullptr)
{
// #110398# If no currency format was previously selected (we're not
// about to add another currency), try to select the initial currency
// format (nCurFormatKey) that was set in FormatChanged() after
// matching the format string entered in the dialog.
bAdaptSelPos = true;
pCurCurrencyEntry = const_cast<NfCurrencyEntry*>(pTmpCurrencyEntry);
bBankingSymbol = bTmpBanking;
nCurCurrencyEntryPos = FindCurrencyFormat(pTmpCurrencyEntry, bTmpBanking);
}
else
{
if (pTmpCurrencyEntry == pCurCurrencyEntry)
bAdaptSelPos = true;
else
{
bAdaptSelPos = false;
pTmpCurrencyEntry = pCurCurrencyEntry;
}
bTmpBanking = bBankingSymbol;
}
if (pTmpCurrencyEntry != nullptr)
{
rSymbol = pTmpCurrencyEntry->BuildSymbolString(false);
rBankSymbol = pTmpCurrencyEntry->BuildSymbolString(true);
rShortSymbol = pTmpCurrencyEntry->BuildSymbolString(bTmpBanking, true);
}
for (const auto& rEntry : *pCurFmtTable)
{
sal_uInt32 nKey = rEntry.first;
const SvNumberformat* pNumEntry = rEntry.second;
if (!IsRemoved_Impl(nKey))
{
if (pNumEntry->GetType() & SvNumFormatType::DEFINED || pNumEntry->IsAdditionalBuiltin())
{
SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
CategoryToPos_Impl(nMyCat, nMyType);
aNewFormNInfo = pNumEntry->GetFormatstring();
bool bInsFlag = false;
if (pNumEntry->HasNewCurrency())
{
bInsFlag = true; // merge locale formats into currency selection
}
else if ((!bTmpBanking && aNewFormNInfo.indexOf(rSymbol) >= 0)
|| (bTmpBanking && aNewFormNInfo.indexOf(rBankSymbol) >= 0))
{
bInsFlag = true;
}
else if (aNewFormNInfo.indexOf(rShortSymbol) >= 0)
{
OUString rTstSymbol;
const NfCurrencyEntry* pTstCurrencyEntry;
bool bTstBanking;
pFormatter->GetNewCurrencySymbolString(nKey, rTstSymbol, &pTstCurrencyEntry,
&bTstBanking);
if (pTmpCurrencyEntry == pTstCurrencyEntry && bTstBanking == bTmpBanking)
{
bInsFlag = true;
}
}
if (bInsFlag)
{
aList.push_back(aNewFormNInfo);
aKeyList.push_back(nKey);
}
}
}
}
NfWSStringsDtor aWSStringsDtor;
sal_uInt16 nDefault;
if (pTmpCurrencyEntry && nCurCategory != SvNumFormatType::ALL)
{
nDefault
= pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pTmpCurrencyEntry, bTmpBanking);
if (!bTmpBanking)
pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pTmpCurrencyEntry, true);
}
else
nDefault = 0;
if (!bTmpBanking && nCurCategory != SvNumFormatType::ALL)
{
// append formats for all currencies defined in the current I18N locale
const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
sal_uInt16 nCurrCount = rCurrencyTable.size();
LanguageType eLang = MsLangId::getRealLanguage(eCurLanguage);
for (sal_uInt16 i = 0; i < nCurrCount; ++i)
{
const NfCurrencyEntry* pCurr = &rCurrencyTable[i];
if (pCurr->GetLanguage() == eLang && pTmpCurrencyEntry != pCurr)
{
pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pCurr, false);
pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, *pCurr, true);
}
}
}
size_t nOldListCount = rList.size();
for (size_t i = 0, nPos = nOldListCount; i < aWSStringsDtor.size(); ++i)
{
bool bFlag = true;
OUString aInsStr(aWSStringsDtor[i]);
size_t j;
for (j = 0; j < aList.size(); ++j)
{
if (aList[j] == aInsStr)
{
bFlag = false;
break;
}
}
if (bFlag)
{
rList.push_back(aInsStr);
aCurEntryList.insert(aCurEntryList.begin() + (nPos++), NUMBERFORMAT_ENTRY_NOT_FOUND);
}
else
{
rList.push_back(aList[j]);
aList.erase(aList.begin() + j);
aCurEntryList.insert(aCurEntryList.begin() + (nPos++), aKeyList[j]);
aKeyList.erase(aKeyList.begin() + j);
}
}
for (size_t i = 0; i < aKeyList.size(); ++i)
{
if (aKeyList[i] != NUMBERFORMAT_ENTRY_NOT_FOUND)
{
rList.push_back(aList[i]);
aCurEntryList.push_back(aKeyList[i]);
}
}
for (size_t i = nOldListCount; i < rList.size(); ++i)
{
aCurrencyFormatList.push_back(rList[i]);
if (nSelPos == SELPOS_NONE && bAdaptSelPos && aCurEntryList[i] == nCurFormatKey)
nSelPos = i;
}
if (nSelPos == SELPOS_NONE && nCurCategory != SvNumFormatType::ALL)
nSelPos = nDefault;
return nSelPos;
}
short SvxNumberFormatShell::FillEListWithUsD_Impl(std::vector<OUString>& rList,
SvNumFormatType eCategory, short nSelPos)
{
/* Create a current list of format entries. The return value is
* the list position of the current format. If the list is empty
* or if there is no current format, SELPOS_NONE is delivered.
*/
assert(pCurFmtTable != nullptr);
OUString aNewFormNInfo;
const bool bCatDefined = (eCategory == SvNumFormatType::DEFINED);
const bool bCategoryMatch = (eCategory != SvNumFormatType::ALL && !bCatDefined);
const bool bNatNumCurrency = (eCategory == SvNumFormatType::CURRENCY);
for (const auto& rEntry : *pCurFmtTable)
{
const SvNumberformat* pNumEntry = rEntry.second;
if (bCategoryMatch && (pNumEntry->GetMaskedType() & eCategory) != eCategory)
continue; // for; type does not match category if not ALL
const bool bUserDefined = bool(pNumEntry->GetType() & SvNumFormatType::DEFINED);
if (!bUserDefined && bCatDefined)
continue; // for; not user defined in DEFINED category
if (!(bUserDefined || (!bCatDefined && pNumEntry->IsAdditionalBuiltin())))
continue; // for; does not match criteria at all
const sal_uInt32 nKey = rEntry.first;
if (!IsRemoved_Impl(nKey))
{
aNewFormNInfo = pNumEntry->GetFormatstring();
if (bNatNumCurrency && (aNewFormNInfo.indexOf("NatNum12") < 0 || bUserDefined))
continue; // for; extra CURRENCY must be not user-defined NatNum12 type
bool bAdd = true;
if (pNumEntry->HasNewCurrency())
{
bool bTestBanking;
sal_uInt16 nPos = FindCurrencyTableEntry(aNewFormNInfo, bTestBanking);
bAdd = !IsInTable(nPos, bTestBanking, aNewFormNInfo);
}
if (bAdd)
{
if (nKey == nCurFormatKey)
nSelPos = aCurEntryList.size();
rList.push_back(aNewFormNInfo);
aCurEntryList.push_back(nKey);
}
}
}
return nSelPos;
}
void SvxNumberFormatShell::GetPreviewString_Impl(OUString& rString, const Color*& rpColor)
{
rpColor = nullptr;
// #50441# if a string was set in addition to the value, use it for text formats
bool bUseText
= (eValType == SvxNumberValueType::String
|| (!aValStr.isEmpty() && (pFormatter->GetType(nCurFormatKey) & SvNumFormatType::TEXT)));
if (bUseText)
{
pFormatter->GetOutputString(aValStr, nCurFormatKey, rString, &rpColor);
}
else
{
pFormatter->GetOutputString(nValNum, nCurFormatKey, rString, &rpColor, bUseStarFormat);
}
}
::std::vector<sal_uInt32>::iterator SvxNumberFormatShell::GetRemoved_Impl(size_t nKey)
{
return ::std::find(aDelList.begin(), aDelList.end(), nKey);
}
bool SvxNumberFormatShell::IsRemoved_Impl(size_t nKey)
{
return GetRemoved_Impl(nKey) != aDelList.end();
}
::std::vector<sal_uInt32>::iterator SvxNumberFormatShell::GetAdded_Impl(size_t nKey)
{
return ::std::find(aAddList.begin(), aAddList.end(), nKey);
}
// Conversion routines:
void SvxNumberFormatShell::PosToCategory_Impl(sal_uInt16 nPos, SvNumFormatType& rCategory)
{
// map category css::form positions (->resource)
switch (nPos)
{
case CAT_USERDEFINED:
rCategory = SvNumFormatType::DEFINED;
break;
case CAT_NUMBER:
rCategory = SvNumFormatType::NUMBER;
break;
case CAT_PERCENT:
rCategory = SvNumFormatType::PERCENT;
break;
case CAT_CURRENCY:
rCategory = SvNumFormatType::CURRENCY;
break;
case CAT_DATE:
rCategory = SvNumFormatType::DATE;
break;
case CAT_TIME:
rCategory = SvNumFormatType::TIME;
break;
case CAT_SCIENTIFIC:
rCategory = SvNumFormatType::SCIENTIFIC;
break;
case CAT_FRACTION:
rCategory = SvNumFormatType::FRACTION;
break;
case CAT_BOOLEAN:
rCategory = SvNumFormatType::LOGICAL;
break;
case CAT_TEXT:
rCategory = SvNumFormatType::TEXT;
break;
case CAT_ALL:
default:
rCategory = SvNumFormatType::ALL;
break;
}
}
void SvxNumberFormatShell::CategoryToPos_Impl(SvNumFormatType nCategory, sal_uInt16& rPos)
{
// map category to css::form positions (->resource)
switch (nCategory)
{
case SvNumFormatType::DEFINED:
rPos = CAT_USERDEFINED;
break;
case SvNumFormatType::NUMBER:
rPos = CAT_NUMBER;
break;
case SvNumFormatType::PERCENT:
rPos = CAT_PERCENT;
break;
case SvNumFormatType::CURRENCY:
rPos = CAT_CURRENCY;
break;
case SvNumFormatType::DATETIME:
case SvNumFormatType::DATE:
rPos = CAT_DATE;
break;
case SvNumFormatType::TIME:
rPos = CAT_TIME;
break;
case SvNumFormatType::SCIENTIFIC:
rPos = CAT_SCIENTIFIC;
break;
case SvNumFormatType::FRACTION:
rPos = CAT_FRACTION;
break;
case SvNumFormatType::LOGICAL:
rPos = CAT_BOOLEAN;
break;
case SvNumFormatType::TEXT:
rPos = CAT_TEXT;
break;
case SvNumFormatType::ALL:
default:
rPos = CAT_ALL;
}
}
/*
* Function: Formats the number nValue dependent on rFormatStr
* and stores the result in rPreviewStr.
* Input: FormatString, color, number to format
* Output: Output string rPreviewStr
*/
void SvxNumberFormatShell::MakePrevStringFromVal(const OUString& rFormatStr, OUString& rPreviewStr,
const Color*& rpFontColor, double nValue)
{
rpFontColor = nullptr;
pFormatter->GetPreviewString(rFormatStr, nValue, rPreviewStr, &rpFontColor, eCurLanguage);
}
/*
* Function: Returns the comment for a given entry.
* Input: Number of the entry
* Output: Comment string
*/
void SvxNumberFormatShell::SetComment4Entry(short nEntry, const OUString& aEntStr)
{
SvNumberformat* pNumEntry;
if (nEntry < 0)
return;
sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
pNumEntry = const_cast<SvNumberformat*>(pFormatter->GetEntry(nMyNfEntry));
if (pNumEntry != nullptr)
pNumEntry->SetComment(aEntStr);
}
/*
* Function: Returns the comment for a given entry.
* Input: Number of the entry
* Output: Comment string
*/
OUString SvxNumberFormatShell::GetComment4Entry(short nEntry)
{
if (nEntry < 0)
return OUString();
if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
{
sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
if (pNumEntry != nullptr)
return pNumEntry->GetComment();
}
return OUString();
}
/*
* Function: Returns the category number for a given entry.
* Input: Number of the entry
* Output: Category number
*/
short SvxNumberFormatShell::GetCategory4Entry(short nEntry) const
{
if (nEntry < 0)
return 0;
if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
{
sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
if (nMyNfEntry != NUMBERFORMAT_ENTRY_NOT_FOUND)
{
const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
if (pNumEntry != nullptr)
{
SvNumFormatType nMyCat = pNumEntry->GetMaskedType();
sal_uInt16 nMyType;
CategoryToPos_Impl(nMyCat, nMyType);
return static_cast<short>(nMyType);
}
return 0;
}
else if (!aCurrencyFormatList.empty())
{
return CAT_CURRENCY;
}
}
return 0;
}
/*
* Function: Returns the information about whether an entry is user-specific.
* Input: Number of the entry
* Output: User-specific?
*/
bool SvxNumberFormatShell::GetUserDefined4Entry(short nEntry)
{
if (nEntry < 0)
return false;
if (o3tl::make_unsigned(nEntry) < aCurEntryList.size())
{
sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
if (pNumEntry != nullptr)
{
if (pNumEntry->GetType() & SvNumFormatType::DEFINED)
{
return true;
}
}
}
return false;
}
/*
* Function: Returns the format string for a given entry.
* Input: Number of the entry
* Output: Format string
*/
OUString SvxNumberFormatShell::GetFormat4Entry(short nEntry)
{
if (nEntry < 0)
return OUString();
if (!aCurrencyFormatList.empty()
&& (!pFormatter->GetEntry(aCurEntryList[nEntry])
|| pFormatter->GetEntry(aCurEntryList[nEntry])->GetFormatstring().indexOf("NatNum12")
< 0))
{
if (aCurrencyFormatList.size() > o3tl::make_unsigned(nEntry))
return aCurrencyFormatList[nEntry];
}
else
{
sal_uInt32 nMyNfEntry = aCurEntryList[nEntry];
const SvNumberformat* pNumEntry = pFormatter->GetEntry(nMyNfEntry);
if (pNumEntry != nullptr)
return pNumEntry->GetFormatstring();
}
return OUString();
}
/*
* Function: Returns the list number for a given format index.
* Input: Number of the entry
* Output: Category number
*/
short SvxNumberFormatShell::GetListPos4Entry(sal_uInt32 nIdx, std::u16string_view rFmtString)
{
short nSelP = SELPOS_NONE;
if (nIdx != NUMBERFORMAT_ENTRY_NEW_CURRENCY)
{
// Check list size against return type limit.
if (aCurEntryList.size() <= o3tl::make_unsigned(::std::numeric_limits<short>::max()))
{
for (size_t i = 0; i < aCurEntryList.size(); ++i)
{
if (aCurEntryList[i] == nIdx)
{
nSelP = i;
break;
}
}
}
else
{
OSL_FAIL("svx::SvxNumberFormatShell::GetListPos4Entry(), list got too large!");
}
}
else
{
// A second list holds the generated currency formats.
for (size_t i = 0; i < aCurrencyFormatList.size(); ++i)
{
if (rFmtString == aCurrencyFormatList[i])
{
nSelP = static_cast<short>(i);
break;
}
}
}
return nSelP;
}
OUString SvxNumberFormatShell::GetStandardName() const
{
return pFormatter->GetStandardName(eCurLanguage);
}
void SvxNumberFormatShell::GetCurrencySymbols(std::vector<OUString>& rList, sal_uInt16* pPos)
{
const NfCurrencyEntry* pTmpCurrencyEntry = SvNumberFormatter::MatchSystemCurrency();
bool bFlag = (pTmpCurrencyEntry == nullptr);
SvxCurrencyToolBoxControl::GetCurrencySymbols(rList, bFlag, aCurCurrencyList);
if (pPos == nullptr)
return;
const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
sal_uInt16 nTableCount = rCurrencyTable.size();
*pPos = 0;
size_t nCount = aCurCurrencyList.size();
if (bFlag)
{
*pPos = 1;
nCurCurrencyEntryPos = 1;
}
else
{
for (size_t i = 1; i < nCount; i++)
{
const sal_uInt16 j = aCurCurrencyList[i];
if (j != sal_uInt16(-1) && j < nTableCount && pTmpCurrencyEntry == &rCurrencyTable[j])
{
*pPos = static_cast<sal_uInt16>(i);
nCurCurrencyEntryPos = static_cast<sal_uInt16>(i);
break;
}
}
}
}
void SvxNumberFormatShell::SetCurrencySymbol(sal_uInt32 nPos)
{
const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
sal_uInt16 nCount = rCurrencyTable.size();
bBankingSymbol = (nPos >= nCount);
if (nPos >= aCurCurrencyList.size())
return;
sal_uInt16 nCurrencyPos = aCurCurrencyList[nPos];
if (nCurrencyPos != sal_uInt16(-1))
{
pCurCurrencyEntry = const_cast<NfCurrencyEntry*>(&rCurrencyTable[nCurrencyPos]);
nCurCurrencyEntryPos = nPos;
}
else
{
pCurCurrencyEntry = nullptr;
nCurCurrencyEntryPos = 0;
nCurFormatKey = pFormatter->GetFormatIndex(NF_CURRENCY_1000DEC2_RED, eCurLanguage);
}
}
void SvxNumberFormatShell::SetCurCurrencyEntry(NfCurrencyEntry* pCEntry)
{
pCurCurrencyEntry = pCEntry;
}
bool SvxNumberFormatShell::IsTmpCurrencyFormat(const OUString& rFmtString)
{
sal_uInt32 nFound;
FindEntry(rFmtString, &nFound);
return nFound == NUMBERFORMAT_ENTRY_NEW_CURRENCY;
}
sal_uInt16 SvxNumberFormatShell::FindCurrencyFormat(const OUString& rFmtString)
{
const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
sal_uInt16 nCount = rCurrencyTable.size();
bool bTestBanking = false;
sal_uInt16 nPos = FindCurrencyTableEntry(rFmtString, bTestBanking);
if (nPos != sal_uInt16(-1))
{
sal_uInt16 nStart = 0;
if (bTestBanking && aCurCurrencyList.size() > nPos)
{
nStart = nCount;
}
for (size_t j = nStart; j < aCurCurrencyList.size(); j++)
{
if (aCurCurrencyList[j] == nPos)
return j;
}
}
return sal_uInt16(-1);
}
sal_uInt16 SvxNumberFormatShell::FindCurrencyTableEntry(const OUString& rFmtString,
bool& bTestBanking)
{
sal_uInt16 nPos = sal_uInt16(-1);
const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
sal_uInt16 nCount = rCurrencyTable.size();
const SvNumberformat* pFormat;
OUString aSymbol, aExtension;
sal_uInt32 nFound = pFormatter->TestNewString(rFmtString, eCurLanguage);
if (nFound != NUMBERFORMAT_ENTRY_NOT_FOUND
&& ((pFormat = pFormatter->GetEntry(nFound)) != nullptr)
&& pFormat->GetNewCurrencySymbol(aSymbol, aExtension))
{
// eventually match with format locale
const NfCurrencyEntry* pTmpCurrencyEntry = SvNumberFormatter::GetCurrencyEntry(
bTestBanking, aSymbol, aExtension, pFormat->GetLanguage());
if (pTmpCurrencyEntry)
{
for (sal_uInt16 i = 0; i < nCount; i++)
{
if (pTmpCurrencyEntry == &rCurrencyTable[i])
{
nPos = i;
break;
}
}
}
}
else
{
// search symbol string only
for (sal_uInt16 i = 0; i < nCount; i++)
{
const NfCurrencyEntry* pTmpCurrencyEntry = &rCurrencyTable[i];
OUString _aSymbol = pTmpCurrencyEntry->BuildSymbolString(false);
OUString aBankSymbol = pTmpCurrencyEntry->BuildSymbolString(true);
if (rFmtString.indexOf(_aSymbol) != -1)
{
bTestBanking = false;
nPos = i;
break;
}
else if (rFmtString.indexOf(aBankSymbol) != -1)
{
bTestBanking = true;
nPos = i;
break;
}
}
}
return nPos;
}
sal_uInt16 SvxNumberFormatShell::FindCurrencyFormat(const NfCurrencyEntry* pTmpCurrencyEntry,
bool bTmpBanking)
{
const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
sal_uInt16 nCount = rCurrencyTable.size();
sal_uInt16 nPos = 0;
for (sal_uInt16 i = 0; i < nCount; i++)
{
if (pTmpCurrencyEntry == &rCurrencyTable[i])
{
nPos = i;
break;
}
}
sal_uInt16 nStart = 0;
if (bTmpBanking && aCurCurrencyList.size() > nPos)
{
nStart = nCount;
}
for (size_t j = nStart; j < aCurCurrencyList.size(); j++)
{
if (aCurCurrencyList[j] == nPos)
return j;
}
return sal_uInt16(-1);
}
bool SvxNumberFormatShell::IsInTable(sal_uInt16 const nPos, bool const bTmpBanking,
std::u16string_view rFmtString) const
{
bool bFlag = false;
if (nPos != sal_uInt16(-1))
{
const NfCurrencyTable& rCurrencyTable = SvNumberFormatter::GetTheCurrencyTable();
if (nPos < rCurrencyTable.size())
{
NfWSStringsDtor aWSStringsDtor;
pFormatter->GetCurrencyFormatStrings(aWSStringsDtor, rCurrencyTable[nPos], bTmpBanking);
for (const OUString& s : aWSStringsDtor)
{
if (s == rFmtString)
{
bFlag = true;
break;
}
}
}
}
return bFlag;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */