LibreOffice Module sw (master) 1
DocumentRedlineManager.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18*/
20#include <frmfmt.hxx>
21#include <rootfrm.hxx>
22#include <txtfrm.hxx>
23#include <doc.hxx>
24#include <docsh.hxx>
25#include <fmtfld.hxx>
26#include <frmtool.hxx>
27#include <IDocumentUndoRedo.hxx>
30#include <IDocumentState.hxx>
31#include <redline.hxx>
32#include <UndoRedline.hxx>
33#include <docary.hxx>
34#include <ndtxt.hxx>
35#include <unocrsr.hxx>
36#include <ftnidx.hxx>
37#include <authfld.hxx>
38#include <strings.hrc>
39#include <swmodule.hxx>
40#include <osl/diagnose.h>
41#include <editeng/prntitem.hxx>
42
43using namespace com::sun::star;
44
45#ifdef DBG_UTIL
46
47 #define ERROR_PREFIX "redline table corrupted: "
48
49 namespace
50 {
51 // helper function for lcl_CheckRedline
52 // 1. make sure that pPos->nContent points into pPos->nNode
53 // 2. check that position is valid and doesn't point after text
54 void lcl_CheckPosition( const SwPosition* pPos )
55 {
56 assert(dynamic_cast<SwContentIndexReg*>(&pPos->GetNode())
57 == pPos->GetContentNode());
58
59 SwTextNode* pTextNode = pPos->GetNode().GetTextNode();
60 if( pTextNode == nullptr )
61 {
62 assert(pPos->GetContentIndex() == 0);
63 }
64 else
65 {
66 assert(pPos->GetContentIndex() >= 0 && pPos->GetContentIndex() <= pTextNode->Len());
67 }
68 }
69
70 void lcl_CheckPam( const SwPaM* pPam )
71 {
72 assert(pPam);
73 lcl_CheckPosition( pPam->GetPoint() );
74 lcl_CheckPosition( pPam->GetMark() );
75 }
76
77 // check validity of the redline table. Checks redline bounds, and make
78 // sure the redlines are sorted and non-overlapping.
79 void lcl_CheckRedline( const IDocumentRedlineAccess& redlineAccess )
80 {
81 const SwRedlineTable& rTable = redlineAccess.GetRedlineTable();
82
83 // verify valid redline positions
84 for(SwRangeRedline* i : rTable)
85 lcl_CheckPam( i );
86
87 for(SwRangeRedline* j : rTable)
88 {
89 // check for empty redlines
90 // note: these can destroy sorting in SwTextNode::Update()
91 // if there's another one without mark on the same pos.
92 OSL_ENSURE( ( *(j->GetPoint()) != *(j->GetMark()) ) ||
93 ( j->GetContentIdx() != nullptr ),
94 ERROR_PREFIX "empty redline" );
95 }
96
97 // verify proper redline sorting
98 for( size_t n = 1; n < rTable.size(); ++n )
99 {
100 const SwRangeRedline* pPrev = rTable[ n-1 ];
101 const SwRangeRedline* pCurrent = rTable[ n ];
102
103 // check redline sorting
104 SAL_WARN_IF( *pPrev->Start() > *pCurrent->Start(), "sw",
105 ERROR_PREFIX "not sorted correctly" );
106
107 // check for overlapping redlines
108 SAL_WARN_IF( *pPrev->End() > *pCurrent->Start(), "sw",
109 ERROR_PREFIX "overlapping redlines" );
110 }
111
112 assert(std::is_sorted(rTable.begin(), rTable.end(), CompareSwRedlineTable()));
113 }
114 }
115
116 #define CHECK_REDLINE( pDoc ) lcl_CheckRedline( pDoc );
117
118#else
119
120 #define CHECK_REDLINE( pDoc )
121
122#endif
123
124namespace sw {
125
127{
128 auto const pAuthType(static_cast<SwAuthorityFieldType*>(rIDFA.GetFieldType(
129 SwFieldIds::TableOfAuthorities, OUString(), false)));
130 if (pAuthType) // created on demand...
131 {
132 pAuthType->DelSequenceArray();
133 }
134 rIDFA.GetFieldType(SwFieldIds::RefPageGet, OUString(), false)->UpdateFields();
136 rIDFA.UpdateExpFields(nullptr, false);
137 rIDFA.UpdateRefFields();
138}
139
141{
142 if (rDoc.IsClipBoard())
143 {
144 return;
145 }
146 // no need to call UpdateFootnoteNums for FTNNUM_PAGE:
147 // the AppendFootnote/RemoveFootnote will do it by itself!
149 SwPosition currentStart(*rPam.Start());
150 SwTextNode * pStartNode(rPam.Start()->GetNode().GetTextNode());
151 while (!pStartNode)
152 {
153 // note: branch only taken for redlines, not fieldmarks
154 SwStartNode *const pTableOrSectionNode(
155 currentStart.GetNode().IsTableNode()
156 ? static_cast<SwStartNode*>(currentStart.GetNode().GetTableNode())
157 : static_cast<SwStartNode*>(currentStart.GetNode().GetSectionNode()));
158 if ( !pTableOrSectionNode )
159 {
160 SAL_WARN("sw.core", "UpdateFramesForAddDeleteRedline:: known pathology (or ChangesInRedline mode)");
161 return;
162 }
163 for (SwNodeOffset j = pTableOrSectionNode->GetIndex(); j <= pTableOrSectionNode->EndOfSectionIndex(); ++j)
164 {
165 pTableOrSectionNode->GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
166 }
167 for (SwRootFrame const*const pLayout : rDoc.GetAllLayouts())
168 {
169 if (pLayout->HasMergedParas())
170 {
171 if (pTableOrSectionNode->IsTableNode())
172 {
173 static_cast<SwTableNode*>(pTableOrSectionNode)->DelFrames(pLayout);
174 }
175 else
176 {
177 static_cast<SwSectionNode*>(pTableOrSectionNode)->DelFrames(pLayout);
178 }
179 }
180 }
181 currentStart.Assign( pTableOrSectionNode->EndOfSectionIndex() + 1 );
182 pStartNode = currentStart.GetNode().GetTextNode();
183 }
184 if (currentStart < *rPam.End())
185 {
186 SwTextNode * pNode(pStartNode);
187 do
188 {
189 // deleted text node: remove it from "hidden" list
190 // to update numbering in Show Changes mode
191 SwPosition aPos( *pNode, pNode->Len() );
192 if ( pNode->GetNumRule() && aPos < *rPam.End() )
193 pNode->RemoveFromListRLHidden();
194
195 std::vector<SwTextFrame*> frames;
197 for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
198 {
199 if (pFrame->getRootFrame()->HasMergedParas())
200 {
201 frames.push_back(pFrame);
202 }
203 // set anchored objects as deleted
204 pFrame->SetDrawObjsAsDeleted(true);
205 }
206 if (frames.empty())
207 {
208 auto const& layouts(rDoc.GetAllLayouts());
209 assert(std::none_of(layouts.begin(), layouts.end(),
210 [](SwRootFrame const*const pLayout) { return pLayout->IsHideRedlines(); }));
211 (void) layouts;
212 break;
213 }
215 SwTextNode * pLast(pNode);
216 for (SwTextFrame * pFrame : frames)
217 {
218 SwTextNode & rFirstNode(pFrame->GetMergedPara()
219 ? *pFrame->GetMergedPara()->pFirstNode
220 : *pNode);
221 assert(pNode == pStartNode
222 ? rFirstNode.GetIndex() <= pNode->GetIndex()
223 : &rFirstNode == pNode);
224 // clear old one first to avoid DelFrames confusing updates & asserts...
225 pFrame->SetMergedPara(nullptr);
226 pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
227 *pFrame, rFirstNode, eMode));
228 eMode = sw::FrameMode::New; // Existing is not idempotent!
229 // the first node of the new redline is not necessarily the first
230 // node of the merged frame, there could be another redline nearby
231 sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, *pNode, nullptr);
232 // if redline is split across table and table cell is empty, there's no redline in the cell and so no merged para
233 if (pFrame->GetMergedPara())
234 {
235 pLast = const_cast<SwTextNode*>(pFrame->GetMergedPara()->pLastNode);
236 }
237 }
238 SwNodeIndex tmp(*pLast);
239 // skip over hidden sections!
240 pNode = static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, /*bSkipHidden=*/true, /*bSkipProtect=*/false));
241 }
242 while (pNode && pNode->GetIndex() <= rPam.End()->GetNodeIndex());
243 }
244 // fields last - SwGetRefField::UpdateField requires up-to-date frames
245 UpdateFieldsForRedline(rDoc.getIDocumentFieldsAccess()); // after footnotes
246
247 // update SwPostItMgr / notes in the margin
248 rDoc.GetDocShell()->Broadcast(
250}
251
253{
254 // tdf#147006 fieldmark command may be empty => do not call AppendAllObjs()
255 if (rDoc.IsClipBoard() || *rPam.GetPoint() == *rPam.GetMark())
256 {
257 return;
258 }
259 bool isAppendObjsCalled(false);
261 SwPosition currentStart(*rPam.Start());
262 SwTextNode * pStartNode(rPam.Start()->GetNode().GetTextNode());
263 while (!pStartNode)
264 {
265 // note: branch only taken for redlines, not fieldmarks
266 SwStartNode *const pTableOrSectionNode(
267 currentStart.GetNode().IsTableNode()
268 ? static_cast<SwStartNode*>(currentStart.GetNode().GetTableNode())
269 : static_cast<SwStartNode*>(currentStart.GetNode().GetSectionNode()));
270 assert(pTableOrSectionNode); // known pathology
271 for (SwNodeOffset j = pTableOrSectionNode->GetIndex(); j <= pTableOrSectionNode->EndOfSectionIndex(); ++j)
272 {
273 pTableOrSectionNode->GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::None);
274 }
276 {
277 // note: this will also create frames for all currently hidden flys
278 // because it calls AppendAllObjs
279 ::MakeFrames(&rDoc, currentStart.GetNode(), *pTableOrSectionNode->EndOfSectionNode());
280 isAppendObjsCalled = true;
281 }
282 currentStart.Assign( pTableOrSectionNode->EndOfSectionIndex() + 1 );
283 pStartNode = currentStart.GetNode().GetTextNode();
284 }
285 if (currentStart < *rPam.End())
286 {
287 SwTextNode * pNode(pStartNode);
288 do
289 {
290 // undeleted text node: add it to the "hidden" list
291 // to update numbering in Show Changes mode
292 SwPosition aPos( *pNode, pNode->Len() );
293 if ( pNode->GetNumRule() && aPos < *rPam.End() )
294 pNode->AddToListRLHidden();
295
296 std::vector<SwTextFrame*> frames;
298 for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
299 {
300 if (pFrame->getRootFrame()->HasMergedParas())
301 {
302 frames.push_back(pFrame);
303 }
304 // set anchored objects as not deleted
305 pFrame->SetDrawObjsAsDeleted(false);
306 }
307 if (frames.empty())
308 {
309 // in SwUndoSaveSection::SaveSection(), DelFrames() preceded this call
310 if (!pNode->FindTableBoxStartNode() && !pNode->FindFlyStartNode())
311 {
312 auto const& layouts(rDoc.GetAllLayouts());
313 assert(std::none_of(layouts.begin(), layouts.end(),
314 [](SwRootFrame const*const pLayout) { return pLayout->IsHideRedlines(); }));
315 (void) layouts;
316 }
317 isAppendObjsCalled = true; // skip that!
318 break;
319 }
320
321 // no nodes can be unmerged by this - skip MakeFrames() etc.
322 if (rPam.GetPoint()->GetNode() == rPam.GetMark()->GetNode())
323 {
324 break; // continue with AppendAllObjs()
325 }
326
327 // first, call CheckParaRedlineMerge on the first paragraph,
328 // to init flag on new merge range (if any) + 1st node post the merge
330 SwTextNode * pLast(pNode);
331 for (SwTextFrame * pFrame : frames)
332 {
333 if (auto const pMergedPara = pFrame->GetMergedPara())
334 {
335 pLast = const_cast<SwTextNode*>(pMergedPara->pLastNode);
336 assert(pNode == pStartNode
337 ? pMergedPara->pFirstNode->GetIndex() <= pNode->GetIndex()
338 : pMergedPara->pFirstNode == pNode);
339 // clear old one first to avoid DelFrames confusing updates & asserts...
340 SwTextNode & rFirstNode(*pMergedPara->pFirstNode);
341 pFrame->SetMergedPara(nullptr);
342 pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
343 *pFrame, rFirstNode, eMode));
344 eMode = sw::FrameMode::New; // Existing is not idempotent!
345 // update pNode so MakeFrames starts on 2nd node
346 pNode = &rFirstNode;
347 }
348 }
349 if (pLast != pNode)
350 {
351 // now start node until end of merge + 1 has proper flags; MakeFrames
352 // should pick up from the next node in need of frames by checking flags
353 SwNodeIndex const start(*pNode, +1);
354 SwNodeIndex const end(*pLast, +1); // end is exclusive
355 // note: this will also create frames for all currently hidden flys
356 // both on first and non-first nodes because it calls AppendAllObjs
357 ::MakeFrames(&rDoc, start.GetNode(), end.GetNode());
358 isAppendObjsCalled = true;
359 // re-use this to move flys that are now on the wrong frame, with end
360 // of redline as "second" node; the nodes between start and end should
361 // be complete with MakeFrames already
362 sw::MoveMergedFlysAndFootnotes(frames, *pNode, *pLast, false);
363 }
364 SwNodeIndex tmp(*pLast);
365 // skip over hidden sections!
366 pNode = static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, /*bSkipHidden=*/true, /*bSkipProtect=*/false));
367 }
368 while (pNode && pNode->GetIndex() <= rPam.End()->GetNodeIndex());
369 }
370
371 if (!isAppendObjsCalled)
372 { // recreate flys in the one node the hard way...
373 for (auto const& pLayout : rDoc.GetAllLayouts())
374 {
375 if (pLayout->HasMergedParas())
376 {
377 AppendAllObjs(rDoc.GetSpzFrameFormats(), pLayout);
378 break;
379 }
380 }
381 }
382 // fields last - SwGetRefField::UpdateField requires up-to-date frames
383 UpdateFieldsForRedline(rDoc.getIDocumentFieldsAccess()); // after footnotes
384
385 // update SwPostItMgr / notes in the margin
386 rDoc.GetDocShell()->Broadcast(
388}
389
390} // namespace sw
391
392namespace
393{
394 bool IsPrevPos( const SwPosition & rPos1, const SwPosition & rPos2 )
395 {
396 const SwContentNode* pCNd;
397 if( 0 != rPos2.GetContentIndex() )
398 return false;
399 if( rPos2.GetNodeIndex() - 1 != rPos1.GetNodeIndex() )
400 return false;
401 pCNd = rPos1.GetNode().GetContentNode();
402 return pCNd && rPos1.GetContentIndex() == pCNd->Len();
403 }
404
405 // copy style or return with SwRedlineExtra_FormatColl with reject data of the upcoming copy
406 SwRedlineExtraData_FormatColl* lcl_CopyStyle( const SwPosition & rFrom, const SwPosition & rTo, bool bCopy = true )
407 {
408 SwTextNode* pToNode = rTo.GetNode().GetTextNode();
409 SwTextNode* pFromNode = rFrom.GetNode().GetTextNode();
410 if (pToNode != nullptr && pFromNode != nullptr && pToNode != pFromNode)
411 {
412 const SwPaM aPam(*pToNode);
413 SwDoc& rDoc = aPam.GetDoc();
414 // using Undo, copy paragraph style
415 SwTextFormatColl* pFromColl = pFromNode->GetTextColl();
416 SwTextFormatColl* pToColl = pToNode->GetTextColl();
417 if (bCopy && pFromColl != pToColl)
418 rDoc.SetTextFormatColl(aPam, pFromColl);
419
420 // using Undo, remove direct paragraph formatting of the "To" paragraph,
421 // and apply here direct paragraph formatting of the "From" paragraph
423 RES_PARATR_BEGIN, RES_PARATR_END - 3, // skip RSID and GRABBAG
424 RES_PARATR_LIST_BEGIN, RES_UL_SPACE, // skip PAGEDESC and BREAK
426 aTmp(rDoc.GetAttrPool());
427 SfxItemSet aTmp2(aTmp);
428
429 pToNode->GetParaAttr(aTmp, 0, 0);
430 pFromNode->GetParaAttr(aTmp2, 0, 0);
431
432 bool bSameSet = aTmp == aTmp2;
433
434 if (!bSameSet)
435 {
436 for( sal_uInt16 nItem = 0; nItem < aTmp.TotalCount(); ++nItem)
437 {
438 sal_uInt16 nWhich = aTmp.GetWhichByPos(nItem);
439 if( SfxItemState::SET == aTmp.GetItemState( nWhich, false ) &&
440 SfxItemState::SET != aTmp2.GetItemState( nWhich, false ) )
441 aTmp2.Put( aTmp.GetPool()->GetDefaultItem(nWhich), nWhich );
442 }
443 }
444
445 if (bCopy && !bSameSet)
447 else if (!bCopy && (!bSameSet || pFromColl != pToColl))
448 return new SwRedlineExtraData_FormatColl( pFromColl->GetName(), USHRT_MAX, &aTmp2 );
449 }
450 return nullptr;
451 }
452
453 // delete the empty tracked table row (i.e. if it's last tracked deletion was accepted)
454 void lcl_DeleteTrackedTableRow ( const SwPosition* pPos )
455 {
456 const SwTableBox* pBox = pPos->GetNode().GetTableBox();
457 if ( !pBox )
458 return;
459
460 const SwTableLine* pLine = pBox->GetUpper();
461 const SvxPrintItem *pHasTextChangesOnlyProp =
463 // empty table row with property "HasTextChangesOnly" = false
464 if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() )
465 {
466 if ( pLine->IsEmpty() )
467 {
468 SwCursor aCursor( *pPos, nullptr );
469 pPos->GetDoc().DeleteRow( aCursor );
470 }
471 else
472 {
473 // update property "HasTextChangesOnly"
475 (void)pLine->UpdateTextChangesOnly(nPos);
476 }
477 }
478 }
479
480 // at rejection of a deletion in a table, remove the tracking of the table row
481 // (also at accepting the last redline insertion of a tracked table row insertion)
482 void lcl_RemoveTrackingOfTableRow( const SwPosition* pPos, bool bRejectDeletion )
483 {
484 const SwTableBox* pBox = pPos->GetNode().GetTableBox();
485 if ( !pBox )
486 return;
487
488 const SwTableLine* pLine = pBox->GetUpper();
489 const SvxPrintItem *pHasTextChangesOnlyProp =
491 // table row property "HasTextChangesOnly" is set and its value is false
492 if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() )
493 {
494 bool bNoMoreInsertion = false;
495 if ( !bRejectDeletion )
496 {
498 SwRedlineTable::size_type nInsert = pLine->UpdateTextChangesOnly(nPos, /*bUpdateProperty=*/false);
499
500 if ( SwRedlineTable::npos == nInsert )
501 bNoMoreInsertion = true;
502 }
503 if ( bRejectDeletion || bNoMoreInsertion )
504 {
505 SvxPrintItem aUnsetTracking(RES_PRINT, true);
506 SwCursor aCursor( *pPos, nullptr );
507 pPos->GetDoc().SetRowNotTracked( aCursor, aUnsetTracking );
508 }
509 }
510 }
511
512 bool lcl_AcceptRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
513 bool bCallDelete,
514 const SwPosition* pSttRng = nullptr,
515 const SwPosition* pEndRng = nullptr )
516 {
517 bool bRet = true;
518 SwRangeRedline* pRedl = rArr[ rPos ];
519 SwPosition *pRStt = nullptr, *pREnd = nullptr;
521 if( pSttRng && pEndRng )
522 {
523 pRStt = pRedl->Start();
524 pREnd = pRedl->End();
525 eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
526 }
527
529
530 switch( pRedl->GetType() )
531 {
532 case RedlineType::Insert:
533 case RedlineType::Format:
534 {
535 bool bCheck = false, bReplace = false;
536 switch( eCmp )
537 {
539 if( *pSttRng == *pRStt )
540 pRedl->SetStart( *pEndRng, pRStt );
541 else
542 {
543 if( *pEndRng != *pREnd )
544 {
545 // split up
546 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
547 pNew->SetStart( *pEndRng );
548 rArr.Insert( pNew ); ++rPos;
549 }
550 pRedl->SetEnd( *pSttRng, pREnd );
551 bCheck = true;
552 }
553 break;
554
556 pRedl->SetStart( *pEndRng, pRStt );
557 bReplace = true;
558 break;
559
561 pRedl->SetEnd( *pSttRng, pREnd );
562 bCheck = true;
563 break;
564
567 {
568 bool bInsert = RedlineType::Insert == pRedl->GetType();
569 SwPosition aPos(pRedl->Start()->GetNode());
570 rArr.DeleteAndDestroy( rPos-- );
571
572 // remove tracking of the table row, if needed
573 if ( bInsert )
574 lcl_RemoveTrackingOfTableRow( &aPos, /*bRejectDelete=*/false );
575 }
576 break;
577
578 default:
579 bRet = false;
580 }
581
582 if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
583 {
584 // re-insert
585 rArr.Remove( pRedl );
586 rArr.Insert( pRedl );
587 }
588 }
589 break;
590 case RedlineType::Delete:
591 {
592 SwDoc& rDoc = pRedl->GetDoc();
593 const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
594 bool bDelRedl = false;
595 switch( eCmp )
596 {
598 if( bCallDelete )
599 {
600 pDelStt = pSttRng;
601 pDelEnd = pEndRng;
602 }
603 break;
604
606 if( bCallDelete )
607 {
608 pDelStt = pRStt;
609 pDelEnd = pEndRng;
610 }
611 break;
613 if( bCallDelete )
614 {
615 pDelStt = pREnd;
616 pDelEnd = pSttRng;
617 }
618 break;
619
622 {
623 rArr.Remove( rPos-- );
624 bDelRedl = true;
625 if( bCallDelete )
626 {
627 pDelStt = pRedl->Start();
628 pDelEnd = pRedl->End();
629 }
630 }
631 break;
632 default:
633 bRet = false;
634 }
635
636 if( pDelStt && pDelEnd )
637 {
638 SwPaM aPam( *pDelStt, *pDelEnd );
639 SwContentNode* pCSttNd = pDelStt->GetNode().GetContentNode();
640 SwContentNode* pCEndNd = pDelEnd->GetNode().GetContentNode();
641 pRStt = pRedl->Start();
642 pREnd = pRedl->End();
643
644 // keep style of the empty paragraph after deletion of wholly paragraphs
645 if( pCSttNd && pCEndNd && pRStt && pREnd && pRStt->GetContentIndex() == 0 )
646 lcl_CopyStyle(*pREnd, *pRStt);
647
648 if( bDelRedl )
649 delete pRedl;
650
653
654 if( pCSttNd && pCEndNd )
655 {
657 lcl_DeleteTrackedTableRow( aPam.End() );
658 }
659 else if (pCSttNd && !pCEndNd)
660 {
661 aPam.GetBound().nContent.Assign( nullptr, 0 );
662 aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
664 }
665 else
666 {
668 }
670 }
671 else if( bDelRedl )
672 delete pRedl;
673 }
674 break;
675
676 case RedlineType::FmtColl:
677 rArr.DeleteAndDestroy( rPos-- );
678 break;
679
680 case RedlineType::ParagraphFormat:
681 rArr.DeleteAndDestroy( rPos-- );
682 break;
683
684 default:
685 bRet = false;
686 }
687 return bRet;
688 }
689
690 bool lcl_RejectRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
691 bool bCallDelete,
692 const SwPosition* pSttRng = nullptr,
693 const SwPosition* pEndRng = nullptr )
694 {
695 bool bRet = true;
696 SwRangeRedline* pRedl = rArr[ rPos ];
697 SwDoc& rDoc = pRedl->GetDoc();
698 SwPosition *pRStt = nullptr, *pREnd = nullptr;
700 if( pSttRng && pEndRng )
701 {
702 pRStt = pRedl->Start();
703 pREnd = pRedl->End();
704 eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
705 }
706
708
709 switch( pRedl->GetType() )
710 {
711 case RedlineType::Insert:
712 {
713 const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
714 bool bDelRedl = false;
715 switch( eCmp )
716 {
718 if( bCallDelete )
719 {
720 pDelStt = pSttRng;
721 pDelEnd = pEndRng;
722 }
723 break;
724
726 if( bCallDelete )
727 {
728 pDelStt = pRStt;
729 pDelEnd = pEndRng;
730 }
731 break;
733 if( bCallDelete )
734 {
735 pDelStt = pREnd;
736 pDelEnd = pSttRng;
737 }
738 break;
741 {
742 // delete the range again
743 rArr.Remove( rPos-- );
744 bDelRedl = true;
745 if( bCallDelete )
746 {
747 pDelStt = pRedl->Start();
748 pDelEnd = pRedl->End();
749 }
750 }
751 break;
752
753 default:
754 bRet = false;
755 }
756 if( pDelStt && pDelEnd )
757 {
758 SwPaM aPam( *pDelStt, *pDelEnd );
759
760 SwContentNode* pCSttNd = pDelStt->GetNode().GetContentNode();
761 SwContentNode* pCEndNd = pDelEnd->GetNode().GetContentNode();
762
763 if( bDelRedl )
764 delete pRedl;
765
768
769 if( pCSttNd && pCEndNd )
770 {
772 lcl_DeleteTrackedTableRow( aPam.End() );
773 }
774 else if (pCSttNd && !pCEndNd)
775 {
776 aPam.GetBound().nContent.Assign( nullptr, 0 );
777 aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
778 if (aPam.End()->GetNode().IsStartNode())
779 { // end node will be deleted too! see nNodeDiff+1
780 aPam.End()->Adjust(SwNodeOffset(-1));
781 }
782 assert(!aPam.End()->GetNode().IsStartNode());
784 }
785 else
786 {
788 }
790 }
791 else if( bDelRedl )
792 delete pRedl;
793 }
794 break;
795 case RedlineType::Delete:
796 {
797 SwRangeRedline* pNew = nullptr;
798 bool bCheck = false, bReplace = false;
799 SwPaM const updatePaM(pSttRng ? *pSttRng : *pRedl->Start(),
800 pEndRng ? *pEndRng : *pRedl->End());
801
802 if( pRedl->GetExtraData() )
803 pRedl->GetExtraData()->Reject( *pRedl );
804
805 // remove tracking of the table row, if needed
806 lcl_RemoveTrackingOfTableRow( updatePaM.End(), /*bRejectDelete=*/true );
807
808 switch( eCmp )
809 {
811 {
812 if( 1 < pRedl->GetStackCount() )
813 {
814 pNew = new SwRangeRedline( *pRedl );
815 pNew->PopData();
816 }
817 if( *pSttRng == *pRStt )
818 {
819 pRedl->SetStart( *pEndRng, pRStt );
820 bReplace = true;
821 if( pNew )
822 pNew->SetEnd( *pEndRng );
823 }
824 else
825 {
826 if( *pEndRng != *pREnd )
827 {
828 // split up
829 SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
830 pCpy->SetStart( *pEndRng );
831 rArr.Insert( pCpy ); ++rPos;
832 if( pNew )
833 pNew->SetEnd( *pEndRng );
834 }
835
836 pRedl->SetEnd( *pSttRng, pREnd );
837 bCheck = true;
838 if( pNew )
839 pNew->SetStart( *pSttRng );
840 }
841 }
842 break;
843
845 if( 1 < pRedl->GetStackCount() )
846 {
847 pNew = new SwRangeRedline( *pRedl );
848 pNew->PopData();
849 }
850 pRedl->SetStart( *pEndRng, pRStt );
851 bReplace = true;
852 if( pNew )
853 pNew->SetEnd( *pEndRng );
854 break;
855
857 if( 1 < pRedl->GetStackCount() )
858 {
859 pNew = new SwRangeRedline( *pRedl );
860 pNew->PopData();
861 }
862 pRedl->SetEnd( *pSttRng, pREnd );
863 bCheck = true;
864 if( pNew )
865 pNew->SetStart( *pSttRng );
866 break;
867
870 if( !pRedl->PopData() )
871 // deleting the RedlineObject is enough
872 rArr.DeleteAndDestroy( rPos-- );
873 break;
874
875 default:
876 bRet = false;
877 }
878
879 if( pNew )
880 {
881 rArr.Insert( pNew ); ++rPos;
882 }
883
884 if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
885 {
886 // re-insert
887 rArr.Remove( pRedl );
888 rArr.Insert( pRedl );
889 }
890
892 }
893 break;
894
895 case RedlineType::Format:
896 case RedlineType::FmtColl:
897 case RedlineType::ParagraphFormat:
898 {
899 // tdf#52391 instead of hidden acception at the requested
900 // rejection, remove direct text formatting to get the potential
901 // original state of the text (FIXME if the original text
902 // has already contained direct text formatting: unfortunately
903 // ODF 1.2 doesn't support rejection of format-only changes)
904 if ( pRedl->GetType() == RedlineType::Format )
905 {
906 SwPaM aPam( *(pRedl->Start()), *(pRedl->End()) );
907 rDoc.ResetAttrs(aPam);
908 }
909 else if ( pRedl->GetType() == RedlineType::ParagraphFormat )
910 {
911 // handle paragraph formatting changes
912 // (range is only a full paragraph or a part of it)
913 const SwPosition* pStt = pRedl->Start();
914 SwTextNode* pTNd = pStt->GetNode().GetTextNode();
915 if( pTNd )
916 {
917 // expand range to the whole paragraph
918 // and reset only the paragraph attributes
919 SwPaM aPam( *pTNd, pTNd->GetText().getLength() );
920 o3tl::sorted_vector<sal_uInt16> aResetAttrsArray;
921
922 constexpr std::pair<sal_uInt16, sal_uInt16> aResetableSetRange[] = {
925 };
926
927 for (const auto& [nBegin, nEnd] : aResetableSetRange)
928 {
929 for (sal_uInt16 i = nBegin; i <= nEnd; ++i)
930 aResetAttrsArray.insert( i );
931 }
932
933 rDoc.ResetAttrs(aPam, false, aResetAttrsArray);
934
935 // remove numbering
936 if ( pTNd->GetNumRule() )
937 rDoc.DelNumRules(aPam);
938 }
939 }
940
941 if( pRedl->GetExtraData() )
942 pRedl->GetExtraData()->Reject( *pRedl );
943
944 rArr.DeleteAndDestroy( rPos-- );
945 }
946 break;
947
948 default:
949 bRet = false;
950 }
951 return bRet;
952 }
953
954 typedef bool (*Fn_AcceptReject)( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
955 bool bCallDelete,
956 const SwPosition* pSttRng,
957 const SwPosition* pEndRng);
958
959
960 int lcl_AcceptRejectRedl( Fn_AcceptReject fn_AcceptReject,
961 SwRedlineTable& rArr, bool bCallDelete,
962 const SwPaM& rPam)
963 {
965 int nCount = 0;
966
967 const SwPosition* pStt = rPam.Start(),
968 * pEnd = rPam.End();
969 const SwRangeRedline* pFnd = rArr.FindAtPosition( *pStt, n );
970 if( pFnd && // Is new a part of it?
971 ( *pFnd->Start() != *pStt || *pFnd->End() > *pEnd ))
972 {
973 // Only revoke the partial selection
974 if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd ))
975 nCount++;
976 ++n;
977 }
978
979 // tdf#119824 first we will accept only overlapping paragraph format changes
980 // in the first loop to avoid potential content changes during Redo
981 bool bHasParagraphFormatChange = false;
982 for( int m = 0 ; m < 2 && !bHasParagraphFormatChange; ++m )
983 {
984 for(SwRedlineTable::size_type o = n ; o < rArr.size(); ++o )
985 {
986 SwRangeRedline* pTmp = rArr[ o ];
987 if( pTmp->HasMark() && pTmp->IsVisible() )
988 {
989 if( *pTmp->End() <= *pEnd )
990 {
991 if( (m > 0 || RedlineType::ParagraphFormat == pTmp->GetType()) &&
992 (*fn_AcceptReject)( rArr, o, bCallDelete, nullptr, nullptr ))
993 {
994 bHasParagraphFormatChange = true;
995 nCount++;
996 }
997 }
998 else
999 {
1000 if( *pTmp->Start() < *pEnd )
1001 {
1002 // Only revoke the partial selection
1003 if( (m > 0 || RedlineType::ParagraphFormat == pTmp->GetType()) &&
1004 (*fn_AcceptReject)( rArr, o, bCallDelete, pStt, pEnd ))
1005 {
1006 bHasParagraphFormatChange = true;
1007 nCount++;
1008 }
1009 }
1010 break;
1011 }
1012 }
1013 }
1014 }
1015 return nCount;
1016 }
1017
1018 void lcl_AdjustRedlineRange( SwPaM& rPam )
1019 {
1020 // The Selection is only in the ContentSection. If there are Redlines
1021 // to Non-ContentNodes before or after that, then the Selections
1022 // expand to them.
1023 auto [pStt, pEnd] = rPam.StartEnd(); // SwPosition*
1024 SwDoc& rDoc = rPam.GetDoc();
1025 if( !pStt->GetContentIndex() &&
1026 !rDoc.GetNodes()[ pStt->GetNodeIndex() - 1 ]->IsContentNode() )
1027 {
1028 const SwRangeRedline* pRedl = rDoc.getIDocumentRedlineAccess().GetRedline( *pStt, nullptr );
1029 if( pRedl )
1030 {
1031 const SwPosition* pRStt = pRedl->Start();
1032 if( !pRStt->GetContentIndex() && pRStt->GetNodeIndex() ==
1033 pStt->GetNodeIndex() - 1 )
1034 *pStt = *pRStt;
1035 }
1036 }
1037 if( pEnd->GetNode().IsContentNode() &&
1038 !rDoc.GetNodes()[ pEnd->GetNodeIndex() + 1 ]->IsContentNode() &&
1039 pEnd->GetContentIndex() == pEnd->GetNode().GetContentNode()->Len() )
1040 {
1041 const SwRangeRedline* pRedl = rDoc.getIDocumentRedlineAccess().GetRedline( *pEnd, nullptr );
1042 if( pRedl )
1043 {
1044 const SwPosition* pREnd = pRedl->End();
1045 if( !pREnd->GetContentIndex() && pREnd->GetNodeIndex() ==
1046 pEnd->GetNodeIndex() + 1 )
1047 *pEnd = *pREnd;
1048 }
1049 }
1050 }
1051
1054 class TemporaryRedlineUpdater
1055 {
1056 private:
1057 SwRangeRedline & m_rRedline;
1058 std::shared_ptr<SwUnoCursor> m_pCursor;
1059 public:
1060 TemporaryRedlineUpdater(SwDoc & rDoc, SwRangeRedline & rRedline)
1061 : m_rRedline(rRedline)
1062 , m_pCursor(rDoc.CreateUnoCursor(*rRedline.GetPoint(), false))
1063 {
1064 if (m_rRedline.HasMark())
1065 {
1066 m_pCursor->SetMark();
1067 *m_pCursor->GetMark() = *m_rRedline.GetMark();
1068 m_rRedline.GetMark()->Assign(rDoc.GetNodes().GetEndOfContent());
1069 }
1070 m_rRedline.GetPoint()->Assign(rDoc.GetNodes().GetEndOfContent());
1071 }
1072 ~TemporaryRedlineUpdater()
1073 {
1074 static_cast<SwPaM&>(m_rRedline) = *m_pCursor;
1075 }
1076 };
1077}
1078
1079namespace sw
1080{
1081
1083 : m_rDoc(i_rSwdoc)
1084 , meRedlineFlags(RedlineFlags::ShowInsert | RedlineFlags::ShowDelete)
1085 , mbIsRedlineMove(false)
1086 , mnAutoFormatRedlnCommentNo(0)
1087{
1088}
1089
1091{
1092 return meRedlineFlags;
1093}
1094
1096{
1097 if( meRedlineFlags == eMode )
1098 return;
1099
1102 {
1103 bool bSaveInXMLImportFlag = m_rDoc.IsInXMLImport();
1104 m_rDoc.SetInXMLImport( false );
1105 // and then hide/display everything
1106 void (SwRangeRedline::*pFnc)(sal_uInt16, size_t, bool); // Allow compiler warn if use of
1107 // uninitialized ptr is possible
1108
1111 pFnc = &SwRangeRedline::Show;
1112 else if (eShowMode == RedlineFlags::ShowInsert)
1113 pFnc = &SwRangeRedline::Hide;
1114 else if (eShowMode == RedlineFlags::ShowDelete)
1116 else
1117 {
1118 pFnc = &SwRangeRedline::Hide;
1120 }
1121
1123 CHECK_REDLINE( *this )
1124
1127 {
1128 // sw_redlinehide: the problem here is that MoveFromSection
1129 // creates the frames wrongly (non-merged), because its own
1130 // SwRangeRedline has wrong positions until after the nodes
1131 // are all moved, so fix things up by force by re-creating
1132 // all merged frames from scratch.
1134 for (SwRootFrame *const pLayout : layouts)
1135 {
1136 if (pLayout->IsHideRedlines())
1137 {
1138 pLayout->SetHideRedlines(false);
1139 hiddenLayouts.insert(pLayout);
1140 }
1141 }
1142 }
1143
1144 for (sal_uInt16 nLoop = 1; nLoop <= 2; ++nLoop)
1145 for (size_t i = 0; i < maRedlineTable.size(); ++i)
1146 {
1147 SwRangeRedline *const pRedline = maRedlineTable[i];
1148 (pRedline->*pFnc)(nLoop, i, false);
1149 while (maRedlineTable.size() <= i
1150 || maRedlineTable[i] != pRedline)
1151 { // ensure current position
1152 --i; // a previous redline may have been deleted
1153 }
1154 }
1155
1156 //SwRangeRedline::MoveFromSection routinely changes
1157 //the keys that mpRedlineTable is sorted by
1159
1161 CHECK_REDLINE( *this )
1162
1163 for (SwRootFrame *const pLayout : hiddenLayouts)
1164 {
1165 pLayout->SetHideRedlines(true);
1166 }
1167
1168 m_rDoc.SetInXMLImport( bSaveInXMLImportFlag );
1169 }
1172
1173 // #TODO - add 'SwExtraRedlineTable' also ?
1174}
1175
1177{
1179}
1180
1182{
1183 return bool(RedlineFlags::Ignore & meRedlineFlags);
1184}
1185
1187{
1189}
1190
1192{
1193 return maRedlineTable;
1194}
1195
1197{
1198 return maRedlineTable;
1199}
1200
1202{
1203 return maExtraRedlineTable;
1204}
1205
1207{
1208 return maExtraRedlineTable;
1209}
1210
1212{
1213 if (&rNode.GetNodes() != &m_rDoc.GetNodes())
1214 return false;
1215
1216 SwPosition aPos(rNode);
1217 SwNode & rEndOfRedlines = m_rDoc.GetNodes().GetEndOfRedlines();
1218 SwPaM aPam(SwPosition(*rEndOfRedlines.StartOfSectionNode()),
1219 SwPosition(rEndOfRedlines));
1220
1221 return aPam.ContainsPosition(aPos);
1222}
1223
1225{
1226 return mbIsRedlineMove;
1227}
1228
1230{
1231 mbIsRedlineMove = bFlag;
1232}
1233
1234/*
1235Text means Text not "polluted" by Redlines.
1236
1237Behaviour of Insert-Redline:
1238 - in the Text - insert Redline Object
1239 - in InsertRedline (own) - ignore, existing is extended
1240 - in InsertRedline (others) - split up InsertRedline and
1241 insert Redline Object
1242 - in DeleteRedline - split up DeleteRedline or
1243 move at the end/beginning
1244
1245Behaviour of Delete-Redline:
1246 - in the Text - insert Redline Object
1247 - in DeleteRedline (own/others) - ignore
1248 - in InsertRedline (own) - ignore, but delete character
1249 - in InsertRedline (others) - split up InsertRedline and
1250 insert Redline Object
1251 - Text and own Insert overlap - delete Text in the own Insert,
1252 extend in the other Text
1253 (up to the Insert!)
1254 - Text and other Insert overlap - insert Redline Object, the
1255 other Insert is overlapped by
1256 the Delete
1257*/
1260{
1261 CHECK_REDLINE( *this )
1262
1264 {
1265 if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
1266 {
1268 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
1269 // The ShowMode needs to be retained!
1272 meRedlineFlags = eOld;
1273 }
1274 delete pNewRedl;
1275 pNewRedl = nullptr;
1276 CHECK_REDLINE( *this )
1277 return AppendResult::IGNORED;
1278 }
1279
1280
1281 bool bMerged = false;
1282
1284
1286 {
1287 pNewRedl->SetAutoFormat();
1289 {
1292 }
1293 }
1294
1295 auto [pStt, pEnd] = pNewRedl->StartEnd(); // SwPosition*
1296 {
1297 SwTextNode* pTextNode = pStt->GetNode().GetTextNode();
1298 if( pTextNode == nullptr )
1299 {
1300 if( pStt->GetContentIndex() > 0 )
1301 {
1302 OSL_ENSURE( false, "Redline start: non-text-node with content" );
1303 pStt->SetContent( 0 );
1304 }
1305 }
1306 else
1307 {
1308 if( pStt->GetContentIndex() > pTextNode->Len() )
1309 {
1310 OSL_ENSURE( false, "Redline start: index after text" );
1311 pStt->SetContent( pTextNode->Len() );
1312 }
1313 }
1314 pTextNode = pEnd->GetNode().GetTextNode();
1315 if( pTextNode == nullptr )
1316 {
1317 if( pEnd->GetContentIndex() > 0 )
1318 {
1319 OSL_ENSURE( false, "Redline end: non-text-node with content" );
1320 pEnd->SetContent(0);
1321 }
1322 }
1323 else
1324 {
1325 if( pEnd->GetContentIndex() > pTextNode->Len() )
1326 {
1327 OSL_ENSURE( false, "Redline end: index after text" );
1328 pEnd->SetContent( pTextNode->Len() );
1329 }
1330 }
1331 }
1332 if( ( *pStt == *pEnd ) &&
1333 ( pNewRedl->GetContentIdx() == nullptr ) )
1334 { // Do not insert empty redlines
1335 delete pNewRedl;
1336 return AppendResult::IGNORED;
1337 }
1338 bool bCompress = false;
1340 // look up the first Redline for the starting position
1341 if( !GetRedline( *pStt, &n ) && n )
1342 --n;
1343 const SwRedlineTable::size_type nStartPos = n;
1344 bool bDec = false;
1345
1346 for( ; pNewRedl && n < maRedlineTable.size(); bDec ? n : ++n )
1347 {
1348 bDec = false;
1349
1350 SwRangeRedline* pRedl = maRedlineTable[ n ];
1351 auto [pRStt, pREnd] = pRedl->StartEnd();
1352
1353 // #i8518# remove empty redlines while we're at it
1354 if( ( *pRStt == *pREnd ) &&
1355 ( pRedl->GetContentIdx() == nullptr ) )
1356 {
1358 continue;
1359 }
1360
1361 SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
1362
1363 if ( SwComparePosition::Before == eCmpPos && !IsPrevPos( *pEnd, *pRStt ))
1364 break;
1365
1366 switch( pNewRedl->GetType() )
1367 {
1368 case RedlineType::Insert:
1369 switch( pRedl->GetType() )
1370 {
1371 case RedlineType::Insert:
1372 if( pRedl->IsOwnRedline( *pNewRedl ) &&
1373 // don't join inserted characters with moved text
1374 !pRedl->IsMoved() )
1375 {
1376 bool bDelete = false;
1377
1378 // Merge if applicable?
1379 if( (( SwComparePosition::Behind == eCmpPos &&
1380 IsPrevPos( *pREnd, *pStt ) ) ||
1381 ( SwComparePosition::CollideStart == eCmpPos ) ||
1382 ( SwComparePosition::OverlapBehind == eCmpPos ) ) &&
1383 pRedl->CanCombine( *pNewRedl ) &&
1384 ( n+1 >= maRedlineTable.size() ||
1385 ( *maRedlineTable[ n+1 ]->Start() >= *pEnd &&
1386 *maRedlineTable[ n+1 ]->Start() != *pREnd ) ) )
1387 {
1388 pRedl->SetEnd( *pEnd, pREnd );
1389 if( !pRedl->HasValidRange() )
1390 {
1391 // re-insert
1393 maRedlineTable.Insert( pRedl );
1394 }
1395
1396 bMerged = true;
1397 bDelete = true;
1398 }
1399 else if( (( SwComparePosition::Before == eCmpPos &&
1400 IsPrevPos( *pEnd, *pRStt ) ) ||
1401 ( SwComparePosition::CollideEnd == eCmpPos ) ||
1402 ( SwComparePosition::OverlapBefore == eCmpPos ) ) &&
1403 pRedl->CanCombine( *pNewRedl ) &&
1404 ( !n ||
1405 *maRedlineTable[ n-1 ]->End() != *pRStt ))
1406 {
1407 pRedl->SetStart( *pStt, pRStt );
1408 // re-insert
1410 maRedlineTable.Insert( pRedl );
1411
1412 bMerged = true;
1413 bDelete = true;
1414 }
1415 else if ( SwComparePosition::Outside == eCmpPos )
1416 {
1417 // own insert-over-insert redlines:
1418 // just scrap the inside ones
1420 bDec = true;
1421 }
1422 else if( SwComparePosition::OverlapBehind == eCmpPos )
1423 {
1424 *pStt = *pREnd;
1425 if( ( *pStt == *pEnd ) &&
1426 ( pNewRedl->GetContentIdx() == nullptr ) )
1427 bDelete = true;
1428 }
1429 else if( SwComparePosition::OverlapBefore == eCmpPos )
1430 {
1431 *pEnd = *pRStt;
1432 if( ( *pStt == *pEnd ) &&
1433 ( pNewRedl->GetContentIdx() == nullptr ) )
1434 bDelete = true;
1435 }
1436 else if( SwComparePosition::Inside == eCmpPos )
1437 {
1438 bDelete = true;
1439 bMerged = true;
1440 }
1441 else if( SwComparePosition::Equal == eCmpPos )
1442 bDelete = true;
1443
1444 if( bDelete )
1445 {
1446 delete pNewRedl;
1447 pNewRedl = nullptr;
1448 bCompress = true;
1449
1450 // set IsMoved checking nearby redlines
1451 if (n < maRedlineTable.size()) // in case above 're-insert' failed
1453 }
1454 }
1455 else if( SwComparePosition::Inside == eCmpPos )
1456 {
1457 // split up
1458 if( *pEnd != *pREnd )
1459 {
1460 SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
1461 pCpy->SetStart( *pEnd );
1462 maRedlineTable.Insert( pCpy );
1463 }
1464 pRedl->SetEnd( *pStt, pREnd );
1465 if( ( *pStt == *pRStt ) &&
1466 ( pRedl->GetContentIdx() == nullptr ) )
1467 {
1469 bDec = true;
1470 }
1471 else if( !pRedl->HasValidRange() )
1472 {
1473 // re-insert
1475 maRedlineTable.Insert( pRedl );
1476 }
1477 }
1478 else if ( SwComparePosition::Outside == eCmpPos )
1479 {
1480 // handle overlapping redlines in broken documents
1481
1482 // split up the new redline, since it covers the
1483 // existing redline. Insert the first part, and
1484 // progress with the remainder as usual
1485 SwRangeRedline* pSplit = new SwRangeRedline( *pNewRedl );
1486 pSplit->SetEnd( *pRStt );
1487 pNewRedl->SetStart( *pREnd );
1488 maRedlineTable.Insert( pSplit );
1489 if( *pStt == *pEnd && pNewRedl->GetContentIdx() == nullptr )
1490 {
1491 delete pNewRedl;
1492 pNewRedl = nullptr;
1493 bCompress = true;
1494 }
1495 }
1496 else if ( SwComparePosition::OverlapBehind == eCmpPos )
1497 {
1498 // handle overlapping redlines in broken documents
1499 pNewRedl->SetStart( *pREnd );
1500 }
1501 else if ( SwComparePosition::OverlapBefore == eCmpPos )
1502 {
1503 // handle overlapping redlines in broken documents
1504 *pEnd = *pRStt;
1505 if( ( *pStt == *pEnd ) &&
1506 ( pNewRedl->GetContentIdx() == nullptr ) )
1507 {
1508 delete pNewRedl;
1509 pNewRedl = nullptr;
1510 bCompress = true;
1511 }
1512 }
1513 break;
1514 case RedlineType::Delete:
1515 if( SwComparePosition::Inside == eCmpPos )
1516 {
1517 // split up
1518 if( *pEnd != *pREnd )
1519 {
1520 SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
1521 pCpy->SetStart( *pEnd );
1522 maRedlineTable.Insert( pCpy );
1523 }
1524 pRedl->SetEnd( *pStt, pREnd );
1525 if( ( *pStt == *pRStt ) &&
1526 ( pRedl->GetContentIdx() == nullptr ) )
1527 {
1529 bDec = true;
1530 }
1531 else if( !pRedl->HasValidRange() )
1532 {
1533 // re-insert
1535 maRedlineTable.Insert( pRedl, n );
1536 }
1537 }
1538 else if ( SwComparePosition::Outside == eCmpPos )
1539 {
1540 // handle overlapping redlines in broken documents
1541
1542 // split up the new redline, since it covers the
1543 // existing redline. Insert the first part, and
1544 // progress with the remainder as usual
1545 SwRangeRedline* pSplit = new SwRangeRedline( *pNewRedl );
1546 pSplit->SetEnd( *pRStt );
1547 pNewRedl->SetStart( *pREnd );
1548 maRedlineTable.Insert( pSplit );
1549 if( *pStt == *pEnd && pNewRedl->GetContentIdx() == nullptr )
1550 {
1551 delete pNewRedl;
1552 pNewRedl = nullptr;
1553 bCompress = true;
1554 }
1555 }
1556 else if ( SwComparePosition::Equal == eCmpPos )
1557 {
1558 // handle identical redlines in broken documents
1559 // delete old (delete) redline
1561 bDec = true;
1562 }
1563 else if ( SwComparePosition::OverlapBehind == eCmpPos )
1564 { // Another workaround for broken redlines
1565 pNewRedl->SetStart( *pREnd );
1566 }
1567 break;
1568 case RedlineType::Format:
1569 switch( eCmpPos )
1570 {
1572 pRedl->SetStart( *pEnd, pRStt );
1573 // re-insert
1575 maRedlineTable.Insert( pRedl, n );
1576 bDec = true;
1577 break;
1578
1580 pRedl->SetEnd( *pStt, pREnd );
1581 if( *pStt == *pRStt && pRedl->GetContentIdx() == nullptr )
1582 {
1584 bDec = true;
1585 }
1586 break;
1587
1590 // Overlaps the current one completely or has the
1591 // same dimension, delete the old one
1593 bDec = true;
1594 break;
1595
1597 // Overlaps the current one completely,
1598 // split or shorten the new one
1599 if( *pEnd != *pREnd )
1600 {
1601 if( *pEnd != *pRStt )
1602 {
1603 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
1604 pNew->SetStart( *pEnd );
1605 pRedl->SetEnd( *pStt, pREnd );
1606 if( *pStt == *pRStt && pRedl->GetContentIdx() == nullptr )
1608 AppendRedline( pNew, bCallDelete );
1609 n = 0; // re-initialize
1610 bDec = true;
1611 }
1612 }
1613 else
1614 pRedl->SetEnd( *pStt, pREnd );
1615 break;
1616 default:
1617 break;
1618 }
1619 break;
1620 default:
1621 break;
1622 }
1623 break;
1624
1625 case RedlineType::Delete:
1626 switch( pRedl->GetType() )
1627 {
1628 case RedlineType::Delete:
1629 switch( eCmpPos )
1630 {
1632 {
1633 // Overlaps the current one completely,
1634 // split the new one
1635 if (*pEnd == *pREnd)
1636 {
1637 pNewRedl->SetEnd(*pRStt, pEnd);
1638 }
1639 else if (*pStt == *pRStt)
1640 {
1641 pNewRedl->SetStart(*pREnd, pStt);
1642 }
1643 else
1644 {
1645 SwRangeRedline* pNew = new SwRangeRedline( *pNewRedl );
1646 pNew->SetStart( *pREnd );
1647 pNewRedl->SetEnd( *pRStt, pEnd );
1648 AppendRedline( pNew, bCallDelete );
1649 n = 0; // re-initialize
1650 bDec = true;
1651 }
1652 }
1653 break;
1654
1657 delete pNewRedl;
1658 pNewRedl = nullptr;
1659 bCompress = true;
1660 break;
1661
1664 if( pRedl->IsOwnRedline( *pNewRedl ) &&
1665 pRedl->CanCombine( *pNewRedl ))
1666 {
1667 // If that's the case we can merge it, meaning
1668 // the new one covers this well
1669 if( SwComparePosition::OverlapBehind == eCmpPos )
1670 pNewRedl->SetStart( *pRStt, pStt );
1671 else
1672 pNewRedl->SetEnd( *pREnd, pEnd );
1674 bDec = true;
1675 }
1676 else if( SwComparePosition::OverlapBehind == eCmpPos )
1677 pNewRedl->SetStart( *pREnd, pStt );
1678 else
1679 pNewRedl->SetEnd( *pRStt, pEnd );
1680 break;
1681
1683 if (pRStt->GetContentIndex() != 0
1684 && pRStt->GetNode() != pREnd->GetNode())
1685 { // tdf#147466 HACK: don't combine in this case to avoid the tdf#119571 code from *undeleting* section nodes
1686 break;
1687 }
1688 [[fallthrough]];
1690 if( pRedl->IsOwnRedline( *pNewRedl ) &&
1691 pRedl->CanCombine( *pNewRedl ) )
1692 {
1694 {
1695 // Before we can merge, we make it visible!
1696 // We insert temporarily so that pNew is
1697 // also dealt with when moving the indices.
1698 maRedlineTable.Insert(pNewRedl);
1699 pRedl->Show(0, maRedlineTable.GetPos(pRedl));
1700 maRedlineTable.Remove( pNewRedl );
1701 pRStt = pRedl->Start();
1702 pREnd = pRedl->End();
1703 }
1704
1705 // If that's the case we can merge it, meaning
1706 // the new one covers this well
1707 if( SwComparePosition::CollideStart == eCmpPos )
1708 pNewRedl->SetStart( *pRStt, pStt );
1709 else
1710 pNewRedl->SetEnd( *pREnd, pEnd );
1711
1712 // delete current (below), and restart process with
1713 // previous
1714 SwRedlineTable::size_type nToBeDeleted = n;
1715 bDec = true;
1716
1717 if( *(pNewRedl->Start()) <= *pREnd )
1718 {
1719 // Whoooah, we just extended the new 'redline'
1720 // beyond previous redlines, so better start
1721 // again. Of course this is not supposed to
1722 // happen, and in an ideal world it doesn't,
1723 // but unfortunately this code is buggy and
1724 // totally rotten so it does happen and we
1725 // better fix it.
1726 n = 0;
1727 bDec = true;
1728 }
1729
1730 maRedlineTable.DeleteAndDestroy( nToBeDeleted );
1731 }
1732 break;
1733 default:
1734 break;
1735 }
1736 break;
1737
1738 case RedlineType::Insert:
1739 {
1740 // b62341295: Do not throw away redlines
1741 // even if they are not allowed to be combined
1743 if( !( eOld & RedlineFlags::DontCombineRedlines ) &&
1744 pRedl->IsOwnRedline( *pNewRedl ) &&
1745 // tdf#116084 tdf#121176 don't combine anonymized deletion
1746 // and anonymized insertion, i.e. with the same dummy timestamp
1747 !pRedl->GetRedlineData(0).IsAnonymized() )
1748 {
1749
1750 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
1751 // The ShowMode needs to be retained!
1753 switch( eCmpPos )
1754 {
1756 bCompress = true;
1758 bDec = true;
1759 [[fallthrough]];
1760
1762 if( bCallDelete )
1763 {
1764 // DeleteAndJoin does not yield the
1765 // desired result if there is no paragraph to
1766 // join with, i.e. at the end of the document.
1767 // For this case, we completely delete the
1768 // paragraphs (if, of course, we also start on
1769 // a paragraph boundary).
1770 if( (pStt->GetContentIndex() == 0) &&
1771 pEnd->GetNode().IsEndNode() )
1772 {
1773 pEnd->Adjust(SwNodeOffset(-1));
1775 }
1776 else
1778
1779 bCompress = true;
1780 }
1781 delete pNewRedl;
1782 pNewRedl = nullptr;
1783 break;
1784
1786 {
1788 bDec = true;
1789 if( bCallDelete )
1790 {
1791 TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1793 n = 0; // re-initialize
1794 }
1795 delete pRedl;
1796 }
1797 break;
1798
1800 {
1801 SwPaM aPam( *pRStt, *pEnd );
1802
1803 if( *pEnd == *pREnd )
1805 else
1806 {
1807 pRedl->SetStart( *pEnd, pRStt );
1808 // re-insert
1810 maRedlineTable.Insert( pRedl, n );
1811 }
1812
1813 if( bCallDelete )
1814 {
1815 TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1817 n = 0; // re-initialize
1818 }
1819 bDec = true;
1820 }
1821 break;
1822
1824 {
1825 SwPaM aPam( *pStt, *pREnd );
1826
1827 if( *pStt == *pRStt )
1828 {
1830 bDec = true;
1831 }
1832 else
1833 pRedl->SetEnd( *pStt, pREnd );
1834
1835 if( bCallDelete )
1836 {
1837 TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1839 n = 0; // re-initialize
1840 bDec = true;
1841 }
1842 }
1843 break;
1844 default:
1845 break;
1846 }
1847
1848 meRedlineFlags = eOld;
1849 }
1850 else
1851 {
1852 // it may be necessary to split the existing redline in
1853 // two. In this case, pRedl will be changed to cover
1854 // only part of its former range, and pNew will cover
1855 // the remainder.
1856 SwRangeRedline* pNew = nullptr;
1857
1858 switch( eCmpPos )
1859 {
1861 {
1862 pRedl->PushData( *pNewRedl );
1863 delete pNewRedl;
1864 pNewRedl = nullptr;
1866 {
1867 pRedl->Hide(0, maRedlineTable.GetPos(pRedl));
1868 }
1869 bCompress = true;
1870 }
1871 break;
1872
1874 {
1875 if( *pRStt == *pStt )
1876 {
1877 // #i97421#
1878 // redline w/out extent loops
1879 if (*pStt != *pEnd)
1880 {
1881 pNewRedl->PushData( *pRedl, false );
1882 pRedl->SetStart( *pEnd, pRStt );
1883 // re-insert
1885 maRedlineTable.Insert( pRedl, n );
1886 bDec = true;
1887 }
1888 }
1889 else
1890 {
1891 pNewRedl->PushData( *pRedl, false );
1892 if( *pREnd != *pEnd )
1893 {
1894 pNew = new SwRangeRedline( *pRedl );
1895 pNew->SetStart( *pEnd );
1896 }
1897 pRedl->SetEnd( *pStt, pREnd );
1898 if( !pRedl->HasValidRange() )
1899 {
1900 // re-insert
1902 maRedlineTable.Insert( pRedl, n );
1903 }
1904 }
1905 }
1906 break;
1907
1909 {
1910 pRedl->PushData( *pNewRedl );
1911 if( *pEnd == *pREnd )
1912 {
1913 pNewRedl->SetEnd( *pRStt, pEnd );
1914 }
1915 else if (*pStt == *pRStt)
1916 {
1917 pNewRedl->SetStart(*pREnd, pStt);
1918 }
1919 else
1920 {
1921 pNew = new SwRangeRedline( *pNewRedl );
1922 pNew->SetEnd( *pRStt );
1923 pNewRedl->SetStart( *pREnd, pStt );
1924 }
1925 bCompress = true;
1926 }
1927 break;
1928
1930 {
1931 if( *pEnd == *pREnd )
1932 {
1933 pRedl->PushData( *pNewRedl );
1934 pNewRedl->SetEnd( *pRStt, pEnd );
1936 {
1937 maRedlineTable.Insert(pNewRedl);
1938 pRedl->Hide(0, maRedlineTable.GetPos(pRedl));
1939 maRedlineTable.Remove( pNewRedl );
1940 }
1941 }
1942 else
1943 {
1944 pNew = new SwRangeRedline( *pRedl );
1945 pNew->PushData( *pNewRedl );
1946 pNew->SetEnd( *pEnd );
1947 pNewRedl->SetEnd( *pRStt, pEnd );
1948 pRedl->SetStart( *pNew->End(), pRStt ) ;
1949 // re-insert
1951 maRedlineTable.Insert( pRedl );
1952 bDec = true;
1953 }
1954 }
1955 break;
1956
1958 {
1959 if( *pStt == *pRStt )
1960 {
1961 pRedl->PushData( *pNewRedl );
1962 pNewRedl->SetStart( *pREnd, pStt );
1964 {
1965 maRedlineTable.Insert( pNewRedl );
1966 pRedl->Hide(0, maRedlineTable.GetPos(pRedl));
1967 maRedlineTable.Remove( pNewRedl );
1968 }
1969 }
1970 else
1971 {
1972 pNew = new SwRangeRedline( *pRedl );
1973 pNew->PushData( *pNewRedl );
1974 pNew->SetStart( *pStt );
1975 pNewRedl->SetStart( *pREnd, pStt );
1976 pRedl->SetEnd( *pNew->Start(), pREnd );
1977 if( !pRedl->HasValidRange() )
1978 {
1979 // re-insert
1981 maRedlineTable.Insert( pRedl );
1982 }
1983 }
1984 }
1985 break;
1986 default:
1987 break;
1988 }
1989
1990 // insert the pNew part (if it exists)
1991 if( pNew )
1992 {
1993 maRedlineTable.Insert( pNew );
1994
1995 // pNew must be deleted if Insert() wasn't
1996 // successful. But that can't happen, since pNew is
1997 // part of the original pRedl redline.
1998 // OSL_ENSURE( bRet, "Can't insert existing redline?" );
1999
2000 // restart (now with pRedl being split up)
2001 n = 0;
2002 bDec = true;
2003 }
2004 }
2005 }
2006 break;
2007
2008 case RedlineType::Format:
2009 switch( eCmpPos )
2010 {
2012 pRedl->SetStart( *pEnd, pRStt );
2013 // re-insert
2015 maRedlineTable.Insert( pRedl, n );
2016 bDec = true;
2017 break;
2018
2020 pRedl->SetEnd( *pStt, pREnd );
2021 break;
2022
2025 // Overlaps the current one completely or has the
2026 // same dimension, delete the old one
2028 bDec = true;
2029 break;
2030
2032 // Overlaps the current one completely,
2033 // split or shorten the new one
2034 if( *pEnd != *pREnd )
2035 {
2036 if( *pEnd != *pRStt )
2037 {
2038 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
2039 pNew->SetStart( *pEnd );
2040 pRedl->SetEnd( *pStt, pREnd );
2041 if( ( *pStt == *pRStt ) &&
2042 ( pRedl->GetContentIdx() == nullptr ) )
2044 AppendRedline( pNew, bCallDelete );
2045 n = 0; // re-initialize
2046 bDec = true;
2047 }
2048 }
2049 else
2050 pRedl->SetEnd( *pStt, pREnd );
2051 break;
2052 default:
2053 break;
2054 }
2055 break;
2056 default:
2057 break;
2058 }
2059 break;
2060
2061 case RedlineType::Format:
2062 switch( pRedl->GetType() )
2063 {
2064 case RedlineType::Insert:
2065 case RedlineType::Delete:
2066 switch( eCmpPos )
2067 {
2069 pNewRedl->SetEnd( *pRStt, pEnd );
2070 break;
2071
2073 pNewRedl->SetStart( *pREnd, pStt );
2074 break;
2075
2078 delete pNewRedl;
2079 pNewRedl = nullptr;
2080 break;
2081
2083 // Overlaps the current one completely,
2084 // split or shorten the new one
2085 if (*pEnd == *pREnd)
2086 {
2087 pNewRedl->SetEnd(*pRStt, pEnd);
2088 }
2089 else if (*pStt == *pRStt)
2090 {
2091 pNewRedl->SetStart(*pREnd, pStt);
2092 }
2093 else
2094 {
2095 SwRangeRedline* pNew = new SwRangeRedline( *pNewRedl );
2096 pNew->SetStart( *pREnd );
2097 pNewRedl->SetEnd( *pRStt, pEnd );
2098 AppendRedline( pNew, bCallDelete );
2099 n = 0; // re-initialize
2100 bDec = true;
2101 }
2102 break;
2103 default:
2104 break;
2105 }
2106 break;
2107 case RedlineType::Format:
2108 switch( eCmpPos )
2109 {
2112 {
2113 // Overlaps the current one completely or has the
2114 // same dimension, delete the old one
2116 bDec = true;
2117 }
2118 break;
2119
2121 if( pRedl->IsOwnRedline( *pNewRedl ) &&
2122 pRedl->CanCombine( *pNewRedl ))
2123 {
2124 // own one can be ignored completely
2125 delete pNewRedl;
2126 pNewRedl = nullptr;
2127 }
2128 else if( *pREnd == *pEnd )
2129 // or else only shorten the current one
2130 pRedl->SetEnd( *pStt, pREnd );
2131 else if( *pRStt == *pStt )
2132 {
2133 // or else only shorten the current one
2134 pRedl->SetStart( *pEnd, pRStt );
2135 // re-insert
2137 maRedlineTable.Insert( pRedl, n );
2138 bDec = true;
2139 }
2140 else
2141 {
2142 // If it lies completely within the current one
2143 // we need to split it
2144 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
2145 pNew->SetStart( *pEnd );
2146 pRedl->SetEnd( *pStt, pREnd );
2147 AppendRedline( pNew, bCallDelete );
2148 n = 0; // re-initialize
2149 bDec = true;
2150 }
2151 break;
2152
2155 if( pRedl->IsOwnRedline( *pNewRedl ) &&
2156 pRedl->CanCombine( *pNewRedl ))
2157 {
2158 // If that's the case we can merge it, meaning
2159 // the new one covers this well
2160 if( SwComparePosition::OverlapBehind == eCmpPos )
2161 pNewRedl->SetStart( *pRStt, pStt );
2162 else
2163 pNewRedl->SetEnd( *pREnd, pEnd );
2165 bDec = false;
2166 }
2167 else if( SwComparePosition::OverlapBehind == eCmpPos )
2168 pNewRedl->SetStart( *pREnd, pStt );
2169 else
2170 pNewRedl->SetEnd( *pRStt, pEnd );
2171 break;
2172
2174 if( pRedl->IsOwnRedline( *pNewRedl ) &&
2175 pRedl->CanCombine( *pNewRedl ) &&
2176 (n == 0 || *maRedlineTable[ n-1 ]->End() < *pStt))
2177 {
2178 // If that's the case we can merge it, meaning
2179 // the new one covers this well
2180 pNewRedl->SetEnd( *pREnd, pEnd );
2182 bDec = true;
2183 }
2184 break;
2186 if( pRedl->IsOwnRedline( *pNewRedl ) &&
2187 pRedl->CanCombine( *pNewRedl ) &&
2188 (n+1 >= maRedlineTable.size() ||
2189 (*maRedlineTable[ n+1 ]->Start() >= *pEnd &&
2190 *maRedlineTable[ n+1 ]->Start() != *pREnd)))
2191 {
2192 // If that's the case we can merge it, meaning
2193 // the new one covers this well
2194 pNewRedl->SetStart( *pRStt, pStt );
2196 bDec = true;
2197 }
2198 break;
2199 default:
2200 break;
2201 }
2202 break;
2203 default:
2204 break;
2205 }
2206 break;
2207
2208 case RedlineType::FmtColl:
2209 // How should we behave here?
2210 // insert as is
2211 break;
2212 default:
2213 break;
2214 }
2215 }
2216
2217 if( pNewRedl )
2218 {
2219 if( ( *pStt == *pEnd ) &&
2220 ( pNewRedl->GetContentIdx() == nullptr ) )
2221 { // Do not insert empty redlines
2222 delete pNewRedl;
2223 pNewRedl = nullptr;
2224 }
2225 else
2226 {
2227 if ( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2228 {
2229 if ( pStt->GetContentIndex() != 0 )
2230 {
2231 // tdf#119571 update the style of the joined paragraph
2232 // after a partially deleted paragraph to show its correct style
2233 // in "Show changes" mode, too. All removed paragraphs
2234 // get the style of the first (partially deleted) paragraph
2235 // to avoid text insertion with bad style in the deleted
2236 // area later (except paragraphs of the removed tables).
2237
2238 SwContentNode* pDelNd = pStt->GetNode().GetContentNode();
2239 // start copying the style of the first paragraph from the end of the range
2240 SwContentNode* pTextNd = pEnd->GetNode().GetContentNode();
2241 SwNodeIndex aIdx( pEnd->GetNode() );
2242 bool bFirst = true;
2243
2244 while (pTextNd != nullptr && pDelNd->GetIndex() < pTextNd->GetIndex())
2245 {
2246 if( pTextNd->IsTextNode() )
2247 {
2248 SwPosition aPos(aIdx);
2249
2250 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2251 {
2252 bCompress = true;
2253
2254 // split redline to store ExtraData per paragraphs
2255 SwRangeRedline* pPar = new SwRangeRedline( *pNewRedl );
2256 pPar->SetStart( aPos );
2257 pNewRedl->SetEnd( aPos );
2258
2259 // get extradata for reset formatting of the modified paragraph
2260 SwRedlineExtraData_FormatColl* pExtraData = lcl_CopyStyle(aPos, *pStt, false);
2261 if (pExtraData)
2262 {
2263 std::unique_ptr<SwRedlineExtraData_FormatColl> xRedlineExtraData;
2264 if (!bFirst)
2265 pExtraData->SetFormatAll(false);
2266 xRedlineExtraData.reset(pExtraData);
2267 pPar->SetExtraData( xRedlineExtraData.get() );
2268 }
2269
2270 // skip empty redlines without ExtraData
2271 // FIXME: maybe checking pExtraData is redundant here
2272 if ( pExtraData || *pPar->Start() != *pPar->End() )
2273 maRedlineTable.Insert( pPar );
2274 else
2275 delete pPar;
2276 }
2277
2278 // modify paragraph formatting
2279 lcl_CopyStyle(*pStt, aPos);
2280 }
2281
2282 if (bFirst)
2283 bFirst = false;
2284
2285 // Jump to the previous paragraph and if needed, skip paragraphs of
2286 // the removed table(s) in the range to avoid leaving empty tables
2287 // because of the non-continuous redline range over the table.
2288 // FIXME: this is not enough for tables with inner redlines, where
2289 // tracked deletion of the text containing such a table leaves an
2290 // empty table at the place of the table (a problem inherited from OOo).
2291 pTextNd = nullptr;
2292 while( --aIdx > *pDelNd && !aIdx.GetNode().IsContentNode() )
2293 {
2294 // possible table end
2295 if( aIdx.GetNode().IsEndNode() && aIdx.GetNode().FindTableNode() )
2296 {
2297 SwNodeIndex aIdx2 = aIdx;
2298 // search table start and skip table paragraphs
2299 while ( pDelNd->GetIndex() < aIdx2.GetIndex() )
2300 {
2301 SwTableNode* pTable = aIdx2.GetNode().GetTableNode();
2302 if( pTable &&
2303 pTable->EndOfSectionNode()->GetIndex() == aIdx.GetIndex() )
2304 {
2305 aIdx = aIdx2;
2306 break;
2307 }
2308 --aIdx2;
2309 }
2310 }
2311 }
2312
2313 if (aIdx.GetNode().IsContentNode())
2314 pTextNd = aIdx.GetNode().GetContentNode();
2315 }
2316 }
2317
2318 // delete tables of the deletion explicitly, to avoid
2319 // remaining empty tables after accepting the rejection
2320 // and visible empty tables in Hide Changes mode
2321 // (this was the case, if tables have already contained
2322 // other tracked changes)
2323 // FIXME: because of recursive nature of AppendRedline,
2324 // this doesn't work for selections with multiple tables
2325 if ( m_rDoc.GetIDocumentUndoRedo().DoesUndo() )
2326 {
2327 SwNodeIndex aSttIdx( pStt->GetNode() );
2328 SwNodeIndex aEndIdx( pEnd->GetNode() );
2329 while ( aSttIdx < aEndIdx )
2330 {
2331 if ( aSttIdx.GetNode().IsTableNode() )
2332 {
2333 SvxPrintItem aNotTracked(RES_PRINT, false);
2334 SwCursor aCursor( SwPosition(aSttIdx), nullptr );
2335 m_rDoc.SetRowNotTracked( aCursor, aNotTracked, /*bAll=*/true );
2336 }
2337 ++aSttIdx;
2338 }
2339 }
2340 }
2341 bool const ret = maRedlineTable.Insert( pNewRedl );
2342 assert(ret || !pNewRedl);
2343 if (ret && !pNewRedl)
2344 {
2345 bMerged = true; // treat InsertWithValidRanges as "merge"
2346 }
2347 }
2348 }
2349
2350 if( bCompress )
2351 CompressRedlines(nStartPos);
2352
2353 CHECK_REDLINE( *this )
2354
2355 return (nullptr != pNewRedl)
2358}
2359
2361{
2362 // #TODO - equivalent for 'SwTableRowRedline'
2363 /*
2364 CHECK_REDLINE( this )
2365 */
2366
2368 {
2369 // #TODO - equivalent for 'SwTableRowRedline'
2370 /*
2371 pNewRedl->InvalidateRange();
2372 */
2373
2374 // Make equivalent of 'AppendRedline' checks inside here too
2375
2376 maExtraRedlineTable.Insert( pNewRedl );
2377 }
2378 else
2379 {
2380 // TO DO - equivalent for 'SwTableRowRedline'
2381 /*
2382 if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2383 {
2384 RedlineFlags eOld = meRedlineFlags;
2385 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2386 // The ShowMode needs to be retained!
2387 meRedlineFlags = eOld & ~(RedlineFlags::On | RedlineFlags::Ignore);
2388 DeleteAndJoin( *pNewRedl );
2389 meRedlineFlags = eOld;
2390 }
2391 delete pNewRedl, pNewRedl = 0;
2392 */
2393 }
2394 // #TODO - equivalent for 'SwTableRowRedline'
2395 /*
2396 CHECK_REDLINE( this )
2397 */
2398
2399 return nullptr != pNewRedl;
2400}
2401
2403{
2404 // #TODO - equivalent for 'SwTableCellRedline'
2405 /*
2406 CHECK_REDLINE( this )
2407 */
2408
2410 {
2411 // #TODO - equivalent for 'SwTableCellRedline'
2412 /*
2413 pNewRedl->InvalidateRange();
2414 */
2415
2416 // Make equivalent of 'AppendRedline' checks inside here too
2417
2418 maExtraRedlineTable.Insert( pNewRedl );
2419 }
2420 else
2421 {
2422 // TO DO - equivalent for 'SwTableCellRedline'
2423 /*
2424 if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2425 {
2426 RedlineFlags eOld = meRedlineFlags;
2427 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2428 // The ShowMode needs to be retained!
2429 meRedlineFlags = eOld & ~(RedlineFlags::On | RedlineFlags::Ignore);
2430 DeleteAndJoin( *pNewRedl );
2431 meRedlineFlags = eOld;
2432 }
2433 delete pNewRedl, pNewRedl = 0;
2434 */
2435 }
2436 // #TODO - equivalent for 'SwTableCellRedline'
2437 /*
2438 CHECK_REDLINE( this )
2439 */
2440
2441 return nullptr != pNewRedl;
2442}
2443
2445{
2446 CHECK_REDLINE( *this )
2447
2448 void (SwRangeRedline::*pFnc)(sal_uInt16, size_t, bool) = nullptr;
2451 pFnc = &SwRangeRedline::Show;
2452 else if (eShow == RedlineFlags::ShowInsert)
2453 pFnc = &SwRangeRedline::Hide;
2454
2455 // Try to merge identical ones
2456 if (nStartIndex == 0)
2457 nStartIndex = 1;
2458 for( SwRedlineTable::size_type n = nStartIndex; n < maRedlineTable.size(); ++n )
2459 {
2460 SwRangeRedline* pPrev = maRedlineTable[ n-1 ],
2461 * pCur = maRedlineTable[ n ];
2462 auto [pPrevStt,pPrevEnd] = pPrev->StartEnd();
2463 auto [pCurStt, pCurEnd] = pCur->StartEnd();
2464
2465 if( *pPrevEnd == *pCurStt && pPrev->CanCombine( *pCur ) &&
2466 pPrevStt->GetNode().StartOfSectionNode() ==
2467 pCurEnd->GetNode().StartOfSectionNode() &&
2468 !pCurEnd->GetNode().StartOfSectionNode()->IsTableNode() )
2469 {
2470 // we then can merge them
2471 SwRedlineTable::size_type nPrevIndex = n-1;
2472 pPrev->Show(0, nPrevIndex);
2473 pCur->Show(0, n);
2474
2475 pPrev->SetEnd( *pCur->End() );
2477 --n;
2478 if( pFnc )
2479 (pPrev->*pFnc)(0, nPrevIndex, false);
2480 }
2481 }
2482 CHECK_REDLINE( *this )
2483
2484 // #TODO - add 'SwExtraRedlineTable' also ?
2485}
2486
2488{
2489 bool bChg = false;
2490 auto [pStt, pEnd] = rRange.StartEnd(); // SwPosition*
2492 //FIXME overlapping problem GetRedline( *pStt, &n );
2493 for ( ; n < maRedlineTable.size(); ++n)
2494 {
2495 SwRangeRedline * pRedline = maRedlineTable[ n ];
2496 auto [pRedlineStart, pRedlineEnd] = pRedline->StartEnd();
2497 if (*pRedlineStart <= *pStt && *pEnd <= *pRedlineEnd)
2498 {
2499 bChg = true;
2500 int nn = 0;
2501 if (*pStt == *pRedlineStart)
2502 nn += 1;
2503 if (*pEnd == *pRedlineEnd)
2504 nn += 2;
2505
2506 SwRangeRedline* pNew = nullptr;
2507 switch( nn )
2508 {
2509 case 0:
2510 pNew = new SwRangeRedline( *pRedline );
2511 pRedline->SetEnd( *pStt, pRedlineEnd );
2512 pNew->SetStart( *pEnd );
2513 break;
2514
2515 case 1:
2516 *pRedlineStart = *pEnd;
2517 break;
2518
2519 case 2:
2520 *pRedlineEnd = *pStt;
2521 break;
2522
2523 case 3:
2526 pRedline = nullptr;
2527 break;
2528 }
2529 if (pRedline && !pRedline->HasValidRange())
2530 {
2531 // re-insert
2533 maRedlineTable.Insert( pRedline, n );
2534 }
2535 if( pNew )
2536 maRedlineTable.Insert( pNew, n );
2537 }
2538 else if (*pEnd < *pRedlineStart)
2539 break;
2540 }
2541 return bChg;
2542
2543 // #TODO - add 'SwExtraRedlineTable' also ?
2544}
2545
2546bool DocumentRedlineManager::DeleteRedline( const SwPaM& rRange, bool bSaveInUndo,
2547 RedlineType nDelType )
2548{
2549 if( !rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() )
2550 return false;
2551
2552 bool bChg = false;
2553
2554 if (bSaveInUndo && m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2555 {
2556 std::unique_ptr<SwUndoRedline> pUndo(new SwUndoRedline( SwUndoId::REDLINE, rRange ));
2557 if( pUndo->GetRedlSaveCount() )
2558 {
2559 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2560 }
2561 }
2562
2563 auto [pStt, pEnd] = rRange.StartEnd(); // SwPosition*
2565 GetRedline( *pStt, &n );
2566 for( ; n < maRedlineTable.size() ; ++n )
2567 {
2568 SwRangeRedline* pRedl = maRedlineTable[ n ];
2569 if( RedlineType::Any != nDelType && nDelType != pRedl->GetType() )
2570 continue;
2571
2572 auto [pRStt, pREnd] = pRedl->StartEnd(); // SwPosition*
2573 switch( ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ) )
2574 {
2579 bChg = true;
2580 break;
2581
2584 pRedl->SetStart( *pEnd, pRStt );
2586 // re-insert
2588 maRedlineTable.Insert( pRedl );
2589 --n;
2590 break;
2591
2594 pRedl->SetEnd( *pStt, pREnd );
2596 if( !pRedl->HasValidRange() )
2597 {
2598 // re-insert
2600 maRedlineTable.Insert( pRedl );
2601 --n;
2602 }
2603 break;
2604
2606 {
2607 // this one needs to be split
2609 if( *pRStt == *pStt )
2610 {
2611 pRedl->SetStart( *pEnd, pRStt );
2613 // re-insert
2615 maRedlineTable.Insert( pRedl );
2616 --n;
2617 }
2618 else
2619 {
2620 SwRangeRedline* pCpy;
2621 if( *pREnd != *pEnd )
2622 {
2623 pCpy = new SwRangeRedline( *pRedl );
2624 pCpy->SetStart( *pEnd );
2626 }
2627 else
2628 pCpy = nullptr;
2629 pRedl->SetEnd( *pStt, pREnd );
2631 if( !pRedl->HasValidRange() )
2632 {
2633 // re-insert
2635 maRedlineTable.Insert( pRedl );
2636 --n;
2637 }
2638 if( pCpy )
2639 maRedlineTable.Insert( pCpy );
2640 }
2641 }
2642 break;
2643
2645 // remove (not hidden) empty redlines created for fixing tdf#119571
2646 // (Note: hidden redlines are all empty, i.e. start and end are equal.)
2647 if ( pRedl->HasMark() && *pRedl->GetMark() == *pRedl->GetPoint() )
2648 {
2651 bChg = true;
2652 break;
2653 }
2654 [[fallthrough]];
2655
2657 n = maRedlineTable.size();
2658 break;
2659 default:
2660 break;
2661 }
2662 }
2663
2664 if( bChg )
2666
2667 return bChg;
2668
2669 // #TODO - add 'SwExtraRedlineTable' also ?
2670}
2671
2672bool DocumentRedlineManager::DeleteRedline( const SwStartNode& rNode, bool bSaveInUndo,
2673 RedlineType nDelType )
2674{
2675 SwPaM aTemp(*rNode.EndOfSectionNode(), rNode);
2676 return DeleteRedline(aTemp, bSaveInUndo, nDelType);
2677}
2678
2680{
2681 const SwNodeOffset nNdIdx = rNd.GetIndex();
2682 // if the table only contains good (i.e. non-overlapping) data, we can do a binary search
2684 {
2685 // binary search to the first redline with end >= the needle
2686 auto it = std::lower_bound(maRedlineTable.begin(), maRedlineTable.end(), rNd,
2687 [&nNdIdx](const SwRangeRedline* lhs, const SwNode& /*rhs*/)
2688 {
2689 return lhs->End()->GetNodeIndex() < nNdIdx;
2690 });
2691 for( ; it != maRedlineTable.end(); ++it)
2692 {
2693 const SwRangeRedline* pTmp = *it;
2694 auto [pStart, pEnd] = pTmp->StartEnd(); // SwPosition*
2695 SwNodeOffset nStart = pStart->GetNodeIndex(),
2696 nEnd = pEnd->GetNodeIndex();
2697
2698 if( ( RedlineType::Any == nType || nType == pTmp->GetType()) &&
2699 nStart <= nNdIdx && nNdIdx <= nEnd )
2700 return std::distance(maRedlineTable.begin(), it);
2701
2702 if( nStart > nNdIdx )
2703 break;
2704 }
2705 }
2706 else
2707 {
2708 for( SwRedlineTable::size_type n = 0; n < maRedlineTable.size() ; ++n )
2709 {
2710 const SwRangeRedline* pTmp = maRedlineTable[ n ];
2711 SwNodeOffset nPt = pTmp->GetPoint()->GetNodeIndex(),
2712 nMk = pTmp->GetMark()->GetNodeIndex();
2713 if( nPt < nMk )
2714 std::swap( nMk, nPt );
2715
2716 if( ( RedlineType::Any == nType || nType == pTmp->GetType()) &&
2717 nMk <= nNdIdx && nNdIdx <= nPt )
2718 return n;
2719
2720 if( nMk > nNdIdx )
2721 break;
2722 }
2723 }
2724 return SwRedlineTable::npos;
2725
2726 // #TODO - add 'SwExtraRedlineTable' also ?
2727}
2728
2729bool DocumentRedlineManager::HasRedline( const SwPaM& rPam, RedlineType nType, bool bStartOrEndInRange ) const
2730{
2731 SwPosition currentStart(*rPam.Start());
2732 SwPosition currentEnd(*rPam.End());
2733 const SwNode& rEndNode(currentEnd.GetNode());
2734
2736 n < maRedlineTable.size(); ++n )
2737 {
2738 const SwRangeRedline* pTmp = maRedlineTable[ n ];
2739
2740 if ( pTmp->Start()->GetNode() > rEndNode )
2741 break;
2742
2743 if( RedlineType::Any != nType && nType != pTmp->GetType() )
2744 continue;
2745
2746 // redline over the range
2747 if ( currentStart < *pTmp->End() && *pTmp->Start() <= currentEnd &&
2748 // starting or ending within the range
2749 ( !bStartOrEndInRange ||
2750 ( currentStart < *pTmp->Start() || *pTmp->End() < currentEnd ) ) )
2751 {
2752 return true;
2753 }
2754 }
2755 return false;
2756}
2757
2759 SwRedlineTable::size_type* pFndPos ) const
2760{
2762 if( nO > 0 )
2763 {
2764 nO--;
2765 while( nU <= nO )
2766 {
2767 nM = nU + ( nO - nU ) / 2;
2768 const SwRangeRedline* pRedl = maRedlineTable[ nM ];
2769 auto [pStt, pEnd] = pRedl->StartEnd();
2770 if( pEnd == pStt
2771 ? *pStt == rPos
2772 : ( *pStt <= rPos && rPos < *pEnd ) )
2773 {
2774 while( nM && rPos == *maRedlineTable[ nM - 1 ]->End() &&
2775 rPos == *maRedlineTable[ nM - 1 ]->Start() )
2776 {
2777 --nM;
2778 pRedl = maRedlineTable[ nM ];
2779 }
2780 // if there are format and insert changes in the same position
2781 // show insert change first.
2782 // since the redlines are sorted by position, only check the redline
2783 // before and after the current redline
2784 if( RedlineType::Format == pRedl->GetType() )
2785 {
2786 if( nM && rPos >= *maRedlineTable[ nM - 1 ]->Start() &&
2787 rPos <= *maRedlineTable[ nM - 1 ]->End() &&
2788 ( RedlineType::Insert == maRedlineTable[ nM - 1 ]->GetType() ) )
2789 {
2790 --nM;
2791 pRedl = maRedlineTable[ nM ];
2792 }
2793 else if( ( nM + 1 ) <= nO && rPos >= *maRedlineTable[ nM + 1 ]->Start() &&
2794 rPos <= *maRedlineTable[ nM + 1 ]->End() &&
2795 ( RedlineType::Insert == maRedlineTable[ nM + 1 ]->GetType() ) )
2796 {
2797 ++nM;
2798 pRedl = maRedlineTable[ nM ];
2799 }
2800 }
2801
2802 if( pFndPos )
2803 *pFndPos = nM;
2804 return pRedl;
2805 }
2806 else if( *pEnd <= rPos )
2807 nU = nM + 1;
2808 else if( nM == 0 )
2809 {
2810 if( pFndPos )
2811 *pFndPos = nU;
2812 return nullptr;
2813 }
2814 else
2815 nO = nM - 1;
2816 }
2817 }
2818 if( pFndPos )
2819 *pFndPos = nU;
2820 return nullptr;
2821
2822 // #TODO - add 'SwExtraRedlineTable' also ?
2823}
2824
2826{
2827 bool bRet = false;
2828
2829 // Switch to visible in any case
2833
2835 pTmp->Show(0, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
2836 pTmp->Show(1, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
2837 if( pTmp->HasMark() && pTmp->IsVisible() )
2838 {
2839 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2840 {
2841 SwRewriter aRewriter;
2842
2843 aRewriter.AddRule(UndoArg1, pTmp->GetDescr());
2844 m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::ACCEPT_REDLINE, &aRewriter);
2845 }
2846
2847 int nLoopCnt = 2;
2848 sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2849
2850 do {
2851
2852 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2853 {
2854 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
2855 std::make_unique<SwUndoAcceptRedline>(*pTmp) );
2856 }
2857
2858 bRet |= lcl_AcceptRedline( maRedlineTable, nPos, bCallDelete );
2859
2860 if( nSeqNo )
2861 {
2862 if( SwRedlineTable::npos == nPos )
2863 nPos = 0;
2864 SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
2865 ? maRedlineTable.FindNextSeqNo( nSeqNo, nPos )
2866 : maRedlineTable.FindPrevSeqNo( nSeqNo, nPos );
2867 if( SwRedlineTable::npos != nFndPos || ( 0 != ( --nLoopCnt ) &&
2868 SwRedlineTable::npos != ( nFndPos =
2869 maRedlineTable.FindPrevSeqNo( nSeqNo, nPos ))) )
2870 {
2871 nPos = nFndPos;
2872 pTmp = maRedlineTable[ nPos ];
2873 }
2874 else
2875 nLoopCnt = 0;
2876 }
2877 else
2878 nLoopCnt = 0;
2879
2880 } while( nLoopCnt );
2881
2882 if( bRet )
2883 {
2886 }
2887
2888 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2889 {
2890 m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
2891 }
2892 }
2893 return bRet;
2894
2895 // #TODO - add 'SwExtraRedlineTable' also ?
2896}
2897
2898bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool bCallDelete )
2899{
2900 // Switch to visible in any case
2904
2905 // The Selection is only in the ContentSection. If there are Redlines
2906 // to Non-ContentNodes before or after that, then the Selections
2907 // expand to them.
2908 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2909 lcl_AdjustRedlineRange( aPam );
2910
2911 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2912 {
2914 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAcceptRedline>( aPam ));
2915 }
2916
2917 int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, maRedlineTable,
2918 bCallDelete, aPam );
2919 if( nRet > 0 )
2920 {
2923 }
2924 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2925 {
2926 OUString aTmpStr;
2927
2928 {
2929 SwRewriter aRewriter;
2930 aRewriter.AddRule(UndoArg1, OUString::number(nRet));
2931 aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
2932 }
2933
2934 SwRewriter aRewriter;
2935 aRewriter.AddRule(UndoArg1, aTmpStr);
2936
2937 m_rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::ACCEPT_REDLINE, &aRewriter );
2938 }
2939 return nRet != 0;
2940
2941 // #TODO - add 'SwExtraRedlineTable' also ?
2942}
2943
2945{
2946 auto [pStt, pEnd] = rPam.StartEnd(); // SwPosition*
2947
2948 const SwNodeOffset nSttIdx = pStt->GetNodeIndex();
2949 const SwNodeOffset nEndIdx = pEnd->GetNodeIndex();
2950
2951 for( SwRedlineTable::size_type n = 0; n < maRedlineTable.size() ; ++n )
2952 {
2953 const SwRangeRedline* pTmp = maRedlineTable[ n ];
2954 SwNodeOffset nPt = pTmp->GetPoint()->GetNodeIndex(),
2955 nMk = pTmp->GetMark()->GetNodeIndex();
2956 if( nPt < nMk )
2957 std::swap( nMk, nPt );
2958
2959 if( RedlineType::ParagraphFormat == pTmp->GetType() &&
2960 ( (nSttIdx <= nMk && nMk <= nEndIdx) || (nSttIdx <= nPt && nPt <= nEndIdx) ) )
2961 AcceptRedline( n, false );
2962
2963 if( nMk > nEndIdx )
2964 break;
2965 }
2966}
2967
2969{
2970 bool bRet = false;
2971
2972 // Switch to visible in any case
2976
2978 pTmp->Show(0, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
2979 pTmp->Show(1, maRedlineTable.GetPos(pTmp), /*bForced=*/true);
2980 if( pTmp->HasMark() && pTmp->IsVisible() )
2981 {
2982 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2983 {
2984 SwRewriter aRewriter;
2985
2986 aRewriter.AddRule(UndoArg1, pTmp->GetDescr());
2987 m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::REJECT_REDLINE, &aRewriter);
2988 }
2989
2990 int nLoopCnt = 2;
2991 sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2992
2993 do {
2994
2995 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2996 {
2997 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
2998 std::make_unique<SwUndoRejectRedline>( *pTmp ) );
2999 }
3000
3001 bRet |= lcl_RejectRedline( maRedlineTable, nPos, bCallDelete );
3002
3003 if( nSeqNo )
3004 {
3005 if( SwRedlineTable::npos == nPos )
3006 nPos = 0;
3007 SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
3008 ? maRedlineTable.FindNextSeqNo( nSeqNo, nPos )
3009 : maRedlineTable.FindPrevSeqNo( nSeqNo, nPos );
3010 if( SwRedlineTable::npos != nFndPos || ( 0 != ( --nLoopCnt ) &&
3011 SwRedlineTable::npos != ( nFndPos =
3012 maRedlineTable.FindPrevSeqNo( nSeqNo, nPos ))) )
3013 {
3014 nPos = nFndPos;
3015 pTmp = maRedlineTable[ nPos ];
3016 }
3017 else
3018 nLoopCnt = 0;
3019 }
3020 else
3021 nLoopCnt = 0;
3022
3023 } while( nLoopCnt );
3024
3025 if( bRet )
3026 {
3029 }
3030
3031 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3032 {
3033 m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
3034 }
3035 }
3036 return bRet;
3037
3038 // #TODO - add 'SwExtraRedlineTable' also ?
3039}
3040
3041bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool bCallDelete )
3042{
3043 // Switch to visible in any case
3047
3048 // The Selection is only in the ContentSection. If there are Redlines
3049 // to Non-ContentNodes before or after that, then the Selections
3050 // expand to them.
3051 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
3052 lcl_AdjustRedlineRange( aPam );
3053
3054 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3055 {
3057 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoRejectRedline>(aPam) );
3058 }
3059
3060 int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, maRedlineTable,
3061 bCallDelete, aPam );
3062 if( nRet > 0 )
3063 {
3066 }
3067 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
3068 {
3069 OUString aTmpStr;
3070
3071 {
3072 SwRewriter aRewriter;
3073 aRewriter.AddRule(UndoArg1, OUString::number(nRet));
3074 aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
3075 }
3076
3077 SwRewriter aRewriter;
3078 aRewriter.AddRule(UndoArg1, aTmpStr);
3079
3080 m_rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::REJECT_REDLINE, &aRewriter );
3081 }
3082
3083 return nRet != 0;
3084
3085 // #TODO - add 'SwExtraRedlineTable' also ?
3086}
3087
3089{
3090 bool bSuccess = true;
3091 OUString sUndoStr;
3092 IDocumentUndoRedo& rUndoMgr = m_rDoc.GetIDocumentUndoRedo();
3093
3094 if (maRedlineTable.size() > 1)
3095 {
3096 {
3097 SwRewriter aRewriter;
3098 aRewriter.AddRule(UndoArg1, OUString::number(maRedlineTable.size()));
3099 sUndoStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
3100 }
3101
3102 SwRewriter aRewriter;
3103 aRewriter.AddRule(UndoArg1, sUndoStr);
3104 rUndoMgr.StartUndo(bAccept ? SwUndoId::ACCEPT_REDLINE : SwUndoId::REJECT_REDLINE, &aRewriter);
3105 }
3106
3107 while (!maRedlineTable.empty() && bSuccess)
3108 {
3109 if (bAccept)
3110 bSuccess = AcceptRedline(maRedlineTable.size() - 1, true);
3111 else
3112 bSuccess = RejectRedline(maRedlineTable.size() - 1, true);
3113 }
3114
3115 if (!sUndoStr.isEmpty())
3116 {
3117 rUndoMgr.EndUndo(SwUndoId::EMPTY, nullptr);
3118 }
3119}
3120
3122{
3123 rPam.DeleteMark();
3124 rPam.SetMark();
3125
3126 SwPosition& rSttPos = *rPam.GetPoint();
3127 SwPosition aSavePos( rSttPos );
3128 bool bRestart;
3129
3130 // If the starting position points to the last valid ContentNode,
3131 // we take the next Redline in any case.
3133 const SwRangeRedline* pFnd = GetRedlineTable().FindAtPosition( rSttPos, n );
3134 if( pFnd )
3135 {
3136 const SwPosition* pEnd = pFnd->End();
3137 if( !pEnd->GetNode().IsContentNode() )
3138 {
3139 SwNodeIndex aTmp( pEnd->GetNode() );
3140 SwContentNode* pCNd = SwNodes::GoPrevSection( &aTmp );
3141 if( !pCNd || ( aTmp == rSttPos.GetNode() &&
3142 pCNd->Len() == rSttPos.GetContentIndex() ))
3143 pFnd = nullptr;
3144 }
3145 if( pFnd )
3146 rSttPos = *pFnd->End();
3147 }
3148
3149 do {
3150 bRestart = false;
3151
3152 for( ; !pFnd && n < maRedlineTable.size(); ++n )
3153 {
3154 pFnd = maRedlineTable[ n ];
3155 if( pFnd->HasMark() && pFnd->IsVisible() )
3156 {
3157 *rPam.GetMark() = *pFnd->Start();
3158 rSttPos = *pFnd->End();
3159 break;
3160 }
3161 else
3162 pFnd = nullptr;
3163 }
3164
3165 if( pFnd )
3166 {
3167 // Merge all of the same type and author that are
3168 // consecutive into one Selection.
3169 const SwPosition* pPrevEnd = pFnd->End();
3170 while( ++n < maRedlineTable.size() )
3171 {
3172 const SwRangeRedline* pTmp = maRedlineTable[ n ];
3173 if( pTmp->HasMark() && pTmp->IsVisible() )
3174 {
3175 const SwPosition *pRStt;
3176 if( pFnd->GetType() != pTmp->GetType() ||
3177 pFnd->GetAuthor() != pTmp->GetAuthor() )
3178 break;
3179 pRStt = pTmp->Start();
3180 if( *pPrevEnd == *pRStt || IsPrevPos( *pPrevEnd, *pRStt ) )
3181 {
3182 pPrevEnd = pTmp->End();
3183 rSttPos = *pPrevEnd;
3184 }
3185 else
3186 break;
3187 }
3188 }
3189 }
3190
3191 if( pFnd )
3192 {
3193 const SwRangeRedline* pSaveFnd = pFnd;
3194
3195 SwContentNode* pCNd;
3196 SwPosition* pPos = rPam.GetMark();
3197 if( !pPos->GetNode().IsContentNode() )
3198 {
3199 pCNd = m_rDoc.GetNodes().GoNextSection( pPos );
3200 if( pCNd )
3201 {
3202 if( pPos->GetNode() <= rPam.GetPoint()->GetNode() )
3203 pPos->Assign( *pCNd, 0 );
3204 else
3205 pFnd = nullptr;
3206 }
3207 }
3208
3209 if( pFnd )
3210 {
3211 pPos = rPam.GetPoint();
3212 if( !pPos->GetNode().IsContentNode() )
3213 {
3214 pCNd = SwNodes::GoPrevSection( pPos );
3215 if( pCNd )
3216 {
3217 if( pPos->GetNode() >= rPam.GetMark()->GetNode() )
3218 pPos->Assign( *pCNd, pCNd->Len() );
3219 else
3220 pFnd = nullptr;
3221 }
3222 }
3223 }
3224
3225 if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
3226 {
3227 if( n < maRedlineTable.size() )
3228 {
3229 bRestart = true;
3230 *rPam.GetPoint() = *pSaveFnd->End();
3231 }
3232 else
3233 {
3234 rPam.DeleteMark();
3235 *rPam.GetPoint() = aSavePos;
3236 }
3237 pFnd = nullptr;
3238 }
3239 }
3240 } while( bRestart );
3241
3242 return pFnd;
3243
3244 // #TODO - add 'SwExtraRedlineTable' also ?
3245}
3246
3248{
3249 rPam.DeleteMark();
3250 rPam.SetMark();
3251
3252 SwPosition& rSttPos = *rPam.GetPoint();
3253 SwPosition aSavePos( rSttPos );
3254 bool bRestart;
3255
3256 // If the starting position points to the last valid ContentNode,
3257 // we take the previous Redline in any case.
3259 const SwRangeRedline* pFnd = GetRedlineTable().FindAtPosition( rSttPos, n, false );
3260 if( pFnd )
3261 {
3262 const SwPosition* pStt = pFnd->Start();
3263 if( !pStt->GetNode().IsContentNode() )
3264 {
3265 SwNodeIndex aTmp( pStt->GetNode() );
3266 SwContentNode* pCNd = m_rDoc.GetNodes().GoNextSection( &aTmp );
3267 if( !pCNd || ( aTmp == rSttPos.GetNode() &&
3268 !rSttPos.GetContentIndex() ))
3269 pFnd = nullptr;
3270 }
3271 if( pFnd )
3272 rSttPos = *pFnd->Start();
3273 }
3274
3275 do {
3276 bRestart = false;
3277
3278 while( !pFnd && 0 < n )
3279 {
3280 pFnd = maRedlineTable[ --n ];
3281 if( pFnd->HasMark() && pFnd->IsVisible() )
3282 {
3283 *rPam.GetMark() = *pFnd->End();
3284 rSttPos = *pFnd->Start();
3285 }
3286 else
3287 pFnd = nullptr;
3288 }
3289
3290 if( pFnd )
3291 {
3292 // Merge all of the same type and author that are
3293 // consecutive into one Selection.
3294 const SwPosition* pNextStt = pFnd->Start();
3295 while( 0 < n )
3296 {
3297 const SwRangeRedline* pTmp = maRedlineTable[ --n ];
3298 if( pTmp->HasMark() && pTmp->IsVisible() )
3299 {
3300 const SwPosition *pREnd;
3301 if( pFnd->GetType() == pTmp->GetType() &&
3302 pFnd->GetAuthor() == pTmp->GetAuthor() &&
3303 ( *pNextStt == *( pREnd = pTmp->End() ) ||
3304 IsPrevPos( *pREnd, *pNextStt )) )
3305 {
3306 pNextStt = pTmp->Start();
3307 rSttPos = *pNextStt;
3308 }
3309 else
3310 {
3311 ++n;
3312 break;
3313 }
3314 }
3315 }
3316 }
3317
3318 if( pFnd )
3319 {
3320 const SwRangeRedline* pSaveFnd = pFnd;
3321
3322 SwContentNode* pCNd;
3323 SwPosition* pPos = rPam.GetMark();
3324 if( !pPos->GetNode().IsContentNode() )
3325 {
3326 pCNd = SwNodes::GoPrevSection( pPos );
3327 if( pCNd )
3328 {
3329 if( pPos->GetNode() >= rPam.GetPoint()->GetNode() )
3330 pPos->Assign( *pCNd, pCNd->Len() );
3331 else
3332 pFnd = nullptr;
3333 }
3334 }
3335
3336 if( pFnd )
3337 {
3338 pPos = rPam.GetPoint();
3339 if( !pPos->GetNode().IsContentNode() )
3340 {
3341 pCNd = m_rDoc.GetNodes().GoNextSection( pPos );
3342 if( pCNd )
3343 {
3344 if( pPos->GetNode() <= rPam.GetMark()->GetNode() )
3345 pPos->Assign( *pCNd, 0 );
3346 else
3347 pFnd = nullptr;
3348 }
3349 }
3350 }
3351
3352 if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
3353 {
3354 if( n )
3355 {
3356 bRestart = true;
3357 *rPam.GetPoint() = *pSaveFnd->Start();
3358 }
3359 else
3360 {
3361 rPam.DeleteMark();
3362 *rPam.GetPoint() = aSavePos;
3363 }
3364 pFnd = nullptr;
3365 }
3366 }
3367 } while( bRestart );
3368
3369 return pFnd;
3370
3371 // #TODO - add 'SwExtraRedlineTable' also ?
3372}
3373
3374// Set comment at the Redline
3375bool DocumentRedlineManager::SetRedlineComment( const SwPaM& rPaM, const OUString& rS )
3376{
3377 bool bRet = false;
3378 auto [pStt, pEnd] = rPaM.StartEnd(); // SwPosition*
3380 if( GetRedlineTable().FindAtPosition( *pStt, n ) )
3381 {
3382 for( ; n < maRedlineTable.size(); ++n )
3383 {
3384 bRet = true;
3385 SwRangeRedline* pTmp = maRedlineTable[ n ];
3386 if( pStt != pEnd && *pTmp->Start() > *pEnd )
3387 break;
3388
3389 pTmp->SetComment( rS );
3390 if( *pTmp->End() >= *pEnd )
3391 break;
3392 }
3393 }
3394 if( bRet )
3396
3397 return bRet;
3398
3399 // #TODO - add 'SwExtraRedlineTable' also ?
3400}
3401
3402// Create a new author if necessary
3404{
3405 return SW_MOD()->GetRedlineAuthor();
3406}
3407
3409std::size_t DocumentRedlineManager::InsertRedlineAuthor( const OUString& rNew )
3410{
3411 return SW_MOD()->InsertRedlineAuthor(rNew);
3412}
3413
3415{
3416 const SwRedlineTable& rTable = GetRedlineTable();
3417 for(SwRangeRedline* pRedl : rTable)
3418 {
3419 if( pRedl->IsVisible() )
3421 }
3422
3423 // #TODO - add 'SwExtraRedlineTable' also ?
3424}
3425
3426const uno::Sequence <sal_Int8>& DocumentRedlineManager::GetRedlinePassword() const
3427{
3428 return maRedlinePasswd;
3429}
3430
3432 /*[in]*/const uno::Sequence <sal_Int8>& rNewPassword)
3433{
3434 maRedlinePasswd = rNewPassword;
3436}
3437
3442void DocumentRedlineManager::SetAutoFormatRedlineComment( const OUString* pText, sal_uInt16 nSeqNo )
3443{
3444 m_rDoc.SetAutoFormatRedline( nullptr != pText );
3445 if( pText )
3446 {
3447 moAutoFormatRedlnComment = *pText;
3448 }
3449 else
3450 {
3452 }
3453
3455}
3456
3458{
3459 const SwRedlineTable& rTable = GetRedlineTable();
3460 for (SwRedlineTable::size_type i = rTable.size(); i > 0; --i)
3461 {
3462 SwRangeRedline* pRedline = rTable[i-1];
3463 if ( pRedline->GetType() == RedlineType::Delete )
3464 {
3465 if ( bDeletion && pRedline->IsVisible() )
3466 {
3467 pRedline->Hide(0, rTable.GetPos(pRedline), false);
3468 pRedline->Hide(1, rTable.GetPos(pRedline), false);
3469 }
3470 else if ( !bDeletion && !pRedline->IsVisible() )
3471 {
3472 pRedline->Show(0, rTable.GetPos(pRedline), true);
3473 pRedline->Show(1, rTable.GetPos(pRedline), true);
3474 }
3475 }
3476 else if ( pRedline->GetType() == RedlineType::Insert )
3477 {
3478 if ( !bDeletion && pRedline->IsVisible() )
3479 {
3480 pRedline->ShowOriginal(0, rTable.GetPos(pRedline), false);
3481 pRedline->ShowOriginal(1, rTable.GetPos(pRedline), false);
3482 }
3483 else if ( bDeletion && !pRedline->IsVisible() )
3484 {
3485 pRedline->Show(0, rTable.GetPos(pRedline), true);
3486 pRedline->Show(1, rTable.GetPos(pRedline), true);
3487 }
3488 }
3489 }
3490}
3491
3493{
3494 const SwRedlineTable& rTable = GetRedlineTable();
3495 for (SwRedlineTable::size_type i = rTable.size(); i > 0; --i)
3496 {
3497 SwRangeRedline* pRedline = rTable[i-1];
3498 if ( !pRedline->IsVisible() )
3499 {
3500 pRedline->Show(0, rTable.GetPos(pRedline), true);
3501 pRedline->Show(1, rTable.GetPos(pRedline), true);
3502 }
3503 }
3504}
3505
3507{
3508}
3509
3510}
3511
3512/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define ERROR_PREFIX
#define CHECK_REDLINE(pDoc)
@ ShowDelete
show all deletes
@ On
RedlineFlags on.
@ ShowInsert
show all inserts
@ Ignore
ignore Redlines
@ UndoArg1
Definition: SwRewriter.hxx:29
virtual bool DeleteAndJoin(SwPaM &, SwDeleteFlags flags=SwDeleteFlags::Default)=0
complete delete of a given PaM
virtual void DeleteRange(SwPaM &)=0
Delete a range SwFlyFrameFormat.
virtual bool DelFullPara(SwPaM &)=0
Delete full paragraphs.
virtual void InsertItemSet(const SwPaM &rRg, const SfxItemSet &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr)=0
Document fields related interfaces.
virtual SwFieldType * GetSysFieldType(const SwFieldIds eWhich) const =0
virtual SwFieldType * GetFieldType(SwFieldIds nResId, const OUString &rName, bool bDbFieldMatching) const =0
virtual void UpdateRefFields()=0
virtual void UpdateExpFields(SwTextField *pField, bool bUpdateRefFields)=0
virtual const SwRootFrame * GetCurrentLayout() const =0
virtual bool IsRedlineOn() const =0
Query if redlining is on.
static bool IsShowOriginal(const RedlineFlags eM)
virtual void SetRedlineFlags_intern(RedlineFlags eMode)=0
Set a new redline mode.
virtual const SwRedlineTable & GetRedlineTable() const =0
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const =0
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
static bool IsHideChanges(const RedlineFlags eM)
virtual void SetModified()=0
Must be called manually at changes of format.
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
virtual sal_Int32 Len() const
Definition: node.cxx:1258
Definition: doc.hxx:195
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:402
o3tl::sorted_vector< SwRootFrame * > GetAllLayouts()
Definition: doclay.cxx:1683
bool IsClipBoard() const
Definition: doc.hxx:974
bool IsAutoFormatRedline() const
Definition: doc.hxx:1459
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:323
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:152
SwNodes & GetNodes()
Definition: doc.hxx:420
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:365
void SetRowNotTracked(const SwCursor &rCursor, const SvxPrintItem &rNotTracked, bool bAll=false, bool bIns=false)
rNotTracked = false means that the row was deleted or inserted with its tracked cell content bAll: de...
Definition: ndtbl1.cxx:581
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:343
bool IsInXMLImport() const
Definition: doc.hxx:981
void DelNumRules(const SwPaM &, SwRootFrame const *pLayout=nullptr)
Definition: docnum.cxx:1316
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:413
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:645
void SetInXMLImport(bool bNew)
Definition: doc.hxx:982
void SetAutoFormatRedline(bool bFlag)
Definition: doc.hxx:1460
void ResetAttrs(const SwPaM &rRg, bool bTextAttr=true, const o3tl::sorted_vector< sal_uInt16 > &rAttrs=o3tl::sorted_vector< sal_uInt16 >(), const bool bSendDataChangedEvents=true, SwRootFrame const *pLayout=nullptr)
Reset attributes.
Definition: docfmt.cxx:243
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1331
void DeleteRow(const SwCursor &rCursor)
Deleting Columns/Rows.
Definition: ndtbl.cxx:1795
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:755
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter <bResetListAttrs>.
Definition: docfmt.cxx:1081
SwDocShell * GetDocShell()
Definition: doc.hxx:1364
Table that holds 'extra' redlines, such as 'table row insert/delete', 'paragraph moves' etc....
Definition: docary.hxx:282
void Insert(SwExtraRedline *p)
Definition: docredln.cxx:2069
virtual void UpdateFields()
Definition: fldbas.cxx:217
void UpdateFootnote(const SwNode &rStt)
Definition: ftnidx.cxx:59
const OUString & GetName() const
Definition: format.hxx:131
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
TElementType * Next()
Definition: calbck.hxx:380
TElementType * First()
Definition: calbck.hxx:372
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNode & GetNode() const
Definition: ndindex.hxx:123
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:111
Base class of the Writer document model elements.
Definition: node.hxx:98
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:903
SwSectionNode * GetSectionNode()
Definition: node.hxx:658
SwNodeOffset GetIndex() const
Definition: node.hxx:312
const SwStartNode * FindTableBoxStartNode() const
Definition: node.hxx:218
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:744
SwTableBox * GetTableBox() const
If node is in a table return the respective table box.
Definition: node.cxx:774
bool IsContentNode() const
Definition: node.hxx:679
bool IsEndNode() const
Definition: node.hxx:683
const SwStartNode * FindFlyStartNode() const
Definition: node.hxx:220
bool IsTableNode() const
Definition: node.hxx:691
bool IsTextNode() const
Definition: node.hxx:687
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:380
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:153
SwNodeOffset EndOfSectionIndex() const
Definition: node.hxx:728
SwContentNode * GetContentNode()
Definition: node.hxx:666
SwTableNode * GetTableNode()
Definition: node.hxx:650
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:733
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:165
SwNode & GetEndOfRedlines() const
Section for all Redlines.
Definition: ndarr.hxx:160
SwContentNode * GoNextSection(SwNodeIndex *, bool bSkipHidden=true, bool bSkipProtect=true) const
Go to next content-node that is not protected or hidden (Both set FALSE ==> GoNext/GoPrevious!...
Definition: nodes.cxx:1948
static SwContentNode * GoPrevSection(SwNodeIndex *, bool bSkipHidden=true, bool bSkipProtect=true)
Definition: nodes.cxx:2064
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:187
const SwPosition * GetMark() const
Definition: pam.hxx:263
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:642
bool ContainsPosition(const SwPosition &rPos) const
Definition: pam.hxx:313
std::pair< const SwPosition *, const SwPosition * > StartEnd() const
Because sometimes the cost of the operator<= can add up.
Definition: pam.hxx:277
const SwPosition * End() const
Definition: pam.hxx:271
SwDoc & GetDoc() const
Definition: pam.hxx:299
void DeleteMark()
Definition: pam.hxx:231
const SwPosition * GetPoint() const
Definition: pam.hxx:261
const SwPosition * Start() const
Definition: pam.hxx:266
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:259
void Show(sal_uInt16 nLoop, size_t nMyPos, bool bForced=false)
Definition: docredln.cxx:1256
void InvalidateRange(Invalidation)
Initiate the layout.
Definition: docredln.cxx:1389
void SetExtraData(const SwRedlineExtraData *pData)
ExtraData gets copied, the pointer is therefore not taken over by the RedLineObject.
Definition: redline.hxx:229
void SetSeqNo(sal_uInt16 nNo)
Definition: redline.hxx:238
sal_uInt16 GetStackCount() const
Definition: docredln.cxx:1917
std::size_t GetAuthor(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1925
const SwNodeIndex * GetContentIdx() const
Definition: redline.hxx:195
bool IsVisible() const
Definition: redline.hxx:200
void Hide(sal_uInt16 nLoop, size_t nMyPos, bool bForced=false)
Definition: docredln.cxx:1310
bool IsOwnRedline(const SwRangeRedline &rRedl) const
Definition: redline.hxx:256
const SwRedlineExtraData * GetExtraData() const
Definition: redline.hxx:231
void SetAutoFormat()
Definition: redline.hxx:212
OUString GetDescr(bool bSimplified=false)
Returns textual description of a redline data element of this redline.
Definition: docredln.cxx:1981
bool IsMoved() const
Definition: redline.hxx:282
void SetStart(const SwPosition &rPos, SwPosition *pSttPtr=nullptr)
Definition: docredln.cxx:1213
void SetEnd(const SwPosition &rPos, SwPosition *pEndPtr=nullptr)
Definition: docredln.cxx:1221
void ShowOriginal(sal_uInt16 nLoop, size_t nMyPos, bool bForced=false)
Definition: docredln.cxx:1346
bool HasValidRange() const
Do we have a valid selection?
Definition: docredln.cxx:1230
void PushData(const SwRangeRedline &rRedl, bool bOwnAsNext=true)
Definition: docredln.cxx:1891
void SetComment(const OUString &rS)
Definition: redline.hxx:225
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1940
bool CanCombine(const SwRangeRedline &rRedl) const
Definition: docredln.cxx:1885
const SwRedlineData & GetRedlineData(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1963
sal_uInt16 GetSeqNo() const
Definition: redline.hxx:237
bool IsAnonymized() const
Definition: redline.hxx:131
void SetFormatAll(bool bAll)
Definition: redline.hxx:69
virtual void Reject(SwPaM &rPam) const
Definition: docredln.cxx:864
size_type FindNextSeqNo(sal_uInt16 nSeqNo, size_type nSttPos) const
Search next or previous Redline with the same Seq.
Definition: docredln.cxx:686
size_type FindPrevSeqNo(sal_uInt16 nSeqNo, size_type nSttPos) const
Definition: docredln.cxx:709
bool empty() const
Definition: docary.hxx:266
vector_type::const_iterator end() const
Definition: docary.hxx:270
bool isMoved(size_type tableIndex) const
Definition: docredln.cxx:756
bool Insert(SwRangeRedline *&p)
Definition: docredln.cxx:415
void DeleteAndDestroy(size_type nPos)
Definition: docredln.cxx:663
static constexpr size_type npos
Definition: docary.hxx:223
size_type size() const
Definition: docary.hxx:267
vector_type::const_iterator begin() const
Definition: docary.hxx:269
void Remove(size_type nPos)
Definition: docredln.cxx:634
vector_type::size_type size_type
Definition: docary.hxx:222
bool HasOverlappingElements() const
Definition: docary.hxx:237
void Resort()
Definition: docary.hxx:271
size_type GetPos(const SwRangeRedline *p) const
Definition: docredln.cxx:618
const SwRangeRedline * FindAtPosition(const SwPosition &startPosition, size_type &tableIndex, bool next=true) const
Find the redline at the given position.
Definition: docredln.cxx:730
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:25
OUString Apply(const OUString &rStr) const
Definition: SwRewriter.cxx:39
The root element of a Writer document layout.
Definition: rootfrm.hxx:83
bool HasMergedParas() const
Definition: wsfrm.cxx:4757
A section node represents the start of a section on the UI, i.e.
Definition: node.hxx:575
Starts a section of nodes in the document model.
Definition: node.hxx:348
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:436
SwTableLine * GetUpper()
Definition: swtable.hxx:470
Redline that holds information about a table-cell that had some change.
Definition: redline.hxx:321
SwTableLine is one table row in the document model.
Definition: swtable.hxx:374
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:396
SwRedlineTable::size_type UpdateTextChangesOnly(SwRedlineTable::size_type &rRedlinePos, bool bUpdateProperty=true) const
Definition: swtable.cxx:1691
bool IsEmpty() const
Definition: swtable.cxx:1566
Redline that holds information about a table-row that had some change.
Definition: redline.hxx:300
Represents the style of a paragraph.
Definition: fmtcol.hxx:61
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:166
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:291
bool GetParaAttr(SfxItemSet &rSet, sal_Int32 nStt, sal_Int32 nEnd, const bool bOnlyTextAttr=false, const bool bGetFromChrFormat=true, const bool bMergeIndentValuesOfNumRule=false, SwRootFrame const *pLayout=nullptr) const
Query the attributes of textnode over the range.
Definition: thints.cxx:2140
SwNumRule * GetNumRule(bool bInParent=true) const
Returns numbering rule of this text node.
Definition: ndtxt.cxx:2919
const OUString & GetText() const
Definition: ndtxt.hxx:244
void AddToListRLHidden()
Definition: ndtxt.cxx:4505
void RemoveFromListRLHidden()
Definition: ndtxt.cxx:4547
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:897
std::pair< const_iterator, bool > insert(Value &&x)
css::uno::Sequence< sal_Int8 > maRedlinePasswd
virtual bool SplitRedline(const SwPaM &rPam) override
virtual RedlineFlags GetRedlineFlags() const override
Replaced by SwRootFrame::IsHideRedlines() (this is model-level redline hiding).
virtual AppendResult AppendRedline(SwRangeRedline *pPtr, bool bCallDelete) override
Append a new redline.
virtual bool IsRedlineMove() const override
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const override
virtual void SetRedlineFlags_intern(RedlineFlags eMode) override
Set a new redline mode.
virtual const SwRangeRedline * SelPrevRedline(SwPaM &rPam) const override
virtual void SetRedlineMove(bool bFlag) override
virtual bool IsRedlineOn() const override
Query if redlining is on.
virtual const SwRangeRedline * SelNextRedline(SwPaM &rPam) const override
void SetAutoFormatRedlineComment(const OUString *pText, sal_uInt16 nSeqNo=0)
Set comment-text for Redline.
virtual bool HasRedline(const SwPaM &rPam, RedlineType nType, bool bStartOrEndInRange) const override
virtual const SwRedlineTable & GetRedlineTable() const override
virtual bool AcceptRedline(SwRedlineTable::size_type nPos, bool bCallDelete) override
virtual void UpdateRedlineAttr() override
virtual void SetRedlineFlags(RedlineFlags eMode) override
Set a new redline mode.
std::optional< OUString > moAutoFormatRedlnComment
virtual void CompressRedlines(size_t nStartIdx=0) override
virtual std::size_t InsertRedlineAuthor(const OUString &rAuthor) override
Insert new author into the Table for the Readers etc.
sal_uInt16 mnAutoFormatRedlnCommentNo
SeqNo for conjoining of AutoFormat-Redlines.
virtual bool SetRedlineComment(const SwPaM &rPam, const OUString &rComment) override
virtual std::size_t GetRedlineAuthor() override
virtual void SetRedlinePassword(const css::uno::Sequence< sal_Int8 > &rNewPassword) override
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const override
virtual bool RejectRedline(SwRedlineTable::size_type nPos, bool bCallDelete) override
virtual const SwExtraRedlineTable & GetExtraRedlineTable() const override
virtual const css::uno::Sequence< sal_Int8 > & GetRedlinePassword() const override
virtual bool IsInRedlines(const SwNode &rNode) const override
virtual bool DeleteRedline(const SwPaM &rPam, bool bSaveInUndo, RedlineType nDelType) override
virtual bool AppendTableCellRedline(SwTableCellRedline *pPtr) override
virtual void AcceptRedlineParagraphFormatting(const SwPaM &rPam) override
virtual bool AppendTableRowRedline(SwTableRowRedline *pPtr) override
virtual void AcceptAllRedline(bool bAcceptReject) override
virtual bool IsIgnoreRedline() const override
RedlineType
int nCount
SwDoc & m_rDoc
Definition: docbm.cxx:1215
float u
@ TableOfAuthorities
void MakeFrames(SwDoc *pDoc, SwNode &rSttIdx, SwNode &rEndIdx)
Definition: frmtool.cxx:2017
void AppendAllObjs(const SwFrameFormats *pTable, const SwFrame *pSib)
Definition: frmtool.cxx:1381
constexpr sal_uInt16 RES_PARATR_BEGIN(RES_TXTATR_END)
constexpr sal_uInt16 RES_FRMATR_END(141)
constexpr sal_uInt16 RES_PARATR_END(82)
constexpr sal_uInt16 RES_PARATR_LIST_BEGIN(RES_PARATR_END)
constexpr TypedWhichId< SwFormatContent > RES_CNTNT(101)
constexpr TypedWhichId< SvxULSpaceItem > RES_UL_SPACE(98)
constexpr TypedWhichId< SvxPrintItem > RES_PRINT(104)
Mode eMode
sal_Int64 n
sal_uInt16 nPos
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
int i
m
end
Dialog to specify the properties of date form field.
void UpdateFramesForRemoveDeleteRedline(SwDoc &rDoc, SwPaM const &rPam)
void MoveMergedFlysAndFootnotes(std::vector< SwTextFrame * > const &rFrames, SwTextNode const &rFirstNode, SwTextNode &rSecondNode, bool)
Definition: ndtxt.cxx:375
void CheckAnchoredFlyConsistency(SwDoc const &rDoc)
Definition: atrfrm.cxx:3675
static void UpdateFieldsForRedline(IDocumentFieldsAccess &rIDFA)
void UpdateFramesForAddDeleteRedline(SwDoc &rDoc, SwPaM const &rPam)
void AddRemoveFlysAnchoredToFrameStartingAtNode(SwTextFrame &rFrame, SwTextNode &rTextNode, std::set< SwNodeOffset > *pSkipped)
rTextNode is the first one of the "new" merge - if rTextNode isn't the same as MergedPara::pFirstNode...
Definition: wsfrm.cxx:4309
std::unique_ptr< sw::MergedPara > CheckParaRedlineMerge(SwTextFrame &rFrame, SwTextNode &rTextNode, FrameMode eMode)
Definition: redlnitr.cxx:268
o3tl::strong_int< sal_Int32, struct Tag_SwNodeOffset > SwNodeOffset
Definition: nodeoffset.hxx:16
SwComparePosition ComparePosition(const T &rStt1, const T &rEnd1, const T &rStt2, const T &rEnd2)
Definition: pam.hxx:122
SwComparePosition
Definition: pam.hxx:109
@ OverlapBehind
Pos1 overlaps Pos2 at the end.
@ CollideEnd
Pos1 end touches at Pos2 start.
@ Behind
Pos1 behind Pos2.
@ OverlapBefore
Pos1 overlaps Pos2 at the beginning.
@ Outside
Pos2 completely contained in Pos1.
@ Before
Pos1 before Pos2.
@ Inside
Pos1 completely contained in Pos2.
@ CollideStart
Pos1 start touches at Pos2 end.
@ Equal
Pos1 is as large as Pos2.
QPRO_FUNC_TYPE nType
Marks a position in the document model.
Definition: pam.hxx:37
SwNode & GetNode() const
Definition: pam.hxx:80
void Assign(const SwNode &rNd, SwNodeOffset nDelta, sal_Int32 nContentOffset=0)
These all set both nNode and nContent.
Definition: pam.cxx:230
void SetContent(sal_Int32 nContentIndex)
Set content index, only valid to call this if the position points to a SwContentNode subclass.
Definition: pam.cxx:266
const SwContentNode * GetContentNode() const
Definition: pam.hxx:83
SwNodeOffset GetNodeIndex() const
Definition: pam.hxx:77
sal_Int32 GetContentIndex() const
Definition: pam.hxx:84
SwDoc & GetDoc() const
Returns the document this position is in.
Definition: pam.cxx:217
OUString SwResId(TranslateId aId)
Definition: swmodule.cxx:168
#define SW_MOD()
Definition: swmodule.hxx:256
@ REJECT_REDLINE
@ ACCEPT_REDLINE