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 "clickableimage.hxx" 31 #include "controlfeatureinterception.hxx" 32 #include "urltransformer.hxx" 33 #include "componenttools.hxx" 34 #include <com/sun/star/form/XSubmit.hpp> 35 #include <com/sun/star/awt/SystemPointer.hpp> 36 #include <com/sun/star/form/FormComponentType.hpp> 37 #include <com/sun/star/frame/XDispatch.hpp> 38 #include <com/sun/star/frame/XDispatchProvider.hpp> 39 #include <com/sun/star/frame/FrameSearchFlag.hpp> 40 #include <com/sun/star/frame/XController.hpp> 41 #include <com/sun/star/frame/XFrame.hpp> 42 #include <com/sun/star/awt/ActionEvent.hpp> 43 #include <com/sun/star/awt/XActionListener.hpp> 44 #include <tools/urlobj.hxx> 45 #include <tools/debug.hxx> 46 #include <vcl/svapp.hxx> 47 #include <sfx2/docfile.hxx> 48 #include <sfx2/objsh.hxx> 49 #include <vos/mutex.hxx> 50 #include "services.hxx" 51 #include <comphelper/container.hxx> 52 #include <comphelper/listenernotification.hxx> 53 #include <svtools/imageresourceaccess.hxx> 54 #define LOCAL_URL_PREFIX '#' 55 56 //......................................................................... 57 namespace frm 58 { 59 //......................................................................... 60 61 using namespace ::com::sun::star::uno; 62 using namespace ::com::sun::star::sdb; 63 using namespace ::com::sun::star::sdbc; 64 using namespace ::com::sun::star::sdbcx; 65 using namespace ::com::sun::star::beans; 66 using namespace ::com::sun::star::container; 67 using namespace ::com::sun::star::form; 68 using namespace ::com::sun::star::awt; 69 using namespace ::com::sun::star::io; 70 using namespace ::com::sun::star::lang; 71 using namespace ::com::sun::star::util; 72 using namespace ::com::sun::star::frame; 73 using namespace ::com::sun::star::form::submission; 74 using ::com::sun::star::awt::MouseEvent; 75 using ::com::sun::star::task::XInteractionHandler; 76 77 //================================================================== 78 // OClickableImageBaseControl 79 //================================================================== 80 //------------------------------------------------------------------------------ 81 Sequence<Type> OClickableImageBaseControl::_getTypes() 82 { 83 static Sequence<Type> aTypes; 84 if (!aTypes.getLength()) 85 aTypes = concatSequences(OControl::_getTypes(), OClickableImageBaseControl_BASE::getTypes()); 86 return aTypes; 87 } 88 89 //------------------------------------------------------------------------------ 90 OClickableImageBaseControl::OClickableImageBaseControl(const Reference<XMultiServiceFactory>& _rxFactory, const ::rtl::OUString& _aService) 91 :OControl(_rxFactory, _aService) 92 ,m_pThread(NULL) 93 ,m_aSubmissionVetoListeners( m_aMutex ) 94 ,m_aApproveActionListeners( m_aMutex ) 95 ,m_aActionListeners( m_aMutex ) 96 { 97 m_pFeatureInterception.reset( new ControlFeatureInterception( _rxFactory ) ); 98 } 99 100 //------------------------------------------------------------------------------ 101 OClickableImageBaseControl::~OClickableImageBaseControl() 102 { 103 if (!OComponentHelper::rBHelper.bDisposed) 104 { 105 acquire(); 106 dispose(); 107 } 108 } 109 110 // UNO Anbindung 111 //------------------------------------------------------------------------------ 112 Any SAL_CALL OClickableImageBaseControl::queryAggregation(const Type& _rType) throw (RuntimeException) 113 { 114 Any aReturn = OControl::queryAggregation(_rType); 115 if (!aReturn.hasValue()) 116 aReturn = OClickableImageBaseControl_BASE::queryInterface(_rType); 117 return aReturn; 118 } 119 120 // XApproveActionBroadcaster 121 //------------------------------------------------------------------------------ 122 void OClickableImageBaseControl::addApproveActionListener( 123 const Reference<XApproveActionListener>& l) throw( RuntimeException ) 124 { 125 m_aApproveActionListeners.addInterface(l); 126 } 127 128 //------------------------------------------------------------------------------ 129 void OClickableImageBaseControl::removeApproveActionListener( 130 const Reference<XApproveActionListener>& l) throw( RuntimeException ) 131 { 132 m_aApproveActionListeners.removeInterface(l); 133 } 134 135 //-------------------------------------------------------------------- 136 void SAL_CALL OClickableImageBaseControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException) 137 { 138 m_pFeatureInterception->registerDispatchProviderInterceptor( _rxInterceptor ); 139 } 140 141 //-------------------------------------------------------------------- 142 void SAL_CALL OClickableImageBaseControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException) 143 { 144 m_pFeatureInterception->releaseDispatchProviderInterceptor( _rxInterceptor ); 145 } 146 147 // OComponentHelper 148 //------------------------------------------------------------------------------ 149 void OClickableImageBaseControl::disposing() 150 { 151 EventObject aEvent( static_cast< XWeak* >( this ) ); 152 m_aApproveActionListeners.disposeAndClear( aEvent ); 153 m_aActionListeners.disposeAndClear( aEvent ); 154 m_aSubmissionVetoListeners.disposeAndClear( aEvent ); 155 m_pFeatureInterception->dispose(); 156 157 { 158 ::osl::MutexGuard aGuard( m_aMutex ); 159 if( m_pThread ) 160 { 161 m_pThread->release(); 162 m_pThread = NULL; 163 } 164 } 165 166 OControl::disposing(); 167 } 168 169 //------------------------------------------------------------------------------ 170 OImageProducerThread_Impl* OClickableImageBaseControl::getImageProducerThread() 171 { 172 if ( !m_pThread ) 173 { 174 m_pThread = new OImageProducerThread_Impl( this ); 175 m_pThread->acquire(); 176 m_pThread->create(); 177 } 178 return m_pThread; 179 } 180 181 //------------------------------------------------------------------------------ 182 bool OClickableImageBaseControl::approveAction( ) 183 { 184 sal_Bool bCancelled = sal_False; 185 EventObject aEvent( static_cast< XWeak* >( this ) ); 186 187 ::cppu::OInterfaceIteratorHelper aIter( m_aApproveActionListeners ); 188 while( !bCancelled && aIter.hasMoreElements() ) 189 { 190 // Jede approveAction-Methode muss thread-safe sein!!! 191 if( !static_cast< XApproveActionListener* >( aIter.next() )->approveAction( aEvent ) ) 192 bCancelled = sal_True; 193 } 194 195 return !bCancelled; 196 } 197 198 //------------------------------------------------------------------------------ 199 // Diese Methode wird auch aus einem Thread gerufen und muss deshalb 200 // thread-safe sein. 201 void OClickableImageBaseControl::actionPerformed_Impl(sal_Bool bNotifyListener, const MouseEvent& rEvt) 202 { 203 if( bNotifyListener ) 204 { 205 if ( !approveAction() ) 206 return; 207 } 208 209 // Ob der Rest des Codes Thread-Safe ist weiss man nicht genau. Deshalb 210 // wird das meiste bei gelocktem Solar-Mutex erledigen. 211 Reference<XPropertySet> xSet; 212 Reference< XInterface > xModelsParent; 213 FormButtonType eButtonType = FormButtonType_PUSH; 214 { 215 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 216 217 // Parent holen 218 Reference<XFormComponent> xComp(getModel(), UNO_QUERY); 219 if (!xComp.is()) 220 return; 221 222 xModelsParent = xComp->getParent(); 223 if (!xModelsParent.is()) 224 return; 225 226 // which button type? 227 xSet = xSet.query( xComp ); 228 if ( !xSet.is() ) 229 return; 230 xSet->getPropertyValue(PROPERTY_BUTTONTYPE) >>= eButtonType; 231 } 232 233 switch (eButtonType) 234 { 235 case FormButtonType_RESET: 236 { 237 // reset-Methoden muessen thread-safe sein! 238 Reference<XReset> xReset(xModelsParent, UNO_QUERY); 239 if (!xReset.is()) 240 return; 241 242 xReset->reset(); 243 } 244 break; 245 246 case FormButtonType_SUBMIT: 247 { 248 // if some outer component can provide an interaction handler, use it 249 Reference< XInteractionHandler > xHandler( m_pFeatureInterception->queryDispatch( "private:/InteractionHandler" ), UNO_QUERY ); 250 try 251 { 252 implSubmit( rEvt, xHandler ); 253 } 254 catch( const Exception& ) 255 { 256 // ignore 257 } 258 } 259 break; 260 261 case FormButtonType_URL: 262 { 263 ::vos::OGuard aGuard( Application::GetSolarMutex() ); 264 265 Reference< XModel > xModel = getXModel(xModelsParent); 266 if (!xModel.is()) 267 return; 268 269 /////////////////////////////////////////////////////////////////////// 270 // Jetzt URL ausfuehren 271 Reference< XController > xController = xModel->getCurrentController(); 272 if (!xController.is()) 273 return; 274 275 Reference< XFrame > xFrame = xController->getFrame(); 276 if( !xFrame.is() ) 277 return; 278 279 URL aURL; 280 aURL.Complete = 281 getString(xSet->getPropertyValue(PROPERTY_TARGET_URL)); 282 283 if (aURL.Complete.getLength() && (LOCAL_URL_PREFIX == aURL.Complete.getStr()[0])) 284 { // the URL contains a local URL only. Since the URLTransformer does not handle this case correctly 285 // (it can't: it does not know the document URL), we have to take care for this ourself. 286 // The real solution would be to not allow such relative URLs (there is a rule that at runtime, all 287 // URLs have to be absolute), but for compatibility reasons this is no option. 288 // The more as the user does not want to see a local URL as "file://<path>/<document>#mark" if it 289 // could be "#mark" as well. 290 // If we someday say that this hack (yes, it's kind of a hack) is not sustainable anymore, the complete 291 // solutiuon would be: 292 // * recognize URLs consisting of a mark only while _reading_ the document 293 // * for this, allow the INetURLObject (which at the moment is invoked when reading URLs) to 294 // transform such mark-only URLs into correct absolute URLs 295 // * at the UI, show only the mark 296 // * !!!! recognize every SAVEAS on the document, so the absolute URL can be adjusted. This seems 297 // rather impossible !!! 298 // 89752 - 23.07.2001 - frank.schoenheit@sun.com 299 aURL.Mark = aURL.Complete; 300 aURL.Complete = xModel->getURL(); 301 aURL.Complete += aURL.Mark; 302 } 303 304 sal_Bool bDispatchUrlInternal = sal_False; 305 xSet->getPropertyValue(PROPERTY_DISPATCHURLINTERNAL) >>= bDispatchUrlInternal; 306 if ( bDispatchUrlInternal ) 307 { 308 m_pFeatureInterception->getTransformer().parseSmartWithAsciiProtocol( aURL, INET_FILE_SCHEME ); 309 310 ::rtl::OUString aTargetFrame; 311 xSet->getPropertyValue(PROPERTY_TARGET_FRAME) >>= aTargetFrame; 312 313 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch( aURL, aTargetFrame, 314 FrameSearchFlag::SELF | FrameSearchFlag::PARENT | 315 FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE ); 316 317 Sequence<PropertyValue> aArgs(1); 318 PropertyValue& rProp = aArgs.getArray()[0]; 319 rProp.Name = ::rtl::OUString::createFromAscii("Referer"); 320 rProp.Value <<= xModel->getURL(); 321 322 if (xDisp.is()) 323 xDisp->dispatch( aURL, aArgs ); 324 } 325 else 326 { 327 URL aHyperLink = m_pFeatureInterception->getTransformer().getStrictURLFromAscii( ".uno:OpenHyperlink" ); 328 329 Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch(aHyperLink, ::rtl::OUString() , 0); 330 331 if ( xDisp.is() ) 332 { 333 Sequence<PropertyValue> aProps(3); 334 aProps[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL")); 335 aProps[0].Value <<= aURL.Complete; 336 337 aProps[1].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("FrameName")); 338 aProps[1].Value = xSet->getPropertyValue(PROPERTY_TARGET_FRAME); 339 340 aProps[2].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Referer")); 341 aProps[2].Value <<= xModel->getURL(); 342 343 xDisp->dispatch( aHyperLink, aProps ); 344 } 345 } 346 } break; 347 default: 348 { 349 // notify the action listeners for a push button 350 ActionEvent aEvt(static_cast<XWeak*>(this), m_aActionCommand); 351 m_aActionListeners.notifyEach( &XActionListener::actionPerformed, aEvt ); 352 } 353 } 354 } 355 356 357 //-------------------------------------------------------------------- 358 void SAL_CALL OClickableImageBaseControl::addSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener ) throw (NoSupportException, RuntimeException) 359 { 360 m_aSubmissionVetoListeners.addInterface( listener ); 361 } 362 363 //-------------------------------------------------------------------- 364 void SAL_CALL OClickableImageBaseControl::removeSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener ) throw (NoSupportException, RuntimeException) 365 { 366 m_aSubmissionVetoListeners.removeInterface( listener ); 367 } 368 369 //-------------------------------------------------------------------- 370 void SAL_CALL OClickableImageBaseControl::submitWithInteraction( const Reference< XInteractionHandler >& _rxHandler ) throw (VetoException, WrappedTargetException, RuntimeException) 371 { 372 implSubmit( MouseEvent(), _rxHandler ); 373 } 374 375 //-------------------------------------------------------------------- 376 void SAL_CALL OClickableImageBaseControl::submit( ) throw (VetoException, WrappedTargetException, RuntimeException) 377 { 378 implSubmit( MouseEvent(), NULL ); 379 } 380 381 //-------------------------------------------------------------------- 382 Sequence< ::rtl::OUString > SAL_CALL OClickableImageBaseControl::getSupportedServiceNames( ) throw (RuntimeException) 383 { 384 Sequence< ::rtl::OUString > aSupported = OControl::getSupportedServiceNames(); 385 aSupported.realloc( aSupported.getLength() + 1 ); 386 387 ::rtl::OUString* pArray = aSupported.getArray(); 388 pArray[ aSupported.getLength() - 1 ] = FRM_SUN_CONTROL_SUBMITBUTTON; 389 390 return aSupported; 391 } 392 393 //-------------------------------------------------------------------- 394 void OClickableImageBaseControl::implSubmit( const MouseEvent& _rEvent, const Reference< XInteractionHandler >& _rxHandler ) SAL_THROW((VetoException, WrappedTargetException, RuntimeException)) 395 { 396 try 397 { 398 // allow the veto listeners to join the game 399 m_aSubmissionVetoListeners.notifyEach( &XSubmissionVetoListener::submitting, EventObject( *this ) ); 400 401 // see whether there's an "submit interceptor" set at our model 402 Reference< submission::XSubmissionSupplier > xSubmissionSupp( getModel(), UNO_QUERY ); 403 Reference< XSubmission > xSubmission; 404 if ( xSubmissionSupp.is() ) 405 xSubmission = xSubmissionSupp->getSubmission(); 406 407 if ( xSubmission.is() ) 408 { 409 if ( !_rxHandler.is() ) 410 xSubmission->submit(); 411 else 412 xSubmission->submitWithInteraction( _rxHandler ); 413 } 414 else 415 { 416 // no "interceptor" -> ordinary (old-way) submission 417 Reference< XChild > xChild( getModel(), UNO_QUERY ); 418 Reference< XSubmit > xParentSubmission; 419 if ( xChild.is() ) 420 xParentSubmission = xParentSubmission.query( xChild->getParent() ); 421 if ( xParentSubmission.is() ) 422 xParentSubmission->submit( this, _rEvent ); 423 } 424 } 425 catch( const VetoException& ) 426 { 427 // allowed to leave 428 throw; 429 } 430 catch( const RuntimeException& ) 431 { 432 // allowed to leave 433 throw; 434 } 435 catch( const WrappedTargetException& e ) 436 { 437 // allowed to leave 438 throw; 439 } 440 catch( const Exception& e ) 441 { 442 OSL_ENSURE( sal_False, "OClickableImageBaseControl::implSubmit: caught an unknown exception!" ); 443 throw WrappedTargetException( ::rtl::OUString(), *this, makeAny( e ) ); 444 } 445 } 446 447 //================================================================== 448 // OClickableImageBaseModel 449 //================================================================== 450 //------------------------------------------------------------------------------ 451 Sequence<Type> OClickableImageBaseModel::_getTypes() 452 { 453 return concatSequences( 454 OControlModel::_getTypes(), 455 OClickableImageBaseModel_Base::getTypes() 456 ); 457 } 458 459 //------------------------------------------------------------------ 460 DBG_NAME( OClickableImageBaseModel ) 461 //------------------------------------------------------------------ 462 OClickableImageBaseModel::OClickableImageBaseModel( const Reference< XMultiServiceFactory >& _rxFactory, const ::rtl::OUString& _rUnoControlModelTypeName, 463 const ::rtl::OUString& rDefault ) 464 :OControlModel( _rxFactory, _rUnoControlModelTypeName, rDefault ) 465 ,OPropertyChangeListener(m_aMutex) 466 ,m_pMedium(NULL) 467 ,m_pProducer( NULL ) 468 ,m_bDispatchUrlInternal(sal_False) 469 ,m_bDownloading(sal_False) 470 ,m_bProdStarted(sal_False) 471 { 472 DBG_CTOR( OClickableImageBaseModel, NULL ); 473 implConstruct(); 474 m_eButtonType = FormButtonType_PUSH; 475 } 476 477 //------------------------------------------------------------------ 478 OClickableImageBaseModel::OClickableImageBaseModel( const OClickableImageBaseModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory ) 479 :OControlModel( _pOriginal, _rxFactory ) 480 ,OPropertyChangeListener( m_aMutex ) 481 ,m_pMedium( NULL ) 482 ,m_pProducer( NULL ) 483 ,m_bDispatchUrlInternal(sal_False) 484 ,m_bDownloading( sal_False ) 485 ,m_bProdStarted( sal_False ) 486 { 487 DBG_CTOR( OClickableImageBaseModel, NULL ); 488 implConstruct(); 489 490 // copy properties 491 m_eButtonType = _pOriginal->m_eButtonType; 492 m_sTargetURL = _pOriginal->m_sTargetURL; 493 m_sTargetFrame = _pOriginal->m_sTargetFrame; 494 m_bDispatchUrlInternal = _pOriginal->m_bDispatchUrlInternal; 495 } 496 497 //------------------------------------------------------------------------------ 498 void OClickableImageBaseModel::implInitializeImageURL( ) 499 { 500 osl_incrementInterlockedCount( &m_refCount ); 501 { 502 // simulate a propertyChanged event for the ImageURL 503 // 2003-05-15 - #109591# - fs@openoffice.org 504 Any aImageURL; 505 getFastPropertyValue( aImageURL, PROPERTY_ID_IMAGE_URL ); 506 _propertyChanged( PropertyChangeEvent( *this, PROPERTY_IMAGE_URL, sal_False, PROPERTY_ID_IMAGE_URL, Any( ), aImageURL ) ); 507 } 508 osl_decrementInterlockedCount( &m_refCount ); 509 } 510 511 //------------------------------------------------------------------------------ 512 void OClickableImageBaseModel::implConstruct() 513 { 514 m_pProducer = new ImageProducer; 515 increment( m_refCount ); 516 { 517 m_xProducer = m_pProducer; 518 519 if ( m_xAggregateSet.is() ) 520 { 521 OPropertyChangeMultiplexer* pMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet ); 522 pMultiplexer->addProperty( PROPERTY_IMAGE_URL ); 523 } 524 } 525 decrement(m_refCount); 526 } 527 528 //------------------------------------------------------------------------------ 529 OClickableImageBaseModel::~OClickableImageBaseModel() 530 { 531 if (!OComponentHelper::rBHelper.bDisposed) 532 { 533 acquire(); 534 dispose(); 535 } 536 DBG_ASSERT(m_pMedium == NULL, "OClickableImageBaseModel::~OClickableImageBaseModel : leaving a memory leak ..."); 537 // spaetestens im dispose sollte das aufgeraeumt worden sein 538 539 DBG_DTOR( OClickableImageBaseModel, NULL ); 540 } 541 542 // XImageProducer 543 //-------------------------------------------------------------------- 544 void SAL_CALL OClickableImageBaseModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) 545 { 546 ImageModelMethodGuard aGuard( *this ); 547 GetImageProducer()->addConsumer( _rxConsumer ); 548 } 549 550 //-------------------------------------------------------------------- 551 void SAL_CALL OClickableImageBaseModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException) 552 { 553 ImageModelMethodGuard aGuard( *this ); 554 GetImageProducer()->removeConsumer( _rxConsumer ); 555 } 556 557 //-------------------------------------------------------------------- 558 void SAL_CALL OClickableImageBaseModel::startProduction( ) throw (RuntimeException) 559 { 560 ImageModelMethodGuard aGuard( *this ); 561 GetImageProducer()->startProduction(); 562 } 563 564 //-------------------------------------------------------------------- 565 Reference< submission::XSubmission > SAL_CALL OClickableImageBaseModel::getSubmission() throw (RuntimeException) 566 { 567 return m_xSubmissionDelegate; 568 } 569 570 //-------------------------------------------------------------------- 571 void SAL_CALL OClickableImageBaseModel::setSubmission( const Reference< submission::XSubmission >& _submission ) throw (RuntimeException) 572 { 573 m_xSubmissionDelegate = _submission; 574 } 575 576 //-------------------------------------------------------------------- 577 Sequence< ::rtl::OUString > SAL_CALL OClickableImageBaseModel::getSupportedServiceNames( ) throw (RuntimeException) 578 { 579 Sequence< ::rtl::OUString > aSupported = OControlModel::getSupportedServiceNames(); 580 aSupported.realloc( aSupported.getLength() + 1 ); 581 582 ::rtl::OUString* pArray = aSupported.getArray(); 583 pArray[ aSupported.getLength() - 1 ] = FRM_SUN_COMPONENT_SUBMITBUTTON; 584 585 return aSupported; 586 } 587 588 // OComponentHelper 589 //------------------------------------------------------------------------------ 590 void OClickableImageBaseModel::disposing() 591 { 592 OControlModel::disposing(); 593 if (m_pMedium) 594 { 595 delete m_pMedium; 596 m_pMedium = NULL; 597 } 598 599 m_xProducer = NULL; 600 m_pProducer = NULL; 601 } 602 603 //------------------------------------------------------------------------------ 604 Any SAL_CALL OClickableImageBaseModel::queryAggregation(const Type& _rType) throw (RuntimeException) 605 { 606 // order matters: 607 // we definately want to "overload" the XImageProducer interface of our aggregate, 608 // thus check OClickableImageBaseModel_Base (which provides this) first 609 Any aReturn = OClickableImageBaseModel_Base::queryInterface( _rType ); 610 611 // BUT: _don't_ let it feel responsible for the XTypeProvider interface 612 // (as this is implemented by our base class in the proper way) 613 if ( _rType.equals( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) ) 614 || !aReturn.hasValue() 615 ) 616 aReturn = OControlModel::queryAggregation( _rType ); 617 618 return aReturn; 619 } 620 621 //------------------------------------------------------------------------------ 622 void OClickableImageBaseModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const 623 { 624 switch (nHandle) 625 { 626 case PROPERTY_ID_BUTTONTYPE : rValue <<= m_eButtonType; break; 627 case PROPERTY_ID_TARGET_URL : rValue <<= m_sTargetURL; break; 628 case PROPERTY_ID_TARGET_FRAME : rValue <<= m_sTargetFrame; break; 629 case PROPERTY_ID_DISPATCHURLINTERNAL : rValue <<= m_bDispatchUrlInternal; break; 630 default: 631 OControlModel::getFastPropertyValue(rValue, nHandle); 632 } 633 } 634 635 //------------------------------------------------------------------------------ 636 void OClickableImageBaseModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) throw ( Exception) 637 { 638 switch (nHandle) 639 { 640 case PROPERTY_ID_BUTTONTYPE : 641 DBG_ASSERT(isA(rValue, static_cast<FormButtonType*>(NULL)), "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 642 rValue >>= m_eButtonType; 643 break; 644 645 case PROPERTY_ID_TARGET_URL : 646 DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 647 rValue >>= m_sTargetURL; 648 break; 649 650 case PROPERTY_ID_TARGET_FRAME : 651 DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 652 rValue >>= m_sTargetFrame; 653 break; 654 655 case PROPERTY_ID_DISPATCHURLINTERNAL: 656 DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" ); 657 rValue >>= m_bDispatchUrlInternal; 658 break; 659 660 default: 661 OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue); 662 } 663 } 664 665 //------------------------------------------------------------------------------ 666 sal_Bool OClickableImageBaseModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue) 667 throw( IllegalArgumentException ) 668 { 669 switch (nHandle) 670 { 671 case PROPERTY_ID_BUTTONTYPE : 672 return tryPropertyValueEnum( rConvertedValue, rOldValue, rValue, m_eButtonType ); 673 674 case PROPERTY_ID_TARGET_URL : 675 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetURL); 676 677 case PROPERTY_ID_TARGET_FRAME : 678 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetFrame); 679 680 case PROPERTY_ID_DISPATCHURLINTERNAL : 681 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bDispatchUrlInternal); 682 683 default: 684 return OControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue); 685 } 686 } 687 688 //------------------------------------------------------------------------------ 689 void OClickableImageBaseModel::StartProduction() 690 { 691 ImageProducer *pImgProd = GetImageProducer(); 692 // grab the ImageURL 693 rtl::OUString sURL; 694 getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ImageURL") ) ) >>= sURL; 695 if (!m_pMedium) 696 { 697 if ( ::svt::GraphicAccess::isSupportedURL( sURL ) ) 698 pImgProd->SetImage( sURL ); 699 else 700 // caution: the medium may be NULL if somebody gave us a invalid URL to work with 701 // 11/24/2000 - 79667 - FS 702 pImgProd->SetImage(String()); 703 m_bDownloading = sal_False; 704 return; 705 } 706 if (m_pMedium->GetErrorCode()==0) 707 { 708 SvStream* pStream = m_pMedium->GetInStream(); 709 710 pImgProd->SetImage(*pStream); 711 pImgProd->startProduction(); 712 m_bProdStarted = sal_True; 713 } 714 else 715 { 716 pImgProd->SetImage(String()); 717 delete m_pMedium; 718 m_pMedium = 0; 719 m_bDownloading = sal_False; 720 } 721 } 722 723 //------------------------------------------------------------------------------ 724 void OClickableImageBaseModel::SetURL( const ::rtl::OUString& rURL ) 725 { 726 if (m_pMedium || !rURL.getLength()) 727 { 728 // Den Stream am Producer freigeben, bevor das Medium geloscht wird. 729 GetImageProducer()->SetImage(String()); 730 delete m_pMedium; 731 m_pMedium = NULL; 732 } 733 734 // the SfxMedium is not allowed to be created with an invalid URL, so we have to check this first 735 // 23.01.2001 - 81927 - FS 736 INetURLObject aUrl(rURL); 737 if (INET_PROT_NOT_VALID == aUrl.GetProtocol()) 738 // we treat an invalid URL like we would treat no URL 739 return; 740 741 if (rURL.getLength() && !::svt::GraphicAccess::isSupportedURL( rURL ) ) 742 { 743 if (m_pMedium) 744 delete m_pMedium; 745 746 m_pMedium = new SfxMedium(rURL, STREAM_STD_READ, sal_False); 747 m_pMedium->SetDataAvailableLink( 748 STATIC_LINK(this, OClickableImageBaseModel, DataAvailableLink)); 749 750 // Das XModel suchen, um an die Object-Shell oder zumindest den 751 // Referer zu gelangen. 752 // Das Model findet man allerdings nur beim Laden von HTML-Dokumenten 753 // und dann, wenn die URL in einem bereits geladenen Dokument 754 // geaendert wird. Waehrend des Ladens kommt man nicht an das 755 // Model ran. 756 Reference< XModel > xModel; 757 InterfaceRef xIfc( *this ); 758 while( !xModel.is() && xIfc.is() ) 759 { 760 Reference<XChild> xChild( xIfc, UNO_QUERY ); 761 xIfc = xChild->getParent(); 762 query_interface(xIfc, xModel); 763 } 764 765 // Die Object-Shell suchen, indem wir 766 // ueber alle Object-Shells iterieren und deren XModel mit dem 767 // eigenen vergleichen. Als Optimierung probieren wir aber erstmal 768 // die aktuelle Object-Shell. 769 // wir unser XModel mit dem aller Object 770 SfxObjectShell *pObjSh = 0; 771 772 if( xModel.is() ) 773 { 774 SfxObjectShell *pTestObjSh = SfxObjectShell::Current(); 775 if( pTestObjSh ) 776 { 777 Reference< XModel > xTestModel = pTestObjSh->GetModel(); 778 if( xTestModel == xModel ) 779 pObjSh = pTestObjSh; 780 } 781 if( !pObjSh ) 782 { 783 pTestObjSh = SfxObjectShell::GetFirst(); 784 while( !pObjSh && pTestObjSh ) 785 { 786 Reference< XModel > xTestModel = pTestObjSh->GetModel(); 787 if( xTestModel == xModel ) 788 pObjSh = pTestObjSh; 789 else 790 pTestObjSh = SfxObjectShell::GetNext( *pTestObjSh ); 791 } 792 } 793 } 794 795 #ifdef USE_REGISTER_TRANSFER 796 if( pObjSh ) 797 { 798 // Medium registrieren, damit abgebrochen werden kann 799 pObjSh->RegisterTransfer( *m_pMedium ); 800 801 // Target-Frame uebertragen, damit auch javascript:-URLs 802 // "geladen" werden koennen. 803 const SfxMedium *pShMedium = pObjSh->GetMedium(); 804 if( pShMedium ) 805 m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame()); 806 } 807 else 808 { 809 // Keine Object-Shell, aber ein Medium? Dann uebernehmen wir 810 // zumindest den Referer. 811 if( xModel.is() ) 812 { 813 ::rtl::OUString sReferer( xModel->getURL() ); 814 if( sReferer.getLength() ) 815 m_pMedium->SetReferer( OUStringToString(sReferer, CHARSET_SYSTEM) ); 816 } 817 } 818 #else 819 if( pObjSh ) 820 { 821 // Target-Frame uebertragen, damit auch javascript:-URLs 822 // "geladen" werden koennen. 823 const SfxMedium *pShMedium = pObjSh->GetMedium(); 824 if( pShMedium ) 825 m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame()); 826 } 827 828 if( xModel.is() ) 829 { 830 ::rtl::OUString sReferer( xModel->getURL() ); 831 if( sReferer.getLength() ) 832 m_pMedium->SetReferer( sReferer ); 833 } 834 #endif 835 836 // Downloading-Flag auf sal_True setzen. Es werden dann auch 837 // Data-Available-Links, wenn wir in den Pending-Staus gelangen. 838 m_bDownloading = sal_True; 839 m_bProdStarted = sal_False; 840 841 // Download anstossen (Achtung: Kann auch synchron sein). 842 m_pMedium->DownLoad(STATIC_LINK(this, OClickableImageBaseModel, DownloadDoneLink)); 843 } 844 else 845 { 846 if ( ::svt::GraphicAccess::isSupportedURL( rURL ) ) 847 GetImageProducer()->SetImage( rURL ); 848 GetImageProducer()->startProduction(); 849 } 850 } 851 852 //------------------------------------------------------------------------------ 853 void OClickableImageBaseModel::DataAvailable() 854 { 855 if (!m_bProdStarted) 856 StartProduction(); 857 858 GetImageProducer()->NewDataAvailable(); 859 } 860 861 //------------------------------------------------------------------------------ 862 void OClickableImageBaseModel::DownloadDone() 863 { 864 DataAvailable(); 865 m_bDownloading = sal_False; 866 } 867 868 //------------------------------------------------------------------------------ 869 IMPL_STATIC_LINK( OClickableImageBaseModel, DownloadDoneLink, void*, EMPTYARG ) 870 { 871 ::osl::MutexGuard aGuard( pThis->m_aMutex ); 872 pThis->DownloadDone(); 873 return 0; 874 } 875 876 //------------------------------------------------------------------------------ 877 IMPL_STATIC_LINK( OClickableImageBaseModel, DataAvailableLink, void*, EMPTYARG ) 878 { 879 ::osl::MutexGuard aGuard( pThis->m_aMutex ); 880 pThis->DataAvailable(); 881 return 0; 882 } 883 884 //------------------------------------------------------------------------------ 885 void OClickableImageBaseModel::_propertyChanged( const PropertyChangeEvent& rEvt ) 886 throw( RuntimeException ) 887 { 888 // Wenn eine URL gesetzt worden ist, muss die noch an den ImageProducer 889 // weitergereicht werden. 890 ::osl::MutexGuard aGuard(m_aMutex); 891 SetURL( getString(rEvt.NewValue) ); 892 } 893 894 // ----------------------------------------------------------------------------- 895 Any OClickableImageBaseModel::getPropertyDefaultByHandle( sal_Int32 nHandle ) const 896 { 897 switch (nHandle) 898 { 899 case PROPERTY_ID_BUTTONTYPE : return makeAny( FormButtonType_PUSH ); 900 case PROPERTY_ID_TARGET_URL : 901 case PROPERTY_ID_TARGET_FRAME : return makeAny( ::rtl::OUString() ); 902 case PROPERTY_ID_DISPATCHURLINTERNAL : return makeAny( sal_False ); 903 default: 904 return OControlModel::getPropertyDefaultByHandle(nHandle); 905 } 906 } 907 908 //================================================================== 909 // OImageProducerThread_Impl 910 //================================================================== 911 //------------------------------------------------------------------ 912 EventObject* OImageProducerThread_Impl::cloneEvent( const EventObject* _pEvt ) const 913 { 914 return new EventObject( *_pEvt ); 915 } 916 917 //------------------------------------------------------------------ 918 void OImageProducerThread_Impl::processEvent( ::cppu::OComponentHelper *pCompImpl, 919 const EventObject* pEvt, 920 const Reference<XControl>&, 921 sal_Bool ) 922 { 923 ((OClickableImageBaseControl *)pCompImpl)->actionPerformed_Impl( sal_True, *(MouseEvent *)pEvt ); 924 } 925 926 //......................................................................... 927 } // namespace frm 928 //......................................................................... 929 930