LibreOffice Module sw (master)  1
undobj.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  */
19 
20 #include <IShellCursorSupplier.hxx>
21 #include <txtftn.hxx>
22 #include <fmtanchr.hxx>
23 #include <ftnidx.hxx>
24 #include <frmfmt.hxx>
25 #include <doc.hxx>
26 #include <UndoManager.hxx>
28 #include <docary.hxx>
29 #include <swundo.hxx>
30 #include <pam.hxx>
31 #include <pamtyp.hxx>
32 #include <ndtxt.hxx>
33 #include <UndoCore.hxx>
34 #include <rolbck.hxx>
35 #include <ndnotxt.hxx>
36 #include <IMark.hxx>
37 #include <mvsave.hxx>
38 #include <redline.hxx>
39 #include <crossrefbookmark.hxx>
40 #include <strings.hrc>
41 #include <docsh.hxx>
42 #include <view.hxx>
43 #include <sal/log.hxx>
44 
45 // This class saves the Pam as integers and can recompose those into a PaM
47  : m_nSttNode( 0 ), m_nEndNode( 0 ), m_nSttContent( 0 ), m_nEndContent( 0 )
48 {
49 }
50 
51 SwUndRng::SwUndRng( const SwPaM& rPam )
52 {
53  SetValues( rPam );
54 }
55 
56 void SwUndRng::SetValues( const SwPaM& rPam )
57 {
58  const SwPosition *pStt = rPam.Start();
59  if( rPam.HasMark() )
60  {
61  const SwPosition *pEnd = rPam.GetPoint() == pStt
62  ? rPam.GetMark()
63  : rPam.GetPoint();
64  m_nEndNode = pEnd->nNode.GetIndex();
66  }
67  else
68  {
69  // no selection !!
70  m_nEndNode = 0;
72  }
73 
74  m_nSttNode = pStt->nNode.GetIndex();
76 }
77 
78 void SwUndRng::SetPaM( SwPaM & rPam, bool bCorrToContent ) const
79 {
80  rPam.DeleteMark();
81  rPam.GetPoint()->nNode = m_nSttNode;
82  SwNode& rNd = rPam.GetNode();
83  if( rNd.IsContentNode() )
85  else if( bCorrToContent )
87  else
88  rPam.GetPoint()->nContent.Assign( nullptr, 0 );
89 
90  if( !m_nEndNode && COMPLETE_STRING == m_nEndContent ) // no selection
91  return ;
92 
93  rPam.SetMark();
95  return; // nothing left to do
96 
97  rPam.GetPoint()->nNode = m_nEndNode;
98  if( rPam.GetNode().IsContentNode() )
100  else if( bCorrToContent )
102  else
103  rPam.GetPoint()->nContent.Assign( nullptr, 0 );
104 }
105 
107  ::sw::UndoRedoContext & rContext, bool const bCorrToContent) const
108 {
109  SwPaM & rPaM( rContext.GetCursorSupplier().CreateNewShellCursor() );
110  SetPaM( rPaM, bCorrToContent );
111  return rPaM;
112 }
113 
115  const sal_uLong* pEndIdx )
116 {
117  SwNodeIndex aIdx( rDoc.GetNodes(), nSttIdx );
118  SwNodeIndex aEndIdx( rDoc.GetNodes(), pEndIdx ? *pEndIdx
119  : aIdx.GetNode().EndOfSectionIndex() );
120  SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() );
121  SwDoc::CorrAbs( aIdx, aEndIdx, aPos, true );
122 }
123 
124 void SwUndo::RemoveIdxFromRange( SwPaM& rPam, bool bMoveNext )
125 {
126  const SwPosition* pEnd = rPam.End();
127  if( bMoveNext )
128  {
129  if( pEnd != rPam.GetPoint() )
130  rPam.Exchange();
131 
132  SwNodeIndex aStt( rPam.GetMark()->nNode );
133  SwNodeIndex aEnd( rPam.GetPoint()->nNode );
134 
135  if( !rPam.Move( fnMoveForward ) )
136  {
137  rPam.Exchange();
138  if( !rPam.Move( fnMoveBackward ) )
139  {
140  rPam.GetPoint()->nNode = rPam.GetDoc()->GetNodes().GetEndOfPostIts();
141  rPam.GetPoint()->nContent.Assign( nullptr, 0 );
142  }
143  }
144 
145  SwDoc::CorrAbs( aStt, aEnd, *rPam.GetPoint(), true );
146  }
147  else
148  SwDoc::CorrAbs( rPam, *pEnd, true );
149 }
150 
151 void SwUndo::RemoveIdxRel( sal_uLong nIdx, const SwPosition& rPos )
152 {
153  // Move only the Cursor. Bookmarks/TOXMarks/etc. are done by the corresponding
154  // JoinNext/JoinPrev
155  SwNodeIndex aIdx( rPos.nNode.GetNode().GetNodes(), nIdx );
156  ::PaMCorrRel( aIdx, rPos );
157 }
158 
159 SwUndo::SwUndo(SwUndoId const nId, const SwDoc* pDoc)
160  : m_nId(nId), m_nOrigRedlineFlags(RedlineFlags::NONE)
161  , m_nViewShellId(CreateViewShellId(pDoc))
162  , m_isRepeatIgnored(false)
163  , m_bCacheComment(true)
164 {
165 }
166 
168 {
169  ViewShellId nRet(-1);
170 
171  if (const SwDocShell* pDocShell = pDoc->GetDocShell())
172  {
173  if (const SwView* pView = pDocShell->GetView())
174  nRet = pView->GetViewShellId();
175  }
176 
177  return nRet;
178 }
179 
180 bool SwUndo::IsDelBox() const
181 {
184 }
185 
187 {
188 }
189 
191 {
192 public:
193  UndoRedoRedlineGuard(::sw::UndoRedoContext const & rContext, SwUndo const & rUndo)
194  : m_rRedlineAccess(rContext.GetDoc().getIDocumentRedlineAccess())
195  , m_eMode(m_rRedlineAccess.GetRedlineFlags())
196  {
197  RedlineFlags const eTmpMode = rUndo.GetRedlineFlags();
198  if ((RedlineFlags::ShowMask & eTmpMode) != (RedlineFlags::ShowMask & m_eMode))
199  {
200  m_rRedlineAccess.SetRedlineFlags( eTmpMode );
201  }
203  }
205  {
207  }
208 private:
211 };
212 
214 {
215  assert(false); // SwUndo::Undo(): ERROR: must call UndoWithContext instead
216 }
217 
219 {
220  assert(false); // SwUndo::Redo(): ERROR: must call RedoWithContext instead
221 }
222 
224 {
225  ::sw::UndoRedoContext *const pContext(
226  dynamic_cast< ::sw::UndoRedoContext * >(& rContext));
227  assert(pContext);
228  const UndoRedoRedlineGuard aUndoRedoRedlineGuard(*pContext, *this);
229  UndoImpl(*pContext);
230 }
231 
233 {
234  ::sw::UndoRedoContext *const pContext(
235  dynamic_cast< ::sw::UndoRedoContext * >(& rContext));
236  assert(pContext);
237  const UndoRedoRedlineGuard aUndoRedoRedlineGuard(*pContext, *this);
238  RedoImpl(*pContext);
239 }
240 
242 {
243  if (m_isRepeatIgnored)
244  {
245  return; // ignore Repeat for multi-selections
246  }
247  ::sw::RepeatContext *const pRepeatContext(
248  dynamic_cast< ::sw::RepeatContext * >(& rContext));
249  assert(pRepeatContext);
250  RepeatImpl(*pRepeatContext);
251 }
252 
253 bool SwUndo::CanRepeat(SfxRepeatTarget & rContext) const
254 {
255  assert(dynamic_cast< ::sw::RepeatContext * >(& rContext));
256  (void)rContext;
257  // a MultiSelection action that doesn't do anything must still return true
259 }
260 
262 {
263 }
264 
266 {
267  const char *pId = nullptr;
268  switch (eId)
269  {
270  case SwUndoId::EMPTY:
271  pId = STR_CANT_UNDO;
272  break;
273  case SwUndoId::START:
274  case SwUndoId::END:
275  break;
276  case SwUndoId::DELETE:
277  pId = STR_DELETE_UNDO;
278  break;
279  case SwUndoId::INSERT:
280  pId = STR_INSERT_UNDO;
281  break;
282  case SwUndoId::OVERWRITE:
283  pId = STR_OVR_UNDO;
284  break;
285  case SwUndoId::SPLITNODE:
286  pId = STR_SPLITNODE_UNDO;
287  break;
288  case SwUndoId::INSATTR:
289  pId = STR_INSATTR_UNDO;
290  break;
292  pId = STR_SETFMTCOLL_UNDO;
293  break;
294  case SwUndoId::RESETATTR:
295  pId = STR_RESET_ATTR_UNDO;
296  break;
298  pId = STR_INSFMT_ATTR_UNDO;
299  break;
301  pId = STR_INSERT_DOC_UNDO;
302  break;
303  case SwUndoId::COPY:
304  pId = STR_COPY_UNDO;
305  break;
306  case SwUndoId::INSTABLE:
307  pId = STR_INSTABLE_UNDO;
308  break;
310  pId = STR_TABLETOTEXT_UNDO;
311  break;
313  pId = STR_TEXTTOTABLE_UNDO;
314  break;
315  case SwUndoId::SORT_TXT:
316  pId = STR_SORT_TXT;
317  break;
318  case SwUndoId::INSLAYFMT:
319  pId = STR_INSERTFLY;
320  break;
322  pId = STR_TABLEHEADLINE;
323  break;
325  pId = STR_INSERTSECTION;
326  break;
328  pId = STR_OUTLINE_LR;
329  break;
331  pId = STR_OUTLINE_UD;
332  break;
333  case SwUndoId::INSNUM:
334  pId = STR_INSNUM;
335  break;
336  case SwUndoId::NUMUP:
337  pId = STR_NUMUP;
338  break;
339  case SwUndoId::MOVENUM:
340  pId = STR_MOVENUM;
341  break;
343  pId = STR_INSERTDRAW;
344  break;
346  pId = STR_NUMORNONUM;
347  break;
349  pId = STR_INC_LEFTMARGIN;
350  break;
352  pId = STR_DEC_LEFTMARGIN;
353  break;
355  pId = STR_INSERTLABEL;
356  break;
358  pId = STR_SETNUMRULESTART;
359  break;
360  case SwUndoId::CHGFTN:
361  pId = STR_CHANGEFTN;
362  break;
363  case SwUndoId::REDLINE:
364  SAL_INFO("sw.core", "Should NEVER be used/translated");
365  return "$1";
367  pId = STR_ACCEPT_REDLINE;
368  break;
370  pId = STR_REJECT_REDLINE;
371  break;
373  pId = STR_SPLIT_TABLE;
374  break;
376  pId = STR_DONTEXPAND;
377  break;
379  pId = STR_AUTOCORRECT;
380  break;
382  pId = STR_MERGE_TABLE;
383  break;
385  pId = STR_TRANSLITERATE;
386  break;
388  pId = STR_PASTE_CLIPBOARD_UNDO;
389  break;
390  case SwUndoId::TYPING:
391  pId = STR_TYPING_UNDO;
392  break;
393  case SwUndoId::MOVE:
394  pId = STR_MOVE_UNDO;
395  break;
397  pId = STR_INSERT_GLOSSARY;
398  break;
400  pId = STR_DELBOOKMARK;
401  break;
403  pId = STR_INSBOOKMARK;
404  break;
405  case SwUndoId::SORT_TBL:
406  pId = STR_SORT_TBL;
407  break;
408  case SwUndoId::DELLAYFMT:
409  pId = STR_DELETEFLY;
410  break;
412  pId = STR_AUTOFORMAT;
413  break;
414  case SwUndoId::REPLACE:
415  pId = STR_REPLACE;
416  break;
418  pId = STR_DELETESECTION;
419  break;
421  pId = STR_CHANGESECTION;
422  break;
424  pId = STR_CHANGEDEFATTR;
425  break;
426  case SwUndoId::DELNUM:
427  pId = STR_DELNUM;
428  break;
429  case SwUndoId::DRAWUNDO:
430  pId = STR_DRAWUNDO;
431  break;
432  case SwUndoId::DRAWGROUP:
433  pId = STR_DRAWGROUP;
434  break;
436  pId = STR_DRAWUNGROUP;
437  break;
439  pId = STR_DRAWDELETE;
440  break;
441  case SwUndoId::REREAD:
442  pId = STR_REREAD;
443  break;
444  case SwUndoId::DELGRF:
445  pId = STR_DELGRF;
446  break;
448  pId = STR_TABLE_ATTR;
449  break;
451  pId = STR_UNDO_TABLE_AUTOFMT;
452  break;
454  pId = STR_UNDO_TABLE_INSCOL;
455  break;
457  pId = STR_UNDO_TABLE_INSROW;
458  break;
460  pId = STR_UNDO_TABLE_DELBOX;
461  break;
463  pId = STR_UNDO_TABLE_SPLIT;
464  break;
466  pId = STR_UNDO_TABLE_MERGE;
467  break;
468  case SwUndoId::TBLNUMFMT:
469  pId = STR_TABLE_NUMFORMAT;
470  break;
471  case SwUndoId::INSTOX:
472  pId = STR_INSERT_TOX;
473  break;
475  pId = STR_CLEAR_TOX_RANGE;
476  break;
477  case SwUndoId::TBLCPYTBL:
478  pId = STR_TABLE_TBLCPYTBL;
479  break;
480  case SwUndoId::CPYTBL:
481  pId = STR_TABLE_CPYTBL;
482  break;
484  pId = STR_INS_FROM_SHADOWCRSR;
485  break;
486  case SwUndoId::CHAINE:
487  pId = STR_UNDO_CHAIN;
488  break;
489  case SwUndoId::UNCHAIN:
490  pId = STR_UNDO_UNCHAIN;
491  break;
492  case SwUndoId::FTNINFO:
493  pId = STR_UNDO_FTNINFO;
494  break;
496  pId = STR_UNDO_COMPAREDOC;
497  break;
499  pId = STR_UNDO_SETFLYFRMFMT;
500  break;
502  pId = STR_UNDO_SETRUBYATTR;
503  break;
504  case SwUndoId::TOXCHANGE:
505  pId = STR_TOXCHANGE;
506  break;
508  pId = STR_UNDO_PAGEDESC_CREATE;
509  break;
511  pId = STR_UNDO_PAGEDESC;
512  break;
514  pId = STR_UNDO_PAGEDESC_DELETE;
515  break;
517  pId = STR_UNDO_HEADER_FOOTER;
518  break;
519  case SwUndoId::FIELD:
520  pId = STR_UNDO_FIELD;
521  break;
523  pId = STR_UNDO_TXTFMTCOL_CREATE;
524  break;
526  pId = STR_UNDO_TXTFMTCOL_DELETE;
527  break;
529  pId = STR_UNDO_TXTFMTCOL_RENAME;
530  break;
532  pId = STR_UNDO_CHARFMT_CREATE;
533  break;
535  pId = STR_UNDO_CHARFMT_DELETE;
536  break;
538  pId = STR_UNDO_CHARFMT_RENAME;
539  break;
541  pId = STR_UNDO_FRMFMT_CREATE;
542  break;
544  pId = STR_UNDO_FRMFMT_DELETE;
545  break;
547  pId = STR_UNDO_FRMFMT_RENAME;
548  break;
550  pId = STR_UNDO_NUMRULE_CREATE;
551  break;
553  pId = STR_UNDO_NUMRULE_DELETE;
554  break;
556  pId = STR_UNDO_NUMRULE_RENAME;
557  break;
559  pId = STR_UNDO_BOOKMARK_RENAME;
560  break;
562  pId = STR_UNDO_INDEX_ENTRY_INSERT;
563  break;
565  pId = STR_UNDO_INDEX_ENTRY_DELETE;
566  break;
568  pId = STR_UNDO_COL_DELETE;
569  break;
571  pId = STR_UNDO_ROW_DELETE;
572  break;
574  pId = STR_UNDO_PAGEDESC_RENAME;
575  break;
576  case SwUndoId::NUMDOWN:
577  pId = STR_NUMDOWN;
578  break;
580  pId = STR_UNDO_FLYFRMFMT_TITLE;
581  break;
583  pId = STR_UNDO_FLYFRMFMT_DESCRIPTION;
584  break;
586  pId = STR_UNDO_TBLSTYLE_CREATE;
587  break;
589  pId = STR_UNDO_TBLSTYLE_DELETE;
590  break;
592  pId = STR_UNDO_TBLSTYLE_UPDATE;
593  break;
595  pId = STR_REPLACE_UNDO;
596  break;
598  pId = STR_INSERT_PAGE_BREAK_UNDO;
599  break;
601  pId = STR_INSERT_COLUMN_BREAK_UNDO;
602  break;
604  pId = STR_INSERT_ENV_UNDO;
605  break;
607  pId = STR_DRAG_AND_COPY;
608  break;
610  pId = STR_DRAG_AND_MOVE;
611  break;
613  pId = STR_INSERT_CHART;
614  break;
616  pId = STR_INSERT_FOOTNOTE;
617  break;
619  pId = STR_INSERT_URLBTN;
620  break;
622  pId = STR_INSERT_URLTXT;
623  break;
625  pId = STR_DELETE_INVISIBLECNTNT;
626  break;
628  pId = STR_REPLACE_STYLE;
629  break;
631  pId = STR_DELETE_PAGE_BREAK;
632  break;
634  pId = STR_TEXT_CORRECTION;
635  break;
637  pId = STR_UNDO_TABLE_DELETE;
638  break;
639  case SwUndoId::CONFLICT:
640  break;
642  pId = STR_PARAGRAPH_SIGN_UNDO;
643  break;
645  pId = STR_UNDO_INSERT_FORM_FIELD;
646  break;
647  };
648 
649  assert(pId);
650  return SwResId(pId);
651 }
652 
653 OUString SwUndo::GetComment() const
654 {
655  OUString aResult;
656 
657  if (m_bCacheComment)
658  {
659  if (! maComment)
660  {
662 
663  SwRewriter aRewriter = GetRewriter();
664 
665  maComment = aRewriter.Apply(*maComment);
666  }
667 
668  aResult = *maComment;
669  }
670  else
671  {
672  aResult = GetUndoComment(GetId());
673 
674  SwRewriter aRewriter = GetRewriter();
675 
676  aResult = aRewriter.Apply(aResult);
677  }
678 
679  return aResult;
680 }
681 
683 {
684  return m_nViewShellId;
685 }
686 
688 {
689  SwRewriter aResult;
690 
691  return aResult;
692 }
693 
695 {}
696 
697 SwUndoSaveContent::~SwUndoSaveContent() COVERITY_NOEXCEPT_FALSE
698 {
699 }
700 
701 // This is needed when deleting content. For REDO all contents will be moved
702 // into the UndoNodesArray. These methods always create a new node to insert
703 // content. As a result, the attributes will not be expanded.
704 // - MoveTo moves from NodesArray into UndoNodesArray
705 // - MoveFrom moves from UndoNodesArray into NodesArray
706 
707 // If pEndNdIdx is given, Undo/Redo calls -Ins/DelFly. In that case the whole
708 // section should be moved.
710  sal_uLong* pEndNdIdx )
711 {
712  SwDoc& rDoc = *rPaM.GetDoc();
713  ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
714 
715  SwNoTextNode* pCpyNd = rPaM.GetNode().GetNoTextNode();
716 
717  // here comes the actual delete (move)
718  SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes();
719  SwPosition aPos( pEndNdIdx ? rNds.GetEndOfPostIts()
720  : rNds.GetEndOfExtras() );
721 
722  const SwPosition* pStt = rPaM.Start(), *pEnd = rPaM.End();
723 
724  sal_uLong nTmpMvNode = aPos.nNode.GetIndex();
725 
726  if( pCpyNd || pEndNdIdx )
727  {
728  SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 );
729  rDoc.GetNodes().MoveNodes( aRg, rNds, aPos.nNode, true );
730  aPos.nContent = 0;
731  --aPos.nNode;
732  }
733  else
734  {
735  rDoc.GetNodes().MoveRange( rPaM, aPos, rNds );
736  }
737  if( pEndNdIdx )
738  *pEndNdIdx = aPos.nNode.GetIndex();
739 
740  // old position
741  aPos.nNode = nTmpMvNode;
742  if( pNodeIdx )
743  *pNodeIdx = aPos.nNode;
744 }
745 
747  SwPosition& rInsPos,
748  const sal_uLong* pEndNdIdx, bool const bForceCreateFrames)
749 {
750  // here comes the recovery
751  SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes();
752  if( nNodeIdx == rNds.GetEndOfPostIts().GetIndex() )
753  return; // nothing saved
754 
755  ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
756 
757  SwPaM aPaM( rInsPos );
758  if( pEndNdIdx ) // than get the section from it
759  aPaM.GetPoint()->nNode.Assign( rNds, *pEndNdIdx );
760  else
761  {
762  aPaM.GetPoint()->nNode = rNds.GetEndOfExtras();
763  GoInContent( aPaM, fnMoveBackward );
764  }
765 
766  SwTextNode* pTextNd = aPaM.GetNode().GetTextNode();
767  if (!pEndNdIdx && pTextNd)
768  {
769  aPaM.SetMark();
770  aPaM.GetPoint()->nNode = nNodeIdx;
771  aPaM.GetPoint()->nContent.Assign(aPaM.GetContentNode(), 0);
772 
773  SaveRedlEndPosForRestore aRedlRest( rInsPos.nNode, rInsPos.nContent.GetIndex() );
774 
775  rNds.MoveRange( aPaM, rInsPos, rDoc.GetNodes() );
776 
777  // delete the last Node as well
778  if( !aPaM.GetPoint()->nContent.GetIndex() ||
779  ( aPaM.GetPoint()->nNode++ && // still empty Nodes at the end?
780  &rNds.GetEndOfExtras() != &aPaM.GetPoint()->nNode.GetNode() ))
781  {
782  aPaM.GetPoint()->nContent.Assign( nullptr, 0 );
783  aPaM.SetMark();
784  rNds.Delete( aPaM.GetPoint()->nNode,
785  rNds.GetEndOfExtras().GetIndex() -
786  aPaM.GetPoint()->nNode.GetIndex() );
787  }
788 
789  aRedlRest.Restore();
790  }
791  else
792  {
793  SwNodeRange aRg( rNds, nNodeIdx, rNds, (pEndNdIdx
794  ? ((*pEndNdIdx) + 1)
795  : rNds.GetEndOfExtras().GetIndex() ) );
796  rNds.MoveNodes(aRg, rDoc.GetNodes(), rInsPos.nNode, nullptr == pEndNdIdx || bForceCreateFrames);
797 
798  }
799 }
800 
801 // These two methods move the Point of Pam backwards/forwards. With that, one
802 // can span an area for a Undo/Redo. (The Point is then positioned in front of
803 // the area to manipulate!)
804 // The flag indicates if there is still content in front of Point.
806 {
807  rPam.SetMark();
808  if( rPam.Move( fnMoveBackward ))
809  return true;
810 
811  // If there is no content onwards, set Point simply to the previous position
812  // (Node and Content, so that Content will be detached!)
813  --rPam.GetPoint()->nNode;
814  rPam.GetPoint()->nContent.Assign( nullptr, 0 );
815  return false;
816 }
817 
818 void SwUndoSaveContent::MovePtForward( SwPaM& rPam, bool bMvBkwrd )
819 {
820  // Was there content before this position?
821  if( bMvBkwrd )
822  rPam.Move( fnMoveForward );
823  else
824  {
825  ++rPam.GetPoint()->nNode;
826  SwContentNode* pCNd = rPam.GetContentNode();
827  if( pCNd )
828  pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
829  else
830  rPam.Move( fnMoveForward );
831  }
832 }
833 
834 // Delete all objects that have ContentIndices to the given area.
835 // Currently (1994) these exist:
836 // - Footnotes
837 // - Flys
838 // - Bookmarks
839 
840 // #i81002# - extending method
841 // delete certain (not all) cross-reference bookmarks at text node of <rMark>
842 // and at text node of <rPoint>, if these text nodes aren't the same.
844  const SwPosition& rPoint,
845  DelContentType nDelContentType )
846 {
847  const SwPosition *pStt = rMark < rPoint ? &rMark : &rPoint,
848  *pEnd = &rMark == pStt ? &rPoint : &rMark;
849 
850  SwDoc* pDoc = rMark.nNode.GetNode().GetDoc();
851 
852  ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
853 
854  // 1. Footnotes
855  if( DelContentType::Ftn & nDelContentType )
856  {
857  SwFootnoteIdxs& rFootnoteArr = pDoc->GetFootnoteIdxs();
858  if( !rFootnoteArr.empty() )
859  {
860  const SwNode* pFootnoteNd;
861  size_t nPos = 0;
862  rFootnoteArr.SeekEntry( pStt->nNode, &nPos );
863  SwTextFootnote* pSrch;
864 
865  // for now delete all that come afterwards
866  while( nPos < rFootnoteArr.size() && ( pFootnoteNd =
867  &( pSrch = rFootnoteArr[ nPos ] )->GetTextNode())->GetIndex()
868  <= pEnd->nNode.GetIndex() )
869  {
870  const sal_Int32 nFootnoteSttIdx = pSrch->GetStart();
871  if( (DelContentType::CheckNoCntnt & nDelContentType )
872  ? (&pEnd->nNode.GetNode() == pFootnoteNd )
873  : (( &pStt->nNode.GetNode() == pFootnoteNd &&
874  pStt->nContent.GetIndex() > nFootnoteSttIdx) ||
875  ( &pEnd->nNode.GetNode() == pFootnoteNd &&
876  nFootnoteSttIdx >= pEnd->nContent.GetIndex() )) )
877  {
878  ++nPos; // continue searching
879  continue;
880  }
881 
882 // FIXME: duplicated code here and below -> refactor?
883  // Unfortunately an index needs to be created. Otherwise there
884  // will be problems with TextNode because the index will be
885  // deleted in the DTOR of SwFootnote!
886  SwTextNode* pTextNd = const_cast<SwTextNode*>(static_cast<const SwTextNode*>(pFootnoteNd));
887  if( !m_pHistory )
888  m_pHistory.reset( new SwHistory );
889  SwTextAttr* const pFootnoteHint =
890  pTextNd->GetTextAttrForCharAt( nFootnoteSttIdx );
891  assert(pFootnoteHint);
892  SwIndex aIdx( pTextNd, nFootnoteSttIdx );
893  m_pHistory->Add( pFootnoteHint, pTextNd->GetIndex(), false );
894  pTextNd->EraseText( aIdx, 1 );
895  }
896 
897  while( nPos-- && ( pFootnoteNd = &( pSrch = rFootnoteArr[ nPos ] )->
898  GetTextNode())->GetIndex() >= pStt->nNode.GetIndex() )
899  {
900  const sal_Int32 nFootnoteSttIdx = pSrch->GetStart();
901  if( !(DelContentType::CheckNoCntnt & nDelContentType) && (
902  ( &pStt->nNode.GetNode() == pFootnoteNd &&
903  pStt->nContent.GetIndex() > nFootnoteSttIdx ) ||
904  ( &pEnd->nNode.GetNode() == pFootnoteNd &&
905  nFootnoteSttIdx >= pEnd->nContent.GetIndex() )))
906  continue; // continue searching
907 
908  // Unfortunately an index needs to be created. Otherwise there
909  // will be problems with TextNode because the index will be
910  // deleted in the DTOR of SwFootnote!
911  SwTextNode* pTextNd = const_cast<SwTextNode*>(static_cast<const SwTextNode*>(pFootnoteNd));
912  if( !m_pHistory )
913  m_pHistory.reset( new SwHistory );
914  SwTextAttr* const pFootnoteHint =
915  pTextNd->GetTextAttrForCharAt( nFootnoteSttIdx );
916  assert(pFootnoteHint);
917  SwIndex aIdx( pTextNd, nFootnoteSttIdx );
918  m_pHistory->Add( pFootnoteHint, pTextNd->GetIndex(), false );
919  pTextNd->EraseText( aIdx, 1 );
920  }
921  }
922  }
923 
924  // 2. Flys
925  if( DelContentType::Fly & nDelContentType )
926  {
927  sal_uInt16 nChainInsPos = m_pHistory ? m_pHistory->Count() : 0;
928  const SwFrameFormats& rSpzArr = *pDoc->GetSpzFrameFormats();
929  if( !rSpzArr.empty() )
930  {
931  const bool bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex();
932  SwFrameFormat* pFormat;
933  const SwFormatAnchor* pAnchor;
934  size_t n = rSpzArr.size();
935  const SwPosition* pAPos;
936 
937  while( n && !rSpzArr.empty() )
938  {
939  pFormat = rSpzArr[--n];
940  pAnchor = &pFormat->GetAnchor();
941  switch( pAnchor->GetAnchorId() )
942  {
943  case RndStdIds::FLY_AS_CHAR:
944  if( nullptr != (pAPos = pAnchor->GetContentAnchor() ) &&
945  (( DelContentType::CheckNoCntnt & nDelContentType )
946  ? ( pStt->nNode <= pAPos->nNode &&
947  pAPos->nNode < pEnd->nNode )
948  : ( *pStt <= *pAPos && *pAPos < *pEnd )) )
949  {
950  if( !m_pHistory )
951  m_pHistory.reset( new SwHistory );
952  SwTextNode *const pTextNd =
953  pAPos->nNode.GetNode().GetTextNode();
954  SwTextAttr* const pFlyHint = pTextNd->GetTextAttrForCharAt(
955  pAPos->nContent.GetIndex());
956  assert(pFlyHint);
957  m_pHistory->Add( pFlyHint, 0, false );
958  // reset n so that no Format is skipped
959  n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
960  }
961  break;
962  case RndStdIds::FLY_AT_PARA:
963  {
964  pAPos = pAnchor->GetContentAnchor();
965  if( pAPos )
966  {
967  bool bTmp;
968  if( DelContentType::CheckNoCntnt & nDelContentType )
969  bTmp = pStt->nNode <= pAPos->nNode && pAPos->nNode < pEnd->nNode;
970  else
971  {
972  if (bDelFwrd)
973  bTmp = rMark.nNode < pAPos->nNode &&
974  pAPos->nNode <= rPoint.nNode;
975  else
976  bTmp = rPoint.nNode <= pAPos->nNode &&
977  pAPos->nNode < rMark.nNode;
978  }
979 
980  if (bTmp)
981  {
982  if( !m_pHistory )
983  m_pHistory.reset( new SwHistory );
984 
985  // Moving the anchor?
986  if( !( DelContentType::CheckNoCntnt & nDelContentType ) &&
987  (rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex())
988  // Do not try to move the anchor to a table!
989  && rMark.nNode.GetNode().IsTextNode())
990  {
991  m_pHistory->Add( *pFormat );
992  SwFormatAnchor aAnch( *pAnchor );
993  SwPosition aPos( rMark.nNode );
994  aAnch.SetAnchor( &aPos );
995  pFormat->SetFormatAttr( aAnch );
996  }
997  else
998  {
999  m_pHistory->Add( *static_cast<SwFlyFrameFormat *>(pFormat), nChainInsPos );
1000  // reset n so that no Format is skipped
1001  n = n >= rSpzArr.size() ?
1002  rSpzArr.size() : n+1;
1003  }
1004  }
1005  }
1006  }
1007  break;
1008  case RndStdIds::FLY_AT_CHAR:
1009  if( nullptr != (pAPos = pAnchor->GetContentAnchor() ) &&
1010  ( pStt->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) )
1011  {
1012  if( !m_pHistory )
1013  m_pHistory.reset( new SwHistory );
1015  *pAPos, *pStt, *pEnd, nDelContentType))
1016  {
1017  m_pHistory->Add( *static_cast<SwFlyFrameFormat *>(pFormat), nChainInsPos );
1018  n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
1019  }
1020  else if (!((DelContentType::CheckNoCntnt |
1022  & nDelContentType))
1023  {
1024  if( *pStt <= *pAPos && *pAPos < *pEnd )
1025  {
1026  // These are the objects anchored
1027  // between section start and end position
1028  // Do not try to move the anchor to a table!
1029  if( rMark.nNode.GetNode().GetTextNode() )
1030  {
1031  m_pHistory->Add( *pFormat );
1032  SwFormatAnchor aAnch( *pAnchor );
1033  aAnch.SetAnchor( &rMark );
1034  pFormat->SetFormatAttr( aAnch );
1035  }
1036  }
1037  }
1038  }
1039  break;
1040  case RndStdIds::FLY_AT_FLY:
1041 
1042  if( nullptr != (pAPos = pAnchor->GetContentAnchor() ) &&
1043  pStt->nNode == pAPos->nNode )
1044  {
1045  if( !m_pHistory )
1046  m_pHistory.reset( new SwHistory );
1047 
1048  m_pHistory->Add( *static_cast<SwFlyFrameFormat *>(pFormat), nChainInsPos );
1049 
1050  // reset n so that no Format is skipped
1051  n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
1052  }
1053  break;
1054  default: break;
1055  }
1056  }
1057  }
1058  }
1059 
1060  // 3. Bookmarks
1061  if( DelContentType::Bkm & nDelContentType )
1062  {
1063  IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1064  if( pMarkAccess->getAllMarksCount() )
1065  {
1066  for( sal_Int32 n = 0; n < pMarkAccess->getAllMarksCount(); ++n )
1067  {
1068  // #i81002#
1069  bool bSavePos = false;
1070  bool bSaveOtherPos = false;
1071  const ::sw::mark::IMark *const pBkmk = pMarkAccess->getAllMarksBegin()[n];
1072  auto const type(IDocumentMarkAccess::GetType(*pBkmk));
1073 
1074  if( DelContentType::CheckNoCntnt & nDelContentType )
1075  {
1076  if ( pStt->nNode <= pBkmk->GetMarkPos().nNode
1077  && pBkmk->GetMarkPos().nNode < pEnd->nNode )
1078  {
1079  bSavePos = true;
1080  }
1081  if ( pBkmk->IsExpanded()
1082  && pStt->nNode <= pBkmk->GetOtherMarkPos().nNode
1083  && pBkmk->GetOtherMarkPos().nNode < pEnd->nNode )
1084  {
1085  bSaveOtherPos = true;
1086  }
1087  }
1088  else
1089  {
1090  // #i92125#
1091  // keep cross-reference bookmarks, if content inside one paragraph is deleted.
1092  if ( rMark.nNode == rPoint.nNode
1095  {
1096  continue;
1097  }
1098 
1099  bool bMaybe = false;
1100  if ( *pStt <= pBkmk->GetMarkPos() && pBkmk->GetMarkPos() <= *pEnd )
1101  {
1102  if ( pBkmk->GetMarkPos() == *pEnd
1103  || ( *pStt == pBkmk->GetMarkPos() && pBkmk->IsExpanded() ) )
1104  bMaybe = true;
1105  else
1106  bSavePos = true;
1107  }
1108  if( pBkmk->IsExpanded() &&
1109  *pStt <= pBkmk->GetOtherMarkPos() && pBkmk->GetOtherMarkPos() <= *pEnd )
1110  {
1111  if ( bSavePos || bSaveOtherPos
1112  || (*pStt < pBkmk->GetOtherMarkPos() && pBkmk->GetOtherMarkPos() < *pEnd)
1117  {
1118  if( bMaybe )
1119  bSavePos = true;
1120  bSaveOtherPos = true;
1121  }
1122  }
1123 
1124  if ( !bSavePos && !bSaveOtherPos
1125  && dynamic_cast< const ::sw::mark::CrossRefBookmark* >(pBkmk) )
1126  {
1127  // certain special handling for cross-reference bookmarks
1128  const bool bDifferentTextNodesAtMarkAndPoint =
1129  rMark.nNode != rPoint.nNode
1130  && rMark.nNode.GetNode().GetTextNode()
1131  && rPoint.nNode.GetNode().GetTextNode();
1132  if ( bDifferentTextNodesAtMarkAndPoint )
1133  {
1134  // delete cross-reference bookmark at <pStt>, if only part of
1135  // <pEnd> text node content is deleted.
1136  if( pStt->nNode == pBkmk->GetMarkPos().nNode
1137  && pEnd->nContent.GetIndex() != pEnd->nNode.GetNode().GetTextNode()->Len() )
1138  {
1139  bSavePos = true;
1140  bSaveOtherPos = false; // cross-reference bookmarks are not expanded
1141  }
1142  // delete cross-reference bookmark at <pEnd>, if only part of
1143  // <pStt> text node content is deleted.
1144  else if( pEnd->nNode == pBkmk->GetMarkPos().nNode &&
1145  pStt->nContent.GetIndex() != 0 )
1146  {
1147  bSavePos = true;
1148  bSaveOtherPos = false; // cross-reference bookmarks are not expanded
1149  }
1150  }
1151  }
1153  {
1154  // delete annotation marks, if its end position is covered by the deletion
1155  const SwPosition& rAnnotationEndPos = pBkmk->GetMarkEnd();
1156  if ( *pStt < rAnnotationEndPos && rAnnotationEndPos <= *pEnd )
1157  {
1158  bSavePos = true;
1159  bSaveOtherPos = pBkmk->IsExpanded(); //tdf#90138, only save the other pos if there is one
1160  }
1161  }
1162  }
1163 
1164  if ( bSavePos || bSaveOtherPos )
1165  {
1167  {
1168  if( !m_pHistory )
1169  m_pHistory.reset( new SwHistory );
1170  m_pHistory->Add( *pBkmk, bSavePos, bSaveOtherPos );
1171  }
1172  if ( bSavePos
1173  && ( bSaveOtherPos
1174  || !pBkmk->IsExpanded() ) )
1175  {
1176  pMarkAccess->deleteMark(pMarkAccess->getAllMarksBegin()+n);
1177  n--;
1178  }
1179  }
1180  }
1181  }
1182  }
1183 }
1184 
1185 // save a complete section into UndoNodes array
1187  : m_nMoveLen( 0 ), m_nStartPos( ULONG_MAX )
1188 {
1189 }
1190 
1192 {
1193  if (m_pMovedStart) // delete also the section from UndoNodes array
1194  {
1195  // SaveSection saves the content in the PostIt section.
1196  SwNodes& rUNds = m_pMovedStart->GetNode().GetNodes();
1197  rUNds.Delete( *m_pMovedStart, m_nMoveLen );
1198 
1199  m_pMovedStart.reset();
1200  }
1201  m_pRedlineSaveData.reset();
1202 }
1203 
1205 {
1206  SwNodeRange aRg( rSttIdx.GetNode(), *rSttIdx.GetNode().EndOfSectionNode() );
1207  SaveSection( aRg );
1208 }
1209 
1211  const SwNodeRange& rRange, bool const bExpandNodes)
1212 {
1213  SwPaM aPam( rRange.aStart, rRange.aEnd );
1214 
1215  // delete all footnotes, fly frames, bookmarks
1216  DelContentIndex( *aPam.GetMark(), *aPam.GetPoint() );
1217 
1218  // redlines *before* CorrAbs, because DelBookmarks will make them 0-length
1219  // but *after* DelContentIndex because that also may use FillSaveData (in
1220  // flys) and that will be restored *after* this one...
1223  {
1224  m_pRedlineSaveData.reset();
1225  }
1226 
1227  {
1228  // move certain indexes out of deleted range
1229  SwNodeIndex aSttIdx( aPam.Start()->nNode.GetNode() );
1230  SwNodeIndex aEndIdx( aPam.End()->nNode.GetNode() );
1231  SwNodeIndex aMvStt( aEndIdx, 1 );
1232  SwDoc::CorrAbs( aSttIdx, aEndIdx, SwPosition( aMvStt ), true );
1233  }
1234 
1235  m_nStartPos = rRange.aStart.GetIndex();
1236 
1237  if (bExpandNodes)
1238  {
1239  --aPam.GetPoint()->nNode;
1240  ++aPam.GetMark()->nNode;
1241  }
1242 
1243  SwContentNode* pCNd = aPam.GetContentNode( false );
1244  if( pCNd )
1245  aPam.GetMark()->nContent.Assign( pCNd, 0 );
1246  if( nullptr != ( pCNd = aPam.GetContentNode()) )
1247  aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
1248 
1249  // Keep positions as SwIndex so that this section can be deleted in DTOR
1250  sal_uLong nEnd;
1251  m_pMovedStart.reset(new SwNodeIndex(rRange.aStart));
1252  MoveToUndoNds(aPam, m_pMovedStart.get(), &nEnd);
1253  m_nMoveLen = nEnd - m_pMovedStart->GetIndex() + 1;
1254 }
1255 
1257  sal_uInt16 nSectType )
1258 {
1259  if( ULONG_MAX != m_nStartPos ) // was there any content?
1260  {
1261  // check if the content is at the old position
1262  SwNodeIndex aSttIdx( pDoc->GetNodes(), m_nStartPos );
1263 
1264  // move the content from UndoNodes array into Fly
1265  SwStartNode* pSttNd = SwNodes::MakeEmptySection( aSttIdx,
1266  static_cast<SwStartNodeType>(nSectType) );
1267 
1268  RestoreSection( pDoc, SwNodeIndex( *pSttNd->EndOfSectionNode() ));
1269 
1270  if( pIdx )
1271  *pIdx = *pSttNd;
1272  }
1273 }
1274 
1276  SwDoc *const pDoc, const SwNodeIndex& rInsPos, bool bForceCreateFrames)
1277 {
1278  if( ULONG_MAX != m_nStartPos ) // was there any content?
1279  {
1280  SwPosition aInsPos( rInsPos );
1281  sal_uLong nEnd = m_pMovedStart->GetIndex() + m_nMoveLen - 1;
1282  MoveFromUndoNds(*pDoc, m_pMovedStart->GetIndex(), aInsPos, &nEnd, bForceCreateFrames);
1283 
1284  // destroy indices again, content was deleted from UndoNodes array
1285  m_pMovedStart.reset();
1286  m_nMoveLen = 0;
1287 
1288  if( m_pRedlineSaveData )
1289  {
1291  m_pRedlineSaveData.reset();
1292  }
1293  }
1294 }
1295 
1296 // save and set the RedlineData
1298  SwComparePosition eCmpPos,
1299  const SwPosition& rSttPos,
1300  const SwPosition& rEndPos,
1301  SwRangeRedline& rRedl,
1302  bool bCopyNext )
1303  : SwUndRng( rRedl )
1304  , SwRedlineData( rRedl.GetRedlineData(), bCopyNext )
1305 {
1306  assert( SwComparePosition::Outside == eCmpPos ||
1307  !rRedl.GetContentIdx() ); // "Redline with Content"
1308 
1309  switch (eCmpPos)
1310  {
1311  case SwComparePosition::OverlapBefore: // Pos1 overlaps Pos2 at the beginning
1312  m_nEndNode = rEndPos.nNode.GetIndex();
1313  m_nEndContent = rEndPos.nContent.GetIndex();
1314  break;
1315 
1316  case SwComparePosition::OverlapBehind: // Pos1 overlaps Pos2 at the end
1317  m_nSttNode = rSttPos.nNode.GetIndex();
1318  m_nSttContent = rSttPos.nContent.GetIndex();
1319  break;
1320 
1321  case SwComparePosition::Inside: // Pos1 lays completely in Pos2
1322  m_nSttNode = rSttPos.nNode.GetIndex();
1323  m_nSttContent = rSttPos.nContent.GetIndex();
1324  m_nEndNode = rEndPos.nNode.GetIndex();
1325  m_nEndContent = rEndPos.nContent.GetIndex();
1326  break;
1327 
1328  case SwComparePosition::Outside: // Pos2 lays completely in Pos1
1329  if ( rRedl.GetContentIdx() )
1330  {
1331  // than move section into UndoArray and memorize it
1332  SaveSection( *rRedl.GetContentIdx() );
1333  rRedl.SetContentIdx( nullptr );
1334  }
1335  break;
1336 
1337  case SwComparePosition::Equal: // Pos1 is exactly as big as Pos2
1338  break;
1339 
1340  default:
1341  assert(false);
1342  }
1343 
1344 #if OSL_DEBUG_LEVEL > 0
1346 #endif
1347 }
1348 
1350 {
1351 }
1352 
1354 {
1355  SwDoc& rDoc = *rPam.GetDoc();
1356  SwRangeRedline* pRedl = new SwRangeRedline( *this, rPam );
1357 
1358  if( GetMvSttIdx() )
1359  {
1360  SwNodeIndex aIdx( rDoc.GetNodes() );
1361  RestoreSection( &rDoc, &aIdx, SwNormalStartNode );
1362  if( GetHistory() )
1363  GetHistory()->Rollback( &rDoc );
1364  pRedl->SetContentIdx( &aIdx );
1365  }
1366  SetPaM( *pRedl );
1367  // First, delete the "old" so that in an Append no unexpected things will
1368  // happen, e.g. a delete in an insert. In the latter case the just restored
1369  // content will be deleted and not the one you originally wanted.
1370  rDoc.getIDocumentRedlineAccess().DeleteRedline( *pRedl, false, RedlineType::Any );
1371 
1374  //#i92154# let UI know about a new redline with comment
1375  if (rDoc.GetDocShell() && (!pRedl->GetComment().isEmpty()) )
1376  rDoc.GetDocShell()->Broadcast(SwRedlineHint());
1377 
1378  auto const result(rDoc.getIDocumentRedlineAccess().AppendRedline(pRedl, true));
1379  assert(result != IDocumentRedlineAccess::AppendResult::IGNORED); // SwRedlineSaveData::RedlineToDoc: insert redline failed
1380  (void) result; // unused in non-debug
1382 }
1383 
1385  const SwPaM& rRange,
1386  SwRedlineSaveDatas& rSData,
1387  bool bDelRange,
1388  bool bCopyNext )
1389 {
1390  rSData.clear();
1391 
1392  const SwPosition* pStt = rRange.Start();
1393  const SwPosition* pEnd = rRange.End();
1394  const SwRedlineTable& rTable = rRange.GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1396  rRange.GetDoc()->getIDocumentRedlineAccess().GetRedline( *pStt, &n );
1397  for ( ; n < rTable.size(); ++n )
1398  {
1399  SwRangeRedline* pRedl = rTable[n];
1400 
1401  const SwComparePosition eCmpPos =
1402  ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() );
1403  if ( eCmpPos != SwComparePosition::Before
1404  && eCmpPos != SwComparePosition::Behind
1405  && eCmpPos != SwComparePosition::CollideEnd
1406  && eCmpPos != SwComparePosition::CollideStart )
1407  {
1408 
1409  rSData.push_back(std::unique_ptr<SwRedlineSaveData, o3tl::default_delete<SwRedlineSaveData>>(new SwRedlineSaveData(eCmpPos, *pStt, *pEnd, *pRedl, bCopyNext)));
1410  }
1411  }
1412  if( !rSData.empty() && bDelRange )
1413  {
1414  rRange.GetDoc()->getIDocumentRedlineAccess().DeleteRedline( rRange, false, RedlineType::Any );
1415  }
1416  return !rSData.empty();
1417 }
1418 
1420  const SwPaM& rRange,
1421  SwRedlineSaveDatas& rSData )
1422 {
1423  rSData.clear();
1424 
1425  const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
1426  const SwRedlineTable& rTable = rRange.GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1428  rRange.GetDoc()->getIDocumentRedlineAccess().GetRedline( *pStt, &n );
1429  for ( ; n < rTable.size(); ++n )
1430  {
1431  SwRangeRedline* pRedl = rTable[n];
1432  if ( RedlineType::Format == pRedl->GetType() )
1433  {
1434  const SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() );
1435  if ( eCmpPos != SwComparePosition::Before
1436  && eCmpPos != SwComparePosition::Behind
1437  && eCmpPos != SwComparePosition::CollideEnd
1438  && eCmpPos != SwComparePosition::CollideStart )
1439  {
1440  rSData.push_back(std::unique_ptr<SwRedlineSaveData, o3tl::default_delete<SwRedlineSaveData>>(new SwRedlineSaveData(eCmpPos, *pStt, *pEnd, *pRedl, true)));
1441  }
1442 
1443  }
1444  }
1445  return !rSData.empty();
1446 }
1447 
1448 
1450 {
1453  SwPaM aPam( rDoc.GetNodes().GetEndOfContent() );
1454 
1455  for( size_t n = rSData.size(); n; )
1456  rSData[ --n ].RedlineToDoc( aPam );
1457 
1458 #if OSL_DEBUG_LEVEL > 0
1459  // check redline count against count saved in RedlineSaveData object
1460  assert(rSData.empty() ||
1461  (rSData[0].nRedlineCount == rDoc.getIDocumentRedlineAccess().GetRedlineTable().size()));
1462  // "redline count not restored properly"
1463 #endif
1464 
1466 }
1467 
1469 {
1470  for( size_t n = rSData.size(); n; )
1471  if( rSData[ --n ].GetMvSttIdx() )
1472  return true;
1473  return false;
1474 }
1475 
1477  const SwRedlineSaveDatas& rCheck, bool bCurrIsEnd )
1478 {
1479  if( rCurr.size() != rCheck.size() )
1480  return false;
1481 
1482  for( size_t n = 0; n < rCurr.size(); ++n )
1483  {
1484  const SwRedlineSaveData& rSet = rCurr[ n ];
1485  const SwRedlineSaveData& rGet = rCheck[ n ];
1486  if( rSet.m_nSttNode != rGet.m_nSttNode ||
1487  rSet.GetMvSttIdx() || rGet.GetMvSttIdx() ||
1488  ( bCurrIsEnd ? rSet.m_nSttContent != rGet.m_nEndContent
1489  : rSet.m_nEndContent != rGet.m_nSttContent ) ||
1490  !rGet.CanCombine( rSet ) )
1491  {
1492  return false;
1493  }
1494  }
1495 
1496  for( size_t n = 0; n < rCurr.size(); ++n )
1497  {
1498  SwRedlineSaveData& rSet = rCurr[ n ];
1499  const SwRedlineSaveData& rGet = rCheck[ n ];
1500  if( bCurrIsEnd )
1501  rSet.m_nSttContent = rGet.m_nSttContent;
1502  else
1503  rSet.m_nEndContent = rGet.m_nEndContent;
1504  }
1505  return true;
1506 }
1507 
1508 OUString ShortenString(const OUString & rStr, sal_Int32 nLength, const OUString & rFillStr)
1509 {
1510  assert(nLength - rFillStr.getLength() >= 2);
1511 
1512  if (rStr.getLength() <= nLength)
1513  return rStr;
1514 
1515  nLength -= rFillStr.getLength();
1516  if ( nLength < 2 )
1517  nLength = 2;
1518 
1519  const sal_Int32 nFrontLen = nLength - nLength / 2;
1520  const sal_Int32 nBackLen = nLength - nFrontLen;
1521 
1522  return rStr.copy(0, nFrontLen)
1523  + rFillStr
1524  + rStr.copy(rStr.getLength() - nBackLen);
1525 }
1526 
1527 static bool IsAtEndOfSection(SwPosition const& rAnchorPos)
1528 {
1529  SwNodeIndex node(*rAnchorPos.nNode.GetNode().EndOfSectionNode());
1530  SwContentNode *const pNode(SwNodes::GoPrevious(&node));
1531  assert(pNode);
1532  assert(rAnchorPos.nNode <= node); // last valid anchor pos is last content
1533  return node == rAnchorPos.nNode && rAnchorPos.nContent == pNode->Len();
1534 }
1535 
1536 static bool IsAtStartOfSection(SwPosition const& rAnchorPos)
1537 {
1538  SwNodes const& rNodes(rAnchorPos.nNode.GetNodes());
1539  SwNodeIndex node(*rAnchorPos.nNode.GetNode().StartOfSectionNode());
1540  SwContentNode *const pNode(rNodes.GoNext(&node));
1541  assert(pNode);
1542  (void) pNode;
1543  assert(node <= rAnchorPos.nNode);
1544  return node == rAnchorPos.nNode && rAnchorPos.nContent == 0;
1545 }
1546 
1548  SwPosition const & rStart, SwPosition const & rEnd,
1549  DelContentType const nDelContentType)
1550 {
1551  // CheckNoCntnt means DelFullPara which is obvious to handle
1552  if (DelContentType::CheckNoCntnt & nDelContentType)
1553  { // exclude selection end node because it won't be deleted
1554  return (rAnchorPos.nNode < rEnd.nNode)
1555  && (rStart.nNode <= rAnchorPos.nNode);
1556  }
1557 
1558  if (rAnchorPos.GetDoc()->IsInReading())
1559  { // FIXME hack for writerfilter RemoveLastParagraph(); can't test file format more specific?
1560  return (rStart < rAnchorPos) && (rAnchorPos < rEnd);
1561  }
1562 
1563  // in general, exclude the start and end position
1564  return ((rStart < rAnchorPos)
1565  || (rStart == rAnchorPos
1566  && !(nDelContentType & DelContentType::ExcludeAtCharFlyAtStartEnd)
1567  // special case: fully deleted node
1568  && ((rStart.nNode != rEnd.nNode && rStart.nContent == 0)
1569  || IsAtStartOfSection(rAnchorPos))))
1570  && ((rAnchorPos < rEnd)
1571  || (rAnchorPos == rEnd
1572  && !(nDelContentType & DelContentType::ExcludeAtCharFlyAtStartEnd)
1573  // special case: fully deleted node
1574  && ((rEnd.nNode != rStart.nNode && rEnd.nContent == rEnd.nNode.GetNode().GetTextNode()->Len())
1575  || IsAtEndOfSection(rAnchorPos))));
1576 }
1577 
1578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static bool IsAtEndOfSection(SwPosition const &rAnchorPos)
Definition: undobj.cxx:1527
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:682
Starts a section of nodes in the document model.
Definition: node.hxx:303
SwPaM & AddUndoRedoPaM(::sw::UndoRedoContext &, bool const bCorrToContent=false) const
Definition: undobj.cxx:106
virtual sal_Int32 Len() const
Definition: node.cxx:1180
void DeleteMark()
Definition: pam.hxx:177
sal_uLong m_nStartPos
Definition: undobj.hxx:194
sal_uLong GetIndex() const
Definition: node.hxx:282
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:223
bool GoInContent(SwPaM &rPam, SwMoveFnCollection const &fnMove)
Definition: pam.cxx:905
std::unique_ptr< SwRedlineSaveDatas > m_pRedlineSaveData
Definition: undobj.hxx:192
Marks a position in the document model.
Definition: pam.hxx:35
std::unique_ptr< SwHistory > m_pHistory
Definition: undobj.hxx:156
SwNodes const & GetUndoNodes() const
Definition: docundo.cxx:76
void SetContentIdx(const SwNodeIndex *)
Definition: docredln.cxx:1654
SwComparePosition ComparePosition(const T &rStt1, const T &rEnd1, const T &rStt2, const T &rEnd2)
Definition: pam.hxx:77
static bool IsAtStartOfSection(SwPosition const &rAnchorPos)
Definition: undobj.cxx:1536
SwUndoId
Definition: swundo.hxx:29
SwDocShell * GetDocShell()
Definition: doc.hxx:1342
virtual SwPaM & CreateNewShellCursor()=0
virtual AppendResult AppendRedline(SwRangeRedline *pNewRedl, bool bCallDelete)=0
Append a new redline.
size_t size() const
Definition: UndoCore.hxx:76
bool Rollback(SwDoc *pDoc, sal_uInt16 nStart=0)
Definition: rolbck.cxx:1152
virtual void SetRedlineFlags_intern(RedlineFlags eMode)=0
Set a new redline mode.
static bool FillSaveDataForFormat(const SwPaM &, SwRedlineSaveDatas &)
Definition: undobj.cxx:1419
SwNodeIndex nNode
Definition: pam.hxx:37
virtual void Repeat(SfxRepeatTarget &) override
Definition: undobj.cxx:241
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:284
sal_uIntPtr sal_uLong
Pos1 is as large as Pos2.
static SW_DLLPUBLIC MarkType GetType(const ::sw::mark::IMark &rMark)
Returns the MarkType used to create the mark.
Definition: docbm.cxx:474
const SwPosition * GetMark() const
Definition: pam.hxx:209
sal_uLong m_nEndNode
Definition: undobj.hxx:218
Pos1 completely contained in Pos2.
static ViewShellId CreateViewShellId(const SwDoc *pDoc)
Try to obtain the view shell ID of the current view.
Definition: undobj.cxx:167
Provides access to the marks of a document.
Definition: doc.hxx:185
~SwUndoSaveContent() COVERITY_NOEXCEPT_FALSE
Definition: undobj.cxx:697
SwRedlineSaveData(SwComparePosition eCmpPos, const SwPosition &rSttPos, const SwPosition &rEndPos, SwRangeRedline &rRedl, bool bCopyNext)
Definition: undobj.cxx:1297
static SwContentNode * GoPrevious(SwNodeIndex *)
Definition: nodes.cxx:1288
SwNode & GetNode() const
Definition: ndindex.hxx:119
UndoRedoRedlineGuard(::sw::UndoRedoContext const &rContext, SwUndo const &rUndo)
Definition: undobj.cxx:193
const SwHistory * GetHistory() const
Definition: undobj.hxx:209
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1602
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:143
SwNode & GetEndOfPostIts() const
A still empty section.
Definition: ndarr.hxx:153
static void RemoveIdxFromSection(SwDoc &, sal_uLong nSttIdx, const sal_uLong *pEndIdx=nullptr)
Definition: undobj.cxx:114
bool IsDestroyFrameAnchoredAtChar(SwPosition const &rAnchorPos, SwPosition const &rStart, SwPosition const &rEnd, DelContentType const nDelContentType)
will DelContentIndex destroy a frame anchored at character at rAnchorPos?
Definition: undobj.cxx:1547
virtual void RepeatImpl(::sw::RepeatContext &)
Definition: undobj.cxx:261
SwUndoId GetId() const
Definition: undobj.hxx:100
bool CanCombine(const SwRedlineData &rCmp) const
Definition: docredln.cxx:921
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:737
IShellCursorSupplier & GetCursorSupplier()
Definition: UndoCore.hxx:96
SwUndRng()
Definition: undobj.cxx:46
size_type size() const
Definition: docary.hxx:368
void push_back(std::unique_ptr< SwRedlineSaveData, o3tl::default_delete< SwRedlineSaveData >> pNew)
Definition: UndoCore.hxx:77
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
void SetValues(const SwPaM &rPam)
Definition: undobj.cxx:56
SwTextAttr * GetTextAttrForCharAt(const sal_Int32 nIndex, const sal_uInt16 nWhich=RES_TXTATR_END) const
get the text attribute at position nIndex which owns the dummy character CH_TXTATR_* at that position...
Definition: ndtxt.cxx:3059
Pos1 end touches at Pos2 start.
sal_uLong m_nMoveLen
Definition: undobj.hxx:193
void Delete(const SwNodeIndex &rPos, sal_uLong nNodes=1)
delete nodes
Definition: nodes.cxx:1061
SwNodeIndex * GetMvSttIdx() const
Definition: UndoCore.hxx:57
SwIndex nContent
Definition: pam.hxx:38
SwDoc * GetDoc() const
Returns the document this position is in.
Definition: pam.cxx:176
SwNodeIndex aStart
Definition: ndindex.hxx:132
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
virtual SwRewriter GetRewriter() const
Returns the rewriter for this object.
Definition: undobj.cxx:687
Pos2 completely contained in Pos1.
static bool CanRedlineGroup(SwRedlineSaveDatas &rCurr, const SwRedlineSaveDatas &rCheck, bool bCurrIsEnd)
Definition: undobj.cxx:1476
bool empty() const
Definition: docary.hxx:224
Pos1 before Pos2.
RedlineFlags on.
static void MoveToUndoNds(SwPaM &rPam, SwNodeIndex *pNodeIdx, sal_uLong *pEndNdIdx=nullptr)
Definition: undobj.cxx:709
size_type size() const
static void RemoveIdxFromRange(SwPaM &rPam, bool bMoveNext)
Definition: undobj.cxx:124
virtual bool CanRepeat(SfxRepeatTarget &) const override
Definition: undobj.cxx:253
RedlineFlags GetRedlineFlags() const
Definition: undobj.hxx:118
Specific frame formats (frames, DrawObjects).
Definition: docary.hxx:201
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:164
virtual std::unique_ptr< ILazyDeleter > deleteMark(const IDocumentMarkAccess::const_iterator_t &ppMark)=0
Deletes a mark.
virtual const_iterator_t getAllMarksBegin() const =0
returns a STL-like random access iterator to the begin of the sequence of marks.
bool IsContentNode() const
Definition: node.hxx:628
static void MovePtForward(SwPaM &rPam, bool bMvBkwrd)
Definition: undobj.cxx:818
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
virtual void UndoImpl(::sw::UndoRedoContext &)=0
bool Move(SwMoveFnCollection const &fnMove=fnMoveForward, SwGoInDoc fnGo=GoInContent)
Movement of cursor.
Definition: pam.cxx:485
SwTextFootnote * SeekEntry(const SwNodeIndex &rIdx, size_t *pPos=nullptr) const
Definition: ftnidx.cxx:409
Style of a layout element.
Definition: frmfmt.hxx:57
::sw::UndoManager & GetUndoManager()
Definition: doc.cxx:132
static bool HasHiddenRedlines(const SwRedlineSaveDatas &rSData)
Definition: undobj.cxx:1468
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:131
const SwPosition * GetPoint() const
Definition: pam.hxx:207
Pos1 start touches at Pos2 end.
void DelContentIndex(const SwPosition &pMark, const SwPosition &pPoint, DelContentType nDelContentType=DelContentType::AllMask)
Definition: undobj.cxx:843
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:198
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
OUString Apply(const OUString &rStr) const
Definition: SwRewriter.cxx:43
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
OUString ShortenString(const OUString &rStr, sal_Int32 nLength, const OUString &rFillStr)
Shortens a string to a maximum length.
Definition: undobj.cxx:1508
static void SetSaveData(SwDoc &rDoc, SwRedlineSaveDatas &rSData)
Definition: undobj.cxx:1449
void Exchange()
Definition: pam.cxx:473
MetadataImporterPluginType * result
virtual bool DeleteRedline(const SwPaM &rPam, bool bSaveInUndo, RedlineType nDelType)=0
SwContentNode * GetContentNode()
Definition: node.hxx:615
vector_type::size_type size_type
Definition: docary.hxx:330
FlyAnchors.
Definition: fmtanchr.hxx:34
void MakeStartIndex(SwIndex *pIdx)
Definition: node.hxx:391
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
SwNoTextNode * GetNoTextNode()
Definition: ndnotxt.hxx:96
sal_Int32 m_nEndContent
Definition: undobj.hxx:219
SwDoc * GetDoc()
Definition: node.hxx:702
SwDoc * GetDoc() const
Definition: pam.hxx:243
virtual void UndoWithContext(SfxUndoContext &) override
Definition: undobj.cxx:223
Marks a character position inside a document model node.
Definition: index.hxx:37
void PaMCorrRel(const SwNodeIndex &rOldNode, const SwPosition &rNewPos, const sal_Int32 nOffset)
Sets all PaMs in OldNode to relative Pos.
Definition: doccorr.cxx:235
boost::optional< OUString > maComment
Definition: undobj.hxx:61
Marks a node in the document model.
Definition: ndindex.hxx:31
bool m_bCacheComment
Definition: undobj.hxx:60
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:693
static bool MovePtBackward(SwPaM &rPam)
Definition: undobj.cxx:805
OUString SwResId(const char *pId)
Definition: swmodule.cxx:190
bool empty() const
virtual OUString GetComment() const override
Returns textual comment for this undo object.
Definition: undobj.cxx:653
std::unique_ptr< SwNodeIndex > m_pMovedStart
Definition: undobj.hxx:191
bool IsInReading() const
Definition: doc.hxx:950
const SwPosition * Start() const
Definition: pam.hxx:212
void RedlineToDoc(SwPaM const &rPam)
Definition: undobj.cxx:1353
IDocumentRedlineAccess & m_rRedlineAccess
Definition: undobj.cxx:209
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const =0
sal_uLong m_nSttNode
Definition: undobj.hxx:218
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:458
const OUString & GetComment(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1733
ignore Redlines
RedlineFlags const m_eMode
Definition: undobj.cxx:210
void EraseText(const SwIndex &rIdx, const sal_Int32 nCount=SAL_MAX_INT32, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
delete text content ATTENTION: must not be called with a range that overlaps the start of an attribut...
Definition: ndtxt.cxx:2668
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
void RestoreSection(SwDoc *pDoc, SwNodeIndex *pIdx, sal_uInt16 nSectType)
Definition: undobj.cxx:1256
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:334
void SetPaM(SwPaM &, bool bCorrToContent=false) const
Definition: undobj.cxx:78
static void MoveFromUndoNds(SwDoc &rDoc, sal_uLong nNodeIdx, SwPosition &rInsPos, const sal_uLong *pEndNdIdx=nullptr, bool bForceCreateFrames=false)
Definition: undobj.cxx:746
DelContentType
Definition: undobj.hxx:132
virtual sal_Int32 getAllMarksCount() const =0
returns the number of marks.
ViewShellId const m_nViewShellId
Definition: undobj.hxx:56
void CorrAbs(const SwNodeIndex &rOldNode, const SwPosition &rNewPos, const sal_Int32 nOffset=0, bool bMoveCursor=false)
Definition: doccorr.cxx:162
Pos1 overlaps Pos2 at the end.
const SwNodes & GetNodes() const
Definition: ndindex.hxx:156
virtual ~SwUndo() override
Definition: undobj.cxx:186
SwMoveFnCollection const & fnMoveForward
SwPam::Move()/Find() default argument.
Definition: paminit.cxx:59
virtual void SetRedlineFlags(RedlineFlags eMode)=0
Set a new redline mode.
#define SAL_INFO(area, stream)
sal_Int32 GetIndex() const
Definition: index.hxx:95
SwNodes & GetNodes()
Definition: doc.hxx:402
SwUndo(SwUndoId const nId, const SwDoc *pDoc)
Definition: undobj.cxx:159
const SwPosition * End() const
Definition: pam.hxx:217
SwNodeIndex aEnd
Definition: ndindex.hxx:133
bool m_isRepeatIgnored
for multi-selection, only repeat 1st selection
Definition: undobj.hxx:57
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1728
virtual void Redo() override
Definition: undobj.cxx:218
virtual void RedoWithContext(SfxUndoContext &) override
Definition: undobj.cxx:232
static void RemoveIdxRel(sal_uLong, const SwPosition &)
Definition: undobj.cxx:151
bool empty() const
Definition: UndoCore.hxx:75
sal_uInt16 nRedlineCount
Definition: UndoCore.hxx:63
SwMoveFnCollection const & fnMoveBackward
Definition: paminit.cxx:58
friend class SwRangeRedline
Definition: redline.hxx:89
virtual void RedoImpl(::sw::UndoRedoContext &)=0
OUString GetUndoComment(SwUndoId eId)
Definition: undobj.cxx:265
virtual void Undo() override
Definition: undobj.cxx:213
SwFootnoteIdxs & GetFootnoteIdxs()
Definition: doc.hxx:627
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
size_t size() const
Definition: docary.hxx:225
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:459
Pos1 behind Pos2.
static bool FillSaveData(const SwPaM &rRange, SwRedlineSaveDatas &rSData, bool bDelRange=true, bool bCopyNext=true)
Definition: undobj.cxx:1384
virtual const SwRedlineTable & GetRedlineTable() const =0
ViewShellId GetViewShellId() const override
See SfxUndoAction::GetViewShellId().
Definition: undobj.cxx:682
SwNode & GetEndOfExtras() const
This is the last EndNode of a special section.
Definition: ndarr.hxx:162
sal_Int32 nPos
bool IsTextNode() const
Definition: node.hxx:636
void SaveSection(const SwNodeIndex &rSttIdx)
Definition: undobj.cxx:1204
SwNodeIndex * GetContentIdx() const
Definition: redline.hxx:184
bool IsDelBox() const
Definition: undobj.cxx:180
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
Pos1 overlaps Pos2 at the beginning.
sal_Int32 m_nSttContent
Definition: undobj.hxx:219
Definition: view.hxx:146
SwComparePosition
Definition: pam.hxx:64
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:842
void SetAnchor(const SwPosition *pPos)
Definition: atrfrm.cxx:1476
bool MoveNodes(const SwNodeRange &, SwNodes &rNodes, const SwNodeIndex &, bool bNewFrames=true)
move the node pointer
Definition: nodes.cxx:394
static SwStartNode * MakeEmptySection(const SwNodeIndex &rIdx, SwStartNodeType=SwNormalStartNode)
Create an empty section of Start- and EndNote.
Definition: nodes.cxx:1890
Base class of the Writer document model elements.
Definition: node.hxx:79
void MoveRange(SwPaM &, SwPosition &, SwNodes &rNodes)
move a range
Definition: nodes.cxx:1437
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo