tdf#167761 sw format redline, char style+direct: add ODT export

The bugdoc contains a format redline that changes the character style
from Strong to Quote and the font size from 24 to 36. Exporting to ODT,
loading the ODT and rejecting the redline, the font size is set to 24,
but the character style is set to default instead of Strong.

What happens is that the item set of the format redline contains the
necessary SvxFontHeightItem, but contains no SwFormatCharFormat. This is
because the ODT export writes no parents for char automatic styles,
because char formatting outside the redline table has 2 pool items for
such char formatting: a dedicated SwFormatCharFormat for the char style
and a separate SwFormatAutoFormat for other char props, so the ODT
export "knows" to ignore the autoformat parent and creates this markup:
<text:span text:style-name="...named style..."><text:span text:style-name="...automatic style...">t</text:span></text:span>

Fix the problem by explicitly exporting the parent style name when we
write an automatic style that is referred from the redline table (and
not from the body text). This is similar to what e.g. "frame" autostyles
already do, which also have parents. The result is this markup:
    <style:style style:name="..." style:family="text" style:parent-style-name="Strong_20_Emphasis">
      <style:text-properties fo:font-size="24pt"/>
...
          <text:format-change loext:style-name="...">
which contains both the named character style name and the automatic
style, describing the direct formatting.

The ODT import side still needs fixing.

