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

Eike Rathke erack at redhat.com
Tue Apr 18 15:01:52 UTC 2017


 svl/source/numbers/zforscan.cxx |  182 ++++++++++++++++++++++++++++++++++++++++
 svl/source/numbers/zforscan.hxx |    9 +
 2 files changed, 191 insertions(+)

New commits:
commit 51478cefaa4e265b42e3f67eda0a64767ff3efba
Author: Eike Rathke <erack at redhat.com>
Date:   Tue Apr 18 16:57:00 2017 +0200

    Resolves: tdf#107012 follow date order of the target locale
    
    ... when converting format codes between locales, so en-US MM/DD/YYYY
    correctly ends up as de-DE DD.MM.YYYY instead of MM.DD.YYYY
    
    Change-Id: Iccfdd4787fc05462f47266c77cc9e95d14dae60d

diff --git a/svl/source/numbers/zforscan.cxx b/svl/source/numbers/zforscan.cxx
index 788cd42e194f..7ba86595b068 100644
--- a/svl/source/numbers/zforscan.cxx
+++ b/svl/source/numbers/zforscan.cxx
@@ -1520,6 +1520,17 @@ int ImpSvNumberformatScan::FinalScanGetCalendar( sal_Int32& nPos, sal_uInt16& i,
     return 0;
 }
 
