diff options
Diffstat (limited to 'forms/source/component/ImageControl.cxx')
-rw-r--r-- | forms/source/component/ImageControl.cxx | 1023 |
1 files changed, 1023 insertions, 0 deletions
diff --git a/forms/source/component/ImageControl.cxx b/forms/source/component/ImageControl.cxx new file mode 100644 index 000000000000..a2ad111a79b7 --- /dev/null +++ b/forms/source/component/ImageControl.cxx @@ -0,0 +1,1023 @@ +/************************************************************************* + * + * 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 "ImageControl.hxx" + +#include "property.hrc" +#include "frm_resource.hrc" +#include "frm_resource.hxx" +#include "services.hxx" +#include "componenttools.hxx" + +#include <svtools/imageresourceaccess.hxx> +#include <unotools/ucblockbytes.hxx> +#include <sfx2/filedlghelper.hxx> +#include <com/sun/star/awt/XPopupMenu.hpp> +#include <com/sun/star/awt/PopupMenuDirection.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/awt/XDialog.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/NotConnectedException.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/graphic/GraphicObject.hpp> +#include <tools/urlobj.hxx> +#include <tools/stream.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <vcl/svapp.hxx> +#include <unotools/streamhelper.hxx> +#include <comphelper/extract.hxx> +#include <comphelper/guarding.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <svl/urihelper.hxx> + +#include <memory> + +#define ID_OPEN_GRAPHICS 1 +#define ID_CLEAR_GRAPHICS 2 + +//......................................................................... +namespace frm +{ +//......................................................................... +using namespace ::com::sun::star; +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::ui::dialogs; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::graphic; +using namespace ::com::sun::star::frame; + +//============================================================================== +//= OImageControlModel +//============================================================================== +namespace +{ + enum ImageStoreType + { + ImageStoreBinary, + ImageStoreLink, + + ImageStoreInvalid + }; + + ImageStoreType lcl_getImageStoreType( const sal_Int32 _nFieldType ) + { + // binary/longvarchar types could be used to store images in binary representation + if ( ( _nFieldType == DataType::BINARY ) + || ( _nFieldType == DataType::VARBINARY ) + || ( _nFieldType == DataType::LONGVARBINARY ) + || ( _nFieldType == DataType::OTHER ) + || ( _nFieldType == DataType::OBJECT ) + || ( _nFieldType == DataType::BLOB ) + || ( _nFieldType == DataType::LONGVARCHAR ) + || ( _nFieldType == DataType::CLOB ) + ) + return ImageStoreBinary; + + // char types could be used to store links to images + if ( ( _nFieldType == DataType::CHAR ) + || ( _nFieldType == DataType::VARCHAR ) + ) + return ImageStoreLink; + + return ImageStoreInvalid; + } +} + +//============================================================================== +// OImageControlModel +//============================================================================== + +//------------------------------------------------------------------------------ +InterfaceRef SAL_CALL OImageControlModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) +{ + return *(new OImageControlModel(_rxFactory)); +} + +//------------------------------------------------------------------------------ +Sequence<Type> OImageControlModel::_getTypes() +{ + return concatSequences( + OBoundControlModel::_getTypes(), + OImageControlModel_Base::getTypes() + ); +} + +DBG_NAME(OImageControlModel) +//------------------------------------------------------------------ +OImageControlModel::OImageControlModel(const Reference<XMultiServiceFactory>& _rxFactory) + :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_IMAGECONTROL, FRM_SUN_CONTROL_IMAGECONTROL, sal_False, sal_False, sal_False ) + // use the old control name for compytibility reasons + ,m_pImageProducer( NULL ) + ,m_bExternalGraphic( true ) + ,m_bReadOnly( sal_False ) + ,m_sImageURL() + ,m_xGraphicObject() +{ + DBG_CTOR( OImageControlModel, NULL ); + m_nClassId = FormComponentType::IMAGECONTROL; + initOwnValueProperty( PROPERTY_IMAGE_URL ); + + implConstruct(); +} + +//------------------------------------------------------------------ +OImageControlModel::OImageControlModel( const OImageControlModel* _pOriginal, const Reference< XMultiServiceFactory >& _rxFactory ) + :OBoundControlModel( _pOriginal, _rxFactory ) + // use the old control name for compytibility reasons + ,m_pImageProducer( NULL ) + ,m_bExternalGraphic( true ) + ,m_bReadOnly( _pOriginal->m_bReadOnly ) + ,m_sImageURL( _pOriginal->m_sImageURL ) + ,m_xGraphicObject( _pOriginal->m_xGraphicObject ) +{ + DBG_CTOR( OImageControlModel, NULL ); + implConstruct(); + + osl_incrementInterlockedCount( &m_refCount ); + { + // simulate a propertyChanged event for the ImageURL + // 2003-05-15 - #109591# - fs@openoffice.org + ::osl::MutexGuard aGuard( m_aMutex ); + impl_handleNewImageURL_lck( eOther ); + } + osl_decrementInterlockedCount( &m_refCount ); +} + +//------------------------------------------------------------------ +void OImageControlModel::implConstruct() +{ + m_pImageProducer = new ImageProducer; + m_xImageProducer = m_pImageProducer; + m_pImageProducer->SetDoneHdl( LINK( this, OImageControlModel, OnImageImportDone ) ); +} + +//------------------------------------------------------------------ +OImageControlModel::~OImageControlModel() +{ + if (!OComponentHelper::rBHelper.bDisposed) + { + acquire(); + dispose(); + } + + DBG_DTOR(OImageControlModel,NULL); +} + +// XCloneable +//------------------------------------------------------------------------------ +IMPLEMENT_DEFAULT_CLONING( OImageControlModel ) + +// XServiceInfo +//------------------------------------------------------------------------------ +StringSequence OImageControlModel::getSupportedServiceNames() throw() +{ + StringSequence aSupported = OBoundControlModel::getSupportedServiceNames(); + aSupported.realloc(aSupported.getLength() + 1); + + ::rtl::OUString*pArray = aSupported.getArray(); + pArray[aSupported.getLength()-1] = FRM_SUN_COMPONENT_IMAGECONTROL; + return aSupported; +} + +//------------------------------------------------------------------------------ +Any SAL_CALL OImageControlModel::queryAggregation(const Type& _rType) throw (RuntimeException) +{ + // oder matters: we want to "override" the XImageProducer interface of the aggreate with out + // own XImageProducer interface, thus we need to query OImageControlModel_Base first + Any aReturn = OImageControlModel_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 = OBoundControlModel::queryAggregation( _rType ); + + return aReturn; +} + +//------------------------------------------------------------------------------ +sal_Bool OImageControlModel::approveDbColumnType( sal_Int32 _nColumnType ) +{ + return ImageStoreInvalid != lcl_getImageStoreType( _nColumnType ); +} + +//------------------------------------------------------------------------------ +void OImageControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const +{ + switch (nHandle) + { + case PROPERTY_ID_READONLY: + rValue <<= (sal_Bool)m_bReadOnly; + break; + case PROPERTY_ID_IMAGE_URL: + rValue <<= m_sImageURL; + break; + case PROPERTY_ID_GRAPHIC: + rValue <<= m_xGraphicObject.is() ? m_xGraphicObject->getGraphic() : Reference< XGraphic >(); + break; + default: + OBoundControlModel::getFastPropertyValue(rValue, nHandle); + } +} + +//------------------------------------------------------------------------------ +void OImageControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) throw ( ::com::sun::star::uno::Exception) +{ + switch (nHandle) + { + case PROPERTY_ID_READONLY : + DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "OImageControlModel::setFastPropertyValue_NoBroadcast : invalid type !" ); + m_bReadOnly = getBOOL(rValue); + break; + + case PROPERTY_ID_IMAGE_URL: + OSL_VERIFY( rValue >>= m_sImageURL ); + impl_handleNewImageURL_lck( eOther ); + { + ControlModelLock aLock( *this ); + // that's a fake ... onValuePropertyChange expects to receive the only lock to our instance, + // but we're already called with our mutex locked ... + onValuePropertyChange( aLock ); + } + break; + + case PROPERTY_ID_GRAPHIC: + { + Reference< XGraphic > xGraphic; + OSL_VERIFY( rValue >>= xGraphic ); + if ( !xGraphic.is() ) + m_xGraphicObject.clear(); + else + { + m_xGraphicObject = GraphicObject::create( m_aContext.getUNOContext() ); + m_xGraphicObject->setGraphic( xGraphic ); + } + + if ( m_bExternalGraphic ) + { + // if that's an external graphic, i.e. one which has not been loaded by ourselves in response to a + // new image URL, then also adjust our ImageURL. + ::rtl::OUString sNewImageURL; + if ( m_xGraphicObject.is() ) + { + sNewImageURL = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.GraphicObject:" ) ); + sNewImageURL = sNewImageURL + m_xGraphicObject->getUniqueID(); + } + m_sImageURL = sNewImageURL; + // TODO: speaking strictly, this would need to be notified, since ImageURL is a bound property. However, + // this method here is called with a locked mutex, so we cannot simply call listeners ... + // I think the missing notification (and thus clients which potentially cannot observe the change) + // is less severe than the potential deadlock ... + } + } + break; + + default: + OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue); + break; + } +} + +//------------------------------------------------------------------------------ +sal_Bool OImageControlModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue) + throw( IllegalArgumentException ) +{ + switch (nHandle) + { + case PROPERTY_ID_READONLY : + return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bReadOnly); + + case PROPERTY_ID_IMAGE_URL: + return tryPropertyValue( rConvertedValue, rOldValue, rValue, m_sImageURL ); + + case PROPERTY_ID_GRAPHIC: + { + const Reference< XGraphic > xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC ), UNO_QUERY ); + return tryPropertyValue( rConvertedValue, rOldValue, rValue, xGraphic ); + } + + default: + return OBoundControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue); + } +} + +//------------------------------------------------------------------------------ +void OImageControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const +{ + BEGIN_DESCRIBE_PROPERTIES( 4, OBoundControlModel ) + DECL_IFACE_PROP2( GRAPHIC, XGraphic, BOUND, TRANSIENT ); + DECL_PROP1 ( IMAGE_URL, ::rtl::OUString, BOUND ); + DECL_BOOL_PROP1 ( READONLY, BOUND ); + DECL_PROP1 ( TABINDEX, sal_Int16, BOUND ); + END_DESCRIBE_PROPERTIES(); +} + +//------------------------------------------------------------------------------ +void OImageControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ o_rAggregateProperties ) const +{ + OBoundControlModel::describeAggregateProperties( o_rAggregateProperties ); + // remove ImageULR and Graphic properties, we "overload" them. This is because our aggregate synchronizes those + // two, but we have an own sychronization mechanism. + RemoveProperty( o_rAggregateProperties, PROPERTY_IMAGE_URL ); + RemoveProperty( o_rAggregateProperties, PROPERTY_GRAPHIC ); +} + +//------------------------------------------------------------------------------ +::rtl::OUString OImageControlModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException) +{ + return FRM_COMPONENT_IMAGECONTROL; // old (non-sun) name for compatibility ! +} + +//------------------------------------------------------------------------------ +void OImageControlModel::write(const Reference<XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + // Basisklasse + OBoundControlModel::write(_rxOutStream); + // Version + _rxOutStream->writeShort(0x0003); + // Name + _rxOutStream->writeBoolean(m_bReadOnly); + writeHelpTextCompatibly(_rxOutStream); + // from version 0x0003 : common properties + writeCommonProperties(_rxOutStream); +} + +//------------------------------------------------------------------------------ +void OImageControlModel::read(const Reference<XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) +{ + OBoundControlModel::read(_rxInStream); + + // Version + sal_uInt16 nVersion = _rxInStream->readShort(); + switch (nVersion) + { + case 0x0001: + m_bReadOnly = _rxInStream->readBoolean(); + break; + case 0x0002: + m_bReadOnly = _rxInStream->readBoolean(); + readHelpTextCompatibly(_rxInStream); + break; + case 0x0003: + m_bReadOnly = _rxInStream->readBoolean(); + readHelpTextCompatibly(_rxInStream); + readCommonProperties(_rxInStream); + break; + default : + DBG_ERROR("OImageControlModel::read : unknown version !"); + m_bReadOnly = sal_False; + defaultCommonProperties(); + break; + } + // Nach dem Lesen die Defaultwerte anzeigen + if ( getControlSource().getLength() ) + { // (not if we don't have a control source - the "State" property acts like it is persistent, then + ::osl::MutexGuard aGuard(m_aMutex); // resetNoBroadcast expects this mutex guarding + resetNoBroadcast(); + } +} + +//------------------------------------------------------------------------------ +sal_Bool OImageControlModel::impl_updateStreamForURL_lck( const ::rtl::OUString& _rURL, ValueChangeInstigator _eInstigator ) +{ + // create a stream for the image specified by the URL + ::std::auto_ptr< SvStream > pImageStream; + Reference< XInputStream > xImageStream; + + if ( ::svt::GraphicAccess::isSupportedURL( _rURL ) ) + { + xImageStream = ::svt::GraphicAccess::getImageXStream( getContext().getLegacyServiceFactory(), _rURL ); + } + else + { + pImageStream.reset( ::utl::UcbStreamHelper::CreateStream( _rURL, STREAM_READ ) ); + sal_Bool bSetNull = ( pImageStream.get() == NULL ) || ( ERRCODE_NONE != pImageStream->GetErrorCode() ); + + if ( !bSetNull ) + { + // get the size of the stream + pImageStream->Seek(STREAM_SEEK_TO_END); + sal_Int32 nSize = (sal_Int32)pImageStream->Tell(); + if (pImageStream->GetBufferSize() < 8192) + pImageStream->SetBufferSize(8192); + pImageStream->Seek(STREAM_SEEK_TO_BEGIN); + + xImageStream = new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream.get(), sal_False ), nSize ); + } + } + + if ( xImageStream.is() ) + { + if ( m_xColumnUpdate.is() ) + m_xColumnUpdate->updateBinaryStream( xImageStream, xImageStream->available() ); + else + setControlValue( makeAny( xImageStream ), _eInstigator ); + xImageStream->closeInput(); + return sal_True; + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +sal_Bool OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator ) +{ + switch ( lcl_getImageStoreType( getFieldType() ) ) + { + case ImageStoreBinary: + if ( impl_updateStreamForURL_lck( m_sImageURL, _eInstigator ) ) + return sal_True; + break; + + case ImageStoreLink: + { + ::rtl::OUString sCommitURL( m_sImageURL ); + if ( m_sDocumentURL.getLength() ) + sCommitURL = URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL, sCommitURL ); + OSL_ENSURE( m_xColumnUpdate.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" ); + if ( m_xColumnUpdate.is() ) + { + m_xColumnUpdate->updateString( sCommitURL ); + return sal_True; + } + } + break; + + case ImageStoreInvalid: + OSL_ENSURE( false, "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" ); + break; + } + + // if we're here, then the above code was unable to update our field/control from the given URL + // => fall back to NULL/VOID + if ( m_xColumnUpdate.is() ) + m_xColumnUpdate->updateNull(); + else + setControlValue( Any(), _eInstigator ); + + return sal_True; +} + +//------------------------------------------------------------------------------ +sal_Bool OImageControlModel::commitControlValueToDbColumn( bool _bPostReset ) +{ + if ( _bPostReset ) + { + // since this is a "commit after reset", we can simply update the column + // with null - this is our "default" which we were just reset to + if ( m_xColumnUpdate.is() ) + m_xColumnUpdate->updateNull(); + } + else + { + ::osl::MutexGuard aGuard(m_aMutex); + return impl_handleNewImageURL_lck( eDbColumnBinding ); + } + + return sal_True; +} + +//------------------------------------------------------------------------------ +namespace +{ + bool lcl_isValidDocumentURL( const ::rtl::OUString& _rDocURL ) + { + return ( _rDocURL.getLength() && !_rDocURL.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "private:object" ) ) ); + } +} + +//------------------------------------------------------------------------------ +void OImageControlModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm ) +{ + OBoundControlModel::onConnectedDbColumn( _rxForm ); + + try + { + Reference< XModel > xDocument( getXModel( *this ) ); + if ( xDocument.is() ) + { + m_sDocumentURL = xDocument->getURL(); + if ( !lcl_isValidDocumentURL( m_sDocumentURL ) ) + { + Reference< XChild > xAsChild( xDocument, UNO_QUERY ); + while ( xAsChild.is() && !lcl_isValidDocumentURL( m_sDocumentURL ) ) + { + xDocument.set( xAsChild->getParent(), UNO_QUERY ); + if ( xDocument.is() ) + m_sDocumentURL = xDocument->getURL(); + xAsChild.set( xDocument, UNO_QUERY ); + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +void OImageControlModel::onDisconnectedDbColumn() +{ + OBoundControlModel::onDisconnectedDbColumn(); + + m_sDocumentURL = ::rtl::OUString(); +} + +//------------------------------------------------------------------------------ +Any OImageControlModel::translateDbColumnToControlValue() +{ + switch ( lcl_getImageStoreType( getFieldType() ) ) + { + case ImageStoreBinary: + { + Reference< XInputStream > xImageStream( m_xColumn->getBinaryStream() ); + if ( m_xColumn->wasNull() ) + xImageStream.clear(); + return makeAny( xImageStream ); + } + case ImageStoreLink: + { + ::rtl::OUString sImageLink( m_xColumn->getString() ); + if ( m_sDocumentURL.getLength() ) + sImageLink = INetURLObject::GetAbsURL( m_sDocumentURL, sImageLink ); + return makeAny( sImageLink ); + } + case ImageStoreInvalid: + OSL_ENSURE( false, "OImageControlModel::translateDbColumnToControlValue: invalid field type!" ); + break; + } + return Any(); +} + +//------------------------------------------------------------------------------ +Any OImageControlModel::getControlValue( ) const +{ + return makeAny( m_sImageURL ); +} + +//------------------------------------------------------------------------------ +void OImageControlModel::doSetControlValue( const Any& _rValue ) +{ + DBG_ASSERT( GetImageProducer() && m_xImageProducer.is(), "OImageControlModel::doSetControlValue: no image producer!" ); + if ( !GetImageProducer() || !m_xImageProducer.is() ) + return; + + bool bStartProduction = false; + switch ( lcl_getImageStoreType( getFieldType() ) ) + { + case ImageStoreBinary: + { + // give the image producer the stream + Reference< XInputStream > xInStream; + _rValue >>= xInStream; + GetImageProducer()->setImage( xInStream ); + bStartProduction = true; + } + break; + + case ImageStoreLink: + { + ::rtl::OUString sImageURL; + _rValue >>= sImageURL; + GetImageProducer()->SetImage( sImageURL ); + bStartProduction = true; + } + break; + + case ImageStoreInvalid: + OSL_ENSURE( false, "OImageControlModel::doSetControlValue: invalid field type!" ); + break; + + } // switch ( lcl_getImageStoreType( getFieldType() ) ) + + if ( bStartProduction ) + { + // start production + Reference< XImageProducer > xProducer = m_xImageProducer; + { + // release our mutex once (it's acquired in the calling method!), as starting the image production may + // result in the locking of the solar mutex (unfortunally the default implementation of our aggregate, + // VCLXImageControl, does this locking) + // FS - 74438 - 30.03.00 + MutexRelease aRelease(m_aMutex); + xProducer->startProduction(); + } + } +} + +// OComponentHelper +//------------------------------------------------------------------ +void SAL_CALL OImageControlModel::disposing() +{ + OBoundControlModel::disposing(); +} + +//------------------------------------------------------------------------------ +void OImageControlModel::resetNoBroadcast() +{ + if ( hasField() ) // only reset when we are connected to a column + OBoundControlModel::resetNoBroadcast( ); +} + +//-------------------------------------------------------------------- +Reference< XImageProducer > SAL_CALL OImageControlModel::getImageProducer() throw ( RuntimeException) +{ + return this; +} + +//-------------------------------------------------------------------- +void SAL_CALL OImageControlModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) +{ + GetImageProducer()->addConsumer( _rxConsumer ); +} + +//-------------------------------------------------------------------- +void SAL_CALL OImageControlModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) +{ + GetImageProducer()->removeConsumer( _rxConsumer ); +} + +//-------------------------------------------------------------------- +void SAL_CALL OImageControlModel::startProduction( ) throw (RuntimeException) +{ + GetImageProducer()->startProduction(); +} + +//------------------------------------------------------------------------------ +IMPL_LINK( OImageControlModel, OnImageImportDone, ::Graphic*, i_pGraphic ) +{ + const Reference< XGraphic > xGraphic( i_pGraphic != NULL ? Image( i_pGraphic->GetBitmapEx() ).GetXGraphic() : NULL ); + m_bExternalGraphic = false; + try + { + setPropertyValue( PROPERTY_GRAPHIC, makeAny( xGraphic ) ); + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + m_bExternalGraphic = true; + return 1L; +} + +//================================================================== +// OImageControlControl +//================================================================== + +//------------------------------------------------------------------ +InterfaceRef SAL_CALL OImageControlControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) +{ + return *(new OImageControlControl(_rxFactory)); +} + +//------------------------------------------------------------------------------ +Sequence<Type> OImageControlControl::_getTypes() +{ + return concatSequences( + OBoundControl::_getTypes(), + OImageControlControl_Base::getTypes() + ); +} + +//------------------------------------------------------------------------------ +OImageControlControl::OImageControlControl(const Reference<XMultiServiceFactory>& _rxFactory) + :OBoundControl(_rxFactory, VCL_CONTROL_IMAGECONTROL) + ,m_aModifyListeners( m_aMutex ) +{ + increment(m_refCount); + { + // als Focus- und MouseListener anmelden + Reference< XWindow > xComp; + query_aggregation( m_xAggregate, xComp ); + if ( xComp.is() ) + xComp->addMouseListener( this ); + } + decrement(m_refCount); +} + +//------------------------------------------------------------------------------ +Any SAL_CALL OImageControlControl::queryAggregation(const Type& _rType) throw (RuntimeException) +{ + Any aReturn = OBoundControl::queryAggregation( _rType ); + if ( !aReturn.hasValue() ) + aReturn = ::cppu::queryInterface( + _rType, + static_cast< XMouseListener* >( this ), + static_cast< XModifyBroadcaster* >( this ) + ); + + return aReturn; +} + +//------------------------------------------------------------------------------ +StringSequence OImageControlControl::getSupportedServiceNames() throw() +{ + StringSequence aSupported = OBoundControl::getSupportedServiceNames(); + aSupported.realloc(aSupported.getLength() + 1); + + ::rtl::OUString*pArray = aSupported.getArray(); + pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_IMAGECONTROL; + return aSupported; +} + +//------------------------------------------------------------------------------ +void SAL_CALL OImageControlControl::addModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException) +{ + m_aModifyListeners.addInterface( _Listener ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OImageControlControl::removeModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException) +{ + m_aModifyListeners.removeInterface( _Listener ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OImageControlControl::disposing() +{ + EventObject aEvent( *this ); + m_aModifyListeners.disposeAndClear( aEvent ); + + OBoundControl::disposing(); +} + +//------------------------------------------------------------------------------ +void SAL_CALL OImageControlControl::disposing( const EventObject& _Event ) throw(RuntimeException) +{ + OBoundControl::disposing( _Event ); +} + +//------------------------------------------------------------------------------ +void OImageControlControl::implClearGraphics( sal_Bool _bForce ) +{ + Reference< XPropertySet > xSet( getModel(), UNO_QUERY ); + if ( xSet.is() ) + { + if ( _bForce ) + { + ::rtl::OUString sOldImageURL; + xSet->getPropertyValue( PROPERTY_IMAGE_URL ) >>= sOldImageURL; + + if ( !sOldImageURL.getLength() ) + // the ImageURL is already empty, so simply setting a new empty one would not suffice + // (since it would be ignored) + xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:emptyImage" ) ) ) ); + // (the concrete URL we're passing here doens't matter. It's important that + // the model cannot resolve it to a a valid resource describing an image stream + } + + xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString() ) ); + } +} + +//------------------------------------------------------------------------------ +bool OImageControlControl::implInsertGraphics() +{ + Reference< XPropertySet > xSet( getModel(), UNO_QUERY ); + if ( !xSet.is() ) + return false; + + ::rtl::OUString sTitle = FRM_RES_STRING(RID_STR_IMPORT_GRAPHIC); + // build some arguments for the upcoming dialog + try + { + ::sfx2::FileDialogHelper aDialog( TemplateDescription::FILEOPEN_LINK_PREVIEW, SFXWB_GRAPHIC ); + aDialog.SetTitle( sTitle ); + + Reference< XFilePickerControlAccess > xController( aDialog.GetFilePicker(), UNO_QUERY_THROW ); + xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, ::cppu::bool2any(sal_True)); + + Reference<XPropertySet> xBoundField; + if ( hasProperty( PROPERTY_BOUNDFIELD, xSet ) ) + xSet->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xBoundField; + sal_Bool bHasField = xBoundField.is(); + + // if the control is bound to a DB field, then it's not possible to decide whether or not to link + xController->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK, !bHasField ); + + // if the control is bound to a DB field, then linking of the image depends on the type of the field + sal_Bool bImageIsLinked = sal_True; + if ( bHasField ) + { + sal_Int32 nFieldType = DataType::OTHER; + OSL_VERIFY( xBoundField->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType ); + bImageIsLinked = ( lcl_getImageStoreType( nFieldType ) == ImageStoreLink ); + } + xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, makeAny( bImageIsLinked ) ); + + if ( ERRCODE_NONE == aDialog.Execute() ) + { + // reset the url property in case it already has the value we're about to set - in this case + // our propertyChanged would not get called without this. + implClearGraphics( sal_False ); + sal_Bool bIsLink = sal_False; + xController->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0) >>= bIsLink; + // Force bIsLink to be sal_True if we're bound to a field. Though we initialized the file picker with IsLink=TRUE + // in this case, and disabled the respective control, there might be picker implementations which do not + // respect this, and return IsLink=FALSE here. In this case, "normalize" the flag. + // #i112659# / 2010-08-26 / frank.schoenheit@oracle.com + bIsLink |= bHasField; + if ( !bIsLink ) + { + Graphic aGraphic; + aDialog.GetGraphic( aGraphic ); + xSet->setPropertyValue( PROPERTY_GRAPHIC, makeAny( aGraphic.GetXGraphic() ) ); + } + else + xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString( aDialog.GetPath() ) ) ); + + return true; + } + } + catch(Exception&) + { + DBG_ERROR("OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!"); + } + return false; +} + +//------------------------------------------------------------------------------ +bool OImageControlControl::impl_isEmptyGraphics_nothrow() const +{ + bool bIsEmpty = true; + + try + { + Reference< XPropertySet > xModelProps( const_cast< OImageControlControl* >( this )->getModel(), UNO_QUERY_THROW ); + Reference< XGraphic > xGraphic; + OSL_VERIFY( xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Graphic" ) ) ) >>= xGraphic ); + bIsEmpty = !xGraphic.is(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return bIsEmpty; +} + +// MouseListener +//------------------------------------------------------------------------------ +void OImageControlControl::mousePressed(const ::com::sun::star::awt::MouseEvent& e) throw ( ::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if (e.Buttons != MouseButton::LEFT) + return; + + bool bModified = false; + // is this a request for a context menu? + if ( e.PopupTrigger ) + { + Reference< XPopupMenu > xMenu( m_aContext.createComponent( "com.sun.star.awt.PopupMenu" ), UNO_QUERY ); + DBG_ASSERT( xMenu.is(), "OImageControlControl::mousePressed: could not create a popup menu!" ); + + Reference< XWindowPeer > xWindowPeer = getPeer(); + DBG_ASSERT( xWindowPeer.is(), "OImageControlControl::mousePressed: no window!" ); + + if ( xMenu.is() && xWindowPeer.is() ) + { + xMenu->insertItem( ID_OPEN_GRAPHICS, FRM_RES_STRING( RID_STR_OPEN_GRAPHICS ), 0, 0 ); + xMenu->insertItem( ID_CLEAR_GRAPHICS, FRM_RES_STRING( RID_STR_CLEAR_GRAPHICS ), 0, 1 ); + + // check if the ImageURL is empty + if ( impl_isEmptyGraphics_nothrow() ) + xMenu->enableItem( ID_CLEAR_GRAPHICS, sal_False ); + + awt::Rectangle aRect( e.X, e.Y, 0, 0 ); + if ( ( e.X < 0 ) || ( e.Y < 0 ) ) + { // context menu triggered by keyboard + // position it in the center of the control + // 102205 - 16.08.2002 - fs@openoffice.org + Reference< XWindow > xWindow( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY ); + OSL_ENSURE( xWindow.is(), "OImageControlControl::mousePressed: me not a window? How this?" ); + if ( xWindow.is() ) + { + awt::Rectangle aPosSize = xWindow->getPosSize(); + aRect.X = aPosSize.Width / 2; + aRect.Y = aPosSize.Height / 2; + } + } + + const sal_Int16 nResult = xMenu->execute( xWindowPeer, aRect, PopupMenuDirection::EXECUTE_DEFAULT ); + + switch ( nResult ) + { + case ID_OPEN_GRAPHICS: + implInsertGraphics(); + bModified = true; + break; + + case ID_CLEAR_GRAPHICS: + implClearGraphics( sal_True ); + bModified = true; + break; + } + } + } + else + { + ////////////////////////////////////////////////////////////////////// + // Doppelclick + if (e.ClickCount == 2) + { + + Reference<XPropertySet> xSet(getModel(), UNO_QUERY); + if (!xSet.is()) + return; + + // wenn Control nicht gebunden ist, kein Dialog (da die zu schickende URL hinterher sowieso + // versanden wuerde) + // FS - #64946# - 19.04.99 + Reference<XPropertySet> xBoundField; + if (hasProperty(PROPERTY_BOUNDFIELD, xSet)) + ::cppu::extractInterface(xBoundField, xSet->getPropertyValue(PROPERTY_BOUNDFIELD)); + if (!xBoundField.is()) + { + // but only if our IMAGE_URL property is handled as if it is transient, which is equivalent to + // an empty control source + if (!hasProperty(PROPERTY_CONTROLSOURCE, xSet) || (::comphelper::getString(xSet->getPropertyValue(PROPERTY_CONTROLSOURCE)).getLength() != 0)) + return; + } + + sal_Bool bReadOnly = false; + xSet->getPropertyValue(PROPERTY_READONLY) >>= bReadOnly; + if (bReadOnly) + return; + + if ( implInsertGraphics() ) + bModified = true; + } + } + + if ( bModified ) + { + EventObject aEvent( *this ); + m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL OImageControlControl::mouseReleased(const awt::MouseEvent& /*e*/) throw ( RuntimeException ) +{ +} + +//------------------------------------------------------------------------------ +void SAL_CALL OImageControlControl::mouseEntered(const awt::MouseEvent& /*e*/) throw ( RuntimeException ) +{ +} + +//------------------------------------------------------------------------------ +void SAL_CALL OImageControlControl::mouseExited(const awt::MouseEvent& /*e*/) throw ( RuntimeException ) +{ +} + +//......................................................................... +} // namespace frm +//......................................................................... + |