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