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