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 */
19 #include <DocumentRedlineManager.hxx>
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>
28 #include <IDocumentFieldsAccess.hxx>
29 #include <IDocumentLayoutAccess.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
41 using namespace com::sun::star;
42
43 #ifdef DBG_UTIL
44
45 #define ERROR_PREFIX "redline table corrupted: "
46
47 namespace
48 {
49 // helper function for lcl_CheckRedline
50 // 1. make sure that pPos->nContent points into pPos->nNode
51 // 2. check that position is valid and doesn't point after text
lcl_CheckPosition(const SwPosition * pPos)52 void lcl_CheckPosition( const SwPosition* pPos )
53 {
54 assert(dynamic_cast<SwIndexReg*>(&pPos->nNode.GetNode())
55 == pPos->nContent.GetIdxReg());
56
57 SwTextNode* pTextNode = pPos->nNode.GetNode().GetTextNode();
58 if( pTextNode == nullptr )
59 {
60 assert(pPos->nContent == 0);
61 }
62 else
63 {
64 assert(pPos->nContent >= 0 && pPos->nContent <= pTextNode->Len());
65 }
66 }
67
lcl_CheckPam(const SwPaM * pPam)68 void lcl_CheckPam( const SwPaM* pPam )
69 {
70 assert(pPam);
71 lcl_CheckPosition( pPam->GetPoint() );
72 lcl_CheckPosition( pPam->GetMark() );
73 }
74
75 // check validity of the redline table. Checks redline bounds, and make
76 // sure the redlines are sorted and non-overlapping.
lcl_CheckRedline(IDocumentRedlineAccess & redlineAccess)77 void lcl_CheckRedline( IDocumentRedlineAccess& redlineAccess )
78 {
79 const SwRedlineTable& rTable = redlineAccess.GetRedlineTable();
80
81 // verify valid redline positions
82 for(SwRangeRedline* i : rTable)
83 lcl_CheckPam( i );
84
85 for(SwRangeRedline* j : rTable)
86 {
87 // check for empty redlines
88 // note: these can destroy sorting in SwTextNode::Update()
89 // if there's another one without mark on the same pos.
90 OSL_ENSURE( ( *(j->GetPoint()) != *(j->GetMark()) ) ||
91 ( j->GetContentIdx() != nullptr ),
92 ERROR_PREFIX "empty redline" );
93 }
94
95 // verify proper redline sorting
96 for( size_t n = 1; n < rTable.size(); ++n )
97 {
98 const SwRangeRedline* pPrev = rTable[ n-1 ];
99 const SwRangeRedline* pCurrent = rTable[ n ];
100
101 // check redline sorting
102 SAL_WARN_IF( *pPrev->Start() > *pCurrent->Start(), "sw",
103 ERROR_PREFIX "not sorted correctly" );
104
105 // check for overlapping redlines
106 SAL_WARN_IF( *pPrev->End() > *pCurrent->Start(), "sw",
107 ERROR_PREFIX "overlapping redlines" );
108 }
109
110 assert(std::is_sorted(rTable.begin(), rTable.end(), CompareSwRedlineTable()));
111 }
112 }
113
114 #define CHECK_REDLINE( pDoc ) lcl_CheckRedline( pDoc );
115
116 #else
117
118 #define CHECK_REDLINE( pDoc )
119
120 #endif
121
122 namespace sw {
123
UpdateFieldsForRedline(IDocumentFieldsAccess & rIDFA)124 static void UpdateFieldsForRedline(IDocumentFieldsAccess & rIDFA)
125 {
126 auto const pAuthType(static_cast<SwAuthorityFieldType*>(rIDFA.GetFieldType(
127 SwFieldIds::TableOfAuthorities, OUString(), false)));
128 if (pAuthType) // created on demand...
129 {
130 pAuthType->DelSequenceArray();
131 }
132 rIDFA.GetFieldType(SwFieldIds::RefPageGet, OUString(), false)->UpdateFields();
133 rIDFA.GetSysFieldType(SwFieldIds::Chapter)->UpdateFields();
134 rIDFA.UpdateExpFields(nullptr, false);
135 rIDFA.UpdateRefFields();
136 }
137
UpdateFramesForAddDeleteRedline(SwDoc & rDoc,SwPaM const & rPam)138 void UpdateFramesForAddDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
139 {
140 // no need to call UpdateFootnoteNums for FTNNUM_PAGE:
141 // the AppendFootnote/RemoveFootnote will do it by itself!
142 rDoc.GetFootnoteIdxs().UpdateFootnote(rPam.Start()->nNode);
143 SwPosition currentStart(*rPam.Start());
144 SwTextNode * pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
145 while (!pStartNode)
146 {
147 SwStartNode *const pTableOrSectionNode(
148 currentStart.nNode.GetNode().IsTableNode()
149 ? static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetTableNode())
150 : static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetSectionNode()));
151 assert(pTableOrSectionNode); // known pathology
152 for (sal_uLong j = pTableOrSectionNode->GetIndex(); j <= pTableOrSectionNode->EndOfSectionIndex(); ++j)
153 {
154 pTableOrSectionNode->GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
155 }
156 for (SwRootFrame const*const pLayout : rDoc.GetAllLayouts())
157 {
158 if (pLayout->IsHideRedlines())
159 {
160 if (pTableOrSectionNode->IsTableNode())
161 {
162 static_cast<SwTableNode*>(pTableOrSectionNode)->DelFrames(pLayout);
163 }
164 else
165 {
166 static_cast<SwSectionNode*>(pTableOrSectionNode)->DelFrames(pLayout);
167 }
168 }
169 }
170 currentStart.nNode = pTableOrSectionNode->EndOfSectionIndex() + 1;
171 currentStart.nContent.Assign(currentStart.nNode.GetNode().GetContentNode(), 0);
172 pStartNode = currentStart.nNode.GetNode().GetTextNode();
173 }
174 if (currentStart < *rPam.End())
175 {
176 SwTextNode * pNode(pStartNode);
177 do
178 {
179 std::vector<SwTextFrame*> frames;
180 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNode);
181 for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
182 {
183 if (pFrame->getRootFrame()->IsHideRedlines())
184 {
185 frames.push_back(pFrame);
186 }
187 }
188 if (frames.empty())
189 {
190 auto const& layouts(rDoc.GetAllLayouts());
191 assert(std::none_of(layouts.begin(), layouts.end(),
192 [](SwRootFrame const*const pLayout) { return pLayout->IsHideRedlines(); }));
193 (void) layouts;
194 break;
195 }
196 auto eMode(sw::FrameMode::Existing);
197 SwTextNode * pLast(pNode);
198 for (SwTextFrame * pFrame : frames)
199 {
200 SwTextNode & rFirstNode(pFrame->GetMergedPara()
201 ? *pFrame->GetMergedPara()->pFirstNode
202 : *pNode);
203 assert(pNode == pStartNode
204 ? rFirstNode.GetIndex() <= pNode->GetIndex()
205 : &rFirstNode == pNode);
206 // clear old one first to avoid DelFrames confusing updates & asserts...
207 pFrame->SetMergedPara(nullptr);
208 pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
209 *pFrame, rFirstNode, eMode));
210 eMode = sw::FrameMode::New; // Existing is not idempotent!
211 // the first node of the new redline is not necessarily the first
212 // node of the merged frame, there could be another redline nearby
213 sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, *pNode, nullptr);
214 // if redline is split across table and table cell is empty, there's no redline in the cell and so no merged para
215 if (pFrame->GetMergedPara())
216 {
217 pLast = const_cast<SwTextNode*>(pFrame->GetMergedPara()->pLastNode);
218 }
219 }
220 SwNodeIndex tmp(*pLast);
221 // skip over hidden sections!
222 pNode = static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, /*bSkipHidden=*/true, /*bSkipProtect=*/false));
223 }
224 while (pNode && pNode->GetIndex() <= rPam.End()->nNode.GetIndex());
225 }
226 // fields last - SwGetRefField::UpdateField requires up-to-date frames
227 UpdateFieldsForRedline(rDoc.getIDocumentFieldsAccess()); // after footnotes
228
229 // update SwPostItMgr / notes in the margin
230 rDoc.GetDocShell()->Broadcast(
231 SwFormatFieldHint(nullptr, SwFormatFieldHintWhich::REMOVED) );
232 }
233
UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc,SwPaM const & rPam)234 void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
235 {
236 bool isAppendObjsCalled(false);
237 rDoc.GetFootnoteIdxs().UpdateFootnote(rPam.Start()->nNode);
238 SwPosition currentStart(*rPam.Start());
239 SwTextNode * pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
240 while (!pStartNode)
241 {
242 SwStartNode const*const pTableOrSectionNode(
243 currentStart.nNode.GetNode().IsTableNode()
244 ? static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetTableNode())
245 : static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetSectionNode()));
246 assert(pTableOrSectionNode); // known pathology
247 for (sal_uLong j = pTableOrSectionNode->GetIndex(); j <= pTableOrSectionNode->EndOfSectionIndex(); ++j)
248 {
249 pTableOrSectionNode->GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::None);
250 }
251 if (rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->IsHideRedlines())
252 {
253 // note: this will also create frames for all currently hidden flys
254 // because it calls AppendAllObjs
255 SwNodeIndex const end(*pTableOrSectionNode->EndOfSectionNode());
256 ::MakeFrames(&rDoc, currentStart.nNode, end);
257 isAppendObjsCalled = true;
258 }
259 currentStart.nNode = pTableOrSectionNode->EndOfSectionIndex() + 1;
260 currentStart.nContent.Assign(currentStart.nNode.GetNode().GetContentNode(), 0);
261 pStartNode = currentStart.nNode.GetNode().GetTextNode();
262 }
263 if (currentStart < *rPam.End())
264 {
265 SwTextNode * pNode(pStartNode);
266 do
267 {
268 std::vector<SwTextFrame*> frames;
269 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNode);
270 for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
271 {
272 if (pFrame->getRootFrame()->IsHideRedlines())
273 {
274 frames.push_back(pFrame);
275 }
276 }
277 if (frames.empty())
278 {
279 auto const& layouts(rDoc.GetAllLayouts());
280 assert(std::none_of(layouts.begin(), layouts.end(),
281 [](SwRootFrame const*const pLayout) { return pLayout->IsHideRedlines(); }));
282 (void) layouts;
283 break;
284 }
285
286 // first, call CheckParaRedlineMerge on the first paragraph,
287 // to init flag on new merge range (if any) + 1st node post the merge
288 auto eMode(sw::FrameMode::Existing);
289 SwTextNode * pLast(pNode);
290 for (SwTextFrame * pFrame : frames)
291 {
292 if (auto const pMergedPara = pFrame->GetMergedPara())
293 {
294 pLast = const_cast<SwTextNode*>(pMergedPara->pLastNode);
295 assert(pNode == pStartNode
296 ? pMergedPara->pFirstNode->GetIndex() <= pNode->GetIndex()
297 : pMergedPara->pFirstNode == pNode);
298 // clear old one first to avoid DelFrames confusing updates & asserts...
299 SwTextNode & rFirstNode(*pMergedPara->pFirstNode);
300 pFrame->SetMergedPara(nullptr);
301 pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
302 *pFrame, rFirstNode, eMode));
303 eMode = sw::FrameMode::New; // Existing is not idempotent!
304 }
305 }
306 if (pLast != pNode)
307 {
308 // now start node until end of merge + 1 has proper flags; MakeFrames
309 // should pick up from the next node in need of frames by checking flags
310 SwNodeIndex const start(*pNode, +1);
311 SwNodeIndex const end(*pLast, +1); // end is exclusive
312 // note: this will also create frames for all currently hidden flys
313 // both on first and non-first nodes because it calls AppendAllObjs
314 ::MakeFrames(&rDoc, start, end);
315 isAppendObjsCalled = true;
316 // re-use this to move flys that are now on the wrong frame, with end
317 // of redline as "second" node; the nodes between start and end should
318 // be complete with MakeFrames already
319 sw::MoveMergedFlysAndFootnotes(frames, *pNode, *pLast, false);
320 }
321 SwNodeIndex tmp(*pLast);
322 // skip over hidden sections!
323 pNode = static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, /*bSkipHidden=*/true, /*bSkipProtect=*/false));
324 }
325 while (pNode && pNode->GetIndex() <= rPam.End()->nNode.GetIndex());
326 }
327
328 if (!isAppendObjsCalled)
329 { // recreate flys in the one node the hard way...
330 for (auto const& pLayout : rDoc.GetAllLayouts())
331 {
332 if (pLayout->IsHideRedlines())
333 {
334 AppendAllObjs(rDoc.GetSpzFrameFormats(), pLayout);
335 break;
336 }
337 }
338 }
339 // fields last - SwGetRefField::UpdateField requires up-to-date frames
340 UpdateFieldsForRedline(rDoc.getIDocumentFieldsAccess()); // after footnotes
341
342 // update SwPostItMgr / notes in the margin
343 rDoc.GetDocShell()->Broadcast(
344 SwFormatFieldHint(nullptr, SwFormatFieldHintWhich::INSERTED) );
345 }
346
347 } // namespace sw
348
349 namespace
350 {
IsPrevPos(const SwPosition & rPos1,const SwPosition & rPos2)351 bool IsPrevPos( const SwPosition & rPos1, const SwPosition & rPos2 )
352 {
353 const SwContentNode* pCNd;
354 return 0 == rPos2.nContent.GetIndex() &&
355 rPos2.nNode.GetIndex() - 1 == rPos1.nNode.GetIndex() &&
356 nullptr != ( pCNd = rPos1.nNode.GetNode().GetContentNode() ) &&
357 rPos1.nContent.GetIndex() == pCNd->Len();
358 }
359
360 // copy style or return with SwRedlineExtra_FormatColl with reject data of the upcoming copy
lcl_CopyStyle(const SwPosition & rFrom,const SwPosition & rTo,bool bCopy=true)361 SwRedlineExtraData_FormatColl* lcl_CopyStyle( const SwPosition & rFrom, const SwPosition & rTo, bool bCopy = true )
362 {
363 SwTextNode* pToNode = rTo.nNode.GetNode().GetTextNode();
364 SwTextNode* pFromNode = rFrom.nNode.GetNode().GetTextNode();
365 if (pToNode != nullptr && pFromNode != nullptr && pToNode != pFromNode)
366 {
367 const SwPaM aPam(*pToNode);
368 SwDoc* pDoc = aPam.GetDoc();
369 // using Undo, copy paragraph style
370 SwTextFormatColl* pFromColl = pFromNode->GetTextColl();
371 SwTextFormatColl* pToColl = pToNode->GetTextColl();
372 if (bCopy && pFromColl != pToColl)
373 pDoc->SetTextFormatColl(aPam, pFromColl);
374
375 // using Undo, remove direct paragraph formatting of the "To" paragraph,
376 // and apply here direct paragraph formatting of the "From" paragraph
377 SfxItemSet aTmp(
378 pDoc->GetAttrPool(),
379 svl::Items<
380 RES_PARATR_BEGIN, RES_PARATR_END - 3, // skip RSID and GRABBAG
381 RES_PARATR_LIST_BEGIN, RES_UL_SPACE, // skip PAGEDESC and BREAK
382 RES_CNTNT, RES_FRMATR_END - 1>{});
383 SfxItemSet aTmp2(aTmp);
384
385 pToNode->GetParaAttr(aTmp, 0, 0);
386 pFromNode->GetParaAttr(aTmp2, 0, 0);
387
388 bool bSameSet = aTmp == aTmp2;
389
390 if (!bSameSet)
391 {
392 for( sal_uInt16 nItem = 0; nItem < aTmp.TotalCount(); ++nItem)
393 {
394 sal_uInt16 nWhich = aTmp.GetWhichByPos(nItem);
395 if( SfxItemState::SET == aTmp.GetItemState( nWhich, false ) &&
396 SfxItemState::SET != aTmp2.GetItemState( nWhich, false ) )
397 aTmp2.Put( aTmp.GetPool()->GetDefaultItem(nWhich), nWhich );
398 }
399 }
400
401 if (bCopy && !bSameSet)
402 pDoc->getIDocumentContentOperations().InsertItemSet(aPam, aTmp2);
403 else if (!bCopy && (!bSameSet || pFromColl != pToColl))
404 return new SwRedlineExtraData_FormatColl( pFromColl->GetName(), USHRT_MAX, &aTmp2 );
405 }
406 return nullptr;
407 }
408
lcl_AcceptRedline(SwRedlineTable & rArr,SwRedlineTable::size_type & rPos,bool bCallDelete,const SwPosition * pSttRng=nullptr,const SwPosition * pEndRng=nullptr)409 bool lcl_AcceptRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
410 bool bCallDelete,
411 const SwPosition* pSttRng = nullptr,
412 const SwPosition* pEndRng = nullptr )
413 {
414 bool bRet = true;
415 SwRangeRedline* pRedl = rArr[ rPos ];
416 SwPosition *pRStt = nullptr, *pREnd = nullptr;
417 SwComparePosition eCmp = SwComparePosition::Outside;
418 if( pSttRng && pEndRng )
419 {
420 pRStt = pRedl->Start();
421 pREnd = pRedl->End();
422 eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
423 }
424
425 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Remove);
426
427 switch( pRedl->GetType() )
428 {
429 case RedlineType::Insert:
430 case RedlineType::Format:
431 {
432 bool bCheck = false, bReplace = false;
433 switch( eCmp )
434 {
435 case SwComparePosition::Inside:
436 if( *pSttRng == *pRStt )
437 pRedl->SetStart( *pEndRng, pRStt );
438 else
439 {
440 if( *pEndRng != *pREnd )
441 {
442 // split up
443 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
444 pNew->SetStart( *pEndRng );
445 rArr.Insert( pNew ); ++rPos;
446 }
447 pRedl->SetEnd( *pSttRng, pREnd );
448 bCheck = true;
449 }
450 break;
451
452 case SwComparePosition::OverlapBefore:
453 pRedl->SetStart( *pEndRng, pRStt );
454 bReplace = true;
455 break;
456
457 case SwComparePosition::OverlapBehind:
458 pRedl->SetEnd( *pSttRng, pREnd );
459 bCheck = true;
460 break;
461
462 case SwComparePosition::Outside:
463 case SwComparePosition::Equal:
464 rArr.DeleteAndDestroy( rPos-- );
465 break;
466
467 default:
468 bRet = false;
469 }
470
471 if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
472 {
473 // re-insert
474 rArr.Remove( pRedl );
475 rArr.Insert( pRedl );
476 }
477 }
478 break;
479 case RedlineType::Delete:
480 {
481 SwDoc& rDoc = *pRedl->GetDoc();
482 const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
483 bool bDelRedl = false;
484 switch( eCmp )
485 {
486 case SwComparePosition::Inside:
487 if( bCallDelete )
488 {
489 pDelStt = pSttRng;
490 pDelEnd = pEndRng;
491 }
492 break;
493
494 case SwComparePosition::OverlapBefore:
495 if( bCallDelete )
496 {
497 pDelStt = pRStt;
498 pDelEnd = pEndRng;
499 }
500 break;
501 case SwComparePosition::OverlapBehind:
502 if( bCallDelete )
503 {
504 pDelStt = pREnd;
505 pDelEnd = pSttRng;
506 }
507 break;
508
509 case SwComparePosition::Outside:
510 case SwComparePosition::Equal:
511 {
512 rArr.Remove( rPos-- );
513 bDelRedl = true;
514 if( bCallDelete )
515 {
516 pDelStt = pRedl->Start();
517 pDelEnd = pRedl->End();
518 }
519 }
520 break;
521 default:
522 bRet = false;
523 }
524
525 if( pDelStt && pDelEnd )
526 {
527 SwPaM aPam( *pDelStt, *pDelEnd );
528 SwContentNode* pCSttNd = pDelStt->nNode.GetNode().GetContentNode();
529 SwContentNode* pCEndNd = pDelEnd->nNode.GetNode().GetContentNode();
530 pRStt = pRedl->Start();
531 pREnd = pRedl->End();
532
533 // keep style of the empty paragraph after deletion of wholly paragraphs
534 if( pCSttNd && pCEndNd && pRStt && pREnd && pRStt->nContent == 0 )
535 lcl_CopyStyle(*pREnd, *pRStt);
536
537 if( bDelRedl )
538 delete pRedl;
539
540 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
541 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore));
542
543 if( pCSttNd && pCEndNd )
544 rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
545 else if (pCSttNd && !pCEndNd)
546 {
547 aPam.GetBound().nContent.Assign( nullptr, 0 );
548 aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
549 rDoc.getIDocumentContentOperations().DelFullPara( aPam );
550 }
551 else
552 {
553 rDoc.getIDocumentContentOperations().DeleteRange(aPam);
554 }
555 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
556 }
557 else if( bDelRedl )
558 delete pRedl;
559 }
560 break;
561
562 case RedlineType::FmtColl:
563 rArr.DeleteAndDestroy( rPos-- );
564 break;
565
566 case RedlineType::ParagraphFormat:
567 rArr.DeleteAndDestroy( rPos-- );
568 break;
569
570 default:
571 bRet = false;
572 }
573 return bRet;
574 }
575
lcl_RejectRedline(SwRedlineTable & rArr,SwRedlineTable::size_type & rPos,bool bCallDelete,const SwPosition * pSttRng=nullptr,const SwPosition * pEndRng=nullptr)576 bool lcl_RejectRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
577 bool bCallDelete,
578 const SwPosition* pSttRng = nullptr,
579 const SwPosition* pEndRng = nullptr )
580 {
581 bool bRet = true;
582 SwRangeRedline* pRedl = rArr[ rPos ];
583 SwDoc& rDoc = *pRedl->GetDoc();
584 SwPosition *pRStt = nullptr, *pREnd = nullptr;
585 SwComparePosition eCmp = SwComparePosition::Outside;
586 if( pSttRng && pEndRng )
587 {
588 pRStt = pRedl->Start();
589 pREnd = pRedl->End();
590 eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
591 }
592
593 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Remove);
594
595 switch( pRedl->GetType() )
596 {
597 case RedlineType::Insert:
598 {
599 const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
600 bool bDelRedl = false;
601 switch( eCmp )
602 {
603 case SwComparePosition::Inside:
604 if( bCallDelete )
605 {
606 pDelStt = pSttRng;
607 pDelEnd = pEndRng;
608 }
609 break;
610
611 case SwComparePosition::OverlapBefore:
612 if( bCallDelete )
613 {
614 pDelStt = pRStt;
615 pDelEnd = pEndRng;
616 }
617 break;
618 case SwComparePosition::OverlapBehind:
619 if( bCallDelete )
620 {
621 pDelStt = pREnd;
622 pDelEnd = pSttRng;
623 }
624 break;
625 case SwComparePosition::Outside:
626 case SwComparePosition::Equal:
627 {
628 // delete the range again
629 rArr.Remove( rPos-- );
630 bDelRedl = true;
631 if( bCallDelete )
632 {
633 pDelStt = pRedl->Start();
634 pDelEnd = pRedl->End();
635 }
636 }
637 break;
638
639 default:
640 bRet = false;
641 }
642 if( pDelStt && pDelEnd )
643 {
644 SwPaM aPam( *pDelStt, *pDelEnd );
645
646 SwContentNode* pCSttNd = pDelStt->nNode.GetNode().GetContentNode();
647 SwContentNode* pCEndNd = pDelEnd->nNode.GetNode().GetContentNode();
648
649 if( bDelRedl )
650 delete pRedl;
651
652 RedlineFlags eOld = rDoc.getIDocumentRedlineAccess().GetRedlineFlags();
653 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore));
654
655 if( pCSttNd && pCEndNd )
656 rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
657 else if (pCSttNd && !pCEndNd)
658 {
659 aPam.GetBound().nContent.Assign( nullptr, 0 );
660 aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
661 if (aPam.End()->nNode.GetNode().IsStartNode())
662 { // end node will be deleted too! see nNodeDiff+1
663 --aPam.End()->nNode;
664 }
665 assert(!aPam.End()->nNode.GetNode().IsStartNode());
666 rDoc.getIDocumentContentOperations().DelFullPara( aPam );
667 }
668 else
669 {
670 rDoc.getIDocumentContentOperations().DeleteRange(aPam);
671 }
672 rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld );
673 }
674 else if( bDelRedl )
675 delete pRedl;
676 }
677 break;
678 case RedlineType::Delete:
679 {
680 SwRangeRedline* pNew = nullptr;
681 bool bCheck = false, bReplace = false;
682 SwPaM const updatePaM(pSttRng ? *pSttRng : *pRedl->Start(),
683 pEndRng ? *pEndRng : *pRedl->End());
684
685 if( pRedl->GetExtraData() )
686 pRedl->GetExtraData()->Reject( *pRedl );
687
688 switch( eCmp )
689 {
690 case SwComparePosition::Inside:
691 {
692 if( 1 < pRedl->GetStackCount() )
693 {
694 pNew = new SwRangeRedline( *pRedl );
695 pNew->PopData();
696 }
697 if( *pSttRng == *pRStt )
698 {
699 pRedl->SetStart( *pEndRng, pRStt );
700 bReplace = true;
701 if( pNew )
702 pNew->SetEnd( *pEndRng );
703 }
704 else
705 {
706 if( *pEndRng != *pREnd )
707 {
708 // split up
709 SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
710 pCpy->SetStart( *pEndRng );
711 rArr.Insert( pCpy ); ++rPos;
712 if( pNew )
713 pNew->SetEnd( *pEndRng );
714 }
715
716 pRedl->SetEnd( *pSttRng, pREnd );
717 bCheck = true;
718 if( pNew )
719 pNew->SetStart( *pSttRng );
720 }
721 }
722 break;
723
724 case SwComparePosition::OverlapBefore:
725 if( 1 < pRedl->GetStackCount() )
726 {
727 pNew = new SwRangeRedline( *pRedl );
728 pNew->PopData();
729 }
730 pRedl->SetStart( *pEndRng, pRStt );
731 bReplace = true;
732 if( pNew )
733 pNew->SetEnd( *pEndRng );
734 break;
735
736 case SwComparePosition::OverlapBehind:
737 if( 1 < pRedl->GetStackCount() )
738 {
739 pNew = new SwRangeRedline( *pRedl );
740 pNew->PopData();
741 }
742 pRedl->SetEnd( *pSttRng, pREnd );
743 bCheck = true;
744 if( pNew )
745 pNew->SetStart( *pSttRng );
746 break;
747
748 case SwComparePosition::Outside:
749 case SwComparePosition::Equal:
750 if( !pRedl->PopData() )
751 // deleting the RedlineObject is enough
752 rArr.DeleteAndDestroy( rPos-- );
753 break;
754
755 default:
756 bRet = false;
757 }
758
759 if( pNew )
760 {
761 rArr.Insert( pNew ); ++rPos;
762 }
763
764 if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
765 {
766 // re-insert
767 rArr.Remove( pRedl );
768 rArr.Insert( pRedl );
769 }
770
771 sw::UpdateFramesForRemoveDeleteRedline(rDoc, updatePaM);
772 }
773 break;
774
775 case RedlineType::Format:
776 case RedlineType::FmtColl:
777 case RedlineType::ParagraphFormat:
778 {
779 // tdf#52391 instead of hidden acception at the requested
780 // rejection, remove direct text formatting to get the potential
781 // original state of the text (FIXME if the original text
782 // has already contained direct text formatting: unfortunately
783 // ODF 1.2 doesn't support rejection of format-only changes)
784 if ( pRedl->GetType() == RedlineType::Format )
785 {
786 SwPaM aPam( *(pRedl->Start()), *(pRedl->End()) );
787 rDoc.ResetAttrs(aPam);
788 }
789 else if ( pRedl->GetType() == RedlineType::ParagraphFormat )
790 {
791 // handle paragraph formatting changes
792 // (range is only a full paragraph or a part of it)
793 const SwPosition* pStt = pRedl->Start();
794 SwTextNode* pTNd = pStt->nNode.GetNode().GetTextNode();
795 if( pTNd )
796 {
797 // expand range to the whole paragraph
798 // and reset only the paragraph attributes
799 SwPaM aPam( *pTNd, pTNd->GetText().getLength() );
800 std::set<sal_uInt16> aResetAttrsArray;
801
802 sal_uInt16 aResetableSetRange[] = {
803 RES_PARATR_BEGIN, RES_PARATR_END - 1,
804 RES_PARATR_LIST_BEGIN, RES_FRMATR_END - 1,
805 0
806 };
807
808 const sal_uInt16 *pUShorts = aResetableSetRange;
809 while (*pUShorts)
810 {
811 for (sal_uInt16 i = pUShorts[0]; i <= pUShorts[1]; ++i)
812 aResetAttrsArray.insert( aResetAttrsArray.end(), i );
813 pUShorts += 2;
814 }
815
816 rDoc.ResetAttrs(aPam, false, aResetAttrsArray);
817
818 // remove numbering
819 if ( pTNd->GetNumRule() )
820 rDoc.DelNumRules(aPam);
821 }
822 }
823
824 if( pRedl->GetExtraData() )
825 pRedl->GetExtraData()->Reject( *pRedl );
826
827 rArr.DeleteAndDestroy( rPos-- );
828 }
829 break;
830
831 default:
832 bRet = false;
833 }
834 return bRet;
835 }
836
837 typedef bool (*Fn_AcceptReject)( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
838 bool bCallDelete,
839 const SwPosition* pSttRng,
840 const SwPosition* pEndRng);
841
842
lcl_AcceptRejectRedl(Fn_AcceptReject fn_AcceptReject,SwRedlineTable & rArr,bool bCallDelete,const SwPaM & rPam)843 int lcl_AcceptRejectRedl( Fn_AcceptReject fn_AcceptReject,
844 SwRedlineTable& rArr, bool bCallDelete,
845 const SwPaM& rPam)
846 {
847 SwRedlineTable::size_type n = 0;
848 int nCount = 0;
849
850 const SwPosition* pStt = rPam.Start(),
851 * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
852 : rPam.GetPoint();
853 const SwRangeRedline* pFnd = rArr.FindAtPosition( *pStt, n );
854 if( pFnd && // Is new a part of it?
855 ( *pFnd->Start() != *pStt || *pFnd->End() > *pEnd ))
856 {
857 // Only revoke the partial selection
858 if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd ))
859 nCount++;
860 ++n;
861 }
862
863 // tdf#119824 first we will accept only overlapping paragraph format changes
864 // in the first loop to avoid potential content changes during Redo
865 bool bHasParagraphFormatChange = false;
866 for( int m = 0 ; m < 2 && !bHasParagraphFormatChange; ++m )
867 {
868 for(SwRedlineTable::size_type o = n ; o < rArr.size(); ++o )
869 {
870 SwRangeRedline* pTmp = rArr[ o ];
871 if( pTmp->HasMark() && pTmp->IsVisible() )
872 {
873 if( *pTmp->End() <= *pEnd )
874 {
875 if( (m > 0 || RedlineType::ParagraphFormat == pTmp->GetType()) &&
876 (*fn_AcceptReject)( rArr, o, bCallDelete, nullptr, nullptr ))
877 {
878 bHasParagraphFormatChange = true;
879 nCount++;
880 }
881 }
882 else
883 {
884 if( *pTmp->Start() < *pEnd )
885 {
886 // Only revoke the partial selection
887 if( (m > 0 || RedlineType::ParagraphFormat == pTmp->GetType()) &&
888 (*fn_AcceptReject)( rArr, o, bCallDelete, pStt, pEnd ))
889 {
890 bHasParagraphFormatChange = true;
891 nCount++;
892 }
893 }
894 break;
895 }
896 }
897 }
898 }
899 return nCount;
900 }
901
lcl_AdjustRedlineRange(SwPaM & rPam)902 void lcl_AdjustRedlineRange( SwPaM& rPam )
903 {
904 // The Selection is only in the ContentSection. If there are Redlines
905 // to Non-ContentNodes before or after that, then the Selections
906 // expand to them.
907 SwPosition* pStt = rPam.Start(),
908 * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
909 : rPam.GetPoint();
910 SwDoc* pDoc = rPam.GetDoc();
911 if( !pStt->nContent.GetIndex() &&
912 !pDoc->GetNodes()[ pStt->nNode.GetIndex() - 1 ]->IsContentNode() )
913 {
914 const SwRangeRedline* pRedl = pDoc->getIDocumentRedlineAccess().GetRedline( *pStt, nullptr );
915 if( pRedl )
916 {
917 const SwPosition* pRStt = pRedl->Start();
918 if( !pRStt->nContent.GetIndex() && pRStt->nNode.GetIndex() ==
919 pStt->nNode.GetIndex() - 1 )
920 *pStt = *pRStt;
921 }
922 }
923 if( pEnd->nNode.GetNode().IsContentNode() &&
924 !pDoc->GetNodes()[ pEnd->nNode.GetIndex() + 1 ]->IsContentNode() &&
925 pEnd->nContent.GetIndex() == pEnd->nNode.GetNode().GetContentNode()->Len() )
926 {
927 const SwRangeRedline* pRedl = pDoc->getIDocumentRedlineAccess().GetRedline( *pEnd, nullptr );
928 if( pRedl )
929 {
930 const SwPosition* pREnd = pRedl->End();
931 if( !pREnd->nContent.GetIndex() && pREnd->nNode.GetIndex() ==
932 pEnd->nNode.GetIndex() + 1 )
933 *pEnd = *pREnd;
934 }
935 }
936 }
937
938 /// in case some text is deleted, ensure that the not-yet-inserted
939 /// SwRangeRedline has its positions corrected not to point to deleted node
940 class TemporaryRedlineUpdater
941 {
942 private:
943 SwRangeRedline & m_rRedline;
944 std::shared_ptr<SwUnoCursor> m_pCursor;
945 public:
TemporaryRedlineUpdater(SwDoc & rDoc,SwRangeRedline & rRedline)946 TemporaryRedlineUpdater(SwDoc & rDoc, SwRangeRedline & rRedline)
947 : m_rRedline(rRedline)
948 , m_pCursor(rDoc.CreateUnoCursor(*rRedline.GetPoint(), false))
949 {
950 if (m_rRedline.HasMark())
951 {
952 m_pCursor->SetMark();
953 *m_pCursor->GetMark() = *m_rRedline.GetMark();
954 *m_rRedline.GetMark() = SwPosition(rDoc.GetNodes().GetEndOfContent());
955 }
956 *m_rRedline.GetPoint() = SwPosition(rDoc.GetNodes().GetEndOfContent());
957 }
~TemporaryRedlineUpdater()958 ~TemporaryRedlineUpdater()
959 {
960 static_cast<SwPaM&>(m_rRedline) = *m_pCursor;
961 }
962 };
963 }
964
965 namespace sw
966 {
967
DocumentRedlineManager(SwDoc & i_rSwdoc)968 DocumentRedlineManager::DocumentRedlineManager(SwDoc& i_rSwdoc)
969 : m_rDoc(i_rSwdoc)
970 , meRedlineFlags(RedlineFlags::ShowInsert | RedlineFlags::ShowDelete)
971 , mpRedlineTable(new SwRedlineTable)
972 , mpExtraRedlineTable(new SwExtraRedlineTable)
973 , mbIsRedlineMove(false)
974 , mnAutoFormatRedlnCommentNo(0)
975 {
976 }
977
GetRedlineFlags() const978 RedlineFlags DocumentRedlineManager::GetRedlineFlags() const
979 {
980 return meRedlineFlags;
981 }
982
SetRedlineFlags(RedlineFlags eMode)983 void DocumentRedlineManager::SetRedlineFlags( RedlineFlags eMode )
984 {
985 if( meRedlineFlags != eMode )
986 {
987 if( (RedlineFlags::ShowMask & meRedlineFlags) != (RedlineFlags::ShowMask & eMode)
988 || !(RedlineFlags::ShowMask & eMode) )
989 {
990 bool bSaveInXMLImportFlag = m_rDoc.IsInXMLImport();
991 m_rDoc.SetInXMLImport( false );
992 // and then hide/display everything
993 void (SwRangeRedline::*pFnc)(sal_uInt16, size_t); // Allow compiler warn if use of
994 // uninitialized ptr is possible
995
996 RedlineFlags eShowMode = RedlineFlags::ShowMask & eMode;
997 if (eShowMode == (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete))
998 pFnc = &SwRangeRedline::Show;
999 else if (eShowMode == RedlineFlags::ShowInsert)
1000 pFnc = &SwRangeRedline::Hide;
1001 else if (eShowMode == RedlineFlags::ShowDelete)
1002 pFnc = &SwRangeRedline::ShowOriginal;
1003 else
1004 {
1005 pFnc = &SwRangeRedline::Hide;
1006 eMode |= RedlineFlags::ShowInsert;
1007 }
1008
1009 CheckAnchoredFlyConsistency(m_rDoc);
1010 CHECK_REDLINE( *this )
1011
1012 std::set<SwRootFrame *> hiddenLayouts;
1013 if (eShowMode == (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete))
1014 {
1015 // sw_redlinehide: the problem here is that MoveFromSection
1016 // creates the frames wrongly (non-merged), because its own
1017 // SwRangeRedline has wrong positions until after the nodes
1018 // are all moved, so fix things up by force by re-creating
1019 // all merged frames from scratch.
1020 std::set<SwRootFrame *> const layouts(m_rDoc.GetAllLayouts());
1021 for (SwRootFrame *const pLayout : layouts)
1022 {
1023 if (pLayout->IsHideRedlines())
1024 {
1025 pLayout->SetHideRedlines(false);
1026 hiddenLayouts.insert(pLayout);
1027 }
1028 }
1029 }
1030
1031 for (sal_uInt16 nLoop = 1; nLoop <= 2; ++nLoop)
1032 for (size_t i = 0; i < mpRedlineTable->size(); ++i)
1033 {
1034 SwRangeRedline *const pRedline((*mpRedlineTable)[i]);
1035 (pRedline->*pFnc)(nLoop, i);
1036 while (mpRedlineTable->size() <= i
1037 || (*mpRedlineTable)[i] != pRedline)
1038 { // ensure current position
1039 --i; // a previous redline may have been deleted
1040 }
1041 }
1042
1043 //SwRangeRedline::MoveFromSection routinely changes
1044 //the keys that mpRedlineTable is sorted by
1045 mpRedlineTable->Resort();
1046
1047 CheckAnchoredFlyConsistency(m_rDoc);
1048 CHECK_REDLINE( *this )
1049
1050 for (SwRootFrame *const pLayout : hiddenLayouts)
1051 {
1052 pLayout->SetHideRedlines(true);
1053 }
1054
1055 m_rDoc.SetInXMLImport( bSaveInXMLImportFlag );
1056 }
1057 meRedlineFlags = eMode;
1058 m_rDoc.getIDocumentState().SetModified();
1059 }
1060
1061 // #TODO - add 'SwExtraRedlineTable' also ?
1062 }
1063
IsRedlineOn() const1064 bool DocumentRedlineManager::IsRedlineOn() const
1065 {
1066 return IDocumentRedlineAccess::IsRedlineOn(meRedlineFlags);
1067 }
1068
IsIgnoreRedline() const1069 bool DocumentRedlineManager::IsIgnoreRedline() const
1070 {
1071 return bool(RedlineFlags::Ignore & meRedlineFlags);
1072 }
1073
SetRedlineFlags_intern(RedlineFlags eMode)1074 void DocumentRedlineManager::SetRedlineFlags_intern(RedlineFlags eMode)
1075 {
1076 meRedlineFlags = eMode;
1077 }
1078
GetRedlineTable() const1079 const SwRedlineTable& DocumentRedlineManager::GetRedlineTable() const
1080 {
1081 return *mpRedlineTable;
1082 }
1083
GetRedlineTable()1084 SwRedlineTable& DocumentRedlineManager::GetRedlineTable()
1085 {
1086 return *mpRedlineTable;
1087 }
1088
GetExtraRedlineTable() const1089 const SwExtraRedlineTable& DocumentRedlineManager::GetExtraRedlineTable() const
1090 {
1091 return *mpExtraRedlineTable;
1092 }
1093
GetExtraRedlineTable()1094 SwExtraRedlineTable& DocumentRedlineManager::GetExtraRedlineTable()
1095 {
1096 return *mpExtraRedlineTable;
1097 }
1098
HasExtraRedlineTable() const1099 bool DocumentRedlineManager::HasExtraRedlineTable() const
1100 {
1101 return mpExtraRedlineTable != nullptr;
1102 }
1103
IsInRedlines(const SwNode & rNode) const1104 bool DocumentRedlineManager::IsInRedlines(const SwNode & rNode) const
1105 {
1106 SwPosition aPos(rNode);
1107 SwNode & rEndOfRedlines = m_rDoc.GetNodes().GetEndOfRedlines();
1108 SwPaM aPam(SwPosition(*rEndOfRedlines.StartOfSectionNode()),
1109 SwPosition(rEndOfRedlines));
1110
1111 return aPam.ContainsPosition(aPos);
1112 }
1113
IsRedlineMove() const1114 bool DocumentRedlineManager::IsRedlineMove() const
1115 {
1116 return mbIsRedlineMove;
1117 }
1118
SetRedlineMove(bool bFlag)1119 void DocumentRedlineManager::SetRedlineMove(bool bFlag)
1120 {
1121 mbIsRedlineMove = bFlag;
1122 }
1123
1124 /*
1125 Text means Text not "polluted" by Redlines.
1126
1127 Behaviour of Insert-Redline:
1128 - in the Text - insert Redline Object
1129 - in InsertRedline (own) - ignore, existing is extended
1130 - in InsertRedline (others) - split up InsertRedline and
1131 insert Redline Object
1132 - in DeleteRedline - split up DeleteRedline or
1133 move at the end/beginning
1134
1135 Behaviour of Delete-Redline:
1136 - in the Text - insert Redline Object
1137 - in DeleteRedline (own/others) - ignore
1138 - in InsertRedline (own) - ignore, but delete character
1139 - in InsertRedline (others) - split up InsertRedline and
1140 insert Redline Object
1141 - Text and own Insert overlap - delete Text in the own Insert,
1142 extend in the other Text
1143 (up to the Insert!)
1144 - Text and other Insert overlap - insert Redline Object, the
1145 other Insert is overlapped by
1146 the Delete
1147 */
1148 IDocumentRedlineAccess::AppendResult
AppendRedline(SwRangeRedline * pNewRedl,bool const bCallDelete)1149 DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCallDelete)
1150 {
1151 bool bMerged = false;
1152 CHECK_REDLINE( *this )
1153
1154 if (IsRedlineOn() && !IsShowOriginal(meRedlineFlags))
1155 {
1156 pNewRedl->InvalidateRange(SwRangeRedline::Invalidation::Add);
1157
1158 if( m_rDoc.IsAutoFormatRedline() )
1159 {
1160 pNewRedl->SetAutoFormat();
1161 if( mpAutoFormatRedlnComment && !mpAutoFormatRedlnComment->isEmpty() )
1162 {
1163 pNewRedl->SetComment( *mpAutoFormatRedlnComment );
1164 pNewRedl->SetSeqNo( mnAutoFormatRedlnCommentNo );
1165 }
1166 }
1167
1168 SwPosition* pStt = pNewRedl->Start(),
1169 * pEnd = pStt == pNewRedl->GetPoint() ? pNewRedl->GetMark()
1170 : pNewRedl->GetPoint();
1171 {
1172 SwTextNode* pTextNode = pStt->nNode.GetNode().GetTextNode();
1173 if( pTextNode == nullptr )
1174 {
1175 if( pStt->nContent > 0 )
1176 {
1177 OSL_ENSURE( false, "Redline start: non-text-node with content" );
1178 pStt->nContent = 0;
1179 }
1180 }
1181 else
1182 {
1183 if( pStt->nContent > pTextNode->Len() )
1184 {
1185 OSL_ENSURE( false, "Redline start: index after text" );
1186 pStt->nContent = pTextNode->Len();
1187 }
1188 }
1189 pTextNode = pEnd->nNode.GetNode().GetTextNode();
1190 if( pTextNode == nullptr )
1191 {
1192 if( pEnd->nContent > 0 )
1193 {
1194 OSL_ENSURE( false, "Redline end: non-text-node with content" );
1195 pEnd->nContent = 0;
1196 }
1197 }
1198 else
1199 {
1200 if( pEnd->nContent > pTextNode->Len() )
1201 {
1202 OSL_ENSURE( false, "Redline end: index after text" );
1203 pEnd->nContent = pTextNode->Len();
1204 }
1205 }
1206 }
1207 if( ( *pStt == *pEnd ) &&
1208 ( pNewRedl->GetContentIdx() == nullptr ) )
1209 { // Do not insert empty redlines
1210 delete pNewRedl;
1211 return AppendResult::IGNORED;
1212 }
1213 bool bCompress = false;
1214 SwRedlineTable::size_type n = 0;
1215 // look up the first Redline for the starting position
1216 if( !GetRedline( *pStt, &n ) && n )
1217 --n;
1218 bool bDec = false;
1219
1220 for( ; pNewRedl && n < mpRedlineTable->size(); bDec ? n : ++n )
1221 {
1222 bDec = false;
1223
1224 SwRangeRedline* pRedl = (*mpRedlineTable)[ n ];
1225 SwPosition* pRStt = pRedl->Start(),
1226 * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
1227 : pRedl->GetPoint();
1228
1229 // #i8518# remove empty redlines while we're at it
1230 if( ( *pRStt == *pREnd ) &&
1231 ( pRedl->GetContentIdx() == nullptr ) )
1232 {
1233 mpRedlineTable->DeleteAndDestroy(n);
1234 continue;
1235 }
1236
1237 SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
1238
1239 switch( pNewRedl->GetType() )
1240 {
1241 case RedlineType::Insert:
1242 switch( pRedl->GetType() )
1243 {
1244 case RedlineType::Insert:
1245 if( pRedl->IsOwnRedline( *pNewRedl ) )
1246 {
1247 bool bDelete = false;
1248
1249 // Merge if applicable?
1250 if( (( SwComparePosition::Behind == eCmpPos &&
1251 IsPrevPos( *pREnd, *pStt ) ) ||
1252 ( SwComparePosition::CollideStart == eCmpPos ) ||
1253 ( SwComparePosition::OverlapBehind == eCmpPos ) ) &&
1254 pRedl->CanCombine( *pNewRedl ) &&
1255 ( n+1 >= mpRedlineTable->size() ||
1256 ( *(*mpRedlineTable)[ n+1 ]->Start() >= *pEnd &&
1257 *(*mpRedlineTable)[ n+1 ]->Start() != *pREnd ) ) )
1258 {
1259 pRedl->SetEnd( *pEnd, pREnd );
1260 if( !pRedl->HasValidRange() )
1261 {
1262 // re-insert
1263 mpRedlineTable->Remove( n );
1264 mpRedlineTable->Insert( pRedl );
1265 }
1266
1267 bMerged = true;
1268 bDelete = true;
1269 }
1270 else if( (( SwComparePosition::Before == eCmpPos &&
1271 IsPrevPos( *pEnd, *pRStt ) ) ||
1272 ( SwComparePosition::CollideEnd == eCmpPos ) ||
1273 ( SwComparePosition::OverlapBefore == eCmpPos ) ) &&
1274 pRedl->CanCombine( *pNewRedl ) &&
1275 ( !n ||
1276 *(*mpRedlineTable)[ n-1 ]->End() != *pRStt ))
1277 {
1278 pRedl->SetStart( *pStt, pRStt );
1279 // re-insert
1280 mpRedlineTable->Remove( n );
1281 mpRedlineTable->Insert( pRedl );
1282
1283 bMerged = true;
1284 bDelete = true;
1285 }
1286 else if ( SwComparePosition::Outside == eCmpPos )
1287 {
1288 // own insert-over-insert redlines:
1289 // just scrap the inside ones
1290 mpRedlineTable->DeleteAndDestroy( n );
1291 bDec = true;
1292 }
1293 else if( SwComparePosition::OverlapBehind == eCmpPos )
1294 {
1295 *pStt = *pREnd;
1296 if( ( *pStt == *pEnd ) &&
1297 ( pNewRedl->GetContentIdx() == nullptr ) )
1298 bDelete = true;
1299 }
1300 else if( SwComparePosition::OverlapBefore == eCmpPos )
1301 {
1302 *pEnd = *pRStt;
1303 if( ( *pStt == *pEnd ) &&
1304 ( pNewRedl->GetContentIdx() == nullptr ) )
1305 bDelete = true;
1306 }
1307 else if( SwComparePosition::Inside == eCmpPos )
1308 {
1309 bDelete = true;
1310 bMerged = true;
1311 }
1312 else if( SwComparePosition::Equal == eCmpPos )
1313 bDelete = true;
1314
1315 if( bDelete )
1316 {
1317 delete pNewRedl;
1318 pNewRedl = nullptr;
1319 bCompress = true;
1320 }
1321 }
1322 else if( SwComparePosition::Inside == eCmpPos )
1323 {
1324 // split up
1325 if( *pEnd != *pREnd )
1326 {
1327 SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
1328 pCpy->SetStart( *pEnd );
1329 mpRedlineTable->Insert( pCpy );
1330 }
1331 pRedl->SetEnd( *pStt, pREnd );
1332 if( ( *pStt == *pRStt ) &&
1333 ( pRedl->GetContentIdx() == nullptr ) )
1334 {
1335 mpRedlineTable->DeleteAndDestroy( n );
1336 bDec = true;
1337 }
1338 else if( !pRedl->HasValidRange() )
1339 {
1340 // re-insert
1341 mpRedlineTable->Remove( n );
1342 mpRedlineTable->Insert( pRedl );
1343 }
1344 }
1345 else if ( SwComparePosition::Outside == eCmpPos )
1346 {
1347 // handle overlapping redlines in broken documents
1348
1349 // split up the new redline, since it covers the
1350 // existing redline. Insert the first part, and
1351 // progress with the remainder as usual
1352 SwRangeRedline* pSplit = new SwRangeRedline( *pNewRedl );
1353 pSplit->SetEnd( *pRStt );
1354 pNewRedl->SetStart( *pREnd );
1355 mpRedlineTable->Insert( pSplit );
1356 if( *pStt == *pEnd && pNewRedl->GetContentIdx() == nullptr )
1357 {
1358 delete pNewRedl;
1359 pNewRedl = nullptr;
1360 bCompress = true;
1361 }
1362 }
1363 else if ( SwComparePosition::OverlapBehind == eCmpPos )
1364 {
1365 // handle overlapping redlines in broken documents
1366 pNewRedl->SetStart( *pREnd );
1367 }
1368 else if ( SwComparePosition::OverlapBefore == eCmpPos )
1369 {
1370 // handle overlapping redlines in broken documents
1371 *pEnd = *pRStt;
1372 if( ( *pStt == *pEnd ) &&
1373 ( pNewRedl->GetContentIdx() == nullptr ) )
1374 {
1375 delete pNewRedl;
1376 pNewRedl = nullptr;
1377 bCompress = true;
1378 }
1379 }
1380 break;
1381 case RedlineType::Delete:
1382 if( SwComparePosition::Inside == eCmpPos )
1383 {
1384 // split up
1385 if( *pEnd != *pREnd )
1386 {
1387 SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
1388 pCpy->SetStart( *pEnd );
1389 mpRedlineTable->Insert( pCpy );
1390 }
1391 pRedl->SetEnd( *pStt, pREnd );
1392 if( ( *pStt == *pRStt ) &&
1393 ( pRedl->GetContentIdx() == nullptr ) )
1394 {
1395 mpRedlineTable->DeleteAndDestroy( n );
1396 bDec = true;
1397 }
1398 else if( !pRedl->HasValidRange() )
1399 {
1400 // re-insert
1401 mpRedlineTable->Remove( n );
1402 mpRedlineTable->Insert( pRedl, n );
1403 }
1404 }
1405 else if ( SwComparePosition::Outside == eCmpPos )
1406 {
1407 // handle overlapping redlines in broken documents
1408
1409 // split up the new redline, since it covers the
1410 // existing redline. Insert the first part, and
1411 // progress with the remainder as usual
1412 SwRangeRedline* pSplit = new SwRangeRedline( *pNewRedl );
1413 pSplit->SetEnd( *pRStt );
1414 pNewRedl->SetStart( *pREnd );
1415 mpRedlineTable->Insert( pSplit );
1416 if( *pStt == *pEnd && pNewRedl->GetContentIdx() == nullptr )
1417 {
1418 delete pNewRedl;
1419 pNewRedl = nullptr;
1420 bCompress = true;
1421 }
1422 }
1423 else if ( SwComparePosition::Equal == eCmpPos )
1424 {
1425 // handle identical redlines in broken documents
1426 // delete old (delete) redline
1427 mpRedlineTable->DeleteAndDestroy( n );
1428 bDec = true;
1429 }
1430 else if ( SwComparePosition::OverlapBehind == eCmpPos )
1431 { // Another workaround for broken redlines
1432 pNewRedl->SetStart( *pREnd );
1433 }
1434 break;
1435 case RedlineType::Format:
1436 switch( eCmpPos )
1437 {
1438 case SwComparePosition::OverlapBefore:
1439 pRedl->SetStart( *pEnd, pRStt );
1440 // re-insert
1441 mpRedlineTable->Remove( n );
1442 mpRedlineTable->Insert( pRedl, n );
1443 bDec = true;
1444 break;
1445
1446 case SwComparePosition::OverlapBehind:
1447 pRedl->SetEnd( *pStt, pREnd );
1448 if( *pStt == *pRStt && pRedl->GetContentIdx() == nullptr )
1449 {
1450 mpRedlineTable->DeleteAndDestroy( n );
1451 bDec = true;
1452 }
1453 break;
1454
1455 case SwComparePosition::Equal:
1456 case SwComparePosition::Outside:
1457 // Overlaps the current one completely or has the
1458 // same dimension, delete the old one
1459 mpRedlineTable->DeleteAndDestroy( n );
1460 bDec = true;
1461 break;
1462
1463 case SwComparePosition::Inside:
1464 // Overlaps the current one completely,
1465 // split or shorten the new one
1466 if( *pEnd != *pREnd )
1467 {
1468 if( *pEnd != *pRStt )
1469 {
1470 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
1471 pNew->SetStart( *pEnd );
1472 pRedl->SetEnd( *pStt, pREnd );
1473 if( *pStt == *pRStt && pRedl->GetContentIdx() == nullptr )
1474 mpRedlineTable->DeleteAndDestroy( n );
1475 AppendRedline( pNew, bCallDelete );
1476 n = 0; // re-initialize
1477 bDec = true;
1478 }
1479 }
1480 else
1481 pRedl->SetEnd( *pStt, pREnd );
1482 break;
1483 default:
1484 break;
1485 }
1486 break;
1487 default:
1488 break;
1489 }
1490 break;
1491
1492 case RedlineType::Delete:
1493 switch( pRedl->GetType() )
1494 {
1495 case RedlineType::Delete:
1496 switch( eCmpPos )
1497 {
1498 case SwComparePosition::Outside:
1499 {
1500 // Overlaps the current one completely,
1501 // split the new one
1502 if (*pEnd == *pREnd)
1503 {
1504 pNewRedl->SetEnd(*pRStt, pEnd);
1505 }
1506 else if (*pStt == *pRStt)
1507 {
1508 pNewRedl->SetStart(*pREnd, pStt);
1509 }
1510 else
1511 {
1512 SwRangeRedline* pNew = new SwRangeRedline( *pNewRedl );
1513 pNew->SetStart( *pREnd );
1514 pNewRedl->SetEnd( *pRStt, pEnd );
1515 AppendRedline( pNew, bCallDelete );
1516 n = 0; // re-initialize
1517 bDec = true;
1518 }
1519 }
1520 break;
1521
1522 case SwComparePosition::Inside:
1523 case SwComparePosition::Equal:
1524 delete pNewRedl;
1525 pNewRedl = nullptr;
1526 bCompress = true;
1527 break;
1528
1529 case SwComparePosition::OverlapBefore:
1530 case SwComparePosition::OverlapBehind:
1531 if( pRedl->IsOwnRedline( *pNewRedl ) &&
1532 pRedl->CanCombine( *pNewRedl ))
1533 {
1534 // If that's the case we can merge it, meaning
1535 // the new one covers this well
1536 if( SwComparePosition::OverlapBehind == eCmpPos )
1537 pNewRedl->SetStart( *pRStt, pStt );
1538 else
1539 pNewRedl->SetEnd( *pREnd, pEnd );
1540 mpRedlineTable->DeleteAndDestroy( n );
1541 bDec = true;
1542 }
1543 else if( SwComparePosition::OverlapBehind == eCmpPos )
1544 pNewRedl->SetStart( *pREnd, pStt );
1545 else
1546 pNewRedl->SetEnd( *pRStt, pEnd );
1547 break;
1548
1549 case SwComparePosition::CollideStart:
1550 case SwComparePosition::CollideEnd:
1551 if( pRedl->IsOwnRedline( *pNewRedl ) &&
1552 pRedl->CanCombine( *pNewRedl ) )
1553 {
1554 if( IsHideChanges( meRedlineFlags ))
1555 {
1556 // Before we can merge, we make it visible!
1557 // We insert temporarily so that pNew is
1558 // also dealt with when moving the indices.
1559 mpRedlineTable->Insert(pNewRedl);
1560 pRedl->Show(0, mpRedlineTable->GetPos(pRedl));
1561 mpRedlineTable->Remove( pNewRedl );
1562 pRStt = pRedl->Start();
1563 pREnd = pRedl->End();
1564 }
1565
1566 // If that's the case we can merge it, meaning
1567 // the new one covers this well
1568 if( SwComparePosition::CollideStart == eCmpPos )
1569 pNewRedl->SetStart( *pRStt, pStt );
1570 else
1571 pNewRedl->SetEnd( *pREnd, pEnd );
1572
1573 // delete current (below), and restart process with
1574 // previous
1575 SwRedlineTable::size_type nToBeDeleted = n;
1576 bDec = true;
1577
1578 if( *(pNewRedl->Start()) <= *pREnd )
1579 {
1580 // Whoooah, we just extended the new 'redline'
1581 // beyond previous redlines, so better start
1582 // again. Of course this is not supposed to
1583 // happen, and in an ideal world it doesn't,
1584 // but unfortunately this code is buggy and
1585 // totally rotten so it does happen and we
1586 // better fix it.
1587 n = 0;
1588 bDec = true;
1589 }
1590
1591 mpRedlineTable->DeleteAndDestroy( nToBeDeleted );
1592 }
1593 break;
1594 default:
1595 break;
1596 }
1597 break;
1598
1599 case RedlineType::Insert:
1600 {
1601 // b62341295: Do not throw away redlines
1602 // even if they are not allowed to be combined
1603 RedlineFlags eOld = meRedlineFlags;
1604 if( !( eOld & RedlineFlags::DontCombineRedlines ) &&
1605 pRedl->IsOwnRedline( *pNewRedl ) )
1606 {
1607
1608 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
1609 // The ShowMode needs to be retained!
1610 meRedlineFlags = eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore);
1611 switch( eCmpPos )
1612 {
1613 case SwComparePosition::Equal:
1614 bCompress = true;
1615 mpRedlineTable->DeleteAndDestroy( n );
1616 bDec = true;
1617 [[fallthrough]];
1618
1619 case SwComparePosition::Inside:
1620 if( bCallDelete )
1621 {
1622 // DeleteAndJoin does not yield the
1623 // desired result if there is no paragraph to
1624 // join with, i.e. at the end of the document.
1625 // For this case, we completely delete the
1626 // paragraphs (if, of course, we also start on
1627 // a paragraph boundary).
1628 if( (pStt->nContent == 0) &&
1629 pEnd->nNode.GetNode().IsEndNode() )
1630 {
1631 pEnd->nNode--;
1632 pEnd->nContent.Assign(
1633 pEnd->nNode.GetNode().GetTextNode(), 0);
1634 m_rDoc.getIDocumentContentOperations().DelFullPara( *pNewRedl );
1635 }
1636 else
1637 m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pNewRedl );
1638
1639 bCompress = true;
1640 }
1641 if( !bCallDelete && !bDec && *pEnd == *pREnd )
1642 {
1643 m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pNewRedl );
1644 bCompress = true;
1645 }
1646 else if ( bCallDelete || !bDec )
1647 {
1648 // delete new redline, except in some cases of fallthrough from previous
1649 // case ::Equal (eg. same portion w:del in w:ins in OOXML import)
1650 delete pNewRedl;
1651 pNewRedl = nullptr;
1652 }
1653 break;
1654
1655 case SwComparePosition::Outside:
1656 {
1657 mpRedlineTable->Remove( n );
1658 bDec = true;
1659 if( bCallDelete )
1660 {
1661 TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1662 m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pRedl );
1663 n = 0; // re-initialize
1664 }
1665 delete pRedl;
1666 }
1667 break;
1668
1669 case SwComparePosition::OverlapBefore:
1670 {
1671 SwPaM aPam( *pRStt, *pEnd );
1672
1673 if( *pEnd == *pREnd )
1674 mpRedlineTable->DeleteAndDestroy( n );
1675 else
1676 {
1677 pRedl->SetStart( *pEnd, pRStt );
1678 // re-insert
1679 mpRedlineTable->Remove( n );
1680 mpRedlineTable->Insert( pRedl, n );
1681 }
1682
1683 if( bCallDelete )
1684 {
1685 TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1686 m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
1687 n = 0; // re-initialize
1688 }
1689 bDec = true;
1690 }
1691 break;
1692
1693 case SwComparePosition::OverlapBehind:
1694 {
1695 SwPaM aPam( *pStt, *pREnd );
1696
1697 if( *pStt == *pRStt )
1698 {
1699 mpRedlineTable->DeleteAndDestroy( n );
1700 bDec = true;
1701 }
1702 else
1703 pRedl->SetEnd( *pStt, pREnd );
1704
1705 if( bCallDelete )
1706 {
1707 TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1708 m_rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam );
1709 n = 0; // re-initialize
1710 bDec = true;
1711 }
1712 }
1713 break;
1714 default:
1715 break;
1716 }
1717
1718 meRedlineFlags = eOld;
1719 }
1720 else
1721 {
1722 // it may be necessary to split the existing redline in
1723 // two. In this case, pRedl will be changed to cover
1724 // only part of its former range, and pNew will cover
1725 // the remainder.
1726 SwRangeRedline* pNew = nullptr;
1727
1728 switch( eCmpPos )
1729 {
1730 case SwComparePosition::Equal:
1731 {
1732 pRedl->PushData( *pNewRedl );
1733 delete pNewRedl;
1734 pNewRedl = nullptr;
1735 if( IsHideChanges( meRedlineFlags ))
1736 {
1737 pRedl->Hide(0, mpRedlineTable->GetPos(pRedl));
1738 }
1739 bCompress = true;
1740 }
1741 break;
1742
1743 case SwComparePosition::Inside:
1744 {
1745 if( *pRStt == *pStt )
1746 {
1747 // #i97421#
1748 // redline w/out extent loops
1749 if (*pStt != *pEnd)
1750 {
1751 pNewRedl->PushData( *pRedl, false );
1752 pRedl->SetStart( *pEnd, pRStt );
1753 // re-insert
1754 mpRedlineTable->Remove( n );
1755 mpRedlineTable->Insert( pRedl, n );
1756 bDec = true;
1757 }
1758 }
1759 else
1760 {
1761 pNewRedl->PushData( *pRedl, false );
1762 if( *pREnd != *pEnd )
1763 {
1764 pNew = new SwRangeRedline( *pRedl );
1765 pNew->SetStart( *pEnd );
1766 }
1767 pRedl->SetEnd( *pStt, pREnd );
1768 if( !pRedl->HasValidRange() )
1769 {
1770 // re-insert
1771 mpRedlineTable->Remove( n );
1772 mpRedlineTable->Insert( pRedl, n );
1773 }
1774 }
1775 }
1776 break;
1777
1778 case SwComparePosition::Outside:
1779 {
1780 pRedl->PushData( *pNewRedl );
1781 if( *pEnd == *pREnd )
1782 {
1783 pNewRedl->SetEnd( *pRStt, pEnd );
1784 }
1785 else if (*pStt == *pRStt)
1786 {
1787 pNewRedl->SetStart(*pREnd, pStt);
1788 }
1789 else
1790 {
1791 pNew = new SwRangeRedline( *pNewRedl );
1792 pNew->SetEnd( *pRStt );
1793 pNewRedl->SetStart( *pREnd, pStt );
1794 }
1795 bCompress = true;
1796 }
1797 break;
1798
1799 case SwComparePosition::OverlapBefore:
1800 {
1801 if( *pEnd == *pREnd )
1802 {
1803 pRedl->PushData( *pNewRedl );
1804 pNewRedl->SetEnd( *pRStt, pEnd );
1805 if( IsHideChanges( meRedlineFlags ))
1806 {
1807 mpRedlineTable->Insert(pNewRedl);
1808 pRedl->Hide(0, mpRedlineTable->GetPos(pRedl));
1809 mpRedlineTable->Remove( pNewRedl );
1810 }
1811 }
1812 else
1813 {
1814 pNew = new SwRangeRedline( *pRedl );
1815 pNew->PushData( *pNewRedl );
1816 pNew->SetEnd( *pEnd );
1817 pNewRedl->SetEnd( *pRStt, pEnd );
1818 pRedl->SetStart( *pNew->End(), pRStt ) ;
1819 // re-insert
1820 mpRedlineTable->Remove( n );
1821 mpRedlineTable->Insert( pRedl );
1822 bDec = true;
1823 }
1824 }
1825 break;
1826
1827 case SwComparePosition::OverlapBehind:
1828 {
1829 if( *pStt == *pRStt )
1830 {
1831 pRedl->PushData( *pNewRedl );
1832 pNewRedl->SetStart( *pREnd, pStt );
1833 if( IsHideChanges( meRedlineFlags ))
1834 {
1835 mpRedlineTable->Insert( pNewRedl );
1836 pRedl->Hide(0, mpRedlineTable->GetPos(pRedl));
1837 mpRedlineTable->Remove( pNewRedl );
1838 }
1839 }
1840 else
1841 {
1842 pNew = new SwRangeRedline( *pRedl );
1843 pNew->PushData( *pNewRedl );
1844 pNew->SetStart( *pStt );
1845 pNewRedl->SetStart( *pREnd, pStt );
1846 pRedl->SetEnd( *pNew->Start(), pREnd );
1847 if( !pRedl->HasValidRange() )
1848 {
1849 // re-insert
1850 mpRedlineTable->Remove( n );
1851 mpRedlineTable->Insert( pRedl );
1852 }
1853 }
1854 }
1855 break;
1856 default:
1857 break;
1858 }
1859
1860 // insert the pNew part (if it exists)
1861 if( pNew )
1862 {
1863 mpRedlineTable->Insert( pNew );
1864
1865 // pNew must be deleted if Insert() wasn't
1866 // successful. But that can't happen, since pNew is
1867 // part of the original pRedl redline.
1868 // OSL_ENSURE( bRet, "Can't insert existing redline?" );
1869
1870 // restart (now with pRedl being split up)
1871 n = 0;
1872 bDec = true;
1873 }
1874 }
1875 }
1876 break;
1877
1878 case RedlineType::Format:
1879 switch( eCmpPos )
1880 {
1881 case SwComparePosition::OverlapBefore:
1882 pRedl->SetStart( *pEnd, pRStt );
1883 // re-insert
1884 mpRedlineTable->Remove( n );
1885 mpRedlineTable->Insert( pRedl, n );
1886 bDec = true;
1887 break;
1888
1889 case SwComparePosition::OverlapBehind:
1890 pRedl->SetEnd( *pStt, pREnd );
1891 break;
1892
1893 case SwComparePosition::Equal:
1894 case SwComparePosition::Outside:
1895 // Overlaps the current one completely or has the
1896 // same dimension, delete the old one
1897 mpRedlineTable->DeleteAndDestroy( n );
1898 bDec = true;
1899 break;
1900
1901 case SwComparePosition::Inside:
1902 // Overlaps the current one completely,
1903 // split or shorten the new one
1904 if( *pEnd != *pREnd )
1905 {
1906 if( *pEnd != *pRStt )
1907 {
1908 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
1909 pNew->SetStart( *pEnd );
1910 pRedl->SetEnd( *pStt, pREnd );
1911 if( ( *pStt == *pRStt ) &&
1912 ( pRedl->GetContentIdx() == nullptr ) )
1913 mpRedlineTable->DeleteAndDestroy( n );
1914 AppendRedline( pNew, bCallDelete );
1915 n = 0; // re-initialize
1916 bDec = true;
1917 }
1918 }
1919 else
1920 pRedl->SetEnd( *pStt, pREnd );
1921 break;
1922 default:
1923 break;
1924 }
1925 break;
1926 default:
1927 break;
1928 }
1929 break;
1930
1931 case RedlineType::Format:
1932 switch( pRedl->GetType() )
1933 {
1934 case RedlineType::Insert:
1935 case RedlineType::Delete:
1936 switch( eCmpPos )
1937 {
1938 case SwComparePosition::OverlapBefore:
1939 pNewRedl->SetEnd( *pRStt, pEnd );
1940 break;
1941
1942 case SwComparePosition::OverlapBehind:
1943 pNewRedl->SetStart( *pREnd, pStt );
1944 break;
1945
1946 case SwComparePosition::Equal:
1947 case SwComparePosition::Inside:
1948 delete pNewRedl;
1949 pNewRedl = nullptr;
1950 break;
1951
1952 case SwComparePosition::Outside:
1953 // Overlaps the current one completely,
1954 // split or shorten the new one
1955 if (*pEnd == *pREnd)
1956 {
1957 pNewRedl->SetEnd(*pRStt, pEnd);
1958 }
1959 else if (*pStt == *pRStt)
1960 {
1961 pNewRedl->SetStart(*pREnd, pStt);
1962 }
1963 else
1964 {
1965 SwRangeRedline* pNew = new SwRangeRedline( *pNewRedl );
1966 pNew->SetStart( *pREnd );
1967 pNewRedl->SetEnd( *pRStt, pEnd );
1968 AppendRedline( pNew, bCallDelete );
1969 n = 0; // re-initialize
1970 bDec = true;
1971 }
1972 break;
1973 default:
1974 break;
1975 }
1976 break;
1977 case RedlineType::Format:
1978 switch( eCmpPos )
1979 {
1980 case SwComparePosition::Outside:
1981 case SwComparePosition::Equal:
1982 {
1983 // Overlaps the current one completely or has the
1984 // same dimension, delete the old one
1985 mpRedlineTable->DeleteAndDestroy( n );
1986 bDec = true;
1987 }
1988 break;
1989
1990 case SwComparePosition::Inside:
1991 if( pRedl->IsOwnRedline( *pNewRedl ) &&
1992 pRedl->CanCombine( *pNewRedl ))
1993 {
1994 // own one can be ignored completely
1995 delete pNewRedl;
1996 pNewRedl = nullptr;
1997 }
1998 else if( *pREnd == *pEnd )
1999 // or else only shorten the current one
2000 pRedl->SetEnd( *pStt, pREnd );
2001 else if( *pRStt == *pStt )
2002 {
2003 // or else only shorten the current one
2004 pRedl->SetStart( *pEnd, pRStt );
2005 // re-insert
2006 mpRedlineTable->Remove( n );
2007 mpRedlineTable->Insert( pRedl, n );
2008 bDec = true;
2009 }
2010 else
2011 {
2012 // If it lies completely within the current one
2013 // we need to split it
2014 SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
2015 pNew->SetStart( *pEnd );
2016 pRedl->SetEnd( *pStt, pREnd );
2017 AppendRedline( pNew, bCallDelete );
2018 n = 0; // re-initialize
2019 bDec = true;
2020 }
2021 break;
2022
2023 case SwComparePosition::OverlapBefore:
2024 case SwComparePosition::OverlapBehind:
2025 if( pRedl->IsOwnRedline( *pNewRedl ) &&
2026 pRedl->CanCombine( *pNewRedl ))
2027 {
2028 // If that's the case we can merge it, meaning
2029 // the new one covers this well
2030 if( SwComparePosition::OverlapBehind == eCmpPos )
2031 pNewRedl->SetStart( *pRStt, pStt );
2032 else
2033 pNewRedl->SetEnd( *pREnd, pEnd );
2034 mpRedlineTable->DeleteAndDestroy( n );
2035 bDec = false;
2036 }
2037 else if( SwComparePosition::OverlapBehind == eCmpPos )
2038 pNewRedl->SetStart( *pREnd, pStt );
2039 else
2040 pNewRedl->SetEnd( *pRStt, pEnd );
2041 break;
2042
2043 case SwComparePosition::CollideEnd:
2044 if( pRedl->IsOwnRedline( *pNewRedl ) &&
2045 pRedl->CanCombine( *pNewRedl ) && n &&
2046 *(*mpRedlineTable)[ n-1 ]->End() < *pStt )
2047 {
2048 // If that's the case we can merge it, meaning
2049 // the new one covers this well
2050 pNewRedl->SetEnd( *pREnd, pEnd );
2051 mpRedlineTable->DeleteAndDestroy( n );
2052 bDec = true;
2053 }
2054 break;
2055 case SwComparePosition::CollideStart:
2056 if( pRedl->IsOwnRedline( *pNewRedl ) &&
2057 pRedl->CanCombine( *pNewRedl ) &&
2058 n+1 < mpRedlineTable->size() &&
2059 *(*mpRedlineTable)[ n+1 ]->Start() < *pEnd )
2060 {
2061 // If that's the case we can merge it, meaning
2062 // the new one covers this well
2063 pNewRedl->SetStart( *pRStt, pStt );
2064 mpRedlineTable->DeleteAndDestroy( n );
2065 bDec = true;
2066 }
2067 break;
2068 default:
2069 break;
2070 }
2071 break;
2072 default:
2073 break;
2074 }
2075 break;
2076
2077 case RedlineType::FmtColl:
2078 // How should we behave here?
2079 // insert as is
2080 break;
2081 default:
2082 break;
2083 }
2084 }
2085
2086 if( pNewRedl )
2087 {
2088 if( ( *pStt == *pEnd ) &&
2089 ( pNewRedl->GetContentIdx() == nullptr ) )
2090 { // Do not insert empty redlines
2091 delete pNewRedl;
2092 pNewRedl = nullptr;
2093 }
2094 else
2095 {
2096 if ( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2097 {
2098 if ( pStt->nContent != 0 )
2099 {
2100 // tdf#119571 update the style of the joined paragraph
2101 // after a partially deleted paragraph to show its correct style
2102 // in "Show changes" mode, too. All removed paragraphs
2103 // get the style of the first (partially deleted) paragraph
2104 // to avoid text insertion with bad style in the deleted
2105 // area later.
2106
2107 SwContentNode* pDelNd = pStt->nNode.GetNode().GetContentNode();
2108 SwContentNode* pTextNd = pEnd->nNode.GetNode().GetContentNode();
2109 SwTextNode* pDelNode = pStt->nNode.GetNode().GetTextNode();
2110 SwTextNode* pTextNode;
2111 SwNodeIndex aIdx( pEnd->nNode.GetNode() );
2112 bool bFirst = true;
2113
2114 while (pDelNode != nullptr && pTextNd != nullptr && pDelNd->GetIndex() < pTextNd->GetIndex())
2115 {
2116 pTextNode = pTextNd->GetTextNode();
2117 if (pTextNode && pDelNode != pTextNode )
2118 {
2119 SwPosition aPos(aIdx);
2120
2121 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2122 {
2123 bCompress = true;
2124
2125 // split redline to store ExtraData per paragraphs
2126 SwRangeRedline* pPar = new SwRangeRedline( *pNewRedl );
2127 pPar->SetStart( aPos );
2128 pNewRedl->SetEnd( aPos );
2129
2130 // get extradata for reset formatting of the modified paragraph
2131 SwRedlineExtraData_FormatColl* pExtraData = lcl_CopyStyle(aPos, *pStt, false);
2132 if (pExtraData)
2133 {
2134 std::unique_ptr<SwRedlineExtraData_FormatColl> xRedlineExtraData;
2135 if (!bFirst)
2136 pExtraData->SetFormatAll(false);
2137 xRedlineExtraData.reset(pExtraData);
2138 pPar->SetExtraData( xRedlineExtraData.get() );
2139 }
2140 mpRedlineTable->Insert( pPar );
2141 }
2142
2143 // modify paragraph formatting
2144 lcl_CopyStyle(*pStt, aPos);
2145 }
2146 pTextNd = SwNodes::GoPrevious( &aIdx );
2147
2148 if (bFirst)
2149 bFirst = false;
2150 }
2151 }
2152 }
2153 bool const ret = mpRedlineTable->Insert( pNewRedl );
2154 assert(ret || !pNewRedl);
2155 if (ret && !pNewRedl)
2156 {
2157 bMerged = true; // treat InsertWithValidRanges as "merge"
2158 }
2159 }
2160 }
2161
2162 if( bCompress )
2163 CompressRedlines();
2164 }
2165 else
2166 {
2167 if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2168 {
2169 RedlineFlags eOld = meRedlineFlags;
2170 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2171 // The ShowMode needs to be retained!
2172 meRedlineFlags = eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore);
2173 m_rDoc.getIDocumentContentOperations().DeleteAndJoin( *pNewRedl );
2174 meRedlineFlags = eOld;
2175 }
2176 delete pNewRedl;
2177 pNewRedl = nullptr;
2178 }
2179 CHECK_REDLINE( *this )
2180
2181 return (nullptr != pNewRedl)
2182 ? AppendResult::APPENDED
2183 : (bMerged ? AppendResult::MERGED : AppendResult::IGNORED);
2184 }
2185
AppendTableRowRedline(SwTableRowRedline * pNewRedl)2186 bool DocumentRedlineManager::AppendTableRowRedline( SwTableRowRedline* pNewRedl )
2187 {
2188 // #TODO - equivalent for 'SwTableRowRedline'
2189 /*
2190 CHECK_REDLINE( this )
2191 */
2192
2193 if (IsRedlineOn() && !IsShowOriginal(meRedlineFlags))
2194 {
2195 // #TODO - equivalent for 'SwTableRowRedline'
2196 /*
2197 pNewRedl->InvalidateRange();
2198 */
2199
2200 // Make equivalent of 'AppendRedline' checks inside here too
2201
2202 mpExtraRedlineTable->Insert( pNewRedl );
2203 }
2204 else
2205 {
2206 // TO DO - equivalent for 'SwTableRowRedline'
2207 /*
2208 if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2209 {
2210 RedlineFlags eOld = meRedlineFlags;
2211 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2212 // The ShowMode needs to be retained!
2213 meRedlineFlags = eOld & ~(RedlineFlags::On | RedlineFlags::Ignore);
2214 DeleteAndJoin( *pNewRedl );
2215 meRedlineFlags = eOld;
2216 }
2217 delete pNewRedl, pNewRedl = 0;
2218 */
2219 }
2220 // #TODO - equivalent for 'SwTableRowRedline'
2221 /*
2222 CHECK_REDLINE( this )
2223 */
2224
2225 return nullptr != pNewRedl;
2226 }
2227
AppendTableCellRedline(SwTableCellRedline * pNewRedl)2228 bool DocumentRedlineManager::AppendTableCellRedline( SwTableCellRedline* pNewRedl )
2229 {
2230 // #TODO - equivalent for 'SwTableCellRedline'
2231 /*
2232 CHECK_REDLINE( this )
2233 */
2234
2235 if (IsRedlineOn() && !IsShowOriginal(meRedlineFlags))
2236 {
2237 // #TODO - equivalent for 'SwTableCellRedline'
2238 /*
2239 pNewRedl->InvalidateRange();
2240 */
2241
2242 // Make equivalent of 'AppendRedline' checks inside here too
2243
2244 mpExtraRedlineTable->Insert( pNewRedl );
2245 }
2246 else
2247 {
2248 // TO DO - equivalent for 'SwTableCellRedline'
2249 /*
2250 if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2251 {
2252 RedlineFlags eOld = meRedlineFlags;
2253 // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2254 // The ShowMode needs to be retained!
2255 meRedlineFlags = eOld & ~(RedlineFlags::On | RedlineFlags::Ignore);
2256 DeleteAndJoin( *pNewRedl );
2257 meRedlineFlags = eOld;
2258 }
2259 delete pNewRedl, pNewRedl = 0;
2260 */
2261 }
2262 // #TODO - equivalent for 'SwTableCellRedline'
2263 /*
2264 CHECK_REDLINE( this )
2265 */
2266
2267 return nullptr != pNewRedl;
2268 }
2269
CompressRedlines()2270 void DocumentRedlineManager::CompressRedlines()
2271 {
2272 CHECK_REDLINE( *this )
2273
2274 void (SwRangeRedline::*pFnc)(sal_uInt16, size_t) = nullptr;
2275 RedlineFlags eShow = RedlineFlags::ShowMask & meRedlineFlags;
2276 if( eShow == (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete))
2277 pFnc = &SwRangeRedline::Show;
2278 else if (eShow == RedlineFlags::ShowInsert)
2279 pFnc = &SwRangeRedline::Hide;
2280
2281 // Try to merge identical ones
2282 for( SwRedlineTable::size_type n = 1; n < mpRedlineTable->size(); ++n )
2283 {
2284 SwRangeRedline* pPrev = (*mpRedlineTable)[ n-1 ],
2285 * pCur = (*mpRedlineTable)[ n ];
2286 const SwPosition* pPrevStt = pPrev->Start(),
2287 * pPrevEnd = pPrevStt == pPrev->GetPoint()
2288 ? pPrev->GetMark() : pPrev->GetPoint();
2289 const SwPosition* pCurStt = pCur->Start(),
2290 * pCurEnd = pCurStt == pCur->GetPoint()
2291 ? pCur->GetMark() : pCur->GetPoint();
2292 if( *pPrevEnd == *pCurStt && pPrev->CanCombine( *pCur ) &&
2293 pPrevStt->nNode.GetNode().StartOfSectionNode() ==
2294 pCurEnd->nNode.GetNode().StartOfSectionNode() &&
2295 !pCurEnd->nNode.GetNode().StartOfSectionNode()->IsTableNode() )
2296 {
2297 // we then can merge them
2298 SwRedlineTable::size_type nPrevIndex = n-1;
2299 pPrev->Show(0, nPrevIndex);
2300 pCur->Show(0, n);
2301
2302 pPrev->SetEnd( *pCur->End() );
2303 mpRedlineTable->DeleteAndDestroy( n );
2304 --n;
2305 if( pFnc )
2306 (pPrev->*pFnc)(0, nPrevIndex);
2307 }
2308 }
2309 CHECK_REDLINE( *this )
2310
2311 // #TODO - add 'SwExtraRedlineTable' also ?
2312 }
2313
SplitRedline(const SwPaM & rRange)2314 bool DocumentRedlineManager::SplitRedline( const SwPaM& rRange )
2315 {
2316 bool bChg = false;
2317 SwRedlineTable::size_type n = 0;
2318 const SwPosition* pStt = rRange.Start();
2319 const SwPosition* pEnd = rRange.End();
2320 GetRedline( *pStt, &n );
2321 for ( ; n < mpRedlineTable->size(); ++n)
2322 {
2323 SwRangeRedline * pRedline = (*mpRedlineTable)[ n ];
2324 SwPosition *const pRedlineStart = pRedline->Start();
2325 SwPosition *const pRedlineEnd = pRedline->End();
2326 if (*pRedlineStart <= *pStt && *pStt <= *pRedlineEnd &&
2327 *pRedlineStart <= *pEnd && *pEnd <= *pRedlineEnd)
2328 {
2329 bChg = true;
2330 int nn = 0;
2331 if (*pStt == *pRedlineStart)
2332 nn += 1;
2333 if (*pEnd == *pRedlineEnd)
2334 nn += 2;
2335
2336 SwRangeRedline* pNew = nullptr;
2337 switch( nn )
2338 {
2339 case 0:
2340 pNew = new SwRangeRedline( *pRedline );
2341 pRedline->SetEnd( *pStt, pRedlineEnd );
2342 pNew->SetStart( *pEnd );
2343 break;
2344
2345 case 1:
2346 *pRedlineStart = *pEnd;
2347 break;
2348
2349 case 2:
2350 *pRedlineEnd = *pStt;
2351 break;
2352
2353 case 3:
2354 pRedline->InvalidateRange(SwRangeRedline::Invalidation::Remove);
2355 mpRedlineTable->DeleteAndDestroy( n-- );
2356 pRedline = nullptr;
2357 break;
2358 }
2359 if (pRedline && !pRedline->HasValidRange())
2360 {
2361 // re-insert
2362 mpRedlineTable->Remove( n );
2363 mpRedlineTable->Insert( pRedline, n );
2364 }
2365 if( pNew )
2366 mpRedlineTable->Insert( pNew, n );
2367 }
2368 else if (*pEnd < *pRedlineStart)
2369 break;
2370 }
2371 return bChg;
2372
2373 // #TODO - add 'SwExtraRedlineTable' also ?
2374 }
2375
DeleteRedline(const SwPaM & rRange,bool bSaveInUndo,RedlineType nDelType)2376 bool DocumentRedlineManager::DeleteRedline( const SwPaM& rRange, bool bSaveInUndo,
2377 RedlineType nDelType )
2378 {
2379 if( !rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() )
2380 return false;
2381
2382 bool bChg = false;
2383
2384 if (bSaveInUndo && m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2385 {
2386 std::unique_ptr<SwUndoRedline> pUndo(new SwUndoRedline( SwUndoId::REDLINE, rRange ));
2387 if( pUndo->GetRedlSaveCount() )
2388 {
2389 m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2390 }
2391 }
2392
2393 const SwPosition* pStt = rRange.Start(),
2394 * pEnd = pStt == rRange.GetPoint() ? rRange.GetMark()
2395 : rRange.GetPoint();
2396 SwRedlineTable::size_type n = 0;
2397 GetRedline( *pStt, &n );
2398 for( ; n < mpRedlineTable->size() ; ++n )
2399 {
2400 SwRangeRedline* pRedl = (*mpRedlineTable)[ n ];
2401 if( RedlineType::Any != nDelType && nDelType != pRedl->GetType() )
2402 continue;
2403
2404 SwPosition* pRStt = pRedl->Start(),
2405 * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
2406 : pRedl->GetPoint();
2407 switch( ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ) )
2408 {
2409 case SwComparePosition::Equal:
2410 case SwComparePosition::Outside:
2411 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Remove);
2412 mpRedlineTable->DeleteAndDestroy( n-- );
2413 bChg = true;
2414 break;
2415
2416 case SwComparePosition::OverlapBefore:
2417 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Remove);
2418 pRedl->SetStart( *pEnd, pRStt );
2419 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Add);
2420 // re-insert
2421 mpRedlineTable->Remove( n );
2422 mpRedlineTable->Insert( pRedl );
2423 --n;
2424 break;
2425
2426 case SwComparePosition::OverlapBehind:
2427 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Remove);
2428 pRedl->SetEnd( *pStt, pREnd );
2429 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Add);
2430 if( !pRedl->HasValidRange() )
2431 {
2432 // re-insert
2433 mpRedlineTable->Remove( n );
2434 mpRedlineTable->Insert( pRedl );
2435 --n;
2436 }
2437 break;
2438
2439 case SwComparePosition::Inside:
2440 {
2441 // this one needs to be split
2442 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Remove);
2443 if( *pRStt == *pStt )
2444 {
2445 pRedl->SetStart( *pEnd, pRStt );
2446 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Add);
2447 // re-insert
2448 mpRedlineTable->Remove( n );
2449 mpRedlineTable->Insert( pRedl );
2450 --n;
2451 }
2452 else
2453 {
2454 SwRangeRedline* pCpy;
2455 if( *pREnd != *pEnd )
2456 {
2457 pCpy = new SwRangeRedline( *pRedl );
2458 pCpy->SetStart( *pEnd );
2459 pCpy->InvalidateRange(SwRangeRedline::Invalidation::Add);
2460 }
2461 else
2462 pCpy = nullptr;
2463 pRedl->SetEnd( *pStt, pREnd );
2464 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Add);
2465 if( !pRedl->HasValidRange() )
2466 {
2467 // re-insert
2468 mpRedlineTable->Remove( n );
2469 mpRedlineTable->Insert( pRedl );
2470 --n;
2471 }
2472 if( pCpy )
2473 mpRedlineTable->Insert( pCpy );
2474 }
2475 }
2476 break;
2477
2478 case SwComparePosition::CollideEnd:
2479 case SwComparePosition::Before:
2480 n = mpRedlineTable->size();
2481 break;
2482 default:
2483 break;
2484 }
2485 }
2486
2487 if( bChg )
2488 m_rDoc.getIDocumentState().SetModified();
2489
2490 return bChg;
2491
2492 // #TODO - add 'SwExtraRedlineTable' also ?
2493 }
2494
DeleteRedline(const SwStartNode & rNode,bool bSaveInUndo,RedlineType nDelType)2495 bool DocumentRedlineManager::DeleteRedline( const SwStartNode& rNode, bool bSaveInUndo,
2496 RedlineType nDelType )
2497 {
2498 SwPaM aTemp(*rNode.EndOfSectionNode(), rNode);
2499 return DeleteRedline(aTemp, bSaveInUndo, nDelType);
2500 }
2501
GetRedlinePos(const SwNode & rNd,RedlineType nType) const2502 SwRedlineTable::size_type DocumentRedlineManager::GetRedlinePos( const SwNode& rNd, RedlineType nType ) const
2503 {
2504 const sal_uLong nNdIdx = rNd.GetIndex();
2505 for( SwRedlineTable::size_type n = 0; n < mpRedlineTable->size() ; ++n )
2506 {
2507 const SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
2508 sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
2509 nMk = pTmp->GetMark()->nNode.GetIndex();
2510 if( nPt < nMk ) { long nTmp = nMk; nMk = nPt; nPt = nTmp; }
2511
2512 if( ( RedlineType::Any == nType || nType == pTmp->GetType()) &&
2513 nMk <= nNdIdx && nNdIdx <= nPt )
2514 return n;
2515
2516 if( nMk > nNdIdx )
2517 break;
2518 }
2519 return SwRedlineTable::npos;
2520
2521 // #TODO - add 'SwExtraRedlineTable' also ?
2522 }
2523
GetRedline(const SwPosition & rPos,SwRedlineTable::size_type * pFndPos) const2524 const SwRangeRedline* DocumentRedlineManager::GetRedline( const SwPosition& rPos,
2525 SwRedlineTable::size_type* pFndPos ) const
2526 {
2527 SwRedlineTable::size_type nO = mpRedlineTable->size(), nM, nU = 0;
2528 if( nO > 0 )
2529 {
2530 nO--;
2531 while( nU <= nO )
2532 {
2533 nM = nU + ( nO - nU ) / 2;
2534 const SwRangeRedline* pRedl = (*mpRedlineTable)[ nM ];
2535 const SwPosition* pStt = pRedl->Start();
2536 const SwPosition* pEnd = pStt == pRedl->GetPoint()
2537 ? pRedl->GetMark()
2538 : pRedl->GetPoint();
2539 if( pEnd == pStt
2540 ? *pStt == rPos
2541 : ( *pStt <= rPos && rPos < *pEnd ) )
2542 {
2543 while( nM && rPos == *(*mpRedlineTable)[ nM - 1 ]->End() &&
2544 rPos == *(*mpRedlineTable)[ nM - 1 ]->Start() )
2545 {
2546 --nM;
2547 pRedl = (*mpRedlineTable)[ nM ];
2548 }
2549 // if there are format and insert changes in the same position
2550 // show insert change first.
2551 // since the redlines are sorted by position, only check the redline
2552 // before and after the current redline
2553 if( RedlineType::Format == pRedl->GetType() )
2554 {
2555 if( nM && rPos >= *(*mpRedlineTable)[ nM - 1 ]->Start() &&
2556 rPos <= *(*mpRedlineTable)[ nM - 1 ]->End() &&
2557 ( RedlineType::Insert == (*mpRedlineTable)[ nM - 1 ]->GetType() ) )
2558 {
2559 --nM;
2560 pRedl = (*mpRedlineTable)[ nM ];
2561 }
2562 else if( ( nM + 1 ) <= nO && rPos >= *(*mpRedlineTable)[ nM + 1 ]->Start() &&
2563 rPos <= *(*mpRedlineTable)[ nM + 1 ]->End() &&
2564 ( RedlineType::Insert == (*mpRedlineTable)[ nM + 1 ]->GetType() ) )
2565 {
2566 ++nM;
2567 pRedl = (*mpRedlineTable)[ nM ];
2568 }
2569 }
2570
2571 if( pFndPos )
2572 *pFndPos = nM;
2573 return pRedl;
2574 }
2575 else if( *pEnd <= rPos )
2576 nU = nM + 1;
2577 else if( nM == 0 )
2578 {
2579 if( pFndPos )
2580 *pFndPos = nU;
2581 return nullptr;
2582 }
2583 else
2584 nO = nM - 1;
2585 }
2586 }
2587 if( pFndPos )
2588 *pFndPos = nU;
2589 return nullptr;
2590
2591 // #TODO - add 'SwExtraRedlineTable' also ?
2592 }
2593
AcceptRedline(SwRedlineTable::size_type nPos,bool bCallDelete)2594 bool DocumentRedlineManager::AcceptRedline( SwRedlineTable::size_type nPos, bool bCallDelete )
2595 {
2596 bool bRet = false;
2597
2598 // Switch to visible in any case
2599 if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
2600 (RedlineFlags::ShowMask & meRedlineFlags) )
2601 SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | meRedlineFlags );
2602
2603 SwRangeRedline* pTmp = (*mpRedlineTable)[ nPos ];
2604 if( pTmp->HasMark() && pTmp->IsVisible() )
2605 {
2606 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2607 {
2608 SwRewriter aRewriter;
2609
2610 aRewriter.AddRule(UndoArg1, pTmp->GetDescr());
2611 m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::ACCEPT_REDLINE, &aRewriter);
2612 }
2613
2614 int nLoopCnt = 2;
2615 sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2616
2617 do {
2618
2619 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2620 {
2621 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
2622 std::make_unique<SwUndoAcceptRedline>(*pTmp) );
2623 }
2624
2625 bRet |= lcl_AcceptRedline( *mpRedlineTable, nPos, bCallDelete );
2626
2627 if( nSeqNo )
2628 {
2629 if( SwRedlineTable::npos == nPos )
2630 nPos = 0;
2631 SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
2632 ? mpRedlineTable->FindNextSeqNo( nSeqNo, nPos )
2633 : mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos );
2634 if( SwRedlineTable::npos != nFndPos || ( 0 != ( --nLoopCnt ) &&
2635 SwRedlineTable::npos != ( nFndPos =
2636 mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos ))) )
2637 {
2638 nPos = nFndPos;
2639 pTmp = (*mpRedlineTable)[ nPos ];
2640 }
2641 else
2642 nLoopCnt = 0;
2643 }
2644 else
2645 nLoopCnt = 0;
2646
2647 } while( nLoopCnt );
2648
2649 if( bRet )
2650 {
2651 CompressRedlines();
2652 m_rDoc.getIDocumentState().SetModified();
2653 }
2654
2655 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2656 {
2657 m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
2658 }
2659 }
2660 return bRet;
2661
2662 // #TODO - add 'SwExtraRedlineTable' also ?
2663 }
2664
AcceptRedline(const SwPaM & rPam,bool bCallDelete)2665 bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool bCallDelete )
2666 {
2667 // Switch to visible in any case
2668 if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
2669 (RedlineFlags::ShowMask & meRedlineFlags) )
2670 SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | meRedlineFlags );
2671
2672 // The Selection is only in the ContentSection. If there are Redlines
2673 // to Non-ContentNodes before or after that, then the Selections
2674 // expand to them.
2675 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2676 lcl_AdjustRedlineRange( aPam );
2677
2678 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2679 {
2680 m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::ACCEPT_REDLINE, nullptr );
2681 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAcceptRedline>( aPam ));
2682 }
2683
2684 int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, *mpRedlineTable,
2685 bCallDelete, aPam );
2686 if( nRet > 0 )
2687 {
2688 CompressRedlines();
2689 m_rDoc.getIDocumentState().SetModified();
2690 }
2691 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2692 {
2693 OUString aTmpStr;
2694
2695 {
2696 SwRewriter aRewriter;
2697 aRewriter.AddRule(UndoArg1, OUString::number(nRet));
2698 aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
2699 }
2700
2701 SwRewriter aRewriter;
2702 aRewriter.AddRule(UndoArg1, aTmpStr);
2703
2704 m_rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::ACCEPT_REDLINE, &aRewriter );
2705 }
2706 return nRet != 0;
2707
2708 // #TODO - add 'SwExtraRedlineTable' also ?
2709 }
2710
AcceptRedlineParagraphFormatting(const SwPaM & rPam)2711 void DocumentRedlineManager::AcceptRedlineParagraphFormatting( const SwPaM &rPam )
2712 {
2713 const SwPosition* pStt = rPam.Start(),
2714 * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
2715 : rPam.GetPoint();
2716
2717 const sal_uLong nSttIdx = pStt->nNode.GetIndex();
2718 const sal_uLong nEndIdx = pEnd->nNode.GetIndex();
2719
2720 for( SwRedlineTable::size_type n = 0; n < mpRedlineTable->size() ; ++n )
2721 {
2722 const SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
2723 sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
2724 nMk = pTmp->GetMark()->nNode.GetIndex();
2725 if( nPt < nMk ) { long nTmp = nMk; nMk = nPt; nPt = nTmp; }
2726
2727 if( RedlineType::ParagraphFormat == pTmp->GetType() &&
2728 ( (nSttIdx <= nMk && nMk <= nEndIdx) || (nSttIdx <= nPt && nPt <= nEndIdx) ) )
2729 AcceptRedline( n, false );
2730
2731 if( nMk > nEndIdx )
2732 break;
2733 }
2734 }
2735
RejectRedline(SwRedlineTable::size_type nPos,bool bCallDelete)2736 bool DocumentRedlineManager::RejectRedline( SwRedlineTable::size_type nPos, bool bCallDelete )
2737 {
2738 bool bRet = false;
2739
2740 // Switch to visible in any case
2741 if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
2742 (RedlineFlags::ShowMask & meRedlineFlags) )
2743 SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | meRedlineFlags );
2744
2745 SwRangeRedline* pTmp = (*mpRedlineTable)[ nPos ];
2746 if( pTmp->HasMark() && pTmp->IsVisible() )
2747 {
2748 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2749 {
2750 SwRewriter aRewriter;
2751
2752 aRewriter.AddRule(UndoArg1, pTmp->GetDescr());
2753 m_rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::REJECT_REDLINE, &aRewriter);
2754 }
2755
2756 int nLoopCnt = 2;
2757 sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2758
2759 do {
2760
2761 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2762 {
2763 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
2764 std::make_unique<SwUndoRejectRedline>( *pTmp ) );
2765 }
2766
2767 bRet |= lcl_RejectRedline( *mpRedlineTable, nPos, bCallDelete );
2768
2769 if( nSeqNo )
2770 {
2771 if( SwRedlineTable::npos == nPos )
2772 nPos = 0;
2773 SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
2774 ? mpRedlineTable->FindNextSeqNo( nSeqNo, nPos )
2775 : mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos );
2776 if( SwRedlineTable::npos != nFndPos || ( 0 != ( --nLoopCnt ) &&
2777 SwRedlineTable::npos != ( nFndPos =
2778 mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos ))) )
2779 {
2780 nPos = nFndPos;
2781 pTmp = (*mpRedlineTable)[ nPos ];
2782 }
2783 else
2784 nLoopCnt = 0;
2785 }
2786 else
2787 nLoopCnt = 0;
2788
2789 } while( nLoopCnt );
2790
2791 if( bRet )
2792 {
2793 CompressRedlines();
2794 m_rDoc.getIDocumentState().SetModified();
2795 }
2796
2797 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2798 {
2799 m_rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
2800 }
2801 }
2802 return bRet;
2803
2804 // #TODO - add 'SwExtraRedlineTable' also ?
2805 }
2806
RejectRedline(const SwPaM & rPam,bool bCallDelete)2807 bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool bCallDelete )
2808 {
2809 // Switch to visible in any case
2810 if( (RedlineFlags::ShowInsert | RedlineFlags::ShowDelete) !=
2811 (RedlineFlags::ShowMask & meRedlineFlags) )
2812 SetRedlineFlags( RedlineFlags::ShowInsert | RedlineFlags::ShowDelete | meRedlineFlags );
2813
2814 // The Selection is only in the ContentSection. If there are Redlines
2815 // to Non-ContentNodes before or after that, then the Selections
2816 // expand to them.
2817 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2818 lcl_AdjustRedlineRange( aPam );
2819
2820 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2821 {
2822 m_rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::REJECT_REDLINE, nullptr );
2823 m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoRejectRedline>(aPam) );
2824 }
2825
2826 int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, *mpRedlineTable,
2827 bCallDelete, aPam );
2828 if( nRet > 0 )
2829 {
2830 CompressRedlines();
2831 m_rDoc.getIDocumentState().SetModified();
2832 }
2833 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2834 {
2835 OUString aTmpStr;
2836
2837 {
2838 SwRewriter aRewriter;
2839 aRewriter.AddRule(UndoArg1, OUString::number(nRet));
2840 aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
2841 }
2842
2843 SwRewriter aRewriter;
2844 aRewriter.AddRule(UndoArg1, aTmpStr);
2845
2846 m_rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::REJECT_REDLINE, &aRewriter );
2847 }
2848
2849 return nRet != 0;
2850
2851 // #TODO - add 'SwExtraRedlineTable' also ?
2852 }
2853
AcceptAllRedline(bool bAccept)2854 void DocumentRedlineManager::AcceptAllRedline(bool bAccept)
2855 {
2856 bool bSuccess = true;
2857 OUString sUndoStr;
2858 IDocumentUndoRedo& rUndoMgr = m_rDoc.GetIDocumentUndoRedo();
2859
2860 if (mpRedlineTable->size() > 1)
2861 {
2862 {
2863 SwRewriter aRewriter;
2864 aRewriter.AddRule(UndoArg1, OUString::number(mpRedlineTable->size()));
2865 sUndoStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
2866 }
2867
2868 SwRewriter aRewriter;
2869 aRewriter.AddRule(UndoArg1, sUndoStr);
2870 rUndoMgr.StartUndo(bAccept ? SwUndoId::ACCEPT_REDLINE : SwUndoId::REJECT_REDLINE, &aRewriter);
2871 }
2872
2873 while (!mpRedlineTable->empty() && bSuccess)
2874 {
2875 if (bAccept)
2876 bSuccess = AcceptRedline(mpRedlineTable->size() - 1, true);
2877 else
2878 bSuccess = RejectRedline(mpRedlineTable->size() - 1, true);
2879 }
2880
2881 if (!sUndoStr.isEmpty())
2882 {
2883 rUndoMgr.EndUndo(SwUndoId::EMPTY, nullptr);
2884 }
2885 }
2886
SelNextRedline(SwPaM & rPam) const2887 const SwRangeRedline* DocumentRedlineManager::SelNextRedline( SwPaM& rPam ) const
2888 {
2889 rPam.DeleteMark();
2890 rPam.SetMark();
2891
2892 SwPosition& rSttPos = *rPam.GetPoint();
2893 SwPosition aSavePos( rSttPos );
2894 bool bRestart;
2895
2896 // If the starting position points to the last valid ContentNode,
2897 // we take the next Redline in any case.
2898 SwRedlineTable::size_type n = 0;
2899 const SwRangeRedline* pFnd = GetRedlineTable().FindAtPosition( rSttPos, n );
2900 if( pFnd )
2901 {
2902 const SwPosition* pEnd = pFnd->End();
2903 if( !pEnd->nNode.GetNode().IsContentNode() )
2904 {
2905 SwNodeIndex aTmp( pEnd->nNode );
2906 SwContentNode* pCNd = SwNodes::GoPrevSection( &aTmp );
2907 if( !pCNd || ( aTmp == rSttPos.nNode &&
2908 pCNd->Len() == rSttPos.nContent.GetIndex() ))
2909 pFnd = nullptr;
2910 }
2911 if( pFnd )
2912 rSttPos = *pFnd->End();
2913 }
2914
2915 do {
2916 bRestart = false;
2917
2918 for( ; !pFnd && n < mpRedlineTable->size(); ++n )
2919 {
2920 pFnd = (*mpRedlineTable)[ n ];
2921 if( pFnd->HasMark() && pFnd->IsVisible() )
2922 {
2923 *rPam.GetMark() = *pFnd->Start();
2924 rSttPos = *pFnd->End();
2925 break;
2926 }
2927 else
2928 pFnd = nullptr;
2929 }
2930
2931 if( pFnd )
2932 {
2933 // Merge all of the same type and author that are
2934 // consecutive into one Selection.
2935 const SwPosition* pPrevEnd = pFnd->End();
2936 while( ++n < mpRedlineTable->size() )
2937 {
2938 const SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
2939 if( pTmp->HasMark() && pTmp->IsVisible() )
2940 {
2941 const SwPosition *pRStt;
2942 if( pFnd->GetType() == pTmp->GetType() &&
2943 pFnd->GetAuthor() == pTmp->GetAuthor() &&
2944 ( *pPrevEnd == *( pRStt = pTmp->Start() ) ||
2945 IsPrevPos( *pPrevEnd, *pRStt )) )
2946 {
2947 pPrevEnd = pTmp->End();
2948 rSttPos = *pPrevEnd;
2949 }
2950 else
2951 break;
2952 }
2953 }
2954 }
2955
2956 if( pFnd )
2957 {
2958 const SwRangeRedline* pSaveFnd = pFnd;
2959
2960 SwContentNode* pCNd;
2961 SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
2962 if( !pIdx->GetNode().IsContentNode() &&
2963 nullptr != ( pCNd = m_rDoc.GetNodes().GoNextSection( pIdx )) )
2964 {
2965 if( *pIdx <= rPam.GetPoint()->nNode )
2966 rPam.GetMark()->nContent.Assign( pCNd, 0 );
2967 else
2968 pFnd = nullptr;
2969 }
2970
2971 if( pFnd )
2972 {
2973 pIdx = &rPam.GetPoint()->nNode;
2974 if( !pIdx->GetNode().IsContentNode() &&
2975 nullptr != ( pCNd = SwNodes::GoPrevSection( pIdx )) )
2976 {
2977 if( *pIdx >= rPam.GetMark()->nNode )
2978 rPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
2979 else
2980 pFnd = nullptr;
2981 }
2982 }
2983
2984 if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
2985 {
2986 if( n < mpRedlineTable->size() )
2987 {
2988 bRestart = true;
2989 *rPam.GetPoint() = *pSaveFnd->End();
2990 }
2991 else
2992 {
2993 rPam.DeleteMark();
2994 *rPam.GetPoint() = aSavePos;
2995 }
2996 pFnd = nullptr;
2997 }
2998 }
2999 } while( bRestart );
3000
3001 return pFnd;
3002
3003 // #TODO - add 'SwExtraRedlineTable' also ?
3004 }
3005
SelPrevRedline(SwPaM & rPam) const3006 const SwRangeRedline* DocumentRedlineManager::SelPrevRedline( SwPaM& rPam ) const
3007 {
3008 rPam.DeleteMark();
3009 rPam.SetMark();
3010
3011 SwPosition& rSttPos = *rPam.GetPoint();
3012 SwPosition aSavePos( rSttPos );
3013 bool bRestart;
3014
3015 // If the starting position points to the last valid ContentNode,
3016 // we take the previous Redline in any case.
3017 SwRedlineTable::size_type n = 0;
3018 const SwRangeRedline* pFnd = GetRedlineTable().FindAtPosition( rSttPos, n, false );
3019 if( pFnd )
3020 {
3021 const SwPosition* pStt = pFnd->Start();
3022 if( !pStt->nNode.GetNode().IsContentNode() )
3023 {
3024 SwNodeIndex aTmp( pStt->nNode );
3025 SwContentNode* pCNd = m_rDoc.GetNodes().GoNextSection( &aTmp );
3026 if( !pCNd || ( aTmp == rSttPos.nNode &&
3027 !rSttPos.nContent.GetIndex() ))
3028 pFnd = nullptr;
3029 }
3030 if( pFnd )
3031 rSttPos = *pFnd->Start();
3032 }
3033
3034 do {
3035 bRestart = false;
3036
3037 while( !pFnd && 0 < n )
3038 {
3039 pFnd = (*mpRedlineTable)[ --n ];
3040 if( pFnd->HasMark() && pFnd->IsVisible() )
3041 {
3042 *rPam.GetMark() = *pFnd->End();
3043 rSttPos = *pFnd->Start();
3044 }
3045 else
3046 pFnd = nullptr;
3047 }
3048
3049 if( pFnd )
3050 {
3051 // Merge all of the same type and author that are
3052 // consecutive into one Selection.
3053 const SwPosition* pNextStt = pFnd->Start();
3054 while( 0 < n )
3055 {
3056 const SwRangeRedline* pTmp = (*mpRedlineTable)[ --n ];
3057 if( pTmp->HasMark() && pTmp->IsVisible() )
3058 {
3059 const SwPosition *pREnd;
3060 if( pFnd->GetType() == pTmp->GetType() &&
3061 pFnd->GetAuthor() == pTmp->GetAuthor() &&
3062 ( *pNextStt == *( pREnd = pTmp->End() ) ||
3063 IsPrevPos( *pREnd, *pNextStt )) )
3064 {
3065 pNextStt = pTmp->Start();
3066 rSttPos = *pNextStt;
3067 }
3068 else
3069 {
3070 ++n;
3071 break;
3072 }
3073 }
3074 }
3075 }
3076
3077 if( pFnd )
3078 {
3079 const SwRangeRedline* pSaveFnd = pFnd;
3080
3081 SwContentNode* pCNd;
3082 SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
3083 if( !pIdx->GetNode().IsContentNode() &&
3084 nullptr != ( pCNd = SwNodes::GoPrevSection( pIdx )) )
3085 {
3086 if( *pIdx >= rPam.GetPoint()->nNode )
3087 rPam.GetMark()->nContent.Assign( pCNd, pCNd->Len() );
3088 else
3089 pFnd = nullptr;
3090 }
3091
3092 if( pFnd )
3093 {
3094 pIdx = &rPam.GetPoint()->nNode;
3095 if( !pIdx->GetNode().IsContentNode() &&
3096 nullptr != ( pCNd = m_rDoc.GetNodes().GoNextSection( pIdx )) )
3097 {
3098 if( *pIdx <= rPam.GetMark()->nNode )
3099 rPam.GetPoint()->nContent.Assign( pCNd, 0 );
3100 else
3101 pFnd = nullptr;
3102 }
3103 }
3104
3105 if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
3106 {
3107 if( n )
3108 {
3109 bRestart = true;
3110 *rPam.GetPoint() = *pSaveFnd->Start();
3111 }
3112 else
3113 {
3114 rPam.DeleteMark();
3115 *rPam.GetPoint() = aSavePos;
3116 }
3117 pFnd = nullptr;
3118 }
3119 }
3120 } while( bRestart );
3121
3122 return pFnd;
3123
3124 // #TODO - add 'SwExtraRedlineTable' also ?
3125 }
3126
3127 // Set comment at the Redline
SetRedlineComment(const SwPaM & rPaM,const OUString & rS)3128 bool DocumentRedlineManager::SetRedlineComment( const SwPaM& rPaM, const OUString& rS )
3129 {
3130 bool bRet = false;
3131 const SwPosition* pStt = rPaM.Start(),
3132 * pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
3133 : rPaM.GetPoint();
3134 SwRedlineTable::size_type n = 0;
3135 if( GetRedlineTable().FindAtPosition( *pStt, n ) )
3136 {
3137 for( ; n < mpRedlineTable->size(); ++n )
3138 {
3139 bRet = true;
3140 SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
3141 if( pStt != pEnd && *pTmp->Start() > *pEnd )
3142 break;
3143
3144 pTmp->SetComment( rS );
3145 if( *pTmp->End() >= *pEnd )
3146 break;
3147 }
3148 }
3149 if( bRet )
3150 m_rDoc.getIDocumentState().SetModified();
3151
3152 return bRet;
3153
3154 // #TODO - add 'SwExtraRedlineTable' also ?
3155 }
3156
3157 // Create a new author if necessary
GetRedlineAuthor()3158 std::size_t DocumentRedlineManager::GetRedlineAuthor()
3159 {
3160 return SW_MOD()->GetRedlineAuthor();
3161 }
3162
3163 /// Insert new author into the Table for the Readers etc.
InsertRedlineAuthor(const OUString & rNew)3164 std::size_t DocumentRedlineManager::InsertRedlineAuthor( const OUString& rNew )
3165 {
3166 return SW_MOD()->InsertRedlineAuthor(rNew);
3167 }
3168
UpdateRedlineAttr()3169 void DocumentRedlineManager::UpdateRedlineAttr()
3170 {
3171 const SwRedlineTable& rTable = GetRedlineTable();
3172 for(SwRangeRedline* pRedl : rTable)
3173 {
3174 if( pRedl->IsVisible() )
3175 pRedl->InvalidateRange(SwRangeRedline::Invalidation::Add);
3176 }
3177
3178 // #TODO - add 'SwExtraRedlineTable' also ?
3179 }
3180
GetRedlinePassword() const3181 const uno::Sequence <sal_Int8>& DocumentRedlineManager::GetRedlinePassword() const
3182 {
3183 return maRedlinePasswd;
3184 }
3185
SetRedlinePassword(const uno::Sequence<sal_Int8> & rNewPassword)3186 void DocumentRedlineManager::SetRedlinePassword(
3187 /*[in]*/const uno::Sequence <sal_Int8>& rNewPassword)
3188 {
3189 maRedlinePasswd = rNewPassword;
3190 m_rDoc.getIDocumentState().SetModified();
3191 }
3192
3193 /// Set comment text for the Redline, which is inserted later on via
3194 /// AppendRedline. Is used by Autoformat.
3195 /// A null pointer resets the mode. The pointer is not copied, so it
3196 /// needs to stay valid!
SetAutoFormatRedlineComment(const OUString * pText,sal_uInt16 nSeqNo)3197 void DocumentRedlineManager::SetAutoFormatRedlineComment( const OUString* pText, sal_uInt16 nSeqNo )
3198 {
3199 m_rDoc.SetAutoFormatRedline( nullptr != pText );
3200 if( pText )
3201 {
3202 mpAutoFormatRedlnComment.reset( new OUString( *pText ) );
3203 }
3204 else
3205 {
3206 mpAutoFormatRedlnComment.reset();
3207 }
3208
3209 mnAutoFormatRedlnCommentNo = nSeqNo;
3210 }
3211
~DocumentRedlineManager()3212 DocumentRedlineManager::~DocumentRedlineManager()
3213 {
3214 }
3215
3216 }
3217
3218 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3219