diff options
-rw-r--r-- | sw/CppunitTest_sw_layoutwriter.mk | 72 | ||||
-rw-r--r-- | sw/Module_sw.mk | 1 | ||||
-rw-r--r-- | sw/inc/calc.hxx | 1 | ||||
-rw-r--r-- | sw/inc/usrfld.hxx | 14 | ||||
-rw-r--r-- | sw/qa/extras/layout/data/user-field-type-language.fodt | 21 | ||||
-rw-r--r-- | sw/qa/extras/layout/layout.cxx | 63 | ||||
-rw-r--r-- | sw/source/core/bastyp/calc.cxx | 5 | ||||
-rw-r--r-- | sw/source/core/fields/usrfld.cxx | 31 |
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: |