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/beans/PropertyAttribute.hpp>
34 #include <com/sun/star/form/FormComponentType.hpp>
35 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
36 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
37 #include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
38 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
39 #include <com/sun/star/sdbc/DataType.hpp>
40 #include <com/sun/star/awt/MouseButton.hpp>
41 #include <com/sun/star/awt/XWindow.hpp>
42 #include <com/sun/star/graphic/XGraphic.hpp>
43 #include <com/sun/star/graphic/GraphicObject.hpp>
44 #include <tools/urlobj.hxx>
45 #include <tools/stream.hxx>
46 #include <tools/debug.hxx>
47 #include <comphelper/diagnose_ex.hxx>
48 #include <vcl/graph.hxx>
49 #include <vcl/svapp.hxx>
50 #include <unotools/streamhelper.hxx>
51 #include <comphelper/guarding.hxx>
52 #include <comphelper/property.hxx>
53 #include <comphelper/types.hxx>
54 #include <cppuhelper/queryinterface.hxx>
55 #include <unotools/ucbstreamhelper.hxx>
56 #include <svl/urihelper.hxx>
60 #define ID_OPEN_GRAPHICS 1
61 #define ID_CLEAR_GRAPHICS 2
66 using namespace ::com::sun::star
;
67 using namespace ::com::sun::star::uno
;
68 using namespace ::com::sun::star::sdb
;
69 using namespace ::com::sun::star::sdbc
;
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_bExternalGraphic( true )
134 ,m_bReadOnly( false )
136 m_nClassId
= FormComponentType::IMAGECONTROL
;
137 initOwnValueProperty( PROPERTY_IMAGE_URL
);
143 OImageControlModel::OImageControlModel( const OImageControlModel
* _pOriginal
, const Reference
< XComponentContext
>& _rxFactory
)
144 :OBoundControlModel( _pOriginal
, _rxFactory
)
145 // use the old control name for compytibility reasons
146 ,m_bExternalGraphic( true )
147 ,m_bReadOnly( _pOriginal
->m_bReadOnly
)
148 ,m_sImageURL( _pOriginal
->m_sImageURL
)
149 ,m_xGraphicObject( _pOriginal
->m_xGraphicObject
)
153 osl_atomic_increment( &m_refCount
);
155 // simulate a propertyChanged event for the ImageURL
156 ::osl::MutexGuard
aGuard( m_aMutex
);
157 impl_handleNewImageURL_lck( eOther
);
159 osl_atomic_decrement( &m_refCount
);
163 void OImageControlModel::implConstruct()
165 m_xImageProducer
= new ImageProducer
;
166 m_xImageProducer
->SetDoneHdl( LINK( this, OImageControlModel
, OnImageImportDone
) );
170 OImageControlModel::~OImageControlModel()
172 if (!OComponentHelper::rBHelper
.bDisposed
)
182 css::uno::Reference
< css::util::XCloneable
> SAL_CALL
OImageControlModel::createClone()
184 rtl::Reference
<OImageControlModel
> pClone
= new OImageControlModel(this, getContext());
185 pClone
->clonedFrom(this);
191 css::uno::Sequence
<OUString
> OImageControlModel::getSupportedServiceNames()
193 css::uno::Sequence
<OUString
> 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
)
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
)
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 m_sImageURL
= OUString();
280 // TODO: speaking strictly, this would need to be notified, since ImageURL is a bound property. However,
281 // this method here is called with a locked mutex, so we cannot simply call listeners ...
282 // I think the missing notification (and thus clients which potentially cannot observe the change)
283 // is less severe than the potential deadlock ...
289 OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle
, rValue
);
295 sal_Bool
OImageControlModel::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
299 case PROPERTY_ID_READONLY
:
300 return tryPropertyValue(rConvertedValue
, rOldValue
, rValue
, m_bReadOnly
);
302 case PROPERTY_ID_IMAGE_URL
:
303 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_sImageURL
);
305 case PROPERTY_ID_GRAPHIC
:
307 const Reference
< XGraphic
> xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC
), UNO_QUERY
);
308 return tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, xGraphic
);
312 return OBoundControlModel::convertFastPropertyValue(rConvertedValue
, rOldValue
, nHandle
, rValue
);
317 void OImageControlModel::describeFixedProperties( Sequence
< Property
>& _rProps
) const
319 OBoundControlModel::describeFixedProperties( _rProps
);
320 sal_Int32 nOldCount
= _rProps
.getLength();
321 _rProps
.realloc( nOldCount
+ 4);
322 css::beans::Property
* pProperties
= _rProps
.getArray() + nOldCount
;
323 *pProperties
++ = css::beans::Property(PROPERTY_GRAPHIC
, PROPERTY_ID_GRAPHIC
, cppu::UnoType
<XGraphic
>::get(),
324 css::beans::PropertyAttribute::BOUND
| css::beans::PropertyAttribute::TRANSIENT
);
325 *pProperties
++ = css::beans::Property(PROPERTY_IMAGE_URL
, PROPERTY_ID_IMAGE_URL
, cppu::UnoType
<OUString
>::get(), css::beans::PropertyAttribute::BOUND
);
326 *pProperties
++ = css::beans::Property(PROPERTY_READONLY
, PROPERTY_ID_READONLY
, cppu::UnoType
<bool>::get(),
327 css::beans::PropertyAttribute::BOUND
);
328 *pProperties
++ = css::beans::Property(PROPERTY_TABINDEX
, PROPERTY_ID_TABINDEX
, cppu::UnoType
<sal_Int16
>::get(), css::beans::PropertyAttribute::BOUND
);
329 DBG_ASSERT( pProperties
== _rProps
.getArray() + _rProps
.getLength(), "<...>::describeFixedProperties/getInfoHelper: forgot to adjust the count ?");
333 void OImageControlModel::describeAggregateProperties( Sequence
< Property
>& /* [out] */ o_rAggregateProperties
) const
335 OBoundControlModel::describeAggregateProperties( o_rAggregateProperties
);
336 // remove ImageURL and Graphic properties, we "override" them.
337 // This is because our aggregate synchronizes those
338 // two, but we have an own synchronization mechanism.
339 RemoveProperty( o_rAggregateProperties
, PROPERTY_IMAGE_URL
);
340 RemoveProperty( o_rAggregateProperties
, PROPERTY_GRAPHIC
);
344 OUString
OImageControlModel::getServiceName()
346 return FRM_COMPONENT_IMAGECONTROL
; // old (non-sun) name for compatibility !
350 void OImageControlModel::write(const Reference
<XObjectOutputStream
>& _rxOutStream
)
353 OBoundControlModel::write(_rxOutStream
);
355 _rxOutStream
->writeShort(0x0003);
357 _rxOutStream
->writeBoolean(m_bReadOnly
);
358 writeHelpTextCompatibly(_rxOutStream
);
359 // from version 0x0003 : common properties
360 writeCommonProperties(_rxOutStream
);
364 void OImageControlModel::read(const Reference
<XObjectInputStream
>& _rxInStream
)
366 OBoundControlModel::read(_rxInStream
);
369 sal_uInt16 nVersion
= _rxInStream
->readShort();
373 m_bReadOnly
= _rxInStream
->readBoolean();
376 m_bReadOnly
= _rxInStream
->readBoolean();
377 readHelpTextCompatibly(_rxInStream
);
380 m_bReadOnly
= _rxInStream
->readBoolean();
381 readHelpTextCompatibly(_rxInStream
);
382 readCommonProperties(_rxInStream
);
385 OSL_FAIL("OImageControlModel::read : unknown version !");
387 defaultCommonProperties();
390 // Display default values after read
391 if ( !getControlSource().isEmpty() )
392 { // (not if we don't have a control source - the "State" property acts like it is persistent, then
393 ::osl::MutexGuard
aGuard(m_aMutex
); // resetNoBroadcast expects this mutex guarding
399 bool OImageControlModel::impl_updateStreamForURL_lck( const OUString
& _rURL
, ValueChangeInstigator _eInstigator
)
401 // create a stream for the image specified by the URL
402 std::unique_ptr
< SvStream
> pImageStream
;
403 Reference
< XInputStream
> xImageStream
;
405 if ( ::svt::GraphicAccess::isSupportedURL( _rURL
) )
407 xImageStream
= ::svt::GraphicAccess::getImageXStream( getContext(), _rURL
);
411 pImageStream
= ::utl::UcbStreamHelper::CreateStream( _rURL
, StreamMode::READ
);
412 bool bSetNull
= (pImageStream
== nullptr) || (ERRCODE_NONE
!= pImageStream
->GetErrorCode());
416 // get the size of the stream
417 sal_uInt64
const nSize
= pImageStream
->remainingSize();
418 if (pImageStream
->GetBufferSize() < 8192)
419 pImageStream
->SetBufferSize(8192);
420 pImageStream
->Seek(STREAM_SEEK_TO_BEGIN
);
422 xImageStream
= new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream
.get(), false ), nSize
);
426 if ( xImageStream
.is() )
428 if ( m_xColumnUpdate
.is() )
429 m_xColumnUpdate
->updateBinaryStream( xImageStream
, xImageStream
->available() );
431 setControlValue( Any( xImageStream
), _eInstigator
);
432 xImageStream
->closeInput();
440 void OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator
)
442 switch ( lcl_getImageStoreType( getFieldType() ) )
444 case ImageStoreBinary
:
445 if ( impl_updateStreamForURL_lck( m_sImageURL
, _eInstigator
) )
451 OUString
sCommitURL( m_sImageURL
);
452 if ( !m_sDocumentURL
.isEmpty() )
453 sCommitURL
= URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL
, sCommitURL
);
454 OSL_ENSURE( m_xColumnUpdate
.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" );
455 if ( m_xColumnUpdate
.is() )
457 m_xColumnUpdate
->updateString( sCommitURL
);
463 case ImageStoreInvalid
:
464 OSL_FAIL( "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" );
468 // if we're here, then the above code was unable to update our field/control from the given URL
469 // => fall back to NULL/VOID
470 if ( m_xColumnUpdate
.is() )
471 m_xColumnUpdate
->updateNull();
473 setControlValue( Any(), _eInstigator
);
477 bool OImageControlModel::commitControlValueToDbColumn( bool _bPostReset
)
481 // since this is a "commit after reset", we can simply update the column
482 // with null - this is our "default" which we were just reset to
483 if ( m_xColumnUpdate
.is() )
484 m_xColumnUpdate
->updateNull();
488 ::osl::MutexGuard
aGuard(m_aMutex
);
489 impl_handleNewImageURL_lck( eDbColumnBinding
);
498 bool lcl_isValidDocumentURL( std::u16string_view _rDocURL
)
500 return ( !_rDocURL
.empty() && _rDocURL
!= u
"private:object" );
505 void OImageControlModel::onConnectedDbColumn( const Reference
< XInterface
>& _rxForm
)
507 OBoundControlModel::onConnectedDbColumn( _rxForm
);
511 Reference
< XModel
> xDocument( getXModel( *this ) );
512 if ( xDocument
.is() )
514 m_sDocumentURL
= xDocument
->getURL();
515 if ( !lcl_isValidDocumentURL( m_sDocumentURL
) )
517 Reference
< XChild
> xAsChild( xDocument
, UNO_QUERY
);
518 while ( xAsChild
.is() && !lcl_isValidDocumentURL( m_sDocumentURL
) )
520 xDocument
.set( xAsChild
->getParent(), UNO_QUERY
);
521 if ( xDocument
.is() )
522 m_sDocumentURL
= xDocument
->getURL();
523 xAsChild
.set( xDocument
, UNO_QUERY
);
528 catch( const Exception
& )
530 DBG_UNHANDLED_EXCEPTION("forms.component");
535 void OImageControlModel::onDisconnectedDbColumn()
537 OBoundControlModel::onDisconnectedDbColumn();
539 m_sDocumentURL
.clear();
543 Any
OImageControlModel::translateDbColumnToControlValue()
545 switch ( lcl_getImageStoreType( getFieldType() ) )
547 case ImageStoreBinary
:
549 Reference
< XInputStream
> xImageStream( m_xColumn
->getBinaryStream() );
550 if ( m_xColumn
->wasNull() )
551 xImageStream
.clear();
552 return Any( xImageStream
);
556 OUString
sImageLink( m_xColumn
->getString() );
557 if ( !m_sDocumentURL
.isEmpty() )
558 sImageLink
= INetURLObject::GetAbsURL( m_sDocumentURL
, sImageLink
);
559 return Any( sImageLink
);
561 case ImageStoreInvalid
:
562 OSL_FAIL( "OImageControlModel::translateDbColumnToControlValue: invalid field type!" );
569 Any
OImageControlModel::getControlValue( ) const
571 return Any( m_sImageURL
);
575 void OImageControlModel::doSetControlValue( const Any
& _rValue
)
577 DBG_ASSERT( GetImageProducer() && m_xImageProducer
.is(), "OImageControlModel::doSetControlValue: no image producer!" );
578 if ( !GetImageProducer() || !m_xImageProducer
.is() )
581 bool bStartProduction
= false;
582 switch ( lcl_getImageStoreType( getFieldType() ) )
584 case ImageStoreBinary
:
586 // give the image producer the stream
587 Reference
< XInputStream
> xInStream
;
588 _rValue
>>= xInStream
;
589 GetImageProducer()->setImage( xInStream
);
590 bStartProduction
= true;
597 _rValue
>>= sImageURL
;
598 GetImageProducer()->SetImage( sImageURL
);
599 bStartProduction
= true;
603 case ImageStoreInvalid
:
604 OSL_FAIL( "OImageControlModel::doSetControlValue: invalid field type!" );
607 } // switch ( lcl_getImageStoreType( getFieldType() ) )
609 if ( bStartProduction
)
612 rtl::Reference
< ImageProducer
> xProducer
= m_xImageProducer
;
614 // release our mutex once (it's acquired in the calling method!), as starting the image production may
615 // result in the locking of the solar mutex (unfortunately the default implementation of our aggregate,
616 // VCLXImageControl, does this locking)
617 MutexRelease
aRelease(m_aMutex
);
618 xProducer
->startProduction();
623 void OImageControlModel::resetNoBroadcast()
625 if ( hasField() ) // only reset when we are connected to a column
626 OBoundControlModel::resetNoBroadcast( );
630 Reference
< XImageProducer
> SAL_CALL
OImageControlModel::getImageProducer()
636 void SAL_CALL
OImageControlModel::addConsumer( const Reference
< XImageConsumer
>& _rxConsumer
)
638 GetImageProducer()->addConsumer( _rxConsumer
);
642 void SAL_CALL
OImageControlModel::removeConsumer( const Reference
< XImageConsumer
>& _rxConsumer
)
644 GetImageProducer()->removeConsumer( _rxConsumer
);
648 void SAL_CALL
OImageControlModel::startProduction( )
650 GetImageProducer()->startProduction();
654 IMPL_LINK( OImageControlModel
, OnImageImportDone
, ::Graphic
*, i_pGraphic
, void )
656 const Reference
< XGraphic
> xGraphic(i_pGraphic
!= nullptr ? i_pGraphic
->GetXGraphic() : nullptr);
657 m_bExternalGraphic
= false;
660 setPropertyValue( PROPERTY_GRAPHIC
, Any( xGraphic
) );
662 catch ( const Exception
& )
664 DBG_UNHANDLED_EXCEPTION("forms.component");
666 m_bExternalGraphic
= true;
670 // OImageControlControl
672 Sequence
<Type
> OImageControlControl::_getTypes()
674 return concatSequences(
675 OBoundControl::_getTypes(),
676 OImageControlControl_Base::getTypes()
681 OImageControlControl::OImageControlControl(const Reference
<XComponentContext
>& _rxFactory
)
682 :OBoundControl(_rxFactory
, VCL_CONTROL_IMAGECONTROL
)
683 ,m_aModifyListeners( m_aMutex
)
685 osl_atomic_increment(&m_refCount
);
687 // Add as Focus- and MouseListener
688 Reference
< XWindow
> xComp
;
689 query_aggregation( m_xAggregate
, xComp
);
691 xComp
->addMouseListener( this );
693 osl_atomic_decrement(&m_refCount
);
697 Any SAL_CALL
OImageControlControl::queryAggregation(const Type
& _rType
)
699 Any aReturn
= OBoundControl::queryAggregation( _rType
);
700 if ( !aReturn
.hasValue() )
701 aReturn
= ::cppu::queryInterface(
703 static_cast< XMouseListener
* >( this ),
704 static_cast< XModifyBroadcaster
* >( this )
711 css::uno::Sequence
<OUString
> OImageControlControl::getSupportedServiceNames()
713 css::uno::Sequence
<OUString
> aSupported
= OBoundControl::getSupportedServiceNames();
714 aSupported
.realloc(aSupported
.getLength() + 2);
716 OUString
*pArray
= aSupported
.getArray();
717 pArray
[aSupported
.getLength()-2] = FRM_SUN_CONTROL_IMAGECONTROL
;
718 pArray
[aSupported
.getLength()-1] = STARDIV_ONE_FORM_CONTROL_IMAGECONTROL
;
723 void SAL_CALL
OImageControlControl::addModifyListener( const Reference
< XModifyListener
>& Listener
)
725 m_aModifyListeners
.addInterface( Listener
);
729 void SAL_CALL
OImageControlControl::removeModifyListener( const Reference
< XModifyListener
>& Listener
)
731 m_aModifyListeners
.removeInterface( Listener
);
735 void SAL_CALL
OImageControlControl::disposing()
737 EventObject
aEvent( *this );
738 m_aModifyListeners
.disposeAndClear( aEvent
);
740 OBoundControl::disposing();
744 void SAL_CALL
OImageControlControl::disposing( const EventObject
& Event
)
746 OBoundControl::disposing( Event
);
750 void OImageControlControl::implClearGraphics( bool _bForce
)
752 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
758 OUString sOldImageURL
;
759 xSet
->getPropertyValue( PROPERTY_IMAGE_URL
) >>= sOldImageURL
;
761 if ( sOldImageURL
.isEmpty() )
762 // the ImageURL is already empty, so simply setting a new empty one would not suffice
763 // (since it would be ignored)
764 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, Any( OUString( "private:emptyImage" ) ) );
765 // (the concrete URL we're passing here doesn't matter. It's important that
766 // the model cannot resolve it to a valid resource describing an image stream
769 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, Any( OUString() ) );
773 bool OImageControlControl::implInsertGraphics()
775 Reference
< XPropertySet
> xSet( getModel(), UNO_QUERY
);
779 OUString sTitle
= ResourceManager::loadString(RID_STR_IMPORT_GRAPHIC
);
780 // build some arguments for the upcoming dialog
783 Reference
< XWindow
> xWindow( static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY
);
784 ::sfx2::FileDialogHelper
aDialog(TemplateDescription::FILEOPEN_LINK_PREVIEW
, FileDialogFlags::Graphic
,
785 Application::GetFrameWeld(xWindow
));
786 aDialog
.SetContext(sfx2::FileDialogHelper::FormsInsertImage
);
787 aDialog
.SetTitle( sTitle
);
789 Reference
< XFilePickerControlAccess
> xController( aDialog
.GetFilePicker(), UNO_QUERY_THROW
);
790 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW
, 0, css::uno::Any(true));
792 Reference
<XPropertySet
> xBoundField
;
793 if ( hasProperty( PROPERTY_BOUNDFIELD
, xSet
) )
794 xSet
->getPropertyValue( PROPERTY_BOUNDFIELD
) >>= xBoundField
;
795 bool bHasField
= xBoundField
.is();
797 // if the control is bound to a DB field, then it's not possible to decide whether or not to link
798 xController
->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK
, !bHasField
);
800 // if the control is bound to a DB field, then linking of the image depends on the type of the field
801 bool bImageIsLinked
= true;
804 sal_Int32 nFieldType
= DataType::OTHER
;
805 OSL_VERIFY( xBoundField
->getPropertyValue( PROPERTY_FIELDTYPE
) >>= nFieldType
);
806 bImageIsLinked
= ( lcl_getImageStoreType( nFieldType
) == ImageStoreLink
);
808 xController
->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0, Any( bImageIsLinked
) );
810 if ( ERRCODE_NONE
== aDialog
.Execute() )
812 // reset the url property in case it already has the value we're about to set - in this case
813 // our propertyChanged would not get called without this.
814 implClearGraphics( false );
815 bool bIsLink
= false;
816 xController
->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK
, 0) >>= bIsLink
;
817 // Force bIsLink to be sal_True if we're bound to a field. Though we initialized the file picker with IsLink=TRUE
818 // in this case, and disabled the respective control, there might be picker implementations which do not
819 // respect this, and return IsLink=FALSE here. In this case, "normalize" the flag.
821 bIsLink
|= bHasField
;
825 aDialog
.GetGraphic( aGraphic
);
826 xSet
->setPropertyValue( PROPERTY_GRAPHIC
, Any( aGraphic
.GetXGraphic() ) );
829 xSet
->setPropertyValue( PROPERTY_IMAGE_URL
, Any( aDialog
.GetPath() ) );
834 catch(const Exception
&)
836 TOOLS_WARN_EXCEPTION( "forms.component", "OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!");
842 bool OImageControlControl::impl_isEmptyGraphics_nothrow() const
844 bool bIsEmpty
= true;
848 Reference
< XPropertySet
> xModelProps( const_cast< OImageControlControl
* >( this )->getModel(), UNO_QUERY_THROW
);
849 Reference
< XGraphic
> xGraphic
;
850 OSL_VERIFY( xModelProps
->getPropertyValue("Graphic") >>= xGraphic
);
851 bIsEmpty
= !xGraphic
.is();
853 catch( const Exception
& )
855 DBG_UNHANDLED_EXCEPTION("forms.component");
863 void OImageControlControl::mousePressed(const css::awt::MouseEvent
& e
)
865 SolarMutexGuard aGuard
;
867 if (e
.Buttons
!= MouseButton::LEFT
)
870 bool bModified
= false;
871 // is this a request for a context menu?
872 if ( e
.PopupTrigger
)
874 Reference
< XPopupMenu
> xMenu( awt::PopupMenu::create( m_xContext
) );
875 DBG_ASSERT( xMenu
.is(), "OImageControlControl::mousePressed: could not create a popup menu!" );
877 Reference
< XWindowPeer
> xWindowPeer
= getPeer();
878 DBG_ASSERT( xWindowPeer
.is(), "OImageControlControl::mousePressed: no window!" );
880 if ( xMenu
.is() && xWindowPeer
.is() )
882 xMenu
->insertItem( ID_OPEN_GRAPHICS
, ResourceManager::loadString(RID_STR_OPEN_GRAPHICS
), 0, 0 );
883 xMenu
->insertItem( ID_CLEAR_GRAPHICS
, ResourceManager::loadString(RID_STR_CLEAR_GRAPHICS
), 0, 1 );
885 // check if the ImageURL is empty
886 if ( impl_isEmptyGraphics_nothrow() )
887 xMenu
->enableItem( ID_CLEAR_GRAPHICS
, false );
889 awt::Rectangle
aRect( e
.X
, e
.Y
, 0, 0 );
890 if ( ( e
.X
< 0 ) || ( e
.Y
< 0 ) )
891 { // context menu triggered by keyboard
892 // position it in the center of the control
893 Reference
< XWindow
> xWindow( static_cast< ::cppu::OWeakObject
* >( this ), UNO_QUERY
);
894 OSL_ENSURE( xWindow
.is(), "OImageControlControl::mousePressed: me not a window? How this?" );
897 awt::Rectangle aPosSize
= xWindow
->getPosSize();
898 aRect
.X
= aPosSize
.Width
/ 2;
899 aRect
.Y
= aPosSize
.Height
/ 2;
903 const sal_Int16 nResult
= xMenu
->execute( xWindowPeer
, aRect
, PopupMenuDirection::EXECUTE_DEFAULT
);
907 case ID_OPEN_GRAPHICS
:
908 implInsertGraphics();
912 case ID_CLEAR_GRAPHICS
:
913 implClearGraphics( true );
923 if (e
.ClickCount
== 2)
926 Reference
<XPropertySet
> xSet(getModel(), UNO_QUERY
);
930 // If the Control is not bound, do not display a dialog (because the to-be-sent URL would be invalid anyway)
931 Reference
<XPropertySet
> xBoundField
;
932 if (hasProperty(PROPERTY_BOUNDFIELD
, xSet
))
934 xSet
->getPropertyValue(PROPERTY_BOUNDFIELD
),
935 css::uno::UNO_QUERY
);
936 if (!xBoundField
.is())
938 // but only if our IMAGE_URL property is handled as if it is transient, which is equivalent to
939 // an empty control source
940 if ( !hasProperty(PROPERTY_CONTROLSOURCE
, xSet
) || !::comphelper::getString(xSet
->getPropertyValue(PROPERTY_CONTROLSOURCE
)).isEmpty() )
944 bool bReadOnly
= false;
945 xSet
->getPropertyValue(PROPERTY_READONLY
) >>= bReadOnly
;
949 if ( implInsertGraphics() )
956 EventObject
aEvent( *this );
957 m_aModifyListeners
.notifyEach( &XModifyListener::modified
, aEvent
);
962 void SAL_CALL
OImageControlControl::mouseReleased(const awt::MouseEvent
& /*e*/)
967 void SAL_CALL
OImageControlControl::mouseEntered(const awt::MouseEvent
& /*e*/)
972 void SAL_CALL
OImageControlControl::mouseExited(const awt::MouseEvent
& /*e*/)
978 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
979 com_sun_star_form_OImageControlModel_get_implementation(css::uno::XComponentContext
* component
,
980 css::uno::Sequence
<css::uno::Any
> const &)
982 return cppu::acquire(new frm::OImageControlModel(component
));
985 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
986 com_sun_star_form_OImageControlControl_get_implementation(css::uno::XComponentContext
* component
,
987 css::uno::Sequence
<css::uno::Any
> const &)
989 return cppu::acquire(new frm::OImageControlControl(component
));
992 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */