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 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp> 31 #include <com/sun/star/container/XChild.hpp> 32 #include <com/sun/star/embed/XEmbedPersist.hpp> 33 #include <com/sun/star/embed/XLinkageSupport.hpp> 34 #include <com/sun/star/embed/Aspects.hpp> 35 #include <com/sun/star/embed/EmbedMisc.hpp> 36 #include <com/sun/star/embed/EmbedStates.hpp> 37 #include <com/sun/star/util/XCloseable.hpp> 38 #include <com/sun/star/util/XModifiable.hpp> 39 #include <com/sun/star/document/XEventBroadcaster.hpp> 40 #include <cppuhelper/implbase1.hxx> 41 42 #include <cppuhelper/implbase2.hxx> 43 #include <toolkit/helper/vclunohelper.hxx> 44 #include <hintids.hxx> 45 #include <tools/urlobj.hxx> 46 #include <sfx2/docfile.hxx> 47 #include <sfx2/app.hxx> 48 #include <sfx2/linkmgr.hxx> 49 #include <unotools/configitem.hxx> 50 #ifndef _OUTDEV_HXX //autogen 51 #include <vcl/outdev.hxx> 52 #endif 53 #include <fmtanchr.hxx> 54 #include <frmfmt.hxx> 55 #include <doc.hxx> 56 #include <docsh.hxx> 57 #include <pam.hxx> 58 #include <section.hxx> 59 #include <cntfrm.hxx> 60 #include <frmatr.hxx> 61 #ifndef _DOCSH_HXX 62 #include <docsh.hxx> 63 #endif 64 #include <ndole.hxx> 65 66 #include <comphelper/classids.hxx> 67 #include <vcl/graph.hxx> 68 #include <sot/formats.hxx> 69 #include <unotools/ucbstreamhelper.hxx> 70 #include <svtools/filter.hxx> 71 #ifndef _COMCORE_HRC 72 #include <comcore.hrc> 73 #endif 74 75 using rtl::OUString; 76 using namespace utl; 77 using namespace com::sun::star::uno; 78 using namespace com::sun::star; 79 80 class SwOLELRUCache : private SvPtrarr, private utl::ConfigItem 81 { 82 sal_uInt16 nLRU_InitSize; 83 sal_Bool bInUnload; 84 uno::Sequence< rtl::OUString > GetPropertyNames(); 85 86 public: 87 SwOLELRUCache(); 88 89 virtual void Notify( const uno::Sequence< 90 rtl::OUString>& aPropertyNames ); 91 virtual void Commit(); 92 void Load(); 93 94 void SetInUnload( sal_Bool bFlag ) { bInUnload = bFlag; } 95 using SvPtrarr::Count; 96 97 void InsertObj( SwOLEObj& rObj ); 98 void RemoveObj( SwOLEObj& rObj ); 99 100 void RemovePtr( SwOLEObj* pObj ) 101 { 102 sal_uInt16 nPos = SvPtrarr::GetPos( pObj ); 103 if( USHRT_MAX != nPos ) 104 SvPtrarr::Remove( nPos ); 105 } 106 }; 107 108 SwOLELRUCache* pOLELRU_Cache = 0; 109 110 class SwOLEListener_Impl : public ::cppu::WeakImplHelper1< embed::XStateChangeListener > 111 { 112 SwOLEObj* mpObj; 113 public: 114 SwOLEListener_Impl( SwOLEObj* pObj ); 115 void Release(); 116 virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (embed::WrongStateException, uno::RuntimeException); 117 virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (uno::RuntimeException); 118 virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw (uno::RuntimeException); 119 }; 120 121 SwOLEListener_Impl::SwOLEListener_Impl( SwOLEObj* pObj ) 122 : mpObj( pObj ) 123 { 124 if ( mpObj->IsOleRef() && mpObj->GetOleRef()->getCurrentState() == embed::EmbedStates::RUNNING ) 125 { 126 pOLELRU_Cache->InsertObj( *mpObj ); 127 } 128 } 129 130 void SAL_CALL SwOLEListener_Impl::changingState( const lang::EventObject&, ::sal_Int32 , ::sal_Int32 ) throw (embed::WrongStateException, uno::RuntimeException) 131 { 132 } 133 134 void SAL_CALL SwOLEListener_Impl::stateChanged( const lang::EventObject&, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (uno::RuntimeException) 135 { 136 if ( mpObj && nOldState == embed::EmbedStates::LOADED && nNewState == embed::EmbedStates::RUNNING ) 137 { 138 if( !pOLELRU_Cache ) 139 pOLELRU_Cache = new SwOLELRUCache; 140 pOLELRU_Cache->InsertObj( *mpObj ); 141 } 142 else if ( mpObj && nNewState == embed::EmbedStates::LOADED && nOldState == embed::EmbedStates::RUNNING ) 143 { 144 if ( pOLELRU_Cache ) 145 pOLELRU_Cache->RemoveObj( *mpObj ); 146 } 147 } 148 149 void SwOLEListener_Impl::Release() 150 { 151 if ( mpObj && pOLELRU_Cache ) 152 pOLELRU_Cache->RemoveObj( *mpObj ); 153 mpObj=0; 154 release(); 155 } 156 157 void SAL_CALL SwOLEListener_Impl::disposing( const lang::EventObject& ) throw (uno::RuntimeException) 158 { 159 if ( mpObj && pOLELRU_Cache ) 160 pOLELRU_Cache->RemoveObj( *mpObj ); 161 } 162 163 // -------------------- 164 // SwEmbedObjectLink 165 // -------------------- 166 // TODO/LATER: actually SwEmbedObjectLink should be used here, but because different objects are used to control 167 // embedded object different link objects with the same functionality had to be implemented 168 169 class SwEmbedObjectLink : public sfx2::SvBaseLink 170 { 171 SwOLENode* pOleNode; 172 173 public: 174 SwEmbedObjectLink(SwOLENode* pNode); 175 virtual ~SwEmbedObjectLink(); 176 177 virtual void Closed(); 178 virtual void DataChanged( const String& rMimeType, 179 const uno::Any & rValue ); 180 181 sal_Bool Connect() { return GetRealObject() != NULL; } 182 }; 183 184 // ----------------------------------------------------------------------------- 185 186 SwEmbedObjectLink::SwEmbedObjectLink(SwOLENode* pNode): 187 ::sfx2::SvBaseLink( ::sfx2::LINKUPDATE_ONCALL, SOT_FORMATSTR_ID_SVXB ), 188 pOleNode(pNode) 189 { 190 SetSynchron( sal_False ); 191 } 192 193 // ----------------------------------------------------------------------------- 194 195 SwEmbedObjectLink::~SwEmbedObjectLink() 196 { 197 } 198 199 // ----------------------------------------------------------------------------- 200 201 void SwEmbedObjectLink::DataChanged( const String& , 202 const uno::Any & ) 203 { 204 if ( !pOleNode->UpdateLinkURL_Impl() ) 205 { 206 // the link URL was not changed 207 uno::Reference< embed::XEmbeddedObject > xObject = pOleNode->GetOLEObj().GetOleRef(); 208 OSL_ENSURE( xObject.is(), "The object must exist always!\n" ); 209 if ( xObject.is() ) 210 { 211 // let the object reload the link 212 // TODO/LATER: reload call could be used for this case 213 214 try 215 { 216 sal_Int32 nState = xObject->getCurrentState(); 217 if ( nState != embed::EmbedStates::LOADED ) 218 { 219 // in some cases the linked file probably is not locked so it could be changed 220 xObject->changeState( embed::EmbedStates::LOADED ); 221 xObject->changeState( nState ); 222 } 223 } 224 catch ( uno::Exception& ) 225 { 226 } 227 } 228 } 229 230 pOleNode->GetNewReplacement(); 231 // Initiate repainting 232 // pObj->SetChanged(); 233 } 234 235 // ----------------------------------------------------------------------------- 236 237 void SwEmbedObjectLink::Closed() 238 { 239 pOleNode->BreakFileLink_Impl(); 240 SvBaseLink::Closed(); 241 } 242 243 244 // -------------------- 245 // SwOLENode 246 // -------------------- 247 248 SwOLENode::SwOLENode( const SwNodeIndex &rWhere, 249 const svt::EmbeddedObjectRef& xObj, 250 SwGrfFmtColl *pGrfColl, 251 SwAttrSet* pAutoAttr ) : 252 SwNoTxtNode( rWhere, ND_OLENODE, pGrfColl, pAutoAttr ), 253 aOLEObj( xObj ), 254 pGraphic(0), 255 bOLESizeInvalid( sal_False ), 256 mpObjectLink( NULL ) 257 { 258 aOLEObj.SetNode( this ); 259 } 260 261 SwOLENode::SwOLENode( const SwNodeIndex &rWhere, 262 const String &rString, 263 sal_Int64 nAspect, 264 SwGrfFmtColl *pGrfColl, 265 SwAttrSet* pAutoAttr ) : 266 SwNoTxtNode( rWhere, ND_OLENODE, pGrfColl, pAutoAttr ), 267 aOLEObj( rString, nAspect ), 268 pGraphic(0), 269 bOLESizeInvalid( sal_False ), 270 mpObjectLink( NULL ) 271 { 272 aOLEObj.SetNode( this ); 273 } 274 275 SwOLENode::~SwOLENode() 276 { 277 DisconnectFileLink_Impl(); 278 delete pGraphic; 279 } 280 281 Graphic* SwOLENode::GetGraphic() 282 { 283 if ( aOLEObj.GetOleRef().is() ) 284 return aOLEObj.xOLERef.GetGraphic(); 285 return pGraphic; 286 } 287 288 Graphic* SwOLENode::GetHCGraphic() 289 { 290 return aOLEObj.xOLERef.GetHCGraphic(); 291 } 292 293 SwCntntNode *SwOLENode::SplitCntntNode( const SwPosition & ) 294 { 295 // OLE-Objecte vervielfaeltigen ?? 296 ASSERT( sal_False, "OleNode: can't split." ); 297 return this; 298 } 299 300 // Laden eines in den Undo-Bereich verschobenen OLE-Objekts 301 302 sal_Bool SwOLENode::RestorePersistentData() 303 { 304 DBG_ASSERT( aOLEObj.GetOleRef().is(), "No object to restore!" ); 305 if ( aOLEObj.xOLERef.is() ) 306 { 307 // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese 308 SfxObjectShell* p = GetDoc()->GetPersist(); 309 if( !p ) 310 { 311 // TODO/LATER: reicht hier nicht ein EmbeddedObjectContainer? Was passiert mit 312 // diesem Dokument? 313 ASSERT( !this, "warum wird hier eine DocShell angelegt?" ); 314 p = new SwDocShell( GetDoc(), SFX_CREATE_MODE_INTERNAL ); 315 p->DoInitNew( NULL ); 316 } 317 318 uno::Reference < container::XChild > xChild( aOLEObj.xOLERef.GetObject(), uno::UNO_QUERY ); 319 if ( xChild.is() ) 320 xChild->setParent( p->GetModel() ); 321 322 DBG_ASSERT( aOLEObj.aName.Len(), "No object name!" ); 323 ::rtl::OUString aObjName; 324 if ( !p->GetEmbeddedObjectContainer().InsertEmbeddedObject( aOLEObj.xOLERef.GetObject(), aObjName ) ) 325 { 326 if ( xChild.is() ) 327 xChild->setParent( 0 ); 328 DBG_ERROR( "InsertObject failed" ); 329 } 330 else 331 { 332 aOLEObj.aName = aObjName; 333 aOLEObj.xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aObjName ); 334 CheckFileLink_Impl(); 335 } 336 } 337 338 return sal_True; 339 } 340 341 // OLE object is transported into UNDO area 342 sal_Bool SwOLENode::SavePersistentData() 343 { 344 if( aOLEObj.xOLERef.is() ) 345 { 346 comphelper::EmbeddedObjectContainer* pCnt = aOLEObj.xOLERef.GetContainer(); 347 348 #if OSL_DEBUG_LEVEL > 0 349 SfxObjectShell* p = GetDoc()->GetPersist(); 350 DBG_ASSERT( p, "No document!" ); 351 if( p ) 352 { 353 comphelper::EmbeddedObjectContainer& rCnt = p->GetEmbeddedObjectContainer(); 354 OSL_ENSURE( !pCnt || &rCnt == pCnt, "The helper is assigned to unexpected container!\n" ); 355 } 356 #endif 357 358 if ( pCnt && pCnt->HasEmbeddedObject( aOLEObj.aName ) ) 359 { 360 uno::Reference < container::XChild > xChild( aOLEObj.xOLERef.GetObject(), uno::UNO_QUERY ); 361 if ( xChild.is() ) 362 xChild->setParent( 0 ); 363 364 pCnt->RemoveEmbeddedObject( aOLEObj.aName, sal_False ); 365 366 // TODO/LATER: aOLEObj.aName has no meaning here, since the undo container contains the object 367 // by different name, in future it might makes sence that the name is transported here. 368 aOLEObj.xOLERef.AssignToContainer( 0, aOLEObj.aName ); 369 try 370 { 371 // "unload" object 372 aOLEObj.xOLERef->changeState( embed::EmbedStates::LOADED ); 373 } 374 catch ( uno::Exception& ) 375 { 376 } 377 } 378 } 379 380 DisconnectFileLink_Impl(); 381 382 return sal_True; 383 } 384 385 386 SwOLENode * SwNodes::MakeOLENode( const SwNodeIndex & rWhere, 387 const svt::EmbeddedObjectRef& xObj, 388 SwGrfFmtColl* pGrfColl, 389 SwAttrSet* pAutoAttr ) 390 { 391 ASSERT( pGrfColl,"SwNodes::MakeOLENode: Formatpointer ist 0." ); 392 393 SwOLENode *pNode = 394 new SwOLENode( rWhere, xObj, pGrfColl, pAutoAttr ); 395 396 // set parent if XChild is supported 397 //!! needed to supply Math objects with a valid reference device 398 uno::Reference< container::XChild > xChild( pNode->GetOLEObj().GetObject().GetObject(), UNO_QUERY ); 399 if (xChild.is()) 400 { 401 SwDocShell *pDocSh = GetDoc()->GetDocShell(); 402 if (pDocSh) 403 xChild->setParent( pDocSh->GetModel() ); 404 } 405 406 return pNode; 407 } 408 409 410 SwOLENode * SwNodes::MakeOLENode( const SwNodeIndex & rWhere, 411 const String &rName, sal_Int64 nAspect, SwGrfFmtColl* pGrfColl, SwAttrSet* pAutoAttr ) 412 { 413 ASSERT( pGrfColl,"SwNodes::MakeOLENode: Formatpointer ist 0." ); 414 415 SwOLENode *pNode = 416 new SwOLENode( rWhere, rName, nAspect, pGrfColl, pAutoAttr ); 417 418 // set parent if XChild is supported 419 //!! needed to supply Math objects with a valid reference device 420 uno::Reference< container::XChild > xChild( pNode->GetOLEObj().GetObject().GetObject(), UNO_QUERY ); 421 if (xChild.is()) 422 { 423 SwDocShell *pDocSh= GetDoc()->GetDocShell(); 424 if (pDocSh) 425 xChild->setParent( pDocSh->GetModel() ); 426 } 427 428 return pNode; 429 } 430 431 Size SwOLENode::GetTwipSize() const 432 { 433 MapMode aMapMode( MAP_TWIP ); 434 return ((SwOLENode*)this)->aOLEObj.GetObject().GetSize( &aMapMode ); 435 } 436 437 SwCntntNode* SwOLENode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const 438 { 439 // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese 440 SfxObjectShell* pPersistShell = pDoc->GetPersist(); 441 if( !pPersistShell ) 442 { 443 // TODO/LATER: is EmbeddedObjectContainer not enough? 444 // the created document will be closed by pDoc ( should use SfxObjectShellLock ) 445 pPersistShell = new SwDocShell( pDoc, SFX_CREATE_MODE_INTERNAL ); 446 pDoc->SetTmpDocShell( pPersistShell ); 447 pPersistShell->DoInitNew( NULL ); 448 } 449 450 // Wir hauen das Ding auf SvPersist-Ebene rein 451 // TODO/LATER: check if using the same naming scheme for all apps works here 452 ::rtl::OUString aNewName/*( Sw3Io::UniqueName( p->GetStorage(), "Obj" ) )*/; 453 SfxObjectShell* pSrc = GetDoc()->GetPersist(); 454 455 pPersistShell->GetEmbeddedObjectContainer().CopyAndGetEmbeddedObject( 456 pSrc->GetEmbeddedObjectContainer(), 457 pSrc->GetEmbeddedObjectContainer().GetEmbeddedObject( aOLEObj.aName ), 458 aNewName ); 459 460 SwOLENode* pOLENd = pDoc->GetNodes().MakeOLENode( rIdx, aNewName, GetAspect(), 461 (SwGrfFmtColl*)pDoc->GetDfltGrfFmtColl(), 462 (SwAttrSet*)GetpSwAttrSet() ); 463 464 pOLENd->SetChartTblName( GetChartTblName() ); 465 pOLENd->SetTitle( GetTitle() ); 466 pOLENd->SetDescription( GetDescription() ); 467 pOLENd->SetContour( HasContour(), HasAutomaticContour() ); 468 pOLENd->SetAspect( GetAspect() ); // the replacement image must be already copied 469 470 pOLENd->SetOLESizeInvalid( sal_True ); 471 pDoc->SetOLEPrtNotifyPending(); 472 473 return pOLENd; 474 } 475 476 sal_Bool SwOLENode::IsInGlobalDocSection() const 477 { 478 // suche den "Body Anchor" 479 sal_uLong nEndExtraIdx = GetNodes().GetEndOfExtras().GetIndex(); 480 const SwNode* pAnchorNd = this; 481 do { 482 SwFrmFmt* pFlyFmt = pAnchorNd->GetFlyFmt(); 483 if( !pFlyFmt ) 484 return sal_False; 485 486 const SwFmtAnchor& rAnchor = pFlyFmt->GetAnchor(); 487 if( !rAnchor.GetCntntAnchor() ) 488 return sal_False; 489 490 pAnchorNd = &rAnchor.GetCntntAnchor()->nNode.GetNode(); 491 } while( pAnchorNd->GetIndex() < nEndExtraIdx ); 492 493 const SwSectionNode* pSectNd = pAnchorNd->FindSectionNode(); 494 if( !pSectNd ) 495 return sal_False; 496 497 while( pSectNd ) 498 { 499 pAnchorNd = pSectNd; 500 pSectNd = pAnchorNd->StartOfSectionNode()->FindSectionNode(); 501 } 502 503 // in pAnchorNd steht der zuletzt gefundene Section Node. Der muss 504 // jetzt die Bedingung fuers GlobalDoc erfuellen. 505 pSectNd = (SwSectionNode*)pAnchorNd; 506 return FILE_LINK_SECTION == pSectNd->GetSection().GetType() && 507 pSectNd->GetIndex() > nEndExtraIdx; 508 } 509 510 sal_Bool SwOLENode::IsOLEObjectDeleted() const 511 { 512 sal_Bool bRet = sal_False; 513 if( aOLEObj.xOLERef.is() ) 514 { 515 SfxObjectShell* p = GetDoc()->GetPersist(); 516 if( p ) // muss da sein 517 { 518 return !p->GetEmbeddedObjectContainer().HasEmbeddedObject( aOLEObj.aName ); 519 //SvInfoObjectRef aRef( p->Find( aOLEObj.aName ) ); 520 //if( aRef.Is() ) 521 // bRet = aRef->IsDeleted(); 522 } 523 } 524 return bRet; 525 } 526 527 void SwOLENode::GetNewReplacement() 528 { 529 if ( aOLEObj.xOLERef.is() ) 530 aOLEObj.xOLERef.UpdateReplacement(); 531 } 532 533 sal_Bool SwOLENode::UpdateLinkURL_Impl() 534 { 535 sal_Bool bResult = sal_False; 536 537 if ( mpObjectLink ) 538 { 539 String aNewLinkURL; 540 GetDoc()->GetLinkManager().GetDisplayNames( mpObjectLink, 0, &aNewLinkURL, 0, 0 ); 541 if ( !aNewLinkURL.EqualsIgnoreCaseAscii( maLinkURL ) ) 542 { 543 if ( !aOLEObj.xOLERef.is() ) 544 aOLEObj.GetOleRef(); 545 546 uno::Reference< embed::XEmbeddedObject > xObj = aOLEObj.xOLERef.GetObject(); 547 uno::Reference< embed::XCommonEmbedPersist > xPersObj( xObj, uno::UNO_QUERY ); 548 OSL_ENSURE( xPersObj.is(), "The object must exist!\n" ); 549 if ( xPersObj.is() ) 550 { 551 try 552 { 553 sal_Int32 nCurState = xObj->getCurrentState(); 554 if ( nCurState != embed::EmbedStates::LOADED ) 555 xObj->changeState( embed::EmbedStates::LOADED ); 556 557 // TODO/LATER: there should be possible to get current mediadescriptor settings from the object 558 uno::Sequence< beans::PropertyValue > aArgs( 1 ); 559 aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ); 560 aArgs[0].Value <<= ::rtl::OUString( aNewLinkURL ); 561 xPersObj->reload( aArgs, uno::Sequence< beans::PropertyValue >() ); 562 563 maLinkURL = aNewLinkURL; 564 bResult = sal_True; 565 566 if ( nCurState != embed::EmbedStates::LOADED ) 567 xObj->changeState( nCurState ); 568 } 569 catch( uno::Exception& ) 570 {} 571 } 572 573 if ( !bResult ) 574 { 575 // TODO/LATER: return the old name to the link manager, is it possible? 576 } 577 } 578 } 579 580 return bResult; 581 } 582 583 void SwOLENode::BreakFileLink_Impl() 584 { 585 SfxObjectShell* pPers = GetDoc()->GetPersist(); 586 587 if ( pPers ) 588 { 589 uno::Reference< embed::XStorage > xStorage = pPers->GetStorage(); 590 if ( xStorage.is() ) 591 { 592 try 593 { 594 uno::Reference< embed::XLinkageSupport > xLinkSupport( aOLEObj.GetOleRef(), uno::UNO_QUERY_THROW ); 595 xLinkSupport->breakLink( xStorage, aOLEObj.GetCurrentPersistName() ); 596 DisconnectFileLink_Impl(); 597 maLinkURL = String(); 598 } 599 catch( uno::Exception& ) 600 { 601 } 602 } 603 } 604 } 605 606 void SwOLENode::DisconnectFileLink_Impl() 607 { 608 if ( mpObjectLink ) 609 { 610 GetDoc()->GetLinkManager().Remove( mpObjectLink ); 611 mpObjectLink = NULL; 612 } 613 } 614 615 void SwOLENode::CheckFileLink_Impl() 616 { 617 if ( aOLEObj.xOLERef.GetObject().is() && !mpObjectLink ) 618 { 619 try 620 { 621 uno::Reference< embed::XLinkageSupport > xLinkSupport( aOLEObj.xOLERef.GetObject(), uno::UNO_QUERY_THROW ); 622 if ( xLinkSupport->isLink() ) 623 { 624 String aLinkURL = xLinkSupport->getLinkURL(); 625 if ( aLinkURL.Len() ) 626 { 627 // this is a file link so the model link manager should handle it 628 mpObjectLink = new SwEmbedObjectLink( this ); 629 maLinkURL = aLinkURL; 630 GetDoc()->GetLinkManager().InsertFileLink( *mpObjectLink, OBJECT_CLIENT_OLE, aLinkURL, NULL, NULL ); 631 mpObjectLink->Connect(); 632 } 633 } 634 } 635 catch( uno::Exception& ) 636 { 637 } 638 } 639 } 640 641 // --> OD 2009-03-05 #i99665# 642 bool SwOLENode::IsChart() const 643 { 644 bool bIsChart( false ); 645 646 const uno::Reference< embed::XEmbeddedObject > xEmbObj = 647 const_cast<SwOLEObj&>(GetOLEObj()).GetOleRef(); 648 if ( xEmbObj.is() ) 649 { 650 SvGlobalName aClassID( xEmbObj->getClassID() ); 651 bIsChart = SotExchange::IsChart( aClassID ); 652 } 653 654 return bIsChart; 655 } 656 // <-- 657 658 SwOLEObj::SwOLEObj( const svt::EmbeddedObjectRef& xObj ) : 659 pOLENd( 0 ), 660 pListener( 0 ), 661 xOLERef( xObj ) 662 { 663 xOLERef.Lock( sal_True ); 664 if ( xObj.is() ) 665 { 666 pListener = new SwOLEListener_Impl( this ); 667 pListener->acquire(); 668 xObj->addStateChangeListener( pListener ); 669 } 670 } 671 672 673 SwOLEObj::SwOLEObj( const String &rString, sal_Int64 nAspect ) : 674 pOLENd( 0 ), 675 pListener( 0 ), 676 aName( rString ) 677 { 678 xOLERef.Lock( sal_True ); 679 xOLERef.SetViewAspect( nAspect ); 680 } 681 682 683 SwOLEObj::~SwOLEObj() 684 { 685 if( pListener ) 686 { 687 if ( xOLERef.is() ) 688 xOLERef->removeStateChangeListener( pListener ); 689 pListener->Release(); 690 } 691 692 if( pOLENd && !pOLENd->GetDoc()->IsInDtor() ) 693 { 694 // if the model is not currently in destruction it means that this object should be removed from the model 695 comphelper::EmbeddedObjectContainer* pCnt = xOLERef.GetContainer(); 696 697 #if OSL_DEBUG_LEVEL > 0 698 SfxObjectShell* p = pOLENd->GetDoc()->GetPersist(); 699 DBG_ASSERT( p, "No document!" ); 700 if( p ) 701 { 702 comphelper::EmbeddedObjectContainer& rCnt = p->GetEmbeddedObjectContainer(); 703 OSL_ENSURE( !pCnt || &rCnt == pCnt, "The helper is assigned to unexpected container!\n" ); 704 } 705 #endif 706 707 if ( pCnt && pCnt->HasEmbeddedObject( aName ) ) 708 { 709 uno::Reference < container::XChild > xChild( xOLERef.GetObject(), uno::UNO_QUERY ); 710 if ( xChild.is() ) 711 xChild->setParent( 0 ); 712 713 // not already removed by deleting the object 714 xOLERef.AssignToContainer( 0, aName ); 715 716 // unlock object so that object can be closed in RemoveEmbeddedObject 717 // successful closing of the object will automatically clear the reference then 718 xOLERef.Lock(sal_False); 719 720 // Always remove object from conteiner it is connected to 721 try 722 { 723 pCnt->RemoveEmbeddedObject( aName ); 724 } 725 catch ( uno::Exception& ) 726 { 727 } 728 } 729 730 } 731 732 if ( xOLERef.is() ) 733 // in case the object wasn't closed: release it 734 // in case the object was not in the container: it's still locked, try to close 735 xOLERef.Clear(); 736 } 737 738 739 void SwOLEObj::SetNode( SwOLENode* pNode ) 740 { 741 pOLENd = pNode; 742 if ( !aName.Len() ) 743 { 744 SwDoc* pDoc = pNode->GetDoc(); 745 746 // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese 747 SfxObjectShell* p = pDoc->GetPersist(); 748 if( !p ) 749 { 750 // TODO/LATER: reicht hier nicht ein EmbeddedObjectContainer? Was passiert mit 751 // diesem Dokument? 752 ASSERT( !this, "warum wird hier eine DocShell angelegt?" ); 753 p = new SwDocShell( pDoc, SFX_CREATE_MODE_INTERNAL ); 754 p->DoInitNew( NULL ); 755 } 756 757 ::rtl::OUString aObjName; 758 uno::Reference < container::XChild > xChild( xOLERef.GetObject(), uno::UNO_QUERY ); 759 if ( xChild.is() && xChild->getParent() != p->GetModel() ) 760 // it is possible that the parent was set already 761 xChild->setParent( p->GetModel() ); 762 if (!p->GetEmbeddedObjectContainer().InsertEmbeddedObject( xOLERef.GetObject(), aObjName ) ) 763 { 764 DBG_ERROR( "InsertObject failed" ); 765 if ( xChild.is() ) 766 xChild->setParent( 0 ); 767 } 768 else 769 xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aObjName ); 770 771 ( (SwOLENode*)pOLENd )->CheckFileLink_Impl(); // for this notification nonconst access is required 772 773 aName = aObjName; 774 } 775 } 776 777 sal_Bool SwOLEObj::IsOleRef() const 778 { 779 return xOLERef.is(); 780 } 781 782 const uno::Reference < embed::XEmbeddedObject > SwOLEObj::GetOleRef() 783 { 784 if( !xOLERef.is() ) 785 { 786 SfxObjectShell* p = pOLENd->GetDoc()->GetPersist(); 787 ASSERT( p, "kein SvPersist vorhanden" ); 788 789 uno::Reference < embed::XEmbeddedObject > xObj = p->GetEmbeddedObjectContainer().GetEmbeddedObject( aName ); 790 ASSERT( !xOLERef.is(), "rekursiver Aufruf von GetOleRef() ist nicht erlaubt" ) 791 792 if ( !xObj.is() ) 793 { 794 //Das Teil konnte nicht geladen werden (wahrsch. Kaputt). 795 Rectangle aArea; 796 SwFrm *pFrm = pOLENd->getLayoutFrm(0); 797 if ( pFrm ) 798 { 799 Size aSz( pFrm->Frm().SSize() ); 800 const MapMode aSrc ( MAP_TWIP ); 801 const MapMode aDest( MAP_100TH_MM ); 802 aSz = OutputDevice::LogicToLogic( aSz, aSrc, aDest ); 803 aArea.SetSize( aSz ); 804 } 805 else 806 aArea.SetSize( Size( 5000, 5000 ) ); 807 // TODO/LATER: set replacement graphic for dead object 808 // It looks as if it should work even without the object, because the replace will be generated automatically 809 ::rtl::OUString aTmpName; 810 xObj = p->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_DUMMY_CLASSID ).GetByteSequence(), aTmpName ); 811 } 812 // else 813 { 814 xOLERef.Assign( xObj, xOLERef.GetViewAspect() ); 815 xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aName ); 816 pListener = new SwOLEListener_Impl( this ); 817 pListener->acquire(); 818 xObj->addStateChangeListener( pListener ); 819 } 820 821 ( (SwOLENode*)pOLENd )->CheckFileLink_Impl(); // for this notification nonconst access is required 822 } 823 else if ( xOLERef->getCurrentState() == embed::EmbedStates::RUNNING ) 824 { 825 // move object to first position in cache 826 if( !pOLELRU_Cache ) 827 pOLELRU_Cache = new SwOLELRUCache; 828 pOLELRU_Cache->InsertObj( *this ); 829 } 830 831 return xOLERef.GetObject(); 832 } 833 834 svt::EmbeddedObjectRef& SwOLEObj::GetObject() 835 { 836 GetOleRef(); 837 return xOLERef; 838 } 839 840 sal_Bool SwOLEObj::UnloadObject() 841 { 842 sal_Bool bRet = sal_True; 843 //Nicht notwendig im Doc DTor (MM) 844 //ASSERT( pOLERef && pOLERef->Is() && 1 < (*pOLERef)->GetRefCount(), 845 // "Falscher RefCount fuers Unload" ); 846 if ( pOLENd ) 847 { 848 const SwDoc* pDoc = pOLENd->GetDoc(); 849 bRet = UnloadObject( xOLERef.GetObject(), pDoc, xOLERef.GetViewAspect() ); 850 } 851 852 return bRet; 853 } 854 855 sal_Bool SwOLEObj::UnloadObject( uno::Reference< embed::XEmbeddedObject > xObj, const SwDoc* pDoc, sal_Int64 nAspect ) 856 { 857 if ( !pDoc ) 858 return sal_False; 859 860 sal_Bool bRet = sal_True; 861 sal_Int32 nState = xObj.is() ? xObj->getCurrentState() : embed::EmbedStates::LOADED; 862 sal_Bool bIsActive = ( nState != embed::EmbedStates::LOADED && nState != embed::EmbedStates::RUNNING ); 863 sal_Int64 nMiscStatus = xObj->getStatus( nAspect ); 864 865 if( nState != embed::EmbedStates::LOADED && !pDoc->IsInDtor() && !bIsActive && 866 embed::EmbedMisc::MS_EMBED_ALWAYSRUN != ( nMiscStatus & embed::EmbedMisc::MS_EMBED_ALWAYSRUN ) && 867 embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY != ( nMiscStatus & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) ) 868 { 869 SfxObjectShell* p = pDoc->GetPersist(); 870 if( p ) 871 { 872 if( pDoc->get(IDocumentSettingAccess::PURGE_OLE) ) 873 { 874 try 875 { 876 uno::Reference < util::XModifiable > xMod( xObj->getComponent(), uno::UNO_QUERY ); 877 if( xMod.is() && xMod->isModified() ) 878 { 879 uno::Reference < embed::XEmbedPersist > xPers( xObj, uno::UNO_QUERY ); 880 if ( xPers.is() ) 881 xPers->storeOwn(); 882 else { 883 DBG_ERROR("Modified object without persistance in cache!"); 884 } 885 } 886 887 // setting object to loaded state will remove it from cache 888 xObj->changeState( embed::EmbedStates::LOADED ); 889 } 890 catch ( uno::Exception& ) 891 { 892 bRet = sal_False; 893 } 894 } 895 else 896 bRet = sal_False; 897 } 898 } 899 900 return bRet; 901 } 902 903 String SwOLEObj::GetDescription() 904 { 905 String aResult; 906 uno::Reference< embed::XEmbeddedObject > xEmbObj = GetOleRef(); 907 if ( xEmbObj.is() ) 908 { 909 SvGlobalName aClassID( xEmbObj->getClassID() ); 910 if ( SotExchange::IsMath( aClassID ) ) 911 aResult = SW_RES(STR_MATH_FORMULA); 912 else if ( SotExchange::IsChart( aClassID ) ) 913 aResult = SW_RES(STR_CHART); 914 else 915 aResult = SW_RES(STR_OLE); 916 } 917 918 return aResult; 919 } 920 921 922 SwOLELRUCache::SwOLELRUCache() 923 : SvPtrarr( 64, 16 ), 924 utl::ConfigItem( OUString::createFromAscii( "Office.Common/Cache" )), 925 nLRU_InitSize( 20 ), 926 bInUnload( sal_False ) 927 { 928 EnableNotification( GetPropertyNames() ); 929 Load(); 930 } 931 932 uno::Sequence< rtl::OUString > SwOLELRUCache::GetPropertyNames() 933 { 934 Sequence< OUString > aNames( 1 ); 935 OUString* pNames = aNames.getArray(); 936 pNames[0] = OUString::createFromAscii( "Writer/OLE_Objects" ); 937 return aNames; 938 } 939 940 void SwOLELRUCache::Notify( const uno::Sequence< rtl::OUString>& ) 941 { 942 Load(); 943 } 944 945 void SwOLELRUCache::Commit() 946 { 947 } 948 949 void SwOLELRUCache::Load() 950 { 951 Sequence< OUString > aNames( GetPropertyNames() ); 952 Sequence< Any > aValues = GetProperties( aNames ); 953 const Any* pValues = aValues.getConstArray(); 954 DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" ); 955 if( aValues.getLength() == aNames.getLength() && pValues->hasValue() ) 956 { 957 sal_Int32 nVal = 0; 958 *pValues >>= nVal; 959 //if( 20 > nVal ) 960 // nVal = 20; 961 962 { 963 if( nVal < nLRU_InitSize ) 964 { 965 // size of cache has been changed 966 sal_uInt16 nCount = SvPtrarr::Count(); 967 sal_uInt16 nPos = nCount; 968 969 // try to remove the last entries until new maximum size is reached 970 while( nCount > nVal ) 971 { 972 SwOLEObj* pObj = (SwOLEObj*) SvPtrarr::GetObject( --nPos ); 973 if ( pObj->UnloadObject() ) 974 nCount--; 975 if ( !nPos ) 976 break; 977 } 978 } 979 } 980 981 nLRU_InitSize = (sal_uInt16)nVal; 982 } 983 } 984 985 void SwOLELRUCache::InsertObj( SwOLEObj& rObj ) 986 { 987 SwOLEObj* pObj = &rObj; 988 sal_uInt16 nPos = SvPtrarr::GetPos( pObj ); 989 if( nPos ) 990 { 991 // object is currently not the first in cache 992 if( USHRT_MAX != nPos ) 993 SvPtrarr::Remove( nPos ); 994 995 SvPtrarr::Insert( pObj, 0 ); 996 997 // try to remove objects if necessary (of course not the freshly inserted one at nPos=0) 998 sal_uInt16 nCount = SvPtrarr::Count(); 999 nPos = nCount-1; 1000 while( nPos && nCount > nLRU_InitSize ) 1001 { 1002 pObj = (SwOLEObj*) SvPtrarr::GetObject( nPos-- ); 1003 if ( pObj->UnloadObject() ) 1004 nCount--; 1005 } 1006 } 1007 } 1008 1009 void SwOLELRUCache::RemoveObj( SwOLEObj& rObj ) 1010 { 1011 sal_uInt16 nPos = SvPtrarr::GetPos( &rObj ); 1012 if ( nPos != 0xFFFF ) 1013 SvPtrarr::Remove( nPos ); 1014 if( !Count() ) 1015 DELETEZ( pOLELRU_Cache ); 1016 } 1017 1018