Change-Id: I19a67cf5e2c538cfcfa1b13097241954667d2c89
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190181
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Miklos Vajna
2025-08-26 12:32:30 +02:00
parent b188d71d49
commit c625247680
6 changed files with 87 additions and 7 deletions
+4 -2
View File
@@ -195,7 +195,8 @@ public:
const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
bool& rbHasCharStyle,
bool& rbHasAutoStyle,
const XMLPropertyState** pAddState = nullptr) const;
const XMLPropertyState** pAddState = nullptr,
const OUString* pParentName = nullptr) const;
void exportTextRangeEnumeration(
const css::uno::Reference< css::container::XEnumeration > & rRangeEnum,
@@ -400,7 +401,8 @@ public:
void Add(
XmlStyleFamily nFamily,
const css::uno::Reference< css::beans::XPropertySet > & rPropSet,
std::span<const XMLPropertyState> aAddStates = {} );
std::span<const XMLPropertyState> aAddStates = {},
bool bCheckParent = false );
/// find style name for specified family and parent
OUString Find(
+1
View File
@@ -19,6 +19,7 @@ $(eval $(call gb_CppunitTest_use_externals,xmloff_text,\
$(eval $(call gb_CppunitTest_add_exception_objects,xmloff_text, \
xmloff/qa/unit/text \
xmloff/qa/unit/text/txtprmap \
xmloff/qa/unit/text/txtparae \
))
$(eval $(call gb_CppunitTest_use_libraries,xmloff_text, \
+53
View File
@@ -0,0 +1,53 @@
/* -*- 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 <test/unoapixml_test.hxx>
using namespace com::sun::star;
namespace
{
/// Covers xmloff/source/text/txtparae.cxx fixes.
class Test : public UnoApiXmlTest
{
public:
Test();
};
Test::Test()
: UnoApiXmlTest(u"/xmloff/qa/unit/text/data/"_ustr)
{
}
CPPUNIT_TEST_FIXTURE(Test, testRedlineFormatCharStyleDirectExport)
{
// Given a document that contains a format redline: both the character style and direct
// formatting changes:
loadFromFile(u"format-charstyle-direct.docx");
// When exporting the document to ODT:
save(u"writer8"_ustr);
// Then make sure the named style is not lost in the redline:
xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
OString aAutoName
= getXPath(pXmlDoc, "//text:tracked-changes/text:changed-region/text:format-change",
"style-name")
.toUtf8();
// Without the accompanying fix in place, this test would have failed with:
// - XPath '//office:automatic-styles/style:style[@style:name='T2']' no attribute 'parent-style-name' exist
// i.e. the named character style in the format redline was lost.
OUString aParentName = getXPath(
pXmlDoc, "//office:automatic-styles/style:style[@style:name='" + aAutoName + "']",
"parent-style-name");
CPPUNIT_ASSERT_EQUAL(u"Strong_20_Emphasis"_ustr, aParentName);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+13 -2
View File
@@ -269,7 +269,10 @@ void XMLRedlineExport::ExportChangeAutoStyle(
aAny >>= xAutoFormat;
if (xAutoFormat.is())
{
rExport.GetTextParagraphExport()->Add(XmlStyleFamily::TEXT_TEXT, xAutoFormat);
// Check for parent style when declaring the automatic style.
rExport.GetTextParagraphExport()->Add(XmlStyleFamily::TEXT_TEXT, xAutoFormat,
/*aAddStates=*/{},
/*bCheckParent=*/true);
}
}
@@ -373,7 +376,15 @@ void XMLRedlineExport::ExportChangedRegion(
{
bool bIsUICharStyle;
bool bHasAutoStyle;
OUString sStyle = rExport.GetTextParagraphExport()->FindTextStyle(xAutoStyle, bIsUICharStyle, bHasAutoStyle);
OUString aParentName;
uno::Reference<beans::XPropertySetInfo> xPropSetInfo = xAutoStyle->getPropertySetInfo();
if (xPropSetInfo->hasPropertyByName("CharStyleName"))
{
// Consider parent style when referring to the declared automatic style.
xAutoStyle->getPropertyValue("CharStyleName") >>= aParentName;
}
OUString sStyle = rExport.GetTextParagraphExport()->FindTextStyle(
xAutoStyle, bIsUICharStyle, bHasAutoStyle, /*pAddState=*/nullptr, &aParentName);
if (!sStyle.isEmpty())
{
rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_STYLE_NAME, rExport.EncodeStyleName(sStyle));
+16 -3
View File
@@ -653,7 +653,8 @@ void FieldParamExporter::ExportParameter(const OUString& sKey, const OUString& s
void XMLTextParagraphExport::Add( XmlStyleFamily nFamily,
const Reference < XPropertySet > & rPropSet,
const std::span<const XMLPropertyState> aAddStates )
const std::span<const XMLPropertyState> aAddStates,
bool bCheckParent )
{
rtl::Reference < SvXMLExportPropertyMapper > xPropMapper;
switch( nFamily )
@@ -737,6 +738,11 @@ void XMLTextParagraphExport::Add( XmlStyleFamily nFamily,
break;
case XmlStyleFamily::TEXT_TEXT:
{
if (bCheckParent && xPropSetInfo->hasPropertyByName(gsCharStyleName))
{
rPropSet->getPropertyValue(gsCharStyleName) >>= sParent;
}
// Get parent and remove hyperlinks (they aren't of interest)
rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper());
sal_uInt16 nIgnoreProps = 0;
@@ -912,7 +918,8 @@ OUString XMLTextParagraphExport::FindTextStyle(
const Reference < XPropertySet > & rPropSet,
bool& rbHasCharStyle,
bool& rbHasAutoStyle,
const XMLPropertyState** ppAddStates ) const
const XMLPropertyState** ppAddStates,
const OUString* pParentName) const
{
rtl::Reference < SvXMLExportPropertyMapper > xPropMapper(GetTextPropMapper());
std::vector<XMLPropertyState> aPropStates(xPropMapper->Filter(GetExport(), rPropSet));
@@ -975,9 +982,15 @@ OUString XMLTextParagraphExport::FindTextStyle(
aPropStates.erase( aSecondDel );
aPropStates.erase( aFirstDel );
}
OUString aParentName;
if (pParentName)
{
// Format redlines can have an autostyle with a parent.
aParentName = *pParentName;
}
sName = GetAutoStylePool().Find(
XmlStyleFamily::TEXT_TEXT,
OUString(), // AutoStyles should not have parents!
aParentName,
aPropStates );
rbHasAutoStyle = true;
}