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