blob: c613e943773eadbcd4e1e64ab4d02d56142db2a9 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Quick Controls module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qquickexclusivegroup_p.h"
#include <qvariant.h>
#include <qdebug.h>
#include "qquickaction_p.h"
#define CHECKED_PROPERTY "checked"
QT_BEGIN_NAMESPACE
static const char *checkableSignals[] = {
CHECKED_PROPERTY"Changed()",
"toggled(bool)",
"toggled()",
0
};
static bool isChecked(const QObject *o)
{
if (!o) return false;
QVariant checkedVariant = o->property(CHECKED_PROPERTY);
return checkedVariant.isValid() && checkedVariant.toBool();
}
/*!
\qmltype ExclusiveGroup
\instantiates QQuickExclusiveGroup1
\ingroup controls
\inqmlmodule QtQuick.Controls
\brief ExclusiveGroup provides a way to declare several checkable controls as mutually exclusive.
ExclusiveGroup can contain several \l Action items, and those will automatically get their
\l Action::exclusiveGroup property assigned.
\code
ExclusiveGroup {
id: radioInputGroup
Action {
id: dabRadioInput
text: "DAB"
checkable: true
}
Action {
id: fmRadioInput
text: "FM"
checkable: true
}
Action {
id: amRadioInput
text: "AM"
checkable: true
}
}
\endcode
Several controls already support ExclusiveGroup, e.g. \l Action,
\l MenuItem, \l {QtQuick.Controls::}{Button}, and \l RadioButton.
As ExclusiveGroup only supports \l Action as child items, we need to manually
assign the \c exclusiveGroup property for other objects.
\code
GroupBox {
id: group2
title: qsTr("Tab Position")
Layout.fillWidth: true
RowLayout {
ExclusiveGroup { id: tabPositionGroup }
RadioButton {
id: topButton
text: qsTr("Top")
checked: true
exclusiveGroup: tabPositionGroup
Layout.minimumWidth: 100
}
RadioButton {
id: bottomButton
text: qsTr("Bottom")
exclusiveGroup: tabPositionGroup
Layout.minimumWidth: 100
}
}
}
\endcode
\section1 Adding support to ExclusiveGroup
It is possible to add support for ExclusiveGroup for an object or control. It should have a \c checked
property, and either a \c checkedChanged, \c toggled(), or \c toggled(bool) signal. It also needs
to be bound with \l ExclusiveGroup::bindCheckable() when its ExclusiveGroup typed property is set.
\code
Item {
id: myItem
property bool checked: false
property ExclusiveGroup exclusiveGroup: null
onExclusiveGroupChanged: {
if (exclusiveGroup)
exclusiveGroup.bindCheckable(myItem)
}
}
\endcode
The example above shows the minimum code necessary to add ExclusiveGroup support to any item.
*/
/*!
\qmlproperty object ExclusiveGroup::current
The currently selected object. Defaults to the first checked object bound to the ExclusiveGroup.
If there is none, then it defaults to \c null.
*/
/*!
\qmlmethod void ExclusiveGroup::bindCheckable(object)
Registers \a object to the exclusive group.
You should only need to call this function when creating a component you want to be compatible with ExclusiveGroup.
\sa ExclusiveGroup::unbindCheckable()
*/
/*!
\qmlmethod void ExclusiveGroup::unbindCheckable(object)
Unregisters \a object from the exclusive group.
You should only need to call this function when creating a component you want to be compatible with ExclusiveGroup.
\sa ExclusiveGroup::bindCheckable()
*/
QQuickExclusiveGroup1::QQuickExclusiveGroup1(QObject *parent)
: QObject(parent), m_current(0)
{
int index = metaObject()->indexOfMethod("updateCurrent()");
m_updateCurrentMethod = metaObject()->method(index);
}
QQmlListProperty<QQuickAction1> QQuickExclusiveGroup1::actions()
{
return QQmlListProperty<QQuickAction1>(this, 0, &QQuickExclusiveGroup1::append_actions, 0, 0, 0);
}
void QQuickExclusiveGroup1::append_actions(QQmlListProperty<QQuickAction1> *list, QQuickAction1 *action)
{
if (QQuickExclusiveGroup1 *eg = qobject_cast<QQuickExclusiveGroup1 *>(list->object))
action->setExclusiveGroup(eg);
}
void QQuickExclusiveGroup1::setCurrent(QObject * o)
{
if (m_current == o)
return;
if (m_current)
m_current->setProperty(CHECKED_PROPERTY, QVariant(false));
m_current = o;
if (m_current)
m_current->setProperty(CHECKED_PROPERTY, QVariant(true));
emit currentChanged();
}
void QQuickExclusiveGroup1::updateCurrent()
{
QObject *checkable = sender();
if (isChecked(checkable))
setCurrent(checkable);
}
void QQuickExclusiveGroup1::bindCheckable(QObject *o)
{
for (const char **signalName = checkableSignals; *signalName; signalName++) {
int signalIndex = o->metaObject()->indexOfSignal(*signalName);
if (signalIndex != -1) {
QMetaMethod signalMethod = o->metaObject()->method(signalIndex);
connect(o, signalMethod, this, m_updateCurrentMethod, Qt::UniqueConnection);
connect(o, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*)), Qt::UniqueConnection);
if (!m_current && isChecked(o))
setCurrent(o);
return;
}
}
qWarning() << "QQuickExclusiveGroup1::bindCheckable(): Cannot bind to" << o;
}
void QQuickExclusiveGroup1::unbindCheckable(QObject *o)
{
if (m_current == o)
setCurrent(0);
for (const char **signalName = checkableSignals; *signalName; signalName++) {
int signalIndex = o->metaObject()->indexOfSignal(*signalName);
if (signalIndex != -1) {
QMetaMethod signalMethod = o->metaObject()->method(signalIndex);
if (disconnect(o, signalMethod, this, m_updateCurrentMethod)) {
disconnect(o, SIGNAL(destroyed(QObject*)), this, SLOT(unbindCheckable(QObject*)));
break;
}
}
}
}
QT_END_NAMESPACE