1// Copyright (C) 2019 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 "qactiongroup.h"
5
6#include "qaction.h"
7#include "qaction_p.h"
8#include "qactiongroup_p.h"
9#include "qevent.h"
10#include "qlist.h"
11
12QT_BEGIN_NAMESPACE
13
14QActionGroupPrivate::QActionGroupPrivate() :
15 enabled(1), visible(1)
16{
17}
18
19QActionGroupPrivate::~QActionGroupPrivate() = default;
20
21void QActionGroup::_q_actionChanged()
22{
23 Q_D(QActionGroup);
24 auto action = qobject_cast<QAction*>(object: sender());
25 Q_ASSERT_X(action != nullptr, "QActionGroup::_q_actionChanged", "internal error");
26 if (d->exclusionPolicy != QActionGroup::ExclusionPolicy::None) {
27 if (action->isChecked()) {
28 if (action != d->current) {
29 if (!d->current.isNull())
30 d->current->setChecked(false);
31 d->current = action;
32 }
33 } else if (action == d->current) {
34 d->current = nullptr;
35 }
36 }
37}
38
39void QActionGroup::_q_actionTriggered()
40{
41 auto action = qobject_cast<QAction*>(object: sender());
42 Q_ASSERT_X(action != nullptr, "QActionGroup::_q_actionTriggered", "internal error");
43 emit triggered(action);
44}
45
46void QActionGroup::_q_actionHovered()
47{
48 auto action = qobject_cast<QAction*>(object: sender());
49 Q_ASSERT_X(action != nullptr, "QActionGroup::_q_actionHovered", "internal error");
50 emit hovered(action);
51}
52
53/*!
54 \class QActionGroup
55 \brief The QActionGroup class groups actions together.
56 \since 6.0
57
58 \inmodule QtGui
59
60 QActionGroup is a base class for classes grouping
61 classes inhheriting QAction objects together.
62
63 In some situations it is useful to group QAction objects together.
64 For example, if you have a \uicontrol{Left Align} action, a \uicontrol{Right
65 Align} action, a \uicontrol{Justify} action, and a \uicontrol{Center} action,
66 only one of these actions should be active at any one time. One
67 simple way of achieving this is to group the actions together in
68 an action group, inheriting QActionGroup.
69
70 \sa QAction
71*/
72
73/*!
74 \enum QActionGroup::ExclusionPolicy
75
76 This enum specifies the different policies that can be used to
77 control how the group performs exclusive checking on checkable actions.
78
79 \value None
80 The actions in the group can be checked independently of each other.
81
82 \value Exclusive
83 Exactly one action can be checked at any one time.
84 This is the default policy.
85
86 \value ExclusiveOptional
87 At most one action can be checked at any one time. The actions
88 can also be all unchecked.
89
90 \sa exclusionPolicy
91*/
92
93/*!
94 Constructs an action group for the \a parent object.
95
96 The action group is exclusive by default. Call setExclusive(false)
97 to make the action group non-exclusive. To make the group exclusive
98 but allow unchecking the active action call instead
99 setExclusionPolicy(QActionGroup::ExclusionPolicy::ExclusiveOptional)
100*/
101QActionGroup::QActionGroup(QObject* parent) :
102 QActionGroup(*new QActionGroupPrivate, parent)
103{
104}
105
106QActionGroup::QActionGroup(QActionGroupPrivate &dd, QObject *parent) :
107 QObject(dd, parent)
108{
109}
110
111/*!
112 Destroys the action group.
113*/
114QActionGroup::~QActionGroup() = default;
115
116/*!
117 \fn QAction *QActionGroup::addAction(QAction *action)
118
119 Adds the \a action to this group, and returns it.
120
121 Normally an action is added to a group by creating it with the
122 group as its parent, so this function is not usually used.
123
124 \sa QAction::setActionGroup()
125*/
126QAction *QActionGroup::addAction(QAction* a)
127{
128 Q_D(QActionGroup);
129 if (!d->actions.contains(t: a)) {
130 d->actions.append(t: a);
131 QObject::connect(sender: a, signal: &QAction::triggered, context: this, slot: &QActionGroup::_q_actionTriggered);
132 QObject::connect(sender: a, signal: &QAction::changed, context: this, slot: &QActionGroup::_q_actionChanged);
133 QObject::connect(sender: a, signal: &QAction::hovered, context: this, slot: &QActionGroup::_q_actionHovered);
134 }
135 a->d_func()->setEnabled(enable: d->enabled, byGroup: true);
136 if (!a->d_func()->forceInvisible)
137 a->d_func()->setVisible(d->visible);
138 if (a->isChecked())
139 d->current = a;
140 QActionGroup *oldGroup = a->d_func()->group;
141 if (oldGroup != this) {
142 if (oldGroup)
143 oldGroup->removeAction(a);
144 a->d_func()->group = this;
145 a->d_func()->sendDataChanged();
146 }
147 return a;
148}
149
150/*!
151 Creates and returns an action with \a text. The newly created
152 action is a child of this action group.
153
154 Normally an action is added to a group by creating it with the
155 group as parent, so this function is not usually used.
156
157 \sa QAction::setActionGroup()
158*/
159QAction *QActionGroup::addAction(const QString &text)
160{
161 return new QAction(text, this);
162}
163
164/*!
165 Creates and returns an action with \a text and an \a icon. The
166 newly created action is a child of this action group.
167
168 Normally an action is added to a group by creating it with the
169 group as its parent, so this function is not usually used.
170
171 \sa QAction::setActionGroup()
172*/
173QAction *QActionGroup::addAction(const QIcon &icon, const QString &text)
174{
175 return new QAction(icon, text, this);
176}
177
178/*!
179 Removes the \a action from this group. The action will have no
180 parent as a result.
181
182 \sa QAction::setActionGroup()
183*/
184void QActionGroup::removeAction(QAction *action)
185{
186 Q_D(QActionGroup);
187 if (d->actions.removeAll(t: action)) {
188 if (action == d->current)
189 d->current = nullptr;
190 QObject::disconnect(sender: action, signal: &QAction::triggered, receiver: this, slot: &QActionGroup::_q_actionTriggered);
191 QObject::disconnect(sender: action, signal: &QAction::changed, receiver: this, slot: &QActionGroup::_q_actionChanged);
192 QObject::disconnect(sender: action, signal: &QAction::hovered, receiver: this, slot: &QActionGroup::_q_actionHovered);
193 action->d_func()->group = nullptr;
194 }
195}
196
197/*!
198 Returns the list of this groups's actions. This may be empty.
199*/
200QList<QAction*> QActionGroup::actions() const
201{
202 Q_D(const QActionGroup);
203 return d->actions;
204}
205
206/*!
207 \brief Enable or disable the group exclusion checking
208
209 This is a convenience method that calls
210 setExclusionPolicy(ExclusionPolicy::Exclusive) when \a b is true,
211 else setExclusionPolicy(QActionGroup::ExclusionPolicy::None).
212
213 \sa QActionGroup::exclusionPolicy
214*/
215void QActionGroup::setExclusive(bool b)
216{
217 setExclusionPolicy(b ? QActionGroup::ExclusionPolicy::Exclusive
218 : QActionGroup::ExclusionPolicy::None);
219}
220
221/*!
222 \brief Returns true if the group is exclusive
223
224 The group is exclusive if the ExclusionPolicy is either Exclusive
225 or ExclusionOptional.
226
227*/
228bool QActionGroup::isExclusive() const
229{
230 return exclusionPolicy() != QActionGroup::ExclusionPolicy::None;
231}
232
233/*!
234 \property QActionGroup::exclusionPolicy
235 \brief This property holds the group exclusive checking policy
236
237 If exclusionPolicy is set to Exclusive, only one checkable
238 action in the action group can ever be active at any time. If the user
239 chooses another checkable action in the group, the one they chose becomes
240 active and the one that was active becomes inactive. If exclusionPolicy is
241 set to ExclusionOptional the group is exclusive but the active checkable
242 action in the group can be unchecked leaving the group with no actions
243 checked.
244
245 \sa QAction::checkable
246*/
247void QActionGroup::setExclusionPolicy(QActionGroup::ExclusionPolicy policy)
248{
249 Q_D(QActionGroup);
250 d->exclusionPolicy = policy;
251}
252
253QActionGroup::ExclusionPolicy QActionGroup::exclusionPolicy() const
254{
255 Q_D(const QActionGroup);
256 return d->exclusionPolicy;
257}
258
259/*!
260 \fn void QActionGroup::setDisabled(bool b)
261
262 This is a convenience function for the \l enabled property, that
263 is useful for signals--slots connections. If \a b is true the
264 action group is disabled; otherwise it is enabled.
265*/
266
267/*!
268 \property QActionGroup::enabled
269 \brief whether the action group is enabled
270
271 Each action in the group will be enabled or disabled unless it
272 has been explicitly disabled.
273
274 \sa QAction::setEnabled()
275*/
276void QActionGroup::setEnabled(bool b)
277{
278 Q_D(QActionGroup);
279 d->enabled = b;
280 for (auto action : std::as_const(t&: d->actions)) {
281 action->d_func()->setEnabled(enable: b, byGroup: true);
282 }
283}
284
285bool QActionGroup::isEnabled() const
286{
287 Q_D(const QActionGroup);
288 return d->enabled;
289}
290
291/*!
292 Returns the currently checked action in the group, or \nullptr if
293 none are checked.
294*/
295QAction *QActionGroup::checkedAction() const
296{
297 Q_D(const QActionGroup);
298 return d->current.data();
299}
300
301/*!
302 \property QActionGroup::visible
303 \brief whether the action group is visible
304
305 Each action in the action group will match the visible state of
306 this group unless it has been explicitly hidden.
307
308 \sa QAction::setEnabled()
309*/
310void QActionGroup::setVisible(bool b)
311{
312 Q_D(QActionGroup);
313 d->visible = b;
314 for (auto action : std::as_const(t&: d->actions)) {
315 if (!action->d_func()->forceInvisible)
316 action->d_func()->setVisible(b);
317 }
318}
319
320bool QActionGroup::isVisible() const
321{
322 Q_D(const QActionGroup);
323 return d->visible;
324}
325
326QT_END_NAMESPACE
327
328#include "moc_qactiongroup.cpp"
329

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