sw/qa/core/doc/DocumentRedlineManager.cxx               |   44 ++++++++++++++++
 sw/source/core/doc/DocumentContentOperationsManager.cxx |    7 ++
 2 files changed, 50 insertions(+), 1 deletion(-)

New commits:
commit a720f7d8bdbfff6507d82e8fd5c117e93e2503b0
Author:     Miklos Vajna <[email protected]>
AuthorDate: Thu Sep 18 08:50:41 2025 +0200
Commit:     Caolán McNamara <[email protected]>
CommitDate: Thu Sep 18 10:08:57 2025 +0200

    tdf#168325 sw format redline, char style: improve recording
    
    Create a new Writer document with a single word in it, set the Emphasis 
character
    style on it, enable redline record, change char style to Strong
    Emphasis, save to ODT. The format redline refers to an automatic style,
    while it should refer to the old char style (Emphasis).
    
    This happens because the redline record for format redline works
    incorrectly: it not only records the char style (before changing the
    char style), but also the expanded value of the char style, which leads
    to the creation of an automatic style on ODT export. This doesn't happen
    if exporting an originally DOCX file to ODT.
    
    Fix the problem by explicitly asking for the current character
    properties in a way so that char styles are not expanded, when making a
    copy of the old formatting & storing it in a format redline.
    
    Also drop storing RSIDs in format redlines, they are not interesting and
    again would lead to unwanted creation of automatic styles.
    
    Change-Id: Idd34afb1f0570589254a9eb259af4fc3465aec22
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191109
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/qa/core/doc/DocumentRedlineManager.cxx 
b/sw/qa/core/doc/DocumentRedlineManager.cxx
index 8fac406a45aa..7bd923ec34a2 100644
--- a/sw/qa/core/doc/DocumentRedlineManager.cxx
+++ b/sw/qa/core/doc/DocumentRedlineManager.cxx
@@ -11,6 +11,7 @@
 
 #include <editeng/wghtitem.hxx>
 #include <comphelper/scopeguard.hxx>
+#include <comphelper/propertyvalue.hxx>
 
 #include <IDocumentRedlineAccess.hxx>
 #include <docsh.hxx>
@@ -19,6 +20,7 @@
 #include <wrtsh.hxx>
 #include <swmodule.hxx>
 #include <strings.hrc>
+#include <fchrfmt.hxx>
 
 namespace
 {
@@ -128,6 +130,48 @@ CPPUNIT_TEST_FIXTURE(Test, testInsThenFormatSelf)
     // i.e. a delete was created instead of removing the insert.
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFormatRedlineRecordOldCharStyle)
+{
+    // Given a document with one char style applied + redline record on:
+    createSwDoc();
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->Insert(u"x"_ustr);
+    pWrtShell->SelAll();
+    uno::Sequence<beans::PropertyValue> aPropertyValues = {
+        comphelper::makePropertyValue(u"Style"_ustr, 
uno::Any(u"Emphasis"_ustr)),
+        comphelper::makePropertyValue(u"FamilyName"_ustr, 
uno::Any(u"CharacterStyles"_ustr)),
+    };
+    dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, aPropertyValues);
+    pDocShell->SetChangeRecording(true);
+
+    // When changing to a second char style:
+    aPropertyValues = {
+        comphelper::makePropertyValue(u"Style"_ustr, uno::Any(u"Strong 
Emphasis"_ustr)),
+        comphelper::makePropertyValue(u"FamilyName"_ustr, 
uno::Any(u"CharacterStyles"_ustr)),
+    };
+    dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, aPropertyValues);
+
+    // Then make sure the redline refers to the old char style and just to 
that:
+    SwDoc* pDoc = pDocShell->GetDoc();
+    IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
+    SwRedlineTable& rRedlines = rIDRA.GetRedlineTable();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rRedlines.size());
+    const SwRangeRedline& rRedline = *rRedlines[0];
+    CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedline.GetType());
+    auto pExtraData = dynamic_cast<const 
SwRedlineExtraData_FormatColl*>(rRedline.GetExtraData());
+    CPPUNIT_ASSERT(pExtraData);
+    std::shared_ptr<SfxItemSet> pRedlineSet = pExtraData->GetItemSet();
+    CPPUNIT_ASSERT(pRedlineSet);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 5
+    // i.e. more than just the char style change was recorded, which was 
unexpected.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(1), pRedlineSet->Count());
+    const SwFormatCharFormat& rOldCharFormat = 
pRedlineSet->Get(RES_TXTATR_CHARFMT);
+    CPPUNIT_ASSERT_EQUAL(u"Emphasis"_ustr, 
rOldCharFormat.GetCharFormat()->GetName());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 4b73850dd41f..133923e3119e 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1303,7 +1303,11 @@ namespace //local functions originally from docfmt.cxx
             SfxItemSetFixed<RES_CHRATR_BEGIN,     RES_TXTATR_WITHEND_END - 1,
                         RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1>  aSet( 
rDoc.GetAttrPool() );
             SwTextNode * pNode = rRg.Start()->GetNode().GetTextNode();
-            pNode->GetParaAttr( aSet, rRg.Start()->GetContentIndex() + 1, 
rRg.End()->GetContentIndex() );
+            // bGetFromChrFormat would be true by default and we want no 
expansion of the character
+            // style to direct formatting for redline purposes.
+            pNode->GetParaAttr(aSet, rRg.Start()->GetContentIndex() + 1,
+                               rRg.End()->GetContentIndex(), 
/*bOnlyTextAttr=*/false,
+                               /*bGetFromChrFormat=*/false);
 
             aSet.ClearItem( RES_TXTATR_REFMARK );
             aSet.ClearItem( RES_TXTATR_TOXMARK );
@@ -1311,6 +1315,7 @@ namespace //local functions originally from docfmt.cxx
             aSet.ClearItem( RES_TXTATR_INETFMT );
             aSet.ClearItem( RES_TXTATR_META );
             aSet.ClearItem( RES_TXTATR_METAFIELD );
+            aSet.ClearItem(RES_CHRATR_RSID);
 
             // After GetParaAttr aSet can contain invalid/dontcare items (true 
== IsInvalidItem,
             // DONTCARE == SfxItemState), e.g. RES_TXTATR_CHARFMT and (a copy 
of) this

Reply via email to