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