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 <osl/diagnose.h>
41 #include <editeng/prntitem.hxx>
42 
43 using namespace com::sun::star;
44 
45 #ifdef DBG_UTIL
46 
47  #define ERROR_PREFIX "redline table corrupted: "
48 
49  namespace
50  {
51  // helper function for lcl_CheckRedline
52  // 1. make sure that pPos->nContent points into pPos->nNode
53  // 2. check that position is valid and doesn't point after text
54  void lcl_CheckPosition( const SwPosition* pPos )
55  {
56  assert(dynamic_cast<SwIndexReg*>(&pPos->nNode.GetNode())
57  == pPos->nContent.GetIdxReg());
58 
59  SwTextNode* pTextNode = pPos->nNode.GetNode().GetTextNode();
60  if( pTextNode == nullptr )
61  {
62  assert(pPos->nContent == 0);
63  }
64  else
65  {
66  assert(pPos->nContent >= 0 && pPos->nContent <= pTextNode->Len());
67  }
68  }
69 
70  void lcl_CheckPam( const SwPaM* pPam )
71  {
72  assert(pPam);
73  lcl_CheckPosition( pPam->GetPoint() );
74  lcl_CheckPosition( pPam->GetMark() );
75  }
76 
77  // check validity of the redline table. Checks redline bounds, and make
78  // sure the redlines are sorted and non-overlapping.
79  void lcl_CheckRedline( IDocumentRedlineAccess& redlineAccess )
80  {
81  const SwRedlineTable& rTable = redlineAccess.GetRedlineTable();
82 
83  // verify valid redline positions
84  for(SwRangeRedline* i : rTable)
85  lcl_CheckPam( i );
86 
87  for(SwRangeRedline* j : rTable)
88  {
89  // check for empty redlines
90  // note: these can destroy sorting in SwTextNode::Update()
91  // if there's another one without mark on the same pos.
92  OSL_ENSURE( ( *(j->GetPoint()) != *(j->GetMark()) ) ||
93  ( j->GetContentIdx() != nullptr ),
94  ERROR_PREFIX "empty redline" );
95  }
96 
97  // verify proper redline sorting
98  for( size_t n = 1; n < rTable.size(); ++n )
99  {
100  const SwRangeRedline* pPrev = rTable[ n-1 ];
101  const SwRangeRedline* pCurrent = rTable[ n ];
102 
103  // check redline sorting
104  SAL_WARN_IF( *pPrev->Start() > *pCurrent->Start(), "sw",
105  ERROR_PREFIX "not sorted correctly" );
106 
107  // check for overlapping redlines
108  SAL_WARN_IF( *pPrev->End() > *pCurrent->Start(), "sw",
109  ERROR_PREFIX "overlapping redlines" );
110  }
111 
112  assert(std::is_sorted(rTable.begin(), rTable.end(), CompareSwRedlineTable()));
113  }
114  }
115 
116  #define CHECK_REDLINE( pDoc ) lcl_CheckRedline( pDoc );
117 
118 #else
119 
120  #define CHECK_REDLINE( pDoc )
121 
122 #endif
123 
124 namespace sw {
125 
127 {
128  auto const pAuthType(static_cast<SwAuthorityFieldType*>(rIDFA.GetFieldType(
129  SwFieldIds::TableOfAuthorities, OUString(), false)));
130  if (pAuthType) // created on demand...
131  {
132  pAuthType->DelSequenceArray();
133  }
134  rIDFA.GetFieldType(SwFieldIds::RefPageGet, OUString(), false)->UpdateFields();
136  rIDFA.UpdateExpFields(nullptr, false);
137  rIDFA.UpdateRefFields();
138 }
139 
140 void UpdateFramesForAddDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
141 {
142  if (rDoc.IsClipBoard())
143  {
144  return;
145  }
146  // no need to call UpdateFootnoteNums for FTNNUM_PAGE:
147  // the AppendFootnote/RemoveFootnote will do it by itself!
148  rDoc.GetFootnoteIdxs().UpdateFootnote(rPam.Start()->nNode);
149  SwPosition currentStart(*rPam.Start());
150  SwTextNode * pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
151  while (!pStartNode)
152  {
153  // note: branch only taken for redlines, not fieldmarks
154  SwStartNode *const pTableOrSectionNode(
155  currentStart.nNode.GetNode().IsTableNode()
156  ? static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetTableNode())
157  : static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetSectionNode()));
158  if ( !pTableOrSectionNode )
159  {
160  SAL_WARN("sw.core", "UpdateFramesForAddDeleteRedline:: known pathology (or ChangesInRedline mode)");
161  return;
162  }
163  for (sal_uLong j = pTableOrSectionNode->GetIndex(); j <= pTableOrSectionNode->EndOfSectionIndex(); ++j)
164  {
165  pTableOrSectionNode->GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
166  }
167  for (SwRootFrame const*const pLayout : rDoc.GetAllLayouts())
168  {
169  if (pLayout->HasMergedParas())
170  {
171  if (pTableOrSectionNode->IsTableNode())
172  {
173  static_cast<SwTableNode*>(pTableOrSectionNode)->DelFrames(pLayout);
174  }
175  else
176  {
177  static_cast<SwSectionNode*>(pTableOrSectionNode)->DelFrames(pLayout);
178  }
179  }
180  }
181  currentStart.nNode = pTableOrSectionNode->EndOfSectionIndex() + 1;
182  currentStart.nContent.Assign(currentStart.nNode.GetNode().GetContentNode(), 0);
183  pStartNode = currentStart.nNode.GetNode().GetTextNode();
184  }
185  if (currentStart < *rPam.End())
186  {
187  SwTextNode * pNode(pStartNode);
188  do
189  {
190  std::vector<SwTextFrame*> frames;
192  for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
193  {
194  if (pFrame->getRootFrame()->HasMergedParas())
195  {
196  frames.push_back(pFrame);
197  }
198  // set anchored objects as deleted
199  pFrame->SetDrawObjsAsDeleted(true);
200  }
201  if (frames.empty())
202  {
203  auto const& layouts(rDoc.GetAllLayouts());
204  assert(std::none_of(layouts.begin(), layouts.end(),
205  [](SwRootFrame const*const pLayout) { return pLayout->IsHideRedlines(); }));
206  (void) layouts;
207  break;
208  }
210  SwTextNode * pLast(pNode);
211  for (SwTextFrame * pFrame : frames)
212  {
213  SwTextNode & rFirstNode(pFrame->GetMergedPara()
214  ? *pFrame->GetMergedPara()->pFirstNode
215  : *pNode);
216  assert(pNode == pStartNode
217  ? rFirstNode.GetIndex() <= pNode->GetIndex()
218  : &rFirstNode == pNode);
219  // clear old one first to avoid DelFrames confusing updates & asserts...
220  pFrame->SetMergedPara(nullptr);
221  pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
222  *pFrame, rFirstNode, eMode));
223  eMode = sw::FrameMode::New; // Existing is not idempotent!
224  // the first node of the new redline is not necessarily the first
225  // node of the merged frame, there could be another redline nearby
226  sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, *pNode, nullptr);
227  // if redline is split across table and table cell is empty, there's no redline in the cell and so no merged para
228  if (pFrame->GetMergedPara())
229  {
230  pLast = const_cast<SwTextNode*>(pFrame->GetMergedPara()->pLastNode);
231  }
232  }
233  SwNodeIndex tmp(*pLast);
234  // skip over hidden sections!
235  pNode = static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, /*bSkipHidden=*/true, /*bSkipProtect=*/false));
236  }
237  while (pNode && pNode->GetIndex() <= rPam.End()->nNode.GetIndex());
238  }
239  // fields last - SwGetRefField::UpdateField requires up-to-date frames
240  UpdateFieldsForRedline(rDoc.getIDocumentFieldsAccess()); // after footnotes
241 
242  // update SwPostItMgr / notes in the margin
243  rDoc.GetDocShell()->Broadcast(
245 }
246 
248 {
249  if (rDoc.IsClipBoard())
250  {
251  return;
252  }
253  bool isAppendObjsCalled(false);
254  rDoc.GetFootnoteIdxs().UpdateFootnote(rPam.Start()->nNode);
255  SwPosition currentStart(*rPam.Start());
256  SwTextNode * pStartNode(rPam.Start()->nNode.GetNode().GetTextNode());
257  while (!pStartNode)
258  {
259  // note: branch only taken for redlines, not fieldmarks
260  SwStartNode const*const pTableOrSectionNode(
261  currentStart.nNode.GetNode().IsTableNode()
262  ? static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetTableNode())
263  : static_cast<SwStartNode*>(currentStart.nNode.GetNode().GetSectionNode()));
264  assert(pTableOrSectionNode); // known pathology
265  for (sal_uLong j = pTableOrSectionNode->GetIndex(); j <= pTableOrSectionNode->EndOfSectionIndex(); ++j)
266  {
267  pTableOrSectionNode->GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::None);
268  }
270  {
271  // note: this will also create frames for all currently hidden flys
272  // because it calls AppendAllObjs
273  SwNodeIndex const end(*pTableOrSectionNode->EndOfSectionNode());
274  ::MakeFrames(&rDoc, currentStart.nNode, end);
275  isAppendObjsCalled = true;
276  }
277  currentStart.nNode = pTableOrSectionNode->EndOfSectionIndex() + 1;
278  currentStart.nContent.Assign(currentStart.nNode.GetNode().GetContentNode(), 0);
279  pStartNode = currentStart.nNode.GetNode().GetTextNode();
280  }
281  if (currentStart < *rPam.End())
282  {
283  SwTextNode * pNode(pStartNode);
284  do
285  {
286  std::vector<SwTextFrame*> frames;
288  for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
289  {
290  if (pFrame->getRootFrame()->HasMergedParas())
291  {
292  frames.push_back(pFrame);
293  }
294  // set anchored objects as not deleted
295  pFrame->SetDrawObjsAsDeleted(false);
296  }
297  if (frames.empty())
298  {
299  // in SwUndoSaveSection::SaveSection(), DelFrames() preceded this call
300  if (!pNode->FindTableBoxStartNode() && !pNode->FindFlyStartNode())
301  {
302  auto const& layouts(rDoc.GetAllLayouts());
303  assert(std::none_of(layouts.begin(), layouts.end(),
304  [](SwRootFrame const*const pLayout) { return pLayout->IsHideRedlines(); }));
305  (void) layouts;
306  }
307  isAppendObjsCalled = true; // skip that!
308  break;
309  }
310 
311  // first, call CheckParaRedlineMerge on the first paragraph,
312  // to init flag on new merge range (if any) + 1st node post the merge
314  SwTextNode * pLast(pNode);
315  for (SwTextFrame * pFrame : frames)
316  {
317  if (auto const pMergedPara = pFrame->GetMergedPara())
318  {
319  pLast = const_cast<SwTextNode*>(pMergedPara->pLastNode);
320  assert(pNode == pStartNode
321  ? pMergedPara->pFirstNode->GetIndex() <= pNode->GetIndex()
322  : pMergedPara->pFirstNode == pNode);
323  // clear old one first to avoid DelFrames confusing updates & asserts...
324  SwTextNode & rFirstNode(*pMergedPara->pFirstNode);
325  pFrame->SetMergedPara(nullptr);
326  pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
327  *pFrame, rFirstNode, eMode));
328  eMode = sw::FrameMode::New; // Existing is not idempotent!
329  // update pNode so MakeFrames starts on 2nd node
330  pNode = &rFirstNode;
331  }
332  }
333  if (pLast != pNode)
334  {
335  // now start node until end of merge + 1 has proper flags; MakeFrames
336  // should pick up from the next node in need of frames by checking flags
337  SwNodeIndex const start(*pNode, +1);
338  SwNodeIndex const end(*pLast, +1); // end is exclusive
339  // note: this will also create frames for all currently hidden flys
340  // both on first and non-first nodes because it calls AppendAllObjs
341  ::MakeFrames(&rDoc, start, end);
342  isAppendObjsCalled = true;
343  // re-use this to move flys that are now on the wrong frame, with end
344  // of redline as "second" node; the nodes between start and end should
345  // be complete with MakeFrames already
346  sw::MoveMergedFlysAndFootnotes(frames, *pNode, *pLast, false);
347  }
348  SwNodeIndex tmp(*pLast);
349  // skip over hidden sections!
350  pNode = static_cast<SwTextNode*>(pLast->GetNodes().GoNextSection(&tmp, /*bSkipHidden=*/true, /*bSkipProtect=*/false));
351  }
352  while (pNode && pNode->GetIndex() <= rPam.End()->nNode.GetIndex());
353  }
354 
355  if (!isAppendObjsCalled)
356  { // recreate flys in the one node the hard way...
357  for (auto const& pLayout : rDoc.GetAllLayouts())
358  {
359  if (pLayout->HasMergedParas())
360  {
361  AppendAllObjs(rDoc.GetSpzFrameFormats(), pLayout);
362  break;
363  }
364  }
365  }
366  // fields last - SwGetRefField::UpdateField requires up-to-date frames
367  UpdateFieldsForRedline(rDoc.getIDocumentFieldsAccess()); // after footnotes
368 
369  // update SwPostItMgr / notes in the margin
370  rDoc.GetDocShell()->Broadcast(
372 }
373 
374 } // namespace sw
375 
376 namespace
377 {
378  bool IsPrevPos( const SwPosition & rPos1, const SwPosition & rPos2 )
379  {
380  const SwContentNode* pCNd;
381  if( 0 != rPos2.nContent.GetIndex() )
382  return false;
383  if( rPos2.nNode.GetIndex() - 1 != rPos1.nNode.GetIndex() )
384  return false;
385  pCNd = rPos1.nNode.GetNode().GetContentNode();
386  return pCNd && rPos1.nContent.GetIndex() == pCNd->Len();
387  }
388 
389  // copy style or return with SwRedlineExtra_FormatColl with reject data of the upcoming copy
390  SwRedlineExtraData_FormatColl* lcl_CopyStyle( const SwPosition & rFrom, const SwPosition & rTo, bool bCopy = true )
391  {
392  SwTextNode* pToNode = rTo.nNode.GetNode().GetTextNode();
393  SwTextNode* pFromNode = rFrom.nNode.GetNode().GetTextNode();
394  if (pToNode != nullptr && pFromNode != nullptr && pToNode != pFromNode)
395  {
396  const SwPaM aPam(*pToNode);
397  SwDoc& rDoc = aPam.GetDoc();
398  // using Undo, copy paragraph style
399  SwTextFormatColl* pFromColl = pFromNode->GetTextColl();
400  SwTextFormatColl* pToColl = pToNode->GetTextColl();
401  if (bCopy && pFromColl != pToColl)
402  rDoc.SetTextFormatColl(aPam, pFromColl);
403 
404  // using Undo, remove direct paragraph formatting of the "To" paragraph,
405  // and apply here direct paragraph formatting of the "From" paragraph
406  SfxItemSet aTmp(
407  rDoc.GetAttrPool(),
408  svl::Items<
409  RES_PARATR_BEGIN, RES_PARATR_END - 3, // skip RSID and GRABBAG
410  RES_PARATR_LIST_BEGIN, RES_UL_SPACE, // skip PAGEDESC and BREAK
411  RES_CNTNT, RES_FRMATR_END - 1>);
412  SfxItemSet aTmp2(aTmp);
413 
414  pToNode->GetParaAttr(aTmp, 0, 0);
415  pFromNode->GetParaAttr(aTmp2, 0, 0);
416 
417  bool bSameSet = aTmp == aTmp2;
418 
419  if (!bSameSet)
420  {
421  for( sal_uInt16 nItem = 0; nItem < aTmp.TotalCount(); ++nItem)
422  {
423  sal_uInt16 nWhich = aTmp.GetWhichByPos(nItem);
424  if( SfxItemState::SET == aTmp.GetItemState( nWhich, false ) &&
425  SfxItemState::SET != aTmp2.GetItemState( nWhich, false ) )
426  aTmp2.Put( aTmp.GetPool()->GetDefaultItem(nWhich), nWhich );
427  }
428  }
429 
430  if (bCopy && !bSameSet)
431  rDoc.getIDocumentContentOperations().InsertItemSet(aPam, aTmp2);
432  else if (!bCopy && (!bSameSet || pFromColl != pToColl))
433  return new SwRedlineExtraData_FormatColl( pFromColl->GetName(), USHRT_MAX, &aTmp2 );
434  }
435  return nullptr;
436  }
437 
438  // delete the empty tracked table row (i.e. if it's last tracked deletion was accepted)
439  void lcl_DeleteTrackedTableRow ( SwPosition* pPos )
440  {
441  if ( const SwTableBox* pBox = pPos->nNode.GetNode().GetTableBox() )
442  {
443  const SwTableLine* pLine = pBox->GetUpper();
444  const SvxPrintItem *pHasTextChangesOnlyProp =
446  // empty table row with property "HasTextChangesOnly" = false
447  if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() &&
448  pLine->IsEmpty() )
449  {
450  SwCursor aCursor( *pPos, nullptr );
451  pPos->GetDoc().DeleteRow( aCursor );
452  }
453  }
454  }
455 
456  // at rejection of a deletion in a table, remove the tracking of the table row
457  void lcl_RemoveTrackingOfTableRow( const SwPosition* pPos )
458  {
459  if ( const SwTableBox* pBox = pPos->nNode.GetNode().GetTableBox() )
460  {
461  const SwTableLine* pLine = pBox->GetUpper();
462  const SvxPrintItem *pHasTextChangesOnlyProp =
464  // table row property "HasTextChangesOnly" is set and its value is false
465  if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() )
466  {
467  SvxPrintItem aUnsetTracking(RES_PRINT, true);
468  SwCursor aCursor( *pPos, nullptr );
469  pPos->GetDoc().SetRowNotTracked( aCursor, aUnsetTracking );
470  }
471  }
472  }
473 
474  bool lcl_AcceptRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
475  bool bCallDelete,
476  const SwPosition* pSttRng = nullptr,
477  const SwPosition* pEndRng = nullptr )
478  {
479  bool bRet = true;
480  SwRangeRedline* pRedl = rArr[ rPos ];
481  SwPosition *pRStt = nullptr, *pREnd = nullptr;
483  if( pSttRng && pEndRng )
484  {
485  pRStt = pRedl->Start();
486  pREnd = pRedl->End();
487  eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
488  }
489 
491 
492  switch( pRedl->GetType() )
493  {
494  case RedlineType::Insert:
495  case RedlineType::Format:
496  {
497  bool bCheck = false, bReplace = false;
498  switch( eCmp )
499  {
501  if( *pSttRng == *pRStt )
502  pRedl->SetStart( *pEndRng, pRStt );
503  else
504  {
505  if( *pEndRng != *pREnd )
506  {
507  // split up
508  SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
509  pNew->SetStart( *pEndRng );
510  rArr.Insert( pNew ); ++rPos;
511  }
512  pRedl->SetEnd( *pSttRng, pREnd );
513  bCheck = true;
514  }
515  break;
516 
518  pRedl->SetStart( *pEndRng, pRStt );
519  bReplace = true;
520  break;
521 
523  pRedl->SetEnd( *pSttRng, pREnd );
524  bCheck = true;
525  break;
526 
529  rArr.DeleteAndDestroy( rPos-- );
530  break;
531 
532  default:
533  bRet = false;
534  }
535 
536  if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
537  {
538  // re-insert
539  rArr.Remove( pRedl );
540  rArr.Insert( pRedl );
541  }
542  }
543  break;
544  case RedlineType::Delete:
545  {
546  SwDoc& rDoc = pRedl->GetDoc();
547  const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
548  bool bDelRedl = false;
549  switch( eCmp )
550  {
552  if( bCallDelete )
553  {
554  pDelStt = pSttRng;
555  pDelEnd = pEndRng;
556  }
557  break;
558 
560  if( bCallDelete )
561  {
562  pDelStt = pRStt;
563  pDelEnd = pEndRng;
564  }
565  break;
567  if( bCallDelete )
568  {
569  pDelStt = pREnd;
570  pDelEnd = pSttRng;
571  }
572  break;
573 
576  {
577  rArr.Remove( rPos-- );
578  bDelRedl = true;
579  if( bCallDelete )
580  {
581  pDelStt = pRedl->Start();
582  pDelEnd = pRedl->End();
583  }
584  }
585  break;
586  default:
587  bRet = false;
588  }
589 
590  if( pDelStt && pDelEnd )
591  {
592  SwPaM aPam( *pDelStt, *pDelEnd );
593  SwContentNode* pCSttNd = pDelStt->nNode.GetNode().GetContentNode();
594  SwContentNode* pCEndNd = pDelEnd->nNode.GetNode().GetContentNode();
595  pRStt = pRedl->Start();
596  pREnd = pRedl->End();
597 
598  // keep style of the empty paragraph after deletion of wholly paragraphs
599  if( pCSttNd && pCEndNd && pRStt && pREnd && pRStt->nContent == 0 )
600  lcl_CopyStyle(*pREnd, *pRStt);
601 
602  if( bDelRedl )
603  delete pRedl;
604 
607 
608  if( pCSttNd && pCEndNd )
609  {
611  lcl_DeleteTrackedTableRow( aPam.End() );
612  }
613  else if (pCSttNd && !pCEndNd)
614  {
615  aPam.GetBound().nContent.Assign( nullptr, 0 );
616  aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
618  }
619  else
620  {
622  }
624  }
625  else if( bDelRedl )
626  delete pRedl;
627  }
628  break;
629 
630  case RedlineType::FmtColl:
631  rArr.DeleteAndDestroy( rPos-- );
632  break;
633 
634  case RedlineType::ParagraphFormat:
635  rArr.DeleteAndDestroy( rPos-- );
636  break;
637 
638  default:
639  bRet = false;
640  }
641  return bRet;
642  }
643 
644  bool lcl_RejectRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
645  bool bCallDelete,
646  const SwPosition* pSttRng = nullptr,
647  const SwPosition* pEndRng = nullptr )
648  {
649  bool bRet = true;
650  SwRangeRedline* pRedl = rArr[ rPos ];
651  SwDoc& rDoc = pRedl->GetDoc();
652  SwPosition *pRStt = nullptr, *pREnd = nullptr;
654  if( pSttRng && pEndRng )
655  {
656  pRStt = pRedl->Start();
657  pREnd = pRedl->End();
658  eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd );
659  }
660 
662 
663  switch( pRedl->GetType() )
664  {
665  case RedlineType::Insert:
666  {
667  const SwPosition *pDelStt = nullptr, *pDelEnd = nullptr;
668  bool bDelRedl = false;
669  switch( eCmp )
670  {
672  if( bCallDelete )
673  {
674  pDelStt = pSttRng;
675  pDelEnd = pEndRng;
676  }
677  break;
678 
680  if( bCallDelete )
681  {
682  pDelStt = pRStt;
683  pDelEnd = pEndRng;
684  }
685  break;
687  if( bCallDelete )
688  {
689  pDelStt = pREnd;
690  pDelEnd = pSttRng;
691  }
692  break;
695  {
696  // delete the range again
697  rArr.Remove( rPos-- );
698  bDelRedl = true;
699  if( bCallDelete )
700  {
701  pDelStt = pRedl->Start();
702  pDelEnd = pRedl->End();
703  }
704  }
705  break;
706 
707  default:
708  bRet = false;
709  }
710  if( pDelStt && pDelEnd )
711  {
712  SwPaM aPam( *pDelStt, *pDelEnd );
713 
714  SwContentNode* pCSttNd = pDelStt->nNode.GetNode().GetContentNode();
715  SwContentNode* pCEndNd = pDelEnd->nNode.GetNode().GetContentNode();
716 
717  if( bDelRedl )
718  delete pRedl;
719 
722 
723  if( pCSttNd && pCEndNd )
724  {
726  lcl_DeleteTrackedTableRow( aPam.End() );
727  }
728  else if (pCSttNd && !pCEndNd)
729  {
730  aPam.GetBound().nContent.Assign( nullptr, 0 );
731  aPam.GetBound( false ).nContent.Assign( nullptr, 0 );
732  if (aPam.End()->nNode.GetNode().IsStartNode())
733  { // end node will be deleted too! see nNodeDiff+1
734  --aPam.End()->nNode;
735  }
736  assert(!aPam.End()->nNode.GetNode().IsStartNode());
738  }
739  else
740  {
742  }
744  }
745  else if( bDelRedl )
746  delete pRedl;
747  }
748  break;
749  case RedlineType::Delete:
750  {
751  SwRangeRedline* pNew = nullptr;
752  bool bCheck = false, bReplace = false;
753  SwPaM const updatePaM(pSttRng ? *pSttRng : *pRedl->Start(),
754  pEndRng ? *pEndRng : *pRedl->End());
755 
756  if( pRedl->GetExtraData() )
757  pRedl->GetExtraData()->Reject( *pRedl );
758 
759  // remove tracking of the table row, if needed
760  lcl_RemoveTrackingOfTableRow( updatePaM.End() );
761 
762  switch( eCmp )
763  {
765  {
766  if( 1 < pRedl->GetStackCount() )
767  {
768  pNew = new SwRangeRedline( *pRedl );
769  pNew->PopData();
770  }
771  if( *pSttRng == *pRStt )
772  {
773  pRedl->SetStart( *pEndRng, pRStt );
774  bReplace = true;
775  if( pNew )
776  pNew->SetEnd( *pEndRng );
777  }
778  else
779  {
780  if( *pEndRng != *pREnd )
781  {
782  // split up
783  SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
784  pCpy->SetStart( *pEndRng );
785  rArr.Insert( pCpy ); ++rPos;
786  if( pNew )
787  pNew->SetEnd( *pEndRng );
788  }
789 
790  pRedl->SetEnd( *pSttRng, pREnd );
791  bCheck = true;
792  if( pNew )
793  pNew->SetStart( *pSttRng );
794  }
795  }
796  break;
797 
799  if( 1 < pRedl->GetStackCount() )
800  {
801  pNew = new SwRangeRedline( *pRedl );
802  pNew->PopData();
803  }
804  pRedl->SetStart( *pEndRng, pRStt );
805  bReplace = true;
806  if( pNew )
807  pNew->SetEnd( *pEndRng );
808  break;
809 
811  if( 1 < pRedl->GetStackCount() )
812  {
813  pNew = new SwRangeRedline( *pRedl );
814  pNew->PopData();
815  }
816  pRedl->SetEnd( *pSttRng, pREnd );
817  bCheck = true;
818  if( pNew )
819  pNew->SetStart( *pSttRng );
820  break;
821 
824  if( !pRedl->PopData() )
825  // deleting the RedlineObject is enough
826  rArr.DeleteAndDestroy( rPos-- );
827  break;
828 
829  default:
830  bRet = false;
831  }
832 
833  if( pNew )
834  {
835  rArr.Insert( pNew ); ++rPos;
836  }
837 
838  if( bReplace || ( bCheck && !pRedl->HasValidRange() ))
839  {
840  // re-insert
841  rArr.Remove( pRedl );
842  rArr.Insert( pRedl );
843  }
844 
846  }
847  break;
848 
849  case RedlineType::Format:
850  case RedlineType::FmtColl:
851  case RedlineType::ParagraphFormat:
852  {
853  // tdf#52391 instead of hidden acception at the requested
854  // rejection, remove direct text formatting to get the potential
855  // original state of the text (FIXME if the original text
856  // has already contained direct text formatting: unfortunately
857  // ODF 1.2 doesn't support rejection of format-only changes)
858  if ( pRedl->GetType() == RedlineType::Format )
859  {
860  SwPaM aPam( *(pRedl->Start()), *(pRedl->End()) );
861  rDoc.ResetAttrs(aPam);
862  }
863  else if ( pRedl->GetType() == RedlineType::ParagraphFormat )
864  {
865  // handle paragraph formatting changes
866  // (range is only a full paragraph or a part of it)
867  const SwPosition* pStt = pRedl->Start();
868  SwTextNode* pTNd = pStt->nNode.GetNode().GetTextNode();
869  if( pTNd )
870  {
871  // expand range to the whole paragraph
872  // and reset only the paragraph attributes
873  SwPaM aPam( *pTNd, pTNd->GetText().getLength() );
874  o3tl::sorted_vector<sal_uInt16> aResetAttrsArray;
875 
876  constexpr std::pair<sal_uInt16, sal_uInt16> aResetableSetRange[] = {
877  { RES_PARATR_BEGIN, RES_PARATR_END - 1 },
879  };
880 
881  for (const auto& [nBegin, nEnd] : aResetableSetRange)
882  {
883  for (sal_uInt16 i = nBegin; i <= nEnd; ++i)
884  aResetAttrsArray.insert( i );
885  }
886 
887  rDoc.ResetAttrs(aPam, false, aResetAttrsArray);
888 
889  // remove numbering
890  if ( pTNd->GetNumRule() )
891  rDoc.DelNumRules(aPam);
892  }
893  }
894 
895  if( pRedl->GetExtraData() )
896  pRedl->GetExtraData()->Reject( *pRedl );
897 
898  rArr.DeleteAndDestroy( rPos-- );
899  }
900  break;
901 
902  default:
903  bRet = false;
904  }
905  return bRet;
906  }
907 
908  typedef bool (*Fn_AcceptReject)( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos,
909  bool bCallDelete,
910  const SwPosition* pSttRng,
911  const SwPosition* pEndRng);
912 
913 
914  int lcl_AcceptRejectRedl( Fn_AcceptReject fn_AcceptReject,
915  SwRedlineTable& rArr, bool bCallDelete,
916  const SwPaM& rPam)
917  {
919  int nCount = 0;
920 
921  const SwPosition* pStt = rPam.Start(),
922  * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
923  : rPam.GetPoint();
924  const SwRangeRedline* pFnd = rArr.FindAtPosition( *pStt, n );
925  if( pFnd && // Is new a part of it?
926  ( *pFnd->Start() != *pStt || *pFnd->End() > *pEnd ))
927  {
928  // Only revoke the partial selection
929  if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd ))
930  nCount++;
931  ++n;
932  }
933 
934  // tdf#119824 first we will accept only overlapping paragraph format changes
935  // in the first loop to avoid potential content changes during Redo
936  bool bHasParagraphFormatChange = false;
937  for( int m = 0 ; m < 2 && !bHasParagraphFormatChange; ++m )
938  {
939  for(SwRedlineTable::size_type o = n ; o < rArr.size(); ++o )
940  {
941  SwRangeRedline* pTmp = rArr[ o ];
942  if( pTmp->HasMark() && pTmp->IsVisible() )
943  {
944  if( *pTmp->End() <= *pEnd )
945  {
946  if( (m > 0 || RedlineType::ParagraphFormat == pTmp->GetType()) &&
947  (*fn_AcceptReject)( rArr, o, bCallDelete, nullptr, nullptr ))
948  {
949  bHasParagraphFormatChange = true;
950  nCount++;
951  }
952  }
953  else
954  {
955  if( *pTmp->Start() < *pEnd )
956  {
957  // Only revoke the partial selection
958  if( (m > 0 || RedlineType::ParagraphFormat == pTmp->GetType()) &&
959  (*fn_AcceptReject)( rArr, o, bCallDelete, pStt, pEnd ))
960  {
961  bHasParagraphFormatChange = true;
962  nCount++;
963  }
964  }
965  break;
966  }
967  }
968  }
969  }
970  return nCount;
971  }
972 
973  void lcl_AdjustRedlineRange( SwPaM& rPam )
974  {
975  // The Selection is only in the ContentSection. If there are Redlines
976  // to Non-ContentNodes before or after that, then the Selections
977  // expand to them.
978  SwPosition* pStt = rPam.Start(),
979  * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
980  : rPam.GetPoint();
981  SwDoc& rDoc = rPam.GetDoc();
982  if( !pStt->nContent.GetIndex() &&
983  !rDoc.GetNodes()[ pStt->nNode.GetIndex() - 1 ]->IsContentNode() )
984  {
985  const SwRangeRedline* pRedl = rDoc.getIDocumentRedlineAccess().GetRedline( *pStt, nullptr );
986  if( pRedl )
987  {
988  const SwPosition* pRStt = pRedl->Start();
989  if( !pRStt->nContent.GetIndex() && pRStt->nNode.GetIndex() ==
990  pStt->nNode.GetIndex() - 1 )
991  *pStt = *pRStt;
992  }
993  }
994  if( pEnd->nNode.GetNode().IsContentNode() &&
995  !rDoc.GetNodes()[ pEnd->nNode.GetIndex() + 1 ]->IsContentNode() &&
996  pEnd->nContent.GetIndex() == pEnd->nNode.GetNode().GetContentNode()->Len() )
997  {
998  const SwRangeRedline* pRedl = rDoc.getIDocumentRedlineAccess().GetRedline( *pEnd, nullptr );
999  if( pRedl )
1000  {
1001  const SwPosition* pREnd = pRedl->End();
1002  if( !pREnd->nContent.GetIndex() && pREnd->nNode.GetIndex() ==
1003  pEnd->nNode.GetIndex() + 1 )
1004  *pEnd = *pREnd;
1005  }
1006  }
1007  }
1008 
1011  class TemporaryRedlineUpdater
1012  {
1013  private:
1014  SwRangeRedline & m_rRedline;
1015  std::shared_ptr<SwUnoCursor> m_pCursor;
1016  public:
1017  TemporaryRedlineUpdater(SwDoc & rDoc, SwRangeRedline & rRedline)
1018  : m_rRedline(rRedline)
1019  , m_pCursor(rDoc.CreateUnoCursor(*rRedline.GetPoint(), false))
1020  {
1021  if (m_rRedline.HasMark())
1022  {
1023  m_pCursor->SetMark();
1024  *m_pCursor->GetMark() = *m_rRedline.GetMark();
1025  *m_rRedline.GetMark() = SwPosition(rDoc.GetNodes().GetEndOfContent());
1026  }
1027  *m_rRedline.GetPoint() = SwPosition(rDoc.GetNodes().GetEndOfContent());
1028  }
1029  ~TemporaryRedlineUpdater()
1030  {
1031  static_cast<SwPaM&>(m_rRedline) = *m_pCursor;
1032  }
1033  };
1034 }
1035 
1036 namespace sw
1037 {
1038 
1039 DocumentRedlineManager::DocumentRedlineManager(SwDoc& i_rSwdoc)
1040  : m_rDoc(i_rSwdoc)
1041  , meRedlineFlags(RedlineFlags::ShowInsert | RedlineFlags::ShowDelete)
1042  , mpRedlineTable(new SwRedlineTable)
1043  , mpExtraRedlineTable(new SwExtraRedlineTable)
1044  , mbIsRedlineMove(false)
1045  , mnAutoFormatRedlnCommentNo(0)
1046 {
1047 }
1048 
1050 {
1051  return meRedlineFlags;
1052 }
1053 
1055 {
1056  if( meRedlineFlags == eMode )
1057  return;
1058 
1060  || !(RedlineFlags::ShowMask & eMode) )
1061  {
1062  bool bSaveInXMLImportFlag = m_rDoc.IsInXMLImport();
1063  m_rDoc.SetInXMLImport( false );
1064  // and then hide/display everything
1065  void (SwRangeRedline::*pFnc)(sal_uInt16, size_t, bool); // Allow compiler warn if use of
1066  // uninitialized ptr is possible
1067 
1068  RedlineFlags eShowMode = RedlineFlags::ShowMask & eMode;
1070  pFnc = &SwRangeRedline::Show;
1071  else if (eShowMode == RedlineFlags::ShowInsert)
1072  pFnc = &SwRangeRedline::Hide;
1073  else if (eShowMode == RedlineFlags::ShowDelete)
1075  else
1076  {
1077  pFnc = &SwRangeRedline::Hide;
1078  eMode |= RedlineFlags::ShowInsert;
1079  }
1080 
1082  CHECK_REDLINE( *this )
1083 
1084  o3tl::sorted_vector<SwRootFrame *> hiddenLayouts;
1086  {
1087  // sw_redlinehide: the problem here is that MoveFromSection
1088  // creates the frames wrongly (non-merged), because its own
1089  // SwRangeRedline has wrong positions until after the nodes
1090  // are all moved, so fix things up by force by re-creating
1091  // all merged frames from scratch.
1093  for (SwRootFrame *const pLayout : layouts)
1094  {
1095  if (pLayout->IsHideRedlines())
1096  {
1097  pLayout->SetHideRedlines(false);
1098  hiddenLayouts.insert(pLayout);
1099  }
1100  }
1101  }
1102 
1103  for (sal_uInt16 nLoop = 1; nLoop <= 2; ++nLoop)
1104  for (size_t i = 0; i < mpRedlineTable->size(); ++i)
1105  {
1106  SwRangeRedline *const pRedline((*mpRedlineTable)[i]);
1107  (pRedline->*pFnc)(nLoop, i, false);
1108  while (mpRedlineTable->size() <= i
1109  || (*mpRedlineTable)[i] != pRedline)
1110  { // ensure current position
1111  --i; // a previous redline may have been deleted
1112  }
1113  }
1114 
1115  //SwRangeRedline::MoveFromSection routinely changes
1116  //the keys that mpRedlineTable is sorted by
1117  mpRedlineTable->Resort();
1118 
1120  CHECK_REDLINE( *this )
1121 
1122  for (SwRootFrame *const pLayout : hiddenLayouts)
1123  {
1124  pLayout->SetHideRedlines(true);
1125  }
1126 
1127  m_rDoc.SetInXMLImport( bSaveInXMLImportFlag );
1128  }
1129  meRedlineFlags = eMode;
1131 
1132  // #TODO - add 'SwExtraRedlineTable' also ?
1133 }
1134 
1136 {
1138 }
1139 
1141 {
1142  return bool(RedlineFlags::Ignore & meRedlineFlags);
1143 }
1144 
1146 {
1147  meRedlineFlags = eMode;
1148 }
1149 
1151 {
1152  return *mpRedlineTable;
1153 }
1154 
1156 {
1157  return *mpRedlineTable;
1158 }
1159 
1161 {
1162  return *mpExtraRedlineTable;
1163 }
1164 
1166 {
1167  return *mpExtraRedlineTable;
1168 }
1169 
1171 {
1172  return mpExtraRedlineTable != nullptr;
1173 }
1174 
1176 {
1177  SwPosition aPos(rNode);
1178  SwNode & rEndOfRedlines = m_rDoc.GetNodes().GetEndOfRedlines();
1179  SwPaM aPam(SwPosition(*rEndOfRedlines.StartOfSectionNode()),
1180  SwPosition(rEndOfRedlines));
1181 
1182  return aPam.ContainsPosition(aPos);
1183 }
1184 
1186 {
1187  return mbIsRedlineMove;
1188 }
1189 
1191 {
1192  mbIsRedlineMove = bFlag;
1193 }
1194 
1195 /*
1196 Text means Text not "polluted" by Redlines.
1197 
1198 Behaviour of Insert-Redline:
1199  - in the Text - insert Redline Object
1200  - in InsertRedline (own) - ignore, existing is extended
1201  - in InsertRedline (others) - split up InsertRedline and
1202  insert Redline Object
1203  - in DeleteRedline - split up DeleteRedline or
1204  move at the end/beginning
1205 
1206 Behaviour of Delete-Redline:
1207  - in the Text - insert Redline Object
1208  - in DeleteRedline (own/others) - ignore
1209  - in InsertRedline (own) - ignore, but delete character
1210  - in InsertRedline (others) - split up InsertRedline and
1211  insert Redline Object
1212  - Text and own Insert overlap - delete Text in the own Insert,
1213  extend in the other Text
1214  (up to the Insert!)
1215  - Text and other Insert overlap - insert Redline Object, the
1216  other Insert is overlapped by
1217  the Delete
1218 */
1220 DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCallDelete)
1221 {
1222  bool bMerged = false;
1223  CHECK_REDLINE( *this )
1224 
1226  {
1228 
1229  if( m_rDoc.IsAutoFormatRedline() )
1230  {
1231  pNewRedl->SetAutoFormat();
1233  {
1234  pNewRedl->SetComment( *mpAutoFormatRedlnComment );
1235  pNewRedl->SetSeqNo( mnAutoFormatRedlnCommentNo );
1236  }
1237  }
1238 
1239  SwPosition* pStt = pNewRedl->Start(),
1240  * pEnd = pStt == pNewRedl->GetPoint() ? pNewRedl->GetMark()
1241  : pNewRedl->GetPoint();
1242  {
1243  SwTextNode* pTextNode = pStt->nNode.GetNode().GetTextNode();
1244  if( pTextNode == nullptr )
1245  {
1246  if( pStt->nContent > 0 )
1247  {
1248  OSL_ENSURE( false, "Redline start: non-text-node with content" );
1249  pStt->nContent = 0;
1250  }
1251  }
1252  else
1253  {
1254  if( pStt->nContent > pTextNode->Len() )
1255  {
1256  OSL_ENSURE( false, "Redline start: index after text" );
1257  pStt->nContent = pTextNode->Len();
1258  }
1259  }
1260  pTextNode = pEnd->nNode.GetNode().GetTextNode();
1261  if( pTextNode == nullptr )
1262  {
1263  if( pEnd->nContent > 0 )
1264  {
1265  OSL_ENSURE( false, "Redline end: non-text-node with content" );
1266  pEnd->nContent = 0;
1267  }
1268  }
1269  else
1270  {
1271  if( pEnd->nContent > pTextNode->Len() )
1272  {
1273  OSL_ENSURE( false, "Redline end: index after text" );
1274  pEnd->nContent = pTextNode->Len();
1275  }
1276  }
1277  }
1278  if( ( *pStt == *pEnd ) &&
1279  ( pNewRedl->GetContentIdx() == nullptr ) )
1280  { // Do not insert empty redlines
1281  delete pNewRedl;
1282  return AppendResult::IGNORED;
1283  }
1284  bool bCompress = false;
1286  // look up the first Redline for the starting position
1287  if( !GetRedline( *pStt, &n ) && n )
1288  --n;
1289  bool bDec = false;
1290 
1291  for( ; pNewRedl && n < mpRedlineTable->size(); bDec ? n : ++n )
1292  {
1293  bDec = false;
1294 
1295  SwRangeRedline* pRedl = (*mpRedlineTable)[ n ];
1296  SwPosition* pRStt = pRedl->Start(),
1297  * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
1298  : pRedl->GetPoint();
1299 
1300  // #i8518# remove empty redlines while we're at it
1301  if( ( *pRStt == *pREnd ) &&
1302  ( pRedl->GetContentIdx() == nullptr ) )
1303  {
1304  mpRedlineTable->DeleteAndDestroy(n);
1305  continue;
1306  }
1307 
1308  SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
1309 
1310  switch( pNewRedl->GetType() )
1311  {
1312  case RedlineType::Insert:
1313  switch( pRedl->GetType() )
1314  {
1315  case RedlineType::Insert:
1316  if( pRedl->IsOwnRedline( *pNewRedl ) )
1317  {
1318  bool bDelete = false;
1319 
1320  // Merge if applicable?
1321  if( (( SwComparePosition::Behind == eCmpPos &&
1322  IsPrevPos( *pREnd, *pStt ) ) ||
1323  ( SwComparePosition::CollideStart == eCmpPos ) ||
1324  ( SwComparePosition::OverlapBehind == eCmpPos ) ) &&
1325  pRedl->CanCombine( *pNewRedl ) &&
1326  ( n+1 >= mpRedlineTable->size() ||
1327  ( *(*mpRedlineTable)[ n+1 ]->Start() >= *pEnd &&
1328  *(*mpRedlineTable)[ n+1 ]->Start() != *pREnd ) ) )
1329  {
1330  pRedl->SetEnd( *pEnd, pREnd );
1331  if( !pRedl->HasValidRange() )
1332  {
1333  // re-insert
1334  mpRedlineTable->Remove( n );
1335  mpRedlineTable->Insert( pRedl );
1336  }
1337 
1338  bMerged = true;
1339  bDelete = true;
1340  }
1341  else if( (( SwComparePosition::Before == eCmpPos &&
1342  IsPrevPos( *pEnd, *pRStt ) ) ||
1343  ( SwComparePosition::CollideEnd == eCmpPos ) ||
1344  ( SwComparePosition::OverlapBefore == eCmpPos ) ) &&
1345  pRedl->CanCombine( *pNewRedl ) &&
1346  ( !n ||
1347  *(*mpRedlineTable)[ n-1 ]->End() != *pRStt ))
1348  {
1349  pRedl->SetStart( *pStt, pRStt );
1350  // re-insert
1351  mpRedlineTable->Remove( n );
1352  mpRedlineTable->Insert( pRedl );
1353 
1354  bMerged = true;
1355  bDelete = true;
1356  }
1357  else if ( SwComparePosition::Outside == eCmpPos )
1358  {
1359  // own insert-over-insert redlines:
1360  // just scrap the inside ones
1361  mpRedlineTable->DeleteAndDestroy( n );
1362  bDec = true;
1363  }
1364  else if( SwComparePosition::OverlapBehind == eCmpPos )
1365  {
1366  *pStt = *pREnd;
1367  if( ( *pStt == *pEnd ) &&
1368  ( pNewRedl->GetContentIdx() == nullptr ) )
1369  bDelete = true;
1370  }
1371  else if( SwComparePosition::OverlapBefore == eCmpPos )
1372  {
1373  *pEnd = *pRStt;
1374  if( ( *pStt == *pEnd ) &&
1375  ( pNewRedl->GetContentIdx() == nullptr ) )
1376  bDelete = true;
1377  }
1378  else if( SwComparePosition::Inside == eCmpPos )
1379  {
1380  bDelete = true;
1381  bMerged = true;
1382  }
1383  else if( SwComparePosition::Equal == eCmpPos )
1384  bDelete = true;
1385 
1386  if( bDelete )
1387  {
1388  delete pNewRedl;
1389  pNewRedl = nullptr;
1390  bCompress = true;
1391  }
1392  }
1393  else if( SwComparePosition::Inside == eCmpPos )
1394  {
1395  // split up
1396  if( *pEnd != *pREnd )
1397  {
1398  SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
1399  pCpy->SetStart( *pEnd );
1400  mpRedlineTable->Insert( pCpy );
1401  }
1402  pRedl->SetEnd( *pStt, pREnd );
1403  if( ( *pStt == *pRStt ) &&
1404  ( pRedl->GetContentIdx() == nullptr ) )
1405  {
1406  mpRedlineTable->DeleteAndDestroy( n );
1407  bDec = true;
1408  }
1409  else if( !pRedl->HasValidRange() )
1410  {
1411  // re-insert
1412  mpRedlineTable->Remove( n );
1413  mpRedlineTable->Insert( pRedl );
1414  }
1415  }
1416  else if ( SwComparePosition::Outside == eCmpPos )
1417  {
1418  // handle overlapping redlines in broken documents
1419 
1420  // split up the new redline, since it covers the
1421  // existing redline. Insert the first part, and
1422  // progress with the remainder as usual
1423  SwRangeRedline* pSplit = new SwRangeRedline( *pNewRedl );
1424  pSplit->SetEnd( *pRStt );
1425  pNewRedl->SetStart( *pREnd );
1426  mpRedlineTable->Insert( pSplit );
1427  if( *pStt == *pEnd && pNewRedl->GetContentIdx() == nullptr )
1428  {
1429  delete pNewRedl;
1430  pNewRedl = nullptr;
1431  bCompress = true;
1432  }
1433  }
1434  else if ( SwComparePosition::OverlapBehind == eCmpPos )
1435  {
1436  // handle overlapping redlines in broken documents
1437  pNewRedl->SetStart( *pREnd );
1438  }
1439  else if ( SwComparePosition::OverlapBefore == eCmpPos )
1440  {
1441  // handle overlapping redlines in broken documents
1442  *pEnd = *pRStt;
1443  if( ( *pStt == *pEnd ) &&
1444  ( pNewRedl->GetContentIdx() == nullptr ) )
1445  {
1446  delete pNewRedl;
1447  pNewRedl = nullptr;
1448  bCompress = true;
1449  }
1450  }
1451  break;
1452  case RedlineType::Delete:
1453  if( SwComparePosition::Inside == eCmpPos )
1454  {
1455  // split up
1456  if( *pEnd != *pREnd )
1457  {
1458  SwRangeRedline* pCpy = new SwRangeRedline( *pRedl );
1459  pCpy->SetStart( *pEnd );
1460  mpRedlineTable->Insert( pCpy );
1461  }
1462  pRedl->SetEnd( *pStt, pREnd );
1463  if( ( *pStt == *pRStt ) &&
1464  ( pRedl->GetContentIdx() == nullptr ) )
1465  {
1466  mpRedlineTable->DeleteAndDestroy( n );
1467  bDec = true;
1468  }
1469  else if( !pRedl->HasValidRange() )
1470  {
1471  // re-insert
1472  mpRedlineTable->Remove( n );
1473  mpRedlineTable->Insert( pRedl, n );
1474  }
1475  }
1476  else if ( SwComparePosition::Outside == eCmpPos )
1477  {
1478  // handle overlapping redlines in broken documents
1479 
1480  // split up the new redline, since it covers the
1481  // existing redline. Insert the first part, and
1482  // progress with the remainder as usual
1483  SwRangeRedline* pSplit = new SwRangeRedline( *pNewRedl );
1484  pSplit->SetEnd( *pRStt );
1485  pNewRedl->SetStart( *pREnd );
1486  mpRedlineTable->Insert( pSplit );
1487  if( *pStt == *pEnd && pNewRedl->GetContentIdx() == nullptr )
1488  {
1489  delete pNewRedl;
1490  pNewRedl = nullptr;
1491  bCompress = true;
1492  }
1493  }
1494  else if ( SwComparePosition::Equal == eCmpPos )
1495  {
1496  // handle identical redlines in broken documents
1497  // delete old (delete) redline
1498  mpRedlineTable->DeleteAndDestroy( n );
1499  bDec = true;
1500  }
1501  else if ( SwComparePosition::OverlapBehind == eCmpPos )
1502  { // Another workaround for broken redlines
1503  pNewRedl->SetStart( *pREnd );
1504  }
1505  break;
1506  case RedlineType::Format:
1507  switch( eCmpPos )
1508  {
1510  pRedl->SetStart( *pEnd, pRStt );
1511  // re-insert
1512  mpRedlineTable->Remove( n );
1513  mpRedlineTable->Insert( pRedl, n );
1514  bDec = true;
1515  break;
1516 
1518  pRedl->SetEnd( *pStt, pREnd );
1519  if( *pStt == *pRStt && pRedl->GetContentIdx() == nullptr )
1520  {
1521  mpRedlineTable->DeleteAndDestroy( n );
1522  bDec = true;
1523  }
1524  break;
1525 
1528  // Overlaps the current one completely or has the
1529  // same dimension, delete the old one
1530  mpRedlineTable->DeleteAndDestroy( n );
1531  bDec = true;
1532  break;
1533 
1535  // Overlaps the current one completely,
1536  // split or shorten the new one
1537  if( *pEnd != *pREnd )
1538  {
1539  if( *pEnd != *pRStt )
1540  {
1541  SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
1542  pNew->SetStart( *pEnd );
1543  pRedl->SetEnd( *pStt, pREnd );
1544  if( *pStt == *pRStt && pRedl->GetContentIdx() == nullptr )
1545  mpRedlineTable->DeleteAndDestroy( n );
1546  AppendRedline( pNew, bCallDelete );
1547  n = 0; // re-initialize
1548  bDec = true;
1549  }
1550  }
1551  else
1552  pRedl->SetEnd( *pStt, pREnd );
1553  break;
1554  default:
1555  break;
1556  }
1557  break;
1558  default:
1559  break;
1560  }
1561  break;
1562 
1563  case RedlineType::Delete:
1564  switch( pRedl->GetType() )
1565  {
1566  case RedlineType::Delete:
1567  switch( eCmpPos )
1568  {
1570  {
1571  // Overlaps the current one completely,
1572  // split the new one
1573  if (*pEnd == *pREnd)
1574  {
1575  pNewRedl->SetEnd(*pRStt, pEnd);
1576  }
1577  else if (*pStt == *pRStt)
1578  {
1579  pNewRedl->SetStart(*pREnd, pStt);
1580  }
1581  else
1582  {
1583  SwRangeRedline* pNew = new SwRangeRedline( *pNewRedl );
1584  pNew->SetStart( *pREnd );
1585  pNewRedl->SetEnd( *pRStt, pEnd );
1586  AppendRedline( pNew, bCallDelete );
1587  n = 0; // re-initialize
1588  bDec = true;
1589  }
1590  }
1591  break;
1592 
1595  delete pNewRedl;
1596  pNewRedl = nullptr;
1597  bCompress = true;
1598  break;
1599 
1602  if( pRedl->IsOwnRedline( *pNewRedl ) &&
1603  pRedl->CanCombine( *pNewRedl ))
1604  {
1605  // If that's the case we can merge it, meaning
1606  // the new one covers this well
1607  if( SwComparePosition::OverlapBehind == eCmpPos )
1608  pNewRedl->SetStart( *pRStt, pStt );
1609  else
1610  pNewRedl->SetEnd( *pREnd, pEnd );
1611  mpRedlineTable->DeleteAndDestroy( n );
1612  bDec = true;
1613  }
1614  else if( SwComparePosition::OverlapBehind == eCmpPos )
1615  pNewRedl->SetStart( *pREnd, pStt );
1616  else
1617  pNewRedl->SetEnd( *pRStt, pEnd );
1618  break;
1619 
1622  if( pRedl->IsOwnRedline( *pNewRedl ) &&
1623  pRedl->CanCombine( *pNewRedl ) )
1624  {
1626  {
1627  // Before we can merge, we make it visible!
1628  // We insert temporarily so that pNew is
1629  // also dealt with when moving the indices.
1630  mpRedlineTable->Insert(pNewRedl);
1631  pRedl->Show(0, mpRedlineTable->GetPos(pRedl));
1632  mpRedlineTable->Remove( pNewRedl );
1633  pRStt = pRedl->Start();
1634  pREnd = pRedl->End();
1635  }
1636 
1637  // If that's the case we can merge it, meaning
1638  // the new one covers this well
1639  if( SwComparePosition::CollideStart == eCmpPos )
1640  pNewRedl->SetStart( *pRStt, pStt );
1641  else
1642  pNewRedl->SetEnd( *pREnd, pEnd );
1643 
1644  // delete current (below), and restart process with
1645  // previous
1646  SwRedlineTable::size_type nToBeDeleted = n;
1647  bDec = true;
1648 
1649  if( *(pNewRedl->Start()) <= *pREnd )
1650  {
1651  // Whoooah, we just extended the new 'redline'
1652  // beyond previous redlines, so better start
1653  // again. Of course this is not supposed to
1654  // happen, and in an ideal world it doesn't,
1655  // but unfortunately this code is buggy and
1656  // totally rotten so it does happen and we
1657  // better fix it.
1658  n = 0;
1659  bDec = true;
1660  }
1661 
1662  mpRedlineTable->DeleteAndDestroy( nToBeDeleted );
1663  }
1664  break;
1665  default:
1666  break;
1667  }
1668  break;
1669 
1670  case RedlineType::Insert:
1671  {
1672  // b62341295: Do not throw away redlines
1673  // even if they are not allowed to be combined
1675  if( !( eOld & RedlineFlags::DontCombineRedlines ) &&
1676  pRedl->IsOwnRedline( *pNewRedl ) )
1677  {
1678 
1679  // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
1680  // The ShowMode needs to be retained!
1682  switch( eCmpPos )
1683  {
1685  bCompress = true;
1686  mpRedlineTable->DeleteAndDestroy( n );
1687  bDec = true;
1688  [[fallthrough]];
1689 
1691  if( bCallDelete )
1692  {
1693  // DeleteAndJoin does not yield the
1694  // desired result if there is no paragraph to
1695  // join with, i.e. at the end of the document.
1696  // For this case, we completely delete the
1697  // paragraphs (if, of course, we also start on
1698  // a paragraph boundary).
1699  if( (pStt->nContent == 0) &&
1700  pEnd->nNode.GetNode().IsEndNode() )
1701  {
1702  pEnd->nNode--;
1703  pEnd->nContent.Assign(
1704  pEnd->nNode.GetNode().GetTextNode(), 0);
1706  }
1707  else
1709 
1710  bCompress = true;
1711  }
1712  if( !bCallDelete && !bDec && *pEnd == *pREnd )
1713  {
1715  bCompress = true;
1716  }
1717  else if ( bCallDelete || !bDec )
1718  {
1719  // delete new redline, except in some cases of fallthrough from previous
1720  // case ::Equal (eg. same portion w:del in w:ins in OOXML import)
1721  delete pNewRedl;
1722  pNewRedl = nullptr;
1723  }
1724  break;
1725 
1727  {
1728  mpRedlineTable->Remove( n );
1729  bDec = true;
1730  if( bCallDelete )
1731  {
1732  TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1734  n = 0; // re-initialize
1735  }
1736  delete pRedl;
1737  }
1738  break;
1739 
1741  {
1742  SwPaM aPam( *pRStt, *pEnd );
1743 
1744  if( *pEnd == *pREnd )
1745  mpRedlineTable->DeleteAndDestroy( n );
1746  else
1747  {
1748  pRedl->SetStart( *pEnd, pRStt );
1749  // re-insert
1750  mpRedlineTable->Remove( n );
1751  mpRedlineTable->Insert( pRedl, n );
1752  }
1753 
1754  if( bCallDelete )
1755  {
1756  TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1758  n = 0; // re-initialize
1759  }
1760  bDec = true;
1761  }
1762  break;
1763 
1765  {
1766  SwPaM aPam( *pStt, *pREnd );
1767 
1768  if( *pStt == *pRStt )
1769  {
1770  mpRedlineTable->DeleteAndDestroy( n );
1771  bDec = true;
1772  }
1773  else
1774  pRedl->SetEnd( *pStt, pREnd );
1775 
1776  if( bCallDelete )
1777  {
1778  TemporaryRedlineUpdater const u(m_rDoc, *pNewRedl);
1780  n = 0; // re-initialize
1781  bDec = true;
1782  }
1783  }
1784  break;
1785  default:
1786  break;
1787  }
1788 
1789  meRedlineFlags = eOld;
1790  }
1791  else
1792  {
1793  // it may be necessary to split the existing redline in
1794  // two. In this case, pRedl will be changed to cover
1795  // only part of its former range, and pNew will cover
1796  // the remainder.
1797  SwRangeRedline* pNew = nullptr;
1798 
1799  switch( eCmpPos )
1800  {
1802  {
1803  pRedl->PushData( *pNewRedl );
1804  delete pNewRedl;
1805  pNewRedl = nullptr;
1807  {
1808  pRedl->Hide(0, mpRedlineTable->GetPos(pRedl));
1809  }
1810  bCompress = true;
1811  }
1812  break;
1813 
1815  {
1816  if( *pRStt == *pStt )
1817  {
1818  // #i97421#
1819  // redline w/out extent loops
1820  if (*pStt != *pEnd)
1821  {
1822  pNewRedl->PushData( *pRedl, false );
1823  pRedl->SetStart( *pEnd, pRStt );
1824  // re-insert
1825  mpRedlineTable->Remove( n );
1826  mpRedlineTable->Insert( pRedl, n );
1827  bDec = true;
1828  }
1829  }
1830  else
1831  {
1832  pNewRedl->PushData( *pRedl, false );
1833  if( *pREnd != *pEnd )
1834  {
1835  pNew = new SwRangeRedline( *pRedl );
1836  pNew->SetStart( *pEnd );
1837  }
1838  pRedl->SetEnd( *pStt, pREnd );
1839  if( !pRedl->HasValidRange() )
1840  {
1841  // re-insert
1842  mpRedlineTable->Remove( n );
1843  mpRedlineTable->Insert( pRedl, n );
1844  }
1845  }
1846  }
1847  break;
1848 
1850  {
1851  pRedl->PushData( *pNewRedl );
1852  if( *pEnd == *pREnd )
1853  {
1854  pNewRedl->SetEnd( *pRStt, pEnd );
1855  }
1856  else if (*pStt == *pRStt)
1857  {
1858  pNewRedl->SetStart(*pREnd, pStt);
1859  }
1860  else
1861  {
1862  pNew = new SwRangeRedline( *pNewRedl );
1863  pNew->SetEnd( *pRStt );
1864  pNewRedl->SetStart( *pREnd, pStt );
1865  }
1866  bCompress = true;
1867  }
1868  break;
1869 
1871  {
1872  if( *pEnd == *pREnd )
1873  {
1874  pRedl->PushData( *pNewRedl );
1875  pNewRedl->SetEnd( *pRStt, pEnd );
1877  {
1878  mpRedlineTable->Insert(pNewRedl);
1879  pRedl->Hide(0, mpRedlineTable->GetPos(pRedl));
1880  mpRedlineTable->Remove( pNewRedl );
1881  }
1882  }
1883  else
1884  {
1885  pNew = new SwRangeRedline( *pRedl );
1886  pNew->PushData( *pNewRedl );
1887  pNew->SetEnd( *pEnd );
1888  pNewRedl->SetEnd( *pRStt, pEnd );
1889  pRedl->SetStart( *pNew->End(), pRStt ) ;
1890  // re-insert
1891  mpRedlineTable->Remove( n );
1892  mpRedlineTable->Insert( pRedl );
1893  bDec = true;
1894  }
1895  }
1896  break;
1897 
1899  {
1900  if( *pStt == *pRStt )
1901  {
1902  pRedl->PushData( *pNewRedl );
1903  pNewRedl->SetStart( *pREnd, pStt );
1905  {
1906  mpRedlineTable->Insert( pNewRedl );
1907  pRedl->Hide(0, mpRedlineTable->GetPos(pRedl));
1908  mpRedlineTable->Remove( pNewRedl );
1909  }
1910  }
1911  else
1912  {
1913  pNew = new SwRangeRedline( *pRedl );
1914  pNew->PushData( *pNewRedl );
1915  pNew->SetStart( *pStt );
1916  pNewRedl->SetStart( *pREnd, pStt );
1917  pRedl->SetEnd( *pNew->Start(), pREnd );
1918  if( !pRedl->HasValidRange() )
1919  {
1920  // re-insert
1921  mpRedlineTable->Remove( n );
1922  mpRedlineTable->Insert( pRedl );
1923  }
1924  }
1925  }
1926  break;
1927  default:
1928  break;
1929  }
1930 
1931  // insert the pNew part (if it exists)
1932  if( pNew )
1933  {
1934  mpRedlineTable->Insert( pNew );
1935 
1936  // pNew must be deleted if Insert() wasn't
1937  // successful. But that can't happen, since pNew is
1938  // part of the original pRedl redline.
1939  // OSL_ENSURE( bRet, "Can't insert existing redline?" );
1940 
1941  // restart (now with pRedl being split up)
1942  n = 0;
1943  bDec = true;
1944  }
1945  }
1946  }
1947  break;
1948 
1949  case RedlineType::Format:
1950  switch( eCmpPos )
1951  {
1953  pRedl->SetStart( *pEnd, pRStt );
1954  // re-insert
1955  mpRedlineTable->Remove( n );
1956  mpRedlineTable->Insert( pRedl, n );
1957  bDec = true;
1958  break;
1959 
1961  pRedl->SetEnd( *pStt, pREnd );
1962  break;
1963 
1966  // Overlaps the current one completely or has the
1967  // same dimension, delete the old one
1968  mpRedlineTable->DeleteAndDestroy( n );
1969  bDec = true;
1970  break;
1971 
1973  // Overlaps the current one completely,
1974  // split or shorten the new one
1975  if( *pEnd != *pREnd )
1976  {
1977  if( *pEnd != *pRStt )
1978  {
1979  SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
1980  pNew->SetStart( *pEnd );
1981  pRedl->SetEnd( *pStt, pREnd );
1982  if( ( *pStt == *pRStt ) &&
1983  ( pRedl->GetContentIdx() == nullptr ) )
1984  mpRedlineTable->DeleteAndDestroy( n );
1985  AppendRedline( pNew, bCallDelete );
1986  n = 0; // re-initialize
1987  bDec = true;
1988  }
1989  }
1990  else
1991  pRedl->SetEnd( *pStt, pREnd );
1992  break;
1993  default:
1994  break;
1995  }
1996  break;
1997  default:
1998  break;
1999  }
2000  break;
2001 
2002  case RedlineType::Format:
2003  switch( pRedl->GetType() )
2004  {
2005  case RedlineType::Insert:
2006  case RedlineType::Delete:
2007  switch( eCmpPos )
2008  {
2010  pNewRedl->SetEnd( *pRStt, pEnd );
2011  break;
2012 
2014  pNewRedl->SetStart( *pREnd, pStt );
2015  break;
2016 
2019  delete pNewRedl;
2020  pNewRedl = nullptr;
2021  break;
2022 
2024  // Overlaps the current one completely,
2025  // split or shorten the new one
2026  if (*pEnd == *pREnd)
2027  {
2028  pNewRedl->SetEnd(*pRStt, pEnd);
2029  }
2030  else if (*pStt == *pRStt)
2031  {
2032  pNewRedl->SetStart(*pREnd, pStt);
2033  }
2034  else
2035  {
2036  SwRangeRedline* pNew = new SwRangeRedline( *pNewRedl );
2037  pNew->SetStart( *pREnd );
2038  pNewRedl->SetEnd( *pRStt, pEnd );
2039  AppendRedline( pNew, bCallDelete );
2040  n = 0; // re-initialize
2041  bDec = true;
2042  }
2043  break;
2044  default:
2045  break;
2046  }
2047  break;
2048  case RedlineType::Format:
2049  switch( eCmpPos )
2050  {
2053  {
2054  // Overlaps the current one completely or has the
2055  // same dimension, delete the old one
2056  mpRedlineTable->DeleteAndDestroy( n );
2057  bDec = true;
2058  }
2059  break;
2060 
2062  if( pRedl->IsOwnRedline( *pNewRedl ) &&
2063  pRedl->CanCombine( *pNewRedl ))
2064  {
2065  // own one can be ignored completely
2066  delete pNewRedl;
2067  pNewRedl = nullptr;
2068  }
2069  else if( *pREnd == *pEnd )
2070  // or else only shorten the current one
2071  pRedl->SetEnd( *pStt, pREnd );
2072  else if( *pRStt == *pStt )
2073  {
2074  // or else only shorten the current one
2075  pRedl->SetStart( *pEnd, pRStt );
2076  // re-insert
2077  mpRedlineTable->Remove( n );
2078  mpRedlineTable->Insert( pRedl, n );
2079  bDec = true;
2080  }
2081  else
2082  {
2083  // If it lies completely within the current one
2084  // we need to split it
2085  SwRangeRedline* pNew = new SwRangeRedline( *pRedl );
2086  pNew->SetStart( *pEnd );
2087  pRedl->SetEnd( *pStt, pREnd );
2088  AppendRedline( pNew, bCallDelete );
2089  n = 0; // re-initialize
2090  bDec = true;
2091  }
2092  break;
2093 
2096  if( pRedl->IsOwnRedline( *pNewRedl ) &&
2097  pRedl->CanCombine( *pNewRedl ))
2098  {
2099  // If that's the case we can merge it, meaning
2100  // the new one covers this well
2101  if( SwComparePosition::OverlapBehind == eCmpPos )
2102  pNewRedl->SetStart( *pRStt, pStt );
2103  else
2104  pNewRedl->SetEnd( *pREnd, pEnd );
2105  mpRedlineTable->DeleteAndDestroy( n );
2106  bDec = false;
2107  }
2108  else if( SwComparePosition::OverlapBehind == eCmpPos )
2109  pNewRedl->SetStart( *pREnd, pStt );
2110  else
2111  pNewRedl->SetEnd( *pRStt, pEnd );
2112  break;
2113 
2115  if( pRedl->IsOwnRedline( *pNewRedl ) &&
2116  pRedl->CanCombine( *pNewRedl ) && n &&
2117  *(*mpRedlineTable)[ n-1 ]->End() < *pStt )
2118  {
2119  // If that's the case we can merge it, meaning
2120  // the new one covers this well
2121  pNewRedl->SetEnd( *pREnd, pEnd );
2122  mpRedlineTable->DeleteAndDestroy( n );
2123  bDec = true;
2124  }
2125  break;
2127  if( pRedl->IsOwnRedline( *pNewRedl ) &&
2128  pRedl->CanCombine( *pNewRedl ) &&
2129  n+1 < mpRedlineTable->size() &&
2130  *(*mpRedlineTable)[ n+1 ]->Start() < *pEnd )
2131  {
2132  // If that's the case we can merge it, meaning
2133  // the new one covers this well
2134  pNewRedl->SetStart( *pRStt, pStt );
2135  mpRedlineTable->DeleteAndDestroy( n );
2136  bDec = true;
2137  }
2138  break;
2139  default:
2140  break;
2141  }
2142  break;
2143  default:
2144  break;
2145  }
2146  break;
2147 
2148  case RedlineType::FmtColl:
2149  // How should we behave here?
2150  // insert as is
2151  break;
2152  default:
2153  break;
2154  }
2155  }
2156 
2157  if( pNewRedl )
2158  {
2159  if( ( *pStt == *pEnd ) &&
2160  ( pNewRedl->GetContentIdx() == nullptr ) )
2161  { // Do not insert empty redlines
2162  delete pNewRedl;
2163  pNewRedl = nullptr;
2164  }
2165  else
2166  {
2167  if ( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2168  {
2169  if ( pStt->nContent != 0 )
2170  {
2171  // tdf#119571 update the style of the joined paragraph
2172  // after a partially deleted paragraph to show its correct style
2173  // in "Show changes" mode, too. All removed paragraphs
2174  // get the style of the first (partially deleted) paragraph
2175  // to avoid text insertion with bad style in the deleted
2176  // area later.
2177 
2178  SwContentNode* pDelNd = pStt->nNode.GetNode().GetContentNode();
2179  SwContentNode* pTextNd = pEnd->nNode.GetNode().GetContentNode();
2180  SwTextNode* pDelNode = pStt->nNode.GetNode().GetTextNode();
2181  SwTextNode* pTextNode;
2182  SwNodeIndex aIdx( pEnd->nNode.GetNode() );
2183  bool bFirst = true;
2184 
2185  while (pDelNode != nullptr && pTextNd != nullptr && pDelNd->GetIndex() < pTextNd->GetIndex())
2186  {
2187  pTextNode = pTextNd->GetTextNode();
2188  if (pTextNode && pDelNode != pTextNode )
2189  {
2190  SwPosition aPos(aIdx);
2191 
2193  {
2194  bCompress = true;
2195 
2196  // split redline to store ExtraData per paragraphs
2197  SwRangeRedline* pPar = new SwRangeRedline( *pNewRedl );
2198  pPar->SetStart( aPos );
2199  pNewRedl->SetEnd( aPos );
2200 
2201  // get extradata for reset formatting of the modified paragraph
2202  SwRedlineExtraData_FormatColl* pExtraData = lcl_CopyStyle(aPos, *pStt, false);
2203  if (pExtraData)
2204  {
2205  std::unique_ptr<SwRedlineExtraData_FormatColl> xRedlineExtraData;
2206  if (!bFirst)
2207  pExtraData->SetFormatAll(false);
2208  xRedlineExtraData.reset(pExtraData);
2209  pPar->SetExtraData( xRedlineExtraData.get() );
2210  }
2211 
2212  // skip empty redlines without ExtraData
2213  // FIXME: maybe checking pExtraData is redundant here
2214  if ( pExtraData || *pPar->Start() != *pPar->End() )
2215  mpRedlineTable->Insert( pPar );
2216  else
2217  delete pPar;
2218  }
2219 
2220  // modify paragraph formatting
2221  lcl_CopyStyle(*pStt, aPos);
2222  }
2223  pTextNd = SwNodes::GoPrevious( &aIdx );
2224 
2225  if (bFirst)
2226  bFirst = false;
2227  }
2228  }
2229  }
2230  bool const ret = mpRedlineTable->Insert( pNewRedl );
2231  assert(ret || !pNewRedl);
2232  if (ret && !pNewRedl)
2233  {
2234  bMerged = true; // treat InsertWithValidRanges as "merge"
2235  }
2236  }
2237  }
2238 
2239  if( bCompress )
2240  CompressRedlines();
2241  }
2242  else
2243  {
2244  if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2245  {
2247  // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2248  // The ShowMode needs to be retained!
2251  meRedlineFlags = eOld;
2252  }
2253  delete pNewRedl;
2254  pNewRedl = nullptr;
2255  }
2256  CHECK_REDLINE( *this )
2257 
2258  return (nullptr != pNewRedl)
2261 }
2262 
2264 {
2265  // #TODO - equivalent for 'SwTableRowRedline'
2266  /*
2267  CHECK_REDLINE( this )
2268  */
2269 
2271  {
2272  // #TODO - equivalent for 'SwTableRowRedline'
2273  /*
2274  pNewRedl->InvalidateRange();
2275  */
2276 
2277  // Make equivalent of 'AppendRedline' checks inside here too
2278 
2279  mpExtraRedlineTable->Insert( pNewRedl );
2280  }
2281  else
2282  {
2283  // TO DO - equivalent for 'SwTableRowRedline'
2284  /*
2285  if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2286  {
2287  RedlineFlags eOld = meRedlineFlags;
2288  // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2289  // The ShowMode needs to be retained!
2290  meRedlineFlags = eOld & ~(RedlineFlags::On | RedlineFlags::Ignore);
2291  DeleteAndJoin( *pNewRedl );
2292  meRedlineFlags = eOld;
2293  }
2294  delete pNewRedl, pNewRedl = 0;
2295  */
2296  }
2297  // #TODO - equivalent for 'SwTableRowRedline'
2298  /*
2299  CHECK_REDLINE( this )
2300  */
2301 
2302  return nullptr != pNewRedl;
2303 }
2304 
2306 {
2307  // #TODO - equivalent for 'SwTableCellRedline'
2308  /*
2309  CHECK_REDLINE( this )
2310  */
2311 
2313  {
2314  // #TODO - equivalent for 'SwTableCellRedline'
2315  /*
2316  pNewRedl->InvalidateRange();
2317  */
2318 
2319  // Make equivalent of 'AppendRedline' checks inside here too
2320 
2321  mpExtraRedlineTable->Insert( pNewRedl );
2322  }
2323  else
2324  {
2325  // TO DO - equivalent for 'SwTableCellRedline'
2326  /*
2327  if( bCallDelete && RedlineType::Delete == pNewRedl->GetType() )
2328  {
2329  RedlineFlags eOld = meRedlineFlags;
2330  // Set to NONE, so that the Delete::Redo merges the Redline data correctly!
2331  // The ShowMode needs to be retained!
2332  meRedlineFlags = eOld & ~(RedlineFlags::On | RedlineFlags::Ignore);
2333  DeleteAndJoin( *pNewRedl );
2334  meRedlineFlags = eOld;
2335  }
2336  delete pNewRedl, pNewRedl = 0;
2337  */
2338  }
2339  // #TODO - equivalent for 'SwTableCellRedline'
2340  /*
2341  CHECK_REDLINE( this )
2342  */
2343 
2344  return nullptr != pNewRedl;
2345 }
2346 
2348 {
2349  CHECK_REDLINE( *this )
2350 
2351  void (SwRangeRedline::*pFnc)(sal_uInt16, size_t, bool) = nullptr;
2354  pFnc = &SwRangeRedline::Show;
2355  else if (eShow == RedlineFlags::ShowInsert)
2356  pFnc = &SwRangeRedline::Hide;
2357 
2358  // Try to merge identical ones
2359  for( SwRedlineTable::size_type n = 1; n < mpRedlineTable->size(); ++n )
2360  {
2361  SwRangeRedline* pPrev = (*mpRedlineTable)[ n-1 ],
2362  * pCur = (*mpRedlineTable)[ n ];
2363  const SwPosition* pPrevStt = pPrev->Start(),
2364  * pPrevEnd = pPrevStt == pPrev->GetPoint()
2365  ? pPrev->GetMark() : pPrev->GetPoint();
2366  const SwPosition* pCurStt = pCur->Start(),
2367  * pCurEnd = pCurStt == pCur->GetPoint()
2368  ? pCur->GetMark() : pCur->GetPoint();
2369  if( *pPrevEnd == *pCurStt && pPrev->CanCombine( *pCur ) &&
2370  pPrevStt->nNode.GetNode().StartOfSectionNode() ==
2371  pCurEnd->nNode.GetNode().StartOfSectionNode() &&
2372  !pCurEnd->nNode.GetNode().StartOfSectionNode()->IsTableNode() )
2373  {
2374  // we then can merge them
2375  SwRedlineTable::size_type nPrevIndex = n-1;
2376  pPrev->Show(0, nPrevIndex);
2377  pCur->Show(0, n);
2378 
2379  pPrev->SetEnd( *pCur->End() );
2380  mpRedlineTable->DeleteAndDestroy( n );
2381  --n;
2382  if( pFnc )
2383  (pPrev->*pFnc)(0, nPrevIndex, false);
2384  }
2385  }
2386  CHECK_REDLINE( *this )
2387 
2388  // #TODO - add 'SwExtraRedlineTable' also ?
2389 }
2390 
2392 {
2393  bool bChg = false;
2395  const SwPosition* pStt = rRange.Start();
2396  const SwPosition* pEnd = rRange.End();
2397  GetRedline( *pStt, &n );
2398  for ( ; n < mpRedlineTable->size(); ++n)
2399  {
2400  SwRangeRedline * pRedline = (*mpRedlineTable)[ n ];
2401  SwPosition *const pRedlineStart = pRedline->Start();
2402  SwPosition *const pRedlineEnd = pRedline->End();
2403  if (*pRedlineStart <= *pStt && *pStt <= *pRedlineEnd &&
2404  *pRedlineStart <= *pEnd && *pEnd <= *pRedlineEnd)
2405  {
2406  bChg = true;
2407  int nn = 0;
2408  if (*pStt == *pRedlineStart)
2409  nn += 1;
2410  if (*pEnd == *pRedlineEnd)
2411  nn += 2;
2412 
2413  SwRangeRedline* pNew = nullptr;
2414  switch( nn )
2415  {
2416  case 0:
2417  pNew = new SwRangeRedline( *pRedline );
2418  pRedline->SetEnd( *pStt, pRedlineEnd );
2419  pNew->SetStart( *pEnd );
2420  break;
2421 
2422  case 1:
2423  *pRedlineStart = *pEnd;
2424  break;
2425 
2426  case 2:
2427  *pRedlineEnd = *pStt;
2428  break;
2429 
2430  case 3:
2432  mpRedlineTable->DeleteAndDestroy( n-- );
2433  pRedline = nullptr;
2434  break;
2435  }
2436  if (pRedline && !pRedline->HasValidRange())
2437  {
2438  // re-insert
2439  mpRedlineTable->Remove( n );
2440  mpRedlineTable->Insert( pRedline, n );
2441  }
2442  if( pNew )
2443  mpRedlineTable->Insert( pNew, n );
2444  }
2445  else if (*pEnd < *pRedlineStart)
2446  break;
2447  }
2448  return bChg;
2449 
2450  // #TODO - add 'SwExtraRedlineTable' also ?
2451 }
2452 
2453 bool DocumentRedlineManager::DeleteRedline( const SwPaM& rRange, bool bSaveInUndo,
2454  RedlineType nDelType )
2455 {
2456  if( !rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() )
2457  return false;
2458 
2459  bool bChg = false;
2460 
2461  if (bSaveInUndo && m_rDoc.GetIDocumentUndoRedo().DoesUndo())
2462  {
2463  std::unique_ptr<SwUndoRedline> pUndo(new SwUndoRedline( SwUndoId::REDLINE, rRange ));
2464  if( pUndo->GetRedlSaveCount() )
2465  {
2466  m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
2467  }
2468  }
2469 
2470  const SwPosition* pStt = rRange.Start(),
2471  * pEnd = pStt == rRange.GetPoint() ? rRange.GetMark()
2472  : rRange.GetPoint();
2474  GetRedline( *pStt, &n );
2475  for( ; n < mpRedlineTable->size() ; ++n )
2476  {
2477  SwRangeRedline* pRedl = (*mpRedlineTable)[ n ];
2478  if( RedlineType::Any != nDelType && nDelType != pRedl->GetType() )
2479  continue;
2480 
2481  SwPosition* pRStt = pRedl->Start(),
2482  * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark()
2483  : pRedl->GetPoint();
2484  switch( ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ) )
2485  {
2489  mpRedlineTable->DeleteAndDestroy( n-- );
2490  bChg = true;
2491  break;
2492 
2495  pRedl->SetStart( *pEnd, pRStt );
2497  // re-insert
2498  mpRedlineTable->Remove( n );
2499  mpRedlineTable->Insert( pRedl );
2500  --n;
2501  break;
2502 
2505  pRedl->SetEnd( *pStt, pREnd );
2507  if( !pRedl->HasValidRange() )
2508  {
2509  // re-insert
2510  mpRedlineTable->Remove( n );
2511  mpRedlineTable->Insert( pRedl );
2512  --n;
2513  }
2514  break;
2515 
2517  {
2518  // this one needs to be split
2520  if( *pRStt == *pStt )
2521  {
2522  pRedl->SetStart( *pEnd, pRStt );
2524  // re-insert
2525  mpRedlineTable->Remove( n );
2526  mpRedlineTable->Insert( pRedl );
2527  --n;
2528  }
2529  else
2530  {
2531  SwRangeRedline* pCpy;
2532  if( *pREnd != *pEnd )
2533  {
2534  pCpy = new SwRangeRedline( *pRedl );
2535  pCpy->SetStart( *pEnd );
2537  }
2538  else
2539  pCpy = nullptr;
2540  pRedl->SetEnd( *pStt, pREnd );
2542  if( !pRedl->HasValidRange() )
2543  {
2544  // re-insert
2545  mpRedlineTable->Remove( n );
2546  mpRedlineTable->Insert( pRedl );
2547  --n;
2548  }
2549  if( pCpy )
2550  mpRedlineTable->Insert( pCpy );
2551  }
2552  }
2553  break;
2554 
2556  // remove (not hidden) empty redlines created for fixing tdf#119571
2557  // (Note: hidden redlines are all empty, i.e. start and end are equal.)
2558  if ( pRedl->HasMark() && *pRedl->GetMark() == *pRedl->GetPoint() )
2559  {
2561  mpRedlineTable->DeleteAndDestroy( n-- );
2562  bChg = true;
2563  break;
2564  }
2565  [[fallthrough]];
2566 
2568  n = mpRedlineTable->size();
2569  break;
2570  default:
2571  break;
2572  }
2573  }
2574 
2575  if( bChg )
2577 
2578  return bChg;
2579 
2580  // #TODO - add 'SwExtraRedlineTable' also ?
2581 }
2582 
2583 bool DocumentRedlineManager::DeleteRedline( const SwStartNode& rNode, bool bSaveInUndo,
2584  RedlineType nDelType )
2585 {
2586  SwPaM aTemp(*rNode.EndOfSectionNode(), rNode);
2587  return DeleteRedline(aTemp, bSaveInUndo, nDelType);
2588 }
2589 
2591 {
2592  const sal_uLong nNdIdx = rNd.GetIndex();
2593  for( SwRedlineTable::size_type n = 0; n < mpRedlineTable->size() ; ++n )
2594  {
2595  const SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
2596  sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
2597  nMk = pTmp->GetMark()->nNode.GetIndex();
2598  if( nPt < nMk ) { tools::Long nTmp = nMk; nMk = nPt; nPt = nTmp; }
2599 
2600  if( ( RedlineType::Any == nType || nType == pTmp->GetType()) &&
2601  nMk <= nNdIdx && nNdIdx <= nPt )
2602  return n;
2603 
2604  if( nMk > nNdIdx )
2605  break;
2606  }
2607  return SwRedlineTable::npos;
2608 
2609  // #TODO - add 'SwExtraRedlineTable' also ?
2610 }
2611 
2612 bool DocumentRedlineManager::HasRedline( const SwPaM& rPam, RedlineType nType, bool bStartOrEndInRange ) const
2613 {
2614  SwPosition currentStart(*rPam.Start());
2615  SwPosition currentEnd(*rPam.End());
2616  SwNodeIndex pEndNodeIndex(currentEnd.nNode.GetNode());
2617 
2618  for( SwRedlineTable::size_type n = GetRedlinePos( rPam.Start()->nNode.GetNode(), nType );
2619  n < mpRedlineTable->size(); ++n )
2620  {
2621  const SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
2622 
2623  if ( pTmp->Start()->nNode > pEndNodeIndex )
2624  break;
2625 
2626  if( RedlineType::Any != nType && nType != pTmp->GetType() )
2627  continue;
2628 
2629  // redline over the range
2630  if ( currentStart < *pTmp->End() && *pTmp->Start() <= currentEnd &&
2631  // starting or ending within the range
2632  ( !bStartOrEndInRange ||
2633  ( currentStart < *pTmp->Start() || *pTmp->End() < currentEnd ) ) )
2634  {
2635  return true;
2636  }
2637  }
2638  return false;
2639 }
2640 
2642  SwRedlineTable::size_type* pFndPos ) const
2643 {
2644  SwRedlineTable::size_type nO = mpRedlineTable->size(), nM, nU = 0;
2645  if( nO > 0 )
2646  {
2647  nO--;
2648  while( nU <= nO )
2649  {
2650  nM = nU + ( nO - nU ) / 2;
2651  const SwRangeRedline* pRedl = (*mpRedlineTable)[ nM ];
2652  const SwPosition* pStt = pRedl->Start();
2653  const SwPosition* pEnd = pStt == pRedl->GetPoint()
2654  ? pRedl->GetMark()
2655  : pRedl->GetPoint();
2656  if( pEnd == pStt
2657  ? *pStt == rPos
2658  : ( *pStt <= rPos && rPos < *pEnd ) )
2659  {
2660  while( nM && rPos == *(*mpRedlineTable)[ nM - 1 ]->End() &&
2661  rPos == *(*mpRedlineTable)[ nM - 1 ]->Start() )
2662  {
2663  --nM;
2664  pRedl = (*mpRedlineTable)[ nM ];
2665  }
2666  // if there are format and insert changes in the same position
2667  // show insert change first.
2668  // since the redlines are sorted by position, only check the redline
2669  // before and after the current redline
2670  if( RedlineType::Format == pRedl->GetType() )
2671  {
2672  if( nM && rPos >= *(*mpRedlineTable)[ nM - 1 ]->Start() &&
2673  rPos <= *(*mpRedlineTable)[ nM - 1 ]->End() &&
2674  ( RedlineType::Insert == (*mpRedlineTable)[ nM - 1 ]->GetType() ) )
2675  {
2676  --nM;
2677  pRedl = (*mpRedlineTable)[ nM ];
2678  }
2679  else if( ( nM + 1 ) <= nO && rPos >= *(*mpRedlineTable)[ nM + 1 ]->Start() &&
2680  rPos <= *(*mpRedlineTable)[ nM + 1 ]->End() &&
2681  ( RedlineType::Insert == (*mpRedlineTable)[ nM + 1 ]->GetType() ) )
2682  {
2683  ++nM;
2684  pRedl = (*mpRedlineTable)[ nM ];
2685  }
2686  }
2687 
2688  if( pFndPos )
2689  *pFndPos = nM;
2690  return pRedl;
2691  }
2692  else if( *pEnd <= rPos )
2693  nU = nM + 1;
2694  else if( nM == 0 )
2695  {
2696  if( pFndPos )
2697  *pFndPos = nU;
2698  return nullptr;
2699  }
2700  else
2701  nO = nM - 1;
2702  }
2703  }
2704  if( pFndPos )
2705  *pFndPos = nU;
2706  return nullptr;
2707 
2708  // #TODO - add 'SwExtraRedlineTable' also ?
2709 }
2710 
2712 {
2713  bool bRet = false;
2714 
2715  // Switch to visible in any case
2719 
2720  SwRangeRedline* pTmp = (*mpRedlineTable)[ nPos ];
2721  pTmp->Show(0, mpRedlineTable->GetPos(pTmp), /*bForced=*/true);
2722  pTmp->Show(1, mpRedlineTable->GetPos(pTmp), /*bForced=*/true);
2723  if( pTmp->HasMark() && pTmp->IsVisible() )
2724  {
2726  {
2727  SwRewriter aRewriter;
2728 
2729  aRewriter.AddRule(UndoArg1, pTmp->GetDescr());
2731  }
2732 
2733  int nLoopCnt = 2;
2734  sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2735 
2736  do {
2737 
2739  {
2741  std::make_unique<SwUndoAcceptRedline>(*pTmp) );
2742  }
2743 
2744  bRet |= lcl_AcceptRedline( *mpRedlineTable, nPos, bCallDelete );
2745 
2746  if( nSeqNo )
2747  {
2748  if( SwRedlineTable::npos == nPos )
2749  nPos = 0;
2750  SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
2751  ? mpRedlineTable->FindNextSeqNo( nSeqNo, nPos )
2752  : mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos );
2753  if( SwRedlineTable::npos != nFndPos || ( 0 != ( --nLoopCnt ) &&
2754  SwRedlineTable::npos != ( nFndPos =
2755  mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos ))) )
2756  {
2757  nPos = nFndPos;
2758  pTmp = (*mpRedlineTable)[ nPos ];
2759  }
2760  else
2761  nLoopCnt = 0;
2762  }
2763  else
2764  nLoopCnt = 0;
2765 
2766  } while( nLoopCnt );
2767 
2768  if( bRet )
2769  {
2770  CompressRedlines();
2772  }
2773 
2775  {
2777  }
2778  }
2779  return bRet;
2780 
2781  // #TODO - add 'SwExtraRedlineTable' also ?
2782 }
2783 
2784 bool DocumentRedlineManager::AcceptRedline( const SwPaM& rPam, bool bCallDelete )
2785 {
2786  // Switch to visible in any case
2790 
2791  // The Selection is only in the ContentSection. If there are Redlines
2792  // to Non-ContentNodes before or after that, then the Selections
2793  // expand to them.
2794  SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2795  lcl_AdjustRedlineRange( aPam );
2796 
2798  {
2800  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAcceptRedline>( aPam ));
2801  }
2802 
2803  int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, *mpRedlineTable,
2804  bCallDelete, aPam );
2805  if( nRet > 0 )
2806  {
2807  CompressRedlines();
2809  }
2811  {
2812  OUString aTmpStr;
2813 
2814  {
2815  SwRewriter aRewriter;
2816  aRewriter.AddRule(UndoArg1, OUString::number(nRet));
2817  aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
2818  }
2819 
2820  SwRewriter aRewriter;
2821  aRewriter.AddRule(UndoArg1, aTmpStr);
2822 
2824  }
2825  return nRet != 0;
2826 
2827  // #TODO - add 'SwExtraRedlineTable' also ?
2828 }
2829 
2831 {
2832  const SwPosition* pStt = rPam.Start(),
2833  * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark()
2834  : rPam.GetPoint();
2835 
2836  const sal_uLong nSttIdx = pStt->nNode.GetIndex();
2837  const sal_uLong nEndIdx = pEnd->nNode.GetIndex();
2838 
2839  for( SwRedlineTable::size_type n = 0; n < mpRedlineTable->size() ; ++n )
2840  {
2841  const SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
2842  sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(),
2843  nMk = pTmp->GetMark()->nNode.GetIndex();
2844  if( nPt < nMk ) { tools::Long nTmp = nMk; nMk = nPt; nPt = nTmp; }
2845 
2846  if( RedlineType::ParagraphFormat == pTmp->GetType() &&
2847  ( (nSttIdx <= nMk && nMk <= nEndIdx) || (nSttIdx <= nPt && nPt <= nEndIdx) ) )
2848  AcceptRedline( n, false );
2849 
2850  if( nMk > nEndIdx )
2851  break;
2852  }
2853 }
2854 
2856 {
2857  bool bRet = false;
2858 
2859  // Switch to visible in any case
2863 
2864  SwRangeRedline* pTmp = (*mpRedlineTable)[ nPos ];
2865  pTmp->Show(0, mpRedlineTable->GetPos(pTmp), /*bForced=*/true);
2866  pTmp->Show(1, mpRedlineTable->GetPos(pTmp), /*bForced=*/true);
2867  if( pTmp->HasMark() && pTmp->IsVisible() )
2868  {
2870  {
2871  SwRewriter aRewriter;
2872 
2873  aRewriter.AddRule(UndoArg1, pTmp->GetDescr());
2875  }
2876 
2877  int nLoopCnt = 2;
2878  sal_uInt16 nSeqNo = pTmp->GetSeqNo();
2879 
2880  do {
2881 
2883  {
2885  std::make_unique<SwUndoRejectRedline>( *pTmp ) );
2886  }
2887 
2888  bRet |= lcl_RejectRedline( *mpRedlineTable, nPos, bCallDelete );
2889 
2890  if( nSeqNo )
2891  {
2892  if( SwRedlineTable::npos == nPos )
2893  nPos = 0;
2894  SwRedlineTable::size_type nFndPos = 2 == nLoopCnt
2895  ? mpRedlineTable->FindNextSeqNo( nSeqNo, nPos )
2896  : mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos );
2897  if( SwRedlineTable::npos != nFndPos || ( 0 != ( --nLoopCnt ) &&
2898  SwRedlineTable::npos != ( nFndPos =
2899  mpRedlineTable->FindPrevSeqNo( nSeqNo, nPos ))) )
2900  {
2901  nPos = nFndPos;
2902  pTmp = (*mpRedlineTable)[ nPos ];
2903  }
2904  else
2905  nLoopCnt = 0;
2906  }
2907  else
2908  nLoopCnt = 0;
2909 
2910  } while( nLoopCnt );
2911 
2912  if( bRet )
2913  {
2914  CompressRedlines();
2916  }
2917 
2919  {
2921  }
2922  }
2923  return bRet;
2924 
2925  // #TODO - add 'SwExtraRedlineTable' also ?
2926 }
2927 
2928 bool DocumentRedlineManager::RejectRedline( const SwPaM& rPam, bool bCallDelete )
2929 {
2930  // Switch to visible in any case
2934 
2935  // The Selection is only in the ContentSection. If there are Redlines
2936  // to Non-ContentNodes before or after that, then the Selections
2937  // expand to them.
2938  SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2939  lcl_AdjustRedlineRange( aPam );
2940 
2942  {
2944  m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoRejectRedline>(aPam) );
2945  }
2946 
2947  int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, *mpRedlineTable,
2948  bCallDelete, aPam );
2949  if( nRet > 0 )
2950  {
2951  CompressRedlines();
2953  }
2955  {
2956  OUString aTmpStr;
2957 
2958  {
2959  SwRewriter aRewriter;
2960  aRewriter.AddRule(UndoArg1, OUString::number(nRet));
2961  aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
2962  }
2963 
2964  SwRewriter aRewriter;
2965  aRewriter.AddRule(UndoArg1, aTmpStr);
2966 
2968  }
2969 
2970  return nRet != 0;
2971 
2972  // #TODO - add 'SwExtraRedlineTable' also ?
2973 }
2974 
2976 {
2977  bool bSuccess = true;
2978  OUString sUndoStr;
2980 
2981  if (mpRedlineTable->size() > 1)
2982  {
2983  {
2984  SwRewriter aRewriter;
2985  aRewriter.AddRule(UndoArg1, OUString::number(mpRedlineTable->size()));
2986  sUndoStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
2987  }
2988 
2989  SwRewriter aRewriter;
2990  aRewriter.AddRule(UndoArg1, sUndoStr);
2991  rUndoMgr.StartUndo(bAccept ? SwUndoId::ACCEPT_REDLINE : SwUndoId::REJECT_REDLINE, &aRewriter);
2992  }
2993 
2994  while (!mpRedlineTable->empty() && bSuccess)
2995  {
2996  if (bAccept)
2997  bSuccess = AcceptRedline(mpRedlineTable->size() - 1, true);
2998  else
2999  bSuccess = RejectRedline(mpRedlineTable->size() - 1, true);
3000  }
3001 
3002  if (!sUndoStr.isEmpty())
3003  {
3004  rUndoMgr.EndUndo(SwUndoId::EMPTY, nullptr);
3005  }
3006 }
3007 
3009 {
3010  rPam.DeleteMark();
3011  rPam.SetMark();
3012 
3013  SwPosition& rSttPos = *rPam.GetPoint();
3014  SwPosition aSavePos( rSttPos );
3015  bool bRestart;
3016 
3017  // If the starting position points to the last valid ContentNode,
3018  // we take the next Redline in any case.
3020  const SwRangeRedline* pFnd = GetRedlineTable().FindAtPosition( rSttPos, n );
3021  if( pFnd )
3022  {
3023  const SwPosition* pEnd = pFnd->End();
3024  if( !pEnd->nNode.GetNode().IsContentNode() )
3025  {
3026  SwNodeIndex aTmp( pEnd->nNode );
3027  SwContentNode* pCNd = SwNodes::GoPrevSection( &aTmp );
3028  if( !pCNd || ( aTmp == rSttPos.nNode &&
3029  pCNd->Len() == rSttPos.nContent.GetIndex() ))
3030  pFnd = nullptr;
3031  }
3032  if( pFnd )
3033  rSttPos = *pFnd->End();
3034  }
3035 
3036  do {
3037  bRestart = false;
3038 
3039  for( ; !pFnd && n < mpRedlineTable->size(); ++n )
3040  {
3041  pFnd = (*mpRedlineTable)[ n ];
3042  if( pFnd->HasMark() && pFnd->IsVisible() )
3043  {
3044  *rPam.GetMark() = *pFnd->Start();
3045  rSttPos = *pFnd->End();
3046  break;
3047  }
3048  else
3049  pFnd = nullptr;
3050  }
3051 
3052  if( pFnd )
3053  {
3054  // Merge all of the same type and author that are
3055  // consecutive into one Selection.
3056  const SwPosition* pPrevEnd = pFnd->End();
3057  while( ++n < mpRedlineTable->size() )
3058  {
3059  const SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
3060  if( pTmp->HasMark() && pTmp->IsVisible() )
3061  {
3062  const SwPosition *pRStt;
3063  if( pFnd->GetType() != pTmp->GetType() ||
3064  pFnd->GetAuthor() != pTmp->GetAuthor() )
3065  break;
3066  pRStt = pTmp->Start();
3067  if( *pPrevEnd == *pRStt || IsPrevPos( *pPrevEnd, *pRStt ) )
3068  {
3069  pPrevEnd = pTmp->End();
3070  rSttPos = *pPrevEnd;
3071  }
3072  else
3073  break;
3074  }
3075  }
3076  }
3077 
3078  if( pFnd )
3079  {
3080  const SwRangeRedline* pSaveFnd = pFnd;
3081 
3082  SwContentNode* pCNd;
3083  SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
3084  if( !pIdx->GetNode().IsContentNode() )
3085  {
3086  pCNd = m_rDoc.GetNodes().GoNextSection( pIdx );
3087  if( pCNd )
3088  {
3089  if( *pIdx <= rPam.GetPoint()->nNode )
3090  rPam.GetMark()->nContent.Assign( pCNd, 0 );
3091  else
3092  pFnd = nullptr;
3093  }
3094  }
3095 
3096  if( pFnd )
3097  {
3098  pIdx = &rPam.GetPoint()->nNode;
3099  if( !pIdx->GetNode().IsContentNode() )
3100  {
3101  pCNd = SwNodes::GoPrevSection( pIdx );
3102  if( pCNd )
3103  {
3104  if( *pIdx >= rPam.GetMark()->nNode )
3105  rPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
3106  else
3107  pFnd = nullptr;
3108  }
3109  }
3110  }
3111 
3112  if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
3113  {
3114  if( n < mpRedlineTable->size() )
3115  {
3116  bRestart = true;
3117  *rPam.GetPoint() = *pSaveFnd->End();
3118  }
3119  else
3120  {
3121  rPam.DeleteMark();
3122  *rPam.GetPoint() = aSavePos;
3123  }
3124  pFnd = nullptr;
3125  }
3126  }
3127  } while( bRestart );
3128 
3129  return pFnd;
3130 
3131  // #TODO - add 'SwExtraRedlineTable' also ?
3132 }
3133 
3135 {
3136  rPam.DeleteMark();
3137  rPam.SetMark();
3138 
3139  SwPosition& rSttPos = *rPam.GetPoint();
3140  SwPosition aSavePos( rSttPos );
3141  bool bRestart;
3142 
3143  // If the starting position points to the last valid ContentNode,
3144  // we take the previous Redline in any case.
3146  const SwRangeRedline* pFnd = GetRedlineTable().FindAtPosition( rSttPos, n, false );
3147  if( pFnd )
3148  {
3149  const SwPosition* pStt = pFnd->Start();
3150  if( !pStt->nNode.GetNode().IsContentNode() )
3151  {
3152  SwNodeIndex aTmp( pStt->nNode );
3153  SwContentNode* pCNd = m_rDoc.GetNodes().GoNextSection( &aTmp );
3154  if( !pCNd || ( aTmp == rSttPos.nNode &&
3155  !rSttPos.nContent.GetIndex() ))
3156  pFnd = nullptr;
3157  }
3158  if( pFnd )
3159  rSttPos = *pFnd->Start();
3160  }
3161 
3162  do {
3163  bRestart = false;
3164 
3165  while( !pFnd && 0 < n )
3166  {
3167  pFnd = (*mpRedlineTable)[ --n ];
3168  if( pFnd->HasMark() && pFnd->IsVisible() )
3169  {
3170  *rPam.GetMark() = *pFnd->End();
3171  rSttPos = *pFnd->Start();
3172  }
3173  else
3174  pFnd = nullptr;
3175  }
3176 
3177  if( pFnd )
3178  {
3179  // Merge all of the same type and author that are
3180  // consecutive into one Selection.
3181  const SwPosition* pNextStt = pFnd->Start();
3182  while( 0 < n )
3183  {
3184  const SwRangeRedline* pTmp = (*mpRedlineTable)[ --n ];
3185  if( pTmp->HasMark() && pTmp->IsVisible() )
3186  {
3187  const SwPosition *pREnd;
3188  if( pFnd->GetType() == pTmp->GetType() &&
3189  pFnd->GetAuthor() == pTmp->GetAuthor() &&
3190  ( *pNextStt == *( pREnd = pTmp->End() ) ||
3191  IsPrevPos( *pREnd, *pNextStt )) )
3192  {
3193  pNextStt = pTmp->Start();
3194  rSttPos = *pNextStt;
3195  }
3196  else
3197  {
3198  ++n;
3199  break;
3200  }
3201  }
3202  }
3203  }
3204 
3205  if( pFnd )
3206  {
3207  const SwRangeRedline* pSaveFnd = pFnd;
3208 
3209  SwContentNode* pCNd;
3210  SwNodeIndex* pIdx = &rPam.GetMark()->nNode;
3211  if( !pIdx->GetNode().IsContentNode() )
3212  {
3213  pCNd = SwNodes::GoPrevSection( pIdx );
3214  if( pCNd )
3215  {
3216  if( *pIdx >= rPam.GetPoint()->nNode )
3217  rPam.GetMark()->nContent.Assign( pCNd, pCNd->Len() );
3218  else
3219  pFnd = nullptr;
3220  }
3221  }
3222 
3223  if( pFnd )
3224  {
3225  pIdx = &rPam.GetPoint()->nNode;
3226  if( !pIdx->GetNode().IsContentNode() )
3227  {
3228  pCNd = m_rDoc.GetNodes().GoNextSection( pIdx );
3229  if( pCNd )
3230  {
3231  if( *pIdx <= rPam.GetMark()->nNode )
3232  rPam.GetPoint()->nContent.Assign( pCNd, 0 );
3233  else
3234  pFnd = nullptr;
3235  }
3236  }
3237  }
3238 
3239  if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() )
3240  {
3241  if( n )
3242  {
3243  bRestart = true;
3244  *rPam.GetPoint() = *pSaveFnd->Start();
3245  }
3246  else
3247  {
3248  rPam.DeleteMark();
3249  *rPam.GetPoint() = aSavePos;
3250  }
3251  pFnd = nullptr;
3252  }
3253  }
3254  } while( bRestart );
3255 
3256  return pFnd;
3257 
3258  // #TODO - add 'SwExtraRedlineTable' also ?
3259 }
3260 
3261 // Set comment at the Redline
3262 bool DocumentRedlineManager::SetRedlineComment( const SwPaM& rPaM, const OUString& rS )
3263 {
3264  bool bRet = false;
3265  const SwPosition* pStt = rPaM.Start(),
3266  * pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
3267  : rPaM.GetPoint();
3269  if( GetRedlineTable().FindAtPosition( *pStt, n ) )
3270  {
3271  for( ; n < mpRedlineTable->size(); ++n )
3272  {
3273  bRet = true;
3274  SwRangeRedline* pTmp = (*mpRedlineTable)[ n ];
3275  if( pStt != pEnd && *pTmp->Start() > *pEnd )
3276  break;
3277 
3278  pTmp->SetComment( rS );
3279  if( *pTmp->End() >= *pEnd )
3280  break;
3281  }
3282  }
3283  if( bRet )
3285 
3286  return bRet;
3287 
3288  // #TODO - add 'SwExtraRedlineTable' also ?
3289 }
3290 
3291 // Create a new author if necessary
3293 {
3294  return SW_MOD()->GetRedlineAuthor();
3295 }
3296 
3298 std::size_t DocumentRedlineManager::InsertRedlineAuthor( const OUString& rNew )
3299 {
3300  return SW_MOD()->InsertRedlineAuthor(rNew);
3301 }
3302 
3304 {
3305  const SwRedlineTable& rTable = GetRedlineTable();
3306  for(SwRangeRedline* pRedl : rTable)
3307  {
3308  if( pRedl->IsVisible() )
3310  }
3311 
3312  // #TODO - add 'SwExtraRedlineTable' also ?
3313 }
3314 
3315 const uno::Sequence <sal_Int8>& DocumentRedlineManager::GetRedlinePassword() const
3316 {
3317  return maRedlinePasswd;
3318 }
3319 
3321  /*[in]*/const uno::Sequence <sal_Int8>& rNewPassword)
3322 {
3323  maRedlinePasswd = rNewPassword;
3325 }
3326 
3331 void DocumentRedlineManager::SetAutoFormatRedlineComment( const OUString* pText, sal_uInt16 nSeqNo )
3332 {
3333  m_rDoc.SetAutoFormatRedline( nullptr != pText );
3334  if( pText )
3335  {
3336  mpAutoFormatRedlnComment.reset( new OUString( *pText ) );
3337  }
3338  else
3339  {
3340  mpAutoFormatRedlnComment.reset();
3341  }
3342 
3343  mnAutoFormatRedlnCommentNo = nSeqNo;
3344 }
3345 
3346 void DocumentRedlineManager::HideAll( bool bDeletion )
3347 {
3348  const SwRedlineTable& rTable = GetRedlineTable();
3349  for (SwRedlineTable::size_type i = rTable.size(); i > 0; --i)
3350  {
3351  SwRangeRedline* pRedline = rTable[i-1];
3352  if ( pRedline->GetType() == RedlineType::Delete )
3353  {
3354  if ( bDeletion && pRedline->IsVisible() )
3355  {
3356  pRedline->Hide(0, rTable.GetPos(pRedline), false);
3357  pRedline->Hide(1, rTable.GetPos(pRedline), false);
3358  }
3359  else if ( !bDeletion && !pRedline->IsVisible() )
3360  {
3361  pRedline->Show(0, rTable.GetPos(pRedline), true);
3362  pRedline->Show(1, rTable.GetPos(pRedline), true);
3363  }
3364  }
3365  else if ( pRedline->GetType() == RedlineType::Insert )
3366  {
3367  if ( !bDeletion && pRedline->IsVisible() )
3368  {
3369  pRedline->ShowOriginal(0, rTable.GetPos(pRedline), false);
3370  pRedline->ShowOriginal(1, rTable.GetPos(pRedline), false);
3371  }
3372  else if ( bDeletion && !pRedline->IsVisible() )
3373  {
3374  pRedline->Show(0, rTable.GetPos(pRedline), true);
3375  pRedline->Show(1, rTable.GetPos(pRedline), true);
3376  }
3377  }
3378  }
3379 }
3380 
3382 {
3383  const SwRedlineTable& rTable = GetRedlineTable();
3384  for (SwRedlineTable::size_type i = rTable.size(); i > 0; --i)
3385  {
3386  SwRangeRedline* pRedline = rTable[i-1];
3387  if ( !pRedline->IsVisible() )
3388  {
3389  pRedline->Show(0, rTable.GetPos(pRedline), true);
3390  pRedline->Show(1, rTable.GetPos(pRedline), true);
3391  }
3392  }
3393 }
3394 
3396 {
3397 }
3398 
3399 }
3400 
3401 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:683
Starts a section of nodes in the document model.
Definition: node.hxx:312
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:158
virtual sal_Int32 Len() const
Definition: node.cxx:1246
void DeleteMark()
Definition: pam.hxx:177
std::unique_ptr< SwRedlineTable > mpRedlineTable
bool CanCombine(const SwRangeRedline &rRedl) const
Definition: docredln.cxx:1755
sal_uLong GetIndex() const
Definition: node.hxx:291
const SwRedlineExtraData * GetExtraData() const
Definition: redline.hxx:215
virtual AppendResult AppendRedline(SwRangeRedline *pPtr, bool bCallDelete) override
Append a new redline.
void Show(sal_uInt16 nLoop, size_t nMyPos, bool bForced=false)
Definition: docredln.cxx:1119
sal_uInt16 GetSeqNo() const
Definition: redline.hxx:221
Represents the style of a paragraph.
Definition: fmtcol.hxx:56
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 UpdateFramesForAddDeleteRedline(SwDoc &rDoc, SwPaM const &rPam)
constexpr TypedWhichId< SvxPrintItem > RES_PRINT(98)
SwTableBox * GetTableBox() const
If node is in a table return the respective table box.
Definition: node.cxx:754
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:215
virtual const SwRootFrame * GetCurrentLayout() const =0
static constexpr auto Items
virtual std::size_t GetRedlineAuthor() override
SwDocShell * GetDocShell()
Definition: doc.hxx:1352
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
void DeleteRow(const SwCursor &rCursor)
Deleting Columns/Rows.
Definition: ndtbl.cxx:1830
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:276
virtual void SetModified()=0
Must be called manually at changes of format.
sal_uIntPtr sal_uLong
long Long
Pos1 is as large as Pos2.
const SwPosition * GetMark() const
Definition: pam.hxx:209
Pos1 completely contained in Pos2.
sal_Int64 n
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
void Remove(size_type nPos)
Definition: docredln.cxx:617
void SetSeqNo(sal_uInt16 nNo)
Definition: redline.hxx:222
Definition: doc.hxx:188
constexpr sal_uInt16 RES_FRMATR_END(133)
static SwContentNode * GoPrevSection(SwNodeIndex *, bool bSkipHidden=true, bool bSkipProtect=true)
Definition: nodes.cxx:1968
TElementType * Next()
Definition: calbck.hxx:333
#define ERROR_PREFIX
void SetEnd(const SwPosition &rPos, SwPosition *pEndPtr=nullptr)
Definition: docredln.cxx:1084
virtual bool DeleteRedline(const SwPaM &rPam, bool bSaveInUndo, RedlineType nDelType) override
virtual void DeleteRange(SwPaM &)=0
Delete a range SwFlyFrameFormat.
static SwContentNode * GoPrevious(SwNodeIndex *)
Definition: nodes.cxx:1310
SwTableLine is one table row in the document model.
Definition: swtable.hxx:351
SwNode & GetNode() const
Definition: ndindex.hxx:119
virtual const SwExtraRedlineTable & GetExtraRedlineTable() const override
virtual void UpdateRedlineAttr() override
Dialog to specify the properties of date form field.
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
virtual bool DeleteAndJoin(SwPaM &, const bool bForceJoinNext=false)=0
complete delete of a given PaM
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
The root element of a Writer document layout.
Definition: rootfrm.hxx:82
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:744
bool HasValidRange() const
Do we have a valid selection?
Definition: docredln.cxx:1093
show all inserts
size_type size() const
Definition: docary.hxx:261
void UpdateFields() const
Definition: fldbas.cxx:148
virtual void UpdateExpFields(SwTextField *pField, bool bUpdateRefFields)=0
Pos1 end touches at Pos2 start.
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:357
SwDoc & m_rDoc
Definition: docbm.cxx:1208
bool IsOwnRedline(const SwRangeRedline &rRedl) const
Definition: redline.hxx:240
virtual const SwRangeRedline * SelPrevRedline(SwPaM &rPam) const override
virtual void Reject(SwPaM &rPam) const
Definition: docredln.cxx:755
constexpr sal_uInt16 RES_PARATR_BEGIN(RES_TXTATR_END)
SwIndex nContent
Definition: pam.hxx:38
void ResetAttrs(const SwPaM &rRg, bool bTextAttr=true, const o3tl::sorted_vector< sal_uInt16 > &rAttrs=o3tl::sorted_vector< sal_uInt16 >(), const bool bSendDataChangedEvents=true, SwRootFrame const *pLayout=nullptr)
Reset attributes.
Definition: docfmt.cxx:242
bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset=true, const bool bResetListAttrs=false, SwRootFrame const *pLayout=nullptr)
Add 4th optional parameter .
Definition: docfmt.cxx:1072
std::unique_ptr< sw::MergedPara > CheckParaRedlineMerge(SwTextFrame &rFrame, SwTextNode &rTextNode, FrameMode eMode)
Definition: redlnitr.cxx:205
const OUString & GetName() const
Definition: format.hxx:115
int nCount
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
Pos2 completely contained in Pos1.
void AddRemoveFlysAnchoredToFrameStartingAtNode(SwTextFrame &rFrame, SwTextNode &rTextNode, std::set< sal_uLong > *pSkipped)
rTextNode is the first one of the "new" merge - if rTextNode isn't the same as MergedPara::pFirstNode...
Definition: wsfrm.cxx:4272
void SetInXMLImport(bool bNew)
Definition: doc.hxx:971
Mode eMode
o3tl::sorted_vector< SwRootFrame * > GetAllLayouts()
Definition: doclay.cxx:1670
void ShowOriginal(sal_uInt16 nLoop, size_t nMyPos, bool bForced=false)
Definition: docredln.cxx:1209
Pos1 before Pos2.
RedlineFlags on.
virtual bool DoesUndo() const =0
Is Undo enabled?
sal_uInt16 GetStackCount() const
Definition: docredln.cxx:1787
void SetExtraData(const SwRedlineExtraData *pData)
ExtraData gets copied, the pointer is therefore not taken over by the RedLineObject.
Definition: redline.hxx:213
void MakeFrames(SwDoc *pDoc, const SwNodeIndex &rSttIdx, const SwNodeIndex &rEndIdx)
Definition: frmtool.cxx:1965
Redline that holds information about a table-cell that had some change.
Definition: redline.hxx:301
virtual void AcceptAllRedline(bool bAcceptReject) override
OUString GetDescr(bool bSimplified=false)
Returns textual description of a redline data element of this redline.
Definition: docredln.cxx:1846
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:163
bool ContainsPosition(const SwPosition &rPos) const
Definition: pam.hxx:257
void DelNumRules(const SwPaM &, SwRootFrame const *pLayout=nullptr)
Definition: docnum.cxx:1308
void InvalidateRange(Invalidation)
Initiate the layout.
Definition: docredln.cxx:1252
Table that holds 'extra' redlines, such as 'table row insert/delete', 'paragraph moves' etc...
Definition: docary.hxx:272
bool IsContentNode() const
Definition: node.hxx:629
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
size_type GetPos(const SwRangeRedline *p) const
Definition: docredln.cxx:601
virtual void UpdateRefFields()=0
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
#define SW_MOD()
Definition: swmodule.hxx:256
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const override
int i
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:132
void DeleteAndDestroy(size_type nPos)
Definition: docredln.cxx:645
const SwPosition * GetPoint() const
Definition: pam.hxx:207
Pos1 start touches at Pos2 end.
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
OUString Apply(const OUString &rStr) const
Definition: SwRewriter.cxx:41
virtual void SetRedlinePassword(const css::uno::Sequence< sal_Int8 > &rNewPassword) override
void SetFormatAll(bool bAll)
Definition: redline.hxx:69
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:2055
Document fields related interfaces.
virtual void AcceptRedlineParagraphFormatting(const SwPaM &rPam) override
TElementType * First()
Definition: calbck.hxx:325
static bool IsShowOriginal(const RedlineFlags eM)
virtual const SwRangeRedline * SelNextRedline(SwPaM &rPam) const override
SwContentNode * GetContentNode()
Definition: node.hxx:616
vector_type::size_type size_type
Definition: docary.hxx:223
virtual bool HasExtraRedlineTable() const override
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
void Hide(sal_uInt16 nLoop, size_t nMyPos, bool bForced=false)
Definition: docredln.cxx:1173
void SetRowNotTracked(const SwCursor &rCursor, const SvxPrintItem &rNotTracked)
rNotTracked = false means that the row was deleted or inserted with its tracked cell content ...
Definition: ndtbl1.cxx:539
float u
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:27
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:2798
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:394
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:373
const SwRangeRedline * FindAtPosition(const SwPosition &startPosition, size_type &tableIndex, bool next=true) const
Find the redline at the given position.
Definition: docredln.cxx:712
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:360
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:694
virtual bool SplitRedline(const SwPaM &rPam) override
virtual bool HasRedline(const SwPaM &rPam, RedlineType nType, bool bStartOrEndInRange) const override
std::unique_ptr< SwExtraRedlineTable > mpExtraRedlineTable
virtual bool IsInRedlines(const SwNode &rNode) const override
void SetAutoFormatRedlineComment(const OUString *pText, sal_uInt16 nSeqNo=0)
Set comment-text for Redline.
Redline that holds information about a table-row that had some change.
Definition: redline.hxx:280
show all deletes
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:405
enumrange< T >::Iterator end(enumrange< T >)
const SwPosition * Start() const
Definition: pam.hxx:212
bool IsVisible() const
Definition: redline.hxx:187
constexpr TypedWhichId< SwFormatContent > RES_CNTNT(95)
virtual void SetRedlineMove(bool bFlag) override
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const =0
virtual bool RejectRedline(SwRedlineTable::size_type nPos, bool bCallDelete) override
void SetComment(const OUString &rS)
Definition: redline.hxx:209
ignore Redlines
virtual bool IsRedlineMove() const override
void UpdateFootnote(const SwNodeIndex &rStt)
Definition: ftnidx.cxx:60
sal_uLong EndOfSectionIndex() const
Definition: node.hxx:678
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
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:1795
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:1349
Pos1 overlaps Pos2 at the end.
void PushData(const SwRangeRedline &rRedl, bool bOwnAsNext=true)
Definition: docredln.cxx:1761
virtual void CompressRedlines() override
static void UpdateFieldsForRedline(IDocumentFieldsAccess &rIDFA)
virtual void SetRedlineFlags_intern(RedlineFlags eMode) override
Set a new redline mode.
static bool IsHideChanges(const RedlineFlags eM)
virtual bool DelFullPara(SwPaM &)=0
Delete full paragraphs.
virtual bool SetRedlineComment(const SwPaM &rPam, const OUString &rComment) override
sal_Int32 GetIndex() const
Definition: index.hxx:91
bool IsClipBoard() const
Definition: doc.hxx:963
virtual bool IsRedlineOn() const =0
Query if redlining is on.
virtual bool AcceptRedline(SwRedlineTable::size_type nPos, bool bCallDelete) override
constexpr sal_uInt16 RES_PARATR_LIST_BEGIN(RES_PARATR_END)
SwNodes & GetNodes()
Definition: doc.hxx:409
void SetAutoFormat()
Definition: redline.hxx:199
const SwPosition * End() const
Definition: pam.hxx:217
SwDoc & GetDoc() const
Returns the document this position is in.
Definition: pam.cxx:181
constexpr sal_uInt16 RES_PARATR_END(82)
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1810
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:395
bool IsAutoFormatRedline() const
Definition: doc.hxx:1447
const SwStartNode * FindTableBoxStartNode() const
Definition: node.hxx:197
virtual SwRedlineTable::size_type GetRedlinePos(const SwNode &rNode, RedlineType nType) const override
SwTableBox * GetUpper()
Definition: swtable.hxx:369
const SwStartNode * FindFlyStartNode() const
Definition: node.hxx:199
virtual bool IsIgnoreRedline() const override
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:634
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:1916
#define SAL_WARN(area, stream)
bool IsTableNode() const
Definition: node.hxx:641
SwDoc & GetDoc() const
Definition: pam.hxx:243
bool HasMergedParas() const
Definition: rootfrm.hxx:426
virtual SwFieldType * GetSysFieldType(const SwFieldIds eWhich) const =0
RedlineType
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:478
Pos1 behind Pos2.
tuple m
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:120
css::uno::Sequence< sal_Int8 > maRedlinePasswd
virtual const SwRedlineTable & GetRedlineTable() const =0
bool Insert(SwRangeRedline *&p)
Definition: docredln.cxx:431
SwNode & GetEndOfRedlines() const
Section for all Redlines.
Definition: ndarr.hxx:158
std::pair< const_iterator, bool > insert(Value &&x)
const SwIndexReg * GetIdxReg() const
Definition: index.hxx:97
OUString SwResId(std::string_view aId)
Definition: swmodule.cxx:165
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
static constexpr size_type npos
Definition: docary.hxx:224
virtual const css::uno::Sequence< sal_Int8 > & GetRedlinePassword() const override
constexpr TypedWhichId< SvxULSpaceItem > RES_UL_SPACE(92)
SwNodeIndex * GetContentIdx() const
Definition: redline.hxx:183
virtual bool IsRedlineOn() const override
Query if redlining is on.
Pos1 overlaps Pos2 at the beginning.
virtual bool AppendTableRowRedline(SwTableRowRedline *pPtr) override
bool IsEmpty() const
Definition: swtable.cxx:1548
void SetStart(const SwPosition &rPos, SwPosition *pSttPtr=nullptr)
Definition: docredln.cxx:1076
bool IsInXMLImport() const
Definition: doc.hxx:970
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1319
SwComparePosition
Definition: pam.hxx:64
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:850
virtual bool AppendTableCellRedline(SwTableCellRedline *pPtr) override
void SetAutoFormatRedline(bool bFlag)
Definition: doc.hxx:1448
void CheckAnchoredFlyConsistency(SwDoc const &rDoc)
Definition: atrfrm.cxx:3666
Base class of the Writer document model elements.
Definition: node.hxx:80
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:844
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo