LibreOffice Module sw (master)  1
undel.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 <UndoDelete.hxx>
21 #include <hintids.hxx>
22 #include <unotools/charclass.hxx>
23 #include <frmfmt.hxx>
24 #include <fmtanchr.hxx>
25 #include <doc.hxx>
26 #include <UndoManager.hxx>
29 #include <swtable.hxx>
30 #include <swundo.hxx>
31 #include <pam.hxx>
32 #include <ndtxt.hxx>
33 #include <UndoCore.hxx>
34 #include <rolbck.hxx>
35 #include <poolfmt.hxx>
36 #include <mvsave.hxx>
37 #include <docary.hxx>
38 #include <frmtool.hxx>
39 #include <txtfrm.hxx>
40 #include <rootfrm.hxx>
41 #include <strings.hrc>
42 #include <vector>
43 
44 // DELETE
45 /* lcl_MakeAutoFrames has to call MakeFrames for objects bounded "AtChar"
46  ( == AUTO ), if the anchor frame has be moved via MoveNodes(..) and
47  DelFrames(..)
48 */
49 static void lcl_MakeAutoFrames( const SwFrameFormats& rSpzArr, sal_uLong nMovedIndex )
50 {
51  for( size_t n = 0; n < rSpzArr.size(); ++n )
52  {
53  SwFrameFormat * pFormat = rSpzArr[n];
54  const SwFormatAnchor* pAnchor = &pFormat->GetAnchor();
55  if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_CHAR)
56  {
57  const SwPosition* pAPos = pAnchor->GetContentAnchor();
58  if( pAPos && nMovedIndex == pAPos->nNode.GetIndex() )
59  pFormat->MakeFrames();
60  }
61  }
62 }
63 
64 static SwTextNode * FindFirstAndNextNode(SwDoc & rDoc, SwUndRng const& rRange,
65  SwRedlineSaveDatas const& rRedlineSaveData,
66  SwTextNode *& o_rpFirstMergedDeletedTextNode)
67 {
68  // redlines are corrected now to exclude the deleted node
69  assert(rRange.m_nEndContent == 0);
70  sal_uLong nEndOfRedline = 0;
71  for (size_t i = 0; i < rRedlineSaveData.size(); ++i)
72  {
73  auto const& rRedline(rRedlineSaveData[i]);
74  if (rRedline.m_nSttNode <= rRange.m_nSttNode
75  && rRedline.m_nSttNode < rRange.m_nEndNode
76  && rRange.m_nEndNode <= rRedline.m_nEndNode
77  && rRedline.GetType() == RedlineType::Delete)
78  {
79  nEndOfRedline = rRedline.m_nEndNode;
80  o_rpFirstMergedDeletedTextNode = rDoc.GetNodes()[rRedline.m_nSttNode]->GetTextNode();
81  assert(rRange.m_nSttNode == rRange.m_nEndNode - 1); // otherwise this needs to iterate more RL to find the first node?
82  break;
83  }
84  }
85  if (nEndOfRedline)
86  {
87  assert(o_rpFirstMergedDeletedTextNode);
88  SwTextNode * pNextNode(nullptr);
89  for (sal_uLong i = rRange.m_nEndNode; /* i <= nEndOfRedline */; ++i)
90  {
91  SwNode *const pNode(rDoc.GetNodes()[i]);
92  assert(!pNode->IsEndNode()); // cannot be both leaving section here *and* overlapping redline
93  if (pNode->IsStartNode())
94  {
95  i = pNode->EndOfSectionIndex(); // will be incremented again
96  }
97  else if (pNode->IsTextNode())
98  {
99  pNextNode = pNode->GetTextNode();
100  break;
101  }
102  }
103  assert(pNextNode);
104  return pNextNode;
105  }
106  else
107  {
108  return nullptr;
109  }
110 }
111 
112 static void DelFullParaMoveFrames(SwDoc & rDoc, SwUndRng const& rRange,
113  SwRedlineSaveDatas const& rRedlineSaveData)
114 {
115  SwTextNode * pFirstMergedDeletedTextNode(nullptr);
116  SwTextNode *const pNextNode = FindFirstAndNextNode(rDoc, rRange,
117  rRedlineSaveData, pFirstMergedDeletedTextNode);
118  if (pNextNode)
119  {
120  std::vector<SwTextFrame*> frames;
121  SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pFirstMergedDeletedTextNode);
122  for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
123  {
124  if (pFrame->getRootFrame()->IsHideRedlines())
125  {
126  assert(pFrame->GetMergedPara());
127  assert(pFrame->GetMergedPara()->pFirstNode == pFirstMergedDeletedTextNode);
128  assert(pNextNode->GetIndex() <= pFrame->GetMergedPara()->pLastNode->GetIndex());
129  frames.push_back(pFrame);
130  }
131  }
132  for (SwTextFrame *const pFrame : frames)
133  {
134  // sw_redlinehide: don't need FrameMode::Existing here
135  // because everything from pNextNode onwards is already
136  // correctly hidden
137  pFrame->RegisterToNode(*pNextNode, true);
138  }
139  }
140 }
141 
142 // SwUndoDelete has to perform a deletion and to record anything that is needed
143 // to restore the situation before the deletion. Unfortunately a part of the
144 // deletion will be done after calling this Ctor, this has to be kept in mind!
145 // In this Ctor only the complete paragraphs will be deleted, the joining of
146 // the first and last paragraph of the selection will be handled outside this
147 // function.
148 // Here are the main steps of the function:
149 // 1. Deletion/recording of content indices of the selection: footnotes, fly
150 // frames and bookmarks
151 // Step 1 could shift all nodes by deletion of footnotes => nNdDiff will be set.
152 // 2. If the paragraph where the selection ends, is the last content of a
153 // section so that this section becomes empty when the paragraphs will be
154 // joined we have to do some smart actions ;-) The paragraph will be moved
155 // outside the section and replaced by a dummy text node, the complete
156 // section will be deleted in step 3. The difference between replacement
157 // dummy and original is nReplacementDummy.
158 // 3. Moving complete selected nodes into the UndoArray. Before this happens the
159 // selection has to be extended if there are sections which would become
160 // empty otherwise. BTW: sections will be moved into the UndoArray if they
161 // are complete part of the selection. Sections starting or ending outside
162 // of the selection will not be removed from the DocNodeArray even they got
163 // a "dummy"-copy in the UndoArray.
164 // 4. We have to anticipate the joining of the two paragraphs if the start
165 // paragraph is inside a section and the end paragraph not. Then we have to
166 // move the paragraph into this section and to record this in nSectDiff.
168  SwPaM& rPam,
169  bool bFullPara,
170  bool bCalledByTableCpy )
171  : SwUndo(SwUndoId::DELETE, rPam.GetDoc()),
172  SwUndRng( rPam ),
173  m_nNode(0),
174  m_nNdDiff(0),
175  m_nSectDiff(0),
176  m_nReplaceDummy(0),
177  m_nSetPos(0),
178  m_bGroup( false ),
179  m_bBackSp( false ),
180  m_bJoinNext( false ),
181  m_bTableDelLastNd( false ),
182  // bFullPara is set e.g. if an empty paragraph before a table is deleted
183  m_bDelFullPara( bFullPara ),
184  m_bResetPgDesc( false ),
185  m_bResetPgBrk( false ),
186  m_bFromTableCopy( bCalledByTableCpy )
187 {
188 
189  m_bCacheComment = false;
190 
191  SwDoc * pDoc = rPam.GetDoc();
192 
194  {
196  if( !FillSaveData( rPam, *m_pRedlSaveData ))
197  {
198  m_pRedlSaveData.reset();
199  }
200  }
201 
202  if( !m_pHistory )
203  m_pHistory.reset( new SwHistory );
204 
205  // delete all footnotes for now
206  const SwPosition *pStt = rPam.Start(),
207  *pEnd = rPam.GetPoint() == pStt
208  ? rPam.GetMark()
209  : rPam.GetPoint();
210 
211  // Step 1. deletion/record of content indices
212  if( m_bDelFullPara )
213  {
214  OSL_ENSURE( rPam.HasMark(), "PaM without Mark" );
215  DelContentIndex( *rPam.GetMark(), *rPam.GetPoint(),
217 
218  ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
219  DelBookmarks(pStt->nNode, pEnd->nNode);
220  }
221  else
222  {
223  DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
224  ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
225  if (m_nEndNode - m_nSttNode > 1) // check for fully selected nodes
226  {
227  SwNodeIndex const start(pStt->nNode, +1);
228  DelBookmarks(start, pEnd->nNode);
229  }
230  }
231 
232  m_nSetPos = m_pHistory ? m_pHistory->Count() : 0;
233 
234  // Is already anything deleted?
235  m_nNdDiff = m_nSttNode - pStt->nNode.GetIndex();
236 
237  m_bJoinNext = !bFullPara && pEnd == rPam.GetPoint();
238  m_bBackSp = !bFullPara && !m_bJoinNext;
239 
240  SwTextNode *pSttTextNd = nullptr, *pEndTextNd = nullptr;
241  if( !bFullPara )
242  {
243  pSttTextNd = pStt->nNode.GetNode().GetTextNode();
244  pEndTextNd = m_nSttNode == m_nEndNode
245  ? pSttTextNd
246  : pEnd->nNode.GetNode().GetTextNode();
247  }
248  else if (m_pRedlSaveData)
249  {
250  DelFullParaMoveFrames(*pDoc, *this, *m_pRedlSaveData);
251  }
252 
253  bool bMoveNds = *pStt != *pEnd // any area still existent?
254  && ( SaveContent( pStt, pEnd, pSttTextNd, pEndTextNd ) || m_bFromTableCopy );
255 
256  if( pSttTextNd && pEndTextNd && pSttTextNd != pEndTextNd )
257  {
258  // two different TextNodes, thus save also the TextFormatCollection
259  m_pHistory->Add( pSttTextNd->GetTextColl(),pStt->nNode.GetIndex(), SwNodeType::Text );
260  m_pHistory->Add( pEndTextNd->GetTextColl(),pEnd->nNode.GetIndex(), SwNodeType::Text );
261 
262  if( !m_bJoinNext ) // Selection from bottom to top
263  {
264  // When using JoinPrev() all AUTO-PageBreak's will be copied
265  // correctly. To restore them with UNDO, Auto-PageBreak of the
266  // EndNode needs to be reset. Same for PageDesc and ColBreak.
267  if( pEndTextNd->HasSwAttrSet() )
268  {
269  SwRegHistory aRegHist( *pEndTextNd, m_pHistory.get() );
270  if( SfxItemState::SET == pEndTextNd->GetpSwAttrSet()->GetItemState(
271  RES_BREAK, false ) )
272  pEndTextNd->ResetAttr( RES_BREAK );
273  if( pEndTextNd->HasSwAttrSet() &&
274  SfxItemState::SET == pEndTextNd->GetpSwAttrSet()->GetItemState(
275  RES_PAGEDESC, false ) )
276  pEndTextNd->ResetAttr( RES_PAGEDESC );
277  }
278  }
279  }
280 
281  // Move now also the PaM. The SPoint is at the beginning of a SSelection.
282  if( pEnd == rPam.GetPoint() && ( !bFullPara || pSttTextNd || pEndTextNd ) )
283  rPam.Exchange();
284 
285  if( !pSttTextNd && !pEndTextNd )
286  --rPam.GetPoint()->nNode;
287  rPam.DeleteMark(); // the SPoint is in the selection
288 
289  if( !pEndTextNd )
290  m_nEndContent = 0;
291  if( !pSttTextNd )
292  m_nSttContent = 0;
293 
294  if( bMoveNds ) // Do Nodes exist that need to be moved?
295  {
296  SwNodes& rNds = pDoc->GetUndoManager().GetUndoNodes();
297  SwNodes& rDocNds = pDoc->GetNodes();
298  SwNodeRange aRg( rDocNds, m_nSttNode - m_nNdDiff,
299  rDocNds, m_nEndNode - m_nNdDiff );
300  if( !bFullPara && !pEndTextNd &&
301  &aRg.aEnd.GetNode() != &pDoc->GetNodes().GetEndOfContent() )
302  {
303  SwNode* pNode = aRg.aEnd.GetNode().StartOfSectionNode();
304  if( pNode->GetIndex() >= m_nSttNode - m_nNdDiff )
305  ++aRg.aEnd; // Deletion of a complete table
306  }
307  SwNode* pTmpNd;
308  // Step 2: Expand selection if necessary
309  if( m_bJoinNext || bFullPara )
310  {
311  // If all content of a section will be moved into Undo, the section
312  // itself should be moved completely.
313  while( aRg.aEnd.GetIndex() + 2 < rDocNds.Count() &&
314  ( (pTmpNd = rDocNds[ aRg.aEnd.GetIndex()+1 ])->IsEndNode() &&
315  pTmpNd->StartOfSectionNode()->IsSectionNode() &&
316  pTmpNd->StartOfSectionNode()->GetIndex() >= aRg.aStart.GetIndex() ) )
317  ++aRg.aEnd;
319  if( m_nReplaceDummy )
320  { // The selection has been expanded, because
321  ++aRg.aEnd;
322  if( pEndTextNd )
323  {
324  // The end text node has to leave the (expanded) selection
325  // The dummy is needed because MoveNodes deletes empty
326  // sections
327  ++m_nReplaceDummy;
328  SwNodeRange aMvRg( *pEndTextNd, 0, *pEndTextNd, 1 );
329  SwPosition aSplitPos( *pEndTextNd );
330  ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
331  pDoc->getIDocumentContentOperations().SplitNode( aSplitPos, false );
332  rDocNds.MoveNodes( aMvRg, rDocNds, aRg.aEnd );
333  --aRg.aEnd;
334  }
335  else
336  m_nReplaceDummy = 0;
337  }
338  }
339  if( m_bBackSp || bFullPara )
340  {
341  // See above, the selection has to be expanded if there are "nearly
342  // empty" sections and a replacement dummy has to be set if needed.
343  while( 1 < aRg.aStart.GetIndex() &&
344  ( (pTmpNd = rDocNds[ aRg.aStart.GetIndex()-1 ])->IsSectionNode() &&
345  pTmpNd->EndOfSectionIndex() < aRg.aEnd.GetIndex() ) )
346  --aRg.aStart;
347  if( pSttTextNd )
348  {
350  if( m_nReplaceDummy )
351  {
352  SwNodeRange aMvRg( *pSttTextNd, 0, *pSttTextNd, 1 );
353  SwPosition aSplitPos( *pSttTextNd );
354  ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
355  pDoc->getIDocumentContentOperations().SplitNode( aSplitPos, false );
356  rDocNds.MoveNodes( aMvRg, rDocNds, aRg.aStart );
357  --aRg.aStart;
358  }
359  }
360  }
361 
362  if( m_bFromTableCopy )
363  {
364  if( !pEndTextNd )
365  {
366  if( pSttTextNd )
367  ++aRg.aStart;
368  else if( !bFullPara && !aRg.aEnd.GetNode().IsContentNode() )
369  --aRg.aEnd;
370  }
371  }
372  else if (pSttTextNd && (pEndTextNd || pSttTextNd->GetText().getLength()))
373  ++aRg.aStart;
374 
375  // Step 3: Moving into UndoArray...
376  m_nNode = rNds.GetEndOfContent().GetIndex();
377  rDocNds.MoveNodes( aRg, rNds, SwNodeIndex( rNds.GetEndOfContent() ));
378  m_pMvStt.reset( new SwNodeIndex( rNds, m_nNode ) );
379  // remember difference!
381 
382  if( pSttTextNd && pEndTextNd )
383  {
384  //Step 4: Moving around sections
385  m_nSectDiff = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
386  // nSect is the number of sections which starts(ends) between start
387  // and end node of the selection. The "loser" paragraph has to be
388  // moved into the section(s) of the "winner" paragraph
389  if( m_nSectDiff )
390  {
391  if( m_bJoinNext )
392  {
393  SwNodeRange aMvRg( *pEndTextNd, 0, *pEndTextNd, 1 );
394  rDocNds.MoveNodes( aMvRg, rDocNds, aRg.aStart );
395  }
396  else
397  {
398  SwNodeRange aMvRg( *pSttTextNd, 0, *pSttTextNd, 1 );
399  rDocNds.MoveNodes( aMvRg, rDocNds, aRg.aEnd );
400  }
401  }
402  }
405  m_bJoinNext ? pEndTextNd->GetIndex() : pSttTextNd->GetIndex() );
406  }
407  else
408  m_nNode = 0; // moved no node -> no difference at the end
409 
410  // Are there any Nodes that got deleted before that (FootNotes
411  // have ContentNodes)?
412  if( !pSttTextNd && !pEndTextNd )
413  {
414  m_nNdDiff = m_nSttNode - rPam.GetPoint()->nNode.GetIndex() - (bFullPara ? 0 : 1);
415  rPam.Move( fnMoveForward, GoInNode );
416  }
417  else
418  {
420  if( m_nSectDiff && m_bBackSp )
422  m_nNdDiff -= rPam.GetPoint()->nNode.GetIndex();
423  }
424 
425  if( !rPam.GetNode().IsContentNode() )
426  rPam.GetPoint()->nContent.Assign( nullptr, 0 );
427 
428  // is a history necessary here at all?
429  if( m_pHistory && !m_pHistory->Count() )
430  m_pHistory.reset();
431 }
432 
433 bool SwUndoDelete::SaveContent( const SwPosition* pStt, const SwPosition* pEnd,
434  SwTextNode* pSttTextNd, SwTextNode* pEndTextNd )
435 {
436  sal_uLong nNdIdx = pStt->nNode.GetIndex();
437  // 1 - copy start in Start-String
438  if( pSttTextNd )
439  {
440  bool bOneNode = m_nSttNode == m_nEndNode;
441  SwRegHistory aRHst( *pSttTextNd, m_pHistory.get() );
442  // always save all text atttibutes because of possibly overlapping
443  // areas of on/off
444  m_pHistory->CopyAttr( pSttTextNd->GetpSwpHints(), nNdIdx,
445  0, pSttTextNd->GetText().getLength(), true );
446  if( !bOneNode && pSttTextNd->HasSwAttrSet() )
447  m_pHistory->CopyFormatAttr( *pSttTextNd->GetpSwAttrSet(), nNdIdx );
448 
449  // the length might have changed (!!Fields!!)
450  sal_Int32 nLen = (bOneNode
451  ? pEnd->nContent.GetIndex()
452  : pSttTextNd->GetText().getLength())
453  - pStt->nContent.GetIndex();
454 
455  // delete now also the text (all attribute changes are added to
456  // UNDO history)
457  m_aSttStr = pSttTextNd->GetText().copy(m_nSttContent, nLen);
458  pSttTextNd->EraseText( pStt->nContent, nLen );
459  if( pSttTextNd->GetpSwpHints() )
460  pSttTextNd->GetpSwpHints()->DeRegister();
461 
462  // METADATA: store
463  bool emptied( !m_aSttStr->isEmpty() && !pSttTextNd->Len() );
464  if (!bOneNode || emptied) // merging may overwrite xmlids...
465  {
466  m_pMetadataUndoStart = emptied
467  ? pSttTextNd->CreateUndoForDelete()
468  : pSttTextNd->CreateUndo();
469  }
470 
471  if( bOneNode )
472  return false; // stop moving more nodes
473  }
474 
475  // 2 - copy end into End-String
476  if( pEndTextNd )
477  {
478  SwIndex aEndIdx( pEndTextNd );
479  nNdIdx = pEnd->nNode.GetIndex();
480  SwRegHistory aRHst( *pEndTextNd, m_pHistory.get() );
481 
482  // always save all text atttibutes because of possibly overlapping
483  // areas of on/off
484  m_pHistory->CopyAttr( pEndTextNd->GetpSwpHints(), nNdIdx, 0,
485  pEndTextNd->GetText().getLength(), true );
486 
487  if( pEndTextNd->HasSwAttrSet() )
488  m_pHistory->CopyFormatAttr( *pEndTextNd->GetpSwAttrSet(), nNdIdx );
489 
490  // delete now also the text (all attribute changes are added to
491  // UNDO history)
492  m_aEndStr = pEndTextNd->GetText().copy( 0, pEnd->nContent.GetIndex() );
493  pEndTextNd->EraseText( aEndIdx, pEnd->nContent.GetIndex() );
494  if( pEndTextNd->GetpSwpHints() )
495  pEndTextNd->GetpSwpHints()->DeRegister();
496 
497  // METADATA: store
498  bool emptied = !m_aEndStr->isEmpty() && !pEndTextNd->Len();
499 
500  m_pMetadataUndoEnd = emptied
501  ? pEndTextNd->CreateUndoForDelete()
502  : pEndTextNd->CreateUndo();
503  }
504 
505  // if there are only two Nodes then we're done
506  if( ( pSttTextNd || pEndTextNd ) && m_nSttNode + 1 == m_nEndNode )
507  return false; // do not move any Node
508 
509  return true; // move Nodes lying in between
510 }
511 
512 bool SwUndoDelete::CanGrouping( SwDoc* pDoc, const SwPaM& rDelPam )
513 {
514  // Is Undo greater than one Node (that is Start and EndString)?
515  if( !m_aSttStr || m_aSttStr->isEmpty() || m_aEndStr )
516  return false;
517 
518  // only the deletion of single char's can be condensed
520  return false;
521 
522  const SwPosition *pStt = rDelPam.Start(),
523  *pEnd = rDelPam.GetPoint() == pStt
524  ? rDelPam.GetMark()
525  : rDelPam.GetPoint();
526 
527  if( pStt->nNode != pEnd->nNode ||
528  pStt->nContent.GetIndex()+1 != pEnd->nContent.GetIndex() ||
529  pEnd->nNode != m_nSttNode )
530  return false;
531 
532  // Distinguish between BackSpace and Delete because the Undo array needs to
533  // be constructed differently!
534  if( pEnd->nContent == m_nSttContent )
535  {
536  if( m_bGroup && !m_bBackSp ) return false;
537  m_bBackSp = true;
538  }
539  else if( pStt->nContent == m_nSttContent )
540  {
541  if( m_bGroup && m_bBackSp ) return false;
542  m_bBackSp = false;
543  }
544  else
545  return false;
546 
547  // are both Nodes (Node/Undo array) TextNodes at all?
548  SwTextNode * pDelTextNd = pStt->nNode.GetNode().GetTextNode();
549  if( !pDelTextNd ) return false;
550 
551  sal_Int32 nUChrPos = m_bBackSp ? 0 : m_aSttStr->getLength()-1;
552  sal_Unicode cDelChar = pDelTextNd->GetText()[ pStt->nContent.GetIndex() ];
553  CharClass& rCC = GetAppCharClass();
554  if( ( CH_TXTATR_BREAKWORD == cDelChar || CH_TXTATR_INWORD == cDelChar ) ||
555  rCC.isLetterNumeric( OUString( cDelChar ), 0 ) !=
556  rCC.isLetterNumeric( *m_aSttStr, nUChrPos ) )
557  return false;
558 
559  {
560  SwRedlineSaveDatas aTmpSav;
561  const bool bSaved = FillSaveData( rDelPam, aTmpSav, false );
562 
563  bool bOk = ( !m_pRedlSaveData && !bSaved ) ||
564  ( m_pRedlSaveData && bSaved &&
566  // aTmpSav.DeleteAndDestroyAll();
567  if( !bOk )
568  return false;
569 
570  pDoc->getIDocumentRedlineAccess().DeleteRedline( rDelPam, false, RedlineType::Any );
571  }
572 
573  // Both 'deletes' can be consolidated, so 'move' the related character
574  if( m_bBackSp )
575  m_nSttContent--; // BackSpace: add char to array!
576  else
577  {
578  m_nEndContent++; // Delete: attach char at the end
579  nUChrPos++;
580  }
581  m_aSttStr = m_aSttStr->replaceAt( nUChrPos, 0, OUString(cDelChar) );
582  pDelTextNd->EraseText( pStt->nContent, 1 );
583 
584  m_bGroup = true;
585  return true;
586 }
587 
589 {
590  if( m_pMvStt ) // Delete also the selection from UndoNodes array
591  {
592  // Insert saves content in IconSection
593  m_pMvStt->GetNode().GetNodes().Delete( *m_pMvStt, m_nNode );
594  m_pMvStt.reset();
595  }
596  m_pRedlSaveData.reset();
597 }
598 
600 {
601  SwRewriter aRewriter;
602 
603  bool bDone = false;
604 
605  for ( sal_uInt16 n = 0; n < rHistory.Count(); n++)
606  {
607  OUString aDescr = rHistory[n]->GetDescription();
608 
609  if (!aDescr.isEmpty())
610  {
611  aRewriter.AddRule(UndoArg2, aDescr);
612 
613  bDone = true;
614  break;
615  }
616  }
617 
618  if (! bDone)
619  {
620  aRewriter.AddRule(UndoArg2, SwResId(STR_FIELD));
621  }
622 
623  return aRewriter;
624 }
625 
627 {
628  switch (nChar)
629  {
630  case CH_TXTATR_BREAKWORD:
631  case CH_TXTATR_INWORD:
632  case CH_TXTATR_TAB:
633  case CH_TXTATR_NEWLINE:
638  case CH_TXT_ATR_FIELDSEP:
639  case CH_TXT_ATR_FIELDEND:
640  return true;
641 
642  default:
643  break;
644  }
645 
646  return false;
647 }
648 
649 static OUString lcl_DenotedPortion(const OUString& rStr, sal_Int32 nStart, sal_Int32 nEnd)
650 {
651  OUString aResult;
652 
653  auto nCount = nEnd - nStart;
654  if (nCount > 0)
655  {
656  sal_Unicode cLast = rStr[nEnd - 1];
657  if (lcl_IsSpecialCharacter(cLast))
658  {
659  switch(cLast)
660  {
661  case CH_TXTATR_TAB:
662  aResult = SwResId(STR_UNDO_TABS, nCount);
663 
664  break;
665  case CH_TXTATR_NEWLINE:
666  aResult = SwResId(STR_UNDO_NLS, nCount);
667 
668  break;
669 
670  case CH_TXTATR_INWORD:
671  case CH_TXTATR_BREAKWORD:
673  break;
674 
679  case CH_TXT_ATR_FIELDSEP:
680  case CH_TXT_ATR_FIELDEND:
681  break; // nothing?
682 
683  default:
684  assert(!"unexpected special character");
685  break;
686  }
687  SwRewriter aRewriter;
688  aRewriter.AddRule(UndoArg1, OUString::number(nCount));
689  aResult = aRewriter.Apply(aResult);
690  }
691  else
692  {
693  aResult = SwResId(STR_START_QUOTE) +
694  rStr.copy(nStart, nCount) +
695  SwResId(STR_END_QUOTE);
696  }
697  }
698 
699  return aResult;
700 }
701 
702 OUString DenoteSpecialCharacters(const OUString & rStr)
703 {
704  OUStringBuffer aResult;
705 
706  if (!rStr.isEmpty())
707  {
708  bool bStart = false;
709  sal_Int32 nStart = 0;
710  sal_Unicode cLast = 0;
711 
712  for( sal_Int32 i = 0; i < rStr.getLength(); i++)
713  {
714  if (lcl_IsSpecialCharacter(rStr[i]))
715  {
716  if (cLast != rStr[i])
717  bStart = true;
718 
719  }
720  else
721  {
722  if (lcl_IsSpecialCharacter(cLast))
723  bStart = true;
724  }
725 
726  if (bStart)
727  {
728  aResult.append(lcl_DenotedPortion(rStr, nStart, i));
729 
730  nStart = i;
731  bStart = false;
732  }
733 
734  cLast = rStr[i];
735  }
736 
737  aResult.append(lcl_DenotedPortion(rStr, nStart, rStr.getLength()));
738  }
739  else
741 
742  return aResult.makeStringAndClear();
743 }
744 
746 {
747  SwRewriter aResult;
748 
749  if (m_nNode != 0)
750  {
751  if (!m_sTableName.isEmpty())
752  {
753 
754  SwRewriter aRewriter;
755  aRewriter.AddRule(UndoArg1, SwResId(STR_START_QUOTE));
756  aRewriter.AddRule(UndoArg2, m_sTableName);
757  aRewriter.AddRule(UndoArg3, SwResId(STR_END_QUOTE));
758 
759  OUString sTmp = aRewriter.Apply(SwResId(STR_TABLE_NAME));
760  aResult.AddRule(UndoArg1, sTmp);
761  }
762  else
763  aResult.AddRule(UndoArg1, SwResId(STR_PARAGRAPHS));
764  }
765  else
766  {
767  OUString aStr;
768 
769  if (m_aSttStr && m_aEndStr && m_aSttStr->isEmpty() &&
770  m_aEndStr->isEmpty())
771  {
772  aStr = SwResId(STR_PARAGRAPH_UNDO);
773  }
774  else
775  {
776  o3tl::optional<OUString> aTmpStr;
777  if (m_aSttStr)
778  aTmpStr = m_aSttStr;
779  else if (m_aEndStr)
780  aTmpStr = m_aEndStr;
781 
782  if (aTmpStr)
783  {
784  aStr = DenoteSpecialCharacters(*aTmpStr);
785  }
786  else
787  {
789  }
790  }
791 
792  aStr = ShortenString(aStr, nUndoStringLength, SwResId(STR_LDOTS));
793  if (m_pHistory)
794  {
796  aStr = aRewriter.Apply(aStr);
797  }
798 
799  aResult.AddRule(UndoArg1, aStr);
800  }
801 
802  return aResult;
803 }
804 
805 // Every object, anchored "AtContent" will be reanchored at rPos
806 static void lcl_ReAnchorAtContentFlyFrames( const SwFrameFormats& rSpzArr, SwPosition &rPos, sal_uLong nOldIdx )
807 {
808  if( !rSpzArr.empty() )
809  {
810  SwFlyFrameFormat* pFormat;
811  const SwFormatAnchor* pAnchor;
812  const SwPosition* pAPos;
813  for( size_t n = 0; n < rSpzArr.size(); ++n )
814  {
815  pFormat = static_cast<SwFlyFrameFormat*>(rSpzArr[n]);
816  pAnchor = &pFormat->GetAnchor();
817  if (pAnchor->GetAnchorId() == RndStdIds::FLY_AT_PARA)
818  {
819  pAPos = pAnchor->GetContentAnchor();
820  if( pAPos && nOldIdx == pAPos->nNode.GetIndex() )
821  {
822  SwFormatAnchor aAnch( *pAnchor );
823  aAnch.SetAnchor( &rPos );
824  pFormat->SetFormatAttr( aAnch );
825  }
826  }
827  }
828  }
829 }
830 
832 {
833  SwDoc& rDoc = rContext.GetDoc();
834 
835  sal_uLong nCalcStt = m_nSttNode - m_nNdDiff;
836 
837  if( m_nSectDiff && m_bBackSp )
838  nCalcStt += m_nSectDiff;
839 
840  SwNodeIndex aIdx(rDoc.GetNodes(), nCalcStt);
841  SwNode* pInsNd = &aIdx.GetNode();
842  SwNode* pMovedNode = nullptr;
843 
844  { // code block so that SwPosition is detached when deleting a Node
845  SwPosition aPos( aIdx );
846  if( !m_bDelFullPara )
847  {
848  if( pInsNd->IsTableNode() )
849  {
850  pInsNd = rDoc.GetNodes().MakeTextNode( aIdx,
851  rDoc.GetDfltTextFormatColl() );
852  --aIdx;
853  aPos.nNode = aIdx;
854  aPos.nContent.Assign( pInsNd->GetContentNode(), m_nSttContent );
855  }
856  else
857  {
858  if( pInsNd->IsContentNode() )
859  aPos.nContent.Assign( static_cast<SwContentNode*>(pInsNd), m_nSttContent );
860  if( !m_bTableDelLastNd )
861  pInsNd = nullptr; // do not delete Node!
862  }
863  }
864  else
865  pInsNd = nullptr; // do not delete Node!
866 
867  bool bNodeMove = 0 != m_nNode;
868 
869  if( m_aEndStr )
870  {
871  // discard attributes since they all saved!
872  SwTextNode* pTextNd = aPos.nNode.GetNode().GetTextNode();
873 
874  if( pTextNd && pTextNd->HasSwAttrSet() )
875  pTextNd->ResetAllAttr();
876 
877  if( pTextNd && pTextNd->GetpSwpHints() )
878  pTextNd->ClearSwpHintsArr( true );
879 
880  if( m_aSttStr && !m_bFromTableCopy )
881  {
882  sal_uLong nOldIdx = aPos.nNode.GetIndex();
883  rDoc.getIDocumentContentOperations().SplitNode( aPos, false );
884  // After the split all objects are anchored at the first
885  // paragraph, but the pHistory of the fly frame formats relies
886  // on anchoring at the start of the selection
887  // => selection backwards needs a correction.
888  if( m_bBackSp )
889  lcl_ReAnchorAtContentFlyFrames(*rDoc.GetSpzFrameFormats(), aPos, nOldIdx);
890  pTextNd = aPos.nNode.GetNode().GetTextNode();
891  }
892  if( pTextNd )
893  {
894  OUString const ins( pTextNd->InsertText(*m_aEndStr, aPos.nContent,
896  assert(ins.getLength() == m_aEndStr->getLength()); // must succeed
897  (void) ins;
898  // METADATA: restore
900  }
901  }
902  else if (m_aSttStr && bNodeMove && pInsNd == nullptr)
903  {
904  SwTextNode * pNd = aPos.nNode.GetNode().GetTextNode();
905  if( pNd )
906  {
907  if (m_nSttContent < pNd->GetText().getLength())
908  {
909  sal_uLong nOldIdx = aPos.nNode.GetIndex();
910  rDoc.getIDocumentContentOperations().SplitNode( aPos, false );
911  if( m_bBackSp )
912  lcl_ReAnchorAtContentFlyFrames(*rDoc.GetSpzFrameFormats(), aPos, nOldIdx);
913  }
914  else
915  ++aPos.nNode;
916  }
917  }
918  if( m_nSectDiff )
919  {
920  sal_uLong nMoveIndex = aPos.nNode.GetIndex();
921  int nDiff = 0;
922  if( m_bJoinNext )
923  {
924  nMoveIndex += m_nSectDiff + 1;
925  pMovedNode = &aPos.nNode.GetNode();
926  }
927  else
928  {
929  nMoveIndex -= m_nSectDiff + 1;
930  ++nDiff;
931  }
932  SwNodeIndex aMvIdx(rDoc.GetNodes(), nMoveIndex);
933  SwNodeRange aRg( aPos.nNode, 0 - nDiff, aPos.nNode, 1 - nDiff );
934  --aPos.nNode;
935  if( !m_bJoinNext )
936  pMovedNode = &aPos.nNode.GetNode();
937  rDoc.GetNodes().MoveNodes(aRg, rDoc.GetNodes(), aMvIdx);
938  ++aPos.nNode;
939  }
940 
941  if( bNodeMove )
942  {
943  SwNodeRange aRange( *m_pMvStt, 0, *m_pMvStt, m_nNode );
944  SwNodeIndex aCopyIndex( aPos.nNode, -1 );
945  rDoc.GetUndoManager().GetUndoNodes().Copy_(aRange, aPos.nNode,
946  // sw_redlinehide: delay creating frames: the flags on the
947  // nodes aren't necessarily up-to-date, and the redlines
948  // from m_pRedlSaveData aren't applied yet...
949  false);
950 
951  if( m_nReplaceDummy )
952  {
953  sal_uLong nMoveIndex;
954  if( m_bJoinNext )
955  {
956  nMoveIndex = m_nEndNode - m_nNdDiff;
957  aPos.nNode = nMoveIndex + m_nReplaceDummy;
958  }
959  else
960  {
961  aPos = SwPosition( aCopyIndex );
962  nMoveIndex = aPos.nNode.GetIndex() + m_nReplaceDummy + 1;
963  }
964  SwNodeIndex aMvIdx(rDoc.GetNodes(), nMoveIndex);
965  SwNodeRange aRg( aPos.nNode, 0, aPos.nNode, 1 );
966  pMovedNode = &aPos.nNode.GetNode();
967  rDoc.GetNodes().MoveNodes(aRg, rDoc.GetNodes(), aMvIdx);
968  rDoc.GetNodes().Delete( aMvIdx);
969  }
970  }
971 
972  if( m_aSttStr )
973  {
974  aPos.nNode = m_nSttNode - m_nNdDiff + ( m_bJoinNext ? 0 : m_nReplaceDummy );
975  SwTextNode * pTextNd = aPos.nNode.GetNode().GetTextNode();
976  // If more than a single Node got deleted, also all "Node"
977  // attributes were saved
978  if (pTextNd != nullptr)
979  {
980  if( pTextNd->HasSwAttrSet() && bNodeMove && !m_aEndStr )
981  pTextNd->ResetAllAttr();
982 
983  if( pTextNd->GetpSwpHints() )
984  pTextNd->ClearSwpHintsArr( true );
985 
986  // SectionNode mode and selection from top to bottom:
987  // -> in StartNode is still the rest of the Join => delete
988  aPos.nContent.Assign( pTextNd, m_nSttContent );
989  OUString const ins( pTextNd->InsertText(*m_aSttStr, aPos.nContent,
991  assert(ins.getLength() == m_aSttStr->getLength()); // must succeed
992  (void) ins;
993  // METADATA: restore
994  pTextNd->RestoreMetadata(m_pMetadataUndoStart);
995  }
996  }
997 
998  if( m_pHistory )
999  {
1000  m_pHistory->TmpRollback(&rDoc, m_nSetPos, false);
1001  if( m_nSetPos ) // there were Footnodes/FlyFrames
1002  {
1003  // are there others than these ones?
1004  if( m_nSetPos < m_pHistory->Count() )
1005  {
1006  // if so save the attributes of the others
1007  SwHistory aHstr;
1008  aHstr.Move( 0, m_pHistory.get(), m_nSetPos );
1009  m_pHistory->Rollback(&rDoc);
1010  m_pHistory->Move( 0, &aHstr );
1011  }
1012  else
1013  {
1014  m_pHistory->Rollback(&rDoc);
1015  m_pHistory.reset();
1016  }
1017  }
1018  }
1019 
1020  if( m_bResetPgDesc || m_bResetPgBrk )
1021  {
1022  sal_uInt16 nStt = m_bResetPgDesc ? sal_uInt16(RES_PAGEDESC) : sal_uInt16(RES_BREAK);
1023  sal_uInt16 nEnd = m_bResetPgBrk ? sal_uInt16(RES_BREAK) : sal_uInt16(RES_PAGEDESC);
1024 
1025  SwNode* pNode = rDoc.GetNodes()[ m_nEndNode + 1 ];
1026  if( pNode->IsContentNode() )
1027  static_cast<SwContentNode*>(pNode)->ResetAttr( nStt, nEnd );
1028  else if( pNode->IsTableNode() )
1029  static_cast<SwTableNode*>(pNode)->GetTable().GetFrameFormat()->ResetFormatAttr( nStt, nEnd );
1030  }
1031  }
1032  // delete the temporarily added Node
1033  if( pInsNd )
1034  rDoc.GetNodes().Delete( aIdx );
1035  if( m_pRedlSaveData )
1036  SetSaveData(rDoc, *m_pRedlSaveData);
1037 
1038  sal_uLong delFullParaEndNode(m_nEndNode);
1040  {
1041  SwTextNode * pFirstMergedDeletedTextNode(nullptr);
1042  SwTextNode *const pNextNode = FindFirstAndNextNode(rDoc, *this,
1043  *m_pRedlSaveData, pFirstMergedDeletedTextNode);
1044  if (pNextNode)
1045  {
1046  bool bNonMerged(false);
1047  std::vector<SwTextFrame*> frames;
1049  for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
1050  {
1051  if (pFrame->getRootFrame()->IsHideRedlines())
1052  {
1053  frames.push_back(pFrame);
1054  }
1055  else
1056  {
1057  bNonMerged = true;
1058  }
1059  }
1060  for (SwTextFrame *const pFrame : frames)
1061  {
1062  // could either destroy the text frames, or move them...
1063  // destroying them would have the advantage that we don't
1064  // need special code to *exclude* pFirstMergedDeletedTextNode
1065  // from MakeFrames for the layouts in Hide mode but not
1066  // layouts in Show mode ...
1067  // ... except that MakeFrames won't create them then :(
1068  pFrame->RegisterToNode(*pFirstMergedDeletedTextNode);
1069  assert(pFrame->GetMergedPara());
1070  assert(!bNonMerged); // delFullParaEndNode is such an awful hack
1071  (void) bNonMerged;
1072  delFullParaEndNode = pFirstMergedDeletedTextNode->GetIndex();
1073  }
1074  }
1075  }
1076  else if (m_aSttStr && (!m_bFromTableCopy || 0 != m_nNode))
1077  {
1078  // only now do we have redlines in the document again; fix up the split
1079  // frames
1080  SwTextNode *const pStartNode(aIdx.GetNodes()[m_nSttNode]->GetTextNode());
1081  assert(pStartNode);
1082  std::vector<SwTextFrame*> frames;
1084  for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
1085  {
1086  if (pFrame->getRootFrame()->IsHideRedlines())
1087  {
1088  frames.push_back(pFrame);
1089  }
1090  }
1092  for (SwTextFrame * pFrame : frames)
1093  {
1094  // SplitNode could have moved the original frame to the start node
1095  // & created a new one on end, or could have created new frame on
1096  // start node... grab start node's frame and recreate MergedPara.
1097  SwTextNode & rFirstNode(pFrame->GetMergedPara()
1098  ? *pFrame->GetMergedPara()->pFirstNode
1099  : *pStartNode);
1100  assert(rFirstNode.GetIndex() <= pStartNode->GetIndex());
1101  pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
1102  *pFrame, rFirstNode, eMode));
1103  eMode = sw::FrameMode::New; // Existing is not idempotent!
1104  // note: this may or may not delete frames on the end node
1105  }
1106  }
1107 
1108  // create frames after SetSaveData has recreated redlines
1109  if (0 != m_nNode)
1110  {
1111  // tdf#121031 if the start node is a text node, it already has a frame;
1112  // if it's a table, it does not
1113  // tdf#109376 exception: end on non-text-node -> start node was inserted
1114  SwNodeIndex const start(rDoc.GetNodes(), m_nSttNode +
1115  ((m_bDelFullPara || !rDoc.GetNodes()[m_nSttNode]->IsTextNode() || pInsNd)
1116  ? 0 : 1));
1117  // don't include end node in the range: it may have been merged already
1118  // by the start node, or it may be merged by one of the moved nodes,
1119  // but if it isn't merged, its current frame(s) should be good...
1120  SwNodeIndex const end(rDoc.GetNodes(), m_bDelFullPara ? delFullParaEndNode : m_nEndNode);
1121  ::MakeFrames(&rDoc, start, end);
1122  }
1123 
1124  if (pMovedNode)
1125  { // probably better do this after creating all frames
1126  lcl_MakeAutoFrames(*rDoc.GetSpzFrameFormats(), pMovedNode->GetIndex());
1127  }
1128 
1129  AddUndoRedoPaM(rContext, true);
1130 }
1131 
1133 {
1134  SwPaM & rPam = AddUndoRedoPaM(rContext);
1135  SwDoc& rDoc = *rPam.GetDoc();
1136 
1137  if( m_pRedlSaveData )
1138  {
1139  const bool bSuccess = FillSaveData(rPam, *m_pRedlSaveData);
1140  OSL_ENSURE(bSuccess,
1141  "SwUndoDelete::Redo: used to have redline data, but now none?");
1142  if (!bSuccess)
1143  {
1144  m_pRedlSaveData.reset();
1145  }
1146  }
1147 
1148  if( !m_bDelFullPara )
1149  {
1150  // tdf#128739 correct cursors but do not delete bookmarks yet
1151  ::PaMCorrAbs(rPam, *rPam.End());
1152  SetPaM(rPam);
1153 
1154  if( !m_bJoinNext ) // then restore selection from bottom to top
1155  rPam.Exchange();
1156  }
1157 
1158  if( m_pHistory ) // are the attributes saved?
1159  {
1160  m_pHistory->SetTmpEnd( m_pHistory->Count() );
1161  SwHistory aHstr;
1162  aHstr.Move( 0, m_pHistory.get() );
1163 
1164  if( m_bDelFullPara )
1165  {
1166  OSL_ENSURE( rPam.HasMark(), "PaM without Mark" );
1167  DelContentIndex( *rPam.GetMark(), *rPam.GetPoint(),
1169 
1170  DelBookmarks(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
1171  }
1172  else
1173  DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
1174  m_nSetPos = m_pHistory ? m_pHistory->Count() : 0;
1175 
1176  m_pHistory->Move( m_nSetPos, &aHstr );
1177  }
1178  else
1179  {
1180  if( m_bDelFullPara )
1181  {
1182  OSL_ENSURE( rPam.HasMark(), "PaM without Mark" );
1183  DelContentIndex( *rPam.GetMark(), *rPam.GetPoint(),
1185 
1186  DelBookmarks( rPam.GetMark()->nNode, rPam.GetPoint()->nNode );
1187  }
1188  else
1189  DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
1190  m_nSetPos = m_pHistory ? m_pHistory->Count() : 0;
1191  }
1192 
1193  if( !m_aSttStr && !m_aEndStr )
1194  {
1196  {
1197  DelFullParaMoveFrames(rDoc, *this, *m_pRedlSaveData);
1198  }
1199 
1200  SwNodeIndex aSttIdx = ( m_bDelFullPara || m_bJoinNext )
1201  ? rPam.GetMark()->nNode
1202  : rPam.GetPoint()->nNode;
1203  SwTableNode* pTableNd = aSttIdx.GetNode().GetTableNode();
1204  if( pTableNd )
1205  {
1206  if( m_bTableDelLastNd )
1207  {
1208  // than add again a Node at the end
1209  const SwNodeIndex aTmpIdx( *pTableNd->EndOfSectionNode(), 1 );
1210  rDoc.GetNodes().MakeTextNode( aTmpIdx,
1212  }
1213 
1214  SwContentNode* pNextNd = rDoc.GetNodes()[
1215  pTableNd->EndOfSectionIndex()+1 ]->GetContentNode();
1216  if( pNextNd )
1217  {
1218  SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat();
1219 
1220  const SfxPoolItem *pItem;
1221  if( SfxItemState::SET == pTableFormat->GetItemState( RES_PAGEDESC,
1222  false, &pItem ) )
1223  pNextNd->SetAttr( *pItem );
1224 
1225  if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK,
1226  false, &pItem ) )
1227  pNextNd->SetAttr( *pItem );
1228  }
1229  pTableNd->DelFrames();
1230  }
1231  else if (*rPam.GetMark() == *rPam.GetPoint())
1232  { // paragraph with only footnote or as-char fly, delete that
1233  // => DelContentIndex has already deleted it! nothing to do here
1234  assert(m_nEndNode == m_nSttNode);
1235  return;
1236  }
1237 
1238  // avoid asserts from ~SwIndexReg for deleted nodes
1239  SwPaM aTmp(*rPam.End());
1240  if (!aTmp.Move(fnMoveForward, GoInNode))
1241  {
1242  *aTmp.GetPoint() = *rPam.Start();
1243  aTmp.Move(fnMoveBackward, GoInNode);
1244  }
1245  assert(aTmp.GetPoint()->nNode != rPam.GetPoint()->nNode
1246  && aTmp.GetPoint()->nNode != rPam.GetMark()->nNode);
1247  ::PaMCorrAbs(rPam, *aTmp.GetPoint());
1248 
1249  rPam.DeleteMark();
1250 
1251  rDoc.GetNodes().Delete( aSttIdx, m_nEndNode - m_nSttNode );
1252  }
1253  else if( m_bDelFullPara )
1254  {
1255  assert(!"dead code");
1256  // The Pam was incremented by one at Point (== end) to provide space
1257  // for UNDO. This now needs to be reverted!
1258  --rPam.End()->nNode;
1259  if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
1260  *rPam.GetMark() = *rPam.GetPoint();
1262  }
1263  else
1265 }
1266 
1268 {
1269  // this action does not seem idempotent,
1270  // so make sure it is only executed once on repeat
1271  if (rContext.m_bDeleteRepeated)
1272  return;
1273 
1274  SwPaM & rPam = rContext.GetRepeatPaM();
1275  SwDoc& rDoc = *rPam.GetDoc();
1276  ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
1277  if( !rPam.HasMark() )
1278  {
1279  rPam.SetMark();
1280  rPam.Move( fnMoveForward, GoInContent );
1281  }
1282  if( m_bDelFullPara )
1284  else
1286  rContext.m_bDeleteRepeated = true;
1287 }
1288 
1289 void SwUndoDelete::SetTableName(const OUString & rName)
1290 {
1291  m_sTableName = rName;
1292 }
1293 
1294 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uLong m_nNdDiff
Definition: UndoDelete.hxx:49
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:682
SwPaM & AddUndoRedoPaM(::sw::UndoRedoContext &, bool const bCorrToContent=false) const
Definition: undobj.cxx:105
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
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:915
sal_uLong Count() const
Definition: ndarr.hxx:142
static OUString GetPlaceHolder(SwUndoArg eId)
Definition: SwRewriter.cxx:55
Marks a position in the document model.
Definition: pam.hxx:35
void DelBookmarks(const SwNodeIndex &rStt, const SwNodeIndex &rEnd, std::vector< SaveBookmark > *pSaveBkmk, const SwIndex *pSttIdx, const SwIndex *pEndIdx)
Definition: docbm.cxx:1729
bool IsSectionNode() const
Definition: node.hxx:644
std::unique_ptr< SwHistory > m_pHistory
Definition: undobj.hxx:161
SwNodes const & GetUndoNodes() const
Definition: docundo.cxx:71
virtual void RedoImpl(::sw::UndoRedoContext &) override
Definition: undel.cxx:1132
void DelFrames(SwRootFrame const *pLayout=nullptr)
Method deletes all views of document for the node.
Definition: ndtbl.cxx:2414
const OUString & GetText() const
Definition: ndtxt.hxx:210
SwUndoId
Definition: swundo.hxx:29
virtual sal_uInt16 ResetAllAttr() override
Definition: ndtxt.cxx:5141
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:218
std::unique_ptr< SwNodeIndex > m_pMvStt
Definition: UndoDelete.hxx:40
size_t size() const
Definition: UndoCore.hxx:76
o3tl::optional< OUString > m_aSttStr
Definition: UndoDelete.hxx:41
SwNodeIndex nNode
Definition: pam.hxx:37
sal_uLong m_nNode
Definition: UndoDelete.hxx:48
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:273
sal_uIntPtr sal_uLong
SwPaM & GetRepeatPaM()
Definition: UndoCore.hxx:128
const SwPosition * GetMark() const
Definition: pam.hxx:209
sal_uLong m_nEndNode
Definition: undobj.hxx:223
sal_Int64 n
bool SaveContent(const SwPosition *pStt, const SwPosition *pEnd, SwTextNode *pSttTextNd, SwTextNode *pEndTextNd)
Definition: undel.cxx:433
Definition: doc.hxx:185
TElementType * Next()
Definition: calbck.hxx:373
sal_uInt16 m_nSetPos
Definition: UndoDelete.hxx:52
bool m_bJoinNext
Definition: UndoDelete.hxx:56
SwNode & GetNode() const
Definition: ndindex.hxx:119
#define CH_TXTATR_NEWLINE
Definition: hintids.hxx:139
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:143
virtual bool DeleteAndJoin(SwPaM &, const bool bForceJoinNext=false)=0
complete delete of a given PaM
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:314
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:143
void Copy_(const SwNodeRange &rRg, const SwNodeIndex &rInsPos, bool bNewFrames=true) const
Definition: ndarr.hxx:176
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:201
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:738
static SwTextNode * FindFirstAndNextNode(SwDoc &rDoc, SwUndRng const &rRange, SwRedlineSaveDatas const &rRedlineSaveData, SwTextNode *&o_rpFirstMergedDeletedTextNode)
Definition: undel.cxx:64
virtual SwRewriter GetRewriter() const override
Returns rewriter for this undo object.
Definition: undel.cxx:745
bool CanGrouping(SwDoc *, const SwPaM &)
Definition: undel.cxx:512
o3tl::optional< OUString > m_aEndStr
Definition: UndoDelete.hxx:41
std::shared_ptr< MetadatableUndo > CreateUndoForDelete()
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:136
void Delete(const SwNodeIndex &rPos, sal_uLong nNodes=1)
delete nodes
Definition: nodes.cxx:1065
bool isLetterNumeric(const OUString &rStr, sal_Int32 nPos) const
sal_uInt16 sal_Unicode
bool m_bResetPgBrk
Definition: UndoDelete.hxx:60
#define CH_TXTATR_INWORD
Definition: hintids.hxx:137
SwTableNode * GetTableNode()
Definition: node.hxx:599
SwUndoDelete(SwPaM &, bool bFullPara=false, bool bCalledByTableCpy=false)
Definition: undel.cxx:167
SwIndex nContent
Definition: pam.hxx:38
bool empty() const
Definition: docary.hxx:367
sal_uLong m_nReplaceDummy
Definition: UndoDelete.hxx:51
SwNodeIndex aStart
Definition: ndindex.hxx:132
IDocumentStylePoolAccess const & getIDocumentStylePoolAccess() const
Definition: doc.cxx:425
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:773
std::unique_ptr< sw::MergedPara > CheckParaRedlineMerge(SwTextFrame &rFrame, SwTextNode &rTextNode, FrameMode eMode)
Definition: redlnitr.cxx:52
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:140
int nCount
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
Mode eMode
const SwTable & GetTable() const
Definition: node.hxx:497
static bool CanRedlineGroup(SwRedlineSaveDatas &rCurr, const SwRedlineSaveDatas &rCheck, bool bCurrIsEnd)
Definition: undobj.cxx:1466
bool empty() const
Definition: docary.hxx:224
SwDoc & GetDoc() const
Definition: UndoCore.hxx:94
static OUString lcl_DenotedPortion(const OUString &rStr, sal_Int32 nStart, sal_Int32 nEnd)
Definition: undel.cxx:649
virtual ~SwUndoDelete() override
Definition: undel.cxx:588
void MakeFrames(SwDoc *pDoc, const SwNodeIndex &rSttIdx, const SwNodeIndex &rEndIdx)
Definition: frmtool.cxx:1831
Specific frame formats (frames, DrawObjects).
Definition: docary.hxx:201
SwNode & GetEndOfContent() const
Regular ContentSection (i.e. the BodyText).
Definition: ndarr.hxx:163
virtual void RepeatImpl(::sw::RepeatContext &) override
Definition: undel.cxx:1267
void SetTableName(const OUString &rName)
Definition: undel.cxx:1289
bool const m_bFromTableCopy
Definition: UndoDelete.hxx:61
bool IsContentNode() const
Definition: node.hxx:628
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
const SwAttrSet * GetpSwAttrSet() const
Definition: node.hxx:443
bool Move(SwMoveFnCollection const &fnMove=fnMoveForward, SwGoInDoc fnGo=GoInContent)
Movement of cursor.
Definition: pam.cxx:495
Style of a layout element.
Definition: frmfmt.hxx:57
::sw::UndoManager & GetUndoManager()
Definition: doc.cxx:132
void DeRegister()
deregister the currently registered History
Definition: ndhints.hxx:197
std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd
Definition: UndoDelete.hxx:44
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
bool GoInNode(SwPaM &rPam, SwMoveFnCollection const &fnMove)
Definition: pam.cxx:906
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:131
const SwPosition * GetPoint() const
Definition: pam.hxx:207
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
Count
static void SetSaveData(SwDoc &rDoc, SwRedlineSaveDatas &rSData)
Definition: undobj.cxx:1439
static SwRewriter lcl_RewriterFromHistory(SwHistory &rHistory)
Definition: undel.cxx:599
void Exchange()
Definition: pam.cxx:483
TElementType * First()
Definition: calbck.hxx:342
int i
virtual bool DeleteRedline(const SwPaM &rPam, bool bSaveInUndo, RedlineType nDelType)=0
bool m_bTableDelLastNd
Definition: UndoDelete.hxx:57
FlyAnchors.
Definition: fmtanchr.hxx:34
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
sal_Int32 m_nEndContent
Definition: undobj.hxx:224
SwDoc * GetDoc() const
Definition: pam.hxx:243
sal_uLong m_nSectDiff
Definition: UndoDelete.hxx:50
static void DelFullParaMoveFrames(SwDoc &rDoc, SwUndRng const &rRange, SwRedlineSaveDatas const &rRedlineSaveData)
Definition: undel.cxx:112
Marks a character position inside a document model node.
Definition: index.hxx:37
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:145
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:29
std::shared_ptr< MetadatableUndo > CreateUndo() const
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:396
Marks a node in the document model.
Definition: ndindex.hxx:31
bool m_bCacheComment
Definition: undobj.hxx:60
bool HasSwAttrSet() const
Definition: node.hxx:444
OUString SwResId(const char *pId)
Definition: swmodule.cxx:178
enumrange< T >::Iterator end(enumrange< T >)
const SwPosition * Start() const
Definition: pam.hxx:212
virtual bool IsIgnoreRedline() const =0
static void lcl_MakeAutoFrames(const SwFrameFormats &rSpzArr, sal_uLong nMovedIndex)
Definition: undel.cxx:49
sal_uInt16 Count() const
Definition: rolbck.hxx:372
sal_uLong m_nSttNode
Definition: undobj.hxx:223
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:458
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:2659
OUString InsertText(const OUString &rStr, const SwIndex &rIdx, const SwInsertFlags nMode=SwInsertFlags::DEFAULT)
insert text content
Definition: ndtxt.cxx:2276
void ClearSwpHintsArr(bool bDelFields)
Definition: thints.cxx:3365
sal_uLong EndOfSectionIndex() const
Definition: node.hxx:677
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
#define CH_TXT_ATR_INPUTFIELDEND
Definition: hintids.hxx:141
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:334
bool m_bResetPgDesc
Definition: UndoDelete.hxx:59
virtual bool SetAttr(const SfxPoolItem &)
made virtual
Definition: node.cxx:1484
void SetPaM(SwPaM &, bool bCorrToContent=false) const
Definition: undobj.cxx:77
DelContentType
Definition: undobj.hxx:132
OUString ShortenString(const OUString &rStr, sal_Int32 nLength, const OUString &rFillStr)
Shortens a string to a maximum length.
Definition: undobj.cxx:1498
static void lcl_ReAnchorAtContentFlyFrames(const SwFrameFormats &rSpzArr, SwPosition &rPos, sal_uLong nOldIdx)
Definition: undel.cxx:806
SwMoveFnCollection const & fnMoveForward
SwPam::Move()/Find() default argument.
Definition: paminit.cxx:59
virtual bool DelFullPara(SwPaM &)=0
Delete full paragraphs.
OUString DenoteSpecialCharacters(const OUString &rStr)
Denotes special characters in a string.
Definition: undel.cxx:702
sal_Int32 GetIndex() const
Definition: index.hxx:95
virtual void MakeFrames()
Creates the views.
Definition: atrfrm.cxx:2642
SwNodes & GetNodes()
Definition: doc.hxx:403
virtual SwTextFormatColl * GetTextCollFromPool(sal_uInt16 nId, bool bRegardLanguage=true)=0
Return "Auto-Collection with ID.
const SwPosition * End() const
Definition: pam.hxx:217
SwNodeIndex aEnd
Definition: ndindex.hxx:133
#define CH_TXTATR_TAB
Definition: hintids.hxx:138
void PaMCorrAbs(const SwPaM &rRange, const SwPosition &rNewPos)
Function declarations so that everything below the CursorShell can move the Cursor once in a while...
Definition: doccorr.cxx:85
double getLength(const B2DPolygon &rCandidate)
static bool lcl_IsSpecialCharacter(sal_Unicode nChar)
Definition: undel.cxx:626
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:147
SwMoveFnCollection const & fnMoveBackward
Definition: paminit.cxx:58
virtual bool SplitNode(const SwPosition &rPos, bool bChkTableStart)=0
Split a node at rPos (implemented only for TextNode).
bool IsTableNode() const
Definition: node.hxx:640
size_t size() const
Definition: docary.hxx:225
std::unique_ptr< SwRedlineSaveDatas > m_pRedlSaveData
Definition: UndoDelete.hxx:42
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:469
static bool FillSaveData(const SwPaM &rRange, SwRedlineSaveDatas &rSData, bool bDelRange=true, bool bCopyNext=true)
Definition: undobj.cxx:1374
virtual const SwRedlineTable & GetRedlineTable() const =0
#define RES_PAGEDESC
Definition: hintids.hxx:293
#define RES_BREAK
Definition: hintids.hxx:294
std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart
Definition: UndoDelete.hxx:43
#define CH_TXT_ATR_FIELDSEP
Definition: hintids.hxx:146
CharClass & GetAppCharClass()
Definition: init.cxx:709
void Move(sal_uInt16 nPos, SwHistory *pIns, sal_uInt16 const nStart=0)
Definition: rolbck.hxx:380
bool const m_bDelFullPara
Definition: UndoDelete.hxx:58
OUString m_sTableName
Definition: UndoDelete.hxx:46
aStr
void RestoreMetadata(std::shared_ptr< MetadatableUndo > const &i_pUndo)
sal_Int32 m_nSttContent
Definition: undobj.hxx:224
virtual void UndoImpl(::sw::UndoRedoContext &) override
Definition: undel.cxx:831
const int nUndoStringLength
Definition: UndoCore.hxx:224
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:842
SwTextNode * MakeTextNode(const SwNodeIndex &rWhere, SwTextFormatColl *pColl, bool bNewFrames=true)
Implementations of "Make...Node" are in the given .cxx-files.
Definition: ndtxt.cxx:103
void SetAnchor(const SwPosition *pPos)
Definition: atrfrm.cxx:1477
bool MoveNodes(const SwNodeRange &, SwNodes &rNodes, const SwNodeIndex &, bool bNewFrames=true)
move the node pointer
Definition: nodes.cxx:394
Base class of the Writer document model elements.
Definition: node.hxx:79
SwTextFormatColl * GetTextColl() const
Definition: ndtxt.hxx:836
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo