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