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