Update git submodules
[LibreOffice.git] / svtools / source / misc / embedhlp.cxx
blobb3a291936aed0ece49c85633c304fa5bca2ee3ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
60 #include <memory>
62 using namespace com::sun::star;
64 namespace svt {
66 namespace {
68 class EmbedEventListener_Impl : public ::cppu::WeakImplHelper < embed::XStateChangeListener,
69 document::XEventListener,
70 util::XModifyListener,
71 util::XCloseListener >
73 public:
74 EmbeddedObjectRef* pObject;
75 sal_Int32 nState;
77 explicit EmbedEventListener_Impl( EmbeddedObjectRef* p ) :
78 pObject(p)
79 , nState(-1)
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!" );
105 if ( xClose.is() )
106 xClose->addCloseListener( pRet );
108 uno::Reference < document::XEventBroadcaster > xBrd = p->GetObject();
109 if ( xBrd.is() )
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 );
116 if ( xMod.is() )
117 // listen for changes in running state (update replacements in case of changes)
118 xMod->addModifyListener( pRet );
122 return pRet;
125 void SAL_CALL EmbedEventListener_Impl::changingState( const lang::EventObject&,
126 ::sal_Int32,
127 ::sal_Int32 )
131 void SAL_CALL EmbedEventListener_Impl::stateChanged( const lang::EventObject&,
132 ::sal_Int32 nOldState,
133 ::sal_Int32 nNewState )
135 SolarMutexGuard aGuard;
136 nState = nNewState;
137 if ( !pObject )
138 return;
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
171 if ( xMod.is() )
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) )
180 return;
182 if ( nState == embed::EmbedStates::RUNNING )
184 // updates only necessary in non-active states
185 if( pObject->IsChart() )
186 pObject->UpdateReplacementOnDemand();
187 else
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() )
222 pObject->Clear();
223 pObject = nullptr;
227 void SAL_CALL EmbedEventListener_Impl::disposing( const lang::EventObject& aEvent )
229 if ( pObject && aEvent.Source == pObject->GetObject() )
231 pObject->Clear();
232 pObject = nullptr;
236 struct EmbeddedObjectRef_Impl
238 uno::Reference <embed::XEmbeddedObject> mxObj;
240 rtl::Reference<EmbedEventListener_Impl> mxListener;
241 OUString aPersistName;
242 OUString aMediaType;
243 comphelper::EmbeddedObjectContainer* pContainer;
244 std::optional<Graphic> oGraphic;
245 sal_Int64 nViewAspect;
246 bool bIsLocked:1;
247 bool bNeedUpdate:1;
248 bool bUpdating:1;
250 // #i104867#
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() :
257 pContainer(nullptr),
258 nViewAspect(embed::Aspects::MSOLE_CONTENT),
259 bIsLocked(false),
260 bNeedUpdate(false),
261 bUpdating(false),
262 mnGraphicVersion(0),
263 aDefaultSizeForChart_In_100TH_MM(awt::Size(8000,7000))
266 EmbeddedObjectRef_Impl( const EmbeddedObjectRef_Impl& r ) :
267 mxObj(r.mxObj),
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),
275 mnGraphicVersion(0),
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);
292 if (pComponent.is())
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);
303 if (oGraphic)
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()
343 Clear();
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!");
350 Clear();
351 mpImpl->nViewAspect = nAspect;
352 mpImpl->mxObj = xObj;
353 mpImpl->mxListener = EmbedEventListener_Impl::Create( this );
355 //#i103460#
356 if ( IsChart() )
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 )
455 if ( 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!");
465 return;
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();
481 Graphic aNewGraphic;
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 );
512 Size aResult;
514 if ( mpImpl->nViewAspect == embed::Aspects::MSOLE_ICON )
516 const Graphic* pGraphic = GetGraphic();
517 if ( pGraphic )
519 aSourceMapMode = pGraphic->GetPrefMapMode();
520 aResult = pGraphic->GetPrefSize();
522 else
523 aResult = Size( 2500, 2500 );
525 else
527 awt::Size aSize;
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");
557 aSize.Width = 5000;
558 aSize.Height = 5000;
561 aResult = Size( aSize.Width, aSize.Height );
564 if ( pTargetMapMode )
565 aResult = OutputDevice::LogicToLogic( aResult, aSourceMapMode, *pTargetMapMode );
567 return aResult;
570 void EmbeddedObjectRef::SetGraphicStream( const uno::Reference< io::XInputStream >& xInGrStream,
571 const OUString& rMediaType )
573 Graphic aNewGraphic;
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);
617 if ( xStream.is() )
619 const sal_Int32 nConstBufferSize = 32000;
620 std::unique_ptr<SvMemoryStream> pStream(new SvMemoryStream( 32000, 32000 ));
623 sal_Int32 nRead=0;
624 uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
627 nRead = xStream->readBytes ( aSequence, nConstBufferSize );
628 pStream->WriteBytes(aSequence.getConstArray(), nRead);
630 while ( nRead == nConstBufferSize );
631 pStream->Seek(0);
632 pStream->MakeReadOnly();
633 return pStream;
635 catch (const uno::Exception&)
637 DBG_UNHANDLED_EXCEPTION("svtools.misc", "discarding broken embedded object preview");
638 xStream.clear();
643 if ( !xStream.is() )
645 SAL_INFO( "svtools.misc", "getting stream from object" );
646 bool bUpdateAllowed(true);
647 const comphelper::EmbeddedObjectContainer* pContainer = GetContainer();
649 if(pContainer)
651 uno::Reference<embed::XLinkageSupport> const xLinkage(
652 mpImpl->mxObj, uno::UNO_QUERY);
653 if (xLinkage.is() && xLinkage->isLink())
655 bUpdateAllowed = pContainer->getUserAllowsLinkUpdate();
660 if (bUpdateAllowed)
662 // update wanted or no stream in container storage available
663 xStream = GetGraphicReplacementStream(mpImpl->nViewAspect, mpImpl->mxObj, &mpImpl->aMediaType);
665 if(xStream.is())
667 if (mpImpl->pContainer)
669 bool bInsertGraphicStream = true;
670 uno::Reference<io::XSeekable> xSeekable(xStream, uno::UNO_QUERY);
671 std::optional<sal_Int64> oPosition;
672 if (xSeekable.is())
674 oPosition = xSeekable->getPosition();
676 if (bUpdate)
678 std::unique_ptr<SvStream> pResult = utl::UcbStreamHelper::CreateStream(xStream);
679 if (pResult)
681 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
682 Graphic aGraphic;
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;
707 return pResult;
712 return nullptr;
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 );
725 pOut->Push();
726 pOut->SetBackground();
727 pOut->SetFont( aFnt );
729 Point aPt;
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 );
738 bool bTiny = false;
739 if( aPt.X() < 0 )
741 bTiny = true;
742 aPt.setX( 0 );
744 if( aPt.Y() < 0 )
746 bTiny = true;
747 aPt.setY( 0 );
749 if( bTiny )
751 // decrease for small images
752 aFnt.SetFontSize( Size( 0, aAppFontSz.Height() * i / 8 ) );
753 pOut->SetFont( aFnt );
755 else
756 break;
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)
764 aPt.setY( nHeight );
765 Point aP = rRect.TopLeft();
766 Size aBmpSize = aBmp.GetSizePixel();
767 // fit bitmap in
768 if( nHeight * 10 / nWidth
769 > aBmpSize.Height() * 10 / aBmpSize.Width() )
771 // adjust to the width
772 // keep proportions
773 tools::Long nH = nWidth * aBmpSize.Height() / aBmpSize.Width();
774 // center
775 aP.AdjustY((nHeight - nH) / 2 );
776 nHeight = nH;
778 else
780 // adjust to the height
781 // keep proportions
782 tools::Long nW = nHeight * aBmpSize.Width() / aBmpSize.Height();
783 // center
784 aP.AdjustX((nWidth - nW) / 2 );
785 nWidth = nW;
788 pOut->DrawBitmapEx(aP, Size( nWidth, nHeight ), aBmp);
791 pOut->IntersectClipRegion( rRect );
792 aPt += rRect.TopLeft();
793 pOut->DrawText( aPt, rText );
794 pOut->Pop();
797 void EmbeddedObjectRef::DrawShading( const tools::Rectangle &rRect, OutputDevice *pOut )
799 GDIMetaFile * pMtf = pOut->GetConnectMetaFile();
800 if( pMtf && pMtf->IsRecord() )
801 return;
803 pOut->Push();
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() );
816 else
817 a1 += Point( i, 0 );
818 if( i > aPixSize.Height() )
819 a2 += Point( i - aPixSize.Height(), aPixSize.Height() );
820 else
821 a2 += Point( 0, i );
823 pOut->DrawLine( pOut->PixelToLogic( a1 ), pOut->PixelToLogic( a2 ) );
826 pOut->Pop();
830 bool EmbeddedObjectRef::TryRunningState( const uno::Reference < embed::XEmbeddedObject >& xEmbObj )
832 if ( !xEmbObj.is() )
833 return false;
837 if ( xEmbObj->getCurrentState() == embed::EmbedStates::LOADED )
838 xEmbObj->changeState( embed::EmbedStates::RUNNING );
840 catch (const uno::Exception&)
842 return false;
845 return true;
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))
861 aStream.Seek(0);
862 uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
863 aContainer.InsertGraphicStream(xStream, aName, aMediaType);
865 else
866 OSL_FAIL("Export of graphic is failed!");
868 else
870 TypeSerializer aSerializer(aStream);
871 aSerializer.writeGraphic(rGraphic);
872 if (aStream.GetError() == ERRCODE_NONE)
874 aStream.Seek(0);
875 uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
876 aContainer.InsertGraphicStream(xStream, aName, aMediaType);
878 else
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 )
887 noexcept
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");
906 return;
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());
918 if( pObj )
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())
944 return false;
946 return EmbeddedObjectRef::IsChart(mpImpl->mxObj);
949 // MT: Only used for getting accessible attributes, which are not localized
950 OUString EmbeddedObjectRef::GetChartType()
952 OUString Style;
953 if ( mpImpl->mxObj.is() )
955 if ( IsChart() )
957 if ( svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObj ) )
959 uno::Reference< chart2::XChartDocument > xChart( mpImpl->mxObj->getComponent(), uno::UNO_QUERY );
960 if (xChart.is())
962 uno::Reference< chart2::XDiagram > xDiagram( xChart->getFirstDiagram());
963 if( ! xDiagram.is())
964 return OUString();
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 )
975 Style += "3D ";
976 else
977 Style += "2D ";
978 for( const auto& rChartType : aChartTypes )
980 OUString strChartType = rChartType->getChartType();
981 if (strChartType == "com.sun.star.chart2.AreaChartType")
983 Style += "Areas";
984 bGetChartType = true;
986 else if (strChartType == "com.sun.star.chart2.BarChartType")
988 Style += "Bars";
989 bGetChartType = true;
991 else if (strChartType == "com.sun.star.chart2.ColumnChartType")
993 uno::Reference< beans::XPropertySet > xProp( rCooSys, uno::UNO_QUERY );
994 if( xProp.is())
996 bool bCurrent = false;
997 if( xProp->getPropertyValue( u"SwapXAndYAxis"_ustr ) >>= bCurrent )
999 if (bCurrent)
1000 Style += "Bars";
1001 else
1002 Style += "Columns";
1003 bGetChartType = true;
1007 else if (strChartType == "com.sun.star.chart2.LineChartType")
1009 Style += "Lines";
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")
1019 Style += "Pies";
1020 bGetChartType = true;
1022 else if (strChartType == "com.sun.star.chart2.NetChartType")
1024 Style += "Radar";
1025 bGetChartType = true;
1027 else if (strChartType == "com.sun.star.chart2.CandleStickChartType")
1029 Style += "Candle Stick Chart";
1030 bGetChartType = true;
1032 if (bGetChartType)
1033 return Style;
1040 return Style;
1043 // #i104867#
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);
1073 } // namespace svt
1075 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */