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