+bool ImpSvNumberformatScan::IsDateFragment( size_t nPos1, size_t nPos2 ) const
+{
+    return nPos2 - nPos1 == 2 && nTypeArray[nPos1+1] == NF_SYMBOLTYPE_DATESEP;
+}
+
+void ImpSvNumberformatScan::SwapArrayElements( size_t nPos1, size_t nPos2 )
+{
+    std::swap( nTypeArray[nPos1], nTypeArray[nPos2]);
+    std::swap( sStrArray[nPos1], sStrArray[nPos2]);
+}
+
 sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
 {
     const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
@@ -1535,6 +1546,9 @@ sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
     sal_Unicode cOldKeyH    = sKeyword[NF_KEY_H][0];
     sal_Unicode cOldKeyMI   = sKeyword[NF_KEY_MI][0];
     sal_Unicode cOldKeyS    = sKeyword[NF_KEY_S][0];
+    DateOrder eOldDateOrder = pLoc->getDateOrder();
+    sal_uInt16 nDayPos, nMonthPos, nYearPos;
+    nDayPos = nMonthPos = nYearPos = SAL_MAX_UINT16;
 
     // If the group separator is a No-Break Space (French) continue with a
     // normal space instead so queries on space work correctly.
@@ -1546,6 +1560,7 @@ sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
     {
         sOldThousandSep = " ";
     }
+    bool bNewDateOrder = false;
     // change locale data et al
     if (bConvertMode)
     {
@@ -1554,6 +1569,7 @@ sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
         pLoc = pFormatter->GetLocaleData();
         //! init new keywords
         InitKeywords();
+        bNewDateOrder = (eOldDateOrder != pLoc->getDateOrder());
     }
     const CharClass* pChrCls = pFormatter->GetCharClass();
 
@@ -2318,6 +2334,37 @@ sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
             case NF_KEY_RR :                        // RR
                 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
                 nPos = nPos + sStrArray[i].getLength();
+                if (bNewDateOrder)
+                {
+                    // For simple numeric date formats record date order and
+                    // later rearrange.
+                    switch (nTypeArray[i])
+                    {
+                        case NF_KEY_M:
+                        case NF_KEY_MM:
+                            if (nMonthPos == SAL_MAX_UINT16)
+                                nMonthPos = i;
+                            else
+                                bNewDateOrder = false;
+                        break;
+                        case NF_KEY_D:
+                        case NF_KEY_DD:
+                            if (nDayPos == SAL_MAX_UINT16)
+                                nDayPos = i;
+                            else
+                                bNewDateOrder = false;
+                        break;
+                        case NF_KEY_YY:
+                        case NF_KEY_YYYY:
+                            if (nYearPos == SAL_MAX_UINT16)
+                                nYearPos = i;
+                            else
+                                bNewDateOrder = false;
+                        break;
+                        default:
+                            ;   // nothing
+                    }
+                }
                 i++;
                 break;
             default: // Other keywords
@@ -2613,6 +2660,37 @@ sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
                 bTimePart = false;
                 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
                 nPos = nPos + sStrArray[i].getLength();
+                if (bNewDateOrder)
+                {
+                    // For simple numeric date formats record date order and
+                    // later rearrange.
+                    switch (nTypeArray[i])
+                    {
+                        case NF_KEY_M:
+                        case NF_KEY_MM:
+                            if (nMonthPos == SAL_MAX_UINT16)
+                                nMonthPos = i;
+                            else
+                                bNewDateOrder = false;
+                        break;
+                        case NF_KEY_D:
+                        case NF_KEY_DD:
+                            if (nDayPos == SAL_MAX_UINT16)
+                                nDayPos = i;
+                            else
+                                bNewDateOrder = false;
+                        break;
+                        case NF_KEY_YY:
+                        case NF_KEY_YYYY:
+                            if (nYearPos == SAL_MAX_UINT16)
+                                nYearPos = i;
+                            else
+                                bNewDateOrder = false;
+                        break;
+                        default:
+                            ;   // nothing
+                    }
+                }
                 i++;
                 break;
             case NF_KEY_THAI_T :
@@ -2652,6 +2730,110 @@ sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
     }
     if ( bConvertMode )
     {
+        if (bNewDateOrder && sOldDateSep == "-")
+        {
+            // Keep ISO formats Y-M-D, Y-M and M-D
+            if (IsDateFragment( nYearPos, nMonthPos))
+            {
+                nTypeArray[nYearPos+1] = NF_SYMBOLTYPE_STRING;
+                sStrArray[nYearPos+1] = sOldDateSep;
+                bNewDateOrder = false;
+            }
+            if (IsDateFragment( nMonthPos, nDayPos))
+            {
+                nTypeArray[nMonthPos+1] = NF_SYMBOLTYPE_STRING;
+                sStrArray[nMonthPos+1] = sOldDateSep;
+                bNewDateOrder = false;
+            }
+        }
+        if (bNewDateOrder)
+        {
+            // Rearrange date order to the target locale if the original order
+            // includes date separators and is adjacent.
+            /* TODO: for incomplete dates trailing separators need to be
+             * handled according to the locale's usage, e.g. en-US M/D should
+             * be converted to de-DE D.M. and vice versa. As is, it's
+             * M/D -> D.M and D.M. -> M/D/ where specifically the latter looks
+             * odd. Check accepted date patterns and append/remove? */
+            switch (eOldDateOrder)
+            {
+                case DateOrder::DMY:
+                    switch (pLoc->getDateOrder())
+                    {
+                        case DateOrder::MDY:
+                            if (IsDateFragment( nDayPos, nMonthPos))
+                                SwapArrayElements( nDayPos, nMonthPos);
+                        break;
+                        case DateOrder::YMD:
+                            if (nYearPos != SAL_MAX_UINT16)
+                            {
+                                if (IsDateFragment( nDayPos, nMonthPos) && IsDateFragment( nMonthPos, nYearPos))
+                                    SwapArrayElements( nDayPos, nYearPos);
+                            }
+                            else
+                            {
+                                if (IsDateFragment( nDayPos, nMonthPos))
+                                    SwapArrayElements( nDayPos, nMonthPos);
+                            }
+                        break;
+                        default:
+                            ;   // nothing
+                    }
+                break;
+                case DateOrder::MDY:
+                    switch (pLoc->getDateOrder())
+                    {
+                        case DateOrder::DMY:
+                            if (IsDateFragment( nMonthPos, nDayPos))
+                                SwapArrayElements( nMonthPos, nDayPos);
+                        break;
+                        case DateOrder::YMD:
+                            if (nYearPos != SAL_MAX_UINT16)
+                            {
+                                if (IsDateFragment( nMonthPos, nDayPos) && IsDateFragment( nDayPos, nYearPos))
+                                {
+                                    SwapArrayElements( nYearPos, nMonthPos);    // YDM
+                                    SwapArrayElements( nYearPos, nDayPos);      // YMD
+                                }
+                            }
+                        break;
+                        default:
+                            ;   // nothing
+                    }
+                break;
+                case DateOrder::YMD:
+                    switch (pLoc->getDateOrder())
+                    {
+                        case DateOrder::DMY:
+                            if (nYearPos != SAL_MAX_UINT16)
+                            {
+                                if (IsDateFragment( nYearPos, nMonthPos) && IsDateFragment( nMonthPos, nDayPos))
+                                    SwapArrayElements( nYearPos, nDayPos);
+                            }
+                            else
+                            {
+                                if (IsDateFragment( nMonthPos, nDayPos))
+                                    SwapArrayElements( nMonthPos, nDayPos);
+                            }
+                        break;
+                        case DateOrder::MDY:
+                            if (nYearPos != SAL_MAX_UINT16)
+                            {
+                                if (IsDateFragment( nYearPos, nMonthPos) && IsDateFragment( nMonthPos, nDayPos))
+                                {
+                                    SwapArrayElements( nYearPos, nDayPos);      // DMY
+                                    SwapArrayElements( nYearPos, nMonthPos);    // MDY
+                                }
+                            }
+                        break;
+                        default:
+                            ;   // nothing
+                    }
+                break;
+                default:
+                    ;   // nothing
+            }
+        }
         // strings containing keywords of the target locale must be quoted, so
         // the user sees the difference and is able to edit the format string
         for ( i=0; i < nAnzStrings; i++ )
diff --git a/svl/source/numbers/zforscan.hxx b/svl/source/numbers/zforscan.hxx
index 30fc8384e80b..13d5b1a67177 100644
--- a/svl/source/numbers/zforscan.hxx
+++ b/svl/source/numbers/zforscan.hxx
@@ -241,6 +241,15 @@ private: // Private section
         reused instead of shifting all one up and nPos is decremented! */
     bool InsertSymbol( sal_uInt16 & nPos, svt::NfSymbolType eType, const OUString& rStr );
 
+    /** Whether two key symbols are adjacent separated by date separator.
+        This can only be used at the end of FinalScan() after
+        NF_SYMBOLTYPE_DATESEP has already been set.
+     */
+    bool IsDateFragment( size_t nPos1, size_t nPos2 ) const;
+
+    /** Swap nTypeArray and sStrArray elements at positions. */
+    void SwapArrayElements( size_t nPos1, size_t nPos2 );
+
     static bool StringEqualsChar( const OUString& rStr, sal_Unicode ch )
         { return rStr.getLength() == 1 && rStr[0] == ch; }
 


More information about the Libreoffice-commits mailing list