sw/qa/core/doc/data/del-then-format.docx |binary sw/qa/core/doc/doc.cxx | 25 +++++++++++++++++++++++++ sw/source/core/doc/DocumentRedlineManager.cxx | 24 +++++++++++++++++++++--- 3 files changed, 46 insertions(+), 3 deletions(-)
New commits: commit 96faaaf83a1c8b897ce675d175b4d8756d0ea0df Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue May 13 08:41:24 2025 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue May 13 15:28:34 2025 +0200 tdf#166319 sw interdependent redlines: handle accept of delete under format The bugdoc has <del>AA<format>BB</format>CC</del> in it, clicking accept in the middle of AA results in a leftover BB in the document. This is because the outer redline type of BB is format, so the other type is not accepted together with the delete accept. But this is not correct: if the delete is to be accepted, then it's just a small detail that there was a format on top of it: all this delete is meant to be accepted, like Word does. Fix the problem similar to how commit 90077e9b4372e1e3445cc6fb2158a0f2bbb8b1b8 (tdf#166319 sw interdependent redlines: handle reject of insert under format, 2025-05-09) handled the reject of inserts: if there is a format, then see if it has an underlying delete, and if so, still combine the to-be-accepted changes. Note that rejecting the format + deleting the range means we get correctly working undo/redo for this use-case. Change-Id: I8f05d8f94574d5e89432bf9c2df3a737fa8d6d13 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185251 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmik...@collabora.com> diff --git a/sw/qa/core/doc/data/del-then-format.docx b/sw/qa/core/doc/data/del-then-format.docx new file mode 100644 index 000000000000..f458578f5568 Binary files /dev/null and b/sw/qa/core/doc/data/del-then-format.docx differ diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx index dce183e12355..e7af522adeeb 100644 --- a/sw/qa/core/doc/doc.cxx +++ b/sw/qa/core/doc/doc.cxx @@ -792,6 +792,31 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testInsThenFormat) CPPUNIT_ASSERT(pTextNode->GetText().isEmpty()); } +CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testDelThenFormat) +{ + // Given a document with <del>A<format>B</format>C</del> style redlines: + // When importing that document: + createSwDoc("del-then-format.docx"); + + // When accepting the delete: + SwDocShell* pDocShell = getSwDocShell(); + SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); + pWrtShell->AcceptRedline(0); + + // Then make sure no redlines and no content remain: + SwDoc* pDoc = pDocShell->GetDoc(); + IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess(); + SwRedlineTable& rRedlines = rIDRA.GetRedlineTable(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 0 + // - Actual : 1 + // i.e. the delete-then-format redline remained in the document. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rRedlines.size()); + SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode(); + // Also make sure the text of the format-on-delete redline is removed. + CPPUNIT_ASSERT(pTextNode->GetText().isEmpty()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index b4b016e06983..cd25b95ab5c5 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -1137,6 +1137,14 @@ namespace /// delete-on-insert can be combined if accepting an insert. bool CanCombineTypesForAcceptReject(SwRedlineData& rInnerData, SwRangeRedline& rOuterRedline) { + if (rInnerData.GetType() == RedlineType::Delete) + { + // Delete is OK to have 'format' on it, but 'insert' will be next to the 'delete'. + return rOuterRedline.GetType() == RedlineType::Format + && rOuterRedline.GetStackCount() > 1 + && rOuterRedline.GetType(1) == RedlineType::Delete; + } + if (rInnerData.GetType() != RedlineType::Insert) { return false; @@ -3286,8 +3294,7 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr else if (CanCombineTypesForAcceptReject(aOrigData, *pTmp) && pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData)) { - // The Insert redline we want to accept has another type of redline too - // we should leave the other type of redline, and only accept the inner insert. + // The Insert/Delete redline we want to accept has another type of redline too if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) { m_rDoc.GetIDocumentUndoRedo().AppendUndo( @@ -3295,7 +3302,18 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr } nPamEndtNI = pTmp->Start()->GetNodeIndex(); nPamEndCI = pTmp->Start()->GetContentIndex(); - bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1); + if (aOrigData.GetType() == RedlineType::Delete) + { + // We should delete the other type of redline when accepting the inner delete. + SwPaM aPam(*pTmp->Start(), *pTmp->End()); + bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, bCallDelete); + m_rDoc.getIDocumentContentOperations().DeleteRange(aPam); + } + else + { + // we should leave the other type of redline, and only accept the inner insert. + bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1); + } nRdlIdx++; //we will decrease it in the loop anyway. } } while (nRdlIdx > 0);