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
->EraseText( 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
->EraseText( 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
->EraseText( 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
->InsertText( *pEndStr
, aPos
.nContent
,
715 IDocumentContentOperations::INS_NOHINTEXPAND
);
717 pTxtNd
->RestoreMetadata(m_pMetadataUndoEnd
);
720 else if( pSttStr
&& bNodeMove
)
722 SwTxtNode
* pNd
= aPos
.nNode
.GetNode().GetTxtNode();
725 if( nSttCntnt
< pNd
->GetTxt().Len() )
727 ULONG nOldIdx
= aPos
.nNode
.GetIndex();
728 pDoc
->SplitNode( aPos
, false );
730 lcl_ReAnchorAtCntntFlyFrames( *pDoc
->GetSpzFrmFmts(), aPos
, nOldIdx
);
736 SwNode
* pMovedNode
= NULL
;
739 ULONG nMoveIndex
= aPos
.nNode
.GetIndex();
743 nMoveIndex
+= nSectDiff
+ 1;
744 pMovedNode
= &aPos
.nNode
.GetNode();
748 nMoveIndex
-= nSectDiff
+ 1;
751 SwNodeIndex
aMvIdx( pDoc
->GetNodes(), nMoveIndex
);
752 SwNodeRange
aRg( aPos
.nNode
, 0 - nDiff
, aPos
.nNode
, 1 - nDiff
);
755 pMovedNode
= &aPos
.nNode
.GetNode();
756 pDoc
->GetNodes()._MoveNodes( aRg
, pDoc
->GetNodes(), aMvIdx
, TRUE
);
762 SwNodeRange
aRange( *pMvStt
, 0, *pMvStt
, nNode
);
763 SwNodeIndex
aCopyIndex( aPos
.nNode
, -1 );
764 pUNds
->_Copy( aRange
, aPos
.nNode
);
771 nMoveIndex
= nEndNode
- nNdDiff
;
772 aPos
.nNode
= nMoveIndex
+ nReplaceDummy
;
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 );
788 lcl_MakeAutoFrms( *pDoc
->GetSpzFrmFmts(), pMovedNode
->GetIndex() );
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
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
);
811 pTxtNd
->RestoreMetadata(m_pMetadataUndoStart
);
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
825 aHstr
.Move( 0, pHistory
, nSetPos
);
826 pHistory
->Rollback( pDoc
);
827 pHistory
->Move( 0, &aHstr
);
831 pHistory
->Rollback( pDoc
);
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 !!
851 pDoc
->GetNodes().Delete( aIdx
, 1 );
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();
869 rDoc
.DeleteRedline( rPam
, false, USHRT_MAX
);
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() );
885 aHstr
.Move( 0, pHistory
);
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
);
896 DelCntntIndex( *rPam
.GetMark(), *rPam
.GetPoint() );
897 nSetPos
= pHistory
? pHistory
->Count() : 0;
899 pHistory
->Move( nSetPos
, &aHstr
);
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
);
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();
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();
936 SwFrmFmt
* pTableFmt
= pTblNd
->GetTable().GetFrmFmt();
938 const SfxPoolItem
*pItem
;
939 if( SFX_ITEM_SET
== pTableFmt
->GetItemState( RES_PAGEDESC
,
941 pNextNd
->SetAttr( *pItem
);
943 if( SFX_ITEM_SET
== pTableFmt
->GetItemState( RES_BREAK
,
945 pNextNd
->SetAttr( *pItem
);
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
966 if( rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
)
967 *rPam
.GetMark() = *rPam
.GetPoint();
968 rDoc
.DelFullPara( rPam
);
971 rDoc
.DeleteAndJoin( rPam
);
974 void SwUndoDelete::Repeat( SwUndoIter
& rUndoIter
)
976 if( UNDO_DELETE
== rUndoIter
.GetLastUndoId() )
979 SwPaM
& rPam
= *rUndoIter
.pAktPam
;
980 SwDoc
& rDoc
= *rPam
.GetDoc();
981 BOOL bGroupUndo
= rDoc
.DoesGroupUndo();
982 rDoc
.DoGroupUndo( FALSE
);
983 if( !rPam
.HasMark() )
986 rPam
.Move( fnMoveForward
, fnGoCntnt
);
989 rDoc
.DelFullPara( rPam
);
991 rDoc
.DeleteAndJoin( rPam
);
992 rDoc
.DoGroupUndo( bGroupUndo
);
993 rUndoIter
.pLastUndoObj
= this;
997 void SwUndoDelete::SetTableName(const String
& rName
)