update dev300-m58
[ooovba.git] / sw / source / core / undo / undel.cxx
blob458266bde613af3f15478a398b5a72e5910cd2db
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: undel.cxx,v $
10 * $Revision: 1.27 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <unotools/charclass.hxx>
37 #include <svx/brkitem.hxx>
38 #include <fmtpdsc.hxx>
39 #include <frmfmt.hxx>
40 #include <fmtanchr.hxx>
41 #include <doc.hxx>
42 #include <swtable.hxx>
43 #include <swundo.hxx> // fuer die UndoIds
44 #include <pam.hxx>
45 #include <ndtxt.hxx>
46 #include <undobj.hxx>
47 #include <rolbck.hxx>
48 #include <poolfmt.hxx>
49 #include <mvsave.hxx>
50 #include <redline.hxx>
51 #include <docary.hxx>
52 #include <sfx2/app.hxx>
54 #include <fldbas.hxx>
55 #include <fmtfld.hxx>
56 #include <comcore.hrc> // #111827#
57 #include <undo.hrc>
59 // #include <svx/svxacorr.hxx>
60 // #include <comphelper/processfactory.hxx>
61 // #include <svx/unolingu.hxx>
62 // #include <unotools/localedatawrapper.hxx>
64 // using namespace comphelper;
66 inline SwDoc& SwUndoIter::GetDoc() const { return *pAktPam->GetDoc(); }
69 // DELETE
70 /* lcl_MakeAutoFrms has to call MakeFrms for objects bounded "AtChar" ( == AUTO ),
71 if the anchor frame has be moved via _MoveNodes(..) and DelFrms(..)
74 void lcl_MakeAutoFrms( const SwSpzFrmFmts& rSpzArr, ULONG nMovedIndex )
76 if( rSpzArr.Count() )
78 SwFlyFrmFmt* pFmt;
79 const SwFmtAnchor* pAnchor;
80 for( USHORT n = 0; n < rSpzArr.Count(); ++n )
82 pFmt = (SwFlyFrmFmt*)rSpzArr[n];
83 pAnchor = &pFmt->GetAnchor();
84 if( pAnchor->GetAnchorId() == FLY_AUTO_CNTNT )
86 const SwPosition* pAPos = pAnchor->GetCntntAnchor();
87 if( pAPos && nMovedIndex == pAPos->nNode.GetIndex() )
88 pFmt->MakeFrms();
95 SwUndoDelete has to perform a deletion and to record anything that is needed to restore the
96 situation before the deletion. Unfortunately a part of the deletion will be done after calling
97 this Ctor, this has to be kept in mind! In this Ctor only the complete paragraphs will be deleted,
98 the joining of the first and last paragraph of the selection will be handled outside this function.
99 Here are the main steps of the function:
100 1. Deletion/recording of content indizes of the selection: footnotes, fly frames and bookmarks
101 Step 1 could shift all nodes by deletion of footnotes => nNdDiff will be set.
102 2. If the paragraph where the selection ends, is the last content of a section so that this
103 section becomes empty when the paragraphs will be joined we have to do some smart actions ;-)
104 The paragraph will be moved outside the section and replaced by a dummy text node, the complete
105 section will be deleted in step 3. The difference between replacement dummy and original is
106 nReplacementDummy.
107 3. Moving complete selected nodes into the UndoArray. Before this happens the selection has to be
108 extended if there are sections which would become empty otherwise. BTW: sections will be moved into
109 the UndoArray if they are complete part of the selection. Sections starting or ending outside of the
110 selection will not be removed from the DocNodeArray even they got a "dummy"-copy in the UndoArray.
111 4. We have to anticipate the joining of the two paragraphs if the start paragraph is inside a
112 section and the end paragraph not. Then we have to move the paragraph into this section and to
113 record this in nSectDiff.
116 SwUndoDelete::SwUndoDelete( SwPaM& rPam, BOOL bFullPara, BOOL bCalledByTblCpy )
117 : SwUndo(UNDO_DELETE), SwUndRng( rPam ),
118 pMvStt( 0 ), pSttStr(0), pEndStr(0), pRedlData(0), pRedlSaveData(0),
119 nNode(0), nNdDiff(0), nSectDiff(0), nReplaceDummy(0), nSetPos(0),
120 bGroup( FALSE ), bBackSp( FALSE ), bJoinNext( FALSE ), bTblDelLastNd( FALSE ),
121 bDelFullPara( bFullPara ), bResetPgDesc( FALSE ), bResetPgBrk( FALSE ),
122 bFromTableCopy( bCalledByTblCpy )
124 bDelFullPara = bFullPara; // This is set e.g. if an empty paragraph before a table is deleted
126 bCacheComment = false;
128 SwDoc * pDoc = rPam.GetDoc();
130 if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
132 pRedlSaveData = new SwRedlineSaveDatas;
133 if( !FillSaveData( rPam, *pRedlSaveData ))
134 delete pRedlSaveData, pRedlSaveData = 0;
137 if( !pHistory )
138 pHistory = new SwHistory;
140 // loesche erstmal alle Fussnoten
141 const SwPosition *pStt = rPam.Start(),
142 *pEnd = rPam.GetPoint() == pStt
143 ? rPam.GetMark()
144 : rPam.GetPoint();
146 // Step 1. deletion/record of content indizes
147 if( bDelFullPara )
149 ASSERT( rPam.HasMark(), "PaM ohne Mark" );
150 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
151 DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
153 BOOL bDoesUndo = pDoc->DoesUndo();
154 pDoc->DoUndo( FALSE );
155 _DelBookmarks(pStt->nNode, pEnd->nNode);
156 pDoc->DoUndo( bDoesUndo );
158 else
159 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
161 nSetPos = pHistory ? pHistory->Count() : 0;
163 // wurde schon was geloescht ??
164 nNdDiff = nSttNode - pStt->nNode.GetIndex();
166 bJoinNext = !bFullPara && pEnd == rPam.GetPoint();
167 bBackSp = !bFullPara && !bJoinNext;
169 SwTxtNode *pSttTxtNd = 0, *pEndTxtNd = 0;
170 if( !bFullPara )
172 pSttTxtNd = pStt->nNode.GetNode().GetTxtNode();
173 pEndTxtNd = nSttNode == nEndNode
174 ? pSttTxtNd
175 : pEnd->nNode.GetNode().GetTxtNode();
178 BOOL bMoveNds = *pStt == *pEnd // noch ein Bereich vorhanden ??
179 ? FALSE
180 : ( SaveCntnt( pStt, pEnd, pSttTxtNd, pEndTxtNd ) || bFromTableCopy );
182 if( pSttTxtNd && pEndTxtNd && pSttTxtNd != pEndTxtNd )
184 // zwei unterschiedliche TextNodes, also speicher noch die
185 // TextFormatCollection fuers
186 pHistory->Add( pSttTxtNd->GetTxtColl(),pStt->nNode.GetIndex(), ND_TEXTNODE );
187 pHistory->Add( pEndTxtNd->GetTxtColl(),pEnd->nNode.GetIndex(), ND_TEXTNODE );
189 if( !bJoinNext ) // Selection von Unten nach Oben
191 // Beim JoinPrev() werden die AUTO-PageBreak's richtig
192 // kopiert. Um diese beim Undo wieder herzustellen, muss das
193 // Auto-PageBreak aus dem EndNode zurueckgesetzt werden.
194 // - fuer die PageDesc, ColBreak dito !
195 if( pEndTxtNd->HasSwAttrSet() )
197 SwRegHistory aRegHist( *pEndTxtNd, pHistory );
198 if( SFX_ITEM_SET == pEndTxtNd->GetpSwAttrSet()->GetItemState(
199 RES_BREAK, FALSE ) )
200 pEndTxtNd->ResetAttr( RES_BREAK );
201 if( pEndTxtNd->HasSwAttrSet() &&
202 SFX_ITEM_SET == pEndTxtNd->GetpSwAttrSet()->GetItemState(
203 RES_PAGEDESC, FALSE ) )
204 pEndTxtNd->ResetAttr( RES_PAGEDESC );
210 // verschiebe jetzt noch den PaM !!!
211 // der SPoint steht am Anfang der SSelection
212 if( pEnd == rPam.GetPoint() && ( !bFullPara || pSttTxtNd || pEndTxtNd ) )
213 rPam.Exchange();
215 if( !pSttTxtNd && !pEndTxtNd )
216 rPam.GetPoint()->nNode--;
217 rPam.DeleteMark(); // der SPoint ist aus dem Bereich
219 if( !pEndTxtNd )
220 nEndCntnt = 0;
221 if( !pSttTxtNd )
222 nSttCntnt = 0;
224 if( bMoveNds ) // sind noch Nodes zu verschieben ?
226 SwNodes& rNds = (SwNodes&)*pDoc->GetUndoNds();
227 SwNodes& rDocNds = pDoc->GetNodes();
228 SwNodeRange aRg( rDocNds, nSttNode - nNdDiff,
229 rDocNds, nEndNode - nNdDiff );
230 if( !bFullPara && !pEndTxtNd &&
231 &aRg.aEnd.GetNode() != &pDoc->GetNodes().GetEndOfContent() )
233 SwNode* pNode = aRg.aEnd.GetNode().StartOfSectionNode();
234 if( pNode->GetIndex() >= nSttNode - nNdDiff )
235 aRg.aEnd++; // Deletion of a complete table
237 SwNode* pTmpNd;
238 // Step 2: Expand selection if necessary
239 if( bJoinNext || bFullPara )
241 // If all content of a section will be moved into Undo,
242 // the section itself should be moved complete.
243 while( aRg.aEnd.GetIndex() + 2 < rDocNds.Count() &&
244 ( (pTmpNd = rDocNds[ aRg.aEnd.GetIndex()+1 ])->IsEndNode() &&
245 pTmpNd->StartOfSectionNode()->IsSectionNode() &&
246 pTmpNd->StartOfSectionNode()->GetIndex() >= aRg.aStart.GetIndex() ) )
247 aRg.aEnd++;
248 nReplaceDummy = aRg.aEnd.GetIndex() + nNdDiff - nEndNode;
249 if( nReplaceDummy )
250 { // The selection has been expanded, because
251 aRg.aEnd++;
252 if( pEndTxtNd )
254 // The end text node has to leave the (expanded) selection
255 // The dummy is needed because _MoveNodes deletes empty sections
256 ++nReplaceDummy;
257 SwNodeRange aMvRg( *pEndTxtNd, 0, *pEndTxtNd, 1 );
258 SwPosition aSplitPos( *pEndTxtNd );
259 BOOL bDoesUndo = pDoc->DoesUndo();
260 pDoc->DoUndo( FALSE );
261 pDoc->SplitNode( aSplitPos, false );
262 rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, TRUE );
263 pDoc->DoUndo( bDoesUndo );
264 aRg.aEnd--;
266 else
267 nReplaceDummy = 0;
270 if( bBackSp || bFullPara )
272 //See above, the selection has to expanded if there are "nearly empty" sections
273 // and a replacement dummy has to be set if needed.
274 while( 1 < aRg.aStart.GetIndex() &&
275 ( (pTmpNd = rDocNds[ aRg.aStart.GetIndex()-1 ])->IsSectionNode() &&
276 pTmpNd->EndOfSectionIndex() < aRg.aEnd.GetIndex() ) )
277 aRg.aStart--;
278 if( pSttTxtNd )
280 nReplaceDummy = nSttNode - nNdDiff - aRg.aStart.GetIndex();
281 if( nReplaceDummy )
283 SwNodeRange aMvRg( *pSttTxtNd, 0, *pSttTxtNd, 1 );
284 SwPosition aSplitPos( *pSttTxtNd );
285 BOOL bDoesUndo = pDoc->DoesUndo();
286 pDoc->DoUndo( FALSE );
287 pDoc->SplitNode( aSplitPos, false );
288 rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aStart, TRUE );
289 pDoc->DoUndo( bDoesUndo );
290 aRg.aStart--;
295 if( bFromTableCopy )
297 if( !pEndTxtNd )
299 if( pSttTxtNd )
300 aRg.aStart++;
301 else if( !bFullPara && !aRg.aEnd.GetNode().IsCntntNode() )
302 aRg.aEnd--;
305 else if( pSttTxtNd && ( pEndTxtNd || pSttTxtNd->GetTxt().Len() ) )
306 aRg.aStart++;
308 // Step 3: Moving into UndoArray...
309 nNode = rNds.GetEndOfContent().GetIndex();
310 rDocNds._MoveNodes( aRg, rNds, SwNodeIndex( rNds.GetEndOfContent() ));
311 pMvStt = new SwNodeIndex( rNds, nNode );
312 nNode = rNds.GetEndOfContent().GetIndex() - nNode; // Differenz merken !
313 if( pSttTxtNd && pEndTxtNd )
315 //Step 4: Moving around sections
316 nSectDiff = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
317 // nSect is the number of sections which starts(ends) between start and end node of the
318 // selection. The "loser" paragraph has to be moved into the section(s) of the
319 // "winner" paragraph
320 if( nSectDiff )
322 if( bJoinNext )
324 SwNodeRange aMvRg( *pEndTxtNd, 0, *pEndTxtNd, 1 );
325 rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aStart, TRUE );
327 else
329 SwNodeRange aMvRg( *pSttTxtNd, 0, *pSttTxtNd, 1 );
330 rDocNds._MoveNodes( aMvRg, rDocNds, aRg.aEnd, TRUE );
334 if( nSectDiff || nReplaceDummy )
335 lcl_MakeAutoFrms( *pDoc->GetSpzFrmFmts(),
336 bJoinNext ? pEndTxtNd->GetIndex() : pSttTxtNd->GetIndex() );
338 else
339 nNode = 0; // kein Node verschoben -> keine Differenz zum Ende
341 // wurden davor noch Nodes geloescht ?? (FootNotes haben ContentNodes!)
342 if( !pSttTxtNd && !pEndTxtNd )
344 nNdDiff = nSttNode - rPam.GetPoint()->nNode.GetIndex() - (bFullPara ? 0 : 1);
345 rPam.Move( fnMoveForward, fnGoNode );
347 else
349 nNdDiff = nSttNode;
350 if( nSectDiff && bBackSp )
351 nNdDiff += nSectDiff;
352 nNdDiff -= rPam.GetPoint()->nNode.GetIndex();
355 if( !rPam.GetNode()->IsCntntNode() )
356 rPam.GetPoint()->nContent.Assign( 0, 0 );
358 // wird die History ueberhaupt benoetigt ??
359 if( pHistory && !pHistory->Count() )
360 DELETEZ( pHistory );
363 BOOL SwUndoDelete::SaveCntnt( const SwPosition* pStt, const SwPosition* pEnd,
364 SwTxtNode* pSttTxtNd, SwTxtNode* pEndTxtNd )
366 ULONG nNdIdx = pStt->nNode.GetIndex();
367 // 1 - kopiere den Anfang in den Start-String
368 if( pSttTxtNd )
370 BOOL bOneNode = nSttNode == nEndNode;
371 xub_StrLen nLen = bOneNode ? nEndCntnt - nSttCntnt
372 : pSttTxtNd->GetTxt().Len() - nSttCntnt;
373 SwRegHistory aRHst( *pSttTxtNd, pHistory );
374 // always save all text atttibutes because of possibly overlapping
375 // areas of on/off
376 pHistory->CopyAttr( pSttTxtNd->GetpSwpHints(), nNdIdx,
377 0, pSttTxtNd->GetTxt().Len(), true );
378 if( !bOneNode && pSttTxtNd->HasSwAttrSet() )
379 pHistory->CopyFmtAttr( *pSttTxtNd->GetpSwAttrSet(), nNdIdx );
381 // die Laenge kann sich veraendert haben (!!Felder!!)
382 nLen = ( bOneNode ? pEnd->nContent.GetIndex() : pSttTxtNd->GetTxt().Len() )
383 - pStt->nContent.GetIndex();
386 // loesche jetzt noch den Text (alle Attribut-Aenderungen kommen in
387 // die Undo-History
388 pSttStr = (String*)new String( pSttTxtNd->GetTxt().Copy( nSttCntnt, nLen ));
389 pSttTxtNd->Erase( pStt->nContent, nLen );
390 if( pSttTxtNd->GetpSwpHints() )
391 pSttTxtNd->GetpSwpHints()->DeRegister();
393 // METADATA: store
394 bool emptied( pSttStr->Len() && !pSttTxtNd->Len() );
395 if (!bOneNode || emptied) // merging may overwrite xmlids...
397 m_pMetadataUndoStart = pSttTxtNd->CreateUndo( emptied );
400 if( bOneNode )
401 return FALSE; // keine Nodes mehr verschieben
405 // 2 - kopiere das Ende in den End-String
406 if( pEndTxtNd )
408 SwIndex aEndIdx( pEndTxtNd );
409 nNdIdx = pEnd->nNode.GetIndex();
410 SwRegHistory aRHst( *pEndTxtNd, pHistory );
412 // always save all text atttibutes because of possibly overlapping
413 // areas of on/off
414 pHistory->CopyAttr( pEndTxtNd->GetpSwpHints(), nNdIdx, 0,
415 pEndTxtNd->GetTxt().Len(), true );
417 if( pEndTxtNd->HasSwAttrSet() )
418 pHistory->CopyFmtAttr( *pEndTxtNd->GetpSwAttrSet(), nNdIdx );
421 // loesche jetzt noch den Text (alle Attribut-Aenderungen kommen in
422 // die Undo-History
423 pEndStr = (String*)new String( pEndTxtNd->GetTxt().Copy( 0,
424 pEnd->nContent.GetIndex() ));
425 pEndTxtNd->Erase( aEndIdx, pEnd->nContent.GetIndex() );
426 if( pEndTxtNd->GetpSwpHints() )
427 pEndTxtNd->GetpSwpHints()->DeRegister();
429 // METADATA: store
430 bool emptied( pEndStr->Len() && !pEndTxtNd->Len() );
431 m_pMetadataUndoEnd = pEndTxtNd->CreateUndo( emptied );
434 // sind es nur zwei Nodes, dann ist schon alles erledigt.
435 if( ( pSttTxtNd || pEndTxtNd ) && nSttNode + 1 == nEndNode )
436 return FALSE; // keine Nodes mehr verschieben
438 return TRUE; // verschiebe die dazwischen liegenden Nodes
442 BOOL SwUndoDelete::CanGrouping( SwDoc* pDoc, const SwPaM& rDelPam )
444 // ist das Undo groesser als 1 Node ? (sprich: Start und EndString)
445 if( pSttStr ? !pSttStr->Len() || pEndStr : TRUE )
446 return FALSE;
448 // es kann nur das Loeschen von einzelnen char's zusammengefasst werden
449 if( nSttNode != nEndNode || ( !bGroup && nSttCntnt+1 != nEndCntnt ))
450 return FALSE;
452 const SwPosition *pStt = rDelPam.Start(),
453 *pEnd = rDelPam.GetPoint() == pStt
454 ? rDelPam.GetMark()
455 : rDelPam.GetPoint();
457 if( pStt->nNode != pEnd->nNode ||
458 pStt->nContent.GetIndex()+1 != pEnd->nContent.GetIndex() ||
459 pEnd->nNode != nSttNode )
460 return FALSE;
462 // untercheide zwischen BackSpace und Delete. Es muss dann das
463 // Undo-Array unterschiedlich aufgebaut werden !!
464 if( pEnd->nContent == nSttCntnt )
466 if( bGroup && !bBackSp ) return FALSE;
467 bBackSp = TRUE;
469 else if( pStt->nContent == nSttCntnt )
471 if( bGroup && bBackSp ) return FALSE;
472 bBackSp = FALSE;
474 else
475 return FALSE;
477 // sind die beiden Nodes (Nodes-/Undo-Array) ueberhaupt TextNodes?
478 SwTxtNode * pDelTxtNd = pStt->nNode.GetNode().GetTxtNode();
479 if( !pDelTxtNd ) return FALSE;
481 xub_StrLen nUChrPos = bBackSp ? 0 : pSttStr->Len()-1;
482 sal_Unicode cDelChar = pDelTxtNd->GetTxt().GetChar( pStt->nContent.GetIndex() );
483 CharClass& rCC = GetAppCharClass();
484 if( ( CH_TXTATR_BREAKWORD == cDelChar || CH_TXTATR_INWORD == cDelChar ) ||
485 rCC.isLetterNumeric( String( cDelChar ), 0 ) !=
486 rCC.isLetterNumeric( *pSttStr, nUChrPos ) )
487 return FALSE;
490 SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas;
491 if( !FillSaveData( rDelPam, *pTmpSav, FALSE ))
492 delete pTmpSav, pTmpSav = 0;
494 BOOL bOk = ( !pRedlSaveData && !pTmpSav ) ||
495 ( pRedlSaveData && pTmpSav &&
496 SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav, bBackSp ));
497 delete pTmpSav;
498 if( !bOk )
499 return FALSE;
501 pDoc->DeleteRedline( rDelPam, false, USHRT_MAX );
504 // Ok, die beiden 'Deletes' koennen zusammen gefasst werden, also
505 // 'verschiebe' das enstprechende Zeichen
506 if( bBackSp )
507 nSttCntnt--; // BackSpace: Zeichen in Array einfuegen !!
508 else
510 nEndCntnt++; // Delete: Zeichen am Ende anhaengen
511 nUChrPos++;
513 pSttStr->Insert( cDelChar, nUChrPos );
514 pDelTxtNd->Erase( pStt->nContent, 1 );
516 bGroup = TRUE;
517 return TRUE;
522 SwUndoDelete::~SwUndoDelete()
524 delete pSttStr;
525 delete pEndStr;
526 if( pMvStt ) // loesche noch den Bereich aus dem UndoNodes Array
528 // Insert speichert den Inhalt in der IconSection
529 pMvStt->GetNode().GetNodes().Delete( *pMvStt, nNode );
530 delete pMvStt;
532 delete pRedlData;
533 delete pRedlSaveData;
536 static SwRewriter lcl_RewriterFromHistory(SwHistory & rHistory)
538 SwRewriter aRewriter;
540 bool bDone = false;
542 for ( USHORT n = 0; n < rHistory.Count(); n++)
544 String aDescr = rHistory[n]->GetDescription();
546 if (aDescr.Len() > 0)
548 aRewriter.AddRule(UNDO_ARG2, aDescr);
550 bDone = true;
551 break;
555 if (! bDone)
557 aRewriter.AddRule(UNDO_ARG2, SW_RES(STR_FIELD));
560 return aRewriter;
563 SwRewriter SwUndoDelete::GetRewriter() const
565 SwRewriter aResult;
566 String * pStr = NULL;
568 if (nNode != 0)
570 if (sTableName.Len() > 0)
573 SwRewriter aRewriter;
574 aRewriter.AddRule(UNDO_ARG1, SW_RES(STR_START_QUOTE));
575 aRewriter.AddRule(UNDO_ARG2, sTableName);
576 aRewriter.AddRule(UNDO_ARG3, SW_RES(STR_END_QUOTE));
578 String sTmp = aRewriter.Apply(SW_RES(STR_TABLE_NAME));
579 aResult.AddRule(UNDO_ARG1, sTmp);
581 else
582 aResult.AddRule(UNDO_ARG1, String(SW_RES(STR_PARAGRAPHS)));
584 else
586 String aStr;
588 if (pSttStr != NULL && pEndStr != NULL && pSttStr->Len() == 0 &&
589 pEndStr->Len() == 0)
591 aStr = SW_RES(STR_PARAGRAPH_UNDO);
593 else
595 if (pSttStr != NULL)
596 pStr = pSttStr;
597 else if (pEndStr != NULL)
598 pStr = pEndStr;
600 if (pStr != NULL)
602 aStr = DenoteSpecialCharacters(*pStr);
604 else
606 aStr = UNDO_ARG2;
610 aStr = ShortenString(aStr, nUndoStringLength, String(SW_RES(STR_LDOTS)));
611 if (pHistory)
613 SwRewriter aRewriter = lcl_RewriterFromHistory(*pHistory);
614 aStr = aRewriter.Apply(aStr);
617 aResult.AddRule(UNDO_ARG1, aStr);
620 return aResult;
623 // Every object, anchored "AtCntnt" will be reanchored at rPos
624 void lcl_ReAnchorAtCntntFlyFrames( const SwSpzFrmFmts& rSpzArr, SwPosition &rPos, ULONG nOldIdx )
626 if( rSpzArr.Count() )
628 SwFlyFrmFmt* pFmt;
629 const SwFmtAnchor* pAnchor;
630 const SwPosition* pAPos;
631 for( USHORT n = 0; n < rSpzArr.Count(); ++n )
633 pFmt = (SwFlyFrmFmt*)rSpzArr[n];
634 pAnchor = &pFmt->GetAnchor();
635 if( pAnchor->GetAnchorId() == FLY_AT_CNTNT )
637 pAPos = pAnchor->GetCntntAnchor();
638 if( pAPos && nOldIdx == pAPos->nNode.GetIndex() )
640 SwFmtAnchor aAnch( *pAnchor );
641 aAnch.SetAnchor( &rPos );
642 pFmt->SetFmtAttr( aAnch );
649 void SwUndoDelete::Undo( SwUndoIter& rUndoIter )
651 SwDoc* pDoc = &rUndoIter.GetDoc();
652 BOOL bUndo = pDoc->DoesUndo();
653 pDoc->DoUndo( FALSE );
655 ULONG nCalcStt = nSttNode - nNdDiff;
657 if( nSectDiff && bBackSp )
658 nCalcStt += nSectDiff;
660 SwNodeIndex aIdx( pDoc->GetNodes(), nCalcStt );
661 SwNode* pInsNd = &aIdx.GetNode();
663 { // Block, damit der SwPosition beim loeschen vom Node
664 // abgemeldet ist
665 SwPosition aPos( aIdx );
666 if( !bDelFullPara )
668 if( pInsNd->IsTableNode() )
670 pInsNd = pDoc->GetNodes().MakeTxtNode( aIdx,
671 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
672 aIdx--;
673 aPos.nNode = aIdx;
674 aPos.nContent.Assign( pInsNd->GetCntntNode(), nSttCntnt );
676 else
678 if( pInsNd->IsCntntNode() )
679 aPos.nContent.Assign( (SwCntntNode*)pInsNd, nSttCntnt );
680 if( !bTblDelLastNd )
681 pInsNd = 0; // Node nicht loeschen !!
684 else
685 pInsNd = 0; // Node nicht loeschen !!
687 SwNodes* pUNds = (SwNodes*)pDoc->GetUndoNds();
688 BOOL bNodeMove = 0 != nNode;
690 if( pEndStr )
692 // alle Attribute verwerfen, wurden alle gespeichert!
693 SwTxtNode* pTxtNd = aPos.nNode.GetNode().GetTxtNode();
695 if( pTxtNd && pTxtNd->HasSwAttrSet() )
696 pTxtNd->ResetAllAttr();
698 if( pTxtNd && pTxtNd->GetpSwpHints() )
699 pTxtNd->ClearSwpHintsArr( true );
701 if( pSttStr && !bFromTableCopy )
703 ULONG nOldIdx = aPos.nNode.GetIndex();
704 pDoc->SplitNode( aPos, false );
705 // After the split all objects are anchored at the first paragraph,
706 // but the pHistory of the fly frame formats relies on anchoring at
707 // the start of the selection => selection backwards needs a correction.
708 if( bBackSp )
709 lcl_ReAnchorAtCntntFlyFrames( *pDoc->GetSpzFrmFmts(), aPos, nOldIdx );
710 pTxtNd = aPos.nNode.GetNode().GetTxtNode();
712 if( pTxtNd )
714 pTxtNd->Insert( *pEndStr, aPos.nContent, INS_NOHINTEXPAND );
715 // METADATA: restore
716 pTxtNd->RestoreMetadata(m_pMetadataUndoEnd);
719 else if( pSttStr && bNodeMove )
721 SwTxtNode * pNd = aPos.nNode.GetNode().GetTxtNode();
722 if( pNd )
724 if( nSttCntnt < pNd->GetTxt().Len() )
726 ULONG nOldIdx = aPos.nNode.GetIndex();
727 pDoc->SplitNode( aPos, false );
728 if( bBackSp )
729 lcl_ReAnchorAtCntntFlyFrames( *pDoc->GetSpzFrmFmts(), aPos, nOldIdx );
731 else
732 aPos.nNode++;
735 SwNode* pMovedNode = NULL;
736 if( nSectDiff )
738 ULONG nMoveIndex = aPos.nNode.GetIndex();
739 int nDiff = 0;
740 if( bJoinNext )
742 nMoveIndex += nSectDiff + 1;
743 pMovedNode = &aPos.nNode.GetNode();
745 else
747 nMoveIndex -= nSectDiff + 1;
748 ++nDiff;
750 SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex );
751 SwNodeRange aRg( aPos.nNode, 0 - nDiff, aPos.nNode, 1 - nDiff );
752 aPos.nNode--;
753 if( !bJoinNext )
754 pMovedNode = &aPos.nNode.GetNode();
755 pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, TRUE );
756 aPos.nNode++;
759 if( bNodeMove )
761 SwNodeRange aRange( *pMvStt, 0, *pMvStt, nNode );
762 SwNodeIndex aCopyIndex( aPos.nNode, -1 );
763 pUNds->_Copy( aRange, aPos.nNode );
765 if( nReplaceDummy )
767 ULONG nMoveIndex;
768 if( bJoinNext )
770 nMoveIndex = nEndNode - nNdDiff;
771 aPos.nNode = nMoveIndex + nReplaceDummy;
773 else
775 aPos = SwPosition( aCopyIndex );
776 nMoveIndex = aPos.nNode.GetIndex() + nReplaceDummy + 1;
778 SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex );
779 SwNodeRange aRg( aPos.nNode, 0, aPos.nNode, 1 );
780 pMovedNode = &aPos.nNode.GetNode();
781 pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, TRUE );
782 pDoc->GetNodes().Delete( aMvIdx, 1 );
786 if( pMovedNode )
787 lcl_MakeAutoFrms( *pDoc->GetSpzFrmFmts(), pMovedNode->GetIndex() );
789 if( pSttStr )
791 aPos.nNode = nSttNode - nNdDiff + ( bJoinNext ? 0 : nReplaceDummy );
792 SwTxtNode * pTxtNd = aPos.nNode.GetNode().GetTxtNode();
793 // wenn mehr als ein Node geloescht wurde, dann wurden auch
794 // alle "Node"-Attribute gespeichert
796 if (pTxtNd != NULL)
798 if( pTxtNd->HasSwAttrSet() && bNodeMove && !pEndStr )
799 pTxtNd->ResetAllAttr();
801 if( pTxtNd->GetpSwpHints() )
802 pTxtNd->ClearSwpHintsArr( true );
804 // SectionNode-Modus und von oben nach unten selektiert:
805 // -> im StartNode steht noch der Rest vom Join => loeschen
806 aPos.nContent.Assign( pTxtNd, nSttCntnt );
807 pTxtNd->Insert( *pSttStr, aPos.nContent, INS_NOHINTEXPAND );
808 // METADATA: restore
809 pTxtNd->RestoreMetadata(m_pMetadataUndoStart);
813 if( pHistory )
815 pHistory->TmpRollback( pDoc, nSetPos, false );
816 if( nSetPos ) // es gab Fussnoten/FlyFrames
818 // gibts ausser diesen noch andere ?
819 if( nSetPos < pHistory->Count() )
821 // dann sicher die Attribute anderen Attribute
822 SwHistory aHstr;
823 aHstr.Move( 0, pHistory, nSetPos );
824 pHistory->Rollback( pDoc );
825 pHistory->Move( 0, &aHstr );
827 else
829 pHistory->Rollback( pDoc );
830 DELETEZ( pHistory );
835 if( bResetPgDesc || bResetPgBrk )
837 USHORT nStt = static_cast<USHORT>( bResetPgDesc ? RES_PAGEDESC : RES_BREAK );
838 USHORT nEnd = static_cast<USHORT>( bResetPgBrk ? RES_BREAK : RES_PAGEDESC );
840 SwNode* pNode = pDoc->GetNodes()[ nEndNode + 1 ];
841 if( pNode->IsCntntNode() )
842 ((SwCntntNode*)pNode)->ResetAttr( nStt, nEnd );
843 else if( pNode->IsTableNode() )
844 ((SwTableNode*)pNode)->GetTable().GetFrmFmt()->ResetFmtAttr( nStt, nEnd );
847 // den temp. eingefuegten Node noch loeschen !!
848 if( pInsNd )
849 pDoc->GetNodes().Delete( aIdx, 1 );
850 if( pRedlSaveData )
851 SetSaveData( *pDoc, *pRedlSaveData );
853 pDoc->DoUndo( bUndo ); // Undo wieder einschalten
854 SetPaM( rUndoIter, TRUE );
857 void SwUndoDelete::Redo( SwUndoIter& rUndoIter )
859 rUndoIter.SetUpdateAttr( TRUE );
861 SwPaM& rPam = *rUndoIter.pAktPam;
862 SwDoc& rDoc = *rPam.GetDoc();
864 SetPaM( rPam );
866 if( pRedlSaveData )
867 rDoc.DeleteRedline( rPam, false, USHRT_MAX );
869 if( !bDelFullPara )
871 SwUndRng aTmpRng( rPam );
872 RemoveIdxFromRange( rPam, FALSE );
873 aTmpRng.SetPaM( rPam );
875 if( !bJoinNext ) // Dann Selektion von unten nach oben
876 rPam.Exchange(); // wieder herstellen!
879 if( pHistory ) // wurden Attribute gesichert ?
881 pHistory->SetTmpEnd( pHistory->Count() );
882 SwHistory aHstr;
883 aHstr.Move( 0, pHistory );
885 if( bDelFullPara )
887 ASSERT( rPam.HasMark(), "PaM ohne Mark" );
888 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
889 DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
891 _DelBookmarks(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
893 else
894 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
895 nSetPos = pHistory ? pHistory->Count() : 0;
897 pHistory->Move( nSetPos, &aHstr );
899 else
901 if( bDelFullPara )
903 ASSERT( rPam.HasMark(), "PaM ohne Mark" );
904 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
905 DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
907 _DelBookmarks( rPam.GetMark()->nNode, rPam.GetPoint()->nNode );
909 else
910 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
911 nSetPos = pHistory ? pHistory->Count() : 0;
914 if( !pSttStr && !pEndStr )
916 SwNodeIndex aSttIdx = ( bDelFullPara || bJoinNext )
917 ? rPam.GetMark()->nNode
918 : rPam.GetPoint()->nNode;
919 SwTableNode* pTblNd = aSttIdx.GetNode().GetTableNode();
920 if( pTblNd )
922 if( bTblDelLastNd )
924 // dann am Ende wieder einen Node einfuegen
925 const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
926 rDoc.GetNodes().MakeTxtNode( aTmpIdx,
927 rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
930 SwCntntNode* pNextNd = rDoc.GetNodes()[
931 pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
932 if( pNextNd )
934 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
936 const SfxPoolItem *pItem;
937 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
938 FALSE, &pItem ) )
939 pNextNd->SetAttr( *pItem );
941 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
942 FALSE, &pItem ) )
943 pNextNd->SetAttr( *pItem );
945 pTblNd->DelFrms();
948 rPam.SetMark();
949 rPam.DeleteMark();
951 rDoc.GetNodes().Delete( aSttIdx, nEndNode - nSttNode );
953 // setze den Cursor immer in einen ContentNode !!
954 if( !rPam.Move( fnMoveBackward, fnGoCntnt ) &&
955 !rPam.Move( fnMoveForward, fnGoCntnt ) )
956 rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), 0 );
958 else if( bDelFullPara )
960 // der Pam wurde am Point( == Ende) um eins erhoeht, um einen
961 // Bereich fuers Undo zu haben. Der muss jetzt aber wieder entfernt
962 // werden!!!
963 rPam.End()->nNode--;
964 if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
965 *rPam.GetMark() = *rPam.GetPoint();
966 rDoc.DelFullPara( rPam );
968 else
969 rDoc.DeleteAndJoin( rPam );
972 void SwUndoDelete::Repeat( SwUndoIter& rUndoIter )
974 if( UNDO_DELETE == rUndoIter.GetLastUndoId() )
975 return;
977 SwPaM& rPam = *rUndoIter.pAktPam;
978 SwDoc& rDoc = *rPam.GetDoc();
979 BOOL bGroupUndo = rDoc.DoesGroupUndo();
980 rDoc.DoGroupUndo( FALSE );
981 if( !rPam.HasMark() )
983 rPam.SetMark();
984 rPam.Move( fnMoveForward, fnGoCntnt );
986 if( bDelFullPara )
987 rDoc.DelFullPara( rPam );
988 else
989 rDoc.DeleteAndJoin( rPam );
990 rDoc.DoGroupUndo( bGroupUndo );
991 rUndoIter.pLastUndoObj = this;
995 void SwUndoDelete::SetTableName(const String & rName)
997 sTableName = rName;