Update ooo320-m1
[ooovba.git] / sw / source / core / undo / undel.cxx
blob1ebc3a084f20b83df1ccc6933e5d7a82ed22d392
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->EraseText( 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->EraseText( 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->EraseText( 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->InsertText( *pEndStr, aPos.nContent,
715 IDocumentContentOperations::INS_NOHINTEXPAND );
716 // METADATA: restore
717 pTxtNd->RestoreMetadata(m_pMetadataUndoEnd);
720 else if( pSttStr && bNodeMove )
722 SwTxtNode * pNd = aPos.nNode.GetNode().GetTxtNode();
723 if( pNd )
725 if( nSttCntnt < pNd->GetTxt().Len() )
727 ULONG nOldIdx = aPos.nNode.GetIndex();
728 pDoc->SplitNode( aPos, false );
729 if( bBackSp )
730 lcl_ReAnchorAtCntntFlyFrames( *pDoc->GetSpzFrmFmts(), aPos, nOldIdx );
732 else
733 aPos.nNode++;
736 SwNode* pMovedNode = NULL;
737 if( nSectDiff )
739 ULONG nMoveIndex = aPos.nNode.GetIndex();
740 int nDiff = 0;
741 if( bJoinNext )
743 nMoveIndex += nSectDiff + 1;
744 pMovedNode = &aPos.nNode.GetNode();
746 else
748 nMoveIndex -= nSectDiff + 1;
749 ++nDiff;
751 SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex );
752 SwNodeRange aRg( aPos.nNode, 0 - nDiff, aPos.nNode, 1 - nDiff );
753 aPos.nNode--;
754 if( !bJoinNext )
755 pMovedNode = &aPos.nNode.GetNode();
756 pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, TRUE );
757 aPos.nNode++;
760 if( bNodeMove )
762 SwNodeRange aRange( *pMvStt, 0, *pMvStt, nNode );
763 SwNodeIndex aCopyIndex( aPos.nNode, -1 );
764 pUNds->_Copy( aRange, aPos.nNode );
766 if( nReplaceDummy )
768 ULONG nMoveIndex;
769 if( bJoinNext )
771 nMoveIndex = nEndNode - nNdDiff;
772 aPos.nNode = nMoveIndex + nReplaceDummy;
774 else
776 aPos = SwPosition( aCopyIndex );
777 nMoveIndex = aPos.nNode.GetIndex() + nReplaceDummy + 1;
779 SwNodeIndex aMvIdx( pDoc->GetNodes(), nMoveIndex );
780 SwNodeRange aRg( aPos.nNode, 0, aPos.nNode, 1 );
781 pMovedNode = &aPos.nNode.GetNode();
782 pDoc->GetNodes()._MoveNodes( aRg, pDoc->GetNodes(), aMvIdx, TRUE );
783 pDoc->GetNodes().Delete( aMvIdx, 1 );
787 if( pMovedNode )
788 lcl_MakeAutoFrms( *pDoc->GetSpzFrmFmts(), pMovedNode->GetIndex() );
790 if( pSttStr )
792 aPos.nNode = nSttNode - nNdDiff + ( bJoinNext ? 0 : nReplaceDummy );
793 SwTxtNode * pTxtNd = aPos.nNode.GetNode().GetTxtNode();
794 // wenn mehr als ein Node geloescht wurde, dann wurden auch
795 // alle "Node"-Attribute gespeichert
797 if (pTxtNd != NULL)
799 if( pTxtNd->HasSwAttrSet() && bNodeMove && !pEndStr )
800 pTxtNd->ResetAllAttr();
802 if( pTxtNd->GetpSwpHints() )
803 pTxtNd->ClearSwpHintsArr( true );
805 // SectionNode-Modus und von oben nach unten selektiert:
806 // -> im StartNode steht noch der Rest vom Join => loeschen
807 aPos.nContent.Assign( pTxtNd, nSttCntnt );
808 pTxtNd->InsertText( *pSttStr, aPos.nContent,
809 IDocumentContentOperations::INS_NOHINTEXPAND );
810 // METADATA: restore
811 pTxtNd->RestoreMetadata(m_pMetadataUndoStart);
815 if( pHistory )
817 pHistory->TmpRollback( pDoc, nSetPos, false );
818 if( nSetPos ) // es gab Fussnoten/FlyFrames
820 // gibts ausser diesen noch andere ?
821 if( nSetPos < pHistory->Count() )
823 // dann sicher die Attribute anderen Attribute
824 SwHistory aHstr;
825 aHstr.Move( 0, pHistory, nSetPos );
826 pHistory->Rollback( pDoc );
827 pHistory->Move( 0, &aHstr );
829 else
831 pHistory->Rollback( pDoc );
832 DELETEZ( pHistory );
837 if( bResetPgDesc || bResetPgBrk )
839 USHORT nStt = static_cast<USHORT>( bResetPgDesc ? RES_PAGEDESC : RES_BREAK );
840 USHORT nEnd = static_cast<USHORT>( bResetPgBrk ? RES_BREAK : RES_PAGEDESC );
842 SwNode* pNode = pDoc->GetNodes()[ nEndNode + 1 ];
843 if( pNode->IsCntntNode() )
844 ((SwCntntNode*)pNode)->ResetAttr( nStt, nEnd );
845 else if( pNode->IsTableNode() )
846 ((SwTableNode*)pNode)->GetTable().GetFrmFmt()->ResetFmtAttr( nStt, nEnd );
849 // den temp. eingefuegten Node noch loeschen !!
850 if( pInsNd )
851 pDoc->GetNodes().Delete( aIdx, 1 );
852 if( pRedlSaveData )
853 SetSaveData( *pDoc, *pRedlSaveData );
855 pDoc->DoUndo( bUndo ); // Undo wieder einschalten
856 SetPaM( rUndoIter, TRUE );
859 void SwUndoDelete::Redo( SwUndoIter& rUndoIter )
861 rUndoIter.SetUpdateAttr( TRUE );
863 SwPaM& rPam = *rUndoIter.pAktPam;
864 SwDoc& rDoc = *rPam.GetDoc();
866 SetPaM( rPam );
868 if( pRedlSaveData )
869 rDoc.DeleteRedline( rPam, false, USHRT_MAX );
871 if( !bDelFullPara )
873 SwUndRng aTmpRng( rPam );
874 RemoveIdxFromRange( rPam, FALSE );
875 aTmpRng.SetPaM( rPam );
877 if( !bJoinNext ) // Dann Selektion von unten nach oben
878 rPam.Exchange(); // wieder herstellen!
881 if( pHistory ) // wurden Attribute gesichert ?
883 pHistory->SetTmpEnd( pHistory->Count() );
884 SwHistory aHstr;
885 aHstr.Move( 0, pHistory );
887 if( bDelFullPara )
889 ASSERT( rPam.HasMark(), "PaM ohne Mark" );
890 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
891 DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
893 _DelBookmarks(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
895 else
896 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
897 nSetPos = pHistory ? pHistory->Count() : 0;
899 pHistory->Move( nSetPos, &aHstr );
901 else
903 if( bDelFullPara )
905 ASSERT( rPam.HasMark(), "PaM ohne Mark" );
906 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint(),
907 DelCntntType(nsDelCntntType::DELCNT_ALL | nsDelCntntType::DELCNT_CHKNOCNTNT) );
909 _DelBookmarks( rPam.GetMark()->nNode, rPam.GetPoint()->nNode );
911 else
912 DelCntntIndex( *rPam.GetMark(), *rPam.GetPoint() );
913 nSetPos = pHistory ? pHistory->Count() : 0;
916 if( !pSttStr && !pEndStr )
918 SwNodeIndex aSttIdx = ( bDelFullPara || bJoinNext )
919 ? rPam.GetMark()->nNode
920 : rPam.GetPoint()->nNode;
921 SwTableNode* pTblNd = aSttIdx.GetNode().GetTableNode();
922 if( pTblNd )
924 if( bTblDelLastNd )
926 // dann am Ende wieder einen Node einfuegen
927 const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
928 rDoc.GetNodes().MakeTxtNode( aTmpIdx,
929 rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
932 SwCntntNode* pNextNd = rDoc.GetNodes()[
933 pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
934 if( pNextNd )
936 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
938 const SfxPoolItem *pItem;
939 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
940 FALSE, &pItem ) )
941 pNextNd->SetAttr( *pItem );
943 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
944 FALSE, &pItem ) )
945 pNextNd->SetAttr( *pItem );
947 pTblNd->DelFrms();
950 rPam.SetMark();
951 rPam.DeleteMark();
953 rDoc.GetNodes().Delete( aSttIdx, nEndNode - nSttNode );
955 // setze den Cursor immer in einen ContentNode !!
956 if( !rPam.Move( fnMoveBackward, fnGoCntnt ) &&
957 !rPam.Move( fnMoveForward, fnGoCntnt ) )
958 rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), 0 );
960 else if( bDelFullPara )
962 // der Pam wurde am Point( == Ende) um eins erhoeht, um einen
963 // Bereich fuers Undo zu haben. Der muss jetzt aber wieder entfernt
964 // werden!!!
965 rPam.End()->nNode--;
966 if( rPam.GetPoint()->nNode == rPam.GetMark()->nNode )
967 *rPam.GetMark() = *rPam.GetPoint();
968 rDoc.DelFullPara( rPam );
970 else
971 rDoc.DeleteAndJoin( rPam );
974 void SwUndoDelete::Repeat( SwUndoIter& rUndoIter )
976 if( UNDO_DELETE == rUndoIter.GetLastUndoId() )
977 return;
979 SwPaM& rPam = *rUndoIter.pAktPam;
980 SwDoc& rDoc = *rPam.GetDoc();
981 BOOL bGroupUndo = rDoc.DoesGroupUndo();
982 rDoc.DoGroupUndo( FALSE );
983 if( !rPam.HasMark() )
985 rPam.SetMark();
986 rPam.Move( fnMoveForward, fnGoCntnt );
988 if( bDelFullPara )
989 rDoc.DelFullPara( rPam );
990 else
991 rDoc.DeleteAndJoin( rPam );
992 rDoc.DoGroupUndo( bGroupUndo );
993 rUndoIter.pLastUndoObj = this;
997 void SwUndoDelete::SetTableName(const String & rName)
999 sTableName = rName;