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