sw/qa/extras/uiwriter/uiwriter2.cxx                     |   95 ++++++++++++++++
 sw/source/core/doc/DocumentContentOperationsManager.cxx |    4 
 sw/source/core/doc/docedt.cxx                           |    7 +
 sw/source/core/inc/UndoRedline.hxx                      |    8 +
 sw/source/core/inc/mvsave.hxx                           |    2 
 sw/source/core/undo/unredln.cxx                         |   32 +++++
 6 files changed, 142 insertions(+), 6 deletions(-)

New commits:
commit 767237c7eace6537098de69083035dd5c322c1e5
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Wed Jun 15 15:08:16 2022 +0200
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Thu Jun 16 11:56:00 2022 +0200

    tdf#135976 sw: preserve flys on backspace/delete with redlining enabled
    
    This is a continuation of commit 85376a02348810812d515ee72140dbf56f2b6040
    for the case when redlining is turned on.
    
    Also try to restore the anchors in SwUndoRedlineDelete.
    
    (regression from commit 3345feb67f2c49a1b76639965b56968e1c5f03ee)
    
    Change-Id: I4199f5755398d469a606618c037ad9756cb7aeba
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135909
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>
    (cherry picked from commit 4b7210b16ce6a817e154de5589a7651cbaf473c9)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135935

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx 
b/sw/qa/extras/uiwriter/uiwriter2.cxx
index e62532c0a20d..0ff16f74e59d 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -22,6 +22,7 @@
 #include <wrtsh.hxx>
 #include <IDocumentRedlineAccess.hxx>
 #include <flyfrm.hxx>
+#include <pagefrm.hxx>
 #include <fmtanchr.hxx>
 #include <UndoManager.hxx>
 #include <sortedobjs.hxx>
@@ -1081,6 +1082,100 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf139982)
     CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf135976)
+{
+    SwDoc* const pDoc = createSwDoc();
+    SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    pWrtShell->Insert("foobar");
+
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, 
/*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);
+
+    // turn on redlining and show changes
+    pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | 
RedlineFlags::ShowDelete
+                                                      | 
RedlineFlags::ShowInsert);
+    dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
+                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+    CPPUNIT_ASSERT_MESSAGE(
+        "redlines should be visible",
+        
IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
+    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->UnSelectFrame();
+    pWrtShell->SttEndDoc(/*bStart=*/false);
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+
+    pWrtShell->DelLeft();
+    pWrtShell->DelLeft();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    // the problem was that the fly was deleted from the layout
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    // check that the anchor was moved outside the redline
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    // check that the anchor was restored
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Redo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    // now again in the other direction:
+
+    pWrtShell->SttEndDoc(/*bStart=*/false);
+    pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 3, 
/*bBasicCall=*/false);
+
+    pWrtShell->DelRight();
+    pWrtShell->DelRight();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    // the problem was that the fly was deleted from the layout
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Redo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+
+    pWrtShell->Undo(2);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(size_t(1), 
pWrtShell->GetLayout()->GetLastPage()->GetSortedObjs()->size());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), 
pFly->GetAnchor().GetContentAnchor()->nContent.GetIndex());
+}
+
 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 3d38a8f9521f..962cea631e5f 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -4102,7 +4102,7 @@ 
DocumentContentOperationsManager::~DocumentContentOperationsManager()
 }
 //Private methods
 
-bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & 
rPam, SwDeleteFlags const /*flags*/)
+bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & 
rPam, SwDeleteFlags const flags)
 {
     assert(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn());
 
@@ -4183,7 +4183,7 @@ bool 
DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & rPam
         {
             assert(pRedline->HasValidRange());
             undos.emplace_back(std::make_unique<SwUndoRedlineDelete>(
-                        *pRedline, SwUndoId::DELETE));
+                        *pRedline, SwUndoId::DELETE, flags));
         }
         const SwRewriter aRewriter = undos.front()->GetRewriter();
         // can only group a single undo action
diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx
index c7c3d7c2f3c4..3751ae034577 100644
--- a/sw/source/core/doc/docedt.cxx
+++ b/sw/source/core/doc/docedt.cxx
@@ -28,6 +28,7 @@
 #include <mdiexp.hxx>
 #include <mvsave.hxx>
 #include <redline.hxx>
+#include <rolbck.hxx>
 #include <rootfrm.hxx>
 #include <splargs.hxx>
 #include <swcrsr.hxx>
@@ -132,7 +133,7 @@ void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& 
rArr )
 }
 
 void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
