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 #ifndef COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX 25 #define COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX 26 27 #include <cppuhelper/interfacecontainer.hxx> 28 29 /** === begin UNO includes === **/ 30 #include <com/sun/star/lang/XEventListener.hpp> 31 /** === end UNO includes === **/ 32 #include "comphelper/comphelperdllapi.h" 33 34 #include <memory> 35 36 //........................................................................ 37 namespace comphelper 38 { 39 //........................................................................ 40 41 //==================================================================== 42 //= OListenerContainer 43 //==================================================================== 44 /** abstract base class which manages a listener container, including 45 THB's listener notification pattern which cares for removing listeners 46 which throw an DisposedException upon notification 47 48 Using this class is pretty easy: 49 <ul> 50 <li>Derive from it, and overwrite implNotify.</li> 51 <li>Use <member>impl_addListener</member> and <member>impl_removeListener</member> in your 52 XFoo::addFooListener and XFoo::removeFooListener methods.</li> 53 <li>call <member>impl_notify</member> whenever the event you want to notify happened</li> 54 <li>call <member>disposing</member> upon the disposal of your broadcaster.</li> 55 </ul> 56 57 See <type>OListenerContainerBase</type> for an implementation which even saves 58 you some more work, by doing the casts for you. 59 60 @see http://www.openoffice.org/servlets/ReadMsg?list=interface-announce&msgId=494345 61 @see OListenerContainerBase 62 */ 63 class COMPHELPER_DLLPUBLIC OListenerContainer 64 { 65 private: 66 ::cppu::OInterfaceContainerHelper m_aListeners; 67 68 public: 69 /** sends a XEventObject::disposing notification to all listeners, and clears the 70 listener container 71 72 You'll usually call this from within your own dispose/disposing method 73 */ 74 void disposing( const ::com::sun::star::lang::EventObject& _rEventSource ); 75 76 /** clears the container without calling <member scope="com::sun::star::lang">XEventListener::disposing</member> 77 at the listeners 78 */ 79 void clear(); 80 81 /** determines whether the listener container is currently empty 82 */ 83 inline bool 84 empty() const SAL_THROW(()); 85 86 /** determines the number of elements in the container 87 */ 88 inline size_t 89 size() const SAL_THROW(()); 90 91 /** creates an iterator for looping through all registered listeners 92 */ 93 inline ::std::auto_ptr< ::cppu::OInterfaceIteratorHelper > 94 createIterator(); 95 96 protected: 97 OListenerContainer( ::osl::Mutex& _rMutex ); 98 99 virtual ~OListenerContainer(); 100 101 void impl_addListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener ); 102 void impl_removeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener ); 103 104 /** notifies all listeners of the given event, using THB's notification pattern 105 106 internally, this method will call <member>implNotify</member> for every listener 107 108 @return 109 <TRUE/> if all listeners have been notified, <FALSE/> else. The latter can happen 110 if <member>implNotify</member> cancelles the notification loop. 111 112 @see implNotify 113 */ 114 bool impl_notify( const ::com::sun::star::lang::EventObject& _rEvent ) SAL_THROW(( ::com::sun::star::uno::Exception )); 115 116 protected: 117 /** call a single listener 118 119 @pure 120 121 @throws ::com::sun::star::uno::Exception 122 if the listener throws an exception during notification. Please don't catch 123 any listener exceptions in your implementation of this method, simply let them 124 pass to the caller. 125 126 @param _rxListener 127 specifies the listener to call. Is guaranteed to not be <NULL/> 128 @param _rEvent 129 the event to broadcast. This is the same as passed to <member>notify</member>, so if 130 your base class knows the type passed into <member>notify</member>, it can safely assume 131 that <arg>_rEvent</arg> is also of this type. 132 133 @return 134 <TRUE/> if the remaining listeners should be called, <FALSE/> if the notification 135 loop should be cancelled 136 137 @see notify 138 */ 139 virtual bool implNotify( 140 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener, 141 const ::com::sun::star::lang::EventObject& _rEvent 142 ) SAL_THROW( ( ::com::sun::star::uno::Exception ) ) = 0; 143 }; 144 145 //==================================================================== empty() const146 inline bool OListenerContainer::empty() const SAL_THROW(()) 147 { 148 return ( m_aListeners.getLength() == 0 ); 149 } 150 size() const151 inline size_t OListenerContainer::size() const SAL_THROW(()) 152 { 153 return m_aListeners.getLength(); 154 } 155 createIterator()156 inline ::std::auto_ptr< ::cppu::OInterfaceIteratorHelper > OListenerContainer::createIterator() 157 { 158 ::std::auto_ptr< ::cppu::OInterfaceIteratorHelper > pIterator( new ::cppu::OInterfaceIteratorHelper( m_aListeners ) ); 159 return pIterator; 160 } 161 162 //==================================================================== 163 //= OSimpleListenerContainer 164 //==================================================================== 165 /** helper class for simple notification of the form LISTENER::METHOD( EVENT ) 166 167 This class is not threadsafe! 168 169 @param LISTENER 170 the listener class to call, e.g. <type scope="com::sun::star::lang">XEventListener</type> 171 @param EVENT 172 the event type to notify, e.g. <type scope="com::sun::star::lang">EventObject</type> 173 */ 174 template< class LISTENER, class EVENT > 175 class OSimpleListenerContainer : protected OListenerContainer 176 { 177 public: 178 typedef LISTENER ListenerClass; 179 typedef EVENT EventClass; 180 typedef void ( SAL_CALL LISTENER::*NotificationMethod )( const EventClass& ); 181 182 private: 183 NotificationMethod m_pNotificationMethod; 184 185 public: OSimpleListenerContainer(::osl::Mutex & _rMutex)186 OSimpleListenerContainer( ::osl::Mutex& _rMutex ) 187 :OListenerContainer( _rMutex ) 188 ,m_pNotificationMethod( NULL ) 189 { 190 } 191 addListener(const::com::sun::star::uno::Reference<ListenerClass> & _rxListener)192 inline void addListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener ) 193 { 194 OListenerContainer::impl_addListener( _rxListener.get() ); 195 } 196 removeListener(const::com::sun::star::uno::Reference<ListenerClass> & _rxListener)197 inline void removeListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener ) 198 { 199 OListenerContainer::impl_removeListener( _rxListener.get() ); 200 } 201 202 // publish some otherwise hidden base functionality 203 using OListenerContainer::disposing; 204 using OListenerContainer::clear; 205 using OListenerContainer::empty; 206 using OListenerContainer::size; 207 using OListenerContainer::createIterator; 208 209 /// typed notification 210 inline bool notify( const EventClass& _rEvent, NotificationMethod _pNotify ) SAL_THROW(( ::com::sun::star::uno::Exception )); 211 212 protected: 213 inline virtual bool implNotify( 214 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener, 215 const ::com::sun::star::lang::EventObject& _rEvent 216 ) SAL_THROW( ( ::com::sun::star::uno::Exception ) ); 217 }; 218 219 //-------------------------------------------------------------------- 220 template< class LISTENER, class EVENT > notify(const EventClass & _rEvent,NotificationMethod _pNotify)221 inline bool OSimpleListenerContainer< LISTENER, EVENT >::notify( const EventClass& _rEvent, NotificationMethod _pNotify ) SAL_THROW(( ::com::sun::star::uno::Exception )) 222 { 223 m_pNotificationMethod = _pNotify; 224 bool bRet = OListenerContainer::impl_notify( _rEvent ); 225 m_pNotificationMethod = NULL; 226 return bRet; 227 } 228 229 //-------------------------------------------------------------------- 230 template< class LISTENER, class EVENT > implNotify(const::com::sun::star::uno::Reference<::com::sun::star::lang::XEventListener> & _rxListener,const::com::sun::star::lang::EventObject & _rEvent)231 inline bool OSimpleListenerContainer< LISTENER, EVENT >::implNotify( 232 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener, 233 const ::com::sun::star::lang::EventObject& _rEvent ) SAL_THROW( ( ::com::sun::star::uno::Exception ) ) 234 { 235 const EventClass& rTypedEvent( static_cast< const EventClass& >( _rEvent ) ); 236 ListenerClass* pTypedListener( static_cast< ListenerClass* >( _rxListener.get() ) ); 237 (pTypedListener->*m_pNotificationMethod)( rTypedEvent ); 238 return true; 239 } 240 241 //==================================================================== 242 //= OListenerContainerBase 243 //==================================================================== 244 /** is a specialization of OListenerContainer which saves you some additional type casts, 245 by making the required listener and event types template arguments. 246 */ 247 template< class LISTENER, class EVENT > 248 class OListenerContainerBase : public OListenerContainer 249 { 250 public: 251 typedef LISTENER ListenerClass; 252 typedef EVENT EventClass; 253 254 public: OListenerContainerBase(::osl::Mutex & _rMutex)255 inline OListenerContainerBase( ::osl::Mutex& _rMutex ) : OListenerContainer( _rMutex ) 256 { 257 } 258 addTypedListener(const::com::sun::star::uno::Reference<ListenerClass> & _rxListener)259 inline void addTypedListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener ) 260 { 261 OListenerContainer::impl_addListener( _rxListener.get() ); 262 } 263 removeTypedListener(const::com::sun::star::uno::Reference<ListenerClass> & _rxListener)264 inline void removeTypedListener( const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener ) 265 { 266 OListenerContainer::impl_removeListener( _rxListener.get() ); 267 } 268 notify(const EventClass & _rEvent)269 inline bool notify( const EventClass& _rEvent ) 270 { 271 return OListenerContainer::impl_notify( _rEvent ); 272 } 273 274 using OListenerContainer::impl_notify; 275 276 protected: 277 inline virtual bool implNotify( 278 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener, 279 const ::com::sun::star::lang::EventObject& _rEvent 280 ) SAL_THROW( ( ::com::sun::star::uno::Exception ) ); 281 282 virtual bool implTypedNotify( 283 const ::com::sun::star::uno::Reference< ListenerClass >& _rxListener, 284 const EventClass& _rEvent 285 ) SAL_THROW( ( ::com::sun::star::uno::Exception ) ) = 0; 286 }; 287 288 template< class LISTENER, class EVENT > implNotify(const::com::sun::star::uno::Reference<::com::sun::star::lang::XEventListener> & _rxListener,const::com::sun::star::lang::EventObject & _rEvent)289 inline bool OListenerContainerBase< LISTENER, EVENT >::implNotify( 290 const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& _rxListener, 291 const ::com::sun::star::lang::EventObject& _rEvent ) SAL_THROW( ( ::com::sun::star::uno::Exception ) ) 292 { 293 return implTypedNotify( 294 ::com::sun::star::uno::Reference< ListenerClass >( static_cast< ListenerClass* >( _rxListener.get() ) ), 295 static_cast< const EventClass& >( _rEvent ) 296 ); 297 } 298 299 //........................................................................ 300 } // namespace comphelper 301 //........................................................................ 302 303 #endif // COMPHELPER_INC_COMPHELPER_LISTENERNOTIFICATION_HXX 304 305