tdf#167761 sw format redline, char style: implement DOCX import

Open the bugdoc, there should be a format redline that tracks the change
of the char style from Strong to QuoteChar, but the doc model contains
no redlines.

What happens is that we try to handle character style as a character
property, but SwUnoCursorHelper::makeRedline() uses
SfxItemPropertySet::setPropertyValue() for CharStyleName, which calls
into SwFormatCharFormat::PutValue(), which fails, so the redline is not
created.

Fix the problem by reusing lcl_setCharStyle(), that knows how to set the
character style on an item set.

The DOCX export worked already.

Change-Id: I9479cadfdf6cb598cd4b11d49d851236c8ec09e3
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189918
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins
This commit is contained in:
Miklos Vajna
2025-08-19 16:25:42 +02:00
parent a0eb4dcd04
commit a6d8608595
7 changed files with 88 additions and 7 deletions
@@ -4160,7 +4160,7 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
</rng:element>
</rng:define>
<!-- https://lists.freedesktop.org/archives/libreoffice/2025-May/093327.html Hierarchical tracked changes -->
<!-- https://issues.oasis-open.org/browse/OFFICE-4174 Hierarchical tracked changes -->
<rng:define name="text-changed-region" combine="choice">
<rng:element name="text:changed-region">
<rng:ref name="text-changed-region-attr"/>
@@ -4171,7 +4171,7 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
</rng:element>
</rng:define>
<!-- TODO(vmiklos) no proposal for style on format changes -->
<!-- https://issues.oasis-open.org/browse/OFFICE-4173 Style on format changes -->
<rng:define name="text-changed-region-content" combine="choice">
<rng:element name="text:format-change">
<rng:optional>
+1
View File
@@ -15,6 +15,7 @@ $(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_core_unocore))
$(eval $(call gb_CppunitTest_add_exception_objects,sw_core_unocore, \
sw/qa/core/unocore/unocore \
sw/qa/core/unocore/unocrsrhelper \
))
# note: this links msword only for the reason to have an order dependency,
+2
View File
@@ -242,6 +242,8 @@ namespace SwUnoCursorHelper
css::uno::Reference<css::text::XFlatParagraphIterator>
CreateFlatParagraphIterator(SwDoc &, sal_Int32, bool);
void SetCharStyle(SwDoc& rDoc, const css::uno::Any& rValue, SfxItemSet& rSet);
} // namespace SwUnoCursorHelper
#endif
+65
View File
@@ -0,0 +1,65 @@
/* -*- 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 <IDocumentRedlineAccess.hxx>
#include <docsh.hxx>
#include <fchrfmt.hxx>
#include <redline.hxx>
#include <wrtsh.hxx>
using namespace com::sun::star;
namespace
{
/// Covers sw/source/core/unocore/unocrsrhelper.cxx fixes.
class Test : public SwModelTestBase
{
public:
Test()
: SwModelTestBase(u"/sw/qa/core/unocore/data/"_ustr)
{
}
};
CPPUNIT_TEST_FIXTURE(Test, testFormatCharStyleChangeDocxImport)
{
// Given a document with a format redline, containing a char style change (strong -> quote):
// When importing that document:
createSwDoc("format-char-style-change.docx");
// Then make sure the model has the new style name, the redline has the old style name:
SwDocShell* pDocShell = getSwDocShell();
SwDoc* pDoc = pDocShell->GetDoc();
SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
pWrtShell->SttEndDoc(/*bStt=*/false);
SfxItemSetFixed<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT> aSet(pDoc->GetAttrPool());
pWrtShell->GetCurAttr(aSet);
const SwFormatCharFormat& rNewCharFormat = aSet.Get(RES_TXTATR_CHARFMT);
CPPUNIT_ASSERT_EQUAL(u"Quote Char"_ustr, rNewCharFormat.GetCharFormat()->GetName().toString());
const IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
const SwRedlineTable& rRedlineTable = rIDRA.GetRedlineTable();
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 1
// - Actual : 0
// i.e. the import result had no redlines.
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlineTable.size());
const SwRangeRedline* pRedline = rRedlineTable[0];
auto pExtraData = dynamic_cast<const SwRedlineExtraData_FormatColl*>(pRedline->GetExtraData());
CPPUNIT_ASSERT(pExtraData);
std::shared_ptr<SfxItemSet> pRedlineSet = pExtraData->GetItemSet();
CPPUNIT_ASSERT(pRedlineSet);
const SwFormatCharFormat& rOldCharFormat = pRedlineSet->Get(RES_TXTATR_CHARFMT);
CPPUNIT_ASSERT_EQUAL(u"Strong Emphasis"_ustr,
rOldCharFormat.GetCharFormat()->GetName().toString());
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+10
View File
@@ -1324,6 +1324,7 @@ void makeRedline( SwPaM const & rPaM,
std::vector<uno::Any> aValues;
aEntries.reserve(aRevertProperties.getLength());
sal_uInt16 nStyleId = USHRT_MAX;
sal_uInt16 nCharStyleId = USHRT_MAX;
sal_uInt16 nNumId = USHRT_MAX;
for (const auto& rRevertProperty : aRevertProperties)
{
@@ -1349,6 +1350,10 @@ void makeRedline( SwPaM const & rPaM,
aWhichPairs = aWhichPairs.MergeRange(pEntry->nWID, pEntry->nWID);
if (rPropertyName == "ParaStyleName")
nStyleId = aEntries.size();
else if (rPropertyName == "CharStyleName")
{
nCharStyleId = aEntries.size();
}
}
aEntries.push_back(pEntry);
aValues.push_back(rRevertProperty.Value);
@@ -1378,6 +1383,11 @@ void makeRedline( SwPaM const & rPaM,
pRule->SetUsedByRedline(true);
}
}
else if (i == nCharStyleId)
{
// Set this manually, SwFormatCharFormat::PutValue() would fail.
SwUnoCursorHelper::SetCharStyle(rDoc, rValue, aItemSet);
}
else
{
SfxItemPropertyMapEntry const*const pEntry = aEntries[i];
+8 -5
View File
@@ -177,10 +177,12 @@ void SwUnoCursorHelper::GetTextFromPam(SwPaM & rPam, OUString & rBuffer,
}
namespace SwUnoCursorHelper
{
/// @throws lang::IllegalArgumentException
/// @throws uno::RuntimeException
static void
lcl_setCharStyle(SwDoc& rDoc, const uno::Any & rValue, SfxItemSet & rSet)
void
SetCharStyle(SwDoc& rDoc, const uno::Any & rValue, SfxItemSet & rSet)
{
SwDocShell *const pDocSh = rDoc.GetDocShell();
if(!pDocSh)
@@ -203,6 +205,7 @@ lcl_setCharStyle(SwDoc& rDoc, const uno::Any & rValue, SfxItemSet & rSet)
const SwFormatCharFormat aFormat(pStyle->GetCharFormat());
rSet.Put(aFormat);
};
}
/// @throws lang::IllegalArgumentException
static void
@@ -352,7 +355,7 @@ lcl_setCharFormatSequence(SwPaM & rPam, uno::Any const& rValue)
aStyle <<= aCharStyles.getConstArray()[nStyle];
// create a local set and apply each format directly
SfxItemSetFixed<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT> aSet(rPam.GetDoc().GetAttrPool());
lcl_setCharStyle(rPam.GetDoc(), aStyle, aSet);
SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), aStyle, aSet);
// the first style should replace the current attributes,
// all other have to be added
SwUnoCursorHelper::SetCursorAttr(rPam, aSet, nStyle
@@ -444,7 +447,7 @@ SwUnoCursorHelper::SetCursorPropertyValue(
switch (rEntry.nWID)
{
case RES_TXTATR_CHARFMT:
lcl_setCharStyle(rPam.GetDoc(), rValue, rItemSet);
SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), rValue, rItemSet);
break;
case RES_TXTATR_AUTOFMT:
lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(),
@@ -538,7 +541,7 @@ SwUnoCursorHelper::SetCursorPropertyValue(
}
if (prop.Name == "CharStyleName")
{
lcl_setCharStyle(rPam.GetDoc(), prop.Value, items);
SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), prop.Value, items);
}
else
{