summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2018-08-02 17:53:06 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2018-08-13 16:31:46 +0200
commit7e80dd415c7dc8af2d4e61fcfa4f10ebe1dfb71d (patch)
tree8788ec75eafbfc8ec80996844c75a67c7e3bd196
parent6391274bbaf9c3ccd7b4ceb593317b9321a5fe15 (diff)
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. Reviewed-on: https://gerrit.libreoffice.org/58492 Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk> Tested-by: Jenkins (cherry picked from commit 6ca5d288ca810f128163da121777ee2e11c46edc) Conflicts: sw/qa/extras/layout/layout.cxx Change-Id: I26ff18e74f477729a66b066c4baf6d215a7685bc
-rw-r--r--sw/inc/calc.hxx1
-rw-r--r--sw/inc/usrfld.hxx14
-rw-r--r--sw/qa/extras/layout/data/user-field-type-language.fodt21
-rw-r--r--sw/qa/extras/layout/layout.cxx24
-rw-r--r--sw/source/core/bastyp/calc.cxx5
-rw-r--r--sw/source/core/fields/usrfld.cxx31
6 files changed, 92 insertions, 4 deletions
diff --git a/sw/inc/calc.hxx b/sw/inc/calc.hxx
index c6f3380cceee..125c5e2f6ab9 100644
--- a/sw/inc/calc.hxx
+++ b/sw/inc/calc.hxx
@@ -197,6 +197,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 9d241df8a118..a439a3a7412f 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;
@@ -83,6 +91,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 9a73e2025147..7167647ac93b 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -9,6 +9,8 @@
#include <swmodeltestbase.hxx>
#include <test/mtfxmldump.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <unotools/syslocaleoptions.hxx>
static char const DATA_DIRECTORY[] = "/sw/qa/extras/layout/data/";
@@ -19,11 +21,13 @@ public:
void testTdf116830();
void testTdf116925();
void testTdf117028();
+ void testUserFieldTypeLanguage();
CPPUNIT_TEST_SUITE(SwLayoutWriter);
CPPUNIT_TEST(testTdf116830);
CPPUNIT_TEST(testTdf116925);
CPPUNIT_TEST(testTdf117028);
+ CPPUNIT_TEST(testUserFieldTypeLanguage);
CPPUNIT_TEST_SUITE_END();
private:
@@ -108,6 +112,26 @@ void SwLayoutWriter::testTdf117028()
assertXPathContent(pXmlDoc, "//textarray/text", "Hello");
}
+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 0edb21517878..1532a3a898b7 100644
--- a/sw/source/core/bastyp/calc.cxx
+++ b/sw/source/core/bastyp/calc.cxx
@@ -637,6 +637,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 080dcfc77bd1..0b25a940802a 100644
--- a/sw/source/core/fields/usrfld.cxx
+++ b/sw/source/core/fields/usrfld.cxx
@@ -39,6 +39,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)
@@ -222,7 +234,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() )
@@ -306,10 +332,7 @@ bool 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: