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