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 :
21 : #include <svtools/embedhlp.hxx>
22 : #include <vcl/graphicfilter.hxx>
23 : #include <svtools/svtools.hrc>
24 : #include <svtools/svtresid.hxx>
25 :
26 : #include <comphelper/embeddedobjectcontainer.hxx>
27 : #include <comphelper/seqstream.hxx>
28 : #include <toolkit/helper/vclunohelper.hxx>
29 : #include <unotools/ucbstreamhelper.hxx>
30 : #include <unotools/streamwrap.hxx>
31 : #include <com/sun/star/chart2/XChartDocument.hpp>
32 : #include <com/sun/star/chart2/XCoordinateSystem.hpp>
33 : #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
34 : #include <com/sun/star/chart2/XDiagram.hpp>
35 : #include <com/sun/star/chart2/XChartTypeContainer.hpp>
36 : #include <com/sun/star/chart2/XChartType.hpp>
37 : #include <tools/globname.hxx>
38 : #include <comphelper/classids.hxx>
39 : #include <com/sun/star/util/XModifyListener.hpp>
40 : #include <com/sun/star/util/XModifiable.hpp>
41 : #include <com/sun/star/embed/Aspects.hpp>
42 : #include <com/sun/star/embed/EmbedMisc.hpp>
43 : #include <com/sun/star/embed/EmbedStates.hpp>
44 : #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
45 : #include <com/sun/star/embed/XEmbeddedObject.hpp>
46 : #include <com/sun/star/embed/XStateChangeListener.hpp>
47 : #include <com/sun/star/datatransfer/XTransferable.hpp>
48 : #include <com/sun/star/chart2/XDefaultSizeTransmitter.hpp>
49 : #include <cppuhelper/implbase4.hxx>
50 : #include <vcl/svapp.hxx>
51 : #include <osl/mutex.hxx>
52 : #include <boost/scoped_ptr.hpp>
53 :
54 : using namespace com::sun::star;
55 :
56 : namespace svt {
57 :
58 4648 : class EmbedEventListener_Impl : public ::cppu::WeakImplHelper4 < embed::XStateChangeListener,
59 : document::XEventListener,
60 : util::XModifyListener,
61 : util::XCloseListener >
62 : {
63 : public:
64 : EmbeddedObjectRef* pObject;
65 : sal_Int32 nState;
66 :
67 2354 : EmbedEventListener_Impl( EmbeddedObjectRef* p ) :
68 : pObject(p)
69 2354 : , nState(-1)
70 2354 : {}
71 :
72 : static EmbedEventListener_Impl* Create( EmbeddedObjectRef* );
73 :
74 : virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState )
75 : throw (embed::WrongStateException, uno::RuntimeException, std::exception) SAL_OVERRIDE;
76 : virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState )
77 : throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
78 : virtual void SAL_CALL queryClosing( const lang::EventObject& Source, sal_Bool GetsOwnership )
79 : throw (util::CloseVetoException, uno::RuntimeException, std::exception) SAL_OVERRIDE;
80 : virtual void SAL_CALL notifyClosing( const lang::EventObject& Source ) throw (uno::RuntimeException, std::exception) SAL_OVERRIDE;
81 : virtual void SAL_CALL notifyEvent( const document::EventObject& aEvent ) throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
82 : virtual void SAL_CALL disposing( const lang::EventObject& aEvent ) throw( uno::RuntimeException, std::exception ) SAL_OVERRIDE;
83 : virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
84 : };
85 :
86 2354 : EmbedEventListener_Impl* EmbedEventListener_Impl::Create( EmbeddedObjectRef* p )
87 : {
88 2354 : EmbedEventListener_Impl* xRet = new EmbedEventListener_Impl( p );
89 2354 : xRet->acquire();
90 :
91 2354 : if ( p->GetObject().is() )
92 : {
93 2324 : p->GetObject()->addStateChangeListener( xRet );
94 :
95 2324 : uno::Reference < util::XCloseable > xClose( p->GetObject(), uno::UNO_QUERY );
96 : DBG_ASSERT( xClose.is(), "Object does not support XCloseable!" );
97 2324 : if ( xClose.is() )
98 2324 : xClose->addCloseListener( xRet );
99 :
100 4648 : uno::Reference < document::XEventBroadcaster > xBrd( p->GetObject(), uno::UNO_QUERY );
101 2324 : if ( xBrd.is() )
102 2324 : xBrd->addEventListener( xRet );
103 :
104 2324 : xRet->nState = p->GetObject()->getCurrentState();
105 2324 : if ( xRet->nState == embed::EmbedStates::RUNNING )
106 : {
107 2054 : uno::Reference < util::XModifiable > xMod( p->GetObject()->getComponent(), uno::UNO_QUERY );
108 2054 : if ( xMod.is() )
109 : // listen for changes in running state (update replacements in case of changes)
110 2050 : xMod->addModifyListener( xRet );
111 2324 : }
112 : }
113 :
114 2354 : return xRet;
115 : }
116 :
117 608 : void SAL_CALL EmbedEventListener_Impl::changingState( const lang::EventObject&,
118 : ::sal_Int32,
119 : ::sal_Int32 )
120 : throw ( embed::WrongStateException,
121 : uno::RuntimeException, std::exception )
122 : {
123 608 : }
124 :
125 596 : void SAL_CALL EmbedEventListener_Impl::stateChanged( const lang::EventObject&,
126 : ::sal_Int32 nOldState,
127 : ::sal_Int32 nNewState )
128 : throw ( uno::RuntimeException, std::exception )
129 : {
130 596 : SolarMutexGuard aGuard;
131 596 : nState = nNewState;
132 596 : if ( !pObject )
133 596 : return;
134 :
135 1192 : uno::Reference < util::XModifiable > xMod( pObject->GetObject()->getComponent(), uno::UNO_QUERY );
136 596 : if ( nNewState == embed::EmbedStates::RUNNING )
137 : {
138 : // TODO/LATER: container must be set before!
139 : // When is this event created? Who sets the new container when it changed?
140 238 : if( ( pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON ) && nOldState != embed::EmbedStates::LOADED && !pObject->IsChart() )
141 : // get new replacement after deactivation
142 0 : pObject->UpdateReplacement();
143 :
144 238 : if( pObject->IsChart() && nOldState == embed::EmbedStates::UI_ACTIVE )
145 : {
146 : //create a new metafile replacement when leaving the edit mode
147 : //for buggy documents where the old image looks different from the correct one
148 2 : if( xMod.is() && !xMod->isModified() )//in case of modification a new replacement will be requested anyhow
149 0 : pObject->UpdateReplacementOnDemand();
150 : }
151 :
152 238 : if ( xMod.is() && nOldState == embed::EmbedStates::LOADED )
153 : // listen for changes (update replacements in case of changes)
154 236 : xMod->addModifyListener( this );
155 : }
156 358 : else if ( nNewState == embed::EmbedStates::LOADED )
157 : {
158 : // in loaded state we can't listen
159 356 : if ( xMod.is() )
160 0 : xMod->removeModifyListener( this );
161 596 : }
162 : }
163 :
164 13631 : void SAL_CALL EmbedEventListener_Impl::modified( const lang::EventObject& ) throw (uno::RuntimeException, std::exception)
165 : {
166 13631 : SolarMutexGuard aGuard;
167 13631 : if ( pObject && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON )
168 : {
169 10988 : if ( nState == embed::EmbedStates::RUNNING )
170 : {
171 : // updates only necessary in non-active states
172 10966 : if( pObject->IsChart() )
173 1236 : pObject->UpdateReplacementOnDemand();
174 : else
175 9730 : pObject->UpdateReplacement();
176 : }
177 44 : else if ( nState == embed::EmbedStates::ACTIVE ||
178 22 : nState == embed::EmbedStates::UI_ACTIVE ||
179 0 : nState == embed::EmbedStates::INPLACE_ACTIVE )
180 : {
181 : // in case the object is inplace or UI active the replacement image should be updated on demand
182 22 : pObject->UpdateReplacementOnDemand();
183 : }
184 13631 : }
185 13631 : }
186 :
187 18554 : void SAL_CALL EmbedEventListener_Impl::notifyEvent( const document::EventObject& aEvent ) throw( uno::RuntimeException, std::exception )
188 : {
189 18554 : SolarMutexGuard aGuard;
190 :
191 18554 : if ( pObject && aEvent.EventName == "OnVisAreaChanged" && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON && !pObject->IsChart() )
192 : {
193 8 : pObject->UpdateReplacement();
194 18554 : }
195 18554 : }
196 :
197 422 : void SAL_CALL EmbedEventListener_Impl::queryClosing( const lang::EventObject& Source, sal_Bool )
198 : throw ( util::CloseVetoException, uno::RuntimeException, std::exception)
199 : {
200 : // An embedded object can be shared between several objects (f.e. for undo purposes)
201 : // the object will not be closed before the last "customer" is destroyed
202 : // Now the EmbeddedObjectRef helper class works like a "lock" on the object
203 422 : if ( pObject && pObject->IsLocked() && Source.Source == pObject->GetObject() )
204 422 : throw util::CloseVetoException();
205 0 : }
206 :
207 0 : void SAL_CALL EmbedEventListener_Impl::notifyClosing( const lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException, std::exception)
208 : {
209 0 : if ( pObject && Source.Source == pObject->GetObject() )
210 : {
211 0 : pObject->Clear();
212 0 : pObject = 0;
213 : }
214 0 : }
215 :
216 2286 : void SAL_CALL EmbedEventListener_Impl::disposing( const lang::EventObject& aEvent ) throw( uno::RuntimeException, std::exception )
217 : {
218 2286 : if ( pObject && aEvent.Source == pObject->GetObject() )
219 : {
220 0 : pObject->Clear();
221 0 : pObject = 0;
222 : }
223 2286 : }
224 :
225 : struct EmbeddedObjectRef_Impl
226 : {
227 : uno::Reference <embed::XEmbeddedObject> mxObj;
228 :
229 : EmbedEventListener_Impl* xListener;
230 : OUString aPersistName;
231 : OUString aMediaType;
232 : comphelper::EmbeddedObjectContainer* pContainer;
233 : Graphic* pGraphic;
234 : sal_Int64 nViewAspect;
235 : bool bIsLocked:1;
236 : bool bNeedUpdate:1;
237 :
238 : // #i104867#
239 : sal_uInt32 mnGraphicVersion;
240 : awt::Size aDefaultSizeForChart_In_100TH_MM;//#i103460# charts do not necessaryly have an own size within ODF files, in this case they need to use the size settings from the surrounding frame, which is made available with this member
241 :
242 1462 : EmbeddedObjectRef_Impl() :
243 : xListener(0),
244 : pContainer(NULL),
245 : pGraphic(NULL),
246 : nViewAspect(embed::Aspects::MSOLE_CONTENT),
247 : bIsLocked(false),
248 : bNeedUpdate(false),
249 : mnGraphicVersion(0),
250 1462 : aDefaultSizeForChart_In_100TH_MM(awt::Size(8000,7000))
251 1462 : {}
252 :
253 872 : EmbeddedObjectRef_Impl( const EmbeddedObjectRef_Impl& r ) :
254 : mxObj(r.mxObj),
255 : xListener(0),
256 : aPersistName(r.aPersistName),
257 : aMediaType(r.aMediaType),
258 : pContainer(r.pContainer),
259 : pGraphic(NULL),
260 : nViewAspect(r.nViewAspect),
261 : bIsLocked(r.bIsLocked),
262 : bNeedUpdate(r.bNeedUpdate),
263 : mnGraphicVersion(0),
264 872 : aDefaultSizeForChart_In_100TH_MM(r.aDefaultSizeForChart_In_100TH_MM)
265 : {
266 872 : if (r.pGraphic && !r.bNeedUpdate)
267 572 : pGraphic = new Graphic(*r.pGraphic);
268 872 : }
269 :
270 2334 : ~EmbeddedObjectRef_Impl()
271 2334 : {
272 2334 : delete pGraphic;
273 2334 : }
274 : };
275 :
276 18612 : const uno::Reference <embed::XEmbeddedObject>& EmbeddedObjectRef::operator->() const
277 : {
278 18612 : return mpImpl->mxObj;
279 : }
280 :
281 39481 : const uno::Reference <embed::XEmbeddedObject>& EmbeddedObjectRef::GetObject() const
282 : {
283 39481 : return mpImpl->mxObj;
284 : }
285 :
286 1214 : EmbeddedObjectRef::EmbeddedObjectRef() : mpImpl(new EmbeddedObjectRef_Impl) {}
287 :
288 248 : EmbeddedObjectRef::EmbeddedObjectRef( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Int64 nAspect ) :
289 248 : mpImpl(new EmbeddedObjectRef_Impl)
290 : {
291 248 : mpImpl->nViewAspect = nAspect;
292 248 : mpImpl->mxObj = xObj;
293 248 : mpImpl->xListener = EmbedEventListener_Impl::Create( this );
294 248 : }
295 :
296 872 : EmbeddedObjectRef::EmbeddedObjectRef( const EmbeddedObjectRef& rObj ) :
297 872 : mpImpl(new EmbeddedObjectRef_Impl(*rObj.mpImpl))
298 : {
299 872 : mpImpl->xListener = EmbedEventListener_Impl::Create( this );
300 872 : }
301 :
302 2334 : EmbeddedObjectRef::~EmbeddedObjectRef()
303 : {
304 2334 : Clear();
305 2334 : delete mpImpl;
306 2334 : }
307 :
308 1234 : void EmbeddedObjectRef::Assign( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Int64 nAspect )
309 : {
310 : DBG_ASSERT(!mpImpl->mxObj.is(), "Never assign an already assigned object!");
311 :
312 1234 : Clear();
313 1234 : mpImpl->nViewAspect = nAspect;
314 1234 : mpImpl->mxObj = xObj;
315 1234 : mpImpl->xListener = EmbedEventListener_Impl::Create( this );
316 :
317 : //#i103460#
318 1234 : if ( IsChart() )
319 : {
320 478 : uno::Reference < chart2::XDefaultSizeTransmitter > xSizeTransmitter( xObj, uno::UNO_QUERY );
321 : DBG_ASSERT( xSizeTransmitter.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
322 478 : if( xSizeTransmitter.is() )
323 478 : xSizeTransmitter->setDefaultSize( mpImpl->aDefaultSizeForChart_In_100TH_MM );
324 : }
325 1234 : }
326 :
327 4514 : void EmbeddedObjectRef::Clear()
328 : {
329 4514 : if (mpImpl->mxObj.is() && mpImpl->xListener)
330 : {
331 2324 : mpImpl->mxObj->removeStateChangeListener(mpImpl->xListener);
332 :
333 2324 : uno::Reference<util::XCloseable> xClose(mpImpl->mxObj, uno::UNO_QUERY);
334 2324 : if ( xClose.is() )
335 2324 : xClose->removeCloseListener( mpImpl->xListener );
336 :
337 4648 : uno::Reference<document::XEventBroadcaster> xBrd(mpImpl->mxObj, uno::UNO_QUERY);
338 2324 : if ( xBrd.is() )
339 2324 : xBrd->removeEventListener( mpImpl->xListener );
340 :
341 2324 : if ( mpImpl->bIsLocked )
342 : {
343 1146 : if ( xClose.is() )
344 : {
345 : try
346 : {
347 1146 : mpImpl->mxObj->changeState(embed::EmbedStates::LOADED);
348 1146 : xClose->close( true );
349 : }
350 172 : catch (const util::CloseVetoException&)
351 : {
352 : // there's still someone who needs the object!
353 : }
354 0 : catch (const uno::Exception&)
355 : {
356 : OSL_FAIL( "Error on switching of the object to loaded state and closing!\n" );
357 : }
358 : }
359 : }
360 :
361 2324 : if ( mpImpl->xListener )
362 : {
363 2324 : mpImpl->xListener->pObject = 0;
364 2324 : mpImpl->xListener->release();
365 2324 : mpImpl->xListener = 0;
366 : }
367 :
368 2324 : mpImpl->mxObj = NULL;
369 4648 : mpImpl->bNeedUpdate = false;
370 : }
371 :
372 4514 : mpImpl->pContainer = 0;
373 4514 : mpImpl->bIsLocked = false;
374 4514 : mpImpl->bNeedUpdate = false;
375 4514 : }
376 :
377 25522 : bool EmbeddedObjectRef::is() const
378 : {
379 25522 : return mpImpl->mxObj.is();
380 : }
381 :
382 1804 : void EmbeddedObjectRef::AssignToContainer( comphelper::EmbeddedObjectContainer* pContainer, const OUString& rPersistName )
383 : {
384 1804 : mpImpl->pContainer = pContainer;
385 1804 : mpImpl->aPersistName = rPersistName;
386 :
387 1804 : if ( mpImpl->pGraphic && !mpImpl->bNeedUpdate && pContainer )
388 562 : SetGraphicToContainer( *mpImpl->pGraphic, *pContainer, mpImpl->aPersistName, OUString() );
389 1804 : }
390 :
391 10266 : comphelper::EmbeddedObjectContainer* EmbeddedObjectRef::GetContainer() const
392 : {
393 10266 : return mpImpl->pContainer;
394 : }
395 :
396 20165 : sal_Int64 EmbeddedObjectRef::GetViewAspect() const
397 : {
398 20165 : return mpImpl->nViewAspect;
399 : }
400 :
401 340 : void EmbeddedObjectRef::SetViewAspect( sal_Int64 nAspect )
402 : {
403 340 : mpImpl->nViewAspect = nAspect;
404 340 : }
405 :
406 1872 : void EmbeddedObjectRef::Lock( bool bLock )
407 : {
408 1872 : mpImpl->bIsLocked = bLock;
409 1872 : }
410 :
411 422 : bool EmbeddedObjectRef::IsLocked() const
412 : {
413 422 : return mpImpl->bIsLocked;
414 : }
415 :
416 9750 : void EmbeddedObjectRef::GetReplacement( bool bUpdate )
417 : {
418 9750 : if ( bUpdate )
419 : {
420 9738 : DELETEZ( mpImpl->pGraphic );
421 9738 : mpImpl->aMediaType = OUString();
422 9738 : mpImpl->pGraphic = new Graphic;
423 9738 : mpImpl->mnGraphicVersion++;
424 : }
425 12 : else if ( !mpImpl->pGraphic )
426 : {
427 12 : mpImpl->pGraphic = new Graphic;
428 12 : mpImpl->mnGraphicVersion++;
429 : }
430 : else
431 : {
432 : OSL_FAIL("No update, but replacement exists already!");
433 9750 : return;
434 : }
435 :
436 9750 : boost::scoped_ptr<SvStream> pGraphicStream(GetGraphicStream( bUpdate ));
437 9750 : if ( pGraphicStream )
438 : {
439 9750 : GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
440 9750 : if( mpImpl->pGraphic )
441 9750 : rGF.ImportGraphic( *mpImpl->pGraphic, OUString(), *pGraphicStream, GRFILTER_FORMAT_DONTKNOW );
442 9750 : mpImpl->mnGraphicVersion++;
443 9750 : }
444 : }
445 :
446 174 : const Graphic* EmbeddedObjectRef::GetGraphic( OUString* pMediaType ) const
447 : {
448 : try
449 : {
450 174 : if ( mpImpl->bNeedUpdate )
451 : // bNeedUpdate will be set to false while retrieving new replacement
452 0 : const_cast < EmbeddedObjectRef* >(this)->GetReplacement(true);
453 174 : else if ( !mpImpl->pGraphic )
454 12 : const_cast < EmbeddedObjectRef* >(this)->GetReplacement(false);
455 : }
456 0 : catch( const uno::Exception& ex )
457 : {
458 : SAL_WARN("svtools.misc", "Something went wrong on getting the graphic: " << ex.Message);
459 : }
460 :
461 174 : if ( mpImpl->pGraphic && pMediaType )
462 0 : *pMediaType = mpImpl->aMediaType;
463 174 : return mpImpl->pGraphic;
464 : }
465 :
466 650 : Size EmbeddedObjectRef::GetSize( MapMode* pTargetMapMode ) const
467 : {
468 650 : MapMode aSourceMapMode( MAP_100TH_MM );
469 650 : Size aResult;
470 :
471 650 : if ( mpImpl->nViewAspect == embed::Aspects::MSOLE_ICON )
472 : {
473 0 : const Graphic* pGraphic = GetGraphic();
474 0 : if ( pGraphic )
475 : {
476 0 : aSourceMapMode = pGraphic->GetPrefMapMode();
477 0 : aResult = pGraphic->GetPrefSize();
478 : }
479 : else
480 0 : aResult = Size( 2500, 2500 );
481 : }
482 : else
483 : {
484 650 : awt::Size aSize;
485 :
486 650 : if (mpImpl->mxObj.is())
487 : {
488 : try
489 : {
490 650 : aSize = mpImpl->mxObj->getVisualAreaSize(mpImpl->nViewAspect);
491 : }
492 40 : catch(const embed::NoVisualAreaSizeException&)
493 : {
494 : }
495 2 : catch(const uno::Exception&)
496 : {
497 : OSL_FAIL( "Something went wrong on getting of the size of the object!" );
498 : }
499 :
500 : try
501 : {
502 650 : aSourceMapMode = VCLUnoHelper::UnoEmbed2VCLMapUnit(mpImpl->mxObj->getMapUnit(mpImpl->nViewAspect));
503 : }
504 2 : catch(const uno::Exception&)
505 : {
506 : OSL_FAIL( "Can not get the map mode!" );
507 : }
508 : }
509 :
510 650 : if ( !aSize.Height && !aSize.Width )
511 : {
512 216 : aSize.Width = 5000;
513 216 : aSize.Height = 5000;
514 : }
515 :
516 650 : aResult = Size( aSize.Width, aSize.Height );
517 : }
518 :
519 650 : if ( pTargetMapMode )
520 650 : aResult = OutputDevice::LogicToLogic( aResult, aSourceMapMode, *pTargetMapMode );
521 :
522 650 : return aResult;
523 : }
524 :
525 0 : void EmbeddedObjectRef::SetGraphicStream( const uno::Reference< io::XInputStream >& xInGrStream,
526 : const OUString& rMediaType )
527 : {
528 0 : if ( mpImpl->pGraphic )
529 0 : delete mpImpl->pGraphic;
530 0 : mpImpl->pGraphic = new Graphic();
531 0 : mpImpl->aMediaType = rMediaType;
532 0 : mpImpl->mnGraphicVersion++;
533 :
534 0 : boost::scoped_ptr<SvStream> pGraphicStream(::utl::UcbStreamHelper::CreateStream( xInGrStream ));
535 :
536 0 : if ( pGraphicStream )
537 : {
538 0 : GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
539 0 : rGF.ImportGraphic( *mpImpl->pGraphic, "", *pGraphicStream, GRFILTER_FORMAT_DONTKNOW );
540 0 : mpImpl->mnGraphicVersion++;
541 :
542 0 : if ( mpImpl->pContainer )
543 : {
544 0 : pGraphicStream->Seek( 0 );
545 0 : uno::Reference< io::XInputStream > xInSeekGrStream = new ::utl::OSeekableInputStreamWrapper( pGraphicStream.get() );
546 :
547 0 : mpImpl->pContainer->InsertGraphicStream( xInSeekGrStream, mpImpl->aPersistName, rMediaType );
548 : }
549 : }
550 :
551 0 : mpImpl->bNeedUpdate = false;
552 :
553 0 : }
554 :
555 146 : void EmbeddedObjectRef::SetGraphic( const Graphic& rGraphic, const OUString& rMediaType )
556 : {
557 146 : if ( mpImpl->pGraphic )
558 6 : delete mpImpl->pGraphic;
559 146 : mpImpl->pGraphic = new Graphic( rGraphic );
560 146 : mpImpl->aMediaType = rMediaType;
561 146 : mpImpl->mnGraphicVersion++;
562 :
563 146 : if ( mpImpl->pContainer )
564 104 : SetGraphicToContainer( rGraphic, *mpImpl->pContainer, mpImpl->aPersistName, rMediaType );
565 :
566 146 : mpImpl->bNeedUpdate = false;
567 146 : }
568 :
569 9750 : SvStream* EmbeddedObjectRef::GetGraphicStream( bool bUpdate ) const
570 : {
571 : DBG_ASSERT( bUpdate || mpImpl->pContainer, "Can't retrieve current graphic!" );
572 9750 : uno::Reference < io::XInputStream > xStream;
573 9750 : if ( mpImpl->pContainer && !bUpdate )
574 : {
575 : SAL_INFO( "svtools.misc", "getting stream from container" );
576 : // try to get graphic stream from container storage
577 12 : xStream = mpImpl->pContainer->GetGraphicStream(mpImpl->mxObj, &mpImpl->aMediaType);
578 12 : if ( xStream.is() )
579 : {
580 12 : const sal_Int32 nConstBufferSize = 32000;
581 12 : SvStream *pStream = new SvMemoryStream( 32000, 32000 );
582 : try
583 : {
584 12 : sal_Int32 nRead=0;
585 12 : uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
586 12 : do
587 : {
588 12 : nRead = xStream->readBytes ( aSequence, nConstBufferSize );
589 12 : pStream->Write( aSequence.getConstArray(), nRead );
590 : }
591 : while ( nRead == nConstBufferSize );
592 12 : pStream->Seek(0);
593 12 : return pStream;
594 : }
595 0 : catch (const uno::Exception& ex)
596 : {
597 : SAL_WARN("svtools.misc", "discarding broken embedded object preview: " << ex.Message);
598 0 : delete pStream;
599 0 : xStream.clear();
600 : }
601 : }
602 : }
603 :
604 9738 : if ( !xStream.is() )
605 : {
606 : SAL_INFO( "svtools.misc", "getting stream from object" );
607 9738 : bool bUserAllowsLinkUpdate(true);
608 9738 : const comphelper::EmbeddedObjectContainer* pContainer = GetContainer();
609 :
610 9738 : if(pContainer)
611 : {
612 1568 : bUserAllowsLinkUpdate = pContainer->getUserAllowsLinkUpdate();
613 : }
614 :
615 9738 : if(bUserAllowsLinkUpdate)
616 : {
617 : // update wanted or no stream in container storage available
618 9738 : xStream = GetGraphicReplacementStream(mpImpl->nViewAspect, mpImpl->mxObj, &mpImpl->aMediaType);
619 :
620 9738 : if(xStream.is())
621 : {
622 9738 : if (mpImpl->pContainer)
623 1568 : mpImpl->pContainer->InsertGraphicStream(xStream,mpImpl->aPersistName,mpImpl->aMediaType);
624 :
625 9738 : SvStream* pResult = ::utl::UcbStreamHelper::CreateStream( xStream );
626 9738 : if (pResult && bUpdate)
627 9738 : mpImpl->bNeedUpdate = false;
628 :
629 9738 : return pResult;
630 : }
631 : }
632 : }
633 :
634 0 : return NULL;
635 : }
636 :
637 0 : void EmbeddedObjectRef::DrawPaintReplacement( const Rectangle &rRect, const OUString &rText, OutputDevice *pOut )
638 : {
639 0 : MapMode aMM( MAP_APPFONT );
640 0 : Size aAppFontSz = pOut->LogicToLogic( Size( 0, 8 ), &aMM, NULL );
641 0 : vcl::Font aFnt( OUString("Helvetica"), aAppFontSz );
642 0 : aFnt.SetTransparent( true );
643 0 : aFnt.SetColor( Color( COL_LIGHTRED ) );
644 0 : aFnt.SetWeight( WEIGHT_BOLD );
645 0 : aFnt.SetFamily( FAMILY_SWISS );
646 :
647 0 : pOut->Push();
648 0 : pOut->SetBackground();
649 0 : pOut->SetFont( aFnt );
650 :
651 0 : Point aPt;
652 :
653 : // Now scale text such that it fits in the rectangle
654 : // We start with the default size and decrease 1-AppFont
655 0 : for( sal_uInt16 i = 8; i > 2; i-- )
656 : {
657 0 : aPt.X() = (rRect.GetWidth() - pOut->GetTextWidth( rText )) / 2;
658 0 : aPt.Y() = (rRect.GetHeight() - pOut->GetTextHeight()) / 2;
659 :
660 0 : bool bTiny = false;
661 0 : if( aPt.X() < 0 ) bTiny = true, aPt.X() = 0;
662 0 : if( aPt.Y() < 0 ) bTiny = true, aPt.Y() = 0;
663 0 : if( bTiny )
664 : {
665 : // decrease for small images
666 0 : aFnt.SetSize( Size( 0, aAppFontSz.Height() * i / 8 ) );
667 0 : pOut->SetFont( aFnt );
668 : }
669 : else
670 0 : break;
671 : }
672 :
673 0 : Bitmap aBmp( SvtResId( BMP_PLUGIN ) );
674 0 : long nHeight = rRect.GetHeight() - pOut->GetTextHeight();
675 0 : long nWidth = rRect.GetWidth();
676 0 : if(nHeight > 0 && nWidth > 0 && aBmp.GetSizePixel().Width() > 0)
677 : {
678 0 : aPt.Y() = nHeight;
679 0 : Point aP = rRect.TopLeft();
680 0 : Size aBmpSize = aBmp.GetSizePixel();
681 : // fit bitmap in
682 0 : if( nHeight * 10 / nWidth
683 0 : > aBmpSize.Height() * 10 / aBmpSize.Width() )
684 : {
685 : // adjust to the width
686 : // keep proportions
687 0 : long nH = nWidth * aBmpSize.Height() / aBmpSize.Width();
688 : // center
689 0 : aP.Y() += (nHeight - nH) / 2;
690 0 : nHeight = nH;
691 : }
692 : else
693 : {
694 : // adjust to the height
695 : // keep proportions
696 0 : long nW = nHeight * aBmpSize.Width() / aBmpSize.Height();
697 : // center
698 0 : aP.X() += (nWidth - nW) / 2;
699 0 : nWidth = nW;
700 : }
701 :
702 0 : pOut->DrawBitmap( aP, Size( nWidth, nHeight ), aBmp );
703 : }
704 :
705 0 : pOut->IntersectClipRegion( rRect );
706 0 : aPt += rRect.TopLeft();
707 0 : pOut->DrawText( aPt, rText );
708 0 : pOut->Pop();
709 0 : }
710 :
711 0 : void EmbeddedObjectRef::DrawShading( const Rectangle &rRect, OutputDevice *pOut )
712 : {
713 0 : GDIMetaFile * pMtf = pOut->GetConnectMetaFile();
714 0 : if( pMtf && pMtf->IsRecord() )
715 0 : return;
716 :
717 0 : pOut->Push();
718 0 : pOut->SetLineColor( Color( COL_BLACK ) );
719 :
720 0 : Size aPixSize = pOut->LogicToPixel( rRect.GetSize() );
721 0 : aPixSize.Width() -= 1;
722 0 : aPixSize.Height() -= 1;
723 0 : Point aPixViewPos = pOut->LogicToPixel( rRect.TopLeft() );
724 0 : sal_Int32 nMax = aPixSize.Width() + aPixSize.Height();
725 0 : for( sal_Int32 i = 5; i < nMax; i += 5 )
726 : {
727 0 : Point a1( aPixViewPos ), a2( aPixViewPos );
728 0 : if( i > aPixSize.Width() )
729 0 : a1 += Point( aPixSize.Width(), i - aPixSize.Width() );
730 : else
731 0 : a1 += Point( i, 0 );
732 0 : if( i > aPixSize.Height() )
733 0 : a2 += Point( i - aPixSize.Height(), aPixSize.Height() );
734 : else
735 0 : a2 += Point( 0, i );
736 :
737 0 : pOut->DrawLine( pOut->PixelToLogic( a1 ), pOut->PixelToLogic( a2 ) );
738 : }
739 :
740 0 : pOut->Pop();
741 :
742 : }
743 :
744 2429 : bool EmbeddedObjectRef::TryRunningState( const uno::Reference < embed::XEmbeddedObject >& xEmbObj )
745 : {
746 2429 : if ( !xEmbObj.is() )
747 0 : return false;
748 :
749 : try
750 : {
751 2429 : if ( xEmbObj->getCurrentState() == embed::EmbedStates::LOADED )
752 106 : xEmbObj->changeState( embed::EmbedStates::RUNNING );
753 : }
754 60 : catch (const uno::Exception&)
755 : {
756 30 : return false;
757 : }
758 :
759 2399 : return true;
760 : }
761 :
762 696 : void EmbeddedObjectRef::SetGraphicToContainer( const Graphic& rGraphic,
763 : comphelper::EmbeddedObjectContainer& aContainer,
764 : const OUString& aName,
765 : const OUString& aMediaType )
766 : {
767 696 : SvMemoryStream aStream;
768 696 : aStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
769 696 : if ( rGraphic.ExportNative( aStream ) )
770 : {
771 696 : aStream.Seek( 0 );
772 :
773 696 : uno::Reference < io::XInputStream > xStream = new ::utl::OSeekableInputStreamWrapper( aStream );
774 696 : aContainer.InsertGraphicStream( xStream, aName, aMediaType );
775 : }
776 : else
777 696 : OSL_FAIL( "Export of graphic is failed!\n" );
778 696 : }
779 :
780 9738 : uno::Reference< io::XInputStream > EmbeddedObjectRef::GetGraphicReplacementStream(
781 : sal_Int64 nViewAspect,
782 : const uno::Reference< embed::XEmbeddedObject >& xObj,
783 : OUString* pMediaType )
784 : throw()
785 : {
786 9738 : return ::comphelper::EmbeddedObjectContainer::GetGraphicReplacementStream(nViewAspect,xObj,pMediaType);
787 : }
788 :
789 14335 : bool EmbeddedObjectRef::IsChart(const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj)
790 : {
791 14335 : SvGlobalName aObjClsId(xObj->getClassID());
792 28670 : if(
793 57340 : SvGlobalName(SO3_SCH_CLASSID_30) == aObjClsId
794 28670 : || SvGlobalName(SO3_SCH_CLASSID_40) == aObjClsId
795 28670 : || SvGlobalName(SO3_SCH_CLASSID_50) == aObjClsId
796 71675 : || SvGlobalName(SO3_SCH_CLASSID_60) == aObjClsId)
797 : {
798 3719 : return true;
799 : }
800 :
801 10616 : return false;
802 : }
803 :
804 237 : bool EmbeddedObjectRef::IsGLChart(const ::com::sun::star::uno::Reference < ::com::sun::star::embed::XEmbeddedObject >& xObj)
805 : {
806 237 : static const char* env = getenv("CHART_DUMMY_FACTORY");
807 237 : if (IsChart(xObj))
808 : {
809 203 : if (env)
810 0 : return true;
811 :
812 203 : uno::Reference< chart2::XChartDocument > xChartDoc(xObj->getComponent(), uno::UNO_QUERY);
813 203 : if (!xChartDoc.is())
814 0 : return false;
815 :
816 203 : return xChartDoc->isOpenGLChart();
817 : }
818 34 : return false;
819 : }
820 :
821 9738 : void EmbeddedObjectRef::UpdateReplacement()
822 : {
823 9738 : GetReplacement( true );
824 9738 : }
825 :
826 1258 : void EmbeddedObjectRef::UpdateReplacementOnDemand()
827 : {
828 1258 : DELETEZ( mpImpl->pGraphic );
829 1258 : mpImpl->bNeedUpdate = true;
830 1258 : mpImpl->mnGraphicVersion++;
831 :
832 1258 : if( mpImpl->pContainer )
833 : {
834 : //remove graphic from container thus a new up to date one is requested on save
835 1098 : mpImpl->pContainer->RemoveGraphicStream( mpImpl->aPersistName );
836 : }
837 1258 : }
838 :
839 14336 : bool EmbeddedObjectRef::IsChart() const
840 : {
841 : //todo maybe for 3.0:
842 : //if the changes work good for chart
843 : //we should apply them for all own ole objects
844 :
845 : //#i83708# #i81857# #i79578# request an ole replacement image only if really necessary
846 : //as this call can be very expensive and does block the user interface as long at it takes
847 :
848 14336 : if (!mpImpl->mxObj.is())
849 238 : return false;
850 :
851 14098 : return EmbeddedObjectRef::IsChart(mpImpl->mxObj);
852 : }
853 :
854 229 : bool EmbeddedObjectRef::IsGLChart() const
855 : {
856 229 : if (!mpImpl->mxObj.is())
857 0 : return false;
858 :
859 229 : return EmbeddedObjectRef::IsGLChart(mpImpl->mxObj);
860 : }
861 :
862 : // MT: Only used for getting accessible attributes, which are not localized
863 0 : OUString EmbeddedObjectRef::GetChartType()
864 : {
865 0 : OUString Style;
866 0 : if ( mpImpl->mxObj.is() )
867 : {
868 0 : if ( IsChart() )
869 : {
870 0 : if ( svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObj ) )
871 : {
872 0 : uno::Reference< chart2::XChartDocument > xChart( mpImpl->mxObj->getComponent(), uno::UNO_QUERY );
873 0 : if (xChart.is())
874 : {
875 0 : uno::Reference< chart2::XDiagram > xDiagram( xChart->getFirstDiagram());
876 0 : if( ! xDiagram.is())
877 0 : return OUString();
878 0 : uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
879 0 : uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
880 : // IA2 CWS. Unused: int nCoordinateCount = aCooSysSeq.getLength();
881 0 : bool bGetChartType = false;
882 0 : for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
883 : {
884 0 : uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
885 0 : uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes());
886 0 : int nDimesionCount = aCooSysSeq[nCooSysIdx]->getDimension();
887 0 : if( nDimesionCount == 3 )
888 0 : Style += "3D ";
889 : else
890 0 : Style += "2D ";
891 0 : for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx )
892 : {
893 0 : OUString strChartType = aChartTypes[nCTIdx]->getChartType();
894 0 : if (strChartType == "com.sun.star.chart2.AreaChartType")
895 : {
896 0 : Style += "Areas";
897 0 : bGetChartType = true;
898 : }
899 0 : else if (strChartType == "com.sun.star.chart2.BarChartType")
900 : {
901 0 : Style += "Bars";
902 0 : bGetChartType = true;
903 : }
904 0 : else if (strChartType == "com.sun.star.chart2.ColumnChartType")
905 : {
906 0 : uno::Reference< beans::XPropertySet > xProp( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY );
907 0 : if( xProp.is())
908 : {
909 0 : bool bCurrent = false;
910 0 : if( xProp->getPropertyValue( OUString("SwapXAndYAxis") ) >>= bCurrent )
911 : {
912 0 : if (bCurrent)
913 0 : Style += "Bars";
914 : else
915 0 : Style += "Columns";
916 0 : bGetChartType = true;
917 : }
918 0 : }
919 : }
920 0 : else if (strChartType == "com.sun.star.chart2.LineChartType")
921 : {
922 0 : Style += "Lines";
923 0 : bGetChartType = true;
924 : }
925 0 : else if (strChartType == "com.sun.star.chart2.ScatterChartType")
926 : {
927 0 : Style += "XY Chart";
928 0 : bGetChartType = true;
929 : }
930 0 : else if (strChartType == "com.sun.star.chart2.PieChartType")
931 : {
932 0 : Style += "Pies";
933 0 : bGetChartType = true;
934 : }
935 0 : else if (strChartType == "com.sun.star.chart2.NetChartType")
936 : {
937 0 : Style += "Radar";
938 0 : bGetChartType = true;
939 : }
940 0 : else if (strChartType == "com.sun.star.chart2.CandleStickChartType")
941 : {
942 0 : Style += "Candle Stick Chart";
943 0 : bGetChartType = true;
944 : }
945 0 : if (bGetChartType)
946 0 : return Style;
947 0 : }
948 0 : }
949 0 : }
950 : }
951 : }
952 : }
953 0 : return Style;
954 : }
955 :
956 : // #i104867#
957 164 : sal_uInt32 EmbeddedObjectRef::getGraphicVersion() const
958 : {
959 164 : return mpImpl->mnGraphicVersion;
960 : }
961 :
962 70 : void EmbeddedObjectRef::SetDefaultSizeForChart( const Size& rSizeIn_100TH_MM )
963 : {
964 : //#i103460# charts do not necessaryly have an own size within ODF files,
965 : //for this case they need to use the size settings from the surrounding frame,
966 : //which is made available with this method
967 :
968 70 : mpImpl->aDefaultSizeForChart_In_100TH_MM = awt::Size( rSizeIn_100TH_MM.getWidth(), rSizeIn_100TH_MM.getHeight() );
969 :
970 70 : uno::Reference<chart2::XDefaultSizeTransmitter> xSizeTransmitter(mpImpl->mxObj, uno::UNO_QUERY);
971 : DBG_ASSERT( xSizeTransmitter.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
972 70 : if( xSizeTransmitter.is() )
973 70 : xSizeTransmitter->setDefaultSize( mpImpl->aDefaultSizeForChart_In_100TH_MM );
974 70 : }
975 :
976 1227 : } // namespace svt
977 :
978 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|