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