1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "ImageControl.hxx"
22 #include "property.hrc"
23 #include "frm_resource.hrc"
24 #include "frm_resource.hxx"
25 #include "services.hxx"
26 #include "componenttools.hxx"
28 #include <svtools/imageresourceaccess.hxx>
29 #include <sfx2/filedlghelper.hxx>
30 #include <com/sun/star/awt/PopupMenu.hpp>
31 #include <com/sun/star/awt/XPopupMenu.hpp>
32 #include <com/sun/star/awt/PopupMenuDirection.hpp>
33 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
34 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
35 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
36 #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
37 #include <com/sun/star/sdbc/DataType.hpp>
38 #include <com/sun/star/awt/MouseButton.hpp>
39 #include <com/sun/star/awt/XWindow.hpp>
40 #include <com/sun/star/awt/XDialog.hpp>
41 #include <com/sun/star/io/XActiveDataSink.hpp>
42 #include <com/sun/star/io/NotConnectedException.hpp>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/graphic/XGraphic.hpp>
45 #include <com/sun/star/graphic/GraphicObject.hpp>
46 #include <tools/urlobj.hxx>
47 #include <tools/stream.hxx>
48 #include <tools/debug.hxx>
49 #include <tools/diagnose_ex.h>
50 #include <vcl/svapp.hxx>
51 #include <unotools/streamhelper.hxx>
52 #include <comphelper/guarding.hxx>
53 #include <comphelper/processfactory.hxx>
54 #include <unotools/ucbstreamhelper.hxx>
55 #include <svl/urihelper.hxx>
57 #include <boost/scoped_ptr.hpp>
59 #define ID_OPEN_GRAPHICS 1
60 #define ID_CLEAR_GRAPHICS 2
65 using namespace ::com::sun::star
;
66 using namespace ::com::sun::star::uno
;
67 using namespace ::com::sun::star::sdb
;
68 using namespace ::com::sun::star::sdbc
;
69 using namespace ::com::sun::star::sdbcx
;
70 using namespace ::com::sun::star::beans
;
71 using namespace ::com::sun::star::container
;
72 using namespace ::com::sun::star::form
;
73 using namespace ::com::sun::star::awt
;
74 using namespace ::com::sun::star::io
;
75 using namespace ::com::sun::star::ui::dialogs
;
76 using namespace ::com::sun::star::lang
;
77 using namespace ::com::sun::star::util
;
78 using namespace ::com::sun::star::graphic
;
79 using namespace ::com::sun::star::frame
;
82 //= OImageControlModel
94 ImageStoreType
lcl_getImageStoreType( const sal_Int32 _nFieldType
)
96 // binary/longvarchar types could be used to store images in binary representation
97 if ( ( _nFieldType
== DataType::BINARY
)
98 || ( _nFieldType
== DataType::VARBINARY
)
99 || ( _nFieldType
== DataType::LONGVARBINARY
)
100 || ( _nFieldType
== DataType::OTHER
)
101 || ( _nFieldType
== DataType::OBJECT
)
102 || ( _nFieldType
== DataType::BLOB
)
103 || ( _nFieldType
== DataType::LONGVARCHAR
)
104 || ( _nFieldType
== DataType::CLOB
)
106 return ImageStoreBinary
;
108 // char types could be used to store links to images
109 if ( ( _nFieldType
== DataType::CHAR
)
110 || ( _nFieldType
== DataType::VARCHAR
)
112 return ImageStoreLink
;
114 return ImageStoreInvalid
;
119 // OImageControlModel
121 Sequence
<Type
> OImageControlModel::_getTypes()
123 return concatSequences(
124 OBoundControlModel::_getTypes(),
125 OImageControlModel_Base::getTypes()
130 OImageControlModel::OImageControlModel(const Reference
<XComponentContext
>& _rxFactory
)
131 :OBoundControlModel( _rxFactory
, VCL_CONTROLMODEL_IMAGECONTROL
, FRM_SUN_CONTROL_IMAGECONTROL
, false, false, false )
132 // use the old control name for compytibility reasons
133 ,m_pImageProducer( NULL
)
134 ,m_bExternalGraphic( true )
135 ,m_bReadOnly( false )
139 m_nClassId
= FormComponentType::IMAGECONTROL
;
140 initOwnValueProperty( PROPERTY_IMAGE_URL
);
146 OImageControlModel::OImageControlModel( const OImageControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
)
147 :OBoundControlModel( _pOriginal
, _rxFactory
)
148 // use the old control name for compytibility reasons
149 ,m_pImageProducer( NULL
)
150 ,m_bExternalGraphic( true )
151 ,m_bReadOnly( _pOriginal
->m_bReadOnly
)
152 ,m_sImageURL( _pOriginal
->m_sImageURL
)
153 ,m_xGraphicObject( _pOriginal
->m_xGraphicObject
)
157 osl_atomic_increment( &m_refCount
);
159 // simulate a propertyChanged event for the ImageURL
160 ::osl::MutexGuard
aGuard( m_aMutex
);
161 impl_handleNewImageURL_lck( eOther
);
163 osl_atomic_decrement( &m_refCount
);
167 void OImageControlModel::implConstruct()
169 m_pImageProducer
= new ImageProducer
;
170 m_xImageProducer
= m_pImageProducer
;
171 m_pImageProducer
->SetDoneHdl( LINK( this, OImageControlModel
, OnImageImportDone
) );
175 OImageControlModel::~OImageControlModel()
177 if (!OComponentHelper::rBHelper
.bDisposed
)
187 IMPLEMENT_DEFAULT_CLONING( OImageControlModel
)
191 StringSequence
OImageControlModel::getSupportedServiceNames() throw(std::exception
)
193 StringSequence aSupported
= OBoundControlModel::getSupportedServiceNames();
194 aSupported
.realloc(aSupported
.getLength() + 2);
196 OUString
*pArray
= aSupported
.getArray();
197 pArray
[aSupported
.getLength()-2] = FRM_SUN_COMPONENT_IMAGECONTROL
;
198 pArray
[aSupported
.getLength()-1] = FRM_COMPONENT_IMAGECONTROL
;
203 Any SAL_CALL
OImageControlModel::queryAggregation(const Type
& _rType
) throw (RuntimeException
, std::exception
)
205 // Order matters: we want to "override" the XImageProducer interface of the aggregate without
206 // own XImageProducer interface, thus we need to query OImageControlModel_Base first
207 Any aReturn
= OImageControlModel_Base::queryInterface( _rType
);
209 // BUT: _don't_ let it feel responsible for the XTypeProvider interface
210 // (as this is implemented by our base class in the proper way)
211 if ( _rType
.equals( cppu::UnoType
<XTypeProvider
>::get() )
212 || !aReturn
.hasValue()
214 aReturn
= OBoundControlModel::queryAggregation( _rType
);
220 bool OImageControlModel::approveDbColumnType( sal_Int32 _nColumnType
)
222 return ImageStoreInvalid
!= lcl_getImageStoreType( _nColumnType
);
226 void OImageControlModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
230 case PROPERTY_ID_READONLY
:
231 rValue
<<= m_bReadOnly
;
233 case PROPERTY_ID_IMAGE_URL
:
234 rValue
<<= m_sImageURL
;
236 case PROPERTY_ID_GRAPHIC
:
237 rValue
<<= m_xGraphicObject
.is() ? m_xGraphicObject
->getGraphic() : Reference
< XGraphic
>();
240 OBoundControlModel::getFastPropertyValue(rValue
, nHandle
);
245 void OImageControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
) throw ( ::com::sun::star::uno::Exception
, std::exception
)
249 case PROPERTY_ID_READONLY
:
250 DBG_ASSERT(rValue
.getValueType().getTypeClass() == TypeClass_BOOLEAN
, "OImageControlModel::setFastPropertyValue_NoBroadcast : invalid type !" );
251 m_bReadOnly
= getBOOL(rValue
);
254 case PROPERTY_ID_IMAGE_URL
:
255 OSL_VERIFY( rValue
>>= m_sImageURL
);
256 impl_handleNewImageURL_lck( eOther
);
258 ControlModelLock
aLock( *this );
259 // that's a fake ... onValuePropertyChange expects to receive the only lock to our instance,
260 // but we're already called with our mutex locked ...
261 onValuePropertyChange( aLock
);
265 case PROPERTY_ID_GRAPHIC
:
267 Reference
< XGraphic
> xGraphic
;
268 OSL_VERIFY( rValue
>>= xGraphic
);
269 if ( !xGraphic
.is() )
270 m_xGraphicObject
.clear();
273 m_xGraphicObject
= graphic::GraphicObject::create( m_xContext
);
274 m_xGraphicObject
->setGraphic( xGraphic
);
277 if ( m_bExternalGraphic
)
279 // if that's an external graphic, i.e. one which has not been loaded by ourselves in response to a
280 // new image URL, then also adjust our ImageURL.
281 OUString sNewImageURL
;
282 if ( m_xGraphicObject
.is() )
284 sNewImageURL
= "vnd.sun.star.GraphicObject:";
285 sNewImageURL
= sNewImageURL
+ m_xGraphicObject
->getUniqueID();
287 m_sImageURL
= sNewImageURL
;
288 // TODO: speaking strictly, this would need to be notified, since ImageURL is a bound property. However,
289 // this method here is called with a locked mutex, so we cannot simply call listeners ...
290 // I think the missing notification (and thus clients which potentially cannot observe the change)
291 // is less severe than the potential deadlock ...
297 OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
303 sal_Bool
OImageControlModel::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
304 throw( IllegalArgumentException
)
308 case PROPERTY_ID_READONLY
:
309 return tryPropertyValue(rConvertedValue
, rOldValue
, rValue
, m_bReadOnly
);
311 case PROPERTY_ID_IMAGE_URL
:
312 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_sImageURL
);
314 case PROPERTY_ID_GRAPHIC
:
316 const Reference
< XGraphic
> xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC
), UNO_QUERY
);
317 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, xGraphic
);
321 return OBoundControlModel::convertFastPropertyValue(rConvertedValue
, rOldValue
, nHandle
, rValue
);
326 void OImageControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
328 BEGIN_DESCRIBE_PROPERTIES( 4, OBoundControlModel
)
329 DECL_IFACE_PROP2( GRAPHIC
, XGraphic
, BOUND
, TRANSIENT
);
330 DECL_PROP1 ( IMAGE_URL
, OUString
, BOUND
);
331 DECL_BOOL_PROP1 ( READONLY
, BOUND
);
332 DECL_PROP1 ( TABINDEX
, sal_Int16
, BOUND
);
333 END_DESCRIBE_PROPERTIES();
337 void OImageControlModel::describeAggregateProperties( Sequence
< Property
>& /* [out] */ o_rAggregateProperties
) const
339 OBoundControlModel::describeAggregateProperties( o_rAggregateProperties
);
340 // remove ImageURL and Graphic properties, we "override" them.
341 // This is because our aggregate synchronizes those
342 // two, but we have an own sychronization mechanism.
343 RemoveProperty( o_rAggregateProperties
, PROPERTY_IMAGE_URL
);
344 RemoveProperty( o_rAggregateProperties
, PROPERTY_GRAPHIC
);
348 OUString
OImageControlModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
350 return OUString(FRM_COMPONENT_IMAGECONTROL
); // old (non-sun) name for compatibility !
354 void OImageControlModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
357 OBoundControlModel::write(_rxOutStream
);
359 _rxOutStream
->writeShort(0x0003);
361 _rxOutStream
->writeBoolean(m_bReadOnly
);
362 writeHelpTextCompatibly(_rxOutStream
);
363 // from version 0x0003 : common properties
364 writeCommonProperties(_rxOutStream
);
368 void OImageControlModel::read(const Reference
<XObjectInputStream
>& _rxInStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
370 OBoundControlModel::read(_rxInStream
);
373 sal_uInt16 nVersion
= _rxInStream
->readShort();
377 m_bReadOnly
= _rxInStream
->readBoolean();
380 m_bReadOnly
= _rxInStream
->readBoolean();
381 readHelpTextCompatibly(_rxInStream
);
384 m_bReadOnly
= _rxInStream
->readBoolean();
385 readHelpTextCompatibly(_rxInStream
);
386 readCommonProperties(_rxInStream
);
389 OSL_FAIL("OImageControlModel::read : unknown version !");
391 defaultCommonProperties();
394 // Display default values after read
395 if ( !getControlSource().isEmpty() )
396 { // (not if we don't have a control source - the "State" property acts like it is persistent, then
397 ::osl::MutexGuard
aGuard(m_aMutex
); // resetNoBroadcast expects this mutex guarding
403 bool OImageControlModel::impl_updateStreamForURL_lck( const OUString
& _rURL
, ValueChangeInstigator _eInstigator
)
405 // create a stream for the image specified by the URL
406 boost::scoped_ptr
< SvStream
> pImageStream
;
407 Reference
< XInputStream
> xImageStream
;
409 if ( ::svt::GraphicAccess::isSupportedURL( _rURL
) )
411 xImageStream
= ::svt::GraphicAccess::getImageXStream( getContext(), _rURL
);
415 pImageStream
.reset( ::utl::UcbStreamHelper::CreateStream( _rURL
, StreamMode::READ
) );
416 bool bSetNull
= ( pImageStream
.get() == NULL
) || ( ERRCODE_NONE
!= pImageStream
->GetErrorCode() );
420 // get the size of the stream
421 sal_uInt64
const nSize
= pImageStream
->remainingSize();
422 if (pImageStream
->GetBufferSize() < 8192)
423 pImageStream
->SetBufferSize(8192);
424 pImageStream
->Seek(STREAM_SEEK_TO_BEGIN
);
426 xImageStream
= new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream
.get(), false ), nSize
);
430 if ( xImageStream
.is() )
432 if ( m_xColumnUpdate
.is() )
433 m_xColumnUpdate
->updateBinaryStream( xImageStream
, xImageStream
->available() );
435 setControlValue( makeAny( xImageStream
), _eInstigator
);
436 xImageStream
->closeInput();
444 bool OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator
)
446 switch ( lcl_getImageStoreType( getFieldType() ) )
448 case ImageStoreBinary
:
449 if ( impl_updateStreamForURL_lck( m_sImageURL
, _eInstigator
) )
455 OUString
sCommitURL( m_sImageURL
);
456 if ( !m_sDocumentURL
.isEmpty() )
457 sCommitURL
= URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL
, sCommitURL
);
458 OSL_ENSURE( m_xColumnUpdate
.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" );
459 if ( m_xColumnUpdate
.is() )
461 m_xColumnUpdate
->updateString( sCommitURL
);
467 case ImageStoreInvalid
:
468 OSL_FAIL( "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" );
472 // if we're here, then the above code was unable to update our field/control from the given URL
473 // => fall back to NULL/VOID
474 if ( m_xColumnUpdate
.is() )
475 m_xColumnUpdate
->updateNull();
477 setControlValue( Any(), _eInstigator
);
483 bool OImageControlModel::commitControlValueToDbColumn( bool _bPostReset
)
487 // since this is a "commit after reset", we can simply update the column
488 // with null - this is our "default" which we were just reset to
489 if ( m_xColumnUpdate
.is() )
490 m_xColumnUpdate
->updateNull();
494 ::osl::MutexGuard
aGuard(m_aMutex
);
495 return impl_handleNewImageURL_lck( eDbColumnBinding
);
504 bool lcl_isValidDocumentURL( const OUString
& _rDocURL
)
506 return ( !_rDocURL
.isEmpty() && _rDocURL
!= "private:object" );
511 void OImageControlModel::onConnectedDbColumn( const Reference
< XInterface
>& _rxForm
)
513 OBoundControlModel::onConnectedDbColumn( _rxForm
);
517 Reference
< XModel
> xDocument( getXModel( *this ) );
518 if ( xDocument
.is() )
520 m_sDocumentURL
= xDocument
->getURL();
521 if ( !lcl_isValidDocumentURL( m_sDocumentURL
) )
523 Reference
< XChild
> xAsChild( xDocument
, UNO_QUERY
);
524 while ( xAsChild
.is() && !lcl_isValidDocumentURL( m_sDocumentURL
) )
526 xDocument
.set( xAsChild
->getParent(), UNO_QUERY
);
527 if ( xDocument
.is() )
528 m_sDocumentURL
= xDocument
->getURL();
529 xAsChild
.set( xDocument
, UNO_QUERY
);
534 catch( const Exception
& )
536 DBG_UNHANDLED_EXCEPTION();
541 void OImageControlModel::onDisconnectedDbColumn()
543 OBoundControlModel::onDisconnectedDbColumn();
545 m_sDocumentURL
.clear();
549 Any
OImageControlModel::translateDbColumnToControlValue()
551 switch ( lcl_getImageStoreType( getFieldType() ) )
553 case ImageStoreBinary
:
555 Reference
< XInputStream
> xImageStream( m_xColumn
->getBinaryStream() );
556 if ( m_xColumn
->wasNull() )
557 xImageStream
.clear();
558 return makeAny( xImageStream
);
562 OUString
sImageLink( m_xColumn
->getString() );
563 if ( !m_sDocumentURL
.isEmpty() )
564 sImageLink
= INetURLObject::GetAbsURL( m_sDocumentURL
, sImageLink
);
565 return makeAny( sImageLink
);
567 case ImageStoreInvalid
:
568 OSL_FAIL( "OImageControlModel::translateDbColumnToControlValue: invalid field type!" );
575 Any
OImageControlModel::getControlValue( ) const
577 return makeAny( m_sImageURL
);
581 void OImageControlModel::doSetControlValue( const Any
& _rValue
)
583 DBG_ASSERT( GetImageProducer() && m_xImageProducer
.is(), "OImageControlModel::doSetControlValue: no image producer!" );
584 if ( !GetImageProducer() || !m_xImageProducer
.is() )
587 bool bStartProduction
= false;
588 switch ( lcl_getImageStoreType( getFieldType() ) )
590 case ImageStoreBinary
:
592 // give the image producer the stream
593 Reference
< XInputStream
> xInStream
;
594 _rValue
>>= xInStream
;
595 GetImageProducer()->setImage( xInStream
);
596 bStartProduction
= true;
603 _rValue
>>= sImageURL
;
604 GetImageProducer()->SetImage( sImageURL
);
605 bStartProduction
= true;
609 case ImageStoreInvalid
:
610 OSL_FAIL( "OImageControlModel::doSetControlValue: invalid field type!" );
613 } // switch ( lcl_getImageStoreType( getFieldType() ) )
615 if ( bStartProduction
)
618 Reference
< XImageProducer
> xProducer
= m_xImageProducer
;
620 // release our mutex once (it's acquired in the calling method!), as starting the image production may
621 // result in the locking of the solar mutex (unfortunately the default implementation of our aggregate,
622 // VCLXImageControl, does this locking)
623 MutexRelease
aRelease(m_aMutex
);
624 xProducer
->startProduction();
631 void SAL_CALL
OImageControlModel::disposing()
633 OBoundControlModel::disposing();
637 void OImageControlModel::resetNoBroadcast()
639 if ( hasField() ) // only reset when we are connected to a column
640 OBoundControlModel::resetNoBroadcast( );
644 Reference
< XImageProducer
> SAL_CALL
OImageControlModel::getImageProducer() throw ( RuntimeException
, std::exception
)
650 void SAL_CALL
OImageControlModel::addConsumer( const Reference
< XImageConsumer
>& _rxConsumer
) throw (RuntimeException
, std::exception
)
652 GetImageProducer()->addConsumer( _rxConsumer
);
656 void SAL_CALL
OImageControlModel::removeConsumer( const Reference
< XImageConsumer
>& _rxConsumer
) throw (RuntimeException
, std::exception
)
658 GetImageProducer()->removeConsumer( _rxConsumer
);
662 void SAL_CALL
OImageControlModel::startProduction( ) throw (RuntimeException
, std::exception
)
664 GetImageProducer()->startProduction();
668 IMPL_LINK( OImageControlModel
, OnImageImportDone
, ::Graphic
*, i_pGraphic
)
670 const Reference
< XGraphic
> xGraphic( i_pGraphic
!= NULL
? Image( i_pGraphic
->GetBitmapEx() ).GetXGraphic() : NULL
);
671 m_bExternalGraphic
= false;
674 setPropertyValue( PROPERTY_GRAPHIC
, makeAny( xGraphic
) );
676 catch ( const Exception
& )
678 DBG_UNHANDLED_EXCEPTION();
680 m_bExternalGraphic
= true;
685 // OImageControlControl
687 Sequence
<Type
> OImageControlControl::_getTypes()
689 return concatSequences(
690 OBoundControl::_getTypes(),
691 OImageControlControl_Base::getTypes()
696 OImageControlControl::OImageControlControl(const Reference
<XComponentContext
>& _rxFactory
)
697 :OBoundControl(_rxFactory
, VCL_CONTROL_IMAGECONTROL
)
698 ,m_aModifyListeners( m_aMutex
)
700 osl_atomic_increment(&m_refCount
);
702 // Add as Focus- and MouseListener
703 Reference
< XWindow
> xComp
;
704 query_aggregation( m_xAggregate
, xComp
);
706 xComp
->addMouseListener( this );
708 osl_atomic_decrement(&m_refCount
);
712 Any SAL_CALL
OImageControlControl::queryAggregation(const Type
& _rType
) throw (RuntimeException
, std::exception
)
714 Any aReturn
= OBoundControl::queryAggregation( _rType
);
715 if ( !aReturn
.hasValue() )
716 aReturn
= ::cppu::queryInterface(
718 static_cast< XMouseListener
* >( this ),
719 static_cast< XModifyBroadcaster
* >( this )
726 StringSequence
OImageControlControl::getSupportedServiceNames() throw(std::exception
)
728 StringSequence aSupported
= OBoundControl::getSupportedServiceNames();
729 aSupported
.realloc(aSupported
.getLength() + 2);
731 OUString
*pArray
= aSupported
.getArray();
732 pArray
[aSupported
.getLength()-2] = FRM_SUN_CONTROL_IMAGECONTROL
;
733 pArray
[aSupported
.getLength()-1] = STARDIV_ONE_FORM_CONTROL_IMAGECONTROL
;
738 void SAL_CALL
OImageControlControl::addModifyListener( const Reference
< XModifyListener
>& _Listener
) throw (RuntimeException
, std::exception
)
740 m_aModifyListeners
.addInterface( _Listener
);
744 void SAL_CALL
OImageControlControl::removeModifyListener( const Reference
< XModifyListener
>& _Listener
) throw (RuntimeException
, std::exception
)
746 m_aModifyListeners
.removeInterface( _Listener
);
750 void SAL_CALL
OImageControlControl::disposing()
752 EventObject
aEvent( *this );
753 m_aModifyListeners
.disposeAndClear( aEvent
);
755 OBoundControl::disposing();
759 void SAL_CALL
OImageControlControl::disposing( const EventObject
& _Event
) throw(RuntimeException
, std::exception
)
761 OBoundControl::disposing( _Event
);
765 void OImageControlControl::implClearGraphics( bool _bForce
)
767 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
772 OUString sOldImageURL
;
773 xSet
->getPropertyValue( PROPERTY_IMAGE_URL
) >>= sOldImageURL
;
775 if ( sOldImageURL
.isEmpty() )
776 // the ImageURL is already empty, so simply setting a new empty one would not suffice
777 // (since it would be ignored)
778 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString( "private:emptyImage" ) ) );
779 // (the concrete URL we're passing here doesn't matter. It's important that
780 // the model cannot resolve it to a valid resource describing an image stream
783 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString() ) );
788 bool OImageControlControl::implInsertGraphics()
790 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
794 OUString sTitle
= FRM_RES_STRING(RID_STR_IMPORT_GRAPHIC
);
795 // build some arguments for the upcoming dialog
798 ::sfx2::FileDialogHelper
aDialog( TemplateDescription::FILEOPEN_LINK_PREVIEW
, SFXWB_GRAPHIC
);
799 aDialog
.SetTitle( sTitle
);
801 Reference
< XFilePickerControlAccess
> xController( aDialog
.GetFilePicker(), UNO_QUERY_THROW
);
802 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
, 0, css::uno::Any(true));
804 Reference
<XPropertySet
> xBoundField
;
805 if ( hasProperty( PROPERTY_BOUNDFIELD
, xSet
) )
806 xSet
->getPropertyValue( PROPERTY_BOUNDFIELD
) >>= xBoundField
;
807 bool bHasField
= xBoundField
.is();
809 // if the control is bound to a DB field, then it's not possible to decide whether or not to link
810 xController
->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK
, !bHasField
);
812 // if the control is bound to a DB field, then linking of the image depends on the type of the field
813 bool bImageIsLinked
= true;
816 sal_Int32 nFieldType
= DataType::OTHER
;
817 OSL_VERIFY( xBoundField
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
);
818 bImageIsLinked
= ( lcl_getImageStoreType( nFieldType
) == ImageStoreLink
);
820 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0, makeAny( bImageIsLinked
) );
822 if ( ERRCODE_NONE
== aDialog
.Execute() )
824 // reset the url property in case it already has the value we're about to set - in this case
825 // our propertyChanged would not get called without this.
826 implClearGraphics( false );
827 bool bIsLink
= false;
828 xController
->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0) >>= bIsLink
;
829 // Force bIsLink to be sal_True if we're bound to a field. Though we initialized the file picker with IsLink=TRUE
830 // in this case, and disabled the respective control, there might be picker implementations which do not
831 // respect this, and return IsLink=FALSE here. In this case, "normalize" the flag.
833 bIsLink
|= bHasField
;
837 aDialog
.GetGraphic( aGraphic
);
838 xSet
->setPropertyValue( PROPERTY_GRAPHIC
, makeAny( aGraphic
.GetXGraphic() ) );
841 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString( aDialog
.GetPath() ) ) );
846 catch(const Exception
&)
848 OSL_FAIL("OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!");
854 bool OImageControlControl::impl_isEmptyGraphics_nothrow() const
856 bool bIsEmpty
= true;
860 Reference
< XPropertySet
> xModelProps( const_cast< OImageControlControl
* >( this )->getModel(), UNO_QUERY_THROW
);
861 Reference
< XGraphic
> xGraphic
;
862 OSL_VERIFY( xModelProps
->getPropertyValue("Graphic") >>= xGraphic
);
863 bIsEmpty
= !xGraphic
.is();
865 catch( const Exception
& )
867 DBG_UNHANDLED_EXCEPTION();
875 void OImageControlControl::mousePressed(const ::com::sun::star::awt::MouseEvent
& e
) throw ( ::com::sun::star::uno::RuntimeException
, std::exception
)
877 SolarMutexGuard aGuard
;
879 if (e
.Buttons
!= MouseButton::LEFT
)
882 bool bModified
= false;
883 // is this a request for a context menu?
884 if ( e
.PopupTrigger
)
886 Reference
< XPopupMenu
> xMenu( awt::PopupMenu::create( m_xContext
) );
887 DBG_ASSERT( xMenu
.is(), "OImageControlControl::mousePressed: could not create a popup menu!" );
889 Reference
< XWindowPeer
> xWindowPeer
= getPeer();
890 DBG_ASSERT( xWindowPeer
.is(), "OImageControlControl::mousePressed: no window!" );
892 if ( xMenu
.is() && xWindowPeer
.is() )
894 xMenu
->insertItem( ID_OPEN_GRAPHICS
, FRM_RES_STRING( RID_STR_OPEN_GRAPHICS
), 0, 0 );
895 xMenu
->insertItem( ID_CLEAR_GRAPHICS
, FRM_RES_STRING( RID_STR_CLEAR_GRAPHICS
), 0, 1 );
897 // check if the ImageURL is empty
898 if ( impl_isEmptyGraphics_nothrow() )
899 xMenu
->enableItem( ID_CLEAR_GRAPHICS
, sal_False
);
901 awt::Rectangle
aRect( e
.X
, e
.Y
, 0, 0 );
902 if ( ( e
.X
< 0 ) || ( e
.Y
< 0 ) )
903 { // context menu triggered by keyboard
904 // position it in the center of the control
905 Reference
< XWindow
> xWindow( static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY
);
906 OSL_ENSURE( xWindow
.is(), "OImageControlControl::mousePressed: me not a window? How this?" );
909 awt::Rectangle aPosSize
= xWindow
->getPosSize();
910 aRect
.X
= aPosSize
.Width
/ 2;
911 aRect
.Y
= aPosSize
.Height
/ 2;
915 const sal_Int16 nResult
= xMenu
->execute( xWindowPeer
, aRect
, PopupMenuDirection::EXECUTE_DEFAULT
);
919 case ID_OPEN_GRAPHICS
:
920 implInsertGraphics();
924 case ID_CLEAR_GRAPHICS
:
925 implClearGraphics( true );
935 if (e
.ClickCount
== 2)
938 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
942 // If the Control is not bound, do not display a dialog (because the to-be-sent URL would be invalid anyway)
943 Reference
<XPropertySet
> xBoundField
;
944 if (hasProperty(PROPERTY_BOUNDFIELD
, xSet
))
946 xSet
->getPropertyValue(PROPERTY_BOUNDFIELD
),
947 css::uno::UNO_QUERY
);
948 if (!xBoundField
.is())
950 // but only if our IMAGE_URL property is handled as if it is transient, which is equivalent to
951 // an empty control source
952 if ( !hasProperty(PROPERTY_CONTROLSOURCE
, xSet
) || !::comphelper::getString(xSet
->getPropertyValue(PROPERTY_CONTROLSOURCE
)).isEmpty() )
956 bool bReadOnly
= false;
957 xSet
->getPropertyValue(PROPERTY_READONLY
) >>= bReadOnly
;
961 if ( implInsertGraphics() )
968 EventObject
aEvent( *this );
969 m_aModifyListeners
.notifyEach( &XModifyListener::modified
, aEvent
);
974 void SAL_CALL
OImageControlControl::mouseReleased(const awt::MouseEvent
& /*e*/) throw ( RuntimeException
, std::exception
)
979 void SAL_CALL
OImageControlControl::mouseEntered(const awt::MouseEvent
& /*e*/) throw ( RuntimeException
, std::exception
)
984 void SAL_CALL
OImageControlControl::mouseExited(const awt::MouseEvent
& /*e*/) throw ( RuntimeException
, std::exception
)
990 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
991 com_sun_star_form_OImageControlModel_get_implementation(::com::sun::star::uno::XComponentContext
* component
,
992 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
994 return cppu::acquire(new frm::OImageControlModel(component
));
997 extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface
* SAL_CALL
998 com_sun_star_form_OImageControlControl_get_implementation(::com::sun::star::uno::XComponentContext
* component
,
999 ::com::sun::star::uno::Sequence
<css::uno::Any
> const &)
1001 return cppu::acquire(new frm::OImageControlControl(component
));
1004 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */