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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/corelib/kernel/qsignalmapper.cpp