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