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