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