summaryrefslogtreecommitdiffstats
path: root/forms/source/component/clickableimage.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:51:28 +0000
commit940b4d1848e8c70ab7642901a68594e8016caffc (patch)
treeeb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /forms/source/component/clickableimage.cxx
parentInitial commit. (diff)
downloadlibreoffice-1ad18e38974bb28c3d98d0be8f7d8c18fc56de29.tar.xz
libreoffice-1ad18e38974bb28c3d98d0be8f7d8c18fc56de29.zip
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'forms/source/component/clickableimage.cxx')
-rw-r--r--forms/source/component/clickableimage.cxx844
1 files changed, 844 insertions, 0 deletions
diff --git a/forms/source/component/clickableimage.cxx b/forms/source/component/clickableimage.cxx
new file mode 100644
index 000000000..68861e42c
--- /dev/null
+++ b/forms/source/component/clickableimage.cxx
@@ -0,0 +1,844 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "clickableimage.hxx"
+#include <controlfeatureinterception.hxx>
+#include <urltransformer.hxx>
+#include <componenttools.hxx>
+#include <com/sun/star/form/XSubmit.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/awt/ActionEvent.hpp>
+#include <com/sun/star/awt/XActionListener.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/GraphicObject.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <tools/urlobj.hxx>
+#include <tools/debug.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <osl/mutex.hxx>
+#include <property.hxx>
+#include <services.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <svtools/imageresourceaccess.hxx>
+#define LOCAL_URL_PREFIX '#'
+
+
+namespace frm
+{
+
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::form;
+ using namespace ::com::sun::star::awt;
+ using namespace ::com::sun::star::io;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::frame;
+ using namespace ::com::sun::star::form::submission;
+ using namespace ::com::sun::star::graphic;
+ using ::com::sun::star::awt::MouseEvent;
+ using ::com::sun::star::task::XInteractionHandler;
+
+
+ // OClickableImageBaseControl
+
+
+ Sequence<Type> OClickableImageBaseControl::_getTypes()
+ {
+ static Sequence<Type> const aTypes =
+ concatSequences(OControl::_getTypes(), OClickableImageBaseControl_BASE::getTypes());
+ return aTypes;
+ }
+
+
+ OClickableImageBaseControl::OClickableImageBaseControl(const Reference<XComponentContext>& _rxFactory, const OUString& _aService)
+ :OControl(_rxFactory, _aService)
+ ,m_aSubmissionVetoListeners( m_aMutex )
+ ,m_aApproveActionListeners( m_aMutex )
+ ,m_aActionListeners( m_aMutex )
+ {
+ m_pFeatureInterception.reset( new ControlFeatureInterception( _rxFactory ) );
+ }
+
+
+ OClickableImageBaseControl::~OClickableImageBaseControl()
+ {
+ if (!OComponentHelper::rBHelper.bDisposed)
+ {
+ acquire();
+ dispose();
+ }
+ }
+
+ // UNO Binding
+
+ Any SAL_CALL OClickableImageBaseControl::queryAggregation(const Type& _rType)
+ {
+ Any aReturn = OControl::queryAggregation(_rType);
+ if (!aReturn.hasValue())
+ aReturn = OClickableImageBaseControl_BASE::queryInterface(_rType);
+ return aReturn;
+ }
+
+ // XApproveActionBroadcaster
+
+ void OClickableImageBaseControl::addApproveActionListener(
+ const Reference<XApproveActionListener>& l)
+ {
+ m_aApproveActionListeners.addInterface(l);
+ }
+
+
+ void OClickableImageBaseControl::removeApproveActionListener(
+ const Reference<XApproveActionListener>& l)
+ {
+ m_aApproveActionListeners.removeInterface(l);
+ }
+
+
+ void SAL_CALL OClickableImageBaseControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor )
+ {
+ m_pFeatureInterception->registerDispatchProviderInterceptor( _rxInterceptor );
+ }
+
+
+ void SAL_CALL OClickableImageBaseControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor )
+ {
+ m_pFeatureInterception->releaseDispatchProviderInterceptor( _rxInterceptor );
+ }
+
+ // OComponentHelper
+
+ void OClickableImageBaseControl::disposing()
+ {
+ EventObject aEvent( static_cast< XWeak* >( this ) );
+ m_aApproveActionListeners.disposeAndClear( aEvent );
+ m_aActionListeners.disposeAndClear( aEvent );
+ m_aSubmissionVetoListeners.disposeAndClear( aEvent );
+ m_pFeatureInterception->dispose();
+
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_pThread.clear();
+ }
+
+ OControl::disposing();
+ }
+
+
+ OImageProducerThread_Impl* OClickableImageBaseControl::getImageProducerThread()
+ {
+ if ( !m_pThread.is() )
+ {
+ m_pThread = new OImageProducerThread_Impl( this );
+ m_pThread->create();
+ }
+ return m_pThread.get();
+ }
+
+
+ bool OClickableImageBaseControl::approveAction( )
+ {
+ bool bCancelled = false;
+ EventObject aEvent( static_cast< XWeak* >( this ) );
+
+ ::comphelper::OInterfaceIteratorHelper2 aIter( m_aApproveActionListeners );
+ while( !bCancelled && aIter.hasMoreElements() )
+ {
+ // Every approveAction method must be thread-safe!
+ if( !static_cast< XApproveActionListener* >( aIter.next() )->approveAction( aEvent ) )
+ bCancelled = true;
+ }
+
+ return !bCancelled;
+ }
+
+
+ // This method is also called from a thread and thus must be thread-safe.
+ void OClickableImageBaseControl::actionPerformed_Impl(bool bNotifyListener, const MouseEvent& rEvt)
+ {
+ if( bNotifyListener )
+ {
+ if ( !approveAction() )
+ return;
+ }
+
+ // Whether the rest of the code is thread-safe, one can't tell. Therefore
+ // we do most of the work on a locked solar mutex.
+ Reference<XPropertySet> xSet;
+ Reference< XInterface > xModelsParent;
+ FormButtonType eButtonType = FormButtonType_PUSH;
+ {
+ SolarMutexGuard aGuard;
+
+ // Get parent
+ Reference<XFormComponent> xComp(getModel(), UNO_QUERY);
+ if (!xComp.is())
+ return;
+
+ xModelsParent = xComp->getParent();
+ if (!xModelsParent.is())
+ return;
+
+ // Which button type?
+ xSet.set(xComp, css::uno::UNO_QUERY);
+ if ( !xSet.is() )
+ return;
+ xSet->getPropertyValue(PROPERTY_BUTTONTYPE) >>= eButtonType;
+ }
+
+ switch (eButtonType)
+ {
+ case FormButtonType_RESET:
+ {
+ // Reset methods must be thread-safe!
+ Reference<XReset> xReset(xModelsParent, UNO_QUERY);
+ if (!xReset.is())
+ return;
+
+ xReset->reset();
+ }
+ break;
+
+ case FormButtonType_SUBMIT:
+ {
+ // if some outer component can provide an interaction handler, use it
+ Reference< XInteractionHandler > xHandler( m_pFeatureInterception->queryDispatch( "private:/InteractionHandler" ), UNO_QUERY );
+ try
+ {
+ implSubmit( rEvt, xHandler );
+ }
+ catch( const Exception& )
+ {
+ // ignore
+ }
+ }
+ break;
+
+ case FormButtonType_URL:
+ {
+ SolarMutexGuard aGuard;
+
+ Reference< XModel > xModel = getXModel(xModelsParent);
+ if (!xModel.is())
+ return;
+
+
+ // Execute URL now
+ Reference< XController > xController = xModel->getCurrentController();
+ if (!xController.is())
+ return;
+
+ Reference< XFrame > xFrame = xController->getFrame();
+ if( !xFrame.is() )
+ return;
+
+ URL aURL;
+ aURL.Complete =
+ getString(xSet->getPropertyValue(PROPERTY_TARGET_URL));
+
+ if (!aURL.Complete.isEmpty() && (LOCAL_URL_PREFIX == aURL.Complete[0]))
+ { // FIXME: The URL contains a local URL only. Since the URLTransformer does not handle this case correctly
+ // (it can't: it does not know the document URL), we have to take care for this ourself.
+ // The real solution would be to not allow such relative URLs (there is a rule that at runtime, all
+ // URLs have to be absolute), but for compatibility reasons this is no option.
+ // The more as the user does not want to see a local URL as "file://<path>/<document>#mark" if it
+ // could be "#mark" as well.
+ // If we someday say that this hack (yes, it's kind of a hack) is not sustainable anymore, the complete
+ // solution would be:
+ // * recognize URLs consisting of a mark only while _reading_ the document
+ // * for this, allow the INetURLObject (which at the moment is invoked when reading URLs) to
+ // transform such mark-only URLs into correct absolute URLs
+ // * at the UI, show only the mark
+ // * !!! recognize every SAVEAS on the document, so the absolute URL can be adjusted. This seems
+ // rather impossible !!!
+ aURL.Mark = aURL.Complete;
+ aURL.Complete = xModel->getURL();
+ aURL.Complete += aURL.Mark;
+ }
+
+ bool bDispatchUrlInternal = false;
+ xSet->getPropertyValue(PROPERTY_DISPATCHURLINTERNAL) >>= bDispatchUrlInternal;
+ if ( bDispatchUrlInternal )
+ {
+ m_pFeatureInterception->getTransformer().parseSmartWithAsciiProtocol( aURL, INET_FILE_SCHEME );
+
+ OUString aTargetFrame;
+ xSet->getPropertyValue(PROPERTY_TARGET_FRAME) >>= aTargetFrame;
+
+ Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch( aURL, aTargetFrame,
+ FrameSearchFlag::SELF | FrameSearchFlag::PARENT |
+ FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE );
+
+ Sequence<PropertyValue> aArgs(1);
+ PropertyValue& rProp = aArgs.getArray()[0];
+ rProp.Name = "Referer";
+ rProp.Value <<= xModel->getURL();
+
+ if (xDisp.is())
+ xDisp->dispatch( aURL, aArgs );
+ }
+ else
+ {
+ URL aHyperLink = m_pFeatureInterception->getTransformer().getStrictURLFromAscii( ".uno:OpenHyperlink" );
+
+ Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY_THROW)->queryDispatch(aHyperLink, OUString() , 0);
+
+ if ( xDisp.is() )
+ {
+ Sequence<PropertyValue> aProps(3);
+ aProps[0].Name = "URL";
+ aProps[0].Value <<= aURL.Complete;
+
+ aProps[1].Name = "FrameName";
+ aProps[1].Value = xSet->getPropertyValue(PROPERTY_TARGET_FRAME);
+
+ aProps[2].Name = "Referer";
+ aProps[2].Value <<= xModel->getURL();
+
+ xDisp->dispatch( aHyperLink, aProps );
+ }
+ }
+ } break;
+ default:
+ {
+ // notify the action listeners for a push button
+ ActionEvent aEvt(static_cast<XWeak*>(this), m_aActionCommand);
+ m_aActionListeners.notifyEach( &XActionListener::actionPerformed, aEvt );
+ }
+ }
+ }
+
+
+ void SAL_CALL OClickableImageBaseControl::addSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener )
+ {
+ m_aSubmissionVetoListeners.addInterface( listener );
+ }
+
+
+ void SAL_CALL OClickableImageBaseControl::removeSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener )
+ {
+ m_aSubmissionVetoListeners.removeInterface( listener );
+ }
+
+
+ void SAL_CALL OClickableImageBaseControl::submitWithInteraction( const Reference< XInteractionHandler >& _rxHandler )
+ {
+ implSubmit( MouseEvent(), _rxHandler );
+ }
+
+
+ void SAL_CALL OClickableImageBaseControl::submit( )
+ {
+ implSubmit( MouseEvent(), nullptr );
+ }
+
+
+ Sequence< OUString > SAL_CALL OClickableImageBaseControl::getSupportedServiceNames( )
+ {
+ Sequence< OUString > aSupported = OControl::getSupportedServiceNames();
+ aSupported.realloc( aSupported.getLength() + 1 );
+
+ OUString* pArray = aSupported.getArray();
+ pArray[ aSupported.getLength() - 1 ] = FRM_SUN_CONTROL_SUBMITBUTTON;
+
+ return aSupported;
+ }
+
+
+ void OClickableImageBaseControl::implSubmit( const MouseEvent& _rEvent, const Reference< XInteractionHandler >& _rxHandler )
+ {
+ try
+ {
+ // allow the veto listeners to join the game
+ m_aSubmissionVetoListeners.notifyEach( &XSubmissionVetoListener::submitting, EventObject( *this ) );
+
+ // see whether there's an "submit interceptor" set at our model
+ Reference< submission::XSubmissionSupplier > xSubmissionSupp( getModel(), UNO_QUERY );
+ Reference< XSubmission > xSubmission;
+ if ( xSubmissionSupp.is() )
+ xSubmission = xSubmissionSupp->getSubmission();
+
+ if ( xSubmission.is() )
+ {
+ if ( !_rxHandler.is() )
+ xSubmission->submit();
+ else
+ xSubmission->submitWithInteraction( _rxHandler );
+ }
+ else
+ {
+ // no "interceptor" -> ordinary (old-way) submission
+ Reference< XChild > xChild( getModel(), UNO_QUERY );
+ Reference< XSubmit > xParentSubmission;
+ if ( xChild.is() )
+ xParentSubmission.set(xChild->getParent(), css::uno::UNO_QUERY);
+ if ( xParentSubmission.is() )
+ xParentSubmission->submit( this, _rEvent );
+ }
+ }
+ catch( const VetoException& )
+ {
+ // allowed to leave
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ // allowed to leave
+ throw;
+ }
+ catch( const WrappedTargetException& )
+ {
+ // allowed to leave
+ throw;
+ }
+ catch( const Exception& )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ OSL_FAIL( "OClickableImageBaseControl::implSubmit: caught an unknown exception!" );
+ throw WrappedTargetException( OUString(), *this, anyEx );
+ }
+ }
+
+
+ // OClickableImageBaseModel
+
+
+ Sequence<Type> OClickableImageBaseModel::_getTypes()
+ {
+ return concatSequences(
+ OControlModel::_getTypes(),
+ OClickableImageBaseModel_Base::getTypes()
+ );
+ }
+
+
+ OClickableImageBaseModel::OClickableImageBaseModel( const Reference< XComponentContext >& _rxFactory, const OUString& _rUnoControlModelTypeName,
+ const OUString& rDefault )
+ :OControlModel( _rxFactory, _rUnoControlModelTypeName, rDefault )
+ ,OPropertyChangeListener(m_aMutex)
+ ,m_xGraphicObject()
+ ,m_bDispatchUrlInternal(false)
+ ,m_bProdStarted(false)
+ {
+ implConstruct();
+ m_eButtonType = FormButtonType_PUSH;
+ }
+
+
+ OClickableImageBaseModel::OClickableImageBaseModel( const OClickableImageBaseModel* _pOriginal, const Reference<XComponentContext>& _rxFactory )
+ :OControlModel( _pOriginal, _rxFactory )
+ ,OPropertyChangeListener( m_aMutex )
+ ,m_xGraphicObject( _pOriginal->m_xGraphicObject )
+ ,m_bDispatchUrlInternal(false)
+ ,m_bProdStarted( false )
+ {
+ implConstruct();
+
+ // copy properties
+ m_eButtonType = _pOriginal->m_eButtonType;
+ m_sTargetURL = _pOriginal->m_sTargetURL;
+ m_sTargetFrame = _pOriginal->m_sTargetFrame;
+ m_bDispatchUrlInternal = _pOriginal->m_bDispatchUrlInternal;
+ }
+
+
+ void OClickableImageBaseModel::implInitializeImageURL( )
+ {
+ osl_atomic_increment( &m_refCount );
+ {
+ // simulate a propertyChanged event for the ImageURL
+ Any aImageURL;
+ getFastPropertyValue( aImageURL, PROPERTY_ID_IMAGE_URL );
+ _propertyChanged( PropertyChangeEvent( *this, PROPERTY_IMAGE_URL, false, PROPERTY_ID_IMAGE_URL, Any( ), aImageURL ) );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+
+ void OClickableImageBaseModel::implConstruct()
+ {
+ m_xProducer = new ImageProducer;
+ m_xProducer->SetDoneHdl( LINK( this, OClickableImageBaseModel, OnImageImportDone ) );
+ osl_atomic_increment( &m_refCount );
+ {
+ if ( m_xAggregateSet.is() )
+ {
+ OPropertyChangeMultiplexer* pMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet );
+ pMultiplexer->addProperty( PROPERTY_IMAGE_URL );
+ }
+ }
+ osl_atomic_decrement(&m_refCount);
+ }
+
+
+ OClickableImageBaseModel::~OClickableImageBaseModel()
+ {
+ if (!OComponentHelper::rBHelper.bDisposed)
+ {
+ acquire();
+ dispose();
+ }
+ DBG_ASSERT(m_pMedium == nullptr, "OClickableImageBaseModel::~OClickableImageBaseModel : leaving a memory leak ...");
+ // This should be cleaned up at least in the dispose
+
+ }
+
+ // XImageProducer
+
+ void SAL_CALL OClickableImageBaseModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer )
+ {
+ ImageModelMethodGuard aGuard( *this );
+ GetImageProducer()->addConsumer( _rxConsumer );
+ }
+
+
+ void SAL_CALL OClickableImageBaseModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer )
+ {
+ ImageModelMethodGuard aGuard( *this );
+ GetImageProducer()->removeConsumer( _rxConsumer );
+ }
+
+
+ void SAL_CALL OClickableImageBaseModel::startProduction( )
+ {
+ ImageModelMethodGuard aGuard( *this );
+ GetImageProducer()->startProduction();
+ }
+
+
+ Reference< submission::XSubmission > SAL_CALL OClickableImageBaseModel::getSubmission()
+ {
+ return m_xSubmissionDelegate;
+ }
+
+
+ void SAL_CALL OClickableImageBaseModel::setSubmission( const Reference< submission::XSubmission >& _submission )
+ {
+ m_xSubmissionDelegate = _submission;
+ }
+
+
+ Sequence< OUString > SAL_CALL OClickableImageBaseModel::getSupportedServiceNames( )
+ {
+ Sequence< OUString > aSupported = OControlModel::getSupportedServiceNames();
+ aSupported.realloc( aSupported.getLength() + 1 );
+
+ OUString* pArray = aSupported.getArray();
+ pArray[ aSupported.getLength() - 1 ] = FRM_SUN_COMPONENT_SUBMITBUTTON;
+
+ return aSupported;
+ }
+
+ // OComponentHelper
+
+ void OClickableImageBaseModel::disposing()
+ {
+ OControlModel::disposing();
+ m_pMedium.reset();
+ m_xProducer.clear();
+ }
+
+
+ Any SAL_CALL OClickableImageBaseModel::queryAggregation(const Type& _rType)
+ {
+ // order matters:
+ // we definitely want to "override" the XImageProducer interface of our aggregate,
+ // thus check OClickableImageBaseModel_Base (which provides this) first
+ Any aReturn = OClickableImageBaseModel_Base::queryInterface( _rType );
+
+ // BUT: _don't_ let it feel responsible for the XTypeProvider interface
+ // (as this is implemented by our base class in the proper way)
+ if ( _rType.equals( cppu::UnoType<XTypeProvider>::get() )
+ || !aReturn.hasValue()
+ )
+ aReturn = OControlModel::queryAggregation( _rType );
+
+ return aReturn;
+ }
+
+
+ void OClickableImageBaseModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_BUTTONTYPE : rValue <<= m_eButtonType; break;
+ case PROPERTY_ID_TARGET_URL : rValue <<= m_sTargetURL; break;
+ case PROPERTY_ID_TARGET_FRAME : rValue <<= m_sTargetFrame; break;
+ case PROPERTY_ID_DISPATCHURLINTERNAL : rValue <<= m_bDispatchUrlInternal; break;
+ default:
+ OControlModel::getFastPropertyValue(rValue, nHandle);
+ }
+ }
+
+
+ void OClickableImageBaseModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue)
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_BUTTONTYPE :
+ DBG_ASSERT(rValue.has<FormButtonType>(), "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
+ rValue >>= m_eButtonType;
+ break;
+
+ case PROPERTY_ID_TARGET_URL :
+ DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
+ rValue >>= m_sTargetURL;
+ break;
+
+ case PROPERTY_ID_TARGET_FRAME :
+ DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
+ rValue >>= m_sTargetFrame;
+ break;
+
+ case PROPERTY_ID_DISPATCHURLINTERNAL:
+ DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
+ rValue >>= m_bDispatchUrlInternal;
+ break;
+
+ default:
+ OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue);
+ }
+ }
+
+
+ sal_Bool OClickableImageBaseModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_BUTTONTYPE :
+ return tryPropertyValueEnum( rConvertedValue, rOldValue, rValue, m_eButtonType );
+
+ case PROPERTY_ID_TARGET_URL :
+ return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetURL);
+
+ case PROPERTY_ID_TARGET_FRAME :
+ return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetFrame);
+
+ case PROPERTY_ID_DISPATCHURLINTERNAL :
+ return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bDispatchUrlInternal);
+
+ default:
+ return OControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
+ }
+ }
+
+
+ void OClickableImageBaseModel::StartProduction()
+ {
+ ImageProducer *pImgProd = GetImageProducer();
+ // grab the ImageURL
+ OUString sURL;
+ getPropertyValue("ImageURL") >>= sURL;
+ if (!m_pMedium)
+ {
+ if ( ::svt::GraphicAccess::isSupportedURL( sURL ) )
+ pImgProd->SetImage( sURL );
+ else
+ // caution: the medium may be NULL if somebody gave us an invalid URL to work with
+ pImgProd->SetImage(OUString());
+ return;
+ }
+ if (m_pMedium->GetErrorCode()==ERRCODE_NONE)
+ {
+ SvStream* pStream = m_pMedium->GetInStream();
+
+ pImgProd->SetImage(*pStream);
+ pImgProd->startProduction();
+ m_bProdStarted = true;
+ }
+ else
+ {
+ pImgProd->SetImage(OUString());
+ m_pMedium.reset();
+ }
+ }
+
+ SfxObjectShell* OClickableImageBaseModel::GetObjectShell()
+ {
+ // Find the XModel to get to the Object shell or at least the
+ // Referer.
+ // There's only a Model if we load HTML documents and the URL is
+ // changed in a document that is already loaded. There's no way
+ // we can get to the Model during loading.
+ Reference< XModel > xModel;
+ css::uno::Reference<css::uno::XInterface> xIfc( *this );
+ while( !xModel.is() && xIfc.is() )
+ {
+ Reference<XChild> xChild( xIfc, UNO_QUERY );
+ xIfc = xChild->getParent();
+ xModel.set(xIfc, css::uno::UNO_QUERY);
+ }
+
+ // Search for the Object shell by iterating over all Object shells
+ // and comparing their XModel to ours.
+ // As an optimization, we try the current Object shell first.
+ SfxObjectShell *pObjSh = nullptr;
+
+ if( xModel.is() )
+ {
+ SfxObjectShell *pTestObjSh = SfxObjectShell::Current();
+ if( pTestObjSh )
+ {
+ Reference< XModel > xTestModel = pTestObjSh->GetModel();
+ if( xTestModel == xModel )
+ pObjSh = pTestObjSh;
+ }
+ if( !pObjSh )
+ {
+ pTestObjSh = SfxObjectShell::GetFirst();
+ while( !pObjSh && pTestObjSh )
+ {
+ Reference< XModel > xTestModel = pTestObjSh->GetModel();
+ if( xTestModel == xModel )
+ pObjSh = pTestObjSh;
+ else
+ pTestObjSh = SfxObjectShell::GetNext( *pTestObjSh );
+ }
+ }
+ }
+
+ return pObjSh;
+ }
+
+ void OClickableImageBaseModel::SetURL( const OUString& rURL )
+ {
+ if (m_pMedium || rURL.isEmpty())
+ {
+ // Free the stream at the Producer, before the medium is deleted
+ GetImageProducer()->SetImage(OUString());
+ m_pMedium.reset();
+ }
+
+ // the SfxMedium is not allowed to be created with an invalid URL, so we have to check this first
+ INetURLObject aUrl(rURL);
+ if (INetProtocol::NotValid == aUrl.GetProtocol())
+ // we treat an invalid URL like we would treat no URL
+ return;
+
+ if (!rURL.isEmpty() && !::svt::GraphicAccess::isSupportedURL( rURL ) )
+ {
+ m_pMedium.reset(new SfxMedium(rURL, StreamMode::STD_READ));
+
+ SfxObjectShell *pObjSh = GetObjectShell();
+
+ if( pObjSh )
+ {
+ // Transfer target frame, so that javascript: URLs
+ // can also be "loaded"
+ const SfxMedium *pShMedium = pObjSh->GetMedium();
+ if( pShMedium )
+ m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame());
+ }
+
+ m_bProdStarted = false;
+
+ // Kick off download (caution: can be synchronous).
+ m_pMedium->Download(LINK(this, OClickableImageBaseModel, DownloadDoneLink));
+ }
+ else
+ {
+ if ( ::svt::GraphicAccess::isSupportedURL( rURL ) )
+ GetImageProducer()->SetImage( rURL );
+ GetImageProducer()->startProduction();
+ }
+ }
+
+
+ void OClickableImageBaseModel::DataAvailable()
+ {
+ if (!m_bProdStarted)
+ StartProduction();
+
+ GetImageProducer()->NewDataAvailable();
+ }
+
+
+ IMPL_LINK_NOARG( OClickableImageBaseModel, DownloadDoneLink, void*, void )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ DataAvailable();
+ }
+
+
+ void OClickableImageBaseModel::_propertyChanged( const PropertyChangeEvent& rEvt )
+ {
+ // If a URL was set, it needs to be passed onto the ImageProducer.
+ ::osl::MutexGuard aGuard(m_aMutex);
+ SetURL( getString(rEvt.NewValue) );
+ }
+
+
+ Any OClickableImageBaseModel::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_BUTTONTYPE : return makeAny( FormButtonType_PUSH );
+ case PROPERTY_ID_TARGET_URL :
+ case PROPERTY_ID_TARGET_FRAME : return makeAny( OUString() );
+ case PROPERTY_ID_DISPATCHURLINTERNAL : return makeAny( false );
+ default:
+ return OControlModel::getPropertyDefaultByHandle(nHandle);
+ }
+ }
+
+ IMPL_LINK( OClickableImageBaseModel, OnImageImportDone, Graphic*, i_pGraphic, void )
+ {
+ const Reference< XGraphic > xGraphic( i_pGraphic != nullptr ? Graphic(i_pGraphic->GetBitmapEx()).GetXGraphic() : nullptr );
+ if ( !xGraphic.is() )
+ {
+ m_xGraphicObject.clear();
+ }
+ else
+ {
+ m_xGraphicObject = css::graphic::GraphicObject::create( m_xContext );
+ m_xGraphicObject->setGraphic( xGraphic );
+ }
+ }
+
+
+ // OImageProducerThread_Impl
+
+ void OImageProducerThread_Impl::processEvent( ::cppu::OComponentHelper *pCompImpl,
+ const EventObject* pEvt,
+ const Reference<XControl>&,
+ bool )
+ {
+ static_cast<OClickableImageBaseControl *>(pCompImpl)->actionPerformed_Impl( true, *static_cast<const MouseEvent *>(pEvt) );
+ }
+
+
+} // namespace frm
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */