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                        |   64 ++++++++++++
 sw/source/core/unocore/unocrsrhelper.cxx                    |   10 +
 sw/source/core/unocore/unoobj.cxx                           |   13 +-
 7 files changed, 87 insertions(+), 7 deletions(-)

New commits:
commit 030b4dec07c9b57dd55e5491582c39bb59b86385
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Aug 19 08:40:53 2025 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Tue Aug 19 13:13:06 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/+/189897
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng 
b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
index 34041dbe9ab9..90906a05b6a3 100644
--- a/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.4+libreoffice-schema.rng
@@ -4035,7 +4035,7 @@ 
xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
       </rng:optional>
   </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"/>
@@ -4046,7 +4046,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 922bff3ad046..11f3bbc0cc8c 100644
--- a/sw/inc/unocrsrhelper.hxx
+++ b/sw/inc/unocrsrhelper.hxx
@@ -241,6 +241,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..75420a6df754
--- /dev/null
+++ b/sw/qa/core/unocore/unocrsrhelper.cxx
@@ -0,0 +1,64 @@
+/* -*- 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());
+    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());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unocrsrhelper.cxx 
b/sw/source/core/unocore/unocrsrhelper.cxx
index b5eec4b97084..e108b1bcde7d 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);
@@ -1377,6 +1382,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 73455510672c..5968b67b4f16 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -188,10 +188,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)
@@ -214,6 +216,7 @@ lcl_setCharStyle(SwDoc& rDoc, const uno::Any & rValue, 
SfxItemSet & rSet)
     const SwFormatCharFormat aFormat(pStyle->GetCharFormat());
     rSet.Put(aFormat);
 };
+}
 
 /// @throws lang::IllegalArgumentException
 static void
@@ -363,7 +366,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
@@ -455,7 +458,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(),
@@ -549,7 +552,7 @@ SwUnoCursorHelper::SetCursorPropertyValue(
                         }
                         if (prop.Name == "CharStyleName")
                         {
-                            lcl_setCharStyle(rPam.GetDoc(), prop.Value, items);
+                            SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), 
prop.Value, items);
                         }
                         else
                         {

Reply via email to