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