summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/CppunitTest_sw_layoutwriter.mk72
-rw-r--r--sw/Module_sw.mk1
-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.cxx63
-rw-r--r--sw/source/core/bastyp/calc.cxx5
-rw-r--r--sw/source/core/fields/usrfld.cxx31
8 files changed, 204 insertions, 4 deletions
diff --git a/sw/CppunitTest_sw_layoutwriter.mk b/sw/CppunitTest_sw_layoutwriter.mk
new file mode 100644
index 000000000000..675299180e44
--- /dev/null
+++ b/sw/CppunitTest_sw_layoutwriter.mk
@@ -0,0 +1,72 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_layoutwriter))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_layoutwriter, \
+ sw/qa/extras/layout/layout \
+))
+
+# note: this links msword only for the reason to have a order dependency,
+# because "make sw.check" will not see the dependency through services.rdb
+$(eval $(call gb_CppunitTest_use_libraries,sw_layoutwriter, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ editeng \
+ msword \
+ sal \
+ sfx \
+ svl \
+ svt \
+ svxcore \
+ sw \
+ test \
+ unotest \
+ vcl \
+ tl \
+ utl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_layoutwriter,\
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sw_layoutwriter,\
+ -I$(SRCDIR)/sw/inc \
+ -I$(SRCDIR)/sw/source/core/inc \
+ -I$(SRCDIR)/sw/qa/extras/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,sw_layoutwriter))
+
+$(eval $(call gb_CppunitTest_use_ure,sw_layoutwriter))
+$(eval $(call gb_CppunitTest_use_vcl,sw_layoutwriter))
+
+$(eval $(call gb_CppunitTest_use_rdb,sw_layoutwriter,services))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_layoutwriter))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,sw_layoutwriter, \
+ modules/swriter \
+))
+
+$(call gb_CppunitTest_get_target,sw_layoutwriter): \
+ $(call gb_Library_get_target,textconv_dict)
+
+ifneq ($(filter MORE_FONTS,$(BUILD_TYPE)),)
+$(call gb_CppunitTest_get_target,sw_layoutwriter): \
+ $(call gb_ExternalPackage_get_target,fonts_liberation)
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index 39b466fc616f..981c68836ce8 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -69,6 +69,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
CppunitTest_sw_odfexport \
CppunitTest_sw_odfimport \
CppunitTest_sw_uiwriter \
+ CppunitTest_sw_layoutwriter \
CppunitTest_sw_mailmerge \
CppunitTest_sw_globalfilter \
))
diff --git a/sw/inc/calc.hxx b/sw/inc/calc.hxx
index 6b85dbdf0968..fd68e0708ced 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 ) { eError = eErr; }
bool IsCalcError() const { return 0 != eError; }
diff --git a/sw/inc/usrfld.hxx b/sw/inc/usrfld.hxx
index 8f57b78c4787..c874a9dea769 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;
@@ -87,6 +95,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
new file mode 100644
index 000000000000..84d1e55e5a22
--- /dev/null
+++ b/sw/qa/extras/layout/layout.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#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/";
+
+/// Test to assert layout / rendering result of Writer.
+class SwLayoutWriter : public SwModelTestBase
+{
+public:
+ void testUserFieldTypeLanguage();
+
+ CPPUNIT_TEST_SUITE(SwLayoutWriter);
+ CPPUNIT_TEST(testUserFieldTypeLanguage);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ SwDoc* createDoc(const char* pName = nullptr);
+};
+
+SwDoc* SwLayoutWriter::createDoc(const char* pName)
+{
+ load(DATA_DIRECTORY, pName);
+
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ return pTextDoc->GetDocShell()->GetDoc();
+}
+
+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();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/bastyp/calc.cxx b/sw/source/core/bastyp/calc.cxx
index 272b89f9357f..9f58d3bd5115 100644
--- a/sw/source/core/bastyp/calc.cxx
+++ b/sw/source/core/bastyp/calc.cxx
@@ -633,6 +633,11 @@ void SwCalc::Pop()
aRekurStack.pop_back();
}
+CharClass* SwCalc::GetCharClass()
+{
+ return pCharClass;
+}
+
SwCalcOper SwCalc::GetToken()
{
#if OSL_DEBUG_LEVEL > 1
diff --git a/sw/source/core/fields/usrfld.cxx b/sw/source/core/fields/usrfld.cxx
index e14ffa13e037..f67f74a81113 100644
--- a/sw/source/core/fields/usrfld.cxx
+++ b/sw/source/core/fields/usrfld.cxx
@@ -35,6 +35,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)
@@ -218,7 +230,21 @@ double SwUserFieldType::GetValue( SwCalc& rCalc )
rCalc.SetCalcError( CALC_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() )
@@ -302,10 +328,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_uInt32>(LANGUAGE_SYSTEM));
+ aContent = DoubleToString(nValue, static_cast<sal_uInt16>(GetFieldTypeLanguage()));
}
break;
case FIELD_PROP_PAR2: