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