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  : nSttNode( 0 ), nEndNode( 0 ), nSttContent( 0 ), 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  nEndNode = pEnd->nNode.GetIndex();
65  nEndContent = pEnd->nContent.GetIndex();
66  }
67  else
68  {
69  // no selection !!
70  nEndNode = 0;
72  }
73 
74  nSttNode = pStt->nNode.GetIndex();
75  nSttContent = pStt->nContent.GetIndex();
76 }
77 
78 void SwUndRng::SetPaM( SwPaM & rPam, bool bCorrToContent ) const
79 {
80  rPam.DeleteMark();
81  rPam.GetPoint()->nNode = 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( !nEndNode && COMPLETE_STRING == nEndContent ) // no selection
91  return ;
92 
93  rPam.SetMark();
95  return; // nothing left to do
96 
97  rPam.GetPoint()->nNode = 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), nOrigRedlineFlags(RedlineFlags::NONE)
161  , m_nViewShellId(CreateViewShellId(pDoc))
162  , m_isRepeatIgnored(false)
163  , 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 OUString("$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 (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 if( pEndNdIdx || !pTextNd )
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  else {
800  assert(false); // wtf?
801  }
802 }
803 
804 // These two methods move the Point of Pam backwards/forwards. With that, one
805 // can span an area for a Undo/Redo. (The Point is then positioned in front of
806 // the area to manipulate!)
807 // The flag indicates if there is still content in front of Point.
809 {
810  rPam.SetMark();
811  if( rPam.Move( fnMoveBackward ))
812  return true;
813 
814  // If there is no content onwards, set Point simply to the previous position
815  // (Node and Content, so that Content will be detached!)
816  --rPam.GetPoint()->nNode;
817  rPam.GetPoint()->nContent.Assign( nullptr, 0 );
818  return false;
819 }
820 
821 void SwUndoSaveContent::MovePtForward( SwPaM& rPam, bool bMvBkwrd )
822 {
823  // Was there content before this position?
824  if( bMvBkwrd )
825  rPam.Move( fnMoveForward );
826  else
827  {
828  ++rPam.GetPoint()->nNode;
829  SwContentNode* pCNd = rPam.GetContentNode();
830  if( pCNd )
831  pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
832  else
833  rPam.Move( fnMoveForward );
834  }
835 }
836 
837 // Delete all objects that have ContentIndices to the given area.
838 // Currently (1994) these exist:
839 // - Footnotes
840 // - Flys
841 // - Bookmarks
842 
843 // #i81002# - extending method
844 // delete certain (not all) cross-reference bookmarks at text node of <rMark>
845 // and at text node of <rPoint>, if these text nodes aren't the same.
847  const SwPosition& rPoint,
848  DelContentType nDelContentType )
849 {
850  const SwPosition *pStt = rMark < rPoint ? &rMark : &rPoint,
851  *pEnd = &rMark == pStt ? &rPoint : &rMark;
852 
853  SwDoc* pDoc = rMark.nNode.GetNode().GetDoc();
854 
855  ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
856 
857  // 1. Footnotes
858  if( DelContentType::Ftn & nDelContentType )
859  {
860  SwFootnoteIdxs& rFootnoteArr = pDoc->GetFootnoteIdxs();
861  if( !rFootnoteArr.empty() )
862  {
863  const SwNode* pFootnoteNd;
864  size_t nPos = 0;
865  rFootnoteArr.SeekEntry( pStt->nNode, &nPos );
866  SwTextFootnote* pSrch;
867 
868  // for now delete all that come afterwards
869  while( nPos < rFootnoteArr.size() && ( pFootnoteNd =
870  &( pSrch = rFootnoteArr[ nPos ] )->GetTextNode())->GetIndex()
871  <= pEnd->nNode.GetIndex() )
872  {
873  const sal_Int32 nFootnoteSttIdx = pSrch->GetStart();
874  if( (DelContentType::CheckNoCntnt & nDelContentType )
875  ? (&pEnd->nNode.GetNode() == pFootnoteNd )
876  : (( &pStt->nNode.GetNode() == pFootnoteNd &&
877  pStt->nContent.GetIndex() > nFootnoteSttIdx) ||
878  ( &pEnd->nNode.GetNode() == pFootnoteNd &&
879  nFootnoteSttIdx >= pEnd->nContent.GetIndex() )) )
880  {
881  ++nPos; // continue searching
882  continue;
883  }
884 
885 // FIXME: duplicated code here and below -> refactor?
886  // Unfortunately an index needs to be created. Otherwise there
887  // will be problems with TextNode because the index will be
888  // deleted in the DTOR of SwFootnote!
889  SwTextNode* pTextNd = const_cast<SwTextNode*>(static_cast<const SwTextNode*>(pFootnoteNd));
890  if( !pHistory )
891  pHistory.reset( new SwHistory );
892  SwTextAttr* const pFootnoteHint =
893  pTextNd->GetTextAttrForCharAt( nFootnoteSttIdx );
894  assert(pFootnoteHint);
895  SwIndex aIdx( pTextNd, nFootnoteSttIdx );
896  pHistory->Add( pFootnoteHint, pTextNd->GetIndex(), false );
897  pTextNd->EraseText( aIdx, 1 );
898  }
899 
900  while( nPos-- && ( pFootnoteNd = &( pSrch = rFootnoteArr[ nPos ] )->
901  GetTextNode())->GetIndex() >= pStt->nNode.GetIndex() )
902  {
903  const sal_Int32 nFootnoteSttIdx = pSrch->GetStart();
904  if( !(DelContentType::CheckNoCntnt & nDelContentType) && (
905  ( &pStt->nNode.GetNode() == pFootnoteNd &&
906  pStt->nContent.GetIndex() > nFootnoteSttIdx ) ||
907  ( &pEnd->nNode.GetNode() == pFootnoteNd &&
908  nFootnoteSttIdx >= pEnd->nContent.GetIndex() )))
909  continue; // continue searching
910 
911  // Unfortunately an index needs to be created. Otherwise there
912  // will be problems with TextNode because the index will be
913  // deleted in the DTOR of SwFootnote!
914  SwTextNode* pTextNd = const_cast<SwTextNode*>(static_cast<const SwTextNode*>(pFootnoteNd));
915  if( !pHistory )
916  pHistory.reset( new SwHistory );
917  SwTextAttr* const pFootnoteHint =
918  pTextNd->GetTextAttrForCharAt( nFootnoteSttIdx );
919  assert(pFootnoteHint);
920  SwIndex aIdx( pTextNd, nFootnoteSttIdx );
921  pHistory->Add( pFootnoteHint, pTextNd->GetIndex(), false );
922  pTextNd->EraseText( aIdx, 1 );
923  }
924  }
925  }
926 
927  // 2. Flys
928  if( DelContentType::Fly & nDelContentType )
929  {
930  sal_uInt16 nChainInsPos = pHistory ? pHistory->Count() : 0;
931  const SwFrameFormats& rSpzArr = *pDoc->GetSpzFrameFormats();
932  if( !rSpzArr.empty() )
933  {
934  const bool bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex();
935  SwFrameFormat* pFormat;
936  const SwFormatAnchor* pAnchor;
937  size_t n = rSpzArr.size();
938  const SwPosition* pAPos;
939 
940  while( n && !rSpzArr.empty() )
941  {
942  pFormat = rSpzArr[--n];
943  pAnchor = &pFormat->GetAnchor();
944  switch( pAnchor->GetAnchorId() )
945  {
946  case RndStdIds::FLY_AS_CHAR:
947  if( nullptr != (pAPos = pAnchor->GetContentAnchor() ) &&
948  (( DelContentType::CheckNoCntnt & nDelContentType )
949  ? ( pStt->nNode <= pAPos->nNode &&
950  pAPos->nNode < pEnd->nNode )
951  : ( *pStt <= *pAPos && *pAPos < *pEnd )) )
952  {
953  if( !pHistory )
954  pHistory.reset( new SwHistory );
955  SwTextNode *const pTextNd =
956  pAPos->nNode.GetNode().GetTextNode();
957  SwTextAttr* const pFlyHint = pTextNd->GetTextAttrForCharAt(
958  pAPos->nContent.GetIndex());
959  assert(pFlyHint);
960  pHistory->Add( pFlyHint, 0, false );
961  // reset n so that no Format is skipped
962  n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
963  }
964  break;
965  case RndStdIds::FLY_AT_PARA:
966  {
967  pAPos = pAnchor->GetContentAnchor();
968  if( pAPos )
969  {
970  bool bTmp;
971  if( DelContentType::CheckNoCntnt & nDelContentType )
972  bTmp = pStt->nNode <= pAPos->nNode && pAPos->nNode < pEnd->nNode;
973  else
974  {
975  if (bDelFwrd)
976  bTmp = rMark.nNode < pAPos->nNode &&
977  pAPos->nNode <= rPoint.nNode;
978  else
979  bTmp = rPoint.nNode <= pAPos->nNode &&
980  pAPos->nNode < rMark.nNode;
981  }
982 
983  if (bTmp)
984  {
985  if( !pHistory )
986  pHistory.reset( new SwHistory );
987 
988  // Moving the anchor?
989  if( !( DelContentType::CheckNoCntnt & nDelContentType ) &&
990  (rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex())
991  // Do not try to move the anchor to a table!
992  && rMark.nNode.GetNode().IsTextNode())
993  {
994  pHistory->Add( *pFormat );
995  SwFormatAnchor aAnch( *pAnchor );
996  SwPosition aPos( rMark.nNode );
997  aAnch.SetAnchor( &aPos );
998  pFormat->SetFormatAttr( aAnch );
999  }
1000  else
1001  {
1002  pHistory->Add( *static_cast<SwFlyFrameFormat *>(pFormat), nChainInsPos );
1003  // reset n so that no Format is skipped
1004  n = n >= rSpzArr.size() ?
1005  rSpzArr.size() : n+1;
1006  }
1007  }
1008  }
1009  }
1010  break;
1011  case RndStdIds::FLY_AT_CHAR:
1012  if( nullptr != (pAPos = pAnchor->GetContentAnchor() ) &&
1013  ( pStt->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) )
1014  {
1015  if( !pHistory )
1016  pHistory.reset( new SwHistory );
1018  *pAPos, *pStt, *pEnd, nDelContentType))
1019  {
1020  pHistory->Add( *static_cast<SwFlyFrameFormat *>(pFormat), nChainInsPos );
1021  n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
1022  }
1023  else if( !( DelContentType::CheckNoCntnt & nDelContentType ) )
1024  {
1025  if( *pStt <= *pAPos && *pAPos < *pEnd )
1026  {
1027  // These are the objects anchored
1028  // between section start and end position
1029  // Do not try to move the anchor to a table!
1030  if( rMark.nNode.GetNode().GetTextNode() )
1031  {
1032  pHistory->Add( *pFormat );
1033  SwFormatAnchor aAnch( *pAnchor );
1034  aAnch.SetAnchor( &rMark );
1035  pFormat->SetFormatAttr( aAnch );
1036  }
1037  }
1038  }
1039  }
1040  break;
1041  case RndStdIds::FLY_AT_FLY:
1042 
1043  if( nullptr != (pAPos = pAnchor->GetContentAnchor() ) &&
1044  pStt->nNode == pAPos->nNode )
1045  {
1046  if( !pHistory )
1047  pHistory.reset( new SwHistory );
1048 
1049  pHistory->Add( *static_cast<SwFlyFrameFormat *>(pFormat), nChainInsPos );
1050 
1051  // reset n so that no Format is skipped
1052  n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
1053  }
1054  break;
1055  default: break;
1056  }
1057  }
1058  }
1059  }
1060 
1061  // 3. Bookmarks
1062  if( DelContentType::Bkm & nDelContentType )
1063  {
1064  IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1065  if( pMarkAccess->getAllMarksCount() )
1066  {
1067 
1068  for( sal_Int32 n = 0; n < pMarkAccess->getAllMarksCount(); ++n )
1069  {
1070  // #i81002#
1071  bool bSavePos = false;
1072  bool bSaveOtherPos = false;
1073  const ::sw::mark::IMark* pBkmk = (pMarkAccess->getAllMarksBegin() + n)->get();
1074 
1075  if( DelContentType::CheckNoCntnt & nDelContentType )
1076  {
1077  if ( pStt->nNode <= pBkmk->GetMarkPos().nNode
1078  && pBkmk->GetMarkPos().nNode < pEnd->nNode )
1079  {
1080  bSavePos = true;
1081  }
1082  if ( pBkmk->IsExpanded()
1083  && pStt->nNode <= pBkmk->GetOtherMarkPos().nNode
1084  && pBkmk->GetOtherMarkPos().nNode < pEnd->nNode )
1085  {
1086  bSaveOtherPos = true;
1087  }
1088  }
1089  else
1090  {
1091  // #i92125#
1092  // keep cross-reference bookmarks, if content inside one paragraph is deleted.
1093  if ( rMark.nNode == rPoint.nNode
1096  {
1097  continue;
1098  }
1099 
1100  bool bMaybe = false;
1101  if ( *pStt <= pBkmk->GetMarkPos() && pBkmk->GetMarkPos() <= *pEnd )
1102  {
1103  if ( pBkmk->GetMarkPos() == *pEnd
1104  || ( *pStt == pBkmk->GetMarkPos() && pBkmk->IsExpanded() ) )
1105  bMaybe = true;
1106  else
1107  bSavePos = true;
1108  }
1109  if( pBkmk->IsExpanded() &&
1110  *pStt <= pBkmk->GetOtherMarkPos() && pBkmk->GetOtherMarkPos() <= *pEnd )
1111  {
1112  if ( bSavePos || bSaveOtherPos
1113  || ( pBkmk->GetOtherMarkPos() < *pEnd && pBkmk->GetOtherMarkPos() > *pStt ) )
1114  {
1115  if( bMaybe )
1116  bSavePos = true;
1117  bSaveOtherPos = true;
1118  }
1119  }
1120 
1121  if ( !bSavePos && !bSaveOtherPos
1122  && dynamic_cast< const ::sw::mark::CrossRefBookmark* >(pBkmk) )
1123  {
1124  // certain special handling for cross-reference bookmarks
1125  const bool bDifferentTextNodesAtMarkAndPoint =
1126  rMark.nNode != rPoint.nNode
1127  && rMark.nNode.GetNode().GetTextNode()
1128  && rPoint.nNode.GetNode().GetTextNode();
1129  if ( bDifferentTextNodesAtMarkAndPoint )
1130  {
1131  // delete cross-reference bookmark at <pStt>, if only part of
1132  // <pEnd> text node content is deleted.
1133  if( pStt->nNode == pBkmk->GetMarkPos().nNode
1134  && pEnd->nContent.GetIndex() != pEnd->nNode.GetNode().GetTextNode()->Len() )
1135  {
1136  bSavePos = true;
1137  bSaveOtherPos = false; // cross-reference bookmarks are not expanded
1138  }
1139  // delete cross-reference bookmark at <pEnd>, if only part of
1140  // <pStt> text node content is deleted.
1141  else if( pEnd->nNode == pBkmk->GetMarkPos().nNode &&
1142  pStt->nContent.GetIndex() != 0 )
1143  {
1144  bSavePos = true;
1145  bSaveOtherPos = false; // cross-reference bookmarks are not expanded
1146  }
1147  }
1148  }
1150  {
1151  // delete annotation marks, if its end position is covered by the deletion
1152  const SwPosition& rAnnotationEndPos = pBkmk->GetMarkEnd();
1153  if ( *pStt < rAnnotationEndPos && rAnnotationEndPos <= *pEnd )
1154  {
1155  bSavePos = true;
1156  bSaveOtherPos = pBkmk->IsExpanded(); //tdf#90138, only save the other pos if there is one
1157  }
1158  }
1159  }
1160 
1161  if ( bSavePos || bSaveOtherPos )
1162  {
1164  {
1165  if( !pHistory )
1166  pHistory.reset( new SwHistory );
1167  pHistory->Add( *pBkmk, bSavePos, bSaveOtherPos );
1168  }
1169  if ( bSavePos
1170  && ( bSaveOtherPos
1171  || !pBkmk->IsExpanded() ) )
1172  {
1173  pMarkAccess->deleteMark(pMarkAccess->getAllMarksBegin()+n);
1174  n--;
1175  }
1176  }
1177  }
1178  }
1179  }
1180 }
1181 
1182 // save a complete section into UndoNodes array
1184  : nMvLen( 0 ), nStartPos( ULONG_MAX )
1185 {
1186 }
1187 
1189 {
1190  if (m_pMovedStart) // delete also the section from UndoNodes array
1191  {
1192  // SaveSection saves the content in the PostIt section.
1193  SwNodes& rUNds = m_pMovedStart->GetNode().GetNodes();
1194  rUNds.Delete( *m_pMovedStart, nMvLen );
1195 
1196  m_pMovedStart.reset();
1197  }
1198  pRedlSaveData.reset();
1199 }
1200 
1202 {
1203  SwNodeRange aRg( rSttIdx.GetNode(), *rSttIdx.GetNode().EndOfSectionNode() );
1204  SaveSection( aRg );
1205 }
1206 
1208  const SwNodeRange& rRange, bool const bExpandNodes)
1209 {
1210  SwPaM aPam( rRange.aStart, rRange.aEnd );
1211 
1212  // delete all footnotes, fly frames, bookmarks
1213  DelContentIndex( *aPam.GetMark(), *aPam.GetPoint() );
1214 
1215  // redlines *before* CorrAbs, because DelBookmarks will make them 0-length
1216  // but *after* DelContentIndex because that also may use FillSaveData (in
1217  // flys) and that will be restored *after* this one...
1218  pRedlSaveData.reset( new SwRedlineSaveDatas );
1219  if (!SwUndo::FillSaveData( aPam, *pRedlSaveData ))
1220  {
1221  pRedlSaveData.reset();
1222  }
1223 
1224  {
1225  // move certain indexes out of deleted range
1226  SwNodeIndex aSttIdx( aPam.Start()->nNode.GetNode() );
1227  SwNodeIndex aEndIdx( aPam.End()->nNode.GetNode() );
1228  SwNodeIndex aMvStt( aEndIdx, 1 );
1229  SwDoc::CorrAbs( aSttIdx, aEndIdx, SwPosition( aMvStt ), true );
1230  }
1231 
1232  nStartPos = rRange.aStart.GetIndex();
1233 
1234  if (bExpandNodes)
1235  {
1236  --aPam.GetPoint()->nNode;
1237  ++aPam.GetMark()->nNode;
1238  }
1239 
1240  SwContentNode* pCNd = aPam.GetContentNode( false );
1241  if( pCNd )
1242  aPam.GetMark()->nContent.Assign( pCNd, 0 );
1243  if( nullptr != ( pCNd = aPam.GetContentNode()) )
1244  aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
1245 
1246  // Keep positions as SwIndex so that this section can be deleted in DTOR
1247  sal_uLong nEnd;
1248  m_pMovedStart.reset(new SwNodeIndex(rRange.aStart));
1249  MoveToUndoNds(aPam, m_pMovedStart.get(), &nEnd);
1250  nMvLen = nEnd - m_pMovedStart->GetIndex() + 1;
1251 }
1252 
1254  sal_uInt16 nSectType )
1255 {
1256  if( ULONG_MAX != nStartPos ) // was there any content?
1257  {
1258  // check if the content is at the old position
1259  SwNodeIndex aSttIdx( pDoc->GetNodes(), nStartPos );
1260 
1261  // move the content from UndoNodes array into Fly
1262  SwStartNode* pSttNd = SwNodes::MakeEmptySection( aSttIdx,
1263  static_cast<SwStartNodeType>(nSectType) );
1264 
1265  RestoreSection( pDoc, SwNodeIndex( *pSttNd->EndOfSectionNode() ));
1266 
1267  if( pIdx )
1268  *pIdx = *pSttNd;
1269  }
1270 }
1271 
1273  SwDoc *const pDoc, const SwNodeIndex& rInsPos, bool bForceCreateFrames)
1274 {
1275  if( ULONG_MAX != nStartPos ) // was there any content?
1276  {
1277  SwPosition aInsPos( rInsPos );
1278  sal_uLong nEnd = m_pMovedStart->GetIndex() + nMvLen - 1;
1279  MoveFromUndoNds(*pDoc, m_pMovedStart->GetIndex(), aInsPos, &nEnd, bForceCreateFrames);
1280 
1281  // destroy indices again, content was deleted from UndoNodes array
1282  m_pMovedStart.reset();
1283  nMvLen = 0;
1284 
1285  if( pRedlSaveData )
1286  {
1288  pRedlSaveData.reset();
1289  }
1290  }
1291 }
1292 
1293 // save and set the RedlineData
1295  SwComparePosition eCmpPos,
1296  const SwPosition& rSttPos,
1297  const SwPosition& rEndPos,
1298  SwRangeRedline& rRedl,
1299  bool bCopyNext )
1300  : SwUndRng( rRedl )
1301  , SwRedlineData( rRedl.GetRedlineData(), bCopyNext )
1302 {
1303  assert( SwComparePosition::Outside == eCmpPos ||
1304  !rRedl.GetContentIdx() ); // "Redline with Content"
1305 
1306  switch (eCmpPos)
1307  {
1308  case SwComparePosition::OverlapBefore: // Pos1 overlaps Pos2 at the beginning
1309  nEndNode = rEndPos.nNode.GetIndex();
1310  nEndContent = rEndPos.nContent.GetIndex();
1311  break;
1312 
1313  case SwComparePosition::OverlapBehind: // Pos1 overlaps Pos2 at the end
1314  nSttNode = rSttPos.nNode.GetIndex();
1315  nSttContent = rSttPos.nContent.GetIndex();
1316  break;
1317 
1318  case SwComparePosition::Inside: // Pos1 lays completely in Pos2
1319  nSttNode = rSttPos.nNode.GetIndex();
1320  nSttContent = rSttPos.nContent.GetIndex();
1321  nEndNode = rEndPos.nNode.GetIndex();
1322  nEndContent = rEndPos.nContent.GetIndex();
1323  break;
1324 
1325  case SwComparePosition::Outside: // Pos2 lays completely in Pos1
1326  if ( rRedl.GetContentIdx() )
1327  {
1328  // than move section into UndoArray and memorize it
1329  SaveSection( *rRedl.GetContentIdx() );
1330  rRedl.SetContentIdx( nullptr );
1331  }
1332  break;
1333 
1334  case SwComparePosition::Equal: // Pos1 is exactly as big as Pos2
1335  break;
1336 
1337  default:
1338  assert(false);
1339  }
1340 
1341 #if OSL_DEBUG_LEVEL > 0
1343 #endif
1344 }
1345 
1347 {
1348 }
1349 
1351 {
1352  SwDoc& rDoc = *rPam.GetDoc();
1353  SwRangeRedline* pRedl = new SwRangeRedline( *this, rPam );
1354 
1355  if( GetMvSttIdx() )
1356  {
1357  SwNodeIndex aIdx( rDoc.GetNodes() );
1358  RestoreSection( &rDoc, &aIdx, SwNormalStartNode );
1359  if( GetHistory() )
1360  GetHistory()->Rollback( &rDoc );
1361  pRedl->SetContentIdx( &aIdx );
1362  }
1363  SetPaM( *pRedl );
1364  // First, delete the "old" so that in an Append no unexpected things will
1365  // happen, e.g. a delete in an insert. In the latter case the just restored
1366  // content will be deleted and not the one you originally wanted.
1367  rDoc.getIDocumentRedlineAccess().DeleteRedline( *pRedl, false, USHRT_MAX );
1368 
1371  //#i92154# let UI know about a new redline with comment
1372  if (rDoc.GetDocShell() && (!pRedl->GetComment().isEmpty()) )
1373  rDoc.GetDocShell()->Broadcast(SwRedlineHint());
1374 
1375  auto const result(rDoc.getIDocumentRedlineAccess().AppendRedline(pRedl, true));
1376  assert(result != IDocumentRedlineAccess::AppendResult::IGNORED); // SwRedlineSaveData::RedlineToDoc: insert redline failed
1377  (void) result; // unused in non-debug
1379 }
1380 
1382  const SwPaM& rRange,
1383  SwRedlineSaveDatas& rSData,
1384  bool bDelRange,
1385  bool bCopyNext )
1386 {
1387  rSData.clear();
1388 
1389  const SwPosition* pStt = rRange.Start();
1390  const SwPosition* pEnd = rRange.End();
1391  const SwRedlineTable& rTable = rRange.GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1393  rRange.GetDoc()->getIDocumentRedlineAccess().GetRedline( *pStt, &n );
1394  for ( ; n < rTable.size(); ++n )
1395  {
1396  SwRangeRedline* pRedl = rTable[n];
1397 
1398  const SwComparePosition eCmpPos =
1399  ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() );
1400  if ( eCmpPos != SwComparePosition::Before
1401  && eCmpPos != SwComparePosition::Behind
1402  && eCmpPos != SwComparePosition::CollideEnd
1403  && eCmpPos != SwComparePosition::CollideStart )
1404  {
1405 
1406  rSData.push_back(std::unique_ptr<SwRedlineSaveData, o3tl::default_delete<SwRedlineSaveData>>(new SwRedlineSaveData(eCmpPos, *pStt, *pEnd, *pRedl, bCopyNext)));
1407  }
1408  }
1409  if( !rSData.empty() && bDelRange )
1410  {
1411  rRange.GetDoc()->getIDocumentRedlineAccess().DeleteRedline( rRange, false, USHRT_MAX );
1412  }
1413  return !rSData.empty();
1414 }
1415 
1417  const SwPaM& rRange,
1418  SwRedlineSaveDatas& rSData )
1419 {
1420  rSData.clear();
1421 
1422  const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
1423  const SwRedlineTable& rTable = rRange.GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
1425  rRange.GetDoc()->getIDocumentRedlineAccess().GetRedline( *pStt, &n );
1426  for ( ; n < rTable.size(); ++n )
1427  {
1428  SwRangeRedline* pRedl = rTable[n];
1429  if ( nsRedlineType_t::REDLINE_FORMAT == pRedl->GetType() )
1430  {
1431  const SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() );
1432  if ( eCmpPos != SwComparePosition::Before
1433  && eCmpPos != SwComparePosition::Behind
1434  && eCmpPos != SwComparePosition::CollideEnd
1435  && eCmpPos != SwComparePosition::CollideStart )
1436  {
1437  rSData.push_back(std::unique_ptr<SwRedlineSaveData, o3tl::default_delete<SwRedlineSaveData>>(new SwRedlineSaveData(eCmpPos, *pStt, *pEnd, *pRedl, true)));
1438  }
1439 
1440  }
1441  }
1442  return !rSData.empty();
1443 }
1444 
1445 
1447 {
1450  SwPaM aPam( rDoc.GetNodes().GetEndOfContent() );
1451 
1452  for( size_t n = rSData.size(); n; )
1453  rSData[ --n ].RedlineToDoc( aPam );
1454 
1455 #if OSL_DEBUG_LEVEL > 0
1456  // check redline count against count saved in RedlineSaveData object
1457  assert(rSData.empty() ||
1458  (rSData[0].nRedlineCount == rDoc.getIDocumentRedlineAccess().GetRedlineTable().size()));
1459  // "redline count not restored properly"
1460 #endif
1461 
1463 }
1464 
1466 {
1467  for( size_t n = rSData.size(); n; )
1468  if( rSData[ --n ].GetMvSttIdx() )
1469  return true;
1470  return false;
1471 }
1472 
1474  const SwRedlineSaveDatas& rCheck, bool bCurrIsEnd )
1475 {
1476  if( rCurr.size() != rCheck.size() )
1477  return false;
1478 
1479  for( size_t n = 0; n < rCurr.size(); ++n )
1480  {
1481  const SwRedlineSaveData& rSet = rCurr[ n ];
1482  const SwRedlineSaveData& rGet = rCheck[ n ];
1483  if( rSet.nSttNode != rGet.nSttNode ||
1484  rSet.GetMvSttIdx() || rGet.GetMvSttIdx() ||
1485  ( bCurrIsEnd ? rSet.nSttContent != rGet.nEndContent
1486  : rSet.nEndContent != rGet.nSttContent ) ||
1487  !rGet.CanCombine( rSet ) )
1488  {
1489  return false;
1490  }
1491  }
1492 
1493  for( size_t n = 0; n < rCurr.size(); ++n )
1494  {
1495  SwRedlineSaveData& rSet = rCurr[ n ];
1496  const SwRedlineSaveData& rGet = rCheck[ n ];
1497  if( bCurrIsEnd )
1498  rSet.nSttContent = rGet.nSttContent;
1499  else
1500  rSet.nEndContent = rGet.nEndContent;
1501  }
1502  return true;
1503 }
1504 
1505 OUString ShortenString(const OUString & rStr, sal_Int32 nLength, const OUString & rFillStr)
1506 {
1507  assert(nLength - rFillStr.getLength() >= 2);
1508 
1509  if (rStr.getLength() <= nLength)
1510  return rStr;
1511 
1512  nLength -= rFillStr.getLength();
1513  if ( nLength < 2 )
1514  nLength = 2;
1515 
1516  const sal_Int32 nFrontLen = nLength - nLength / 2;
1517  const sal_Int32 nBackLen = nLength - nFrontLen;
1518 
1519  return rStr.copy(0, nFrontLen)
1520  + rFillStr
1521  + rStr.copy(rStr.getLength() - nBackLen);
1522 }
1523 
1525  SwPosition const & rStart, SwPosition const & rEnd,
1526  DelContentType const nDelContentType)
1527 {
1528  // Here we identified the objects to destroy:
1529  // - anchored between start and end of the selection
1530  // - anchored in start of the selection with "CheckNoContent"
1531  // - anchored in start of sel. and the selection start at pos 0
1532  return (rAnchorPos.nNode < rEnd.nNode)
1533  && ( (DelContentType::CheckNoCntnt & nDelContentType)
1534  || (rStart.nNode < rAnchorPos.nNode)
1535  || !rStart.nContent.GetIndex()
1536  );
1537 }
1538 
1539 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:682
Starts a section of nodes in the document model.
Definition: node.hxx:303
sal_Int32 & GetStart()
start position
Definition: txatbase.hxx:77
SwPaM & AddUndoRedoPaM(::sw::UndoRedoContext &, bool const bCorrToContent=false) const
Definition: undobj.cxx:106
virtual sal_Int32 Len() const
Definition: node.cxx:1183
void DeleteMark()
Definition: pam.hxx:177
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:903
std::unique_ptr< SwHistory > pHistory
Definition: undobj.hxx:154
Marks a position in the document model.
Definition: pam.hxx:35
const RedlineType_t REDLINE_FORMAT
sal_Int32 nSttContent
Definition: undobj.hxx:217
SwNodes const & GetUndoNodes() const
Definition: docundo.cxx:74
void SetContentIdx(const SwNodeIndex *)
Definition: docredln.cxx:1705
SwComparePosition ComparePosition(const T &rStt1, const T &rEnd1, const T &rStt2, const T &rEnd2)
Definition: pam.hxx:77
SwUndoId
Definition: swundo.hxx:29
SwDocShell * GetDocShell()
Definition: doc.hxx:1340
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:1126
virtual void SetRedlineFlags_intern(RedlineFlags eMode)=0
Set a new redline mode.
static bool FillSaveDataForFormat(const SwPaM &, SwRedlineSaveDatas &)
Definition: undobj.cxx:1416
SwNodeIndex nNode
Definition: pam.hxx:37
virtual void Repeat(SfxRepeatTarget &) override
Definition: undobj.cxx:241
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:322
const SwPosition * GetMark() const
Definition: pam.hxx:209
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
std::unique_ptr< SwRedlineSaveDatas > pRedlSaveData
Definition: undobj.hxx:190
SwRedlineSaveData(SwComparePosition eCmpPos, const SwPosition &rSttPos, const SwPosition &rEndPos, SwRangeRedline &rRedl, bool bCopyNext)
Definition: undobj.cxx:1294
bool bCacheComment
Definition: undobj.hxx:59
SwNode & GetNode() const
Definition: ndindex.hxx:118
UndoRedoRedlineGuard(::sw::UndoRedoContext const &rContext, SwUndo const &rUndo)
Definition: undobj.cxx:193
const SwHistory * GetHistory() const
Definition: undobj.hxx:207
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1348
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
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:1524
virtual bool DeleteRedline(const SwPaM &rPam, bool bSaveInUndo, sal_uInt16 nDelType)=0
virtual void RepeatImpl(::sw::RepeatContext &)
Definition: undobj.cxx:261
SwUndoId GetId() const
Definition: undobj.hxx:99
bool CanCombine(const SwRedlineData &rCmp) const
Definition: docredln.cxx:973
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:738
IShellCursorSupplier & GetCursorSupplier()
Definition: UndoCore.hxx:96
sal_uLong nEndNode
Definition: undobj.hxx:216
SwUndRng()
Definition: undobj.cxx:46
size_type size() const
Definition: docary.hxx:370
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:3060
Pos1 end touches at Pos2 start.
void Delete(const SwNodeIndex &rPos, sal_uLong nNodes=1)
delete nodes
Definition: nodes.cxx:1063
SwNodeIndex * GetMvSttIdx() const
Definition: UndoCore.hxx:57
SwIndex nContent
Definition: pam.hxx:38
SwNodeIndex aStart
Definition: ndindex.hxx:131
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
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:1473
bool empty() const
Definition: docary.hxx:223
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:117
Specific frame formats (frames, DrawObjects).
Definition: docary.hxx:200
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:164
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:821
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:483
SwTextFootnote * SeekEntry(const SwNodeIndex &rIdx, size_t *pPos=nullptr) const
Definition: ftnidx.cxx:409
RedlineType_t GetType(sal_uInt16 nPos=0) const
Definition: redline.hxx:225
Style of a layout element.
Definition: frmfmt.hxx:57
::sw::UndoManager & GetUndoManager()
Definition: doc.cxx:165
static bool HasHiddenRedlines(const SwRedlineSaveDatas &rSData)
Definition: undobj.cxx:1465
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
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:846
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:1505
static void SetSaveData(SwDoc &rDoc, SwRedlineSaveDatas &rSData)
Definition: undobj.cxx:1446
void Exchange()
Definition: pam.cxx:471
MetadataImporterPluginType * result
SwContentNode * GetContentNode()
Definition: node.hxx:615
vector_type::size_type size_type
Definition: docary.hxx:331
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
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:241
boost::optional< OUString > maComment
Definition: undobj.hxx:60
sal_uLong nSttNode
Definition: undobj.hxx:216
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:693
static bool MovePtBackward(SwPaM &rPam)
Definition: undobj.cxx:808
OUString SwResId(const char *pId)
Definition: swmodule.cxx:191
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:189
sal_Int32 nEndContent
Definition: undobj.hxx:217
const SwPosition * Start() const
Definition: pam.hxx:212
void RedlineToDoc(SwPaM const &rPam)
Definition: undobj.cxx:1350
IDocumentRedlineAccess & m_rRedlineAccess
Definition: undobj.cxx:209
virtual const SwRangeRedline * GetRedline(const SwPosition &rPos, SwRedlineTable::size_type *pFndPos) const =0
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:460
const OUString & GetComment(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1784
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:2669
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
void RestoreSection(SwDoc *pDoc, SwNodeIndex *pIdx, sal_uInt16 nSectType)
Definition: undobj.cxx:1253
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:367
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:131
virtual sal_Int32 getAllMarksCount() const =0
returns the number of marks.
ViewShellId const m_nViewShellId
Definition: undobj.hxx:55
void CorrAbs(const SwNodeIndex &rOldNode, const SwPosition &rNewPos, const sal_Int32 nOffset=0, bool bMoveCursor=false)
Definition: doccorr.cxx:168
Pos1 overlaps Pos2 at the end.
virtual ~SwUndo() override
Definition: undobj.cxx:186
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:259
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:403
SwUndo(SwUndoId const nId, const SwDoc *pDoc)
Definition: undobj.cxx:159
const SwPosition * End() const
Definition: pam.hxx:217
SwNodeIndex aEnd
Definition: ndindex.hxx:132
bool m_isRepeatIgnored
for multi-selection, only repeat 1st selection
Definition: undobj.hxx:56
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:108
virtual std::shared_ptr< ILazyDeleter > deleteMark(const IDocumentMarkAccess::const_iterator_t &ppMark)=0
Deletes a mark.
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:628
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
size_t size() const
Definition: docary.hxx:224
sal_uLong nMvLen
Definition: undobj.hxx:191
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:457
Pos1 behind Pos2.
static bool FillSaveData(const SwPaM &rRange, SwRedlineSaveDatas &rSData, bool bDelRange=true, bool bCopyNext=true)
Definition: undobj.cxx:1381
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
sal_uLong nStartPos
Definition: undobj.hxx:192
void SaveSection(const SwNodeIndex &rSttIdx)
Definition: undobj.cxx:1201
SwNodeIndex * GetContentIdx() const
Definition: redline.hxx:202
bool IsDelBox() const
Definition: undobj.cxx:180
const sal_Int32 COMPLETE_STRING
Definition: swtypes.hxx:61
Pos1 overlaps Pos2 at the beginning.
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:1486
bool MoveNodes(const SwNodeRange &, SwNodes &rNodes, const SwNodeIndex &, bool bNewFrames=true)
move the node pointer
Definition: nodes.cxx:396
static SwStartNode * MakeEmptySection(const SwNodeIndex &rIdx, SwStartNodeType=SwNormalStartNode)
Create an empty section of Start- and EndNote.
Definition: nodes.cxx:1892
Base class of the Writer document model elements.
Definition: node.hxx:79
void MoveRange(SwPaM &, SwPosition &, SwNodes &rNodes)
move a range
Definition: nodes.cxx:1439
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo