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
46QT_BEGIN_NAMESPACE
47
48class QSignalMapperPrivate : public QObjectPrivate
49{
50 Q_DECLARE_PUBLIC(QSignalMapper)
51public:
52 void _q_senderDestroyed()
53 {
54 Q_Q(QSignalMapper);
55 q->removeMappings(q->sender());
56 }
57
58 template <class Signal, class Container>
59 void emitMappedValue(QObject *sender, Signal signal, const Container &mappedValues)
60 {
61 Q_Q(QSignalMapper);
62
63 auto it = mappedValues.find(sender);
64 if (it != mappedValues.end())
65 Q_EMIT(q->*signal)(*it);
66 }
67
68 void emitMappedValues(QObject *sender)
69 {
70 emitMappedValue(sender, &QSignalMapper::mappedInt, intHash);
71 emitMappedValue(sender, &QSignalMapper::mappedString, stringHash);
72 emitMappedValue(sender, &QSignalMapper::mappedObject, objectHash);
73 }
74
75 QHash<QObject *, int> intHash;
76 QHash<QObject *, QString> stringHash;
77 QHash<QObject *, QObject *> objectHash;
78};
79
80/*!
81 \class QSignalMapper
82 \inmodule QtCore
83 \brief The QSignalMapper class bundles signals from identifiable senders.
84
85 \ingroup objectmodel
86
87
88 This class collects a set of parameterless signals, and re-emits
89 them with integer, string or widget parameters corresponding to
90 the object that sent the signal. Note that in most cases you can
91 use lambdas for passing custom parameters to slots. This is less
92 costly and will simplify the code.
93
94 The class supports the mapping of particular strings, integers,
95 objects and widgets with particular objects using setMapping().
96 The objects' signals can then be connected to the map() slot which
97 will emit a signal (it could be mappedInt(), mappedString()
98 and mappedObject()) with a value associated with
99 the original signalling object. Mappings can be removed later using
100 removeMappings().
101
102 Example: Suppose we want to create a custom widget that contains
103 a group of buttons (like a tool palette). One approach is to
104 connect each button's \c clicked() signal to its own custom slot;
105 but in this example we want to connect all the buttons to a
106 single slot and parameterize the slot by the button that was
107 clicked.
108
109 Here's the definition of a simple custom widget that has a single
110 signal, \c clicked(), which is emitted with the text of the button
111 that was clicked:
112
113 \snippet qsignalmapper/buttonwidget.h 0
114 \snippet qsignalmapper/buttonwidget.h 1
115
116 The only function that we need to implement is the constructor:
117
118 \snippet qsignalmapper/buttonwidget.cpp 0
119 \snippet qsignalmapper/buttonwidget.cpp 1
120 \snippet qsignalmapper/buttonwidget.cpp 2
121
122 A list of texts is passed to the constructor. A signal mapper is
123 constructed and for each text in the list a QPushButton is
124 created. We connect each button's \c clicked() signal to the
125 signal mapper's map() slot, and create a mapping in the signal
126 mapper from each button to the button's text. Finally we connect
127 the signal mapper's mappedString() signal to the custom widget's
128 \c clicked() signal. When the user clicks a button, the custom
129 widget will emit a single \c clicked() signal whose argument is
130 the text of the button the user clicked.
131
132 This class was mostly useful before lambda functions could be used as
133 slots. The example above can be rewritten simpler without QSignalMapper
134 by connecting to a lambda function.
135
136 \snippet qsignalmapper/buttonwidget.cpp 3
137
138 \sa QObject, QButtonGroup, QActionGroup
139*/
140
141/*!
142 Constructs a QSignalMapper with parent \a parent.
143*/
144QSignalMapper::QSignalMapper(QObject* parent)
145 : QObject(*new QSignalMapperPrivate, parent)
146{
147}
148
149/*!
150 Destroys the QSignalMapper.
151*/
152QSignalMapper::~QSignalMapper()
153{
154}
155
156/*!
157 Adds a mapping so that when map() is signalled from the given \a
158 sender, the signal mappedInt(\a id) is emitted.
159
160 There may be at most one integer ID for each sender.
161
162 \sa mapping()
163*/
164void QSignalMapper::setMapping(QObject *sender, int id)
165{
166 Q_D(QSignalMapper);
167 d->intHash.insert(sender, id);
168 connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
169}
170
171/*!
172 Adds a mapping so that when map() is signalled from the \a sender,
173 the signal mappedString(\a text ) is emitted.
174
175 There may be at most one text for each sender.
176*/
177void QSignalMapper::setMapping(QObject *sender, const QString &text)
178{
179 Q_D(QSignalMapper);
180 d->stringHash.insert(sender, text);
181 connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
182}
183
184/*!
185 Adds a mapping so that when map() is signalled from the \a sender,
186 the signal mappedObject(\a object ) is emitted.
187
188 There may be at most one object for each sender.
189*/
190void QSignalMapper::setMapping(QObject *sender, QObject *object)
191{
192 Q_D(QSignalMapper);
193 d->objectHash.insert(sender, object);
194 connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
195}
196
197/*!
198 Returns the sender QObject that is associated with the \a id.
199
200 \sa setMapping()
201*/
202QObject *QSignalMapper::mapping(int id) const
203{
204 Q_D(const QSignalMapper);
205 return d->intHash.key(id);
206}
207
208/*!
209 \overload mapping()
210*/
211QObject *QSignalMapper::mapping(const QString &id) const
212{
213 Q_D(const QSignalMapper);
214 return d->stringHash.key(id);
215}
216
217/*!
218 \overload mapping()
219
220 Returns the sender QObject that is associated with the \a object.
221*/
222QObject *QSignalMapper::mapping(QObject *object) const
223{
224 Q_D(const QSignalMapper);
225 return d->objectHash.key(object);
226}
227
228/*!
229 Removes all mappings for \a sender.
230
231 This is done automatically when mapped objects are destroyed.
232
233 \note This does not disconnect any signals. If \a sender is not destroyed
234 then this will need to be done explicitly if required.
235*/
236void QSignalMapper::removeMappings(QObject *sender)
237{
238 Q_D(QSignalMapper);
239
240 d->intHash.remove(sender);
241 d->stringHash.remove(sender);
242 d->objectHash.remove(sender);
243}
244
245/*!
246 This slot emits signals based on which object sends signals to it.
247*/
248void QSignalMapper::map() { map(sender()); }
249
250/*!
251 This slot emits signals based on the \a sender object.
252*/
253void QSignalMapper::map(QObject *sender)
254{
255 d_func()->emitMappedValues(sender);
256}
257
258/*!
259 \fn void QSignalMapper::mappedInt(int i)
260 \since 5.15
261
262 This signal is emitted when map() is signalled from an object that
263 has an integer mapping set. The object's mapped integer is passed
264 in \a i.
265
266 \sa setMapping()
267*/
268
269/*!
270 \fn void QSignalMapper::mappedString(const QString &text)
271 \since 5.15
272
273 This signal is emitted when map() is signalled from an object that
274 has a string mapping set. The object's mapped string is passed in
275 \a text.
276
277 \sa setMapping()
278*/
279
280/*!
281 \fn void QSignalMapper::mappedObject(QObject *object)
282 \since 5.15
283
284 This signal is emitted when map() is signalled from an object that
285 has an object mapping set. The object provided by the map is passed in
286 \a object.
287
288 \sa setMapping()
289*/
290
291QT_END_NAMESPACE
292
293#include "moc_qsignalmapper.cpp"
294