1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qglobal.h"
41
42 #include "qsignalmapper.h"
43 #include "qhash.h"
44 #include "qobject_p.h"
45
46 QT_BEGIN_NAMESPACE
47
48 class QSignalMapperPrivate : public QObjectPrivate
49 {
50 Q_DECLARE_PUBLIC(QSignalMapper)
51 public:
_q_senderDestroyed()52 void _q_senderDestroyed() {
53 Q_Q(QSignalMapper);
54 q->removeMappings(q->sender());
55 }
56
57 template <class Signal, class Container>
emitMappedValue(QObject * sender,Signal signal,const Container & mappedValues)58 void emitMappedValue(QObject *sender, Signal signal, const Container &mappedValues)
59 {
60 Q_Q(QSignalMapper);
61
62 auto it = mappedValues.find(sender);
63 if (it != mappedValues.end()) {
64 #if QT_DEPRECATED_SINCE(5, 15)
65 QT_WARNING_PUSH
66 QT_WARNING_DISABLE_DEPRECATED
67 Q_EMIT q->mapped(*it);
68 QT_WARNING_POP
69 #endif
70 Q_EMIT (q->*signal)(*it);
71 }
72 }
73
emitMappedValues(QObject * sender)74 void emitMappedValues(QObject *sender)
75 {
76 emitMappedValue(sender, &QSignalMapper::mappedInt, intHash);
77 emitMappedValue(sender, &QSignalMapper::mappedString, stringHash);
78 emitMappedValue(sender, &QSignalMapper::mappedWidget, widgetHash);
79 emitMappedValue(sender, &QSignalMapper::mappedObject, objectHash);
80 }
81
82 QHash<QObject *, int> intHash;
83 QHash<QObject *, QString> stringHash;
84 QHash<QObject *, QWidget*> widgetHash;
85 QHash<QObject *, QObject*> objectHash;
86 };
87
88 /*!
89 \class QSignalMapper
90 \inmodule QtCore
91 \brief The QSignalMapper class bundles signals from identifiable senders.
92
93 \ingroup objectmodel
94
95
96 This class collects a set of parameterless signals, and re-emits
97 them with integer, string or widget parameters corresponding to
98 the object that sent the signal. Note that in most cases you can
99 use lambdas for passing custom parameters to slots. This is less
100 costly and will simplify the code.
101
102 The class supports the mapping of particular strings, integers,
103 objects and widgets with particular objects using setMapping().
104 The objects' signals can then be connected to the map() slot which
105 will emit a signal (it could be mappedInt(), mappedString(),
106 mappedWidget() and mappedObject()) with a value associated with
107 the original signalling object. Mappings can be removed later using
108 removeMappings().
109
110 Example: Suppose we want to create a custom widget that contains
111 a group of buttons (like a tool palette). One approach is to
112 connect each button's \c clicked() signal to its own custom slot;
113 but in this example we want to connect all the buttons to a
114 single slot and parameterize the slot by the button that was
115 clicked.
116
117 Here's the definition of a simple custom widget that has a single
118 signal, \c clicked(), which is emitted with the text of the button
119 that was clicked:
120
121 \snippet qsignalmapper/buttonwidget.h 0
122 \snippet qsignalmapper/buttonwidget.h 1
123
124 The only function that we need to implement is the constructor:
125
126 \snippet qsignalmapper/buttonwidget.cpp 0
127 \snippet qsignalmapper/buttonwidget.cpp 1
128 \snippet qsignalmapper/buttonwidget.cpp 2
129
130 A list of texts is passed to the constructor. A signal mapper is
131 constructed and for each text in the list a QPushButton is
132 created. We connect each button's \c clicked() signal to the
133 signal mapper's map() slot, and create a mapping in the signal
134 mapper from each button to the button's text. Finally we connect
135 the signal mapper's mappedString() signal to the custom widget's
136 \c clicked() signal. When the user clicks a button, the custom
137 widget will emit a single \c clicked() signal whose argument is
138 the text of the button the user clicked.
139
140 This class was mostly useful before lambda functions could be used as
141 slots. The example above can be rewritten simpler without QSignalMapper
142 by connecting to a lambda function.
143
144 \snippet qsignalmapper/buttonwidget.cpp 3
145
146 \sa QObject, QButtonGroup, QActionGroup
147 */
148
149 /*!
150 Constructs a QSignalMapper with parent \a parent.
151 */
QSignalMapper(QObject * parent)152 QSignalMapper::QSignalMapper(QObject* parent)
153 : QObject(*new QSignalMapperPrivate, parent)
154 {
155 }
156
157 /*!
158 Destroys the QSignalMapper.
159 */
~QSignalMapper()160 QSignalMapper::~QSignalMapper()
161 {
162 }
163
164 /*!
165 Adds a mapping so that when map() is signalled from the given \a
166 sender, the signal mappedInt(\a id) is emitted.
167
168 There may be at most one integer ID for each sender.
169
170 \sa mapping()
171 */
setMapping(QObject * sender,int id)172 void QSignalMapper::setMapping(QObject *sender, int id)
173 {
174 Q_D(QSignalMapper);
175 d->intHash.insert(sender, id);
176 connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
177 }
178
179 /*!
180 Adds a mapping so that when map() is signalled from the \a sender,
181 the signal mappedString(\a text ) is emitted.
182
183 There may be at most one text for each sender.
184 */
setMapping(QObject * sender,const QString & text)185 void QSignalMapper::setMapping(QObject *sender, const QString &text)
186 {
187 Q_D(QSignalMapper);
188 d->stringHash.insert(sender, text);
189 connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
190 }
191
192 /*!
193 Adds a mapping so that when map() is signalled from the \a sender,
194 the signal mappedWidget(\a widget ) is emitted.
195
196 There may be at most one widget for each sender.
197 */
setMapping(QObject * sender,QWidget * widget)198 void QSignalMapper::setMapping(QObject *sender, QWidget *widget)
199 {
200 Q_D(QSignalMapper);
201 d->widgetHash.insert(sender, widget);
202 connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
203 }
204
205 /*!
206 Adds a mapping so that when map() is signalled from the \a sender,
207 the signal mappedObject(\a object ) is emitted.
208
209 There may be at most one object for each sender.
210 */
setMapping(QObject * sender,QObject * object)211 void QSignalMapper::setMapping(QObject *sender, QObject *object)
212 {
213 Q_D(QSignalMapper);
214 d->objectHash.insert(sender, object);
215 connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
216 }
217
218 /*!
219 Returns the sender QObject that is associated with the \a id.
220
221 \sa setMapping()
222 */
mapping(int id) const223 QObject *QSignalMapper::mapping(int id) const
224 {
225 Q_D(const QSignalMapper);
226 return d->intHash.key(id);
227 }
228
229 /*!
230 \overload mapping()
231 */
mapping(const QString & id) const232 QObject *QSignalMapper::mapping(const QString &id) const
233 {
234 Q_D(const QSignalMapper);
235 return d->stringHash.key(id);
236 }
237
238 /*!
239 \overload mapping()
240
241 Returns the sender QObject that is associated with the \a widget.
242 */
mapping(QWidget * widget) const243 QObject *QSignalMapper::mapping(QWidget *widget) const
244 {
245 Q_D(const QSignalMapper);
246 return d->widgetHash.key(widget);
247 }
248
249 /*!
250 \overload mapping()
251
252 Returns the sender QObject that is associated with the \a object.
253 */
mapping(QObject * object) const254 QObject *QSignalMapper::mapping(QObject *object) const
255 {
256 Q_D(const QSignalMapper);
257 return d->objectHash.key(object);
258 }
259
260 /*!
261 Removes all mappings for \a sender.
262
263 This is done automatically when mapped objects are destroyed.
264
265 \note This does not disconnect any signals. If \a sender is not destroyed
266 then this will need to be done explicitly if required.
267 */
removeMappings(QObject * sender)268 void QSignalMapper::removeMappings(QObject *sender)
269 {
270 Q_D(QSignalMapper);
271
272 d->intHash.remove(sender);
273 d->stringHash.remove(sender);
274 d->widgetHash.remove(sender);
275 d->objectHash.remove(sender);
276 }
277
278 /*!
279 This slot emits signals based on which object sends signals to it.
280 */
map()281 void QSignalMapper::map() { map(sender()); }
282
283 /*!
284 This slot emits signals based on the \a sender object.
285 */
map(QObject * sender)286 void QSignalMapper::map(QObject *sender)
287 {
288 d_func()->emitMappedValues(sender);
289 }
290
291 #if QT_DEPRECATED_SINCE(5, 15)
292 /*!
293 \fn void QSignalMapper::mapped(int i)
294 \obsolete
295 \overload
296
297 This signal is emitted when map() is signalled from an object that
298 has an integer mapping set. The object's mapped integer is passed
299 in \a i.
300
301 \sa setMapping()
302 */
303
304 /*!
305 \fn void QSignalMapper::mapped(const QString &text)
306 \obsolete
307 \overload
308
309 This signal is emitted when map() is signalled from an object that
310 has a string mapping set. The object's mapped string is passed in
311 \a text.
312
313 \sa setMapping()
314 */
315
316 /*!
317 \fn void QSignalMapper::mapped(QWidget *widget)
318 \obsolete
319 \overload
320
321 This signal is emitted when map() is signalled from an object that
322 has a widget mapping set. The object's mapped widget is passed in
323 \a widget.
324
325 \sa setMapping()
326 */
327
328 /*!
329 \fn void QSignalMapper::mapped(QObject *object)
330 \obsolete
331 \overload
332
333 This signal is emitted when map() is signalled from an object that
334 has an object mapping set. The object provided by the map is passed in
335 \a object.
336
337 \sa setMapping()
338 */
339 #endif
340
341 /*!
342 \fn void QSignalMapper::mappedInt(int i)
343 \since 5.15
344
345 This signal is emitted when map() is signalled from an object that
346 has an integer mapping set. The object's mapped integer is passed
347 in \a i.
348
349 \sa setMapping()
350 */
351
352 /*!
353 \fn void QSignalMapper::mappedString(const QString &text)
354 \since 5.15
355
356 This signal is emitted when map() is signalled from an object that
357 has a string mapping set. The object's mapped string is passed in
358 \a text.
359
360 \sa setMapping()
361 */
362
363 /*!
364 \fn void QSignalMapper::mappedWidget(QWidget *widget)
365 \since 5.15
366
367 This signal is emitted when map() is signalled from an object that
368 has a widget mapping set. The object's mapped widget is passed in
369 \a widget.
370
371 \sa setMapping()
372 */
373
374 /*!
375 \fn void QSignalMapper::mappedObject(QObject *object)
376 \since 5.15
377
378 This signal is emitted when map() is signalled from an object that
379 has an object mapping set. The object provided by the map is passed in
380 \a object.
381
382 \sa setMapping()
383 */
384
385 QT_END_NAMESPACE
386
387 #include "moc_qsignalmapper.cpp"
388