[Libreoffice-commits] core.git: include/svl include/xmloff svl/source xmloff/source

Eike Rathke erack at redhat.com
Thu Oct 5 07:26:56 UTC 2017


 include/svl/zforlist.hxx         |    6 +++
 include/svl/zformat.hxx          |   32 +++++++++++++++++++-
 include/xmloff/xmlnumfe.hxx      |    4 +-
 svl/source/numbers/zforlist.cxx  |   47 ++++++++++++++++++++++++++----
 svl/source/numbers/zformat.cxx   |   61 ++++++++++++++++++++++++++++++++++++---
 xmloff/source/style/xmlnumfe.cxx |   23 ++++++++++----
 6 files changed, 154 insertions(+), 19 deletions(-)

New commits:
commit 5be8c9cc1b92101e6f9fe5685df86e77d3eee3cc
Author: Eike Rathke <erack at redhat.com>
Date:   Wed Oct 4 23:50:31 2017 +0200

    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 at redhat.com>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/include/svl/zforlist.hxx b/include/svl/zforlist.hxx
index 35a1bc5c50c1..19015cc1000c 100644
--- a/include/svl/zforlist.hxx
+++ b/include/svl/zforlist.hxx
@@ -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
diff --git a/include/svl/zformat.hxx b/include/svl/zformat.hxx
index 6fcb24dd7a24..5d0e1f288643 100644
--- a/include/svl/zformat.hxx
+++ b/include/svl/zformat.hxx
@@ -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
diff --git a/include/xmloff/xmlnumfe.hxx b/include/xmloff/xmlnumfe.hxx
index c3c51ea57797..79df5c853f5d 100644
--- a/include/xmloff/xmlnumfe.hxx
+++ b/include/xmloff/xmlnumfe.hxx
@@ -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,
diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx
index c573a02ba377..1a5147daaa54 100644
--- a/svl/source/numbers/zforlist.cxx
+++ b/svl/source/numbers/zforlist.cxx
@@ -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();
diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx
index d40c7d977f17..116b5e668df5 100644
--- a/svl/source/numbers/zformat.cxx
+++ b/svl/source/numbers/zformat.cxx
@@ -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 );
diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx
index a1ee8d905804..c2f1920e8bda 100644
--- a/xmloff/source/style/xmlnumfe.cxx
+++ b/xmloff/source/style/xmlnumfe.cxx
@@ -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);
                 }


More information about the Libreoffice-commits mailing list