LibreOffice Module svtools (master) 1
embedhlp.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <libxml/xmlwriter.h>
21
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>
28#include <bitmaps.hlst>
29
30#include <sal/log.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>
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>
57#include <vcl/svapp.hxx>
59#include <tools/debug.hxx>
60#include <memory>
61
62using namespace com::sun::star;
63
64namespace svt {
65
66namespace {
67
68class EmbedEventListener_Impl : public ::cppu::WeakImplHelper < embed::XStateChangeListener,
69 document::XEventListener,
70 util::XModifyListener,
71 util::XCloseListener >
72{
73public:
74 EmbeddedObjectRef* pObject;
75 sal_Int32 nState;
76
77 explicit EmbedEventListener_Impl( EmbeddedObjectRef* p ) :
78 pObject(p)
79 , nState(-1)
80 {}
81
82 static rtl::Reference<EmbedEventListener_Impl> Create( EmbeddedObjectRef* );
83
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;
91};
92
93}
94
95rtl::Reference<EmbedEventListener_Impl> EmbedEventListener_Impl::Create( EmbeddedObjectRef* p )
96{
97 rtl::Reference<EmbedEventListener_Impl> pRet(new EmbedEventListener_Impl( p ));
98
99 if ( p->GetObject().is() )
100 {
101 p->GetObject()->addStateChangeListener( pRet );
102
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 );
107
108 uno::Reference < document::XEventBroadcaster > xBrd = p->GetObject();
109 if ( xBrd.is() )
110 xBrd->addEventListener( pRet );
111
112 pRet->nState = p->GetObject()->getCurrentState();
113 if ( pRet->nState == embed::EmbedStates::RUNNING )
114 {
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 );
119 }
120 }
121
122 return pRet;
123}
124
125void SAL_CALL EmbedEventListener_Impl::changingState( const lang::EventObject&,
126 ::sal_Int32,
127 ::sal_Int32 )
128{
129}
130
131void SAL_CALL EmbedEventListener_Impl::stateChanged( const lang::EventObject&,
132 ::sal_Int32 nOldState,
133 ::sal_Int32 nNewState )
134{
135 SolarMutexGuard aGuard;
136 nState = nNewState;
137 if ( !pObject )
138 return;
139
140 uno::Reference < util::XModifiable > xMod( pObject->GetObject()->getComponent(), uno::UNO_QUERY );
141 if ( nNewState == embed::EmbedStates::RUNNING )
142 {
143 bool bProtected = false;
145 {
146 bProtected = pObject->GetIsProtectedHdl().Call(nullptr);
147 }
148
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
155
156 if( pObject->IsChart() && nOldState == embed::EmbedStates::UI_ACTIVE )
157 {
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
162 }
163
164 if ( xMod.is() && nOldState == embed::EmbedStates::LOADED )
165 // listen for changes (update replacements in case of changes)
166 xMod->addModifyListener( this );
167 }
168 else if ( nNewState == embed::EmbedStates::LOADED )
169 {
170 // in loaded state we can't listen
171 if ( xMod.is() )
172 xMod->removeModifyListener( this );
173 }
174}
175
176void SAL_CALL EmbedEventListener_Impl::modified( const lang::EventObject& )
177{
178 SolarMutexGuard aGuard;
179 if ( !(pObject && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON) )
180 return;
181
182 if ( nState == embed::EmbedStates::RUNNING )
183 {
184 // updates only necessary in non-active states
185 if( pObject->IsChart() )
187 else
189 }
190 else if ( nState == embed::EmbedStates::ACTIVE ||
191 nState == embed::EmbedStates::UI_ACTIVE ||
192 nState == embed::EmbedStates::INPLACE_ACTIVE )
193 {
194 // in case the object is inplace or UI active the replacement image should be updated on demand
196 }
197}
198
199void SAL_CALL EmbedEventListener_Impl::notifyEvent( const document::EventObject& aEvent )
200{
201 SolarMutexGuard aGuard;
202
203 if ( pObject && aEvent.EventName == "OnVisAreaChanged" && pObject->GetViewAspect() != embed::Aspects::MSOLE_ICON && !pObject->IsChart() )
204 {
206 }
207}
208
209void SAL_CALL EmbedEventListener_Impl::queryClosing( const lang::EventObject& Source, sal_Bool )
210{
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();
216}
217
218void SAL_CALL EmbedEventListener_Impl::notifyClosing( const lang::EventObject& Source )
219{
220 if ( pObject && Source.Source == pObject->GetObject() )
221 {
222 pObject->Clear();
223 pObject = nullptr;
224 }
225}
226
227void SAL_CALL EmbedEventListener_Impl::disposing( const lang::EventObject& aEvent )
228{
229 if ( pObject && aEvent.Source == pObject->GetObject() )
230 {
231 pObject->Clear();
232 pObject = nullptr;
233 }
234}
235
237{
238 uno::Reference <embed::XEmbeddedObject> mxObj;
239
241 OUString aPersistName;
242 OUString aMediaType;
244 std::optional<Graphic> oGraphic;
245 sal_Int64 nViewAspect;
246 bool bIsLocked:1;
248 bool bUpdating:1;
249
250 // #i104867#
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
253
255
257 pContainer(nullptr),
258 nViewAspect(embed::Aspects::MSOLE_CONTENT),
259 bIsLocked(false),
260 bNeedUpdate(false),
261 bUpdating(false),
264 {}
265
267 mxObj(r.mxObj),
277 {
278 if (r.oGraphic && !r.bNeedUpdate)
279 oGraphic.emplace(*r.oGraphic);
280 }
281
282 void dumpAsXml(xmlTextWriterPtr pWriter) const
283 {
284 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("EmbeddedObjectRef_Impl"));
285 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
286
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())
293 {
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());
298 }
299 (void)xmlTextWriterEndElement(pWriter);
300
301 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("pGraphic"));
302 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", oGraphic ? &*oGraphic : nullptr);
303 if (oGraphic)
304 {
305 (void)xmlTextWriterWriteAttribute(
306 pWriter, BAD_CAST("is-none"),
307 BAD_CAST(OString::boolean(oGraphic->IsNone()).getStr()));
308 }
309 (void)xmlTextWriterEndElement(pWriter);
310
311 (void)xmlTextWriterEndElement(pWriter);
312 }
313};
314
315const uno::Reference <embed::XEmbeddedObject>& EmbeddedObjectRef::operator->() const
316{
317 return mpImpl->mxObj;
318}
319
320const uno::Reference <embed::XEmbeddedObject>& EmbeddedObjectRef::GetObject() const
321{
322 return mpImpl->mxObj;
323}
324
326
327EmbeddedObjectRef::EmbeddedObjectRef( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Int64 nAspect ) :
328 mpImpl(new EmbeddedObjectRef_Impl)
329{
330 mpImpl->nViewAspect = nAspect;
331 mpImpl->mxObj = xObj;
332 mpImpl->mxListener = EmbedEventListener_Impl::Create( this );
333}
334
336 mpImpl(new EmbeddedObjectRef_Impl(*rObj.mpImpl))
337{
338 mpImpl->mxListener = EmbedEventListener_Impl::Create( this );
339}
340
342{
343 Clear();
344}
345
346void EmbeddedObjectRef::Assign( const uno::Reference < embed::XEmbeddedObject >& xObj, sal_Int64 nAspect )
347{
348 DBG_ASSERT(!mpImpl->mxObj.is(), "Never assign an already assigned object!");
349
350 Clear();
351 mpImpl->nViewAspect = nAspect;
352 mpImpl->mxObj = xObj;
353 mpImpl->mxListener = EmbedEventListener_Impl::Create( this );
354
355 //#i103460#
356 if ( IsChart() )
357 {
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 );
362 }
363}
364
366{
367 if (mpImpl->mxObj.is() && mpImpl->mxListener.is())
368 {
369 mpImpl->mxObj->removeStateChangeListener(mpImpl->mxListener);
370
371 mpImpl->mxObj->removeCloseListener( mpImpl->mxListener );
372 mpImpl->mxObj->removeEventListener( mpImpl->mxListener );
373
374 if ( mpImpl->bIsLocked )
375 {
376 try
377 {
378 mpImpl->mxObj->changeState(embed::EmbedStates::LOADED);
379 mpImpl->mxObj->close( true );
380 }
381 catch (const util::CloseVetoException&)
382 {
383 // there's still someone who needs the object!
384 }
385 catch (const uno::Exception&)
386 {
387 TOOLS_WARN_EXCEPTION("svtools.misc", "Error on switching of the object to loaded state and closing");
388 }
389 }
390 }
391
392 if (mpImpl->mxListener.is())
393 {
394 mpImpl->mxListener->pObject = nullptr;
395 mpImpl->mxListener.clear();
396 }
397
398 mpImpl->mxObj = nullptr;
399 mpImpl->pContainer = nullptr;
400 mpImpl->bIsLocked = false;
401 mpImpl->bNeedUpdate = false;
402}
403
405{
406 return mpImpl->mxObj.is();
407}
408
409void EmbeddedObjectRef::AssignToContainer( comphelper::EmbeddedObjectContainer* pContainer, const OUString& rPersistName )
410{
411 mpImpl->pContainer = pContainer;
412 mpImpl->aPersistName = rPersistName;
413
414 if ( mpImpl->oGraphic && !mpImpl->bNeedUpdate && pContainer )
415 SetGraphicToContainer( *mpImpl->oGraphic, *pContainer, mpImpl->aPersistName, OUString() );
416}
417
419{
420 return mpImpl->pContainer;
421}
422
424{
425 return mpImpl->nViewAspect;
426}
427
428void EmbeddedObjectRef::SetViewAspect( sal_Int64 nAspect )
429{
430 mpImpl->nViewAspect = nAspect;
431}
432
433void EmbeddedObjectRef::Lock( bool bLock )
434{
435 mpImpl->bIsLocked = bLock;
436}
437
439{
440 return mpImpl->bIsLocked;
441}
442
444{
445 mpImpl->m_aIsProtectedHdl = rProtectedHdl;
446}
447
449{
450 return mpImpl->m_aIsProtectedHdl;
451}
452
454{
455 Graphic aOldGraphic;
456
457 if ( bUpdate )
458 {
459 if (mpImpl->oGraphic)
460 aOldGraphic = *mpImpl->oGraphic;
461
462 mpImpl->oGraphic.reset();
463 mpImpl->aMediaType.clear();
464 mpImpl->oGraphic.emplace();
465 mpImpl->mnGraphicVersion++;
466 }
467 else if ( !mpImpl->oGraphic )
468 {
469 mpImpl->oGraphic.emplace();
470 mpImpl->mnGraphicVersion++;
471 }
472 else
473 {
474 OSL_FAIL("No update, but replacement exists already!");
475 return;
476 }
477
478 std::unique_ptr<SvStream> pGraphicStream(GetGraphicStream( bUpdate ));
479 if (!pGraphicStream && aOldGraphic.IsNone())
480 {
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");
486 }
487
488 if ( pGraphicStream )
489 {
491 if( mpImpl->oGraphic )
492 rGF.ImportGraphic( *mpImpl->oGraphic, u"", *pGraphicStream );
493 mpImpl->mnGraphicVersion++;
494 }
495
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())
499 {
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");
505 }
506}
507
509{
510 try
511 {
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);
517 }
518 catch( const uno::Exception& )
519 {
520 DBG_UNHANDLED_EXCEPTION("svtools.misc", "Something went wrong on getting the graphic");
521 }
522
523 return mpImpl->oGraphic ? &*mpImpl->oGraphic : nullptr;
524}
525
526Size EmbeddedObjectRef::GetSize( MapMode const * pTargetMapMode ) const
527{
528 MapMode aSourceMapMode( MapUnit::Map100thMM );
529 Size aResult;
530
531 if ( mpImpl->nViewAspect == embed::Aspects::MSOLE_ICON )
532 {
533 const Graphic* pGraphic = GetGraphic();
534 if ( pGraphic )
535 {
536 aSourceMapMode = pGraphic->GetPrefMapMode();
537 aResult = pGraphic->GetPrefSize();
538 }
539 else
540 aResult = Size( 2500, 2500 );
541 }
542 else
543 {
544 awt::Size aSize;
545
546 if (mpImpl->mxObj.is())
547 {
548 try
549 {
550 aSize = mpImpl->mxObj->getVisualAreaSize(mpImpl->nViewAspect);
551 }
552 catch(const embed::NoVisualAreaSizeException&)
553 {
554 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: no visual area size");
555 }
556 catch (const uno::Exception&)
557 {
558 TOOLS_WARN_EXCEPTION("svtools.misc", "Something went wrong on getting of the size of the object");
559 }
560
561 try
562 {
563 aSourceMapMode = MapMode(VCLUnoHelper::UnoEmbed2VCLMapUnit(mpImpl->mxObj->getMapUnit(mpImpl->nViewAspect)));
564 }
565 catch (const uno::Exception&)
566 {
567 TOOLS_WARN_EXCEPTION("svtools.misc", "Can not get the map mode");
568 }
569 }
570
571 if ( !aSize.Height && !aSize.Width )
572 {
573 SAL_WARN("svtools.misc", "EmbeddedObjectRef::GetSize: empty size, defaulting to 5x5cm");
574 aSize.Width = 5000;
575 aSize.Height = 5000;
576 }
577
578 aResult = Size( aSize.Width, aSize.Height );
579 }
580
581 if ( pTargetMapMode )
582 aResult = OutputDevice::LogicToLogic( aResult, aSourceMapMode, *pTargetMapMode );
583
584 return aResult;
585}
586
587void EmbeddedObjectRef::SetGraphicStream( const uno::Reference< io::XInputStream >& xInGrStream,
588 const OUString& rMediaType )
589{
590 mpImpl->oGraphic.emplace();
591 mpImpl->aMediaType = rMediaType;
592 mpImpl->mnGraphicVersion++;
593
594 std::unique_ptr<SvStream> pGraphicStream(::utl::UcbStreamHelper::CreateStream( xInGrStream ));
595
596 if ( pGraphicStream )
597 {
599 rGF.ImportGraphic( *mpImpl->oGraphic, u"", *pGraphicStream );
600 mpImpl->mnGraphicVersion++;
601
602 if ( mpImpl->pContainer )
603 {
604 pGraphicStream->Seek( 0 );
605 uno::Reference< io::XInputStream > xInSeekGrStream = new ::utl::OSeekableInputStreamWrapper( pGraphicStream.get() );
606
607 mpImpl->pContainer->InsertGraphicStream( xInSeekGrStream, mpImpl->aPersistName, rMediaType );
608 }
609 }
610
611 mpImpl->bNeedUpdate = false;
612
613}
614
615void EmbeddedObjectRef::SetGraphic( const Graphic& rGraphic, const OUString& rMediaType )
616{
617 mpImpl->oGraphic.emplace( rGraphic );
618 mpImpl->aMediaType = rMediaType;
619 mpImpl->mnGraphicVersion++;
620
621 if ( mpImpl->pContainer )
622 SetGraphicToContainer( rGraphic, *mpImpl->pContainer, mpImpl->aPersistName, rMediaType );
623
624 mpImpl->bNeedUpdate = false;
625}
626
627std::unique_ptr<SvStream> EmbeddedObjectRef::GetGraphicStream( bool bUpdate ) const
628{
629 DBG_ASSERT( bUpdate || mpImpl->pContainer, "Can't retrieve current graphic!" );
630 uno::Reference < io::XInputStream > xStream;
631 if ( mpImpl->pContainer && !bUpdate )
632 {
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() )
637 {
638 const sal_Int32 nConstBufferSize = 32000;
639 std::unique_ptr<SvMemoryStream> pStream(new SvMemoryStream( 32000, 32000 ));
640 try
641 {
642 sal_Int32 nRead=0;
643 uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );
644 do
645 {
646 nRead = xStream->readBytes ( aSequence, nConstBufferSize );
647 pStream->WriteBytes(aSequence.getConstArray(), nRead);
648 }
649 while ( nRead == nConstBufferSize );
650 pStream->Seek(0);
651 pStream->MakeReadOnly();
652 return pStream;
653 }
654 catch (const uno::Exception&)
655 {
656 DBG_UNHANDLED_EXCEPTION("svtools.misc", "discarding broken embedded object preview");
657 xStream.clear();
658 }
659 }
660 }
661
662 if ( !xStream.is() )
663 {
664 SAL_INFO( "svtools.misc", "getting stream from object" );
665 bool bUpdateAllowed(true);
667
668 if(pContainer)
669 {
670 uno::Reference<embed::XLinkageSupport> const xLinkage(
671 mpImpl->mxObj, uno::UNO_QUERY);
672 if (xLinkage.is() && xLinkage->isLink())
673 {
674 bUpdateAllowed = pContainer->getUserAllowsLinkUpdate();
675
676 }
677 }
678
679 if (bUpdateAllowed)
680 {
681 // update wanted or no stream in container storage available
682 xStream = GetGraphicReplacementStream(mpImpl->nViewAspect, mpImpl->mxObj, &mpImpl->aMediaType);
683
684 if(xStream.is())
685 {
686 if (mpImpl->pContainer)
687 {
688 bool bInsertGraphicStream = true;
689 uno::Reference<io::XSeekable> xSeekable(xStream, uno::UNO_QUERY);
690 std::optional<sal_Int64> oPosition;
691 if (xSeekable.is())
692 {
693 oPosition = xSeekable->getPosition();
694 }
695 if (bUpdate)
696 {
697 std::unique_ptr<SvStream> pResult = utl::UcbStreamHelper::CreateStream(xStream);
698 if (pResult)
699 {
701 Graphic aGraphic;
702 rGF.ImportGraphic(aGraphic, u"", *pResult);
703 if (aGraphic.IsNone())
704 {
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;
709 }
710 }
711 }
712 if (xSeekable.is() && oPosition.has_value())
713 {
714 xSeekable->seek(*oPosition);
715 }
716 if (bInsertGraphicStream)
717 {
718 mpImpl->pContainer->InsertGraphicStream(xStream,mpImpl->aPersistName,mpImpl->aMediaType);
719 }
720 }
721
722 std::unique_ptr<SvStream> pResult = ::utl::UcbStreamHelper::CreateStream( xStream );
723 if (pResult && bUpdate)
724 mpImpl->bNeedUpdate = false;
725
726 return pResult;
727 }
728 }
729 }
730
731 return nullptr;
732}
733
734void EmbeddedObjectRef::DrawPaintReplacement( const tools::Rectangle &rRect, const OUString &rText, OutputDevice *pOut )
735{
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 );
743
744 pOut->Push();
745 pOut->SetBackground();
746 pOut->SetFont( aFnt );
747
748 Point aPt;
749
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-- )
753 {
754 aPt.setX( (rRect.GetWidth() - pOut->GetTextWidth( rText )) / 2 );
755 aPt.setY( (rRect.GetHeight() - pOut->GetTextHeight()) / 2 );
756
757 bool bTiny = false;
758 if( aPt.X() < 0 )
759 {
760 bTiny = true;
761 aPt.setX( 0 );
762 }
763 if( aPt.Y() < 0 )
764 {
765 bTiny = true;
766 aPt.setY( 0 );
767 }
768 if( bTiny )
769 {
770 // decrease for small images
771 aFnt.SetFontSize( Size( 0, aAppFontSz.Height() * i / 8 ) );
772 pOut->SetFont( aFnt );
773 }
774 else
775 break;
776 }
777
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)
782 {
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() )
789 {
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;
796 }
797 else
798 {
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;
805 }
806
807 pOut->DrawBitmapEx(aP, Size( nWidth, nHeight ), aBmp);
808 }
809
810 pOut->IntersectClipRegion( rRect );
811 aPt += rRect.TopLeft();
812 pOut->DrawText( aPt, rText );
813 pOut->Pop();
814}
815
817{
818 GDIMetaFile * pMtf = pOut->GetConnectMetaFile();
819 if( pMtf && pMtf->IsRecord() )
820 return;
821
822 pOut->Push();
823 pOut->SetLineColor( COL_BLACK );
824
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 )
831 {
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 );
841
842 pOut->DrawLine( pOut->PixelToLogic( a1 ), pOut->PixelToLogic( a2 ) );
843 }
844
845 pOut->Pop();
846
847}
848
849bool EmbeddedObjectRef::TryRunningState( const uno::Reference < embed::XEmbeddedObject >& xEmbObj )
850{
851 if ( !xEmbObj.is() )
852 return false;
853
854 try
855 {
856 if ( xEmbObj->getCurrentState() == embed::EmbedStates::LOADED )
857 xEmbObj->changeState( embed::EmbedStates::RUNNING );
858 }
859 catch (const uno::Exception&)
860 {
861 return false;
862 }
863
864 return true;
865}
866
869 const OUString& aName,
870 const OUString& aMediaType )
871{
872 SvMemoryStream aStream;
874
875 auto pGfxLink = rGraphic.GetSharedGfxLink();
876 if (pGfxLink && pGfxLink->IsNative())
877 {
878 if (pGfxLink->ExportNative(aStream))
879 {
880 aStream.Seek(0);
881 uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
882 aContainer.InsertGraphicStream(xStream, aName, aMediaType);
883 }
884 else
885 OSL_FAIL("Export of graphic is failed!");
886 }
887 else
888 {
889 TypeSerializer aSerializer(aStream);
890 aSerializer.writeGraphic(rGraphic);
891 if (aStream.GetError() == ERRCODE_NONE)
892 {
893 aStream.Seek(0);
894 uno::Reference <io::XInputStream> xStream = new ::utl::OSeekableInputStreamWrapper(aStream);
895 aContainer.InsertGraphicStream(xStream, aName, aMediaType);
896 }
897 else
898 OSL_FAIL("Export of graphic is failed!");
899 }
900}
901
902uno::Reference< io::XInputStream > EmbeddedObjectRef::GetGraphicReplacementStream(
903 sal_Int64 nViewAspect,
904 const uno::Reference< embed::XEmbeddedObject >& xObj,
905 OUString* pMediaType )
906 noexcept
907{
908 return ::comphelper::EmbeddedObjectContainer::GetGraphicReplacementStream(nViewAspect,xObj,pMediaType);
909}
910
911bool EmbeddedObjectRef::IsChart(const css::uno::Reference < css::embed::XEmbeddedObject >& xObj)
912{
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;
918}
919
921{
922 if (mpImpl->bUpdating)
923 {
924 SAL_WARN("svtools.misc", "UpdateReplacement called while UpdateReplacement already underway");
925 return;
926 }
927 mpImpl->bUpdating = true;
928 UpdateOleObject( bUpdateOle );
929 GetReplacement(true);
930 UpdateOleObject( false );
931 mpImpl->bUpdating = false;
932}
933
935{
936 embed::EmbeddedUpdate* pObj = dynamic_cast<embed::EmbeddedUpdate*> (GetObject().get());
937 if( pObj )
938 pObj->SetOleState( bUpdateOle );
939}
940
941
943{
944 mpImpl->oGraphic.reset();
945 mpImpl->bNeedUpdate = true;
946 mpImpl->mnGraphicVersion++;
947
948 if( mpImpl->pContainer )
949 {
950 //remove graphic from container thus a new up to date one is requested on save
951 mpImpl->pContainer->RemoveGraphicStream( mpImpl->aPersistName );
952 }
953}
954
956{
957 //todo maybe for 3.0:
958 //if the changes work good for chart
959 //we should apply them for all own ole objects
960
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
963
964 if (!mpImpl->mxObj.is())
965 return false;
966
967 return EmbeddedObjectRef::IsChart(mpImpl->mxObj);
968}
969
970// MT: Only used for getting accessible attributes, which are not localized
972{
973 OUString Style;
974 if ( mpImpl->mxObj.is() )
975 {
976 if ( IsChart() )
977 {
979 {
980 uno::Reference< chart2::XChartDocument > xChart( mpImpl->mxObj->getComponent(), uno::UNO_QUERY );
981 if (xChart.is())
982 {
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 )
991 {
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 )
1000 {
1001 OUString strChartType = rChartType->getChartType();
1002 if (strChartType == "com.sun.star.chart2.AreaChartType")
1003 {
1004 Style += "Areas";
1005 bGetChartType = true;
1006 }
1007 else if (strChartType == "com.sun.star.chart2.BarChartType")
1008 {
1009 Style += "Bars";
1010 bGetChartType = true;
1011 }
1012 else if (strChartType == "com.sun.star.chart2.ColumnChartType")
1013 {
1014 uno::Reference< beans::XPropertySet > xProp( rCooSys, uno::UNO_QUERY );
1015 if( xProp.is())
1016 {
1017 bool bCurrent = false;
1018 if( xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bCurrent )
1019 {
1020 if (bCurrent)
1021 Style += "Bars";
1022 else
1023 Style += "Columns";
1024 bGetChartType = true;
1025 }
1026 }
1027 }
1028 else if (strChartType == "com.sun.star.chart2.LineChartType")
1029 {
1030 Style += "Lines";
1031 bGetChartType = true;
1032 }
1033 else if (strChartType == "com.sun.star.chart2.ScatterChartType")
1034 {
1035 Style += "XY Chart";
1036 bGetChartType = true;
1037 }
1038 else if (strChartType == "com.sun.star.chart2.PieChartType")
1039 {
1040 Style += "Pies";
1041 bGetChartType = true;
1042 }
1043 else if (strChartType == "com.sun.star.chart2.NetChartType")
1044 {
1045 Style += "Radar";
1046 bGetChartType = true;
1047 }
1048 else if (strChartType == "com.sun.star.chart2.CandleStickChartType")
1049 {
1050 Style += "Candle Stick Chart";
1051 bGetChartType = true;
1052 }
1053 if (bGetChartType)
1054 return Style;
1055 }
1056 }
1057 }
1058 }
1059 }
1060 }
1061 return Style;
1062}
1063
1064// #i104867#
1066{
1067 return mpImpl->mnGraphicVersion;
1068}
1069
1071{
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
1075
1076 mpImpl->aDefaultSizeForChart_In_100TH_MM = awt::Size( rSizeIn_100TH_MM.getWidth(), rSizeIn_100TH_MM.getHeight() );
1077
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 );
1082}
1083
1085{
1086 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("EmbeddedObjectRef"));
1087 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
1088
1089 mpImpl->dumpAsXml(pWriter);
1090
1091 (void)xmlTextWriterEndElement(pWriter);
1092}
1093
1094} // namespace svt
1095
1096/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
AnyEventRef aEvent
const Size & GetSizePixel() const
bool IsRecord() const
static GraphicFilter & GetGraphicFilter()
ErrCode ImportGraphic(Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat=GRFILTER_FORMAT_DONTKNOW, sal_uInt16 *pDeterminedFormat=nullptr, GraphicFilterImportFlags nImportFlags=GraphicFilterImportFlags::NONE)
Size GetPrefSize() const
const std::shared_ptr< GfxLink > & GetSharedGfxLink() const
bool IsNone() const
MapMode GetPrefMapMode() const
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
constexpr tools::Long Y() const
void setX(tools::Long nX)
void setY(tools::Long nY)
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
constexpr tools::Long X() const
constexpr tools::Long getHeight() const
constexpr tools::Long Height() const
tools::Long AdjustHeight(tools::Long n)
constexpr tools::Long getWidth() const
tools::Long AdjustWidth(tools::Long n)
constexpr tools::Long Width() const
void SetVersion(sal_Int32 n)
sal_uInt64 Seek(sal_uInt64 nPos)
ErrCode GetError() const
void writeGraphic(const Graphic &rGraphic)
static MapUnit UnoEmbed2VCLMapUnit(sal_Int32 nUnoEmbedMapUnit)
bool InsertGraphicStream(const css::uno::Reference< css::io::XInputStream > &rStream, const OUString &rObjectName, const OUString &rMediaType)
#define SO3_SCH_CLASSID_40
#define SO3_SCH_CLASSID_30
#define SO3_SCH_CLASSID_50
#define SO3_SCH_CLASSID_60
bool IsLocked() const
Definition: embedhlp.cxx:438
void AssignToContainer(comphelper::EmbeddedObjectContainer *pContainer, const OUString &rPersistName)
Definition: embedhlp.cxx:409
void SetViewAspect(sal_Int64 nAspect)
Definition: embedhlp.cxx:428
void SetIsProtectedHdl(const Link< LinkParamNone *, bool > &rProtectedHdl)
Definition: embedhlp.cxx:443
sal_uInt32 getGraphicVersion() const
Definition: embedhlp.cxx:1065
comphelper::EmbeddedObjectContainer * GetContainer() const
Definition: embedhlp.cxx:418
SVT_DLLPRIVATE void UpdateOleObject(bool bUpdateOle)
Definition: embedhlp.cxx:934
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: embedhlp.cxx:1084
static bool TryRunningState(const css::uno::Reference< css::embed::XEmbeddedObject > &)
Definition: embedhlp.cxx:849
const Link< LinkParamNone *, bool > & GetIsProtectedHdl() const
Definition: embedhlp.cxx:448
SVT_DLLPRIVATE std::unique_ptr< SvStream > GetGraphicStream(bool bUpdate) const
Definition: embedhlp.cxx:627
static void DrawPaintReplacement(const tools::Rectangle &rRect, const OUString &rText, OutputDevice *pOut)
Definition: embedhlp.cxx:734
void SetGraphicStream(const css::uno::Reference< css::io::XInputStream > &xInGrStream, const OUString &rMediaType)
Definition: embedhlp.cxx:587
void UpdateReplacement(bool bUpdateOle=false)
Definition: embedhlp.cxx:920
void Lock(bool bLock=true)
Definition: embedhlp.cxx:433
bool IsChart() const
Definition: embedhlp.cxx:955
const css::uno::Reference< css::embed::XEmbeddedObject > & operator->() const
Definition: embedhlp.cxx:315
void SetDefaultSizeForChart(const Size &rSizeIn_100TH_MM)
Definition: embedhlp.cxx:1070
static css::uno::Reference< css::io::XInputStream > GetGraphicReplacementStream(sal_Int64 nViewAspect, const css::uno::Reference< css::embed::XEmbeddedObject > &, OUString *pMediaType) noexcept
Definition: embedhlp.cxx:902
void SetGraphic(const Graphic &rGraphic, const OUString &rMediaType)
Definition: embedhlp.cxx:615
const Graphic * GetGraphic() const
Definition: embedhlp.cxx:508
sal_Int64 GetViewAspect() const
Definition: embedhlp.cxx:423
static void DrawShading(const tools::Rectangle &rRect, OutputDevice *pOut)
Definition: embedhlp.cxx:816
Size GetSize(MapMode const *pTargetMapMode) const
Definition: embedhlp.cxx:526
void UpdateReplacementOnDemand()
Definition: embedhlp.cxx:942
static void SetGraphicToContainer(const Graphic &rGraphic, comphelper::EmbeddedObjectContainer &aContainer, const OUString &aName, const OUString &aMediaType)
Definition: embedhlp.cxx:867
SVT_DLLPRIVATE void GetReplacement(bool bUpdate)
Definition: embedhlp.cxx:453
void Assign(const css::uno::Reference< css::embed::XEmbeddedObject > &xObj, sal_Int64 nAspect)
Definition: embedhlp.cxx:346
OUString GetChartType()
Definition: embedhlp.cxx:971
static bool IsChart(const css::uno::Reference< css::embed::XEmbeddedObject > &xObj)
Definition: embedhlp.cxx:911
const css::uno::Reference< css::embed::XEmbeddedObject > & GetObject() const
Definition: embedhlp.cxx:320
std::unique_ptr< EmbeddedObjectRef_Impl > mpImpl
Definition: embedhlp.hxx:48
constexpr tools::Long GetWidth() const
constexpr Point TopLeft() const
constexpr Size GetSize() const
constexpr tools::Long GetHeight() const
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
void SetFontSize(const Size &)
void SetTransparent(bool bTransparent)
void SetColor(const Color &)
void SetWeight(FontWeight)
void SetFamily(FontFamily)
constexpr ::Color COL_LIGHTRED(0xFF, 0x00, 0x00)
constexpr ::Color COL_BLACK(0x00, 0x00, 0x00)
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
float u
EmbeddedObjectRef * pObject
Definition: embedhlp.cxx:74
sal_Int32 nState
Definition: embedhlp.cxx:75
#define ERRCODE_NONE
#define SOFFICE_FILEFORMAT_CURRENT
struct _xmlTextWriter * xmlTextWriterPtr
FAMILY_SWISS
WEIGHT_BOLD
OUString aName
void * p
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
const sal_Int32 nConstBufferSize
int i
void Create(SwFormatVertOrient &rItem, SvStream &rStrm, sal_uInt16 nVersionAbusedAsSize)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
long Long
uno::Reference< embed::XEmbeddedObject > mxObj
Definition: embedhlp.cxx:238
void dumpAsXml(xmlTextWriterPtr pWriter) const
Definition: embedhlp.cxx:282
std::optional< Graphic > oGraphic
Definition: embedhlp.cxx:244
comphelper::EmbeddedObjectContainer * pContainer
Definition: embedhlp.cxx:243
rtl::Reference< EmbedEventListener_Impl > mxListener
Definition: embedhlp.cxx:240
EmbeddedObjectRef_Impl(const EmbeddedObjectRef_Impl &r)
Definition: embedhlp.cxx:266
awt::Size aDefaultSizeForChart_In_100TH_MM
Definition: embedhlp.cxx:252
Link< LinkParamNone *, bool > m_aIsProtectedHdl
Definition: embedhlp.cxx:254
unsigned char sal_Bool
oslFileHandle & pOut