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