1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_forms.hxx" 30 #include "ImageControl.hxx" 31 32 #include "property.hrc" 33 #include "frm_resource.hrc" 34 #include "frm_resource.hxx" 35 #include "services.hxx" 36 #include "componenttools.hxx" 37 38 #include <svtools/imageresourceaccess.hxx> 39 #include <unotools/ucblockbytes.hxx> 40 #include <sfx2/filedlghelper.hxx> 41 #include <com/sun/star/awt/XPopupMenu.hpp> 42 #include <com/sun/star/awt/PopupMenuDirection.hpp> 43 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp> 44 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> 45 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> 46 #include <com/sun/star/ui/dialogs/XFilePicker.hpp> 47 #include <com/sun/star/sdbc/DataType.hpp> 48 #include <com/sun/star/awt/MouseButton.hpp> 49 #include <com/sun/star/awt/XWindow.hpp> 50 #include <com/sun/star/awt/XDialog.hpp> 51 #include <com/sun/star/io/XActiveDataSink.hpp> 52 #include <com/sun/star/io/NotConnectedException.hpp> 53 #include <com/sun/star/beans/PropertyValue.hpp> 54 #include <com/sun/star/graphic/XGraphic.hpp> 55 #include <com/sun/star/graphic/GraphicObject.hpp> 56 #include <tools/urlobj.hxx> 57 #include <tools/stream.hxx> 58 #include <tools/debug.hxx> 59 #include <tools/diagnose_ex.h> 60 #include <vcl/svapp.hxx> 61 #include <unotools/streamhelper.hxx> 62 #include <comphelper/extract.hxx> 63 #include <comphelper/guarding.hxx> 64 #include <unotools/ucbstreamhelper.hxx> 65 #include <svl/urihelper.hxx> 66 67 #include <memory> 68 69 #define ID_OPEN_GRAPHICS 1 70 #define ID_CLEAR_GRAPHICS 2 71 72 //......................................................................... 73 namespace frm 74 { 75 //......................................................................... 76 using namespace ::com::sun::star; 77 using namespace ::com::sun::star::uno; 78 using namespace ::com::sun::star::sdb; 79 using namespace ::com::sun::star::sdbc; 80 using namespace ::com::sun::star::sdbcx; 81 using namespace ::com::sun::star::beans; 82 using namespace ::com::sun::star::container; 83 using namespace ::com::sun::star::form; 84 using namespace ::com::sun::star::awt; 85 using namespace ::com::sun::star::io; 86 using namespace ::com::sun::star::ui::dialogs; 87 using namespace ::com::sun::star::lang; 88 using namespace ::com::sun::star::util; 89 using namespace ::com::sun::star::graphic; 90 using namespace ::com::sun::star::frame; 91 92 //============================================================================== 93 //= OImageControlModel 94 //============================================================================== 95 namespace 96 { 97 enum ImageStoreType 98 { 99 ImageStoreBinary, 100 ImageStoreLink, 101 102 ImageStoreInvalid 103 }; 104 105 ImageStoreType lcl_getImageStoreType( const sal_Int32 _nFieldType ) 106 { 107 // binary/longvarchar types could be used to store images in binary representation 108 if ( ( _nFieldType == DataType::BINARY ) 109 || ( _nFieldType == DataType::VARBINARY ) 110 || ( _nFieldType == DataType::LONGVARBINARY ) 111 || ( _nFieldType == DataType::OTHER ) 112 || ( _nFieldType == DataType::OBJECT ) 113 || ( _nFieldType == DataType::BLOB ) 114 || ( _nFieldType == DataType::LONGVARCHAR ) 115 || ( _nFieldType == DataType::CLOB ) 116 ) 117 return ImageStoreBinary; 118 119 // char types could be used to store links to images 120 if ( ( _nFieldType == DataType::CHAR ) 121 || ( _nFieldType == DataType::VARCHAR ) 122 ) 123 return ImageStoreLink; 124 125 return ImageStoreInvalid; 126 } 127 } 128 129 //============================================================================== 130 // OImageControlModel 131 //============================================================================== 132 133 //------------------------------------------------------------------------------ 134 InterfaceRef SAL_CALL OImageControlModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) 135 { 136 return *(new OImageControlModel(_rxFactory)); 137 } 138 139 //------------------------------------------------------------------------------ 140 Sequence<Type> OImageControlModel::_getTypes() 141 { 142 return concatSequences( 143 OBoundControlModel::_getTypes(), 144 OImageControlModel_Base::getTypes() 145 ); 146 } 147 148 DBG_NAME(OImageControlModel) 149 //------------------------------------------------------------------ 150 OImageControlModel::OImageControlModel(const Reference<XMultiServiceFactory>& _rxFactory) 151 :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_IMAGECONTROL, FRM_SUN_CONTROL_IMAGECONTROL, sal_False, sal_False, sal_False ) 152 // use the old control name for compytibility reasons 153 ,m_pImageProducer( NULL ) 154 ,m_bExternalGraphic( true ) 155 ,m_bReadOnly( sal_False ) 156 ,m_sImageURL() 157 ,m_xGraphicObject() 158 { 159 DBG_CTOR( OImageControlModel, NULL ); 160 m_nClassId = FormComponentType::IMAGECONTROL; 161 initOwnValueProperty( PROPERTY_IMAGE_URL ); 162 163 implConstruct(); 164 } 165 166 //------------------------------------------------------------------ 167 OImageControlModel::OImageControlModel( const OImageControlModel* _pOriginal, const Reference< XMultiServiceFactory >& _rxFactory ) 168 :OBoundControlModel( _pOriginal, _rxFactory ) 169 // use the old control name for compytibility reasons 170 ,m_pImageProducer( NULL ) 171 ,m_bExternalGraphic( true ) 172 ,m_bReadOnly( _pOriginal->m_bReadOnly ) 173 ,m_sImageURL( _pOriginal->m_sImageURL ) 174 ,m_xGraphicObject( _pOriginal->m_xGraphicObject ) 175 { 176 DBG_CTOR( OImageControlModel, NULL ); 177 implConstruct(); 178 179 osl_incrementInterlockedCount( &m_refCount ); 180 { 181 // simulate a propertyChanged event for the ImageURL 182 // 2003-05-15 - #109591# - fs@openoffice.org 183 ::osl::MutexGuard aGuard( m_aMutex ); 184 impl_handleNewImageURL_lck( eOther ); 185 } 186 osl_decrementInterlockedCount( &m_refCount ); 187 } 188 189 //------------------------------------------------------------------ 190 void OImageControlModel::implConstruct() 191 { 192 m_pImageProducer = new ImageProducer; 193 m_xImageProducer = m_pImageProducer; 194 m_pImageProducer->SetDoneHdl( LINK( this, OImageControlModel, OnImageImportDone ) ); 195 } 196 197 //------------------------------------------------------------------ 198 OImageControlModel::~OImageControlModel() 199 { 200 if (!OComponentHelper::rBHelper.bDisposed) 201 { 202 acquire(); 203 dispose(); 204 } 205 206 DBG_DTOR(OImageControlModel,NULL); 207 } 208 209 // XCloneable 210 //------------------------------------------------------------------------------ 211 IMPLEMENT_DEFAULT_CLONING( OImageControlModel ) 212 213 // XServiceInfo 214 //------------------------------------------------------------------------------ 215 StringSequence OImageControlModel::getSupportedServiceNames() throw() 216 { 217 StringSequence aSupported = OBoundControlModel::getSupportedServiceNames(); 218 aSupported.realloc(aSupported.getLength() + 1); 219 220 ::rtl::OUString*pArray = aSupported.getArray(); 221 pArray[aSupported.getLength()-1] = FRM_SUN_COMPONENT_IMAGECONTROL; 222 return aSupported; 223 } 224 225 //------------------------------------------------------------------------------ 226 Any SAL_CALL OImageControlModel::queryAggregation(const Type& _rType) throw (RuntimeException) 227 { 228 // oder matters: we want to "override" the XImageProducer interface of the aggreate with out 229 // own XImageProducer interface, thus we need to query OImageControlModel_Base first 230 Any aReturn = OImageControlModel_Base::queryInterface( _rType ); 231 232 // BUT: _don't_ let it feel responsible for the XTypeProvider interface 233 // (as this is implemented by our base class in the proper way) 234 if ( _rType.equals( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) ) 235 || !aReturn.hasValue() 236 ) 237 aReturn = OBoundControlModel::queryAggregation( _rType ); 238 239 return aReturn; 240 } 241 242 //------------------------------------------------------------------------------ 243 sal_Bool OImageControlModel::approveDbColumnType( sal_Int32 _nColumnType ) 244 { 245 return ImageStoreInvalid != lcl_getImageStoreType( _nColumnType ); 246 } 247 248 //------------------------------------------------------------------------------ 249 void OImageControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const 250 { 251 switch (nHandle) 252 { 253 case PROPERTY_ID_READONLY: 254 rValue <<= (sal_Bool)m_bReadOnly; 255 break; 256 case PROPERTY_ID_IMAGE_URL: 257 rValue <<= m_sImageURL; 258 break; 259 case PROPERTY_ID_GRAPHIC: 260 rValue <<= m_xGraphicObject.is() ? m_xGraphicObject->getGraphic() : Reference< XGraphic >(); 261 break; 262 default: 263 OBoundControlModel::getFastPropertyValue(rValue, nHandle); 264 } 265 } 266 267 //------------------------------------------------------------------------------ 268 void OImageControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) throw ( ::com::sun::star::uno::Exception) 269 { 270 switch (nHandle) 271 { 272 case PROPERTY_ID_READONLY : 273 DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "OImageControlModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 274 m_bReadOnly = getBOOL(rValue); 275 break; 276 277 case PROPERTY_ID_IMAGE_URL: 278 OSL_VERIFY( rValue >>= m_sImageURL ); 279 impl_handleNewImageURL_lck( eOther ); 280 { 281 ControlModelLock aLock( *this ); 282 // that's a fake ... onValuePropertyChange expects to receive the only lock to our instance, 283 // but we're already called with our mutex locked ... 284 onValuePropertyChange( aLock ); 285 } 286 break; 287 288 case PROPERTY_ID_GRAPHIC: 289 { 290 Reference< XGraphic > xGraphic; 291 OSL_VERIFY( rValue >>= xGraphic ); 292 if ( !xGraphic.is() ) 293 m_xGraphicObject.clear(); 294 else 295 { 296 m_xGraphicObject = GraphicObject::create( m_aContext.getUNOContext() ); 297 m_xGraphicObject->setGraphic( xGraphic ); 298 } 299 300 if ( m_bExternalGraphic ) 301 { 302 // if that's an external graphic, i.e. one which has not been loaded by ourselves in response to a 303 // new image URL, then also adjust our ImageURL. 304 ::rtl::OUString sNewImageURL; 305 if ( m_xGraphicObject.is() ) 306 { 307 sNewImageURL = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.GraphicObject:" ) ); 308 sNewImageURL = sNewImageURL + m_xGraphicObject->getUniqueID(); 309 } 310 m_sImageURL = sNewImageURL; 311 // TODO: speaking strictly, this would need to be notified, since ImageURL is a bound property. However, 312 // this method here is called with a locked mutex, so we cannot simply call listeners ... 313 // I think the missing notification (and thus clients which potentially cannot observe the change) 314 // is less severe than the potential deadlock ... 315 } 316 } 317 break; 318 319 default: 320 OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue); 321 break; 322 } 323 } 324 325 //------------------------------------------------------------------------------ 326 sal_Bool OImageControlModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue) 327 throw( IllegalArgumentException ) 328 { 329 switch (nHandle) 330 { 331 case PROPERTY_ID_READONLY : 332 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bReadOnly); 333 334 case PROPERTY_ID_IMAGE_URL: 335 return tryPropertyValue( rConvertedValue, rOldValue, rValue, m_sImageURL ); 336 337 case PROPERTY_ID_GRAPHIC: 338 { 339 const Reference< XGraphic > xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC ), UNO_QUERY ); 340 return tryPropertyValue( rConvertedValue, rOldValue, rValue, xGraphic ); 341 } 342 343 default: 344 return OBoundControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue); 345 } 346 } 347 348 //------------------------------------------------------------------------------ 349 void OImageControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const 350 { 351 BEGIN_DESCRIBE_PROPERTIES( 4, OBoundControlModel ) 352 DECL_IFACE_PROP2( GRAPHIC, XGraphic, BOUND, TRANSIENT ); 353 DECL_PROP1 ( IMAGE_URL, ::rtl::OUString, BOUND ); 354 DECL_BOOL_PROP1 ( READONLY, BOUND ); 355 DECL_PROP1 ( TABINDEX, sal_Int16, BOUND ); 356 END_DESCRIBE_PROPERTIES(); 357 } 358 359 //------------------------------------------------------------------------------ 360 void OImageControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ o_rAggregateProperties ) const 361 { 362 OBoundControlModel::describeAggregateProperties( o_rAggregateProperties ); 363 // remove ImageULR and Graphic properties, we "overload" them. This is because our aggregate synchronizes those 364 // two, but we have an own sychronization mechanism. 365 RemoveProperty( o_rAggregateProperties, PROPERTY_IMAGE_URL ); 366 RemoveProperty( o_rAggregateProperties, PROPERTY_GRAPHIC ); 367 } 368 369 //------------------------------------------------------------------------------ 370 ::rtl::OUString OImageControlModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException) 371 { 372 return FRM_COMPONENT_IMAGECONTROL; // old (non-sun) name for compatibility ! 373 } 374 375 //------------------------------------------------------------------------------ 376 void OImageControlModel::write(const Reference<XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) 377 { 378 // Basisklasse 379 OBoundControlModel::write(_rxOutStream); 380 // Version 381 _rxOutStream->writeShort(0x0003); 382 // Name 383 _rxOutStream->writeBoolean(m_bReadOnly); 384 writeHelpTextCompatibly(_rxOutStream); 385 // from version 0x0003 : common properties 386 writeCommonProperties(_rxOutStream); 387 } 388 389 //------------------------------------------------------------------------------ 390 void OImageControlModel::read(const Reference<XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) 391 { 392 OBoundControlModel::read(_rxInStream); 393 394 // Version 395 sal_uInt16 nVersion = _rxInStream->readShort(); 396 switch (nVersion) 397 { 398 case 0x0001: 399 m_bReadOnly = _rxInStream->readBoolean(); 400 break; 401 case 0x0002: 402 m_bReadOnly = _rxInStream->readBoolean(); 403 readHelpTextCompatibly(_rxInStream); 404 break; 405 case 0x0003: 406 m_bReadOnly = _rxInStream->readBoolean(); 407 readHelpTextCompatibly(_rxInStream); 408 readCommonProperties(_rxInStream); 409 break; 410 default : 411 DBG_ERROR("OImageControlModel::read : unknown version !"); 412 m_bReadOnly = sal_False; 413 defaultCommonProperties(); 414 break; 415 } 416 // Nach dem Lesen die Defaultwerte anzeigen 417 if ( getControlSource().getLength() ) 418 { // (not if we don't have a control source - the "State" property acts like it is persistent, then 419 ::osl::MutexGuard aGuard(m_aMutex); // resetNoBroadcast expects this mutex guarding 420 resetNoBroadcast(); 421 } 422 } 423 424 //------------------------------------------------------------------------------ 425 sal_Bool OImageControlModel::impl_updateStreamForURL_lck( const ::rtl::OUString& _rURL, ValueChangeInstigator _eInstigator ) 426 { 427 // create a stream for the image specified by the URL 428 ::std::auto_ptr< SvStream > pImageStream; 429 Reference< XInputStream > xImageStream; 430 431 if ( ::svt::GraphicAccess::isSupportedURL( _rURL ) ) 432 { 433 xImageStream = ::svt::GraphicAccess::getImageXStream( getContext().getLegacyServiceFactory(), _rURL ); 434 } 435 else 436 { 437 pImageStream.reset( ::utl::UcbStreamHelper::CreateStream( _rURL, STREAM_READ ) ); 438 sal_Bool bSetNull = ( pImageStream.get() == NULL ) || ( ERRCODE_NONE != pImageStream->GetErrorCode() ); 439 440 if ( !bSetNull ) 441 { 442 // get the size of the stream 443 pImageStream->Seek(STREAM_SEEK_TO_END); 444 sal_Int32 nSize = (sal_Int32)pImageStream->Tell(); 445 if (pImageStream->GetBufferSize() < 8192) 446 pImageStream->SetBufferSize(8192); 447 pImageStream->Seek(STREAM_SEEK_TO_BEGIN); 448 449 xImageStream = new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream.get(), sal_False ), nSize ); 450 } 451 } 452 453 if ( xImageStream.is() ) 454 { 455 if ( m_xColumnUpdate.is() ) 456 m_xColumnUpdate->updateBinaryStream( xImageStream, xImageStream->available() ); 457 else 458 setControlValue( makeAny( xImageStream ), _eInstigator ); 459 xImageStream->closeInput(); 460 return sal_True; 461 } 462 463 return sal_False; 464 } 465 466 //------------------------------------------------------------------------------ 467 sal_Bool OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator ) 468 { 469 switch ( lcl_getImageStoreType( getFieldType() ) ) 470 { 471 case ImageStoreBinary: 472 if ( impl_updateStreamForURL_lck( m_sImageURL, _eInstigator ) ) 473 return sal_True; 474 break; 475 476 case ImageStoreLink: 477 { 478 ::rtl::OUString sCommitURL( m_sImageURL ); 479 if ( m_sDocumentURL.getLength() ) 480 sCommitURL = URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL, sCommitURL ); 481 OSL_ENSURE( m_xColumnUpdate.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" ); 482 if ( m_xColumnUpdate.is() ) 483 { 484 m_xColumnUpdate->updateString( sCommitURL ); 485 return sal_True; 486 } 487 } 488 break; 489 490 case ImageStoreInvalid: 491 OSL_ENSURE( false, "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" ); 492 break; 493 } 494 495 // if we're here, then the above code was unable to update our field/control from the given URL 496 // => fall back to NULL/VOID 497 if ( m_xColumnUpdate.is() ) 498 m_xColumnUpdate->updateNull(); 499 else 500 setControlValue( Any(), _eInstigator ); 501 502 return sal_True; 503 } 504 505 //------------------------------------------------------------------------------ 506 sal_Bool OImageControlModel::commitControlValueToDbColumn( bool _bPostReset ) 507 { 508 if ( _bPostReset ) 509 { 510 // since this is a "commit after reset", we can simply update the column 511 // with null - this is our "default" which we were just reset to 512 if ( m_xColumnUpdate.is() ) 513 m_xColumnUpdate->updateNull(); 514 } 515 else 516 { 517 ::osl::MutexGuard aGuard(m_aMutex); 518 return impl_handleNewImageURL_lck( eDbColumnBinding ); 519 } 520 521 return sal_True; 522 } 523 524 //------------------------------------------------------------------------------ 525 namespace 526 { 527 bool lcl_isValidDocumentURL( const ::rtl::OUString& _rDocURL ) 528 { 529 return ( _rDocURL.getLength() && !_rDocURL.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "private:object" ) ) ); 530 } 531 } 532 533 //------------------------------------------------------------------------------ 534 void OImageControlModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm ) 535 { 536 OBoundControlModel::onConnectedDbColumn( _rxForm ); 537 538 try 539 { 540 Reference< XModel > xDocument( getXModel( *this ) ); 541 if ( xDocument.is() ) 542 { 543 m_sDocumentURL = xDocument->getURL(); 544 if ( !lcl_isValidDocumentURL( m_sDocumentURL ) ) 545 { 546 Reference< XChild > xAsChild( xDocument, UNO_QUERY ); 547 while ( xAsChild.is() && !lcl_isValidDocumentURL( m_sDocumentURL ) ) 548 { 549 xDocument.set( xAsChild->getParent(), UNO_QUERY ); 550 if ( xDocument.is() ) 551 m_sDocumentURL = xDocument->getURL(); 552 xAsChild.set( xDocument, UNO_QUERY ); 553 } 554 } 555 } 556 } 557 catch( const Exception& ) 558 { 559 DBG_UNHANDLED_EXCEPTION(); 560 } 561 } 562 563 //------------------------------------------------------------------------------ 564 void OImageControlModel::onDisconnectedDbColumn() 565 { 566 OBoundControlModel::onDisconnectedDbColumn(); 567 568 m_sDocumentURL = ::rtl::OUString(); 569 } 570 571 //------------------------------------------------------------------------------ 572 Any OImageControlModel::translateDbColumnToControlValue() 573 { 574 switch ( lcl_getImageStoreType( getFieldType() ) ) 575 { 576 case ImageStoreBinary: 577 { 578 Reference< XInputStream > xImageStream( m_xColumn->getBinaryStream() ); 579 if ( m_xColumn->wasNull() ) 580 xImageStream.clear(); 581 return makeAny( xImageStream ); 582 } 583 case ImageStoreLink: 584 { 585 ::rtl::OUString sImageLink( m_xColumn->getString() ); 586 if ( m_sDocumentURL.getLength() ) 587 sImageLink = INetURLObject::GetAbsURL( m_sDocumentURL, sImageLink ); 588 return makeAny( sImageLink ); 589 } 590 case ImageStoreInvalid: 591 OSL_ENSURE( false, "OImageControlModel::translateDbColumnToControlValue: invalid field type!" ); 592 break; 593 } 594 return Any(); 595 } 596 597 //------------------------------------------------------------------------------ 598 Any OImageControlModel::getControlValue( ) const 599 { 600 return makeAny( m_sImageURL ); 601 } 602 603 //------------------------------------------------------------------------------ 604 void OImageControlModel::doSetControlValue( const Any& _rValue ) 605 { 606 DBG_ASSERT( GetImageProducer() && m_xImageProducer.is(), "OImageControlModel::doSetControlValue: no image producer!" ); 607 if ( !GetImageProducer() || !m_xImageProducer.is() ) 608 return; 609 610 bool bStartProduction = false; 611 switch ( lcl_getImageStoreType( getFieldType() ) ) 612 { 613 case ImageStoreBinary: 614 { 615 // give the image producer the stream 616 Reference< XInputStream > xInStream; 617 _rValue >>= xInStream; 618 GetImageProducer()->setImage( xInStream ); 619 bStartProduction = true; 620 } 621 break; 622 623 case ImageStoreLink: 624 { 625 ::rtl::OUString sImageURL; 626 _rValue >>= sImageURL; 627 GetImageProducer()->SetImage( sImageURL ); 628 bStartProduction = true; 629 } 630 break; 631 632 case ImageStoreInvalid: 633 OSL_ENSURE( false, "OImageControlModel::doSetControlValue: invalid field type!" ); 634 break; 635 636 } // switch ( lcl_getImageStoreType( getFieldType() ) ) 637 638 if ( bStartProduction ) 639 { 640 // start production 641 Reference< XImageProducer > xProducer = m_xImageProducer; 642 { 643 // release our mutex once (it's acquired in the calling method!), as starting the image production may 644 // result in the locking of the solar mutex (unfortunally the default implementation of our aggregate, 645 // VCLXImageControl, does this locking) 646 // FS - 74438 - 30.03.00 647 MutexRelease aRelease(m_aMutex); 648 xProducer->startProduction(); 649 } 650 } 651 } 652 653 // OComponentHelper 654 //------------------------------------------------------------------ 655 void SAL_CALL OImageControlModel::disposing() 656 { 657 OBoundControlModel::disposing(); 658 } 659 660 //------------------------------------------------------------------------------ 661 void OImageControlModel::resetNoBroadcast() 662 { 663 if ( hasField() ) // only reset when we are connected to a column 664 OBoundControlModel::resetNoBroadcast( ); 665 } 666 667 //-------------------------------------------------------------------- 668 Reference< XImageProducer > SAL_CALL OImageControlModel::getImageProducer() throw ( RuntimeException) 669 { 670 return this; 671 } 672 673 //-------------------------------------------------------------------- 674 void SAL_CALL OImageControlModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) 675 { 676 GetImageProducer()->addConsumer( _rxConsumer ); 677 } 678 679 //-------------------------------------------------------------------- 680 void SAL_CALL OImageControlModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) 681 { 682 GetImageProducer()->removeConsumer( _rxConsumer ); 683 } 684 685 //-------------------------------------------------------------------- 686 void SAL_CALL OImageControlModel::startProduction( ) throw (RuntimeException) 687 { 688 GetImageProducer()->startProduction(); 689 } 690 691 //------------------------------------------------------------------------------ 692 IMPL_LINK( OImageControlModel, OnImageImportDone, ::Graphic*, i_pGraphic ) 693 { 694 const Reference< XGraphic > xGraphic( i_pGraphic != NULL ? Image( i_pGraphic->GetBitmapEx() ).GetXGraphic() : NULL ); 695 m_bExternalGraphic = false; 696 try 697 { 698 setPropertyValue( PROPERTY_GRAPHIC, makeAny( xGraphic ) ); 699 } 700 catch ( const Exception& ) 701 { 702 DBG_UNHANDLED_EXCEPTION(); 703 } 704 m_bExternalGraphic = true; 705 return 1L; 706 } 707 708 //================================================================== 709 // OImageControlControl 710 //================================================================== 711 712 //------------------------------------------------------------------ 713 InterfaceRef SAL_CALL OImageControlControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory) 714 { 715 return *(new OImageControlControl(_rxFactory)); 716 } 717 718 //------------------------------------------------------------------------------ 719 Sequence<Type> OImageControlControl::_getTypes() 720 { 721 return concatSequences( 722 OBoundControl::_getTypes(), 723 OImageControlControl_Base::getTypes() 724 ); 725 } 726 727 //------------------------------------------------------------------------------ 728 OImageControlControl::OImageControlControl(const Reference<XMultiServiceFactory>& _rxFactory) 729 :OBoundControl(_rxFactory, VCL_CONTROL_IMAGECONTROL) 730 ,m_aModifyListeners( m_aMutex ) 731 { 732 increment(m_refCount); 733 { 734 // als Focus- und MouseListener anmelden 735 Reference< XWindow > xComp; 736 query_aggregation( m_xAggregate, xComp ); 737 if ( xComp.is() ) 738 xComp->addMouseListener( this ); 739 } 740 decrement(m_refCount); 741 } 742 743 //------------------------------------------------------------------------------ 744 Any SAL_CALL OImageControlControl::queryAggregation(const Type& _rType) throw (RuntimeException) 745 { 746 Any aReturn = OBoundControl::queryAggregation( _rType ); 747 if ( !aReturn.hasValue() ) 748 aReturn = ::cppu::queryInterface( 749 _rType, 750 static_cast< XMouseListener* >( this ), 751 static_cast< XModifyBroadcaster* >( this ) 752 ); 753 754 return aReturn; 755 } 756 757 //------------------------------------------------------------------------------ 758 StringSequence OImageControlControl::getSupportedServiceNames() throw() 759 { 760 StringSequence aSupported = OBoundControl::getSupportedServiceNames(); 761 aSupported.realloc(aSupported.getLength() + 1); 762 763 ::rtl::OUString*pArray = aSupported.getArray(); 764 pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_IMAGECONTROL; 765 return aSupported; 766 } 767 768 //------------------------------------------------------------------------------ 769 void SAL_CALL OImageControlControl::addModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException) 770 { 771 m_aModifyListeners.addInterface( _Listener ); 772 } 773 774 //------------------------------------------------------------------------------ 775 void SAL_CALL OImageControlControl::removeModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException) 776 { 777 m_aModifyListeners.removeInterface( _Listener ); 778 } 779 780 //------------------------------------------------------------------------------ 781 void SAL_CALL OImageControlControl::disposing() 782 { 783 EventObject aEvent( *this ); 784 m_aModifyListeners.disposeAndClear( aEvent ); 785 786 OBoundControl::disposing(); 787 } 788 789 //------------------------------------------------------------------------------ 790 void SAL_CALL OImageControlControl::disposing( const EventObject& _Event ) throw(RuntimeException) 791 { 792 OBoundControl::disposing( _Event ); 793 } 794 795 //------------------------------------------------------------------------------ 796 void OImageControlControl::implClearGraphics( sal_Bool _bForce ) 797 { 798 Reference< XPropertySet > xSet( getModel(), UNO_QUERY ); 799 if ( xSet.is() ) 800 { 801 if ( _bForce ) 802 { 803 ::rtl::OUString sOldImageURL; 804 xSet->getPropertyValue( PROPERTY_IMAGE_URL ) >>= sOldImageURL; 805 806 if ( !sOldImageURL.getLength() ) 807 // the ImageURL is already empty, so simply setting a new empty one would not suffice 808 // (since it would be ignored) 809 xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:emptyImage" ) ) ) ); 810 // (the concrete URL we're passing here doens't matter. It's important that 811 // the model cannot resolve it to a a valid resource describing an image stream 812 } 813 814 xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString() ) ); 815 } 816 } 817 818 //------------------------------------------------------------------------------ 819 bool OImageControlControl::implInsertGraphics() 820 { 821 Reference< XPropertySet > xSet( getModel(), UNO_QUERY ); 822 if ( !xSet.is() ) 823 return false; 824 825 ::rtl::OUString sTitle = FRM_RES_STRING(RID_STR_IMPORT_GRAPHIC); 826 // build some arguments for the upcoming dialog 827 try 828 { 829 ::sfx2::FileDialogHelper aDialog( TemplateDescription::FILEOPEN_LINK_PREVIEW, SFXWB_GRAPHIC ); 830 aDialog.SetTitle( sTitle ); 831 832 Reference< XFilePickerControlAccess > xController( aDialog.GetFilePicker(), UNO_QUERY_THROW ); 833 xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, ::cppu::bool2any(sal_True)); 834 835 Reference<XPropertySet> xBoundField; 836 if ( hasProperty( PROPERTY_BOUNDFIELD, xSet ) ) 837 xSet->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xBoundField; 838 sal_Bool bHasField = xBoundField.is(); 839 840 // if the control is bound to a DB field, then it's not possible to decide whether or not to link 841 xController->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK, !bHasField ); 842 843 // if the control is bound to a DB field, then linking of the image depends on the type of the field 844 sal_Bool bImageIsLinked = sal_True; 845 if ( bHasField ) 846 { 847 sal_Int32 nFieldType = DataType::OTHER; 848 OSL_VERIFY( xBoundField->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType ); 849 bImageIsLinked = ( lcl_getImageStoreType( nFieldType ) == ImageStoreLink ); 850 } 851 xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, makeAny( bImageIsLinked ) ); 852 853 if ( ERRCODE_NONE == aDialog.Execute() ) 854 { 855 // reset the url property in case it already has the value we're about to set - in this case 856 // our propertyChanged would not get called without this. 857 implClearGraphics( sal_False ); 858 sal_Bool bIsLink = sal_False; 859 xController->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0) >>= bIsLink; 860 // Force bIsLink to be sal_True if we're bound to a field. Though we initialized the file picker with IsLink=TRUE 861 // in this case, and disabled the respective control, there might be picker implementations which do not 862 // respect this, and return IsLink=FALSE here. In this case, "normalize" the flag. 863 // #i112659# / 2010-08-26 / frank.schoenheit@oracle.com 864 bIsLink |= bHasField; 865 if ( !bIsLink ) 866 { 867 Graphic aGraphic; 868 aDialog.GetGraphic( aGraphic ); 869 xSet->setPropertyValue( PROPERTY_GRAPHIC, makeAny( aGraphic.GetXGraphic() ) ); 870 } 871 else 872 xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString( aDialog.GetPath() ) ) ); 873 874 return true; 875 } 876 } 877 catch(Exception&) 878 { 879 DBG_ERROR("OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!"); 880 } 881 return false; 882 } 883 884 //------------------------------------------------------------------------------ 885 bool OImageControlControl::impl_isEmptyGraphics_nothrow() const 886 { 887 bool bIsEmpty = true; 888 889 try 890 { 891 Reference< XPropertySet > xModelProps( const_cast< OImageControlControl* >( this )->getModel(), UNO_QUERY_THROW ); 892 Reference< XGraphic > xGraphic; 893 OSL_VERIFY( xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Graphic" ) ) ) >>= xGraphic ); 894 bIsEmpty = !xGraphic.is(); 895 } 896 catch( const Exception& ) 897 { 898 DBG_UNHANDLED_EXCEPTION(); 899 } 900 901 return bIsEmpty; 902 } 903 904 // MouseListener 905 //------------------------------------------------------------------------------ 906 void OImageControlControl::mousePressed(const ::com::sun::star::awt::MouseEvent& e) throw ( ::com::sun::star::uno::RuntimeException) 907 { 908 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 909 910 if (e.Buttons != MouseButton::LEFT) 911 return; 912 913 bool bModified = false; 914 // is this a request for a context menu? 915 if ( e.PopupTrigger ) 916 { 917 Reference< XPopupMenu > xMenu( m_aContext.createComponent( "com.sun.star.awt.PopupMenu" ), UNO_QUERY ); 918 DBG_ASSERT( xMenu.is(), "OImageControlControl::mousePressed: could not create a popup menu!" ); 919 920 Reference< XWindowPeer > xWindowPeer = getPeer(); 921 DBG_ASSERT( xWindowPeer.is(), "OImageControlControl::mousePressed: no window!" ); 922 923 if ( xMenu.is() && xWindowPeer.is() ) 924 { 925 xMenu->insertItem( ID_OPEN_GRAPHICS, FRM_RES_STRING( RID_STR_OPEN_GRAPHICS ), 0, 0 ); 926 xMenu->insertItem( ID_CLEAR_GRAPHICS, FRM_RES_STRING( RID_STR_CLEAR_GRAPHICS ), 0, 1 ); 927 928 // check if the ImageURL is empty 929 if ( impl_isEmptyGraphics_nothrow() ) 930 xMenu->enableItem( ID_CLEAR_GRAPHICS, sal_False ); 931 932 awt::Rectangle aRect( e.X, e.Y, 0, 0 ); 933 if ( ( e.X < 0 ) || ( e.Y < 0 ) ) 934 { // context menu triggered by keyboard 935 // position it in the center of the control 936 // 102205 - 16.08.2002 - fs@openoffice.org 937 Reference< XWindow > xWindow( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY ); 938 OSL_ENSURE( xWindow.is(), "OImageControlControl::mousePressed: me not a window? How this?" ); 939 if ( xWindow.is() ) 940 { 941 awt::Rectangle aPosSize = xWindow->getPosSize(); 942 aRect.X = aPosSize.Width / 2; 943 aRect.Y = aPosSize.Height / 2; 944 } 945 } 946 947 const sal_Int16 nResult = xMenu->execute( xWindowPeer, aRect, PopupMenuDirection::EXECUTE_DEFAULT ); 948 949 switch ( nResult ) 950 { 951 case ID_OPEN_GRAPHICS: 952 implInsertGraphics(); 953 bModified = true; 954 break; 955 956 case ID_CLEAR_GRAPHICS: 957 implClearGraphics( sal_True ); 958 bModified = true; 959 break; 960 } 961 } 962 } 963 else 964 { 965 ////////////////////////////////////////////////////////////////////// 966 // Doppelclick 967 if (e.ClickCount == 2) 968 { 969 970 Reference<XPropertySet> xSet(getModel(), UNO_QUERY); 971 if (!xSet.is()) 972 return; 973 974 // wenn Control nicht gebunden ist, kein Dialog (da die zu schickende URL hinterher sowieso 975 // versanden wuerde) 976 // FS - #64946# - 19.04.99 977 Reference<XPropertySet> xBoundField; 978 if (hasProperty(PROPERTY_BOUNDFIELD, xSet)) 979 ::cppu::extractInterface(xBoundField, xSet->getPropertyValue(PROPERTY_BOUNDFIELD)); 980 if (!xBoundField.is()) 981 { 982 // but only if our IMAGE_URL property is handled as if it is transient, which is equivalent to 983 // an empty control source 984 if (!hasProperty(PROPERTY_CONTROLSOURCE, xSet) || (::comphelper::getString(xSet->getPropertyValue(PROPERTY_CONTROLSOURCE)).getLength() != 0)) 985 return; 986 } 987 988 sal_Bool bReadOnly = false; 989 xSet->getPropertyValue(PROPERTY_READONLY) >>= bReadOnly; 990 if (bReadOnly) 991 return; 992 993 if ( implInsertGraphics() ) 994 bModified = true; 995 } 996 } 997 998 if ( bModified ) 999 { 1000 EventObject aEvent( *this ); 1001 m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); 1002 } 1003 } 1004 1005 //------------------------------------------------------------------------------ 1006 void SAL_CALL OImageControlControl::mouseReleased(const awt::MouseEvent& /*e*/) throw ( RuntimeException ) 1007 { 1008 } 1009 1010 //------------------------------------------------------------------------------ 1011 void SAL_CALL OImageControlControl::mouseEntered(const awt::MouseEvent& /*e*/) throw ( RuntimeException ) 1012 { 1013 } 1014 1015 //------------------------------------------------------------------------------ 1016 void SAL_CALL OImageControlControl::mouseExited(const awt::MouseEvent& /*e*/) throw ( RuntimeException ) 1017 { 1018 } 1019 1020 //......................................................................... 1021 } // namespace frm 1022 //......................................................................... 1023 1024