1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <libxml/xmlwriter.h>
22 #include <svtools/embedhlp.hxx>
23 #include <vcl/graphicfilter.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/outdev.hxx>
26 #include <vcl/gfxlink.hxx>
27 #include <vcl/TypeSerializer.hxx>
28 #include <bitmaps.hlst>
30 #include <sal/log.hxx>
31 #include <comphelper/fileformat.h>
32 #include <comphelper/embeddedobjectcontainer.hxx>
33 #include <toolkit/helper/vclunohelper.hxx>
34 #include <unotools/ucbstreamhelper.hxx>
35 #include <unotools/streamwrap.hxx>
36 #include <com/sun/star/chart2/XChartDocument.hpp>
37 #include <com/sun/star/chart2/XCoordinateSystem.hpp>
38 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
39 #include <com/sun/star/chart2/XDiagram.hpp>
40 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
41 #include <com/sun/star/chart2/XChartType.hpp>
42 #include <tools/globname.hxx>
43 #include <comphelper/classids.hxx>
44 #include <com/sun/star/util/CloseVetoException.hpp>
45 #include <com/sun/star/util/XModifyListener.hpp>
46 #include <com/sun/star/util/XModifiable.hpp>
47 #include <com/sun/star/embed/Aspects.hpp>
48 #include <com/sun/star/embed/EmbedStates.hpp>
49 #include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
50 #include <com/sun/star/embed/XEmbeddedObject.hpp>
51 #include <com/sun/star/embed/XStateChangeListener.hpp>
52 #include <com/sun/star/embed/XLinkageSupport.hpp>
53 #include <com/sun/star/chart2/XDefaultSizeTransmitter.hpp>
54 #include <com/sun/star/qa/XDumper.hpp>
55 #include <embeddedobj/embeddedupdate.hxx>
56 #include <cppuhelper/implbase.hxx>
57 #include <vcl/svapp.hxx>
58 #include <comphelper/diagnose_ex.hxx>
59 #include <tools/debug.hxx>
62 using namespace com::sun::star
;
68 class EmbedEventListener_Impl
: public ::cppu::WeakImplHelper
< embed::XStateChangeListener
,
69 document::XEventListener
,
70 util::XModifyListener
,
71 util::XCloseListener
>
74 EmbeddedObjectRef
* pObject
;
77 explicit EmbedEventListener_Impl( EmbeddedObjectRef
* p
) :
82 static rtl::Reference
<EmbedEventListener_Impl
> Create( EmbeddedObjectRef
* );
84 virtual void SAL_CALL
changingState( const lang::EventObject
& aEvent
, ::sal_Int32 nOldState
, ::sal_Int32 nNewState
) override
;
85 virtual void SAL_CALL
stateChanged( const lang::EventObject
& aEvent
, ::sal_Int32 nOldState
, ::sal_Int32 nNewState
) override
;
86 virtual void SAL_CALL
queryClosing( const lang::EventObject
& Source
, sal_Bool GetsOwnership
) override
;
87 virtual void SAL_CALL
notifyClosing( const lang::EventObject
& Source
) override
;
88 virtual void SAL_CALL
notifyEvent( const document::EventObject
& aEvent
) override
;
89 virtual void SAL_CALL
disposing( const lang::EventObject
& aEvent
) override
;
90 virtual void SAL_CALL
modified( const css::lang::EventObject
& aEvent
) override
;
95 rtl::Reference
<EmbedEventListener_Impl
> EmbedEventListener_Impl::Create( EmbeddedObjectRef
* p
)
97 rtl::Reference
<EmbedEventListener_Impl
> pRet(new EmbedEventListener_Impl( p
));
99 if ( p
->GetObject().is() )
101 p
->GetObject()->addStateChangeListener( pRet
);
103 uno::Reference
< util::XCloseable
> xClose
= p
->GetObject();
104 DBG_ASSERT( xClose
.is(), "Object does not support XCloseable!" );
106 xClose
->addCloseListener( pRet
);
108 uno::Reference
< document::XEventBroadcaster
> xBrd
= p
->GetObject();
110 xBrd
->addEventListener( pRet
);
112 pRet
->nState
= p
->GetObject()->getCurrentState();
113 if ( pRet
->nState
== embed::EmbedStates::RUNNING
)
115 uno::Reference
< util::XModifiable
> xMod( p
->GetObject()->getComponent(), uno::UNO_QUERY
);
117 // listen for changes in running state (update replacements in case of changes)
118 xMod
->addModifyListener( pRet
);
125 void SAL_CALL
EmbedEventListener_Impl::changingState( const lang::EventObject
&,
131 void SAL_CALL
EmbedEventListener_Impl::stateChanged( const lang::EventObject
&,
132 ::sal_Int32 nOldState
,
133 ::sal_Int32 nNewState
)
135 SolarMutexGuard aGuard
;
140 uno::Reference
< util::XModifiable
> xMod( pObject
->GetObject()->getComponent(), uno::UNO_QUERY
);
141 if ( nNewState
== embed::EmbedStates::RUNNING
)
143 bool bProtected
= false;
144 if (pObject
->GetIsProtectedHdl().IsSet())
146 bProtected
= pObject
->GetIsProtectedHdl().Call(nullptr);
149 // TODO/LATER: container must be set before!
150 // When is this event created? Who sets the new container when it changed?
151 if ((pObject
->GetViewAspect() != embed::Aspects::MSOLE_ICON
)
152 && nOldState
!= embed::EmbedStates::LOADED
&& !pObject
->IsChart() && !bProtected
)
153 // get new replacement after deactivation
154 pObject
->UpdateReplacement();
156 if( pObject
->IsChart() && nOldState
== embed::EmbedStates::UI_ACTIVE
)
158 //create a new metafile replacement when leaving the edit mode
159 //for buggy documents where the old image looks different from the correct one
160 if( xMod
.is() && !xMod
->isModified() )//in case of modification a new replacement will be requested anyhow
161 pObject
->UpdateReplacementOnDemand();
164 if ( xMod
.is() && nOldState
== embed::EmbedStates::LOADED
)
165 // listen for changes (update replacements in case of changes)
166 xMod
->addModifyListener( this );
168 else if ( nNewState
== embed::EmbedStates::LOADED
)
170 // in loaded state we can't listen
172 xMod
->removeModifyListener( this );
176 void SAL_CALL
EmbedEventListener_Impl::modified( const lang::EventObject
& )
178 SolarMutexGuard aGuard
;
179 if ( !(pObject
&& pObject
->GetViewAspect() != embed::Aspects::MSOLE_ICON
) )
182 if ( nState
== embed::EmbedStates::RUNNING
)
184 // updates only necessary in non-active states
185 if( pObject
->IsChart() )
186 pObject
->UpdateReplacementOnDemand();
188 pObject
->UpdateReplacement();
190 else if ( nState
== embed::EmbedStates::ACTIVE
||
191 nState
== embed::EmbedStates::UI_ACTIVE
||
192 nState
== embed::EmbedStates::INPLACE_ACTIVE
)
194 // in case the object is inplace or UI active the replacement image should be updated on demand
195 pObject
->UpdateReplacementOnDemand();
199 void SAL_CALL
EmbedEventListener_Impl::notifyEvent( const document::EventObject
& aEvent
)
201 SolarMutexGuard aGuard
;
203 if ( pObject
&& aEvent
.EventName
== "OnVisAreaChanged" && pObject
->GetViewAspect() != embed::Aspects::MSOLE_ICON
&& !pObject
->IsChart() )
205 pObject
->UpdateReplacement();
209 void SAL_CALL
EmbedEventListener_Impl::queryClosing( const lang::EventObject
& Source
, sal_Bool
)
211 // An embedded object can be shared between several objects (f.e. for undo purposes)
212 // the object will not be closed before the last "customer" is destroyed
213 // Now the EmbeddedObjectRef helper class works like a "lock" on the object
214 if ( pObject
&& pObject
->IsLocked() && Source
.Source
== pObject
->GetObject() )
215 throw util::CloseVetoException();
218 void SAL_CALL
EmbedEventListener_Impl::notifyClosing( const lang::EventObject
& Source
)
220 if ( pObject
&& Source
.Source
== pObject
->GetObject() )
227 void SAL_CALL
EmbedEventListener_Impl::disposing( const lang::EventObject
& aEvent
)
229 if ( pObject
&& aEvent
.Source
== pObject
->GetObject() )
236 struct EmbeddedObjectRef_Impl
238 uno::Reference
<embed::XEmbeddedObject
> mxObj
;
240 rtl::Reference
<EmbedEventListener_Impl
> mxListener
;
241 OUString aPersistName
;
243 comphelper::EmbeddedObjectContainer
* pContainer
;
244 std::optional
<Graphic
> oGraphic
;
245 sal_Int64 nViewAspect
;
251 sal_uInt32 mnGraphicVersion
;
252 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
254 Link
<LinkParamNone
*, bool> m_aIsProtectedHdl
;
256 EmbeddedObjectRef_Impl() :
258 nViewAspect(embed::Aspects::MSOLE_CONTENT
),
263 aDefaultSizeForChart_In_100TH_MM(awt::Size(8000,7000))
266 EmbeddedObjectRef_Impl( const EmbeddedObjectRef_Impl
& r
) :
268 aPersistName(r
.aPersistName
),
269 aMediaType(r
.aMediaType
),
270 pContainer(r
.pContainer
),
271 nViewAspect(r
.nViewAspect
),
272 bIsLocked(r
.bIsLocked
),
273 bNeedUpdate(r
.bNeedUpdate
),
274 bUpdating(r
.bUpdating
),
276 aDefaultSizeForChart_In_100TH_MM(r
.aDefaultSizeForChart_In_100TH_MM
)
278 if (r
.oGraphic
&& !r
.bNeedUpdate
)
279 oGraphic
.emplace(*r
.oGraphic
);
282 void dumpAsXml(xmlTextWriterPtr pWriter
) const
284 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("EmbeddedObjectRef_Impl"));
285 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
287 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("mxObj"));
288 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("symbol"),
289 BAD_CAST(typeid(*mxObj
).name()));
290 css::uno::Reference
<css::qa::XDumper
> pComponent(
291 mxObj
->getComponent(), css::uno::UNO_QUERY
);
294 auto const s
= pComponent
->dump("");
295 auto const s1
= OUStringToOString(s
, RTL_TEXTENCODING_ISO_8859_1
); //TODO
296 (void)xmlTextWriterWriteRawLen(
297 pWriter
, reinterpret_cast<xmlChar
const *>(s1
.getStr()), s1
.getLength());
299 (void)xmlTextWriterEndElement(pWriter
);
301 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("pGraphic"));
302 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", oGraphic
? &*oGraphic
: nullptr);
305 (void)xmlTextWriterWriteAttribute(
306 pWriter
, BAD_CAST("is-none"),
307 BAD_CAST(OString::boolean(oGraphic
->IsNone()).getStr()));
309 (void)xmlTextWriterEndElement(pWriter
);
311 (void)xmlTextWriterEndElement(pWriter
);
315 const uno::Reference
<embed::XEmbeddedObject
>& EmbeddedObjectRef::operator->() const
317 return mpImpl
->mxObj
;
320 const uno::Reference
<embed::XEmbeddedObject
>& EmbeddedObjectRef::GetObject() const
322 return mpImpl
->mxObj
;
325 EmbeddedObjectRef::EmbeddedObjectRef() : mpImpl(new EmbeddedObjectRef_Impl
) {}
327 EmbeddedObjectRef::EmbeddedObjectRef( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, sal_Int64 nAspect
) :
328 mpImpl(new EmbeddedObjectRef_Impl
)
330 mpImpl
->nViewAspect
= nAspect
;
331 mpImpl
->mxObj
= xObj
;
332 mpImpl
->mxListener
= EmbedEventListener_Impl::Create( this );
335 EmbeddedObjectRef::EmbeddedObjectRef( const EmbeddedObjectRef
& rObj
) :
336 mpImpl(new EmbeddedObjectRef_Impl(*rObj
.mpImpl
))
338 mpImpl
->mxListener
= EmbedEventListener_Impl::Create( this );
341 EmbeddedObjectRef::~EmbeddedObjectRef()
346 void EmbeddedObjectRef::Assign( const uno::Reference
< embed::XEmbeddedObject
>& xObj
, sal_Int64 nAspect
)
348 DBG_ASSERT(!mpImpl
->mxObj
.is(), "Never assign an already assigned object!");
351 mpImpl
->nViewAspect
= nAspect
;
352 mpImpl
->mxObj
= xObj
;
353 mpImpl
->mxListener
= EmbedEventListener_Impl::Create( this );
358 uno::Reference
< chart2::XDefaultSizeTransmitter
> xSizeTransmitter( xObj
, uno::UNO_QUERY
);
359 DBG_ASSERT( xSizeTransmitter
.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
360 if( xSizeTransmitter
.is() )
361 xSizeTransmitter
->setDefaultSize( mpImpl
->aDefaultSizeForChart_In_100TH_MM
);
365 void EmbeddedObjectRef::Clear()
367 if (mpImpl
->mxObj
.is() && mpImpl
->mxListener
.is())
369 mpImpl
->mxObj
->removeStateChangeListener(mpImpl
->mxListener
);
371 mpImpl
->mxObj
->removeCloseListener( mpImpl
->mxListener
);
372 mpImpl
->mxObj
->removeEventListener( mpImpl
->mxListener
);
374 if ( mpImpl
->bIsLocked
)
378 mpImpl
->mxObj
->changeState(embed::EmbedStates::LOADED
);
379 mpImpl
->mxObj
->close( true );
381 catch (const util::CloseVetoException
&)
383 // there's still someone who needs the object!
385 catch (const uno::Exception
&)
387 TOOLS_WARN_EXCEPTION("svtools.misc", "Error on switching of the object to loaded state and closing");
392 if (mpImpl
->mxListener
.is())
394 mpImpl
->mxListener
->pObject
= nullptr;
395 mpImpl
->mxListener
.clear();
398 mpImpl
->mxObj
= nullptr;
399 mpImpl
->pContainer
= nullptr;
400 mpImpl
->bIsLocked
= false;
401 mpImpl
->bNeedUpdate
= false;
404 bool EmbeddedObjectRef::is() const
406 return mpImpl
->mxObj
.is();
409 void EmbeddedObjectRef::AssignToContainer( comphelper::EmbeddedObjectContainer
* pContainer
, const OUString
& rPersistName
)
411 mpImpl
->pContainer
= pContainer
;
412 mpImpl
->aPersistName
= rPersistName
;
414 if ( mpImpl
->oGraphic
&& !mpImpl
->bNeedUpdate
&& pContainer
)
415 SetGraphicToContainer( *mpImpl
->oGraphic
, *pContainer
, mpImpl
->aPersistName
, OUString() );
418 comphelper::EmbeddedObjectContainer
* EmbeddedObjectRef::GetContainer() const
420 return mpImpl
->pContainer
;
423 sal_Int64
EmbeddedObjectRef::GetViewAspect() const
425 return mpImpl
->nViewAspect
;
428 void EmbeddedObjectRef::SetViewAspect( sal_Int64 nAspect
)
430 mpImpl
->nViewAspect
= nAspect
;
433 void EmbeddedObjectRef::Lock( bool bLock
)
435 mpImpl
->bIsLocked
= bLock
;
438 bool EmbeddedObjectRef::IsLocked() const
440 return mpImpl
->bIsLocked
;
443 void EmbeddedObjectRef::SetIsProtectedHdl(const Link
<LinkParamNone
*, bool>& rProtectedHdl
)
445 mpImpl
->m_aIsProtectedHdl
= rProtectedHdl
;
448 const Link
<LinkParamNone
*, bool> & EmbeddedObjectRef::GetIsProtectedHdl() const
450 return mpImpl
->m_aIsProtectedHdl
;
453 void EmbeddedObjectRef::GetReplacement( bool bUpdate
)
459 if (mpImpl
->oGraphic
)
460 aOldGraphic
= *mpImpl
->oGraphic
;
462 mpImpl
->oGraphic
.reset();
463 mpImpl
->aMediaType
.clear();
464 mpImpl
->oGraphic
.emplace();
465 mpImpl
->mnGraphicVersion
++;
467 else if ( !mpImpl
->oGraphic
)
469 mpImpl
->oGraphic
.emplace();
470 mpImpl
->mnGraphicVersion
++;
474 OSL_FAIL("No update, but replacement exists already!");
478 std::unique_ptr
<SvStream
> pGraphicStream(GetGraphicStream( bUpdate
));
479 if (!pGraphicStream
&& aOldGraphic
.IsNone())
481 // We have no old graphic, tried to get an updated one, but that failed. Try to get an old
482 // graphic instead of having no graphic at all.
483 pGraphicStream
= GetGraphicStream(false);
484 SAL_WARN("svtools.misc",
485 "EmbeddedObjectRef::GetReplacement: failed to get updated graphic stream");
488 if ( pGraphicStream
)
490 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
491 if( mpImpl
->oGraphic
)
492 rGF
.ImportGraphic( *mpImpl
->oGraphic
, u
"", *pGraphicStream
);
493 mpImpl
->mnGraphicVersion
++;
496 // note that UpdateReplacementOnDemand which resets mpImpl->oGraphic to null may have been called
497 // e.g. when exporting ooo58458-1.odt to doc
498 if (bUpdate
&& (!mpImpl
->oGraphic
|| mpImpl
->oGraphic
->IsNone()) && !aOldGraphic
.IsNone())
500 // We used to have an old graphic, tried to update and the update
501 // failed. Go back to the old graphic instead of having no graphic at
503 mpImpl
->oGraphic
.emplace(aOldGraphic
);
504 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetReplacement: failed to update graphic");
508 const Graphic
* EmbeddedObjectRef::GetGraphic() const
512 if ( mpImpl
->bNeedUpdate
)
513 // bNeedUpdate will be set to false while retrieving new replacement
514 const_cast < EmbeddedObjectRef
* >(this)->GetReplacement(true);
515 else if ( !mpImpl
->oGraphic
)
516 const_cast < EmbeddedObjectRef
* >(this)->GetReplacement(false);
518 catch( const uno::Exception
& )
520 DBG_UNHANDLED_EXCEPTION("svtools.misc", "Something went wrong on getting the graphic");
523 return mpImpl
->oGraphic
? &*mpImpl
->oGraphic
: nullptr;
526 Size
EmbeddedObjectRef::GetSize( MapMode
const * pTargetMapMode
) const
528 MapMode
aSourceMapMode( MapUnit::Map100thMM
);
531 if ( mpImpl
->nViewAspect
== embed::Aspects::MSOLE_ICON
)
533 const Graphic
* pGraphic
= GetGraphic();
536 aSourceMapMode
= pGraphic
->GetPrefMapMode();
537 aResult
= pGraphic
->GetPrefSize();
540 aResult
= Size( 2500, 2500 );
546 if (mpImpl
->mxObj
.is())
550 aSize
= mpImpl
->mxObj
->getVisualAreaSize(mpImpl
->nViewAspect
);
552 catch(const embed::NoVisualAreaSizeException
&)
554 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: no visual area size");
556 catch (const uno::Exception
&)
558 TOOLS_WARN_EXCEPTION("svtools.misc", "Something went wrong on getting of the size of the object");
563 aSourceMapMode
= MapMode(VCLUnoHelper::UnoEmbed2VCLMapUnit(mpImpl
->mxObj
->getMapUnit(mpImpl
->nViewAspect
)));
565 catch (const uno::Exception
&)
567 TOOLS_WARN_EXCEPTION("svtools.misc", "Can not get the map mode");
571 if ( !aSize
.Height
&& !aSize
.Width
)
573 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: empty size, defaulting to 5x5cm");
578 aResult
= Size( aSize
.Width
, aSize
.Height
);
581 if ( pTargetMapMode
)
582 aResult
= OutputDevice::LogicToLogic( aResult
, aSourceMapMode
, *pTargetMapMode
);
587 void EmbeddedObjectRef::SetGraphicStream( const uno::Reference
< io::XInputStream
>& xInGrStream
,
588 const OUString
& rMediaType
)
590 mpImpl
->oGraphic
.emplace();
591 mpImpl
->aMediaType
= rMediaType
;
592 mpImpl
->mnGraphicVersion
++;
594 std::unique_ptr
<SvStream
> pGraphicStream(::utl::UcbStreamHelper::CreateStream( xInGrStream
));
596 if ( pGraphicStream
)
598 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
599 rGF
.ImportGraphic( *mpImpl
->oGraphic
, u
"", *pGraphicStream
);
600 mpImpl
->mnGraphicVersion
++;
602 if ( mpImpl
->pContainer
)
604 pGraphicStream
->Seek( 0 );
605 uno::Reference
< io::XInputStream
> xInSeekGrStream
= new ::utl::OSeekableInputStreamWrapper( pGraphicStream
.get() );
607 mpImpl
->pContainer
->InsertGraphicStream( xInSeekGrStream
, mpImpl
->aPersistName
, rMediaType
);
611 mpImpl
->bNeedUpdate
= false;
615 void EmbeddedObjectRef::SetGraphic( const Graphic
& rGraphic
, const OUString
& rMediaType
)
617 mpImpl
->oGraphic
.emplace( rGraphic
);
618 mpImpl
->aMediaType
= rMediaType
;
619 mpImpl
->mnGraphicVersion
++;
621 if ( mpImpl
->pContainer
)
622 SetGraphicToContainer( rGraphic
, *mpImpl
->pContainer
, mpImpl
->aPersistName
, rMediaType
);
624 mpImpl
->bNeedUpdate
= false;
627 std::unique_ptr
<SvStream
> EmbeddedObjectRef::GetGraphicStream( bool bUpdate
) const
629 DBG_ASSERT( bUpdate
|| mpImpl
->pContainer
, "Can't retrieve current graphic!" );
630 uno::Reference
< io::XInputStream
> xStream
;
631 if ( mpImpl
->pContainer
&& !bUpdate
)
633 SAL_INFO( "svtools.misc", "getting stream from container" );
634 // try to get graphic stream from container storage
635 xStream
= mpImpl
->pContainer
->GetGraphicStream(mpImpl
->mxObj
, &mpImpl
->aMediaType
);
638 const sal_Int32 nConstBufferSize
= 32000;
639 std::unique_ptr
<SvMemoryStream
> pStream(new SvMemoryStream( 32000, 32000 ));
643 uno::Sequence
< sal_Int8
> aSequence ( nConstBufferSize
);
646 nRead
= xStream
->readBytes ( aSequence
, nConstBufferSize
);
647 pStream
->WriteBytes(aSequence
.getConstArray(), nRead
);
649 while ( nRead
== nConstBufferSize
);
651 pStream
->MakeReadOnly();
654 catch (const uno::Exception
&)
656 DBG_UNHANDLED_EXCEPTION("svtools.misc", "discarding broken embedded object preview");
664 SAL_INFO( "svtools.misc", "getting stream from object" );
665 bool bUpdateAllowed(true);
666 const comphelper::EmbeddedObjectContainer
* pContainer
= GetContainer();
670 uno::Reference
<embed::XLinkageSupport
> const xLinkage(
671 mpImpl
->mxObj
, uno::UNO_QUERY
);
672 if (xLinkage
.is() && xLinkage
->isLink())
674 bUpdateAllowed
= pContainer
->getUserAllowsLinkUpdate();
681 // update wanted or no stream in container storage available
682 xStream
= GetGraphicReplacementStream(mpImpl
->nViewAspect
, mpImpl
->mxObj
, &mpImpl
->aMediaType
);
686 if (mpImpl
->pContainer
)
688 bool bInsertGraphicStream
= true;
689 uno::Reference
<io::XSeekable
> xSeekable(xStream
, uno::UNO_QUERY
);
690 std::optional
<sal_Int64
> oPosition
;
693 oPosition
= xSeekable
->getPosition();
697 std::unique_ptr
<SvStream
> pResult
= utl::UcbStreamHelper::CreateStream(xStream
);
700 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
702 rGF
.ImportGraphic(aGraphic
, u
"", *pResult
);
703 if (aGraphic
.IsNone())
705 // The graphic is not something we can understand, don't overwrite a
706 // potentially working previous graphic.
707 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetGraphicStream: failed to parse xStream");
708 bInsertGraphicStream
= false;
712 if (xSeekable
.is() && oPosition
.has_value())
714 xSeekable
->seek(*oPosition
);
716 if (bInsertGraphicStream
)
718 mpImpl
->pContainer
->InsertGraphicStream(xStream
,mpImpl
->aPersistName
,mpImpl
->aMediaType
);
722 std::unique_ptr
<SvStream
> pResult
= ::utl::UcbStreamHelper::CreateStream( xStream
);
723 if (pResult
&& bUpdate
)
724 mpImpl
->bNeedUpdate
= false;
734 void EmbeddedObjectRef::DrawPaintReplacement( const tools::Rectangle
&rRect
, const OUString
&rText
, OutputDevice
*pOut
)
736 MapMode
aMM( MapUnit::MapAppFont
);
737 Size aAppFontSz
= pOut
->LogicToLogic( Size( 0, 8 ), &aMM
, nullptr );
738 vcl::Font
aFnt( "Helvetica", aAppFontSz
);
739 aFnt
.SetTransparent( true );
740 aFnt
.SetColor( COL_LIGHTRED
);
741 aFnt
.SetWeight( WEIGHT_BOLD
);
742 aFnt
.SetFamily( FAMILY_SWISS
);
745 pOut
->SetBackground();
746 pOut
->SetFont( aFnt
);
750 // Now scale text such that it fits in the rectangle
751 // We start with the default size and decrease 1-AppFont
752 for( sal_uInt16 i
= 8; i
> 2; i
-- )
754 aPt
.setX( (rRect
.GetWidth() - pOut
->GetTextWidth( rText
)) / 2 );
755 aPt
.setY( (rRect
.GetHeight() - pOut
->GetTextHeight()) / 2 );
770 // decrease for small images
771 aFnt
.SetFontSize( Size( 0, aAppFontSz
.Height() * i
/ 8 ) );
772 pOut
->SetFont( aFnt
);
778 BitmapEx
aBmp(BMP_PLUGIN
);
779 tools::Long nHeight
= rRect
.GetHeight() - pOut
->GetTextHeight();
780 tools::Long nWidth
= rRect
.GetWidth();
781 if(nHeight
> 0 && nWidth
> 0 && aBmp
.GetSizePixel().Width() > 0)
784 Point aP
= rRect
.TopLeft();
785 Size aBmpSize
= aBmp
.GetSizePixel();
787 if( nHeight
* 10 / nWidth
788 > aBmpSize
.Height() * 10 / aBmpSize
.Width() )
790 // adjust to the width
792 tools::Long nH
= nWidth
* aBmpSize
.Height() / aBmpSize
.Width();
794 aP
.AdjustY((nHeight
- nH
) / 2 );
799 // adjust to the height
801 tools::Long nW
= nHeight
* aBmpSize
.Width() / aBmpSize
.Height();
803 aP
.AdjustX((nWidth
- nW
) / 2 );
807 pOut
->DrawBitmapEx(aP
, Size( nWidth
, nHeight
), aBmp
);
810 pOut
->IntersectClipRegion( rRect
);
811 aPt
+= rRect
.TopLeft();
812 pOut
->DrawText( aPt
, rText
);
816 void EmbeddedObjectRef::DrawShading( const tools::Rectangle
&rRect
, OutputDevice
*pOut
)
818 GDIMetaFile
* pMtf
= pOut
->GetConnectMetaFile();
819 if( pMtf
&& pMtf
->IsRecord() )
823 pOut
->SetLineColor( COL_BLACK
);
825 Size aPixSize
= pOut
->LogicToPixel( rRect
.GetSize() );
826 aPixSize
.AdjustWidth( -1 );
827 aPixSize
.AdjustHeight( -1 );
828 Point aPixViewPos
= pOut
->LogicToPixel( rRect
.TopLeft() );
829 sal_Int32 nMax
= aPixSize
.Width() + aPixSize
.Height();
830 for( sal_Int32 i
= 5; i
< nMax
; i
+= 5 )
832 Point
a1( aPixViewPos
), a2( aPixViewPos
);
833 if( i
> aPixSize
.Width() )
834 a1
+= Point( aPixSize
.Width(), i
- aPixSize
.Width() );
837 if( i
> aPixSize
.Height() )
838 a2
+= Point( i
- aPixSize
.Height(), aPixSize
.Height() );
842 pOut
->DrawLine( pOut
->PixelToLogic( a1
), pOut
->PixelToLogic( a2
) );
849 bool EmbeddedObjectRef::TryRunningState( const uno::Reference
< embed::XEmbeddedObject
>& xEmbObj
)
856 if ( xEmbObj
->getCurrentState() == embed::EmbedStates::LOADED
)
857 xEmbObj
->changeState( embed::EmbedStates::RUNNING
);
859 catch (const uno::Exception
&)
867 void EmbeddedObjectRef::SetGraphicToContainer( const Graphic
& rGraphic
,
868 comphelper::EmbeddedObjectContainer
& aContainer
,
869 const OUString
& aName
,
870 const OUString
& aMediaType
)
872 SvMemoryStream aStream
;
873 aStream
.SetVersion( SOFFICE_FILEFORMAT_CURRENT
);
875 auto pGfxLink
= rGraphic
.GetSharedGfxLink();
876 if (pGfxLink
&& pGfxLink
->IsNative())
878 if (pGfxLink
->ExportNative(aStream
))
881 uno::Reference
<io::XInputStream
> xStream
= new ::utl::OSeekableInputStreamWrapper(aStream
);
882 aContainer
.InsertGraphicStream(xStream
, aName
, aMediaType
);
885 OSL_FAIL("Export of graphic is failed!");
889 TypeSerializer
aSerializer(aStream
);
890 aSerializer
.writeGraphic(rGraphic
);
891 if (aStream
.GetError() == ERRCODE_NONE
)
894 uno::Reference
<io::XInputStream
> xStream
= new ::utl::OSeekableInputStreamWrapper(aStream
);
895 aContainer
.InsertGraphicStream(xStream
, aName
, aMediaType
);
898 OSL_FAIL("Export of graphic is failed!");
902 uno::Reference
< io::XInputStream
> EmbeddedObjectRef::GetGraphicReplacementStream(
903 sal_Int64 nViewAspect
,
904 const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
905 OUString
* pMediaType
)
908 return ::comphelper::EmbeddedObjectContainer::GetGraphicReplacementStream(nViewAspect
,xObj
,pMediaType
);
911 bool EmbeddedObjectRef::IsChart(const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
)
913 SvGlobalName
aObjClsId(xObj
->getClassID());
914 return SvGlobalName(SO3_SCH_CLASSID_30
) == aObjClsId
915 || SvGlobalName(SO3_SCH_CLASSID_40
) == aObjClsId
916 || SvGlobalName(SO3_SCH_CLASSID_50
) == aObjClsId
917 || SvGlobalName(SO3_SCH_CLASSID_60
) == aObjClsId
;
920 void EmbeddedObjectRef::UpdateReplacement( bool bUpdateOle
)
922 if (mpImpl
->bUpdating
)
924 SAL_WARN("svtools.misc", "UpdateReplacement called while UpdateReplacement already underway");
927 mpImpl
->bUpdating
= true;
928 UpdateOleObject( bUpdateOle
);
929 GetReplacement(true);
930 UpdateOleObject( false );
931 mpImpl
->bUpdating
= false;
934 void EmbeddedObjectRef::UpdateOleObject( bool bUpdateOle
)
936 embed::EmbeddedUpdate
* pObj
= dynamic_cast<embed::EmbeddedUpdate
*> (GetObject().get());
938 pObj
->SetOleState( bUpdateOle
);
942 void EmbeddedObjectRef::UpdateReplacementOnDemand()
944 mpImpl
->oGraphic
.reset();
945 mpImpl
->bNeedUpdate
= true;
946 mpImpl
->mnGraphicVersion
++;
948 if( mpImpl
->pContainer
)
950 //remove graphic from container thus a new up to date one is requested on save
951 mpImpl
->pContainer
->RemoveGraphicStream( mpImpl
->aPersistName
);
955 bool EmbeddedObjectRef::IsChart() const
957 //todo maybe for 3.0:
958 //if the changes work good for chart
959 //we should apply them for all own ole objects
961 //#i83708# #i81857# #i79578# request an ole replacement image only if really necessary
962 //as this call can be very expensive and does block the user interface as long at it takes
964 if (!mpImpl
->mxObj
.is())
967 return EmbeddedObjectRef::IsChart(mpImpl
->mxObj
);
970 // MT: Only used for getting accessible attributes, which are not localized
971 OUString
EmbeddedObjectRef::GetChartType()
974 if ( mpImpl
->mxObj
.is() )
978 if ( svt::EmbeddedObjectRef::TryRunningState( mpImpl
->mxObj
) )
980 uno::Reference
< chart2::XChartDocument
> xChart( mpImpl
->mxObj
->getComponent(), uno::UNO_QUERY
);
983 uno::Reference
< chart2::XDiagram
> xDiagram( xChart
->getFirstDiagram());
986 uno::Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xDiagram
, uno::UNO_QUERY_THROW
);
987 const uno::Sequence
< uno::Reference
< chart2::XCoordinateSystem
> > aCooSysSeq( xCooSysCnt
->getCoordinateSystems());
988 // IA2 CWS. Unused: int nCoordinateCount = aCooSysSeq.getLength();
989 bool bGetChartType
= false;
990 for( const auto& rCooSys
: aCooSysSeq
)
992 uno::Reference
< chart2::XChartTypeContainer
> xCTCnt( rCooSys
, uno::UNO_QUERY_THROW
);
993 const uno::Sequence
< uno::Reference
< chart2::XChartType
> > aChartTypes( xCTCnt
->getChartTypes());
994 int nDimesionCount
= rCooSys
->getDimension();
995 if( nDimesionCount
== 3 )
999 for( const auto& rChartType
: aChartTypes
)
1001 OUString strChartType
= rChartType
->getChartType();
1002 if (strChartType
== "com.sun.star.chart2.AreaChartType")
1005 bGetChartType
= true;
1007 else if (strChartType
== "com.sun.star.chart2.BarChartType")
1010 bGetChartType
= true;
1012 else if (strChartType
== "com.sun.star.chart2.ColumnChartType")
1014 uno::Reference
< beans::XPropertySet
> xProp( rCooSys
, uno::UNO_QUERY
);
1017 bool bCurrent
= false;
1018 if( xProp
->getPropertyValue( "SwapXAndYAxis" ) >>= bCurrent
)
1024 bGetChartType
= true;
1028 else if (strChartType
== "com.sun.star.chart2.LineChartType")
1031 bGetChartType
= true;
1033 else if (strChartType
== "com.sun.star.chart2.ScatterChartType")
1035 Style
+= "XY Chart";
1036 bGetChartType
= true;
1038 else if (strChartType
== "com.sun.star.chart2.PieChartType")
1041 bGetChartType
= true;
1043 else if (strChartType
== "com.sun.star.chart2.NetChartType")
1046 bGetChartType
= true;
1048 else if (strChartType
== "com.sun.star.chart2.CandleStickChartType")
1050 Style
+= "Candle Stick Chart";
1051 bGetChartType
= true;
1065 sal_uInt32
EmbeddedObjectRef::getGraphicVersion() const
1067 return mpImpl
->mnGraphicVersion
;
1070 void EmbeddedObjectRef::SetDefaultSizeForChart( const Size
& rSizeIn_100TH_MM
)
1072 //#i103460# charts do not necessarily have an own size within ODF files,
1073 //for this case they need to use the size settings from the surrounding frame,
1074 //which is made available with this method
1076 mpImpl
->aDefaultSizeForChart_In_100TH_MM
= awt::Size( rSizeIn_100TH_MM
.getWidth(), rSizeIn_100TH_MM
.getHeight() );
1078 uno::Reference
<chart2::XDefaultSizeTransmitter
> xSizeTransmitter(mpImpl
->mxObj
, uno::UNO_QUERY
);
1079 DBG_ASSERT( xSizeTransmitter
.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
1080 if( xSizeTransmitter
.is() )
1081 xSizeTransmitter
->setDefaultSize( mpImpl
->aDefaultSizeForChart_In_100TH_MM
);
1084 void EmbeddedObjectRef::dumpAsXml(xmlTextWriterPtr pWriter
) const
1086 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("EmbeddedObjectRef"));
1087 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
1089 mpImpl
->dumpAsXml(pWriter
);
1091 (void)xmlTextWriterEndElement(pWriter
);
1096 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */