diff options
Diffstat (limited to 'src/quick/util/qquickstategroup.cpp')
-rw-r--r-- | src/quick/util/qquickstategroup.cpp | 193 |
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; } |