diff options
Diffstat (limited to 'forms/source/component/clickableimage.cxx')
-rw-r--r-- | forms/source/component/clickableimage.cxx | 929 |
1 files changed, 929 insertions, 0 deletions
diff --git a/forms/source/component/clickableimage.cxx b/forms/source/component/clickableimage.cxx new file mode 100644 index 000000000000..8deb10c2f170 --- /dev/null +++ b/forms/source/component/clickableimage.cxx @@ -0,0 +1,929 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_forms.hxx" +#include "clickableimage.hxx" +#include "controlfeatureinterception.hxx" +#include "urltransformer.hxx" +#include "componenttools.hxx" +#include <com/sun/star/form/XSubmit.hpp> +#include <com/sun/star/awt/SystemPointer.hpp> +#include <com/sun/star/form/FormComponentType.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 <tools/urlobj.hxx> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/objsh.hxx> +#include <vos/mutex.hxx> +#include "services.hxx" +#include <comphelper/container.hxx> +#include <comphelper/listenernotification.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::sdbcx; + 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 ::com::sun::star::awt::MouseEvent; + using ::com::sun::star::task::XInteractionHandler; + + //================================================================== + // OClickableImageBaseControl + //================================================================== + //------------------------------------------------------------------------------ + Sequence<Type> OClickableImageBaseControl::_getTypes() + { + static Sequence<Type> aTypes; + if (!aTypes.getLength()) + aTypes = concatSequences(OControl::_getTypes(), OClickableImageBaseControl_BASE::getTypes()); + return aTypes; + } + + //------------------------------------------------------------------------------ + OClickableImageBaseControl::OClickableImageBaseControl(const Reference<XMultiServiceFactory>& _rxFactory, const ::rtl::OUString& _aService) + :OControl(_rxFactory, _aService) + ,m_pThread(NULL) + ,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 Anbindung + //------------------------------------------------------------------------------ + Any SAL_CALL OClickableImageBaseControl::queryAggregation(const Type& _rType) throw (RuntimeException) + { + Any aReturn = OControl::queryAggregation(_rType); + if (!aReturn.hasValue()) + aReturn = OClickableImageBaseControl_BASE::queryInterface(_rType); + return aReturn; + } + + // XApproveActionBroadcaster + //------------------------------------------------------------------------------ + void OClickableImageBaseControl::addApproveActionListener( + const Reference<XApproveActionListener>& l) throw( RuntimeException ) + { + m_aApproveActionListeners.addInterface(l); + } + + //------------------------------------------------------------------------------ + void OClickableImageBaseControl::removeApproveActionListener( + const Reference<XApproveActionListener>& l) throw( RuntimeException ) + { + m_aApproveActionListeners.removeInterface(l); + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException) + { + m_pFeatureInterception->registerDispatchProviderInterceptor( _rxInterceptor ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException) + { + 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 ); + if( m_pThread ) + { + m_pThread->release(); + m_pThread = NULL; + } + } + + OControl::disposing(); + } + + //------------------------------------------------------------------------------ + OImageProducerThread_Impl* OClickableImageBaseControl::getImageProducerThread() + { + if ( !m_pThread ) + { + m_pThread = new OImageProducerThread_Impl( this ); + m_pThread->acquire(); + m_pThread->create(); + } + return m_pThread; + } + + //------------------------------------------------------------------------------ + bool OClickableImageBaseControl::approveAction( ) + { + sal_Bool bCancelled = sal_False; + EventObject aEvent( static_cast< XWeak* >( this ) ); + + ::cppu::OInterfaceIteratorHelper aIter( m_aApproveActionListeners ); + while( !bCancelled && aIter.hasMoreElements() ) + { + // Jede approveAction-Methode muss thread-safe sein!!! + if( !static_cast< XApproveActionListener* >( aIter.next() )->approveAction( aEvent ) ) + bCancelled = sal_True; + } + + return !bCancelled; + } + + //------------------------------------------------------------------------------ + // Diese Methode wird auch aus einem Thread gerufen und muss deshalb + // thread-safe sein. + void OClickableImageBaseControl::actionPerformed_Impl(sal_Bool bNotifyListener, const MouseEvent& rEvt) + { + if( bNotifyListener ) + { + if ( !approveAction() ) + return; + } + + // Ob der Rest des Codes Thread-Safe ist weiss man nicht genau. Deshalb + // wird das meiste bei gelocktem Solar-Mutex erledigen. + Reference<XPropertySet> xSet; + Reference< XInterface > xModelsParent; + FormButtonType eButtonType = FormButtonType_PUSH; + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // Parent holen + Reference<XFormComponent> xComp(getModel(), UNO_QUERY); + if (!xComp.is()) + return; + + xModelsParent = xComp->getParent(); + if (!xModelsParent.is()) + return; + + // which button type? + xSet = xSet.query( xComp ); + if ( !xSet.is() ) + return; + xSet->getPropertyValue(PROPERTY_BUTTONTYPE) >>= eButtonType; + } + + switch (eButtonType) + { + case FormButtonType_RESET: + { + // reset-Methoden muessen thread-safe sein! + 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: + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + Reference< XModel > xModel = getXModel(xModelsParent); + if (!xModel.is()) + return; + + /////////////////////////////////////////////////////////////////////// + // Jetzt URL ausfuehren + 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.getLength() && (LOCAL_URL_PREFIX == aURL.Complete.getStr()[0])) + { // 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 + // solutiuon 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 !!! + // 89752 - 23.07.2001 - frank.schoenheit@sun.com + aURL.Mark = aURL.Complete; + aURL.Complete = xModel->getURL(); + aURL.Complete += aURL.Mark; + } + + sal_Bool bDispatchUrlInternal = sal_False; + xSet->getPropertyValue(PROPERTY_DISPATCHURLINTERNAL) >>= bDispatchUrlInternal; + if ( bDispatchUrlInternal ) + { + m_pFeatureInterception->getTransformer().parseSmartWithAsciiProtocol( aURL, INET_FILE_SCHEME ); + + ::rtl::OUString aTargetFrame; + xSet->getPropertyValue(PROPERTY_TARGET_FRAME) >>= aTargetFrame; + + Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch( aURL, aTargetFrame, + FrameSearchFlag::SELF | FrameSearchFlag::PARENT | + FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE ); + + Sequence<PropertyValue> aArgs(1); + PropertyValue& rProp = aArgs.getArray()[0]; + rProp.Name = ::rtl::OUString::createFromAscii("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)->queryDispatch(aHyperLink, ::rtl::OUString() , 0); + + if ( xDisp.is() ) + { + Sequence<PropertyValue> aProps(3); + aProps[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL")); + aProps[0].Value <<= aURL.Complete; + + aProps[1].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FrameName")); + aProps[1].Value = xSet->getPropertyValue(PROPERTY_TARGET_FRAME); + + aProps[2].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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 ) throw (NoSupportException, RuntimeException) + { + m_aSubmissionVetoListeners.addInterface( listener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseControl::removeSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener ) throw (NoSupportException, RuntimeException) + { + m_aSubmissionVetoListeners.removeInterface( listener ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseControl::submitWithInteraction( const Reference< XInteractionHandler >& _rxHandler ) throw (VetoException, WrappedTargetException, RuntimeException) + { + implSubmit( MouseEvent(), _rxHandler ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseControl::submit( ) throw (VetoException, WrappedTargetException, RuntimeException) + { + implSubmit( MouseEvent(), NULL ); + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL OClickableImageBaseControl::getSupportedServiceNames( ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aSupported = OControl::getSupportedServiceNames(); + aSupported.realloc( aSupported.getLength() + 1 ); + + ::rtl::OUString* pArray = aSupported.getArray(); + pArray[ aSupported.getLength() - 1 ] = FRM_SUN_CONTROL_SUBMITBUTTON; + + return aSupported; + } + + //-------------------------------------------------------------------- + void OClickableImageBaseControl::implSubmit( const MouseEvent& _rEvent, const Reference< XInteractionHandler >& _rxHandler ) SAL_THROW((VetoException, WrappedTargetException, RuntimeException)) + { + 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 = xParentSubmission.query( xChild->getParent() ); + if ( xParentSubmission.is() ) + xParentSubmission->submit( this, _rEvent ); + } + } + catch( const VetoException& ) + { + // allowed to leave + throw; + } + catch( const RuntimeException& ) + { + // allowed to leave + throw; + } + catch( const WrappedTargetException& e ) + { + // allowed to leave + throw; + } + catch( const Exception& e ) + { + OSL_ENSURE( sal_False, "OClickableImageBaseControl::implSubmit: caught an unknown exception!" ); + throw WrappedTargetException( ::rtl::OUString(), *this, makeAny( e ) ); + } + } + + //================================================================== + // OClickableImageBaseModel + //================================================================== + //------------------------------------------------------------------------------ + Sequence<Type> OClickableImageBaseModel::_getTypes() + { + return concatSequences( + OControlModel::_getTypes(), + OClickableImageBaseModel_Base::getTypes() + ); + } + + //------------------------------------------------------------------ + DBG_NAME( OClickableImageBaseModel ) + //------------------------------------------------------------------ + OClickableImageBaseModel::OClickableImageBaseModel( const Reference< XMultiServiceFactory >& _rxFactory, const ::rtl::OUString& _rUnoControlModelTypeName, + const ::rtl::OUString& rDefault ) + :OControlModel( _rxFactory, _rUnoControlModelTypeName, rDefault ) + ,OPropertyChangeListener(m_aMutex) + ,m_pMedium(NULL) + ,m_pProducer( NULL ) + ,m_bDispatchUrlInternal(sal_False) + ,m_bDownloading(sal_False) + ,m_bProdStarted(sal_False) + { + DBG_CTOR( OClickableImageBaseModel, NULL ); + implConstruct(); + m_eButtonType = FormButtonType_PUSH; + } + + //------------------------------------------------------------------ + OClickableImageBaseModel::OClickableImageBaseModel( const OClickableImageBaseModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory ) + :OControlModel( _pOriginal, _rxFactory ) + ,OPropertyChangeListener( m_aMutex ) + ,m_pMedium( NULL ) + ,m_pProducer( NULL ) + ,m_bDispatchUrlInternal(sal_False) + ,m_bDownloading( sal_False ) + ,m_bProdStarted( sal_False ) + { + DBG_CTOR( OClickableImageBaseModel, NULL ); + 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_incrementInterlockedCount( &m_refCount ); + { + // simulate a propertyChanged event for the ImageURL + // 2003-05-15 - #109591# - fs@openoffice.org + Any aImageURL; + getFastPropertyValue( aImageURL, PROPERTY_ID_IMAGE_URL ); + _propertyChanged( PropertyChangeEvent( *this, PROPERTY_IMAGE_URL, sal_False, PROPERTY_ID_IMAGE_URL, Any( ), aImageURL ) ); + } + osl_decrementInterlockedCount( &m_refCount ); + } + + //------------------------------------------------------------------------------ + void OClickableImageBaseModel::implConstruct() + { + m_pProducer = new ImageProducer; + increment( m_refCount ); + { + m_xProducer = m_pProducer; + + if ( m_xAggregateSet.is() ) + { + OPropertyChangeMultiplexer* pMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet ); + pMultiplexer->addProperty( PROPERTY_IMAGE_URL ); + } + } + decrement(m_refCount); + } + + //------------------------------------------------------------------------------ + OClickableImageBaseModel::~OClickableImageBaseModel() + { + if (!OComponentHelper::rBHelper.bDisposed) + { + acquire(); + dispose(); + } + DBG_ASSERT(m_pMedium == NULL, "OClickableImageBaseModel::~OClickableImageBaseModel : leaving a memory leak ..."); + // spaetestens im dispose sollte das aufgeraeumt worden sein + + DBG_DTOR( OClickableImageBaseModel, NULL ); + } + + // XImageProducer + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) + { + ImageModelMethodGuard aGuard( *this ); + GetImageProducer()->addConsumer( _rxConsumer ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) + { + ImageModelMethodGuard aGuard( *this ); + GetImageProducer()->removeConsumer( _rxConsumer ); + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseModel::startProduction( ) throw (RuntimeException) + { + ImageModelMethodGuard aGuard( *this ); + GetImageProducer()->startProduction(); + } + + //-------------------------------------------------------------------- + Reference< submission::XSubmission > SAL_CALL OClickableImageBaseModel::getSubmission() throw (RuntimeException) + { + return m_xSubmissionDelegate; + } + + //-------------------------------------------------------------------- + void SAL_CALL OClickableImageBaseModel::setSubmission( const Reference< submission::XSubmission >& _submission ) throw (RuntimeException) + { + m_xSubmissionDelegate = _submission; + } + + //-------------------------------------------------------------------- + Sequence< ::rtl::OUString > SAL_CALL OClickableImageBaseModel::getSupportedServiceNames( ) throw (RuntimeException) + { + Sequence< ::rtl::OUString > aSupported = OControlModel::getSupportedServiceNames(); + aSupported.realloc( aSupported.getLength() + 1 ); + + ::rtl::OUString* pArray = aSupported.getArray(); + pArray[ aSupported.getLength() - 1 ] = FRM_SUN_COMPONENT_SUBMITBUTTON; + + return aSupported; + } + + // OComponentHelper + //------------------------------------------------------------------------------ + void OClickableImageBaseModel::disposing() + { + OControlModel::disposing(); + if (m_pMedium) + { + delete m_pMedium; + m_pMedium = NULL; + } + + m_xProducer = NULL; + m_pProducer = NULL; + } + + //------------------------------------------------------------------------------ + Any SAL_CALL OClickableImageBaseModel::queryAggregation(const Type& _rType) throw (RuntimeException) + { + // order matters: + // we definately want to "overload" 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( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) ) + || !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) throw ( Exception) + { + switch (nHandle) + { + case PROPERTY_ID_BUTTONTYPE : + DBG_ASSERT(isA(rValue, static_cast<FormButtonType*>(NULL)), "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) + throw( IllegalArgumentException ) + { + 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 + rtl::OUString sURL; + getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ImageURL") ) ) >>= sURL; + if (!m_pMedium) + { + if ( ::svt::GraphicAccess::isSupportedURL( sURL ) ) + pImgProd->SetImage( sURL ); + else + // caution: the medium may be NULL if somebody gave us a invalid URL to work with + // 11/24/2000 - 79667 - FS + pImgProd->SetImage(String()); + m_bDownloading = sal_False; + return; + } + if (m_pMedium->GetErrorCode()==0) + { + SvStream* pStream = m_pMedium->GetInStream(); + + pImgProd->SetImage(*pStream); + pImgProd->startProduction(); + m_bProdStarted = sal_True; + } + else + { + pImgProd->SetImage(String()); + delete m_pMedium; + m_pMedium = 0; + m_bDownloading = sal_False; + } + } + + //------------------------------------------------------------------------------ + void OClickableImageBaseModel::SetURL( const ::rtl::OUString& rURL ) + { + if (m_pMedium || !rURL.getLength()) + { + // Den Stream am Producer freigeben, bevor das Medium geloscht wird. + GetImageProducer()->SetImage(String()); + delete m_pMedium; + m_pMedium = NULL; + } + + // the SfxMedium is not allowed to be created with an invalid URL, so we have to check this first + // 23.01.2001 - 81927 - FS + INetURLObject aUrl(rURL); + if (INET_PROT_NOT_VALID == aUrl.GetProtocol()) + // we treat an invalid URL like we would treat no URL + return; + + if (rURL.getLength() && !::svt::GraphicAccess::isSupportedURL( rURL ) ) + { + if (m_pMedium) + delete m_pMedium; + + m_pMedium = new SfxMedium(rURL, STREAM_STD_READ, sal_False); + m_pMedium->SetDataAvailableLink( + STATIC_LINK(this, OClickableImageBaseModel, DataAvailableLink)); + + // Das XModel suchen, um an die Object-Shell oder zumindest den + // Referer zu gelangen. + // Das Model findet man allerdings nur beim Laden von HTML-Dokumenten + // und dann, wenn die URL in einem bereits geladenen Dokument + // geaendert wird. Waehrend des Ladens kommt man nicht an das + // Model ran. + Reference< XModel > xModel; + InterfaceRef xIfc( *this ); + while( !xModel.is() && xIfc.is() ) + { + Reference<XChild> xChild( xIfc, UNO_QUERY ); + xIfc = xChild->getParent(); + query_interface(xIfc, xModel); + } + + // Die Object-Shell suchen, indem wir + // ueber alle Object-Shells iterieren und deren XModel mit dem + // eigenen vergleichen. Als Optimierung probieren wir aber erstmal + // die aktuelle Object-Shell. + // wir unser XModel mit dem aller Object + SfxObjectShell *pObjSh = 0; + + 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 ); + } + } + } + + #ifdef USE_REGISTER_TRANSFER + if( pObjSh ) + { + // Medium registrieren, damit abgebrochen werden kann + pObjSh->RegisterTransfer( *m_pMedium ); + + // Target-Frame uebertragen, damit auch javascript:-URLs + // "geladen" werden koennen. + const SfxMedium *pShMedium = pObjSh->GetMedium(); + if( pShMedium ) + m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame()); + } + else + { + // Keine Object-Shell, aber ein Medium? Dann uebernehmen wir + // zumindest den Referer. + if( xModel.is() ) + { + ::rtl::OUString sReferer( xModel->getURL() ); + if( sReferer.getLength() ) + m_pMedium->SetReferer( OUStringToString(sReferer, CHARSET_SYSTEM) ); + } + } + #else + if( pObjSh ) + { + // Target-Frame uebertragen, damit auch javascript:-URLs + // "geladen" werden koennen. + const SfxMedium *pShMedium = pObjSh->GetMedium(); + if( pShMedium ) + m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame()); + } + + if( xModel.is() ) + { + ::rtl::OUString sReferer( xModel->getURL() ); + if( sReferer.getLength() ) + m_pMedium->SetReferer( sReferer ); + } + #endif + + // Downloading-Flag auf sal_True setzen. Es werden dann auch + // Data-Available-Links, wenn wir in den Pending-Staus gelangen. + m_bDownloading = sal_True; + m_bProdStarted = sal_False; + + // Download anstossen (Achtung: Kann auch synchron sein). + m_pMedium->DownLoad(STATIC_LINK(this, OClickableImageBaseModel, DownloadDoneLink)); + } + else + { + if ( ::svt::GraphicAccess::isSupportedURL( rURL ) ) + GetImageProducer()->SetImage( rURL ); + GetImageProducer()->startProduction(); + } + } + + //------------------------------------------------------------------------------ + void OClickableImageBaseModel::DataAvailable() + { + if (!m_bProdStarted) + StartProduction(); + + GetImageProducer()->NewDataAvailable(); + } + + //------------------------------------------------------------------------------ + void OClickableImageBaseModel::DownloadDone() + { + DataAvailable(); + m_bDownloading = sal_False; + } + + //------------------------------------------------------------------------------ + IMPL_STATIC_LINK( OClickableImageBaseModel, DownloadDoneLink, void*, EMPTYARG ) + { + ::osl::MutexGuard aGuard( pThis->m_aMutex ); + pThis->DownloadDone(); + return 0; + } + + //------------------------------------------------------------------------------ + IMPL_STATIC_LINK( OClickableImageBaseModel, DataAvailableLink, void*, EMPTYARG ) + { + ::osl::MutexGuard aGuard( pThis->m_aMutex ); + pThis->DataAvailable(); + return 0; + } + + //------------------------------------------------------------------------------ + void OClickableImageBaseModel::_propertyChanged( const PropertyChangeEvent& rEvt ) + throw( RuntimeException ) + { + // Wenn eine URL gesetzt worden ist, muss die noch an den ImageProducer + // weitergereicht werden. + ::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( ::rtl::OUString() ); + case PROPERTY_ID_DISPATCHURLINTERNAL : return makeAny( sal_False ); + default: + return OControlModel::getPropertyDefaultByHandle(nHandle); + } + } + + //================================================================== + // OImageProducerThread_Impl + //================================================================== + //------------------------------------------------------------------ + EventObject* OImageProducerThread_Impl::cloneEvent( const EventObject* _pEvt ) const + { + return new EventObject( *_pEvt ); + } + + //------------------------------------------------------------------ + void OImageProducerThread_Impl::processEvent( ::cppu::OComponentHelper *pCompImpl, + const EventObject* pEvt, + const Reference<XControl>&, + sal_Bool ) + { + ((OClickableImageBaseControl *)pCompImpl)->actionPerformed_Impl( sal_True, *(MouseEvent *)pEvt ); + } + +//......................................................................... +} // namespace frm +//......................................................................... + |