LCOV - code coverage report
Current view: top level - forms/source/component - ImageControl.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 202 420 48.1 %
Date: 2015-06-13 12:38:46 Functions: 34 55 61.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include "ImageControl.hxx"
      21             : 
      22             : #include "property.hrc"
      23             : #include "frm_resource.hrc"
      24             : #include "frm_resource.hxx"
      25             : #include "services.hxx"
      26             : #include "componenttools.hxx"
      27             : 
      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>
      56             : 
      57             : #include <boost/scoped_ptr.hpp>
      58             : 
      59             : #define ID_OPEN_GRAPHICS            1
      60             : #define ID_CLEAR_GRAPHICS           2
      61             : 
      62             : namespace frm
      63             : {
      64             : 
      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;
      80             : 
      81             : 
      82             : //= OImageControlModel
      83             : 
      84             : namespace
      85             : {
      86             :     enum ImageStoreType
      87             :     {
      88             :         ImageStoreBinary,
      89             :         ImageStoreLink,
      90             : 
      91             :         ImageStoreInvalid
      92             :     };
      93             : 
      94          12 :     ImageStoreType lcl_getImageStoreType( const sal_Int32 _nFieldType )
      95             :     {
      96             :         // binary/longvarchar types could be used to store images in binary representation
      97          12 :         if  (   ( _nFieldType == DataType::BINARY )
      98          12 :             ||  ( _nFieldType == DataType::VARBINARY )
      99          12 :             ||  ( _nFieldType == DataType::LONGVARBINARY )
     100          12 :             ||  ( _nFieldType == DataType::OTHER )
     101           0 :             ||  ( _nFieldType == DataType::OBJECT )
     102           0 :             ||  ( _nFieldType == DataType::BLOB )
     103           0 :             ||  ( _nFieldType == DataType::LONGVARCHAR )
     104           0 :             ||  ( _nFieldType == DataType::CLOB )
     105             :             )
     106          12 :             return ImageStoreBinary;
     107             : 
     108             :         // char types could be used to store links to images
     109           0 :         if  (   ( _nFieldType == DataType::CHAR )
     110           0 :             ||  ( _nFieldType == DataType::VARCHAR )
     111             :             )
     112           0 :             return ImageStoreLink;
     113             : 
     114           0 :         return ImageStoreInvalid;
     115             :     }
     116             : }
     117             : 
     118             : 
     119             : // OImageControlModel
     120             : 
     121           0 : Sequence<Type> OImageControlModel::_getTypes()
     122             : {
     123             :     return concatSequences(
     124             :         OBoundControlModel::_getTypes(),
     125             :         OImageControlModel_Base::getTypes()
     126           0 :     );
     127             : }
     128             : 
     129             : 
     130          10 : 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 )
     136             :     ,m_sImageURL()
     137          10 :     ,m_xGraphicObject()
     138             : {
     139          10 :     m_nClassId = FormComponentType::IMAGECONTROL;
     140          10 :     initOwnValueProperty( PROPERTY_IMAGE_URL );
     141             : 
     142          10 :     implConstruct();
     143          10 : }
     144             : 
     145             : 
     146           1 : 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           1 :     ,m_xGraphicObject( _pOriginal->m_xGraphicObject )
     154             : {
     155           1 :     implConstruct();
     156             : 
     157           1 :     osl_atomic_increment( &m_refCount );
     158             :     {
     159             :         // simulate a propertyChanged event for the ImageURL
     160           1 :         ::osl::MutexGuard aGuard( m_aMutex );
     161           1 :         impl_handleNewImageURL_lck( eOther );
     162             :     }
     163           1 :     osl_atomic_decrement( &m_refCount );
     164           1 : }
     165             : 
     166             : 
     167          11 : void OImageControlModel::implConstruct()
     168             : {
     169          11 :     m_pImageProducer = new ImageProducer;
     170          11 :     m_xImageProducer = m_pImageProducer;
     171          11 :     m_pImageProducer->SetDoneHdl( LINK( this, OImageControlModel, OnImageImportDone ) );
     172          11 : }
     173             : 
     174             : 
     175          33 : OImageControlModel::~OImageControlModel()
     176             : {
     177          11 :     if (!OComponentHelper::rBHelper.bDisposed)
     178             :     {
     179           0 :         acquire();
     180           0 :         dispose();
     181             :     }
     182             : 
     183          22 : }
     184             : 
     185             : // XCloneable
     186             : 
     187           1 : IMPLEMENT_DEFAULT_CLONING( OImageControlModel )
     188             : 
     189             : // XServiceInfo
     190             : 
     191           7 : StringSequence  OImageControlModel::getSupportedServiceNames() throw(std::exception)
     192             : {
     193           7 :     StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();
     194           7 :     aSupported.realloc(aSupported.getLength() + 2);
     195             : 
     196           7 :     OUString*pArray = aSupported.getArray();
     197           7 :     pArray[aSupported.getLength()-2] = FRM_SUN_COMPONENT_IMAGECONTROL;
     198           7 :     pArray[aSupported.getLength()-1] = FRM_COMPONENT_IMAGECONTROL;
     199           7 :     return aSupported;
     200             : }
     201             : 
     202             : 
     203        1694 : Any SAL_CALL OImageControlModel::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
     204             : {
     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        1694 :     Any aReturn = OImageControlModel_Base::queryInterface( _rType );
     208             : 
     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        3388 :     if  (   _rType.equals( cppu::UnoType<XTypeProvider>::get() )
     212        1694 :         ||  !aReturn.hasValue()
     213             :         )
     214         929 :         aReturn = OBoundControlModel::queryAggregation( _rType );
     215             : 
     216        1694 :     return aReturn;
     217             : }
     218             : 
     219             : 
     220           0 : bool OImageControlModel::approveDbColumnType( sal_Int32 _nColumnType )
     221             : {
     222           0 :     return ImageStoreInvalid != lcl_getImageStoreType( _nColumnType );
     223             : }
     224             : 
     225             : 
     226        1150 : void OImageControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
     227             : {
     228        1150 :     switch (nHandle)
     229             :     {
     230             :         case PROPERTY_ID_READONLY:
     231          44 :             rValue <<= m_bReadOnly;
     232          44 :             break;
     233             :         case PROPERTY_ID_IMAGE_URL:
     234          35 :             rValue <<= m_sImageURL;
     235          35 :             break;
     236             :         case PROPERTY_ID_GRAPHIC:
     237          62 :             rValue <<= m_xGraphicObject.is() ? m_xGraphicObject->getGraphic() : Reference< XGraphic >();
     238          62 :             break;
     239             :         default:
     240        1009 :             OBoundControlModel::getFastPropertyValue(rValue, nHandle);
     241             :     }
     242        1150 : }
     243             : 
     244             : 
     245         102 : void OImageControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) throw ( ::com::sun::star::uno::Exception, std::exception)
     246             : {
     247         102 :     switch (nHandle)
     248             :     {
     249             :         case PROPERTY_ID_READONLY :
     250             :             DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "OImageControlModel::setFastPropertyValue_NoBroadcast : invalid type !" );
     251           9 :             m_bReadOnly = getBOOL(rValue);
     252           9 :             break;
     253             : 
     254             :         case PROPERTY_ID_IMAGE_URL:
     255           5 :             OSL_VERIFY( rValue >>= m_sImageURL );
     256           5 :             impl_handleNewImageURL_lck( eOther );
     257             :             {
     258           5 :                 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           5 :                 onValuePropertyChange( aLock );
     262             :             }
     263           5 :             break;
     264             : 
     265             :         case PROPERTY_ID_GRAPHIC:
     266             :         {
     267           1 :             Reference< XGraphic > xGraphic;
     268           1 :             OSL_VERIFY( rValue >>= xGraphic );
     269           1 :             if ( !xGraphic.is() )
     270           0 :                 m_xGraphicObject.clear();
     271             :             else
     272             :             {
     273           1 :                 m_xGraphicObject = graphic::GraphicObject::create( m_xContext );
     274           1 :                 m_xGraphicObject->setGraphic( xGraphic );
     275             :             }
     276             : 
     277           1 :             if ( m_bExternalGraphic )
     278             :             {
     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           0 :                 OUString sNewImageURL;
     282           0 :                 if ( m_xGraphicObject.is() )
     283             :                 {
     284           0 :                     sNewImageURL = "vnd.sun.star.GraphicObject:";
     285           0 :                     sNewImageURL = sNewImageURL + m_xGraphicObject->getUniqueID();
     286             :                 }
     287           0 :                 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 ...
     292           1 :             }
     293             :         }
     294           1 :         break;
     295             : 
     296             :         default:
     297          87 :             OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue);
     298          87 :             break;
     299             :     }
     300         102 : }
     301             : 
     302             : 
     303         330 : sal_Bool OImageControlModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
     304             :                                 throw( IllegalArgumentException )
     305             : {
     306         330 :     switch (nHandle)
     307             :     {
     308             :         case PROPERTY_ID_READONLY :
     309          29 :             return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bReadOnly);
     310             : 
     311             :         case PROPERTY_ID_IMAGE_URL:
     312          25 :             return tryPropertyValue( rConvertedValue, rOldValue, rValue, m_sImageURL );
     313             : 
     314             :         case PROPERTY_ID_GRAPHIC:
     315             :         {
     316          28 :             const Reference< XGraphic > xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC ), UNO_QUERY );
     317          28 :             return tryPropertyValue( rConvertedValue, rOldValue, rValue, xGraphic );
     318             :         }
     319             : 
     320             :         default:
     321         248 :             return OBoundControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
     322             :     }
     323             : }
     324             : 
     325             : 
     326          11 : void OImageControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
     327             : {
     328          11 :     BEGIN_DESCRIBE_PROPERTIES( 4, OBoundControlModel )
     329          11 :         DECL_IFACE_PROP2( GRAPHIC,   XGraphic,        BOUND, TRANSIENT );
     330          11 :         DECL_PROP1      ( IMAGE_URL, OUString, BOUND );
     331          11 :         DECL_BOOL_PROP1 ( READONLY,                   BOUND );
     332          11 :         DECL_PROP1      ( TABINDEX,  sal_Int16,       BOUND );
     333             :     END_DESCRIBE_PROPERTIES();
     334          11 : }
     335             : 
     336             : 
     337          11 : void OImageControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ o_rAggregateProperties ) const
     338             : {
     339          11 :     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          11 :     RemoveProperty( o_rAggregateProperties, PROPERTY_IMAGE_URL );
     344          11 :     RemoveProperty( o_rAggregateProperties, PROPERTY_GRAPHIC );
     345          11 : }
     346             : 
     347             : 
     348           1 : OUString OImageControlModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException, std::exception)
     349             : {
     350           1 :     return OUString(FRM_COMPONENT_IMAGECONTROL);  // old (non-sun) name for compatibility !
     351             : }
     352             : 
     353             : 
     354           1 : void OImageControlModel::write(const Reference<XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception)
     355             : {
     356             :     // Base class
     357           1 :     OBoundControlModel::write(_rxOutStream);
     358             :     // Version
     359           1 :     _rxOutStream->writeShort(0x0003);
     360             :     // Name
     361           1 :     _rxOutStream->writeBoolean(m_bReadOnly);
     362           1 :     writeHelpTextCompatibly(_rxOutStream);
     363             :     // from version 0x0003 : common properties
     364           1 :     writeCommonProperties(_rxOutStream);
     365           1 : }
     366             : 
     367             : 
     368           1 : void OImageControlModel::read(const Reference<XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException, std::exception)
     369             : {
     370           1 :     OBoundControlModel::read(_rxInStream);
     371             : 
     372             :     // Version
     373           1 :     sal_uInt16 nVersion = _rxInStream->readShort();
     374           1 :     switch (nVersion)
     375             :     {
     376             :         case 0x0001:
     377           0 :             m_bReadOnly = _rxInStream->readBoolean();
     378           0 :             break;
     379             :         case 0x0002:
     380           0 :             m_bReadOnly = _rxInStream->readBoolean();
     381           0 :             readHelpTextCompatibly(_rxInStream);
     382           0 :             break;
     383             :         case 0x0003:
     384           1 :             m_bReadOnly = _rxInStream->readBoolean();
     385           1 :             readHelpTextCompatibly(_rxInStream);
     386           1 :             readCommonProperties(_rxInStream);
     387           1 :             break;
     388             :         default :
     389             :             OSL_FAIL("OImageControlModel::read : unknown version !");
     390           0 :             m_bReadOnly = false;
     391           0 :             defaultCommonProperties();
     392           0 :             break;
     393             :     }
     394             :     // Display default values after read
     395           1 :     if ( !getControlSource().isEmpty() )
     396             :     {   // (not if we don't have a control source - the "State" property acts like it is persistent, then
     397           1 :         ::osl::MutexGuard aGuard(m_aMutex); // resetNoBroadcast expects this mutex guarding
     398           1 :         resetNoBroadcast();
     399             :     }
     400           1 : }
     401             : 
     402             : 
     403           6 : bool OImageControlModel::impl_updateStreamForURL_lck( const OUString& _rURL, ValueChangeInstigator _eInstigator )
     404             : {
     405             :     // create a stream for the image specified by the URL
     406           6 :     boost::scoped_ptr< SvStream > pImageStream;
     407          12 :     Reference< XInputStream > xImageStream;
     408             : 
     409           6 :     if ( ::svt::GraphicAccess::isSupportedURL( _rURL ) )
     410             :     {
     411           0 :         xImageStream = ::svt::GraphicAccess::getImageXStream( getContext(), _rURL );
     412             :     }
     413             :     else
     414             :     {
     415           6 :         pImageStream.reset( ::utl::UcbStreamHelper::CreateStream( _rURL, StreamMode::READ ) );
     416           6 :         bool bSetNull = ( pImageStream.get() == NULL ) || ( ERRCODE_NONE != pImageStream->GetErrorCode() );
     417             : 
     418           6 :         if ( !bSetNull )
     419             :         {
     420             :             // get the size of the stream
     421           1 :             sal_uInt64 const nSize = pImageStream->remainingSize();
     422           1 :             if (pImageStream->GetBufferSize() < 8192)
     423           1 :                 pImageStream->SetBufferSize(8192);
     424           1 :             pImageStream->Seek(STREAM_SEEK_TO_BEGIN);
     425             : 
     426           1 :             xImageStream = new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream.get(), false ), nSize );
     427             :         }
     428             :     }
     429             : 
     430           6 :     if ( xImageStream.is() )
     431             :     {
     432           1 :         if ( m_xColumnUpdate.is() )
     433           0 :             m_xColumnUpdate->updateBinaryStream( xImageStream, xImageStream->available() );
     434             :         else
     435           1 :             setControlValue( makeAny( xImageStream ), _eInstigator );
     436           1 :         xImageStream->closeInput();
     437           1 :         return true;
     438             :     }
     439             : 
     440          11 :     return false;
     441             : }
     442             : 
     443             : 
     444           6 : bool OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator )
     445             : {
     446           6 :     switch ( lcl_getImageStoreType( getFieldType() ) )
     447             :     {
     448             :     case ImageStoreBinary:
     449           6 :         if ( impl_updateStreamForURL_lck( m_sImageURL, _eInstigator ) )
     450           1 :             return true;
     451           5 :         break;
     452             : 
     453             :     case ImageStoreLink:
     454             :     {
     455           0 :         OUString sCommitURL( m_sImageURL );
     456           0 :         if ( !m_sDocumentURL.isEmpty() )
     457           0 :             sCommitURL = URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL, sCommitURL );
     458             :         OSL_ENSURE( m_xColumnUpdate.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" );
     459           0 :         if ( m_xColumnUpdate.is() )
     460             :         {
     461           0 :             m_xColumnUpdate->updateString( sCommitURL );
     462           0 :             return true;
     463           0 :         }
     464             :     }
     465           0 :     break;
     466             : 
     467             :     case ImageStoreInvalid:
     468             :         OSL_FAIL( "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" );
     469           0 :         break;
     470             :     }
     471             : 
     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           5 :     if ( m_xColumnUpdate.is() )
     475           0 :         m_xColumnUpdate->updateNull();
     476             :     else
     477           5 :         setControlValue( Any(), _eInstigator );
     478             : 
     479           5 :     return true;
     480             : }
     481             : 
     482             : 
     483           0 : bool OImageControlModel::commitControlValueToDbColumn( bool _bPostReset )
     484             : {
     485           0 :     if ( _bPostReset )
     486             :     {
     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           0 :         if ( m_xColumnUpdate.is() )
     490           0 :             m_xColumnUpdate->updateNull();
     491             :     }
     492             :     else
     493             :     {
     494           0 :         ::osl::MutexGuard aGuard(m_aMutex);
     495           0 :         return impl_handleNewImageURL_lck( eDbColumnBinding );
     496             :     }
     497             : 
     498           0 :     return true;
     499             : }
     500             : 
     501             : 
     502             : namespace
     503             : {
     504           0 :     bool lcl_isValidDocumentURL( const OUString& _rDocURL )
     505             :     {
     506           0 :         return ( !_rDocURL.isEmpty() && _rDocURL != "private:object" );
     507             :     }
     508             : }
     509             : 
     510             : 
     511           0 : void OImageControlModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm )
     512             : {
     513           0 :     OBoundControlModel::onConnectedDbColumn( _rxForm );
     514             : 
     515             :     try
     516             :     {
     517           0 :         Reference< XModel > xDocument( getXModel( *this ) );
     518           0 :         if ( xDocument.is() )
     519             :         {
     520           0 :             m_sDocumentURL = xDocument->getURL();
     521           0 :             if ( !lcl_isValidDocumentURL( m_sDocumentURL ) )
     522             :             {
     523           0 :                 Reference< XChild > xAsChild( xDocument, UNO_QUERY );
     524           0 :                 while ( xAsChild.is() && !lcl_isValidDocumentURL( m_sDocumentURL ) )
     525             :                 {
     526           0 :                     xDocument.set( xAsChild->getParent(), UNO_QUERY );
     527           0 :                     if ( xDocument.is() )
     528           0 :                         m_sDocumentURL = xDocument->getURL();
     529           0 :                     xAsChild.set( xDocument, UNO_QUERY );
     530           0 :                 }
     531             :             }
     532           0 :         }
     533             :     }
     534           0 :     catch( const Exception& )
     535             :     {
     536             :         DBG_UNHANDLED_EXCEPTION();
     537             :     }
     538           0 : }
     539             : 
     540             : 
     541           0 : void OImageControlModel::onDisconnectedDbColumn()
     542             : {
     543           0 :     OBoundControlModel::onDisconnectedDbColumn();
     544             : 
     545           0 :     m_sDocumentURL.clear();
     546           0 : }
     547             : 
     548             : 
     549           0 : Any OImageControlModel::translateDbColumnToControlValue()
     550             : {
     551           0 :     switch ( lcl_getImageStoreType( getFieldType() ) )
     552             :     {
     553             :     case ImageStoreBinary:
     554             :     {
     555           0 :         Reference< XInputStream > xImageStream( m_xColumn->getBinaryStream() );
     556           0 :         if ( m_xColumn->wasNull() )
     557           0 :             xImageStream.clear();
     558           0 :         return makeAny( xImageStream );
     559             :     }
     560             :     case ImageStoreLink:
     561             :     {
     562           0 :         OUString sImageLink( m_xColumn->getString() );
     563           0 :         if ( !m_sDocumentURL.isEmpty() )
     564           0 :             sImageLink = INetURLObject::GetAbsURL( m_sDocumentURL, sImageLink );
     565           0 :         return makeAny( sImageLink );
     566             :     }
     567             :     case ImageStoreInvalid:
     568             :         OSL_FAIL( "OImageControlModel::translateDbColumnToControlValue: invalid field type!" );
     569           0 :         break;
     570             :     }
     571           0 :     return Any();
     572             : }
     573             : 
     574             : 
     575           0 : Any OImageControlModel::getControlValue( ) const
     576             : {
     577           0 :     return makeAny( m_sImageURL );
     578             : }
     579             : 
     580             : 
     581           6 : void OImageControlModel::doSetControlValue( const Any& _rValue )
     582             : {
     583             :     DBG_ASSERT( GetImageProducer() && m_xImageProducer.is(), "OImageControlModel::doSetControlValue: no image producer!" );
     584           6 :     if ( !GetImageProducer() || !m_xImageProducer.is() )
     585           6 :         return;
     586             : 
     587           6 :     bool bStartProduction = false;
     588           6 :     switch ( lcl_getImageStoreType( getFieldType() ) )
     589             :     {
     590             :     case ImageStoreBinary:
     591             :     {
     592             :         // give the image producer the stream
     593           6 :         Reference< XInputStream > xInStream;
     594           6 :         _rValue >>= xInStream;
     595           6 :         GetImageProducer()->setImage( xInStream );
     596           6 :         bStartProduction = true;
     597             :     }
     598           6 :     break;
     599             : 
     600             :     case ImageStoreLink:
     601             :     {
     602           0 :         OUString sImageURL;
     603           0 :         _rValue >>= sImageURL;
     604           0 :         GetImageProducer()->SetImage( sImageURL );
     605           0 :         bStartProduction = true;
     606             :     }
     607           0 :     break;
     608             : 
     609             :     case ImageStoreInvalid:
     610             :         OSL_FAIL( "OImageControlModel::doSetControlValue: invalid field type!" );
     611           0 :         break;
     612             : 
     613             :     }   // switch ( lcl_getImageStoreType( getFieldType() ) )
     614             : 
     615           6 :     if ( bStartProduction )
     616             :     {
     617             :         // start production
     618           6 :         Reference< XImageProducer > xProducer = m_xImageProducer;
     619             :         {
     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           6 :             MutexRelease aRelease(m_aMutex);
     624           6 :             xProducer->startProduction();
     625           6 :         }
     626             :     }
     627             : }
     628             : 
     629             : // OComponentHelper
     630             : 
     631          11 : void SAL_CALL OImageControlModel::disposing()
     632             : {
     633          11 :     OBoundControlModel::disposing();
     634          11 : }
     635             : 
     636             : 
     637           3 : void OImageControlModel::resetNoBroadcast()
     638             : {
     639           3 :     if ( hasField() )          // only reset when we are connected to a column
     640           0 :         OBoundControlModel::resetNoBroadcast( );
     641           3 : }
     642             : 
     643             : 
     644           1 : Reference< XImageProducer > SAL_CALL OImageControlModel::getImageProducer() throw ( RuntimeException, std::exception)
     645             : {
     646           1 :     return this;
     647             : }
     648             : 
     649             : 
     650           0 : void SAL_CALL OImageControlModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException, std::exception)
     651             : {
     652           0 :     GetImageProducer()->addConsumer( _rxConsumer );
     653           0 : }
     654             : 
     655             : 
     656           0 : void SAL_CALL OImageControlModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException, std::exception)
     657             : {
     658           0 :     GetImageProducer()->removeConsumer( _rxConsumer );
     659           0 : }
     660             : 
     661             : 
     662           0 : void SAL_CALL OImageControlModel::startProduction(  ) throw (RuntimeException, std::exception)
     663             : {
     664           0 :     GetImageProducer()->startProduction();
     665           0 : }
     666             : 
     667             : 
     668          12 : IMPL_LINK( OImageControlModel, OnImageImportDone, ::Graphic*, i_pGraphic )
     669             : {
     670           6 :     const Reference< XGraphic > xGraphic( i_pGraphic != NULL ? Image( i_pGraphic->GetBitmapEx() ).GetXGraphic() : NULL );
     671           6 :     m_bExternalGraphic = false;
     672             :     try
     673             :     {
     674           6 :         setPropertyValue( PROPERTY_GRAPHIC, makeAny( xGraphic ) );
     675             :     }
     676           0 :     catch ( const Exception& )
     677             :     {
     678             :         DBG_UNHANDLED_EXCEPTION();
     679             :     }
     680           6 :     m_bExternalGraphic = true;
     681           6 :     return 1L;
     682             : }
     683             : 
     684             : 
     685             : // OImageControlControl
     686             : 
     687           0 : Sequence<Type> OImageControlControl::_getTypes()
     688             : {
     689             :     return concatSequences(
     690             :         OBoundControl::_getTypes(),
     691             :         OImageControlControl_Base::getTypes()
     692           0 :     );
     693             : }
     694             : 
     695             : 
     696           2 : OImageControlControl::OImageControlControl(const Reference<XComponentContext>& _rxFactory)
     697             :     :OBoundControl(_rxFactory, VCL_CONTROL_IMAGECONTROL)
     698           2 :     ,m_aModifyListeners( m_aMutex )
     699             : {
     700           2 :     osl_atomic_increment(&m_refCount);
     701             :     {
     702             :         // Add as Focus- and MouseListener
     703           2 :         Reference< XWindow > xComp;
     704           2 :         query_aggregation( m_xAggregate, xComp );
     705           2 :         if ( xComp.is() )
     706           2 :             xComp->addMouseListener( this );
     707             :     }
     708           2 :     osl_atomic_decrement(&m_refCount);
     709           2 : }
     710             : 
     711             : 
     712          43 : Any SAL_CALL OImageControlControl::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
     713             : {
     714          43 :     Any aReturn = OBoundControl::queryAggregation( _rType );
     715          43 :     if ( !aReturn.hasValue() )
     716           4 :         aReturn = ::cppu::queryInterface(
     717             :             _rType,
     718             :             static_cast< XMouseListener* >( this ),
     719             :             static_cast< XModifyBroadcaster* >( this )
     720           2 :         );
     721             : 
     722          43 :     return aReturn;
     723             : }
     724             : 
     725             : 
     726           1 : StringSequence  OImageControlControl::getSupportedServiceNames() throw(std::exception)
     727             : {
     728           1 :     StringSequence aSupported = OBoundControl::getSupportedServiceNames();
     729           1 :     aSupported.realloc(aSupported.getLength() + 2);
     730             : 
     731           1 :     OUString*pArray = aSupported.getArray();
     732           1 :     pArray[aSupported.getLength()-2] = FRM_SUN_CONTROL_IMAGECONTROL;
     733           1 :     pArray[aSupported.getLength()-1] = STARDIV_ONE_FORM_CONTROL_IMAGECONTROL;
     734           1 :     return aSupported;
     735             : }
     736             : 
     737             : 
     738           0 : void SAL_CALL OImageControlControl::addModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException, std::exception)
     739             : {
     740           0 :     m_aModifyListeners.addInterface( _Listener );
     741           0 : }
     742             : 
     743             : 
     744           0 : void SAL_CALL OImageControlControl::removeModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException, std::exception)
     745             : {
     746           0 :     m_aModifyListeners.removeInterface( _Listener );
     747           0 : }
     748             : 
     749             : 
     750           2 : void SAL_CALL OImageControlControl::disposing()
     751             : {
     752           2 :     EventObject aEvent( *this );
     753           2 :     m_aModifyListeners.disposeAndClear( aEvent );
     754             : 
     755           2 :     OBoundControl::disposing();
     756           2 : }
     757             : 
     758             : 
     759           2 : void SAL_CALL OImageControlControl::disposing( const EventObject& _Event ) throw(RuntimeException, std::exception)
     760             : {
     761           2 :     OBoundControl::disposing( _Event );
     762           2 : }
     763             : 
     764             : 
     765           0 : void OImageControlControl::implClearGraphics( bool _bForce )
     766             : {
     767           0 :     Reference< XPropertySet > xSet( getModel(), UNO_QUERY );
     768           0 :     if ( xSet.is() )
     769             :     {
     770           0 :         if ( _bForce )
     771             :         {
     772           0 :             OUString sOldImageURL;
     773           0 :             xSet->getPropertyValue( PROPERTY_IMAGE_URL ) >>= sOldImageURL;
     774             : 
     775           0 :             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           0 :                 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
     781             :         }
     782             : 
     783           0 :         xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( OUString() ) );
     784           0 :     }
     785           0 : }
     786             : 
     787             : 
     788           0 : bool OImageControlControl::implInsertGraphics()
     789             : {
     790           0 :     Reference< XPropertySet > xSet( getModel(), UNO_QUERY );
     791           0 :     if ( !xSet.is() )
     792           0 :         return false;
     793             : 
     794           0 :     OUString sTitle = FRM_RES_STRING(RID_STR_IMPORT_GRAPHIC);
     795             :     // build some arguments for the upcoming dialog
     796             :     try
     797             :     {
     798           0 :         ::sfx2::FileDialogHelper aDialog( TemplateDescription::FILEOPEN_LINK_PREVIEW, SFXWB_GRAPHIC );
     799           0 :         aDialog.SetTitle( sTitle );
     800             : 
     801           0 :         Reference< XFilePickerControlAccess > xController( aDialog.GetFilePicker(), UNO_QUERY_THROW );
     802           0 :         xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, css::uno::Any(true));
     803             : 
     804           0 :         Reference<XPropertySet> xBoundField;
     805           0 :         if ( hasProperty( PROPERTY_BOUNDFIELD, xSet ) )
     806           0 :             xSet->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xBoundField;
     807           0 :         bool bHasField = xBoundField.is();
     808             : 
     809             :         // if the control is bound to a DB field, then it's not possible to decide whether or not to link
     810           0 :         xController->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK, !bHasField );
     811             : 
     812             :         // if the control is bound to a DB field, then linking of the image depends on the type of the field
     813           0 :         bool bImageIsLinked = true;
     814           0 :         if ( bHasField )
     815             :         {
     816           0 :             sal_Int32 nFieldType = DataType::OTHER;
     817           0 :             OSL_VERIFY( xBoundField->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType );
     818           0 :             bImageIsLinked = ( lcl_getImageStoreType( nFieldType ) == ImageStoreLink );
     819             :         }
     820           0 :         xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, makeAny( bImageIsLinked ) );
     821             : 
     822           0 :         if ( ERRCODE_NONE == aDialog.Execute() )
     823             :         {
     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           0 :             implClearGraphics( false );
     827           0 :             bool bIsLink = false;
     828           0 :             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.
     832             :             // #i112659#
     833           0 :             bIsLink |= bHasField;
     834           0 :             if ( !bIsLink )
     835             :             {
     836           0 :                 Graphic aGraphic;
     837           0 :                 aDialog.GetGraphic( aGraphic );
     838           0 :                  xSet->setPropertyValue( PROPERTY_GRAPHIC, makeAny( aGraphic.GetXGraphic() ) );
     839             :             }
     840             :             else
     841           0 :                 xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( OUString( aDialog.GetPath() ) ) );
     842             : 
     843           0 :             return true;
     844           0 :         }
     845             :     }
     846           0 :     catch(const Exception&)
     847             :     {
     848             :         OSL_FAIL("OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!");
     849             :     }
     850           0 :     return false;
     851             : }
     852             : 
     853             : 
     854           0 : bool OImageControlControl::impl_isEmptyGraphics_nothrow() const
     855             : {
     856           0 :     bool bIsEmpty = true;
     857             : 
     858             :     try
     859             :     {
     860           0 :         Reference< XPropertySet > xModelProps( const_cast< OImageControlControl* >( this )->getModel(), UNO_QUERY_THROW );
     861           0 :         Reference< XGraphic > xGraphic;
     862           0 :         OSL_VERIFY( xModelProps->getPropertyValue("Graphic") >>= xGraphic );
     863           0 :         bIsEmpty = !xGraphic.is();
     864             :     }
     865           0 :     catch( const Exception& )
     866             :     {
     867             :         DBG_UNHANDLED_EXCEPTION();
     868             :     }
     869             : 
     870           0 :     return bIsEmpty;
     871             : }
     872             : 
     873             : // MouseListener
     874             : 
     875           0 : void OImageControlControl::mousePressed(const ::com::sun::star::awt::MouseEvent& e) throw ( ::com::sun::star::uno::RuntimeException, std::exception)
     876             : {
     877           0 :     SolarMutexGuard aGuard;
     878             : 
     879           0 :     if (e.Buttons != MouseButton::LEFT)
     880           0 :         return;
     881             : 
     882           0 :     bool bModified = false;
     883             :     // is this a request for a context menu?
     884           0 :     if ( e.PopupTrigger )
     885             :     {
     886           0 :         Reference< XPopupMenu > xMenu( awt::PopupMenu::create( m_xContext ) );
     887             :         DBG_ASSERT( xMenu.is(), "OImageControlControl::mousePressed: could not create a popup menu!" );
     888             : 
     889           0 :         Reference< XWindowPeer > xWindowPeer = getPeer();
     890             :         DBG_ASSERT( xWindowPeer.is(), "OImageControlControl::mousePressed: no window!" );
     891             : 
     892           0 :         if ( xMenu.is() && xWindowPeer.is() )
     893             :         {
     894           0 :             xMenu->insertItem( ID_OPEN_GRAPHICS, FRM_RES_STRING( RID_STR_OPEN_GRAPHICS ), 0, 0 );
     895           0 :             xMenu->insertItem( ID_CLEAR_GRAPHICS, FRM_RES_STRING( RID_STR_CLEAR_GRAPHICS ), 0, 1 );
     896             : 
     897             :             // check if the ImageURL is empty
     898           0 :             if ( impl_isEmptyGraphics_nothrow() )
     899           0 :                 xMenu->enableItem( ID_CLEAR_GRAPHICS, sal_False );
     900             : 
     901           0 :             awt::Rectangle aRect( e.X, e.Y, 0, 0 );
     902           0 :             if ( ( e.X < 0 ) || ( e.Y < 0 ) )
     903             :             {   // context menu triggered by keyboard
     904             :                 // position it in the center of the control
     905           0 :                 Reference< XWindow > xWindow( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY );
     906             :                 OSL_ENSURE( xWindow.is(), "OImageControlControl::mousePressed: me not a window? How this?" );
     907           0 :                 if ( xWindow.is() )
     908             :                 {
     909           0 :                     awt::Rectangle aPosSize = xWindow->getPosSize();
     910           0 :                     aRect.X = aPosSize.Width / 2;
     911           0 :                     aRect.Y = aPosSize.Height / 2;
     912           0 :                 }
     913             :             }
     914             : 
     915           0 :             const sal_Int16 nResult = xMenu->execute( xWindowPeer, aRect, PopupMenuDirection::EXECUTE_DEFAULT );
     916             : 
     917           0 :             switch ( nResult )
     918             :             {
     919             :             case ID_OPEN_GRAPHICS:
     920           0 :                 implInsertGraphics();
     921           0 :                 bModified = true;
     922           0 :                 break;
     923             : 
     924             :             case ID_CLEAR_GRAPHICS:
     925           0 :                 implClearGraphics( true );
     926           0 :                 bModified = true;
     927           0 :                 break;
     928             :             }
     929           0 :         }
     930             :     }
     931             :     else
     932             :     {
     933             : 
     934             :         // Double click
     935           0 :         if (e.ClickCount == 2)
     936             :         {
     937             : 
     938           0 :             Reference<XPropertySet>  xSet(getModel(), UNO_QUERY);
     939           0 :             if (!xSet.is())
     940           0 :                 return;
     941             : 
     942             :             // If the Control is not bound, do not display a dialog (because the to-be-sent URL would be invalid anyway)
     943           0 :             Reference<XPropertySet> xBoundField;
     944           0 :             if (hasProperty(PROPERTY_BOUNDFIELD, xSet))
     945             :                 xBoundField.set(
     946           0 :                     xSet->getPropertyValue(PROPERTY_BOUNDFIELD),
     947           0 :                     css::uno::UNO_QUERY);
     948           0 :             if (!xBoundField.is())
     949             :             {
     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           0 :                 if ( !hasProperty(PROPERTY_CONTROLSOURCE, xSet) || !::comphelper::getString(xSet->getPropertyValue(PROPERTY_CONTROLSOURCE)).isEmpty() )
     953           0 :                     return;
     954             :             }
     955             : 
     956           0 :             bool bReadOnly = false;
     957           0 :             xSet->getPropertyValue(PROPERTY_READONLY) >>= bReadOnly;
     958           0 :             if (bReadOnly)
     959           0 :                 return;
     960             : 
     961           0 :             if ( implInsertGraphics() )
     962           0 :                 bModified = true;
     963             :         }
     964             :     }
     965             : 
     966           0 :     if ( bModified )
     967             :     {
     968           0 :         EventObject aEvent( *this );
     969           0 :         m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
     970           0 :     }
     971             : }
     972             : 
     973             : 
     974           0 : void SAL_CALL OImageControlControl::mouseReleased(const awt::MouseEvent& /*e*/) throw ( RuntimeException, std::exception )
     975             : {
     976           0 : }
     977             : 
     978             : 
     979           0 : void SAL_CALL OImageControlControl::mouseEntered(const awt::MouseEvent& /*e*/) throw ( RuntimeException, std::exception )
     980             : {
     981           0 : }
     982             : 
     983             : 
     984           0 : void SAL_CALL OImageControlControl::mouseExited(const awt::MouseEvent& /*e*/) throw ( RuntimeException, std::exception )
     985             : {
     986           0 : }
     987             : 
     988             : }   // namespace frm
     989             : 
     990             : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
     991          10 : com_sun_star_form_OImageControlModel_get_implementation(::com::sun::star::uno::XComponentContext* component,
     992             :         ::com::sun::star::uno::Sequence<css::uno::Any> const &)
     993             : {
     994          10 :     return cppu::acquire(new frm::OImageControlModel(component));
     995             : }
     996             : 
     997             : extern "C" SAL_DLLPUBLIC_EXPORT ::com::sun::star::uno::XInterface* SAL_CALL
     998           2 : com_sun_star_form_OImageControlControl_get_implementation(::com::sun::star::uno::XComponentContext* component,
     999             :         ::com::sun::star::uno::Sequence<css::uno::Any> const &)
    1000             : {
    1001           2 :     return cppu::acquire(new frm::OImageControlControl(component));
    1002         138 : }
    1003             : 
    1004             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11