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