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