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 QtWidgets 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 "private/qbuttongroup_p.h"
41 
42 #include "private/qabstractbutton_p.h"
43 
44 QT_BEGIN_NAMESPACE
45 
46 // detect a checked button other than the current one
detectCheckedButton()47 void QButtonGroupPrivate::detectCheckedButton()
48 {
49     QAbstractButton *previous = checkedButton;
50     checkedButton = nullptr;
51     if (exclusive)
52         return;
53     for (int i = 0; i < buttonList.count(); i++) {
54         if (buttonList.at(i) != previous && buttonList.at(i)->isChecked()) {
55             checkedButton = buttonList.at(i);
56             return;
57         }
58     }
59 }
60 
61 /*!
62     \class QButtonGroup
63     \brief The QButtonGroup class provides a container to organize groups of
64     button widgets.
65 
66     \ingroup organizers
67     \ingroup geomanagement
68     \inmodule QtWidgets
69 
70     QButtonGroup provides an abstract container into which button widgets can
71     be placed. It does not provide a visual representation of this container
72     (see QGroupBox for a container widget), but instead manages the states of
73     each of the buttons in the group.
74 
75     An \l {QButtonGroup::exclusive} {exclusive} button group switches
76     off all checkable (toggle) buttons except the one that has been
77     clicked. By default, a button group is exclusive. The buttons in a
78     button group are usually checkable \l{QPushButton}s, \l{QCheckBox}es
79     (normally for non-exclusive button groups), or \l{QRadioButton}s.
80     If you create an exclusive button group, you should ensure that
81     one of the buttons in the group is initially checked; otherwise,
82     the group will initially be in a state where no buttons are
83     checked.
84 
85     A button can be added to the group with addButton() and removed
86     with removeButton(). If the group is exclusive, the
87     currently checked button is available with checkedButton(). If a
88     button is clicked, the buttonClicked() signal is emitted; for a
89     checkable button in an exclusive group this means that the button
90     has been checked. The list of buttons in the group is returned by
91     buttons().
92 
93     In addition, QButtonGroup can map between integers and buttons.
94     You can assign an integer id to a button with setId(), and
95     retrieve it with id(). The id of the currently checked button is
96     available with checkedId(), and there is an overloaded signal
97     buttonClicked() which emits the id of the button. The id \c {-1}
98     is reserved by QButtonGroup to mean "no such button". The purpose
99     of the mapping mechanism is to simplify the representation of enum
100     values in a user interface.
101 
102     \sa QGroupBox, QPushButton, QCheckBox, QRadioButton
103 */
104 
105 /*!
106     Constructs a new, empty button group with the given \a parent.
107 
108     \sa addButton(), setExclusive()
109 */
QButtonGroup(QObject * parent)110 QButtonGroup::QButtonGroup(QObject *parent)
111     : QObject(*new QButtonGroupPrivate, parent)
112 {
113 }
114 
115 /*!
116     Destroys the button group.
117 */
~QButtonGroup()118 QButtonGroup::~QButtonGroup()
119 {
120     Q_D(QButtonGroup);
121     for (int i = 0; i < d->buttonList.count(); ++i)
122         d->buttonList.at(i)->d_func()->group = nullptr;
123 }
124 
125 /*!
126     \property QButtonGroup::exclusive
127     \brief whether the button group is exclusive
128 
129     If this property is \c true, then only one button in the group can be checked
130     at any given time. The user can click on any button to check it, and that
131     button will replace the existing one as the checked button in the group.
132 
133     In an exclusive group, the user cannot uncheck the currently checked button
134     by clicking on it; instead, another button in the group must be clicked
135     to set the new checked button for that group.
136 
137     By default, this property is \c true.
138 */
exclusive() const139 bool QButtonGroup::exclusive() const
140 {
141     Q_D(const QButtonGroup);
142     return d->exclusive;
143 }
144 
setExclusive(bool exclusive)145 void QButtonGroup::setExclusive(bool exclusive)
146 {
147     Q_D(QButtonGroup);
148     d->exclusive = exclusive;
149 }
150 
151 
152 
153 /*!
154     \fn void QButtonGroup::buttonClicked(QAbstractButton *button)
155 
156     This signal is emitted when the given \a button is clicked. A
157     button is clicked when it is first pressed and then released, when
158     its shortcut key is typed, or when QAbstractButton::click()
159     or QAbstractButton::animateClick() is programmatically called.
160 
161 
162     \sa checkedButton(), QAbstractButton::clicked()
163 */
164 
165 /*!
166     \fn void QButtonGroup::buttonClicked(int id)
167     \obsolete
168 
169     This signal is emitted when a button with the given \a id is
170     clicked.
171 
172     \sa checkedButton(), QAbstractButton::clicked()
173 */
174 
175 /*!
176     \fn void QButtonGroup::idClicked(int id)
177     \since 5.15
178 
179     This signal is emitted when a button with the given \a id is
180     clicked.
181 
182     \sa checkedButton(), QAbstractButton::clicked()
183 */
184 
185 /*!
186     \fn void QButtonGroup::buttonPressed(QAbstractButton *button)
187     \since 4.2
188 
189     This signal is emitted when the given \a button is pressed down.
190 
191     \sa QAbstractButton::pressed()
192 */
193 
194 /*!
195     \fn void QButtonGroup::buttonPressed(int id)
196     \since 4.2
197     \obsolete
198 
199     This signal is emitted when a button with the given \a id is
200     pressed down.
201 
202     \sa QAbstractButton::pressed()
203 */
204 
205 /*!
206     \fn void QButtonGroup::idPressed(int id)
207     \since 5.15
208 
209     This signal is emitted when a button with the given \a id is
210     pressed down.
211 
212     \sa QAbstractButton::pressed()
213 */
214 
215 /*!
216     \fn void QButtonGroup::buttonReleased(QAbstractButton *button)
217     \since 4.2
218 
219     This signal is emitted when the given \a button is released.
220 
221     \sa QAbstractButton::released()
222 */
223 
224 /*!
225     \fn void QButtonGroup::buttonReleased(int id)
226     \since 4.2
227     \obsolete
228 
229     This signal is emitted when a button with the given \a id is
230     released.
231 
232     \sa QAbstractButton::released()
233 */
234 
235 /*!
236     \fn void QButtonGroup::idReleased(int id)
237     \since 5.15
238 
239     This signal is emitted when a button with the given \a id is
240     released.
241 
242     \sa QAbstractButton::released()
243 */
244 
245 /*!
246     \fn void QButtonGroup::buttonToggled(QAbstractButton *button, bool checked)
247     \since 5.2
248 
249     This signal is emitted when the given \a button is toggled.
250     \a checked is true if the button is checked, or false if the button is unchecked.
251 
252     \sa QAbstractButton::toggled()
253 */
254 
255 /*!
256     \fn void QButtonGroup::buttonToggled(int id, bool checked)
257     \since 5.2
258     \obsolete
259 
260     This signal is emitted when a button with the given \a id is toggled.
261     \a checked is true if the button is checked, or false if the button is unchecked.
262 
263     \sa QAbstractButton::toggled()
264 */
265 
266 /*!
267     \fn void QButtonGroup::idToggled(int id, bool checked)
268     \since 5.15
269 
270     This signal is emitted when a button with the given \a id is toggled.
271     \a checked is true if the button is checked, or false if the button is unchecked.
272 
273     \sa QAbstractButton::toggled()
274 */
275 
276 /*!
277     Adds the given \a button to the button group. If \a id is -1,
278     an id will be assigned to the button.
279     Automatically assigned ids are guaranteed to be negative,
280     starting with -2. If you are assigning your own ids, use
281     positive values to avoid conflicts.
282 
283     \sa removeButton(), buttons()
284 */
addButton(QAbstractButton * button,int id)285 void QButtonGroup::addButton(QAbstractButton *button, int id)
286 {
287     Q_D(QButtonGroup);
288     if (QButtonGroup *previous = button->d_func()->group)
289         previous->removeButton(button);
290     button->d_func()->group = this;
291     d->buttonList.append(button);
292     if (id == -1) {
293         const QHash<QAbstractButton*, int>::const_iterator it
294                 = std::min_element(d->mapping.cbegin(), d->mapping.cend());
295         if (it == d->mapping.cend())
296             d->mapping[button] = -2;
297         else
298             d->mapping[button] = *it - 1;
299     } else {
300         d->mapping[button] = id;
301     }
302 
303     if (d->exclusive && button->isChecked())
304         button->d_func()->notifyChecked();
305 }
306 
307 /*!
308     Removes the given \a button from the button group.
309 
310     \sa addButton(), buttons()
311 */
removeButton(QAbstractButton * button)312 void QButtonGroup::removeButton(QAbstractButton *button)
313 {
314     Q_D(QButtonGroup);
315     if (d->checkedButton == button) {
316         d->detectCheckedButton();
317     }
318     if (button->d_func()->group == this) {
319         button->d_func()->group = nullptr;
320         d->buttonList.removeAll(button);
321         d->mapping.remove(button);
322     }
323 }
324 
325 /*!
326     Returns the button group's list of buttons. This may be empty.
327 
328     \sa addButton(), removeButton()
329 */
buttons() const330 QList<QAbstractButton*> QButtonGroup::buttons() const
331 {
332     Q_D(const QButtonGroup);
333     return d->buttonList;
334 }
335 
336 /*!
337     Returns the button group's checked button, or \nullptr if no
338     buttons are checked.
339 
340     \sa buttonClicked()
341 */
checkedButton() const342 QAbstractButton *QButtonGroup::checkedButton() const
343 {
344     Q_D(const QButtonGroup);
345     return d->checkedButton;
346 }
347 
348 /*!
349     \since 4.1
350 
351     Returns the button with the specified \a id, or \nullptr if no
352     such button exists.
353 */
button(int id) const354 QAbstractButton *QButtonGroup::button(int id) const
355 {
356     Q_D(const QButtonGroup);
357     return d->mapping.key(id);
358 }
359 
360 /*!
361     \since 4.1
362 
363     Sets the \a id for the specified \a button. Note that \a id cannot
364     be -1.
365 
366     \sa id()
367 */
setId(QAbstractButton * button,int id)368 void QButtonGroup::setId(QAbstractButton *button, int id)
369 {
370     Q_D(QButtonGroup);
371     if (button && id != -1)
372         d->mapping[button] = id;
373 }
374 
375 /*!
376     \since 4.1
377 
378     Returns the id for the specified \a button, or -1 if no such button
379     exists.
380 
381 
382     \sa setId()
383 */
id(QAbstractButton * button) const384 int QButtonGroup::id(QAbstractButton *button) const
385 {
386     Q_D(const QButtonGroup);
387     return d->mapping.value(button, -1);
388 }
389 
390 /*!
391     \since 4.1
392 
393     Returns the id of the checkedButton(), or -1 if no button is checked.
394 
395     \sa setId()
396 */
checkedId() const397 int QButtonGroup::checkedId() const
398 {
399     Q_D(const QButtonGroup);
400     return d->mapping.value(d->checkedButton, -1);
401 }
402 
403 QT_END_NAMESPACE
404 
405 #include "moc_qbuttongroup.cpp"
406