diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2025-03-20 09:08:43 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2025-03-20 15:17:09 +0100 |
commit | 1df71464588d4cfcba708cf00ef7b6ac94574c8f (patch) | |
tree | 42db886ad09e759e6f7e588ade9fb340fc8cc748 | |
parent | d9bbf0809b3b4722cae9c934ce55cd6189fb67bf (diff) |
cool#11357 sw redline reinstate: handle inserts in selection
In case the cursor is inside an insert redline, then
.uno:ReinstateTrackedChange works for that change, but if multiple
inserts are selected, then this simply results in a reject with no
history.
This happens because SwView::Execute() has a bool for the accept, so if
we have accept/reject/reinstate slots, then by default reinstate is
handled as a reject (this is not terrible, reinstate is meant to be
"reject with history").
Fix the problem by adding a new
SwEditShell::ReinstateRedlinesInSelection() which can decide what
redlines are in the selection and then by invoking reinstate on these
redlines.
Similar to accept/reject, it works to only partially select a redline,
which results in a split: the non-selected part is left unchanged and we
invoke the action on the selected part.
Change-Id: I21a5896f9bd983d8ca8e2480826421c6bffbe556
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183170
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
-rw-r--r-- | sw/inc/editsh.hxx | 3 | ||||
-rw-r--r-- | sw/qa/core/edit/edit.cxx | 50 | ||||
-rw-r--r-- | sw/source/core/edit/edredln.cxx | 68 | ||||
-rw-r--r-- | sw/source/uibase/uiview/view2.cxx | 5 |
4 files changed, 122 insertions, 4 deletions
diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx index c9444a3e0f78..2e2c6b1f3c65 100644 --- a/sw/inc/editsh.hxx +++ b/sw/inc/editsh.hxx @@ -156,6 +156,8 @@ class SAL_DLLPUBLIC_RTTI SwEditShell : public SwCursorShell void SetSectionAttr_( SwSectionFormat& rSectFormat, const SfxItemSet& rSet ); + void ReinstatePaM(const SwRangeRedline& rRedline, SwPaM& rPaM); + using SwViewShell::UpdateFields; using sw::BroadcastingModify::GetInfo; @@ -960,6 +962,7 @@ public: bool AcceptRedlinesInSelection(); bool RejectRedlinesInSelection(); void ReinstateRedline(SwRedlineTable::size_type nPos); + void ReinstateRedlinesInSelection(); /** Search Redline for this Data and @return position in array. If not found, return SwRedlineTable::npos. */ diff --git a/sw/qa/core/edit/edit.cxx b/sw/qa/core/edit/edit.cxx index 10705063a001..89d596d88989 100644 --- a/sw/qa/core/edit/edit.cxx +++ b/sw/qa/core/edit/edit.cxx @@ -117,6 +117,56 @@ CPPUNIT_TEST_FIXTURE(Test, testRedlineReinstateSingleInsert) CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rInnerRedlineData.GetType()); } +CPPUNIT_TEST_FIXTURE(Test, testRedlineReinstateInsertsInSelection) +{ + // Given a document with two insertions: + createSwDoc(); + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + pWrtShell->Insert("aaa"); + SwModule* pModule = SwModule::get(); + pModule->SetRedlineAuthor("Alice"); + RedlineFlags nMode = pWrtShell->GetRedlineFlags(); + pWrtShell->SetRedlineFlags(nMode | RedlineFlags::On); + pWrtShell->Insert("bbb"); + pWrtShell->SetRedlineFlags(nMode); + pWrtShell->Insert("ccc"); + pWrtShell->SetRedlineFlags(nMode | RedlineFlags::On); + pWrtShell->Insert("ddd"); + pWrtShell->SetRedlineFlags(nMode); + pWrtShell->Insert("eee"); + + // When a 2nd user reinstates those changes with a selection: + pModule->SetRedlineAuthor("Bob"); + // Create a selection that excludes the initial "a" and the last "e": + pWrtShell->SttPara(/*bSelect=*/false); + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false); + pWrtShell->EndPara(/*bSelect=*/true); + pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false); + dispatchCommand(mxComponent, ".uno:ReinstateTrackedChange", {}); + + // Then make sure this results in deletes on top of inserts: + SwDoc* pDoc = pWrtShell->GetDoc(); + IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess(); + SwRedlineTable& rRedlines = rIDRA.GetRedlineTable(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 2 + // - Actual : 0 + // i.e. a reject was performed instead of a reinstate. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rRedlines.size()); + const SwRangeRedline* pRedline1 = rRedlines[0]; + const SwRedlineData& rRedlineData1 = pRedline1->GetRedlineData(0); + CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData1.GetType()); + CPPUNIT_ASSERT(rRedlineData1.Next()); + const SwRedlineData& rInnerRedlineData1 = *rRedlineData1.Next(); + CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rInnerRedlineData1.GetType()); + const SwRangeRedline* pRedline2 = rRedlines[1]; + const SwRedlineData& rRedlineData2 = pRedline2->GetRedlineData(0); + CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData2.GetType()); + CPPUNIT_ASSERT(rRedlineData2.Next()); + const SwRedlineData& rInnerRedlineData2 = *rRedlineData2.Next(); + CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rInnerRedlineData2.GetType()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/core/edit/edredln.cxx b/sw/source/core/edit/edredln.cxx index 8d992e56ddef..71bf47e60fc3 100644 --- a/sw/source/core/edit/edredln.cxx +++ b/sw/source/core/edit/edredln.cxx @@ -80,6 +80,14 @@ bool SwEditShell::AcceptRedline( SwRedlineTable::size_type nPos ) return bRet; } +void SwEditShell::ReinstatePaM(const SwRangeRedline& rRedline, SwPaM& rPaM) +{ + if (rRedline.GetType() == RedlineType::Insert) + { + DeleteSel(rPaM, /*isArtificialSelection=*/true); + } +} + void SwEditShell::ReinstateRedline(SwRedlineTable::size_type nPos) { CurrShell aCurr(this); @@ -95,10 +103,7 @@ void SwEditShell::ReinstateRedline(SwRedlineTable::size_type nPos) SwPaM aPaM(*rRedline.GetPoint()); aPaM.SetMark(); *aPaM.GetMark() = *rRedline.GetMark(); - if (rRedline.GetType() == RedlineType::Insert) - { - DeleteSel(aPaM, /*isArtificialSelection=*/true); - } + ReinstatePaM(rRedline, aPaM); EndAllAction(); } @@ -174,6 +179,61 @@ bool SwEditShell::RejectRedlinesInSelection() return bRet; } +void SwEditShell::ReinstateRedlinesInSelection() +{ + CurrShell aCurr( this ); + StartAllAction(); + if (!IsRedlineOn()) + { + RedlineFlags nMode = GetRedlineFlags(); + SetRedlineFlags(nMode | RedlineFlags::On, /*bRecordAllViews=*/false); + } + + SwPosition aCursorStart(*GetCursor()->Start()); + SwPosition aCursorEnd(*GetCursor()->End()); + SwRedlineTable& rTable = GetDoc()->getIDocumentRedlineAccess().GetRedlineTable(); + for (size_t nIndex = 0; nIndex < rTable.size(); ++nIndex) + { + const SwRangeRedline& rRedline = *rTable[nIndex]; + if (!rRedline.HasMark() || !rRedline.IsVisible()) + { + continue; + } + + if (*rRedline.End() < aCursorStart) + { + // Ends before the selection, skip to the next redline. + continue; + } + + if (*rRedline.Start() > aCursorEnd) + { + // Starts after the selection, can stop. + break; + } + + // Check if the redline is only partially selected. + const SwPosition* pStart = rRedline.Start(); + if (*pStart < aCursorStart) + { + pStart = &aCursorStart; + } + const SwPosition* pEnd = rRedline.End(); + if (*pEnd > aCursorEnd) + { + pEnd = &aCursorEnd; + } + + // Process the (partially) selected redline. + SwPaM aPaM(*pEnd); + aPaM.SetMark(); + *aPaM.GetMark() = *pStart; + ReinstatePaM(rRedline, aPaM); + } + + EndAllAction(); +} + // Set the comment at the Redline bool SwEditShell::SetRedlineComment( const OUString& rS ) { diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx index 7dae30f73886..fe46ebea00be 100644 --- a/sw/source/uibase/uiview/view2.cxx +++ b/sw/source/uibase/uiview/view2.cxx @@ -910,6 +910,7 @@ void SwView::Execute(SfxRequest &rReq) if( pCursor->HasMark() && nRedline == SwRedlineTable::npos) { bool bAccept = FN_REDLINE_ACCEPT_DIRECT == nSlot || FN_REDLINE_ACCEPT_TONEXT == nSlot; + bool bReinstate = nSlot == FN_REDLINE_REINSTATE_DIRECT; SwUndoId eUndoId = bAccept ? SwUndoId::ACCEPT_REDLINE : SwUndoId::REJECT_REDLINE; SwWrtShell& rSh = GetWrtShell(); SwRewriter aRewriter; @@ -921,6 +922,10 @@ void SwView::Execute(SfxRequest &rReq) } if ( bAccept ) m_pWrtShell->AcceptRedlinesInSelection(); + else if (bReinstate) + { + m_pWrtShell->ReinstateRedlinesInSelection(); + } else m_pWrtShell->RejectRedlinesInSelection(); if ( bTableSelection ) |