xref: /AOO41X/main/forms/source/component/Button.cxx (revision 24acc54625a85f778a4f966495e8f4cd9d7b247c)
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 
27 #include "Button.hxx"
28 
29 #include <com/sun/star/awt/XVclWindowPeer.hpp>
30 
31 #include <comphelper/streamsection.hxx>
32 #include <comphelper/basicio.hxx>
33 #include <tools/diagnose_ex.h>
34 #include <tools/debug.hxx>
35 #include <tools/urlobj.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vos/mutex.hxx>
38 
39 //.........................................................................
40 namespace frm
41 {
42 //.........................................................................
43 
44 using namespace ::com::sun::star::uno;
45 using namespace ::com::sun::star::sdb;
46 using namespace ::com::sun::star::sdbc;
47 using namespace ::com::sun::star::sdbcx;
48 using namespace ::com::sun::star::beans;
49 using namespace ::com::sun::star::container;
50 using namespace ::com::sun::star::form;
51 using namespace ::com::sun::star::awt;
52 using namespace ::com::sun::star::io;
53 using namespace ::com::sun::star::lang;
54 using namespace ::com::sun::star::util;
55 using ::com::sun::star::frame::XDispatchProviderInterceptor;
56 
57 //==================================================================
58 //= OButtonModel
59 //==================================================================
DBG_NAME(OButtonModel)60 DBG_NAME(OButtonModel)
61 //------------------------------------------------------------------
62 InterfaceRef SAL_CALL OButtonModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
63 {
64     return *(new OButtonModel(_rxFactory));
65 }
66 
67 //------------------------------------------------------------------
OButtonModel(const Reference<XMultiServiceFactory> & _rxFactory)68 OButtonModel::OButtonModel(const Reference<XMultiServiceFactory>& _rxFactory)
69     :OClickableImageBaseModel( _rxFactory, VCL_CONTROLMODEL_COMMANDBUTTON, FRM_SUN_CONTROL_COMMANDBUTTON )
70                                     // use the old control name for compatibility reasons
71     ,m_aResetHelper( *this, m_aMutex )
72     ,m_eDefaultState( STATE_NOCHECK )
73 {
74     DBG_CTOR( OButtonModel, NULL );
75     m_nClassId = FormComponentType::COMMANDBUTTON;
76 }
77 
78 //------------------------------------------------------------------
queryAggregation(const Type & _type)79 Any SAL_CALL OButtonModel::queryAggregation( const Type& _type ) throw(RuntimeException)
80 {
81     Any aReturn = OClickableImageBaseModel::queryAggregation( _type );
82     if ( !aReturn.hasValue() )
83         aReturn = OButtonModel_Base::queryInterface( _type );
84     return aReturn;
85 }
86 
87 //------------------------------------------------------------------
_getTypes()88 Sequence< Type > OButtonModel::_getTypes()
89 {
90     return ::comphelper::concatSequences(
91         OClickableImageBaseModel::_getTypes(),
92         OButtonModel_Base::getTypes()
93     );
94 }
95 
96 //------------------------------------------------------------------
OButtonModel(const OButtonModel * _pOriginal,const Reference<XMultiServiceFactory> & _rxFactory)97 OButtonModel::OButtonModel( const OButtonModel* _pOriginal, const Reference<XMultiServiceFactory>& _rxFactory )
98     :OClickableImageBaseModel( _pOriginal, _rxFactory )
99     ,m_aResetHelper( *this, m_aMutex )
100     ,m_eDefaultState( _pOriginal->m_eDefaultState )
101 {
102     DBG_CTOR( OButtonModel, NULL );
103     m_nClassId = FormComponentType::COMMANDBUTTON;
104 
105     implInitializeImageURL();
106 }
107 
108 //------------------------------------------------------------------------------
~OButtonModel()109 OButtonModel::~OButtonModel()
110 {
111     DBG_DTOR(OButtonModel, NULL);
112 }
113 
114 //------------------------------------------------------------------------------
describeFixedProperties(Sequence<Property> & _rProps) const115 void OButtonModel::describeFixedProperties( Sequence< Property >& _rProps ) const
116 {
117     BEGIN_DESCRIBE_PROPERTIES( 6, OClickableImageBaseModel )
118         DECL_PROP1( BUTTONTYPE,             FormButtonType,             BOUND );
119         DECL_PROP1( DEFAULT_STATE,          sal_Int16,                  BOUND );
120         DECL_PROP1( DISPATCHURLINTERNAL,    sal_Bool,                   BOUND );
121         DECL_PROP1( TARGET_URL,             ::rtl::OUString,            BOUND );
122         DECL_PROP1( TARGET_FRAME,           ::rtl::OUString,            BOUND );
123         DECL_PROP1( TABINDEX,               sal_Int16,                  BOUND );
124     END_DESCRIBE_PROPERTIES();
125 }
126 
127 //------------------------------------------------------------------------------
IMPLEMENT_DEFAULT_CLONING(OButtonModel)128 IMPLEMENT_DEFAULT_CLONING( OButtonModel )
129 
130 // XServiceInfo
131 //------------------------------------------------------------------------------
132 StringSequence  OButtonModel::getSupportedServiceNames() throw()
133 {
134     StringSequence aSupported = OClickableImageBaseModel::getSupportedServiceNames();
135     aSupported.realloc( aSupported.getLength() + 1 );
136 
137     ::rtl::OUString* pArray = aSupported.getArray();
138     pArray[ aSupported.getLength() - 1 ] = FRM_SUN_COMPONENT_COMMANDBUTTON;
139 
140     return aSupported;
141 }
142 
143 //------------------------------------------------------------------------------
getServiceName()144 ::rtl::OUString OButtonModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException)
145 {
146     return FRM_COMPONENT_COMMANDBUTTON; // old (non-sun) name for compatibility !
147 }
148 
149 //------------------------------------------------------------------------------
write(const Reference<XObjectOutputStream> & _rxOutStream)150 void OButtonModel::write(const Reference<XObjectOutputStream>& _rxOutStream) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
151 {
152     OClickableImageBaseModel::write(_rxOutStream);
153 
154     _rxOutStream->writeShort(0x0003);   // Version
155 
156     {
157         OStreamSection aSection( _rxOutStream.get() );
158             // this will allow readers to skip unknown bytes in their dtor
159 
160         _rxOutStream->writeShort( (sal_uInt16)m_eButtonType );
161 
162         ::rtl::OUString sTmp = INetURLObject::decode( m_sTargetURL, '%', INetURLObject::DECODE_UNAMBIGUOUS);
163         _rxOutStream << sTmp;
164         _rxOutStream << m_sTargetFrame;
165         writeHelpTextCompatibly(_rxOutStream);
166         _rxOutStream << isDispatchUrlInternal();
167     }
168 }
169 
170 //------------------------------------------------------------------------------
read(const Reference<XObjectInputStream> & _rxInStream)171 void OButtonModel::read(const Reference<XObjectInputStream>& _rxInStream) throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
172 {
173     OClickableImageBaseModel::read(_rxInStream);
174 
175     sal_uInt16 nVersion = _rxInStream->readShort();     // Version
176     switch (nVersion)
177     {
178         case 0x0001:
179         {
180             m_eButtonType = (FormButtonType)_rxInStream->readShort();
181 
182             _rxInStream >> m_sTargetURL;
183             _rxInStream >> m_sTargetFrame;
184         }
185         break;
186 
187         case 0x0002:
188         {
189             m_eButtonType = (FormButtonType)_rxInStream->readShort();
190 
191             _rxInStream >> m_sTargetURL;
192             _rxInStream >> m_sTargetFrame;
193             readHelpTextCompatibly(_rxInStream);
194         }
195         break;
196 
197         case 0x0003:
198         {
199             OStreamSection aSection( _rxInStream.get() );
200                 // this will skip any unknown bytes in it's dtor
201 
202             // button type
203             m_eButtonType = (FormButtonType)_rxInStream->readShort();
204 
205             // URL
206             _rxInStream >> m_sTargetURL;
207 
208             // target frame
209             _rxInStream >> m_sTargetFrame;
210 
211             // help text
212             readHelpTextCompatibly(_rxInStream);
213 
214             // DispatchInternal
215             sal_Bool bDispath;
216             _rxInStream >> bDispath;
217             setDispatchUrlInternal(bDispath);
218         }
219         break;
220 
221         default:
222             DBG_ERROR("OButtonModel::read : unknown version !");
223             m_eButtonType = FormButtonType_PUSH;
224             m_sTargetURL = ::rtl::OUString();
225             m_sTargetFrame = ::rtl::OUString();
226             break;
227     }
228 }
229 
230 //--------------------------------------------------------------------
disposing()231 void SAL_CALL OButtonModel::disposing()
232 {
233     m_aResetHelper.disposing();
234     OClickableImageBaseModel::disposing();
235 }
236 
237 //--------------------------------------------------------------------
reset()238 void SAL_CALL OButtonModel::reset() throw (RuntimeException)
239 {
240     if ( !m_aResetHelper.approveReset() )
241         return;
242 
243     impl_resetNoBroadcast_nothrow();
244 
245     m_aResetHelper.notifyResetted();
246 }
247 
248 //--------------------------------------------------------------------
addResetListener(const Reference<XResetListener> & _listener)249 void SAL_CALL OButtonModel::addResetListener( const Reference< XResetListener >& _listener ) throw (RuntimeException)
250 {
251     m_aResetHelper.addResetListener( _listener );
252 }
253 
254 //--------------------------------------------------------------------
removeResetListener(const Reference<XResetListener> & _listener)255 void SAL_CALL OButtonModel::removeResetListener( const Reference< XResetListener >& _listener ) throw (RuntimeException)
256 {
257     m_aResetHelper.removeResetListener( _listener );
258 }
259 
260 //--------------------------------------------------------------------
getFastPropertyValue(Any & _rValue,sal_Int32 _nHandle) const261 void SAL_CALL OButtonModel::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
262 {
263     switch ( _nHandle )
264     {
265     case PROPERTY_ID_DEFAULT_STATE:
266         _rValue <<= (sal_Int16)m_eDefaultState;
267         break;
268 
269     default:
270         OClickableImageBaseModel::getFastPropertyValue( _rValue, _nHandle );
271         break;
272     }
273 }
274 
275 //--------------------------------------------------------------------
setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle,const Any & _rValue)276 void SAL_CALL OButtonModel::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue ) throw (Exception)
277 {
278     switch ( _nHandle )
279     {
280     case PROPERTY_ID_DEFAULT_STATE:
281     {
282         sal_Int16 nDefaultState( (sal_Int16)STATE_NOCHECK );
283         OSL_VERIFY( _rValue >>= nDefaultState );
284         m_eDefaultState = (ToggleState)nDefaultState;
285         impl_resetNoBroadcast_nothrow();
286     }
287     break;
288 
289     default:
290         OClickableImageBaseModel::setFastPropertyValue_NoBroadcast( _nHandle, _rValue );
291         break;
292     }
293 }
294 
295 //--------------------------------------------------------------------
convertFastPropertyValue(Any & _rConvertedValue,Any & _rOldValue,sal_Int32 _nHandle,const Any & _rValue)296 sal_Bool SAL_CALL OButtonModel::convertFastPropertyValue( Any& _rConvertedValue, Any& _rOldValue, sal_Int32 _nHandle, const Any& _rValue ) throw (IllegalArgumentException)
297 {
298     sal_Bool bModified = sal_False;
299     switch ( _nHandle )
300     {
301     case PROPERTY_ID_DEFAULT_STATE:
302         bModified = tryPropertyValue( _rConvertedValue, _rOldValue, _rValue, (sal_Int16)m_eDefaultState );
303         break;
304 
305     default:
306         bModified = OClickableImageBaseModel::convertFastPropertyValue( _rConvertedValue, _rOldValue, _nHandle, _rValue );
307         break;
308     }
309     return bModified;
310 }
311 
312 //--------------------------------------------------------------------
getPropertyDefaultByHandle(sal_Int32 _nHandle) const313 Any OButtonModel::getPropertyDefaultByHandle( sal_Int32 _nHandle ) const
314 {
315     Any aDefault;
316     switch ( _nHandle )
317     {
318     case PROPERTY_ID_DEFAULT_STATE:
319         aDefault <<= (sal_Int16)STATE_NOCHECK;
320         break;
321 
322     default:
323         aDefault = OClickableImageBaseModel::getPropertyDefaultByHandle( _nHandle );
324         break;
325     }
326     return aDefault;
327 }
328 
329 //--------------------------------------------------------------------
impl_resetNoBroadcast_nothrow()330 void OButtonModel::impl_resetNoBroadcast_nothrow()
331 {
332     try
333     {
334         setPropertyValue( PROPERTY_STATE, getPropertyValue( PROPERTY_DEFAULT_STATE ) );
335     }
336     catch( const Exception& )
337     {
338         DBG_UNHANDLED_EXCEPTION();
339     }
340 }
341 
342 //==================================================================
343 // OButtonControl
344 //==================================================================
345 //------------------------------------------------------------------
OButtonControl_CreateInstance(const Reference<XMultiServiceFactory> & _rxFactory)346 InterfaceRef SAL_CALL OButtonControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
347 {
348     return *(new OButtonControl(_rxFactory));
349 }
350 
351 //------------------------------------------------------------------------------
_getTypes()352 Sequence<Type> OButtonControl::_getTypes()
353 {
354     return ::comphelper::concatSequences(
355         OButtonControl_BASE::getTypes(),
356         OClickableImageBaseControl::_getTypes(),
357         OFormNavigationHelper::getTypes()
358     );
359 }
360 
361 //------------------------------------------------------------------------------
getSupportedServiceNames()362 StringSequence  OButtonControl::getSupportedServiceNames() throw()
363 {
364     StringSequence aSupported = OClickableImageBaseControl::getSupportedServiceNames();
365     aSupported.realloc(aSupported.getLength() + 1);
366 
367     ::rtl::OUString*pArray = aSupported.getArray();
368     pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_COMMANDBUTTON;
369     return aSupported;
370 }
371 
372 //------------------------------------------------------------------------------
OButtonControl(const Reference<XMultiServiceFactory> & _rxFactory)373 OButtonControl::OButtonControl(const Reference<XMultiServiceFactory>& _rxFactory)
374                  :OClickableImageBaseControl(_rxFactory, VCL_CONTROL_COMMANDBUTTON)
375                  ,OFormNavigationHelper( _rxFactory )
376                  ,m_nClickEvent( 0 )
377                  ,m_nTargetUrlFeatureId( -1 )
378                  ,m_bEnabledByPropertyValue( sal_False )
379 {
380     increment(m_refCount);
381     {
382         // als ActionListener anmelden
383         Reference<XButton>  xButton;
384         query_aggregation( m_xAggregate, xButton);
385         if (xButton.is())
386             xButton->addActionListener(this);
387     }
388     // Refcount bei 1 fuer Listener
389     decrement(m_refCount);
390 }
391 
392 //------------------------------------------------------------------------------
~OButtonControl()393 OButtonControl::~OButtonControl()
394 {
395     if (m_nClickEvent)
396         Application::RemoveUserEvent(m_nClickEvent);
397 }
398 
399 // UNO Anbindung
400 //------------------------------------------------------------------------------
queryAggregation(const Type & _rType)401 Any SAL_CALL OButtonControl::queryAggregation(const Type& _rType) throw (RuntimeException)
402 {
403     // if asked for the XTypeProvider, don't let OButtonControl_BASE do this
404     Any aReturn;
405     if ( !_rType.equals( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) ) )
406         aReturn = OButtonControl_BASE::queryInterface( _rType );
407 
408     if ( !aReturn.hasValue() )
409         aReturn = OClickableImageBaseControl::queryAggregation( _rType );
410 
411     if ( !aReturn.hasValue() )
412         aReturn = OFormNavigationHelper::queryInterface( _rType );
413 
414     return aReturn;
415 }
416 
417 //------------------------------------------------------------------------------
disposing()418 void SAL_CALL OButtonControl::disposing()
419 {
420     startOrStopModelPropertyListening( false );
421 
422     OClickableImageBaseControl::disposing();
423     OFormNavigationHelper::dispose();
424 }
425 
426 //------------------------------------------------------------------------------
disposing(const EventObject & _rSource)427 void SAL_CALL OButtonControl::disposing( const EventObject& _rSource ) throw( RuntimeException )
428 {
429     OControl::disposing( _rSource );
430     OFormNavigationHelper::disposing( _rSource );
431 }
432 
433 // ActionListener
434 //------------------------------------------------------------------------------
actionPerformed(const ActionEvent &)435 void OButtonControl::actionPerformed(const ActionEvent& /*rEvent*/) throw ( ::com::sun::star::uno::RuntimeException)
436 {
437     // Asynchron fuer starutil::URL-Button
438     sal_uLong n = Application::PostUserEvent( LINK(this, OButtonControl,OnClick) );
439     {
440         ::osl::MutexGuard aGuard( m_aMutex );
441         m_nClickEvent = n;
442     }
443 }
444 
445 //------------------------------------------------------------------------------
IMPL_LINK(OButtonControl,OnClick,void *,EMPTYARG)446 IMPL_LINK( OButtonControl, OnClick, void*, EMPTYARG )
447 {
448     ::osl::ClearableMutexGuard aGuard( m_aMutex );
449     m_nClickEvent = 0;
450 
451     if (m_aApproveActionListeners.getLength())
452     {
453         // if there are listeners, start the action in an own thread, to not allow
454         // them to block us here (we're in the application's main thread)
455         getImageProducerThread()->addEvent();
456     }
457     else
458     {
459         // Sonst nicht. Dann darf man aber auf keinen Fal die Listener
460         // benachrichtigen, auch dann nicht, wenn er spaeter hinzukommt.
461         aGuard.clear();
462 
463         // recognize the button type
464         Reference<XPropertySet>  xSet(getModel(), UNO_QUERY);
465         if (!xSet.is())
466             return 0L;
467 
468         if (FormButtonType_PUSH == *(FormButtonType*)xSet->getPropertyValue(PROPERTY_BUTTONTYPE).getValue())
469         {
470             // notify the action listeners for a push button
471             ::cppu::OInterfaceIteratorHelper aIter(m_aActionListeners);
472             ActionEvent aEvt(static_cast<XWeak*>(this), m_aActionCommand);
473             while(aIter.hasMoreElements() )
474             {
475                 // catch exceptions
476                 // and catch them on a per-listener basis - if one listener fails, the others still need
477                 // to get notified
478                 // 97676 - 21.02.2002 - fs@openoffice.org
479                 try
480                 {
481                     static_cast< XActionListener* >( aIter.next() )->actionPerformed(aEvt);
482                 }
483 #ifdef DBG_UTIL
484                 catch( const RuntimeException& )
485                 {
486                     // silent this
487                 }
488 #endif
489                 catch( const Exception& )
490                 {
491                     DBG_ERROR( "OButtonControl::OnClick: caught a exception other than RuntimeException!" );
492                 }
493             }
494         }
495         else
496             actionPerformed_Impl( sal_False, ::com::sun::star::awt::MouseEvent() );
497     }
498     return 0L;
499 }
500 
501 //------------------------------------------------------------------------------
actionPerformed_Impl(sal_Bool _bNotifyListener,const::com::sun::star::awt::MouseEvent & _rEvt)502 void OButtonControl::actionPerformed_Impl( sal_Bool _bNotifyListener, const ::com::sun::star::awt::MouseEvent& _rEvt )
503 {
504     {
505         sal_Int16 nFeatureId = -1;
506         {
507             ::osl::MutexGuard aGuard( m_aMutex );
508             nFeatureId = m_nTargetUrlFeatureId;
509         }
510 
511         if ( nFeatureId != -1 )
512         {
513             if ( !approveAction() )
514                 return;
515 
516             ::vos::OGuard aGuard( Application::GetSolarMutex() );
517             dispatch( nFeatureId );
518             return;
519         }
520     }
521 
522     OClickableImageBaseControl::actionPerformed_Impl( _bNotifyListener, _rEvt );
523 }
524 
525 // XButton
526 //------------------------------------------------------------------------------
setLabel(const::rtl::OUString & Label)527 void OButtonControl::setLabel(const ::rtl::OUString& Label) throw( RuntimeException )
528 {
529     Reference<XButton>  xButton;
530     query_aggregation( m_xAggregate, xButton );
531     if (xButton.is())
532         xButton->setLabel(Label);
533 }
534 
535 //------------------------------------------------------------------------------
setActionCommand(const::rtl::OUString & _rCommand)536 void SAL_CALL OButtonControl::setActionCommand(const ::rtl::OUString& _rCommand) throw( RuntimeException )
537 {
538     {
539         ::osl::MutexGuard aGuard( m_aMutex );
540         m_aActionCommand = _rCommand;
541     }
542 
543     Reference<XButton>  xButton;
544     query_aggregation( m_xAggregate, xButton);
545     if (xButton.is())
546         xButton->setActionCommand(_rCommand);
547 }
548 
549 //------------------------------------------------------------------------------
addActionListener(const Reference<XActionListener> & _rxListener)550 void SAL_CALL OButtonControl::addActionListener(const Reference<XActionListener>& _rxListener) throw( RuntimeException )
551 {
552     m_aActionListeners.addInterface(_rxListener);
553 }
554 
555 //------------------------------------------------------------------------------
removeActionListener(const Reference<XActionListener> & _rxListener)556 void SAL_CALL OButtonControl::removeActionListener(const Reference<XActionListener>& _rxListener) throw( RuntimeException )
557 {
558     m_aActionListeners.removeInterface(_rxListener);
559 }
560 
561 //------------------------------------------------------------------------------
562 class DoPropertyListening
563 {
564 private:
565     Reference< XPropertySet >               m_xProps;
566     Reference< XPropertyChangeListener >    m_xListener;
567     bool                                    m_bStartListening;
568 
569 public:
570     DoPropertyListening(
571         const Reference< XInterface >& _rxComponent,
572         const Reference< XPropertyChangeListener >& _rxListener,
573         bool _bStart
574     );
575 
576     void    handleListening( const ::rtl::OUString& _rPropertyName );
577 };
578 
579 //..............................................................................
DoPropertyListening(const Reference<XInterface> & _rxComponent,const Reference<XPropertyChangeListener> & _rxListener,bool _bStart)580 DoPropertyListening::DoPropertyListening(
581         const Reference< XInterface >& _rxComponent, const Reference< XPropertyChangeListener >& _rxListener,
582         bool _bStart )
583     :m_xProps( _rxComponent, UNO_QUERY )
584     ,m_xListener( _rxListener )
585     ,m_bStartListening( _bStart )
586 {
587     DBG_ASSERT( m_xProps.is() || !_rxComponent.is(), "DoPropertyListening::DoPropertyListening: valid component, but no property set!" );
588     DBG_ASSERT( m_xListener.is(), "DoPropertyListening::DoPropertyListening: invalid listener!" );
589 }
590 
591 //..............................................................................
handleListening(const::rtl::OUString & _rPropertyName)592 void DoPropertyListening::handleListening( const ::rtl::OUString& _rPropertyName )
593 {
594     if ( m_xProps.is() )
595     {
596         if ( m_bStartListening )
597             m_xProps->addPropertyChangeListener( _rPropertyName, m_xListener );
598         else
599             m_xProps->removePropertyChangeListener( _rPropertyName, m_xListener );
600     }
601 }
602 
603 //------------------------------------------------------------------------------
startOrStopModelPropertyListening(bool _bStart)604 void OButtonControl::startOrStopModelPropertyListening( bool _bStart )
605 {
606     DoPropertyListening aListeningHandler( getModel(), this, _bStart );
607     aListeningHandler.handleListening( PROPERTY_TARGET_URL );
608     aListeningHandler.handleListening( PROPERTY_BUTTONTYPE );
609     aListeningHandler.handleListening( PROPERTY_ENABLED );
610 }
611 
612 //------------------------------------------------------------------------------
setModel(const Reference<XControlModel> & _rxModel)613 sal_Bool SAL_CALL OButtonControl::setModel( const Reference< XControlModel >& _rxModel ) throw ( RuntimeException )
614 {
615     startOrStopModelPropertyListening( false );
616     sal_Bool bResult = OClickableImageBaseControl::setModel( _rxModel );
617     startOrStopModelPropertyListening( true );
618 
619     m_bEnabledByPropertyValue = sal_True;
620     Reference< XPropertySet > xModelProps( _rxModel, UNO_QUERY );
621     if ( xModelProps.is() )
622         xModelProps->getPropertyValue( PROPERTY_ENABLED ) >>= m_bEnabledByPropertyValue;
623 
624     modelFeatureUrlPotentiallyChanged( );
625 
626     return bResult;
627 }
628 
629 //------------------------------------------------------------------------------
modelFeatureUrlPotentiallyChanged()630 void OButtonControl::modelFeatureUrlPotentiallyChanged( )
631 {
632     sal_Int16 nOldUrlFeatureId = m_nTargetUrlFeatureId;
633 
634     // doe we have another TargetURL now? If so, we need to update our dispatches
635     m_nTargetUrlFeatureId = getModelUrlFeatureId( );
636     if ( nOldUrlFeatureId != m_nTargetUrlFeatureId )
637     {
638         invalidateSupportedFeaturesSet();
639         if ( !isDesignMode() )
640             updateDispatches( );
641     }
642 }
643 
644 //------------------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & _rEvent)645 void SAL_CALL OButtonControl::propertyChange( const PropertyChangeEvent& _rEvent ) throw ( RuntimeException )
646 {
647     if  (   _rEvent.PropertyName.equals( PROPERTY_TARGET_URL )
648         ||  _rEvent.PropertyName.equals( PROPERTY_BUTTONTYPE )
649         )
650     {
651         modelFeatureUrlPotentiallyChanged( );
652     }
653     else if ( _rEvent.PropertyName.equals( PROPERTY_ENABLED ) )
654     {
655         _rEvent.NewValue >>= m_bEnabledByPropertyValue;
656     }
657 }
658 
659 //------------------------------------------------------------------------------
660 namespace
661 {
isFormControllerURL(const::rtl::OUString & _rURL)662     bool isFormControllerURL( const ::rtl::OUString& _rURL )
663     {
664         const sal_Int32 nPrefixLen = URL_CONTROLLER_PREFIX.length;
665         return  ( _rURL.getLength() > nPrefixLen )
666             &&  ( _rURL.compareToAscii( URL_CONTROLLER_PREFIX, nPrefixLen ) == 0 );
667     }
668 }
669 
670 //------------------------------------------------------------------------------
getModelUrlFeatureId() const671 sal_Int16 OButtonControl::getModelUrlFeatureId( ) const
672 {
673     sal_Int16 nFeatureId = -1;
674 
675     // some URL related properties of the model
676     ::rtl::OUString sUrl;
677     FormButtonType eButtonType = FormButtonType_PUSH;
678 
679     Reference< XPropertySet > xModelProps( const_cast< OButtonControl* >( this )->getModel(), UNO_QUERY );
680     if ( xModelProps.is() )
681     {
682         xModelProps->getPropertyValue( PROPERTY_TARGET_URL ) >>= sUrl;
683         xModelProps->getPropertyValue( PROPERTY_BUTTONTYPE ) >>= eButtonType;
684     }
685 
686     // are we an URL button?
687     if ( eButtonType == FormButtonType_URL )
688     {
689         // is it a feature URL?
690         if ( isFormControllerURL( sUrl ) )
691         {
692             OFormNavigationMapper aMapper( m_aContext.getLegacyServiceFactory() );
693             nFeatureId = aMapper.getFeatureId( sUrl );
694         }
695     }
696 
697     return nFeatureId;
698 }
699 
700 //------------------------------------------------------------------
setDesignMode(sal_Bool _bOn)701 void SAL_CALL OButtonControl::setDesignMode( sal_Bool _bOn ) throw( RuntimeException )
702 {
703     OClickableImageBaseControl::setDesignMode( _bOn  );
704 
705     if ( _bOn )
706         disconnectDispatchers();
707     else
708         connectDispatchers();
709         // this will connect if not already connected and just update else
710 }
711 
712 //------------------------------------------------------------------------------
getSupportedFeatures(::std::vector<sal_Int16> & _rFeatureIds)713 void OButtonControl::getSupportedFeatures( ::std::vector< sal_Int16 >& /* [out] */ _rFeatureIds )
714 {
715     if ( -1 != m_nTargetUrlFeatureId )
716         _rFeatureIds.push_back( m_nTargetUrlFeatureId );
717 }
718 
719 //------------------------------------------------------------------
featureStateChanged(sal_Int16 _nFeatureId,sal_Bool _bEnabled)720 void OButtonControl::featureStateChanged( sal_Int16 _nFeatureId, sal_Bool _bEnabled )
721 {
722     if ( _nFeatureId == m_nTargetUrlFeatureId )
723     {
724         // enable or disable our peer, according to the new state
725         Reference< XVclWindowPeer > xPeer( getPeer(), UNO_QUERY );
726         if ( xPeer.is() )
727             xPeer->setProperty( PROPERTY_ENABLED, makeAny( m_bEnabledByPropertyValue ? _bEnabled : sal_False ) );
728             // if we're disabled according to our model's property, then
729             // we don't care for the feature state, but *are* disabled.
730             // If the model's property states that we're enabled, then we *do*
731             // care for the feature state
732     }
733 
734     // base class
735     OFormNavigationHelper::featureStateChanged( _nFeatureId, _bEnabled );
736 }
737 
738 //------------------------------------------------------------------
allFeatureStatesChanged()739 void OButtonControl::allFeatureStatesChanged( )
740 {
741     if ( -1 != m_nTargetUrlFeatureId )
742         // we have only one supported feature, so simulate it has changed ...
743         featureStateChanged( m_nTargetUrlFeatureId, isEnabled( m_nTargetUrlFeatureId ) );
744 
745     // base class
746     OFormNavigationHelper::allFeatureStatesChanged( );
747 }
748 
749 //------------------------------------------------------------------
isEnabled(sal_Int16 _nFeatureId) const750 bool OButtonControl::isEnabled( sal_Int16 _nFeatureId ) const
751 {
752     if ( const_cast< OButtonControl* >( this )->isDesignMode() )
753         // TODO: the model property?
754        return true;
755 
756     return OFormNavigationHelper::isEnabled( _nFeatureId );
757 }
758 
759 //--------------------------------------------------------------------
registerDispatchProviderInterceptor(const Reference<XDispatchProviderInterceptor> & _rxInterceptor)760 void SAL_CALL OButtonControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException)
761 {
762     OClickableImageBaseControl::registerDispatchProviderInterceptor( _rxInterceptor );
763     OFormNavigationHelper::registerDispatchProviderInterceptor( _rxInterceptor );
764 }
765 
766 //--------------------------------------------------------------------
releaseDispatchProviderInterceptor(const Reference<XDispatchProviderInterceptor> & _rxInterceptor)767 void SAL_CALL OButtonControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException)
768 {
769     OClickableImageBaseControl::releaseDispatchProviderInterceptor( _rxInterceptor );
770     OFormNavigationHelper::releaseDispatchProviderInterceptor( _rxInterceptor );
771 }
772 
773 //.........................................................................
774 }   // namespace frm
775 //.........................................................................
776 
777