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