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