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 <strings.hrc>
23 #include <frm_resource.hxx>
24 #include <property.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/form/FormComponentType.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/XFilePicker3.hpp>
37 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.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/graphic/XGraphic.hpp>
42 #include <com/sun/star/graphic/GraphicObject.hpp>
43 #include <tools/urlobj.hxx>
44 #include <tools/stream.hxx>
45 #include <tools/debug.hxx>
46 #include <tools/diagnose_ex.h>
47 #include <vcl/graph.hxx>
48 #include <vcl/svapp.hxx>
49 #include <unotools/streamhelper.hxx>
50 #include <comphelper/guarding.hxx>
51 #include <comphelper/property.hxx>
52 #include <comphelper/types.hxx>
53 #include <cppuhelper/queryinterface.hxx>
54 #include <unotools/ucbstreamhelper.hxx>
55 #include <svl/urihelper.hxx>
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::beans
;
70 using namespace ::com::sun::star::container
;
71 using namespace ::com::sun::star::form
;
72 using namespace ::com::sun::star::awt
;
73 using namespace ::com::sun::star::io
;
74 using namespace ::com::sun::star::ui::dialogs
;
75 using namespace ::com::sun::star::lang
;
76 using namespace ::com::sun::star::util
;
77 using namespace ::com::sun::star::graphic
;
78 using namespace ::com::sun::star::frame
;
81 //= OImageControlModel
93 ImageStoreType
lcl_getImageStoreType( const sal_Int32 _nFieldType
)
95 // binary/longvarchar types could be used to store images in binary representation
96 if ( ( _nFieldType
== DataType::BINARY
)
97 || ( _nFieldType
== DataType::VARBINARY
)
98 || ( _nFieldType
== DataType::LONGVARBINARY
)
99 || ( _nFieldType
== DataType::OTHER
)
100 || ( _nFieldType
== DataType::OBJECT
)
101 || ( _nFieldType
== DataType::BLOB
)
102 || ( _nFieldType
== DataType::LONGVARCHAR
)
103 || ( _nFieldType
== DataType::CLOB
)
105 return ImageStoreBinary
;
107 // char types could be used to store links to images
108 if ( ( _nFieldType
== DataType::CHAR
)
109 || ( _nFieldType
== DataType::VARCHAR
)
111 return ImageStoreLink
;
113 return ImageStoreInvalid
;
118 // OImageControlModel
120 Sequence
<Type
> OImageControlModel::_getTypes()
122 return concatSequences(
123 OBoundControlModel::_getTypes(),
124 OImageControlModel_Base::getTypes()
129 OImageControlModel::OImageControlModel(const Reference
<XComponentContext
>& _rxFactory
)
130 :OBoundControlModel( _rxFactory
, VCL_CONTROLMODEL_IMAGECONTROL
, FRM_SUN_CONTROL_IMAGECONTROL
, false, false, false )
131 // use the old control name for compytibility reasons
132 ,m_bExternalGraphic( true )
133 ,m_bReadOnly( false )
137 m_nClassId
= FormComponentType::IMAGECONTROL
;
138 initOwnValueProperty( PROPERTY_IMAGE_URL
);
144 OImageControlModel::OImageControlModel( const OImageControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
)
145 :OBoundControlModel( _pOriginal
, _rxFactory
)
146 // use the old control name for compytibility reasons
147 ,m_bExternalGraphic( true )
148 ,m_bReadOnly( _pOriginal
->m_bReadOnly
)
149 ,m_sImageURL( _pOriginal
->m_sImageURL
)
150 ,m_xGraphicObject( _pOriginal
->m_xGraphicObject
)
154 osl_atomic_increment( &m_refCount
);
156 // simulate a propertyChanged event for the ImageURL
157 ::osl::MutexGuard
aGuard( m_aMutex
);
158 impl_handleNewImageURL_lck( eOther
);
160 osl_atomic_decrement( &m_refCount
);
164 void OImageControlModel::implConstruct()
166 m_xImageProducer
= new ImageProducer
;
167 m_xImageProducer
->SetDoneHdl( LINK( this, OImageControlModel
, OnImageImportDone
) );
171 OImageControlModel::~OImageControlModel()
173 if (!OComponentHelper::rBHelper
.bDisposed
)
183 IMPLEMENT_DEFAULT_CLONING( OImageControlModel
)
187 css::uno::Sequence
<OUString
> OImageControlModel::getSupportedServiceNames()
189 css::uno::Sequence
<OUString
> aSupported
= OBoundControlModel::getSupportedServiceNames();
190 aSupported
.realloc(aSupported
.getLength() + 2);
192 OUString
*pArray
= aSupported
.getArray();
193 pArray
[aSupported
.getLength()-2] = FRM_SUN_COMPONENT_IMAGECONTROL
;
194 pArray
[aSupported
.getLength()-1] = FRM_COMPONENT_IMAGECONTROL
;
199 Any SAL_CALL
OImageControlModel::queryAggregation(const Type
& _rType
)
201 // Order matters: we want to "override" the XImageProducer interface of the aggregate without
202 // own XImageProducer interface, thus we need to query OImageControlModel_Base first
203 Any aReturn
= OImageControlModel_Base::queryInterface( _rType
);
205 // BUT: _don't_ let it feel responsible for the XTypeProvider interface
206 // (as this is implemented by our base class in the proper way)
207 if ( _rType
.equals( cppu::UnoType
<XTypeProvider
>::get() )
208 || !aReturn
.hasValue()
210 aReturn
= OBoundControlModel::queryAggregation( _rType
);
216 bool OImageControlModel::approveDbColumnType( sal_Int32 _nColumnType
)
218 return ImageStoreInvalid
!= lcl_getImageStoreType( _nColumnType
);
222 void OImageControlModel::getFastPropertyValue(Any
& rValue
, sal_Int32 nHandle
) const
226 case PROPERTY_ID_READONLY
:
227 rValue
<<= m_bReadOnly
;
229 case PROPERTY_ID_IMAGE_URL
:
230 rValue
<<= m_sImageURL
;
232 case PROPERTY_ID_GRAPHIC
:
233 rValue
<<= m_xGraphicObject
.is() ? m_xGraphicObject
->getGraphic() : Reference
< XGraphic
>();
236 OBoundControlModel::getFastPropertyValue(rValue
, nHandle
);
241 void OImageControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle
, const Any
& rValue
)
245 case PROPERTY_ID_READONLY
:
246 DBG_ASSERT(rValue
.getValueType().getTypeClass() == TypeClass_BOOLEAN
, "OImageControlModel::setFastPropertyValue_NoBroadcast : invalid type !" );
247 m_bReadOnly
= getBOOL(rValue
);
250 case PROPERTY_ID_IMAGE_URL
:
251 OSL_VERIFY( rValue
>>= m_sImageURL
);
252 impl_handleNewImageURL_lck( eOther
);
254 ControlModelLock
aLock( *this );
255 // that's a fake ... onValuePropertyChange expects to receive the only lock to our instance,
256 // but we're already called with our mutex locked ...
257 onValuePropertyChange( aLock
);
261 case PROPERTY_ID_GRAPHIC
:
263 Reference
< XGraphic
> xGraphic
;
264 OSL_VERIFY( rValue
>>= xGraphic
);
265 if ( !xGraphic
.is() )
266 m_xGraphicObject
.clear();
269 m_xGraphicObject
= graphic::GraphicObject::create( m_xContext
);
270 m_xGraphicObject
->setGraphic( xGraphic
);
273 if ( m_bExternalGraphic
)
275 m_sImageURL
= OUString();
276 // TODO: speaking strictly, this would need to be notified, since ImageURL is a bound property. However,
277 // this method here is called with a locked mutex, so we cannot simply call listeners ...
278 // I think the missing notification (and thus clients which potentially cannot observe the change)
279 // is less severe than the potential deadlock ...
285 OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
291 sal_Bool
OImageControlModel::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
295 case PROPERTY_ID_READONLY
:
296 return tryPropertyValue(rConvertedValue
, rOldValue
, rValue
, m_bReadOnly
);
298 case PROPERTY_ID_IMAGE_URL
:
299 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_sImageURL
);
301 case PROPERTY_ID_GRAPHIC
:
303 const Reference
< XGraphic
> xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC
), UNO_QUERY
);
304 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, xGraphic
);
308 return OBoundControlModel::convertFastPropertyValue(rConvertedValue
, rOldValue
, nHandle
, rValue
);
313 void OImageControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
315 BEGIN_DESCRIBE_PROPERTIES( 4, OBoundControlModel
)
316 DECL_IFACE_PROP2( GRAPHIC
, XGraphic
, BOUND
, TRANSIENT
);
317 DECL_PROP1 ( IMAGE_URL
, OUString
, BOUND
);
318 DECL_BOOL_PROP1 ( READONLY
, BOUND
);
319 DECL_PROP1 ( TABINDEX
, sal_Int16
, BOUND
);
320 END_DESCRIBE_PROPERTIES();
324 void OImageControlModel::describeAggregateProperties( Sequence
< Property
>& /* [out] */ o_rAggregateProperties
) const
326 OBoundControlModel::describeAggregateProperties( o_rAggregateProperties
);
327 // remove ImageURL and Graphic properties, we "override" them.
328 // This is because our aggregate synchronizes those
329 // two, but we have an own synchronization mechanism.
330 RemoveProperty( o_rAggregateProperties
, PROPERTY_IMAGE_URL
);
331 RemoveProperty( o_rAggregateProperties
, PROPERTY_GRAPHIC
);
335 OUString
OImageControlModel::getServiceName()
337 return FRM_COMPONENT_IMAGECONTROL
; // old (non-sun) name for compatibility !
341 void OImageControlModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
)
344 OBoundControlModel::write(_rxOutStream
);
346 _rxOutStream
->writeShort(0x0003);
348 _rxOutStream
->writeBoolean(m_bReadOnly
);
349 writeHelpTextCompatibly(_rxOutStream
);
350 // from version 0x0003 : common properties
351 writeCommonProperties(_rxOutStream
);
355 void OImageControlModel::read(const Reference
<XObjectInputStream
>& _rxInStream
)
357 OBoundControlModel::read(_rxInStream
);
360 sal_uInt16 nVersion
= _rxInStream
->readShort();
364 m_bReadOnly
= _rxInStream
->readBoolean();
367 m_bReadOnly
= _rxInStream
->readBoolean();
368 readHelpTextCompatibly(_rxInStream
);
371 m_bReadOnly
= _rxInStream
->readBoolean();
372 readHelpTextCompatibly(_rxInStream
);
373 readCommonProperties(_rxInStream
);
376 OSL_FAIL("OImageControlModel::read : unknown version !");
378 defaultCommonProperties();
381 // Display default values after read
382 if ( !getControlSource().isEmpty() )
383 { // (not if we don't have a control source - the "State" property acts like it is persistent, then
384 ::osl::MutexGuard
aGuard(m_aMutex
); // resetNoBroadcast expects this mutex guarding
390 bool OImageControlModel::impl_updateStreamForURL_lck( const OUString
& _rURL
, ValueChangeInstigator _eInstigator
)
392 // create a stream for the image specified by the URL
393 std::unique_ptr
< SvStream
> pImageStream
;
394 Reference
< XInputStream
> xImageStream
;
396 if ( ::svt::GraphicAccess::isSupportedURL( _rURL
) )
398 xImageStream
= ::svt::GraphicAccess::getImageXStream( getContext(), _rURL
);
402 pImageStream
= ::utl::UcbStreamHelper::CreateStream( _rURL
, StreamMode::READ
);
403 bool bSetNull
= (pImageStream
== nullptr) || (ERRCODE_NONE
!= pImageStream
->GetErrorCode());
407 // get the size of the stream
408 sal_uInt64
const nSize
= pImageStream
->remainingSize();
409 if (pImageStream
->GetBufferSize() < 8192)
410 pImageStream
->SetBufferSize(8192);
411 pImageStream
->Seek(STREAM_SEEK_TO_BEGIN
);
413 xImageStream
= new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream
.get(), false ), nSize
);
417 if ( xImageStream
.is() )
419 if ( m_xColumnUpdate
.is() )
420 m_xColumnUpdate
->updateBinaryStream( xImageStream
, xImageStream
->available() );
422 setControlValue( makeAny( xImageStream
), _eInstigator
);
423 xImageStream
->closeInput();
431 void OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator
)
433 switch ( lcl_getImageStoreType( getFieldType() ) )
435 case ImageStoreBinary
:
436 if ( impl_updateStreamForURL_lck( m_sImageURL
, _eInstigator
) )
442 OUString
sCommitURL( m_sImageURL
);
443 if ( !m_sDocumentURL
.isEmpty() )
444 sCommitURL
= URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL
, sCommitURL
);
445 OSL_ENSURE( m_xColumnUpdate
.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" );
446 if ( m_xColumnUpdate
.is() )
448 m_xColumnUpdate
->updateString( sCommitURL
);
454 case ImageStoreInvalid
:
455 OSL_FAIL( "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" );
459 // if we're here, then the above code was unable to update our field/control from the given URL
460 // => fall back to NULL/VOID
461 if ( m_xColumnUpdate
.is() )
462 m_xColumnUpdate
->updateNull();
464 setControlValue( Any(), _eInstigator
);
468 bool OImageControlModel::commitControlValueToDbColumn( bool _bPostReset
)
472 // since this is a "commit after reset", we can simply update the column
473 // with null - this is our "default" which we were just reset to
474 if ( m_xColumnUpdate
.is() )
475 m_xColumnUpdate
->updateNull();
479 ::osl::MutexGuard
aGuard(m_aMutex
);
480 impl_handleNewImageURL_lck( eDbColumnBinding
);
489 bool lcl_isValidDocumentURL( const OUString
& _rDocURL
)
491 return ( !_rDocURL
.isEmpty() && _rDocURL
!= "private:object" );
496 void OImageControlModel::onConnectedDbColumn( const Reference
< XInterface
>& _rxForm
)
498 OBoundControlModel::onConnectedDbColumn( _rxForm
);
502 Reference
< XModel
> xDocument( getXModel( *this ) );
503 if ( xDocument
.is() )
505 m_sDocumentURL
= xDocument
->getURL();
506 if ( !lcl_isValidDocumentURL( m_sDocumentURL
) )
508 Reference
< XChild
> xAsChild( xDocument
, UNO_QUERY
);
509 while ( xAsChild
.is() && !lcl_isValidDocumentURL( m_sDocumentURL
) )
511 xDocument
.set( xAsChild
->getParent(), UNO_QUERY
);
512 if ( xDocument
.is() )
513 m_sDocumentURL
= xDocument
->getURL();
514 xAsChild
.set( xDocument
, UNO_QUERY
);
519 catch( const Exception
& )
521 DBG_UNHANDLED_EXCEPTION("forms.component");
526 void OImageControlModel::onDisconnectedDbColumn()
528 OBoundControlModel::onDisconnectedDbColumn();
530 m_sDocumentURL
.clear();
534 Any
OImageControlModel::translateDbColumnToControlValue()
536 switch ( lcl_getImageStoreType( getFieldType() ) )
538 case ImageStoreBinary
:
540 Reference
< XInputStream
> xImageStream( m_xColumn
->getBinaryStream() );
541 if ( m_xColumn
->wasNull() )
542 xImageStream
.clear();
543 return makeAny( xImageStream
);
547 OUString
sImageLink( m_xColumn
->getString() );
548 if ( !m_sDocumentURL
.isEmpty() )
549 sImageLink
= INetURLObject::GetAbsURL( m_sDocumentURL
, sImageLink
);
550 return makeAny( sImageLink
);
552 case ImageStoreInvalid
:
553 OSL_FAIL( "OImageControlModel::translateDbColumnToControlValue: invalid field type!" );
560 Any
OImageControlModel::getControlValue( ) const
562 return makeAny( m_sImageURL
);
566 void OImageControlModel::doSetControlValue( const Any
& _rValue
)
568 DBG_ASSERT( GetImageProducer() && m_xImageProducer
.is(), "OImageControlModel::doSetControlValue: no image producer!" );
569 if ( !GetImageProducer() || !m_xImageProducer
.is() )
572 bool bStartProduction
= false;
573 switch ( lcl_getImageStoreType( getFieldType() ) )
575 case ImageStoreBinary
:
577 // give the image producer the stream
578 Reference
< XInputStream
> xInStream
;
579 _rValue
>>= xInStream
;
580 GetImageProducer()->setImage( xInStream
);
581 bStartProduction
= true;
588 _rValue
>>= sImageURL
;
589 GetImageProducer()->SetImage( sImageURL
);
590 bStartProduction
= true;
594 case ImageStoreInvalid
:
595 OSL_FAIL( "OImageControlModel::doSetControlValue: invalid field type!" );
598 } // switch ( lcl_getImageStoreType( getFieldType() ) )
600 if ( bStartProduction
)
603 rtl::Reference
< ImageProducer
> xProducer
= m_xImageProducer
;
605 // release our mutex once (it's acquired in the calling method!), as starting the image production may
606 // result in the locking of the solar mutex (unfortunately the default implementation of our aggregate,
607 // VCLXImageControl, does this locking)
608 MutexRelease
aRelease(m_aMutex
);
609 xProducer
->startProduction();
614 void OImageControlModel::resetNoBroadcast()
616 if ( hasField() ) // only reset when we are connected to a column
617 OBoundControlModel::resetNoBroadcast( );
621 Reference
< XImageProducer
> SAL_CALL
OImageControlModel::getImageProducer()
627 void SAL_CALL
OImageControlModel::addConsumer( const Reference
< XImageConsumer
>& _rxConsumer
)
629 GetImageProducer()->addConsumer( _rxConsumer
);
633 void SAL_CALL
OImageControlModel::removeConsumer( const Reference
< XImageConsumer
>& _rxConsumer
)
635 GetImageProducer()->removeConsumer( _rxConsumer
);
639 void SAL_CALL
OImageControlModel::startProduction( )
641 GetImageProducer()->startProduction();
645 IMPL_LINK( OImageControlModel
, OnImageImportDone
, ::Graphic
*, i_pGraphic
, void )
647 const Reference
< XGraphic
> xGraphic(i_pGraphic
!= nullptr ? i_pGraphic
->GetXGraphic() : nullptr);
648 m_bExternalGraphic
= false;
651 setPropertyValue( PROPERTY_GRAPHIC
, makeAny( xGraphic
) );
653 catch ( const Exception
& )
655 DBG_UNHANDLED_EXCEPTION("forms.component");
657 m_bExternalGraphic
= true;
661 // OImageControlControl
663 Sequence
<Type
> OImageControlControl::_getTypes()
665 return concatSequences(
666 OBoundControl::_getTypes(),
667 OImageControlControl_Base::getTypes()
672 OImageControlControl::OImageControlControl(const Reference
<XComponentContext
>& _rxFactory
)
673 :OBoundControl(_rxFactory
, VCL_CONTROL_IMAGECONTROL
)
674 ,m_aModifyListeners( m_aMutex
)
676 osl_atomic_increment(&m_refCount
);
678 // Add as Focus- and MouseListener
679 Reference
< XWindow
> xComp
;
680 query_aggregation( m_xAggregate
, xComp
);
682 xComp
->addMouseListener( this );
684 osl_atomic_decrement(&m_refCount
);
688 Any SAL_CALL
OImageControlControl::queryAggregation(const Type
& _rType
)
690 Any aReturn
= OBoundControl::queryAggregation( _rType
);
691 if ( !aReturn
.hasValue() )
692 aReturn
= ::cppu::queryInterface(
694 static_cast< XMouseListener
* >( this ),
695 static_cast< XModifyBroadcaster
* >( this )
702 css::uno::Sequence
<OUString
> OImageControlControl::getSupportedServiceNames()
704 css::uno::Sequence
<OUString
> aSupported
= OBoundControl::getSupportedServiceNames();
705 aSupported
.realloc(aSupported
.getLength() + 2);
707 OUString
*pArray
= aSupported
.getArray();
708 pArray
[aSupported
.getLength()-2] = FRM_SUN_CONTROL_IMAGECONTROL
;
709 pArray
[aSupported
.getLength()-1] = STARDIV_ONE_FORM_CONTROL_IMAGECONTROL
;
714 void SAL_CALL
OImageControlControl::addModifyListener( const Reference
< XModifyListener
>& Listener
)
716 m_aModifyListeners
.addInterface( Listener
);
720 void SAL_CALL
OImageControlControl::removeModifyListener( const Reference
< XModifyListener
>& Listener
)
722 m_aModifyListeners
.removeInterface( Listener
);
726 void SAL_CALL
OImageControlControl::disposing()
728 EventObject
aEvent( *this );
729 m_aModifyListeners
.disposeAndClear( aEvent
);
731 OBoundControl::disposing();
735 void SAL_CALL
OImageControlControl::disposing( const EventObject
& Event
)
737 OBoundControl::disposing( Event
);
741 void OImageControlControl::implClearGraphics( bool _bForce
)
743 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
749 OUString sOldImageURL
;
750 xSet
->getPropertyValue( PROPERTY_IMAGE_URL
) >>= sOldImageURL
;
752 if ( sOldImageURL
.isEmpty() )
753 // the ImageURL is already empty, so simply setting a new empty one would not suffice
754 // (since it would be ignored)
755 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString( "private:emptyImage" ) ) );
756 // (the concrete URL we're passing here doesn't matter. It's important that
757 // the model cannot resolve it to a valid resource describing an image stream
760 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( OUString() ) );
764 bool OImageControlControl::implInsertGraphics()
766 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
770 OUString sTitle
= FRM_RES_STRING(RID_STR_IMPORT_GRAPHIC
);
771 // build some arguments for the upcoming dialog
774 Reference
< XWindow
> xWindow( static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY
);
775 ::sfx2::FileDialogHelper
aDialog(TemplateDescription::FILEOPEN_LINK_PREVIEW
, FileDialogFlags::Graphic
,
776 Application::GetFrameWeld(xWindow
));
777 aDialog
.SetTitle( sTitle
);
779 Reference
< XFilePickerControlAccess
> xController( aDialog
.GetFilePicker(), UNO_QUERY_THROW
);
780 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
, 0, css::uno::Any(true));
782 Reference
<XPropertySet
> xBoundField
;
783 if ( hasProperty( PROPERTY_BOUNDFIELD
, xSet
) )
784 xSet
->getPropertyValue( PROPERTY_BOUNDFIELD
) >>= xBoundField
;
785 bool bHasField
= xBoundField
.is();
787 // if the control is bound to a DB field, then it's not possible to decide whether or not to link
788 xController
->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK
, !bHasField
);
790 // if the control is bound to a DB field, then linking of the image depends on the type of the field
791 bool bImageIsLinked
= true;
794 sal_Int32 nFieldType
= DataType::OTHER
;
795 OSL_VERIFY( xBoundField
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
);
796 bImageIsLinked
= ( lcl_getImageStoreType( nFieldType
) == ImageStoreLink
);
798 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0, makeAny( bImageIsLinked
) );
800 if ( ERRCODE_NONE
== aDialog
.Execute() )
802 // reset the url property in case it already has the value we're about to set - in this case
803 // our propertyChanged would not get called without this.
804 implClearGraphics( false );
805 bool bIsLink
= false;
806 xController
->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0) >>= bIsLink
;
807 // Force bIsLink to be sal_True if we're bound to a field. Though we initialized the file picker with IsLink=TRUE
808 // in this case, and disabled the respective control, there might be picker implementations which do not
809 // respect this, and return IsLink=FALSE here. In this case, "normalize" the flag.
811 bIsLink
|= bHasField
;
815 aDialog
.GetGraphic( aGraphic
);
816 xSet
->setPropertyValue( PROPERTY_GRAPHIC
, makeAny( aGraphic
.GetXGraphic() ) );
819 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, makeAny( aDialog
.GetPath() ) );
824 catch(const Exception
&)
826 OSL_FAIL("OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!");
832 bool OImageControlControl::impl_isEmptyGraphics_nothrow() const
834 bool bIsEmpty
= true;
838 Reference
< XPropertySet
> xModelProps( const_cast< OImageControlControl
* >( this )->getModel(), UNO_QUERY_THROW
);
839 Reference
< XGraphic
> xGraphic
;
840 OSL_VERIFY( xModelProps
->getPropertyValue("Graphic") >>= xGraphic
);
841 bIsEmpty
= !xGraphic
.is();
843 catch( const Exception
& )
845 DBG_UNHANDLED_EXCEPTION("forms.component");
853 void OImageControlControl::mousePressed(const css::awt::MouseEvent
& e
)
855 SolarMutexGuard aGuard
;
857 if (e
.Buttons
!= MouseButton::LEFT
)
860 bool bModified
= false;
861 // is this a request for a context menu?
862 if ( e
.PopupTrigger
)
864 Reference
< XPopupMenu
> xMenu( awt::PopupMenu::create( m_xContext
) );
865 DBG_ASSERT( xMenu
.is(), "OImageControlControl::mousePressed: could not create a popup menu!" );
867 Reference
< XWindowPeer
> xWindowPeer
= getPeer();
868 DBG_ASSERT( xWindowPeer
.is(), "OImageControlControl::mousePressed: no window!" );
870 if ( xMenu
.is() && xWindowPeer
.is() )
872 xMenu
->insertItem( ID_OPEN_GRAPHICS
, FRM_RES_STRING( RID_STR_OPEN_GRAPHICS
), 0, 0 );
873 xMenu
->insertItem( ID_CLEAR_GRAPHICS
, FRM_RES_STRING( RID_STR_CLEAR_GRAPHICS
), 0, 1 );
875 // check if the ImageURL is empty
876 if ( impl_isEmptyGraphics_nothrow() )
877 xMenu
->enableItem( ID_CLEAR_GRAPHICS
, false );
879 awt::Rectangle
aRect( e
.X
, e
.Y
, 0, 0 );
880 if ( ( e
.X
< 0 ) || ( e
.Y
< 0 ) )
881 { // context menu triggered by keyboard
882 // position it in the center of the control
883 Reference
< XWindow
> xWindow( static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY
);
884 OSL_ENSURE( xWindow
.is(), "OImageControlControl::mousePressed: me not a window? How this?" );
887 awt::Rectangle aPosSize
= xWindow
->getPosSize();
888 aRect
.X
= aPosSize
.Width
/ 2;
889 aRect
.Y
= aPosSize
.Height
/ 2;
893 const sal_Int16 nResult
= xMenu
->execute( xWindowPeer
, aRect
, PopupMenuDirection::EXECUTE_DEFAULT
);
897 case ID_OPEN_GRAPHICS
:
898 implInsertGraphics();
902 case ID_CLEAR_GRAPHICS
:
903 implClearGraphics( true );
913 if (e
.ClickCount
== 2)
916 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
920 // If the Control is not bound, do not display a dialog (because the to-be-sent URL would be invalid anyway)
921 Reference
<XPropertySet
> xBoundField
;
922 if (hasProperty(PROPERTY_BOUNDFIELD
, xSet
))
924 xSet
->getPropertyValue(PROPERTY_BOUNDFIELD
),
925 css::uno::UNO_QUERY
);
926 if (!xBoundField
.is())
928 // but only if our IMAGE_URL property is handled as if it is transient, which is equivalent to
929 // an empty control source
930 if ( !hasProperty(PROPERTY_CONTROLSOURCE
, xSet
) || !::comphelper::getString(xSet
->getPropertyValue(PROPERTY_CONTROLSOURCE
)).isEmpty() )
934 bool bReadOnly
= false;
935 xSet
->getPropertyValue(PROPERTY_READONLY
) >>= bReadOnly
;
939 if ( implInsertGraphics() )
946 EventObject
aEvent( *this );
947 m_aModifyListeners
.notifyEach( &XModifyListener::modified
, aEvent
);
952 void SAL_CALL
OImageControlControl::mouseReleased(const awt::MouseEvent
& /*e*/)
957 void SAL_CALL
OImageControlControl::mouseEntered(const awt::MouseEvent
& /*e*/)
962 void SAL_CALL
OImageControlControl::mouseExited(const awt::MouseEvent
& /*e*/)
968 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
969 com_sun_star_form_OImageControlModel_get_implementation(css::uno::XComponentContext
* component
,
970 css::uno::Sequence
<css::uno::Any
> const &)
972 return cppu::acquire(new frm::OImageControlModel(component
));
975 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
976 com_sun_star_form_OImageControlControl_get_implementation(css::uno::XComponentContext
* component
,
977 css::uno::Sequence
<css::uno::Any
> const &)
979 return cppu::acquire(new frm::OImageControlControl(component
));
982 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */