2a1d2d42af
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>
1599 lines
53 KiB
C++
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: */
|