OpenShot Library | OpenShotAudio 0.2.2
juce_ListenerList.h
1
2/** @weakgroup juce_core-containers
3 * @{
4 */
5/*
6 ==============================================================================
7
8 This file is part of the JUCE library.
9 Copyright (c) 2017 - ROLI Ltd.
10
11 JUCE is an open source library subject to commercial or open-source
12 licensing.
13
14 The code included in this file is provided under the terms of the ISC license
15 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16 To use, copy, modify, and/or distribute this software for any purpose with or
17 without fee is hereby granted provided that the above copyright notice and
18 this permission notice appear in all copies.
19
20 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22 DISCLAIMED.
23
24 ==============================================================================
25*/
26
27namespace juce
28{
29
30//==============================================================================
31/**
32 Holds a set of objects and can invoke a member function callback on each object
33 in the set with a single call.
34
35 Use a ListenerList to manage a set of objects which need a callback, and you
36 can invoke a member function by simply calling call() or callChecked().
37
38 E.g.
39 @code
40 class MyListenerType
41 {
42 public:
43 void myCallbackMethod (int foo, bool bar);
44 };
45
46 ListenerList<MyListenerType> listeners;
47 listeners.add (someCallbackObjects...);
48
49 // This will invoke myCallbackMethod (1234, true) on each of the objects
50 // in the list...
51 listeners.call ([] (MyListenerType& l) { l.myCallbackMethod (1234, true); });
52 @endcode
53
54 If you add or remove listeners from the list during one of the callbacks - i.e. while
55 it's in the middle of iterating the listeners, then it's guaranteed that no listeners
56 will be mistakenly called after they've been removed, but it may mean that some of the
57 listeners could be called more than once, or not at all, depending on the list's order.
58
59 Sometimes, there's a chance that invoking one of the callbacks might result in the
60 list itself being deleted while it's still iterating - to survive this situation, you can
61 use callChecked() instead of call(), passing it a local object to act as a "BailOutChecker".
62 The BailOutChecker must implement a method of the form "bool shouldBailOut()", and
63 the list will check this after each callback to determine whether it should abort the
64 operation. For an example of a bail-out checker, see the Component::BailOutChecker class,
65 which can be used to check when a Component has been deleted. See also
66 ListenerList::DummyBailOutChecker, which is a dummy checker that always returns false.
67
68 @tags{Core}
69*/
70template <class ListenerClass,
71 class ArrayType = Array<ListenerClass*>>
73{
74public:
75 //==============================================================================
76 /** Creates an empty list. */
77 ListenerList() = default;
78
79 /** Destructor. */
80 ~ListenerList() = default;
81
82 //==============================================================================
83 /** Adds a listener to the list.
84 A listener can only be added once, so if the listener is already in the list,
85 this method has no effect.
86 @see remove
87 */
88 void add (ListenerClass* listenerToAdd)
89 {
90 if (listenerToAdd != nullptr)
91 listeners.addIfNotAlreadyThere (listenerToAdd);
92 else
93 jassertfalse; // Listeners can't be null pointers!
94 }
95
96 /** Removes a listener from the list.
97 If the listener wasn't in the list, this has no effect.
98 */
99 void remove (ListenerClass* listenerToRemove)
100 {
101 jassert (listenerToRemove != nullptr); // Listeners can't be null pointers!
102 listeners.removeFirstMatchingValue (listenerToRemove);
103 }
104
105 /** Returns the number of registered listeners. */
106 int size() const noexcept { return listeners.size(); }
107
108 /** Returns true if no listeners are registered, false otherwise. */
109 bool isEmpty() const noexcept { return listeners.isEmpty(); }
110
111 /** Clears the list. */
112 void clear() { listeners.clear(); }
113
114 /** Returns true if the specified listener has been added to the list. */
115 bool contains (ListenerClass* listener) const noexcept { return listeners.contains (listener); }
116
117 /** Returns the raw array of listeners. */
118 const ArrayType& getListeners() const noexcept { return listeners; }
119
120 //==============================================================================
121 /** Calls a member function on each listener in the list, with multiple parameters. */
122 template <typename Callback>
123 void call (Callback&& callback)
124 {
125 typename ArrayType::ScopedLockType lock (listeners.getLock());
126
127 for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
128 callback (*iter.getListener());
129 }
130
131 /** Calls a member function with 1 parameter, on all but the specified listener in the list.
132 This can be useful if the caller is also a listener and needs to exclude itself.
133 */
134 template <typename Callback>
135 void callExcluding (ListenerClass* listenerToExclude, Callback&& callback)
136 {
137 typename ArrayType::ScopedLockType lock (listeners.getLock());
138
139 for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
140 {
141 auto* l = iter.getListener();
142
143 if (l != listenerToExclude)
144 callback (*l);
145 }
146 }
147
148 /** Calls a member function on each listener in the list, with 1 parameter and a bail-out-checker.
149 See the class description for info about writing a bail-out checker.
150 */
151 template <typename Callback, typename BailOutCheckerType>
152 void callChecked (const BailOutCheckerType& bailOutChecker, Callback&& callback)
153 {
154 typename ArrayType::ScopedLockType lock (listeners.getLock());
155
156 for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
157 callback (*iter.getListener());
158 }
159
160 /** Calls a member function, with 1 parameter, on all but the specified listener in the list
161 with a bail-out-checker. This can be useful if the caller is also a listener and needs to
162 exclude itself. See the class description for info about writing a bail-out checker.
163 */
164 template <typename Callback, typename BailOutCheckerType>
165 void callCheckedExcluding (ListenerClass* listenerToExclude,
166 const BailOutCheckerType& bailOutChecker,
167 Callback&& callback)
168 {
169 typename ArrayType::ScopedLockType lock (listeners.getLock());
170
171 for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
172 {
173 auto* l = iter.getListener();
174
175 if (l != listenerToExclude)
176 callback (*l);
177 }
178 }
179
180 //==============================================================================
181 /** A dummy bail-out checker that always returns false.
182 See the ListenerList notes for more info about bail-out checkers.
183 */
185 {
186 bool shouldBailOut() const noexcept { return false; }
187 };
188
190 using ListenerType = ListenerClass;
191
192 //==============================================================================
193 /** Iterates the listeners in a ListenerList. */
194 template <class BailOutCheckerType, class ListType>
195 struct Iterator
196 {
197 Iterator (const ListType& listToIterate) noexcept
198 : list (listToIterate), index (listToIterate.size())
199 {}
200
201 ~Iterator() = default;
202
203 //==============================================================================
204 bool next() noexcept
205 {
206 if (index <= 0)
207 return false;
208
209 auto listSize = list.size();
210
211 if (--index < listSize)
212 return true;
213
214 index = listSize - 1;
215 return index >= 0;
216 }
217
218 bool next (const BailOutCheckerType& bailOutChecker) noexcept
219 {
220 return (! bailOutChecker.shouldBailOut()) && next();
221 }
222
223 typename ListType::ListenerType* getListener() const noexcept
224 {
225 return list.getListeners().getUnchecked (index);
226 }
227
228 //==============================================================================
229 private:
230 const ListType& list;
231 int index;
232
233 JUCE_DECLARE_NON_COPYABLE (Iterator)
234 };
235
236 //==============================================================================
237 #ifndef DOXYGEN
238 // There are now lambda-based call functions that can be used to replace these old method-based versions.
239 // We'll eventually deprecate these old ones, so please begin moving your code to use lambdas!
240 void call (void (ListenerClass::*callbackFunction) ())
241 {
242 call ([=] (ListenerClass& l) { (l.*callbackFunction)(); });
243 }
244
245 void callExcluding (ListenerClass* listenerToExclude, void (ListenerClass::*callbackFunction) ())
246 {
247 callExcluding (listenerToExclude, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
248 }
249
250 template <class BailOutCheckerType>
251 void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) ())
252 {
253 callChecked (bailOutChecker, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
254 }
255
256 template <class BailOutCheckerType>
257 void callCheckedExcluding (ListenerClass* listenerToExclude,
258 const BailOutCheckerType& bailOutChecker,
259 void (ListenerClass::*callbackFunction) ())
260 {
261 callCheckedExcluding (listenerToExclude, bailOutChecker, [=] (ListenerClass& l) { (l.*callbackFunction)(); });
262 }
263
264 template <typename... MethodArgs, typename... Args>
265 void call (void (ListenerClass::*callbackFunction) (MethodArgs...), Args&&... args)
266 {
267 typename ArrayType::ScopedLockType lock (listeners.getLock());
268
269 for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
270 (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
271 }
272
273 template <typename... MethodArgs, typename... Args>
274 void callExcluding (ListenerClass* listenerToExclude,
275 void (ListenerClass::*callbackFunction) (MethodArgs...),
276 Args&&... args)
277 {
278 typename ArrayType::ScopedLockType lock (listeners.getLock());
279
280 for (Iterator<DummyBailOutChecker, ThisType> iter (*this); iter.next();)
281 if (iter.getListener() != listenerToExclude)
282 (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
283 }
284
285 template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
286 void callChecked (const BailOutCheckerType& bailOutChecker,
287 void (ListenerClass::*callbackFunction) (MethodArgs...),
288 Args&&... args)
289 {
290 typename ArrayType::ScopedLockType lock (listeners.getLock());
291
292 for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
293 (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
294 }
295
296 template <typename BailOutCheckerType, typename... MethodArgs, typename... Args>
297 void callCheckedExcluding (ListenerClass* listenerToExclude,
298 const BailOutCheckerType& bailOutChecker,
299 void (ListenerClass::*callbackFunction) (MethodArgs...),
300 Args&&... args)
301 {
302 typename ArrayType::ScopedLockType lock (listeners.getLock());
303
304 for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
305 if (iter.getListener() != listenerToExclude)
306 (iter.getListener()->*callbackFunction) (static_cast<typename TypeHelpers::ParameterType<Args>::type> (args)...);
307 }
308 #endif
309
310private:
311 //==============================================================================
312 ArrayType listeners;
313
314 JUCE_DECLARE_NON_COPYABLE (ListenerList)
315};
316
317} // namespace juce
318
319/** @}*/
Holds a set of objects and can invoke a member function callback on each object in the set with a sin...
~ListenerList()=default
Destructor.
void callChecked(const BailOutCheckerType &bailOutChecker, Callback &&callback)
Calls a member function on each listener in the list, with 1 parameter and a bail-out-checker.
bool isEmpty() const noexcept
Returns true if no listeners are registered, false otherwise.
void callCheckedExcluding(ListenerClass *listenerToExclude, const BailOutCheckerType &bailOutChecker, Callback &&callback)
Calls a member function, with 1 parameter, on all but the specified listener in the list with a bail-...
void call(Callback &&callback)
Calls a member function on each listener in the list, with multiple parameters.
void callExcluding(ListenerClass *listenerToExclude, Callback &&callback)
Calls a member function with 1 parameter, on all but the specified listener in the list.
void add(ListenerClass *listenerToAdd)
Adds a listener to the list.
void remove(ListenerClass *listenerToRemove)
Removes a listener from the list.
bool contains(ListenerClass *listener) const noexcept
Returns true if the specified listener has been added to the list.
int size() const noexcept
Returns the number of registered listeners.
ListenerList()=default
Creates an empty list.
const ArrayType & getListeners() const noexcept
Returns the raw array of listeners.
void clear()
Clears the list.
A dummy bail-out checker that always returns false.
Iterates the listeners in a ListenerList.