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 "qactiongroup.h"
41
42#ifndef QT_NO_ACTION
43
44#include "qaction_p.h"
45#include "qevent.h"
46#include "qlist.h"
47
48QT_BEGIN_NAMESPACE
49
50class QActionGroupPrivate : public QObjectPrivate
51{
52 Q_DECLARE_PUBLIC(QActionGroup)
53public:
54 QActionGroupPrivate() : enabled(1),
55 visible(1),
56 exclusionPolicy(QActionGroup::ExclusionPolicy::Exclusive)
57 {
58 }
59 QList<QAction *> actions;
60 QPointer<QAction> current;
61 uint enabled : 1;
62 uint visible : 1;
63 QActionGroup::ExclusionPolicy exclusionPolicy;
64
65private:
66 void _q_actionTriggered(); //private slot
67 void _q_actionChanged(); //private slot
68 void _q_actionHovered(); //private slot
69};
70
71void QActionGroupPrivate::_q_actionChanged()
72{
73 Q_Q(QActionGroup);
74 QAction *action = qobject_cast<QAction*>(object: q->sender());
75 Q_ASSERT_X(action != nullptr, "QActionGroup::_q_actionChanged", "internal error");
76 if (exclusionPolicy != QActionGroup::ExclusionPolicy::None) {
77 if (action->isChecked()) {
78 if (action != current) {
79 if(current)
80 current->setChecked(false);
81 current = action;
82 }
83 } else if (action == current) {
84 current = nullptr;
85 }
86 }
87}
88
89void QActionGroupPrivate::_q_actionTriggered()
90{
91 Q_Q(QActionGroup);
92 QAction *action = qobject_cast<QAction*>(object: q->sender());
93 Q_ASSERT_X(action != nullptr, "QActionGroup::_q_actionTriggered", "internal error");
94 emit q->triggered(action);
95}
96
97void QActionGroupPrivate::_q_actionHovered()
98{
99 Q_Q(QActionGroup);
100 QAction *action = qobject_cast<QAction*>(object: q->sender());
101 Q_ASSERT_X(action != nullptr, "QActionGroup::_q_actionHovered", "internal error");
102 emit q->hovered(action);
103}
104
105/*!
106 \class QActionGroup
107 \brief The QActionGroup class groups actions together.
108
109 \ingroup mainwindow-classes
110 \inmodule QtWidgets
111
112 In some situations it is useful to group QAction objects together.
113 For example, if you have a \uicontrol{Left Align} action, a \uicontrol{Right
114 Align} action, a \uicontrol{Justify} action, and a \uicontrol{Center} action,
115 only one of these actions should be active at any one time. One
116 simple way of achieving this is to group the actions together in
117 an action group.
118
119 Here's a example (from the \l{mainwindows/menus}{Menus} example):
120
121 \snippet mainwindows/menus/mainwindow.cpp 6
122
123 Here we create a new action group. Since the action group is
124 exclusive by default, only one of the actions in the group is
125 checked at any one time.
126
127 \image qactiongroup-align.png Alignment options in a QMenu
128
129 A QActionGroup emits an triggered() signal when one of its
130 actions is chosen. Each action in an action group emits its
131 triggered() signal as usual.
132
133 As stated above, an action group is exclusive by default; it
134 ensures that at most only one checkable action is active at any one time.
135 If you want to group checkable actions without making them
136 exclusive, you can turn off exclusiveness by calling
137 setExclusive(false).
138
139 By default the active action of an exclusive group cannot be unchecked.
140 In some cases it may be useful to allow unchecking all the actions,
141 you can allow this by calling
142 setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional).
143
144 Actions can be added to an action group using addAction(), but it
145 is usually more convenient to specify a group when creating
146 actions; this ensures that actions are automatically created with
147 a parent. Actions can be visually separated from each other by
148 adding a separator action to the group; create an action and use
149 QAction's \l {QAction::}{setSeparator()} function to make it
150 considered a separator. Action groups are added to widgets with
151 the QWidget::addActions() function.
152
153 \sa QAction
154*/
155
156/*!
157 \enum QActionGroup::ExclusionPolicy
158
159 This enum specifies the different policies that can be used to
160 control how the group performs exclusive checking on checkable actions.
161
162 \value None
163 The actions in the group can be checked independently of each other.
164
165 \value Exclusive
166 Exactly one action can be checked at any one time.
167 This is the default policy.
168
169 \value ExclusiveOptional
170 At most one action can be checked at any one time. The actions
171 can also be all unchecked.
172
173 \sa exclusionPolicy
174 \since 5.14
175*/
176
177/*!
178 Constructs an action group for the \a parent object.
179
180 The action group is exclusive by default. Call setExclusive(false)
181 to make the action group non-exclusive. To make the group exclusive
182 but allow unchecking the active action call instead
183 setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional)
184*/
185QActionGroup::QActionGroup(QObject* parent) : QObject(*new QActionGroupPrivate, parent)
186{
187}
188
189/*!
190 Destroys the action group.
191*/
192QActionGroup::~QActionGroup()
193{
194}
195
196/*!
197 \fn QAction *QActionGroup::addAction(QAction *action)
198
199 Adds the \a action to this group, and returns it.
200
201 Normally an action is added to a group by creating it with the
202 group as its parent, so this function is not usually used.
203
204 \sa QAction::setActionGroup()
205*/
206QAction *QActionGroup::addAction(QAction* a)
207{
208 Q_D(QActionGroup);
209 if(!d->actions.contains(t: a)) {
210 d->actions.append(t: a);
211 QObject::connect(sender: a, SIGNAL(triggered()), receiver: this, SLOT(_q_actionTriggered()));
212 QObject::connect(sender: a, SIGNAL(changed()), receiver: this, SLOT(_q_actionChanged()));
213 QObject::connect(sender: a, SIGNAL(hovered()), receiver: this, SLOT(_q_actionHovered()));
214 }
215 if(!a->d_func()->forceDisabled) {
216 a->setEnabled(d->enabled);
217 a->d_func()->forceDisabled = false;
218 }
219 if(!a->d_func()->forceInvisible) {
220 a->setVisible(d->visible);
221 a->d_func()->forceInvisible = false;
222 }
223 if(a->isChecked())
224 d->current = a;
225 QActionGroup *oldGroup = a->d_func()->group;
226 if(oldGroup != this) {
227 if (oldGroup)
228 oldGroup->removeAction(a);
229 a->d_func()->group = this;
230 a->d_func()->sendDataChanged();
231 }
232 return a;
233}
234
235/*!
236 Creates and returns an action with \a text. The newly created
237 action is a child of this action group.
238
239 Normally an action is added to a group by creating it with the
240 group as parent, so this function is not usually used.
241
242 \sa QAction::setActionGroup()
243*/
244QAction *QActionGroup::addAction(const QString &text)
245{
246 return new QAction(text, this);
247}
248
249/*!
250 Creates and returns an action with \a text and an \a icon. The
251 newly created action is a child of this action group.
252
253 Normally an action is added to a group by creating it with the
254 group as its parent, so this function is not usually used.
255
256 \sa QAction::setActionGroup()
257*/
258QAction *QActionGroup::addAction(const QIcon &icon, const QString &text)
259{
260 return new QAction(icon, text, this);
261}
262
263/*!
264 Removes the \a action from this group. The action will have no
265 parent as a result.
266
267 \sa QAction::setActionGroup()
268*/
269void QActionGroup::removeAction(QAction *action)
270{
271 Q_D(QActionGroup);
272 if (d->actions.removeAll(t: action)) {
273 if (action == d->current)
274 d->current = nullptr;
275 QObject::disconnect(sender: action, SIGNAL(triggered()), receiver: this, SLOT(_q_actionTriggered()));
276 QObject::disconnect(sender: action, SIGNAL(changed()), receiver: this, SLOT(_q_actionChanged()));
277 QObject::disconnect(sender: action, SIGNAL(hovered()), receiver: this, SLOT(_q_actionHovered()));
278 action->d_func()->group = nullptr;
279 }
280}
281
282/*!
283 Returns the list of this groups's actions. This may be empty.
284*/
285QList<QAction*> QActionGroup::actions() const
286{
287 Q_D(const QActionGroup);
288 return d->actions;
289}
290
291/*!
292 \brief Enable or disable the group exclusion checking
293
294 This is a convenience method that calls
295 setExclusionPolicy(ExclusionPolicy::Exclusive) when \a b is true,
296 else setExclusionPolicy(QActionGroup::ExclusionPolicy::None).
297
298 \sa QActionGroup::exclusionPolicy
299*/
300void QActionGroup::setExclusive(bool b)
301{
302 setExclusionPolicy(b ? QActionGroup::ExclusionPolicy::Exclusive
303 : QActionGroup::ExclusionPolicy::None);
304}
305
306/*!
307 \brief Returns true if the group is exclusive
308
309 The group is exclusive if the ExclusionPolicy is either Exclusive
310 or ExclusionOptional.
311
312*/
313bool QActionGroup::isExclusive() const
314{
315 return exclusionPolicy() != QActionGroup::ExclusionPolicy::None;
316}
317
318/*!
319 \property QActionGroup::exclusionPolicy
320 \brief This property holds the group exclusive checking policy
321
322 If exclusionPolicy is set to Exclusive, only one checkable
323 action in the action group can ever be active at any time. If the user
324 chooses another checkable action in the group, the one they chose becomes
325 active and the one that was active becomes inactive. If exclusionPolicy is
326 set to ExclusionOptional the group is exclusive but the active checkable
327 action in the group can be unchecked leaving the group with no actions
328 checked.
329
330 \sa QAction::checkable
331 \since 5.14
332*/
333void QActionGroup::setExclusionPolicy(QActionGroup::ExclusionPolicy policy)
334{
335 Q_D(QActionGroup);
336 d->exclusionPolicy = policy;
337}
338
339QActionGroup::ExclusionPolicy QActionGroup::exclusionPolicy() const
340{
341 Q_D(const QActionGroup);
342 return d->exclusionPolicy;
343}
344
345/*!
346 \fn void QActionGroup::setDisabled(bool b)
347
348 This is a convenience function for the \l enabled property, that
349 is useful for signals--slots connections. If \a b is true the
350 action group is disabled; otherwise it is enabled.
351*/
352
353/*!
354 \property QActionGroup::enabled
355 \brief whether the action group is enabled
356
357 Each action in the group will be enabled or disabled unless it
358 has been explicitly disabled.
359
360 \sa QAction::setEnabled()
361*/
362void QActionGroup::setEnabled(bool b)
363{
364 Q_D(QActionGroup);
365 d->enabled = b;
366 for (auto action : qAsConst(t&: d->actions)) {
367 if (!action->d_func()->forceDisabled) {
368 action->setEnabled(b);
369 action->d_func()->forceDisabled = false;
370 }
371 }
372}
373
374bool QActionGroup::isEnabled() const
375{
376 Q_D(const QActionGroup);
377 return d->enabled;
378}
379
380/*!
381 Returns the currently checked action in the group, or \nullptr if
382 none are checked.
383*/
384QAction *QActionGroup::checkedAction() const
385{
386 Q_D(const QActionGroup);
387 return d->current;
388}
389
390/*!
391 \property QActionGroup::visible
392 \brief whether the action group is visible
393
394 Each action in the action group will match the visible state of
395 this group unless it has been explicitly hidden.
396
397 \sa QAction::setEnabled()
398*/
399void QActionGroup::setVisible(bool b)
400{
401 Q_D(QActionGroup);
402 d->visible = b;
403 for (auto action : qAsConst(t&: d->actions)) {
404 if (!action->d_func()->forceInvisible) {
405 action->setVisible(b);
406 action->d_func()->forceInvisible = false;
407 }
408 }
409}
410
411bool QActionGroup::isVisible() const
412{
413 Q_D(const QActionGroup);
414 return d->visible;
415}
416
417/*!
418 \fn void QActionGroup::triggered(QAction *action)
419
420 This signal is emitted when the given \a action in the action
421 group is activated by the user; for example, when the user clicks
422 a menu option, toolbar button, or presses an action's shortcut key
423 combination.
424
425 Connect to this signal for command actions.
426
427 \sa QAction::activate()
428*/
429
430/*!
431 \fn void QActionGroup::hovered(QAction *action)
432
433 This signal is emitted when the given \a action in the action
434 group is highlighted by the user; for example, when the user
435 pauses with the cursor over a menu option, toolbar button, or
436 presses an action's shortcut key combination.
437
438 \sa QAction::activate()
439*/
440
441QT_END_NAMESPACE
442
443#include "moc_qactiongroup.cpp"
444
445#endif // QT_NO_ACTION
446

source code of qtbase/src/widgets/kernel/qactiongroup.cpp