-                       SaveFlyArr& rArr, bool bMoveAllFlys )
+        SaveFlyArr& rArr, bool bMoveAllFlys, SwHistory *const pHistory)
 {
     SwFrameFormats& rFormats = 
*rPam.GetPoint()->nNode.GetNode().GetDoc().GetSpzFrameFormats();
     SwFrameFormat* pFormat;
@@ -178,6 +179,10 @@ void SaveFlyInRange( const SwPaM& rPam, const SwPosition& 
rInsPos,
                     || (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()
                             && (bInsPos = (rInsPos == *pAPos))))
             {
+                if (pHistory)
+                {
+                    pHistory->AddChangeFlyAnchor(*pFormat);
+                }
                 SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
                     (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())
                         ? (pAPos->nNode == rSttNdIdx)
diff --git a/sw/source/core/inc/UndoRedline.hxx 
b/sw/source/core/inc/UndoRedline.hxx
index b695b56c49ef..7c815fca6cc1 100644
--- a/sw/source/core/inc/UndoRedline.hxx
+++ b/sw/source/core/inc/UndoRedline.hxx
@@ -22,6 +22,7 @@
 
 #include <memory>
 #include <undobj.hxx>
+#include <IDocumentContentOperations.hxx>
 
 struct SwSortOptions;
 class SwRangeRedline;
@@ -52,17 +53,22 @@ public:
 
 class SwUndoRedlineDelete final : public SwUndoRedline
 {
+private:
+    std::unique_ptr<SwHistory> m_pHistory; ///< for moved fly anchors
+
     bool m_bCanGroup : 1;
     bool m_bIsDelim : 1;
     bool m_bIsBackspace : 1;
 
     OUString m_sRedlineText;
 
+    void InitHistory(SwPaM const& rRange);
+
     virtual void UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
     virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
 
 public:
-    SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUserId );
+    SwUndoRedlineDelete(const SwPaM& rRange, SwUndoId nUserId, SwDeleteFlags 
flags = SwDeleteFlags::Default);
     virtual SwRewriter GetRewriter() const override;
 
     bool CanGrouping( const SwUndoRedlineDelete& rPrev );
diff --git a/sw/source/core/inc/mvsave.hxx b/sw/source/core/inc/mvsave.hxx
index 0076f83f8e54..2e0511a16c69 100644
--- a/sw/source/core/inc/mvsave.hxx
+++ b/sw/source/core/inc/mvsave.hxx
@@ -119,7 +119,7 @@ void RestFlyInRange( SaveFlyArr& rArr, const SwPosition& 
rSttIdx,
                      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 );
+        SaveFlyArr& rArr, bool bMoveAllFlys, SwHistory * pHistory = nullptr);
 
 void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
                     const SwNodeIndex& rPtNdIdx,
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index e48255c3ab5b..1970eff02aeb 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -27,6 +27,8 @@
 #include <pam.hxx>
 #include <ndtxt.hxx>
 #include <txtfrm.hxx>
+#include <mvsave.hxx>
+#include <rolbck.hxx>
 #include <UndoCore.hxx>
 #include <UndoDelete.hxx>
 #include <strings.hrc>
@@ -197,7 +199,8 @@ void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & 
rPam)
     rDoc.getIDocumentRedlineAccess().DeleteRedline(rPam, true, 
RedlineType::Any);
 }
 
-SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId 
)
+SwUndoRedlineDelete::SwUndoRedlineDelete(
+        const SwPaM& rRange, SwUndoId const nUsrId, SwDeleteFlags const flags)
     : SwUndoRedline( nUsrId != SwUndoId::EMPTY ? nUsrId : SwUndoId::DELETE, 
rRange ),
     m_bCanGroup( false ), m_bIsDelim( false ), m_bIsBackspace( false )
 {
@@ -218,6 +221,24 @@ SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& 
rRange, SwUndoId nUsrId )
     }
 
     m_bCacheComment = false;
+    if (flags & SwDeleteFlags::ArtificialSelection)
+    {
+        InitHistory(rRange);
+    }
+}
+
+void SwUndoRedlineDelete::InitHistory(SwPaM const& rRedline)
+{
+    m_pHistory.reset(new SwHistory);
+    // try to rely on direction of rPam here so it works for
+    // backspacing/deleting consecutive characters
+    SaveFlyArr flys;
+    SaveFlyInRange(rRedline, *rRedline.GetMark(), flys, false, 
m_pHistory.get());
+    RestFlyInRange(flys, *rRedline.GetPoint(), &rRedline.GetPoint()->nNode, 
true);
+    if (m_pHistory->Count())
+    {
+        m_bCanGroup = false; // how to group history?
+    }
 }
 
 // bit of a hack, replace everything...
@@ -241,12 +262,21 @@ void SwUndoRedlineDelete::SetRedlineText(const OUString & 
rText)
 void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
 {
     rDoc.getIDocumentRedlineAccess().DeleteRedline(rPam, true, 
RedlineType::Any);
+    if (m_pHistory)
+    {
+        m_pHistory->TmpRollback(&rDoc, 0);
+    }
 }
 
 void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
 {
     if (rPam.GetPoint() != rPam.GetMark())
     {
+        if (m_pHistory) // if it was created before, it must be recreated now
+        {
+            rPam.Normalize(m_bIsBackspace); // to check the correct edge
+            InitHistory(rPam);
+        }
         rDoc.getIDocumentRedlineAccess().AppendRedline( new 
SwRangeRedline(*mpRedlData, rPam), false );
     }
     sw::UpdateFramesForAddDeleteRedline(rDoc, rPam);

Reply via email to