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 72 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. 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 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 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 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 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# 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 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 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 598 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 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 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 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 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