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