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