sw/qa/core/doc/doc.cxx | 15 +++++++++++++++ sw/source/core/doc/DocumentRedlineManager.cxx | 26 ++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-)
New commits: commit 90077e9b4372e1e3445cc6fb2158a0f2bbb8b1b8 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri May 9 09:15:17 2025 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Fri May 9 10:02:17 2025 +0200 tdf#166319 sw interdependent redlines: handle reject of insert under format The bugdoc has <insert>AA<format>BB</format>CC</insert> in it, clicking reject 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 rejected together with the insert reject. But this is not correct: if the insert is to be rejected, then it's just a small detail that there was a format on top of it: all this is meant to be rejected, like Word does. Fix the problem similar to how commit d5ca8b09d5ecdc28e28486e5dbd1ecb655d817ab (tdf#166319 sw interdependent redlines: handle accept of insert under format, 2025-05-05) handled accept: if there is a format, then see if it has an underlying insert, and if so, still combine the to-be-rejected changes. Note that in contrast to insert-then-delete, it's not enough to accept the change to delete it (for the higher level reject purpose), so explicitly call DeleteRange() on the range of the format after the format redline is gone. Change-Id: Iaf1122d8e37e210790972e0312564245fa6f813f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185083 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx index 62e8c198f46a..8870f80fbba3 100644 --- a/sw/qa/core/doc/doc.cxx +++ b/sw/qa/core/doc/doc.cxx @@ -775,6 +775,21 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testInsThenFormat) // Without the accompanying fix in place, this test would have failed, the insert under format // was not accepted. CPPUNIT_ASSERT(!rRedlineData.Next()); + + // And when rejecting the insert: + pWrtShell->Undo(); + SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode(); + CPPUNIT_ASSERT_EQUAL(u"AAABBBCCC"_ustr, pTextNode->GetText()); + pWrtShell->RejectRedline(0); + + // Then make sure no redlines and no content remain: + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 0 + // - Actual : 1 + // i.e. a format-on-insert redline remained. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rRedlines.size()); + // Also make sure the text of the format-on-insert redline is removed. + CPPUNIT_ASSERT(pTextNode->GetText().isEmpty()); } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 1f2dd69b683e..3ec093c5b06f 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -1136,7 +1136,7 @@ namespace /// Decides if it's OK to combine two types of redlines next to each other, e.g. insert and /// delete-on-insert can be combined if accepting an insert. -bool CanCombineTypesForAccept(SwRedlineData& rInnerData, SwRangeRedline& rOuterRedline) +bool CanCombineTypesForAcceptReject(SwRedlineData& rInnerData, SwRangeRedline& rOuterRedline) { if (rInnerData.GetType() != RedlineType::Insert) { @@ -3284,7 +3284,7 @@ bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPosOr bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete); nRdlIdx++; //we will decrease it in the loop anyway. } - else if (CanCombineTypesForAccept(aOrigData, *pTmp) + else if (CanCombineTypesForAcceptReject(aOrigData, *pTmp) && pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData)) { // The Insert redline we want to accept has an other type of redline too @@ -3562,14 +3562,12 @@ bool DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, bCallDelete); nRdlIdx++; //we will decrease it in the loop anyway. } - else if (aOrigData.GetType() == RedlineType::Insert - && pTmp->GetType() == RedlineType::Delete && pTmp->GetStackCount() > 1 - && pTmp->GetType(1) == RedlineType::Insert + else if (CanCombineTypesForAcceptReject(aOrigData, *pTmp) && pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData)) { - // The Insert redline we want to reject has a deletion redline too - // without the insert, the delete is meaningless - // so we rather just accept the deletion redline + // The Insert redline we want to reject has an other type of redline too + // without the insert, the other type is meaningless + // so we rather just accept the other type of redline if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) { std::unique_ptr<SwUndoAcceptRedline> pUndoRdl @@ -3581,7 +3579,19 @@ bool DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPosOr } nPamEndtNI = pTmp->Start()->GetNodeIndex(); nPamEndCI = pTmp->Start()->GetContentIndex(); + std::optional<SwPaM> oPam; + RedlineType eOuterType = pTmp->GetType(); + if (eOuterType == RedlineType::Format) + { + // The accept won't implicitly delete the range, so track its boundaries. + oPam.emplace(*pTmp->Start(), *pTmp->End()); + } bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete); + if (oPam) + { + // Handles undo/redo itself. + m_rDoc.getIDocumentContentOperations().DeleteRange(*oPam); + } nRdlIdx++; //we will decrease it in the loop anyway. }