From f095dda2ef526a6d5da4b6d80fb3cd9d604f3a62 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Thu, 18 Jun 2026 17:08:48 +0200 Subject: [PATCH] cool#15951 engine sw interdependent redlines: hide delete-then-format... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...redlines when hiding changes The bugdoc had a format redline, but redlines were hidden, so it looked like normal text. Then the user selected a word, pressed delete and seemingly nothing happened, which is unexpected. What happened is that pressing delete for a selected format redline creates a delete-then-format redline and our layout code only looked at the "format" on top, not hiding the text when redlines (deletions) were asked to be hidden. Fix the problem by moving GetRedlineTypeIgnoringAdditonalFormat() into SwRangeRedline and then using it in HideIterator::Next(), to hide not only deletions but also delete-then-formats when hiding redlines. This is a problem similar to what commit 1a340196237ed075b337e6a0ac9f8a45132053bb (tdf#166319 sw interdependent redlines: handle ODF export of delete under format, 2025-05-20) fixed, but there the problem was updating the model to match the layout when hiding redlines at a model level; and here the problem was to have the layout from the model in a correct way. Signed-off-by: Miklos Vajna Change-Id: I753d0b9fc8af9d6330f8d0fa719babd7b25ee8f6 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/4808 Reviewed-by: Caolán McNamara Tested-by: Jenkins CPCI (cherry picked from commit 2c5c0e0fca4c510fc436ce9c8850983d953408f7) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207753 Tested-by: Xisco Fauli Reviewed-by: Xisco Fauli --- sw/inc/redline.hxx | 2 ++ sw/qa/core/doc/DocumentRedlineManager.cxx | 20 ++++++++++++++++++++ sw/source/core/doc/docredln.cxx | 14 +++++--------- sw/source/core/text/redlnitr.cxx | 3 ++- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx index f7c26d135781..e78f069910b8 100644 --- a/sw/inc/redline.hxx +++ b/sw/inc/redline.hxx @@ -228,6 +228,8 @@ public: SW_DLLPUBLIC RedlineType GetType( sal_uInt16 nPos = 0 ) const; // Returns true if any redline in the stack matches nType bool ContainsType( RedlineType nType ) const; + /// Like GetType(), but looks through "format" on top of delete. + SW_DLLPUBLIC RedlineType GetTypeIgnoringAdditonalFormat() const; // text content of the redline is only an annotation placeholder // (i.e. a comment, but don't confuse it with comment of the redline) bool IsAnnotation() const; diff --git a/sw/qa/core/doc/DocumentRedlineManager.cxx b/sw/qa/core/doc/DocumentRedlineManager.cxx index d4b20d1efcda..3ed6784a1190 100644 --- a/sw/qa/core/doc/DocumentRedlineManager.cxx +++ b/sw/qa/core/doc/DocumentRedlineManager.cxx @@ -105,6 +105,26 @@ CPPUNIT_TEST_FIXTURE(Test, testRedlineIns) } } +CPPUNIT_TEST_FIXTURE(Test, testHideChangesFormatOnDelete) +{ + // Given a document with a format-on-delete hierarchical redline (the deleted text has a format + // redline on top of the delete redline): + createSwDoc("del-then-format.docx"); + + // When hiding tracked changes: + dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {}); + + // Then make sure the deleted text is also omitted from the layout, just like a plain delete + // redline would be: + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + OUString aPortion = getXPath(pXmlDoc, "//body/txt/SwParaPortion/SwLineLayout", "portion"); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: + // - Actual : BBB + // i.e. only delete was hidden, delete-then-format was still visible. + CPPUNIT_ASSERT_EQUAL(u""_ustr, aPortion); +} + CPPUNIT_TEST_FIXTURE(Test, testInsThenFormatSelf) { // Given a document with ABC redlines, created by Alice: diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx index e19f3f54cffb..8099f89fdf4e 100644 --- a/sw/source/core/doc/docredln.cxx +++ b/sw/source/core/doc/docredln.cxx @@ -1639,14 +1639,11 @@ void SwRangeRedline::CallDisplayFunc(size_t nMyPos) ShowOriginal(0, nMyPos); } -namespace +RedlineType SwRangeRedline::GetTypeIgnoringAdditonalFormat() const { -RedlineType GetRedlineTypeIgnoringAdditonalFormat(const SwRangeRedline& rRedline) -{ - RedlineType eType = rRedline.GetType(); + RedlineType eType = GetType(); - if (eType == RedlineType::Format && rRedline.GetStackCount() > 1 - && rRedline.GetType(1) == RedlineType::Delete) + if (eType == RedlineType::Format && GetStackCount() > 1 && GetType(1) == RedlineType::Delete) { // Consider format-on-delete the same as simple delete, so the range gets moved to the // "Deleted Change Tracking content" toplevel section from body content during file save. @@ -1655,7 +1652,6 @@ RedlineType GetRedlineTypeIgnoringAdditonalFormat(const SwRangeRedline& rRedline return eType; } -} void SwRangeRedline::Show(sal_uInt16 nLoop, size_t nMyPos, bool bForced) { @@ -1678,7 +1674,7 @@ void SwRangeRedline::Show(sal_uInt16 nLoop, size_t nMyPos, bool bForced) rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld | RedlineFlags::Ignore); ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); - switch (GetRedlineTypeIgnoringAdditonalFormat(*this)) + switch (GetTypeIgnoringAdditonalFormat()) { case RedlineType::Insert: // Content has been inserted m_bIsVisible = true; @@ -1718,7 +1714,7 @@ void SwRangeRedline::Hide(sal_uInt16 nLoop, size_t nMyPos, bool /*bForced*/) rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld | RedlineFlags::Ignore); ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); - switch (GetRedlineTypeIgnoringAdditonalFormat(*this)) + switch (GetTypeIgnoringAdditonalFormat()) { case RedlineType::Insert: // Content has been inserted m_bIsVisible = true; diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx index 255e1fbd6866..03e8418ecc9a 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -145,7 +145,8 @@ public: if (m_pEndPos->GetNodeIndex() < pRed->Start()->GetNodeIndex()) break; - if (pRed->GetType() != RedlineType::Delete) + // Hide delete and delete-then-format redline content. + if (pRed->GetTypeIgnoringAdditonalFormat() != RedlineType::Delete) continue; auto [pStart, pEnd] = pRed->StartEnd(); // SwPosition*