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 e739d0f0952129ff12e0c81e4a6fcae99d05a097 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Apr 15 09:42:11 2025 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Wed Apr 23 12:34:23 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 (cherry picked from commit 5dde0947cd1eafde690bd032805be732f5ee6f02) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184266 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> 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 9b724e4d77c0..009a6efb0402 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 8f0302b7f101..5d941fac17b4 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> @@ -1801,6 +1802,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 f6905cafc6cf..e618cbdd1f4e 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 4b6a8f2a8abf..34219649a6de 100644 --- a/sw/source/core/undo/unattr.cxx +++ b/sw/source/core/undo/unattr.cxx @@ -790,6 +790,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();