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