sw/qa/core/doc/data/edit-list-autofmt.docx              |binary
 sw/qa/core/doc/doc.cxx                                  |   25 ++++++++++++++++
 sw/source/core/doc/DocumentContentOperationsManager.cxx |   17 ++++++++++
 sw/source/core/inc/UndoAttribute.hxx                    |    1 
 sw/source/core/undo/unattr.cxx                          |   14 ++++++++
 5 files changed, 57 insertions(+)

New commits:
commit 5dde0947cd1eafde690bd032805be732f5ee6f02
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Apr 15 09:42:11 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Apr 15 15:57:24 2025 +0200

    tdf#166179 sw: fix inconsistent UI state vs command exec for the para marker
    
    Go to the paragraph marker of the 2nd paragraph in the bugdoc, which is
    red & strike-through. The toolbar suggests that strike-through is on,
    but if you click on it, nothing happens.
    
    The reason for this is that the DOCX bugdoc has these character
    properties on the "paragraph marker", which can have its own formatting
    in Word, but not really in Writer. Writer's native way to do something
    similar is to just host character properties on the paragraph, which is
    not possible in Word. This is not a new problem, commit
    5ba30f588d6e41a13d68b1461345fca7a7ca61ac (tdf#64222 sw: better DOCX
    import/export of paragraph marker formatting, 2019-09-17) added the
    RES_PARATR_LIST_AUTOFMT paragraph property to store the formatting of
    the paragraph marker and commit 6287845eab339a8eb3c660d648d012e9f1dcce30
    (tdf#127606 DOCX lists: fix unchangeable formatting, 2020-04-17) already
    ran into this "can't get rid of formatting" problem, where the fix was
    to clear the RES_PARATR_LIST_AUTOFMT paragraph property.
    
    Improves this a little, so:
    1) If you go to the end of the paragraph and the UI hints that you have
       the relevant formatting enabled, then adjust command dispatch, so
       e.g. the "strike-through is enabled" -> press the toggle button ->
       "strike-through is not disabled" use-case works; and
    2) Given that this paragraph marker formatting is currently duplicated
       in the doc model (stored in both RES_PARATR_LIST_AUTOFMT and also as
       an empty hint at the paragraph end), make sure that applying character
       formatting at paragraph end for these paragraphs doesn't result in an
       inconsistent model (we used to only update the hint, but not
       RES_PARATR_LIST_AUTOFMT).
       Do this a bit similar to how
       SwUnoCursorHelper::SetCursorPropertyValue() handles
       RES_PARATR_LIST_AUTOFMT during the DOCX import.
    
    Note that lcl_InsAttr() is used with an item set, so applying a single
    formatting via a toolbar button or using the char format dialog works.
    Even undo/redo works, because SwRegHistory is still on the stack by the
    time we call SwTextNode::SetAttr(), so the undo action will be an
    SwUndoAttr, which has a SwHistorySetFormat, with both a SwHistoryHint
    and an SwFormatAutoFormat set. This is now easier to see, when the
    SwUndoAttr's SwHistory xml dump is part of the doc model xml dump.
    
    Change-Id: Iaa50d1d2b3c6599c4fd617dfd85c9e93e070e972
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184219
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/core/doc/data/edit-list-autofmt.docx 
b/sw/qa/core/doc/data/edit-list-autofmt.docx
new file mode 100644
index 000000000000..d4d6acce531f
Binary files /dev/null and b/sw/qa/core/doc/data/edit-list-autofmt.docx differ
diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index 336d03c404cb..0b29cc5149c9 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -689,6 +689,31 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testAtCharImageCopy)
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs.size());
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testEditListAutofmt)
+{
+    // Given a document with a number portion in para 2, para marker is 
formatted to be red:
+    createSwDoc("edit-list-autofmt.docx");
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    pWrtShell->Down(/*bSelect=*/false);
+    pWrtShell->EndPara();
+
+    // When changing that red to be black:
+    uno::Sequence<beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue("Color.Color", 
static_cast<sal_Int32>(COL_BLACK)),
+    };
+    dispatchCommand(mxComponent, ".uno:Color", aArgs);
+
+    // Then make sure the layout turns into red:
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 00000000
+    // - Actual  : 00ff0000
+    // i.e. clicking on the toolbar button didn't result in a layout update 
because the doc model
+    // became inconsistent.
+    assertXPath(pXmlDoc, 
"/root/page/body/txt[2]/SwParaPortion/SwLineLayout/SwFieldPortion/SwFont",
+                "color", u"00000000");
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 5f6c3fed08dd..6dfd662df6c4 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -75,6 +75,7 @@
 #include <frameformats.hxx>
 #include <annotationmark.hxx>
 #include <formatflysplit.hxx>
