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.cpp242
1 files changed, 129 insertions, 113 deletions
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index d8daec2f07..8fb3130e35 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,7 @@
QT_BEGIN_NAMESPACE
-DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
+using namespace Qt::StringLiterals;
class QQuickStateGroupPrivate : public QObjectPrivate
{
@@ -67,13 +31,15 @@ public:
QQuickState *nullState;
static void append_state(QQmlListProperty<QQuickState> *list, QQuickState *state);
- static int count_state(QQmlListProperty<QQuickState> *list);
- static QQuickState *at_state(QQmlListProperty<QQuickState> *list, int index);
+ static qsizetype count_state(QQmlListProperty<QQuickState> *list);
+ static QQuickState *at_state(QQmlListProperty<QQuickState> *list, qsizetype index);
static void clear_states(QQmlListProperty<QQuickState> *list);
+ static void replace_states(QQmlListProperty<QQuickState> *list, qsizetype index, QQuickState *state);
+ static void removeLast_states(QQmlListProperty<QQuickState> *list);
static void append_transition(QQmlListProperty<QQuickTransition> *list, QQuickTransition *state);
- static int count_transitions(QQmlListProperty<QQuickTransition> *list);
- static QQuickTransition *at_transition(QQmlListProperty<QQuickTransition> *list, int index);
+ static qsizetype count_transitions(QQmlListProperty<QQuickTransition> *list);
+ static QQuickTransition *at_transition(QQmlListProperty<QQuickTransition> *list, qsizetype index);
static void clear_transitions(QQmlListProperty<QQuickTransition> *list);
QList<QQuickState *> states;
@@ -117,7 +83,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)
@@ -128,8 +94,12 @@ 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);
}
QList<QQuickState *> QQuickStateGroup::states() const
@@ -161,29 +131,30 @@ QList<QQuickState *> QQuickStateGroup::states() const
QQmlListProperty<QQuickState> QQuickStateGroup::statesProperty()
{
Q_D(QQuickStateGroup);
- return QQmlListProperty<QQuickState>(this, &d->states, &QQuickStateGroupPrivate::append_state,
- &QQuickStateGroupPrivate::count_state,
- &QQuickStateGroupPrivate::at_state,
- &QQuickStateGroupPrivate::clear_states);
+ return QQmlListProperty<QQuickState>(this, &d->states,
+ &QQuickStateGroupPrivate::append_state,
+ &QQuickStateGroupPrivate::count_state,
+ &QQuickStateGroupPrivate::at_state,
+ &QQuickStateGroupPrivate::clear_states,
+ &QQuickStateGroupPrivate::replace_states,
+ &QQuickStateGroupPrivate::removeLast_states);
}
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);
- }
-
}
-int QQuickStateGroupPrivate::count_state(QQmlListProperty<QQuickState> *list)
+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, int index)
+QQuickState *QQuickStateGroupPrivate::at_state(QQmlListProperty<QQuickState> *list, qsizetype index)
{
QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
return _this->d_func()->states.at(index);
@@ -191,12 +162,43 @@ 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 (int 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);
+ }
+ d->states.clear();
+}
+
+void QQuickStateGroupPrivate::replace_states(QQmlListProperty<QQuickState> *list, qsizetype index, QQuickState *state)
+{
+ auto *self = static_cast<QQuickStateGroup *>(list->object);
+ auto *d = self->d_func();
+ auto *oldState = d->states.at(index);
+ if (oldState != state) {
+ if (oldState)
+ oldState->setStateGroup(nullptr);
+
+ if (state)
+ state->setStateGroup(self);
+ d->states.replace(index, state);
+ if (!oldState || d->currentState == oldState->name())
+ d->setCurrentStateInternal(state ? state->name() : QString(), true);
}
- _this->d_func()->states.clear();
+}
+
+void QQuickStateGroupPrivate::removeLast_states(QQmlListProperty<QQuickState> *list)
+{
+ 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();
}
/*!
@@ -235,13 +237,13 @@ void QQuickStateGroupPrivate::append_transition(QQmlListProperty<QQuickTransitio
_this->d_func()->transitions.append(trans);
}
-int QQuickStateGroupPrivate::count_transitions(QQmlListProperty<QQuickTransition> *list)
+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, int index)
+QQuickTransition *QQuickStateGroupPrivate::at_transition(QQmlListProperty<QQuickTransition> *list, qsizetype index)
{
QQuickStateGroup *_this = static_cast<QQuickStateGroup *>(list->object);
return _this->d_func()->transitions.at(index);
@@ -261,14 +263,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
@@ -303,18 +305,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));
- const QString stateName = state->name();
- if (names.contains(stateName)) {
+ QString stateName = state->name();
+ if (names.contains(stateName))
qmlWarning(state->parent()) << "Found duplicate state name: " << stateName;
- } else {
+ else
names.append(std::move(stateName));
- }
}
if (d->updateAutoState()) {
@@ -342,24 +345,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() && state->when()->evaluate().toBool()) {
- if (stateChangeDebug())
- qWarning() << "Setting auto state due to:"
- << state->when()->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) {
@@ -378,7 +395,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;
@@ -391,26 +408,26 @@ QQuickTransition *QQuickStateGroupPrivate::findTransition(const QString &from, c
const QString fromStateStr = t->fromState();
const QString toStateStr = t->toState();
- QVector<QStringRef> fromState = fromStateStr.splitRef(QLatin1Char(','));
- for (int jj = 0; jj < fromState.count(); ++jj)
+ auto fromState = QStringView{fromStateStr}.split(QLatin1Char(','));
+ for (int jj = 0; jj < fromState.size(); ++jj)
fromState[jj] = fromState.at(jj).trimmed();
- QVector<QStringRef> toState = toStateStr.splitRef(QLatin1Char(','));
- for (int jj = 0; jj < toState.count(); ++jj)
+ auto toState = QStringView{toStateStr}.split(QLatin1Char(','));
+ for (int jj = 0; jj < toState.size(); ++jj)
toState[jj] = toState.at(jj).trimmed();
if (ii == 1)
qSwap(fromState, toState);
int tScore = 0;
const QString asterisk = QStringLiteral("*");
- if (fromState.contains(QStringRef(&from)))
+ if (fromState.contains(QStringView(from)))
tScore += 2;
- else if (fromState.contains(QStringRef(&asterisk)))
+ else if (fromState.contains(QStringView(asterisk)))
tScore += 1;
else
continue;
- if (toState.contains(QStringRef(&to)))
+ if (toState.contains(QStringView(to)))
tScore += 2;
- else if (toState.contains(QStringRef(&asterisk)))
+ else if (toState.contains(QStringView(asterisk)))
tScore += 1;
else
continue;
@@ -454,18 +471,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;
}
}
@@ -475,9 +492,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;
}
}
@@ -499,9 +516,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;
}