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 <vcl/svapp.hxx> 33 #include <vcl/outdev.hxx> 34 35 #include <osl/thread.hxx> 36 #include <salhelper/condition.hxx> 37 #include <comphelper/mediadescriptor.hxx> 38 #include <sfx2/docfile.hxx> 39 #include <sfx2/lnkbase.hxx> 40 #include <sfx2/linkmgr.hxx> 41 #include <sfx2/objsh.hxx> 42 #include <editeng/boxitem.hxx> 43 #ifndef _SVX_SVXIDS_HRC 44 #include <svx/svxids.hrc> // fuer die EventIds 45 #endif 46 #include <sfx2/linkmgr.hxx> 47 #include <svtools/soerr.hxx> 48 #include <fmtfsize.hxx> 49 #include <fmtanchr.hxx> 50 #include <frmatr.hxx> 51 #include <frmfmt.hxx> 52 #include <doc.hxx> 53 #include <pam.hxx> 54 #include <editsh.hxx> 55 #include <swtable.hxx> 56 #include <docary.hxx> 57 #include <swevent.hxx> 58 #include <swbaslnk.hxx> 59 #include <swserv.hxx> 60 #include <ndgrf.hxx> 61 #include <ndole.hxx> 62 #include <hints.hxx> 63 #include <tabfrm.hxx> 64 #include <cntfrm.hxx> 65 #include <htmltbl.hxx> 66 67 using namespace com::sun::star; 68 69 sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ); 70 71 TYPEINIT1( SwBaseLink, ::sfx2::SvBaseLink ); 72 73 SV_IMPL_REF( SwServerObject ) 74 75 void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem ) 76 { 77 //JP 4.7.2001: call fist all not SwNoTxtFrames, then the SwNoTxtFrames. 78 // The reason is, that in the SwNoTxtFrames the Graphic 79 // after a Paint will be swapped out! So all other "behind" 80 // them havent't a loaded Graphic. - #86501# 81 rGrfNd.LockModify(); 82 83 SwClientIter aIter( rGrfNd ); // TODO 84 for( int n = 0; n < 2; ++n ) 85 { 86 SwClient * pLast = aIter.GoStart(); 87 if( pLast ) // konnte zum Anfang gesprungen werden ?? 88 { 89 do { 90 if( (0 == n) ^ ( 0 != pLast->ISA( SwCntntFrm )) ) 91 pLast->ModifyNotification( &rItem, &rItem ); 92 } while( 0 != ( pLast = ++aIter )); 93 } 94 } 95 rGrfNd.UnlockModify(); 96 } 97 98 99 void SwBaseLink::DataChanged( const String& rMimeType, 100 const uno::Any & rValue ) 101 { 102 if( !pCntntNode ) 103 { 104 ASSERT(!this, "DataChanged ohne ContentNode" ); 105 return ; 106 } 107 108 SwDoc* pDoc = pCntntNode->GetDoc(); 109 if( pDoc->IsInDtor() || ChkNoDataFlag() || bIgnoreDataChanged ) 110 { 111 bIgnoreDataChanged = sal_False; 112 return ; 113 } 114 115 sal_uLong nFmt = SotExchange::GetFormatIdFromMimeType( rMimeType ); 116 117 if( pCntntNode->IsNoTxtNode() && 118 nFmt == sfx2::LinkManager::RegisterStatusInfoId() ) 119 { 120 // nur eine Statusaenderung - Events bedienen ? 121 ::rtl::OUString sState; 122 if( rValue.hasValue() && ( rValue >>= sState )) 123 { 124 sal_uInt16 nEvent = 0; 125 switch( sState.toInt32() ) 126 { 127 case sfx2::LinkManager::STATE_LOAD_OK: nEvent = SVX_EVENT_IMAGE_LOAD; break; 128 case sfx2::LinkManager::STATE_LOAD_ERROR: nEvent = SVX_EVENT_IMAGE_ERROR; break; 129 case sfx2::LinkManager::STATE_LOAD_ABORT: nEvent = SVX_EVENT_IMAGE_ABORT; break; 130 } 131 132 SwFrmFmt* pFmt; 133 if( nEvent && 0 != ( pFmt = pCntntNode->GetFlyFmt() )) 134 { 135 SwCallMouseEvent aCallEvent; 136 aCallEvent.Set( EVENT_OBJECT_IMAGE, pFmt ); 137 pDoc->CallEvent( nEvent, aCallEvent ); 138 } 139 } 140 return; // das wars! 141 } 142 143 sal_Bool bUpdate = sal_False; 144 sal_Bool bGraphicArrived = sal_False; 145 sal_Bool bGraphicPieceArrived = sal_False; 146 sal_Bool bDontNotify = sal_False; 147 Size aGrfSz, aFrmFmtSz; 148 149 if( pCntntNode->IsGrfNode() ) 150 { 151 GraphicObject& rGrfObj = ((SwGrfNode*)pCntntNode)->GetGrfObj(); 152 153 bDontNotify = ((SwGrfNode*)pCntntNode)->IsFrameInPaint(); 154 155 bGraphicArrived = GetObj()->IsDataComplete(); 156 bGraphicPieceArrived = GetObj()->IsPending(); 157 ((SwGrfNode*)pCntntNode)->SetGrafikArrived( bGraphicArrived ); 158 159 Graphic aGrf; 160 if( sfx2::LinkManager::GetGraphicFromAny( rMimeType, rValue, aGrf ) && 161 ( GRAPHIC_DEFAULT != aGrf.GetType() || 162 GRAPHIC_DEFAULT != rGrfObj.GetType() ) ) 163 { 164 aGrfSz = ::GetGraphicSizeTwip( aGrf, 0 ); 165 if( static_cast< const SwGrfNode * >( pCntntNode )->IsChgTwipSizeFromPixel() ) 166 { 167 const MapMode aMapTwip( MAP_TWIP ); 168 aFrmFmtSz = 169 Application::GetDefaultDevice()->PixelToLogic( 170 aGrf.GetSizePixel(), aMapTwip ); 171 172 } 173 else 174 { 175 aFrmFmtSz = aGrfSz; 176 } 177 Size aSz( ((SwGrfNode*)pCntntNode)->GetTwipSize() ); 178 179 if( bGraphicPieceArrived && GRAPHIC_DEFAULT != aGrf.GetType() && 180 ( !aSz.Width() || !aSz.Height() ) ) 181 { 182 // wenn nur ein Teil ankommt, aber die Groesse nicht 183 // gesetzt ist, dann muss "unten" der Teil von 184 // bGraphicArrived durchlaufen werden! 185 // (ansonten wird die Grafik in deft. Size gepaintet) 186 bGraphicArrived = sal_True; 187 bGraphicPieceArrived = sal_False; 188 } 189 190 rGrfObj.SetGraphic( aGrf, rGrfObj.GetLink() ); 191 bUpdate = sal_True; 192 193 // Bug 33999: damit der Node den Transparent-Status 194 // richtig gesetzt hat, ohne auf die Grafik 195 // zugreifen zu muessen (sonst erfolgt ein SwapIn!). 196 if( bGraphicArrived ) 197 { 198 // Bug #34735#: immer mit der korrekten Grafik-Size 199 // arbeiten 200 if( aGrfSz.Height() && aGrfSz.Width() && 201 aSz.Height() && aSz.Width() && 202 aGrfSz != aSz ) 203 ((SwGrfNode*)pCntntNode)->SetTwipSize( aGrfSz ); 204 } 205 } 206 if ( bUpdate && !bGraphicArrived && !bGraphicPieceArrived ) 207 ((SwGrfNode*)pCntntNode)->SetTwipSize( Size(0,0) ); 208 } 209 else if( pCntntNode->IsOLENode() ) 210 bUpdate = sal_True; 211 212 ViewShell *pSh = 0; 213 SwEditShell* pESh = pDoc->GetEditShell( &pSh ); 214 215 if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) ) 216 { 217 //Hint ohne Actions verschicken, loest direktes Paint aus. 218 if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) ) 219 { 220 SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED ); 221 pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint ); 222 bUpdate = sal_False; 223 } 224 } 225 226 static sal_Bool bInNotifyLinks = sal_False; 227 if( bUpdate && !bDontNotify && (!bSwapIn || bGraphicArrived) && 228 !bInNotifyLinks) 229 { 230 sal_Bool bLockView = sal_False; 231 if( pSh ) 232 { 233 bLockView = pSh->IsViewLocked(); 234 pSh->LockView( sal_True ); 235 } 236 237 if( pESh ) 238 pESh->StartAllAction(); 239 else if( pSh ) 240 pSh->StartAction(); 241 242 SwMsgPoolItem aMsgHint( static_cast<sal_uInt16>( 243 bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) ); 244 245 if ( bGraphicArrived ) 246 { 247 //Alle benachrichtigen, die am gleichen Link horchen. 248 bInNotifyLinks = sal_True; 249 250 const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks(); 251 for( sal_uInt16 n = rLnks.Count(); n; ) 252 { 253 ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]); 254 if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() && 255 pLnk->ISA( SwBaseLink ) && pLnk->GetObj() == GetObj() ) 256 { 257 SwBaseLink* pBLink = (SwBaseLink*)pLnk; 258 SwGrfNode* pGrfNd = (SwGrfNode*)pBLink->pCntntNode; 259 260 if( pBLink != this && 261 ( !bSwapIn || 262 GRAPHIC_DEFAULT == pGrfNd->GetGrfObj().GetType())) 263 { 264 pBLink->bIgnoreDataChanged = sal_False; 265 pBLink->DataChanged( rMimeType, rValue ); 266 pBLink->bIgnoreDataChanged = sal_True; 267 268 pGrfNd->SetGrafikArrived( ((SwGrfNode*)pCntntNode)-> 269 IsGrafikArrived() ); 270 271 // Fly der Grafik anpassen ! 272 if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) 273 ::lcl_CallModify( *pGrfNd, aMsgHint ); 274 } 275 else if( pBLink == this && 276 !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) 277 // Fly der Grafik anpassen ! 278 ::lcl_CallModify( *pGrfNd, aMsgHint ); 279 } 280 } 281 282 bInNotifyLinks = sal_False; 283 } 284 else 285 { 286 pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint ); 287 } 288 289 290 if( pESh ) 291 { 292 const sal_Bool bEndActionByVirDev = pESh->IsEndActionByVirDev(); 293 pESh->SetEndActionByVirDev( sal_True ); 294 pESh->EndAllAction(); 295 pESh->SetEndActionByVirDev( bEndActionByVirDev ); 296 } 297 else if( pSh ) 298 pSh->EndAction(); 299 300 if( pSh && !bLockView ) 301 pSh->LockView( sal_False ); 302 } 303 } 304 305 sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ) 306 { 307 sal_Bool bRet = sal_False; 308 ViewShell *pSh; 309 CurrShell *pCurr = 0; 310 if ( pGrfNd->GetDoc()->GetEditShell( &pSh ) ) 311 pCurr = new CurrShell( pSh ); 312 313 Size aSz = pGrfNd->GetTwipSize(); 314 if ( !(aSz.Width() && aSz.Height()) && 315 rGrfSz.Width() && rGrfSz.Height() ) 316 { 317 SwFrmFmt* pFmt; 318 if( pGrfNd->IsChgTwipSize() && 319 0 != (pFmt = pGrfNd->GetFlyFmt()) ) 320 { 321 Size aCalcSz( aSz ); 322 if ( !aSz.Height() && aSz.Width() ) 323 //passende Hoehe ausrechnen. 324 aCalcSz.Height() = rFrmSz.Height() * 325 aSz.Width() / rFrmSz.Width(); 326 else if ( !aSz.Width() && aSz.Height() ) 327 //passende Breite ausrechnen 328 aCalcSz.Width() = rFrmSz.Width() * 329 aSz.Height() / rFrmSz.Height(); 330 else 331 //Hoehe und Breite uebernehmen 332 aCalcSz = rFrmSz; 333 334 const SvxBoxItem &rBox = pFmt->GetBox(); 335 aCalcSz.Width() += rBox.CalcLineSpace(BOX_LINE_LEFT) + 336 rBox.CalcLineSpace(BOX_LINE_RIGHT); 337 aCalcSz.Height()+= rBox.CalcLineSpace(BOX_LINE_TOP) + 338 rBox.CalcLineSpace(BOX_LINE_BOTTOM); 339 const SwFmtFrmSize& rOldAttr = pFmt->GetFrmSize(); 340 if( rOldAttr.GetSize() != aCalcSz ) 341 { 342 SwFmtFrmSize aAttr( rOldAttr ); 343 aAttr.SetSize( aCalcSz ); 344 pFmt->SetFmtAttr( aAttr ); 345 bRet = sal_True; 346 } 347 348 if( !aSz.Width() ) 349 { 350 // Wenn die Grafik in einer Tabelle verankert ist, muess 351 // die Tabellen-Spalten neu berechnet werden 352 const SwDoc *pDoc = pGrfNd->GetDoc(); 353 const SwPosition* pAPos = pFmt->GetAnchor().GetCntntAnchor(); 354 SwNode *pANd; 355 SwTableNode *pTblNd; 356 if( pAPos && 357 0 != (pANd = & pAPos->nNode.GetNode()) && 358 0 != (pTblNd = pANd->FindTableNode()) ) 359 { 360 const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize(); 361 SwHTMLTableLayout *pLayout = 362 pTblNd->GetTable().GetHTMLTableLayout(); 363 if( pLayout ) 364 { 365 const sal_uInt16 nBrowseWidth = 366 pLayout->GetBrowseWidthByTable( *pDoc ); 367 if ( nBrowseWidth ) 368 { 369 pLayout->Resize( nBrowseWidth, sal_True, sal_True, 370 bLastGrf ? HTMLTABLE_RESIZE_NOW 371 : 500 ); 372 } 373 } 374 } 375 } 376 } 377 378 // SetTwipSize skaliert ggf. eine ImageMap neu und 379 // braucht dazu das Frame-Format 380 pGrfNd->SetTwipSize( rGrfSz ); 381 } 382 383 delete pCurr; 384 385 return bRet; 386 } 387 388 389 sal_Bool SwBaseLink::SwapIn( sal_Bool bWaitForData, sal_Bool bNativFormat ) 390 { 391 bSwapIn = sal_True; 392 393 sal_Bool bRes; 394 395 if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) )) 396 { 397 AddNextRef(); 398 _GetRealObject(); 399 ReleaseRef(); 400 } 401 402 #if OSL_DEBUG_LEVEL > 1 403 { 404 String sGrfNm; 405 if(GetLinkManager()) 406 GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 ); 407 int x = 0; 408 ++x; 409 } 410 #endif 411 412 if( GetObj() ) 413 { 414 String aMimeType( SotExchange::GetFormatMimeType( GetContentType() )); 415 uno::Any aValue; 416 GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData ); 417 418 if( bWaitForData && !GetObj() ) 419 { 420 ASSERT( !this, "das SvxFileObject wurde in einem GetData geloescht!" ); 421 bRes = sal_False; 422 } 423 else if( 0 != ( bRes = aValue.hasValue() ) ) 424 { 425 //JP 14.04.99: Bug 64820 - das Flag muss beim SwapIn natuerlich 426 // zurueckgesetzt werden. Die Daten sollen ja neu 427 // uebernommen werden 428 bIgnoreDataChanged = sal_False; 429 DataChanged( aMimeType, aValue ); 430 } 431 } 432 else if( !IsSynchron() && bWaitForData ) 433 { 434 SetSynchron( sal_True ); 435 bRes = Update(); 436 SetSynchron( sal_False ); 437 } 438 else 439 bRes = Update(); 440 441 bSwapIn = sal_False; 442 return bRes; 443 } 444 445 void SwBaseLink::Closed() 446 { 447 if( pCntntNode && !pCntntNode->GetDoc()->IsInDtor() ) 448 { 449 // wir heben die Verbindung auf 450 if( pCntntNode->IsGrfNode() ) 451 ((SwGrfNode*)pCntntNode)->ReleaseLink(); 452 } 453 SvBaseLink::Closed(); 454 } 455 456 const SwNode* SwBaseLink::GetAnchor() const 457 { 458 if (pCntntNode) 459 { 460 SwFrmFmt *const pFmt = pCntntNode->GetFlyFmt(); 461 if (pFmt) 462 { 463 const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); 464 SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); 465 if (pAPos && 466 ((FLY_AS_CHAR == rAnchor.GetAnchorId()) || 467 (FLY_AT_CHAR == rAnchor.GetAnchorId()) || 468 (FLY_AT_FLY == rAnchor.GetAnchorId()) || 469 (FLY_AT_PARA == rAnchor.GetAnchorId()))) 470 { 471 return &pAPos->nNode.GetNode(); 472 } 473 return 0; 474 } 475 } 476 477 ASSERT( !this, "GetAnchor nicht ueberlagert" ); 478 return 0; 479 } 480 481 sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const 482 { 483 SwServerObjectRef aRef( (SwServerObject*)GetObj() ); 484 if( aRef.Is() ) 485 { 486 // es ist ein ServerObject, also frage nach allen darin 487 // befindlichen Links, ob wir darin enthalten sind. Ansonsten 488 // handelt es sich um eine Rekursion. 489 return aRef->IsLinkInServer( pChkLnk ); 490 } 491 return sal_False; 492 } 493 494 sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, xub_StrLen, xub_StrLen ) const 495 { 496 // Grafik oder OLE-Links nicht, 497 // Felder oder Sections haben eigene Ableitung! 498 return sal_False; 499 } 500 501 SwBaseLink::~SwBaseLink() 502 { 503 } 504