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