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