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.stahl@allotropia.de>
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index e62532c..0ff16f7 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 3d38a8f..962cea6 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 c7c3d7c..3751ae0 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 b695b56..7c815fc 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 0076f83..2e0511a 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 e48255c..1970eff 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);