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 <unotools/ucblockbytes.hxx>
30 #include <sfx2/filedlghelper.hxx>
31 #include <com/sun/star/awt/PopupMenu.hpp>
32 #include <com/sun/star/awt/XPopupMenu.hpp>
33 #include <com/sun/star/awt/PopupMenuDirection.hpp>
34 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
35 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
36 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
37 #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
38 #include <com/sun/star/sdbc/DataType.hpp>
39 #include <com/sun/star/awt/MouseButton.hpp>
40 #include <com/sun/star/awt/XWindow.hpp>
41 #include <com/sun/star/awt/XDialog.hpp>
42 #include <com/sun/star/io/XActiveDataSink.hpp>
43 #include <com/sun/star/io/NotConnectedException.hpp>
44 #include <com/sun/star/beans/PropertyValue.hpp>
45 #include <com/sun/star/graphic/XGraphic.hpp>
46 #include <com/sun/star/graphic/GraphicObject.hpp>
47 #include <tools/urlobj.hxx>
48 #include <tools/stream.hxx>
49 #include <tools/debug.hxx>
50 #include <tools/diagnose_ex.h>
51 #include <vcl/svapp.hxx>
52 #include <unotools/streamhelper.hxx>
53 #include <comphelper/extract.hxx>
54 #include <comphelper/guarding.hxx>
55 #include <unotools/ucbstreamhelper.hxx>
56 #include <svl/urihelper.hxx>
60 #define ID_OPEN_GRAPHICS 1
61 #define ID_CLEAR_GRAPHICS 2
63 //.........................................................................
66 //.........................................................................
67 using namespace ::com::sun::star
;
68 using namespace ::com::sun::star::uno
;
69 using namespace ::com::sun::star::sdb
;
70 using namespace ::com::sun::star::sdbc
;
71 using namespace ::com::sun::star::sdbcx
;
72 using namespace ::com::sun::star::beans
;
73 using namespace ::com::sun::star::container
;
74 using namespace ::com::sun::star::form
;
75 using namespace ::com::sun::star::awt
;
76 using namespace ::com::sun::star::io
;
77 using namespace ::com::sun::star::ui::dialogs
;
78 using namespace ::com::sun::star::lang
;
79 using namespace ::com::sun::star::util
;
80 using namespace ::com::sun::star::graphic
;
81 using namespace ::com::sun::star::frame
;
83 //==============================================================================
84 //= OImageControlModel
85 //==============================================================================
96 ImageStoreType
lcl_getImageStoreType( const sal_Int32 _nFieldType
)
98 // binary/longvarchar types could be used to store images in binary representation
99 if ( ( _nFieldType
== DataType::BINARY
)
100 || ( _nFieldType
== DataType::VARBINARY
)
101 || ( _nFieldType
== DataType::LONGVARBINARY
)
102 || ( _nFieldType
== DataType::OTHER
)
103 || ( _nFieldType
== DataType::OBJECT
)
104 || ( _nFieldType
== DataType::BLOB
)
105 || ( _nFieldType
== DataType::LONGVARCHAR
)
106 || ( _nFieldType
== DataType::CLOB
)
108 return ImageStoreBinary
;
110 // char types could be used to store links to images
111 if ( ( _nFieldType
== DataType::CHAR
)
112 || ( _nFieldType
== DataType::VARCHAR
)
114 return ImageStoreLink
;
116 return ImageStoreInvalid
;
120 //==============================================================================
121 // OImageControlModel
122 //==============================================================================
124 //------------------------------------------------------------------------------
125 InterfaceRef SAL_CALL
OImageControlModel_CreateInstance(const Reference
<XMultiServiceFactory
>& _rxFactory
)
127 return *(new OImageControlModel(_rxFactory
));
130 //------------------------------------------------------------------------------
131 Sequence
<Type
> OImageControlModel::_getTypes()
133 return concatSequences(
134 OBoundControlModel::_getTypes(),
135 OImageControlModel_Base::getTypes()
139 DBG_NAME(OImageControlModel
)
140 //------------------------------------------------------------------
141 OImageControlModel::OImageControlModel(const Reference
<XMultiServiceFactory
>& _rxFactory
)
142 :OBoundControlModel( _rxFactory
, VCL_CONTROLMODEL_IMAGECONTROL
, FRM_SUN_CONTROL_IMAGECONTROL
, sal_False
, sal_False
, sal_False
)
143 // use the old control name for compytibility reasons
144 ,m_pImageProducer( NULL
)
145 ,m_bExternalGraphic( true )
146 ,m_bReadOnly( sal_False
)
150 DBG_CTOR( OImageControlModel
, NULL
);
151 m_nClassId
= FormComponentType::IMAGECONTROL
;
152 initOwnValueProperty( PROPERTY_IMAGE_URL
);
157 //------------------------------------------------------------------
158 OImageControlModel::OImageControlModel( const OImageControlModel
* _pOriginal
, const Reference
< XMultiServiceFactory
>& _rxFactory
)
159 :OBoundControlModel( _pOriginal
, _rxFactory
)
160 // use the old control name for compytibility reasons
161 ,m_pImageProducer( NULL
)
162 ,m_bExternalGraphic( true )
163 ,m_bReadOnly( _pOriginal
->m_bReadOnly
)
164 ,m_sImageURL( _pOriginal
->m_sImageURL
)
165 ,m_xGraphicObject( _pOriginal
->m_xGraphicObject
)
167 DBG_CTOR( OImageControlModel
, NULL
);
170 osl_atomic_increment( &m_refCount
);
172 // simulate a propertyChanged event for the ImageURL
173 ::osl::MutexGuard
aGuard( m_aMutex
);
174 impl_handleNewImageURL_lck( eOther
);
176 osl_atomic_decrement( &m_refCount
);
179 //------------------------------------------------------------------
180 void OImageControlModel::implConstruct()
182 m_pImageProducer
= new ImageProducer
;
183 m_xImageProducer
= m_pImageProducer
;
184 m_pImageProducer
->SetDoneHdl( LINK( this, OImageControlModel
, OnImageImportDone
) );
187 //------------------------------------------------------------------
188 OImageControlModel::~OImageControlModel()
190 if (!OComponentHelper::rBHelper
.bDisposed
)
196 DBG_DTOR(OImageControlModel
,NULL
);
200 //------------------------------------------------------------------------------
201 IMPLEMENT_DEFAULT_CLONING( OImageControlModel
)
204 //------------------------------------------------------------------------------
205 StringSequence
OImageControlModel::getSupportedServiceNames() throw()
207 StringSequence aSupported
= OBoundControlModel::getSupportedServiceNames();
208 aSupported
.realloc(aSupported
.getLength() + 1);
210 OUString
*pArray
= aSupported
.getArray();
211 pArray
[aSupported
.getLength()-1] = FRM_SUN_COMPONENT_IMAGECONTROL
;
215 //------------------------------------------------------------------------------
216 Any SAL_CALL
OImageControlModel::queryAggregation(const Type
& _rType
) throw (RuntimeException
)
218 // Order matters: we want to "override" the XImageProducer interface of the aggreate with out
219 // own XImageProducer interface, thus we need to query OImageControlModel_Base first
220 Any aReturn
= OImageControlModel_Base::queryInterface( _rType
);
222 // BUT: _don't_ let it feel responsible for the XTypeProvider interface
223 // (as this is implemented by our base class in the proper way)
224 if ( _rType
.equals( ::getCppuType( static_cast< Reference
< XTypeProvider
>* >( NULL
) ) )
225 || !aReturn
.hasValue()
227 aReturn
= OBoundControlModel::queryAggregation( _rType
);
232 //------------------------------------------------------------------------------
233 sal_Bool
OImageControlModel::approveDbColumnType( sal_Int32 _nColumnType
)
235 return ImageStoreInvalid
!= lcl_getImageStoreType( _nColumnType
);
238 //------------------------------------------------------------------------------
239 void OImageControlModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
243 case PROPERTY_ID_READONLY
:
244 rValue
<<= (sal_Bool
)m_bReadOnly
;
246 case PROPERTY_ID_IMAGE_URL
:
247 rValue
<<= m_sImageURL
;
249 case PROPERTY_ID_GRAPHIC
:
250 rValue
<<= m_xGraphicObject
.is() ? m_xGraphicObject
->getGraphic() : Reference
< XGraphic
>();
253 OBoundControlModel::getFastPropertyValue(rValue
, nHandle
);
257 //------------------------------------------------------------------------------
258 void OImageControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
) throw ( ::com::sun::star::uno::Exception
)
262 case PROPERTY_ID_READONLY
:
263 DBG_ASSERT(rValue
.getValueType().getTypeClass() == TypeClass_BOOLEAN
, "OImageControlModel::setFastPropertyValue_NoBroadcast : invalid type !" );
264 m_bReadOnly
= getBOOL(rValue
);
267 case PROPERTY_ID_IMAGE_URL
:
268 OSL_VERIFY( rValue
>>= m_sImageURL
);
269 impl_handleNewImageURL_lck( eOther
);
271 ControlModelLock
aLock( *this );
272 // that's a fake ... onValuePropertyChange expects to receive the only lock to our instance,
273 // but we're already called with our mutex locked ...
274 onValuePropertyChange( aLock
);
278 case PROPERTY_ID_GRAPHIC
:
280 Reference
< XGraphic
> xGraphic
;
281 OSL_VERIFY( rValue
>>= xGraphic
);
282 if ( !xGraphic
.is() )
283 m_xGraphicObject
.clear();
286 m_xGraphicObject
= GraphicObject::create( m_aContext
.getUNOContext() );
287 m_xGraphicObject
->setGraphic( xGraphic
);
290 if ( m_bExternalGraphic
)
292 // if that's an external graphic, i.e. one which has not been loaded by ourselves in response to a
293 // new image URL, then also adjust our ImageURL.
294 OUString sNewImageURL
;
295 if ( m_xGraphicObject
.is() )
297 sNewImageURL
= OUString( "vnd.sun.star.GraphicObject:" );
298 sNewImageURL
= sNewImageURL
+ m_xGraphicObject
->getUniqueID();
300 m_sImageURL
= sNewImageURL
;
301 // TODO: speaking strictly, this would need to be notified, since ImageURL is a bound property. However,
302 // this method here is called with a locked mutex, so we cannot simply call listeners ...
303 // I think the missing notification (and thus clients which potentially cannot observe the change)
304 // is less severe than the potential deadlock ...
310 OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
315 //------------------------------------------------------------------------------
316 sal_Bool
OImageControlModel::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
317 throw( IllegalArgumentException
)
321 case PROPERTY_ID_READONLY
:
322 return tryPropertyValue(rConvertedValue
, rOldValue
, rValue
, m_bReadOnly
);
324 case PROPERTY_ID_IMAGE_URL
:
325 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_sImageURL
);
327 case PROPERTY_ID_GRAPHIC
:
329 const Reference
< XGraphic
> xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC
), UNO_QUERY
);
330 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, xGraphic
);
334 return OBoundControlModel::convertFastPropertyValue(rConvertedValue
, rOldValue
, nHandle
, rValue
);
338 //------------------------------------------------------------------------------
339 void OImageControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
341 BEGIN_DESCRIBE_PROPERTIES( 4, OBoundControlModel
)
342 DECL_IFACE_PROP2( GRAPHIC
, XGraphic
, BOUND
, TRANSIENT
);
343 DECL_PROP1 ( IMAGE_URL
, OUString
, BOUND
);
344 DECL_BOOL_PROP1 ( READONLY
, BOUND
);
345 DECL_PROP1 ( TABINDEX
, sal_Int16
, BOUND
);
346 END_DESCRIBE_PROPERTIES();
349 //------------------------------------------------------------------------------
350 void OImageControlModel::describeAggregateProperties( Sequence
< Property
>& /* [out] */ o_rAggregateProperties
) const
352 OBoundControlModel::describeAggregateProperties( o_rAggregateProperties
);
353 // remove ImageULR and Graphic properties, we "overload" them. This is because our aggregate synchronizes those
354 // two, but we have an own sychronization mechanism.
355 RemoveProperty( o_rAggregateProperties
, PROPERTY_IMAGE_URL
);
356 RemoveProperty( o_rAggregateProperties
, PROPERTY_GRAPHIC
);
359 //------------------------------------------------------------------------------
360 OUString
OImageControlModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException
)
362 return OUString(FRM_COMPONENT_IMAGECONTROL
); // old (non-sun) name for compatibility !
365 //------------------------------------------------------------------------------
366 void OImageControlModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
369 OBoundControlModel::write(_rxOutStream
);
371 _rxOutStream
->writeShort(0x0003);
373 _rxOutStream
->writeBoolean(m_bReadOnly
);
374 writeHelpTextCompatibly(_rxOutStream
);
375 // from version 0x0003 : common properties
376 writeCommonProperties(_rxOutStream
);
379 //------------------------------------------------------------------------------
380 void OImageControlModel::read(const Reference
<XObjectInputStream
>& _rxInStream
) throw ( ::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
382 OBoundControlModel::read(_rxInStream
);
385 sal_uInt16 nVersion
= _rxInStream
->readShort();
389 m_bReadOnly
= _rxInStream
->readBoolean();
392 m_bReadOnly
= _rxInStream
->readBoolean();
393 readHelpTextCompatibly(_rxInStream
);
396 m_bReadOnly
= _rxInStream
->readBoolean();
397 readHelpTextCompatibly(_rxInStream
);
398 readCommonProperties(_rxInStream
);
401 OSL_FAIL("OImageControlModel::read : unknown version !");
402 m_bReadOnly
= sal_False
;
403 defaultCommonProperties();
406 // Display default values after read
407 if ( !getControlSource().isEmpty() )
408 { // (not if we don't have a control source - the "State" property acts like it is persistent, then
409 ::osl::MutexGuard
aGuard(m_aMutex
); // resetNoBroadcast expects this mutex guarding
414 //------------------------------------------------------------------------------
415 sal_Bool
OImageControlModel::impl_updateStreamForURL_lck( const OUString
& _rURL
, ValueChangeInstigator _eInstigator
)
417 // create a stream for the image specified by the URL
418 ::std::auto_ptr
< SvStream
> pImageStream
;
419 Reference
< XInputStream
> xImageStream
;
421 if ( ::svt::GraphicAccess::isSupportedURL( _rURL
) )
423 xImageStream
= ::svt::GraphicAccess::getImageXStream( getContext().getUNOContext(), _rURL
);
427 pImageStream
.reset( ::utl::UcbStreamHelper::CreateStream( _rURL
, STREAM_READ
) );
428 sal_Bool bSetNull
= ( pImageStream
.get() == NULL
) || ( ERRCODE_NONE
!= pImageStream
->GetErrorCode() );
432 // get the size of the stream
433 pImageStream
->Seek(STREAM_SEEK_TO_END
);
434 sal_Int32 nSize
= (sal_Int32
)pImageStream
->Tell();
435 if (pImageStream
->GetBufferSize() < 8192)
436 pImageStream
->SetBufferSize(8192);
437 pImageStream
->Seek(STREAM_SEEK_TO_BEGIN
);
439 xImageStream
= new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream
.get(), sal_False
), nSize
);
443 if ( xImageStream
.is() )
445 if ( m_xColumnUpdate
.is() )
446 m_xColumnUpdate
->updateBinaryStream( xImageStream
, xImageStream
->available() );
448 setControlValue( makeAny( xImageStream
), _eInstigator
);
449 xImageStream
->closeInput();
456 //------------------------------------------------------------------------------
457 sal_Bool
OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator
)
459 switch ( lcl_getImageStoreType( getFieldType() ) )
461 case ImageStoreBinary
:
462 if ( impl_updateStreamForURL_lck( m_sImageURL
, _eInstigator
) )
468 OUString
sCommitURL( m_sImageURL
);
469 if ( !m_sDocumentURL
.isEmpty() )
470 sCommitURL
= URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL
, sCommitURL
);
471 OSL_ENSURE( m_xColumnUpdate
.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" );
472 if ( m_xColumnUpdate
.is() )
474 m_xColumnUpdate
->updateString( sCommitURL
);
480 case ImageStoreInvalid
:
481 OSL_FAIL( "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" );
485 // if we're here, then the above code was unable to update our field/control from the given URL
486 // => fall back to NULL/VOID
487 if ( m_xColumnUpdate
.is() )
488 m_xColumnUpdate
->updateNull();
490 setControlValue( Any(), _eInstigator
);
495 //------------------------------------------------------------------------------
496 sal_Bool
OImageControlModel::commitControlValueToDbColumn( bool _bPostReset
)
500 // since this is a "commit after reset", we can simply update the column
501 // with null - this is our "default" which we were just reset to
502 if ( m_xColumnUpdate
.is() )
503 m_xColumnUpdate
->updateNull();
507 ::osl::MutexGuard
aGuard(m_aMutex
);
508 return impl_handleNewImageURL_lck( eDbColumnBinding
);
514 //------------------------------------------------------------------------------
517 bool lcl_isValidDocumentURL( const OUString
& _rDocURL
)
519 return ( !_rDocURL
.isEmpty() && _rDocURL
!= "private:object" );
523 //------------------------------------------------------------------------------
524 void OImageControlModel::onConnectedDbColumn( const Reference
< XInterface
>& _rxForm
)
526 OBoundControlModel::onConnectedDbColumn( _rxForm
);
530 Reference
< XModel
> xDocument( getXModel( *this ) );
531 if ( xDocument
.is() )
533 m_sDocumentURL
= xDocument
->getURL();
534 if ( !lcl_isValidDocumentURL( m_sDocumentURL
) )
536 Reference
< XChild
> xAsChild( xDocument
, UNO_QUERY
);
537 while ( xAsChild
.is() && !lcl_isValidDocumentURL( m_sDocumentURL
) )
539 xDocument
.set( xAsChild
->getParent(), UNO_QUERY
);
540 if ( xDocument
.is() )
541 m_sDocumentURL
= xDocument
->getURL();
542 xAsChild
.set( xDocument
, UNO_QUERY
);
547 catch( const Exception
& )
549 DBG_UNHANDLED_EXCEPTION();
553 //------------------------------------------------------------------------------
554 void OImageControlModel::onDisconnectedDbColumn()
556 OBoundControlModel::onDisconnectedDbColumn();
558 m_sDocumentURL
= OUString();
561 //------------------------------------------------------------------------------
562 Any
OImageControlModel::translateDbColumnToControlValue()
564 switch ( lcl_getImageStoreType( getFieldType() ) )
566 case ImageStoreBinary
:
568 Reference
< XInputStream
> xImageStream( m_xColumn
->getBinaryStream() );
569 if ( m_xColumn
->wasNull() )
570 xImageStream
.clear();
571 return makeAny( xImageStream
);
575 OUString
sImageLink( m_xColumn
->getString() );
576 if ( !m_sDocumentURL
.isEmpty() )
577 sImageLink
= INetURLObject::GetAbsURL( m_sDocumentURL
, sImageLink
);
578 return makeAny( sImageLink
);
580 case ImageStoreInvalid
:
581 OSL_FAIL( "OImageControlModel::translateDbColumnToControlValue: invalid field type!" );
587 //------------------------------------------------------------------------------
588 Any
OImageControlModel::getControlValue( ) const
590 return makeAny( m_sImageURL
);
593 //------------------------------------------------------------------------------
594 void OImageControlModel::doSetControlValue( const Any
& _rValue
)
596 DBG_ASSERT( GetImageProducer() && m_xImageProducer
.is(), "OImageControlModel::doSetControlValue: no image producer!" );
597 if ( !GetImageProducer() || !m_xImageProducer
.is() )
600 bool bStartProduction
= false;
601 switch ( lcl_getImageStoreType( getFieldType() ) )
603 case ImageStoreBinary
:
605 // give the image producer the stream
606 Reference
< XInputStream
> xInStream
;
607 _rValue
>>= xInStream
;
608 GetImageProducer()->setImage( xInStream
);
609 bStartProduction
= true;
616 _rValue
>>= sImageURL
;
617 GetImageProducer()->SetImage( sImageURL
);
618 bStartProduction
= true;
622 case ImageStoreInvalid
:
623 OSL_FAIL( "OImageControlModel::doSetControlValue: invalid field type!" );
626 } // switch ( lcl_getImageStoreType( getFieldType() ) )
628 if ( bStartProduction
)
631 Reference
< XImageProducer
> xProducer
= m_xImageProducer
;
633 // release our mutex once (it's acquired in the calling method!), as starting the image production may
634 // result in the locking of the solar mutex (unfortunally the default implementation of our aggregate,
635 // VCLXImageControl, does this locking)
636 MutexRelease
aRelease(m_aMutex
);
637 xProducer
->startProduction();
643 //------------------------------------------------------------------
644 void SAL_CALL
OImageControlModel::disposing()
646 OBoundControlModel::disposing();
649 //------------------------------------------------------------------------------
650 void OImageControlModel::resetNoBroadcast()
652 if ( hasField() ) // only reset when we are connected to a column
653 OBoundControlModel::resetNoBroadcast( );
656 //--------------------------------------------------------------------
657 Reference
< XImageProducer
> SAL_CALL
OImageControlModel::getImageProducer() throw ( RuntimeException
)
662 //--------------------------------------------------------------------
663 void SAL_CALL
OImageControlModel::addConsumer( const Reference
< XImageConsumer
>& _rxConsumer
) throw (RuntimeException
)
665 GetImageProducer()->addConsumer( _rxConsumer
);
668 //--------------------------------------------------------------------
669 void SAL_CALL
OImageControlModel::removeConsumer( const Reference
< XImageConsumer
>& _rxConsumer
) throw (RuntimeException
)
671 GetImageProducer()->removeConsumer( _rxConsumer
);
674 //--------------------------------------------------------------------
675 void SAL_CALL
OImageControlModel::startProduction( ) throw (RuntimeException
)
677 GetImageProducer()->startProduction();
680 //------------------------------------------------------------------------------
681 IMPL_LINK( OImageControlModel
, OnImageImportDone
, ::Graphic
*, i_pGraphic
)
683 const Reference
< XGraphic
> xGraphic( i_pGraphic
!= NULL
? Image( i_pGraphic
->GetBitmapEx() ).GetXGraphic() : NULL
);
684 m_bExternalGraphic
= false;
687 setPropertyValue( PROPERTY_GRAPHIC
, makeAny( xGraphic
) );
689 catch ( const Exception
& )
691 DBG_UNHANDLED_EXCEPTION();
693 m_bExternalGraphic
= true;
697 //==================================================================
698 // OImageControlControl
699 //==================================================================
701 //------------------------------------------------------------------
702 InterfaceRef SAL_CALL
OImageControlControl_CreateInstance(const Reference
<XMultiServiceFactory
>& _rxFactory
)
704 return *(new OImageControlControl(_rxFactory
));
707 //------------------------------------------------------------------------------
708 Sequence
<Type
> OImageControlControl::_getTypes()
710 return concatSequences(
711 OBoundControl::_getTypes(),
712 OImageControlControl_Base::getTypes()
716 //------------------------------------------------------------------------------
717 OImageControlControl::OImageControlControl(const Reference
<XMultiServiceFactory
>& _rxFactory
)
718 :OBoundControl(_rxFactory
, VCL_CONTROL_IMAGECONTROL
)
719 ,m_aModifyListeners( m_aMutex
)
721 increment(m_refCount
);
723 // Add as Focus- and MouseListener
724 Reference
< XWindow
> xComp
;
725 query_aggregation( m_xAggregate
, xComp
);
727 xComp
->addMouseListener( this );
729 decrement(m_refCount
);
732 //------------------------------------------------------------------------------
733 Any SAL_CALL
OImageControlControl::queryAggregation(const Type
& _rType
) throw (RuntimeException
)
735 Any aReturn
= OBoundControl::queryAggregation( _rType
);
736 if ( !aReturn
.hasValue() )
737 aReturn
= ::cppu::queryInterface(
739 static_cast< XMouseListener
* >( this ),
740 static_cast< XModifyBroadcaster
* >( this )
746 //------------------------------------------------------------------------------
747 StringSequence
OImageControlControl::getSupportedServiceNames() throw()
749 StringSequence aSupported
= OBoundControl::getSupportedServiceNames();
750 aSupported
.realloc(aSupported
.getLength() + 1);
752 OUString
*pArray
= aSupported
.getArray();
753 pArray
[aSupported
.getLength()-1] = FRM_SUN_CONTROL_IMAGECONTROL
;
757 //------------------------------------------------------------------------------
758 void SAL_CALL
OImageControlControl::addModifyListener( const Reference
< XModifyListener
>& _Listener
) throw (RuntimeException
)
760 m_aModifyListeners
.addInterface( _Listener
);
763 //------------------------------------------------------------------------------
764 void SAL_CALL
OImageControlControl::removeModifyListener( const Reference
< XModifyListener
>& _Listener
) throw (RuntimeException
)
766 m_aModifyListeners
.removeInterface( _Listener
);
769 //------------------------------------------------------------------------------
770 void SAL_CALL
OImageControlControl::disposing()
772 EventObject
aEvent( *this );
773 m_aModifyListeners
.disposeAndClear( aEvent
);
775 OBoundControl::disposing();
778 //------------------------------------------------------------------------------
779 void SAL_CALL
OImageControlControl::disposing( const EventObject
& _Event
) throw(RuntimeException
)
781 OBoundControl::disposing( _Event
);
784 //------------------------------------------------------------------------------
785 void OImageControlControl::implClearGraphics( sal_Bool _bForce
)
787 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
792 OUString sOldImageURL
;
793 xSet
->getPropertyValue( PROPERTY_IMAGE_URL
) >>= sOldImageURL
;
795 if ( sOldImageURL
.isEmpty() )
796 // the ImageURL is already empty, so simply setting a new empty one would not suffice
797 // (since it would be ignored)
798 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString( "private:emptyImage" ) ) );
799 // (the concrete URL we're passing here doens't matter. It's important that
800 // the model cannot resolve it to a a valid resource describing an image stream
803 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString() ) );
807 //------------------------------------------------------------------------------
808 bool OImageControlControl::implInsertGraphics()
810 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
814 OUString sTitle
= FRM_RES_STRING(RID_STR_IMPORT_GRAPHIC
);
815 // build some arguments for the upcoming dialog
818 ::sfx2::FileDialogHelper
aDialog( TemplateDescription::FILEOPEN_LINK_PREVIEW
, SFXWB_GRAPHIC
);
819 aDialog
.SetTitle( sTitle
);
821 Reference
< XFilePickerControlAccess
> xController( aDialog
.GetFilePicker(), UNO_QUERY_THROW
);
822 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
, 0, ::cppu::bool2any(sal_True
));
824 Reference
<XPropertySet
> xBoundField
;
825 if ( hasProperty( PROPERTY_BOUNDFIELD
, xSet
) )
826 xSet
->getPropertyValue( PROPERTY_BOUNDFIELD
) >>= xBoundField
;
827 sal_Bool bHasField
= xBoundField
.is();
829 // if the control is bound to a DB field, then it's not possible to decide whether or not to link
830 xController
->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK
, !bHasField
);
832 // if the control is bound to a DB field, then linking of the image depends on the type of the field
833 sal_Bool bImageIsLinked
= sal_True
;
836 sal_Int32 nFieldType
= DataType::OTHER
;
837 OSL_VERIFY( xBoundField
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
);
838 bImageIsLinked
= ( lcl_getImageStoreType( nFieldType
) == ImageStoreLink
);
840 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0, makeAny( bImageIsLinked
) );
842 if ( ERRCODE_NONE
== aDialog
.Execute() )
844 // reset the url property in case it already has the value we're about to set - in this case
845 // our propertyChanged would not get called without this.
846 implClearGraphics( sal_False
);
847 sal_Bool bIsLink
= sal_False
;
848 xController
->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0) >>= bIsLink
;
849 // Force bIsLink to be sal_True if we're bound to a field. Though we initialized the file picker with IsLink=TRUE
850 // in this case, and disabled the respective control, there might be picker implementations which do not
851 // respect this, and return IsLink=FALSE here. In this case, "normalize" the flag.
853 bIsLink
|= bHasField
;
857 aDialog
.GetGraphic( aGraphic
);
858 xSet
->setPropertyValue( PROPERTY_GRAPHIC
, makeAny( aGraphic
.GetXGraphic() ) );
861 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString( aDialog
.GetPath() ) ) );
866 catch(const Exception
&)
868 OSL_FAIL("OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!");
873 //------------------------------------------------------------------------------
874 bool OImageControlControl::impl_isEmptyGraphics_nothrow() const
876 bool bIsEmpty
= true;
880 Reference
< XPropertySet
> xModelProps( const_cast< OImageControlControl
* >( this )->getModel(), UNO_QUERY_THROW
);
881 Reference
< XGraphic
> xGraphic
;
882 OSL_VERIFY( xModelProps
->getPropertyValue( OUString( "Graphic" ) ) >>= xGraphic
);
883 bIsEmpty
= !xGraphic
.is();
885 catch( const Exception
& )
887 DBG_UNHANDLED_EXCEPTION();
894 //------------------------------------------------------------------------------
895 void OImageControlControl::mousePressed(const ::com::sun::star::awt::MouseEvent
& e
) throw ( ::com::sun::star::uno::RuntimeException
)
897 SolarMutexGuard aGuard
;
899 if (e
.Buttons
!= MouseButton::LEFT
)
902 bool bModified
= false;
903 // is this a request for a context menu?
904 if ( e
.PopupTrigger
)
906 Reference
< XPopupMenu
> xMenu( awt::PopupMenu::create( m_aContext
.getUNOContext() ) );
907 DBG_ASSERT( xMenu
.is(), "OImageControlControl::mousePressed: could not create a popup menu!" );
909 Reference
< XWindowPeer
> xWindowPeer
= getPeer();
910 DBG_ASSERT( xWindowPeer
.is(), "OImageControlControl::mousePressed: no window!" );
912 if ( xMenu
.is() && xWindowPeer
.is() )
914 xMenu
->insertItem( ID_OPEN_GRAPHICS
, FRM_RES_STRING( RID_STR_OPEN_GRAPHICS
), 0, 0 );
915 xMenu
->insertItem( ID_CLEAR_GRAPHICS
, FRM_RES_STRING( RID_STR_CLEAR_GRAPHICS
), 0, 1 );
917 // check if the ImageURL is empty
918 if ( impl_isEmptyGraphics_nothrow() )
919 xMenu
->enableItem( ID_CLEAR_GRAPHICS
, sal_False
);
921 awt::Rectangle
aRect( e
.X
, e
.Y
, 0, 0 );
922 if ( ( e
.X
< 0 ) || ( e
.Y
< 0 ) )
923 { // context menu triggered by keyboard
924 // position it in the center of the control
925 Reference
< XWindow
> xWindow( static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY
);
926 OSL_ENSURE( xWindow
.is(), "OImageControlControl::mousePressed: me not a window? How this?" );
929 awt::Rectangle aPosSize
= xWindow
->getPosSize();
930 aRect
.X
= aPosSize
.Width
/ 2;
931 aRect
.Y
= aPosSize
.Height
/ 2;
935 const sal_Int16 nResult
= xMenu
->execute( xWindowPeer
, aRect
, PopupMenuDirection::EXECUTE_DEFAULT
);
939 case ID_OPEN_GRAPHICS
:
940 implInsertGraphics();
944 case ID_CLEAR_GRAPHICS
:
945 implClearGraphics( sal_True
);
953 //////////////////////////////////////////////////////////////////////
955 if (e
.ClickCount
== 2)
958 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
962 // If the Control is not bound, do not display a dialog (because the to-be-sent URL would be invalid anyway)
963 Reference
<XPropertySet
> xBoundField
;
964 if (hasProperty(PROPERTY_BOUNDFIELD
, xSet
))
965 ::cppu::extractInterface(xBoundField
, xSet
->getPropertyValue(PROPERTY_BOUNDFIELD
));
966 if (!xBoundField
.is())
968 // but only if our IMAGE_URL property is handled as if it is transient, which is equivalent to
969 // an empty control source
970 if ( !hasProperty(PROPERTY_CONTROLSOURCE
, xSet
) || !::comphelper::getString(xSet
->getPropertyValue(PROPERTY_CONTROLSOURCE
)).isEmpty() )
974 sal_Bool bReadOnly
= false;
975 xSet
->getPropertyValue(PROPERTY_READONLY
) >>= bReadOnly
;
979 if ( implInsertGraphics() )
986 EventObject
aEvent( *this );
987 m_aModifyListeners
.notifyEach( &XModifyListener::modified
, aEvent
);
991 //------------------------------------------------------------------------------
992 void SAL_CALL
OImageControlControl::mouseReleased(const awt::MouseEvent
& /*e*/) throw ( RuntimeException
)
996 //------------------------------------------------------------------------------
997 void SAL_CALL
OImageControlControl::mouseEntered(const awt::MouseEvent
& /*e*/) throw ( RuntimeException
)
1001 //------------------------------------------------------------------------------
1002 void SAL_CALL
OImageControlControl::mouseExited(const awt::MouseEvent
& /*e*/) throw ( RuntimeException
)
1006 //.........................................................................
1008 //.........................................................................
1010 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */