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