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