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