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(u
""_ustr
);
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
)
457 // Do not clear / reset mpImpl->oGraphic, because it would appear as no replacement
458 // on any call to getReplacementGraphic during the external calls to the OLE object,
459 // which may release mutexes. Only replace it when done.
460 mpImpl
->aMediaType
.clear();
462 else if (mpImpl
->oGraphic
)
464 OSL_FAIL("No update, but replacement exists already!");
468 std::unique_ptr
<SvStream
> pGraphicStream(GetGraphicStream( bUpdate
));
469 if (!pGraphicStream
&& bUpdate
&& (!mpImpl
->oGraphic
|| mpImpl
->oGraphic
->IsNone()))
471 // We have no old graphic, tried to get an updated one, but that failed. Try to get an old
472 // graphic instead of having no graphic at all.
473 pGraphicStream
= GetGraphicStream(false);
474 SAL_WARN("svtools.misc",
475 "EmbeddedObjectRef::GetReplacement: failed to get updated graphic stream");
478 if ( pGraphicStream
)
480 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
482 rGF
.ImportGraphic(aNewGraphic
, u
"", *pGraphicStream
);
483 if (!aNewGraphic
.IsNone())
485 mpImpl
->oGraphic
.emplace(aNewGraphic
);
486 mpImpl
->mnGraphicVersion
++;
491 const Graphic
* EmbeddedObjectRef::GetGraphic() const
495 if ( mpImpl
->bNeedUpdate
)
496 // bNeedUpdate will be set to false while retrieving new replacement
497 const_cast < EmbeddedObjectRef
* >(this)->GetReplacement(true);
498 else if ( !mpImpl
->oGraphic
)
499 const_cast < EmbeddedObjectRef
* >(this)->GetReplacement(false);
501 catch( const uno::Exception
& )
503 DBG_UNHANDLED_EXCEPTION("svtools.misc", "Something went wrong on getting the graphic");
506 return mpImpl
->oGraphic
? &*mpImpl
->oGraphic
: nullptr;
509 Size
EmbeddedObjectRef::GetSize( MapMode
const * pTargetMapMode
) const
511 MapMode
aSourceMapMode( MapUnit::Map100thMM
);
514 if ( mpImpl
->nViewAspect
== embed::Aspects::MSOLE_ICON
)
516 const Graphic
* pGraphic
= GetGraphic();
519 aSourceMapMode
= pGraphic
->GetPrefMapMode();
520 aResult
= pGraphic
->GetPrefSize();
523 aResult
= Size( 2500, 2500 );
529 if (mpImpl
->mxObj
.is())
533 aSize
= mpImpl
->mxObj
->getVisualAreaSize(mpImpl
->nViewAspect
);
535 catch(const embed::NoVisualAreaSizeException
&)
537 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: no visual area size");
539 catch (const uno::Exception
&)
541 TOOLS_WARN_EXCEPTION("svtools.misc", "Something went wrong on getting of the size of the object");
546 aSourceMapMode
= MapMode(VCLUnoHelper::UnoEmbed2VCLMapUnit(mpImpl
->mxObj
->getMapUnit(mpImpl
->nViewAspect
)));
548 catch (const uno::Exception
&)
550 TOOLS_WARN_EXCEPTION("svtools.misc", "Can not get the map mode");
554 if ( !aSize
.Height
&& !aSize
.Width
)
556 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: empty size, defaulting to 5x5cm");
561 aResult
= Size( aSize
.Width
, aSize
.Height
);
564 if ( pTargetMapMode
)
565 aResult
= OutputDevice::LogicToLogic( aResult
, aSourceMapMode
, *pTargetMapMode
);
570 void EmbeddedObjectRef::SetGraphicStream( const uno::Reference
< io::XInputStream
>& xInGrStream
,
571 const OUString
& rMediaType
)
574 std::unique_ptr
<SvStream
> pGraphicStream(::utl::UcbStreamHelper::CreateStream( xInGrStream
));
576 if ( pGraphicStream
)
578 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
579 rGF
.ImportGraphic(aNewGraphic
, u
"", *pGraphicStream
);
581 if ( mpImpl
->pContainer
)
583 pGraphicStream
->Seek( 0 );
584 uno::Reference
< io::XInputStream
> xInSeekGrStream
= new ::utl::OSeekableInputStreamWrapper( pGraphicStream
.get() );
586 mpImpl
->pContainer
->InsertGraphicStream( xInSeekGrStream
, mpImpl
->aPersistName
, rMediaType
);
590 mpImpl
->oGraphic
.emplace(aNewGraphic
);
591 mpImpl
->aMediaType
= rMediaType
;
592 mpImpl
->mnGraphicVersion
++;
593 mpImpl
->bNeedUpdate
= false;
596 void EmbeddedObjectRef::SetGraphic( const Graphic
& rGraphic
, const OUString
& rMediaType
)
598 mpImpl
->oGraphic
.emplace( rGraphic
);
599 mpImpl
->aMediaType
= rMediaType
;
600 mpImpl
->mnGraphicVersion
++;
602 if ( mpImpl
->pContainer
)
603 SetGraphicToContainer( rGraphic
, *mpImpl
->pContainer
, mpImpl
->aPersistName
, rMediaType
);
605 mpImpl
->bNeedUpdate
= false;
608 std::unique_ptr
<SvStream
> EmbeddedObjectRef::GetGraphicStream( bool bUpdate
) const
610 DBG_ASSERT( bUpdate
|| mpImpl
->pContainer
, "Can't retrieve current graphic!" );
611 uno::Reference
< io::XInputStream
> xStream
;
612 if ( mpImpl
->pContainer
&& !bUpdate
)
614 SAL_INFO( "svtools.misc", "getting stream from container" );
615 // try to get graphic stream from container storage
616 xStream
= mpImpl
->pContainer
->GetGraphicStream(mpImpl
->mxObj
, &mpImpl
->aMediaType
);
619 const sal_Int32 nConstBufferSize
= 32000;
620 std::unique_ptr
<SvMemoryStream
> pStream(new SvMemoryStream( 32000, 32000 ));
624 uno::Sequence
< sal_Int8
> aSequence ( nConstBufferSize
);
627 nRead
= xStream
->readBytes ( aSequence
, nConstBufferSize
);
628 pStream
->WriteBytes(aSequence
.getConstArray(), nRead
);
630 while ( nRead
== nConstBufferSize
);
632 pStream
->MakeReadOnly();
635 catch (const uno::Exception
&)
637 DBG_UNHANDLED_EXCEPTION("svtools.misc", "discarding broken embedded object preview");
645 SAL_INFO( "svtools.misc", "getting stream from object" );
646 bool bUpdateAllowed(true);
647 const comphelper::EmbeddedObjectContainer
* pContainer
= GetContainer();
651 uno::Reference
<embed::XLinkageSupport
> const xLinkage(
652 mpImpl
->mxObj
, uno::UNO_QUERY
);
653 if (xLinkage
.is() && xLinkage
->isLink())
655 bUpdateAllowed
= pContainer
->getUserAllowsLinkUpdate();
662 // update wanted or no stream in container storage available
663 xStream
= GetGraphicReplacementStream(mpImpl
->nViewAspect
, mpImpl
->mxObj
, &mpImpl
->aMediaType
);
667 if (mpImpl
->pContainer
)
669 bool bInsertGraphicStream
= true;
670 uno::Reference
<io::XSeekable
> xSeekable(xStream
, uno::UNO_QUERY
);
671 std::optional
<sal_Int64
> oPosition
;
674 oPosition
= xSeekable
->getPosition();
678 std::unique_ptr
<SvStream
> pResult
= utl::UcbStreamHelper::CreateStream(xStream
);
681 GraphicFilter
& rGF
= GraphicFilter::GetGraphicFilter();
683 rGF
.ImportGraphic(aGraphic
, u
"", *pResult
);
684 if (aGraphic
.IsNone())
686 // The graphic is not something we can understand, don't overwrite a
687 // potentially working previous graphic.
688 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetGraphicStream: failed to parse xStream");
689 bInsertGraphicStream
= false;
693 if (xSeekable
.is() && oPosition
.has_value())
695 xSeekable
->seek(*oPosition
);
697 if (bInsertGraphicStream
)
699 mpImpl
->pContainer
->InsertGraphicStream(xStream
,mpImpl
->aPersistName
,mpImpl
->aMediaType
);
703 std::unique_ptr
<SvStream
> pResult
= ::utl::UcbStreamHelper::CreateStream( xStream
);
704 if (pResult
&& bUpdate
)
705 mpImpl
->bNeedUpdate
= false;
715 void EmbeddedObjectRef::DrawPaintReplacement( const tools::Rectangle
&rRect
, const OUString
&rText
, OutputDevice
*pOut
)
717 MapMode
aMM( MapUnit::MapAppFont
);
718 Size aAppFontSz
= pOut
->LogicToLogic( Size( 0, 8 ), &aMM
, nullptr );
719 vcl::Font
aFnt( u
"Noto Sans"_ustr
, aAppFontSz
);
720 aFnt
.SetTransparent( true );
721 aFnt
.SetColor( COL_LIGHTRED
);
722 aFnt
.SetWeight( WEIGHT_BOLD
);
723 aFnt
.SetFamily( FAMILY_SWISS
);
726 pOut
->SetBackground();
727 pOut
->SetFont( aFnt
);
731 // Now scale text such that it fits in the rectangle
732 // We start with the default size and decrease 1-AppFont
733 for( sal_uInt16 i
= 8; i
> 2; i
-- )
735 aPt
.setX( (rRect
.GetWidth() - pOut
->GetTextWidth( rText
)) / 2 );
736 aPt
.setY( (rRect
.GetHeight() - pOut
->GetTextHeight()) / 2 );
751 // decrease for small images
752 aFnt
.SetFontSize( Size( 0, aAppFontSz
.Height() * i
/ 8 ) );
753 pOut
->SetFont( aFnt
);
759 BitmapEx
aBmp(BMP_PLUGIN
);
760 tools::Long nHeight
= rRect
.GetHeight() - pOut
->GetTextHeight();
761 tools::Long nWidth
= rRect
.GetWidth();
762 if(nHeight
> 0 && nWidth
> 0 && aBmp
.GetSizePixel().Width() > 0)
765 Point aP
= rRect
.TopLeft();
766 Size aBmpSize
= aBmp
.GetSizePixel();
768 if( nHeight
* 10 / nWidth
769 > aBmpSize
.Height() * 10 / aBmpSize
.Width() )
771 // adjust to the width
773 tools::Long nH
= nWidth
* aBmpSize
.Height() / aBmpSize
.Width();
775 aP
.AdjustY((nHeight
- nH
) / 2 );
780 // adjust to the height
782 tools::Long nW
= nHeight
* aBmpSize
.Width() / aBmpSize
.Height();
784 aP
.AdjustX((nWidth
- nW
) / 2 );
788 pOut
->DrawBitmapEx(aP
, Size( nWidth
, nHeight
), aBmp
);
791 pOut
->IntersectClipRegion( rRect
);
792 aPt
+= rRect
.TopLeft();
793 pOut
->DrawText( aPt
, rText
);
797 void EmbeddedObjectRef::DrawShading( const tools::Rectangle
&rRect
, OutputDevice
*pOut
)
799 GDIMetaFile
* pMtf
= pOut
->GetConnectMetaFile();
800 if( pMtf
&& pMtf
->IsRecord() )
804 pOut
->SetLineColor( COL_BLACK
);
806 Size aPixSize
= pOut
->LogicToPixel( rRect
.GetSize() );
807 aPixSize
.AdjustWidth( -1 );
808 aPixSize
.AdjustHeight( -1 );
809 Point aPixViewPos
= pOut
->LogicToPixel( rRect
.TopLeft() );
810 sal_Int32 nMax
= aPixSize
.Width() + aPixSize
.Height();
811 for( sal_Int32 i
= 5; i
< nMax
; i
+= 5 )
813 Point
a1( aPixViewPos
), a2( aPixViewPos
);
814 if( i
> aPixSize
.Width() )
815 a1
+= Point( aPixSize
.Width(), i
- aPixSize
.Width() );
818 if( i
> aPixSize
.Height() )
819 a2
+= Point( i
- aPixSize
.Height(), aPixSize
.Height() );
823 pOut
->DrawLine( pOut
->PixelToLogic( a1
), pOut
->PixelToLogic( a2
) );
830 bool EmbeddedObjectRef::TryRunningState( const uno::Reference
< embed::XEmbeddedObject
>& xEmbObj
)
837 if ( xEmbObj
->getCurrentState() == embed::EmbedStates::LOADED
)
838 xEmbObj
->changeState( embed::EmbedStates::RUNNING
);
840 catch (const uno::Exception
&)
848 void EmbeddedObjectRef::SetGraphicToContainer( const Graphic
& rGraphic
,
849 comphelper::EmbeddedObjectContainer
& aContainer
,
850 const OUString
& aName
,
851 const OUString
& aMediaType
)
853 SvMemoryStream aStream
;
854 aStream
.SetVersion( SOFFICE_FILEFORMAT_CURRENT
);
856 const auto& pGfxLink
= rGraphic
.GetSharedGfxLink();
857 if (pGfxLink
&& pGfxLink
->IsNative())
859 if (pGfxLink
->ExportNative(aStream
))
862 uno::Reference
<io::XInputStream
> xStream
= new ::utl::OSeekableInputStreamWrapper(aStream
);
863 aContainer
.InsertGraphicStream(xStream
, aName
, aMediaType
);
866 OSL_FAIL("Export of graphic is failed!");
870 TypeSerializer
aSerializer(aStream
);
871 aSerializer
.writeGraphic(rGraphic
);
872 if (aStream
.GetError() == ERRCODE_NONE
)
875 uno::Reference
<io::XInputStream
> xStream
= new ::utl::OSeekableInputStreamWrapper(aStream
);
876 aContainer
.InsertGraphicStream(xStream
, aName
, aMediaType
);
879 OSL_FAIL("Export of graphic is failed!");
883 uno::Reference
< io::XInputStream
> EmbeddedObjectRef::GetGraphicReplacementStream(
884 sal_Int64 nViewAspect
,
885 const uno::Reference
< embed::XEmbeddedObject
>& xObj
,
886 OUString
* pMediaType
)
889 return ::comphelper::EmbeddedObjectContainer::GetGraphicReplacementStream(nViewAspect
,xObj
,pMediaType
);
892 bool EmbeddedObjectRef::IsChart(const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObj
)
894 SvGlobalName
aObjClsId(xObj
->getClassID());
895 return SvGlobalName(SO3_SCH_CLASSID_30
) == aObjClsId
896 || SvGlobalName(SO3_SCH_CLASSID_40
) == aObjClsId
897 || SvGlobalName(SO3_SCH_CLASSID_50
) == aObjClsId
898 || SvGlobalName(SO3_SCH_CLASSID_60
) == aObjClsId
;
901 void EmbeddedObjectRef::UpdateReplacement( bool bUpdateOle
)
903 if (mpImpl
->bUpdating
)
905 SAL_WARN("svtools.misc", "UpdateReplacement called while UpdateReplacement already underway");
908 mpImpl
->bUpdating
= true;
909 UpdateOleObject( bUpdateOle
);
910 GetReplacement(true);
911 UpdateOleObject( false );
912 mpImpl
->bUpdating
= false;
915 void EmbeddedObjectRef::UpdateOleObject( bool bUpdateOle
)
917 embed::EmbeddedUpdate
* pObj
= dynamic_cast<embed::EmbeddedUpdate
*> (GetObject().get());
919 pObj
->SetOleState( bUpdateOle
);
923 void EmbeddedObjectRef::UpdateReplacementOnDemand()
925 mpImpl
->bNeedUpdate
= true;
927 if( mpImpl
->pContainer
)
929 //remove graphic from container thus a new up to date one is requested on save
930 mpImpl
->pContainer
->RemoveGraphicStream( mpImpl
->aPersistName
);
934 bool EmbeddedObjectRef::IsChart() const
936 //todo maybe for 3.0:
937 //if the changes work good for chart
938 //we should apply them for all own ole objects
940 //#i83708# #i81857# #i79578# request an ole replacement image only if really necessary
941 //as this call can be very expensive and does block the user interface as long at it takes
943 if (!mpImpl
->mxObj
.is())
946 return EmbeddedObjectRef::IsChart(mpImpl
->mxObj
);
949 // MT: Only used for getting accessible attributes, which are not localized
950 OUString
EmbeddedObjectRef::GetChartType()
953 if ( mpImpl
->mxObj
.is() )
957 if ( svt::EmbeddedObjectRef::TryRunningState( mpImpl
->mxObj
) )
959 uno::Reference
< chart2::XChartDocument
> xChart( mpImpl
->mxObj
->getComponent(), uno::UNO_QUERY
);
962 uno::Reference
< chart2::XDiagram
> xDiagram( xChart
->getFirstDiagram());
965 uno::Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xDiagram
, uno::UNO_QUERY_THROW
);
966 const uno::Sequence
< uno::Reference
< chart2::XCoordinateSystem
> > aCooSysSeq( xCooSysCnt
->getCoordinateSystems());
967 // IA2 CWS. Unused: int nCoordinateCount = aCooSysSeq.getLength();
968 bool bGetChartType
= false;
969 for( const auto& rCooSys
: aCooSysSeq
)
971 uno::Reference
< chart2::XChartTypeContainer
> xCTCnt( rCooSys
, uno::UNO_QUERY_THROW
);
972 const uno::Sequence
< uno::Reference
< chart2::XChartType
> > aChartTypes( xCTCnt
->getChartTypes());
973 int nDimesionCount
= rCooSys
->getDimension();
974 if( nDimesionCount
== 3 )
978 for( const auto& rChartType
: aChartTypes
)
980 OUString strChartType
= rChartType
->getChartType();
981 if (strChartType
== "com.sun.star.chart2.AreaChartType")
984 bGetChartType
= true;
986 else if (strChartType
== "com.sun.star.chart2.BarChartType")
989 bGetChartType
= true;
991 else if (strChartType
== "com.sun.star.chart2.ColumnChartType")
993 uno::Reference
< beans::XPropertySet
> xProp( rCooSys
, uno::UNO_QUERY
);
996 bool bCurrent
= false;
997 if( xProp
->getPropertyValue( u
"SwapXAndYAxis"_ustr
) >>= bCurrent
)
1003 bGetChartType
= true;
1007 else if (strChartType
== "com.sun.star.chart2.LineChartType")
1010 bGetChartType
= true;
1012 else if (strChartType
== "com.sun.star.chart2.ScatterChartType")
1014 Style
+= "XY Chart";
1015 bGetChartType
= true;
1017 else if (strChartType
== "com.sun.star.chart2.PieChartType")
1020 bGetChartType
= true;
1022 else if (strChartType
== "com.sun.star.chart2.NetChartType")
1025 bGetChartType
= true;
1027 else if (strChartType
== "com.sun.star.chart2.CandleStickChartType")
1029 Style
+= "Candle Stick Chart";
1030 bGetChartType
= true;
1044 sal_uInt32
EmbeddedObjectRef::getGraphicVersion() const
1046 return mpImpl
->mnGraphicVersion
;
1049 void EmbeddedObjectRef::SetDefaultSizeForChart( const Size
& rSizeIn_100TH_MM
)
1051 //#i103460# charts do not necessarily have an own size within ODF files,
1052 //for this case they need to use the size settings from the surrounding frame,
1053 //which is made available with this method
1055 mpImpl
->aDefaultSizeForChart_In_100TH_MM
= awt::Size( rSizeIn_100TH_MM
.getWidth(), rSizeIn_100TH_MM
.getHeight() );
1057 uno::Reference
<chart2::XDefaultSizeTransmitter
> xSizeTransmitter(mpImpl
->mxObj
, uno::UNO_QUERY
);
1058 DBG_ASSERT( xSizeTransmitter
.is(), "Object does not support XDefaultSizeTransmitter -> will cause #i103460#!" );
1059 if( xSizeTransmitter
.is() )
1060 xSizeTransmitter
->setDefaultSize( mpImpl
->aDefaultSizeForChart_In_100TH_MM
);
1063 void EmbeddedObjectRef::dumpAsXml(xmlTextWriterPtr pWriter
) const
1065 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("EmbeddedObjectRef"));
1066 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
1068 mpImpl
->dumpAsXml(pWriter
);
1070 (void)xmlTextWriterEndElement(pWriter
);
1075 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */