xref: /trunk/main/sw/source/core/doc/docfly.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 <hintids.hxx>
32 #include <svl/itemiter.hxx>
33 #include <svx/svdobj.hxx>
34 #include <svx/svdpage.hxx>
35 #include <svx/svdmodel.hxx>
36 #include <svx/svdocapt.hxx>
37 #include <svx/svdmark.hxx>
38 #include <fmtfsize.hxx>
39 #include <fmtornt.hxx>
40 #include <fmtsrnd.hxx>
41 #include <dcontact.hxx>
42 
43 #include <ndgrf.hxx>
44 #include <doc.hxx>
45 #include <IDocumentUndoRedo.hxx>
46 #include <ndindex.hxx>
47 #include <docary.hxx>
48 #include <fmtcntnt.hxx>
49 #include <fmtanchr.hxx>
50 #include <txtflcnt.hxx>
51 #include <fmtflcnt.hxx>
52 #include <txtfrm.hxx>
53 #include <pagefrm.hxx>
54 #include <rootfrm.hxx>
55 #include <flyfrms.hxx>
56 #include <frmtool.hxx>
57 #include <frmfmt.hxx>
58 #include <ndtxt.hxx>
59 #include <pam.hxx>
60 #include <tblsel.hxx>
61 #include <swundo.hxx>
62 #include <swtable.hxx>
63 #include <crstate.hxx>
64 #include <UndoCore.hxx>
65 #include <UndoAttribute.hxx>
66 #include <fmtcnct.hxx>
67 #include <dflyobj.hxx>
68 #include <undoflystrattr.hxx>
69 #include <switerator.hxx>
70 
71 extern sal_uInt16 GetHtmlMode( const SwDocShell* );
72 
73 
74 using namespace ::com::sun::star;
75 
76 sal_uInt16 SwDoc::GetFlyCount( FlyCntType eType ) const
77 {
78     const SwSpzFrmFmts& rFmts = *GetSpzFrmFmts();
79     sal_uInt16 nSize = rFmts.Count();
80     sal_uInt16 nCount = 0;
81     const SwNodeIndex* pIdx;
82     for ( sal_uInt16 i = 0; i < nSize; i++)
83     {
84         const SwFrmFmt* pFlyFmt = rFmts[ i ];
85         if( RES_FLYFRMFMT == pFlyFmt->Which()
86             && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() )
87             && pIdx->GetNodes().IsDocNodes()
88             )
89         {
90             const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ];
91 
92             switch( eType )
93             {
94             case FLYCNTTYPE_FRM:
95                 if(!pNd->IsNoTxtNode())
96                     nCount++;
97                 break;
98 
99             case FLYCNTTYPE_GRF:
100                 if( pNd->IsGrfNode() )
101                     nCount++;
102                 break;
103 
104             case FLYCNTTYPE_OLE:
105                 if(pNd->IsOLENode())
106                     nCount++;
107                 break;
108 
109             default:
110                 nCount++;
111             }
112         }
113     }
114     return nCount;
115 }
116 
117 // If you change this, also update SwXFrameEnumeration in unocoll.
118 SwFrmFmt* SwDoc::GetFlyNum( sal_uInt16 nIdx, FlyCntType eType )
119 {
120     SwSpzFrmFmts& rFmts = *GetSpzFrmFmts();
121     SwFrmFmt* pRetFmt = 0;
122     sal_uInt16 nSize = rFmts.Count();
123     const SwNodeIndex* pIdx;
124     sal_uInt16 nCount = 0;
125     for( sal_uInt16 i = 0; !pRetFmt && i < nSize; ++i )
126     {
127         SwFrmFmt* pFlyFmt = rFmts[ i ];
128         if( RES_FLYFRMFMT == pFlyFmt->Which()
129             && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() )
130             && pIdx->GetNodes().IsDocNodes()
131             )
132         {
133             const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ];
134             switch( eType )
135             {
136             case FLYCNTTYPE_FRM:
137                 if( !pNd->IsNoTxtNode() && nIdx == nCount++)
138                     pRetFmt = pFlyFmt;
139                 break;
140             case FLYCNTTYPE_GRF:
141                 if(pNd->IsGrfNode() && nIdx == nCount++ )
142                     pRetFmt = pFlyFmt;
143                 break;
144             case FLYCNTTYPE_OLE:
145                 if(pNd->IsOLENode() && nIdx == nCount++)
146                     pRetFmt = pFlyFmt;
147                 break;
148             default:
149                 if(nIdx == nCount++)
150                     pRetFmt = pFlyFmt;
151             }
152         }
153     }
154     return pRetFmt;
155 }
156 
157 Point lcl_FindAnchorLayPos( SwDoc& rDoc, const SwFmtAnchor& rAnch,
158                             const SwFrmFmt* pFlyFmt )
159 {
160     Point aRet;
161     if( rDoc.GetCurrentViewShell() )    //swmod 071107//swmod 071225
162         switch( rAnch.GetAnchorId() )
163         {
164         case FLY_AS_CHAR:
165             if( pFlyFmt && rAnch.GetCntntAnchor() )
166             {
167                 const SwFrm* pOld = ((SwFlyFrmFmt*)pFlyFmt)->GetFrm( &aRet, sal_False );
168                 if( pOld )
169                     aRet = pOld->Frm().Pos();
170             }
171             break;
172 
173         case FLY_AT_PARA:
174         case FLY_AT_CHAR: // LAYER_IMPL
175             if( rAnch.GetCntntAnchor() )
176             {
177                 const SwPosition *pPos = rAnch.GetCntntAnchor();
178                 const SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode();
179                 const SwFrm* pOld = pNd ? pNd->getLayoutFrm( rDoc.GetCurrentLayout(), &aRet, 0, sal_False ) : 0;
180                 if( pOld )
181                     aRet = pOld->Frm().Pos();
182             }
183             break;
184 
185         case FLY_AT_FLY: // LAYER_IMPL
186             if( rAnch.GetCntntAnchor() )
187             {
188                 const SwFlyFrmFmt* pFmt = (SwFlyFrmFmt*)rAnch.GetCntntAnchor()->
189                                                 nNode.GetNode().GetFlyFmt();
190                 const SwFrm* pOld = pFmt ? pFmt->GetFrm( &aRet, sal_False ) : 0;
191                 if( pOld )
192                     aRet = pOld->Frm().Pos();
193             }
194             break;
195 
196         case FLY_AT_PAGE:
197             {
198                 sal_uInt16 nPgNum = rAnch.GetPageNum();
199                 const SwPageFrm *pPage = (SwPageFrm*)rDoc.GetCurrentLayout()->Lower();
200                 for( sal_uInt16 i = 1; (i <= nPgNum) && pPage; ++i,
201                                     pPage = (const SwPageFrm*)pPage->GetNext() )
202                     if( i == nPgNum )
203                     {
204                         aRet = pPage->Frm().Pos();
205                         break;
206                     }
207             }
208             break;
209         default:
210             break;
211         }
212     return aRet;
213 }
214 
215 #define MAKEFRMS 0
216 #define IGNOREANCHOR 1
217 #define DONTMAKEFRMS 2
218 
219 sal_Int8 SwDoc::SetFlyFrmAnchor( SwFrmFmt& rFmt, SfxItemSet& rSet, sal_Bool bNewFrms )
220 {
221     //Ankerwechsel sind fast immer in alle 'Richtungen' erlaubt.
222     //Ausnahme: Absatz- bzw. Zeichengebundene Rahmen duerfen wenn sie in
223     //Kopf-/Fusszeilen stehen nicht Seitengebunden werden.
224     const SwFmtAnchor &rOldAnch = rFmt.GetAnchor();
225     const RndStdIds nOld = rOldAnch.GetAnchorId();
226 
227     SwFmtAnchor aNewAnch( (SwFmtAnchor&)rSet.Get( RES_ANCHOR ) );
228     RndStdIds nNew = aNewAnch.GetAnchorId();
229 
230     // ist der neue ein gueltiger Anker?
231     if( !aNewAnch.GetCntntAnchor() && (FLY_AT_FLY == nNew ||
232         (FLY_AT_PARA == nNew) || (FLY_AS_CHAR == nNew) ||
233         (FLY_AT_CHAR == nNew) ))
234     {
235         return IGNOREANCHOR;
236     }
237 
238     if( nOld == nNew )
239         return DONTMAKEFRMS;
240 
241 
242     Point aOldAnchorPos( ::lcl_FindAnchorLayPos( *this, rOldAnch, &rFmt ));
243     Point aNewAnchorPos( ::lcl_FindAnchorLayPos( *this, aNewAnch, 0 ));
244 
245     //Die alten Frms vernichten. Dabei werden die Views implizit gehidet und
246     //doppeltes hiden waere so eine art Show!
247     rFmt.DelFrms();
248 
249     if ( FLY_AS_CHAR == nOld )
250     {
251         //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet
252         //werden. Leider reisst dies neben den Frms auch noch das Format mit
253         //in sein Grab. Um dass zu unterbinden loesen wir vorher die
254         //Verbindung zwischen Attribut und Format.
255         const SwPosition *pPos = rOldAnch.GetCntntAnchor();
256         SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode();
257         ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
258         const xub_StrLen nIdx = pPos->nContent.GetIndex();
259         SwTxtAttr * const  pHnt =
260             pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT );
261         ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT,
262                     "Missing FlyInCnt-Hint." );
263         ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == &rFmt,
264                     "Wrong TxtFlyCnt-Hint." );
265         const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt();
266 
267         //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet
268         //werden.
269         pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx );
270     }
271 
272     //Endlich kann das Attribut gesetzt werden. Es muss das erste Attribut
273     //sein; Undo depends on it!
274     rFmt.SetFmtAttr( aNewAnch );
275 
276     //Positionskorrekturen
277     const SfxPoolItem* pItem;
278     switch( nNew )
279     {
280     case FLY_AS_CHAR:
281             //Wenn keine Positionsattribute hereinkommen, dann muss dafuer
282             //gesorgt werden, das keine unerlaubte automatische Ausrichtung
283             //bleibt.
284         {
285             const SwPosition *pPos = aNewAnch.GetCntntAnchor();
286             SwTxtNode *pNd = pPos->nNode.GetNode().GetTxtNode();
287             ASSERT( pNd, "Crsr steht nicht auf TxtNode." );
288 
289             SwFmtFlyCnt aFmt( static_cast<SwFlyFrmFmt*>(&rFmt) );
290             pNd->InsertItem( aFmt, pPos->nContent.GetIndex(), 0 );
291         }
292 
293         if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem ))
294         {
295             SwFmtVertOrient aOldV( rFmt.GetVertOrient() );
296             sal_Bool bSet = sal_True;
297             switch( aOldV.GetVertOrient() )
298             {
299             case text::VertOrientation::LINE_TOP:     aOldV.SetVertOrient( text::VertOrientation::TOP );   break;
300             case text::VertOrientation::LINE_CENTER:  aOldV.SetVertOrient( text::VertOrientation::CENTER); break;
301             case text::VertOrientation::LINE_BOTTOM:  aOldV.SetVertOrient( text::VertOrientation::BOTTOM); break;
302             case text::VertOrientation::NONE:         aOldV.SetVertOrient( text::VertOrientation::CENTER); break;
303             default:
304                 bSet = sal_False;
305             }
306             if( bSet )
307                 rSet.Put( aOldV );
308         }
309         break;
310 
311     case FLY_AT_PARA:
312     case FLY_AT_CHAR: // LAYER_IMPL
313     case FLY_AT_FLY: // LAYER_IMPL
314     case FLY_AT_PAGE:
315         {
316             //Wenn keine Positionsattribute hereinschneien korrigieren wir
317             //die Position so, dass die Dokumentkoordinaten des Flys erhalten
318             //bleiben.
319             //Chg: Wenn sich in den Positionsattributen lediglich die
320             //Ausrichtung veraendert (text::RelOrientation::FRAME vs. text::RelOrientation::PRTAREA), dann wird die
321             //Position ebenfalls korrigiert.
322             if( SFX_ITEM_SET != rSet.GetItemState( RES_HORI_ORIENT, sal_False, &pItem ))
323                 pItem = 0;
324 
325             SwFmtHoriOrient aOldH( rFmt.GetHoriOrient() );
326 
327             if( text::HoriOrientation::NONE == aOldH.GetHoriOrient() && ( !pItem ||
328                 aOldH.GetPos() == ((SwFmtHoriOrient*)pItem)->GetPos() ))
329             {
330                 SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldH.GetPos();
331                 nPos += aOldAnchorPos.X() - aNewAnchorPos.X();
332 
333                 if( pItem )
334                 {
335                     SwFmtHoriOrient* pH = (SwFmtHoriOrient*)pItem;
336                     aOldH.SetHoriOrient( pH->GetHoriOrient() );
337                     aOldH.SetRelationOrient( pH->GetRelationOrient() );
338                 }
339                 aOldH.SetPos( nPos );
340                 rSet.Put( aOldH );
341             }
342 
343             if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem ))
344                 pItem = 0;
345             SwFmtVertOrient aOldV( rFmt.GetVertOrient() );
346 
347             // OD 2004-05-14 #i28922# - correction: compare <aOldV.GetVertOrient()
348             // with <text::VertOrientation::NONE>
349             if( text::VertOrientation::NONE == aOldV.GetVertOrient() && (!pItem ||
350                 aOldV.GetPos() == ((SwFmtVertOrient*)pItem)->GetPos() ) )
351             {
352                 SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldV.GetPos();
353                 nPos += aOldAnchorPos.Y() - aNewAnchorPos.Y();
354                 if( pItem )
355                 {
356                     SwFmtVertOrient* pV = (SwFmtVertOrient*)pItem;
357                     aOldV.SetVertOrient( pV->GetVertOrient() );
358                     aOldV.SetRelationOrient( pV->GetRelationOrient() );
359                 }
360                 aOldV.SetPos( nPos );
361                 rSet.Put( aOldV );
362             }
363         }
364         break;
365     default:
366         break;
367     }
368 
369     if( bNewFrms )
370         rFmt.MakeFrms();
371 
372     return MAKEFRMS;
373 }
374 
375 static bool
376 lcl_SetFlyFrmAttr(SwDoc & rDoc,
377         sal_Int8 (SwDoc::*pSetFlyFrmAnchor)(SwFrmFmt &, SfxItemSet &, sal_Bool),
378         SwFrmFmt & rFlyFmt, SfxItemSet & rSet)
379 {
380     // #i32968# Inserting columns in the frame causes MakeFrmFmt to put two
381     // objects of type SwUndoFrmFmt on the undo stack. We don't want them.
382     ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
383 
384     //Ist das Ankerattribut dabei? Falls ja ueberlassen wir die Verarbeitung
385     //desselben einer Spezialmethode. Sie Returnt sal_True wenn der Fly neu
386     //erzeugt werden muss (z.B. weil ein Wechsel des FlyTyps vorliegt).
387     sal_Int8 const nMakeFrms =
388         (SFX_ITEM_SET == rSet.GetItemState( RES_ANCHOR, sal_False ))
389              ?  (rDoc.*pSetFlyFrmAnchor)( rFlyFmt, rSet, sal_False )
390              :  DONTMAKEFRMS;
391 
392     const SfxPoolItem* pItem;
393     SfxItemIter aIter( rSet );
394     SfxItemSet aTmpSet( rDoc.GetAttrPool(), aFrmFmtSetRange );
395     sal_uInt16 nWhich = aIter.GetCurItem()->Which();
396     do {
397         switch( nWhich )
398         {
399         case RES_FILL_ORDER:
400         case RES_BREAK:
401         case RES_PAGEDESC:
402         case RES_CNTNT:
403         case RES_FOOTER:
404             OSL_ENSURE(false, ":-) unknown Attribute for Fly.");
405             // kein break;
406         case RES_CHAIN:
407             rSet.ClearItem( nWhich );
408             break;
409         case RES_ANCHOR:
410             if( DONTMAKEFRMS != nMakeFrms )
411                 break;
412 
413         default:
414             if( !IsInvalidItem( aIter.GetCurItem() ) && ( SFX_ITEM_SET !=
415                 rFlyFmt.GetAttrSet().GetItemState( nWhich, sal_True, &pItem ) ||
416                 *pItem != *aIter.GetCurItem() ))
417                 aTmpSet.Put( *aIter.GetCurItem() );
418             break;
419         }
420 
421         if( aIter.IsAtEnd() )
422             break;
423 
424     } while( 0 != ( nWhich = aIter.NextItem()->Which() ) );
425 
426     if( aTmpSet.Count() )
427         rFlyFmt.SetFmtAttr( aTmpSet );
428 
429     if( MAKEFRMS == nMakeFrms )
430         rFlyFmt.MakeFrms();
431 
432     return aTmpSet.Count() || MAKEFRMS == nMakeFrms;
433 }
434 
435 sal_Bool SwDoc::SetFlyFrmAttr( SwFrmFmt& rFlyFmt, SfxItemSet& rSet )
436 {
437     if( !rSet.Count() )
438         return sal_False;
439 
440     ::std::auto_ptr<SwUndoFmtAttrHelper> pSaveUndo;
441 
442     if (GetIDocumentUndoRedo().DoesUndo())
443     {
444         GetIDocumentUndoRedo().ClearRedo(); // AppendUndo far below, so leave it
445         pSaveUndo.reset( new SwUndoFmtAttrHelper( rFlyFmt ) );
446     }
447 
448     bool const bRet =
449         lcl_SetFlyFrmAttr(*this, &SwDoc::SetFlyFrmAnchor, rFlyFmt, rSet);
450 
451     if ( pSaveUndo.get() )
452     {
453         if ( pSaveUndo->GetUndo() )
454         {
455             GetIDocumentUndoRedo().AppendUndo( pSaveUndo->ReleaseUndo() );
456         }
457     }
458 
459     SetModified();
460 
461     return bRet;
462 }
463 
464 // --> OD 2009-07-20 #i73249#
465 void SwDoc::SetFlyFrmTitle( SwFlyFrmFmt& rFlyFrmFmt,
466                             const String& sNewTitle )
467 {
468     if ( rFlyFrmFmt.GetObjTitle() == sNewTitle )
469     {
470         return;
471     }
472 
473     ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo());
474 
475     if (GetIDocumentUndoRedo().DoesUndo())
476     {
477         GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt,
478                                           UNDO_FLYFRMFMT_TITLE,
479                                           rFlyFrmFmt.GetObjTitle(),
480                                           sNewTitle ) );
481     }
482 
483     rFlyFrmFmt.SetObjTitle( sNewTitle, true );
484 
485     SetModified();
486 }
487 
488 void SwDoc::SetFlyFrmDescription( SwFlyFrmFmt& rFlyFrmFmt,
489                                   const String& sNewDescription )
490 {
491     if ( rFlyFrmFmt.GetObjDescription() == sNewDescription )
492     {
493         return;
494     }
495 
496     ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo());
497 
498     if (GetIDocumentUndoRedo().DoesUndo())
499     {
500         GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt,
501                                           UNDO_FLYFRMFMT_DESCRIPTION,
502                                           rFlyFrmFmt.GetObjDescription(),
503                                           sNewDescription ) );
504     }
505 
506     rFlyFrmFmt.SetObjDescription( sNewDescription, true );
507 
508     SetModified();
509 }
510 // <--
511 
512 sal_Bool SwDoc::SetFrmFmtToFly( SwFrmFmt& rFmt, SwFrmFmt& rNewFmt,
513                             SfxItemSet* pSet, sal_Bool bKeepOrient )
514 {
515     sal_Bool bChgAnchor = sal_False, bFrmSz = sal_False;
516 
517     const SwFmtFrmSize aFrmSz( rFmt.GetFrmSize() );
518     const SwFmtVertOrient aVert( rFmt.GetVertOrient() );
519     const SwFmtHoriOrient aHori( rFmt.GetHoriOrient() );
520 
521     SwUndoSetFlyFmt* pUndo = 0;
522     bool const bUndo = GetIDocumentUndoRedo().DoesUndo();
523     if (bUndo)
524     {
525         pUndo = new SwUndoSetFlyFmt( rFmt, rNewFmt );
526         GetIDocumentUndoRedo().AppendUndo(pUndo);
527     }
528 
529     // #i32968# Inserting columns in the section causes MakeFrmFmt to put
530     // 2 objects of type SwUndoFrmFmt on the undo stack. We don't want them.
531     ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
532 
533     //Erstmal die Spalten setzen, sonst gibts nix als Aerger mit dem
534     //Set/Reset/Abgleich usw.
535     const SfxPoolItem* pItem;
536     if( SFX_ITEM_SET != rNewFmt.GetAttrSet().GetItemState( RES_COL ))
537         rFmt.ResetFmtAttr( RES_COL );
538 
539     if( rFmt.DerivedFrom() != &rNewFmt )
540     {
541         rFmt.SetDerivedFrom( &rNewFmt );
542 
543         // 1. wenn nicht automatisch -> ignorieren, sonst -> wech
544         // 2. wech damit, MB!
545         if( SFX_ITEM_SET == rNewFmt.GetAttrSet().GetItemState( RES_FRM_SIZE, sal_False ))
546         {
547             rFmt.ResetFmtAttr( RES_FRM_SIZE );
548             bFrmSz = sal_True;
549         }
550 
551         const SfxItemSet* pAsk = pSet;
552         if( !pAsk ) pAsk = &rNewFmt.GetAttrSet();
553         if( SFX_ITEM_SET == pAsk->GetItemState( RES_ANCHOR, sal_False, &pItem )
554             && ((SwFmtAnchor*)pItem)->GetAnchorId() !=
555                 rFmt.GetAnchor().GetAnchorId() )
556         {
557             if( pSet )
558                 bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, *pSet, sal_False );
559             else
560             {
561                 //JP 23.04.98: muss den FlyFmt-Range haben, denn im SetFlyFrmAnchor
562                 //              werden Attribute in diesen gesetzt!
563                 SfxItemSet aFlySet( *rNewFmt.GetAttrSet().GetPool(),
564                                     rNewFmt.GetAttrSet().GetRanges() );
565                 aFlySet.Put( *pItem );
566                 bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, aFlySet, sal_False);
567             }
568         }
569     }
570 
571     //Hori und Vert nur dann resetten, wenn in der Vorlage eine
572     //automatische Ausrichtung eingestellt ist, anderfalls den alten Wert
573     //wieder hineinstopfen.
574     //JP 09.06.98: beim Update der RahmenVorlage sollte der Fly NICHT
575     //              seine Orientierng verlieren (diese wird nicht geupdatet!)
576     //OS: #96584# text::HoriOrientation::NONE and text::VertOrientation::NONE are allowed now
577     if (!bKeepOrient)
578     {
579         rFmt.ResetFmtAttr(RES_VERT_ORIENT);
580         rFmt.ResetFmtAttr(RES_HORI_ORIENT);
581     }
582 
583     rFmt.ResetFmtAttr( RES_PRINT, RES_SURROUND );
584     rFmt.ResetFmtAttr( RES_LR_SPACE, RES_UL_SPACE );
585     rFmt.ResetFmtAttr( RES_BACKGROUND, RES_COL );
586     rFmt.ResetFmtAttr( RES_URL, RES_EDIT_IN_READONLY );
587 
588     if( !bFrmSz )
589         rFmt.SetFmtAttr( aFrmSz );
590 
591     if( bChgAnchor )
592         rFmt.MakeFrms();
593 
594     if( pUndo )
595         pUndo->DeRegisterFromFormat( rFmt );
596 
597     SetModified();
598 
599     return bChgAnchor;
600 }
601 
602 void SwDoc::GetGrfNms( const SwFlyFrmFmt& rFmt, String* pGrfName,
603                         String* pFltName ) const
604 {
605     SwNodeIndex aIdx( *rFmt.GetCntnt().GetCntntIdx(), 1 );
606     const SwGrfNode* pGrfNd = aIdx.GetNode().GetGrfNode();
607     if( pGrfNd && pGrfNd->IsLinkedFile() )
608         pGrfNd->GetFileFilterNms( pGrfName, pFltName );
609 }
610 
611 sal_Bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList,
612                            RndStdIds _eAnchorType,
613                            const sal_Bool _bSameOnly,
614                            const sal_Bool _bPosCorr )
615 {
616     ASSERT( GetCurrentLayout(), "Ohne Layout geht gar nichts" );    //swmod 080218
617 
618     if ( !_rMrkList.GetMarkCount() ||
619          _rMrkList.GetMark( 0 )->GetMarkedSdrObj()->GetUpGroup() )
620     {
621         return false;
622     }
623 
624     GetIDocumentUndoRedo().StartUndo( UNDO_INSATTR, NULL );
625 
626     sal_Bool bUnmark = sal_False;
627     for ( sal_uInt16 i = 0; i < _rMrkList.GetMarkCount(); ++i )
628     {
629         SdrObject* pObj = _rMrkList.GetMark( i )->GetMarkedSdrObj();
630         if ( !pObj->ISA(SwVirtFlyDrawObj) )
631         {
632             SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
633 
634             // OD 27.06.2003 #108784# - consider, that drawing object has
635             // no user call. E.g.: a 'virtual' drawing object is disconnected by
636             // the anchor type change of the 'master' drawing object.
637             // Continue with next selected object and assert, if this isn't excepted.
638             if ( !pContact )
639             {
640 #ifdef DBG_UTIL
641                 bool bNoUserCallExcepted =
642                         pObj->ISA(SwDrawVirtObj) &&
643                         !static_cast<SwDrawVirtObj*>(pObj)->IsConnected();
644                 ASSERT( bNoUserCallExcepted, "SwDoc::ChgAnchor(..) - no contact at selected drawing object" );
645 #endif
646                 continue;
647             }
648 
649             // OD 2004-03-29 #i26791#
650             const SwFrm* pOldAnchorFrm = pContact->GetAnchorFrm( pObj );
651             const SwFrm* pNewAnchorFrm = pOldAnchorFrm;
652 
653             // --> OD 2006-03-01 #i54336#
654             // Instead of only keeping the index position for an as-character
655             // anchored object the complete <SwPosition> is kept, because the
656             // anchor index position could be moved, if the object again is
657             // anchored as character.
658 //            xub_StrLen nIndx = STRING_NOTFOUND;
659             const SwPosition* pOldAsCharAnchorPos( 0L );
660             const RndStdIds eOldAnchorType = pContact->GetAnchorId();
661             if ( !_bSameOnly && eOldAnchorType == FLY_AS_CHAR )
662             {
663                 pOldAsCharAnchorPos = new SwPosition( pContact->GetCntntAnchor() );
664             }
665             // <--
666 
667             if ( _bSameOnly )
668                 _eAnchorType = eOldAnchorType;
669 
670             SwFmtAnchor aNewAnch( _eAnchorType );
671             Rectangle aObjRect( pContact->GetAnchoredObj( pObj )->GetObjRect().SVRect() );
672             const Point aPt( aObjRect.TopLeft() );
673 
674             switch ( _eAnchorType )
675             {
676             case FLY_AT_PARA:
677             case FLY_AT_CHAR:
678                 {
679                     const Point aNewPoint = pOldAnchorFrm &&
680                                             ( pOldAnchorFrm->IsVertical() ||
681                                               pOldAnchorFrm->IsRightToLeft() )
682                                             ? aObjRect.TopRight()
683                                             : aPt;
684 
685                     // OD 18.06.2003 #108784# - allow drawing objects in header/footer
686                     pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aNewPoint, false );
687                     if ( pNewAnchorFrm->IsTxtFrm() && ((SwTxtFrm*)pNewAnchorFrm)->IsFollow() )
688                     {
689                         pNewAnchorFrm = ((SwTxtFrm*)pNewAnchorFrm)->FindMaster();
690                     }
691                     if ( pNewAnchorFrm->IsProtected() )
692                     {
693                         pNewAnchorFrm = 0;
694                     }
695                     else
696                     {
697                         SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() );
698                         aNewAnch.SetType( _eAnchorType );
699                         aNewAnch.SetAnchor( &aPos );
700                     }
701                 }
702                 break;
703 
704             case FLY_AT_FLY: // LAYER_IMPL
705                 {
706                     //Ausgehend von der linken oberen Ecke des Fly den
707                     //dichtesten SwFlyFrm suchen.
708                     SwFrm *pTxtFrm;
709                     {
710                         SwCrsrMoveState aState( MV_SETONLYTEXT );
711                         SwPosition aPos( GetNodes() );
712                         Point aPoint( aPt );
713                         aPoint.X() -= 1;
714                         GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState );
715                         // OD 20.06.2003 #108784# - consider that drawing objects
716                         // can be in header/footer. Thus, <GetFrm()> by left-top-corner
717                         pTxtFrm = aPos.nNode.GetNode().
718                                         GetCntntNode()->getLayoutFrm( GetCurrentLayout(), &aPt, 0, sal_False );
719                     }
720                     const SwFrm *pTmp = ::FindAnchor( pTxtFrm, aPt );
721                     pNewAnchorFrm = pTmp->FindFlyFrm();
722                     if( pNewAnchorFrm && !pNewAnchorFrm->IsProtected() )
723                     {
724                         const SwFrmFmt *pTmpFmt = ((SwFlyFrm*)pNewAnchorFrm)->GetFmt();
725                         const SwFmtCntnt& rCntnt = pTmpFmt->GetCntnt();
726                         SwPosition aPos( *rCntnt.GetCntntIdx() );
727                         aNewAnch.SetAnchor( &aPos );
728                         break;
729                     }
730 
731                     aNewAnch.SetType( FLY_AT_PAGE );
732                     // no break
733                 }
734             case FLY_AT_PAGE:
735                 {
736                     pNewAnchorFrm = GetCurrentLayout()->Lower();
737                     while ( pNewAnchorFrm && !pNewAnchorFrm->Frm().IsInside( aPt ) )
738                         pNewAnchorFrm = pNewAnchorFrm->GetNext();
739                     if ( !pNewAnchorFrm )
740                         continue;
741 
742                     aNewAnch.SetPageNum( ((SwPageFrm*)pNewAnchorFrm)->GetPhyPageNum());
743                 }
744                 break;
745             case FLY_AS_CHAR:
746                 if( _bSameOnly )    // Positions/Groessenaenderung
747                 {
748                     if( !pOldAnchorFrm )
749                     {
750                         pContact->ConnectToLayout();
751                         pOldAnchorFrm = pContact->GetAnchorFrm();
752                     }
753                     ((SwTxtFrm*)pOldAnchorFrm)->Prepare();
754                 }
755                 else            // Ankerwechsel
756                 {
757                     // OD 18.06.2003 #108784# - allow drawing objects in header/footer
758                     pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aPt, false );
759                     if( pNewAnchorFrm->IsProtected() )
760                     {
761                         pNewAnchorFrm = 0;
762                         break;
763                     }
764 
765                     bUnmark = ( 0 != i );
766                     Point aPoint( aPt );
767                     aPoint.X() -= 1;    // nicht im DrawObj landen!!
768                     aNewAnch.SetType( FLY_AS_CHAR );
769                     SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() );
770                     if ( pNewAnchorFrm->Frm().IsInside( aPoint ) )
771                     {
772                     // es muss ein TextNode gefunden werden, denn nur dort
773                     // ist ein inhaltsgebundenes DrawObjekt zu verankern
774                         SwCrsrMoveState aState( MV_SETONLYTEXT );
775                         GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState );  //swmod 080218
776                     }
777                     else
778                     {
779                         SwCntntNode &rCNd = (SwCntntNode&)
780                             *((SwCntntFrm*)pNewAnchorFrm)->GetNode();
781                         if ( pNewAnchorFrm->Frm().Bottom() < aPt.Y() )
782                             rCNd.MakeStartIndex( &aPos.nContent );
783                         else
784                             rCNd.MakeEndIndex( &aPos.nContent );
785                     }
786                     aNewAnch.SetAnchor( &aPos );
787                     SetAttr( aNewAnch, *pContact->GetFmt() );
788                     // OD 2004-04-13 #i26791# - adjust vertical positioning to
789                     // 'center to baseline'
790                     SetAttr( SwFmtVertOrient( 0, text::VertOrientation::CENTER, text::RelOrientation::FRAME ), *pContact->GetFmt() );
791                     SwTxtNode *pNd = aPos.nNode.GetNode().GetTxtNode();
792                     ASSERT( pNd, "Cursor not positioned at TxtNode." );
793 
794                     SwFmtFlyCnt aFmt( pContact->GetFmt() );
795                     pNd->InsertItem( aFmt, aPos.nContent.GetIndex(), 0 );
796                 }
797                 break;
798             default:
799                 ASSERT( !this, "unexpected AnchorId." );
800             }
801 
802             if ( (FLY_AS_CHAR != _eAnchorType) &&
803                  pNewAnchorFrm &&
804                  ( !_bSameOnly || pNewAnchorFrm != pOldAnchorFrm ) )
805             {
806                 // OD 2004-04-06 #i26791# - Direct object positioning no longer
807                 // needed. Apply of attributes (method call <SetAttr(..)>) takes
808                 // care of the invalidation of the object position.
809                 SetAttr( aNewAnch, *pContact->GetFmt() );
810                 if ( _bPosCorr )
811                 {
812                     // --> OD 2004-08-24 #i33313# - consider not connected
813                     // 'virtual' drawing objects
814                     if ( pObj->ISA(SwDrawVirtObj) &&
815                          !static_cast<SwDrawVirtObj*>(pObj)->IsConnected() )
816                     {
817                         SwRect aNewObjRect( aObjRect );
818                         static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( 0L ))
819                                         ->AdjustPositioningAttr( pNewAnchorFrm,
820                                                                  &aNewObjRect );
821 
822                     }
823                     else
824                     {
825                         static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( pObj ))
826                                     ->AdjustPositioningAttr( pNewAnchorFrm );
827                     }
828                 }
829             }
830 
831             // --> OD 2006-03-01 #i54336#
832             if ( pNewAnchorFrm && pOldAsCharAnchorPos )
833             {
834                 //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet
835                 //werden. Leider reisst dies neben den Frms auch noch das Format mit
836                 //in sein Grab. Um dass zu unterbinden loesen wir vorher die
837                 //Verbindung zwischen Attribut und Format.
838                 const xub_StrLen nIndx( pOldAsCharAnchorPos->nContent.GetIndex() );
839                 SwTxtNode* pTxtNode( pOldAsCharAnchorPos->nNode.GetNode().GetTxtNode() );
840                 ASSERT( pTxtNode, "<SwDoc::ChgAnchor(..)> - missing previous anchor text node for as-character anchored object" );
841                 ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
842                 SwTxtAttr * const pHnt =
843                     pTxtNode->GetTxtAttrForCharAt( nIndx, RES_TXTATR_FLYCNT );
844                 const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt();
845 
846                 //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet
847                 //werden.
848                 pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIndx, nIndx );
849                 delete pOldAsCharAnchorPos;
850             }
851             // <--
852         }
853     }
854 
855     GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
856     SetModified();
857 
858     return bUnmark;
859 }
860 
861 
862 int SwDoc::Chainable( const SwFrmFmt &rSource, const SwFrmFmt &rDest )
863 {
864     //Die Source darf noch keinen Follow haben.
865     const SwFmtChain &rOldChain = rSource.GetChain();
866     if ( rOldChain.GetNext() )
867         return SW_CHAIN_SOURCE_CHAINED;
868 
869     //Ziel darf natuerlich nicht gleich Source sein und es
870     //darf keine geschlossene Kette entstehen.
871     const SwFrmFmt *pFmt = &rDest;
872     do {
873         if( pFmt == &rSource )
874             return SW_CHAIN_SELF;
875         pFmt = pFmt->GetChain().GetNext();
876     } while ( pFmt );
877 
878     //Auch eine Verkettung von Innen nach aussen oder von aussen
879     //nach innen ist nicht zulaessig.
880     if( rDest.IsLowerOf( rSource ) || rSource .IsLowerOf( rDest ) )
881         return SW_CHAIN_SELF;
882 
883     //Das Ziel darf noch keinen Master haben.
884     const SwFmtChain &rChain = rDest.GetChain();
885     if( rChain.GetPrev() )
886         return SW_CHAIN_IS_IN_CHAIN;
887 
888     //Das Ziel muss leer sein.
889     const SwNodeIndex* pCntIdx = rDest.GetCntnt().GetCntntIdx();
890     if( !pCntIdx )
891         return SW_CHAIN_NOT_FOUND;
892 
893     SwNodeIndex aNxtIdx( *pCntIdx, 1 );
894     const SwTxtNode* pTxtNd = aNxtIdx.GetNode().GetTxtNode();
895     if( !pTxtNd )
896         return SW_CHAIN_NOT_FOUND;
897 
898     const sal_uLong nFlySttNd = pCntIdx->GetIndex();
899     if( 2 != ( pCntIdx->GetNode().EndOfSectionIndex() - nFlySttNd ) ||
900         pTxtNd->GetTxt().Len() )
901         return SW_CHAIN_NOT_EMPTY;
902 
903     sal_uInt16 nArrLen = GetSpzFrmFmts()->Count();
904     for( sal_uInt16 n = 0; n < nArrLen; ++n )
905     {
906         const SwFmtAnchor& rAnchor = (*GetSpzFrmFmts())[ n ]->GetAnchor();
907         sal_uLong nTstSttNd;
908         // OD 11.12.2003 #i20622# - to-frame anchored objects are allowed.
909         if ( ((rAnchor.GetAnchorId() == FLY_AT_PARA) ||
910               (rAnchor.GetAnchorId() == FLY_AT_CHAR)) &&
911              0 != rAnchor.GetCntntAnchor() &&
912              nFlySttNd <= ( nTstSttNd =
913                         rAnchor.GetCntntAnchor()->nNode.GetIndex() ) &&
914              nTstSttNd < nFlySttNd + 2 )
915         {
916             return SW_CHAIN_NOT_EMPTY;
917         }
918     }
919 
920     //Auf die richtige Area muessen wir auch noch einen Blick werfen.
921     //Beide Flys muessen im selben Bereich (Body, Head/Foot, Fly) sitzen
922     //Wenn die Source nicht der selektierte Rahmen ist, so reicht es
923     //Wenn ein passender gefunden wird (Der Wunsch kann z.B. von der API
924     //kommen).
925 
926     // both in the same fly, header, footer or on the page?
927     const SwFmtAnchor &rSrcAnchor = rSource.GetAnchor(),
928                       &rDstAnchor = rDest.GetAnchor();
929     sal_uLong nEndOfExtras = GetNodes().GetEndOfExtras().GetIndex();
930     sal_Bool bAllowed = sal_False;
931     if ( FLY_AT_PAGE == rSrcAnchor.GetAnchorId() )
932     {
933         if ( (FLY_AT_PAGE == rDstAnchor.GetAnchorId()) ||
934             ( rDstAnchor.GetCntntAnchor() &&
935               rDstAnchor.GetCntntAnchor()->nNode.GetIndex() > nEndOfExtras ))
936             bAllowed = sal_True;
937     }
938     else if( rSrcAnchor.GetCntntAnchor() && rDstAnchor.GetCntntAnchor() )
939     {
940         const SwNodeIndex &rSrcIdx = rSrcAnchor.GetCntntAnchor()->nNode,
941                             &rDstIdx = rDstAnchor.GetCntntAnchor()->nNode;
942         const SwStartNode* pSttNd = 0;
943         if( rSrcIdx == rDstIdx ||
944             ( !pSttNd &&
945                 0 != ( pSttNd = rSrcIdx.GetNode().FindFlyStartNode() ) &&
946                 pSttNd == rDstIdx.GetNode().FindFlyStartNode() ) ||
947             ( !pSttNd &&
948                 0 != ( pSttNd = rSrcIdx.GetNode().FindFooterStartNode() ) &&
949                 pSttNd == rDstIdx.GetNode().FindFooterStartNode() ) ||
950             ( !pSttNd &&
951                 0 != ( pSttNd = rSrcIdx.GetNode().FindHeaderStartNode() ) &&
952                 pSttNd == rDstIdx.GetNode().FindHeaderStartNode() ) ||
953             ( !pSttNd && rDstIdx.GetIndex() > nEndOfExtras &&
954                             rSrcIdx.GetIndex() > nEndOfExtras ))
955             bAllowed = sal_True;
956     }
957 
958     return bAllowed ? SW_CHAIN_OK : SW_CHAIN_WRONG_AREA;
959 }
960 
961 int SwDoc::Chain( SwFrmFmt &rSource, const SwFrmFmt &rDest )
962 {
963     int nErr = Chainable( rSource, rDest );
964     if ( !nErr )
965     {
966         GetIDocumentUndoRedo().StartUndo( UNDO_CHAINE, NULL );
967 
968         SwFlyFrmFmt& rDestFmt = (SwFlyFrmFmt&)rDest;
969 
970         //Follow an den Master haengen.
971         SwFmtChain aChain = rDestFmt.GetChain();
972         aChain.SetPrev( &(SwFlyFrmFmt&)rSource );
973         SetAttr( aChain, rDestFmt );
974 
975         SfxItemSet aSet( GetAttrPool(), RES_FRM_SIZE, RES_FRM_SIZE,
976                                         RES_CHAIN,  RES_CHAIN, 0 );
977 
978         //Follow an den Master haengen.
979         aChain.SetPrev( &(SwFlyFrmFmt&)rSource );
980         SetAttr( aChain, rDestFmt );
981 
982         //Master an den Follow haengen und dafuer sorgen, dass der Master
983         //eine fixierte Hoehe hat.
984         aChain = rSource.GetChain();
985         aChain.SetNext( &rDestFmt );
986         aSet.Put( aChain );
987 
988         SwFmtFrmSize aSize( rSource.GetFrmSize() );
989         if ( aSize.GetHeightSizeType() != ATT_FIX_SIZE )
990         {
991             SwFlyFrm *pFly = SwIterator<SwFlyFrm,SwFmt>::FirstElement( rSource );
992             if ( pFly )
993                 aSize.SetHeight( pFly->Frm().Height() );
994             aSize.SetHeightSizeType( ATT_FIX_SIZE );
995             aSet.Put( aSize );
996         }
997         SetAttr( aSet, rSource );
998 
999         GetIDocumentUndoRedo().EndUndo( UNDO_CHAINE, NULL );
1000     }
1001     return nErr;
1002 }
1003 
1004 void SwDoc::Unchain( SwFrmFmt &rFmt )
1005 {
1006     SwFmtChain aChain( rFmt.GetChain() );
1007     if ( aChain.GetNext() )
1008     {
1009         GetIDocumentUndoRedo().StartUndo( UNDO_UNCHAIN, NULL );
1010         SwFrmFmt *pFollow = aChain.GetNext();
1011         aChain.SetNext( 0 );
1012         SetAttr( aChain, rFmt );
1013         aChain = pFollow->GetChain();
1014         aChain.SetPrev( 0 );
1015         SetAttr( aChain, *pFollow );
1016         GetIDocumentUndoRedo().EndUndo( UNDO_UNCHAIN, NULL );
1017     }
1018 }
1019 
1020 
1021 
1022