Line data Source code
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 <editeng/formatbreakitem.hxx>
24 : #include <fmtpdsc.hxx>
25 : #include <frmfmt.hxx>
26 : #include <fmtanchr.hxx>
27 : #include <doc.hxx>
28 : #include <UndoManager.hxx>
29 : #include <IDocumentRedlineAccess.hxx>
30 : #include <IDocumentStylePoolAccess.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 <comcore.hrc>
45 : #include <undo.hrc>
46 : #include <vector>
47 :
48 : // DELETE
49 : /* lcl_MakeAutoFrms has to call MakeFrms for objects bounded "AtChar"
50 : ( == AUTO ), if the anchor frame has be moved via _MoveNodes(..) and
51 : DelFrms(..)
52 : */
53 18 : static void lcl_MakeAutoFrms( const SwFrmFmts& rSpzArr, sal_uLong nMovedIndex )
54 : {
55 18 : if( !rSpzArr.empty() )
56 : {
57 : SwFlyFrmFmt* pFmt;
58 : const SwFmtAnchor* pAnchor;
59 46 : for( size_t n = 0; n < rSpzArr.size(); ++n )
60 : {
61 34 : pFmt = (SwFlyFrmFmt*)rSpzArr[n];
62 34 : pAnchor = &pFmt->GetAnchor();
63 34 : if (pAnchor->GetAnchorId() == FLY_AT_CHAR)
64 : {
65 0 : const SwPosition* pAPos = pAnchor->GetCntntAnchor();
66 0 : if( pAPos && nMovedIndex == pAPos->nNode.GetIndex() )
67 0 : pFmt->MakeFrms();
68 : }
69 : }
70 : }
71 18 : }
72 :
73 : // SwUndoDelete has to perform a deletion and to record anything that is needed
74 : // to restore the situation before the deletion. Unfortunately a part of the
75 : // deletion will be done after calling this Ctor, this has to be kept in mind!
76 : // In this Ctor only the complete paragraphs will be deleted, the joining of
77 : // the first and last paragraph of the selection will be handled outside this
78 : // function.
79 : // Here are the main steps of the function:
80 : // 1. Deletion/recording of content indices of the selection: footnotes, fly
81 : // frames and bookmarks
82 : // Step 1 could shift all nodes by deletion of footnotes => nNdDiff will be set.
83 : // 2. If the paragraph where the selection ends, is the last content of a
84 : // section so that this section becomes empty when the paragraphs will be
85 : // joined we have to do some smart actions ;-) The paragraph will be moved
86 : // outside the section and replaced by a dummy text node, the complete
87 : // section will be deleted in step 3. The difference between replacement
88 : // dummy and original is nReplacementDummy.
89 : // 3. Moving complete selected nodes into the UndoArray. Before this happens the
90 : // selection has to be extended if there are sections which would become
91 : // empty otherwise. BTW: sections will be moved into the UndoArray if they
92 : // are complete part of the selection. Sections starting or ending outside
93 : // of the selection will not be removed from the DocNodeArray even they got
94 : // a "dummy"-copy in the UndoArray.
95 : // 4. We have to anticipate the joining of the two paragraphs if the start
96 : // paragraph is inside a section and the end paragraph not. Then we have to
97 : // move the paragraph into this section and to record this in nSectDiff.
98 1500 : SwUndoDelete::SwUndoDelete(
99 : SwPaM& rPam,
100 : bool bFullPara,
101 : bool bCalledByTblCpy )
102 : : SwUndo(UNDO_DELETE),
103 : SwUndRng( rPam ),
104 : pMvStt( 0 ),
105 : pSttStr(0),
106 : pEndStr(0),
107 : pRedlData(0),
108 : pRedlSaveData(0),
109 : nNode(0),
110 : nNdDiff(0),
111 : nSectDiff(0),
112 : nReplaceDummy(0),
113 : nSetPos(0),
114 : bGroup( false ),
115 : bBackSp( false ),
116 : bJoinNext( false ),
117 : bTblDelLastNd( false ),
118 : // bFullPara is set e.g. if an empty paragraph before a table is deleted
119 : bDelFullPara( bFullPara ),
120 : bResetPgDesc( false ),
121 : bResetPgBrk( false ),
122 1500 : bFromTableCopy( bCalledByTblCpy )
123 : {
124 :
125 1500 : bCacheComment = false;
126 :
127 1500 : SwDoc * pDoc = rPam.GetDoc();
128 :
129 1500 : if( !pDoc->getIDocumentRedlineAccess().IsIgnoreRedline() && !pDoc->getIDocumentRedlineAccess().GetRedlineTbl().empty() )
130 : {
131 0 : pRedlSaveData = new SwRedlineSaveDatas;
132 0 : if( !FillSaveData( rPam, *pRedlSaveData ))
133 0 : delete pRedlSaveData, pRedlSaveData = 0;
134 : }
135 :
136 1500 : if( !pHistory )
137 1500 : pHistory = new SwHistory;
138 :
139 : // delete all footnotes for now
140 1500 : const SwPosition *pStt = rPam.Start(),
141 1500 : *pEnd = rPam.GetPoint() == pStt
142 : ? rPam.GetMark()
143 1500 : : rPam.GetPoint();
144 :
145 : // Step 1. deletion/record of content indices
146 1500 : if( bDelFullPara )
147 : {
148 : OSL_ENSURE( rPam.HasMark(), "PaM ohne Mark" );
149 438 : DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
150 438 : DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
151 :
152 438 : ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
153 438 : _DelBookmarks(pStt->nNode, pEnd->nNode);
154 : }
155 : else
156 1062 : DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
157 :
158 1500 : nSetPos = pHistory ? pHistory->Count() : 0;
159 :
160 : // Is already anything deleted?
161 1500 : nNdDiff = nSttNode - pStt->nNode.GetIndex();
162 :
163 1500 : bJoinNext = !bFullPara && pEnd == rPam.GetPoint();
164 1500 : bBackSp = !bFullPara && !bJoinNext;
165 :
166 1500 : SwTxtNode *pSttTxtNd = 0, *pEndTxtNd = 0;
167 1500 : if( !bFullPara )
168 : {
169 1062 : pSttTxtNd = pStt->nNode.GetNode().GetTxtNode();
170 1062 : pEndTxtNd = nSttNode == nEndNode
171 : ? pSttTxtNd
172 1062 : : pEnd->nNode.GetNode().GetTxtNode();
173 : }
174 :
175 1500 : bool bMoveNds = *pStt == *pEnd // any area still existent?
176 : ? false
177 1500 : : ( SaveCntnt( pStt, pEnd, pSttTxtNd, pEndTxtNd ) || bFromTableCopy );
178 :
179 1500 : if( pSttTxtNd && pEndTxtNd && pSttTxtNd != pEndTxtNd )
180 : {
181 : // two different TextNodes, thus save also the TextFormatCollection
182 44 : pHistory->Add( pSttTxtNd->GetTxtColl(),pStt->nNode.GetIndex(), ND_TEXTNODE );
183 44 : pHistory->Add( pEndTxtNd->GetTxtColl(),pEnd->nNode.GetIndex(), ND_TEXTNODE );
184 :
185 44 : if( !bJoinNext ) // Selection from bottom to top
186 : {
187 : // When using JoinPrev() all AUTO-PageBreak's will be copied
188 : // correctly. To restore them with UNDO, Auto-PageBreak of the
189 : // EndNode needs to be reset. Same for PageDesc and ColBreak.
190 18 : if( pEndTxtNd->HasSwAttrSet() )
191 : {
192 0 : SwRegHistory aRegHist( *pEndTxtNd, pHistory );
193 0 : if( SfxItemState::SET == pEndTxtNd->GetpSwAttrSet()->GetItemState(
194 0 : RES_BREAK, false ) )
195 0 : pEndTxtNd->ResetAttr( RES_BREAK );
196 0 : if( pEndTxtNd->HasSwAttrSet() &&
197 0 : SfxItemState::SET == pEndTxtNd->GetpSwAttrSet()->GetItemState(
198 0 : RES_PAGEDESC, false ) )
199 0 : pEndTxtNd->ResetAttr( RES_PAGEDESC );
200 : }
201 : }
202 : }
203 :
204 : // Move now also the PaM. The SPoint is at the beginning of a SSelection.
205 1500 : if( pEnd == rPam.GetPoint() && ( !bFullPara || pSttTxtNd || pEndTxtNd ) )
206 960 : rPam.Exchange();
207 :
208 1500 : if( !pSttTxtNd && !pEndTxtNd )
209 450 : rPam.GetPoint()->nNode--;
210 1500 : rPam.DeleteMark(); // the SPoint is in the selection
211 :
212 1500 : if( !pEndTxtNd )
213 450 : nEndCntnt = 0;
214 1500 : if( !pSttTxtNd )
215 454 : nSttCntnt = 0;
216 :
217 1500 : if( bMoveNds ) // Do Nodes exist that need to be moved?
218 : {
219 478 : SwNodes& rNds = pDoc->GetUndoManager().GetUndoNodes();
220 478 : SwNodes& rDocNds = pDoc->GetNodes();
221 478 : SwNodeRange aRg( rDocNds, nSttNode - nNdDiff,
222 956 : rDocNds, nEndNode - nNdDiff );
223 490 : if( !bFullPara && !pEndTxtNd &&
224 12 : &aRg.aEnd.GetNode() != &pDoc->GetNodes().GetEndOfContent() )
225 : {
226 12 : SwNode* pNode = aRg.aEnd.GetNode().StartOfSectionNode();
227 12 : if( pNode->GetIndex() >= nSttNode - nNdDiff )
228 12 : aRg.aEnd++; // Deletion of a complete table
229 : }
230 : SwNode* pTmpNd;
231 : // Step 2: Expand selection if necessary
232 478 : if( bJoinNext || bFullPara )
233 : {
234 : // If all content of a section will be moved into Undo, the section
235 : // itself should be moved completely.
236 1744 : while( aRg.aEnd.GetIndex() + 2 < rDocNds.Count() &&
237 1282 : ( (pTmpNd = rDocNds[ aRg.aEnd.GetIndex()+1 ])->IsEndNode() &&
238 426 : pTmpNd->StartOfSectionNode()->IsSectionNode() &&
239 0 : pTmpNd->StartOfSectionNode()->GetIndex() >= aRg.aStart.GetIndex() ) )
240 0 : aRg.aEnd++;
241 444 : nReplaceDummy = aRg.aEnd.GetIndex() + nNdDiff - nEndNode;
242 444 : if( nReplaceDummy )
243 : { // The selection has been expanded, because
244 0 : aRg.aEnd++;
245 0 : if( pEndTxtNd )
246 : {
247 : // The end text node has to leave the (expanded) selection
248 : // The dummy is needed because _MoveNodes deletes empty
249 : // sections
250 0 : ++nReplaceDummy;
251 0 : SwNodeRange aMvRg( *pEndTxtNd, 0, *pEndTxtNd, 1 );
252 0 : SwPosition aSplitPos( *pEndTxtNd );
253 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
254 0 : pDoc->getIDocumentContentOperations().SplitNode( aSplitPos, false );
255 0 : rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, true );
256 0 : aRg.aEnd--;
257 : }
258 : else
259 0 : nReplaceDummy = 0;
260 : }
261 : }
262 478 : if( bBackSp || bFullPara )
263 : {
264 : // See above, the selection has to be expanded if there are "nearly
265 : // empty" sections and a replacement dummy has to be set if needed.
266 1888 : while( 1 < aRg.aStart.GetIndex() &&
267 944 : ( (pTmpNd = rDocNds[ aRg.aStart.GetIndex()-1 ])->IsSectionNode() &&
268 0 : pTmpNd->EndOfSectionIndex() < aRg.aEnd.GetIndex() ) )
269 0 : aRg.aStart--;
270 472 : if( pSttTxtNd )
271 : {
272 18 : nReplaceDummy = nSttNode - nNdDiff - aRg.aStart.GetIndex();
273 18 : if( nReplaceDummy )
274 : {
275 0 : SwNodeRange aMvRg( *pSttTxtNd, 0, *pSttTxtNd, 1 );
276 0 : SwPosition aSplitPos( *pSttTxtNd );
277 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
278 0 : pDoc->getIDocumentContentOperations().SplitNode( aSplitPos, false );
279 0 : rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aStart, true );
280 0 : aRg.aStart--;
281 : }
282 : }
283 : }
284 :
285 478 : if( bFromTableCopy )
286 : {
287 0 : if( !pEndTxtNd )
288 : {
289 0 : if( pSttTxtNd )
290 0 : aRg.aStart++;
291 0 : else if( !bFullPara && !aRg.aEnd.GetNode().IsCntntNode() )
292 0 : aRg.aEnd--;
293 : }
294 : }
295 478 : else if (pSttTxtNd && (pEndTxtNd || pSttTxtNd->GetTxt().getLength()))
296 24 : aRg.aStart++;
297 :
298 : // Step 3: Moving into UndoArray...
299 478 : nNode = rNds.GetEndOfContent().GetIndex();
300 478 : rDocNds._MoveNodes( aRg, rNds, SwNodeIndex( rNds.GetEndOfContent() ));
301 478 : pMvStt = new SwNodeIndex( rNds, nNode );
302 : // remember difference!
303 478 : nNode = rNds.GetEndOfContent().GetIndex() - nNode;
304 :
305 478 : if( pSttTxtNd && pEndTxtNd )
306 : {
307 : //Step 4: Moving around sections
308 24 : nSectDiff = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
309 : // nSect is the number of sections which starts(ends) between start
310 : // and end node of the selection. The "loser" paragraph has to be
311 : // moved into the section(s) of the "winner" paragraph
312 24 : if( nSectDiff )
313 : {
314 18 : if( bJoinNext )
315 : {
316 0 : SwNodeRange aMvRg( *pEndTxtNd, 0, *pEndTxtNd, 1 );
317 0 : rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aStart, true );
318 : }
319 : else
320 : {
321 18 : SwNodeRange aMvRg( *pSttTxtNd, 0, *pSttTxtNd, 1 );
322 18 : rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, true );
323 : }
324 : }
325 : }
326 478 : if( nSectDiff || nReplaceDummy )
327 18 : lcl_MakeAutoFrms( *pDoc->GetSpzFrmFmts(),
328 36 : bJoinNext ? pEndTxtNd->GetIndex() : pSttTxtNd->GetIndex() );
329 : }
330 : else
331 1022 : nNode = 0; // moved no node -> no difference at the end
332 :
333 : // Are there any Nodes that got deleted before that (FootNotes
334 : // have ContentNodes)?
335 1500 : if( !pSttTxtNd && !pEndTxtNd )
336 : {
337 450 : nNdDiff = nSttNode - rPam.GetPoint()->nNode.GetIndex() - (bFullPara ? 0 : 1);
338 450 : rPam.Move( fnMoveForward, fnGoNode );
339 : }
340 : else
341 : {
342 1050 : nNdDiff = nSttNode;
343 1050 : if( nSectDiff && bBackSp )
344 18 : nNdDiff += nSectDiff;
345 1050 : nNdDiff -= rPam.GetPoint()->nNode.GetIndex();
346 : }
347 :
348 1500 : if( !rPam.GetNode().IsCntntNode() )
349 130 : rPam.GetPoint()->nContent.Assign( 0, 0 );
350 :
351 : // is a history necessary here at all?
352 1500 : if( pHistory && !pHistory->Count() )
353 1078 : DELETEZ( pHistory );
354 1500 : }
355 :
356 1490 : bool SwUndoDelete::SaveCntnt( const SwPosition* pStt, const SwPosition* pEnd,
357 : SwTxtNode* pSttTxtNd, SwTxtNode* pEndTxtNd )
358 : {
359 1490 : sal_uLong nNdIdx = pStt->nNode.GetIndex();
360 : // 1 - copy start in Start-String
361 1490 : if( pSttTxtNd )
362 : {
363 1036 : bool bOneNode = nSttNode == nEndNode;
364 1036 : SwRegHistory aRHst( *pSttTxtNd, pHistory );
365 : // always save all text atttibutes because of possibly overlapping
366 : // areas of on/off
367 : pHistory->CopyAttr( pSttTxtNd->GetpSwpHints(), nNdIdx,
368 1036 : 0, pSttTxtNd->GetTxt().getLength(), true );
369 1036 : if( !bOneNode && pSttTxtNd->HasSwAttrSet() )
370 12 : pHistory->CopyFmtAttr( *pSttTxtNd->GetpSwAttrSet(), nNdIdx );
371 :
372 : // the length might have changed (!!Fields!!)
373 : sal_Int32 nLen = ((bOneNode)
374 992 : ? pEnd->nContent.GetIndex()
375 44 : : pSttTxtNd->GetTxt().getLength())
376 2072 : - pStt->nContent.GetIndex();
377 :
378 : // delete now also the text (all attribute changes are added to
379 : // UNDO history)
380 1036 : pSttStr = new OUString( pSttTxtNd->GetTxt().copy(nSttCntnt, nLen));
381 1036 : pSttTxtNd->EraseText( pStt->nContent, nLen );
382 1036 : if( pSttTxtNd->GetpSwpHints() )
383 78 : pSttTxtNd->GetpSwpHints()->DeRegister();
384 :
385 : // METADATA: store
386 1036 : bool emptied( !pSttStr->isEmpty() && !pSttTxtNd->Len() );
387 1036 : if (!bOneNode || emptied) // merging may overwrite xmlids...
388 : {
389 472 : m_pMetadataUndoStart = (emptied)
390 : ? pSttTxtNd->CreateUndoForDelete()
391 236 : : pSttTxtNd->CreateUndo();
392 : }
393 :
394 1036 : if( bOneNode )
395 992 : return false; // stop moving more nodes
396 : }
397 :
398 : // 2 - copy end into End-String
399 498 : if( pEndTxtNd )
400 : {
401 48 : SwIndex aEndIdx( pEndTxtNd );
402 48 : nNdIdx = pEnd->nNode.GetIndex();
403 96 : SwRegHistory aRHst( *pEndTxtNd, pHistory );
404 :
405 : // always save all text atttibutes because of possibly overlapping
406 : // areas of on/off
407 : pHistory->CopyAttr( pEndTxtNd->GetpSwpHints(), nNdIdx, 0,
408 48 : pEndTxtNd->GetTxt().getLength(), true );
409 :
410 48 : if( pEndTxtNd->HasSwAttrSet() )
411 12 : pHistory->CopyFmtAttr( *pEndTxtNd->GetpSwAttrSet(), nNdIdx );
412 :
413 : // delete now also the text (all attribute changes are added to
414 : // UNDO history)
415 : pEndStr = new OUString( pEndTxtNd->GetTxt().copy( 0,
416 48 : pEnd->nContent.GetIndex() ));
417 48 : pEndTxtNd->EraseText( aEndIdx, pEnd->nContent.GetIndex() );
418 48 : if( pEndTxtNd->GetpSwpHints() )
419 0 : pEndTxtNd->GetpSwpHints()->DeRegister();
420 :
421 : // METADATA: store
422 48 : bool emptied = !pEndStr->isEmpty() && !pEndTxtNd->Len();
423 :
424 96 : m_pMetadataUndoEnd = (emptied)
425 : ? pEndTxtNd->CreateUndoForDelete()
426 96 : : pEndTxtNd->CreateUndo();
427 : }
428 :
429 : // if there are only two Nodes than we're done
430 498 : if( ( pSttTxtNd || pEndTxtNd ) && nSttNode + 1 == nEndNode )
431 20 : return false; // do not move any Node
432 :
433 478 : return true; // move Nodes lying in between
434 : }
435 :
436 16 : bool SwUndoDelete::CanGrouping( SwDoc* pDoc, const SwPaM& rDelPam )
437 : {
438 : // Is Undo greater than one Node (that is Start and EndString)?
439 16 : if( pSttStr ? pSttStr->isEmpty() || pEndStr : sal_True )
440 0 : return false;
441 :
442 : // only the deletion of single char's can be condensed
443 16 : if( nSttNode != nEndNode || ( !bGroup && nSttCntnt+1 != nEndCntnt ))
444 0 : return false;
445 :
446 16 : const SwPosition *pStt = rDelPam.Start(),
447 16 : *pEnd = rDelPam.GetPoint() == pStt
448 : ? rDelPam.GetMark()
449 16 : : rDelPam.GetPoint();
450 :
451 48 : if( pStt->nNode != pEnd->nNode ||
452 30 : pStt->nContent.GetIndex()+1 != pEnd->nContent.GetIndex() ||
453 14 : pEnd->nNode != nSttNode )
454 12 : return false;
455 :
456 : // Distinguish between BackSpace and Delete because the Undo array needs to
457 : // be constructed differently!
458 4 : if( pEnd->nContent == nSttCntnt )
459 : {
460 0 : if( bGroup && !bBackSp ) return false;
461 0 : bBackSp = true;
462 : }
463 4 : else if( pStt->nContent == nSttCntnt )
464 : {
465 0 : if( bGroup && bBackSp ) return false;
466 0 : bBackSp = false;
467 : }
468 : else
469 4 : return false;
470 :
471 : // are both Nodes (Node/Undo array) TextNodes at all?
472 0 : SwTxtNode * pDelTxtNd = pStt->nNode.GetNode().GetTxtNode();
473 0 : if( !pDelTxtNd ) return false;
474 :
475 0 : sal_Int32 nUChrPos = bBackSp ? 0 : pSttStr->getLength()-1;
476 0 : sal_Unicode cDelChar = pDelTxtNd->GetTxt()[ pStt->nContent.GetIndex() ];
477 0 : CharClass& rCC = GetAppCharClass();
478 0 : if( ( CH_TXTATR_BREAKWORD == cDelChar || CH_TXTATR_INWORD == cDelChar ) ||
479 0 : rCC.isLetterNumeric( OUString( cDelChar ), 0 ) !=
480 0 : rCC.isLetterNumeric( *pSttStr, nUChrPos ) )
481 0 : return false;
482 :
483 : {
484 0 : SwRedlineSaveDatas aTmpSav;
485 0 : const bool bSaved = FillSaveData( rDelPam, aTmpSav, false );
486 :
487 0 : bool bOk = ( !pRedlSaveData && !bSaved ) ||
488 0 : ( pRedlSaveData && bSaved &&
489 0 : SwUndo::CanRedlineGroup( *pRedlSaveData, aTmpSav, bBackSp ));
490 : // aTmpSav.DeleteAndDestroyAll();
491 0 : if( !bOk )
492 0 : return false;
493 :
494 0 : pDoc->getIDocumentRedlineAccess().DeleteRedline( rDelPam, false, USHRT_MAX );
495 : }
496 :
497 : // Both 'deletes' can be consolidated, so 'move' the related character
498 0 : if( bBackSp )
499 0 : nSttCntnt--; // BackSpace: add char to array!
500 : else
501 : {
502 0 : nEndCntnt++; // Delete: attach char at the end
503 0 : nUChrPos++;
504 : }
505 0 : (*pSttStr) = pSttStr->replaceAt( nUChrPos, 0, OUString(cDelChar) );
506 0 : pDelTxtNd->EraseText( pStt->nContent, 1 );
507 :
508 0 : bGroup = true;
509 0 : return true;
510 : }
511 :
512 4479 : SwUndoDelete::~SwUndoDelete()
513 : {
514 1493 : delete pSttStr;
515 1493 : delete pEndStr;
516 1493 : if( pMvStt ) // Delete also the selection from UndoNodes array
517 : {
518 : // Insert saves content in IconSection
519 477 : pMvStt->GetNode().GetNodes().Delete( *pMvStt, nNode );
520 477 : delete pMvStt;
521 : }
522 1493 : delete pRedlData;
523 1493 : delete pRedlSaveData;
524 2986 : }
525 :
526 394 : static SwRewriter lcl_RewriterFromHistory(SwHistory & rHistory)
527 : {
528 394 : SwRewriter aRewriter;
529 :
530 394 : bool bDone = false;
531 :
532 1598 : for ( sal_uInt16 n = 0; n < rHistory.Count(); n++)
533 : {
534 1272 : OUString aDescr = rHistory[n]->GetDescription();
535 :
536 1272 : if (!aDescr.isEmpty())
537 : {
538 68 : aRewriter.AddRule(UndoArg2, aDescr);
539 :
540 68 : bDone = true;
541 68 : break;
542 : }
543 1204 : }
544 :
545 394 : if (! bDone)
546 : {
547 326 : aRewriter.AddRule(UndoArg2, SW_RESSTR(STR_FIELD));
548 : }
549 :
550 394 : return aRewriter;
551 : }
552 :
553 446507 : static bool lcl_IsSpecialCharacter(sal_Unicode nChar)
554 : {
555 446507 : switch (nChar)
556 : {
557 : case CH_TXTATR_BREAKWORD:
558 : case CH_TXTATR_INWORD:
559 : case CH_TXTATR_TAB:
560 : case CH_TXTATR_NEWLINE:
561 5292 : return true;
562 :
563 : default:
564 441215 : break;
565 : }
566 :
567 441215 : return false;
568 : }
569 :
570 20085 : static OUString lcl_DenotedPortion(const OUString& rStr, sal_Int32 nStart, sal_Int32 nEnd)
571 : {
572 20085 : OUString aResult;
573 :
574 20085 : if (nEnd - nStart > 0)
575 : {
576 17593 : sal_Unicode cLast = rStr[nEnd - 1];
577 17593 : if (lcl_IsSpecialCharacter(cLast))
578 : {
579 2596 : switch(cLast)
580 : {
581 : case CH_TXTATR_TAB:
582 2416 : aResult = SW_RESSTR(STR_UNDO_TABS);
583 :
584 2416 : break;
585 : case CH_TXTATR_NEWLINE:
586 62 : aResult = SW_RESSTR(STR_UNDO_NLS);
587 :
588 62 : break;
589 :
590 : case CH_TXTATR_INWORD:
591 : case CH_TXTATR_BREAKWORD:
592 118 : aResult = SwRewriter::GetPlaceHolder(UndoArg2);
593 118 : break;
594 :
595 : }
596 2596 : SwRewriter aRewriter;
597 : aRewriter.AddRule(UndoArg1,
598 2596 : OUString::number(nEnd - nStart));
599 2596 : aResult = aRewriter.Apply(aResult);
600 : }
601 : else
602 : {
603 14997 : aResult = SW_RESSTR(STR_START_QUOTE);
604 14997 : aResult += rStr.copy(nStart, nEnd - nStart);
605 14997 : aResult += SW_RESSTR(STR_END_QUOTE);
606 : }
607 : }
608 :
609 20085 : return aResult;
610 : }
611 :
612 21271 : OUString DenoteSpecialCharacters(const OUString & rStr)
613 : {
614 21271 : OUString aResult;
615 :
616 21271 : if (!rStr.isEmpty())
617 : {
618 17401 : bool bStart = false;
619 17401 : sal_Int32 nStart = 0;
620 17401 : sal_Unicode cLast = 0;
621 :
622 233162 : for( sal_Int32 i = 0; i < rStr.getLength(); i++)
623 : {
624 215761 : if (lcl_IsSpecialCharacter(rStr[i]))
625 : {
626 2608 : if (cLast != rStr[i])
627 2596 : bStart = true;
628 :
629 : }
630 : else
631 : {
632 213153 : if (lcl_IsSpecialCharacter(cLast))
633 88 : bStart = true;
634 : }
635 :
636 215761 : if (bStart)
637 : {
638 2684 : aResult += lcl_DenotedPortion(rStr, nStart, i);
639 :
640 2684 : nStart = i;
641 2684 : bStart = false;
642 : }
643 :
644 215761 : cLast = rStr[i];
645 : }
646 :
647 17401 : aResult += lcl_DenotedPortion(rStr, nStart, rStr.getLength());
648 : }
649 : else
650 3870 : aResult = SwRewriter::GetPlaceHolder(UndoArg2);
651 :
652 21271 : return aResult;
653 : }
654 :
655 1504 : SwRewriter SwUndoDelete::GetRewriter() const
656 : {
657 1504 : SwRewriter aResult;
658 :
659 1504 : if (nNode != 0)
660 : {
661 480 : if (!sTableName.isEmpty())
662 : {
663 :
664 8 : SwRewriter aRewriter;
665 8 : aRewriter.AddRule(UndoArg1, SW_RESSTR(STR_START_QUOTE));
666 8 : aRewriter.AddRule(UndoArg2, sTableName);
667 8 : aRewriter.AddRule(UndoArg3, SW_RESSTR(STR_END_QUOTE));
668 :
669 16 : OUString sTmp = aRewriter.Apply(SW_RES(STR_TABLE_NAME));
670 16 : aResult.AddRule(UndoArg1, sTmp);
671 : }
672 : else
673 472 : aResult.AddRule(UndoArg1, SW_RESSTR(STR_PARAGRAPHS));
674 : }
675 : else
676 : {
677 1024 : OUString aStr;
678 :
679 1028 : if (pSttStr != NULL && pEndStr != NULL && pSttStr->isEmpty() &&
680 4 : pEndStr->isEmpty())
681 : {
682 0 : aStr = SW_RESSTR(STR_PARAGRAPH_UNDO);
683 : }
684 : else
685 : {
686 1024 : OUString * pStr = NULL;
687 1024 : if (pSttStr != NULL)
688 1012 : pStr = pSttStr;
689 12 : else if (pEndStr != NULL)
690 0 : pStr = pEndStr;
691 :
692 1024 : if (pStr != NULL)
693 : {
694 1012 : aStr = DenoteSpecialCharacters(*pStr);
695 : }
696 : else
697 : {
698 12 : aStr = SwRewriter::GetPlaceHolder(UndoArg2);
699 : }
700 : }
701 :
702 1024 : aStr = ShortenString(aStr, nUndoStringLength, OUString(SW_RES(STR_LDOTS)));
703 1024 : if (pHistory)
704 : {
705 394 : SwRewriter aRewriter = lcl_RewriterFromHistory(*pHistory);
706 394 : aStr = aRewriter.Apply(aStr);
707 : }
708 :
709 1024 : aResult.AddRule(UndoArg1, aStr);
710 : }
711 :
712 1504 : return aResult;
713 : }
714 :
715 : // Every object, anchored "AtCntnt" will be reanchored at rPos
716 0 : static void lcl_ReAnchorAtCntntFlyFrames( const SwFrmFmts& rSpzArr, SwPosition &rPos, sal_uLong nOldIdx )
717 : {
718 0 : if( !rSpzArr.empty() )
719 : {
720 : SwFlyFrmFmt* pFmt;
721 : const SwFmtAnchor* pAnchor;
722 : const SwPosition* pAPos;
723 0 : for( size_t n = 0; n < rSpzArr.size(); ++n )
724 : {
725 0 : pFmt = (SwFlyFrmFmt*)rSpzArr[n];
726 0 : pAnchor = &pFmt->GetAnchor();
727 0 : if (pAnchor->GetAnchorId() == FLY_AT_PARA)
728 : {
729 0 : pAPos = pAnchor->GetCntntAnchor();
730 0 : if( pAPos && nOldIdx == pAPos->nNode.GetIndex() )
731 : {
732 0 : SwFmtAnchor aAnch( *pAnchor );
733 0 : aAnch.SetAnchor( &rPos );
734 0 : pFmt->SetFmtAttr( aAnch );
735 : }
736 : }
737 : }
738 : }
739 0 : }
740 :
741 2 : void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
742 : {
743 2 : SwDoc *const pDoc = & rContext.GetDoc();
744 :
745 2 : sal_uLong nCalcStt = nSttNode - nNdDiff;
746 :
747 2 : if( nSectDiff && bBackSp )
748 0 : nCalcStt += nSectDiff;
749 :
750 2 : SwNodeIndex aIdx( pDoc->GetNodes(), nCalcStt );
751 2 : SwNode* pInsNd = &aIdx.GetNode();
752 :
753 : { // code block so that SwPosition is detached when deleting a Node
754 2 : SwPosition aPos( aIdx );
755 2 : if( !bDelFullPara )
756 : {
757 2 : if( pInsNd->IsTableNode() )
758 : {
759 0 : pInsNd = pDoc->GetNodes().MakeTxtNode( aIdx,
760 0 : (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
761 0 : aIdx--;
762 0 : aPos.nNode = aIdx;
763 0 : aPos.nContent.Assign( pInsNd->GetCntntNode(), nSttCntnt );
764 : }
765 : else
766 : {
767 2 : if( pInsNd->IsCntntNode() )
768 2 : aPos.nContent.Assign( (SwCntntNode*)pInsNd, nSttCntnt );
769 2 : if( !bTblDelLastNd )
770 2 : pInsNd = 0; // do not delete Node!
771 : }
772 : }
773 : else
774 0 : pInsNd = 0; // do not delete Node!
775 :
776 2 : bool bNodeMove = 0 != nNode;
777 :
778 2 : if( pEndStr )
779 : {
780 : // discard attributes since they all saved!
781 2 : SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode();
782 :
783 2 : if( pTxtNd && pTxtNd->HasSwAttrSet() )
784 0 : pTxtNd->ResetAllAttr();
785 :
786 2 : if( pTxtNd && pTxtNd->GetpSwpHints() )
787 0 : pTxtNd->ClearSwpHintsArr( true );
788 :
789 2 : if( pSttStr && !bFromTableCopy )
790 : {
791 0 : sal_uLong nOldIdx = aPos.nNode.GetIndex();
792 0 : pDoc->getIDocumentContentOperations().SplitNode( aPos, false );
793 : // After the split all objects are anchored at the first
794 : // paragraph, but the pHistory of the fly frame formats relies
795 : // on anchoring at the start of the selection
796 : // => selection backwards needs a correction.
797 0 : if( bBackSp )
798 0 : lcl_ReAnchorAtCntntFlyFrames( *pDoc->GetSpzFrmFmts(), aPos, nOldIdx );
799 0 : pTxtNd = aPos.nNode.GetNode().GetTxtNode();
800 : }
801 2 : if( pTxtNd )
802 : {
803 : OUString const ins( pTxtNd->InsertText(*pEndStr, aPos.nContent,
804 2 : IDocumentContentOperations::INS_NOHINTEXPAND) );
805 : assert(ins.getLength() == pEndStr->getLength()); // must succeed
806 : (void) ins;
807 : // METADATA: restore
808 2 : pTxtNd->RestoreMetadata(m_pMetadataUndoEnd);
809 : }
810 : }
811 0 : else if( pSttStr && bNodeMove )
812 : {
813 0 : SwTxtNode * pNd = aPos.nNode.GetNode().GetTxtNode();
814 0 : if( pNd )
815 : {
816 0 : if (nSttCntnt < pNd->GetTxt().getLength())
817 : {
818 0 : sal_uLong nOldIdx = aPos.nNode.GetIndex();
819 0 : pDoc->getIDocumentContentOperations().SplitNode( aPos, false );
820 0 : if( bBackSp )
821 0 : lcl_ReAnchorAtCntntFlyFrames( *pDoc->GetSpzFrmFmts(), aPos, nOldIdx );
822 : }
823 : else
824 0 : aPos.nNode++;
825 : }
826 : }
827 2 : SwNode* pMovedNode = NULL;
828 2 : if( nSectDiff )
829 : {
830 0 : sal_uLong nMoveIndex = aPos.nNode.GetIndex();
831 0 : int nDiff = 0;
832 0 : if( bJoinNext )
833 : {
834 0 : nMoveIndex += nSectDiff + 1;
835 0 : pMovedNode = &aPos.nNode.GetNode();
836 : }
837 : else
838 : {
839 0 : nMoveIndex -= nSectDiff + 1;
840 0 : ++nDiff;
841 : }
842 0 : SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex );
843 0 : SwNodeRange aRg( aPos.nNode, 0 - nDiff, aPos.nNode, 1 - nDiff );
844 0 : aPos.nNode--;
845 0 : if( !bJoinNext )
846 0 : pMovedNode = &aPos.nNode.GetNode();
847 0 : pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, true );
848 0 : aPos.nNode++;
849 : }
850 :
851 2 : if( bNodeMove )
852 : {
853 2 : SwNodeRange aRange( *pMvStt, 0, *pMvStt, nNode );
854 4 : SwNodeIndex aCopyIndex( aPos.nNode, -1 );
855 2 : pDoc->GetUndoManager().GetUndoNodes()._Copy( aRange, aPos.nNode );
856 :
857 2 : if( nReplaceDummy )
858 : {
859 : sal_uLong nMoveIndex;
860 0 : if( bJoinNext )
861 : {
862 0 : nMoveIndex = nEndNode - nNdDiff;
863 0 : aPos.nNode = nMoveIndex + nReplaceDummy;
864 : }
865 : else
866 : {
867 0 : aPos = SwPosition( aCopyIndex );
868 0 : nMoveIndex = aPos.nNode.GetIndex() + nReplaceDummy + 1;
869 : }
870 0 : SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex );
871 0 : SwNodeRange aRg( aPos.nNode, 0, aPos.nNode, 1 );
872 0 : pMovedNode = &aPos.nNode.GetNode();
873 0 : pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, true );
874 0 : pDoc->GetNodes().Delete( aMvIdx, 1 );
875 2 : }
876 : }
877 :
878 2 : if( pMovedNode )
879 0 : lcl_MakeAutoFrms( *pDoc->GetSpzFrmFmts(), pMovedNode->GetIndex() );
880 :
881 2 : if( pSttStr )
882 : {
883 0 : aPos.nNode = nSttNode - nNdDiff + ( bJoinNext ? 0 : nReplaceDummy );
884 0 : SwTxtNode * pTxtNd = aPos.nNode.GetNode().GetTxtNode();
885 : // If more than a single Node got deleted, also all "Node"
886 : // attributes were saved
887 0 : if (pTxtNd != NULL)
888 : {
889 0 : if( pTxtNd->HasSwAttrSet() && bNodeMove && !pEndStr )
890 0 : pTxtNd->ResetAllAttr();
891 :
892 0 : if( pTxtNd->GetpSwpHints() )
893 0 : pTxtNd->ClearSwpHintsArr( true );
894 :
895 : // SectionNode mode and selection from top to bottom:
896 : // -> in StartNode is still the rest of the Join => delete
897 0 : aPos.nContent.Assign( pTxtNd, nSttCntnt );
898 : OUString const ins( pTxtNd->InsertText(*pSttStr, aPos.nContent,
899 0 : IDocumentContentOperations::INS_NOHINTEXPAND) );
900 : assert(ins.getLength() == pSttStr->getLength()); // must succeed
901 : (void) ins;
902 : // METADATA: restore
903 0 : pTxtNd->RestoreMetadata(m_pMetadataUndoStart);
904 : }
905 : }
906 :
907 2 : if( pHistory )
908 : {
909 2 : pHistory->TmpRollback( pDoc, nSetPos, false );
910 2 : if( nSetPos ) // there were Footnodes/FlyFrames
911 : {
912 : // are there others than these ones?
913 2 : if( nSetPos < pHistory->Count() )
914 : {
915 : // if so save the attributes of the others
916 0 : SwHistory aHstr;
917 0 : aHstr.Move( 0, pHistory, nSetPos );
918 0 : pHistory->Rollback( pDoc );
919 0 : pHistory->Move( 0, &aHstr );
920 : }
921 : else
922 : {
923 2 : pHistory->Rollback( pDoc );
924 2 : DELETEZ( pHistory );
925 : }
926 : }
927 : }
928 :
929 2 : if( bResetPgDesc || bResetPgBrk )
930 : {
931 0 : sal_uInt16 nStt = static_cast<sal_uInt16>( bResetPgDesc ? RES_PAGEDESC : RES_BREAK );
932 0 : sal_uInt16 nEnd = static_cast<sal_uInt16>( bResetPgBrk ? RES_BREAK : RES_PAGEDESC );
933 :
934 0 : SwNode* pNode = pDoc->GetNodes()[ nEndNode + 1 ];
935 0 : if( pNode->IsCntntNode() )
936 0 : ((SwCntntNode*)pNode)->ResetAttr( nStt, nEnd );
937 0 : else if( pNode->IsTableNode() )
938 0 : ((SwTableNode*)pNode)->GetTable().GetFrmFmt()->ResetFmtAttr( nStt, nEnd );
939 2 : }
940 : }
941 : // delete the temporarily added Node
942 2 : if( pInsNd )
943 0 : pDoc->GetNodes().Delete( aIdx, 1 );
944 2 : if( pRedlSaveData )
945 0 : SetSaveData( *pDoc, *pRedlSaveData );
946 :
947 2 : AddUndoRedoPaM(rContext, true);
948 2 : }
949 :
950 0 : void SwUndoDelete::RedoImpl(::sw::UndoRedoContext & rContext)
951 : {
952 0 : SwPaM & rPam = AddUndoRedoPaM(rContext);
953 0 : SwDoc& rDoc = *rPam.GetDoc();
954 :
955 0 : if( pRedlSaveData )
956 : {
957 0 : const bool bSuccess = FillSaveData(rPam, *pRedlSaveData, true);
958 : OSL_ENSURE(bSuccess,
959 : "SwUndoDelete::Redo: used to have redline data, but now none?");
960 0 : if (!bSuccess)
961 : {
962 0 : delete pRedlSaveData, pRedlSaveData = 0;
963 : }
964 : }
965 :
966 0 : if( !bDelFullPara )
967 : {
968 0 : SwUndRng aTmpRng( rPam );
969 0 : RemoveIdxFromRange( rPam, false );
970 0 : aTmpRng.SetPaM( rPam );
971 :
972 0 : if( !bJoinNext ) // then restore selection from bottom to top
973 0 : rPam.Exchange();
974 : }
975 :
976 0 : if( pHistory ) // are the attributes saved?
977 : {
978 0 : pHistory->SetTmpEnd( pHistory->Count() );
979 0 : SwHistory aHstr;
980 0 : aHstr.Move( 0, pHistory );
981 :
982 0 : if( bDelFullPara )
983 : {
984 : OSL_ENSURE( rPam.HasMark(), "PaM without Mark" );
985 0 : DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
986 0 : DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
987 :
988 0 : _DelBookmarks(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
989 : }
990 : else
991 0 : DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
992 0 : nSetPos = pHistory ? pHistory->Count() : 0;
993 :
994 0 : pHistory->Move( nSetPos, &aHstr );
995 : }
996 : else
997 : {
998 0 : if( bDelFullPara )
999 : {
1000 : OSL_ENSURE( rPam.HasMark(), "PaM without Mark" );
1001 0 : DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
1002 0 : DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
1003 :
1004 0 : _DelBookmarks( rPam.GetMark()->nNode, rPam.GetPoint()->nNode );
1005 : }
1006 : else
1007 0 : DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
1008 0 : nSetPos = pHistory ? pHistory->Count() : 0;
1009 : }
1010 :
1011 0 : if( !pSttStr && !pEndStr )
1012 : {
1013 0 : SwNodeIndex aSttIdx = ( bDelFullPara || bJoinNext )
1014 0 : ? rPam.GetMark()->nNode
1015 0 : : rPam.GetPoint()->nNode;
1016 0 : SwTableNode* pTblNd = aSttIdx.GetNode().GetTableNode();
1017 0 : if( pTblNd )
1018 : {
1019 0 : if( bTblDelLastNd )
1020 : {
1021 : // than add again a Node at the end
1022 0 : const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
1023 0 : rDoc.GetNodes().MakeTxtNode( aTmpIdx,
1024 0 : rDoc.getIDocumentStylePoolAccess().GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
1025 : }
1026 :
1027 0 : SwCntntNode* pNextNd = rDoc.GetNodes()[
1028 0 : pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
1029 0 : if( pNextNd )
1030 : {
1031 0 : SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
1032 :
1033 : const SfxPoolItem *pItem;
1034 0 : if( SfxItemState::SET == pTableFmt->GetItemState( RES_PAGEDESC,
1035 0 : false, &pItem ) )
1036 0 : pNextNd->SetAttr( *pItem );
1037 :
1038 0 : if( SfxItemState::SET == pTableFmt->GetItemState( RES_BREAK,
1039 0 : false, &pItem ) )
1040 0 : pNextNd->SetAttr( *pItem );
1041 : }
1042 0 : pTblNd->DelFrms();
1043 : }
1044 :
1045 : // avoid asserts from ~SwIndexReg for deleted nodes
1046 0 : SwPaM aTmp(*rPam.End());
1047 0 : if (!aTmp.Move(fnMoveForward, fnGoNode))
1048 : {
1049 0 : *aTmp.GetPoint() = *rPam.Start();
1050 0 : aTmp.Move(fnMoveBackward, fnGoNode);
1051 : }
1052 : assert(aTmp.GetPoint()->nNode != rPam.GetPoint()->nNode
1053 : && aTmp.GetPoint()->nNode != rPam.GetMark()->nNode);
1054 0 : ::PaMCorrAbs(rPam, *aTmp.GetPoint());
1055 :
1056 0 : rPam.DeleteMark();
1057 :
1058 0 : rDoc.GetNodes().Delete( aSttIdx, nEndNode - nSttNode );
1059 : }
1060 0 : else if( bDelFullPara )
1061 : {
1062 : // The Pam was incremented by one at Point (== end) to provide space
1063 : // for UNDO. This now needs to be reverted!
1064 0 : rPam.End()->nNode--;
1065 0 : if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
1066 0 : *rPam.GetMark() = *rPam.GetPoint();
1067 0 : rDoc.getIDocumentContentOperations().DelFullPara( rPam );
1068 : }
1069 : else
1070 0 : rDoc.getIDocumentContentOperations().DeleteAndJoin( rPam );
1071 0 : }
1072 :
1073 0 : void SwUndoDelete::RepeatImpl(::sw::RepeatContext & rContext)
1074 : {
1075 : // this action does not seem idempotent,
1076 : // so make sure it is only executed once on repeat
1077 0 : if (rContext.m_bDeleteRepeated)
1078 0 : return;
1079 :
1080 0 : SwPaM & rPam = rContext.GetRepeatPaM();
1081 0 : SwDoc& rDoc = *rPam.GetDoc();
1082 0 : ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
1083 0 : if( !rPam.HasMark() )
1084 : {
1085 0 : rPam.SetMark();
1086 0 : rPam.Move( fnMoveForward, fnGoCntnt );
1087 : }
1088 0 : if( bDelFullPara )
1089 0 : rDoc.getIDocumentContentOperations().DelFullPara( rPam );
1090 : else
1091 0 : rDoc.getIDocumentContentOperations().DeleteAndJoin( rPam );
1092 0 : rContext.m_bDeleteRepeated = true;
1093 : }
1094 :
1095 8 : void SwUndoDelete::SetTableName(const OUString & rName)
1096 : {
1097 8 : sTableName = rName;
1098 278 : }
1099 :
1100 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|