xref: /trunk/main/sw/source/core/undo/undobj1.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <svl/itemiter.hxx>
32 
33 #include <hintids.hxx>
34 #include <hints.hxx>
35 #include <fmtflcnt.hxx>
36 #include <fmtanchr.hxx>
37 #include <fmtcntnt.hxx>
38 #include <txtflcnt.hxx>
39 #include <frmfmt.hxx>
40 #include <flyfrm.hxx>
41 #include <UndoCore.hxx>
42 #include <UndoDraw.hxx>
43 #include <rolbck.hxx>       // fuer die Attribut History
44 #include <doc.hxx>
45 #include <docary.hxx>
46 #include <rootfrm.hxx>
47 #include <swundo.hxx>           // fuer die UndoIds
48 #include <pam.hxx>
49 #include <ndtxt.hxx>
50 // OD 26.06.2003 #108784#
51 #include <dcontact.hxx>
52 #include <ndole.hxx>
53 
54 
55 //---------------------------------------------------------------------
56 // SwUndoLayBase /////////////////////////////////////////////////////////
57 
58 SwUndoFlyBase::SwUndoFlyBase( SwFrmFmt* pFormat, SwUndoId nUndoId )
59     : SwUndo( nUndoId ), pFrmFmt( pFormat )
60 {
61 }
62 
63 SwUndoFlyBase::~SwUndoFlyBase()
64 {
65     if( bDelFmt )       // loeschen waehrend eines Undo's ??
66         delete pFrmFmt;
67 }
68 
69 void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrm)
70 {
71     SwDoc *const pDoc = & rContext.GetDoc();
72 
73     // ins Array wieder eintragen
74     SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts();
75     rFlyFmts.Insert( pFrmFmt, rFlyFmts.Count() );
76 
77     // OD 26.06.2003 #108784# - insert 'master' drawing object into drawing page
78     if ( RES_DRAWFRMFMT == pFrmFmt->Which() )
79     {
80         SwDrawContact* pDrawContact =
81             static_cast<SwDrawContact*>(pFrmFmt->FindContactObj());
82         if ( pDrawContact )
83         {
84             pDrawContact->InsertMasterIntoDrawPage();
85             // --> OD 2005-01-31 #i40845# - follow-up of #i35635#
86             // move object to visible layer
87             pDrawContact->MoveObjToVisibleLayer( pDrawContact->GetMaster() );
88             // <--
89         }
90     }
91 
92     SwFmtAnchor aAnchor( (RndStdIds)nRndId );
93 
94     if (FLY_AT_PAGE == nRndId)
95     {
96         aAnchor.SetPageNum( (sal_uInt16)nNdPgPos );
97     }
98     else
99     {
100         SwPosition aNewPos(pDoc->GetNodes().GetEndOfContent());
101         aNewPos.nNode = nNdPgPos;
102         if ((FLY_AS_CHAR == nRndId) || (FLY_AT_CHAR == nRndId))
103         {
104             aNewPos.nContent.Assign( aNewPos.nNode.GetNode().GetCntntNode(),
105                                     nCntPos );
106         }
107         aAnchor.SetAnchor( &aNewPos );
108     }
109 
110     pFrmFmt->SetFmtAttr( aAnchor );     // Anker neu setzen
111 
112     if( RES_DRAWFRMFMT != pFrmFmt->Which() )
113     {
114         // Content holen und -Attribut neu setzen
115         SwNodeIndex aIdx( pDoc->GetNodes() );
116         RestoreSection( pDoc, &aIdx, SwFlyStartNode );
117         pFrmFmt->SetFmtAttr( SwFmtCntnt( aIdx.GetNode().GetStartNode() ));
118     }
119 
120     //JP 18.12.98: Bug 60505 - InCntntAttribut erst setzen, wenn der Inhalt
121     //              vorhanden ist! Sonst wuerde das Layout den Fly vorher
122     //              formatieren, aber keine Inhalt finden; so geschene bei
123     //              Grafiken aus dem Internet
124     if (FLY_AS_CHAR == nRndId)
125     {
126         // es muss mindestens das Attribut im TextNode stehen
127         SwCntntNode* pCNd = aAnchor.GetCntntAnchor()->nNode.GetNode().GetCntntNode();
128         ASSERT( pCNd->IsTxtNode(), "no Text Node at position." );
129         SwFmtFlyCnt aFmt( pFrmFmt );
130         static_cast<SwTxtNode*>(pCNd)->InsertItem( aFmt, nCntPos, nCntPos );
131     }
132 
133     pFrmFmt->MakeFrms();
134 
135     if( bShowSelFrm )
136     {
137         rContext.SetSelections(pFrmFmt, 0);
138     }
139 
140     if( GetHistory() )
141         GetHistory()->Rollback( pDoc );
142 
143     switch( nRndId )
144     {
145     case FLY_AS_CHAR:
146     case FLY_AT_CHAR:
147         {
148             const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
149             nNdPgPos = rAnchor.GetCntntAnchor()->nNode.GetIndex();
150             nCntPos = rAnchor.GetCntntAnchor()->nContent.GetIndex();
151         }
152         break;
153     case FLY_AT_PARA:
154     case FLY_AT_FLY:
155         {
156             const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
157             nNdPgPos = rAnchor.GetCntntAnchor()->nNode.GetIndex();
158         }
159         break;
160     case FLY_AT_PAGE:
161         break;
162     }
163     bDelFmt =  sal_False;
164 }
165 
166 void SwUndoFlyBase::DelFly( SwDoc* pDoc )
167 {
168     bDelFmt = sal_True;                     // im DTOR das Format loeschen
169     pFrmFmt->DelFrms();                 // Frms vernichten.
170 
171     // alle Uno-Objecte sollten sich jetzt abmelden
172     {
173         SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFrmFmt );
174         pFrmFmt->ModifyNotification( &aMsgHint, &aMsgHint );
175     }
176 
177     if ( RES_DRAWFRMFMT != pFrmFmt->Which() )
178     {
179         // gibt es ueberhaupt Inhalt, dann sicher diesen
180         const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt();
181         ASSERT( rCntnt.GetCntntIdx(), "Fly ohne Inhalt" );
182 
183         SaveSection( pDoc, *rCntnt.GetCntntIdx() );
184         ((SwFmtCntnt&)rCntnt).SetNewCntntIdx( (const SwNodeIndex*)0 );
185     }
186     // OD 02.07.2003 #108784# - remove 'master' drawing object from drawing page
187     else if ( RES_DRAWFRMFMT == pFrmFmt->Which() )
188     {
189         SwDrawContact* pDrawContact =
190             static_cast<SwDrawContact*>(pFrmFmt->FindContactObj());
191         if ( pDrawContact )
192         {
193             pDrawContact->RemoveMasterFromDrawPage();
194         }
195     }
196 
197     const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
198     const SwPosition* pPos = rAnchor.GetCntntAnchor();
199     // die Positionen im Nodes-Array haben sich verschoben
200     nRndId = static_cast<sal_uInt16>(rAnchor.GetAnchorId());
201     if (FLY_AS_CHAR == nRndId)
202     {
203         nNdPgPos = pPos->nNode.GetIndex();
204         nCntPos = pPos->nContent.GetIndex();
205         SwTxtNode *const pTxtNd = pPos->nNode.GetNode().GetTxtNode();
206         OSL_ENSURE(pTxtNd, "no Textnode");
207         SwTxtFlyCnt* const pAttr = static_cast<SwTxtFlyCnt*>(
208             pTxtNd->GetTxtAttrForCharAt( nCntPos, RES_TXTATR_FLYCNT ) );
209         // Attribut steht noch im TextNode, loeschen
210         if( pAttr && pAttr->GetFlyCnt().GetFrmFmt() == pFrmFmt )
211         {
212             // Pointer auf 0, nicht loeschen
213             ((SwFmtFlyCnt&)pAttr->GetFlyCnt()).SetFlyFmt();
214             SwIndex aIdx( pPos->nContent );
215             pTxtNd->EraseText( aIdx, 1 );
216         }
217     }
218     else if (FLY_AT_CHAR == nRndId)
219     {
220         nNdPgPos = pPos->nNode.GetIndex();
221         nCntPos = pPos->nContent.GetIndex();
222     }
223     else if ((FLY_AT_PARA == nRndId) || (FLY_AT_FLY == nRndId))
224     {
225         nNdPgPos = pPos->nNode.GetIndex();
226     }
227     else
228     {
229         nNdPgPos = rAnchor.GetPageNum();
230     }
231 
232     pFrmFmt->ResetFmtAttr( RES_ANCHOR );        // Anchor loeschen
233 
234 
235     // aus dem Array austragen
236     SwSpzFrmFmts& rFlyFmts = *(SwSpzFrmFmts*)pDoc->GetSpzFrmFmts();
237     rFlyFmts.Remove( rFlyFmts.GetPos( pFrmFmt ));
238 }
239 
240 // SwUndoInsLayFmt ///////////////////////////////////////////////////////
241 
242 SwUndoInsLayFmt::SwUndoInsLayFmt( SwFrmFmt* pFormat, sal_uLong nNodeIdx, xub_StrLen nCntIdx )
243     : SwUndoFlyBase( pFormat, RES_DRAWFRMFMT == pFormat->Which() ?
244                                             UNDO_INSDRAWFMT : UNDO_INSLAYFMT ),
245     mnCrsrSaveIndexPara( nNodeIdx ), mnCrsrSaveIndexPos( nCntIdx )
246 {
247     const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
248     nRndId = static_cast<sal_uInt16>(rAnchor.GetAnchorId());
249     bDelFmt = sal_False;
250     switch( nRndId )
251     {
252     case FLY_AT_PAGE:
253         nNdPgPos = rAnchor.GetPageNum();
254         break;
255     case FLY_AT_PARA:
256     case FLY_AT_FLY:
257         nNdPgPos = rAnchor.GetCntntAnchor()->nNode.GetIndex();
258         break;
259     case FLY_AS_CHAR:
260     case FLY_AT_CHAR:
261         {
262             const SwPosition* pPos = rAnchor.GetCntntAnchor();
263             nCntPos = pPos->nContent.GetIndex();
264             nNdPgPos = pPos->nNode.GetIndex();
265         }
266         break;
267     default:
268         ASSERT( sal_False, "Was denn fuer ein FlyFrame?" );
269     }
270 }
271 
272 SwUndoInsLayFmt::~SwUndoInsLayFmt()
273 {
274 }
275 
276 void SwUndoInsLayFmt::UndoImpl(::sw::UndoRedoContext & rContext)
277 {
278     SwDoc & rDoc(rContext.GetDoc());
279     const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt();
280     if( rCntnt.GetCntntIdx() )  // kein Inhalt
281     {
282         bool bRemoveIdx = true;
283         if( mnCrsrSaveIndexPara > 0 )
284         {
285             SwTxtNode *const pNode =
286                 rDoc.GetNodes()[mnCrsrSaveIndexPara]->GetTxtNode();
287             if( pNode )
288             {
289                 SwNodeIndex aIdx( rDoc.GetNodes(),
290                         rCntnt.GetCntntIdx()->GetIndex() );
291                 SwNodeIndex aEndIdx( rDoc.GetNodes(),
292                         aIdx.GetNode().EndOfSectionIndex() );
293                 SwIndex aIndex( pNode, mnCrsrSaveIndexPos );
294                 SwPosition aPos( *pNode, aIndex );
295                 rDoc.CorrAbs( aIdx, aEndIdx, aPos, sal_True );
296                 bRemoveIdx = false;
297             }
298         }
299         if( bRemoveIdx )
300         {
301             RemoveIdxFromSection( rDoc, rCntnt.GetCntntIdx()->GetIndex() );
302         }
303     }
304     DelFly(& rDoc);
305 }
306 
307 void SwUndoInsLayFmt::RedoImpl(::sw::UndoRedoContext & rContext)
308 {
309     InsFly(rContext);
310 }
311 
312 void SwUndoInsLayFmt::RepeatImpl(::sw::RepeatContext & rContext)
313 {
314     SwDoc *const pDoc = & rContext.GetDoc();
315     // erfrage und setze den Anker neu
316     SwFmtAnchor aAnchor( pFrmFmt->GetAnchor() );
317     if ((FLY_AT_PARA == aAnchor.GetAnchorId()) ||
318         (FLY_AT_CHAR == aAnchor.GetAnchorId()) ||
319         (FLY_AS_CHAR == aAnchor.GetAnchorId()))
320     {
321         SwPosition aPos( *rContext.GetRepeatPaM().GetPoint() );
322         if (FLY_AT_PARA == aAnchor.GetAnchorId())
323         {
324             aPos.nContent.Assign( 0, 0 );
325         }
326         aAnchor.SetAnchor( &aPos );
327     }
328     else if( FLY_AT_FLY == aAnchor.GetAnchorId() )
329     {
330         SwStartNode const*const pSttNd =
331             rContext.GetRepeatPaM().GetNode()->FindFlyStartNode();
332         if( pSttNd )
333         {
334             SwPosition aPos( *pSttNd );
335             aAnchor.SetAnchor( &aPos );
336         }
337         else
338         {
339             return ;
340         }
341     }
342     else if (FLY_AT_PAGE == aAnchor.GetAnchorId())
343     {
344         aAnchor.SetPageNum( pDoc->GetCurrentLayout()->GetCurrPage( &rContext.GetRepeatPaM() ));
345     }
346     else {
347         ASSERT( sal_False, "was fuer ein Anker ist es denn nun?" );
348     }
349 
350     SwFrmFmt* pFlyFmt = pDoc->CopyLayoutFmt( *pFrmFmt, aAnchor, true, true );
351     (void) pFlyFmt;
352 //FIXME nobody ever did anything with this selection:
353 //    rContext.SetSelections(pFlyFmt, 0);
354 }
355 
356 // #111827#
357 String SwUndoInsLayFmt::GetComment() const
358 {
359     String aResult;
360 
361     // HACK: disable caching:
362     // the SfxUndoManager calls GetComment() too early: the pFrmFmt does not
363     // have a SwDrawContact yet, so it will fall back to SwUndo::GetComment(),
364     // which sets pComment to a wrong value.
365 //    if (! pComment)
366     if (true)
367     {
368         /*
369           If frame format is present and has an SdrObject use the undo
370           comment of the SdrObject. Otherwise use the default comment.
371         */
372 
373         bool bDone = false;
374         if (pFrmFmt)
375         {
376             const SdrObject * pSdrObj = pFrmFmt->FindSdrObject();
377             if ( pSdrObj )
378             {
379                 aResult = SdrUndoNewObj::GetComment( *pSdrObj );
380                 bDone = true;
381             }
382         }
383 
384         if (! bDone)
385             aResult = SwUndo::GetComment();
386     }
387     else
388         aResult = *pComment;
389 
390     return aResult;
391 }
392 
393 // SwUndoDelLayFmt ///////////////////////////////////////////////////////
394 
395 static SwUndoId
396 lcl_GetSwUndoId(SwFrmFmt *const pFrmFmt)
397 {
398     if (RES_DRAWFRMFMT != pFrmFmt->Which())
399     {
400         const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt();
401         OSL_ENSURE( rCntnt.GetCntntIdx(), "Fly without content" );
402 
403         SwNodeIndex firstNode(*rCntnt.GetCntntIdx(), 1);
404         SwNoTxtNode *const pNoTxtNode(firstNode.GetNode().GetNoTxtNode());
405         if (pNoTxtNode && pNoTxtNode->IsGrfNode())
406         {
407             return UNDO_DELGRF;
408         }
409         else if (pNoTxtNode && pNoTxtNode->IsOLENode())
410         {
411             // surprisingly not UNDO_DELOLE, which does not seem to work
412             return UNDO_DELETE;
413         }
414     }
415     return UNDO_DELLAYFMT;
416 }
417 
418 SwUndoDelLayFmt::SwUndoDelLayFmt( SwFrmFmt* pFormat )
419     : SwUndoFlyBase( pFormat, lcl_GetSwUndoId(pFormat) )
420     , bShowSelFrm( sal_True )
421 {
422     SwDoc* pDoc = pFormat->GetDoc();
423     DelFly( pDoc );
424 }
425 
426 SwRewriter SwUndoDelLayFmt::GetRewriter() const
427 {
428     SwRewriter aRewriter;
429 
430     SwDoc * pDoc = pFrmFmt->GetDoc();
431 
432     if (pDoc)
433     {
434         SwNodeIndex* pIdx = GetMvSttIdx();
435         if( 1 == GetMvNodeCnt() && pIdx)
436         {
437             SwNode *const pNd = & pIdx->GetNode();
438 
439             if ( pNd->IsNoTxtNode() && pNd->IsOLENode())
440             {
441                 SwOLENode * pOLENd = pNd->GetOLENode();
442 
443                 aRewriter.AddRule(UNDO_ARG1, pOLENd->GetDescription());
444             }
445         }
446     }
447 
448     return aRewriter;
449 }
450 
451 void SwUndoDelLayFmt::UndoImpl(::sw::UndoRedoContext & rContext)
452 {
453     InsFly( rContext, bShowSelFrm );
454 }
455 
456 void SwUndoDelLayFmt::RedoImpl(::sw::UndoRedoContext & rContext)
457 {
458     SwDoc & rDoc(rContext.GetDoc());
459     const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt();
460     if( rCntnt.GetCntntIdx() )  // kein Inhalt
461     {
462         RemoveIdxFromSection(rDoc, rCntnt.GetCntntIdx()->GetIndex());
463     }
464 
465     DelFly(& rDoc);
466 }
467 
468 void SwUndoDelLayFmt::RedoForRollback()
469 {
470     const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt();
471     if( rCntnt.GetCntntIdx() )  // kein Inhalt
472         RemoveIdxFromSection( *pFrmFmt->GetDoc(),
473                                 rCntnt.GetCntntIdx()->GetIndex() );
474 
475     DelFly( pFrmFmt->GetDoc() );
476 }
477 
478 // SwUndoSetFlyFmt ///////////////////////////////////////////////////////
479 
480 SwUndoSetFlyFmt::SwUndoSetFlyFmt( SwFrmFmt& rFlyFmt, SwFrmFmt& rNewFrmFmt )
481     : SwUndo( UNDO_SETFLYFRMFMT ), SwClient( &rFlyFmt ), pFrmFmt( &rFlyFmt ),
482     pOldFmt( (SwFrmFmt*)rFlyFmt.DerivedFrom() ), pNewFmt( &rNewFrmFmt ),
483     pItemSet( new SfxItemSet( *rFlyFmt.GetAttrSet().GetPool(),
484                                 rFlyFmt.GetAttrSet().GetRanges() )),
485     nOldNode( 0 ), nNewNode( 0 ),
486     nOldCntnt( 0 ), nNewCntnt( 0 ),
487     nOldAnchorTyp( 0 ), nNewAnchorTyp( 0 ), bAnchorChgd( sal_False )
488 {
489 }
490 
491 SwRewriter SwUndoSetFlyFmt::GetRewriter() const
492 {
493     SwRewriter aRewriter;
494 
495     if (pNewFmt)
496         aRewriter.AddRule(UNDO_ARG1, pNewFmt->GetName());
497 
498     return aRewriter;
499 }
500 
501 
502 SwUndoSetFlyFmt::~SwUndoSetFlyFmt()
503 {
504     delete pItemSet;
505 }
506 
507 void SwUndoSetFlyFmt::DeRegisterFromFormat( SwFmt& rFmt )
508 {
509     rFmt.Remove(this);
510 }
511 
512 void SwUndoSetFlyFmt::GetAnchor( SwFmtAnchor& rAnchor,
513                                 sal_uLong nNode, xub_StrLen nCntnt )
514 {
515     RndStdIds nAnchorTyp = rAnchor.GetAnchorId();
516     if (FLY_AT_PAGE != nAnchorTyp)
517     {
518         SwNode* pNd = pFrmFmt->GetDoc()->GetNodes()[ nNode ];
519 
520         if( FLY_AT_FLY == nAnchorTyp
521                 ? ( !pNd->IsStartNode() || SwFlyStartNode !=
522                     ((SwStartNode*)pNd)->GetStartNodeType() )
523                 : !pNd->IsTxtNode() )
524         {
525             pNd = 0;    // invalid position
526         }
527         else
528         {
529             SwPosition aPos( *pNd );
530             if ((FLY_AS_CHAR == nAnchorTyp) ||
531                 (FLY_AT_CHAR == nAnchorTyp))
532             {
533                 if ( nCntnt > static_cast<SwTxtNode*>(pNd)->GetTxt().Len() )
534                 {
535                     pNd = 0;    // invalid position
536                 }
537                 else
538                 {
539                     aPos.nContent.Assign(static_cast<SwTxtNode*>(pNd), nCntnt);
540                 }
541             }
542             if ( pNd )
543             {
544                 rAnchor.SetAnchor( &aPos );
545             }
546         }
547 
548         if( !pNd )
549         {
550             // ungueltige Position - setze auf 1. Seite
551             rAnchor.SetType( FLY_AT_PAGE );
552             rAnchor.SetPageNum( 1 );
553         }
554     }
555     else
556         rAnchor.SetPageNum( nCntnt );
557 }
558 
559 void SwUndoSetFlyFmt::UndoImpl(::sw::UndoRedoContext & rContext)
560 {
561     SwDoc & rDoc = rContext.GetDoc();
562 
563     // ist das neue Format noch vorhanden ??
564     if( USHRT_MAX != rDoc.GetFrmFmts()->GetPos( (const SwFrmFmtPtr)pOldFmt ) )
565     {
566         if( bAnchorChgd )
567             pFrmFmt->DelFrms();
568 
569         if( pFrmFmt->DerivedFrom() != pOldFmt )
570             pFrmFmt->SetDerivedFrom( pOldFmt );
571 
572         SfxItemIter aIter( *pItemSet );
573         const SfxPoolItem* pItem = aIter.GetCurItem();
574         while( pItem )
575         {
576             if( IsInvalidItem( pItem ))
577                 pFrmFmt->ResetFmtAttr( pItemSet->GetWhichByPos(
578                                         aIter.GetCurPos() ));
579             else
580                 pFrmFmt->SetFmtAttr( *pItem );
581 
582             if( aIter.IsAtEnd() )
583                 break;
584             pItem = aIter.NextItem();
585         }
586 
587         if( bAnchorChgd )
588         {
589             const SwFmtAnchor& rOldAnch = pFrmFmt->GetAnchor();
590             if (FLY_AS_CHAR == rOldAnch.GetAnchorId())
591             {
592                 // Bei InCntnt's wird es spannend: Das TxtAttribut muss
593                 // vernichtet werden. Leider reisst dies neben den Frms
594                 // auch noch das Format mit in sein Grab. Um dass zu
595                 // unterbinden loesen wir vorher die Verbindung zwischen
596                 // Attribut und Format.
597                 const SwPosition *pPos = rOldAnch.GetCntntAnchor();
598                 SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode();
599                 ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
600                 const xub_StrLen nIdx = pPos->nContent.GetIndex();
601                 SwTxtAttr * pHnt = pTxtNode->GetTxtAttrForCharAt(
602                         nIdx, RES_TXTATR_FLYCNT );
603                 ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT,
604                             "Missing FlyInCnt-Hint." );
605                 ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == pFrmFmt,
606                             "Wrong TxtFlyCnt-Hint." );
607                 const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt();
608 
609                 // Die Verbindung ist geloest, jetzt muss noch das Attribut
610                 // vernichtet werden.
611                 pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx );
612             }
613 
614             // Anker umsetzen
615             SwFmtAnchor aNewAnchor( (RndStdIds) nOldAnchorTyp );
616             GetAnchor( aNewAnchor, nOldNode, nOldCntnt );
617             pFrmFmt->SetFmtAttr( aNewAnchor );
618 
619             if (FLY_AS_CHAR == aNewAnchor.GetAnchorId())
620             {
621                 SwPosition* pPos = (SwPosition*)aNewAnchor.GetCntntAnchor();
622                 SwFmtFlyCnt aFmt( pFrmFmt );
623                 pPos->nNode.GetNode().GetTxtNode()->InsertItem( aFmt,
624                     nOldCntnt, 0 );
625             }
626 
627             pFrmFmt->MakeFrms();
628         }
629         rContext.SetSelections(pFrmFmt, 0);
630     }
631 }
632 
633 void SwUndoSetFlyFmt::RedoImpl(::sw::UndoRedoContext & rContext)
634 {
635     SwDoc & rDoc = rContext.GetDoc();
636 
637     // ist das neue Format noch vorhanden ??
638     if( USHRT_MAX != rDoc.GetFrmFmts()->GetPos( (const SwFrmFmtPtr)pNewFmt ) )
639     {
640 
641         if( bAnchorChgd )
642         {
643             SwFmtAnchor aNewAnchor( (RndStdIds) nNewAnchorTyp );
644             GetAnchor( aNewAnchor, nNewNode, nNewCntnt );
645             SfxItemSet aSet( rDoc.GetAttrPool(), aFrmFmtSetRange );
646             aSet.Put( aNewAnchor );
647             rDoc.SetFrmFmtToFly( *pFrmFmt, *pNewFmt, &aSet );
648         }
649         else
650             rDoc.SetFrmFmtToFly( *pFrmFmt, *pNewFmt, 0 );
651 
652         rContext.SetSelections(pFrmFmt, 0);
653     }
654 }
655 
656 void SwUndoSetFlyFmt::PutAttr( sal_uInt16 nWhich, const SfxPoolItem* pItem )
657 {
658     if( pItem && pItem != GetDfltAttr( nWhich ) )
659     {
660         // Sonderbehandlung fuer den Anchor
661         if( RES_ANCHOR == nWhich )
662         {
663             // nur den 1. Ankerwechsel vermerken
664             ASSERT( !bAnchorChgd, "mehrfacher Ankerwechsel nicht erlaubt!" );
665 
666             bAnchorChgd = sal_True;
667 
668             const SwFmtAnchor* pAnchor = (SwFmtAnchor*)pItem;
669             switch( nOldAnchorTyp = static_cast<sal_uInt16>(pAnchor->GetAnchorId()) )
670             {
671             case FLY_AS_CHAR:
672             case FLY_AT_CHAR:
673                 nOldCntnt = pAnchor->GetCntntAnchor()->nContent.GetIndex();
674             case FLY_AT_PARA:
675             case FLY_AT_FLY:
676                 nOldNode = pAnchor->GetCntntAnchor()->nNode.GetIndex();
677                 break;
678 
679             default:
680                 nOldCntnt = pAnchor->GetPageNum();
681             }
682 
683             pAnchor = (SwFmtAnchor*)&pFrmFmt->GetAnchor();
684             switch( nNewAnchorTyp = static_cast<sal_uInt16>(pAnchor->GetAnchorId()) )
685             {
686             case FLY_AS_CHAR:
687             case FLY_AT_CHAR:
688                 nNewCntnt = pAnchor->GetCntntAnchor()->nContent.GetIndex();
689             case FLY_AT_PARA:
690             case FLY_AT_FLY:
691                 nNewNode = pAnchor->GetCntntAnchor()->nNode.GetIndex();
692                 break;
693 
694             default:
695                 nNewCntnt = pAnchor->GetPageNum();
696             }
697         }
698         else
699             pItemSet->Put( *pItem );
700     }
701     else
702         pItemSet->InvalidateItem( nWhich );
703 }
704 
705 void SwUndoSetFlyFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* )
706 {
707     if( pOld )
708     {
709         sal_uInt16 nWhich = pOld->Which();
710 
711         if( nWhich < POOLATTR_END )
712             PutAttr( nWhich, pOld );
713         else if( RES_ATTRSET_CHG == nWhich )
714         {
715             SfxItemIter aIter( *((SwAttrSetChg*)pOld)->GetChgSet() );
716             const SfxPoolItem* pItem = aIter.GetCurItem();
717             while( pItem )
718             {
719                 PutAttr( pItem->Which(), pItem );
720                 if( aIter.IsAtEnd() )
721                     break;
722                 pItem = aIter.NextItem();
723             }
724         }
725     }
726 }
727 
728