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