diff options
-rw-r--r-- | sw/inc/redline.hxx | 11 | ||||
-rw-r--r-- | sw/qa/extras/layout/data/tdf145719.odt | bin | 0 -> 10558 bytes | |||
-rw-r--r-- | sw/qa/extras/layout/layout2.cxx | 16 | ||||
-rw-r--r-- | sw/source/core/doc/docredln.cxx | 100 | ||||
-rw-r--r-- | sw/source/core/inc/UndoCore.hxx | 1 | ||||
-rw-r--r-- | sw/source/core/undo/undobj.cxx | 4 |
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 Binary files differnew file mode 100644 index 000000000000..62e4cc4a73e4 --- /dev/null +++ b/sw/qa/extras/layout/data/tdf145719.odt 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 |