schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng | 4 sw/CppunitTest_sw_core_unocore.mk | 1 sw/inc/unocrsrhelper.hxx | 2 sw/qa/core/unocore/data/format-char-style-change.docx |binary sw/qa/core/unocore/unocrsrhelper.cxx | 65 ++++++++++++ sw/source/core/unocore/unocrsrhelper.cxx | 10 + sw/source/core/unocore/unoobj.cxx | 13 +- 7 files changed, 88 insertions(+), 7 deletions(-)
New commits: commit a6d8608595fd1ecfdff35c2003a28589ea1214ad Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Aug 19 08:40:53 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Aug 19 16:25:42 2025 +0200 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 <vmik...@collabora.com> Tested-by: Jenkins diff --git a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng index a9c923703e0f..7b0ce565ab5e 100644 --- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng @@ -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> diff --git a/sw/CppunitTest_sw_core_unocore.mk b/sw/CppunitTest_sw_core_unocore.mk index 43fb58bf4fe1..abdad82fa74b 100644 --- a/sw/CppunitTest_sw_core_unocore.mk +++ b/sw/CppunitTest_sw_core_unocore.mk @@ -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, diff --git a/sw/inc/unocrsrhelper.hxx b/sw/inc/unocrsrhelper.hxx index 270b2a69d6dd..0eda90fdc7c5 100644 --- a/sw/inc/unocrsrhelper.hxx +++ b/sw/inc/unocrsrhelper.hxx @@ -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 diff --git a/sw/qa/core/unocore/data/format-char-style-change.docx b/sw/qa/core/unocore/data/format-char-style-change.docx new file mode 100644 index 000000000000..febf5dc3231d Binary files /dev/null and b/sw/qa/core/unocore/data/format-char-style-change.docx differ diff --git a/sw/qa/core/unocore/unocrsrhelper.cxx b/sw/qa/core/unocore/unocrsrhelper.cxx new file mode 100644 index 000000000000..24bc03413a56 --- /dev/null +++ b/sw/qa/core/unocore/unocrsrhelper.cxx @@ -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: */ diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx index defa0496db1a..f78a2c86f590 100644 --- a/sw/source/core/unocore/unocrsrhelper.cxx +++ b/sw/source/core/unocore/unocrsrhelper.cxx @@ -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]; diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx index 1c3f9d06a610..6921b3bba5ad 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -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 {