Resolves: tdf#102075 support system [$-F400] time and [$-F800] long date
By substituting a (valid matching the type) format using these special LCID modifier values with the current system locale's format. See ECMA-376-1:2016 18.8.31 numFmts (Number Formats) and https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.numberingformats.aspx which seems to be the only documentation available. Change-Id: Ieca048a77d4ef473ae475e202557d1353ff5387d Reviewed-on: https://gerrit.libreoffice.org/43148 Reviewed-by: Eike Rathke <erack@redhat.com> Tested-by: Jenkins <ci@libreoffice.org>
This commit is contained in:
@@ -552,6 +552,9 @@ public:
|
||||
/// Return the format for a format index
|
||||
const SvNumberformat* GetEntry( sal_uInt32 nKey ) const;
|
||||
|
||||
/// Obtain substituted GetFormatEntry(), i.e. system formats.
|
||||
const SvNumberformat* GetSubstitutedEntry( sal_uInt32 nKey, sal_uInt32 & o_rNewKey ) const;
|
||||
|
||||
/// Return the format index of the standard default number format for language/country
|
||||
sal_uInt32 GetStandardIndex(LanguageType eLnge = LANGUAGE_DONTKNOW);
|
||||
|
||||
@@ -904,6 +907,9 @@ private:
|
||||
// return position of a special character
|
||||
sal_Int32 ImpPosToken ( const OUStringBuffer & sFormat, sal_Unicode token, sal_Int32 nStartPos = 0 );
|
||||
|
||||
// Substitute a format during GetFormatEntry(), i.e. system formats.
|
||||
SvNumberformat* ImpSubstituteEntry( SvNumberformat* pFormat, sal_uInt32 * o_pRealKey = nullptr );
|
||||
|
||||
public:
|
||||
|
||||
// own static mutex, may also be used by internal class SvNumberFormatterRegistry_Impl
|
||||
|
@@ -141,9 +141,17 @@ class SVL_DLLPUBLIC SvNumberformat
|
||||
{
|
||||
struct LocaleType
|
||||
{
|
||||
enum class Substitute : sal_uInt8
|
||||
{
|
||||
NONE,
|
||||
TIME,
|
||||
LONGDATE
|
||||
};
|
||||
|
||||
LanguageType meLanguage;
|
||||
Substitute meSubstitute;
|
||||
sal_uInt8 mnNumeralShape;
|
||||
sal_uInt8 mnCalendarType;
|
||||
LanguageType meLanguage;
|
||||
|
||||
OUString generateCode() const;
|
||||
|
||||
@@ -184,6 +192,28 @@ public:
|
||||
|
||||
LanguageType GetLanguage() const { return maLocale.meLanguage;}
|
||||
|
||||
/** If the format is a placeholder and needs to be substituted. */
|
||||
bool IsSubstituted() const
|
||||
{
|
||||
return maLocale.meSubstitute != LocaleType::Substitute::NONE;
|
||||
}
|
||||
|
||||
/** If the format is a placeholder for the sytem time format and needs to
|
||||
be substituted during formatting time.
|
||||
*/
|
||||
bool IsSystemTimeFormat() const
|
||||
{
|
||||
return maLocale.meSubstitute == LocaleType::Substitute::TIME && maLocale.meLanguage == LANGUAGE_SYSTEM;
|
||||
}
|
||||
|
||||
/** If the format is a placeholder for the sytem long date format and needs
|
||||
to be substituted during formatting time.
|
||||
*/
|
||||
bool IsSystemLongDateFormat() const
|
||||
{
|
||||
return maLocale.meSubstitute == LocaleType::Substitute::LONGDATE && maLocale.meLanguage == LANGUAGE_SYSTEM;
|
||||
}
|
||||
|
||||
const OUString& GetFormatstring() const { return sFormatstring; }
|
||||
|
||||
// Build a format string of application defined keywords
|
||||
|
@@ -92,10 +92,10 @@ private:
|
||||
SAL_DLLPRIVATE void WriteRepeatedElement_Impl( sal_Unicode ch );
|
||||
SAL_DLLPRIVATE bool WriteTextWithCurrency_Impl( const OUString& rString,
|
||||
const css::lang::Locale& rLocale );
|
||||
SAL_DLLPRIVATE void ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey,
|
||||
SAL_DLLPRIVATE void ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey,
|
||||
sal_uInt16 nPart, bool bDefPart );
|
||||
|
||||
SAL_DLLPRIVATE void ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey );
|
||||
SAL_DLLPRIVATE void ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey );
|
||||
|
||||
public:
|
||||
SvXMLNumFmtExport( SvXMLExport& rExport,
|
||||
|
@@ -1065,7 +1065,7 @@ bool SvNumberFormatter::IsNumberFormat(const OUString& sString,
|
||||
double& fOutNumber)
|
||||
{
|
||||
short FType;
|
||||
const SvNumberformat* pFormat = GetFormatEntry(F_Index);
|
||||
const SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry(F_Index));
|
||||
if (!pFormat)
|
||||
{
|
||||
ChangeIntl(IniLnge);
|
||||
@@ -1472,7 +1472,8 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
|
||||
OUString& sOutString)
|
||||
{
|
||||
Color* pColor;
|
||||
SvNumberformat* pFormat = GetFormatEntry( nFIndex );
|
||||
sal_uInt32 nRealKey = nFIndex;
|
||||
SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ), &nRealKey);
|
||||
if (!pFormat)
|
||||
{
|
||||
pFormat = GetFormatEntry(ZF_STANDARD);
|
||||
@@ -1507,8 +1508,8 @@ void SvNumberFormatter::GetInputLineString(const double& fOutNumber,
|
||||
bPrecChanged = true;
|
||||
}
|
||||
|
||||
sal_uInt32 nKey = GetEditFormat( fOutNumber, nFIndex, eType, eLang, pFormat);
|
||||
if ( nKey != nFIndex )
|
||||
sal_uInt32 nKey = GetEditFormat( fOutNumber, nRealKey, eType, eLang, pFormat);
|
||||
if ( nKey != nRealKey )
|
||||
{
|
||||
pFormat = GetFormatEntry( nKey );
|
||||
}
|
||||
@@ -1534,6 +1535,8 @@ void SvNumberFormatter::GetOutputString(const OUString& sString,
|
||||
bool bUseStarFormat )
|
||||
{
|
||||
SvNumberformat* pFormat = GetFormatEntry( nFIndex );
|
||||
// ImpSubstituteEntry() is unnecessary here because so far only numeric
|
||||
// (time and date) are substituted.
|
||||
if (!pFormat)
|
||||
{
|
||||
pFormat = GetFormatEntry(ZF_STANDARD_TEXT);
|
||||
@@ -1569,7 +1572,7 @@ void SvNumberFormatter::GetOutputString(const double& fOutNumber,
|
||||
sOutString.clear();
|
||||
return;
|
||||
}
|
||||
SvNumberformat* pFormat = GetFormatEntry( nFIndex );
|
||||
SvNumberformat* pFormat = ImpSubstituteEntry( GetFormatEntry( nFIndex ));
|
||||
if (!pFormat)
|
||||
pFormat = GetFormatEntry(ZF_STANDARD);
|
||||
ChangeIntl(pFormat->GetLanguage());
|
||||
@@ -2216,6 +2219,40 @@ const SvNumberformat* SvNumberFormatter::GetEntry( sal_uInt32 nKey ) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SvNumberformat* SvNumberFormatter::GetSubstitutedEntry( sal_uInt32 nKey, sal_uInt32 & o_rNewKey ) const
|
||||
{
|
||||
// A tad ugly, but GetStandardFormat() and GetFormatIndex() in
|
||||
// ImpSubstituteEntry() may have to add the LANGUAGE_SYSTEM formats if not
|
||||
// already present (which in practice most times they are).
|
||||
SvNumberFormatter* pThis = const_cast<SvNumberFormatter*>(this);
|
||||
return pThis->ImpSubstituteEntry( pThis->GetFormatEntry( nKey), &o_rNewKey);
|
||||
}
|
||||
|
||||
SvNumberformat* SvNumberFormatter::ImpSubstituteEntry( SvNumberformat* pFormat, sal_uInt32 * o_pRealKey )
|
||||
{
|
||||
if (!pFormat || !pFormat->IsSubstituted())
|
||||
return pFormat;
|
||||
|
||||
// XXX NOTE: substitution can not be done in GetFormatEntry() as otherwise
|
||||
// to be substituted formats would "vanish", i.e. from the number formatter
|
||||
// dialog or when exporting to Excel.
|
||||
|
||||
sal_uInt32 nKey;
|
||||
if (pFormat->IsSystemTimeFormat())
|
||||
/* TODO: should we have NF_TIME_SYSTEM for consistency? */
|
||||
nKey = GetStandardFormat( css::util::NumberFormat::TIME, LANGUAGE_SYSTEM);
|
||||
else if (pFormat->IsSystemLongDateFormat())
|
||||
/* TODO: either that above, or have a long option for GetStandardFormat() */
|
||||
nKey = GetFormatIndex( NF_DATE_SYSTEM_LONG, LANGUAGE_SYSTEM);
|
||||
else
|
||||
return pFormat;
|
||||
|
||||
if (o_pRealKey)
|
||||
*o_pRealKey = nKey;
|
||||
SvNumberFormatTable::const_iterator it = aFTable.find( nKey);
|
||||
return it == aFTable.end() ? nullptr : it->second;
|
||||
}
|
||||
|
||||
void SvNumberFormatter::ImpGenerateFormats( sal_uInt32 CLOffset, bool bNoAdditionalFormats )
|
||||
{
|
||||
bool bOldConvertMode = pFormatScanner->GetConvertMode();
|
||||
|
@@ -1208,6 +1208,24 @@ SvNumberformat::SvNumberformat(OUString& rString,
|
||||
}
|
||||
}
|
||||
|
||||
if (!nCheckPos && IsSubstituted())
|
||||
{
|
||||
// For to be substituted formats the scanned type must match the
|
||||
// substitute type.
|
||||
if (IsSystemTimeFormat())
|
||||
{
|
||||
if ((eType & ~css::util::NumberFormat::DEFINED) != css::util::NumberFormat::TIME)
|
||||
nCheckPos = std::max<sal_Int32>( sBuff.indexOf(']') + 1, 1);
|
||||
}
|
||||
else if (IsSystemLongDateFormat())
|
||||
{
|
||||
if ((eType & ~css::util::NumberFormat::DEFINED) != css::util::NumberFormat::DATE)
|
||||
nCheckPos = std::max<sal_Int32>( sBuff.indexOf(']') + 1, 1);
|
||||
}
|
||||
else
|
||||
assert(!"unhandled substitute");
|
||||
}
|
||||
|
||||
if ( bCondition && !nCheckPos )
|
||||
{
|
||||
if ( nIndex == 1 && NumFor[0].GetCount() == 0 &&
|
||||
@@ -1437,6 +1455,21 @@ OUString SvNumberformat::LocaleType::generateCode() const
|
||||
#endif
|
||||
|
||||
sal_uInt16 n16 = static_cast<sal_uInt16>(meLanguage);
|
||||
if (meLanguage == LANGUAGE_SYSTEM)
|
||||
{
|
||||
switch (meSubstitute)
|
||||
{
|
||||
case Substitute::NONE:
|
||||
; // nothing
|
||||
break;
|
||||
case Substitute::TIME:
|
||||
n16 = static_cast<sal_uInt16>(LANGUAGE_NF_SYSTEM_TIME);
|
||||
break;
|
||||
case Substitute::LONGDATE:
|
||||
n16 = static_cast<sal_uInt16>(LANGUAGE_NF_SYSTEM_DATE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (sal_uInt8 i = 0; i < 4; ++i)
|
||||
{
|
||||
sal_uInt8 n = static_cast<sal_uInt8>((n16 & 0xF000) >> 12);
|
||||
@@ -1452,18 +1485,30 @@ OUString SvNumberformat::LocaleType::generateCode() const
|
||||
}
|
||||
|
||||
SvNumberformat::LocaleType::LocaleType()
|
||||
: mnNumeralShape(0)
|
||||
: meLanguage(LANGUAGE_DONTKNOW)
|
||||
, meSubstitute(Substitute::NONE)
|
||||
, mnNumeralShape(0)
|
||||
, mnCalendarType(0)
|
||||
, meLanguage(LANGUAGE_DONTKNOW)
|
||||
{
|
||||
}
|
||||
|
||||
SvNumberformat::LocaleType::LocaleType(sal_uInt32 nRawNum)
|
||||
: mnNumeralShape(0)
|
||||
: meLanguage(LANGUAGE_DONTKNOW)
|
||||
, meSubstitute(Substitute::NONE)
|
||||
, mnNumeralShape(0)
|
||||
, mnCalendarType(0)
|
||||
, meLanguage(LANGUAGE_DONTKNOW)
|
||||
{
|
||||
meLanguage = static_cast<LanguageType>(nRawNum & 0x0000FFFF);
|
||||
if (meLanguage == LANGUAGE_NF_SYSTEM_TIME)
|
||||
{
|
||||
meSubstitute = Substitute::TIME;
|
||||
meLanguage = LANGUAGE_SYSTEM;
|
||||
}
|
||||
else if (meLanguage == LANGUAGE_NF_SYSTEM_DATE)
|
||||
{
|
||||
meSubstitute = Substitute::LONGDATE;
|
||||
meLanguage = LANGUAGE_SYSTEM;
|
||||
}
|
||||
nRawNum = (nRawNum >> 16);
|
||||
mnCalendarType = static_cast<sal_uInt8>(nRawNum & 0xFF);
|
||||
nRawNum = (nRawNum >> 8);
|
||||
@@ -4913,6 +4958,14 @@ OUString SvNumberformat::GetMappedFormatstring( const NfKeywordTable& rKeywords,
|
||||
LanguageType nOriginalLang /* =LANGUAGE_DONTKNOW */ ) const
|
||||
{
|
||||
OUStringBuffer aStr;
|
||||
if (maLocale.meSubstitute != LocaleType::Substitute::NONE)
|
||||
{
|
||||
// XXX: theoretically this could clash with the first subformat's
|
||||
// lcl_insertLCID() below, in practice as long as it is used for system
|
||||
// time and date modifiers it shouldn't (i.e. there is no calendar or
|
||||
// numeral specified as well).
|
||||
aStr.append("[$-").append( maLocale.generateCode()).append(']');
|
||||
}
|
||||
bool bDefault[4];
|
||||
// 1 subformat matches all if no condition specified,
|
||||
bDefault[0] = ( NumFor[1].GetCount() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
|
||||
|
@@ -1040,14 +1040,14 @@ static bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, bool bSystem
|
||||
|
||||
// export one part (condition)
|
||||
|
||||
void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey,
|
||||
void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey,
|
||||
sal_uInt16 nPart, bool bDefPart )
|
||||
{
|
||||
//! for the default part, pass the conditions from the other parts!
|
||||
|
||||
// element name
|
||||
|
||||
NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nKey );
|
||||
NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nRealKey );
|
||||
|
||||
short nFmtType = 0;
|
||||
bool bThousand = false;
|
||||
@@ -1768,7 +1768,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt
|
||||
|
||||
// export one format
|
||||
|
||||
void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey )
|
||||
void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey )
|
||||
{
|
||||
const sal_uInt16 XMLNUM_MAX_PARTS = 4;
|
||||
bool bParts[XMLNUM_MAX_PARTS] = { false, false, false, false };
|
||||
@@ -1812,7 +1812,7 @@ void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uI
|
||||
if (bParts[nPart])
|
||||
{
|
||||
bool bDefault = ( nPart+1 == nUsedParts ); // last = default
|
||||
ExportPart_Impl( rFormat, nKey, nPart, bDefault );
|
||||
ExportPart_Impl( rFormat, nKey, nRealKey, nPart, bDefault );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1829,9 +1829,12 @@ void SvXMLNumFmtExport::Export( bool bIsAutoStyle )
|
||||
bool bNext(pUsedList->GetFirstUsed(nKey));
|
||||
while(bNext)
|
||||
{
|
||||
pFormat = pFormatter->GetEntry(nKey);
|
||||
// ODF has its notation of system formats, so obtain the "real" already
|
||||
// substituted format but use the original key for style name.
|
||||
sal_uInt32 nRealKey = nKey;
|
||||
pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey);
|
||||
if(pFormat)
|
||||
ExportFormat_Impl( *pFormat, nKey );
|
||||
ExportFormat_Impl( *pFormat, nKey, nRealKey );
|
||||
bNext = pUsedList->GetNextUsed(nKey);
|
||||
}
|
||||
if (!bIsAutoStyle)
|
||||
@@ -1853,8 +1856,14 @@ void SvXMLNumFmtExport::Export( bool bIsAutoStyle )
|
||||
if (!pUsedList->IsUsed(nKey))
|
||||
{
|
||||
DBG_ASSERT((pFormat->GetType() & css::util::NumberFormat::DEFINED), "a not user defined numberformat found");
|
||||
sal_uInt32 nRealKey = nKey;
|
||||
if (pFormat->IsSubstituted())
|
||||
{
|
||||
pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey); // export the "real" format
|
||||
assert(pFormat);
|
||||
}
|
||||
// user-defined and used formats are exported
|
||||
ExportFormat_Impl( *pFormat, nKey );
|
||||
ExportFormat_Impl( *pFormat, nKey, nRealKey );
|
||||
// if it is a user-defined Format it will be added else nothing will happen
|
||||
pUsedList->SetUsed(nKey);
|
||||
}
|
||||
|
Reference in New Issue
Block a user