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