Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svtools / source / misc / embedhlp.cxx
blobd784b20a4a3950bb56cd2240947f13bd4aae7fed
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("");
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 Graphic aOldGraphic;
457 if ( 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++;
472 else
474 OSL_FAIL("No update, but replacement exists already!");
475 return;
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
502 // all.
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 );
529 Size aResult;
531 if ( mpImpl->nViewAspect == embed::Aspects::MSOLE_ICON )
533 const Graphic* pGraphic = GetGraphic();
534 if ( pGraphic )
536 aSourceMapMode = pGraphic->GetPrefMapMode();
537 aResult = pGraphic->GetPrefSize();
539 else
540 aResult = Size( 2500, 2500 );
542 else
544 awt::Size aSize;
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");
574 aSize.Width = 5000;
575 aSize.Height = 5000;
578 aResult = Size( aSize.Width, aSize.Height );
581 if ( pTargetMapMode )
582 aResult = OutputDevice::LogicToLogic( aResult, aSourceMapMode, *pTargetMapMode );
584 return aResult;
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);
636 if ( xStream.is() )
638 const sal_Int32 nConstBufferSize = 32000;
639 std::unique_ptr<SvMemoryStream> pStream(new SvMemoryStream( 32000, 32000 ));
642 sal_Int32 nRead=0;
643 uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
646 nRead = xStream->readBytes ( aSequence, nConstBufferSize );
647 pStream->WriteBytes(aSequence.getConstArray(), nRead);
649 while ( nRead == nConstBufferSize );
650 pStream->Seek(0);
651 pStream->MakeReadOnly();
652 return pStream;
654 catch (const uno::Exception&)
656 DBG_UNHANDLED_EXCEPTION("svtools.misc", "discarding broken embedded object preview");
657 xStream.clear();
662 if ( !xStream.is() )
664 SAL_INFO( "svtools.misc", "getting stream from object" );
665 bool bUpdateAllowed(true);
666 const comphelper::EmbeddedObjectContainer* pContainer = GetContainer();
668 if(pContainer)
670 uno::Reference<embed::XLinkageSupport> const xLinkage(
671 mpImpl->mxObj, uno::UNO_QUERY);
672 if (xLinkage.is() && xLinkage->isLink())
674 bUpdateAllowed = pContainer->getUserAllowsLinkUpdate();
679 if (bUpdateAllowed)
681 // update wanted or no stream in container storage available
682 xStream = GetGraphicReplacementStream(mpImpl->nViewAspect, mpImpl->mxObj, &mpImpl->aMediaType);
684 if(xStream.is())
686 if (mpImpl->pContainer)
688 bool bInsertGraphicStream = true;
689 uno::Reference<io::XSeekable> xSeekable(xStream, uno::UNO_QUERY);
690 std::optional<sal_Int64> oPosition;
691 if (xSeekable.is())
693 oPosition = xSeekable->getPosition();
695 if (bUpdate)
697 std::unique_ptr<SvStream> pResult = utl::UcbStreamHelper::CreateStream(xStream);
698 if (pResult)
700 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
701 Graphic aGraphic;
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;
726 return pResult;
731 return nullptr;
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 );
744 pOut->Push();
745 pOut->SetBackground();
746 pOut->SetFont( aFnt );
748 Point aPt;
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 );
757 bool bTiny = false;
758 if( aPt.X() < 0 )
760 bTiny = true;
761 aPt.setX( 0 );
763 if( aPt.Y() < 0 )
765 bTiny = true;
766 aPt.setY( 0 );
768 if( bTiny )
770 // decrease for small images
771 aFnt.SetFontSize( Size( 0, aAppFontSz.Height() * i / 8 ) );
772 pOut->SetFont( aFnt );
774 else
775 break;
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)
783 aPt.setY( nHeight );
784 Point aP = rRect.TopLeft();
785 Size aBmpSize = aBmp.GetSizePixel();
786 // fit bitmap in
787 if( nHeight * 10 / nWidth
788 > aBmpSize.Height() * 10 / aBmpSize.Width() )
790 // adjust to the width
791 // keep proportions
792 tools::Long nH = nWidth * aBmpSize.Height() / aBmpSize.Width();
793 // center
794 aP.AdjustY((nHeight - nH) / 2 );
795 nHeight = nH;
797 else
799 // adjust to the height
800 // keep proportions
801 tools::Long nW = nHeight * aBmpSize.Width() / aBmpSize.Height();
802 // center
803 aP.AdjustX((nWidth - nW) / 2 );
804 nWidth = nW;
807 pOut->DrawBitmapEx(aP, Size( nWidth, nHeight ), aBmp);
810 pOut->IntersectClipRegion( rRect );
811 aPt += rRect.TopLeft();
812 pOut->DrawText( aPt, rText );
813 pOut->Pop();
816 void EmbeddedObjectRef::DrawShading( const tools::Rectangle &rRect, OutputDevice *pOut )
818 GDIMetaFile * pMtf = pOut->GetConnectMetaFile();
819 if( pMtf && pMtf->IsRecord() )
820 return;
822 pOut->Push();
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() );
835 else
836 a1 += Point( i, 0 );
837 if( i > aPixSize.Height() )
838 a2 += Point( i - aPixSize.Height(), aPixSize.Height() );
839 else
840 a2 += Point( 0, i );
842 pOut->DrawLine( pOut->PixelToLogic( a1 ), pOut->PixelToLogic( a2 ) );
845 pOut->Pop();
849 bool EmbeddedObjectRef::TryRunningState( const uno::Reference < embed::XEmbeddedObject >& xEmbObj )
851 if ( !xEmbObj.is() )
852 return false;
856 if ( xEmbObj->getCurrentState() == embed::EmbedStates::LOADED )
857 xEmbObj->changeState( embed::EmbedStates::RUNNING );
859 catch (const uno::Exception&)
861 return false;
864 return true;
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))
880 aStream.Seek(0);
881 uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
882 aContainer.InsertGraphicStream(xStream, aName, aMediaType);
884 else
885 OSL_FAIL("Export of graphic is failed!");
887 else
889 TypeSerializer aSerializer(aStream);
890 aSerializer.writeGraphic(rGraphic);
891 if (aStream.GetError() == ERRCODE_NONE)
893 aStream.Seek(0);
894 uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
895 aContainer.InsertGraphicStream(xStream, aName, aMediaType);
897 else
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 )
906 noexcept
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");
925 return;
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());
937 if( pObj )
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())
965 return false;
967 return EmbeddedObjectRef::IsChart(mpImpl->mxObj);
970 // MT: Only used for getting accessible attributes, which are not localized
971 OUString EmbeddedObjectRef::GetChartType()
973 OUString Style;
974 if ( mpImpl->mxObj.is() )
976 if ( IsChart() )
978 if ( svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObj ) )
980 uno::Reference< chart2::XChartDocument > xChart( mpImpl->mxObj->getComponent(), uno::UNO_QUERY );
981 if (xChart.is())
983 uno::Reference< chart2::XDiagram > xDiagram( xChart->getFirstDiagram());
984 if( ! xDiagram.is())
985 return OUString();
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 )
996 Style += "3D ";
997 else
998 Style += "2D ";
999 for( const auto& rChartType : aChartTypes )
1001 OUString strChartType = rChartType->getChartType();
1002 if (strChartType == "com.sun.star.chart2.AreaChartType")
1004 Style += "Areas";
1005 bGetChartType = true;
1007 else if (strChartType == "com.sun.star.chart2.BarChartType")
1009 Style += "Bars";
1010 bGetChartType = true;
1012 else if (strChartType == "com.sun.star.chart2.ColumnChartType")
1014 uno::Reference< beans::XPropertySet > xProp( rCooSys, uno::UNO_QUERY );
1015 if( xProp.is())
1017 bool bCurrent = false;
1018 if( xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bCurrent )
1020 if (bCurrent)
1021 Style += "Bars";
1022 else
1023 Style += "Columns";
1024 bGetChartType = true;
1028 else if (strChartType == "com.sun.star.chart2.LineChartType")
1030 Style += "Lines";
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")
1040 Style += "Pies";
1041 bGetChartType = true;
1043 else if (strChartType == "com.sun.star.chart2.NetChartType")
1045 Style += "Radar";
1046 bGetChartType = true;
1048 else if (strChartType == "com.sun.star.chart2.CandleStickChartType")
1050 Style += "Candle Stick Chart";
1051 bGetChartType = true;
1053 if (bGetChartType)
1054 return Style;
1061 return Style;
1064 // #i104867#
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);
1094 } // namespace svt
1096 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */