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 3baa9e363bee40c8cdcda4f3e2a4026929a23fd7 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Aug 19 08:40:53 2025 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Thu Aug 21 17:35:12 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 (cherry picked from commit a6d8608595fd1ecfdff35c2003a28589ea1214ad) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189978 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng index 9c5e1f80a63d..0ecec12dad0f 100644 --- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng @@ -4136,7 +4136,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"/> @@ -4147,7 +4147,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 6e4992be12be..fec752c29ea3 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 bdcaebdb7f2a..f6209046a7e8 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -190,10 +190,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) @@ -216,6 +218,7 @@ lcl_setCharStyle(SwDoc& rDoc, const uno::Any & rValue, SfxItemSet & rSet) const SwFormatCharFormat aFormat(pStyle->GetCharFormat()); rSet.Put(aFormat); }; +} /// @throws lang::IllegalArgumentException static void @@ -365,7 +368,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 @@ -457,7 +460,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(), @@ -551,7 +554,7 @@ SwUnoCursorHelper::SetCursorPropertyValue( } if (prop.Name == "CharStyleName") { - lcl_setCharStyle(rPam.GetDoc(), prop.Value, items); + SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), prop.Value, items); } else {