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
GetFlyCount(FlyCntType eType) const75 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.
GetFlyNum(sal_uInt16 nIdx,FlyCntType eType)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
lcl_FindAnchorLayPos(SwDoc & rDoc,const SwFmtAnchor & rAnch,const SwFrmFmt * pFlyFmt)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
SetFlyFrmAnchor(SwFrmFmt & rFmt,SfxItemSet & rSet,sal_Bool bNewFrms)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
lcl_SetFlyFrmAttr(SwDoc & rDoc,sal_Int8 (SwDoc::* pSetFlyFrmAnchor)(SwFrmFmt &,SfxItemSet &,sal_Bool),SwFrmFmt & rFlyFmt,SfxItemSet & rSet)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
CheckForUniqueItemForLineFillNameOrIndex(SfxItemSet & rSet)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
SetFlyFrmAttr(SwFrmFmt & rFlyFmt,SfxItemSet & rSet)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#
SetFlyFrmTitle(SwFlyFrmFmt & rFlyFrmFmt,const String & sNewTitle)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
SetFlyFrmDescription(SwFlyFrmFmt & rFlyFrmFmt,const String & sNewDescription)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
SetFrmFmtToFly(SwFrmFmt & rFmt,SwFrmFmt & rNewFmt,SfxItemSet * pSet,sal_Bool bKeepOrient)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
GetGrfNms(const SwFlyFrmFmt & rFmt,String * pGrfName,String * pFltName) const656 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
ChgAnchor(const SdrMarkList & _rMrkList,RndStdIds _eAnchorType,const sal_Bool _bSameOnly,const sal_Bool _bPosCorr)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( sal_False, "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
Chainable(const SwFrmFmt & rSource,const SwFrmFmt & rDest)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
Chain(SwFrmFmt & rSource,const SwFrmFmt & rDest)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
Unchain(SwFrmFmt & rFmt)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