sw/qa/extras/uiwriter/uiwriter2.cxx                     |   50 ++++++++++++++++
 sw/source/core/doc/DocumentContentOperationsManager.cxx |    9 ++
 sw/source/core/doc/docedt.cxx                           |    4 -
 sw/source/core/inc/mvsave.hxx                           |    2 
 4 files changed, 62 insertions(+), 3 deletions(-)

New commits:
commit 646c6ddd91a98afddf914e3889cb269fc814c060
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Fri Jun 10 16:26:40 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Jun 13 17:59:14 2022 +0200

    tdf#139982 sw: preserve flys in Replace with redlining enabled
    
    The problem is that there isn't a redline type "Replace" so it's
    represented as Delete+Insert.
    
    To prevent the flys anchored in the text from being deleted, move the
    anchors to the point between the old (deleted) and new (inserted) text.
    
    (regression from commit 28b77c89dfcafae82cf2a6d85731b643ff9290e5)
    
    Change-Id: Ib600c9dbfb9421917e4b8d61195c48cf0b364f06
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135604
    Tested-by: Michael Stahl <michael.st...@allotropia.de>
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx 
b/sw/qa/extras/uiwriter/uiwriter2.cxx
index 8aedaf38ef7a..e62532c0a20d 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -1031,6 +1031,56 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf140007)
                          
pDoc->GetNodes()[SwNodeOffset(11)]->GetTextNode()->GetText());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf139982)
+{
+    SwDoc* const pDoc = createSwDoc();
+    SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    // turn on redlining and show changes
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | 
RedlineFlags::ShowDelete
+                                                      | 
RedlineFlags::ShowInsert);
+    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
+                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+    CPPUNIT_ASSERT_MESSAGE(
+        "redlines should be visible",
+        
IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
+
+    pWrtShell->Insert("helloo");
+
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+    {
+        SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+        anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+        SfxItemSet flySet(pDoc->GetAttrPool(), svl::Items<RES_ANCHOR, 
RES_ANCHOR>);
+        flySet.Put(anchor);
+        SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, 
/*bAnchValid=*/true);
+        CPPUNIT_ASSERT(pFly != nullptr);
+    }
+
+    pWrtShell->SttEndDoc(true);
+    pWrtShell->EndPara(/*bSelect=*/true);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Replace("hello", true);
+
+    // the problem was that a redline delete with the same author as redline
+    // insert has its text deleted immediately, including anchored flys.
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Redo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pWrtShell->Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf39721)
 {
 // FIXME: disabled on Windows because of a not reproducible problem (not 
related to the patch)
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 4fcf4519a09f..3d38a8f9521f 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -4601,6 +4601,14 @@ bool DocumentContentOperationsManager::ReplaceRangeImpl( 
SwPaM& rPam, const OUSt
                 InsertItemSet( aTmpRange, aSet );
             }
 
+            // tdf#139982: Appending the redline may immediately delete flys
+            // anchored in the previous text if it's inside an insert redline.
+            // Also flys will be deleted if the redline is accepted. Move them
+            // to the position between the previous text and the new text,
+            // there the chance of surviving both accept and reject is best.
+            SaveFlyArr flys;
+            SaveFlyInRange(aDelPam, *aDelPam.End(), flys, false);
+
             if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
             {
                 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
@@ -4611,6 +4619,7 @@ bool DocumentContentOperationsManager::ReplaceRangeImpl( 
SwPaM& rPam, const OUSt
             pCursor->SetMark();
             *pCursor->GetPoint() = *aDelPam.GetPoint();
             m_rDoc.getIDocumentRedlineAccess().AppendRedline( new 
SwRangeRedline( RedlineType::Delete, aDelPam ), true);
+            RestFlyInRange(flys, *aDelPam.End(), &aDelPam.End()->nNode, true);
             sw::UpdateFramesForAddDeleteRedline(m_rDoc, *pCursor);
 
             *rPam.GetMark() = *aDelPam.GetMark();
diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx
index 779d07a14851..c7c3d7c2f3c4 100644
--- a/sw/source/core/doc/docedt.cxx
+++ b/sw/source/core/doc/docedt.cxx
@@ -50,7 +50,7 @@ using namespace ::com::sun::star::i18n;
 
 
 void RestFlyInRange( SaveFlyArr & rArr, const SwPosition& rStartPos,
-                      const SwNodeIndex* pInsertPos )
+                      const SwNodeIndex* pInsertPos, bool const 
isForceToStartPos)
 {
     SwPosition aPos(rStartPos);
     for(const SaveFly & rSave : rArr)
@@ -59,7 +59,7 @@ void RestFlyInRange( SaveFlyArr & rArr, const SwPosition& 
rStartPos,
         SwFrameFormat* pFormat = rSave.pFrameFormat;
         SwFormatAnchor aAnchor( pFormat->GetAnchor() );
 
-        if (rSave.isAtInsertNode)
+        if (rSave.isAtInsertNode || isForceToStartPos)
         {
             if( pInsertPos != nullptr )
             {
diff --git a/sw/source/core/inc/mvsave.hxx b/sw/source/core/inc/mvsave.hxx
index 32af2d5b5fc8..0076f83f8e54 100644
--- a/sw/source/core/inc/mvsave.hxx
+++ b/sw/source/core/inc/mvsave.hxx
@@ -116,7 +116,7 @@ struct SaveFly
 typedef std::deque< SaveFly > SaveFlyArr;
 
 void RestFlyInRange( SaveFlyArr& rArr, const SwPosition& rSttIdx,
-                      const SwNodeIndex* pInsPos );
+                     const SwNodeIndex* pInsPos, bool isForceToStartPos = 
false);
 void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& rArr );
 void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
                        SaveFlyArr& rArr, bool bMoveAllFlys );

Reply via email to