xref: /aoo41x/main/sw/source/core/ole/ndole.cxx (revision 6170fa3c)
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 
91 	void SetInUnload( sal_Bool bFlag ) 	{ bInUnload = bFlag; }
92 	using SvPtrarr::Count;
93 
94 	void InsertObj( SwOLEObj& rObj );
95 	void RemoveObj( SwOLEObj& rObj );
96 
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 
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 
127 void SAL_CALL SwOLEListener_Impl::changingState( const lang::EventObject&, ::sal_Int32 , ::sal_Int32 ) throw (embed::WrongStateException, uno::RuntimeException)
128 {
129 }
130 
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 
146 void SwOLEListener_Impl::Release()
147 {
148     if ( mpObj && pOLELRU_Cache )
149         pOLELRU_Cache->RemoveObj( *mpObj );
150     mpObj=0;
151     release();
152 }
153 
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 
178 	sal_Bool			Connect() { return GetRealObject() != NULL; }
179 };
180 
181 // -----------------------------------------------------------------------------
182 
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 
192 SwEmbedObjectLink::~SwEmbedObjectLink()
193 {
194 }
195 
196 // -----------------------------------------------------------------------------
197 
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 
234 void SwEmbedObjectLink::Closed()
235 {
236 	pOleNode->BreakFileLink_Impl();
237 	SvBaseLink::Closed();
238 }
239 
240 
241 // --------------------
242 // SwOLENode
243 // --------------------
244 
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 
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 
272 SwOLENode::~SwOLENode()
273 {
274 	DisconnectFileLink_Impl();
275     delete pGraphic;
276 }
277 
278 Graphic* SwOLENode::GetGraphic()
279 {
280     if ( aOLEObj.GetOleRef().is() )
281         return aOLEObj.xOLERef.GetGraphic();
282     return pGraphic;
283 }
284 
285 Graphic* SwOLENode::GetHCGraphic()
286 {
287 	return aOLEObj.xOLERef.GetHCGraphic();
288 }
289 
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 
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
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 
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 
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 
451 Size SwOLENode::GetTwipSize() const
452 {
453 	MapMode aMapMode( MAP_TWIP );
454 	return ((SwOLENode*)this)->aOLEObj.GetObject().GetSize( &aMapMode );
455 }
456 
457 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 
496 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 
530 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 
547 void SwOLENode::GetNewReplacement()
548 {
549 	if ( aOLEObj.xOLERef.is() )
550 		aOLEObj.xOLERef.UpdateReplacement();
551 }
552 
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 
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 
626 void SwOLENode::DisconnectFileLink_Impl()
627 {
628 	if ( mpObjectLink )
629 	{
630         GetDoc()->GetLinkManager().Remove( mpObjectLink );
631 		mpObjectLink = NULL;
632 	}
633 }
634 
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#
662 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 
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 
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 
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 
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 
797 sal_Bool SwOLEObj::IsOleRef() const
798 {
799     return xOLERef.is();
800 }
801 
802 const uno::Reference < embed::XEmbeddedObject > SwOLEObj::GetOleRef()
803 {
804     if( !xOLERef.is() )
805 	{
806         SfxObjectShell* p = pOLENd->GetDoc()->GetPersist();
807 		ASSERT( p, "kein SvPersist vorhanden" );
808 
809         uno::Reference < embed::XEmbeddedObject > xObj = p->GetEmbeddedObjectContainer().GetEmbeddedObject( aName );
810         ASSERT( !xOLERef.is(), "rekursiver Aufruf von GetOleRef() ist nicht erlaubt" )
811 
812 		if ( !xObj.is() )
813 		{
814 			//Das Teil konnte nicht geladen werden (wahrsch. Kaputt).
815 			Rectangle aArea;
816 			SwFrm *pFrm = pOLENd->getLayoutFrm(0);
817 			if ( pFrm )
818 			{
819 				Size aSz( pFrm->Frm().SSize() );
820 				const MapMode aSrc ( MAP_TWIP );
821 				const MapMode aDest( MAP_100TH_MM );
822 				aSz = OutputDevice::LogicToLogic( aSz, aSrc, aDest );
823 				aArea.SetSize( aSz );
824 			}
825 			else
826 				aArea.SetSize( Size( 5000,  5000 ) );
827             // TODO/LATER: set replacement graphic for dead object
828             // It looks as if it should work even without the object, because the replace will be generated automatically
829             ::rtl::OUString aTmpName;
830             xObj = p->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_DUMMY_CLASSID ).GetByteSequence(), aTmpName );
831 		}
832         // else
833         {
834             xOLERef.Assign( xObj, xOLERef.GetViewAspect() );
835             xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aName );
836             pListener = new SwOLEListener_Impl( this );
837             pListener->acquire();
838             xObj->addStateChangeListener( pListener );
839         }
840 
841 		( (SwOLENode*)pOLENd )->CheckFileLink_Impl(); // for this notification nonconst access is required
842 	}
843     else if ( xOLERef->getCurrentState() == embed::EmbedStates::RUNNING )
844     {
845         // move object to first position in cache
846         if( !pOLELRU_Cache )
847             pOLELRU_Cache = new SwOLELRUCache;
848         pOLELRU_Cache->InsertObj( *this );
849     }
850 
851     return xOLERef.GetObject();
852 }
853 
854 svt::EmbeddedObjectRef& SwOLEObj::GetObject()
855 {
856     GetOleRef();
857     return xOLERef;
858 }
859 
860 sal_Bool SwOLEObj::UnloadObject()
861 {
862 	sal_Bool bRet = sal_True;
863 	//Nicht notwendig im Doc DTor (MM)
864     //ASSERT( pOLERef && pOLERef->Is() && 1 < (*pOLERef)->GetRefCount(),
865     //        "Falscher RefCount fuers Unload" );
866 	if ( pOLENd )
867 	{
868 		const SwDoc* pDoc = pOLENd->GetDoc();
869 		bRet = UnloadObject( xOLERef.GetObject(), pDoc, xOLERef.GetViewAspect() );
870 	}
871 
872 	return bRet;
873 }
874 
875 sal_Bool SwOLEObj::UnloadObject( uno::Reference< embed::XEmbeddedObject > xObj, const SwDoc* pDoc, sal_Int64 nAspect )
876 {
877 	if ( !pDoc )
878 		return sal_False;
879 
880 	sal_Bool bRet = sal_True;
881    	sal_Int32 nState = xObj.is() ? xObj->getCurrentState() : embed::EmbedStates::LOADED;
882    	sal_Bool bIsActive = ( nState != embed::EmbedStates::LOADED && nState != embed::EmbedStates::RUNNING );
883 	sal_Int64 nMiscStatus = xObj->getStatus( nAspect );
884 
885    	if( nState != embed::EmbedStates::LOADED && !pDoc->IsInDtor() && !bIsActive &&
886 		embed::EmbedMisc::MS_EMBED_ALWAYSRUN != ( nMiscStatus & embed::EmbedMisc::MS_EMBED_ALWAYSRUN ) &&
887 		embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY != ( nMiscStatus & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) )
888 	{
889         SfxObjectShell* p = pDoc->GetPersist();
890 		if( p )
891 		{
892 			if( pDoc->get(IDocumentSettingAccess::PURGE_OLE) )
893 			{
894                 try
895                 {
896                     uno::Reference < util::XModifiable > xMod( xObj->getComponent(), uno::UNO_QUERY );
897                     if( xMod.is() && xMod->isModified() )
898                     {
899                         uno::Reference < embed::XEmbedPersist > xPers( xObj, uno::UNO_QUERY );
900                         if ( xPers.is() )
901                             xPers->storeOwn();
902                         else {
903                             DBG_ERROR("Modified object without persistance in cache!");
904                         }
905                     }
906 
907                     // setting object to loaded state will remove it from cache
908                     xObj->changeState( embed::EmbedStates::LOADED );
909                 }
910                 catch ( uno::Exception& )
911                 {
912                     bRet = sal_False;
913                 }
914 			}
915 			else
916 				bRet = sal_False;
917 		}
918 	}
919 
920 	return bRet;
921 }
922 
923 String SwOLEObj::GetDescription()
924 {
925     String aResult;
926 	uno::Reference< embed::XEmbeddedObject > xEmbObj = GetOleRef();
927     if ( xEmbObj.is() )
928     {
929 		SvGlobalName aClassID( xEmbObj->getClassID() );
930         if ( SotExchange::IsMath( aClassID ) )
931             aResult = SW_RES(STR_MATH_FORMULA);
932         else if ( SotExchange::IsChart( aClassID ) )
933             aResult = SW_RES(STR_CHART);
934         else
935             aResult = SW_RES(STR_OLE);
936     }
937 
938     return aResult;
939 }
940 
941 
942 SwOLELRUCache::SwOLELRUCache()
943 	: SvPtrarr( 64, 16 ),
944 	utl::ConfigItem( OUString::createFromAscii( "Office.Common/Cache" )),
945     nLRU_InitSize( 20 ),
946     bInUnload( sal_False )
947 {
948 	EnableNotification( GetPropertyNames() );
949 	Load();
950 }
951 
952 uno::Sequence< rtl::OUString > SwOLELRUCache::GetPropertyNames()
953 {
954 	Sequence< OUString > aNames( 1 );
955 	OUString* pNames = aNames.getArray();
956 	pNames[0] = OUString::createFromAscii( "Writer/OLE_Objects" );
957 	return aNames;
958 }
959 
960 void SwOLELRUCache::Notify( const uno::Sequence< rtl::OUString>&  )
961 {
962 	Load();
963 }
964 
965 void SwOLELRUCache::Commit()
966 {
967 }
968 
969 void SwOLELRUCache::Load()
970 {
971 	Sequence< OUString > aNames( GetPropertyNames() );
972 	Sequence< Any > aValues = GetProperties( aNames );
973 	const Any* pValues = aValues.getConstArray();
974 	DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
975     if( aValues.getLength() == aNames.getLength() && pValues->hasValue() )
976 	{
977 		sal_Int32 nVal = 0;
978 		*pValues >>= nVal;
979         //if( 20 > nVal )
980         //    nVal = 20;
981 
982 		{
983             if( nVal < nLRU_InitSize )
984 			{
985                 // size of cache has been changed
986                 sal_uInt16 nCount = SvPtrarr::Count();
987                 sal_uInt16 nPos = nCount;
988 
989                 // try to remove the last entries until new maximum size is reached
990                 while( nCount > nVal )
991 				{
992 					SwOLEObj* pObj = (SwOLEObj*) SvPtrarr::GetObject( --nPos );
993                     if ( pObj->UnloadObject() )
994                         nCount--;
995                     if ( !nPos )
996                         break;
997 				}
998 			}
999 		}
1000 
1001 		nLRU_InitSize = (sal_uInt16)nVal;
1002 	}
1003 }
1004 
1005 void SwOLELRUCache::InsertObj( SwOLEObj& rObj )
1006 {
1007     SwOLEObj* pObj = &rObj;
1008     sal_uInt16 nPos = SvPtrarr::GetPos( pObj );
1009     if( nPos )
1010     {
1011         // object is currently not the first in cache
1012         if( USHRT_MAX != nPos )
1013             SvPtrarr::Remove( nPos );
1014 
1015         SvPtrarr::Insert( pObj, 0 );
1016 
1017         // try to remove objects if necessary (of course not the freshly inserted one at nPos=0)
1018         sal_uInt16 nCount = SvPtrarr::Count();
1019         nPos = nCount-1;
1020         while( nPos && nCount > nLRU_InitSize )
1021         {
1022             pObj = (SwOLEObj*) SvPtrarr::GetObject( nPos-- );
1023             if ( pObj->UnloadObject() )
1024                 nCount--;
1025         }
1026     }
1027 }
1028 
1029 void SwOLELRUCache::RemoveObj( SwOLEObj& rObj )
1030 {
1031     sal_uInt16 nPos = SvPtrarr::GetPos( &rObj );
1032     if ( nPos != 0xFFFF )
1033         SvPtrarr::Remove( nPos );
1034     if( !Count() )
1035         DELETEZ( pOLELRU_Cache );
1036 }
1037 
1038