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