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