sw/inc/calc.hxx                                        |    1 
 sw/inc/usrfld.hxx                                      |   14 +++++++
 sw/qa/extras/layout/data/user-field-type-language.fodt |   21 +++++++++++
 sw/qa/extras/layout/layout.cxx                         |   24 +++++++++++++
 sw/source/core/bastyp/calc.cxx                         |    5 ++
 sw/source/core/fields/usrfld.cxx                       |   31 ++++++++++++++---
 6 files changed, 92 insertions(+), 4 deletions(-)

New commits:
commit 6ca5d288ca810f128163da121777ee2e11c46edc
Author:     Miklos Vajna <vmik...@collabora.co.uk>
AuthorDate: Thu Aug 2 17:53:06 2018 +0200
Commit:     Miklos Vajna <vmik...@collabora.co.uk>
CommitDate: Thu Aug 2 19:10:23 2018 +0200

    sw user field type: fix locale of string -> float conversion
    
    The key part is the SwUserFieldType::GetValue() hunk, the field type has
    to always use the same locale, which means if we get an SwCalc reference
    that works with the document or field locale that has to be switched
    temporarily.
    
    Change-Id: I26ff18e74f477729a66b066c4baf6d215a7685bc
    Reviewed-on: https://gerrit.libreoffice.org/58492
    Reviewed-by: Miklos Vajna <vmik...@collabora.co.uk>
    Tested-by: Jenkins

diff --git a/sw/inc/calc.hxx b/sw/inc/calc.hxx
index 3396c506ab18..94d2643a547f 100644
--- a/sw/inc/calc.hxx
+++ b/sw/inc/calc.hxx
@@ -231,6 +231,7 @@ public:
 
     bool        Push(const SwUserFieldType* pUserFieldType);
     void        Pop();
+    CharClass* GetCharClass();
 
     void        SetCalcError( SwCalcError eErr )    { m_eError = eErr; }
     bool        IsCalcError() const                 { return SwCalcError::NONE 
!= m_eError; }
diff --git a/sw/inc/usrfld.hxx b/sw/inc/usrfld.hxx
index e98258c624c3..ee565278fe6d 100644
--- a/sw/inc/usrfld.hxx
+++ b/sw/inc/usrfld.hxx
@@ -26,12 +26,20 @@ class SfxPoolItem;
 class SwCalc;
 class SwDoc;
 
+/**
+ * The shared part of a user field.
+ *
+ * Tracks the value, but conversion between the float and string representation
+ * always happens with the system locale.
+ */
 class SW_DLLPUBLIC SwUserFieldType : public SwValueFieldType
 {
     bool    bValidValue : 1;
     bool    bDeleted : 1;
+    /// Float value type.
     double  nValue;
     OUString  aName;
+    /// String value type.
     OUString  aContent;
     sal_uInt16  nType;
 
@@ -84,6 +92,12 @@ inline void SwUserFieldType::SetType(sal_uInt16 nSub)
     EnableFormat(!(nSub & nsSwGetSetExpType::GSE_STRING));
 }
 
+/**
+ * The non-shared part of a user field.
+ *
+ * Tracks the number format and the language, conversion between the float and
+ * string representation is independent from the system locale.
+ */
 class SW_DLLPUBLIC SwUserField : public SwValueField
 {
     sal_uInt16  nSubType;
diff --git a/sw/qa/extras/layout/data/user-field-type-language.fodt 
b/sw/qa/extras/layout/data/user-field-type-language.fodt
new file mode 100644
index 000000000000..f741add7ddd7
--- /dev/null
+++ b/sw/qa/extras/layout/data/user-field-type-language.fodt
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document 
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 
office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
+  <office:styles>
+    <style:default-style style:family="paragraph">
+      <style:text-properties fo:language="en" fo:country="GB"/>
+    </style:default-style>
+  </office:styles>
+  <office:automatic-styles>
+    <number:number-style style:name="N10004" number:language="en" 
number:country="GB">
+      <number:number number:decimal-places="2" number:min-integer-digits="1" 
number:grouping="true"/>
+    </number:number-style>
+  </office:automatic-styles>
+  <office:body>
+    <office:text text:use-soft-page-breaks="true">
+      <text:user-field-decls>
+        <text:user-field-decl office:value-type="float" office:value="1234.56" 
text:name="user-field-decl-name-example"/>
+      </text:user-field-decls>
+      <text:p>Before <text:user-field-get style:data-style-name="N10004" 
text:name="user-field-decl-name-example">1,234.56</text:user-field-get> 
after.</text:p>
+    </office:text>
+  </office:body>
+</office:document>
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 96dfcc0a2757..2325fd84e5a2 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -10,6 +10,8 @@
 #include <swmodeltestbase.hxx>
 #include <test/mtfxmldump.hxx>
 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
+#include <comphelper/scopeguard.hxx>
+#include <unotools/syslocaleoptions.hxx>
 
 static char const DATA_DIRECTORY[] = "/sw/qa/extras/layout/data/";
 
@@ -28,6 +30,7 @@ public:
     void testTdf118672();
     void testTdf117923();
     void testTdf109077();
+    void testUserFieldTypeLanguage();
 
     CPPUNIT_TEST_SUITE(SwLayoutWriter);
     CPPUNIT_TEST(testTdf116830);
@@ -41,6 +44,7 @@ public:
     CPPUNIT_TEST(testTdf118672);
     CPPUNIT_TEST(testTdf117923);
     CPPUNIT_TEST(testTdf109077);
+    CPPUNIT_TEST(testUserFieldTypeLanguage);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -250,6 +254,26 @@ void SwLayoutWriter::testTdf109077()
     CPPUNIT_ASSERT_LESS(static_cast<sal_Int32>(15), nTextBoxTop - nShapeTop);
 }
 
