1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19 #ifndef INCLUDED_COMPHELPER_INTERFACECONTAINER3_H
20 #define INCLUDED_COMPHELPER_INTERFACECONTAINER3_H
21
22 #include <sal/config.h>
23
24 #include <com/sun/star/lang/EventObject.hpp>
25 #include <com/sun/star/lang/DisposedException.hpp>
26 #include <comphelper/comphelperdllapi.h>
27 #include <o3tl/cow_wrapper.hxx>
28 #include <vector>
29
30 namespace com
31 {
32 namespace sun
33 {
34 namespace star
35 {
36 namespace uno
37 {
38 class XInterface;
39 }
40 }
41 }
42 }
43 namespace osl
44 {
45 class Mutex;
46 }
47
48 /** */ //for docpp
49 namespace comphelper
50 {
51 template <class ListenerT> class OInterfaceContainerHelper3;
52 /**
53 This is the iterator of an InterfaceContainerHelper. Typically
54 one constructs an instance on the stack for one firing session.
55 It is not allowed to assign or copy an instance of this class.
56
57 @tparam ListenerT UNO event listener type
58 @see OInterfaceContainerHelper
59 */
60 template <class ListenerT> class OInterfaceIteratorHelper3
61 {
62 public:
63 /**
64 Create an iterator over the elements of the container. The iterator
65 copies the elements of the container. A change to the container
66 during the lifetime of an iterator is allowed and does not
67 affect the iterator-instance. The iterator and the container take cares
68 themself for concurrent access, no additional guarding is necessary.
69
70 Remark: The copy is on demand. The iterator copy the elements only if the container
71 change the contents...
72
73 @param rCont the container of the elements.
74 */
OInterfaceIteratorHelper3(OInterfaceContainerHelper3<ListenerT> & rCont_)75 OInterfaceIteratorHelper3(OInterfaceContainerHelper3<ListenerT>& rCont_)
76 : rCont(rCont_)
77 , maData(rCont.maData)
78 , nRemain(maData->size())
79 {
80 }
81
82 /** Return true, if there are more elements in the iterator. */
hasMoreElements() const83 bool hasMoreElements() const { return nRemain != 0; }
84 /** Return the next element of the iterator. Calling this method if
85 hasMoreElements() has returned false, is an error.
86 */
87 css::uno::Reference<ListenerT> const& next();
88
89 /** Removes the current element (the last one returned by next())
90 from the underlying container. Calling this method before
91 next() has been called or calling it twice with no next()
92 in between is an error.
93 */
94 void remove();
95
96 private:
97 OInterfaceContainerHelper3<ListenerT>& rCont;
98 o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>> maData;
99 sal_Int32 nRemain;
100
101 OInterfaceIteratorHelper3(const OInterfaceIteratorHelper3&) = delete;
102 OInterfaceIteratorHelper3& operator=(const OInterfaceIteratorHelper3&) = delete;
103 };
104
105 template <class ListenerT>
next()106 const css::uno::Reference<ListenerT>& OInterfaceIteratorHelper3<ListenerT>::next()
107 {
108 nRemain--;
109 return (*maData)[nRemain];
110 }
111
remove()112 template <class ListenerT> void OInterfaceIteratorHelper3<ListenerT>::remove()
113 {
114 rCont.removeInterface((*maData)[nRemain]);
115 }
116
117 /**
118 A container of interfaces. To access the elements use an iterator.
119 This implementation is thread safe.
120
121 @tparam ListenerT UNO event listener type
122 @see OInterfaceIteratorHelper
123 */
124 template <class ListenerT> class OInterfaceContainerHelper3
125 {
126 public:
127 /**
128 Create an interface container.
129
130 @param rMutex the mutex to protect multi thread access.
131 The lifetime must be longer than the lifetime
132 of this object.
133 */
OInterfaceContainerHelper3(::osl::Mutex & rMutex_)134 OInterfaceContainerHelper3(::osl::Mutex& rMutex_)
135 : rMutex(rMutex_)
136 {
137 }
138 /**
139 Return the number of Elements in the container. Only useful if you have acquired
140 the mutex.
141 */
142 sal_Int32 getLength() const;
143
144 /**
145 Return all interfaces added to this container.
146 **/
147 std::vector<css::uno::Reference<ListenerT>> getElements() const;
148
149 /** Inserts an element into the container. The position is not specified, thus it is not
150 specified in which order events are fired.
151
152 @attention
153 If you add the same interface more than once, then it will be added to the elements list
154 more than once and thus if you want to remove that interface from the list, you have to call
155 removeInterface() the same number of times.
156 In the latter case, you will also get events fired more than once (if the interface is a
157 listener interface).
158
159 @param rxIFace
160 interface to be added; it is allowed to
161 the same interface more than once
162 @return
163 the new count of elements in the container
164 */
165 sal_Int32 addInterface(const css::uno::Reference<ListenerT>& rxIFace);
166 /** Removes an element from the container. It uses interface equality to remove the interface.
167
168 @param rxIFace
169 interface to be removed
170 @return
171 the new count of elements in the container
172 */
173 sal_Int32 removeInterface(const css::uno::Reference<ListenerT>& rxIFace);
174 /**
175 Call disposing on all object in the container that
176 support XEventListener. Then clear the container.
177 */
178 void disposeAndClear(const css::lang::EventObject& rEvt);
179 /**
180 Clears the container without calling disposing().
181 */
182 void clear();
183
184 /** Executes a functor for each contained listener of specified type, e.g.
185 <code>forEach<awt::XPaintListener>(...</code>.
186
187 If a css::lang::DisposedException occurs which relates to
188 the called listener, then that listener is removed from the container.
189
190 @tparam FuncT unary functor type, let your compiler deduce this for you
191 @param func unary functor object expecting an argument of type
192 css::uno::Reference<ListenerT>
193 */
194 template <typename FuncT> inline void forEach(FuncT const& func);
195
196 /** Calls a UNO listener method for each contained listener.
197
198 The listener method must take a single argument of type EventT,
199 and return <code>void</code>.
200
201 If a css::lang::DisposedException occurs which relates to
202 the called listener, then that listener is removed from the container.
203
204 @tparam EventT event type, let your compiler deduce this for you
205 @param NotificationMethod
206 Pointer to a method of a ListenerT interface.
207 @param Event
208 Event to notify to all contained listeners
209
210 Example:
211 @code
212 awt::PaintEvent aEvent( static_cast< cppu::OWeakObject* >( this ), ... );
213 listeners.notifyEach( &XPaintListener::windowPaint, aEvent );
214 @endcode
215 */
216 template <typename EventT>
217 inline void notifyEach(void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&),
218 const EventT& Event);
219
220 private:
221 friend class OInterfaceIteratorHelper3<ListenerT>;
222 o3tl::cow_wrapper<std::vector<css::uno::Reference<ListenerT>>> maData;
223 ::osl::Mutex& rMutex;
224 OInterfaceContainerHelper3(const OInterfaceContainerHelper3&) = delete;
225 OInterfaceContainerHelper3& operator=(const OInterfaceContainerHelper3&) = delete;
226
227 private:
228 template <typename EventT> class NotifySingleListener
229 {
230 private:
231 typedef void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&);
232 NotificationMethod const m_pMethod;
233 const EventT& m_rEvent;
234
235 public:
NotifySingleListener(NotificationMethod method,const EventT & event)236 NotifySingleListener(NotificationMethod method, const EventT& event)
237 : m_pMethod(method)
238 , m_rEvent(event)
239 {
240 }
241
operator ()(const css::uno::Reference<ListenerT> & listener) const242 void operator()(const css::uno::Reference<ListenerT>& listener) const
243 {
244 (listener.get()->*m_pMethod)(m_rEvent);
245 }
246 };
247 };
248
249 template <class T>
250 template <typename FuncT>
forEach(FuncT const & func)251 inline void OInterfaceContainerHelper3<T>::forEach(FuncT const& func)
252 {
253 OInterfaceIteratorHelper3<T> iter(*this);
254 while (iter.hasMoreElements())
255 {
256 auto xListener = iter.next();
257 try
258 {
259 func(xListener);
260 }
261 catch (css::lang::DisposedException const& exc)
262 {
263 if (exc.Context == xListener)
264 iter.remove();
265 }
266 }
267 }
268
269 template <class ListenerT>
270 template <typename EventT>
notifyEach(void (SAL_CALL ListenerT::* NotificationMethod)(const EventT &),const EventT & Event)271 inline void OInterfaceContainerHelper3<ListenerT>::notifyEach(
272 void (SAL_CALL ListenerT::*NotificationMethod)(const EventT&), const EventT& Event)
273 {
274 forEach<NotifySingleListener<EventT>>(NotifySingleListener<EventT>(NotificationMethod, Event));
275 }
276
getLength() const277 template <class ListenerT> sal_Int32 OInterfaceContainerHelper3<ListenerT>::getLength() const
278 {
279 osl::MutexGuard aGuard(rMutex);
280 return maData->size();
281 }
282
283 template <class ListenerT>
284 std::vector<css::uno::Reference<ListenerT>>
getElements() const285 OInterfaceContainerHelper3<ListenerT>::getElements() const
286 {
287 std::vector<css::uno::Reference<ListenerT>> rVec;
288 osl::MutexGuard aGuard(rMutex);
289 rVec = *maData;
290 return rVec;
291 }
292
293 template <class ListenerT>
294 sal_Int32
addInterface(const css::uno::Reference<ListenerT> & rListener)295 OInterfaceContainerHelper3<ListenerT>::addInterface(const css::uno::Reference<ListenerT>& rListener)
296 {
297 assert(rListener.is());
298 osl::MutexGuard aGuard(rMutex);
299
300 maData->push_back(rListener);
301 return maData->size();
302 }
303
304 template <class ListenerT>
removeInterface(const css::uno::Reference<ListenerT> & rListener)305 sal_Int32 OInterfaceContainerHelper3<ListenerT>::removeInterface(
306 const css::uno::Reference<ListenerT>& rListener)
307 {
308 assert(rListener.is());
309 osl::MutexGuard aGuard(rMutex);
310
311 // It is not valid to compare the pointer directly, but it's faster.
312 auto it = std::find_if(maData->begin(), maData->end(),
313 [&rListener](const css::uno::Reference<css::uno::XInterface>& rItem) {
314 return rItem.get() == rListener.get();
315 });
316
317 // interface not found, use the correct compare method
318 if (it == maData->end())
319 it = std::find(maData->begin(), maData->end(), rListener);
320
321 if (it != maData->end())
322 maData->erase(it);
323
324 return maData->size();
325 }
326
327 template <class ListenerT>
disposeAndClear(const css::lang::EventObject & rEvt)328 void OInterfaceContainerHelper3<ListenerT>::disposeAndClear(const css::lang::EventObject& rEvt)
329 {
330 osl::ClearableMutexGuard aGuard(rMutex);
331 OInterfaceIteratorHelper3<ListenerT> aIt(*this);
332 maData->clear();
333 aGuard.clear();
334 while (aIt.hasMoreElements())
335 {
336 try
337 {
338 aIt.next()->disposing(rEvt);
339 }
340 catch (css::uno::RuntimeException&)
341 {
342 // be robust, if e.g. a remote bridge has disposed already.
343 // there is no way to delegate the error to the caller :o(.
344 }
345 }
346 }
347
clear()348 template <class ListenerT> void OInterfaceContainerHelper3<ListenerT>::clear()
349 {
350 osl::MutexGuard aGuard(rMutex);
351 maData->clear();
352 }
353 }
354 #endif
355
356 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
357