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