xref: /trunk/main/sw/source/core/ole/ndole.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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