xref: /AOO41X/main/sw/source/core/ole/ndole.cxx (revision 5ff14ef2c455a7c2a39819566d74aed4bcc9528e)
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 //IAccessibility2 Implementation 2009-----
798 String SwOLEObj::GetStyleString()
799 {
800 	String strStyle;
801 	if (xOLERef.is() && xOLERef.IsChart())
802 		strStyle = xOLERef.GetChartType();
803 	return strStyle;
804 }
805 //-----IAccessibility2 Implementation 2009
806 sal_Bool SwOLEObj::IsOleRef() const
807 {
808     return xOLERef.is();
809 }
810 
811 const uno::Reference < embed::XEmbeddedObject > SwOLEObj::GetOleRef()
812 {
813     if( !xOLERef.is() )
814 	{
815         SfxObjectShell* p = pOLENd->GetDoc()->GetPersist();
816 		ASSERT( p, "kein SvPersist vorhanden" );
817 
818         uno::Reference < embed::XEmbeddedObject > xObj = p->GetEmbeddedObjectContainer().GetEmbeddedObject( aName );
819         ASSERT( !xOLERef.is(), "rekursiver Aufruf von GetOleRef() ist nicht erlaubt" )
820 
821 		if ( !xObj.is() )
822 		{
823 			//Das Teil konnte nicht geladen werden (wahrsch. Kaputt).
824 			Rectangle aArea;
825 			SwFrm *pFrm = pOLENd->getLayoutFrm(0);
826 			if ( pFrm )
827 			{
828 				Size aSz( pFrm->Frm().SSize() );
829 				const MapMode aSrc ( MAP_TWIP );
830 				const MapMode aDest( MAP_100TH_MM );
831 				aSz = OutputDevice::LogicToLogic( aSz, aSrc, aDest );
832 				aArea.SetSize( aSz );
833 			}
834 			else
835 				aArea.SetSize( Size( 5000,  5000 ) );
836             // TODO/LATER: set replacement graphic for dead object
837             // It looks as if it should work even without the object, because the replace will be generated automatically
838             ::rtl::OUString aTmpName;
839             xObj = p->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_DUMMY_CLASSID ).GetByteSequence(), aTmpName );
840 		}
841         // else
842         {
843             xOLERef.Assign( xObj, xOLERef.GetViewAspect() );
844             xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aName );
845             pListener = new SwOLEListener_Impl( this );
846             pListener->acquire();
847             xObj->addStateChangeListener( pListener );
848         }
849 
850 		( (SwOLENode*)pOLENd )->CheckFileLink_Impl(); // for this notification nonconst access is required
851 	}
852     else if ( xOLERef->getCurrentState() == embed::EmbedStates::RUNNING )
853     {
854         // move object to first position in cache
855         if( !pOLELRU_Cache )
856             pOLELRU_Cache = new SwOLELRUCache;
857         pOLELRU_Cache->InsertObj( *this );
858     }
859 
860     return xOLERef.GetObject();
861 }
862 
863 svt::EmbeddedObjectRef& SwOLEObj::GetObject()
864 {
865     GetOleRef();
866     return xOLERef;
867 }
868 
869 sal_Bool SwOLEObj::UnloadObject()
870 {
871 	sal_Bool bRet = sal_True;
872 	//Nicht notwendig im Doc DTor (MM)
873     //ASSERT( pOLERef && pOLERef->Is() && 1 < (*pOLERef)->GetRefCount(),
874     //        "Falscher RefCount fuers Unload" );
875 	if ( pOLENd )
876 	{
877 		const SwDoc* pDoc = pOLENd->GetDoc();
878 		bRet = UnloadObject( xOLERef.GetObject(), pDoc, xOLERef.GetViewAspect() );
879 	}
880 
881 	return bRet;
882 }
883 
884 sal_Bool SwOLEObj::UnloadObject( uno::Reference< embed::XEmbeddedObject > xObj, const SwDoc* pDoc, sal_Int64 nAspect )
885 {
886 	if ( !pDoc )
887 		return sal_False;
888 
889 	sal_Bool bRet = sal_True;
890    	sal_Int32 nState = xObj.is() ? xObj->getCurrentState() : embed::EmbedStates::LOADED;
891    	sal_Bool bIsActive = ( nState != embed::EmbedStates::LOADED && nState != embed::EmbedStates::RUNNING );
892 	sal_Int64 nMiscStatus = xObj->getStatus( nAspect );
893 
894    	if( nState != embed::EmbedStates::LOADED && !pDoc->IsInDtor() && !bIsActive &&
895 		embed::EmbedMisc::MS_EMBED_ALWAYSRUN != ( nMiscStatus & embed::EmbedMisc::MS_EMBED_ALWAYSRUN ) &&
896 		embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY != ( nMiscStatus & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) )
897 	{
898         SfxObjectShell* p = pDoc->GetPersist();
899 		if( p )
900 		{
901 			if( pDoc->get(IDocumentSettingAccess::PURGE_OLE) )
902 			{
903                 try
904                 {
905                     uno::Reference < util::XModifiable > xMod( xObj->getComponent(), uno::UNO_QUERY );
906                     if( xMod.is() && xMod->isModified() )
907                     {
908                         uno::Reference < embed::XEmbedPersist > xPers( xObj, uno::UNO_QUERY );
909                         if ( xPers.is() )
910                             xPers->storeOwn();
911                         else {
912                             DBG_ERROR("Modified object without persistance in cache!");
913                         }
914                     }
915 
916                     // setting object to loaded state will remove it from cache
917                     xObj->changeState( embed::EmbedStates::LOADED );
918                 }
919                 catch ( uno::Exception& )
920                 {
921                     bRet = sal_False;
922                 }
923 			}
924 			else
925 				bRet = sal_False;
926 		}
927 	}
928 
929 	return bRet;
930 }
931 
932 String SwOLEObj::GetDescription()
933 {
934     String aResult;
935 	uno::Reference< embed::XEmbeddedObject > xEmbObj = GetOleRef();
936     if ( xEmbObj.is() )
937     {
938 		SvGlobalName aClassID( xEmbObj->getClassID() );
939         if ( SotExchange::IsMath( aClassID ) )
940             aResult = SW_RES(STR_MATH_FORMULA);
941         else if ( SotExchange::IsChart( aClassID ) )
942             aResult = SW_RES(STR_CHART);
943         else
944             aResult = SW_RES(STR_OLE);
945     }
946 
947     return aResult;
948 }
949 
950 
951 SwOLELRUCache::SwOLELRUCache()
952 	: SvPtrarr( 64, 16 ),
953 	utl::ConfigItem( OUString::createFromAscii( "Office.Common/Cache" )),
954     nLRU_InitSize( 20 ),
955     bInUnload( sal_False )
956 {
957 	EnableNotification( GetPropertyNames() );
958 	Load();
959 }
960 
961 uno::Sequence< rtl::OUString > SwOLELRUCache::GetPropertyNames()
962 {
963 	Sequence< OUString > aNames( 1 );
964 	OUString* pNames = aNames.getArray();
965 	pNames[0] = OUString::createFromAscii( "Writer/OLE_Objects" );
966 	return aNames;
967 }
968 
969 void SwOLELRUCache::Notify( const uno::Sequence< rtl::OUString>&  )
970 {
971 	Load();
972 }
973 
974 void SwOLELRUCache::Commit()
975 {
976 }
977 
978 void SwOLELRUCache::Load()
979 {
980 	Sequence< OUString > aNames( GetPropertyNames() );
981 	Sequence< Any > aValues = GetProperties( aNames );
982 	const Any* pValues = aValues.getConstArray();
983 	DBG_ASSERT( aValues.getLength() == aNames.getLength(), "GetProperties failed" );
984     if( aValues.getLength() == aNames.getLength() && pValues->hasValue() )
985 	{
986 		sal_Int32 nVal = 0;
987 		*pValues >>= nVal;
988         //if( 20 > nVal )
989         //    nVal = 20;
990 
991 		{
992             if( nVal < nLRU_InitSize )
993 			{
994                 // size of cache has been changed
995                 sal_uInt16 nCount = SvPtrarr::Count();
996                 sal_uInt16 nPos = nCount;
997 
998                 // try to remove the last entries until new maximum size is reached
999                 while( nCount > nVal )
1000 				{
1001 					SwOLEObj* pObj = (SwOLEObj*) SvPtrarr::GetObject( --nPos );
1002                     if ( pObj->UnloadObject() )
1003                         nCount--;
1004                     if ( !nPos )
1005                         break;
1006 				}
1007 			}
1008 		}
1009 
1010 		nLRU_InitSize = (sal_uInt16)nVal;
1011 	}
1012 }
1013 
1014 void SwOLELRUCache::InsertObj( SwOLEObj& rObj )
1015 {
1016     SwOLEObj* pObj = &rObj;
1017     sal_uInt16 nPos = SvPtrarr::GetPos( pObj );
1018     if( nPos )
1019     {
1020         // object is currently not the first in cache
1021         if( USHRT_MAX != nPos )
1022             SvPtrarr::Remove( nPos );
1023 
1024         SvPtrarr::Insert( pObj, 0 );
1025 
1026         // try to remove objects if necessary (of course not the freshly inserted one at nPos=0)
1027         sal_uInt16 nCount = SvPtrarr::Count();
1028         nPos = nCount-1;
1029         while( nPos && nCount > nLRU_InitSize )
1030         {
1031             pObj = (SwOLEObj*) SvPtrarr::GetObject( nPos-- );
1032             if ( pObj->UnloadObject() )
1033                 nCount--;
1034         }
1035     }
1036 }
1037 
1038 void SwOLELRUCache::RemoveObj( SwOLEObj& rObj )
1039 {
1040     sal_uInt16 nPos = SvPtrarr::GetPos( &rObj );
1041     if ( nPos != 0xFFFF )
1042         SvPtrarr::Remove( nPos );
1043     if( !Count() )
1044         DELETEZ( pOLELRU_Cache );
1045 }
1046 
1047