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