1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <libxml/xmlwriter.h>
21 #include <boost/property_tree/json_parser.hpp>
23 #include <osl/diagnose.h>
24 #include <sal/log.hxx>
25 #include <tools/datetimeutils.hxx>
26 #include <hintids.hxx>
27 #include <svl/itemiter.hxx>
28 #include <editeng/prntitem.hxx>
29 #include <comphelper/lok.hxx>
30 #include <comphelper/string.hxx>
31 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
32 #include <unotools/datetime.hxx>
33 #include <sfx2/viewsh.hxx>
34 #include <o3tl/string_view.hxx>
35 #include <swmodule.hxx>
37 #include <docredln.hxx>
38 #include <IDocumentUndoRedo.hxx>
39 #include <DocumentContentOperationsManager.hxx>
40 #include <IDocumentRedlineAccess.hxx>
41 #include <IDocumentState.hxx>
42 #include <IDocumentLayoutAccess.hxx>
43 #include <IDocumentStylePoolAccess.hxx>
46 #include <redline.hxx>
47 #include <UndoCore.hxx>
50 #include <poolfmt.hxx>
55 #include <viewopt.hxx>
56 #include <usrpref.hxx>
59 #include <rootfrm.hxx>
60 #include <strings.hrc>
61 #include <swtypes.hxx>
65 #include <flowfrm.hxx>
68 using namespace com::sun::star
;
72 void sw_DebugRedline( const SwDoc
* pDoc
)
74 static SwRedlineTable::size_type nWatch
= 0; // loplugin:constvars:ignore
75 const SwRedlineTable
& rTable
= pDoc
->getIDocumentRedlineAccess().GetRedlineTable();
76 for( SwRedlineTable::size_type n
= 0; n
< rTable
.size(); ++n
)
78 volatile SwRedlineTable::size_type nDummy
= 0;
79 const SwRangeRedline
* pCurrent
= rTable
[ n
];
80 const SwRangeRedline
* pNext
= n
+1 < rTable
.size() ? rTable
[ n
+1 ] : nullptr;
81 if( pCurrent
== pNext
)
84 (void) nDummy
; // Possible debugger breakpoint
91 SwExtraRedlineTable::~SwExtraRedlineTable()
93 DeleteAndDestroyAll();
96 void SwExtraRedlineTable::dumpAsXml(xmlTextWriterPtr pWriter
) const
98 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwExtraRedlineTable"));
99 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
101 for (sal_uInt16 nCurExtraRedlinePos
= 0; nCurExtraRedlinePos
< GetSize(); ++nCurExtraRedlinePos
)
103 const SwExtraRedline
* pExtraRedline
= GetRedline(nCurExtraRedlinePos
);
104 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwExtraRedline"));
105 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
106 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("symbol"), "%s", BAD_CAST(typeid(*pExtraRedline
).name()));
107 (void)xmlTextWriterEndElement(pWriter
);
109 (void)xmlTextWriterEndElement(pWriter
);
112 #if OSL_DEBUG_LEVEL > 0
113 static bool CheckPosition( const SwPosition
* pStt
, const SwPosition
* pEnd
)
116 SwNode
* pSttNode
= &pStt
->GetNode();
117 SwNode
* pEndNode
= &pEnd
->GetNode();
118 SwNode
* pSttTab
= pSttNode
->StartOfSectionNode()->FindTableNode();
119 SwNode
* pEndTab
= pEndNode
->StartOfSectionNode()->FindTableNode();
120 SwNode
* pSttStart
= pSttNode
;
121 while( pSttStart
&& (!pSttStart
->IsStartNode() || pSttStart
->IsSectionNode() ||
122 pSttStart
->IsTableNode() ) )
123 pSttStart
= pSttStart
->StartOfSectionNode();
124 SwNode
* pEndStart
= pEndNode
;
125 while( pEndStart
&& (!pEndStart
->IsStartNode() || pEndStart
->IsSectionNode() ||
126 pEndStart
->IsTableNode() ) )
127 pEndStart
= pEndStart
->StartOfSectionNode();
128 assert(pSttTab
== pEndTab
);
129 if( pSttTab
!= pEndTab
)
131 assert(pSttTab
|| pSttStart
== pEndStart
);
132 if( !pSttTab
&& pSttStart
!= pEndStart
)
140 bool SwExtraRedlineTable::DeleteAllTableRedlines( SwDoc
& rDoc
, const SwTable
& rTable
, bool bSaveInUndo
, RedlineType nRedlineTypeToDelete
)
144 if (bSaveInUndo
&& rDoc
.GetIDocumentUndoRedo().DoesUndo())
146 // #TODO - Add 'Undo' support for deleting 'Table Cell' redlines
148 SwUndoRedline* pUndo = new SwUndoRedline( SwUndoId::REDLINE, rRange );
149 if( pUndo->GetRedlSaveCount() )
151 GetIDocumentUndoRedo().AppendUndo(pUndo);
158 for (sal_uInt16 nCurRedlinePos
= 0; nCurRedlinePos
< GetSize(); )
160 SwExtraRedline
* pExtraRedline
= GetRedline(nCurRedlinePos
);
161 const SwTableCellRedline
* pTableCellRedline
= dynamic_cast<const SwTableCellRedline
*>(pExtraRedline
);
162 if (pTableCellRedline
)
164 const SwTableBox
*pRedTabBox
= &pTableCellRedline
->GetTableBox();
165 const SwTable
& rRedTable
= pRedTabBox
->GetSttNd()->FindTableNode()->GetTable();
166 if ( &rRedTable
== &rTable
)
168 // Redline for this table
169 const SwRedlineData
& aRedlineData
= pTableCellRedline
->GetRedlineData();
170 const RedlineType nRedlineType
= aRedlineData
.GetType();
172 // Check if this redline object type should be deleted
173 if (RedlineType::Any
== nRedlineTypeToDelete
|| nRedlineTypeToDelete
== nRedlineType
)
176 DeleteAndDestroy( nCurRedlinePos
);
178 continue; // don't increment position after delete
186 rDoc
.getIDocumentState().SetModified();
191 bool SwExtraRedlineTable::DeleteTableRowRedline( SwDoc
* pDoc
, const SwTableLine
& rTableLine
, bool bSaveInUndo
, RedlineType nRedlineTypeToDelete
)
195 if (bSaveInUndo
&& pDoc
->GetIDocumentUndoRedo().DoesUndo())
197 // #TODO - Add 'Undo' support for deleting 'Table Cell' redlines
199 SwUndoRedline* pUndo = new SwUndoRedline( SwUndoId::REDLINE, rRange );
200 if( pUndo->GetRedlSaveCount() )
202 GetIDocumentUndoRedo().AppendUndo(pUndo);
209 for(sal_uInt16 nCurRedlinePos
= 0; nCurRedlinePos
< GetSize(); ++nCurRedlinePos
)
211 SwExtraRedline
* pExtraRedline
= GetRedline(nCurRedlinePos
);
212 const SwTableRowRedline
* pTableRowRedline
= dynamic_cast<const SwTableRowRedline
*>(pExtraRedline
);
213 const SwTableLine
*pRedTabLine
= pTableRowRedline
? &pTableRowRedline
->GetTableLine() : nullptr;
214 if ( pRedTabLine
== &rTableLine
)
216 // Redline for this table row
217 const SwRedlineData
& aRedlineData
= pTableRowRedline
->GetRedlineData();
218 const RedlineType nRedlineType
= aRedlineData
.GetType();
220 // Check if this redline object type should be deleted
221 if( RedlineType::Any
!= nRedlineTypeToDelete
&& nRedlineTypeToDelete
!= nRedlineType
)
224 DeleteAndDestroy( nCurRedlinePos
);
230 pDoc
->getIDocumentState().SetModified();
235 bool SwExtraRedlineTable::DeleteTableCellRedline( SwDoc
* pDoc
, const SwTableBox
& rTableBox
, bool bSaveInUndo
, RedlineType nRedlineTypeToDelete
)
239 if (bSaveInUndo
&& pDoc
->GetIDocumentUndoRedo().DoesUndo())
241 // #TODO - Add 'Undo' support for deleting 'Table Cell' redlines
243 SwUndoRedline* pUndo = new SwUndoRedline( SwUndoId::REDLINE, rRange );
244 if( pUndo->GetRedlSaveCount() )
246 GetIDocumentUndoRedo().AppendUndo(pUndo);
253 for(sal_uInt16 nCurRedlinePos
= 0; nCurRedlinePos
< GetSize(); ++nCurRedlinePos
)
255 SwExtraRedline
* pExtraRedline
= GetRedline(nCurRedlinePos
);
256 const SwTableCellRedline
* pTableCellRedline
= dynamic_cast<const SwTableCellRedline
*>(pExtraRedline
);
257 const SwTableBox
*pRedTabBox
= pTableCellRedline
? &pTableCellRedline
->GetTableBox() : nullptr;
258 if ( pRedTabBox
== &rTableBox
)
260 // Redline for this table cell
261 const SwRedlineData
& aRedlineData
= pTableCellRedline
->GetRedlineData();
262 const RedlineType nRedlineType
= aRedlineData
.GetType();
264 // Check if this redline object type should be deleted
265 if( RedlineType::Any
!= nRedlineTypeToDelete
&& nRedlineTypeToDelete
!= nRedlineType
)
268 DeleteAndDestroy( nCurRedlinePos
);
274 pDoc
->getIDocumentState().SetModified();
282 void lcl_LOKInvalidateFrames(const sw::BroadcastingModify
& rMod
, const SwRootFrame
* pLayout
,
283 SwFrameType
const nFrameType
, const Point
* pPoint
)
285 SwIterator
<SwFrame
, sw::BroadcastingModify
, sw::IteratorMode::UnwrapMulti
> aIter(rMod
);
287 for (SwFrame
* pTmpFrame
= aIter
.First(); pTmpFrame
; pTmpFrame
= aIter
.Next() )
289 if ((pTmpFrame
->GetType() & nFrameType
) &&
290 (!pLayout
|| pLayout
== pTmpFrame
->getRootFrame()) &&
291 (!pTmpFrame
->IsFlowFrame() || !SwFlowFrame::CastFlowFrame( pTmpFrame
)->IsFollow()))
295 pTmpFrame
->InvalidateSize();
297 // Also empty the text portion cache, so it gets rebuilt, taking the new redlines
299 if (pTmpFrame
->IsTextFrame())
301 auto pTextFrame
= static_cast<SwTextFrame
*>(pTmpFrame
);
302 pTextFrame
->ClearPara();
309 void lcl_LOKInvalidateStartEndFrames(SwShellCursor
& rCursor
)
311 if (!(rCursor
.HasMark() &&
312 rCursor
.GetPoint()->GetNode().IsContentNode() &&
313 rCursor
.GetPoint()->GetNode().GetContentNode()->getLayoutFrame(rCursor
.GetShell()->GetLayout()) &&
314 (rCursor
.GetMark()->GetNode() == rCursor
.GetPoint()->GetNode() ||
315 (rCursor
.GetMark()->GetNode().IsContentNode() &&
316 rCursor
.GetMark()->GetNode().GetContentNode()->getLayoutFrame(rCursor
.GetShell()->GetLayout())))))
321 auto [pStartPos
, pEndPos
] = rCursor
.StartEnd(); // SwPosition*
323 lcl_LOKInvalidateFrames(*(pStartPos
->GetNode().GetContentNode()),
324 rCursor
.GetShell()->GetLayout(),
325 FRM_CNTNT
, &rCursor
.GetSttPos());
327 lcl_LOKInvalidateFrames(*(pEndPos
->GetNode().GetContentNode()),
328 rCursor
.GetShell()->GetLayout(),
329 FRM_CNTNT
, &rCursor
.GetEndPos());
332 bool lcl_LOKRedlineNotificationEnabled()
334 static bool bDisableRedlineComments
= getenv("DISABLE_REDLINE") != nullptr;
335 if (comphelper::LibreOfficeKit::isActive() && !bDisableRedlineComments
)
341 } // anonymous namespace
343 /// Emits LOK notification about one addition / removal of a redline item.
344 void SwRedlineTable::LOKRedlineNotification(RedlineNotification nType
, SwRangeRedline
* pRedline
)
346 // Disable since usability is very low beyond some small number of changes.
347 if (!lcl_LOKRedlineNotificationEnabled())
350 boost::property_tree::ptree aRedline
;
351 aRedline
.put("action", (nType
== RedlineNotification::Add
? "Add" :
352 (nType
== RedlineNotification::Remove
? "Remove" :
353 (nType
== RedlineNotification::Modify
? "Modify" : "???"))));
354 aRedline
.put("index", pRedline
->GetId());
355 aRedline
.put("author", pRedline
->GetAuthorString(1).toUtf8().getStr());
356 aRedline
.put("type", SwRedlineTypeToOUString(pRedline
->GetRedlineData().GetType()).toUtf8().getStr());
357 aRedline
.put("comment", pRedline
->GetRedlineData().GetComment().toUtf8().getStr());
358 aRedline
.put("description", pRedline
->GetDescr().toUtf8().getStr());
359 OUString sDateTime
= utl::toISO8601(pRedline
->GetRedlineData().GetTimeStamp().GetUNODateTime());
360 aRedline
.put("dateTime", sDateTime
.toUtf8().getStr());
362 auto [pStartPos
, pEndPos
] = pRedline
->StartEnd(); // SwPosition*
363 SwContentNode
* pContentNd
= pRedline
->GetPointContentNode();
364 SwView
* pView
= dynamic_cast<SwView
*>(SfxViewShell::Current());
365 if (pView
&& pContentNd
)
367 SwShellCursor
aCursor(pView
->GetWrtShell(), *pStartPos
);
369 *aCursor
.GetMark() = *pEndPos
;
373 SwRects
* pRects(&aCursor
);
374 std::vector
<OString
> aRects
;
375 for(const SwRect
& rNextRect
: *pRects
)
376 aRects
.push_back(rNextRect
.SVRect().toString());
378 const OString sRects
= comphelper::string::join("; ", aRects
);
379 aRedline
.put("textRange", sRects
.getStr());
381 lcl_LOKInvalidateStartEndFrames(aCursor
);
383 // When this notify method is called text invalidation is not done yet
384 // Calling FillRects updates the text area so invalidation will not run on the correct rects
385 // So we need to do an own invalidation here. It invalidates text frames containing the redlining
386 SwDoc
& rDoc
= pRedline
->GetDoc();
388 if( !rDoc
.IsInDtor() )
390 pSh
= rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell();
392 for(SwNodeIndex
nIdx(pStartPos
->GetNode()); nIdx
<= pEndPos
->GetNode(); ++nIdx
)
394 SwContentNode
* pContentNode
= nIdx
.GetNode().GetContentNode();
396 pSh
->InvalidateWindows(pContentNode
->FindLayoutRect());
401 boost::property_tree::ptree aTree
;
402 aTree
.add_child("redline", aRedline
);
403 std::stringstream aStream
;
404 boost::property_tree::write_json(aStream
, aTree
);
405 std::string aPayload
= aStream
.str();
407 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
410 if (pView
&& pView
->GetDocId() == pViewShell
->GetDocId())
411 pViewShell
->libreOfficeKitViewCallback(nType
== RedlineNotification::Modify
? LOK_CALLBACK_REDLINE_TABLE_ENTRY_MODIFIED
: LOK_CALLBACK_REDLINE_TABLE_SIZE_CHANGED
, OString(aPayload
));
412 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
416 bool SwRedlineTable::Insert(SwRangeRedline
*& p
)
418 if( p
->HasValidRange() )
420 std::pair
<vector_type::const_iterator
, bool> rv
= maVector
.insert( p
);
421 size_type nP
= rv
.first
- begin();
422 LOKRedlineNotification(RedlineNotification::Add
, p
);
424 // detect text moving by checking nearby redlines, except during Undo
425 // (apply isMoved() during OpenDocument and DOCX import, too, to fix
426 // missing text moving handling in ODF and e.g. web version of MSO)
427 if ( p
->GetDoc().GetIDocumentUndoRedo().DoesUndo() ||
428 p
->GetDoc().IsInWriterfilterImport() ||
429 p
->GetDoc().IsInXMLImport() )
434 p
->CallDisplayFunc(nP
);
436 CheckOverlapping(rv
.first
);
439 return InsertWithValidRanges( p
);
442 void SwRedlineTable::CheckOverlapping(vector_type::const_iterator it
)
444 if (m_bHasOverlappingElements
)
446 if (maVector
.size() <= 1) // a single element cannot be overlapping
449 auto itNext
= it
+ 1;
450 if (itNext
!= maVector
.end())
452 auto pNext
= *itNext
;
453 if (pCurr
->End()->GetNodeIndex() >= pNext
->Start()->GetNodeIndex())
455 m_bHasOverlappingElements
= true;
459 if (it
!= maVector
.begin())
461 auto pPrev
= *(it
- 1);
462 if (pPrev
->End()->GetNodeIndex() >= pCurr
->Start()->GetNodeIndex())
463 m_bHasOverlappingElements
= true;
467 bool SwRedlineTable::Insert(SwRangeRedline
*& p
, size_type
& rP
)
469 if( p
->HasValidRange() )
471 std::pair
<vector_type::const_iterator
, bool> rv
= maVector
.insert( p
);
472 rP
= rv
.first
- begin();
473 p
->CallDisplayFunc(rP
);
475 CheckOverlapping(rv
.first
);
478 return InsertWithValidRanges( p
, &rP
);
483 std::vector
<std::unique_ptr
<SwRangeRedline
>> GetAllValidRanges(std::unique_ptr
<SwRangeRedline
> p
)
485 std::vector
<std::unique_ptr
<SwRangeRedline
>> ret
;
486 // Create valid "sub-ranges" from the Selection
487 auto [pStt
, pEnd
] = p
->StartEnd(); // SwPosition*
488 SwPosition
aNewStt( *pStt
);
489 SwNodes
& rNds
= aNewStt
.GetNodes();
492 if( !aNewStt
.GetNode().IsContentNode() )
494 pC
= rNds
.GoNext( &aNewStt
);
496 aNewStt
.Assign(rNds
.GetEndOfContent());
500 if( aNewStt
>= *pEnd
)
503 std::unique_ptr
<SwRangeRedline
> pNew
;
506 pNew
.reset(new SwRangeRedline( p
->GetRedlineData(), aNewStt
));
510 *pNew
->GetPoint() = aNewStt
;
514 GoEndSection( pNew
->GetPoint() );
515 // i60396: If the redlines starts before a table but the table is the last member
516 // of the section, the GoEndSection will end inside the table.
517 // This will result in an incorrect redline, so we've to go back
518 SwNode
* pTab
= pNew
->GetPoint()->GetNode().StartOfSectionNode()->FindTableNode();
519 // We end in a table when pTab != 0
520 if( pTab
&& !pNew
->GetMark()->GetNode().StartOfSectionNode()->FindTableNode() )
521 { // but our Mark was outside the table => Correction
524 // We want to be before the table
525 pNew
->GetPoint()->Assign(*pTab
);
526 pC
= GoPreviousPos( pNew
->GetPoint(), false ); // here we are.
528 pNew
->GetPoint()->SetContent( 0 );
529 pTab
= pNew
->GetPoint()->GetNode().StartOfSectionNode()->FindTableNode();
530 } while( pTab
); // If there is another table we have to repeat our step backwards
533 // insert dummy character to the empty table rows to keep their changes
534 SwNode
& rBoxNode
= pNew
->GetMark()->GetNode();
535 if ( rBoxNode
.GetDoc().GetIDocumentUndoRedo().DoesUndo() && rBoxNode
.GetTableBox() &&
536 rBoxNode
.GetTableBox()->GetUpper()->IsEmpty() && rBoxNode
.GetTextNode() )
538 ::sw::UndoGuard
const undoGuard(rBoxNode
.GetDoc().GetIDocumentUndoRedo());
539 rBoxNode
.GetTextNode()->InsertDummy();
540 pNew
->GetMark()->SetContent( 1 );
543 if( *pNew
->GetPoint() > *pEnd
)
546 if( aNewStt
.GetNode() != pEnd
->GetNode() )
548 SwNode
& rCurNd
= aNewStt
.GetNode();
549 if( rCurNd
.IsStartNode() )
551 if( rCurNd
.EndOfSectionIndex() < pEnd
->GetNodeIndex() )
552 aNewStt
.Assign( *rCurNd
.EndOfSectionNode() );
556 else if( rCurNd
.IsContentNode() )
557 pC
= rCurNd
.GetContentNode();
558 aNewStt
.Adjust(SwNodeOffset(1));
559 } while( aNewStt
.GetNodeIndex() < pEnd
->GetNodeIndex() );
561 if( aNewStt
.GetNode() == pEnd
->GetNode() )
562 aNewStt
.SetContent(pEnd
->GetContentIndex());
565 aNewStt
.Assign(*pC
, pC
->Len() );
568 if( aNewStt
<= *pEnd
)
569 *pNew
->GetPoint() = aNewStt
;
572 aNewStt
= *pNew
->GetPoint();
573 #if OSL_DEBUG_LEVEL > 0
574 CheckPosition( pNew
->GetPoint(), pNew
->GetMark() );
577 if( *pNew
->GetPoint() != *pNew
->GetMark() &&
578 pNew
->HasValidRange())
580 ret
.push_back(std::move(pNew
));
583 if( aNewStt
>= *pEnd
)
585 pC
= rNds
.GoNext( &aNewStt
);
588 } while( aNewStt
< *pEnd
);
595 static void lcl_setRowNotTracked(SwNode
& rNode
)
597 SwDoc
& rDoc
= rNode
.GetDoc();
598 if ( rDoc
.GetIDocumentUndoRedo().DoesUndo() && rNode
.GetTableBox() )
600 SvxPrintItem
aSetTracking(RES_PRINT
, false);
601 SwNodeIndex
aInsPos( *(rNode
.GetTableBox()->GetSttNd()), 1);
602 SwCursor
aCursor( SwPosition(aInsPos
), nullptr );
603 ::sw::UndoGuard
const undoGuard(rNode
.GetDoc().GetIDocumentUndoRedo());
604 rDoc
.SetRowNotTracked( aCursor
, aSetTracking
);
608 bool SwRedlineTable::InsertWithValidRanges(SwRangeRedline
*& p
, size_type
* pInsPos
)
610 bool bAnyIns
= false;
611 bool bInsert
= RedlineType::Insert
== p
->GetType();
612 SwNode
* pSttNode
= &p
->Start()->GetNode();
614 std::vector
<std::unique_ptr
<SwRangeRedline
>> redlines(
615 GetAllValidRanges(std::unique_ptr
<SwRangeRedline
>(p
)));
617 // tdf#147180 set table change tracking in the empty row with text insertion
619 lcl_setRowNotTracked(*pSttNode
);
621 for (std::unique_ptr
<SwRangeRedline
> & pRedline
: redlines
)
623 assert(pRedline
->HasValidRange());
625 auto pTmpRedline
= pRedline
.release();
626 if (Insert(pTmpRedline
, nInsPos
))
628 // tdf#147180 set table tracking to the table row
629 lcl_setRowNotTracked(pTmpRedline
->GetPointNode());
631 pTmpRedline
->CallDisplayFunc(nInsPos
);
633 if (pInsPos
&& *pInsPos
< nInsPos
)
643 bool CompareSwRedlineTable::operator()(SwRangeRedline
* const &lhs
, SwRangeRedline
* const &rhs
) const
648 SwRedlineTable::~SwRedlineTable()
650 maVector
.DeleteAndDestroyAll();
653 SwRedlineTable::size_type
SwRedlineTable::GetPos(const SwRangeRedline
* p
) const
655 vector_type::const_iterator it
= maVector
.find(const_cast<SwRangeRedline
*>(p
));
656 if( it
== maVector
.end() )
658 return it
- maVector
.begin();
661 void SwRedlineTable::Remove( const SwRangeRedline
* p
)
663 const size_type nPos
= GetPos(p
);
669 void SwRedlineTable::Remove( size_type nP
)
671 LOKRedlineNotification(RedlineNotification::Remove
, maVector
[nP
]);
672 SwDoc
* pDoc
= nullptr;
673 if( !nP
&& 1 == size() )
674 pDoc
= &maVector
.front()->GetDoc();
676 maVector
.erase( maVector
.begin() + nP
);
678 if( pDoc
&& !pDoc
->IsInDtor() )
680 SwViewShell
* pSh
= pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell();
682 pSh
->InvalidateWindows( SwRect( 0, 0, SAL_MAX_INT32
, SAL_MAX_INT32
) );
686 void SwRedlineTable::DeleteAndDestroyAll()
688 while (!maVector
.empty())
690 auto const pRedline
= maVector
.back();
691 maVector
.erase_at(maVector
.size() - 1);
692 LOKRedlineNotification(RedlineNotification::Remove
, pRedline
);
695 m_bHasOverlappingElements
= false;
698 void SwRedlineTable::DeleteAndDestroy(size_type
const nP
)
700 auto const pRedline
= maVector
[nP
];
701 maVector
.erase(maVector
.begin() + nP
);
702 LOKRedlineNotification(RedlineNotification::Remove
, pRedline
);
706 SwRedlineTable::size_type
SwRedlineTable::FindNextOfSeqNo( size_type nSttPos
) const
708 return nSttPos
+ 1 < size()
709 ? FindNextSeqNo( operator[]( nSttPos
)->GetSeqNo(), nSttPos
+1 )
713 SwRedlineTable::size_type
SwRedlineTable::FindPrevOfSeqNo( size_type nSttPos
) const
715 return nSttPos
? FindPrevSeqNo( operator[]( nSttPos
)->GetSeqNo(), nSttPos
-1 )
719 /// Find the next or preceding Redline with the same seq.no.
720 /// We can limit the search using look ahead (0 searches the whole array).
721 SwRedlineTable::size_type
SwRedlineTable::FindNextSeqNo( sal_uInt16 nSeqNo
, size_type nSttPos
) const
723 auto constexpr nLookahead
= 20;
724 size_type nRet
= npos
;
725 if( nSeqNo
&& nSttPos
< size() )
727 size_type nEnd
= size();
728 const size_type nTmp
= nSttPos
+ nLookahead
;
734 for( ; nSttPos
< nEnd
; ++nSttPos
)
735 if( nSeqNo
== operator[]( nSttPos
)->GetSeqNo() )
744 SwRedlineTable::size_type
SwRedlineTable::FindPrevSeqNo( sal_uInt16 nSeqNo
, size_type nSttPos
) const
746 auto constexpr nLookahead
= 20;
747 size_type nRet
= npos
;
748 if( nSeqNo
&& nSttPos
< size() )
751 if( nSttPos
> nLookahead
)
752 nEnd
= nSttPos
- nLookahead
;
755 while( nSttPos
> nEnd
)
756 if( nSeqNo
== operator[]( --nSttPos
)->GetSeqNo() )
765 const SwRangeRedline
* SwRedlineTable::FindAtPosition( const SwPosition
& rSttPos
,
769 const SwRangeRedline
* pFnd
= nullptr;
770 for( ; rPos
< maVector
.size() ; ++rPos
)
772 const SwRangeRedline
* pTmp
= (*this)[ rPos
];
773 if( pTmp
->HasMark() && pTmp
->IsVisible() )
775 auto [pRStt
, pREnd
] = pTmp
->StartEnd(); // SwPosition*
776 if( bNext
? *pRStt
<= rSttPos
: *pRStt
< rSttPos
)
778 if( bNext
? *pREnd
> rSttPos
: *pREnd
>= rSttPos
)
791 bool SwRedlineTable::isMoved( size_type rPos
) const
794 auto constexpr nLookahead
= 20;
795 SwRangeRedline
* pRedline
= (*this)[ rPos
];
797 // set redline type of the searched pair
798 RedlineType nPairType
= pRedline
->GetType();
799 if ( RedlineType::Delete
== nPairType
)
800 nPairType
= RedlineType::Insert
;
801 else if ( RedlineType::Insert
== nPairType
)
802 nPairType
= RedlineType::Delete
;
804 // only deleted or inserted text can be moved
807 bool bDeletePaM
= false;
810 // if this redline is visible the content is in this PaM
811 if ( nullptr == pRedline
->GetContentIdx() )
815 else // otherwise it is saved in pContentSect, e.g. during ODT import
817 pPaM
= new SwPaM(pRedline
->GetContentIdx()->GetNode(), *pRedline
->GetContentIdx()->GetNode().EndOfSectionNode() );
821 const OUString sTrimmed
= pPaM
->GetText().trim();
822 // detection of move needs at least 6 characters with an inner
823 // space after stripping white spaces of the redline to skip
824 // frequent deleted and inserted articles or other common
825 // word parts, e.g. 'the' and 'of a' to detect as text moving
826 if ( sTrimmed
.getLength() < 6 || sTrimmed
.indexOf(' ') == -1 )
833 // search pair around the actual redline
834 size_type nEnd
= rPos
+ nLookahead
< size()
837 rPos
= rPos
> nLookahead
? rPos
- nLookahead
: 0;
838 for ( ; rPos
< nEnd
&& !bRet
; ++rPos
)
840 SwRangeRedline
* pPair
= (*this)[ rPos
];
842 // redline must be the requested type and from the same author
843 if ( nPairType
!= pPair
->GetType() ||
844 pRedline
->GetAuthor() != pPair
->GetAuthor() )
849 bool bDeletePairPaM
= false;
852 // if this redline is visible the content is in this PaM
853 if ( nullptr == pPair
->GetContentIdx() )
857 else // otherwise it is saved in pContentSect, e.g. during ODT import
859 // saved in pContentSect, e.g. during ODT import
860 pPairPaM
= new SwPaM(pPair
->GetContentIdx()->GetNode(), *pPair
->GetContentIdx()->GetNode().EndOfSectionNode() );
861 bDeletePairPaM
= true;
864 // pair at tracked moving: same text by trimming trailing white spaces
865 if ( abs(pPaM
->GetText().getLength() - pPairPaM
->GetText().getLength()) <= 2 &&
866 sTrimmed
== o3tl::trim(pPairPaM
->GetText()) )
868 pRedline
->SetMoved();
870 pPair
->InvalidateRange(SwRangeRedline::Invalidation::Add
);
874 if ( bDeletePairPaM
)
884 void SwRedlineTable::dumpAsXml(xmlTextWriterPtr pWriter
) const
886 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwRedlineTable"));
887 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
889 for (SwRedlineTable::size_type nCurRedlinePos
= 0; nCurRedlinePos
< size(); ++nCurRedlinePos
)
890 operator[](nCurRedlinePos
)->dumpAsXml(pWriter
);
892 (void)xmlTextWriterEndElement(pWriter
);
895 SwRedlineExtraData::~SwRedlineExtraData()
899 void SwRedlineExtraData::Reject( SwPaM
& ) const
903 bool SwRedlineExtraData::operator == ( const SwRedlineExtraData
& ) const
908 SwRedlineExtraData_FormatColl::SwRedlineExtraData_FormatColl( OUString aColl
,
909 sal_uInt16 nPoolFormatId
,
910 const SfxItemSet
* pItemSet
,
912 : m_sFormatNm(std::move(aColl
)), m_nPoolId(nPoolFormatId
), m_bFormatAll(bFormatAll
)
914 if( pItemSet
&& pItemSet
->Count() )
915 m_pSet
.reset( new SfxItemSet( *pItemSet
) );
918 SwRedlineExtraData_FormatColl::~SwRedlineExtraData_FormatColl()
922 SwRedlineExtraData
* SwRedlineExtraData_FormatColl::CreateNew() const
924 return new SwRedlineExtraData_FormatColl( m_sFormatNm
, m_nPoolId
, m_pSet
.get(), m_bFormatAll
);
927 void SwRedlineExtraData_FormatColl::Reject( SwPaM
& rPam
) const
929 SwDoc
& rDoc
= rPam
.GetDoc();
931 // What about Undo? Is it turned off?
932 SwTextFormatColl
* pColl
= USHRT_MAX
== m_nPoolId
933 ? rDoc
.FindTextFormatCollByName( m_sFormatNm
)
934 : rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool( m_nPoolId
);
936 RedlineFlags eOld
= rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
937 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld
& ~RedlineFlags(RedlineFlags::On
| RedlineFlags::Ignore
));
939 SwPaM
aPam( *rPam
.GetMark(), *rPam
.GetPoint() );
941 const SwPosition
* pEnd
= rPam
.End();
943 if ( !m_bFormatAll
|| pEnd
->GetContentIndex() == 0 )
945 // don't reject the format of the next paragraph (that is handled by the next redline)
946 if (aPam
.GetPoint()->GetNode() > aPam
.GetMark()->GetNode())
948 aPam
.GetPoint()->Adjust(SwNodeOffset(-1));
949 SwContentNode
* pNode
= aPam
.GetPoint()->GetNode().GetContentNode();
951 aPam
.GetPoint()->SetContent( pNode
->Len() );
953 // tdf#147507 set it back to a content node to avoid of crashing
954 aPam
.GetPoint()->Adjust(SwNodeOffset(+1));
956 else if (aPam
.GetPoint()->GetNode() < aPam
.GetMark()->GetNode())
958 aPam
.GetMark()->Adjust(SwNodeOffset(-1));
959 SwContentNode
* pNode
= aPam
.GetMark()->GetNode().GetContentNode();
960 aPam
.GetMark()->SetContent( pNode
->Len() );
965 rDoc
.SetTextFormatColl( aPam
, pColl
, false );
968 rDoc
.getIDocumentContentOperations().InsertItemSet( aPam
, *m_pSet
);
970 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
973 bool SwRedlineExtraData_FormatColl::operator == ( const SwRedlineExtraData
& r
) const
975 const SwRedlineExtraData_FormatColl
& rCmp
= static_cast<const SwRedlineExtraData_FormatColl
&>(r
);
976 return m_sFormatNm
== rCmp
.m_sFormatNm
&& m_nPoolId
== rCmp
.m_nPoolId
&&
977 m_bFormatAll
== rCmp
.m_bFormatAll
&&
978 ( ( !m_pSet
&& !rCmp
.m_pSet
) ||
979 ( m_pSet
&& rCmp
.m_pSet
&& *m_pSet
== *rCmp
.m_pSet
) );
982 void SwRedlineExtraData_FormatColl::SetItemSet( const SfxItemSet
& rSet
)
985 m_pSet
.reset( new SfxItemSet( rSet
) );
990 SwRedlineExtraData_Format::SwRedlineExtraData_Format( const SfxItemSet
& rSet
)
992 SfxItemIter
aIter( rSet
);
993 for (const SfxPoolItem
* pItem
= aIter
.GetCurItem(); pItem
; pItem
= aIter
.NextItem())
995 m_aWhichIds
.push_back( pItem
->Which() );
999 SwRedlineExtraData_Format::SwRedlineExtraData_Format(
1000 const SwRedlineExtraData_Format
& rCpy
)
1001 : SwRedlineExtraData()
1003 m_aWhichIds
.insert( m_aWhichIds
.begin(), rCpy
.m_aWhichIds
.begin(), rCpy
.m_aWhichIds
.end() );
1006 SwRedlineExtraData_Format::~SwRedlineExtraData_Format()
1010 SwRedlineExtraData
* SwRedlineExtraData_Format::CreateNew() const
1012 return new SwRedlineExtraData_Format( *this );
1015 void SwRedlineExtraData_Format::Reject( SwPaM
& rPam
) const
1017 SwDoc
& rDoc
= rPam
.GetDoc();
1019 RedlineFlags eOld
= rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
1020 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld
& ~RedlineFlags(RedlineFlags::On
| RedlineFlags::Ignore
));
1022 // Actually we need to reset the Attribute here!
1023 for( const auto& rWhichId
: m_aWhichIds
)
1025 rDoc
.getIDocumentContentOperations().InsertPoolItem( rPam
, *GetDfltAttr( rWhichId
),
1026 SetAttrMode::DONTEXPAND
);
1029 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
1032 bool SwRedlineExtraData_Format::operator == ( const SwRedlineExtraData
& rCmp
) const
1034 const size_t nEnd
= m_aWhichIds
.size();
1035 if( nEnd
!= static_cast<const SwRedlineExtraData_Format
&>(rCmp
).m_aWhichIds
.size() )
1038 for( size_t n
= 0; n
< nEnd
; ++n
)
1040 if( static_cast<const SwRedlineExtraData_Format
&>(rCmp
).m_aWhichIds
[n
] != m_aWhichIds
[n
])
1048 SwRedlineData::SwRedlineData( RedlineType eT
, std::size_t nAut
)
1049 : m_pNext( nullptr ), m_pExtraData( nullptr ),
1050 m_aStamp( DateTime::SYSTEM
),
1051 m_nAuthor( nAut
), m_eType( eT
), m_nSeqNo( 0 ), m_bAutoFormat(false), m_bMoved(false)
1053 m_aStamp
.SetNanoSec( 0 );
1056 SwRedlineData::SwRedlineData(
1057 const SwRedlineData
& rCpy
,
1059 : m_pNext( ( bCpyNext
&& rCpy
.m_pNext
) ? new SwRedlineData( *rCpy
.m_pNext
) : nullptr )
1060 , m_pExtraData( rCpy
.m_pExtraData
? rCpy
.m_pExtraData
->CreateNew() : nullptr )
1061 , m_sComment( rCpy
.m_sComment
)
1062 , m_aStamp( rCpy
.m_aStamp
)
1063 , m_nAuthor( rCpy
.m_nAuthor
)
1064 , m_eType( rCpy
.m_eType
)
1065 , m_nSeqNo( rCpy
.m_nSeqNo
)
1066 , m_bAutoFormat(false)
1067 , m_bMoved( rCpy
.m_bMoved
)
1071 // For sw3io: We now own pNext!
1072 SwRedlineData::SwRedlineData(RedlineType eT
, std::size_t nAut
, const DateTime
& rDT
,
1073 OUString aCmnt
, SwRedlineData
*pNxt
)
1074 : m_pNext(pNxt
), m_pExtraData(nullptr), m_sComment(std::move(aCmnt
)), m_aStamp(rDT
),
1075 m_nAuthor(nAut
), m_eType(eT
), m_nSeqNo(0), m_bAutoFormat(false), m_bMoved(false)
1079 SwRedlineData::~SwRedlineData()
1081 delete m_pExtraData
;
1085 // Check whether the absolute difference between the two dates is no larger than one minute (can
1086 // give inaccurate results if at least one of the dates is not valid/normalized):
1087 static bool deltaOneMinute(DateTime
const & t1
, DateTime
const & t2
) {
1088 auto const & [min
, max
] = std::minmax(t1
, t2
);
1089 // Avoid overflow of `min + tools::Time(0, 1)` below when min is close to the maximum valid
1091 if (min
>= DateTime({31, 12, std::numeric_limits
<sal_Int16
>::max()}, {23, 59})) {
1094 return max
<= min
+ tools::Time(0, 1);
1097 bool SwRedlineData::CanCombine(const SwRedlineData
& rCmp
) const
1099 return m_nAuthor
== rCmp
.m_nAuthor
&&
1100 m_eType
== rCmp
.m_eType
&&
1101 m_sComment
== rCmp
.m_sComment
&&
1102 deltaOneMinute(GetTimeStamp(), rCmp
.GetTimeStamp()) &&
1103 m_bMoved
== rCmp
.m_bMoved
&&
1104 (( !m_pNext
&& !rCmp
.m_pNext
) ||
1105 ( m_pNext
&& rCmp
.m_pNext
&&
1106 m_pNext
->CanCombine( *rCmp
.m_pNext
))) &&
1107 (( !m_pExtraData
&& !rCmp
.m_pExtraData
) ||
1108 ( m_pExtraData
&& rCmp
.m_pExtraData
&&
1109 *m_pExtraData
== *rCmp
.m_pExtraData
));
1112 /// ExtraData is copied. The Pointer's ownership is thus NOT transferred
1113 /// to the Redline Object!
1114 void SwRedlineData::SetExtraData( const SwRedlineExtraData
* pData
)
1116 delete m_pExtraData
;
1118 // Check if there is data - and if so - delete it
1120 m_pExtraData
= pData
->CreateNew();
1122 m_pExtraData
= nullptr;
1125 const TranslateId STR_REDLINE_ARY
[] =
1127 STR_UNDO_REDLINE_INSERT
,
1128 STR_UNDO_REDLINE_DELETE
,
1129 STR_UNDO_REDLINE_FORMAT
,
1130 STR_UNDO_REDLINE_TABLE
,
1131 STR_UNDO_REDLINE_FMTCOLL
,
1132 STR_UNDO_REDLINE_PARAGRAPH_FORMAT
,
1133 STR_UNDO_REDLINE_TABLE_ROW_INSERT
,
1134 STR_UNDO_REDLINE_TABLE_ROW_DELETE
,
1135 STR_UNDO_REDLINE_TABLE_CELL_INSERT
,
1136 STR_UNDO_REDLINE_TABLE_CELL_DELETE
1139 OUString
SwRedlineData::GetDescr() const
1141 return SwResId(STR_REDLINE_ARY
[static_cast<int>(GetType())]);
1144 sal_uInt32
SwRangeRedline::s_nLastId
= 1;
1146 SwRangeRedline::SwRangeRedline(RedlineType eTyp
, const SwPaM
& rPam
)
1147 : SwPaM( *rPam
.GetMark(), *rPam
.GetPoint() ),
1148 m_pRedlineData( new SwRedlineData( eTyp
, GetDoc().getIDocumentRedlineAccess().GetRedlineAuthor() ) ),
1149 m_nId( s_nLastId
++ )
1151 GetBound().SetRedline(this);
1152 GetBound(false).SetRedline(this);
1154 m_bDelLastPara
= false;
1155 m_bIsVisible
= true;
1156 if( !rPam
.HasMark() )
1159 // set default comment for single annotations added or deleted
1160 if ( IsAnnotation() )
1162 SetComment( RedlineType::Delete
== eTyp
1163 ? SwResId(STR_REDLINE_COMMENT_DELETED
)
1164 : SwResId(STR_REDLINE_COMMENT_ADDED
) );
1168 SwRangeRedline::SwRangeRedline( const SwRedlineData
& rData
, const SwPaM
& rPam
)
1169 : SwPaM( *rPam
.GetMark(), *rPam
.GetPoint() ),
1170 m_pRedlineData( new SwRedlineData( rData
)),
1171 m_nId( s_nLastId
++ )
1173 GetBound().SetRedline(this);
1174 GetBound(false).SetRedline(this);
1176 m_bDelLastPara
= false;
1177 m_bIsVisible
= true;
1178 if( !rPam
.HasMark() )
1182 SwRangeRedline::SwRangeRedline( const SwRedlineData
& rData
, const SwPosition
& rPos
)
1184 m_pRedlineData( new SwRedlineData( rData
)),
1185 m_nId( s_nLastId
++ )
1187 GetBound().SetRedline(this);
1188 GetBound(false).SetRedline(this);
1190 m_bDelLastPara
= false;
1191 m_bIsVisible
= true;
1194 SwRangeRedline::SwRangeRedline( const SwRangeRedline
& rCpy
)
1195 : SwPaM( *rCpy
.GetMark(), *rCpy
.GetPoint() ),
1196 m_pRedlineData( new SwRedlineData( *rCpy
.m_pRedlineData
)),
1197 m_nId( s_nLastId
++ )
1199 GetBound().SetRedline(this);
1200 GetBound(false).SetRedline(this);
1202 m_bDelLastPara
= false;
1203 m_bIsVisible
= true;
1204 if( !rCpy
.HasMark() )
1208 SwRangeRedline::~SwRangeRedline()
1210 if( m_oContentSect
)
1212 // delete the ContentSection
1213 if( !GetDoc().IsInDtor() )
1214 GetDoc().getIDocumentContentOperations().DeleteSection( &m_oContentSect
->GetNode() );
1215 m_oContentSect
.reset();
1217 delete m_pRedlineData
;
1220 void MaybeNotifyRedlineModification(SwRangeRedline
& rRedline
, SwDoc
& rDoc
)
1222 if (!lcl_LOKRedlineNotificationEnabled())
1225 const SwRedlineTable
& rRedTable
= rDoc
.getIDocumentRedlineAccess().GetRedlineTable();
1226 for (SwRedlineTable::size_type i
= 0; i
< rRedTable
.size(); ++i
)
1228 if (rRedTable
[i
] == &rRedline
)
1230 SwRedlineTable::LOKRedlineNotification(RedlineNotification::Modify
, &rRedline
);
1236 void SwRangeRedline::MaybeNotifyRedlinePositionModification(tools::Long nTop
)
1238 if (!lcl_LOKRedlineNotificationEnabled())
1241 if(!m_oLOKLastNodeTop
|| *m_oLOKLastNodeTop
!= nTop
)
1243 m_oLOKLastNodeTop
= nTop
;
1244 SwRedlineTable::LOKRedlineNotification(RedlineNotification::Modify
, this);
1248 void SwRangeRedline::SetStart( const SwPosition
& rPos
, SwPosition
* pSttPtr
)
1250 if( !pSttPtr
) pSttPtr
= Start();
1253 MaybeNotifyRedlineModification(*this, GetDoc());
1256 void SwRangeRedline::SetEnd( const SwPosition
& rPos
, SwPosition
* pEndPtr
)
1258 if( !pEndPtr
) pEndPtr
= End();
1261 MaybeNotifyRedlineModification(*this, GetDoc());
1264 /// Do we have a valid Selection?
1265 bool SwRangeRedline::HasValidRange() const
1267 const SwNode
* pPtNd
= &GetPoint()->GetNode(),
1268 * pMkNd
= &GetMark()->GetNode();
1269 if( pPtNd
->StartOfSectionNode() == pMkNd
->StartOfSectionNode() &&
1270 !pPtNd
->StartOfSectionNode()->IsTableNode() &&
1271 // invalid if points on the end of content
1272 // end-of-content only invalid if no content index exists
1273 ( pPtNd
!= pMkNd
|| GetContentIdx() != nullptr ||
1274 pPtNd
!= &pPtNd
->GetNodes().GetEndOfContent() )
1280 void SwRangeRedline::CallDisplayFunc(size_t nMyPos
)
1282 RedlineFlags eShow
= RedlineFlags::ShowMask
& GetDoc().getIDocumentRedlineAccess().GetRedlineFlags();
1283 if (eShow
== (RedlineFlags::ShowInsert
| RedlineFlags::ShowDelete
))
1285 else if (eShow
== RedlineFlags::ShowInsert
)
1287 else if (eShow
== RedlineFlags::ShowDelete
)
1288 ShowOriginal(0, nMyPos
);
1291 void SwRangeRedline::Show(sal_uInt16 nLoop
, size_t nMyPos
, bool bForced
)
1293 SwDoc
& rDoc
= GetDoc();
1295 bool bIsShowChangesInMargin
= false;
1298 SwViewShell
* pSh
= rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell();
1300 bIsShowChangesInMargin
= pSh
->GetViewOptions()->IsShowChangesInMargin();
1302 bIsShowChangesInMargin
= SW_MOD()->GetUsrPref(false)->IsShowChangesInMargin();
1305 if( 1 > nLoop
&& !bIsShowChangesInMargin
)
1308 RedlineFlags eOld
= rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
1309 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld
| RedlineFlags::Ignore
);
1310 ::sw::UndoGuard
const undoGuard(rDoc
.GetIDocumentUndoRedo());
1314 case RedlineType::Insert
: // Content has been inserted
1315 m_bIsVisible
= true;
1316 MoveFromSection(nMyPos
);
1319 case RedlineType::Delete
: // Content has been deleted
1320 m_bIsVisible
= !bIsShowChangesInMargin
;
1323 MoveFromSection(nMyPos
);
1328 case 0: MoveToSection(); break;
1329 case 1: CopyToSection(); break;
1330 case 2: DelCopyOfSection(nMyPos
); break;
1335 case RedlineType::Format
: // Attributes have been applied
1336 case RedlineType::Table
: // Table structure has been modified
1337 InvalidateRange(Invalidation::Add
);
1342 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
1345 void SwRangeRedline::Hide(sal_uInt16 nLoop
, size_t nMyPos
, bool /*bForced*/)
1347 SwDoc
& rDoc
= GetDoc();
1348 RedlineFlags eOld
= rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
1349 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld
| RedlineFlags::Ignore
);
1350 ::sw::UndoGuard
const undoGuard(rDoc
.GetIDocumentUndoRedo());
1354 case RedlineType::Insert
: // Content has been inserted
1355 m_bIsVisible
= true;
1357 MoveFromSection(nMyPos
);
1360 case RedlineType::Delete
: // Content has been deleted
1361 m_bIsVisible
= false;
1364 case 0: MoveToSection(); break;
1365 case 1: CopyToSection(); break;
1366 case 2: DelCopyOfSection(nMyPos
); break;
1370 case RedlineType::Format
: // Attributes have been applied
1371 case RedlineType::Table
: // Table structure has been modified
1373 InvalidateRange(Invalidation::Remove
);
1378 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
1381 void SwRangeRedline::ShowOriginal(sal_uInt16 nLoop
, size_t nMyPos
, bool /*bForced*/)
1383 SwDoc
& rDoc
= GetDoc();
1384 RedlineFlags eOld
= rDoc
.getIDocumentRedlineAccess().GetRedlineFlags();
1385 SwRedlineData
* pCur
;
1387 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern(eOld
| RedlineFlags::Ignore
);
1388 ::sw::UndoGuard
const undoGuard(rDoc
.GetIDocumentUndoRedo());
1390 // Determine the Type, it's the first on Stack
1391 for( pCur
= m_pRedlineData
; pCur
->m_pNext
; )
1392 pCur
= pCur
->m_pNext
;
1394 switch( pCur
->m_eType
)
1396 case RedlineType::Insert
: // Content has been inserted
1397 m_bIsVisible
= false;
1400 case 0: MoveToSection(); break;
1401 case 1: CopyToSection(); break;
1402 case 2: DelCopyOfSection(nMyPos
); break;
1406 case RedlineType::Delete
: // Content has been deleted
1407 m_bIsVisible
= true;
1409 MoveFromSection(nMyPos
);
1412 case RedlineType::Format
: // Attributes have been applied
1413 case RedlineType::Table
: // Table structure has been modified
1415 InvalidateRange(Invalidation::Remove
);
1420 rDoc
.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld
);
1423 // trigger the Layout
1424 void SwRangeRedline::InvalidateRange(Invalidation
const eWhy
)
1426 auto [pRStt
, pREnd
] = StartEnd(); // SwPosition*
1427 SwNodeOffset nSttNd
= pRStt
->GetNodeIndex(),
1428 nEndNd
= pREnd
->GetNodeIndex();
1429 sal_Int32 nSttCnt
= pRStt
->GetContentIndex();
1430 sal_Int32 nEndCnt
= pREnd
->GetContentIndex();
1432 SwNodes
& rNds
= GetDoc().GetNodes();
1433 for (SwNodeOffset
n(nSttNd
); n
<= nEndNd
; ++n
)
1435 SwNode
* pNode
= rNds
[n
];
1437 if (pNode
&& pNode
->IsTextNode())
1439 SwTextNode
* pNd
= pNode
->GetTextNode();
1442 n
== nSttNd
? nSttCnt
: 0,
1443 n
== nEndNd
? nEndCnt
: pNd
->GetText().getLength(),
1446 pNd
->TriggerNodeUpdate(sw::LegacyModifyHint(&aHt
, &aHt
));
1448 // SwUpdateAttr must be handled first, otherwise indexes are off
1449 if (GetType() == RedlineType::Delete
)
1451 sal_Int32
const nStart(n
== nSttNd
? nSttCnt
: 0);
1452 sal_Int32
const nLen((n
== nEndNd
? nEndCnt
: pNd
->GetText().getLength()) - nStart
);
1453 if (eWhy
== Invalidation::Add
)
1455 sw::RedlineDelText
const hint(nStart
, nLen
);
1456 pNd
->CallSwClientNotify(hint
);
1460 sw::RedlineUnDelText
const hint(nStart
, nLen
);
1461 pNd
->CallSwClientNotify(hint
);
1468 /** Calculates the start and end position of the intersection rTmp and
1470 void SwRangeRedline::CalcStartEnd( SwNodeOffset nNdIdx
, sal_Int32
& rStart
, sal_Int32
& rEnd
) const
1472 auto [pRStt
, pREnd
] = StartEnd(); // SwPosition*
1473 if( pRStt
->GetNodeIndex() < nNdIdx
)
1475 if( pREnd
->GetNodeIndex() > nNdIdx
)
1477 rStart
= 0; // Paragraph is completely enclosed
1478 rEnd
= COMPLETE_STRING
;
1480 else if (pREnd
->GetNodeIndex() == nNdIdx
)
1482 rStart
= 0; // Paragraph is overlapped in the beginning
1483 rEnd
= pREnd
->GetContentIndex();
1485 else // redline ends before paragraph
1487 rStart
= COMPLETE_STRING
;
1488 rEnd
= COMPLETE_STRING
;
1491 else if( pRStt
->GetNodeIndex() == nNdIdx
)
1493 rStart
= pRStt
->GetContentIndex();
1494 if( pREnd
->GetNodeIndex() == nNdIdx
)
1495 rEnd
= pREnd
->GetContentIndex(); // Within the Paragraph
1497 rEnd
= COMPLETE_STRING
; // Paragraph is overlapped in the end
1501 rStart
= COMPLETE_STRING
;
1502 rEnd
= COMPLETE_STRING
;
1506 static void lcl_storeAnnotationMarks(SwDoc
& rDoc
, const SwPosition
* pStt
, const SwPosition
* pEnd
)
1508 // tdf#115815 keep original start position of collapsed annotation ranges
1509 // as temporary bookmarks (removed after file saving and file loading)
1510 IDocumentMarkAccess
& rDMA(*rDoc
.getIDocumentMarkAccess());
1511 for (auto iter
= rDMA
.getAnnotationMarksBegin();
1512 iter
!= rDMA
.getAnnotationMarksEnd(); )
1514 SwPosition
const& rStartPos((**iter
).GetMarkStart());
1515 if ( *pStt
<= rStartPos
&& rStartPos
< *pEnd
)
1517 IDocumentMarkAccess::const_iterator_t pOldMark
=
1518 rDMA
.findAnnotationBookmark((**iter
).GetName());
1519 if ( pOldMark
== rDMA
.getBookmarksEnd() )
1521 // at start of redlines use a 1-character length bookmark range
1522 // instead of a 0-character length bookmark position to avoid its losing
1523 sal_Int32 nLen
= (*pStt
== rStartPos
) ? 1 : 0;
1524 SwPaM
aPam( rStartPos
.GetNode(), rStartPos
.GetContentIndex(),
1525 rStartPos
.GetNode(), rStartPos
.GetContentIndex() + nLen
);
1526 ::sw::mark::IMark
* pMark
= rDMA
.makeAnnotationBookmark(
1529 IDocumentMarkAccess::MarkType::BOOKMARK
, sw::mark::InsertMode::New
);
1530 ::sw::mark::IBookmark
* pBookmark
= dynamic_cast< ::sw::mark::IBookmark
* >(pMark
);
1533 pBookmark
->SetKeyCode(vcl::KeyCode());
1534 pBookmark
->SetShortName(OUString());
1542 void SwRangeRedline::MoveToSection()
1544 if( !m_oContentSect
)
1546 auto [pStt
, pEnd
] = StartEnd(); // SwPosition*
1548 SwDoc
& rDoc
= GetDoc();
1549 SwPaM
aPam( *pStt
, *pEnd
);
1550 SwContentNode
* pCSttNd
= pStt
->GetNode().GetContentNode();
1551 SwContentNode
* pCEndNd
= pEnd
->GetNode().GetContentNode();
1555 // In order to not move other Redlines' indices, we set them
1556 // to the end (is exclusive)
1557 const SwRedlineTable
& rTable
= rDoc
.getIDocumentRedlineAccess().GetRedlineTable();
1558 for(SwRangeRedline
* pRedl
: rTable
)
1560 if( pRedl
->GetBound() == *pStt
)
1561 pRedl
->GetBound() = *pEnd
;
1562 if( pRedl
->GetBound(false) == *pStt
)
1563 pRedl
->GetBound(false) = *pEnd
;
1567 SwStartNode
* pSttNd
;
1568 SwNodes
& rNds
= rDoc
.GetNodes();
1569 if( pCSttNd
|| pCEndNd
)
1571 SwTextFormatColl
* pColl
= (pCSttNd
&& pCSttNd
->IsTextNode() )
1572 ? pCSttNd
->GetTextNode()->GetTextColl()
1573 : (pCEndNd
&& pCEndNd
->IsTextNode() )
1574 ? pCEndNd
->GetTextNode()->GetTextColl()
1575 : rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
);
1577 pSttNd
= rNds
.MakeTextSection( rNds
.GetEndOfRedlines(),
1578 SwNormalStartNode
, pColl
);
1579 SwTextNode
* pTextNd
= rNds
[ pSttNd
->GetIndex() + 1 ]->GetTextNode();
1581 SwPosition
aPos( *pTextNd
);
1582 if( pCSttNd
&& pCEndNd
)
1584 // tdf#140982 keep annotation ranges in deletions in margin mode
1585 lcl_storeAnnotationMarks( rDoc
, pStt
, pEnd
);
1586 rDoc
.getIDocumentContentOperations().MoveAndJoin( aPam
, aPos
);
1590 if( pCSttNd
&& !pCEndNd
)
1591 m_bDelLastPara
= true;
1592 rDoc
.getIDocumentContentOperations().MoveRange( aPam
, aPos
,
1593 SwMoveFlags::DEFAULT
);
1598 pSttNd
= SwNodes::MakeEmptySection( rNds
.GetEndOfRedlines() );
1600 SwPosition
aPos( *pSttNd
->EndOfSectionNode() );
1601 rDoc
.getIDocumentContentOperations().MoveRange( aPam
, aPos
,
1602 SwMoveFlags::DEFAULT
);
1604 m_oContentSect
.emplace( *pSttNd
);
1606 if( pStt
== GetPoint() )
1612 InvalidateRange(Invalidation::Remove
);
1615 void SwRangeRedline::CopyToSection()
1617 if( m_oContentSect
)
1620 auto [pStt
, pEnd
] = StartEnd(); // SwPosition*
1622 SwContentNode
* pCSttNd
= pStt
->GetNode().GetContentNode();
1623 SwContentNode
* pCEndNd
= pEnd
->GetNode().GetContentNode();
1625 SwStartNode
* pSttNd
;
1626 SwDoc
& rDoc
= GetDoc();
1627 SwNodes
& rNds
= rDoc
.GetNodes();
1629 bool bSaveCopyFlag
= rDoc
.IsCopyIsMove(),
1630 bSaveRdlMoveFlg
= rDoc
.getIDocumentRedlineAccess().IsRedlineMove();
1631 rDoc
.SetCopyIsMove( true );
1633 // The IsRedlineMove() flag causes the behaviour of the
1634 // DocumentContentOperationsManager::CopyFlyInFlyImpl() method to change,
1635 // which will eventually be called by the CopyRange() below.
1636 rDoc
.getIDocumentRedlineAccess().SetRedlineMove(true);
1640 SwTextFormatColl
* pColl
= pCSttNd
->IsTextNode()
1641 ? pCSttNd
->GetTextNode()->GetTextColl()
1642 : rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD
);
1644 pSttNd
= rNds
.MakeTextSection( rNds
.GetEndOfRedlines(),
1645 SwNormalStartNode
, pColl
);
1647 SwPosition
aPos( *pSttNd
, SwNodeOffset(1) );
1649 // tdf#115815 keep original start position of collapsed annotation ranges
1650 // as temporary bookmarks (removed after file saving and file loading)
1651 lcl_storeAnnotationMarks( rDoc
, pStt
, pEnd
);
1652 rDoc
.getIDocumentContentOperations().CopyRange(*this, aPos
, SwCopyFlags::CheckPosInFly
);
1654 // Take over the style from the EndNode if needed
1655 // We don't want this in Doc::Copy
1656 if( pCEndNd
&& pCEndNd
!= pCSttNd
)
1658 SwContentNode
* pDestNd
= aPos
.GetNode().GetContentNode();
1661 if( pDestNd
->IsTextNode() && pCEndNd
->IsTextNode() )
1662 pCEndNd
->GetTextNode()->CopyCollFormat(*pDestNd
->GetTextNode());
1664 pDestNd
->ChgFormatColl( pCEndNd
->GetFormatColl() );
1670 pSttNd
= SwNodes::MakeEmptySection( rNds
.GetEndOfRedlines() );
1674 SwPosition
aPos( *pSttNd
->EndOfSectionNode() );
1675 rDoc
.getIDocumentContentOperations().CopyRange(*this, aPos
, SwCopyFlags::CheckPosInFly
);
1679 SwNodeRange
aRg( pStt
->GetNode(), SwNodeOffset(0), pEnd
->GetNode(), SwNodeOffset(1) );
1680 rDoc
.GetDocumentContentOperationsManager().CopyWithFlyInFly(aRg
, *pSttNd
->EndOfSectionNode());
1683 m_oContentSect
.emplace( *pSttNd
);
1685 rDoc
.SetCopyIsMove( bSaveCopyFlag
);
1686 rDoc
.getIDocumentRedlineAccess().SetRedlineMove( bSaveRdlMoveFlg
);
1689 void SwRangeRedline::DelCopyOfSection(size_t nMyPos
)
1691 if( !m_oContentSect
)
1694 auto [pStt
, pEnd
] = StartEnd(); // SwPosition*
1696 SwDoc
& rDoc
= GetDoc();
1697 SwPaM
aPam( *pStt
, *pEnd
);
1698 SwContentNode
* pCSttNd
= pStt
->GetNode().GetContentNode();
1699 SwContentNode
* pCEndNd
= pEnd
->GetNode().GetContentNode();
1703 // In order to not move other Redlines' indices, we set them
1704 // to the end (is exclusive)
1705 const SwRedlineTable
& rTable
= rDoc
.getIDocumentRedlineAccess().GetRedlineTable();
1706 for(SwRangeRedline
* pRedl
: rTable
)
1708 if( pRedl
->GetBound() == *pStt
)
1709 pRedl
->GetBound() = *pEnd
;
1710 if( pRedl
->GetBound(false) == *pStt
)
1711 pRedl
->GetBound(false) = *pEnd
;
1715 if( pCSttNd
&& pCEndNd
)
1717 // #i100466# - force a <join next> on <delete and join> operation
1718 // tdf#125319 - rather not?
1719 rDoc
.getIDocumentContentOperations().DeleteAndJoin(aPam
/*, true*/);
1721 else if( pCSttNd
|| pCEndNd
)
1723 if( pCSttNd
&& !pCEndNd
)
1724 m_bDelLastPara
= true;
1725 rDoc
.getIDocumentContentOperations().DeleteRange( aPam
);
1727 if( m_bDelLastPara
)
1729 // To prevent dangling references to the paragraph to
1730 // be deleted, redline that point into this paragraph should be
1731 // moved to the new end position. Since redlines in the redline
1732 // table are sorted and the pEnd position is an endnode (see
1733 // bDelLastPara condition above), only redlines before the
1734 // current ones can be affected.
1735 const SwRedlineTable
& rTable
= rDoc
.getIDocumentRedlineAccess().GetRedlineTable();
1737 for( bool bBreak
= false; !bBreak
&& n
> 0; )
1741 if( rTable
[ n
]->GetBound() == *aPam
.GetPoint() )
1743 rTable
[ n
]->GetBound() = *pEnd
;
1746 if( rTable
[ n
]->GetBound(false) == *aPam
.GetPoint() )
1748 rTable
[ n
]->GetBound(false) = *pEnd
;
1753 *GetPoint() = *pEnd
;
1758 aPam
.GetPoint()->SetContent(0);;
1759 rDoc
.getIDocumentContentOperations().DelFullPara( aPam
);
1764 rDoc
.getIDocumentContentOperations().DeleteRange( aPam
);
1767 if( pStt
== GetPoint() )
1773 void SwRangeRedline::MoveFromSection(size_t nMyPos
)
1775 if( m_oContentSect
)
1777 SwDoc
& rDoc
= GetDoc();
1778 const SwRedlineTable
& rTable
= rDoc
.getIDocumentRedlineAccess().GetRedlineTable();
1779 std::vector
<SwPosition
*> aBeforeArr
, aBehindArr
;
1780 bool bBreak
= false;
1781 SwRedlineTable::size_type n
;
1783 for( n
= nMyPos
+1; !bBreak
&& n
< rTable
.size(); ++n
)
1786 if( rTable
[ n
]->GetBound() == *GetPoint() )
1788 SwRangeRedline
* pRedl
= rTable
[n
];
1789 aBehindArr
.push_back(&pRedl
->GetBound());
1792 if( rTable
[ n
]->GetBound(false) == *GetPoint() )
1794 SwRangeRedline
* pRedl
= rTable
[n
];
1795 aBehindArr
.push_back(&pRedl
->GetBound(false));
1799 for( bBreak
= false, n
= nMyPos
; !bBreak
&& n
; )
1803 if( rTable
[ n
]->GetBound() == *GetPoint() )
1805 SwRangeRedline
* pRedl
= rTable
[n
];
1806 aBeforeArr
.push_back(&pRedl
->GetBound());
1809 if( rTable
[ n
]->GetBound(false) == *GetPoint() )
1811 SwRangeRedline
* pRedl
= rTable
[n
];
1812 aBeforeArr
.push_back(&pRedl
->GetBound(false));
1817 const SwNode
* pKeptContentSectNode( &m_oContentSect
->GetNode() ); // #i95711#
1819 SwPaM
aPam( m_oContentSect
->GetNode(),
1820 *m_oContentSect
->GetNode().EndOfSectionNode(), SwNodeOffset(1),
1821 SwNodeOffset( m_bDelLastPara
? -2 : -1 ) );
1822 SwContentNode
* pCNd
= aPam
.GetPointContentNode();
1824 aPam
.GetPoint()->SetContent( pCNd
->Len() );
1826 aPam
.GetPoint()->Adjust(SwNodeOffset(+1));
1828 SwFormatColl
* pColl
= pCNd
&& pCNd
->Len() && aPam
.GetPoint()->GetNode() !=
1829 aPam
.GetMark()->GetNode()
1830 ? pCNd
->GetFormatColl() : nullptr;
1832 SwNodeIndex
aNdIdx( GetPoint()->GetNode(), -1 );
1833 const sal_Int32 nPos
= GetPoint()->GetContentIndex();
1835 SwPosition
aPos( *GetPoint() );
1836 if( m_bDelLastPara
&& *aPam
.GetPoint() == *aPam
.GetMark() )
1838 aPos
.Adjust(SwNodeOffset(-1));
1840 rDoc
.getIDocumentContentOperations().AppendTextNode( aPos
);
1844 rDoc
.getIDocumentContentOperations().MoveRange( aPam
, aPos
,
1845 SwMoveFlags::ALLFLYS
);
1850 GetMark()->Assign(aNdIdx
.GetIndex() + 1);
1851 pCNd
= GetMark()->GetNode().GetContentNode();
1853 GetMark()->SetContent( nPos
);
1855 if( m_bDelLastPara
)
1857 GetPoint()->Adjust(SwNodeOffset(+1));
1858 pCNd
= GetPointContentNode();
1859 m_bDelLastPara
= false;
1862 pCNd
= GetPointContentNode();
1865 pCNd
->ChgFormatColl( pColl
);
1869 // Under certain conditions the previous <SwDoc::Move(..)> has already
1870 // removed the change tracking section of this <SwRangeRedline> instance from
1871 // the change tracking nodes area.
1872 // Thus, check if <pContentSect> still points to the change tracking section
1873 // by comparing it with the "indexed" <SwNode> instance copied before
1874 // perform the intrinsic move.
1875 // Note: Such condition is e.g. a "delete" change tracking only containing a table.
1876 if ( &m_oContentSect
->GetNode() == pKeptContentSectNode
)
1878 rDoc
.getIDocumentContentOperations().DeleteSection( &m_oContentSect
->GetNode() );
1880 m_oContentSect
.reset();
1882 // adjustment of redline table positions must take start and
1883 // end into account, not point and mark.
1884 for( auto& pItem
: aBeforeArr
)
1886 for( auto& pItem
: aBehindArr
)
1890 InvalidateRange(Invalidation::Add
);
1894 void SwRangeRedline::SetContentIdx( const SwNodeIndex
& rIdx
)
1896 if( !m_oContentSect
)
1898 m_oContentSect
= rIdx
;
1899 m_bIsVisible
= false;
1903 OSL_FAIL("SwRangeRedline::SetContentIdx: invalid state");
1908 void SwRangeRedline::ClearContentIdx()
1910 if( m_oContentSect
)
1912 m_oContentSect
.reset();
1916 OSL_FAIL("SwRangeRedline::ClearContentIdx: invalid state");
1920 bool SwRangeRedline::CanCombine( const SwRangeRedline
& rRedl
) const
1922 return IsVisible() && rRedl
.IsVisible() &&
1923 m_pRedlineData
->CanCombine( *rRedl
.m_pRedlineData
);
1926 void SwRangeRedline::PushData( const SwRangeRedline
& rRedl
, bool bOwnAsNext
)
1928 SwRedlineData
* pNew
= new SwRedlineData( *rRedl
.m_pRedlineData
, false );
1931 pNew
->m_pNext
= m_pRedlineData
;
1932 m_pRedlineData
= pNew
;
1936 pNew
->m_pNext
= m_pRedlineData
->m_pNext
;
1937 m_pRedlineData
->m_pNext
= pNew
;
1941 bool SwRangeRedline::PopData()
1943 if( !m_pRedlineData
->m_pNext
)
1945 SwRedlineData
* pCur
= m_pRedlineData
;
1946 m_pRedlineData
= pCur
->m_pNext
;
1947 pCur
->m_pNext
= nullptr;
1952 sal_uInt16
SwRangeRedline::GetStackCount() const
1954 sal_uInt16 nRet
= 1;
1955 for( SwRedlineData
* pCur
= m_pRedlineData
; pCur
->m_pNext
; pCur
= pCur
->m_pNext
)
1960 std::size_t SwRangeRedline::GetAuthor( sal_uInt16 nPos
) const
1962 return GetRedlineData(nPos
).m_nAuthor
;
1965 OUString
const & SwRangeRedline::GetAuthorString( sal_uInt16 nPos
) const
1967 return SW_MOD()->GetRedlineAuthor(GetRedlineData(nPos
).m_nAuthor
);
1970 const DateTime
& SwRangeRedline::GetTimeStamp( sal_uInt16 nPos
) const
1972 return GetRedlineData(nPos
).m_aStamp
;
1975 RedlineType
SwRangeRedline::GetType( sal_uInt16 nPos
) const
1977 return GetRedlineData(nPos
).m_eType
;
1980 bool SwRangeRedline::IsAnnotation() const
1982 return GetText().getLength() == 1 && GetText()[0] == CH_TXTATR_INWORD
;
1985 const OUString
& SwRangeRedline::GetComment( sal_uInt16 nPos
) const
1987 return GetRedlineData(nPos
).m_sComment
;
1990 bool SwRangeRedline::operator<( const SwRangeRedline
& rCmp
) const
1992 if (*Start() < *rCmp
.Start())
1995 return *Start() == *rCmp
.Start() && *End() < *rCmp
.End();
1998 const SwRedlineData
& SwRangeRedline::GetRedlineData(const sal_uInt16 nPos
) const
2000 SwRedlineData
* pCur
= m_pRedlineData
;
2002 sal_uInt16 nP
= nPos
;
2004 while (nP
> 0 && nullptr != pCur
->m_pNext
)
2006 pCur
= pCur
->m_pNext
;
2011 SAL_WARN_IF( nP
!= 0, "sw.core", "Pos " << nPos
<< " is " << nP
<< " too big");
2016 OUString
SwRangeRedline::GetDescr(bool bSimplified
)
2018 // get description of redline data (e.g.: "insert $1")
2019 OUString aResult
= GetRedlineData().GetDescr();
2021 SwPaM
* pPaM
= nullptr;
2022 bool bDeletePaM
= false;
2024 // if this redline is visible the content is in this PaM
2025 if (!m_oContentSect
.has_value())
2029 else // otherwise it is saved in pContentSect
2031 pPaM
= new SwPaM( m_oContentSect
->GetNode(), *m_oContentSect
->GetNode().EndOfSectionNode() );
2035 OUString sDescr
= DenoteSpecialCharacters(pPaM
->GetText().replace('\n', ' '), /*bQuoted=*/!bSimplified
);
2036 if (const SwTextNode
*pTextNode
= pPaM
->GetPointNode().GetTextNode())
2038 if (const SwTextAttr
* pTextAttr
= pTextNode
->GetFieldTextAttrAt(pPaM
->GetPoint()->GetContentIndex() - 1, ::sw::GetTextAttrMode::Default
))
2040 sDescr
= ( bSimplified
? "" : SwResId(STR_START_QUOTE
) )
2041 + pTextAttr
->GetFormatField().GetField()->GetFieldName()
2042 + ( bSimplified
? "" : SwResId(STR_END_QUOTE
) );
2046 // replace $1 in description by description of the redlines text
2047 const OUString aTmpStr
= ShortenString(sDescr
, nUndoStringLength
, SwResId(STR_LDOTS
));
2051 SwRewriter aRewriter
;
2052 aRewriter
.AddRule(UndoArg1
, aTmpStr
);
2054 aResult
= aRewriter
.Apply(aResult
);
2060 sal_Int32 nPos
= aTmpStr
.indexOf(SwResId(STR_LDOTS
));
2062 aResult
= aTmpStr
.copy(0, nPos
+ SwResId(STR_LDOTS
).getLength());
2071 void SwRangeRedline::dumpAsXml(xmlTextWriterPtr pWriter
) const
2073 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwRangeRedline"));
2075 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
2076 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("id"), BAD_CAST(OString::number(GetSeqNo()).getStr()));
2077 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("author"), BAD_CAST(SW_MOD()->GetRedlineAuthor(GetAuthor()).toUtf8().getStr()));
2078 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("date"), BAD_CAST(DateTimeToOString(GetTimeStamp()).getStr()));
2079 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("descr"), BAD_CAST(const_cast<SwRangeRedline
*>(this)->GetDescr().toUtf8().getStr()));
2081 OString sRedlineType
;
2084 case RedlineType::Insert
:
2085 sRedlineType
= "REDLINE_INSERT";
2087 case RedlineType::Delete
:
2088 sRedlineType
= "REDLINE_DELETE";
2090 case RedlineType::Format
:
2091 sRedlineType
= "REDLINE_FORMAT";
2094 sRedlineType
= "UNKNOWN";
2097 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("type"), BAD_CAST(sRedlineType
.getStr()));
2099 SwPaM::dumpAsXml(pWriter
);
2101 (void)xmlTextWriterEndElement(pWriter
);
2104 void SwExtraRedlineTable::Insert( SwExtraRedline
* p
)
2106 m_aExtraRedlines
.push_back( p
);
2107 //p->CallDisplayFunc();
2110 void SwExtraRedlineTable::DeleteAndDestroy(sal_uInt16
const nPos
)
2114 if( !nP && nL && nL == size() )
2115 pDoc = front()->GetDoc();
2118 delete m_aExtraRedlines
[nPos
];
2119 m_aExtraRedlines
.erase(m_aExtraRedlines
.begin() + nPos
);
2123 if( pDoc && !pDoc->IsInDtor() &&
2124 0 != ( pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() ) )
2125 pSh->InvalidateWindows( SwRect( 0, 0, SAL_MAX_INT32, SAL_MAX_INT32 ) );
2129 void SwExtraRedlineTable::DeleteAndDestroyAll()
2131 while (!m_aExtraRedlines
.empty())
2133 auto const pRedline
= m_aExtraRedlines
.back();
2134 m_aExtraRedlines
.pop_back();
2139 SwExtraRedline::~SwExtraRedline()
2143 SwTableRowRedline::SwTableRowRedline(const SwRedlineData
& rData
, const SwTableLine
& rTableLine
)
2144 : m_aRedlineData(rData
)
2145 , m_rTableLine(rTableLine
)
2149 SwTableRowRedline::~SwTableRowRedline()
2153 SwTableCellRedline::SwTableCellRedline(const SwRedlineData
& rData
, const SwTableBox
& rTableBox
)
2154 : m_aRedlineData(rData
)
2155 , m_rTableBox(rTableBox
)
2159 SwTableCellRedline::~SwTableCellRedline()
2163 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */