sw/qa/core/edit/edit.cxx        |   48 ++++++++++++++++++++++++++++++++++++++++
 sw/source/core/edit/edredln.cxx |   11 ++++++++-
 2 files changed, 58 insertions(+), 1 deletion(-)

New commits:
commit 157c00922959adc8fd2e0203ed94dfd847479c54
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Mar 25 09:14:04 2025 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Mar 25 16:35:00 2025 +0100

    cool#11357 sw redline reinstate: handle deletes in selection
    
    In case the cursor is inside a delete redline, then
    .uno:ReinstateTrackedChange works for that change, but if the cursor is
    a selection that covers one or more deletes, then this simply kills the
    selection.
    
    This happens because reinstating creates new redlines, but
    SwEditShell::ReinstateRedlinesInSelection() iterates the redline table
    while reinstating.
    
    Fix the problem by creating a copy of the redline pointers and work on
    that copy, this way all deletes are reinstated correctly.
    
    The command has no explicit state yet, though.
    
    Change-Id: Ia0e7b8365cb423ebf10d8f75aaff30d6495e1f7a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/183302
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/core/edit/edit.cxx b/sw/qa/core/edit/edit.cxx
index 21455842da24..3bf605e565f0 100644
--- a/sw/qa/core/edit/edit.cxx
+++ b/sw/qa/core/edit/edit.cxx
@@ -282,6 +282,54 @@ CPPUNIT_TEST_FIXTURE(Test, 
testRedlineReinstateSingleRichDelete)
     CPPUNIT_ASSERT_GREATER(pRedline2->Start()->nNode, pRedline2->End()->nNode);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testRedlineReinstateDeletesInSelection)
+{
+    // Given a document with two deletions:
+    createSwDoc();
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    pWrtShell->Insert("abcde");
+    SwModule* pModule = SwModule::get();
+    pModule->SetRedlineAuthor("Alice");
+    RedlineFlags nMode = pWrtShell->GetRedlineFlags();
+    pWrtShell->SetRedlineFlags(nMode | RedlineFlags::On);
+    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, 
/*bBasicCall=*/false);
+    pWrtShell->DelRight();
+    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 2, 
/*bBasicCall=*/false);
+    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, 
/*bBasicCall=*/false);
+    pWrtShell->DelRight();
+    pWrtShell->SetRedlineFlags(nMode);
+
+    // 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->EndPara(/*bSelect=*/true);
+    dispatchCommand(mxComponent, ".uno:ReinstateTrackedChange", {});
+
+    // Then make sure this results in inserts after deletes:
+    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: 4
+    // - Actual  : 2
+    // i.e. no insert redlines were created.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rRedlines.size());
+    const SwRangeRedline* pRedline1 = rRedlines[0];
+    const SwRedlineData& rRedlineData1 = pRedline1->GetRedlineData(0);
+    CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData1.GetType());
+    const SwRangeRedline* pRedline2 = rRedlines[1];
+    const SwRedlineData& rRedlineData2 = pRedline2->GetRedlineData(0);
+    CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rRedlineData2.GetType());
+    const SwRangeRedline* pRedline3 = rRedlines[2];
+    const SwRedlineData& rRedlineData3 = pRedline3->GetRedlineData(0);
+    CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlineData3.GetType());
+    const SwRangeRedline* pRedline4 = rRedlines[3];
+    const SwRedlineData& rRedlineData4 = pRedline4->GetRedlineData(0);
+    CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rRedlineData4.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 a99a8f2e459d..6f2bec071498 100644
--- a/sw/source/core/edit/edredln.cxx
+++ b/sw/source/core/edit/edredln.cxx
@@ -220,9 +220,18 @@ void SwEditShell::ReinstateRedlinesInSelection()
     SwPosition aCursorStart(*GetCursor()->Start());
     SwPosition aCursorEnd(*GetCursor()->End());
     SwRedlineTable& rTable = 
GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
+
+    // Work on a copy, since reinstate will modify the table, and reinstate of 
just inserted
+    // redlines is not wanted.
+    std::vector<SwRangeRedline*> aRedlines(rTable.size());
     for (size_t nIndex = 0; nIndex < rTable.size(); ++nIndex)
     {
-        const SwRangeRedline& rRedline = *rTable[nIndex];
+        aRedlines[nIndex] = rTable[nIndex];
+    }
+
+    for (size_t nIndex = 0; nIndex < aRedlines.size(); ++nIndex)
+    {
+        const SwRangeRedline& rRedline = *aRedlines[nIndex];
         if (!rRedline.HasMark() || !rRedline.IsVisible())
         {
             continue;

Reply via email to