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