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