+void SwLayoutWriter::testUserFieldTypeLanguage()
+{
+    // Set the system locale to German, the document will be English.
+    SvtSysLocaleOptions aOptions;
+    aOptions.SetLocaleConfigString("de-DE");
+    aOptions.Commit();
+    comphelper::ScopeGuard g([&aOptions] {
+        aOptions.SetLocaleConfigString(OUString());
+        aOptions.Commit();
+    });
+
+    SwDoc* pDoc = createDoc("user-field-type-language.fodt");
+    SwViewShell* pViewShell = 
pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
+    pViewShell->UpdateFields();
+    xmlDocPtr pXmlDoc = parseLayoutDump();
+    // This was "123,456.00", via a buggy 1234.56 -> 1234,56 -> 123456 ->
+    // 123,456.00 transform chain.
+    assertXPath(pXmlDoc, "/root/page/body/txt/Special[@nType='POR_FLD']", 
"rText", "1,234.56");
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwLayoutWriter);
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/core/bastyp/calc.cxx b/sw/source/core/bastyp/calc.cxx
index d9c3f682ed5b..ed59425aa964 100644
--- a/sw/source/core/bastyp/calc.cxx
+++ b/sw/source/core/bastyp/calc.cxx
@@ -609,6 +609,11 @@ void SwCalc::Pop()
     m_aRekurStack.pop_back();
 }
 
+CharClass* SwCalc::GetCharClass()
+{
+    return m_pCharClass;
+}
+
 SwCalcOper SwCalc::GetToken()
 {
     if( m_nCommandPos >= m_sCommand.getLength() )
diff --git a/sw/source/core/fields/usrfld.cxx b/sw/source/core/fields/usrfld.cxx
index d81ba1c84ae8..5537fc36ea92 100644
--- a/sw/source/core/fields/usrfld.cxx
+++ b/sw/source/core/fields/usrfld.cxx
@@ -41,6 +41,18 @@
 
 using namespace ::com::sun::star;
 
+namespace
+{
+/**
+ * Returns the language used for float <-> string conversions in
+ * SwUserFieldType.
+ */
+LanguageType GetFieldTypeLanguage()
+{
+    return LANGUAGE_SYSTEM;
+}
+}
+
 // Userfields
 
 SwUserField::SwUserField(SwUserFieldType* pTyp, sal_uInt16 nSub, sal_uInt32 
nFormat)
@@ -232,7 +244,21 @@ double SwUserFieldType::GetValue( SwCalc& rCalc )
         rCalc.SetCalcError( SwCalcError::Syntax );
         return 0;
     }
+
+    // See if we need to temporarily switch rCalc's language: in case it
+    // differs from the field type locale.
+    CharClass* pCharClass = rCalc.GetCharClass();
+    LanguageTag aCalcLanguage = pCharClass->getLanguageTag();
+    LanguageTag aFieldTypeLanguage(GetFieldTypeLanguage());
+    bool bSwitchLanguage = aCalcLanguage != aFieldTypeLanguage;
+    if (bSwitchLanguage)
+        pCharClass->setLanguageTag(aFieldTypeLanguage);
+
     nValue = rCalc.Calculate( aContent ).GetDouble();
+
+    if (bSwitchLanguage)
+        pCharClass->setLanguageTag(aCalcLanguage);
+
     rCalc.Pop();
 
     if( !rCalc.IsCalcError() )
@@ -313,10 +339,7 @@ void SwUserFieldType::PutValue( const uno::Any& rAny, 
sal_uInt16 nWhichId )
             rAny >>= fVal;
             nValue = fVal;
 
-            // The following line is in fact wrong, since the language is 
unknown (is part of the
-            // field) and, thus, aContent should also belong to the field. 
Each field can have a
-            // different language, but the same content with just different 
formatting.
-            aContent = DoubleToString(nValue, 
static_cast<sal_uInt16>(LANGUAGE_SYSTEM));
+            aContent = DoubleToString(nValue, 
static_cast<sal_uInt16>(GetFieldTypeLanguage()));
         }
         break;
     case FIELD_PROP_PAR2:
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to