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