summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/inc/redline.hxx11
-rw-r--r--sw/qa/extras/layout/data/tdf145719.odtbin0 -> 10558 bytes
-rw-r--r--sw/qa/extras/layout/layout2.cxx16
-rw-r--r--sw/source/core/doc/docredln.cxx100
-rw-r--r--sw/source/core/inc/UndoCore.hxx1
-rw-r--r--sw/source/core/undo/undobj.cxx4
6 files changed, 93 insertions, 39 deletions
diff --git a/sw/inc/redline.hxx b/sw/inc/redline.hxx
index 8d17948205fa..5e01cfa8349f 100644
--- a/sw/inc/redline.hxx
+++ b/sw/inc/redline.hxx
@@ -95,6 +95,7 @@ class SW_DLLPUBLIC SwRedlineData
RedlineType m_eType;
sal_uInt16 m_nSeqNo;
bool m_bAutoFormat;
+ bool m_bMoved;
public:
SwRedlineData( RedlineType eT, std::size_t nAut );
@@ -111,6 +112,7 @@ public:
return m_nAuthor == rCmp.m_nAuthor &&
m_eType == rCmp.m_eType &&
m_bAutoFormat == rCmp.m_bAutoFormat &&
+ m_bMoved == rCmp.m_bMoved &&
m_sComment == rCmp.m_sComment &&
(( !m_pNext && !rCmp.m_pNext ) ||
( m_pNext && rCmp.m_pNext && *m_pNext == *rCmp.m_pNext )) &&
@@ -133,6 +135,8 @@ public:
void SetAutoFormat() { m_bAutoFormat = true; }
bool IsAutoFormat() const { return m_bAutoFormat; }
+ void SetMoved() { m_bMoved = true; }
+ bool IsMoved() const { return m_bMoved; }
bool CanCombine( const SwRedlineData& rCmp ) const;
// ExtraData gets copied, the pointer is therefore not taken over by
@@ -155,7 +159,6 @@ class SW_DLLPUBLIC SwRangeRedline final : public SwPaM
SwNodeIndex* m_pContentSect;
bool m_bDelLastPara : 1;
bool m_bIsVisible : 1;
- bool m_bIsMoved : 1;
sal_uInt32 m_nId;
std::optional<tools::Long> m_oLOKLastNodeTop;
@@ -175,7 +178,7 @@ public:
SwRangeRedline(SwRedlineData* pData, const SwPosition& rPos,
bool bDelLP) :
SwPaM( rPos ), m_pRedlineData( pData ), m_pContentSect( nullptr ),
- m_bDelLastPara( bDelLP ), m_bIsVisible( true ), m_bIsMoved( false ), m_nId( s_nLastId++ )
+ m_bDelLastPara( bDelLP ), m_bIsVisible( true ), m_nId( s_nLastId++ )
{}
SwRangeRedline( const SwRangeRedline& );
virtual ~SwRangeRedline() override;
@@ -263,8 +266,8 @@ public:
void MaybeNotifyRedlinePositionModification(tools::Long nTop);
- void SetMoved() { m_bIsMoved = true; }
- bool IsMoved() const { return m_bIsMoved; }
+ void SetMoved() { m_pRedlineData->SetMoved(); }
+ bool IsMoved() const { return m_pRedlineData->IsMoved(); }
};
void MaybeNotifyRedlineModification(SwRangeRedline& rRedline, SwDoc& rDoc);
diff --git a/sw/qa/extras/layout/data/tdf145719.odt b/sw/qa/extras/layout/data/tdf145719.odt
new file mode 100644
index 000000000000..62e4cc4a73e4
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf145719.odt
Binary files differ
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index 9eee8228ea8d..3ca1abc2747a 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -350,6 +350,22 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testRedlineMovingDOCX)
assertXPath(pXmlDoc, "/metafile/push/push/push/textcolor[@color='#008000']", 6);
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf145719)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf145719.odt");
+ SwDocShell* pShell = pDoc->GetDocShell();
+
+ // Dump the rendering of the first page as an XML file.
+ std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
+ MetafileXmlDump dumper;
+ xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
+ CPPUNIT_ASSERT(pXmlDoc);
+
+ // text colors show moved text
+ // This was 0 (other color, not COL_GREEN, color of the tracked text movement)
+ assertXPath(pXmlDoc, "/metafile/push/push/push/textcolor[@color='#008000']", 4);
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf145225_RedlineMovingWithBadInsertion)
{
SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf42748.fodt");
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 732d92a40246..d911ecb85d53 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -772,6 +772,7 @@ const SwRangeRedline* SwRedlineTable::FindAtPosition( const SwPosition& rSttPos,
bool SwRedlineTable::isMoved( size_type rPos ) const
{
+ bool bRet = false;
auto constexpr nLookahead = 20;
SwRangeRedline* pRedline = (*this)[ rPos ];
@@ -785,43 +786,79 @@ bool SwRedlineTable::isMoved( size_type rPos ) const
// only deleted or inserted text can be moved
return false;
- // Skip terminating white spaces of the redline, a workaround
- // for a typical difference resulted by e.g. Writer UX:
- // selecting a sentence or a word, and moving it with
- // the mouse, Writer removes a space at the deletion
- // to avoid double spaces, also inserts a space at
- // the insertion point automatically. Because the result
- // can be different (space before and space after the
- // moved text), compare the redlines without terminating spaces
- const OUString sTrimmed = pRedline->GetText().trim();
+ bool bDeletePaM = false;
+ SwPaM* pPaM;
+
+ // if this redline is visible the content is in this PaM
+ if ( nullptr == pRedline->GetContentIdx() )
+ {
+ pPaM = pRedline;
+ }
+ else // otherwise it is saved in pContentSect, e.g. during ODT import
+ {
+ SwNodeIndex aTmpIdx( *pRedline->GetContentIdx()->GetNode().EndOfSectionNode() );
+ pPaM = new SwPaM(*pRedline->GetContentIdx(), aTmpIdx );
+ bDeletePaM = true;
+ }
+
+ const OUString sTrimmed = pPaM->GetText().trim();
if ( sTrimmed.isEmpty() )
+ {
+ if ( bDeletePaM )
+ delete pPaM;
return false;
+ }
// search pair around the actual redline
size_type nEnd = rPos + nLookahead < size()
? rPos + nLookahead
: size();
rPos = rPos > nLookahead ? rPos - nLookahead : 0;
- for ( ; rPos < nEnd ; ++rPos )
+ for ( ; rPos < nEnd && !bRet ; ++rPos )
{
SwRangeRedline* pPair = (*this)[ rPos ];
- // TODO handle also Show Changes in Margin mode
- if ( pPair->HasMark() && pPair->IsVisible() )
+
+ // redline must be the requested type and from the same author
+ if ( nPairType != pPair->GetType() ||
+ pRedline->GetAuthor() != pPair->GetAuthor() )
{
- // pair at tracked moving: same text from the same author, but with opposite type
- if ( nPairType == pPair->GetType() &&
- pRedline->GetAuthor() == pPair->GetAuthor() &&
- abs(pRedline->GetText().getLength() - pPair->GetText().getLength()) <= 2 &&
- sTrimmed == pPair->GetText().trim() )
- {
- pRedline->SetMoved();
- pPair->SetMoved();
- pPair->InvalidateRange(SwRangeRedline::Invalidation::Remove);
- return true;
- }
+ continue;
}
+
+ bool bDeletePairPaM = false;
+ SwPaM* pPairPaM;
+
+ // if this redline is visible the content is in this PaM
+ if ( nullptr == pPair->GetContentIdx() )
+ {
+ pPairPaM = pPair;
+ }
+ else // otherwise it is saved in pContentSect, e.g. during ODT import
+ {
+ // saved in pContentSect, e.g. during ODT import
+ SwNodeIndex aTmpIdx( *pPair->GetContentIdx()->GetNode().EndOfSectionNode() );
+ pPairPaM = new SwPaM(*pPair->GetContentIdx(), aTmpIdx );
+ bDeletePairPaM = true;
+ }
+
+ // pair at tracked moving: same text by trimming terminatin white spaces
+ if ( abs(pPaM->GetText().getLength() - pPairPaM->GetText().getLength()) <= 2 &&
+ sTrimmed == pPairPaM->GetText().trim() )
+ {
+ pRedline->SetMoved();
+ pPair->SetMoved();
+ pPair->InvalidateRange(SwRangeRedline::Invalidation::Remove);
+ bRet = true;
+ }
+
+ if ( bDeletePairPaM )
+ delete pPairPaM;
}
- return false;
+
+ if ( bDeletePaM )
+ delete pPaM;
+
+ return bRet;
}
void SwRedlineTable::dumpAsXml(xmlTextWriterPtr pWriter) const
@@ -987,7 +1024,7 @@ bool SwRedlineExtraData_Format::operator == ( const SwRedlineExtraData& rCmp ) c
SwRedlineData::SwRedlineData( RedlineType eT, std::size_t nAut )
: m_pNext( nullptr ), m_pExtraData( nullptr ),
m_aStamp( DateTime::SYSTEM ),
- m_nAuthor( nAut ), m_eType( eT ), m_nSeqNo( 0 ), m_bAutoFormat(false)
+ m_nAuthor( nAut ), m_eType( eT ), m_nSeqNo( 0 ), m_bAutoFormat(false), m_bMoved(false)
{
m_aStamp.SetNanoSec( 0 );
}
@@ -1003,6 +1040,7 @@ SwRedlineData::SwRedlineData(
, m_eType( rCpy.m_eType )
, m_nSeqNo( rCpy.m_nSeqNo )
, m_bAutoFormat(false)
+ , m_bMoved( rCpy.m_bMoved )
{
}
@@ -1010,7 +1048,7 @@ SwRedlineData::SwRedlineData(
SwRedlineData::SwRedlineData(RedlineType eT, std::size_t nAut, const DateTime& rDT,
const OUString& rCmnt, SwRedlineData *pNxt)
: m_pNext(pNxt), m_pExtraData(nullptr), m_sComment(rCmnt), m_aStamp(rDT),
- m_nAuthor(nAut), m_eType(eT), m_nSeqNo(0), m_bAutoFormat(false)
+ m_nAuthor(nAut), m_eType(eT), m_nSeqNo(0), m_bAutoFormat(false), m_bMoved(false)
{
}
@@ -1030,6 +1068,7 @@ bool SwRedlineData::CanCombine(const SwRedlineData& rCmp) const
m_eType == rCmp.m_eType &&
m_sComment == rCmp.m_sComment &&
aTime == aCompareTime &&
+ m_bMoved == rCmp.m_bMoved &&
(( !m_pNext && !rCmp.m_pNext ) ||
( m_pNext && rCmp.m_pNext &&
m_pNext->CanCombine( *rCmp.m_pNext ))) &&
@@ -1080,7 +1119,6 @@ SwRangeRedline::SwRangeRedline(RedlineType eTyp, const SwPaM& rPam )
{
m_bDelLastPara = false;
m_bIsVisible = true;
- m_bIsMoved = false;
if( !rPam.HasMark() )
DeleteMark();
}
@@ -1093,7 +1131,6 @@ SwRangeRedline::SwRangeRedline( const SwRedlineData& rData, const SwPaM& rPam )
{
m_bDelLastPara = false;
m_bIsVisible = true;
- m_bIsMoved = false;
if( !rPam.HasMark() )
DeleteMark();
}
@@ -1106,7 +1143,6 @@ SwRangeRedline::SwRangeRedline( const SwRedlineData& rData, const SwPosition& rP
{
m_bDelLastPara = false;
m_bIsVisible = true;
- m_bIsMoved = false;
}
SwRangeRedline::SwRangeRedline( const SwRangeRedline& rCpy )
@@ -1117,9 +1153,6 @@ SwRangeRedline::SwRangeRedline( const SwRangeRedline& rCpy )
{
m_bDelLastPara = false;
m_bIsVisible = true;
- // inserting characters within a moved text must keep
- // IsMoved bit in the second part of the split redline
- m_bIsMoved = rCpy.IsMoved();
if( !rCpy.HasMark() )
DeleteMark();
}
@@ -1840,8 +1873,7 @@ void SwRangeRedline::SetContentIdx( const SwNodeIndex* pIdx )
bool SwRangeRedline::CanCombine( const SwRangeRedline& rRedl ) const
{
return IsVisible() && rRedl.IsVisible() &&
- m_pRedlineData->CanCombine( *rRedl.m_pRedlineData ) &&
- !IsMoved() && !rRedl.IsMoved();
+ m_pRedlineData->CanCombine( *rRedl.m_pRedlineData );
}
void SwRangeRedline::PushData( const SwRangeRedline& rRedl, bool bOwnAsNext )
diff --git a/sw/source/core/inc/UndoCore.hxx b/sw/source/core/inc/UndoCore.hxx
index 7e670c9c6ba4..6efaf23c0b61 100644
--- a/sw/source/core/inc/UndoCore.hxx
+++ b/sw/source/core/inc/UndoCore.hxx
@@ -62,6 +62,7 @@ public:
#if OSL_DEBUG_LEVEL > 0
sal_uInt16 m_nRedlineCount;
+ bool m_bRedlineMoved;
#endif
};
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index b03a3e1daded..64faed602dae 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -1367,6 +1367,7 @@ SwRedlineSaveData::SwRedlineSaveData(
#if OSL_DEBUG_LEVEL > 0
m_nRedlineCount = rSttPos.nNode.GetNode().GetDoc().getIDocumentRedlineAccess().GetRedlineTable().size();
+ m_bRedlineMoved = rRedl.IsMoved();
#endif
}
@@ -1481,7 +1482,8 @@ void SwUndo::SetSaveData( SwDoc& rDoc, SwRedlineSaveDatas& rSData )
#if OSL_DEBUG_LEVEL > 0
// check redline count against count saved in RedlineSaveData object
- assert(rSData.empty() ||
+ // except in the case of moved redlines
+ assert(rSData.empty() || rSData[0].m_bRedlineMoved ||
(rSData[0].m_nRedlineCount == rDoc.getIDocumentRedlineAccess().GetRedlineTable().size()));
// "redline count not restored properly"
#endif