+#include <istyleaccess.hxx>
 #include <o3tl/safeint.hxx>
 #include <sal/log.hxx>
 #include <unotools/charclass.hxx>
@@ -1794,6 +1795,22 @@ namespace //local functions originally from docfmt.cxx
                 bRet = history.InsertItems( *pCharSet, nMkPos, nPtPos, nFlags, 
/*ppNewTextAttr*/nullptr )
                     || bRet;
 
+                if (bRet && 
pTextNd->GetSwAttrSet().HasItem(RES_PARATR_LIST_AUTOFMT)
+                    && nMkPos == nPtPos && nMkPos == pTextNd->Len())
+                {
+                    // The hint is created exactly at the paragraph end and 
the paragraph has
+                    // paragraph marker character properties, update that 
autostyle, too.
+                    const SwFormatAutoFormat& rListAutoFormat
+                        = pTextNd->GetAttr(RES_PARATR_LIST_AUTOFMT);
+                    std::unique_ptr<SfxItemSet> pSet = 
rListAutoFormat.GetStyleHandle()->Clone();
+                    pSet->Put(*pCharSet);
+                    IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
+                    std::shared_ptr<SfxItemSet> pAutoStyle
+                        = rStyleAccess.getAutomaticStyle(*pSet, 
IStyleAccess::AUTO_STYLE_CHAR);
+                    SwFormatAutoFormat aListAutofmt(RES_PARATR_LIST_AUTOFMT);
+                    aListAutofmt.SetStyleHandle(pAutoStyle);
+                    pTextNd->SetAttr(aListAutofmt);
+                }
             }
             if( pOtherSet && pOtherSet->Count() )
             {
diff --git a/sw/source/core/inc/UndoAttribute.hxx 
b/sw/source/core/inc/UndoAttribute.hxx
index 64ef447ec0d2..ce0c854f5b35 100644
--- a/sw/source/core/inc/UndoAttribute.hxx
+++ b/sw/source/core/inc/UndoAttribute.hxx
@@ -59,6 +59,7 @@ public:
     void SaveRedlineData( const SwPaM& rPam, bool bInsContent );
 
     SwHistory& GetHistory() { return *m_pHistory; }
+    void dumpAsXml(xmlTextWriterPtr pWriter) const override;
 };
 
 class SwUndoResetAttr final : public SwUndo, private SwUndRng
diff --git a/sw/source/core/undo/unattr.cxx b/sw/source/core/undo/unattr.cxx
index 5720f9a06b04..9944bf1ba104 100644
--- a/sw/source/core/undo/unattr.cxx
+++ b/sw/source/core/undo/unattr.cxx
@@ -804,6 +804,20 @@ void SwUndoAttr::SaveRedlineData( const SwPaM& rPam, bool 
bIsContent )
     }
 }
 
+void SwUndoAttr::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwUndoAttr"));
+    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", 
this);
+
+    if (m_pHistory)
+    {
+        m_pHistory->dumpAsXml(pWriter);
+    }
+
+    (void)xmlTextWriterEndElement(pWriter);
+}
+
+
 void SwUndoAttr::UndoImpl(::sw::UndoRedoContext & rContext)
 {
     SwDoc *const pDoc = & rContext.GetDoc();

Reply via email to