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 //UUUU Need to check for unique item for DrawingLayer items of type NameOrIndex 509 // and evtl. correct that item to ensure unique names for that type. This call may 510 // modify/correct entries inside of the given SfxItemSet 511 CheckForUniqueItemForLineFillNameOrIndex(rSet); 512 513 bool const bRet = 514 lcl_SetFlyFrmAttr(*this, &SwDoc::SetFlyFrmAnchor, rFlyFmt, rSet); 515 516 if ( pSaveUndo.get() ) 517 { 518 if ( pSaveUndo->GetUndo() ) 519 { 520 GetIDocumentUndoRedo().AppendUndo( pSaveUndo->ReleaseUndo() ); 521 } 522 } 523 524 SetModified(); 525 526 return bRet; 527 } 528 529 // --> OD 2009-07-20 #i73249# 530 void SwDoc::SetFlyFrmTitle( SwFlyFrmFmt& rFlyFrmFmt, 531 const String& sNewTitle ) 532 { 533 if ( rFlyFrmFmt.GetObjTitle() == sNewTitle ) 534 { 535 return; 536 } 537 538 ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo()); 539 540 if (GetIDocumentUndoRedo().DoesUndo()) 541 { 542 GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt, 543 UNDO_FLYFRMFMT_TITLE, 544 rFlyFrmFmt.GetObjTitle(), 545 sNewTitle ) ); 546 } 547 548 rFlyFrmFmt.SetObjTitle( sNewTitle, true ); 549 550 SetModified(); 551 } 552 553 void SwDoc::SetFlyFrmDescription( SwFlyFrmFmt& rFlyFrmFmt, 554 const String& sNewDescription ) 555 { 556 if ( rFlyFrmFmt.GetObjDescription() == sNewDescription ) 557 { 558 return; 559 } 560 561 ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo()); 562 563 if (GetIDocumentUndoRedo().DoesUndo()) 564 { 565 GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt, 566 UNDO_FLYFRMFMT_DESCRIPTION, 567 rFlyFrmFmt.GetObjDescription(), 568 sNewDescription ) ); 569 } 570 571 rFlyFrmFmt.SetObjDescription( sNewDescription, true ); 572 573 SetModified(); 574 } 575 // <-- 576 577 sal_Bool SwDoc::SetFrmFmtToFly( SwFrmFmt& rFmt, SwFrmFmt& rNewFmt, 578 SfxItemSet* pSet, sal_Bool bKeepOrient ) 579 { 580 sal_Bool bChgAnchor = sal_False, bFrmSz = sal_False; 581 582 const SwFmtFrmSize aFrmSz( rFmt.GetFrmSize() ); 583 const SwFmtVertOrient aVert( rFmt.GetVertOrient() ); 584 const SwFmtHoriOrient aHori( rFmt.GetHoriOrient() ); 585 586 SwUndoSetFlyFmt* pUndo = 0; 587 bool const bUndo = GetIDocumentUndoRedo().DoesUndo(); 588 if (bUndo) 589 { 590 pUndo = new SwUndoSetFlyFmt( rFmt, rNewFmt ); 591 GetIDocumentUndoRedo().AppendUndo(pUndo); 592 } 593 594 // #i32968# Inserting columns in the section causes MakeFrmFmt to put 595 // 2 objects of type SwUndoFrmFmt on the undo stack. We don't want them. 596 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); 597 598 //Erstmal die Spalten setzen, sonst gibts nix als Aerger mit dem 599 //Set/Reset/Abgleich usw. 600 const SfxPoolItem* pItem; 601 if( SFX_ITEM_SET != rNewFmt.GetAttrSet().GetItemState( RES_COL )) 602 rFmt.ResetFmtAttr( RES_COL ); 603 604 if( rFmt.DerivedFrom() != &rNewFmt ) 605 { 606 rFmt.SetDerivedFrom( &rNewFmt ); 607 608 // 1. wenn nicht automatisch -> ignorieren, sonst -> wech 609 // 2. wech damit, MB! 610 if( SFX_ITEM_SET == rNewFmt.GetAttrSet().GetItemState( RES_FRM_SIZE, sal_False )) 611 { 612 rFmt.ResetFmtAttr( RES_FRM_SIZE ); 613 bFrmSz = sal_True; 614 } 615 616 const SfxItemSet* pAsk = pSet; 617 if( !pAsk ) pAsk = &rNewFmt.GetAttrSet(); 618 if( SFX_ITEM_SET == pAsk->GetItemState( RES_ANCHOR, sal_False, &pItem ) 619 && ((SwFmtAnchor*)pItem)->GetAnchorId() != 620 rFmt.GetAnchor().GetAnchorId() ) 621 { 622 if( pSet ) 623 bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, *pSet, sal_False ); 624 else 625 { 626 //JP 23.04.98: muss den FlyFmt-Range haben, denn im SetFlyFrmAnchor 627 // werden Attribute in diesen gesetzt! 628 SfxItemSet aFlySet( *rNewFmt.GetAttrSet().GetPool(), 629 rNewFmt.GetAttrSet().GetRanges() ); 630 aFlySet.Put( *pItem ); 631 bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, aFlySet, sal_False); 632 } 633 } 634 } 635 636 //Hori und Vert nur dann resetten, wenn in der Vorlage eine 637 //automatische Ausrichtung eingestellt ist, anderfalls den alten Wert 638 //wieder hineinstopfen. 639 //JP 09.06.98: beim Update der RahmenVorlage sollte der Fly NICHT 640 // seine Orientierng verlieren (diese wird nicht geupdatet!) 641 //OS: #96584# text::HoriOrientation::NONE and text::VertOrientation::NONE are allowed now 642 if (!bKeepOrient) 643 { 644 rFmt.ResetFmtAttr(RES_VERT_ORIENT); 645 rFmt.ResetFmtAttr(RES_HORI_ORIENT); 646 } 647 648 rFmt.ResetFmtAttr( RES_PRINT, RES_SURROUND ); 649 rFmt.ResetFmtAttr( RES_LR_SPACE, RES_UL_SPACE ); 650 rFmt.ResetFmtAttr( RES_BACKGROUND, RES_COL ); 651 rFmt.ResetFmtAttr( RES_URL, RES_EDIT_IN_READONLY ); 652 653 if( !bFrmSz ) 654 rFmt.SetFmtAttr( aFrmSz ); 655 656 if( bChgAnchor ) 657 rFmt.MakeFrms(); 658 659 if( pUndo ) 660 pUndo->DeRegisterFromFormat( rFmt ); 661 662 SetModified(); 663 664 return bChgAnchor; 665 } 666 667 void SwDoc::GetGrfNms( const SwFlyFrmFmt& rFmt, String* pGrfName, 668 String* pFltName ) const 669 { 670 SwNodeIndex aIdx( *rFmt.GetCntnt().GetCntntIdx(), 1 ); 671 const SwGrfNode* pGrfNd = aIdx.GetNode().GetGrfNode(); 672 if( pGrfNd && pGrfNd->IsLinkedFile() ) 673 pGrfNd->GetFileFilterNms( pGrfName, pFltName ); 674 } 675 676 sal_Bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList, 677 RndStdIds _eAnchorType, 678 const sal_Bool _bSameOnly, 679 const sal_Bool _bPosCorr ) 680 { 681 ASSERT( GetCurrentLayout(), "Ohne Layout geht gar nichts" ); //swmod 080218 682 683 if ( !_rMrkList.GetMarkCount() || 684 _rMrkList.GetMark( 0 )->GetMarkedSdrObj()->GetUpGroup() ) 685 { 686 return false; 687 } 688 689 GetIDocumentUndoRedo().StartUndo( UNDO_INSATTR, NULL ); 690 691 sal_Bool bUnmark = sal_False; 692 for ( sal_uInt16 i = 0; i < _rMrkList.GetMarkCount(); ++i ) 693 { 694 SdrObject* pObj = _rMrkList.GetMark( i )->GetMarkedSdrObj(); 695 if ( !pObj->ISA(SwVirtFlyDrawObj) ) 696 { 697 SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)); 698 699 // OD 27.06.2003 #108784# - consider, that drawing object has 700 // no user call. E.g.: a 'virtual' drawing object is disconnected by 701 // the anchor type change of the 'master' drawing object. 702 // Continue with next selected object and assert, if this isn't excepted. 703 if ( !pContact ) 704 { 705 #ifdef DBG_UTIL 706 bool bNoUserCallExcepted = 707 pObj->ISA(SwDrawVirtObj) && 708 !static_cast<SwDrawVirtObj*>(pObj)->IsConnected(); 709 ASSERT( bNoUserCallExcepted, "SwDoc::ChgAnchor(..) - no contact at selected drawing object" ); 710 #endif 711 continue; 712 } 713 714 // OD 2004-03-29 #i26791# 715 const SwFrm* pOldAnchorFrm = pContact->GetAnchorFrm( pObj ); 716 const SwFrm* pNewAnchorFrm = pOldAnchorFrm; 717 718 // --> OD 2006-03-01 #i54336# 719 // Instead of only keeping the index position for an as-character 720 // anchored object the complete <SwPosition> is kept, because the 721 // anchor index position could be moved, if the object again is 722 // anchored as character. 723 // xub_StrLen nIndx = STRING_NOTFOUND; 724 const SwPosition* pOldAsCharAnchorPos( 0L ); 725 const RndStdIds eOldAnchorType = pContact->GetAnchorId(); 726 if ( !_bSameOnly && eOldAnchorType == FLY_AS_CHAR ) 727 { 728 pOldAsCharAnchorPos = new SwPosition( pContact->GetCntntAnchor() ); 729 } 730 // <-- 731 732 if ( _bSameOnly ) 733 _eAnchorType = eOldAnchorType; 734 735 SwFmtAnchor aNewAnch( _eAnchorType ); 736 Rectangle aObjRect( pContact->GetAnchoredObj( pObj )->GetObjRect().SVRect() ); 737 const Point aPt( aObjRect.TopLeft() ); 738 739 switch ( _eAnchorType ) 740 { 741 case FLY_AT_PARA: 742 case FLY_AT_CHAR: 743 { 744 const Point aNewPoint = pOldAnchorFrm && 745 ( pOldAnchorFrm->IsVertical() || 746 pOldAnchorFrm->IsRightToLeft() ) 747 ? aObjRect.TopRight() 748 : aPt; 749 750 // OD 18.06.2003 #108784# - allow drawing objects in header/footer 751 pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aNewPoint, false ); 752 if ( pNewAnchorFrm->IsTxtFrm() && ((SwTxtFrm*)pNewAnchorFrm)->IsFollow() ) 753 { 754 pNewAnchorFrm = ((SwTxtFrm*)pNewAnchorFrm)->FindMaster(); 755 } 756 if ( pNewAnchorFrm->IsProtected() ) 757 { 758 pNewAnchorFrm = 0; 759 } 760 else 761 { 762 SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() ); 763 aNewAnch.SetType( _eAnchorType ); 764 aNewAnch.SetAnchor( &aPos ); 765 } 766 } 767 break; 768 769 case FLY_AT_FLY: // LAYER_IMPL 770 { 771 //Ausgehend von der linken oberen Ecke des Fly den 772 //dichtesten SwFlyFrm suchen. 773 SwFrm *pTxtFrm; 774 { 775 SwCrsrMoveState aState( MV_SETONLYTEXT ); 776 SwPosition aPos( GetNodes() ); 777 Point aPoint( aPt ); 778 aPoint.X() -= 1; 779 GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState ); 780 // OD 20.06.2003 #108784# - consider that drawing objects 781 // can be in header/footer. Thus, <GetFrm()> by left-top-corner 782 pTxtFrm = aPos.nNode.GetNode(). 783 GetCntntNode()->getLayoutFrm( GetCurrentLayout(), &aPt, 0, sal_False ); 784 } 785 const SwFrm *pTmp = ::FindAnchor( pTxtFrm, aPt ); 786 pNewAnchorFrm = pTmp->FindFlyFrm(); 787 if( pNewAnchorFrm && !pNewAnchorFrm->IsProtected() ) 788 { 789 const SwFrmFmt *pTmpFmt = ((SwFlyFrm*)pNewAnchorFrm)->GetFmt(); 790 const SwFmtCntnt& rCntnt = pTmpFmt->GetCntnt(); 791 SwPosition aPos( *rCntnt.GetCntntIdx() ); 792 aNewAnch.SetAnchor( &aPos ); 793 break; 794 } 795 796 aNewAnch.SetType( FLY_AT_PAGE ); 797 // no break 798 } 799 case FLY_AT_PAGE: 800 { 801 pNewAnchorFrm = GetCurrentLayout()->Lower(); 802 while ( pNewAnchorFrm && !pNewAnchorFrm->Frm().IsInside( aPt ) ) 803 pNewAnchorFrm = pNewAnchorFrm->GetNext(); 804 if ( !pNewAnchorFrm ) 805 continue; 806 807 aNewAnch.SetPageNum( ((SwPageFrm*)pNewAnchorFrm)->GetPhyPageNum()); 808 } 809 break; 810 case FLY_AS_CHAR: 811 if( _bSameOnly ) // Positions/Groessenaenderung 812 { 813 if( !pOldAnchorFrm ) 814 { 815 pContact->ConnectToLayout(); 816 pOldAnchorFrm = pContact->GetAnchorFrm(); 817 } 818 ((SwTxtFrm*)pOldAnchorFrm)->Prepare(); 819 } 820 else // Ankerwechsel 821 { 822 // OD 18.06.2003 #108784# - allow drawing objects in header/footer 823 pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aPt, false ); 824 if( pNewAnchorFrm->IsProtected() ) 825 { 826 pNewAnchorFrm = 0; 827 break; 828 } 829 830 bUnmark = ( 0 != i ); 831 Point aPoint( aPt ); 832 aPoint.X() -= 1; // nicht im DrawObj landen!! 833 aNewAnch.SetType( FLY_AS_CHAR ); 834 SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() ); 835 if ( pNewAnchorFrm->Frm().IsInside( aPoint ) ) 836 { 837 // es muss ein TextNode gefunden werden, denn nur dort 838 // ist ein inhaltsgebundenes DrawObjekt zu verankern 839 SwCrsrMoveState aState( MV_SETONLYTEXT ); 840 GetCurrentLayout()->GetCrsrOfst( &aPos, aPoint, &aState ); //swmod 080218 841 } 842 else 843 { 844 SwCntntNode &rCNd = (SwCntntNode&) 845 *((SwCntntFrm*)pNewAnchorFrm)->GetNode(); 846 if ( pNewAnchorFrm->Frm().Bottom() < aPt.Y() ) 847 rCNd.MakeStartIndex( &aPos.nContent ); 848 else 849 rCNd.MakeEndIndex( &aPos.nContent ); 850 } 851 aNewAnch.SetAnchor( &aPos ); 852 SetAttr( aNewAnch, *pContact->GetFmt() ); 853 // OD 2004-04-13 #i26791# - adjust vertical positioning to 854 // 'center to baseline' 855 SetAttr( SwFmtVertOrient( 0, text::VertOrientation::CENTER, text::RelOrientation::FRAME ), *pContact->GetFmt() ); 856 SwTxtNode *pNd = aPos.nNode.GetNode().GetTxtNode(); 857 ASSERT( pNd, "Cursor not positioned at TxtNode." ); 858 859 SwFmtFlyCnt aFmt( pContact->GetFmt() ); 860 pNd->InsertItem( aFmt, aPos.nContent.GetIndex(), 0 ); 861 } 862 break; 863 default: 864 ASSERT( !this, "unexpected AnchorId." ); 865 } 866 867 if ( (FLY_AS_CHAR != _eAnchorType) && 868 pNewAnchorFrm && 869 ( !_bSameOnly || pNewAnchorFrm != pOldAnchorFrm ) ) 870 { 871 // OD 2004-04-06 #i26791# - Direct object positioning no longer 872 // needed. Apply of attributes (method call <SetAttr(..)>) takes 873 // care of the invalidation of the object position. 874 SetAttr( aNewAnch, *pContact->GetFmt() ); 875 if ( _bPosCorr ) 876 { 877 // --> OD 2004-08-24 #i33313# - consider not connected 878 // 'virtual' drawing objects 879 if ( pObj->ISA(SwDrawVirtObj) && 880 !static_cast<SwDrawVirtObj*>(pObj)->IsConnected() ) 881 { 882 SwRect aNewObjRect( aObjRect ); 883 static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( 0L )) 884 ->AdjustPositioningAttr( pNewAnchorFrm, 885 &aNewObjRect ); 886 887 } 888 else 889 { 890 static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( pObj )) 891 ->AdjustPositioningAttr( pNewAnchorFrm ); 892 } 893 } 894 } 895 896 // --> OD 2006-03-01 #i54336# 897 if ( pNewAnchorFrm && pOldAsCharAnchorPos ) 898 { 899 //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet 900 //werden. Leider reisst dies neben den Frms auch noch das Format mit 901 //in sein Grab. Um dass zu unterbinden loesen wir vorher die 902 //Verbindung zwischen Attribut und Format. 903 const xub_StrLen nIndx( pOldAsCharAnchorPos->nContent.GetIndex() ); 904 SwTxtNode* pTxtNode( pOldAsCharAnchorPos->nNode.GetNode().GetTxtNode() ); 905 ASSERT( pTxtNode, "<SwDoc::ChgAnchor(..)> - missing previous anchor text node for as-character anchored object" ); 906 ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); 907 SwTxtAttr * const pHnt = 908 pTxtNode->GetTxtAttrForCharAt( nIndx, RES_TXTATR_FLYCNT ); 909 const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt(); 910 911 //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet 912 //werden. 913 pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIndx, nIndx ); 914 delete pOldAsCharAnchorPos; 915 } 916 // <-- 917 } 918 } 919 920 GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); 921 SetModified(); 922 923 return bUnmark; 924 } 925 926 927 int SwDoc::Chainable( const SwFrmFmt &rSource, const SwFrmFmt &rDest ) 928 { 929 //Die Source darf noch keinen Follow haben. 930 const SwFmtChain &rOldChain = rSource.GetChain(); 931 if ( rOldChain.GetNext() ) 932 return SW_CHAIN_SOURCE_CHAINED; 933 934 //Ziel darf natuerlich nicht gleich Source sein und es 935 //darf keine geschlossene Kette entstehen. 936 const SwFrmFmt *pFmt = &rDest; 937 do { 938 if( pFmt == &rSource ) 939 return SW_CHAIN_SELF; 940 pFmt = pFmt->GetChain().GetNext(); 941 } while ( pFmt ); 942 943 //Auch eine Verkettung von Innen nach aussen oder von aussen 944 //nach innen ist nicht zulaessig. 945 if( rDest.IsLowerOf( rSource ) || rSource .IsLowerOf( rDest ) ) 946 return SW_CHAIN_SELF; 947 948 //Das Ziel darf noch keinen Master haben. 949 const SwFmtChain &rChain = rDest.GetChain(); 950 if( rChain.GetPrev() ) 951 return SW_CHAIN_IS_IN_CHAIN; 952 953 //Das Ziel muss leer sein. 954 const SwNodeIndex* pCntIdx = rDest.GetCntnt().GetCntntIdx(); 955 if( !pCntIdx ) 956 return SW_CHAIN_NOT_FOUND; 957 958 SwNodeIndex aNxtIdx( *pCntIdx, 1 ); 959 const SwTxtNode* pTxtNd = aNxtIdx.GetNode().GetTxtNode(); 960 if( !pTxtNd ) 961 return SW_CHAIN_NOT_FOUND; 962 963 const sal_uLong nFlySttNd = pCntIdx->GetIndex(); 964 if( 2 != ( pCntIdx->GetNode().EndOfSectionIndex() - nFlySttNd ) || 965 pTxtNd->GetTxt().Len() ) 966 return SW_CHAIN_NOT_EMPTY; 967 968 sal_uInt16 nArrLen = GetSpzFrmFmts()->Count(); 969 for( sal_uInt16 n = 0; n < nArrLen; ++n ) 970 { 971 const SwFmtAnchor& rAnchor = (*GetSpzFrmFmts())[ n ]->GetAnchor(); 972 sal_uLong nTstSttNd; 973 // OD 11.12.2003 #i20622# - to-frame anchored objects are allowed. 974 if ( ((rAnchor.GetAnchorId() == FLY_AT_PARA) || 975 (rAnchor.GetAnchorId() == FLY_AT_CHAR)) && 976 0 != rAnchor.GetCntntAnchor() && 977 nFlySttNd <= ( nTstSttNd = 978 rAnchor.GetCntntAnchor()->nNode.GetIndex() ) && 979 nTstSttNd < nFlySttNd + 2 ) 980 { 981 return SW_CHAIN_NOT_EMPTY; 982 } 983 } 984 985 //Auf die richtige Area muessen wir auch noch einen Blick werfen. 986 //Beide Flys muessen im selben Bereich (Body, Head/Foot, Fly) sitzen 987 //Wenn die Source nicht der selektierte Rahmen ist, so reicht es 988 //Wenn ein passender gefunden wird (Der Wunsch kann z.B. von der API 989 //kommen). 990 991 // both in the same fly, header, footer or on the page? 992 const SwFmtAnchor &rSrcAnchor = rSource.GetAnchor(), 993 &rDstAnchor = rDest.GetAnchor(); 994 sal_uLong nEndOfExtras = GetNodes().GetEndOfExtras().GetIndex(); 995 sal_Bool bAllowed = sal_False; 996 if ( FLY_AT_PAGE == rSrcAnchor.GetAnchorId() ) 997 { 998 if ( (FLY_AT_PAGE == rDstAnchor.GetAnchorId()) || 999 ( rDstAnchor.GetCntntAnchor() && 1000 rDstAnchor.GetCntntAnchor()->nNode.GetIndex() > nEndOfExtras )) 1001 bAllowed = sal_True; 1002 } 1003 else if( rSrcAnchor.GetCntntAnchor() && rDstAnchor.GetCntntAnchor() ) 1004 { 1005 const SwNodeIndex &rSrcIdx = rSrcAnchor.GetCntntAnchor()->nNode, 1006 &rDstIdx = rDstAnchor.GetCntntAnchor()->nNode; 1007 const SwStartNode* pSttNd = 0; 1008 if( rSrcIdx == rDstIdx || 1009 ( !pSttNd && 1010 0 != ( pSttNd = rSrcIdx.GetNode().FindFlyStartNode() ) && 1011 pSttNd == rDstIdx.GetNode().FindFlyStartNode() ) || 1012 ( !pSttNd && 1013 0 != ( pSttNd = rSrcIdx.GetNode().FindFooterStartNode() ) && 1014 pSttNd == rDstIdx.GetNode().FindFooterStartNode() ) || 1015 ( !pSttNd && 1016 0 != ( pSttNd = rSrcIdx.GetNode().FindHeaderStartNode() ) && 1017 pSttNd == rDstIdx.GetNode().FindHeaderStartNode() ) || 1018 ( !pSttNd && rDstIdx.GetIndex() > nEndOfExtras && 1019 rSrcIdx.GetIndex() > nEndOfExtras )) 1020 bAllowed = sal_True; 1021 } 1022 1023 return bAllowed ? SW_CHAIN_OK : SW_CHAIN_WRONG_AREA; 1024 } 1025 1026 int SwDoc::Chain( SwFrmFmt &rSource, const SwFrmFmt &rDest ) 1027 { 1028 int nErr = Chainable( rSource, rDest ); 1029 if ( !nErr ) 1030 { 1031 GetIDocumentUndoRedo().StartUndo( UNDO_CHAINE, NULL ); 1032 1033 SwFlyFrmFmt& rDestFmt = (SwFlyFrmFmt&)rDest; 1034 1035 //Follow an den Master haengen. 1036 SwFmtChain aChain = rDestFmt.GetChain(); 1037 aChain.SetPrev( &(SwFlyFrmFmt&)rSource ); 1038 SetAttr( aChain, rDestFmt ); 1039 1040 SfxItemSet aSet( GetAttrPool(), RES_FRM_SIZE, RES_FRM_SIZE, 1041 RES_CHAIN, RES_CHAIN, 0 ); 1042 1043 //Follow an den Master haengen. 1044 aChain.SetPrev( &(SwFlyFrmFmt&)rSource ); 1045 SetAttr( aChain, rDestFmt ); 1046 1047 //Master an den Follow haengen und dafuer sorgen, dass der Master 1048 //eine fixierte Hoehe hat. 1049 aChain = rSource.GetChain(); 1050 aChain.SetNext( &rDestFmt ); 1051 aSet.Put( aChain ); 1052 1053 SwFmtFrmSize aSize( rSource.GetFrmSize() ); 1054 if ( aSize.GetHeightSizeType() != ATT_FIX_SIZE ) 1055 { 1056 SwFlyFrm *pFly = SwIterator<SwFlyFrm,SwFmt>::FirstElement( rSource ); 1057 if ( pFly ) 1058 aSize.SetHeight( pFly->Frm().Height() ); 1059 aSize.SetHeightSizeType( ATT_FIX_SIZE ); 1060 aSet.Put( aSize ); 1061 } 1062 SetAttr( aSet, rSource ); 1063 1064 GetIDocumentUndoRedo().EndUndo( UNDO_CHAINE, NULL ); 1065 } 1066 return nErr; 1067 } 1068 1069 void SwDoc::Unchain( SwFrmFmt &rFmt ) 1070 { 1071 SwFmtChain aChain( rFmt.GetChain() ); 1072 if ( aChain.GetNext() ) 1073 { 1074 GetIDocumentUndoRedo().StartUndo( UNDO_UNCHAIN, NULL ); 1075 SwFrmFmt *pFollow = aChain.GetNext(); 1076 aChain.SetNext( 0 ); 1077 SetAttr( aChain, rFmt ); 1078 aChain = pFollow->GetChain(); 1079 aChain.SetPrev( 0 ); 1080 SetAttr( aChain, *pFollow ); 1081 GetIDocumentUndoRedo().EndUndo( UNDO_UNCHAIN, NULL ); 1082 } 1083 } 1084 1085 1086 1087