Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickactiongroup.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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// Qt-Security score:significant reason:default
4
6
7#include <QtCore/private/qobject_p.h>
8#include <QtCore/qmetaobject.h>
9#include <QtCore/qvariant.h>
10#include <QtQml/qqmlinfo.h>
11
12#include "qquickaction_p.h"
14
15#include <QtCore/qpointer.h>
16
18
19/*!
20 \qmltype ActionGroup
21 \inherits QtObject
22//! \nativetype QQuickActionGroup
23 \inqmlmodule QtQuick.Controls
24 \since 5.10
25 \ingroup utilities
26 \brief Groups actions together.
27
28 ActionGroup is a non-visual group of actions. A mutually \l exclusive
29 action group is used with actions where only one of the options can be
30 selected at a time.
31
32 The most straight-forward way to use ActionGroup is to declare actions
33 as children of the group.
34
35 \code
36 ActionGroup {
37 id: alignmentGroup
38
39 Action {
40 checked: true
41 checkable: true
42 text: qsTr("Left")
43 }
44
45 Action {
46 checkable: true
47 text: qsTr("Center")
48 }
49
50 Action {
51 checkable: true
52 text: qsTr("Right")
53 }
54 }
55 \endcode
56
57 Alternatively, the \l group attached property allows declaring the actions
58 elsewhere and assigning them to a specific group.
59
60 \code
61 ActionGroup { id: alignmentGroup }
62
63 Action {
64 checked: true
65 checkable: true
66 text: qsTr("Left")
67 ActionGroup.group: alignmentGroup
68 }
69
70 Action {
71 checkable: true
72 text: qsTr("Center")
73 ActionGroup.group: alignmentGroup
74 }
75
76 Action {
77 checkable: true
78 text: qsTr("Right")
79 ActionGroup.group: alignmentGroup
80 }
81 \endcode
82
83 More advanced use cases can be handled using the \c addAction() and
84 \c removeAction() methods.
85
86 \sa Action, ButtonGroup
87*/
88
89/*!
90 \qmlsignal QtQuick.Controls::ActionGroup::triggered(Action action)
91
92 This signal is emitted when an \a action in the group has been triggered.
93
94 This signal is convenient for implementing a common signal handler for
95 all actions in the same group.
96
97 \code
98 ActionGroup {
99 onTriggered: console.log("triggered:", action.text)
100
101 Action { text: "First" }
102 Action { text: "Second" }
103 Action { text: "Third" }
104 }
105 \endcode
106
107 \sa Action::triggered()
108*/
109
111{
112public:
113 Q_DECLARE_PUBLIC(QQuickActionGroup)
114
115 void clear();
118
119 static bool changeEnabled(QQuickAction *action, bool enabled);
120
121 static void actions_append(QQmlListProperty<QQuickAction> *prop, QQuickAction *obj);
122 static qsizetype actions_count(QQmlListProperty<QQuickAction> *prop);
123 static QQuickAction *actions_at(QQmlListProperty<QQuickAction> *prop, qsizetype index);
124 static void actions_clear(QQmlListProperty<QQuickAction> *prop);
125
126 bool enabled = true;
127 bool exclusive = true;
130};
131
133{
134 for (QQuickAction *action : std::as_const(actions)) {
135 QQuickActionPrivate::get(action)->group = nullptr;
136 QObjectPrivate::disconnect(action, &QQuickAction::triggered, this, &QQuickActionGroupPrivate::actionTriggered);
137 QObjectPrivate::disconnect(action, &QQuickAction::checkedChanged, this, &QQuickActionGroupPrivate::_q_updateCurrent);
138 }
139 actions.clear();
140}
141
143{
144 Q_Q(QQuickActionGroup);
145 QQuickAction *action = qobject_cast<QQuickAction*>(q->sender());
146 if (action)
147 emit q->triggered(action);
148}
149
151{
152 Q_Q(QQuickActionGroup);
153 if (!exclusive)
154 return;
155 QQuickAction *action = qobject_cast<QQuickAction*>(q->sender());
156 if (action && action->isChecked())
157 q->setCheckedAction(action);
158 else if (!actions.contains(checkedAction))
159 q->setCheckedAction(nullptr);
160}
161
162bool QQuickActionGroupPrivate::changeEnabled(QQuickAction *action, bool enabled)
163{
164 return action->isEnabled() != enabled && (!enabled || !QQuickActionPrivate::get(action)->explicitEnabled);
165}
166
167void QQuickActionGroupPrivate::actions_append(QQmlListProperty<QQuickAction> *prop, QQuickAction *obj)
168{
169 QQuickActionGroup *q = static_cast<QQuickActionGroup *>(prop->object);
170 q->addAction(obj);
171}
172
173qsizetype QQuickActionGroupPrivate::actions_count(QQmlListProperty<QQuickAction> *prop)
174{
175 QQuickActionGroupPrivate *p = static_cast<QQuickActionGroupPrivate *>(prop->data);
176 return p->actions.size();
177}
178
179QQuickAction *QQuickActionGroupPrivate::actions_at(QQmlListProperty<QQuickAction> *prop, qsizetype index)
180{
181 QQuickActionGroupPrivate *p = static_cast<QQuickActionGroupPrivate *>(prop->data);
182 return p->actions.value(index);
183}
184
185void QQuickActionGroupPrivate::actions_clear(QQmlListProperty<QQuickAction> *prop)
186{
187 QQuickActionGroupPrivate *p = static_cast<QQuickActionGroupPrivate *>(prop->data);
188 if (!p->actions.isEmpty()) {
189 p->clear();
190 QQuickActionGroup *q = static_cast<QQuickActionGroup *>(prop->object);
191 // QTBUG-52358: don't clear the checked action immediately
192 QMetaObject::invokeMethod(q, "_q_updateCurrent", Qt::QueuedConnection);
193 emit q->actionsChanged();
194 }
195}
196
197QQuickActionGroup::QQuickActionGroup(QObject *parent)
198 : QObject(*(new QQuickActionGroupPrivate), parent)
199{
200}
201
202QQuickActionGroup::~QQuickActionGroup()
203{
204 Q_D(QQuickActionGroup);
205 d->clear();
206}
207
208QQuickActionGroupAttached *QQuickActionGroup::qmlAttachedProperties(QObject *object)
209{
210 return new QQuickActionGroupAttached(object);
211}
212
213/*!
214 \qmlproperty Action QtQuick.Controls::ActionGroup::checkedAction
215
216 This property holds the currently selected action in an exclusive group,
217 or \c null if there is none or the group is non-exclusive.
218
219 By default, it is the first checked action added to an exclusive action group.
220
221 \sa exclusive
222*/
223QQuickAction *QQuickActionGroup::checkedAction() const
224{
225 Q_D(const QQuickActionGroup);
226 return d->checkedAction;
227}
228
229void QQuickActionGroup::setCheckedAction(QQuickAction *checkedAction)
230{
231 Q_D(QQuickActionGroup);
232 if (d->checkedAction == checkedAction)
233 return;
234
235 if (d->checkedAction)
236 d->checkedAction->setChecked(false);
237 d->checkedAction = checkedAction;
238 if (checkedAction)
239 checkedAction->setChecked(true);
240 emit checkedActionChanged();
241}
242
243/*!
244 \qmlproperty list<Action> QtQuick.Controls::ActionGroup::actions
245 \qmldefault
246
247 This property holds the list of actions in the group.
248
249 \sa group
250*/
251QQmlListProperty<QQuickAction> QQuickActionGroup::actions()
252{
253 Q_D(QQuickActionGroup);
254 return QQmlListProperty<QQuickAction>(this, d,
255 QQuickActionGroupPrivate::actions_append,
256 QQuickActionGroupPrivate::actions_count,
257 QQuickActionGroupPrivate::actions_at,
258 QQuickActionGroupPrivate::actions_clear);
259}
260
261/*!
262 \qmlproperty bool QtQuick.Controls::ActionGroup::exclusive
263
264 This property holds whether the action group is exclusive. The default value is \c true.
265
266 If this property is \c true, then only one action in the group can be checked at any given time.
267 The user can trigger any action to check it, and that action will replace the existing one as
268 the checked action in the group.
269
270 In an exclusive group, the user cannot uncheck the currently checked action by triggering it;
271 instead, another action in the group must be triggered to set the new checked action for that
272 group.
273
274 In a non-exclusive group, checking and unchecking actions does not affect the other actions in
275 the group. Furthermore, the value of the \l checkedAction property is \c null.
276*/
277bool QQuickActionGroup::isExclusive() const
278{
279 Q_D(const QQuickActionGroup);
280 return d->exclusive;
281}
282
283void QQuickActionGroup::setExclusive(bool exclusive)
284{
285 Q_D(QQuickActionGroup);
286 if (d->exclusive == exclusive)
287 return;
288
289 d->exclusive = exclusive;
290 emit exclusiveChanged();
291}
292
293/*!
294 \qmlproperty bool QtQuick.Controls::ActionGroup::enabled
295
296 This property holds whether the action group is enabled. The default value is \c true.
297
298 If this property is \c false, then all actions in the group are disabled. If this property
299 is \c true, all actions in the group are enabled, unless explicitly disabled.
300*/
301bool QQuickActionGroup::isEnabled() const
302{
303 Q_D(const QQuickActionGroup);
304 return d->enabled;
305}
306
307void QQuickActionGroup::setEnabled(bool enabled)
308{
309 Q_D(QQuickActionGroup);
310 if (d->enabled == enabled)
311 return;
312
313 for (QQuickAction *action : std::as_const(d->actions)) {
314 if (d->changeEnabled(action, enabled))
315 emit action->enabledChanged(enabled);
316 }
317
318 d->enabled = enabled;
319 emit enabledChanged();
320}
321
322/*!
323 \qmlmethod void QtQuick.Controls::ActionGroup::addAction(Action action)
324
325 Adds an \a action to the action group.
326
327 \note Manually adding objects to a action group is typically unnecessary.
328 The \l actions property and the \l group attached property provide a
329 convenient and declarative syntax.
330
331 \sa actions, group
332*/
333void QQuickActionGroup::addAction(QQuickAction *action)
334{
335 Q_D(QQuickActionGroup);
336 if (!action || d->actions.contains(action))
337 return;
338
339 const bool enabledChange = d->changeEnabled(action, d->enabled);
340
341 QQuickActionPrivate::get(action)->group = this;
342 QObjectPrivate::connect(action, &QQuickAction::triggered, d, &QQuickActionGroupPrivate::actionTriggered);
343 QObjectPrivate::connect(action, &QQuickAction::checkedChanged, d, &QQuickActionGroupPrivate::_q_updateCurrent);
344
345 if (d->exclusive && action->isChecked())
346 setCheckedAction(action);
347 if (enabledChange)
348 emit action->enabledChanged(action->isEnabled());
349
350 d->actions.append(action);
351 emit actionsChanged();
352}
353
354/*!
355 \qmlmethod void QtQuick.Controls::ActionGroup::removeAction(Action action)
356
357 Removes an \a action from the action group.
358
359 \note Manually removing objects from a action group is typically unnecessary.
360 The \l actions property and the \l group attached property provide a
361 convenient and declarative syntax.
362
363 \sa actions, group
364*/
365void QQuickActionGroup::removeAction(QQuickAction *action)
366{
367 Q_D(QQuickActionGroup);
368 if (!action || !d->actions.contains(action))
369 return;
370
371 const bool enabledChange = d->changeEnabled(action, d->enabled);
372
373 QQuickActionPrivate::get(action)->group = nullptr;
374 QObjectPrivate::disconnect(action, &QQuickAction::triggered, d, &QQuickActionGroupPrivate::actionTriggered);
375 QObjectPrivate::disconnect(action, &QQuickAction::checkedChanged, d, &QQuickActionGroupPrivate::_q_updateCurrent);
376
377 if (d->checkedAction == action)
378 setCheckedAction(nullptr);
379 if (enabledChange)
380 emit action->enabledChanged(action->isEnabled());
381
382 d->actions.removeOne(action);
383 emit actionsChanged();
384}
385
387{
388public:
389 QQuickActionGroup *group = nullptr;
390};
391
392QQuickActionGroupAttached::QQuickActionGroupAttached(QObject *parent)
393 : QObject(*(new QQuickActionGroupAttachedPrivate), parent)
394{
395}
396
397/*!
398 \qmlattachedproperty ActionGroup QtQuick.Controls::ActionGroup::group
399
400 This property attaches an action to an action group.
401
402 \code
403 ActionGroup { id: group }
404
405 Action {
406 checked: true
407 text: qsTr("Option A")
408 ActionGroup.group: group
409 }
410
411 Action {
412 text: qsTr("Option B")
413 ActionGroup.group: group
414 }
415 \endcode
416
417 \sa actions
418*/
419QQuickActionGroup *QQuickActionGroupAttached::group() const
420{
421 Q_D(const QQuickActionGroupAttached);
422 return d->group;
423}
424
425void QQuickActionGroupAttached::setGroup(QQuickActionGroup *group)
426{
427 Q_D(QQuickActionGroupAttached);
428 if (d->group == group)
429 return;
430
431 if (d->group)
432 d->group->removeAction(qobject_cast<QQuickAction*>(parent()));
433 d->group = group;
434 if (group)
435 group->addAction(qobject_cast<QQuickAction*>(parent()));
436 emit groupChanged();
437}
438
439QT_END_NAMESPACE
440
441#include "moc_qquickactiongroup_p.cpp"
Groups actions together.
static void actions_append(QQmlListProperty< QQuickAction > *prop, QQuickAction *obj)
static QQuickAction * actions_at(QQmlListProperty< QQuickAction > *prop, qsizetype index)
static qsizetype actions_count(QQmlListProperty< QQuickAction > *prop)
static void actions_clear(QQmlListProperty< QQuickAction > *prop)
QList< QQuickAction * > actions
QPointer< QQuickAction > checkedAction
static bool changeEnabled(QQuickAction *action, bool enabled)