| /************************************************************** | |
| * | |
| * 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 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the 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 | |
| //......................................................................... | |