xref: /trunk/main/forms/source/component/clickableimage.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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)
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)
120     {
121         m_aApproveActionListeners.addInterface(l);
122     }
123 
124     //------------------------------------------------------------------------------
removeApproveActionListener(const Reference<XApproveActionListener> & l)125     void OClickableImageBaseControl::removeApproveActionListener(
126             const Reference<XApproveActionListener>& l)
127     {
128         m_aApproveActionListeners.removeInterface(l);
129     }
130 
131     //--------------------------------------------------------------------
registerDispatchProviderInterceptor(const Reference<XDispatchProviderInterceptor> & _rxInterceptor)132     void SAL_CALL OClickableImageBaseControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor )
133     {
134         m_pFeatureInterception->registerDispatchProviderInterceptor( _rxInterceptor  );
135     }
136 
137     //--------------------------------------------------------------------
releaseDispatchProviderInterceptor(const Reference<XDispatchProviderInterceptor> & _rxInterceptor)138     void SAL_CALL OClickableImageBaseControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor )
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 )
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 )
361     {
362         m_aSubmissionVetoListeners.removeInterface( listener );
363     }
364 
365     //--------------------------------------------------------------------
submitWithInteraction(const Reference<XInteractionHandler> & _rxHandler)366     void SAL_CALL OClickableImageBaseControl::submitWithInteraction( const Reference< XInteractionHandler >& _rxHandler )
367     {
368         implSubmit( MouseEvent(), _rxHandler );
369     }
370 
371     //--------------------------------------------------------------------
submit()372     void SAL_CALL OClickableImageBaseControl::submit(  )
373     {
374         implSubmit( MouseEvent(), NULL );
375     }
376 
377     //--------------------------------------------------------------------
getSupportedServiceNames()378     Sequence< ::rtl::OUString > SAL_CALL OClickableImageBaseControl::getSupportedServiceNames(  )
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 )
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 )
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 )
548     {
549         ImageModelMethodGuard aGuard( *this );
550         GetImageProducer()->removeConsumer( _rxConsumer );
551     }
552 
553     //--------------------------------------------------------------------
startProduction()554     void SAL_CALL OClickableImageBaseModel::startProduction(  )
555     {
556         ImageModelMethodGuard aGuard( *this );
557         GetImageProducer()->startProduction();
558     }
559 
560     //--------------------------------------------------------------------
getSubmission()561     Reference< submission::XSubmission > SAL_CALL OClickableImageBaseModel::getSubmission()
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 )
568     {
569         m_xSubmissionDelegate = _submission;
570     }
571 
572     //--------------------------------------------------------------------
getSupportedServiceNames()573     Sequence< ::rtl::OUString > SAL_CALL OClickableImageBaseModel::getSupportedServiceNames(  )
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)
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)
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     {
664         switch (nHandle)
665         {
666             case PROPERTY_ID_BUTTONTYPE :
667                 return tryPropertyValueEnum( rConvertedValue, rOldValue, rValue, m_eButtonType );
668 
669             case PROPERTY_ID_TARGET_URL :
670                 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetURL);
671 
672             case PROPERTY_ID_TARGET_FRAME :
673                 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetFrame);
674 
675             case PROPERTY_ID_DISPATCHURLINTERNAL :
676                 return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bDispatchUrlInternal);
677 
678             default:
679                 return OControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
680         }
681     }
682 
683     //------------------------------------------------------------------------------
StartProduction()684     void OClickableImageBaseModel::StartProduction()
685     {
686         ImageProducer *pImgProd = GetImageProducer();
687         // grab the ImageURL
688         rtl::OUString sURL;
689         getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ImageURL") ) ) >>= sURL;
690         if (!m_pMedium)
691         {
692             if ( ::svt::GraphicAccess::isSupportedURL( sURL )  )
693                 pImgProd->SetImage( sURL );
694             else
695                 // caution: the medium may be NULL if somebody gave us a invalid URL to work with
696                 // 11/24/2000 - 79667 - FS
697                 pImgProd->SetImage(String());
698             m_bDownloading = sal_False;
699             return;
700         }
701         if (m_pMedium->GetErrorCode()==0)
702         {
703             SvStream* pStream = m_pMedium->GetInStream();
704 
705             pImgProd->SetImage(*pStream);
706             pImgProd->startProduction();
707             m_bProdStarted = sal_True;
708         }
709         else
710         {
711             pImgProd->SetImage(String());
712             delete m_pMedium;
713             m_pMedium = 0;
714             m_bDownloading = sal_False;
715         }
716     }
717 
718     //------------------------------------------------------------------------------
SetURL(const::rtl::OUString & rURL)719     void OClickableImageBaseModel::SetURL( const ::rtl::OUString& rURL )
720     {
721         if (m_pMedium || !rURL.getLength())
722         {
723             // Den Stream am Producer freigeben, bevor das Medium geloscht wird.
724             GetImageProducer()->SetImage(String());
725             delete m_pMedium;
726             m_pMedium = NULL;
727         }
728 
729         // the SfxMedium is not allowed to be created with an invalid URL, so we have to check this first
730         // 23.01.2001 - 81927 - FS
731         INetURLObject aUrl(rURL);
732         if (INET_PROT_NOT_VALID == aUrl.GetProtocol())
733             // we treat an invalid URL like we would treat no URL
734             return;
735 
736         if (rURL.getLength() && !::svt::GraphicAccess::isSupportedURL( rURL ) )
737        {
738             if (m_pMedium)
739                 delete m_pMedium;
740 
741             m_pMedium = new SfxMedium(rURL, STREAM_STD_READ, sal_False);
742             m_pMedium->SetDataAvailableLink(
743                     STATIC_LINK(this, OClickableImageBaseModel, DataAvailableLink));
744 
745             // Das XModel suchen, um an die Object-Shell oder zumindest den
746             // Referer zu gelangen.
747             // Das Model findet man allerdings nur beim Laden von HTML-Dokumenten
748             // und dann, wenn die URL in einem bereits geladenen Dokument
749             // geaendert wird. Waehrend des Ladens kommt man nicht an das
750             // Model ran.
751             Reference< XModel >  xModel;
752             InterfaceRef  xIfc( *this );
753             while( !xModel.is() && xIfc.is() )
754             {
755                 Reference<XChild>  xChild( xIfc, UNO_QUERY );
756                 xIfc = xChild->getParent();
757                 query_interface(xIfc, xModel);
758             }
759 
760             // Die Object-Shell suchen, indem wir
761             // ueber alle Object-Shells iterieren und deren XModel mit dem
762             // eigenen vergleichen. Als Optimierung probieren wir aber erstmal
763             // die aktuelle Object-Shell.
764             // wir unser XModel mit dem aller Object
765             SfxObjectShell *pObjSh = 0;
766 
767             if( xModel.is() )
768             {
769                 SfxObjectShell *pTestObjSh = SfxObjectShell::Current();
770                 if( pTestObjSh )
771                 {
772                     Reference< XModel >  xTestModel = pTestObjSh->GetModel();
773                     if( xTestModel == xModel )
774                         pObjSh = pTestObjSh;
775                 }
776                 if( !pObjSh )
777                 {
778                     pTestObjSh = SfxObjectShell::GetFirst();
779                     while( !pObjSh && pTestObjSh )
780                     {
781                         Reference< XModel > xTestModel = pTestObjSh->GetModel();
782                         if( xTestModel == xModel )
783                             pObjSh = pTestObjSh;
784                         else
785                             pTestObjSh = SfxObjectShell::GetNext( *pTestObjSh );
786                     }
787                 }
788             }
789 
790     #ifdef USE_REGISTER_TRANSFER
791             if( pObjSh )
792             {
793                 // Medium registrieren, damit abgebrochen werden kann
794                 pObjSh->RegisterTransfer( *m_pMedium );
795 
796                 // Target-Frame uebertragen, damit auch javascript:-URLs
797                 // "geladen" werden koennen.
798                 const SfxMedium *pShMedium = pObjSh->GetMedium();
799                 if( pShMedium )
800                     m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame());
801             }
802             else
803             {
804                 // Keine Object-Shell, aber ein Medium? Dann uebernehmen wir
805                 // zumindest den Referer.
806                 if( xModel.is() )
807                 {
808                     ::rtl::OUString sReferer( xModel->getURL() );
809                     if( sReferer.getLength() )
810                         m_pMedium->SetReferer( OUStringToString(sReferer, CHARSET_SYSTEM) );
811                 }
812             }
813     #else
814             if( pObjSh )
815             {
816                 // Target-Frame uebertragen, damit auch javascript:-URLs
817                 // "geladen" werden koennen.
818                 const SfxMedium *pShMedium = pObjSh->GetMedium();
819                 if( pShMedium )
820                     m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame());
821             }
822 
823             if( xModel.is() )
824             {
825                 ::rtl::OUString sReferer( xModel->getURL() );
826                 if( sReferer.getLength() )
827                     m_pMedium->SetReferer( sReferer );
828             }
829     #endif
830 
831             // Downloading-Flag auf sal_True setzen. Es werden dann auch
832             // Data-Available-Links, wenn wir in den Pending-Staus gelangen.
833             m_bDownloading = sal_True;
834             m_bProdStarted = sal_False;
835 
836             // Download anstossen (Achtung: Kann auch synchron sein).
837             m_pMedium->DownLoad(STATIC_LINK(this, OClickableImageBaseModel, DownloadDoneLink));
838         }
839         else
840         {
841             if ( ::svt::GraphicAccess::isSupportedURL( rURL )  )
842                 GetImageProducer()->SetImage( rURL );
843             GetImageProducer()->startProduction();
844         }
845     }
846 
847     //------------------------------------------------------------------------------
DataAvailable()848     void OClickableImageBaseModel::DataAvailable()
849     {
850         if (!m_bProdStarted)
851             StartProduction();
852 
853         GetImageProducer()->NewDataAvailable();
854     }
855 
856     //------------------------------------------------------------------------------
DownloadDone()857     void OClickableImageBaseModel::DownloadDone()
858     {
859         DataAvailable();
860         m_bDownloading = sal_False;
861     }
862 
863     //------------------------------------------------------------------------------
IMPL_STATIC_LINK(OClickableImageBaseModel,DownloadDoneLink,void *,EMPTYARG)864     IMPL_STATIC_LINK( OClickableImageBaseModel, DownloadDoneLink, void*, EMPTYARG )
865     {
866         ::osl::MutexGuard aGuard( pThis->m_aMutex );
867         pThis->DownloadDone();
868         return 0;
869     }
870 
871     //------------------------------------------------------------------------------
IMPL_STATIC_LINK(OClickableImageBaseModel,DataAvailableLink,void *,EMPTYARG)872     IMPL_STATIC_LINK( OClickableImageBaseModel, DataAvailableLink, void*, EMPTYARG )
873     {
874         ::osl::MutexGuard aGuard( pThis->m_aMutex );
875         pThis->DataAvailable();
876         return 0;
877     }
878 
879     //------------------------------------------------------------------------------
_propertyChanged(const PropertyChangeEvent & rEvt)880     void OClickableImageBaseModel::_propertyChanged( const PropertyChangeEvent& rEvt )
881     {
882         // Wenn eine URL gesetzt worden ist, muss die noch an den ImageProducer
883         // weitergereicht werden.
884         ::osl::MutexGuard aGuard(m_aMutex);
885         SetURL( getString(rEvt.NewValue) );
886     }
887 
888     // -----------------------------------------------------------------------------
getPropertyDefaultByHandle(sal_Int32 nHandle) const889     Any OClickableImageBaseModel::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
890     {
891         switch (nHandle)
892         {
893             case PROPERTY_ID_BUTTONTYPE             : return makeAny( FormButtonType_PUSH );
894             case PROPERTY_ID_TARGET_URL             :
895             case PROPERTY_ID_TARGET_FRAME           : return makeAny( ::rtl::OUString() );
896             case PROPERTY_ID_DISPATCHURLINTERNAL    : return makeAny( sal_False );
897             default:
898                 return OControlModel::getPropertyDefaultByHandle(nHandle);
899         }
900     }
901 
902     //==================================================================
903     // OImageProducerThread_Impl
904     //==================================================================
905     //------------------------------------------------------------------
cloneEvent(const EventObject * _pEvt) const906     EventObject* OImageProducerThread_Impl::cloneEvent( const EventObject* _pEvt ) const
907     {
908         return new EventObject( *_pEvt );
909     }
910 
911     //------------------------------------------------------------------
processEvent(::cppu::OComponentHelper * pCompImpl,const EventObject * pEvt,const Reference<XControl> &,sal_Bool)912     void OImageProducerThread_Impl::processEvent( ::cppu::OComponentHelper *pCompImpl,
913                                                 const EventObject* pEvt,
914                                                 const Reference<XControl>&,
915                                                 sal_Bool )
916     {
917         ((OClickableImageBaseControl *)pCompImpl)->actionPerformed_Impl( sal_True, *(MouseEvent *)pEvt );
918     }
919 
920 //.........................................................................
921 }   // namespace frm
922 //.........................................................................
923