xref: /trunk/main/forms/source/component/Button.cxx (revision 24acc546)
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