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