1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: undel.cxx,v $
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>
40 #include <fmtanchr.hxx>
42 #include <swtable.hxx>
43 #include <swundo.hxx> // fuer die UndoIds
48 #include <poolfmt.hxx>
50 #include <redline.hxx>
52 #include <sfx2/app.hxx>
56 #include <comcore.hrc> // #111827#
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(); }
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
)
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() )
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
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;
138 pHistory
= new SwHistory
;
140 // loesche erstmal alle Fussnoten
141 const SwPosition
*pStt
= rPam
.Start(),
142 *pEnd
= rPam
.GetPoint() == pStt
146 // Step 1. deletion/record of content indizes
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
);
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;
172 pSttTxtNd
= pStt
->nNode
.GetNode().GetTxtNode();
173 pEndTxtNd
= nSttNode
== nEndNode
175 : pEnd
->nNode
.GetNode().GetTxtNode();
178 BOOL bMoveNds
= *pStt
== *pEnd
// noch ein Bereich vorhanden ??
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(
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
) )
215 if( !pSttTxtNd
&& !pEndTxtNd
)
216 rPam
.GetPoint()->nNode
--;
217 rPam
.DeleteMark(); // der SPoint ist aus dem Bereich
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
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() ) )
248 nReplaceDummy
= aRg
.aEnd
.GetIndex() + nNdDiff
- nEndNode
;
250 { // The selection has been expanded, because
254 // The end text node has to leave the (expanded) selection
255 // The dummy is needed because _MoveNodes deletes empty sections
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
);
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() ) )
280 nReplaceDummy
= nSttNode
- nNdDiff
- aRg
.aStart
.GetIndex();
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
);
301 else if( !bFullPara
&& !aRg
.aEnd
.GetNode().IsCntntNode() )
305 else if( pSttTxtNd
&& ( pEndTxtNd
|| pSttTxtNd
->GetTxt().Len() ) )
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
324 SwNodeRange
aMvRg( *pEndTxtNd
, 0, *pEndTxtNd
, 1 );
325 rDocNds
._MoveNodes( aMvRg
, rDocNds
, aRg
.aStart
, TRUE
);
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() );
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
);
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() )
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
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
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
388 pSttStr
= (String
*)new String( pSttTxtNd
->GetTxt().Copy( nSttCntnt
, nLen
));
389 pSttTxtNd
->Erase( pStt
->nContent
, nLen
);
390 if( pSttTxtNd
->GetpSwpHints() )
391 pSttTxtNd
->GetpSwpHints()->DeRegister();
394 bool emptied( pSttStr
->Len() && !pSttTxtNd
->Len() );
395 if (!bOneNode
|| emptied
) // merging may overwrite xmlids...
397 m_pMetadataUndoStart
= pSttTxtNd
->CreateUndo( emptied
);
401 return FALSE
; // keine Nodes mehr verschieben
405 // 2 - kopiere das Ende in den End-String
408 SwIndex
aEndIdx( pEndTxtNd
);
409 nNdIdx
= pEnd
->nNode
.GetIndex();
410 SwRegHistory
aRHst( *pEndTxtNd
, pHistory
);
412 // always save all text atttibutes because of possibly overlapping
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
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();
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
)
448 // es kann nur das Loeschen von einzelnen char's zusammengefasst werden
449 if( nSttNode
!= nEndNode
|| ( !bGroup
&& nSttCntnt
+1 != nEndCntnt
))
452 const SwPosition
*pStt
= rDelPam
.Start(),
453 *pEnd
= rDelPam
.GetPoint() == pStt
455 : rDelPam
.GetPoint();
457 if( pStt
->nNode
!= pEnd
->nNode
||
458 pStt
->nContent
.GetIndex()+1 != pEnd
->nContent
.GetIndex() ||
459 pEnd
->nNode
!= nSttNode
)
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
;
469 else if( pStt
->nContent
== nSttCntnt
)
471 if( bGroup
&& bBackSp
) 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
) )
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
));
501 pDoc
->DeleteRedline( rDelPam
, false, USHRT_MAX
);
504 // Ok, die beiden 'Deletes' koennen zusammen gefasst werden, also
505 // 'verschiebe' das enstprechende Zeichen
507 nSttCntnt
--; // BackSpace: Zeichen in Array einfuegen !!
510 nEndCntnt
++; // Delete: Zeichen am Ende anhaengen
513 pSttStr
->Insert( cDelChar
, nUChrPos
);
514 pDelTxtNd
->Erase( pStt
->nContent
, 1 );
522 SwUndoDelete::~SwUndoDelete()
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
);
533 delete pRedlSaveData
;
536 static SwRewriter
lcl_RewriterFromHistory(SwHistory
& rHistory
)
538 SwRewriter aRewriter
;
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
);
557 aRewriter
.AddRule(UNDO_ARG2
, SW_RES(STR_FIELD
));
563 SwRewriter
SwUndoDelete::GetRewriter() const
566 String
* pStr
= NULL
;
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
);
582 aResult
.AddRule(UNDO_ARG1
, String(SW_RES(STR_PARAGRAPHS
)));
588 if (pSttStr
!= NULL
&& pEndStr
!= NULL
&& pSttStr
->Len() == 0 &&
591 aStr
= SW_RES(STR_PARAGRAPH_UNDO
);
597 else if (pEndStr
!= NULL
)
602 aStr
= DenoteSpecialCharacters(*pStr
);
610 aStr
= ShortenString(aStr
, nUndoStringLength
, String(SW_RES(STR_LDOTS
)));
613 SwRewriter aRewriter
= lcl_RewriterFromHistory(*pHistory
);
614 aStr
= aRewriter
.Apply(aStr
);
617 aResult
.AddRule(UNDO_ARG1
, aStr
);
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() )
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
665 SwPosition
aPos( aIdx
);
668 if( pInsNd
->IsTableNode() )
670 pInsNd
= pDoc
->GetNodes().MakeTxtNode( aIdx
,
671 (SwTxtFmtColl
*)pDoc
->GetDfltTxtFmtColl() );
674 aPos
.nContent
.Assign( pInsNd
->GetCntntNode(), nSttCntnt
);
678 if( pInsNd
->IsCntntNode() )
679 aPos
.nContent
.Assign( (SwCntntNode
*)pInsNd
, nSttCntnt
);
681 pInsNd
= 0; // Node nicht loeschen !!
685 pInsNd
= 0; // Node nicht loeschen !!
687 SwNodes
* pUNds
= (SwNodes
*)pDoc
->GetUndoNds();
688 BOOL bNodeMove
= 0 != nNode
;
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.
709 lcl_ReAnchorAtCntntFlyFrames( *pDoc
->GetSpzFrmFmts(), aPos
, nOldIdx
);
710 pTxtNd
= aPos
.nNode
.GetNode().GetTxtNode();
714 pTxtNd
->Insert( *pEndStr
, aPos
.nContent
, INS_NOHINTEXPAND
);
716 pTxtNd
->RestoreMetadata(m_pMetadataUndoEnd
);
719 else if( pSttStr
&& bNodeMove
)
721 SwTxtNode
* pNd
= aPos
.nNode
.GetNode().GetTxtNode();
724 if( nSttCntnt
< pNd
->GetTxt().Len() )
726 ULONG nOldIdx
= aPos
.nNode
.GetIndex();
727 pDoc
->SplitNode( aPos
, false );
729 lcl_ReAnchorAtCntntFlyFrames( *pDoc
->GetSpzFrmFmts(), aPos
, nOldIdx
);
735 SwNode
* pMovedNode
= NULL
;
738 ULONG nMoveIndex
= aPos
.nNode
.GetIndex();
742 nMoveIndex
+= nSectDiff
+ 1;
743 pMovedNode
= &aPos
.nNode
.GetNode();
747 nMoveIndex
-= nSectDiff
+ 1;
750 SwNodeIndex
aMvIdx( pDoc
->GetNodes(), nMoveIndex
);
751 SwNodeRange
aRg( aPos
.nNode
, 0 - nDiff
, aPos
.nNode
, 1 - nDiff
);
754 pMovedNode
= &aPos
.nNode
.GetNode();
755 pDoc
->GetNodes()._MoveNodes( aRg
, pDoc
->GetNodes(), aMvIdx
, TRUE
);
761 SwNodeRange
aRange( *pMvStt
, 0, *pMvStt
, nNode
);
762 SwNodeIndex
aCopyIndex( aPos
.nNode
, -1 );
763 pUNds
->_Copy( aRange
, aPos
.nNode
);
770 nMoveIndex
= nEndNode
- nNdDiff
;
771 aPos
.nNode
= nMoveIndex
+ nReplaceDummy
;
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 );
787 lcl_MakeAutoFrms( *pDoc
->GetSpzFrmFmts(), pMovedNode
->GetIndex() );
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
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
);
809 pTxtNd
->RestoreMetadata(m_pMetadataUndoStart
);
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
823 aHstr
.Move( 0, pHistory
, nSetPos
);
824 pHistory
->Rollback( pDoc
);
825 pHistory
->Move( 0, &aHstr
);
829 pHistory
->Rollback( pDoc
);
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 !!
849 pDoc
->GetNodes().Delete( aIdx
, 1 );
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();
867 rDoc
.DeleteRedline( rPam
, false, USHRT_MAX
);
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() );
883 aHstr
.Move( 0, pHistory
);
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
);
894 DelCntntIndex( *rPam
.GetMark(), *rPam
.GetPoint() );
895 nSetPos
= pHistory
? pHistory
->Count() : 0;
897 pHistory
->Move( nSetPos
, &aHstr
);
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
);
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();
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();
934 SwFrmFmt
* pTableFmt
= pTblNd
->GetTable().GetFrmFmt();
936 const SfxPoolItem
*pItem
;
937 if( SFX_ITEM_SET
== pTableFmt
->GetItemState( RES_PAGEDESC
,
939 pNextNd
->SetAttr( *pItem
);
941 if( SFX_ITEM_SET
== pTableFmt
->GetItemState( RES_BREAK
,
943 pNextNd
->SetAttr( *pItem
);
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
964 if( rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
)
965 *rPam
.GetMark() = *rPam
.GetPoint();
966 rDoc
.DelFullPara( rPam
);
969 rDoc
.DeleteAndJoin( rPam
);
972 void SwUndoDelete::Repeat( SwUndoIter
& rUndoIter
)
974 if( UNDO_DELETE
== rUndoIter
.GetLastUndoId() )
977 SwPaM
& rPam
= *rUndoIter
.pAktPam
;
978 SwDoc
& rDoc
= *rPam
.GetDoc();
979 BOOL bGroupUndo
= rDoc
.DoesGroupUndo();
980 rDoc
.DoGroupUndo( FALSE
);
981 if( !rPam
.HasMark() )
984 rPam
.Move( fnMoveForward
, fnGoCntnt
);
987 rDoc
.DelFullPara( rPam
);
989 rDoc
.DeleteAndJoin( rPam
);
990 rDoc
.DoGroupUndo( bGroupUndo
);
991 rUndoIter
.pLastUndoObj
= this;
995 void SwUndoDelete::SetTableName(const String
& rName
)