Update git submodules
[LibreOffice.git] / forms / source / component / clickableimage.cxx
blob7a6d709241a66bc355e7ca8e894afc831bdd1532
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 "clickableimage.hxx"
21 #include <controlfeatureinterception.hxx>
22 #include <urltransformer.hxx>
23 #include <componenttools.hxx>
24 #include <com/sun/star/form/XSubmit.hpp>
25 #include <com/sun/star/frame/XDispatch.hpp>
26 #include <com/sun/star/frame/XDispatchProvider.hpp>
27 #include <com/sun/star/frame/FrameSearchFlag.hpp>
28 #include <com/sun/star/frame/XController.hpp>
29 #include <com/sun/star/frame/XFrame.hpp>
30 #include <com/sun/star/awt/ActionEvent.hpp>
31 #include <com/sun/star/graphic/XGraphic.hpp>
32 #include <com/sun/star/graphic/GraphicObject.hpp>
33 #include <com/sun/star/util/VetoException.hpp>
34 #include <tools/urlobj.hxx>
35 #include <tools/debug.hxx>
36 #include <comphelper/diagnose_ex.hxx>
37 #include <vcl/graph.hxx>
38 #include <vcl/svapp.hxx>
39 #include <sfx2/docfile.hxx>
40 #include <sfx2/objsh.hxx>
41 #include <osl/mutex.hxx>
42 #include <property.hxx>
43 #include <services.hxx>
44 #include <comphelper/interfacecontainer3.hxx>
45 #include <comphelper/property.hxx>
46 #include <comphelper/propertyvalue.hxx>
47 #include <comphelper/types.hxx>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include <svtools/imageresourceaccess.hxx>
50 #include <unotools/securityoptions.hxx>
51 #define LOCAL_URL_PREFIX '#'
54 namespace frm
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::sdb;
60 using namespace ::com::sun::star::sdbc;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::container;
63 using namespace ::com::sun::star::form;
64 using namespace ::com::sun::star::awt;
65 using namespace ::com::sun::star::lang;
66 using namespace ::com::sun::star::util;
67 using namespace ::com::sun::star::frame;
68 using namespace ::com::sun::star::form::submission;
69 using namespace ::com::sun::star::graphic;
70 using ::com::sun::star::awt::MouseEvent;
71 using ::com::sun::star::task::XInteractionHandler;
74 // OClickableImageBaseControl
77 Sequence<Type> OClickableImageBaseControl::_getTypes()
79 static Sequence<Type> const aTypes =
80 concatSequences(OControl::_getTypes(), OClickableImageBaseControl_BASE::getTypes());
81 return aTypes;
85 OClickableImageBaseControl::OClickableImageBaseControl(const Reference<XComponentContext>& _rxFactory, const OUString& _aService)
86 :OControl(_rxFactory, _aService)
87 ,m_aSubmissionVetoListeners( m_aMutex )
88 ,m_aFeatureInterception( _rxFactory )
89 ,m_aApproveActionListeners( m_aMutex )
90 ,m_aActionListeners( m_aMutex )
95 OClickableImageBaseControl::~OClickableImageBaseControl()
97 if (!OComponentHelper::rBHelper.bDisposed)
99 acquire();
100 dispose();
104 // UNO Binding
106 Any SAL_CALL OClickableImageBaseControl::queryAggregation(const Type& _rType)
108 Any aReturn = OControl::queryAggregation(_rType);
109 if (!aReturn.hasValue())
110 aReturn = OClickableImageBaseControl_BASE::queryInterface(_rType);
111 return aReturn;
114 // XApproveActionBroadcaster
116 void OClickableImageBaseControl::addApproveActionListener(
117 const Reference<XApproveActionListener>& l)
119 m_aApproveActionListeners.addInterface(l);
123 void OClickableImageBaseControl::removeApproveActionListener(
124 const Reference<XApproveActionListener>& l)
126 m_aApproveActionListeners.removeInterface(l);
130 void SAL_CALL OClickableImageBaseControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor )
132 m_aFeatureInterception.registerDispatchProviderInterceptor( _rxInterceptor );
136 void SAL_CALL OClickableImageBaseControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor )
138 m_aFeatureInterception.releaseDispatchProviderInterceptor( _rxInterceptor );
141 // OComponentHelper
143 void OClickableImageBaseControl::disposing()
145 EventObject aEvent( static_cast< XWeak* >( this ) );
146 m_aApproveActionListeners.disposeAndClear( aEvent );
147 m_aActionListeners.disposeAndClear( aEvent );
148 m_aSubmissionVetoListeners.disposeAndClear( aEvent );
149 m_aFeatureInterception.dispose();
152 ::osl::MutexGuard aGuard( m_aMutex );
153 m_pThread.clear();
156 OControl::disposing();
160 OImageProducerThread_Impl* OClickableImageBaseControl::getImageProducerThread()
162 if ( !m_pThread.is() )
164 m_pThread = new OImageProducerThread_Impl( this );
165 m_pThread->create();
167 return m_pThread.get();
171 bool OClickableImageBaseControl::approveAction( )
173 bool bCancelled = false;
174 EventObject aEvent( static_cast< XWeak* >( this ) );
176 ::comphelper::OInterfaceIteratorHelper3 aIter( m_aApproveActionListeners );
177 while( !bCancelled && aIter.hasMoreElements() )
179 // Every approveAction method must be thread-safe!
180 if( !aIter.next()->approveAction( aEvent ) )
181 bCancelled = true;
184 return !bCancelled;
188 // This method is also called from a thread and thus must be thread-safe.
189 void OClickableImageBaseControl::actionPerformed_Impl(bool bNotifyListener, const MouseEvent& rEvt)
191 if( bNotifyListener )
193 if ( !approveAction() )
194 return;
197 // Whether the rest of the code is thread-safe, one can't tell. Therefore
198 // we do most of the work on a locked solar mutex.
199 Reference<XPropertySet> xSet;
200 Reference< XInterface > xModelsParent;
201 FormButtonType eButtonType = FormButtonType_PUSH;
203 SolarMutexGuard aGuard;
205 // Get parent
206 Reference<XFormComponent> xComp(getModel(), UNO_QUERY);
207 if (!xComp.is())
208 return;
210 xModelsParent = xComp->getParent();
211 if (!xModelsParent.is())
212 return;
214 // Which button type?
215 xSet.set(xComp, css::uno::UNO_QUERY);
216 if ( !xSet.is() )
217 return;
218 xSet->getPropertyValue(PROPERTY_BUTTONTYPE) >>= eButtonType;
221 switch (eButtonType)
223 case FormButtonType_RESET:
225 // Reset methods must be thread-safe!
226 Reference<XReset> xReset(xModelsParent, UNO_QUERY);
227 if (!xReset.is())
228 return;
230 xReset->reset();
232 break;
234 case FormButtonType_SUBMIT:
236 // if some outer component can provide an interaction handler, use it
237 Reference< XInteractionHandler > xHandler( m_aFeatureInterception.queryDispatch( u"private:/InteractionHandler"_ustr ), UNO_QUERY );
240 implSubmit( rEvt, xHandler );
242 catch( const Exception& )
244 // ignore
247 break;
249 case FormButtonType_URL:
251 SolarMutexGuard aGuard;
253 Reference< XModel > xModel = getXModel(xModelsParent);
254 if (!xModel.is())
255 return;
258 // Execute URL now
259 Reference< XController > xController = xModel->getCurrentController();
260 if (!xController.is())
261 return;
263 Reference< XFrame > xFrame = xController->getFrame();
264 if( !xFrame.is() )
265 return;
267 URL aURL;
268 aURL.Complete =
269 getString(xSet->getPropertyValue(PROPERTY_TARGET_URL));
271 if (!aURL.Complete.isEmpty() && (LOCAL_URL_PREFIX == aURL.Complete[0]))
272 { // FIXME: The URL contains a local URL only. Since the URLTransformer does not handle this case correctly
273 // (it can't: it does not know the document URL), we have to take care for this ourself.
274 // The real solution would be to not allow such relative URLs (there is a rule that at runtime, all
275 // URLs have to be absolute), but for compatibility reasons this is no option.
276 // The more as the user does not want to see a local URL as "file://<path>/<document>#mark" if it
277 // could be "#mark" as well.
278 // If we someday say that this hack (yes, it's kind of a hack) is not sustainable anymore, the complete
279 // solution would be:
280 // * recognize URLs consisting of a mark only while _reading_ the document
281 // * for this, allow the INetURLObject (which at the moment is invoked when reading URLs) to
282 // transform such mark-only URLs into correct absolute URLs
283 // * at the UI, show only the mark
284 // * !!! recognize every SAVEAS on the document, so the absolute URL can be adjusted. This seems
285 // rather impossible !!!
286 aURL.Mark = aURL.Complete;
287 aURL.Complete = xModel->getURL();
288 aURL.Complete += aURL.Mark;
291 bool bDispatchUrlInternal = false;
292 xSet->getPropertyValue(PROPERTY_DISPATCHURLINTERNAL) >>= bDispatchUrlInternal;
293 if ( bDispatchUrlInternal )
295 m_aFeatureInterception.getTransformer().parseSmartWithProtocol( aURL, INET_FILE_SCHEME );
297 OUString aTargetFrame;
298 xSet->getPropertyValue(PROPERTY_TARGET_FRAME) >>= aTargetFrame;
300 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch( aURL, aTargetFrame,
301 FrameSearchFlag::SELF | FrameSearchFlag::PARENT |
302 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE );
304 Sequence<PropertyValue> aArgs { comphelper::makePropertyValue(u"Referer"_ustr, xModel->getURL()) };
306 if (xDisp.is())
307 xDisp->dispatch( aURL, aArgs );
309 else
311 URL aHyperLink = m_aFeatureInterception.getTransformer().getStrictURL( u".uno:OpenHyperlink"_ustr );
313 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aHyperLink, OUString() , 0);
315 if ( xDisp.is() )
317 Sequence<PropertyValue> aProps{
318 comphelper::makePropertyValue(u"URL"_ustr, aURL.Complete),
319 comphelper::makePropertyValue(
320 u"FrameName"_ustr, xSet->getPropertyValue(PROPERTY_TARGET_FRAME)),
321 comphelper::makePropertyValue(u"Referer"_ustr, xModel->getURL())
324 xDisp->dispatch( aHyperLink, aProps );
327 } break;
328 default:
330 // notify the action listeners for a push button
331 ActionEvent aEvt(static_cast<XWeak*>(this), m_aActionCommand);
332 m_aActionListeners.notifyEach( &XActionListener::actionPerformed, aEvt );
338 void SAL_CALL OClickableImageBaseControl::addSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener )
340 m_aSubmissionVetoListeners.addInterface( listener );
344 void SAL_CALL OClickableImageBaseControl::removeSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener )
346 m_aSubmissionVetoListeners.removeInterface( listener );
350 void SAL_CALL OClickableImageBaseControl::submitWithInteraction( const Reference< XInteractionHandler >& _rxHandler )
352 implSubmit( MouseEvent(), _rxHandler );
356 void SAL_CALL OClickableImageBaseControl::submit( )
358 implSubmit( MouseEvent(), nullptr );
362 Sequence< OUString > SAL_CALL OClickableImageBaseControl::getSupportedServiceNames( )
364 Sequence< OUString > aSupported = OControl::getSupportedServiceNames();
365 aSupported.realloc( aSupported.getLength() + 1 );
367 OUString* pArray = aSupported.getArray();
368 pArray[ aSupported.getLength() - 1 ] = FRM_SUN_CONTROL_SUBMITBUTTON;
370 return aSupported;
374 void OClickableImageBaseControl::implSubmit( const MouseEvent& _rEvent, const Reference< XInteractionHandler >& _rxHandler )
378 // allow the veto listeners to join the game
379 m_aSubmissionVetoListeners.notifyEach( &XSubmissionVetoListener::submitting, EventObject( *this ) );
381 // see whether there's an "submit interceptor" set at our model
382 Reference< submission::XSubmissionSupplier > xSubmissionSupp( getModel(), UNO_QUERY );
383 Reference< XSubmission > xSubmission;
384 if ( xSubmissionSupp.is() )
385 xSubmission = xSubmissionSupp->getSubmission();
387 if ( xSubmission.is() )
389 if ( !_rxHandler.is() )
390 xSubmission->submit();
391 else
392 xSubmission->submitWithInteraction( _rxHandler );
394 else
396 // no "interceptor" -> ordinary (old-way) submission
397 Reference< XChild > xChild( getModel(), UNO_QUERY );
398 Reference< XSubmit > xParentSubmission;
399 if ( xChild.is() )
400 xParentSubmission.set(xChild->getParent(), css::uno::UNO_QUERY);
401 if ( xParentSubmission.is() )
402 xParentSubmission->submit( this, _rEvent );
405 catch( const VetoException& )
407 // allowed to leave
408 throw;
410 catch( const RuntimeException& )
412 // allowed to leave
413 throw;
415 catch( const WrappedTargetException& )
417 // allowed to leave
418 throw;
420 catch( const Exception& )
422 css::uno::Any anyEx = cppu::getCaughtException();
423 TOOLS_WARN_EXCEPTION( "forms.component", "OClickableImageBaseControl::implSubmit: caught an unknown exception!" );
424 throw WrappedTargetException( OUString(), *this, anyEx );
429 // OClickableImageBaseModel
432 Sequence<Type> OClickableImageBaseModel::_getTypes()
434 return concatSequences(
435 OControlModel::_getTypes(),
436 OClickableImageBaseModel_Base::getTypes()
441 OClickableImageBaseModel::OClickableImageBaseModel( const Reference< XComponentContext >& _rxFactory, const OUString& _rUnoControlModelTypeName,
442 const OUString& rDefault )
443 :OControlModel( _rxFactory, _rUnoControlModelTypeName, rDefault )
444 ,OPropertyChangeListener()
445 ,m_bDispatchUrlInternal(false)
446 ,m_bProdStarted(false)
448 implConstruct();
449 m_eButtonType = FormButtonType_PUSH;
453 OClickableImageBaseModel::OClickableImageBaseModel( const OClickableImageBaseModel* _pOriginal, const Reference<XComponentContext>& _rxFactory )
454 :OControlModel( _pOriginal, _rxFactory )
455 ,OPropertyChangeListener()
456 ,m_xGraphicObject( _pOriginal->m_xGraphicObject )
457 ,m_bDispatchUrlInternal(false)
458 ,m_bProdStarted( false )
460 implConstruct();
462 // copy properties
463 m_eButtonType = _pOriginal->m_eButtonType;
464 m_sTargetURL = _pOriginal->m_sTargetURL;
465 m_sTargetFrame = _pOriginal->m_sTargetFrame;
466 m_bDispatchUrlInternal = _pOriginal->m_bDispatchUrlInternal;
470 void OClickableImageBaseModel::implInitializeImageURL( )
472 osl_atomic_increment( &m_refCount );
474 // simulate a propertyChanged event for the ImageURL
475 Any aImageURL;
476 getFastPropertyValue( aImageURL, PROPERTY_ID_IMAGE_URL );
477 _propertyChanged( PropertyChangeEvent( *this, PROPERTY_IMAGE_URL, false, PROPERTY_ID_IMAGE_URL, Any( ), aImageURL ) );
479 osl_atomic_decrement( &m_refCount );
483 void OClickableImageBaseModel::implConstruct()
485 m_xProducer = new ImageProducer;
486 m_xProducer->SetDoneHdl( LINK( this, OClickableImageBaseModel, OnImageImportDone ) );
487 osl_atomic_increment( &m_refCount );
489 if ( m_xAggregateSet.is() )
491 rtl::Reference<OPropertyChangeMultiplexer> pMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet );
492 pMultiplexer->addProperty( PROPERTY_IMAGE_URL );
495 osl_atomic_decrement(&m_refCount);
499 OClickableImageBaseModel::~OClickableImageBaseModel()
501 if (!OComponentHelper::rBHelper.bDisposed)
503 acquire();
504 dispose();
506 DBG_ASSERT(m_pMedium == nullptr, "OClickableImageBaseModel::~OClickableImageBaseModel : leaving a memory leak ...");
507 // This should be cleaned up at least in the dispose
511 // XImageProducer
513 void SAL_CALL OClickableImageBaseModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer )
515 ImageModelMethodGuard aGuard( *this );
516 GetImageProducer()->addConsumer( _rxConsumer );
520 void SAL_CALL OClickableImageBaseModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer )
522 ImageModelMethodGuard aGuard( *this );
523 GetImageProducer()->removeConsumer( _rxConsumer );
527 void SAL_CALL OClickableImageBaseModel::startProduction( )
529 ImageModelMethodGuard aGuard( *this );
530 GetImageProducer()->startProduction();
534 Reference< submission::XSubmission > SAL_CALL OClickableImageBaseModel::getSubmission()
536 return m_xSubmissionDelegate;
540 void SAL_CALL OClickableImageBaseModel::setSubmission( const Reference< submission::XSubmission >& _submission )
542 m_xSubmissionDelegate = _submission;
546 Sequence< OUString > SAL_CALL OClickableImageBaseModel::getSupportedServiceNames( )
548 Sequence< OUString > aSupported = OControlModel::getSupportedServiceNames();
549 aSupported.realloc( aSupported.getLength() + 1 );
551 OUString* pArray = aSupported.getArray();
552 pArray[ aSupported.getLength() - 1 ] = FRM_SUN_COMPONENT_SUBMITBUTTON;
554 return aSupported;
557 // OComponentHelper
559 void OClickableImageBaseModel::disposing()
561 OControlModel::disposing();
562 m_pMedium.reset();
563 m_xProducer.clear();
567 Any SAL_CALL OClickableImageBaseModel::queryAggregation(const Type& _rType)
569 // order matters:
570 // we definitely want to "override" the XImageProducer interface of our aggregate,
571 // thus check OClickableImageBaseModel_Base (which provides this) first
572 Any aReturn = OClickableImageBaseModel_Base::queryInterface( _rType );
574 // BUT: _don't_ let it feel responsible for the XTypeProvider interface
575 // (as this is implemented by our base class in the proper way)
576 if ( _rType.equals( cppu::UnoType<XTypeProvider>::get() )
577 || !aReturn.hasValue()
579 aReturn = OControlModel::queryAggregation( _rType );
581 return aReturn;
585 void OClickableImageBaseModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
587 switch (nHandle)
589 case PROPERTY_ID_BUTTONTYPE : rValue <<= m_eButtonType; break;
590 case PROPERTY_ID_TARGET_URL : rValue <<= m_sTargetURL; break;
591 case PROPERTY_ID_TARGET_FRAME : rValue <<= m_sTargetFrame; break;
592 case PROPERTY_ID_DISPATCHURLINTERNAL : rValue <<= m_bDispatchUrlInternal; break;
593 default:
594 OControlModel::getFastPropertyValue(rValue, nHandle);
599 void OClickableImageBaseModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue)
601 switch (nHandle)
603 case PROPERTY_ID_BUTTONTYPE :
604 DBG_ASSERT(rValue.has<FormButtonType>(), "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
605 rValue >>= m_eButtonType;
606 break;
608 case PROPERTY_ID_TARGET_URL :
609 DBG_ASSERT(rValue.getValueTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
610 rValue >>= m_sTargetURL;
611 break;
613 case PROPERTY_ID_TARGET_FRAME :
614 DBG_ASSERT(rValue.getValueTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
615 rValue >>= m_sTargetFrame;
616 break;
618 case PROPERTY_ID_DISPATCHURLINTERNAL:
619 DBG_ASSERT(rValue.getValueTypeClass() == TypeClass_BOOLEAN, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
620 rValue >>= m_bDispatchUrlInternal;
621 break;
623 default:
624 OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue);
629 sal_Bool OClickableImageBaseModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
631 switch (nHandle)
633 case PROPERTY_ID_BUTTONTYPE :
634 return tryPropertyValueEnum( rConvertedValue, rOldValue, rValue, m_eButtonType );
636 case PROPERTY_ID_TARGET_URL :
637 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetURL);
639 case PROPERTY_ID_TARGET_FRAME :
640 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetFrame);
642 case PROPERTY_ID_DISPATCHURLINTERNAL :
643 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bDispatchUrlInternal);
645 default:
646 return OControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
651 void OClickableImageBaseModel::StartProduction()
653 ImageProducer *pImgProd = GetImageProducer();
654 // grab the ImageURL
655 OUString sURL;
656 getPropertyValue(u"ImageURL"_ustr) >>= sURL;
657 if (!m_pMedium)
659 if ( ::svt::GraphicAccess::isSupportedURL( sURL ) )
660 pImgProd->SetImage( sURL );
661 else
662 // caution: the medium may be NULL if somebody gave us an invalid URL to work with
663 pImgProd->SetImage(OUString());
664 return;
666 if (m_pMedium->GetErrorCode()==ERRCODE_NONE)
668 SvStream* pStream = m_pMedium->GetInStream();
670 pImgProd->SetImage(*pStream);
671 pImgProd->startProduction();
672 m_bProdStarted = true;
674 else
676 pImgProd->SetImage(OUString());
677 m_pMedium.reset();
681 SfxObjectShell* OClickableImageBaseModel::GetObjectShell()
683 // Find the XModel to get to the Object shell or at least the
684 // Referer.
685 // There's only a Model if we load HTML documents and the URL is
686 // changed in a document that is already loaded. There's no way
687 // we can get to the Model during loading.
688 Reference< XModel > xModel;
689 css::uno::Reference<css::uno::XInterface> xIfc( *this );
690 while( !xModel.is() && xIfc.is() )
692 Reference<XChild> xChild( xIfc, UNO_QUERY );
693 xIfc = xChild->getParent();
694 xModel.set(xIfc, css::uno::UNO_QUERY);
697 // Search for the Object shell by iterating over all Object shells
698 // and comparing their XModel to ours.
699 // As an optimization, we try the current Object shell first.
700 SfxObjectShell *pObjSh = nullptr;
702 if( xModel.is() )
704 SfxObjectShell *pTestObjSh = SfxObjectShell::Current();
705 if( pTestObjSh )
707 Reference< XModel > xTestModel = pTestObjSh->GetModel();
708 if( xTestModel == xModel )
709 pObjSh = pTestObjSh;
711 if( !pObjSh )
713 pTestObjSh = SfxObjectShell::GetFirst();
714 while( !pObjSh && pTestObjSh )
716 Reference< XModel > xTestModel = pTestObjSh->GetModel();
717 if( xTestModel == xModel )
718 pObjSh = pTestObjSh;
719 else
720 pTestObjSh = SfxObjectShell::GetNext( *pTestObjSh );
725 return pObjSh;
728 void OClickableImageBaseModel::SetURL( const OUString& rURL )
730 if (m_pMedium || rURL.isEmpty())
732 // Free the stream at the Producer, before the medium is deleted
733 GetImageProducer()->SetImage(OUString());
734 m_pMedium.reset();
737 // the SfxMedium is not allowed to be created with an invalid URL, so we have to check this first
738 INetURLObject aUrl(rURL);
739 if (INetProtocol::NotValid == aUrl.GetProtocol() || aUrl.IsExoticProtocol())
740 // we treat an invalid URL like we would treat no URL
741 return;
743 if (!rURL.isEmpty() && !::svt::GraphicAccess::isSupportedURL( rURL ) )
745 m_pMedium.reset(new SfxMedium(rURL, StreamMode::STD_READ));
747 SfxObjectShell *pObjSh = GetObjectShell();
749 if( pObjSh )
751 // Transfer target frame, so that javascript: URLs
752 // can also be "loaded"
753 const SfxMedium *pShMedium = pObjSh->GetMedium();
754 if( pShMedium )
755 m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame());
758 m_bProdStarted = false;
760 OUString referer;
761 getPropertyValue(u"Referer"_ustr) >>= referer;
762 if (!SvtSecurityOptions::isUntrustedReferer(referer)) {
763 // Kick off download (caution: can be synchronous).
764 m_pMedium->Download(LINK(this, OClickableImageBaseModel, DownloadDoneLink));
767 else
769 if ( ::svt::GraphicAccess::isSupportedURL( rURL ) )
770 GetImageProducer()->SetImage( rURL );
771 GetImageProducer()->startProduction();
776 void OClickableImageBaseModel::DataAvailable()
778 if (!m_bProdStarted)
779 StartProduction();
781 GetImageProducer()->NewDataAvailable();
785 IMPL_LINK_NOARG( OClickableImageBaseModel, DownloadDoneLink, void*, void )
787 ::osl::MutexGuard aGuard( m_aMutex );
788 DataAvailable();
792 void OClickableImageBaseModel::_propertyChanged( const PropertyChangeEvent& rEvt )
794 // If a URL was set, it needs to be passed onto the ImageProducer.
795 ::osl::MutexGuard aGuard(m_aMutex);
796 SetURL( getString(rEvt.NewValue) );
800 Any OClickableImageBaseModel::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
802 switch (nHandle)
804 case PROPERTY_ID_BUTTONTYPE : return Any( FormButtonType_PUSH );
805 case PROPERTY_ID_TARGET_URL :
806 case PROPERTY_ID_TARGET_FRAME : return Any( OUString() );
807 case PROPERTY_ID_DISPATCHURLINTERNAL : return Any( false );
808 default:
809 return OControlModel::getPropertyDefaultByHandle(nHandle);
813 IMPL_LINK( OClickableImageBaseModel, OnImageImportDone, Graphic*, i_pGraphic, void )
815 const Reference< XGraphic > xGraphic( i_pGraphic != nullptr ? Graphic(i_pGraphic->GetBitmapEx()).GetXGraphic() : nullptr );
816 if ( !xGraphic.is() )
818 m_xGraphicObject.clear();
820 else
822 m_xGraphicObject = css::graphic::GraphicObject::create( m_xContext );
823 m_xGraphicObject->setGraphic( xGraphic );
828 // OImageProducerThread_Impl
830 void OImageProducerThread_Impl::processEvent( ::cppu::OComponentHelper *pCompImpl,
831 const EventObject* pEvt,
832 const Reference<XControl>&,
833 bool )
835 static_cast<OClickableImageBaseControl *>(pCompImpl)->actionPerformed_Impl( true, *static_cast<const MouseEvent *>(pEvt) );
839 } // namespace frm
842 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */