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