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