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