1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26
27 #include <svtools/embedhlp.hxx>
28 #include <svtools/filter.hxx>
29 #include <svtools/svtools.hrc>
30 #include <svtools/svtdata.hxx>
31
32 #include <comphelper/embeddedobjectcontainer.hxx>
33 #include <comphelper/seqstream.hxx>
34 #include <toolkit/helper/vclunohelper.hxx>
35 #include <unotools/ucbstreamhelper.hxx>
36 #include <unotools/streamwrap.hxx>
37 #include <com/sun/star/chart2/XChartDocument.hpp>
38 #include <com/sun/star/chart2/XCoordinateSystem.hpp>
39 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
40 #include <com/sun/star/chart2/XDiagram.hpp>
41 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
42 #include <com/sun/star/chart2/XChartType.hpp>
43 #include <tools/globname.hxx>
44 #include <sot/clsids.hxx>
45 #include <com/sun/star/util/XModifyListener.hpp>
46 #ifndef _COM_SUN_STAR_UTIL_XMODIFYiBLE_HPP_
47 #include <com/sun/star/util/XModifiable.hpp>
48 #endif
49 #include <com/sun/star/embed/EmbedStates.hpp>
50 #include <com/sun/star/embed/EmbedMisc.hpp>
51 #include <com/sun/star/embed/XStateChangeListener.hpp>
52 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
53 #include <com/sun/star/util/XModifiable.hpp>
54 #include <com/sun/star/datatransfer/XTransferable.hpp>
55 #include <com/sun/star/chart2/XDefaultSizeTransmitter.hpp>
56 #include <cppuhelper/implbase4.hxx>
57 #include "vcl/svapp.hxx"
58 #include <rtl/logfile.hxx>
59 #include <vos/mutex.hxx>
60
61 using namespace com::sun::star;
62
63 namespace svt
64 {
65
66 class EmbedEventListener_Impl : public ::cppu::WeakImplHelper4 < embed::XStateChangeListener,
67 document::XEventListener,
68 util::XModifyListener,
69 util::XCloseListener >
70 {
71 public:
72 EmbeddedObjectRef* pObject;
73 sal_Int32 nState;
74
EmbedEventListener_Impl(EmbeddedObjectRef * p)75 EmbedEventListener_Impl( EmbeddedObjectRef* p ) :
76 pObject(p)
77 , nState(-1)
78 {}
79
80 static EmbedEventListener_Impl* Create( EmbeddedObjectRef* );
81
82 virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState );
83 virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState );
84 virtual void SAL_CALL queryClosing( const lang::EventObject& Source, ::sal_Bool GetsOwnership );
85 virtual void SAL_CALL notifyClosing( const lang::EventObject& Source );
86 virtual void SAL_CALL notifyEvent( const document::EventObject& aEvent );
87 virtual void SAL_CALL disposing( const lang::EventObject& aEvent );
88 virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent );
89 };
90
Create(EmbeddedObjectRef * p)91 EmbedEventListener_Impl* EmbedEventListener_Impl::Create( EmbeddedObjectRef* p )
92 {
93 EmbedEventListener_Impl* xRet = new EmbedEventListener_Impl( p );
94 xRet->acquire();
95
96 if ( p->GetObject().is() )
97 {
98 p->GetObject()->addStateChangeListener( xRet );
99
100 uno::Reference < util::XCloseable > xClose( p->GetObject(), uno::UNO_QUERY );
101 DBG_ASSERT( xClose.is(), "Object does not support XCloseable!" );
102 if ( xClose.is() )
103 xClose->addCloseListener( xRet );
104
105 uno::Reference < document::XEventBroadcaster > xBrd( p->GetObject(), uno::UNO_QUERY );
106 if ( xBrd.is() )
107 xBrd->addEventListener( xRet );
108
109 xRet->nState = p->GetObject()->getCurrentState();
110 if ( xRet->nState == embed::EmbedStates::RUNNING )
111 {
112 uno::Reference < util::XModifiable > xMod( p->GetObject()->getComponent(), uno::UNO_QUERY );
113 if ( xMod.is() )
114 // listen for changes in running state (update replacements in case of changes)
115 xMod->addModifyListener( xRet );
116 }
117 }
118
119 return xRet;
120 }
121
changingState(const lang::EventObject &,::sal_Int32,::sal_Int32)122 void SAL_CALL EmbedEventListener_Impl::changingState( const lang::EventObject&,
123 ::sal_Int32,
124 ::sal_Int32 )
125 {
126 }
127
stateChanged(const lang::EventObject &,::sal_Int32 nOldState,::sal_Int32 nNewState)128 void SAL_CALL EmbedEventListener_Impl::stateChanged( const lang::EventObject&,
129 ::sal_Int32 nOldState,
130 ::sal_Int32 nNewState )
131 {
132 ::vos::OGuard aGuard( Application::GetSolarMutex() );
133 nState = nNewState;
134 if ( !pObject )
135 return;
136
137 uno::Reference < util::XModifiable > xMod( pObject->GetObject()->getComponent(), uno::UNO_QUERY );
138 if ( nNewState == embed::EmbedStates::RUNNING )
139 {
140 // TODO/LATER: container must be set before!
141 // When is this event created? Who sets the new container when it changed?
142 if( ( pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON ) && nOldState != embed::EmbedStates::LOADED && !pObject->IsChart() )
143 // get new replacement after deactivation
144 pObject->UpdateReplacement();
145
146 if( pObject->IsChart() && nOldState == embed::EmbedStates::UI_ACTIVE )
147 {
148 //create a new metafile replacement when leaving the edit mode
149 //for buggy documents where the old image looks different from the correct one
150 if( xMod.is() && !xMod->isModified() )//in case of modification a new replacement will be requested anyhow
151 pObject->UpdateReplacementOnDemand();
152 }
153
154 if ( xMod.is() && nOldState == embed::EmbedStates::LOADED )
155 // listen for changes (update replacements in case of changes)
156 xMod->addModifyListener( this );
157 }
158 else if ( nNewState == embed::EmbedStates::LOADED )
159 {
160 // in loaded state we can't listen
161 if ( xMod.is() )
162 xMod->removeModifyListener( this );
163 }
164 }
165
modified(const lang::EventObject &)166 void SAL_CALL EmbedEventListener_Impl::modified( const lang::EventObject& )
167 {
168 ::vos::OGuard aGuard( Application::GetSolarMutex() );
169 if ( pObject && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON )
170 {
171 if ( nState == embed::EmbedStates::RUNNING )
172 {
173 // updates only necessary in non-active states
174 if( pObject->IsChart() )
175 pObject->UpdateReplacementOnDemand();
176 else
177 pObject->UpdateReplacement();
178 }
179 else if ( nState == embed::EmbedStates::UI_ACTIVE || 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 pObject->UpdateReplacementOnDemand();
183 }
184 }
185 }
186
notifyEvent(const document::EventObject & aEvent)187 void SAL_CALL EmbedEventListener_Impl::notifyEvent( const document::EventObject& aEvent )
188 {
189 ::vos::OGuard aGuard( Application::GetSolarMutex() );
190
191 #if 0
192 if ( pObject && aEvent.EventName.equalsAscii("OnSaveDone") || aEvent.EventName.equalsAscii("OnSaveAsDone") )
193 {
194 // TODO/LATER: container must be set before!
195 // When is this event created? Who sets the new container when it changed?
196 pObject->UpdateReplacement();
197 }
198 else
199 #endif
200 if ( pObject && aEvent.EventName.equalsAscii("OnVisAreaChanged") && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON && !pObject->IsChart() )
201 {
202 pObject->UpdateReplacement();
203 }
204 }
205
queryClosing(const lang::EventObject & Source,::sal_Bool)206 void SAL_CALL EmbedEventListener_Impl::queryClosing( const lang::EventObject& Source, ::sal_Bool )
207 {
208 // An embedded object can be shared between several objects (f.e. for undo purposes)
209 // the object will not be closed before the last "customer" is destroyed
210 // Now the EmbeddedObjectRef helper class works like a "lock" on the object
211 if ( pObject && pObject->IsLocked() && Source.Source == pObject->GetObject() )
212 throw util::CloseVetoException();
213 }
214
notifyClosing(const lang::EventObject & Source)215 void SAL_CALL EmbedEventListener_Impl::notifyClosing( const lang::EventObject& Source )
216 {
217 if ( pObject && Source.Source == pObject->GetObject() )
218 {
219 pObject->Clear();
220 pObject = 0;
221 }
222 }
223
disposing(const lang::EventObject & aEvent)224 void SAL_CALL EmbedEventListener_Impl::disposing( const lang::EventObject& aEvent )
225 {
226 if ( pObject && aEvent.Source == pObject->GetObject() )
227 {
228 pObject->Clear();
229 pObject = 0;
230 }
231 }
232
233 struct EmbeddedObjectRef_Impl
234 {
235 EmbedEventListener_Impl* xListener;
236 ::rtl::OUString aPersistName;
237 ::rtl::OUString aMediaType;
238 comphelper::EmbeddedObjectContainer* pContainer;
239 Graphic* pGraphic;
240 Graphic* pHCGraphic;
241 sal_Int64 nViewAspect;
242 sal_Bool bIsLocked;
243 sal_Bool bNeedUpdate;
244
245 // #i104867#
246 sal_uInt32 mnGraphicVersion;
247 awt::Size aDefaultSizeForChart_In_100TH_MM;//#i103460# charts do not necessarily 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
248 };
249
Construct_Impl()250 void EmbeddedObjectRef::Construct_Impl()
251 {
252 mpImp = new EmbeddedObjectRef_Impl;
253 mpImp->pContainer = 0;
254 mpImp->pGraphic = 0;
255 mpImp->pHCGraphic = 0;
256 mpImp->nViewAspect = embed::Aspects::MSOLE_CONTENT;
257 mpImp->bIsLocked = sal_False;
258 mpImp->bNeedUpdate = sal_False;
259 mpImp->mnGraphicVersion = 0;
260 mpImp->aDefaultSizeForChart_In_100TH_MM = awt::Size(8000,7000);
261 }
262
EmbeddedObjectRef()263 EmbeddedObjectRef::EmbeddedObjectRef()
264 {
265 Construct_Impl();
266 }
267
EmbeddedObjectRef(const NS_UNO::Reference<NS_EMBED::XEmbeddedObject> & xObj,sal_Int64 nAspect)268 EmbeddedObjectRef::EmbeddedObjectRef( const NS_UNO::Reference < NS_EMBED::XEmbeddedObject >& xObj, sal_Int64 nAspect )
269 {
270 Construct_Impl();
271 mpImp->nViewAspect = nAspect;
272 mxObj = xObj;
273 mpImp->xListener = EmbedEventListener_Impl::Create( this );
274 }
275
EmbeddedObjectRef(const EmbeddedObjectRef & rObj)276 EmbeddedObjectRef::EmbeddedObjectRef( const EmbeddedObjectRef& rObj )
277 {
278 mpImp = new EmbeddedObjectRef_Impl;
279 mpImp->pContainer = rObj.mpImp->pContainer;
280 mpImp->nViewAspect = rObj.mpImp->nViewAspect;
281 mpImp->bIsLocked = rObj.mpImp->bIsLocked;
282 mxObj = rObj.mxObj;
283 mpImp->xListener = EmbedEventListener_Impl::Create( this );
284 mpImp->aPersistName = rObj.mpImp->aPersistName;
285 mpImp->aMediaType = rObj.mpImp->aMediaType;
286 mpImp->bNeedUpdate = rObj.mpImp->bNeedUpdate;
287 mpImp->aDefaultSizeForChart_In_100TH_MM = rObj.mpImp->aDefaultSizeForChart_In_100TH_MM;
288
289 if ( rObj.mpImp->pGraphic && !rObj.mpImp->bNeedUpdate )
290 mpImp->pGraphic = new Graphic( *rObj.mpImp->pGraphic );
291 else
292 mpImp->pGraphic = 0;
293
294 mpImp->pHCGraphic = 0;
295 mpImp->mnGraphicVersion = 0;
296 }
297
~EmbeddedObjectRef()298 EmbeddedObjectRef::~EmbeddedObjectRef()
299 {
300 delete mpImp->pGraphic;
301 if ( mpImp->pHCGraphic )
302 DELETEZ( mpImp->pHCGraphic );
303 Clear();
304 delete mpImp;
305 }
306 /*
307 EmbeddedObjectRef& EmbeddedObjectRef::operator = ( const EmbeddedObjectRef& rObj )
308 {
309 DBG_ASSERT( !mxObj.is(), "Never assign an already assigned object!" );
310
311 delete mpImp->pGraphic;
312 if ( mpImp->pHCGraphic ) DELETEZ( mpImp->pHCGraphic );
313 Clear();
314
315 mpImp->nViewAspect = rObj.mpImp->nViewAspect;
316 mpImp->bIsLocked = rObj.mpImp->bIsLocked;
317 mxObj = rObj.mxObj;
318 mpImp->xListener = EmbedEventListener_Impl::Create( this );
319 mpImp->pContainer = rObj.mpImp->pContainer;
320 mpImp->aPersistName = rObj.mpImp->aPersistName;
321 mpImp->aMediaType = rObj.mpImp->aMediaType;
322 mpImp->bNeedUpdate = rObj.mpImp->bNeedUpdate;
323
324 if ( rObj.mpImp->pGraphic && !rObj.mpImp->bNeedUpdate )
325 mpImp->pGraphic = new Graphic( *rObj.mpImp->pGraphic );
326 else
327 mpImp->pGraphic = 0;
328 return *this;
329 }
330 */
Assign(const NS_UNO::Reference<NS_EMBED::XEmbeddedObject> & xObj,sal_Int64 nAspect)331 void EmbeddedObjectRef::Assign( const NS_UNO::Reference < NS_EMBED::XEmbeddedObject >& xObj, sal_Int64 nAspect )
332 {
333 DBG_ASSERT( !mxObj.is(), "Never assign an already assigned object!" );
334
335 Clear();
336 mpImp->nViewAspect = nAspect;
337 mxObj = xObj;
338 mpImp->xListener = EmbedEventListener_Impl::Create( this );
339
340 //#i103460#
341 if ( IsChart() )
342 {
343 ::com::sun::star::uno::Reference < ::com::sun::star::chart2::XDefaultSizeTransmitter > xSizeTransmitter( xObj, uno::UNO_QUERY );
344 DBG_ASSERT( xSizeTransmitter.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
345 if( xSizeTransmitter.is() )
346 xSizeTransmitter->setDefaultSize( mpImp->aDefaultSizeForChart_In_100TH_MM );
347 }
348 }
349
Clear()350 void EmbeddedObjectRef::Clear()
351 {
352 if ( mxObj.is() && mpImp->xListener )
353 {
354 mxObj->removeStateChangeListener( mpImp->xListener );
355
356 uno::Reference < util::XCloseable > xClose( mxObj, uno::UNO_QUERY );
357 if ( xClose.is() )
358 xClose->removeCloseListener( mpImp->xListener );
359
360 uno::Reference < document::XEventBroadcaster > xBrd( mxObj, uno::UNO_QUERY );
361 if ( xBrd.is() )
362 xBrd->removeEventListener( mpImp->xListener );
363
364 if ( mpImp->bIsLocked )
365 {
366 if ( xClose.is() )
367 {
368 try
369 {
370 mxObj->changeState( embed::EmbedStates::LOADED );
371 xClose->close( sal_True );
372 }
373 catch ( util::CloseVetoException& )
374 {
375 // there's still someone who needs the object!
376 }
377 catch ( uno::Exception& )
378 {
379 OSL_ENSURE( sal_False, "Error on switching of the object to loaded state and closing!\n" );
380 }
381 }
382 }
383
384 if ( mpImp->xListener )
385 {
386 mpImp->xListener->pObject = 0;
387 mpImp->xListener->release();
388 mpImp->xListener = 0;
389 }
390
391 mxObj = 0;
392 mpImp->bNeedUpdate = sal_False;
393 }
394
395 mpImp->pContainer = 0;
396 mpImp->bIsLocked = sal_False;
397 mpImp->bNeedUpdate = sal_False;
398 }
399
AssignToContainer(comphelper::EmbeddedObjectContainer * pContainer,const::rtl::OUString & rPersistName)400 void EmbeddedObjectRef::AssignToContainer( comphelper::EmbeddedObjectContainer* pContainer, const ::rtl::OUString& rPersistName )
401 {
402 mpImp->pContainer = pContainer;
403 mpImp->aPersistName = rPersistName;
404
405 if ( mpImp->pGraphic && !mpImp->bNeedUpdate && pContainer )
406 SetGraphicToContainer( *mpImp->pGraphic, *pContainer, mpImp->aPersistName, ::rtl::OUString() );
407 }
408
GetContainer() const409 comphelper::EmbeddedObjectContainer* EmbeddedObjectRef::GetContainer() const
410 {
411 return mpImp->pContainer;
412 }
413
GetPersistName() const414 ::rtl::OUString EmbeddedObjectRef::GetPersistName() const
415 {
416 return mpImp->aPersistName;
417 }
418
GetMapUnit() const419 MapUnit EmbeddedObjectRef::GetMapUnit() const
420 {
421 if ( mpImp->nViewAspect == embed::Aspects::MSOLE_CONTENT )
422 return VCLUnoHelper::UnoEmbed2VCLMapUnit( mxObj->getMapUnit( mpImp->nViewAspect ) );
423 else
424 // TODO/LATER: currently only CONTENT aspect requires communication with the object
425 return MAP_100TH_MM;
426 }
427
GetViewAspect() const428 sal_Int64 EmbeddedObjectRef::GetViewAspect() const
429 {
430 return mpImp->nViewAspect;
431 }
432
SetViewAspect(sal_Int64 nAspect)433 void EmbeddedObjectRef::SetViewAspect( sal_Int64 nAspect )
434 {
435 mpImp->nViewAspect = nAspect;
436 }
437
Lock(sal_Bool bLock)438 void EmbeddedObjectRef::Lock( sal_Bool bLock )
439 {
440 mpImp->bIsLocked = bLock;
441 }
442
IsLocked() const443 sal_Bool EmbeddedObjectRef::IsLocked() const
444 {
445 return mpImp->bIsLocked;
446 }
447
GetReplacement(sal_Bool bUpdate)448 void EmbeddedObjectRef::GetReplacement( sal_Bool bUpdate )
449 {
450 if ( bUpdate )
451 {
452 DELETEZ( mpImp->pGraphic );
453 mpImp->aMediaType = ::rtl::OUString();
454 mpImp->pGraphic = new Graphic;
455 if ( mpImp->pHCGraphic )
456 DELETEZ( mpImp->pHCGraphic );
457 mpImp->mnGraphicVersion++;
458 }
459 else if ( !mpImp->pGraphic )
460 {
461 mpImp->pGraphic = new Graphic;
462 mpImp->mnGraphicVersion++;
463 }
464 else
465 {
466 DBG_ERROR("No update, but replacement exists already!");
467 return;
468 }
469
470 SvStream* pGraphicStream = GetGraphicStream( bUpdate );
471 if ( pGraphicStream )
472 {
473 GraphicFilter* pGF = GraphicFilter::GetGraphicFilter();
474 if( mpImp->pGraphic )
475 pGF->ImportGraphic( *mpImp->pGraphic, String(), *pGraphicStream, GRFILTER_FORMAT_DONTKNOW );
476 mpImp->mnGraphicVersion++;
477 delete pGraphicStream;
478 }
479 }
480
GetGraphic(::rtl::OUString * pMediaType) const481 Graphic* EmbeddedObjectRef::GetGraphic( ::rtl::OUString* pMediaType ) const
482 {
483 try
484 {
485 if ( mpImp->bNeedUpdate )
486 // bNeedUpdate will be set to false while retrieving new replacement
487 const_cast < EmbeddedObjectRef* >(this)->GetReplacement( sal_True );
488 else if ( !mpImp->pGraphic )
489 const_cast < EmbeddedObjectRef* >(this)->GetReplacement( sal_False );
490 }
491 catch( uno::Exception& )
492 {
493 OSL_ENSURE( sal_False, "Something went wrong on getting the graphic!" );
494 }
495
496 if ( mpImp->pGraphic && pMediaType )
497 *pMediaType = mpImp->aMediaType;
498 return mpImp->pGraphic;
499 }
500
GetSize(MapMode * pTargetMapMode) const501 Size EmbeddedObjectRef::GetSize( MapMode* pTargetMapMode ) const
502 {
503 MapMode aSourceMapMode( MAP_100TH_MM );
504 Size aResult;
505
506 if ( mpImp->nViewAspect == embed::Aspects::MSOLE_ICON )
507 {
508 Graphic* pGraphic = GetGraphic();
509 if ( pGraphic )
510 {
511 aSourceMapMode = pGraphic->GetPrefMapMode();
512 aResult = pGraphic->GetPrefSize();
513 }
514 else
515 aResult = Size( 2500, 2500 );
516 }
517 else
518 {
519 awt::Size aSize;
520
521 if ( mxObj.is() )
522 {
523 try
524 {
525 aSize = mxObj->getVisualAreaSize( mpImp->nViewAspect );
526 }
527 catch( embed::NoVisualAreaSizeException& )
528 {
529 }
530 catch( uno::Exception& )
531 {
532 OSL_ENSURE( sal_False, "Something went wrong on getting of the size of the object!" );
533 }
534
535 try
536 {
537 aSourceMapMode = VCLUnoHelper::UnoEmbed2VCLMapUnit( mxObj->getMapUnit( mpImp->nViewAspect ) );
538 }
539 catch( uno::Exception )
540 {
541 OSL_ENSURE( sal_False, "Can not get the map mode!" );
542 }
543 }
544
545 if ( !aSize.Height && !aSize.Width )
546 {
547 aSize.Width = 5000;
548 aSize.Height = 5000;
549 }
550
551 aResult = Size( aSize.Width, aSize.Height );
552 }
553
554 if ( pTargetMapMode )
555 aResult = OutputDevice::LogicToLogic( aResult, aSourceMapMode, *pTargetMapMode );
556
557 return aResult;
558 }
559
GetHCGraphic() const560 Graphic* EmbeddedObjectRef::GetHCGraphic() const
561 {
562 if ( !mpImp->pHCGraphic )
563 {
564 uno::Reference< io::XInputStream > xInStream;
565 try
566 {
567 // if the object needs size on load, that means that it is not our object
568 // currently the HC mode is supported only for OOo own objects so the following
569 // check is used as an optimization
570 // TODO/LATER: shouldn't there be a special status flag to detect alien implementation?
571 if ( mpImp->nViewAspect == embed::Aspects::MSOLE_CONTENT
572 && mxObj.is() && !( mxObj->getStatus( mpImp->nViewAspect ) & embed::EmbedMisc::EMBED_NEEDSSIZEONLOAD ) )
573 {
574 // TODO/LATER: optimization, it makes no sence to do it for OLE objects
575 if ( mxObj->getCurrentState() == embed::EmbedStates::LOADED )
576 mxObj->changeState( embed::EmbedStates::RUNNING );
577
578 // TODO: return for the aspect of the document
579 embed::VisualRepresentation aVisualRepresentation;
580 uno::Reference< datatransfer::XTransferable > xTransferable( mxObj->getComponent(), uno::UNO_QUERY );
581 if ( !xTransferable.is() )
582 throw uno::RuntimeException();
583
584 datatransfer::DataFlavor aDataFlavor(
585 ::rtl::OUString::createFromAscii(
586 "application/x-openoffice-highcontrast-gdimetafile;windows_formatname=\"GDIMetaFile\"" ),
587 ::rtl::OUString::createFromAscii( "GDIMetaFile" ),
588 ::getCppuType( (const uno::Sequence< sal_Int8 >*) NULL ) );
589
590 uno::Sequence < sal_Int8 > aSeq;
591 if ( ( xTransferable->getTransferData( aDataFlavor ) >>= aSeq ) && aSeq.getLength() )
592 xInStream = new ::comphelper::SequenceInputStream( aSeq );
593 }
594 }
595 catch ( uno::Exception& )
596 {
597 OSL_ENSURE( sal_False, "Something went wrong on getting the high contrast graphic!" );
598 }
599
600 if ( xInStream.is() )
601 {
602 SvStream* pStream = NULL;
603 pStream = ::utl::UcbStreamHelper::CreateStream( xInStream );
604 if ( pStream )
605 {
606 if ( !pStream->GetError() )
607 {
608 GraphicFilter* pGF = GraphicFilter::GetGraphicFilter();
609 Graphic* pGraphic = new Graphic();
610 if ( pGF->ImportGraphic( *pGraphic, String(), *pStream, GRFILTER_FORMAT_DONTKNOW ) == 0 )
611 mpImp->pHCGraphic = pGraphic;
612 else
613 delete pGraphic;
614 mpImp->mnGraphicVersion++;
615 }
616
617 delete pStream;
618 }
619 }
620 }
621
622 return mpImp->pHCGraphic;
623 }
624
SetGraphicStream(const uno::Reference<io::XInputStream> & xInGrStream,const::rtl::OUString & rMediaType)625 void EmbeddedObjectRef::SetGraphicStream( const uno::Reference< io::XInputStream >& xInGrStream,
626 const ::rtl::OUString& rMediaType )
627 {
628 if ( mpImp->pGraphic )
629 delete mpImp->pGraphic;
630 mpImp->pGraphic = new Graphic();
631 mpImp->aMediaType = rMediaType;
632 if ( mpImp->pHCGraphic )
633 DELETEZ( mpImp->pHCGraphic );
634 mpImp->mnGraphicVersion++;
635
636 SvStream* pGraphicStream = ::utl::UcbStreamHelper::CreateStream( xInGrStream );
637
638 if ( pGraphicStream )
639 {
640 GraphicFilter* pGF = GraphicFilter::GetGraphicFilter();
641 pGF->ImportGraphic( *mpImp->pGraphic, String(), *pGraphicStream, GRFILTER_FORMAT_DONTKNOW );
642 mpImp->mnGraphicVersion++;
643
644 if ( mpImp->pContainer )
645 {
646 pGraphicStream->Seek( 0 );
647 uno::Reference< io::XInputStream > xInSeekGrStream = new ::utl::OSeekableInputStreamWrapper( pGraphicStream );
648
649 mpImp->pContainer->InsertGraphicStream( xInSeekGrStream, mpImp->aPersistName, rMediaType );
650 }
651
652 delete pGraphicStream;
653 }
654
655 mpImp->bNeedUpdate = sal_False;
656
657 }
658
SetGraphic(const Graphic & rGraphic,const::rtl::OUString & rMediaType)659 void EmbeddedObjectRef::SetGraphic( const Graphic& rGraphic, const ::rtl::OUString& rMediaType )
660 {
661 if ( mpImp->pGraphic )
662 delete mpImp->pGraphic;
663 mpImp->pGraphic = new Graphic( rGraphic );
664 mpImp->aMediaType = rMediaType;
665 if ( mpImp->pHCGraphic )
666 DELETEZ( mpImp->pHCGraphic );
667 mpImp->mnGraphicVersion++;
668
669 if ( mpImp->pContainer )
670 SetGraphicToContainer( rGraphic, *mpImp->pContainer, mpImp->aPersistName, rMediaType );
671
672 mpImp->bNeedUpdate = sal_False;
673 }
674
GetGraphicStream(sal_Bool bUpdate) const675 SvStream* EmbeddedObjectRef::GetGraphicStream( sal_Bool bUpdate ) const
676 {
677 RTL_LOGFILE_CONTEXT( aLog, "svtools (mv76033) svt::EmbeddedObjectRef::GetGraphicStream" );
678 DBG_ASSERT( bUpdate || mpImp->pContainer, "Can't retrieve current graphic!" );
679 uno::Reference < io::XInputStream > xStream;
680 if ( mpImp->pContainer && !bUpdate )
681 {
682 RTL_LOGFILE_CONTEXT_TRACE( aLog, "getting stream from container" );
683 // try to get graphic stream from container storage
684 xStream = mpImp->pContainer->GetGraphicStream( mxObj, &mpImp->aMediaType );
685 if ( xStream.is() )
686 {
687 const sal_Int32 nConstBufferSize = 32000;
688 SvStream *pStream = new SvMemoryStream( 32000, 32000 );
689 sal_Int32 nRead=0;
690 uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
691 do
692 {
693 nRead = xStream->readBytes ( aSequence, nConstBufferSize );
694 pStream->Write( aSequence.getConstArray(), nRead );
695 }
696 while ( nRead == nConstBufferSize );
697 pStream->Seek(0);
698 return pStream;
699 }
700 }
701
702 if ( !xStream.is() )
703 {
704 RTL_LOGFILE_CONTEXT_TRACE( aLog, "getting stream from object" );
705 bool bUserAllowsLinkUpdate(true);
706 const comphelper::EmbeddedObjectContainer* pContainer = GetContainer();
707
708 if(pContainer)
709 {
710 bUserAllowsLinkUpdate = pContainer->getUserAllowsLinkUpdate();
711 }
712
713 if(bUserAllowsLinkUpdate)
714 {
715 // update wanted or no stream in container storage available
716 xStream = GetGraphicReplacementStream(mpImp->nViewAspect,mxObj,&mpImp->aMediaType);
717
718 if(xStream.is())
719 {
720 if(mpImp->pContainer)
721 mpImp->pContainer->InsertGraphicStream(xStream,mpImp->aPersistName,mpImp->aMediaType);
722
723 SvStream* pResult = ::utl::UcbStreamHelper::CreateStream( xStream );
724 if ( pResult && bUpdate )
725 mpImp->bNeedUpdate = sal_False;
726
727 return pResult;
728 }
729 }
730 }
731
732 return NULL;
733 }
734
DrawPaintReplacement(const Rectangle & rRect,const String & rText,OutputDevice * pOut)735 void EmbeddedObjectRef::DrawPaintReplacement( const Rectangle &rRect, const String &rText, OutputDevice *pOut )
736 {
737 MapMode aMM( MAP_APPFONT );
738 Size aAppFontSz = pOut->LogicToLogic( Size( 0, 8 ), &aMM, NULL );
739 Font aFnt( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM( "Helvetica" ) ), aAppFontSz );
740 aFnt.SetTransparent( sal_True );
741 aFnt.SetColor( Color( COL_LIGHTRED ) );
742 aFnt.SetWeight( WEIGHT_BOLD );
743 aFnt.SetFamily( FAMILY_SWISS );
744
745 pOut->Push();
746 pOut->SetBackground();
747 pOut->SetFont( aFnt );
748
749 Point aPt;
750 // Nun den Text so skalieren, dass er in das Rect passt.
751 // Wir fangen mit der Defaultsize an und gehen 1-AppFont runter
752 for( sal_uInt16 i = 8; i > 2; i-- )
753 {
754 aPt.X() = (rRect.GetWidth() - pOut->GetTextWidth( rText )) / 2;
755 aPt.Y() = (rRect.GetHeight() - pOut->GetTextHeight()) / 2;
756
757 sal_Bool bTiny = sal_False;
758 if( aPt.X() < 0 ) bTiny = sal_True, aPt.X() = 0;
759 if( aPt.Y() < 0 ) bTiny = sal_True, aPt.Y() = 0;
760 if( bTiny )
761 {
762 // heruntergehen bei kleinen Bildern
763 aFnt.SetSize( Size( 0, aAppFontSz.Height() * i / 8 ) );
764 pOut->SetFont( aFnt );
765 }
766 else
767 break;
768 }
769
770 Bitmap aBmp( SvtResId( BMP_PLUGIN ) );
771 long nHeight = rRect.GetHeight() - pOut->GetTextHeight();
772 long nWidth = rRect.GetWidth();
773 if( nHeight > 0 )
774 {
775 aPt.Y() = nHeight;
776 Point aP = rRect.TopLeft();
777 Size aBmpSize = aBmp.GetSizePixel();
778 // Bitmap einpassen
779 if( nHeight * 10 / nWidth
780 > aBmpSize.Height() * 10 / aBmpSize.Width() )
781 {
782 // nach der Breite ausrichten
783 // Proportion beibehalten
784 long nH = nWidth * aBmpSize.Height() / aBmpSize.Width();
785 // zentrieren
786 aP.Y() += (nHeight - nH) / 2;
787 nHeight = nH;
788 }
789 else
790 {
791 // nach der H"ohe ausrichten
792 // Proportion beibehalten
793 long nW = nHeight * aBmpSize.Width() / aBmpSize.Height();
794 // zentrieren
795 aP.X() += (nWidth - nW) / 2;
796 nWidth = nW;
797 }
798
799 pOut->DrawBitmap( aP, Size( nWidth, nHeight ), aBmp );
800 }
801
802 pOut->IntersectClipRegion( rRect );
803 aPt += rRect.TopLeft();
804 pOut->DrawText( aPt, rText );
805 pOut->Pop();
806 }
807
DrawShading(const Rectangle & rRect,OutputDevice * pOut)808 void EmbeddedObjectRef::DrawShading( const Rectangle &rRect, OutputDevice *pOut )
809 {
810 GDIMetaFile * pMtf = pOut->GetConnectMetaFile();
811 if( pMtf && pMtf->IsRecord() )
812 return;
813
814 pOut->Push();
815 pOut->SetLineColor( Color( COL_BLACK ) );
816
817 Size aPixSize = pOut->LogicToPixel( rRect.GetSize() );
818 aPixSize.Width() -= 1;
819 aPixSize.Height() -= 1;
820 Point aPixViewPos = pOut->LogicToPixel( rRect.TopLeft() );
821 sal_Int32 nMax = aPixSize.Width() + aPixSize.Height();
822 for( sal_Int32 i = 5; i < nMax; i += 5 )
823 {
824 Point a1( aPixViewPos ), a2( aPixViewPos );
825 if( i > aPixSize.Width() )
826 a1 += Point( aPixSize.Width(), i - aPixSize.Width() );
827 else
828 a1 += Point( i, 0 );
829 if( i > aPixSize.Height() )
830 a2 += Point( i - aPixSize.Height(), aPixSize.Height() );
831 else
832 a2 += Point( 0, i );
833
834 pOut->DrawLine( pOut->PixelToLogic( a1 ), pOut->PixelToLogic( a2 ) );
835 }
836
837 pOut->Pop();
838
839 }
840
TryRunningState()841 sal_Bool EmbeddedObjectRef::TryRunningState()
842 {
843 return TryRunningState( mxObj );
844 }
845
TryRunningState(const uno::Reference<embed::XEmbeddedObject> & xEmbObj)846 sal_Bool EmbeddedObjectRef::TryRunningState( const uno::Reference < embed::XEmbeddedObject >& xEmbObj )
847 {
848 if ( !xEmbObj.is() )
849 return sal_False;
850
851 try
852 {
853 if ( xEmbObj->getCurrentState() == embed::EmbedStates::LOADED )
854 xEmbObj->changeState( embed::EmbedStates::RUNNING );
855 }
856 catch ( uno::Exception& )
857 {
858 return sal_False;
859 }
860
861 return sal_True;
862 }
863
SetGraphicToContainer(const Graphic & rGraphic,comphelper::EmbeddedObjectContainer & aContainer,const::rtl::OUString & aName,const::rtl::OUString & aMediaType)864 void EmbeddedObjectRef::SetGraphicToContainer( const Graphic& rGraphic,
865 comphelper::EmbeddedObjectContainer& aContainer,
866 const ::rtl::OUString& aName,
867 const ::rtl::OUString& aMediaType )
868 {
869 SvMemoryStream aStream;
870 aStream.SetVersion( SOFFICE_FILEFORMAT_CURRENT );
871 if ( rGraphic.ExportNative( aStream ) )
872 {
873 aStream.Seek( 0 );
874
875 uno::Reference < io::XInputStream > xStream = new ::utl::OSeekableInputStreamWrapper( aStream );
876 aContainer.InsertGraphicStream( xStream, aName, aMediaType );
877 }
878 else
879 OSL_ENSURE( sal_False, "Export of graphic is failed!\n" );
880 }
881
ObjectIsModified(const uno::Reference<embed::XEmbeddedObject> & xObj)882 sal_Bool EmbeddedObjectRef::ObjectIsModified( const uno::Reference< embed::XEmbeddedObject >& xObj )
883 {
884 sal_Bool bResult = sal_False;
885
886 sal_Int32 nState = xObj->getCurrentState();
887 if ( nState != embed::EmbedStates::LOADED && nState != embed::EmbedStates::RUNNING )
888 {
889 // the object is active so if the model is modified the replacement
890 // should be retrieved from the object
891 uno::Reference< util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY );
892 if ( xModifiable.is() )
893 bResult = xModifiable->isModified();
894 }
895
896 return bResult;
897 }
898
GetGraphicReplacementStream(sal_Int64 nViewAspect,const uno::Reference<embed::XEmbeddedObject> & xObj,::rtl::OUString * pMediaType)899 uno::Reference< io::XInputStream > EmbeddedObjectRef::GetGraphicReplacementStream(
900 sal_Int64 nViewAspect,
901 const uno::Reference< embed::XEmbeddedObject >& xObj,
902 ::rtl::OUString* pMediaType )
903 throw()
904 {
905 return ::comphelper::EmbeddedObjectContainer::GetGraphicReplacementStream(nViewAspect,xObj,pMediaType);
906 }
907
UpdateReplacementOnDemand()908 void EmbeddedObjectRef::UpdateReplacementOnDemand()
909 {
910 DELETEZ( mpImp->pGraphic );
911 mpImp->bNeedUpdate = sal_True;
912 if ( mpImp->pHCGraphic )
913 DELETEZ( mpImp->pHCGraphic );
914 mpImp->mnGraphicVersion++;
915
916 if( mpImp->pContainer )
917 {
918 //remove graphic from container thus a new up to date one is requested on save
919 mpImp->pContainer->RemoveGraphicStream( mpImp->aPersistName );
920 }
921 }
922
IsChart() const923 sal_Bool EmbeddedObjectRef::IsChart() const
924 {
925 //todo maybe for 3.0:
926 //if the changes work good for chart
927 //we should apply them for all own ole objects
928
929 //#i83708# #i81857# #i79578# request an ole replacement image only if really necessary
930 //as this call can be very expensive and does block the user interface as long at it takes
931
932 if ( !mxObj.is() )
933 return false;
934
935 SvGlobalName aObjClsId( mxObj->getClassID() );
936 if(
937 SvGlobalName(SO3_SCH_CLASSID_30) == aObjClsId
938 || SvGlobalName(SO3_SCH_CLASSID_40) == aObjClsId
939 || SvGlobalName(SO3_SCH_CLASSID_50) == aObjClsId
940 || SvGlobalName(SO3_SCH_CLASSID_60) == aObjClsId)
941 {
942 return sal_True;
943 }
944
945 return sal_False;
946 }
947
948 // MT: Only used for getting accessible attributes, which are not localized
GetChartType()949 rtl::OUString EmbeddedObjectRef::GetChartType()
950 {
951 rtl::OUString Style;
952 if ( mxObj.is() )
953 {
954 if ( IsChart() )
955 {
956 if ( svt::EmbeddedObjectRef::TryRunningState( mxObj ) )
957 {
958 uno::Reference< chart2::XChartDocument > xChart( mxObj->getComponent(), uno::UNO_QUERY );
959 if (xChart.is())
960 {
961 uno::Reference< chart2::XDiagram > xDiagram( xChart->getFirstDiagram());
962 if( ! xDiagram.is())
963 return String();
964 uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
965 uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
966 // IA2 CWS. Unused: int nCoordinateCount = aCooSysSeq.getLength();
967 sal_Bool bGetChartType = sal_False;
968 for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
969 {
970 uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
971 uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes());
972 int nDimesionCount = aCooSysSeq[nCooSysIdx]->getDimension();
973 if( nDimesionCount == 3 )
974 Style += rtl::OUString::createFromAscii("3D ");
975 else
976 Style += rtl::OUString::createFromAscii("2D ");
977 for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx )
978 {
979 rtl::OUString strChartType = aChartTypes[nCTIdx]->getChartType();
980 if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.AreaChartType")))
981 {
982 Style += rtl::OUString::createFromAscii("Areas");
983 bGetChartType = sal_True;
984 }
985 else if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.BarChartType")))
986 {
987 Style += rtl::OUString::createFromAscii("Bars");
988 bGetChartType = sal_True;
989 }
990 else if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.ColumnChartType")))
991 {
992 uno::Reference< beans::XPropertySet > xProp( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY );
993 if( xProp.is())
994 {
995 bool bCurrent = false;
996 if( xProp->getPropertyValue( rtl::OUString::createFromAscii("SwapXAndYAxis") ) >>= bCurrent )
997 {
998 if (bCurrent)
999 Style += rtl::OUString::createFromAscii("Bars");
1000 else
1001 Style += rtl::OUString::createFromAscii("Columns");
1002 bGetChartType = sal_True;
1003 }
1004 }
1005 }
1006 else if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.LineChartType")))
1007 {
1008 Style += rtl::OUString::createFromAscii("Lines");
1009 bGetChartType = sal_True;
1010 }
1011 else if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.ScatterChartType")))
1012 {
1013 Style += rtl::OUString::createFromAscii("XY Chart");
1014 bGetChartType = sal_True;
1015 }
1016 else if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.PieChartType")))
1017 {
1018 Style += rtl::OUString::createFromAscii("Pies");
1019 bGetChartType = sal_True;
1020 }
1021 else if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.NetChartType")))
1022 {
1023 Style += rtl::OUString::createFromAscii("Radar");
1024 bGetChartType = sal_True;
1025 }
1026 else if (strChartType.equals(::rtl::OUString::createFromAscii("com.sun.star.chart2.CandleStickChartType")))
1027 {
1028 Style += rtl::OUString::createFromAscii("Candle Stick Chart");
1029 bGetChartType = sal_True;
1030 }
1031 if (bGetChartType)
1032 return Style;
1033 }
1034 }
1035 }
1036 }
1037 }
1038 }
1039 return Style;
1040 }
1041
1042 // #i104867#
getGraphicVersion() const1043 sal_uInt32 EmbeddedObjectRef::getGraphicVersion() const
1044 {
1045 return mpImp->mnGraphicVersion;
1046 }
1047
SetDefaultSizeForChart(const Size & rSizeIn_100TH_MM)1048 void EmbeddedObjectRef::SetDefaultSizeForChart( const Size& rSizeIn_100TH_MM )
1049 {
1050 //#i103460# charts do not necessarily have an own size within ODF files,
1051 //for this case they need to use the size settings from the surrounding frame,
1052 //which is made available with this method
1053
1054 mpImp->aDefaultSizeForChart_In_100TH_MM = awt::Size( rSizeIn_100TH_MM.getWidth(), rSizeIn_100TH_MM.getHeight() );
1055
1056 ::com::sun::star::uno::Reference < ::com::sun::star::chart2::XDefaultSizeTransmitter > xSizeTransmitter( mxObj, uno::UNO_QUERY );
1057 DBG_ASSERT( xSizeTransmitter.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
1058 if( xSizeTransmitter.is() )
1059 xSizeTransmitter->setDefaultSize( mpImp->aDefaultSizeForChart_In_100TH_MM );
1060 }
1061
1062 } // namespace svt
1063