tdf#157662 SW: redline: accept/reject done for all parts
Tracked changes divided into smaller parts when they are
overlapping. But if the Author, and Change time, and some more
is equal, then they can be combined into 1 change later..
Modified AcceptRedline / RejectRedline, to seek for all these parts
that are neightbour to each other, and can be combined, and
reject/accept them all at once. Even those that are deepen in the tree.
i.e.: insert that have a delete redline too.
when rejecting an insert redline, that have a delete redline too,
the delete redline is accepted instead. (have the same result.)
when accepting an insert redline, that have a delete redline too,
The delete redline remains, while the insert is deleted. (=accepted)
made some limitations to lessen the probability of regression:
No anonym, No table, No seqNo, and dont use it in RejectAll/AcceptAll
Added unittest to check that accept/reject handle more redlines
at once, but not too many..
Change-Id: Ibd0a39f7847b22b279a797babb30ba162e70a513
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157950
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
diff --git a/sw/inc/IDocumentRedlineAccess.hxx b/sw/inc/IDocumentRedlineAccess.hxx
index 73f87fa..c2b71aa 100644
--- a/sw/inc/IDocumentRedlineAccess.hxx
+++ b/sw/inc/IDocumentRedlineAccess.hxx
@@ -183,15 +183,23 @@ public:
virtual void SetRedlineMove(/*[in]*/bool bFlag) = 0;
virtual bool AcceptRedline(/*[in]*/SwRedlineTable::size_type nPos, /*[in]*/bool bCallDelete) = 0;
virtual bool AcceptRedline(/*[in]*/ SwRedlineTable::size_type nPos, /*[in]*/ bool bCallDelete,
/*[in]*/ bool bRange = false)
= 0;
virtual bool AcceptRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool bCallDelete) = 0;
virtual bool AcceptRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool bCallDelete,
/*[in]*/ sal_Int8 nDepth = 0)
= 0;
virtual void AcceptRedlineParagraphFormatting(/*[in]*/const SwPaM& rPam ) = 0;
virtual bool RejectRedline(/*[in]*/SwRedlineTable::size_type nPos, /*[in]*/bool bCallDelete) = 0;
virtual bool RejectRedline(/*[in]*/ SwRedlineTable::size_type nPos,
/*[in]*/ bool bCallDelete, /*[in]*/ bool bRange = false)
= 0;
virtual bool RejectRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool bCallDelete) = 0;
virtual bool RejectRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool bCallDelete,
/*[in]*/ sal_Int8 nDepth = 0)
= 0;
virtual const SwRangeRedline* SelNextRedline(/*[in]*/SwPaM& rPam) const = 0;
diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx
index 7ef6b9c..d8eba64 100644
--- a/sw/inc/redline.hxx
+++ b/sw/inc/redline.hxx
@@ -144,6 +144,7 @@ public:
void SetMoved() { m_bMoved = true; }
bool IsMoved() const { return m_bMoved; }
bool CanCombine( const SwRedlineData& rCmp ) const;
bool CanCombineForAcceptReject( const SwRedlineData& rCmp ) const;
// ExtraData gets copied, the pointer is therefore not taken over by
// the RedlineObject
@@ -261,6 +262,7 @@ public:
void PushData( const SwRangeRedline& rRedl, bool bOwnAsNext = true );
bool PopData();
bool PopAllDataAfter(int depth);
/**
Returns textual description of a redline data element of
diff --git a/sw/qa/extras/uiwriter/data/tdf157662_redlineNestedInsertDelete.odt b/sw/qa/extras/uiwriter/data/tdf157662_redlineNestedInsertDelete.odt
new file mode 100644
index 0000000..d975215
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf157662_redlineNestedInsertDelete.odt
Binary files differ
diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx b/sw/qa/extras/uiwriter/uiwriter5.cxx
index 285a3ad..d97e0a8 100644
--- a/sw/qa/extras/uiwriter/uiwriter5.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter5.cxx
@@ -2231,6 +2231,68 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testRedlineDOCXTableMoveToFrame)
CPPUNIT_ASSERT(!xTableNames->hasByName("Table2"));
}
CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf157662_AcceptInsertRedlineCutWithDeletion)
{
createSwDoc("tdf157662_redlineNestedInsertDelete.odt");
SwDoc* pDoc = getSwDoc();
// turn on red-lining 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()));
SwEditShell* const pEditShell(pDoc->GetEditShell());
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(9), pEditShell->GetRedlineCount());
// Accept the insert that splitted into 3 parts .. accept all 3 of them
pEditShell->AcceptRedline(6);
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(7), pEditShell->GetRedlineCount());
// The middle had a delete too, rejecting the delete will remove that redline too.
pEditShell->RejectRedline(6);
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(6), pEditShell->GetRedlineCount());
// Accept insert that splitted into 4 parts, but separeted to 2-2 parts, with another insert.
// It will accept only 2 parts, that is not separated. It leave the deletion.
pEditShell->AcceptRedline(0);
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(5), pEditShell->GetRedlineCount());
// Accepting the delete will remove that redline.
// (only that one, as its other half is separated from it with an insert)
pEditShell->AcceptRedline(0);
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(4), pEditShell->GetRedlineCount());
}
CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf157662_RejectInsertRedlineCutWithDeletion)
{
createSwDoc("tdf157662_redlineNestedInsertDelete.odt");
SwDoc* pDoc = getSwDoc();
// turn on red-lining 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()));
SwEditShell* const pEditShell(pDoc->GetEditShell());
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(9), pEditShell->GetRedlineCount());
// Reject the insert that splitted into 3 parts .. reject all 3 of them
// it even remove the deletion, that was on the 2. insert...
pEditShell->RejectRedline(6);
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(6), pEditShell->GetRedlineCount());
// Reject insert that splitted into 4 parts, but separeted to 2-2 parts, with another insert.
// It will reject only 2 parts, that is not separated. It remove the deletion.
pEditShell->RejectRedline(0);
CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(4), pEditShell->GetRedlineCount());
}
CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf143215)
{
// load a table with tracked insertion of an empty row
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index 75c5ba1..f5ab5a9 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -992,6 +992,18 @@ namespace
return bRet;
}
bool lcl_AcceptInnerInsertRedline(SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
int nDepth)
{
SwRangeRedline* pRedl = rArr[rPos];
SwDoc& rDoc = pRedl->GetDoc();
SwPaM const updatePaM(*pRedl->Start(), *pRedl->End());
pRedl->PopAllDataAfter(nDepth);
sw::UpdateFramesForRemoveDeleteRedline(rDoc, updatePaM);
return true;
}
typedef bool (*Fn_AcceptReject)( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
bool bCallDelete,
const SwPosition* pSttRng,
@@ -2863,7 +2875,118 @@ const SwRangeRedline* DocumentRedlineManager::GetRedline( const SwPosition& rPos
// #TODO - add 'SwExtraRedlineTable' also ?
}
bool DocumentRedlineManager::AcceptRedline( SwRedlineTable::size_type nPos, bool bCallDelete )
namespace
{
bool lcl_CanCombineWithRange(SwRangeRedline* pTmp, SwRangeRedline* pOther, SwPosition* pPamAct,
SwPosition* pPamOther, SwPosition* pPamAct2, SwPosition* pPamOther2)
{
if (!pOther->IsVisible())
return false;
if (*pPamAct != *pPamOther)
return false;
if (!pTmp->GetRedlineData(0).CanCombineForAcceptReject(pOther->GetRedlineData(0)))
{
if (pOther->GetStackCount() <= 1
|| !pTmp->GetRedlineData(0).CanCombineForAcceptReject(pOther->GetRedlineData(1)))
return false;
}
if (pPamAct2->GetNode().StartOfSectionNode() != pPamOther2->GetNode().StartOfSectionNode())
return false;
return true;
}
}
void DocumentRedlineManager::FindRangeToAcceptReject(SwRedlineTable::size_type nPos,
SwPosition** pPamStart, SwPosition** pPamEnd,
SwRedlineTable::size_type& nPosEnd) const
{
SwRangeRedline* pTmp = maRedlineTable[nPos];
nPosEnd = nPos;
SwRedlineTable::size_type nPosStart = nPos;
SwRangeRedline* pOther;
while (nPosStart > 0 && (pOther = maRedlineTable[nPosStart - 1])
&& lcl_CanCombineWithRange(pTmp, pOther, *pPamStart, pOther->End(), pOther->Start(),
*pPamEnd))
{
nPosStart--;
*pPamStart = pOther->Start();
}
while (nPosEnd + 1 < maRedlineTable.size() && (pOther = maRedlineTable[nPosEnd + 1])
&& lcl_CanCombineWithRange(pTmp, pOther, *pPamEnd, pOther->Start(), pOther->End(),
*pPamStart))
{
nPosEnd++;
*pPamEnd = pOther->End();
}
}
bool DocumentRedlineManager::AcceptRedlineRange(SwRedlineTable::size_type nPos, bool bCallDelete,
SwPosition* pPamStart, SwPosition* pPamEnd,
SwRedlineTable::size_type& nPosEnd)
{
bool bRet = false;
SwRangeRedline* pTmp = maRedlineTable[nPos];
SwRedlineTable::size_type nRdlIdx = nPosEnd + 1;
SwRedlineData aOrigData = pTmp->GetRedlineData(0);
SwNodeOffset nPamStartNI = pPamStart->GetNodeIndex();
sal_Int32 nPamStartCI = pPamStart->GetContentIndex();
SwNodeOffset nPamEndtNI = pPamEnd->GetNodeIndex();
sal_Int32 nPamEndCI = pPamEnd->GetContentIndex();
do
{
nRdlIdx--;
pTmp = maRedlineTable[nRdlIdx];
if (pTmp->Start()->GetNodeIndex() < nPamStartNI
|| (pTmp->Start()->GetNodeIndex() == nPamStartNI
&& pTmp->Start()->GetContentIndex() < nPamStartCI))
break;
if (pTmp->End()->GetNodeIndex() > nPamEndtNI
|| (pTmp->End()->GetNodeIndex() == nPamEndtNI
&& pTmp->End()->GetContentIndex() > nPamEndCI))
{
}
else if (pTmp->GetRedlineData(0).CanCombineForAcceptReject(aOrigData))
{
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
m_rDoc.GetIDocumentUndoRedo().AppendUndo(
std::make_unique<SwUndoAcceptRedline>(*pTmp));
}
nPamEndtNI = pTmp->Start()->GetNodeIndex();
nPamEndCI = pTmp->Start()->GetContentIndex();
bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete);
nRdlIdx++; //we will decrease it in the loop anyway.
}
else if (aOrigData.GetType() == RedlineType::Insert
&& pTmp->GetType() == RedlineType::Delete && pTmp->GetStackCount() > 1
&& pTmp->GetType(1) == RedlineType::Insert
&& pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData))
{
// The Insert redline we want to accept has a deletion redline too
// we should leave the deletion redline, and only accept the inner insert.
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
m_rDoc.GetIDocumentUndoRedo().AppendUndo(
std::make_unique<SwUndoAcceptRedline>(*pTmp, 1));
}
nPamEndtNI = pTmp->Start()->GetNodeIndex();
nPamEndCI = pTmp->Start()->GetContentIndex();
bRet |= lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1);
nRdlIdx++; //we will decrease it in the loop anyway.
}
} while (nRdlIdx > 0);
return bRet;
}
bool DocumentRedlineManager::AcceptRedline(SwRedlineTable::size_type nPos, bool bCallDelete,
bool bRange)
{
bool bRet = false;
@@ -2873,6 +2996,8 @@ bool DocumentRedlineManager::AcceptRedline( SwRedlineTable::size_type nPos, bool
SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | meRedlineFlags );
SwRangeRedline* pTmp = maRedlineTable[ nPos ];
bool bAnonym = pTmp->GetRedlineData(0).IsAnonymized();
pTmp->Show(0, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
pTmp->Show(1, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
if( pTmp->HasMark() && pTmp->IsVisible() )
@@ -2888,7 +3013,18 @@ bool DocumentRedlineManager::AcceptRedline( SwRedlineTable::size_type nPos, bool
int nLoopCnt = 2;
sal_uInt16 nSeqNo = pTmp->GetSeqNo();
do {
if (bRange && !nSeqNo && !bAnonym
&& !pTmp->Start()->GetNode().StartOfSectionNode()->IsTableNode())
{
auto [pPamStart, pPamEnd] = pTmp->StartEnd();
SwRedlineTable::size_type nPosEnd;
FindRangeToAcceptReject(nPos, &pPamStart, &pPamEnd, nPosEnd);
// Accept redlines between pPamStart-pPamEnd.
// but only those that can be combined with the selected.
bRet |= AcceptRedlineRange(nPos, bCallDelete, pPamStart, pPamEnd, nPosEnd);
}
else do {
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
@@ -2918,7 +3054,7 @@ bool DocumentRedlineManager::AcceptRedline( SwRedlineTable::size_type nPos, bool
else
nLoopCnt = 0;
} while( nLoopCnt );
} while (nLoopCnt);
if( bRet )
{
@@ -2936,7 +3072,7 @@ bool DocumentRedlineManager::AcceptRedline( SwRedlineTable::size_type nPos, bool
// #TODO - add 'SwExtraRedlineTable' also ?
}
bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool bCallDelete )
bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool bCallDelete, sal_Int8 nDepth )
{
// Switch to visible in any case
if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
@@ -2957,11 +3093,23 @@ bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool bCallDelete
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::ACCEPT_REDLINE, nullptr );
m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAcceptRedline>(*pPam));
m_rDoc.GetIDocumentUndoRedo().AppendUndo(
std::make_unique<SwUndoAcceptRedline>(*pPam, nDepth));
}
int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, maRedlineTable,
bCallDelete, *pPam );
int nRet = 0;
if (nDepth == 0)
{
nRet = lcl_AcceptRejectRedl(lcl_AcceptRedline, maRedlineTable, bCallDelete, *pPam);
}
else
{
// For now it is called only if it is an Insert redline in a delete redline.
SwRedlineTable::size_type nRdlIdx = 0;
maRedlineTable.FindAtPosition(*rPam.Start(), nRdlIdx);
if (lcl_AcceptInnerInsertRedline(maRedlineTable, nRdlIdx, 1))
nRet = 1;
}
if( nRet > 0 )
{
CompressRedlines();
@@ -3011,7 +3159,79 @@ void DocumentRedlineManager::AcceptRedlineParagraphFormatting( const SwPaM &rPam
}
}
bool DocumentRedlineManager::RejectRedline( SwRedlineTable::size_type nPos, bool bCallDelete )
bool DocumentRedlineManager::RejectRedlineRange(SwRedlineTable::size_type nPos, bool bCallDelete,
SwPosition* pPamStart, SwPosition* pPamEnd,
SwRedlineTable::size_type& nPosEnd)
{
bool bRet = false;
SwRangeRedline* pTmp = maRedlineTable[nPos];
SwRedlineTable::size_type nRdlIdx = nPosEnd + 1;
SwRedlineData aOrigData = pTmp->GetRedlineData(0);
SwNodeOffset nPamStartNI = pPamStart->GetNodeIndex();
sal_Int32 nPamStartCI = pPamStart->GetContentIndex();
SwNodeOffset nPamEndtNI = pPamEnd->GetNodeIndex();
sal_Int32 nPamEndCI = pPamEnd->GetContentIndex();
do
{
nRdlIdx--;
pTmp = maRedlineTable[nRdlIdx];
if (pTmp->Start()->GetNodeIndex() < nPamStartNI
|| (pTmp->Start()->GetNodeIndex() == nPamStartNI
&& pTmp->Start()->GetContentIndex() < nPamStartCI))
break;
if (pTmp->End()->GetNodeIndex() > nPamEndtNI
|| (pTmp->End()->GetNodeIndex() == nPamEndtNI
&& pTmp->End()->GetContentIndex() > nPamEndCI))
{
}
else if (pTmp->GetRedlineData(0).CanCombineForAcceptReject(aOrigData))
{
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
std::unique_ptr<SwUndoRejectRedline> pUndoRdl
= std::make_unique<SwUndoRejectRedline>(*pTmp);
#if OSL_DEBUG_LEVEL > 0
pUndoRdl->SetRedlineCountDontCheck(true);
#endif
m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndoRdl));
}
nPamEndtNI = pTmp->Start()->GetNodeIndex();
nPamEndCI = pTmp->Start()->GetContentIndex();
bRet |= lcl_RejectRedline(maRedlineTable, nRdlIdx, bCallDelete);
nRdlIdx++; //we will decrease it in the loop anyway.
}
else if (aOrigData.GetType() == RedlineType::Insert
&& pTmp->GetType() == RedlineType::Delete && pTmp->GetStackCount() > 1
&& pTmp->GetType(1) == RedlineType::Insert
&& pTmp->GetRedlineData(1).CanCombineForAcceptReject(aOrigData))
{
// The Insert redline we want to reject has a deletion redline too
// without the insert, the delete is meaningless
// so we rather just accept the deletion redline
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
std::unique_ptr<SwUndoRejectRedline> pUndoRdl
= std::make_unique<SwUndoRejectRedline>(*pTmp, 1);
#if OSL_DEBUG_LEVEL > 0
pUndoRdl->SetRedlineCountDontCheck(true);
#endif
m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndoRdl));
}
nPamEndtNI = pTmp->Start()->GetNodeIndex();
nPamEndCI = pTmp->Start()->GetContentIndex();
bRet |= lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete);
nRdlIdx++; //we will decrease it in the loop anyway.
}
} while (nRdlIdx > 0);
return bRet;
}
bool DocumentRedlineManager::RejectRedline(SwRedlineTable::size_type nPos,
bool bCallDelete, bool bRange)
{
bool bRet = false;
@@ -3021,6 +3241,8 @@ bool DocumentRedlineManager::RejectRedline( SwRedlineTable::size_type nPos, bool
SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | meRedlineFlags );
SwRangeRedline* pTmp = maRedlineTable[ nPos ];
bool bAnonym = pTmp->GetRedlineData(0).IsAnonymized();
pTmp->Show(0, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
pTmp->Show(1, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
if( pTmp->HasMark() && pTmp->IsVisible() )
@@ -3036,7 +3258,19 @@ bool DocumentRedlineManager::RejectRedline( SwRedlineTable::size_type nPos, bool
int nLoopCnt = 2;
sal_uInt16 nSeqNo = pTmp->GetSeqNo();
do {
if (bRange && !nSeqNo && !bAnonym
&& !pTmp->Start()->GetNode().StartOfSectionNode()->IsTableNode())
{
auto [pPamStart, pPamEnd] = pTmp->StartEnd();
SwRedlineTable::size_type nPosEnd;
FindRangeToAcceptReject(nPos, &pPamStart, &pPamEnd, nPosEnd);
// Reject items between pPamStart-pPamEnd
// but only those that can be combined with the selected.
bRet |= RejectRedlineRange(nPos, bCallDelete, pPamStart, pPamEnd, nPosEnd);
}
else do {
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
@@ -3066,7 +3300,7 @@ bool DocumentRedlineManager::RejectRedline( SwRedlineTable::size_type nPos, bool
else
nLoopCnt = 0;
} while( nLoopCnt );
} while (nLoopCnt);
if( bRet )
{
@@ -3084,7 +3318,7 @@ bool DocumentRedlineManager::RejectRedline( SwRedlineTable::size_type nPos, bool
// #TODO - add 'SwExtraRedlineTable' also ?
}
bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool bCallDelete )
bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool bCallDelete, sal_Int8 nDepth )
{
// Switch to visible in any case
if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
@@ -3100,11 +3334,23 @@ bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool bCallDelete
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::REJECT_REDLINE, nullptr );
m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoRejectRedline>(aPam) );
m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoRejectRedline>(aPam, nDepth) );
}
int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, maRedlineTable,
bCallDelete, aPam );
int nRet = 0;
if (nDepth == 0)
{
nRet = lcl_AcceptRejectRedl(lcl_RejectRedline, maRedlineTable, bCallDelete, aPam);
}
else
{
// For now it is called only if it is an Insert redline in a delete redline.
SwRedlineTable::size_type nRdlIdx = 0;
maRedlineTable.FindAtPosition(*rPam.Start(), nRdlIdx);
if (lcl_AcceptRedline(maRedlineTable, nRdlIdx, bCallDelete))
nRet = 1;
}
if( nRet > 0 )
{
CompressRedlines();
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 205e532..50c259f 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -1109,6 +1109,20 @@ bool SwRedlineData::CanCombine(const SwRedlineData& rCmp) const
*m_pExtraData == *rCmp.m_pExtraData ));
}
// Check if we could/should accept/reject the 2 redlineData at the same time.
// No need to check its childs equality
bool SwRedlineData::CanCombineForAcceptReject(const SwRedlineData& rCmp) const
{
return m_nAuthor == rCmp.m_nAuthor &&
m_eType == rCmp.m_eType &&
m_sComment == rCmp.m_sComment &&
deltaOneMinute(GetTimeStamp(), rCmp.GetTimeStamp()) &&
m_bMoved == rCmp.m_bMoved &&
(( !m_pExtraData && !rCmp.m_pExtraData ) ||
( m_pExtraData && rCmp.m_pExtraData &&
*m_pExtraData == *rCmp.m_pExtraData ));
}
/// ExtraData is copied. The Pointer's ownership is thus NOT transferred
/// to the Redline Object!
void SwRedlineData::SetExtraData( const SwRedlineExtraData* pData )
@@ -1981,6 +1995,27 @@ bool SwRangeRedline::PopData()
return true;
}
bool SwRangeRedline::PopAllDataAfter(int depth)
{
assert(depth > 0);
SwRedlineData* pCur = m_pRedlineData;
while (depth > 1)
{
pCur = pCur->m_pNext;
if (!pCur)
return false;
depth--;
}
while (pCur->m_pNext)
{
SwRedlineData* pToDelete = pCur->m_pNext;
pCur->m_pNext = pToDelete->m_pNext;
delete pToDelete;
}
return true;
}
sal_uInt16 SwRangeRedline::GetStackCount() const
{
sal_uInt16 nRet = 1;
diff --git a/sw/source/core/edit/edredln.cxx b/sw/source/core/edit/edredln.cxx
index 835a1c3..1778745 100644
--- a/sw/source/core/edit/edredln.cxx
+++ b/sw/source/core/edit/edredln.cxx
@@ -68,7 +68,7 @@ bool SwEditShell::AcceptRedline( SwRedlineTable::size_type nPos )
{
CurrShell aCurr( this );
StartAllAction();
bool bRet = GetDoc()->getIDocumentRedlineAccess().AcceptRedline( nPos, true );
bool bRet = GetDoc()->getIDocumentRedlineAccess().AcceptRedline( nPos, true, true );
if( !nPos && !::IsExtraData( GetDoc() ) )
lcl_InvalidateAll( this );
EndAllAction();
@@ -79,7 +79,7 @@ bool SwEditShell::RejectRedline( SwRedlineTable::size_type nPos )
{
CurrShell aCurr( this );
StartAllAction();
bool bRet = GetDoc()->getIDocumentRedlineAccess().RejectRedline( nPos, true );
bool bRet = GetDoc()->getIDocumentRedlineAccess().RejectRedline( nPos, true, true );
if( !nPos && !::IsExtraData( GetDoc() ) )
lcl_InvalidateAll( this );
EndAllAction();
diff --git a/sw/source/core/inc/DocumentRedlineManager.hxx b/sw/source/core/inc/DocumentRedlineManager.hxx
index a3644f4..2f9c133 100644
--- a/sw/source/core/inc/DocumentRedlineManager.hxx
+++ b/sw/source/core/inc/DocumentRedlineManager.hxx
@@ -89,15 +89,19 @@ public:
virtual void SetRedlineMove(/*[in]*/bool bFlag) override;
virtual bool AcceptRedline(/*[in]*/SwRedlineTable::size_type nPos, /*[in]*/bool bCallDelete) override;
virtual bool AcceptRedline(/*[in]*/ SwRedlineTable::size_type nPos, /*[in]*/ bool bCallDelete,
/*[in]*/ bool bRange = false) override;
virtual bool AcceptRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool bCallDelete) override;
virtual bool AcceptRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool bCallDelete,
/*[in]*/ sal_Int8 nDepth = 0) override;
virtual void AcceptRedlineParagraphFormatting(/*[in]*/const SwPaM& rPam) override;
virtual bool RejectRedline(/*[in]*/SwRedlineTable::size_type nPos, /*[in]*/bool bCallDelete) override;
virtual bool RejectRedline(/*[in]*/ SwRedlineTable::size_type nPos, /*[in]*/ bool bCallDelete,
/*[in]*/ bool bRange = false) override;
virtual bool RejectRedline(/*[in]*/const SwPaM& rPam, /*[in]*/bool bCallDelete) override;
virtual bool RejectRedline(/*[in]*/ const SwPaM& rPam, /*[in]*/ bool bCallDelete,
/*[in]*/ sal_Int8 nDepth = 0) override;
virtual void AcceptAllRedline(/*[in]*/bool bAcceptReject) override;
@@ -137,6 +141,13 @@ public:
private:
void FindRangeToAcceptReject(SwRedlineTable::size_type nPos, SwPosition** pPamStart,
SwPosition** pPamEnd, SwRedlineTable::size_type& nPosEnd) const;
bool RejectRedlineRange(SwRedlineTable::size_type nPos, bool bCallDelete, SwPosition* pPamStart,
SwPosition* pPamEnd, SwRedlineTable::size_type& nPosEnd);
bool AcceptRedlineRange(SwRedlineTable::size_type nPos, bool bCallDelete, SwPosition* pPamStart,
SwPosition* pPamEnd, SwRedlineTable::size_type& nPosEnd);
DocumentRedlineManager(DocumentRedlineManager const&) = delete;
DocumentRedlineManager& operator=(DocumentRedlineManager const&) = delete;
diff --git a/sw/source/core/inc/UndoCore.hxx b/sw/source/core/inc/UndoCore.hxx
index 5c4b709..94891df 100644
--- a/sw/source/core/inc/UndoCore.hxx
+++ b/sw/source/core/inc/UndoCore.hxx
@@ -61,6 +61,7 @@ public:
#if OSL_DEBUG_LEVEL > 0
sal_uInt16 m_nRedlineCount;
bool m_bRedlineCountDontCheck;
bool m_bRedlineMoved;
#endif
};
@@ -78,6 +79,9 @@ public:
void push_back(std::unique_ptr<SwRedlineSaveData> pNew) { m_Data.push_back(std::move(pNew)); }
const SwRedlineSaveData& operator[](size_t const nIdx) const { return *m_Data[ nIdx ]; }
SwRedlineSaveData& operator[](size_t const nIdx) { return *m_Data[ nIdx ]; }
#if OSL_DEBUG_LEVEL > 0
void SetRedlineCountDontCheck(bool bCheck) { m_Data[0]->m_bRedlineCountDontCheck=bCheck; }
#endif
};
namespace sw {
diff --git a/sw/source/core/inc/UndoRedline.hxx b/sw/source/core/inc/UndoRedline.hxx
index f1cf458..127aeae 100644
--- a/sw/source/core/inc/UndoRedline.hxx
+++ b/sw/source/core/inc/UndoRedline.hxx
@@ -36,12 +36,13 @@ protected:
std::unique_ptr<SwRedlineSaveDatas> mpRedlSaveData;
SwUndoId mnUserId;
bool mbHiddenRedlines;
sal_Int8 mnDepth; // index of the SwRedlineData in SwRangeRedline
virtual void UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam);
virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam);
public:
SwUndoRedline( SwUndoId nUserId, const SwPaM& rRange );
SwUndoRedline( SwUndoId nUserId, const SwPaM& rRange, sal_Int8 nDepth = 0 );
virtual ~SwUndoRedline() override;
@@ -49,6 +50,9 @@ public:
virtual void RedoImpl( ::sw::UndoRedoContext & ) override;
sal_uInt16 GetRedlSaveCount() const;
#if OSL_DEBUG_LEVEL > 0
void SetRedlineCountDontCheck(bool bCheck);
#endif
};
class SwUndoRedlineDelete final : public SwUndoRedline
@@ -106,7 +110,7 @@ private:
virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
public:
SwUndoAcceptRedline( const SwPaM& rRange );
SwUndoAcceptRedline( const SwPaM& rRange, sal_Int8 nDepth = 0 );
virtual void RepeatImpl( ::sw::RepeatContext & ) override;
};
@@ -117,7 +121,7 @@ private:
virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
public:
SwUndoRejectRedline( const SwPaM& rRange );
SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth = 0 );
virtual void RepeatImpl( ::sw::RepeatContext & ) override;
};
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index dce7f3e..bd258dc 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -1410,6 +1410,7 @@ SwRedlineSaveData::SwRedlineSaveData(
#if OSL_DEBUG_LEVEL > 0
m_nRedlineCount = rSttPos.GetNode().GetDoc().getIDocumentRedlineAccess().GetRedlineTable().size();
m_bRedlineCountDontCheck = false;
m_bRedlineMoved = rRedl.IsMoved();
#endif
}
@@ -1525,7 +1526,8 @@ void SwUndo::SetSaveData( SwDoc& rDoc, SwRedlineSaveDatas& rSData )
#if OSL_DEBUG_LEVEL > 0
// check redline count against count saved in RedlineSaveData object
// except in the case of moved redlines
assert(rSData.empty() || rSData[0].m_bRedlineMoved ||
assert(
rSData.empty() || rSData[0].m_bRedlineMoved || rSData[0].m_bRedlineCountDontCheck ||
(rSData[0].m_nRedlineCount == rDoc.getIDocumentRedlineAccess().GetRedlineTable().size()));
// "redline count not restored properly"
#endif
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index a8a572a..f77ceb3 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -37,10 +37,11 @@
#include <sortopt.hxx>
#include <docedt.hxx>
SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange )
SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange, sal_Int8 nDepth )
: SwUndo( SwUndoId::REDLINE, &rRange.GetDoc() ), SwUndRng( rRange ),
mnUserId( nUsrId ),
mbHiddenRedlines( false )
mbHiddenRedlines( false ),
mnDepth( nDepth )
{
// consider Redline
SwDoc& rDoc = rRange.GetDoc();
@@ -88,6 +89,14 @@ sal_uInt16 SwUndoRedline::GetRedlSaveCount() const
return mpRedlSaveData ? mpRedlSaveData->size() : 0;
}
#if OSL_DEBUG_LEVEL > 0
void SwUndoRedline::SetRedlineCountDontCheck(bool bCheck)
{
if (mpRedlSaveData)
mpRedlSaveData->SetRedlineCountDontCheck(bCheck);
}
#endif
void SwUndoRedline::UndoImpl(::sw::UndoRedoContext & rContext)
{
SwDoc& rDoc = rContext.GetDoc();
@@ -417,14 +426,14 @@ void SwUndoRedlineSort::SetSaveRange( const SwPaM& rRange )
m_nSaveEndContent = rPos.GetContentIndex();
}
SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange )
: SwUndoRedline( SwUndoId::ACCEPT_REDLINE, rRange )
SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange, sal_Int8 nDepth /* = 0 */ )
: SwUndoRedline( SwUndoId::ACCEPT_REDLINE, rRange, nDepth )
{
}
void SwUndoAcceptRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
{
rDoc.getIDocumentRedlineAccess().AcceptRedline(rPam, false);
rDoc.getIDocumentRedlineAccess().AcceptRedline(rPam, false, mnDepth);
}
void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext)
@@ -432,14 +441,14 @@ void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext)
rContext.GetDoc().getIDocumentRedlineAccess().AcceptRedline(rContext.GetRepeatPaM(), true);
}
SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange )
: SwUndoRedline( SwUndoId::REJECT_REDLINE, rRange )
SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange, sal_Int8 nDepth /* = 0 */ )
: SwUndoRedline( SwUndoId::REJECT_REDLINE, rRange, nDepth )
{
}
void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
{
rDoc.getIDocumentRedlineAccess().RejectRedline(rPam, false);
rDoc.getIDocumentRedlineAccess().RejectRedline(rPam, false, mnDepth);
}
void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext)