Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <hintids.hxx>
21 : #include <svl/itemiter.hxx>
22 : #include <svx/svdobj.hxx>
23 : #include <svx/svdpage.hxx>
24 : #include <svx/svdmodel.hxx>
25 : #include <svx/svdocapt.hxx>
26 : #include <svx/svdmark.hxx>
27 : #include <fmtfsize.hxx>
28 : #include <fmtornt.hxx>
29 : #include <fmtsrnd.hxx>
30 : #include <dcontact.hxx>
31 : #include <ndgrf.hxx>
32 : #include <doc.hxx>
33 : #include <IDocumentUndoRedo.hxx>
34 : #include <IDocumentDrawModelAccess.hxx>
35 : #include <IDocumentState.hxx>
36 : #include <IDocumentLayoutAccess.hxx>
37 : #include <ndindex.hxx>
38 : #include <docary.hxx>
39 : #include <drawdoc.hxx>
40 : #include <fmtcntnt.hxx>
41 : #include <fmtanchr.hxx>
42 : #include <txtflcnt.hxx>
43 : #include <fmtflcnt.hxx>
44 : #include <txtfrm.hxx>
45 : #include <pagefrm.hxx>
46 : #include <rootfrm.hxx>
47 : #include <flyfrms.hxx>
48 : #include <textboxhelper.hxx>
49 : #include <frmtool.hxx>
50 : #include <frmfmt.hxx>
51 : #include <ndtxt.hxx>
52 : #include <pam.hxx>
53 : #include <tblsel.hxx>
54 : #include <swundo.hxx>
55 : #include <swtable.hxx>
56 : #include <crstate.hxx>
57 : #include <UndoCore.hxx>
58 : #include <UndoAttribute.hxx>
59 : #include <fmtcnct.hxx>
60 : #include <dflyobj.hxx>
61 : #include <undoflystrattr.hxx>
62 : #include <switerator.hxx>
63 : #include <boost/scoped_ptr.hpp>
64 :
65 : //UUUU
66 : #include <svx/xbtmpit.hxx>
67 : #include <svx/xflftrit.hxx>
68 : #include <svx/xlndsit.hxx>
69 : #include <svx/xlnstit.hxx>
70 : #include <svx/xlnedit.hxx>
71 : #include <svx/xflhtit.hxx>
72 :
73 : using namespace ::com::sun::star;
74 :
75 592 : sal_uInt16 SwDoc::GetFlyCount( FlyCntType eType, bool bIgnoreTextBoxes ) const
76 : {
77 592 : const SwFrmFmts& rFmts = *GetSpzFrmFmts();
78 592 : sal_uInt16 nSize = rFmts.size();
79 592 : sal_uInt16 nCount = 0;
80 : const SwNodeIndex* pIdx;
81 :
82 592 : std::set<const SwFrmFmt*> aTextBoxes;
83 592 : if (bIgnoreTextBoxes)
84 536 : aTextBoxes = SwTextBoxHelper::findTextBoxes(this);
85 :
86 1128 : for ( sal_uInt16 i = 0; i < nSize; i++)
87 : {
88 536 : const SwFrmFmt* pFlyFmt = rFmts[ i ];
89 :
90 536 : if (bIgnoreTextBoxes && aTextBoxes.find(pFlyFmt) != aTextBoxes.end())
91 8 : continue;
92 :
93 1056 : if( RES_FLYFRMFMT == pFlyFmt->Which()
94 258 : && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() )
95 786 : && pIdx->GetNodes().IsDocNodes()
96 : )
97 : {
98 258 : const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ];
99 :
100 258 : switch( eType )
101 : {
102 : case FLYCNTTYPE_FRM:
103 196 : if(!pNd->IsNoTxtNode())
104 174 : nCount++;
105 196 : break;
106 :
107 : case FLYCNTTYPE_GRF:
108 30 : if( pNd->IsGrfNode() )
109 12 : nCount++;
110 30 : break;
111 :
112 : case FLYCNTTYPE_OLE:
113 32 : if(pNd->IsOLENode())
114 14 : nCount++;
115 32 : break;
116 :
117 : default:
118 0 : nCount++;
119 : }
120 : }
121 : }
122 592 : return nCount;
123 : }
124 :
125 : /// @attention If you change this, also update SwXFrameEnumeration in unocoll.
126 158 : SwFrmFmt* SwDoc::GetFlyNum( sal_uInt16 nIdx, FlyCntType eType, bool bIgnoreTextBoxes )
127 : {
128 158 : SwFrmFmts& rFmts = *GetSpzFrmFmts();
129 158 : SwFrmFmt* pRetFmt = 0;
130 158 : sal_uInt16 nSize = rFmts.size();
131 : const SwNodeIndex* pIdx;
132 158 : sal_uInt16 nCount = 0;
133 :
134 158 : std::set<const SwFrmFmt*> aTextBoxes;
135 158 : if (bIgnoreTextBoxes)
136 62 : aTextBoxes = SwTextBoxHelper::findTextBoxes(this);
137 :
138 406 : for( sal_uInt16 i = 0; !pRetFmt && i < nSize; ++i )
139 : {
140 248 : SwFrmFmt* pFlyFmt = rFmts[ i ];
141 :
142 248 : if (bIgnoreTextBoxes && aTextBoxes.find(pFlyFmt) != aTextBoxes.end())
143 0 : continue;
144 :
145 496 : if( RES_FLYFRMFMT == pFlyFmt->Which()
146 198 : && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() )
147 446 : && pIdx->GetNodes().IsDocNodes()
148 : )
149 : {
150 198 : const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ];
151 198 : switch( eType )
152 : {
153 : case FLYCNTTYPE_FRM:
154 124 : if( !pNd->IsNoTxtNode() && nIdx == nCount++)
155 98 : pRetFmt = pFlyFmt;
156 124 : break;
157 : case FLYCNTTYPE_GRF:
158 16 : if(pNd->IsGrfNode() && nIdx == nCount++ )
159 10 : pRetFmt = pFlyFmt;
160 16 : break;
161 : case FLYCNTTYPE_OLE:
162 58 : if(pNd->IsOLENode() && nIdx == nCount++)
163 44 : pRetFmt = pFlyFmt;
164 58 : break;
165 : default:
166 0 : if(nIdx == nCount++)
167 0 : pRetFmt = pFlyFmt;
168 : }
169 : }
170 : }
171 158 : return pRetFmt;
172 : }
173 :
174 532 : static Point lcl_FindAnchorLayPos( SwDoc& rDoc, const SwFmtAnchor& rAnch,
175 : const SwFrmFmt* pFlyFmt )
176 : {
177 532 : Point aRet;
178 532 : if( rDoc.getIDocumentLayoutAccess().GetCurrentViewShell() )
179 40 : switch( rAnch.GetAnchorId() )
180 : {
181 : case FLY_AS_CHAR:
182 8 : if( pFlyFmt && rAnch.GetCntntAnchor() )
183 : {
184 2 : const SwFrm* pOld = ((SwFlyFrmFmt*)pFlyFmt)->GetFrm( &aRet, false );
185 2 : if( pOld )
186 2 : aRet = pOld->Frm().Pos();
187 : }
188 8 : break;
189 :
190 : case FLY_AT_PARA:
191 : case FLY_AT_CHAR: // LAYER_IMPL
192 20 : if( rAnch.GetCntntAnchor() )
193 : {
194 20 : const SwPosition *pPos = rAnch.GetCntntAnchor();
195 20 : const SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode();
196 20 : const SwFrm* pOld = pNd ? pNd->getLayoutFrm( rDoc.getIDocumentLayoutAccess().GetCurrentLayout(), &aRet, 0, false ) : 0;
197 20 : if( pOld )
198 20 : aRet = pOld->Frm().Pos();
199 : }
200 20 : break;
201 :
202 : case FLY_AT_FLY: // LAYER_IMPL
203 0 : if( rAnch.GetCntntAnchor() )
204 : {
205 0 : const SwFlyFrmFmt* pFmt = (SwFlyFrmFmt*)rAnch.GetCntntAnchor()->
206 0 : nNode.GetNode().GetFlyFmt();
207 0 : const SwFrm* pOld = pFmt ? pFmt->GetFrm( &aRet, false ) : 0;
208 0 : if( pOld )
209 0 : aRet = pOld->Frm().Pos();
210 : }
211 0 : break;
212 :
213 : case FLY_AT_PAGE:
214 : {
215 12 : sal_uInt16 nPgNum = rAnch.GetPageNum();
216 12 : const SwPageFrm *pPage = (SwPageFrm*)rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->Lower();
217 12 : for( sal_uInt16 i = 1; (i <= nPgNum) && pPage; ++i,
218 0 : pPage = (const SwPageFrm*)pPage->GetNext() )
219 12 : if( i == nPgNum )
220 : {
221 12 : aRet = pPage->Frm().Pos();
222 12 : break;
223 : }
224 : }
225 12 : break;
226 : default:
227 0 : break;
228 : }
229 532 : return aRet;
230 : }
231 :
232 : #define MAKEFRMS 0
233 : #define IGNOREANCHOR 1
234 : #define DONTMAKEFRMS 2
235 :
236 528 : sal_Int8 SwDoc::SetFlyFrmAnchor( SwFrmFmt& rFmt, SfxItemSet& rSet, bool bNewFrms )
237 : {
238 : // Changing anchors is almost always allowed.
239 : // Exception: Paragraph and character bound frames must not become
240 : // page bound, if they are located in the header or footer.
241 528 : const SwFmtAnchor &rOldAnch = rFmt.GetAnchor();
242 528 : const RndStdIds nOld = rOldAnch.GetAnchorId();
243 :
244 528 : SwFmtAnchor aNewAnch( (SwFmtAnchor&)rSet.Get( RES_ANCHOR ) );
245 528 : RndStdIds nNew = aNewAnch.GetAnchorId();
246 :
247 : // Is the new anchor valid?
248 530 : if( !aNewAnch.GetCntntAnchor() && (FLY_AT_FLY == nNew ||
249 4 : (FLY_AT_PARA == nNew) || (FLY_AS_CHAR == nNew) ||
250 : (FLY_AT_CHAR == nNew) ))
251 : {
252 2 : return IGNOREANCHOR;
253 : }
254 :
255 526 : if( nOld == nNew )
256 260 : return DONTMAKEFRMS;
257 :
258 266 : Point aOldAnchorPos( ::lcl_FindAnchorLayPos( *this, rOldAnch, &rFmt ));
259 266 : Point aNewAnchorPos( ::lcl_FindAnchorLayPos( *this, aNewAnch, 0 ));
260 :
261 : // Destroy the old Frames.
262 : // The Views are hidden implicitly, so hiding them another time would be
263 : // kind of a show!
264 266 : rFmt.DelFrms();
265 :
266 266 : if ( FLY_AS_CHAR == nOld )
267 : {
268 : // We need to handle InCntnts in a special way:
269 : // The TxtAttribut needs to be destroyed which, unfortunately, also
270 : // destroys the format. To avoid that, we disconnect the format from
271 : // the attribute.
272 2 : const SwPosition *pPos = rOldAnch.GetCntntAnchor();
273 2 : SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode();
274 : OSL_ENSURE( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
275 2 : const sal_Int32 nIdx = pPos->nContent.GetIndex();
276 : SwTxtAttr * const pHnt =
277 2 : pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT );
278 : OSL_ENSURE( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT,
279 : "Missing FlyInCnt-Hint." );
280 : OSL_ENSURE( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == &rFmt,
281 : "Wrong TxtFlyCnt-Hint." );
282 2 : if (pHnt)
283 2 : const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt();
284 :
285 : // They are disconnected. We now have to destroy the attribute.
286 2 : pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx );
287 : }
288 :
289 : // We can finally set the attribute. It needs to be the first one!
290 : // Undo depends on it!
291 266 : rFmt.SetFmtAttr( aNewAnch );
292 :
293 : // Correct the position
294 : const SfxPoolItem* pItem;
295 266 : switch( nNew )
296 : {
297 : case FLY_AS_CHAR:
298 : // If no position attributes are received, we have to make sure
299 : // that no forbidden automatic alignment is left.
300 : {
301 14 : const SwPosition *pPos = aNewAnch.GetCntntAnchor();
302 14 : SwTxtNode *pNd = pPos->nNode.GetNode().GetTxtNode();
303 : OSL_ENSURE( pNd, "Crsr does not point to TxtNode." );
304 :
305 14 : SwFmtFlyCnt aFmt( static_cast<SwFlyFrmFmt*>(&rFmt) );
306 14 : pNd->InsertItem( aFmt, pPos->nContent.GetIndex(), 0 );
307 : }
308 :
309 14 : if( SfxItemState::SET != rSet.GetItemState( RES_VERT_ORIENT, false, &pItem ))
310 : {
311 14 : SwFmtVertOrient aOldV( rFmt.GetVertOrient() );
312 14 : bool bSet = true;
313 14 : switch( aOldV.GetVertOrient() )
314 : {
315 2 : case text::VertOrientation::LINE_TOP: aOldV.SetVertOrient( text::VertOrientation::TOP ); break;
316 0 : case text::VertOrientation::LINE_CENTER: aOldV.SetVertOrient( text::VertOrientation::CENTER); break;
317 0 : case text::VertOrientation::LINE_BOTTOM: aOldV.SetVertOrient( text::VertOrientation::BOTTOM); break;
318 0 : case text::VertOrientation::NONE: aOldV.SetVertOrient( text::VertOrientation::CENTER); break;
319 : default:
320 12 : bSet = false;
321 : }
322 14 : if( bSet )
323 2 : rSet.Put( aOldV );
324 : }
325 14 : break;
326 :
327 : case FLY_AT_PARA:
328 : case FLY_AT_CHAR: // LAYER_IMPL
329 : case FLY_AT_FLY: // LAYER_IMPL
330 : case FLY_AT_PAGE:
331 : {
332 : // If no position attributes are coming in, we correct the position in a way
333 : // such that the fly's document coordinates are preserved.
334 : // If only the alignment changes in the position attributes (text::RelOrientation::FRAME
335 : // vs. text::RelOrientation::PRTAREA), we also correct the position.
336 252 : if( SfxItemState::SET != rSet.GetItemState( RES_HORI_ORIENT, false, &pItem ))
337 252 : pItem = 0;
338 :
339 252 : SwFmtHoriOrient aOldH( rFmt.GetHoriOrient() );
340 :
341 252 : if( text::HoriOrientation::NONE == aOldH.GetHoriOrient() && ( !pItem ||
342 0 : aOldH.GetPos() == ((SwFmtHoriOrient*)pItem)->GetPos() ))
343 : {
344 178 : SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldH.GetPos();
345 178 : nPos += aOldAnchorPos.getX() - aNewAnchorPos.getX();
346 :
347 178 : if( pItem )
348 : {
349 0 : SwFmtHoriOrient* pH = (SwFmtHoriOrient*)pItem;
350 0 : aOldH.SetHoriOrient( pH->GetHoriOrient() );
351 0 : aOldH.SetRelationOrient( pH->GetRelationOrient() );
352 : }
353 178 : aOldH.SetPos( nPos );
354 178 : rSet.Put( aOldH );
355 : }
356 :
357 252 : if( SfxItemState::SET != rSet.GetItemState( RES_VERT_ORIENT, false, &pItem ))
358 252 : pItem = 0;
359 504 : SwFmtVertOrient aOldV( rFmt.GetVertOrient() );
360 :
361 : // #i28922# - correction: compare <aOldV.GetVertOrient() with
362 : // <text::VertOrientation::NONE>
363 252 : if( text::VertOrientation::NONE == aOldV.GetVertOrient() && (!pItem ||
364 0 : aOldV.GetPos() == ((SwFmtVertOrient*)pItem)->GetPos() ) )
365 : {
366 230 : SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldV.GetPos();
367 230 : nPos += aOldAnchorPos.getY() - aNewAnchorPos.getY();
368 230 : if( pItem )
369 : {
370 0 : SwFmtVertOrient* pV = (SwFmtVertOrient*)pItem;
371 0 : aOldV.SetVertOrient( pV->GetVertOrient() );
372 0 : aOldV.SetRelationOrient( pV->GetRelationOrient() );
373 : }
374 230 : aOldV.SetPos( nPos );
375 230 : rSet.Put( aOldV );
376 252 : }
377 : }
378 252 : break;
379 : default:
380 0 : break;
381 : }
382 :
383 266 : if( bNewFrms )
384 0 : rFmt.MakeFrms();
385 :
386 266 : return MAKEFRMS;
387 : }
388 :
389 : static bool
390 572 : lcl_SetFlyFrmAttr(SwDoc & rDoc,
391 : sal_Int8 (SwDoc::*pSetFlyFrmAnchor)(SwFrmFmt &, SfxItemSet &, bool),
392 : SwFrmFmt & rFlyFmt, SfxItemSet & rSet)
393 : {
394 : // #i32968# Inserting columns in the frame causes MakeFrmFmt to put two
395 : // objects of type SwUndoFrmFmt on the undo stack. We don't want them.
396 572 : ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
397 :
398 : // Is the anchor attribute included?
399 : // If so, we pass it to a special method, which returns sal_True
400 : // if the Fly needs to be created anew, because we e.g change the FlyType.
401 : sal_Int8 const nMakeFrms =
402 572 : (SfxItemState::SET == rSet.GetItemState( RES_ANCHOR, false ))
403 522 : ? (rDoc.*pSetFlyFrmAnchor)( rFlyFmt, rSet, false )
404 1094 : : DONTMAKEFRMS;
405 :
406 : const SfxPoolItem* pItem;
407 1144 : SfxItemIter aIter( rSet );
408 1144 : SfxItemSet aTmpSet( rDoc.GetAttrPool(), aFrmFmtSetRange );
409 572 : sal_uInt16 nWhich = aIter.GetCurItem()->Which();
410 140 : do {
411 712 : switch( nWhich )
412 : {
413 : case RES_FILL_ORDER:
414 : case RES_BREAK:
415 : case RES_PAGEDESC:
416 : case RES_CNTNT:
417 : case RES_FOOTER:
418 : OSL_FAIL( "Unknown Fly attribute." );
419 : // no break;
420 : case RES_CHAIN:
421 0 : rSet.ClearItem( nWhich );
422 0 : break;
423 : case RES_ANCHOR:
424 522 : if( DONTMAKEFRMS != nMakeFrms )
425 262 : break;
426 :
427 : default:
428 1054 : if( !IsInvalidItem( aIter.GetCurItem() ) && ( SfxItemState::SET !=
429 840 : rFlyFmt.GetAttrSet().GetItemState( nWhich, true, &pItem ) ||
430 390 : *pItem != *aIter.GetCurItem() ))
431 154 : aTmpSet.Put( *aIter.GetCurItem() );
432 450 : break;
433 : }
434 :
435 712 : if( aIter.IsAtEnd() )
436 572 : break;
437 :
438 140 : } while( 0 != ( nWhich = aIter.NextItem()->Which() ) );
439 :
440 572 : if( aTmpSet.Count() )
441 84 : rFlyFmt.SetFmtAttr( aTmpSet );
442 :
443 572 : if( MAKEFRMS == nMakeFrms )
444 262 : rFlyFmt.MakeFrms();
445 :
446 1144 : return aTmpSet.Count() || MAKEFRMS == nMakeFrms;
447 : }
448 :
449 693788 : void SwDoc::CheckForUniqueItemForLineFillNameOrIndex(SfxItemSet& rSet)
450 : {
451 693788 : SwDrawModel* pDrawModel = getIDocumentDrawModelAccess().GetOrCreateDrawModel();
452 693788 : SfxItemIter aIter(rSet);
453 :
454 4136448 : for(const SfxPoolItem* pItem = aIter.FirstItem(); pItem; pItem = aIter.NextItem())
455 : {
456 3442660 : if (IsInvalidItem(pItem))
457 0 : continue;
458 3442660 : const SfxPoolItem* pResult = NULL;
459 :
460 3442660 : switch(pItem->Which())
461 : {
462 : case XATTR_FILLBITMAP:
463 : {
464 28 : pResult = static_cast< const XFillBitmapItem* >(pItem)->checkForUniqueItem(pDrawModel);
465 28 : break;
466 : }
467 : case XATTR_LINEDASH:
468 : {
469 0 : pResult = static_cast< const XLineDashItem* >(pItem)->checkForUniqueItem(pDrawModel);
470 0 : break;
471 : }
472 : case XATTR_LINESTART:
473 : {
474 0 : pResult = static_cast< const XLineStartItem* >(pItem)->checkForUniqueItem(pDrawModel);
475 0 : break;
476 : }
477 : case XATTR_LINEEND:
478 : {
479 0 : pResult = static_cast< const XLineEndItem* >(pItem)->checkForUniqueItem(pDrawModel);
480 0 : break;
481 : }
482 : case XATTR_FILLGRADIENT:
483 : {
484 38 : pResult = static_cast< const XFillGradientItem* >(pItem)->checkForUniqueItem(pDrawModel);
485 38 : break;
486 : }
487 : case XATTR_FILLFLOATTRANSPARENCE:
488 : {
489 0 : pResult = static_cast< const XFillFloatTransparenceItem* >(pItem)->checkForUniqueItem(pDrawModel);
490 0 : break;
491 : }
492 : case XATTR_FILLHATCH:
493 : {
494 0 : pResult = static_cast< const XFillHatchItem* >(pItem)->checkForUniqueItem(pDrawModel);
495 0 : break;
496 : }
497 : }
498 :
499 3442660 : if(pResult)
500 : {
501 30 : rSet.Put(*pResult);
502 30 : delete pResult;
503 : }
504 693788 : }
505 693788 : }
506 :
507 572 : bool SwDoc::SetFlyFrmAttr( SwFrmFmt& rFlyFmt, SfxItemSet& rSet )
508 : {
509 572 : if( !rSet.Count() )
510 0 : return false;
511 :
512 572 : boost::scoped_ptr<SwUndoFmtAttrHelper> pSaveUndo;
513 :
514 572 : if (GetIDocumentUndoRedo().DoesUndo())
515 : {
516 38 : GetIDocumentUndoRedo().ClearRedo(); // AppendUndo far below, so leave it
517 38 : pSaveUndo.reset( new SwUndoFmtAttrHelper( rFlyFmt ) );
518 : }
519 :
520 572 : bool const bRet = lcl_SetFlyFrmAttr(*this, &SwDoc::SetFlyFrmAnchor, rFlyFmt, rSet);
521 :
522 572 : if ( pSaveUndo.get() )
523 : {
524 38 : if ( pSaveUndo->GetUndo() )
525 : {
526 36 : GetIDocumentUndoRedo().AppendUndo( pSaveUndo->ReleaseUndo() );
527 : }
528 : }
529 :
530 572 : getIDocumentState().SetModified();
531 :
532 572 : SwTextBoxHelper::syncFlyFrmAttr(rFlyFmt, rSet);
533 :
534 572 : return bRet;
535 : }
536 :
537 : // #i73249#
538 448 : void SwDoc::SetFlyFrmTitle( SwFlyFrmFmt& rFlyFrmFmt,
539 : const OUString& sNewTitle )
540 : {
541 448 : if ( rFlyFrmFmt.GetObjTitle() == sNewTitle )
542 : {
543 894 : return;
544 : }
545 :
546 2 : ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo());
547 :
548 2 : if (GetIDocumentUndoRedo().DoesUndo())
549 : {
550 0 : GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt,
551 : UNDO_FLYFRMFMT_TITLE,
552 : rFlyFrmFmt.GetObjTitle(),
553 0 : sNewTitle ) );
554 : }
555 :
556 2 : rFlyFrmFmt.SetObjTitle( sNewTitle, true );
557 :
558 2 : getIDocumentState().SetModified();
559 : }
560 :
561 460 : void SwDoc::SetFlyFrmDescription( SwFlyFrmFmt& rFlyFrmFmt,
562 : const OUString& sNewDescription )
563 : {
564 460 : if ( rFlyFrmFmt.GetObjDescription() == sNewDescription )
565 : {
566 764 : return;
567 : }
568 :
569 156 : ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo());
570 :
571 156 : if (GetIDocumentUndoRedo().DoesUndo())
572 : {
573 0 : GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt,
574 : UNDO_FLYFRMFMT_DESCRIPTION,
575 : rFlyFrmFmt.GetObjDescription(),
576 0 : sNewDescription ) );
577 : }
578 :
579 156 : rFlyFrmFmt.SetObjDescription( sNewDescription, true );
580 :
581 156 : getIDocumentState().SetModified();
582 : }
583 :
584 36 : bool SwDoc::SetFrmFmtToFly( SwFrmFmt& rFmt, SwFrmFmt& rNewFmt,
585 : SfxItemSet* pSet, bool bKeepOrient )
586 : {
587 36 : bool bChgAnchor = false, bFrmSz = false;
588 :
589 36 : const SwFmtFrmSize aFrmSz( rFmt.GetFrmSize() );
590 72 : const SwFmtVertOrient aVert( rFmt.GetVertOrient() );
591 72 : const SwFmtHoriOrient aHori( rFmt.GetHoriOrient() );
592 :
593 36 : SwUndoSetFlyFmt* pUndo = 0;
594 36 : bool const bUndo = GetIDocumentUndoRedo().DoesUndo();
595 36 : if (bUndo)
596 : {
597 16 : pUndo = new SwUndoSetFlyFmt( rFmt, rNewFmt );
598 16 : GetIDocumentUndoRedo().AppendUndo(pUndo);
599 : }
600 :
601 : // #i32968# Inserting columns in the section causes MakeFrmFmt to put
602 : // 2 objects of type SwUndoFrmFmt on the undo stack. We don't want them.
603 72 : ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
604 :
605 : // Set the column first, or we'll have trouble with
606 : //Set/Reset/Synch. and so on
607 : const SfxPoolItem* pItem;
608 36 : if( SfxItemState::SET != rNewFmt.GetAttrSet().GetItemState( RES_COL ))
609 36 : rFmt.ResetFmtAttr( RES_COL );
610 :
611 36 : if( rFmt.DerivedFrom() != &rNewFmt )
612 : {
613 18 : rFmt.SetDerivedFrom( &rNewFmt );
614 :
615 : // 1. If not automatic = ignore; else = dispose
616 : // 2. Dispose of it!
617 18 : if( SfxItemState::SET == rNewFmt.GetAttrSet().GetItemState( RES_FRM_SIZE, false ))
618 : {
619 0 : rFmt.ResetFmtAttr( RES_FRM_SIZE );
620 0 : bFrmSz = true;
621 : }
622 :
623 18 : const SfxItemSet* pAsk = pSet;
624 18 : if( !pAsk ) pAsk = &rNewFmt.GetAttrSet();
625 36 : if( SfxItemState::SET == pAsk->GetItemState( RES_ANCHOR, false, &pItem )
626 26 : && ((SwFmtAnchor*)pItem)->GetAnchorId() !=
627 8 : rFmt.GetAnchor().GetAnchorId() )
628 : {
629 6 : if( pSet )
630 4 : bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, *pSet, false );
631 : else
632 : {
633 : // Needs to have the FlyFmt range, because we set attributes in it,
634 : // in SetFlyFrmAnchor.
635 2 : SfxItemSet aFlySet( *rNewFmt.GetAttrSet().GetPool(),
636 4 : rNewFmt.GetAttrSet().GetRanges() );
637 2 : aFlySet.Put( *pItem );
638 2 : bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, aFlySet, false);
639 : }
640 : }
641 : }
642 :
643 : // Only reset vertical and horizontal orientation, if we have automatic alignment
644 : // set in the template. Otherwise use the old value.
645 : // If we update the frame template the Fly should NOT lose its orientation (which
646 : // is not being updated!).
647 : // text::HoriOrientation::NONE and text::VertOrientation::NONE are allowed now
648 36 : if (!bKeepOrient)
649 : {
650 36 : rFmt.ResetFmtAttr(RES_VERT_ORIENT);
651 36 : rFmt.ResetFmtAttr(RES_HORI_ORIENT);
652 : }
653 :
654 36 : rFmt.ResetFmtAttr( RES_PRINT, RES_SURROUND );
655 36 : rFmt.ResetFmtAttr( RES_LR_SPACE, RES_UL_SPACE );
656 36 : rFmt.ResetFmtAttr( RES_BACKGROUND, RES_COL );
657 36 : rFmt.ResetFmtAttr( RES_URL, RES_EDIT_IN_READONLY );
658 :
659 36 : if( !bFrmSz )
660 36 : rFmt.SetFmtAttr( aFrmSz );
661 :
662 36 : if( bChgAnchor )
663 4 : rFmt.MakeFrms();
664 :
665 36 : if( pUndo )
666 16 : pUndo->DeRegisterFromFormat( rFmt );
667 :
668 36 : getIDocumentState().SetModified();
669 :
670 72 : return bChgAnchor;
671 : }
672 :
673 22 : void SwDoc::GetGrfNms( const SwFlyFrmFmt& rFmt, OUString* pGrfName,
674 : OUString* pFltName ) const
675 : {
676 22 : SwNodeIndex aIdx( *rFmt.GetCntnt().GetCntntIdx(), 1 );
677 22 : const SwGrfNode* pGrfNd = aIdx.GetNode().GetGrfNode();
678 22 : if( pGrfNd && pGrfNd->IsLinkedFile() )
679 12 : pGrfNd->GetFileFilterNms( pGrfName, pFltName );
680 22 : }
681 :
682 0 : bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList,
683 : RndStdIds _eAnchorType,
684 : const bool _bSameOnly,
685 : const bool _bPosCorr )
686 : {
687 : OSL_ENSURE( getIDocumentLayoutAccess().GetCurrentLayout(), "No layout!" );
688 :
689 0 : if ( !_rMrkList.GetMarkCount() ||
690 0 : _rMrkList.GetMark( 0 )->GetMarkedSdrObj()->GetUpGroup() )
691 : {
692 0 : return false;
693 : }
694 :
695 0 : GetIDocumentUndoRedo().StartUndo( UNDO_INSATTR, NULL );
696 :
697 0 : bool bUnmark = false;
698 0 : for ( size_t i = 0; i < _rMrkList.GetMarkCount(); ++i )
699 : {
700 0 : SdrObject* pObj = _rMrkList.GetMark( i )->GetMarkedSdrObj();
701 0 : if ( !pObj->ISA(SwVirtFlyDrawObj) )
702 : {
703 0 : SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));
704 :
705 : // consider, that drawing object has
706 : // no user call. E.g.: a 'virtual' drawing object is disconnected by
707 : // the anchor type change of the 'master' drawing object.
708 : // Continue with next selected object and assert, if this isn't excepted.
709 0 : if ( !pContact )
710 : {
711 : #if OSL_DEBUG_LEVEL > 0
712 : bool bNoUserCallExcepted =
713 : pObj->ISA(SwDrawVirtObj) &&
714 : !static_cast<SwDrawVirtObj*>(pObj)->IsConnected();
715 : OSL_ENSURE( bNoUserCallExcepted, "SwDoc::ChgAnchor(..) - no contact at selected drawing object" );
716 : #endif
717 0 : continue;
718 : }
719 :
720 : // #i26791#
721 0 : const SwFrm* pOldAnchorFrm = pContact->GetAnchorFrm( pObj );
722 0 : const SwFrm* pNewAnchorFrm = pOldAnchorFrm;
723 :
724 : // #i54336#
725 : // Instead of only keeping the index position for an as-character
726 : // anchored object the complete <SwPosition> is kept, because the
727 : // anchor index position could be moved, if the object again is
728 : // anchored as character.
729 0 : boost::scoped_ptr<const SwPosition> xOldAsCharAnchorPos;
730 0 : const RndStdIds eOldAnchorType = pContact->GetAnchorId();
731 0 : if ( !_bSameOnly && eOldAnchorType == FLY_AS_CHAR )
732 : {
733 0 : xOldAsCharAnchorPos.reset(new SwPosition(pContact->GetCntntAnchor()));
734 : }
735 :
736 0 : if ( _bSameOnly )
737 0 : _eAnchorType = eOldAnchorType;
738 :
739 0 : SwFmtAnchor aNewAnch( _eAnchorType );
740 0 : Rectangle aObjRect( pContact->GetAnchoredObj( pObj )->GetObjRect().SVRect() );
741 0 : const Point aPt( aObjRect.TopLeft() );
742 :
743 0 : switch ( _eAnchorType )
744 : {
745 : case FLY_AT_PARA:
746 : case FLY_AT_CHAR:
747 : {
748 0 : const Point aNewPoint = ( pOldAnchorFrm->IsVertical() ||
749 0 : pOldAnchorFrm->IsRightToLeft() )
750 : ? aObjRect.TopRight()
751 0 : : aPt;
752 :
753 : // allow drawing objects in header/footer
754 0 : pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aNewPoint, false );
755 0 : if ( pNewAnchorFrm->IsTxtFrm() && ((SwTxtFrm*)pNewAnchorFrm)->IsFollow() )
756 : {
757 0 : pNewAnchorFrm = ((SwTxtFrm*)pNewAnchorFrm)->FindMaster();
758 : }
759 0 : if ( pNewAnchorFrm->IsProtected() )
760 : {
761 0 : pNewAnchorFrm = 0;
762 : }
763 : else
764 : {
765 0 : SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() );
766 0 : aNewAnch.SetType( _eAnchorType );
767 0 : aNewAnch.SetAnchor( &aPos );
768 : }
769 : }
770 0 : break;
771 :
772 : case FLY_AT_FLY: // LAYER_IMPL
773 : {
774 : // Search the closest SwFlyFrm starting from the upper left corner.
775 : SwFrm *pTxtFrm;
776 : {
777 0 : SwCrsrMoveState aState( MV_SETONLYTEXT );
778 0 : SwPosition aPos( GetNodes() );
779 0 : Point aPoint( aPt );
780 0 : aPoint.setX(aPoint.getX() - 1);
781 0 : getIDocumentLayoutAccess().GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState );
782 : // consider that drawing objects can be in
783 : // header/footer. Thus, <GetFrm()> by left-top-corner
784 0 : pTxtFrm = aPos.nNode.GetNode().
785 0 : GetCntntNode()->getLayoutFrm( getIDocumentLayoutAccess().GetCurrentLayout(), &aPt, 0, false );
786 : }
787 0 : const SwFrm *pTmp = ::FindAnchor( pTxtFrm, aPt );
788 0 : pNewAnchorFrm = pTmp->FindFlyFrm();
789 0 : if( pNewAnchorFrm && !pNewAnchorFrm->IsProtected() )
790 : {
791 0 : const SwFrmFmt *pTmpFmt = ((SwFlyFrm*)pNewAnchorFrm)->GetFmt();
792 0 : const SwFmtCntnt& rCntnt = pTmpFmt->GetCntnt();
793 0 : SwPosition aPos( *rCntnt.GetCntntIdx() );
794 0 : aNewAnch.SetAnchor( &aPos );
795 0 : break;
796 : }
797 :
798 0 : aNewAnch.SetType( FLY_AT_PAGE );
799 : // no break
800 : }
801 : case FLY_AT_PAGE:
802 : {
803 0 : pNewAnchorFrm = getIDocumentLayoutAccess().GetCurrentLayout()->Lower();
804 0 : while ( pNewAnchorFrm && !pNewAnchorFrm->Frm().IsInside( aPt ) )
805 0 : pNewAnchorFrm = pNewAnchorFrm->GetNext();
806 0 : if ( !pNewAnchorFrm )
807 0 : continue;
808 :
809 0 : aNewAnch.SetPageNum( ((SwPageFrm*)pNewAnchorFrm)->GetPhyPageNum());
810 : }
811 0 : break;
812 : case FLY_AS_CHAR:
813 0 : if( _bSameOnly ) // Change of position/size
814 : {
815 0 : if( !pOldAnchorFrm )
816 : {
817 0 : pContact->ConnectToLayout();
818 0 : pOldAnchorFrm = pContact->GetAnchorFrm();
819 : }
820 0 : ((SwTxtFrm*)pOldAnchorFrm)->Prepare();
821 : }
822 : else // Change of anchors
823 : {
824 : // allow drawing objects in header/footer
825 0 : pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aPt, false );
826 0 : if( pNewAnchorFrm->IsProtected() )
827 : {
828 0 : pNewAnchorFrm = 0;
829 0 : break;
830 : }
831 :
832 0 : bUnmark = ( 0 != i );
833 0 : Point aPoint( aPt );
834 0 : aPoint.setX(aPoint.getX() - 1); // Do not load in the DrawObj!
835 0 : aNewAnch.SetType( FLY_AS_CHAR );
836 0 : SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() );
837 0 : if ( pNewAnchorFrm->Frm().IsInside( aPoint ) )
838 : {
839 : // We need to find a TextNode, because only there we can anchor a
840 : // content-bound DrawObject.
841 0 : SwCrsrMoveState aState( MV_SETONLYTEXT );
842 0 : getIDocumentLayoutAccess().GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState );
843 : }
844 : else
845 : {
846 : SwCntntNode &rCNd = (SwCntntNode&)
847 0 : *((SwCntntFrm*)pNewAnchorFrm)->GetNode();
848 0 : if ( pNewAnchorFrm->Frm().Bottom() < aPt.Y() )
849 0 : rCNd.MakeStartIndex( &aPos.nContent );
850 : else
851 0 : rCNd.MakeEndIndex( &aPos.nContent );
852 : }
853 0 : aNewAnch.SetAnchor( &aPos );
854 0 : SetAttr( aNewAnch, *pContact->GetFmt() );
855 : // #i26791# - adjust vertical positioning to 'center to
856 : // baseline'
857 0 : SetAttr( SwFmtVertOrient( 0, text::VertOrientation::CENTER, text::RelOrientation::FRAME ), *pContact->GetFmt() );
858 0 : SwTxtNode *pNd = aPos.nNode.GetNode().GetTxtNode();
859 : OSL_ENSURE( pNd, "Cursor not positioned at TxtNode." );
860 :
861 0 : SwFmtFlyCnt aFmt( pContact->GetFmt() );
862 0 : pNd->InsertItem( aFmt, aPos.nContent.GetIndex(), 0 );
863 : }
864 0 : break;
865 : default:
866 : OSL_ENSURE( false, "unexpected AnchorId." );
867 : }
868 :
869 0 : if ( (FLY_AS_CHAR != _eAnchorType) &&
870 0 : pNewAnchorFrm &&
871 0 : ( !_bSameOnly || pNewAnchorFrm != pOldAnchorFrm ) )
872 : {
873 : // #i26791# - Direct object positioning no longer needed. Apply
874 : // of attributes (method call <SetAttr(..)>) takes care of the
875 : // invalidation of the object position.
876 0 : SetAttr( aNewAnch, *pContact->GetFmt() );
877 0 : if ( _bPosCorr )
878 : {
879 : // #i33313# - consider not connected 'virtual' drawing
880 : // objects
881 0 : if ( pObj->ISA(SwDrawVirtObj) &&
882 0 : !static_cast<SwDrawVirtObj*>(pObj)->IsConnected() )
883 : {
884 0 : SwRect aNewObjRect( aObjRect );
885 0 : static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( 0L ))
886 : ->AdjustPositioningAttr( pNewAnchorFrm,
887 0 : &aNewObjRect );
888 : }
889 : else
890 : {
891 0 : static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( pObj ))
892 0 : ->AdjustPositioningAttr( pNewAnchorFrm );
893 : }
894 : }
895 : }
896 :
897 : // #i54336#
898 0 : if (xOldAsCharAnchorPos)
899 : {
900 0 : if ( pNewAnchorFrm)
901 : {
902 : // We need to handle InCntnts in a special way:
903 : // The TxtAttribut needs to be destroyed which, unfortunately, also
904 : // destroys the format. To avoid that, we disconnect the format from
905 : // the attribute.
906 0 : const sal_Int32 nIndx( xOldAsCharAnchorPos->nContent.GetIndex() );
907 0 : SwTxtNode* pTxtNode( xOldAsCharAnchorPos->nNode.GetNode().GetTxtNode() );
908 : OSL_ENSURE( pTxtNode, "<SwDoc::ChgAnchor(..)> - missing previous anchor text node for as-character anchored object" );
909 : OSL_ENSURE( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." );
910 : SwTxtAttr * const pHnt =
911 0 : pTxtNode->GetTxtAttrForCharAt( nIndx, RES_TXTATR_FLYCNT );
912 0 : const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt();
913 :
914 : // They are disconnected. We now have to destroy the attribute.
915 0 : pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIndx, nIndx );
916 : }
917 0 : }
918 : }
919 : }
920 :
921 0 : GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
922 0 : getIDocumentState().SetModified();
923 :
924 0 : return bUnmark;
925 : }
926 :
927 26 : int SwDoc::Chainable( const SwFrmFmt &rSource, const SwFrmFmt &rDest )
928 : {
929 : // The Source must not yet have a Follow.
930 26 : const SwFmtChain &rOldChain = rSource.GetChain();
931 26 : if ( rOldChain.GetNext() )
932 18 : return SW_CHAIN_SOURCE_CHAINED;
933 :
934 : // Target must not be equal to Source and we also must not have a closed chain.
935 8 : const SwFrmFmt *pFmt = &rDest;
936 8 : do {
937 8 : if( pFmt == &rSource )
938 0 : return SW_CHAIN_SELF;
939 8 : pFmt = pFmt->GetChain().GetNext();
940 : } while ( pFmt );
941 :
942 : // There must not be a chaining from outside to inside or the other way around.
943 8 : if( rDest.IsLowerOf( rSource ) || rSource .IsLowerOf( rDest ) )
944 0 : return SW_CHAIN_SELF;
945 :
946 : // The Target must not yet have a Master.
947 8 : const SwFmtChain &rChain = rDest.GetChain();
948 8 : if( rChain.GetPrev() )
949 0 : return SW_CHAIN_IS_IN_CHAIN;
950 :
951 : // Target must be empty.
952 8 : const SwNodeIndex* pCntIdx = rDest.GetCntnt().GetCntntIdx();
953 8 : if( !pCntIdx )
954 0 : return SW_CHAIN_NOT_FOUND;
955 :
956 8 : SwNodeIndex aNxtIdx( *pCntIdx, 1 );
957 8 : const SwTxtNode* pTxtNd = aNxtIdx.GetNode().GetTxtNode();
958 8 : if( !pTxtNd )
959 0 : return SW_CHAIN_NOT_FOUND;
960 :
961 8 : const sal_uLong nFlySttNd = pCntIdx->GetIndex();
962 16 : if( 2 != ( pCntIdx->GetNode().EndOfSectionIndex() - nFlySttNd ) ||
963 8 : pTxtNd->GetTxt().getLength() )
964 : {
965 0 : return SW_CHAIN_NOT_EMPTY;
966 : }
967 :
968 8 : sal_uInt16 nArrLen = GetSpzFrmFmts()->size();
969 68 : for( sal_uInt16 n = 0; n < nArrLen; ++n )
970 : {
971 60 : const SwFmtAnchor& rAnchor = (*GetSpzFrmFmts())[ n ]->GetAnchor();
972 : sal_uLong nTstSttNd;
973 : // #i20622# - to-frame anchored objects are allowed.
974 120 : if ( ((rAnchor.GetAnchorId() == FLY_AT_PARA) ||
975 60 : (rAnchor.GetAnchorId() == FLY_AT_CHAR)) &&
976 120 : 0 != rAnchor.GetCntntAnchor() &&
977 : nFlySttNd <= ( nTstSttNd =
978 180 : rAnchor.GetCntntAnchor()->nNode.GetIndex() ) &&
979 60 : nTstSttNd < nFlySttNd + 2 )
980 : {
981 0 : return SW_CHAIN_NOT_EMPTY;
982 : }
983 : }
984 :
985 : // We also need to consider the right area.
986 : // Both Flys need to be located in the same area (Body, Header/Footer, Fly).
987 : // If the Source is not the selected frame, it's enough to find a suitable
988 : // one. e.g. if it's requested by the API.
989 :
990 : // both in the same fly, header, footer or on the page?
991 8 : const SwFmtAnchor &rSrcAnchor = rSource.GetAnchor(),
992 8 : &rDstAnchor = rDest.GetAnchor();
993 8 : sal_uLong nEndOfExtras = GetNodes().GetEndOfExtras().GetIndex();
994 8 : bool bAllowed = false;
995 8 : if ( FLY_AT_PAGE == rSrcAnchor.GetAnchorId() )
996 : {
997 0 : if ( (FLY_AT_PAGE == rDstAnchor.GetAnchorId()) ||
998 0 : ( rDstAnchor.GetCntntAnchor() &&
999 0 : rDstAnchor.GetCntntAnchor()->nNode.GetIndex() > nEndOfExtras ))
1000 0 : bAllowed = true;
1001 : }
1002 8 : else if( rSrcAnchor.GetCntntAnchor() && rDstAnchor.GetCntntAnchor() )
1003 : {
1004 8 : const SwNodeIndex &rSrcIdx = rSrcAnchor.GetCntntAnchor()->nNode,
1005 8 : &rDstIdx = rDstAnchor.GetCntntAnchor()->nNode;
1006 8 : const SwStartNode* pSttNd = 0;
1007 18 : if( rSrcIdx == rDstIdx ||
1008 2 : ( !pSttNd &&
1009 2 : 0 != ( pSttNd = rSrcIdx.GetNode().FindFlyStartNode() ) &&
1010 2 : pSttNd == rDstIdx.GetNode().FindFlyStartNode() ) ||
1011 2 : ( !pSttNd &&
1012 2 : 0 != ( pSttNd = rSrcIdx.GetNode().FindFooterStartNode() ) &&
1013 2 : pSttNd == rDstIdx.GetNode().FindFooterStartNode() ) ||
1014 2 : ( !pSttNd &&
1015 2 : 0 != ( pSttNd = rSrcIdx.GetNode().FindHeaderStartNode() ) &&
1016 18 : pSttNd == rDstIdx.GetNode().FindHeaderStartNode() ) ||
1017 4 : ( !pSttNd && rDstIdx.GetIndex() > nEndOfExtras &&
1018 2 : rSrcIdx.GetIndex() > nEndOfExtras ))
1019 8 : bAllowed = true;
1020 : }
1021 :
1022 8 : return bAllowed ? SW_CHAIN_OK : SW_CHAIN_WRONG_AREA;
1023 : }
1024 :
1025 26 : int SwDoc::Chain( SwFrmFmt &rSource, const SwFrmFmt &rDest )
1026 : {
1027 26 : int nErr = Chainable( rSource, rDest );
1028 26 : if ( !nErr )
1029 : {
1030 8 : GetIDocumentUndoRedo().StartUndo( UNDO_CHAINE, NULL );
1031 :
1032 8 : SwFlyFrmFmt& rDestFmt = (SwFlyFrmFmt&)rDest;
1033 :
1034 : // Attach Follow to the Master.
1035 8 : SwFmtChain aChain = rDestFmt.GetChain();
1036 8 : aChain.SetPrev( &(SwFlyFrmFmt&)rSource );
1037 8 : SetAttr( aChain, rDestFmt );
1038 :
1039 8 : SfxItemSet aSet( GetAttrPool(), RES_FRM_SIZE, RES_FRM_SIZE,
1040 16 : RES_CHAIN, RES_CHAIN, 0 );
1041 :
1042 : // Attach Follow to the Master.
1043 8 : aChain.SetPrev( &(SwFlyFrmFmt&)rSource );
1044 8 : SetAttr( aChain, rDestFmt );
1045 :
1046 : // Attach Master to the Follow.
1047 : // Make sure that the Master has a fixed height.
1048 8 : aChain = rSource.GetChain();
1049 8 : aChain.SetNext( &rDestFmt );
1050 8 : aSet.Put( aChain );
1051 :
1052 16 : SwFmtFrmSize aSize( rSource.GetFrmSize() );
1053 8 : if ( aSize.GetHeightSizeType() != ATT_FIX_SIZE )
1054 : {
1055 0 : SwFlyFrm *pFly = SwIterator<SwFlyFrm,SwFmt>::FirstElement( rSource );
1056 0 : if ( pFly )
1057 0 : aSize.SetHeight( pFly->Frm().Height() );
1058 0 : aSize.SetHeightSizeType( ATT_FIX_SIZE );
1059 0 : aSet.Put( aSize );
1060 : }
1061 8 : SetAttr( aSet, rSource );
1062 :
1063 16 : GetIDocumentUndoRedo().EndUndo( UNDO_CHAINE, NULL );
1064 : }
1065 26 : return nErr;
1066 : }
1067 :
1068 0 : void SwDoc::Unchain( SwFrmFmt &rFmt )
1069 : {
1070 0 : SwFmtChain aChain( rFmt.GetChain() );
1071 0 : if ( aChain.GetNext() )
1072 : {
1073 0 : GetIDocumentUndoRedo().StartUndo( UNDO_UNCHAIN, NULL );
1074 0 : SwFrmFmt *pFollow = aChain.GetNext();
1075 0 : aChain.SetNext( 0 );
1076 0 : SetAttr( aChain, rFmt );
1077 0 : aChain = pFollow->GetChain();
1078 0 : aChain.SetPrev( 0 );
1079 0 : SetAttr( aChain, *pFollow );
1080 0 : GetIDocumentUndoRedo().EndUndo( UNDO_UNCHAIN, NULL );
1081 0 : }
1082 270 : }
1083 :
1084 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|