2
* Copyright 2016 Canonical Ltd.
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License as published by
6
* the Free Software Foundation; version 3.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18
#include "exclusivegroup_p.h"
19
#include "ucaction_p.h"
21
#include <QSignalMapper>
23
#define CHECKED_PROPERTY "checked"
27
static const char *checkableSignals[] = {
32
static bool isChecked(const QObject *o)
35
QVariant checkedVariant = o->property(CHECKED_PROPERTY);
36
return checkedVariant.isValid() && checkedVariant.toBool();
40
* \qmltype ExclusiveGroup
41
* \inqmlmodule Ubuntu.Components
42
* \since Ubuntu.Components 1.3
44
* \inherits ActionList
45
* \brief ExclusiveGroup provides a way to declare several checkable controls as mutually exclusive.
47
* The ExclusiveGroup will only allow a single object to have it's checkable property set to "true"
48
* at any one time. The exclusive group accepts child Actions, but objects other than Actions can be
49
* used by using the \l bindCheckable function as long as they support one of the required signals,
50
* and a "checked" property.
54
* parameterType: Action.Bool
58
* parameterType: Action.Bool
64
ExclusiveGroup::ExclusiveGroup(QObject *parent)
66
, m_signalMapper(new QSignalMapper(this))
67
, m_entranceGuard(false)
69
connect(this, &ActionList::added, this, &ExclusiveGroup::onActionAdded);
70
connect(this, &ActionList::removed, this, &ExclusiveGroup::onActionRemoved);
72
int index = m_signalMapper->metaObject()->indexOfMethod("map()");
73
m_updateCurrentMethod = m_signalMapper->metaObject()->method(index);
74
connect(m_signalMapper, static_cast<void(QSignalMapper::*)(QObject *)>(&QSignalMapper::mapped), this, [this](QObject *object) {
75
if (isChecked(object)) {
81
void ExclusiveGroup::onActionAdded(UCAction *action)
83
action->setExclusiveGroup(this);
86
void ExclusiveGroup::onActionRemoved(UCAction *action)
88
action->setExclusiveGroup(nullptr);
92
* \qmlproperty Action ExclusiveGroup::current
93
* Returns the currently checked action
95
void ExclusiveGroup::setCurrent(QObject *object)
97
if (m_current == object)
101
m_current->setProperty(CHECKED_PROPERTY, QVariant(false));
104
m_current->setProperty(CHECKED_PROPERTY, QVariant(true));
105
Q_EMIT currentChanged();
108
QObject *ExclusiveGroup::current() const
110
return m_current.data();
114
* \qmlmethod void ExclusiveGroup::bindCheckable(object object)
115
* Explicitly bind an objects checkability to this exclusive group.
116
* \note This only works with objects which support the following signals signals:
118
* \li \b toggled(bool)
127
* onObjectAdded: exclusiveGroup.bindCheckable(object)
128
* onObjectRemoved: exclusiveGroup.unbindCheckable(object)
136
* \sa ExclusiveGroup::unbindCheckable
138
void ExclusiveGroup::bindCheckable(QObject *object)
140
for (const char **signalName = checkableSignals; *signalName; signalName++) {
141
int signalIndex = object->metaObject()->indexOfSignal(*signalName);
142
if (signalIndex != -1) {
143
QMetaMethod signalMethod = object->metaObject()->method(signalIndex);
144
connect(object, signalMethod, m_signalMapper, m_updateCurrentMethod, Qt::UniqueConnection);
145
m_signalMapper->setMapping(object, object);
146
connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*)), Qt::UniqueConnection);
147
if (!m_current && isChecked(object))
155
* \qmlmethod void ExclusiveGroup::unbindCheckable(object object)
156
* Explicitly unbind an objects checkability from this exclusive group.
157
* \sa ExclusiveGroup::bindCheckable
159
void ExclusiveGroup::unbindCheckable(QObject *object)
161
if (m_current == object)
164
disconnect(object, 0, m_signalMapper, 0);
165
disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*)));