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