Kaydet (Commit) e87f6c24 authored tarafından Miklos Vajna's avatar Miklos Vajna Kaydeden (comit) Miklos Vajna

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/58492Reviewed-by: 's avatarMiklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins
(cherry picked from commit 6ca5d288)

Conflicts:
	sw/qa/extras/layout/layout.cxx
	sw/source/core/fields/usrfld.cxx

Change-Id: I26ff18e74f477729a66b066c4baf6d215a7685bc
(cherry picked from commit 5109f63c)
üst db51bd20
# -*- 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:
...@@ -69,6 +69,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\ ...@@ -69,6 +69,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
CppunitTest_sw_odfexport \ CppunitTest_sw_odfexport \
CppunitTest_sw_odfimport \ CppunitTest_sw_odfimport \
CppunitTest_sw_uiwriter \ CppunitTest_sw_uiwriter \
CppunitTest_sw_layoutwriter \
CppunitTest_sw_mailmerge \ CppunitTest_sw_mailmerge \
CppunitTest_sw_globalfilter \ CppunitTest_sw_globalfilter \
)) ))
......
...@@ -197,6 +197,7 @@ public: ...@@ -197,6 +197,7 @@ public:
bool Push(const SwUserFieldType* pUserFieldType); bool Push(const SwUserFieldType* pUserFieldType);
void Pop(); void Pop();
CharClass* GetCharClass();
void SetCalcError( SwCalcError eErr ) { eError = eErr; } void SetCalcError( SwCalcError eErr ) { eError = eErr; }
bool IsCalcError() const { return 0 != eError; } bool IsCalcError() const { return 0 != eError; }
......
...@@ -26,12 +26,20 @@ class SfxPoolItem; ...@@ -26,12 +26,20 @@ class SfxPoolItem;
class SwCalc; class SwCalc;
class SwDoc; 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 class SW_DLLPUBLIC SwUserFieldType : public SwValueFieldType
{ {
bool bValidValue : 1; bool bValidValue : 1;
bool bDeleted : 1; bool bDeleted : 1;
/// Float value type.
double nValue; double nValue;
OUString aName; OUString aName;
/// String value type.
OUString aContent; OUString aContent;
sal_uInt16 nType; sal_uInt16 nType;
...@@ -87,6 +95,12 @@ inline void SwUserFieldType::SetType(sal_uInt16 nSub) ...@@ -87,6 +95,12 @@ inline void SwUserFieldType::SetType(sal_uInt16 nSub)
EnableFormat(!(nSub & nsSwGetSetExpType::GSE_STRING)); 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 class SW_DLLPUBLIC SwUserField : public SwValueField
{ {
sal_uInt16 nSubType; sal_uInt16 nSubType;
......
<?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>
/* -*- 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: */
...@@ -633,6 +633,11 @@ void SwCalc::Pop() ...@@ -633,6 +633,11 @@ void SwCalc::Pop()
aRekurStack.pop_back(); aRekurStack.pop_back();
} }
CharClass* SwCalc::GetCharClass()
{
return pCharClass;
}
SwCalcOper SwCalc::GetToken() SwCalcOper SwCalc::GetToken()
{ {
#if OSL_DEBUG_LEVEL > 1 #if OSL_DEBUG_LEVEL > 1
......
...@@ -35,6 +35,18 @@ ...@@ -35,6 +35,18 @@
using namespace ::com::sun::star; using namespace ::com::sun::star;
namespace
{
/**
* Returns the language used for float <-> string conversions in
* SwUserFieldType.
*/
LanguageType GetFieldTypeLanguage()
{
return LANGUAGE_SYSTEM;
}
}
// Userfields // Userfields
SwUserField::SwUserField(SwUserFieldType* pTyp, sal_uInt16 nSub, sal_uInt32 nFormat) SwUserField::SwUserField(SwUserFieldType* pTyp, sal_uInt16 nSub, sal_uInt32 nFormat)
...@@ -218,7 +230,21 @@ double SwUserFieldType::GetValue( SwCalc& rCalc ) ...@@ -218,7 +230,21 @@ double SwUserFieldType::GetValue( SwCalc& rCalc )
rCalc.SetCalcError( CALC_SYNTAX ); rCalc.SetCalcError( CALC_SYNTAX );
return 0; 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(); nValue = rCalc.Calculate( aContent ).GetDouble();
if (bSwitchLanguage)
pCharClass->setLanguageTag(aCalcLanguage);
rCalc.Pop(); rCalc.Pop();
if( !rCalc.IsCalcError() ) if( !rCalc.IsCalcError() )
...@@ -302,10 +328,7 @@ bool SwUserFieldType::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId ) ...@@ -302,10 +328,7 @@ bool SwUserFieldType::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
rAny >>= fVal; rAny >>= fVal;
nValue = fVal; nValue = fVal;
// The following line is in fact wrong, since the language is unknown (is part of the aContent = DoubleToString(nValue, static_cast<sal_uInt16>(GetFieldTypeLanguage()));
// 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));
} }
break; break;
case FIELD_PROP_PAR2: case FIELD_PROP_PAR2:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment