merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / ole / ndole.cxx
blob3ed18d128b7f3ff0c1edd0c01bc4a65b745a84f6
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ndole.cxx,v $
10 * $Revision: 1.44 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
34 #include <com/sun/star/container/XChild.hpp>
35 #include <com/sun/star/embed/XEmbedPersist.hpp>
36 #include <com/sun/star/embed/XLinkageSupport.hpp>
37 #include <com/sun/star/embed/Aspects.hpp>
38 #include <com/sun/star/embed/EmbedMisc.hpp>
39 #include <com/sun/star/embed/EmbedStates.hpp>
40 #include <com/sun/star/util/XCloseable.hpp>
41 #include <com/sun/star/util/XModifiable.hpp>
42 #include <com/sun/star/document/XEventBroadcaster.hpp>
43 #include <cppuhelper/implbase1.hxx>
45 #include <cppuhelper/implbase2.hxx>
46 #include <toolkit/helper/vclunohelper.hxx>
47 #include <hintids.hxx>
48 #include <tools/urlobj.hxx>
49 #include <sfx2/docfile.hxx>
50 #include <sfx2/app.hxx>
51 #include <svx/linkmgr.hxx>
52 #include <unotools/configitem.hxx>
53 #ifndef _OUTDEV_HXX //autogen
54 #include <vcl/outdev.hxx>
55 #endif
56 #include <fmtanchr.hxx>
57 #include <frmfmt.hxx>
58 #include <doc.hxx>
59 #include <docsh.hxx>
60 #include <pam.hxx>
61 #include <section.hxx>
62 #include <cntfrm.hxx>
63 #include <frmatr.hxx>
64 #ifndef _DOCSH_HXX
65 #include <docsh.hxx>
66 #endif
67 #include <ndole.hxx>
69 #include <comphelper/classids.hxx>
70 #include <vcl/graph.hxx>
71 #include <sot/formats.hxx>
72 #include <unotools/ucbstreamhelper.hxx>
73 #include <svtools/filter.hxx>
74 #ifndef _COMCORE_HRC
75 #include <comcore.hrc>
76 #endif
78 using rtl::OUString;
79 using namespace utl;
80 using namespace com::sun::star::uno;
81 using namespace com::sun::star;
83 class SwOLELRUCache : private SvPtrarr, private utl::ConfigItem
85 sal_uInt16 nLRU_InitSize;
86 sal_Bool bInUnload;
87 uno::Sequence< rtl::OUString > GetPropertyNames();
89 public:
90 SwOLELRUCache();
92 virtual void Notify( const uno::Sequence<
93 rtl::OUString>& aPropertyNames );
94 virtual void Commit();
95 void Load();
97 void SetInUnload( BOOL bFlag ) { bInUnload = bFlag; }
98 using SvPtrarr::Count;
100 void InsertObj( SwOLEObj& rObj );
101 void RemoveObj( SwOLEObj& rObj );
103 void RemovePtr( SwOLEObj* pObj )
105 USHORT nPos = SvPtrarr::GetPos( pObj );
106 if( USHRT_MAX != nPos )
107 SvPtrarr::Remove( nPos );
111 SwOLELRUCache* pOLELRU_Cache = 0;
113 class SwOLEListener_Impl : public ::cppu::WeakImplHelper1< embed::XStateChangeListener >
115 SwOLEObj* mpObj;
116 public:
117 SwOLEListener_Impl( SwOLEObj* pObj );
118 void Release();
119 virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (embed::WrongStateException, uno::RuntimeException);
120 virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (uno::RuntimeException);
121 virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw (uno::RuntimeException);
124 SwOLEListener_Impl::SwOLEListener_Impl( SwOLEObj* pObj )
125 : mpObj( pObj )
127 if ( mpObj->IsOleRef() && mpObj->GetOleRef()->getCurrentState() == embed::EmbedStates::RUNNING )
129 pOLELRU_Cache->InsertObj( *mpObj );
133 void SAL_CALL SwOLEListener_Impl::changingState( const lang::EventObject&, ::sal_Int32 , ::sal_Int32 ) throw (embed::WrongStateException, uno::RuntimeException)
137 void SAL_CALL SwOLEListener_Impl::stateChanged( const lang::EventObject&, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) throw (uno::RuntimeException)
139 if ( mpObj && nOldState == embed::EmbedStates::LOADED && nNewState == embed::EmbedStates::RUNNING )
141 if( !pOLELRU_Cache )
142 pOLELRU_Cache = new SwOLELRUCache;
143 pOLELRU_Cache->InsertObj( *mpObj );
145 else if ( mpObj && nNewState == embed::EmbedStates::LOADED && nOldState == embed::EmbedStates::RUNNING )
147 if ( pOLELRU_Cache )
148 pOLELRU_Cache->RemoveObj( *mpObj );
152 void SwOLEListener_Impl::Release()
154 if ( mpObj && pOLELRU_Cache )
155 pOLELRU_Cache->RemoveObj( *mpObj );
156 mpObj=0;
157 release();
160 void SAL_CALL SwOLEListener_Impl::disposing( const lang::EventObject& ) throw (uno::RuntimeException)
162 if ( mpObj && pOLELRU_Cache )
163 pOLELRU_Cache->RemoveObj( *mpObj );
166 // --------------------
167 // SwEmbedObjectLink
168 // --------------------
169 // TODO/LATER: actually SwEmbedObjectLink should be used here, but because different objects are used to control
170 // embedded object different link objects with the same functionality had to be implemented
172 class SwEmbedObjectLink : public sfx2::SvBaseLink
174 SwOLENode* pOleNode;
176 public:
177 SwEmbedObjectLink(SwOLENode* pNode);
178 virtual ~SwEmbedObjectLink();
180 virtual void Closed();
181 virtual void DataChanged( const String& rMimeType,
182 const uno::Any & rValue );
184 sal_Bool Connect() { return GetRealObject() != NULL; }
187 // -----------------------------------------------------------------------------
189 SwEmbedObjectLink::SwEmbedObjectLink(SwOLENode* pNode):
190 ::sfx2::SvBaseLink( ::sfx2::LINKUPDATE_ONCALL, SOT_FORMATSTR_ID_SVXB ),
191 pOleNode(pNode)
193 SetSynchron( FALSE );
196 // -----------------------------------------------------------------------------
198 SwEmbedObjectLink::~SwEmbedObjectLink()
202 // -----------------------------------------------------------------------------
204 void SwEmbedObjectLink::DataChanged( const String& ,
205 const uno::Any & )
207 if ( !pOleNode->UpdateLinkURL_Impl() )
209 // the link URL was not changed
210 uno::Reference< embed::XEmbeddedObject > xObject = pOleNode->GetOLEObj().GetOleRef();
211 OSL_ENSURE( xObject.is(), "The object must exist always!\n" );
212 if ( xObject.is() )
214 // let the object reload the link
215 // TODO/LATER: reload call could be used for this case
219 sal_Int32 nState = xObject->getCurrentState();
220 if ( nState != embed::EmbedStates::LOADED )
222 // in some cases the linked file probably is not locked so it could be changed
223 xObject->changeState( embed::EmbedStates::LOADED );
224 xObject->changeState( nState );
227 catch ( uno::Exception& )
233 pOleNode->GetNewReplacement();
234 // Initiate repainting
235 // pObj->SetChanged();
238 // -----------------------------------------------------------------------------
240 void SwEmbedObjectLink::Closed()
242 pOleNode->BreakFileLink_Impl();
243 SvBaseLink::Closed();
247 // --------------------
248 // SwOLENode
249 // --------------------
251 SwOLENode::SwOLENode( const SwNodeIndex &rWhere,
252 const svt::EmbeddedObjectRef& xObj,
253 SwGrfFmtColl *pGrfColl,
254 SwAttrSet* pAutoAttr ) :
255 SwNoTxtNode( rWhere, ND_OLENODE, pGrfColl, pAutoAttr ),
256 aOLEObj( xObj ),
257 pGraphic(0),
258 bOLESizeInvalid( FALSE ),
259 mpObjectLink( NULL )
261 aOLEObj.SetNode( this );
264 SwOLENode::SwOLENode( const SwNodeIndex &rWhere,
265 const String &rString,
266 sal_Int64 nAspect,
267 SwGrfFmtColl *pGrfColl,
268 SwAttrSet* pAutoAttr ) :
269 SwNoTxtNode( rWhere, ND_OLENODE, pGrfColl, pAutoAttr ),
270 aOLEObj( rString, nAspect ),
271 pGraphic(0),
272 bOLESizeInvalid( FALSE ),
273 mpObjectLink( NULL )
275 aOLEObj.SetNode( this );
278 SwOLENode::~SwOLENode()
280 DisconnectFileLink_Impl();
281 delete pGraphic;
284 Graphic* SwOLENode::GetGraphic()
286 if ( aOLEObj.GetOleRef().is() )
287 return aOLEObj.xOLERef.GetGraphic();
288 return pGraphic;
291 Graphic* SwOLENode::GetHCGraphic()
293 return aOLEObj.xOLERef.GetHCGraphic();
296 SwCntntNode *SwOLENode::SplitCntntNode( const SwPosition & )
298 // OLE-Objecte vervielfaeltigen ??
299 ASSERT( FALSE, "OleNode: can't split." );
300 return this;
303 // Laden eines in den Undo-Bereich verschobenen OLE-Objekts
305 BOOL SwOLENode::RestorePersistentData()
307 DBG_ASSERT( aOLEObj.GetOleRef().is(), "No object to restore!" );
308 if ( aOLEObj.xOLERef.is() )
310 // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese
311 SfxObjectShell* p = GetDoc()->GetPersist();
312 if( !p )
314 // TODO/LATER: reicht hier nicht ein EmbeddedObjectContainer? Was passiert mit
315 // diesem Dokument?
316 ASSERT( !this, "warum wird hier eine DocShell angelegt?" );
317 p = new SwDocShell( GetDoc(), SFX_CREATE_MODE_INTERNAL );
318 p->DoInitNew( NULL );
321 uno::Reference < container::XChild > xChild( aOLEObj.xOLERef.GetObject(), uno::UNO_QUERY );
322 if ( xChild.is() )
323 xChild->setParent( p->GetModel() );
325 DBG_ASSERT( aOLEObj.aName.Len(), "No object name!" );
326 ::rtl::OUString aObjName;
327 if ( !p->GetEmbeddedObjectContainer().InsertEmbeddedObject( aOLEObj.xOLERef.GetObject(), aObjName ) )
329 if ( xChild.is() )
330 xChild->setParent( 0 );
331 DBG_ERROR( "InsertObject failed" );
333 else
335 aOLEObj.aName = aObjName;
336 aOLEObj.xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aObjName );
337 CheckFileLink_Impl();
341 return TRUE;
344 // OLE object is transported into UNDO area
345 BOOL SwOLENode::SavePersistentData()
347 if( aOLEObj.xOLERef.is() )
349 comphelper::EmbeddedObjectContainer* pCnt = aOLEObj.xOLERef.GetContainer();
351 #if OSL_DEBUG_LEVEL > 0
352 SfxObjectShell* p = GetDoc()->GetPersist();
353 DBG_ASSERT( p, "No document!" );
354 if( p )
356 comphelper::EmbeddedObjectContainer& rCnt = p->GetEmbeddedObjectContainer();
357 OSL_ENSURE( !pCnt || &rCnt == pCnt, "The helper is assigned to unexpected container!\n" );
359 #endif
361 if ( pCnt && pCnt->HasEmbeddedObject( aOLEObj.aName ) )
363 uno::Reference < container::XChild > xChild( aOLEObj.xOLERef.GetObject(), uno::UNO_QUERY );
364 if ( xChild.is() )
365 xChild->setParent( 0 );
367 pCnt->RemoveEmbeddedObject( aOLEObj.aName, sal_False );
369 // TODO/LATER: aOLEObj.aName has no meaning here, since the undo container contains the object
370 // by different name, in future it might makes sence that the name is transported here.
371 aOLEObj.xOLERef.AssignToContainer( 0, aOLEObj.aName );
374 // "unload" object
375 aOLEObj.xOLERef->changeState( embed::EmbedStates::LOADED );
377 catch ( uno::Exception& )
383 DisconnectFileLink_Impl();
385 return TRUE;
389 SwOLENode * SwNodes::MakeOLENode( const SwNodeIndex & rWhere,
390 const svt::EmbeddedObjectRef& xObj,
391 SwGrfFmtColl* pGrfColl,
392 SwAttrSet* pAutoAttr )
394 ASSERT( pGrfColl,"SwNodes::MakeOLENode: Formatpointer ist 0." );
396 SwOLENode *pNode =
397 new SwOLENode( rWhere, xObj, pGrfColl, pAutoAttr );
399 // set parent if XChild is supported
400 //!! needed to supply Math objects with a valid reference device
401 uno::Reference< container::XChild > xChild( pNode->GetOLEObj().GetObject().GetObject(), UNO_QUERY );
402 if (xChild.is())
404 SwDocShell *pDocSh = GetDoc()->GetDocShell();
405 if (pDocSh)
406 xChild->setParent( pDocSh->GetModel() );
409 return pNode;
413 SwOLENode * SwNodes::MakeOLENode( const SwNodeIndex & rWhere,
414 const String &rName, sal_Int64 nAspect, SwGrfFmtColl* pGrfColl, SwAttrSet* pAutoAttr )
416 ASSERT( pGrfColl,"SwNodes::MakeOLENode: Formatpointer ist 0." );
418 SwOLENode *pNode =
419 new SwOLENode( rWhere, rName, nAspect, pGrfColl, pAutoAttr );
421 // set parent if XChild is supported
422 //!! needed to supply Math objects with a valid reference device
423 uno::Reference< container::XChild > xChild( pNode->GetOLEObj().GetObject().GetObject(), UNO_QUERY );
424 if (xChild.is())
426 SwDocShell *pDocSh= GetDoc()->GetDocShell();
427 if (pDocSh)
428 xChild->setParent( pDocSh->GetModel() );
431 return pNode;
434 Size SwOLENode::GetTwipSize() const
436 MapMode aMapMode( MAP_TWIP );
437 return ((SwOLENode*)this)->aOLEObj.GetObject().GetSize( &aMapMode );
440 SwCntntNode* SwOLENode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
442 // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese
443 SfxObjectShell* p = pDoc->GetPersist();
444 if( !p )
446 // TODO/LATER: reicht hier nicht ein EmbeddedObjectContainer? Was passiert mit
447 // diesem Dokument?
448 ASSERT( pDoc->GetRefForDocShell(),
449 "wo ist die Ref-Klasse fuer die DocShell?")
450 p = new SwDocShell( pDoc, SFX_CREATE_MODE_INTERNAL );
451 *pDoc->GetRefForDocShell() = p;
452 p->DoInitNew( NULL );
455 // Wir hauen das Ding auf SvPersist-Ebene rein
456 // TODO/LATER: check if using the same naming scheme for all apps works here
457 ::rtl::OUString aNewName/*( Sw3Io::UniqueName( p->GetStorage(), "Obj" ) )*/;
458 SfxObjectShell* pSrc = GetDoc()->GetPersist();
460 p->GetEmbeddedObjectContainer().CopyAndGetEmbeddedObject(
461 pSrc->GetEmbeddedObjectContainer(),
462 pSrc->GetEmbeddedObjectContainer().GetEmbeddedObject( aOLEObj.aName ),
463 aNewName );
465 SwOLENode* pOLENd = pDoc->GetNodes().MakeOLENode( rIdx, aNewName, GetAspect(),
466 (SwGrfFmtColl*)pDoc->GetDfltGrfFmtColl(),
467 (SwAttrSet*)GetpSwAttrSet() );
469 pOLENd->SetChartTblName( GetChartTblName() );
470 pOLENd->SetTitle( GetTitle() );
471 pOLENd->SetDescription( GetDescription() );
472 pOLENd->SetContour( HasContour(), HasAutomaticContour() );
473 pOLENd->SetAspect( GetAspect() ); // the replacement image must be already copied
475 pOLENd->SetOLESizeInvalid( TRUE );
476 pDoc->SetOLEPrtNotifyPending();
478 return pOLENd;
481 BOOL SwOLENode::IsInGlobalDocSection() const
483 // suche den "Body Anchor"
484 ULONG nEndExtraIdx = GetNodes().GetEndOfExtras().GetIndex();
485 const SwNode* pAnchorNd = this;
486 do {
487 SwFrmFmt* pFlyFmt = pAnchorNd->GetFlyFmt();
488 if( !pFlyFmt )
489 return FALSE;
491 const SwFmtAnchor& rAnchor = pFlyFmt->GetAnchor();
492 if( !rAnchor.GetCntntAnchor() )
493 return FALSE;
495 pAnchorNd = &rAnchor.GetCntntAnchor()->nNode.GetNode();
496 } while( pAnchorNd->GetIndex() < nEndExtraIdx );
498 const SwSectionNode* pSectNd = pAnchorNd->FindSectionNode();
499 if( !pSectNd )
500 return FALSE;
502 while( pSectNd )
504 pAnchorNd = pSectNd;
505 pSectNd = pAnchorNd->StartOfSectionNode()->FindSectionNode();
508 // in pAnchorNd steht der zuletzt gefundene Section Node. Der muss
509 // jetzt die Bedingung fuers GlobalDoc erfuellen.
510 pSectNd = (SwSectionNode*)pAnchorNd;
511 return FILE_LINK_SECTION == pSectNd->GetSection().GetType() &&
512 pSectNd->GetIndex() > nEndExtraIdx;
515 BOOL SwOLENode::IsOLEObjectDeleted() const
517 BOOL bRet = FALSE;
518 if( aOLEObj.xOLERef.is() )
520 SfxObjectShell* p = GetDoc()->GetPersist();
521 if( p ) // muss da sein
523 return !p->GetEmbeddedObjectContainer().HasEmbeddedObject( aOLEObj.aName );
524 //SvInfoObjectRef aRef( p->Find( aOLEObj.aName ) );
525 //if( aRef.Is() )
526 // bRet = aRef->IsDeleted();
529 return bRet;
532 void SwOLENode::GetNewReplacement()
534 if ( aOLEObj.xOLERef.is() )
535 aOLEObj.xOLERef.UpdateReplacement();
538 sal_Bool SwOLENode::UpdateLinkURL_Impl()
540 sal_Bool bResult = sal_False;
542 if ( mpObjectLink )
544 String aNewLinkURL;
545 GetDoc()->GetLinkManager().GetDisplayNames( mpObjectLink, 0, &aNewLinkURL, 0, 0 );
546 if ( !aNewLinkURL.EqualsIgnoreCaseAscii( maLinkURL ) )
548 if ( !aOLEObj.xOLERef.is() )
549 aOLEObj.GetOleRef();
551 uno::Reference< embed::XEmbeddedObject > xObj = aOLEObj.xOLERef.GetObject();
552 uno::Reference< embed::XCommonEmbedPersist > xPersObj( xObj, uno::UNO_QUERY );
553 OSL_ENSURE( xPersObj.is(), "The object must exist!\n" );
554 if ( xPersObj.is() )
558 sal_Int32 nCurState = xObj->getCurrentState();
559 if ( nCurState != embed::EmbedStates::LOADED )
560 xObj->changeState( embed::EmbedStates::LOADED );
562 // TODO/LATER: there should be possible to get current mediadescriptor settings from the object
563 uno::Sequence< beans::PropertyValue > aArgs( 1 );
564 aArgs[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
565 aArgs[0].Value <<= ::rtl::OUString( aNewLinkURL );
566 xPersObj->reload( aArgs, uno::Sequence< beans::PropertyValue >() );
568 maLinkURL = aNewLinkURL;
569 bResult = sal_True;
571 if ( nCurState != embed::EmbedStates::LOADED )
572 xObj->changeState( nCurState );
574 catch( uno::Exception& )
578 if ( !bResult )
580 // TODO/LATER: return the old name to the link manager, is it possible?
585 return bResult;
588 void SwOLENode::BreakFileLink_Impl()
590 SfxObjectShell* pPers = GetDoc()->GetPersist();
592 if ( pPers )
594 uno::Reference< embed::XStorage > xStorage = pPers->GetStorage();
595 if ( xStorage.is() )
599 uno::Reference< embed::XLinkageSupport > xLinkSupport( aOLEObj.GetOleRef(), uno::UNO_QUERY_THROW );
600 xLinkSupport->breakLink( xStorage, aOLEObj.GetCurrentPersistName() );
601 DisconnectFileLink_Impl();
602 maLinkURL = String();
604 catch( uno::Exception& )
611 void SwOLENode::DisconnectFileLink_Impl()
613 if ( mpObjectLink )
615 GetDoc()->GetLinkManager().Remove( mpObjectLink );
616 mpObjectLink = NULL;
620 void SwOLENode::CheckFileLink_Impl()
622 if ( aOLEObj.xOLERef.GetObject().is() && !mpObjectLink )
626 uno::Reference< embed::XLinkageSupport > xLinkSupport( aOLEObj.xOLERef.GetObject(), uno::UNO_QUERY_THROW );
627 if ( xLinkSupport->isLink() )
629 String aLinkURL = xLinkSupport->getLinkURL();
630 if ( aLinkURL.Len() )
632 // this is a file link so the model link manager should handle it
633 mpObjectLink = new SwEmbedObjectLink( this );
634 maLinkURL = aLinkURL;
635 GetDoc()->GetLinkManager().InsertFileLink( *mpObjectLink, OBJECT_CLIENT_OLE, aLinkURL, NULL, NULL );
636 mpObjectLink->Connect();
640 catch( uno::Exception& )
646 // --> OD 2009-03-05 #i99665#
647 bool SwOLENode::IsChart() const
649 bool bIsChart( false );
651 const uno::Reference< embed::XEmbeddedObject > xEmbObj =
652 const_cast<SwOLEObj&>(GetOLEObj()).GetOleRef();
653 if ( xEmbObj.is() )
655 SvGlobalName aClassID( xEmbObj->getClassID() );
656 bIsChart = SotExchange::IsChart( aClassID );
659 return bIsChart;
661 // <--
663 SwOLEObj::SwOLEObj( const svt::EmbeddedObjectRef& xObj ) :
664 pOLENd( 0 ),
665 pListener( 0 ),
666 xOLERef( xObj )
668 xOLERef.Lock( TRUE );
669 if ( xObj.is() )
671 pListener = new SwOLEListener_Impl( this );
672 pListener->acquire();
673 xObj->addStateChangeListener( pListener );
678 SwOLEObj::SwOLEObj( const String &rString, sal_Int64 nAspect ) :
679 pOLENd( 0 ),
680 pListener( 0 ),
681 aName( rString )
683 xOLERef.Lock( TRUE );
684 xOLERef.SetViewAspect( nAspect );
688 SwOLEObj::~SwOLEObj()
690 if( pListener )
692 if ( xOLERef.is() )
693 xOLERef->removeStateChangeListener( pListener );
694 pListener->Release();
697 if( pOLENd && !pOLENd->GetDoc()->IsInDtor() )
699 // if the model is not currently in destruction it means that this object should be removed from the model
700 comphelper::EmbeddedObjectContainer* pCnt = xOLERef.GetContainer();
702 #if OSL_DEBUG_LEVEL > 0
703 SfxObjectShell* p = pOLENd->GetDoc()->GetPersist();
704 DBG_ASSERT( p, "No document!" );
705 if( p )
707 comphelper::EmbeddedObjectContainer& rCnt = p->GetEmbeddedObjectContainer();
708 OSL_ENSURE( !pCnt || &rCnt == pCnt, "The helper is assigned to unexpected container!\n" );
710 #endif
712 if ( pCnt && pCnt->HasEmbeddedObject( aName ) )
714 uno::Reference < container::XChild > xChild( xOLERef.GetObject(), uno::UNO_QUERY );
715 if ( xChild.is() )
716 xChild->setParent( 0 );
718 // not already removed by deleting the object
719 xOLERef.AssignToContainer( 0, aName );
721 // unlock object so that object can be closed in RemoveEmbeddedObject
722 // successful closing of the object will automatically clear the reference then
723 xOLERef.Lock(FALSE);
725 // Always remove object from conteiner it is connected to
728 pCnt->RemoveEmbeddedObject( aName );
730 catch ( uno::Exception& )
737 if ( xOLERef.is() )
738 // in case the object wasn't closed: release it
739 // in case the object was not in the container: it's still locked, try to close
740 xOLERef.Clear();
744 void SwOLEObj::SetNode( SwOLENode* pNode )
746 pOLENd = pNode;
747 if ( !aName.Len() )
749 SwDoc* pDoc = pNode->GetDoc();
751 // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese
752 SfxObjectShell* p = pDoc->GetPersist();
753 if( !p )
755 // TODO/LATER: reicht hier nicht ein EmbeddedObjectContainer? Was passiert mit
756 // diesem Dokument?
757 ASSERT( !this, "warum wird hier eine DocShell angelegt?" );
758 p = new SwDocShell( pDoc, SFX_CREATE_MODE_INTERNAL );
759 p->DoInitNew( NULL );
762 ::rtl::OUString aObjName;
763 uno::Reference < container::XChild > xChild( xOLERef.GetObject(), uno::UNO_QUERY );
764 if ( xChild.is() && xChild->getParent() != p->GetModel() )
765 // it is possible that the parent was set already
766 xChild->setParent( p->GetModel() );
767 if (!p->GetEmbeddedObjectContainer().InsertEmbeddedObject( xOLERef.GetObject(), aObjName ) )
769 DBG_ERROR( "InsertObject failed" );
770 if ( xChild.is() )
771 xChild->setParent( 0 );
773 else
774 xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aObjName );
776 ( (SwOLENode*)pOLENd )->CheckFileLink_Impl(); // for this notification nonconst access is required
778 aName = aObjName;
782 BOOL SwOLEObj::IsOleRef() const
784 return xOLERef.is();
787 uno::Reference < embed::XEmbeddedObject > SwOLEObj::GetOleRef()
789 if( !xOLERef.is() )
791 SfxObjectShell* p = pOLENd->GetDoc()->GetPersist();
792 ASSERT( p, "kein SvPersist vorhanden" );
794 uno::Reference < embed::XEmbeddedObject > xObj = p->GetEmbeddedObjectContainer().GetEmbeddedObject( aName );
795 ASSERT( !xOLERef.is(), "rekursiver Aufruf von GetOleRef() ist nicht erlaubt" )
797 if ( !xObj.is() )
799 //Das Teil konnte nicht geladen werden (wahrsch. Kaputt).
800 Rectangle aArea;
801 SwFrm *pFrm = pOLENd->GetFrm();
802 if ( pFrm )
804 Size aSz( pFrm->Frm().SSize() );
805 const MapMode aSrc ( MAP_TWIP );
806 const MapMode aDest( MAP_100TH_MM );
807 aSz = OutputDevice::LogicToLogic( aSz, aSrc, aDest );
808 aArea.SetSize( aSz );
810 else
811 aArea.SetSize( Size( 5000, 5000 ) );
812 // TODO/LATER: set replacement graphic for dead object
813 // It looks as if it should work even without the object, because the replace will be generated automatically
814 ::rtl::OUString aTmpName;
815 xObj = p->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_DUMMY_CLASSID ).GetByteSequence(), aTmpName );
817 // else
819 xOLERef.Assign( xObj, xOLERef.GetViewAspect() );
820 xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aName );
821 pListener = new SwOLEListener_Impl( this );
822 pListener->acquire();
823 xObj->addStateChangeListener( pListener );
826 ( (SwOLENode*)pOLENd )->CheckFileLink_Impl(); // for this notification nonconst access is required
828 else if ( xOLERef->getCurrentState() == embed::EmbedStates::RUNNING )
830 // move object to first position in cache
831 if( !pOLELRU_Cache )
832 pOLELRU_Cache = new SwOLELRUCache;
833 pOLELRU_Cache->InsertObj( *this );
836 return xOLERef.GetObject();
839 svt::EmbeddedObjectRef& SwOLEObj::GetObject()
841 GetOleRef();
842 return xOLERef;
845 BOOL SwOLEObj::UnloadObject()
847 BOOL bRet = TRUE;
848 //Nicht notwendig im Doc DTor (MM)
849 //ASSERT( pOLERef && pOLERef->Is() && 1 < (*pOLERef)->GetRefCount(),
850 // "Falscher RefCount fuers Unload" );
851 if ( pOLENd )
853 const SwDoc* pDoc = pOLENd->GetDoc();
854 bRet = UnloadObject( xOLERef.GetObject(), pDoc, xOLERef.GetViewAspect() );
857 return bRet;
860 BOOL SwOLEObj::UnloadObject( uno::Reference< embed::XEmbeddedObject > xObj, const SwDoc* pDoc, sal_Int64 nAspect )
862 if ( !pDoc )
863 return FALSE;
865 BOOL bRet = TRUE;
866 sal_Int32 nState = xObj.is() ? xObj->getCurrentState() : embed::EmbedStates::LOADED;
867 BOOL bIsActive = ( nState != embed::EmbedStates::LOADED && nState != embed::EmbedStates::RUNNING );
868 sal_Int64 nMiscStatus = xObj->getStatus( nAspect );
870 if( nState != embed::EmbedStates::LOADED && !pDoc->IsInDtor() && !bIsActive &&
871 embed::EmbedMisc::MS_EMBED_ALWAYSRUN != ( nMiscStatus & embed::EmbedMisc::MS_EMBED_ALWAYSRUN ) &&
872 embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY != ( nMiscStatus & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) )
874 SfxObjectShell* p = pDoc->GetPersist();
875 if( p )
877 if( pDoc->get(IDocumentSettingAccess::PURGE_OLE) )
881 uno::Reference < util::XModifiable > xMod( xObj->getComponent(), uno::UNO_QUERY );
882 if( xMod.is() && xMod->isModified() )
884 uno::Reference < embed::XEmbedPersist > xPers( xObj, uno::UNO_QUERY );
885 if ( xPers.is() )
886 xPers->storeOwn();
887 else {
888 DBG_ERROR("Modified object without persistance in cache!");
892 // setting object to loaded state will remove it from cache
893 xObj->changeState( embed::EmbedStates::LOADED );
895 catch ( uno::Exception& )
897 bRet = FALSE;
900 else
901 bRet = FALSE;
905 return bRet;
908 String SwOLEObj::GetDescription()
910 String aResult;
911 uno::Reference< embed::XEmbeddedObject > xEmbObj = GetOleRef();
912 if ( xEmbObj.is() )
914 SvGlobalName aClassID( xEmbObj->getClassID() );
915 if ( SotExchange::IsMath( aClassID ) )
916 aResult = SW_RES(STR_MATH_FORMULA);
917 else if ( SotExchange::IsChart( aClassID ) )
918 aResult = SW_RES(STR_CHART);
919 else
920 aResult = SW_RES(STR_OLE);
923 return aResult;
927 SwOLELRUCache::SwOLELRUCache()
928 : SvPtrarr( 64, 16 ),
929 utl::ConfigItem( OUString::createFromAscii( "Office.Common/Cache" )),
930 nLRU_InitSize( 20 ),
931 bInUnload( sal_False )
933 EnableNotification( GetPropertyNames() );
934 Load();
937 uno::Sequence< rtl::OUString > SwOLELRUCache::GetPropertyNames()
939 Sequence< OUString > aNames( 1 );
940 OUString* pNames = aNames.getArray();
941 pNames[0] = OUString::createFromAscii( "Writer/OLE_Objects" );
942 return aNames;
945 void SwOLELRUCache::Notify( const uno::Sequence< rtl::OUString>& )
947 Load();
950 void SwOLELRUCache::Commit()
954 void SwOLELRUCache::Load()
956 Sequence< OUString > aNames( GetPropertyNames() );
957 Sequence< Any > aValues = GetProperties( aNames );
958 const Any* pValues = aValues.getConstArray();
959 DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
960 if( aValues.getLength() == aNames.getLength() && pValues->hasValue() )
962 sal_Int32 nVal = 0;
963 *pValues >>= nVal;
964 //if( 20 > nVal )
965 // nVal = 20;
968 if( nVal < nLRU_InitSize )
970 // size of cache has been changed
971 USHORT nCount = SvPtrarr::Count();
972 USHORT nPos = nCount;
974 // try to remove the last entries until new maximum size is reached
975 while( nCount > nVal )
977 SwOLEObj* pObj = (SwOLEObj*) SvPtrarr::GetObject( --nPos );
978 if ( pObj->UnloadObject() )
979 nCount--;
980 if ( !nPos )
981 break;
986 nLRU_InitSize = (USHORT)nVal;
990 void SwOLELRUCache::InsertObj( SwOLEObj& rObj )
992 SwOLEObj* pObj = &rObj;
993 USHORT nPos = SvPtrarr::GetPos( pObj );
994 if( nPos )
996 // object is currently not the first in cache
997 if( USHRT_MAX != nPos )
998 SvPtrarr::Remove( nPos );
1000 SvPtrarr::Insert( pObj, 0 );
1002 // try to remove objects if necessary (of course not the freshly inserted one at nPos=0)
1003 USHORT nCount = SvPtrarr::Count();
1004 nPos = nCount-1;
1005 while( nPos && nCount > nLRU_InitSize )
1007 pObj = (SwOLEObj*) SvPtrarr::GetObject( nPos-- );
1008 if ( pObj->UnloadObject() )
1009 nCount--;
1014 void SwOLELRUCache::RemoveObj( SwOLEObj& rObj )
1016 USHORT nPos = SvPtrarr::GetPos( &rObj );
1017 if ( nPos != 0xFFFF )
1018 SvPtrarr::Remove( nPos );
1019 if( !Count() )
1020 DELETEZ( pOLELRU_Cache );