aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/util/qquickstategroup.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/util/qquickstategroup.cpp')
-rw-r--r--src/quick/util/qquickstategroup.cpp193
1 files changed, 91 insertions, 102 deletions
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index b86333943c..f61261035f 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qquickstategroup_p.h"
@@ -53,7 +17,9 @@
QT_BEGIN_NAMESPACE
-DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+using namespace Qt::StringLiterals;
+
+Q_DECLARE_LOGGING_CATEGORY(lcStates)
class QQuickStateGroupPrivate : public QObjectPrivate
{
@@ -119,7 +85,7 @@ public:
}
\endqml
- \sa {Qt Quick States}{Qt Quick States}, {Animation and Transitions in Qt Quick}{Transitions}, {Qt QML}
+ \sa {Qt Quick States}{Qt Quick States}, {Animation and Transitions in Qt Quick}{Transitions}, {Qt Qml}
*/
QQuickStateGroup::QQuickStateGroup(QObject *parent)
@@ -130,8 +96,10 @@ QQuickStateGroup::QQuickStateGroup(QObject *parent)
QQuickStateGroup::~QQuickStateGroup()
{
Q_D(const QQuickStateGroup);
- for (int i = 0; i < d->states.count(); ++i)
- d->states.at(i)->setStateGroup(nullptr);
+ for (QQuickState *state : std::as_const(d->states)) {
+ if (state)
+ state->setStateGroup(nullptr);
+ }
if (d->nullState)
d->nullState->setStateGroup(nullptr);
}
@@ -177,17 +145,15 @@ QQmlListProperty<QQuickState> QQuickStateGroup::statesProperty()
void QQuickStateGroupPrivate::append_state(QQmlListProperty<QQuickState> *list, QQuickState *state)
{
QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
- if (state) {
- _this->d_func()->states.append(state);
+ _this->d_func()->states.append(state);
+ if (state)
state->setStateGroup(_this);
- }
-
}
qsizetype QQuickStateGroupPrivate::count_state(QQmlListProperty<QQuickState> *list)
{
QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
- return _this->d_func()->states.count();
+ return _this->d_func()->states.size();
}
QQuickState *QQuickStateGroupPrivate::at_state(QQmlListProperty<QQuickState> *list, qsizetype index)
@@ -198,34 +164,42 @@ QQuickState *QQuickStateGroupPrivate::at_state(QQmlListProperty<QQuickState> *li
void QQuickStateGroupPrivate::clear_states(QQmlListProperty<QQuickState> *list)
{
- QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
- _this->d_func()->setCurrentStateInternal(QString(), true);
- for (qsizetype i = 0; i < _this->d_func()->states.count(); ++i) {
- _this->d_func()->states.at(i)->setStateGroup(nullptr);
+ QQuickStateGroupPrivate *d = static_cast<QQuickStateGroup *>(list->object)->d_func();
+ d->setCurrentStateInternal(QString(), true);
+ for (QQuickState *state : std::as_const(d->states)) {
+ if (state)
+ state->setStateGroup(nullptr);
}
- _this->d_func()->states.clear();
+ d->states.clear();
}
void QQuickStateGroupPrivate::replace_states(QQmlListProperty<QQuickState> *list, qsizetype index, QQuickState *state)
{
- auto *self = qobject_cast<QQuickStateGroup *>(list->object);
+ auto *self = static_cast<QQuickStateGroup *>(list->object);
auto *d = self->d_func();
auto *oldState = d->states.at(index);
if (oldState != state) {
- oldState->setStateGroup(nullptr);
- state->setStateGroup(self);
+ if (oldState)
+ oldState->setStateGroup(nullptr);
+
+ if (state)
+ state->setStateGroup(self);
d->states.replace(index, state);
- if (d->currentState == oldState->name())
- d->setCurrentStateInternal(state->name(), true);
+ if (!oldState || d->currentState == oldState->name())
+ d->setCurrentStateInternal(state ? state->name() : QString(), true);
}
}
void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty<QQuickState> *list)
{
- auto *d = qobject_cast<QQuickStateGroup *>(list->object)->d_func();
- if (d->currentState == d->states.last()->name())
- d->setCurrentStateInternal(d->states.length() > 1 ? d->states.first()->name() : QString(), true);
- d->states.last()->setStateGroup(nullptr);
+ auto *d = static_cast<QQuickStateGroup *>(list->object)->d_func();
+ if (QQuickState *last = d->states.last()) {
+ if (d->currentState == last->name()) {
+ QQuickState *first = d->states.size() > 1 ? d->states.first() : nullptr;
+ d->setCurrentStateInternal(first ? first->name() : QString(), true);
+ }
+ last->setStateGroup(nullptr);
+ }
d->states.removeLast();
}
@@ -268,7 +242,7 @@ void QQuickStateGroupPrivate::append_transition(QQmlListProperty<QQuickTransitio
qsizetype QQuickStateGroupPrivate::count_transitions(QQmlListProperty<QQuickTransition> *list)
{
QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
- return _this->d_func()->transitions.count();
+ return _this->d_func()->transitions.size();
}
QQuickTransition *QQuickStateGroupPrivate::at_transition(QQmlListProperty<QQuickTransition> *list, qsizetype index)
@@ -291,14 +265,14 @@ void QQuickStateGroupPrivate::clear_transitions(QQmlListProperty<QQuickTransitio
This property is often used in scripts to change between states. For
example:
- \js
+ \qml
function toggle() {
if (button.state == 'On')
button.state = 'Off';
else
button.state = 'On';
}
- \endjs
+ \endqml
If the state group is in its base state (i.e. no explicit state has been
set), \c state will be a blank string. Likewise, you can return a
@@ -333,18 +307,19 @@ void QQuickStateGroup::componentComplete()
d->componentComplete = true;
QVarLengthArray<QString, 4> names;
- names.reserve(d->states.count());
- for (int ii = 0; ii < d->states.count(); ++ii) {
- QQuickState *state = d->states.at(ii);
+ names.reserve(d->states.size());
+ for (QQuickState *state : std::as_const(d->states)) {
+ if (!state)
+ continue;
+
if (!state->isNamed())
state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount));
QString stateName = state->name();
- if (names.contains(stateName)) {
+ if (names.contains(stateName))
qmlWarning(state->parent()) << "Found duplicate state name: " << stateName;
- } else {
+ else
names.append(std::move(stateName));
- }
}
if (d->updateAutoState()) {
@@ -372,23 +347,38 @@ bool QQuickStateGroupPrivate::updateAutoState()
return false;
bool revert = false;
- for (int ii = 0; ii < states.count(); ++ii) {
- QQuickState *state = states.at(ii);
- if (state->isWhenKnown()) {
- if (state->isNamed()) {
- if (state->when()) {
- if (stateChangeDebug())
- qWarning() << "Setting auto state due to expression";
- if (currentState != state->name()) {
- q->setState(state->name());
- return true;
- } else {
- return false;
- }
- } else if (state->name() == currentState) {
- revert = true;
- }
+ for (QQuickState *state : std::as_const(states)) {
+ if (!state || !state->isWhenKnown() || !state->isNamed())
+ continue;
+
+ bool whenValue = state->when();
+ const QQmlPropertyIndex whenIndex(state->metaObject()->indexOfProperty("when"));
+ const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(state, whenIndex);
+ Q_ASSERT(!potentialWhenBinding.isUntypedPropertyBinding());
+
+ // if there is a binding, the value in when might not be up-to-date at this point
+ // so we manually re-evaluate the binding
+ QQmlAbstractBinding *abstractBinding = potentialWhenBinding.asAbstractBinding();
+ if (abstractBinding && abstractBinding->kind() == QQmlAbstractBinding::QmlBinding) {
+ QQmlBinding *binding = static_cast<QQmlBinding *>(abstractBinding);
+ if (binding->hasValidContext()) {
+ const auto boolType = QMetaType::fromType<bool>();
+ const bool isUndefined = !binding->evaluate(&whenValue, boolType);
+ if (isUndefined)
+ whenValue = false;
+ }
+ }
+
+ if (whenValue) {
+ qCDebug(lcStates) << "Setting auto state due to expression";
+ if (currentState != state->name()) {
+ q->setState(state->name());
+ return true;
+ } else {
+ return false;
}
+ } else if (state->name() == currentState) {
+ revert = true;
}
}
if (revert) {
@@ -407,7 +397,7 @@ QQuickTransition *QQuickStateGroupPrivate::findTransition(const QString &from, c
bool reversed = false;
bool done = false;
- for (int ii = 0; !done && ii < transitions.count(); ++ii) {
+ for (int ii = 0; !done && ii < transitions.size(); ++ii) {
QQuickTransition *t = transitions.at(ii);
if (!t->enabled())
continue;
@@ -421,10 +411,10 @@ QQuickTransition *QQuickStateGroupPrivate::findTransition(const QString &from, c
const QString toStateStr = t->toState();
auto fromState = QStringView{fromStateStr}.split(QLatin1Char(','));
- for (int jj = 0; jj < fromState.count(); ++jj)
+ for (int jj = 0; jj < fromState.size(); ++jj)
fromState[jj] = fromState.at(jj).trimmed();
auto toState = QStringView{toStateStr}.split(QLatin1Char(','));
- for (int jj = 0; jj < toState.count(); ++jj)
+ for (int jj = 0; jj < toState.size(); ++jj)
toState[jj] = toState.at(jj).trimmed();
if (ii == 1)
qSwap(fromState, toState);
@@ -483,18 +473,18 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state,
applyingState = true;
QQuickTransition *transition = ignoreTrans ? nullptr : findTransition(currentState, state);
- if (stateChangeDebug()) {
- qWarning() << this << "Changing state. From" << currentState << ". To" << state;
+ if (lcStates().isDebugEnabled()) {
+ qCDebug(lcStates) << this << "changing state from:" << currentState << "to:" << state;
if (transition)
- qWarning() << " using transition" << transition->fromState()
- << transition->toState();
+ qCDebug(lcStates) << " using transition" << transition->fromState()
+ << transition->toState();
}
QQuickState *oldState = nullptr;
if (!currentState.isEmpty()) {
- for (int ii = 0; ii < states.count(); ++ii) {
- if (states.at(ii)->name() == currentState) {
- oldState = states.at(ii);
+ for (QQuickState *state : std::as_const(states)) {
+ if (state && state->name() == currentState) {
+ oldState = state;
break;
}
}
@@ -504,9 +494,9 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state,
emit q->stateChanged(currentState);
QQuickState *newState = nullptr;
- for (int ii = 0; ii < states.count(); ++ii) {
- if (states.at(ii)->name() == currentState) {
- newState = states.at(ii);
+ for (QQuickState *state : std::as_const(states)) {
+ if (state && state->name() == currentState) {
+ newState = state;
break;
}
}
@@ -528,9 +518,8 @@ void QQuickStateGroupPrivate::setCurrentStateInternal(const QString &state,
QQuickState *QQuickStateGroup::findState(const QString &name) const
{
Q_D(const QQuickStateGroup);
- for (int i = 0; i < d->states.count(); ++i) {
- QQuickState *state = d->states.at(i);
- if (state->name() == name)
+ for (QQuickState *state : std::as_const(d->states)) {
+ if (state && state->name() == name)
return state;
}