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