summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt11
-rw-r--r--src/imports/imports.pro3
-rw-r--r--src/imports/scxmlstatemachine/eventconnection.cpp143
-rw-r--r--src/imports/scxmlstatemachine/eventconnection_p.h96
-rw-r--r--src/imports/scxmlstatemachine/invokedservices.cpp133
-rw-r--r--src/imports/scxmlstatemachine/invokedservices_p.h92
-rw-r--r--src/imports/scxmlstatemachine/plugin.cpp88
-rw-r--r--src/imports/scxmlstatemachine/plugins.qmltypes140
-rw-r--r--src/imports/scxmlstatemachine/qmldir5
-rw-r--r--src/imports/scxmlstatemachine/scxmlstatemachine.pro23
-rw-r--r--src/imports/scxmlstatemachine/statemachineextended.cpp57
-rw-r--r--src/imports/scxmlstatemachine/statemachineextended_p.h76
-rw-r--r--src/imports/scxmlstatemachine/statemachineloader.cpp203
-rw-r--r--src/imports/scxmlstatemachine/statemachineloader_p.h102
-rw-r--r--src/plugins/CMakeLists.txt6
-rw-r--r--src/plugins/ecmascriptdatamodel/CMakeLists.txt27
-rw-r--r--src/plugins/ecmascriptdatamodel/ecmascriptdatamodelplugin.json3
-rw-r--r--src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodel.cpp (renamed from src/scxml/qscxmlecmascriptdatamodel.cpp)121
-rw-r--r--src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodel_p.h52
-rw-r--r--src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin.cpp15
-rw-r--r--src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin_p.h35
-rw-r--r--src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties.cpp65
-rw-r--r--src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties_p.h55
-rw-r--r--src/scxml/CMakeLists.txt56
-rw-r--r--src/scxml/Qt5ScxmlConfigExtras.cmake.in48
-rw-r--r--src/scxml/Qt5ScxmlMacros.cmake68
-rw-r--r--src/scxml/Qt6ScxmlMacros.cmake79
-rw-r--r--src/scxml/configure.cmake28
-rw-r--r--src/scxml/configure.json21
-rw-r--r--src/scxml/doc/external-resources.qdoc28
-rw-r--r--src/scxml/doc/qt6-changes.qdoc45
-rw-r--r--src/scxml/doc/qtscxml-cmake-macros.qdoc29
-rw-r--r--src/scxml/doc/qtscxml-examples.qdoc46
-rw-r--r--src/scxml/doc/qtscxml-index.qdoc60
-rw-r--r--src/scxml/doc/qtscxml-instantiating-state-machines.qdoc68
-rw-r--r--src/scxml/doc/qtscxml-module-cpp.qdoc45
-rw-r--r--src/scxml/doc/qtscxml-module-qml.qdoc36
-rw-r--r--src/scxml/doc/qtscxml-module-use.qdocinc30
-rw-r--r--src/scxml/doc/qtscxml-overview.qdoc33
-rw-r--r--src/scxml/doc/qtscxml-scxml-compliance.qdoc28
-rw-r--r--src/scxml/doc/qtscxml.qdocconf30
-rw-r--r--src/scxml/qscxmlcompiler.cpp197
-rw-r--r--src/scxml/qscxmlcompiler.h42
-rw-r--r--src/scxml/qscxmlcompiler_p.h95
-rw-r--r--src/scxml/qscxmlcppdatamodel.cpp48
-rw-r--r--src/scxml/qscxmlcppdatamodel.h40
-rw-r--r--src/scxml/qscxmlcppdatamodel_p.h40
-rw-r--r--src/scxml/qscxmldatamodel.cpp100
-rw-r--r--src/scxml/qscxmldatamodel.h51
-rw-r--r--src/scxml/qscxmldatamodel_p.h59
-rw-r--r--src/scxml/qscxmldatamodelplugin.cpp13
-rw-r--r--src/scxml/qscxmldatamodelplugin_p.h36
-rw-r--r--src/scxml/qscxmlecmascriptdatamodel.h80
-rw-r--r--src/scxml/qscxmlecmascriptplatformproperties.cpp101
-rw-r--r--src/scxml/qscxmlecmascriptplatformproperties_p.h93
-rw-r--r--src/scxml/qscxmlerror.cpp40
-rw-r--r--src/scxml/qscxmlerror.h40
-rw-r--r--src/scxml/qscxmlevent.cpp44
-rw-r--r--src/scxml/qscxmlevent.h40
-rw-r--r--src/scxml/qscxmlevent_p.h40
-rw-r--r--src/scxml/qscxmlexecutablecontent.cpp50
-rw-r--r--src/scxml/qscxmlexecutablecontent.h40
-rw-r--r--src/scxml/qscxmlexecutablecontent_p.h50
-rw-r--r--src/scxml/qscxmlglobals.h52
-rw-r--r--src/scxml/qscxmlglobals_p.h41
-rw-r--r--src/scxml/qscxmlinvokableservice.cpp68
-rw-r--r--src/scxml/qscxmlinvokableservice.h60
-rw-r--r--src/scxml/qscxmlinvokableservice_p.h56
-rw-r--r--src/scxml/qscxmlnulldatamodel.cpp42
-rw-r--r--src/scxml/qscxmlnulldatamodel.h40
-rw-r--r--src/scxml/qscxmlstatemachine.cpp342
-rw-r--r--src/scxml/qscxmlstatemachine.h200
-rw-r--r--src/scxml/qscxmlstatemachine_p.h114
-rw-r--r--src/scxml/qscxmlstatemachineinfo.cpp64
-rw-r--r--src/scxml/qscxmlstatemachineinfo_p.h59
-rw-r--r--src/scxml/qscxmltabledata.cpp110
-rw-r--r--src/scxml/qscxmltabledata.h42
-rw-r--r--src/scxml/qscxmltabledata_p.h61
-rw-r--r--src/scxml/qt_cmdline.cmake0
-rw-r--r--src/scxml/scxml.pro73
-rw-r--r--src/scxmlqml/CMakeLists.txt27
-rw-r--r--src/scxmlqml/eventconnection.cpp117
-rw-r--r--src/scxmlqml/eventconnection_p.h84
-rw-r--r--src/scxmlqml/invokedservices.cpp114
-rw-r--r--src/scxmlqml/invokedservices_p.h73
-rw-r--r--src/scxmlqml/qscxmlqmlglobals_p.h27
-rw-r--r--src/scxmlqml/statemachineextended.cpp21
-rw-r--r--src/scxmlqml/statemachineextended_p.h54
-rw-r--r--src/scxmlqml/statemachineloader.cpp198
-rw-r--r--src/scxmlqml/statemachineloader_p.h87
-rw-r--r--src/src.pro8
-rw-r--r--src/statemachine/CMakeLists.txt53
-rw-r--r--src/statemachine/configure.cmake29
-rw-r--r--src/statemachine/doc/images/animations-architecture.pngbin0 -> 27619 bytes
-rw-r--r--src/statemachine/doc/images/move-blocks-chart.pngbin0 -> 15740 bytes
-rw-r--r--src/statemachine/doc/images/rogue-statechart.pngbin0 -> 2490 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-button-history.pngbin0 -> 8493 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-button-nested.pngbin0 -> 7051 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-button.pngbin0 -> 4233 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-customevents.pngbin0 -> 2544 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-customevents2.pngbin0 -> 6713 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-examples.pngbin0 -> 3326 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-finished.pngbin0 -> 5518 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-nonparallel.pngbin0 -> 5350 bytes
-rw-r--r--src/statemachine/doc/images/statemachine-parallel.pngbin0 -> 8631 bytes
-rw-r--r--src/statemachine/doc/qstatemachine-qml-guide.qdoc293
-rw-r--r--src/statemachine/doc/qt6-changes.qdoc43
-rw-r--r--src/statemachine/doc/qtstatemachine-cpp-guide.qdoc511
-rw-r--r--src/statemachine/doc/qtstatemachine-examples.qdoc12
-rw-r--r--src/statemachine/doc/qtstatemachine-index.qdoc68
-rw-r--r--src/statemachine/doc/qtstatemachine-module-cpp.qdoc16
-rw-r--r--src/statemachine/doc/qtstatemachine-module-qml.qdoc18
-rw-r--r--src/statemachine/doc/qtstatemachine-module-use.qdocinc15
-rw-r--r--src/statemachine/doc/qtstatemachine-overview.qdoc42
-rw-r--r--src/statemachine/doc/qtstatemachine.qdocconf55
-rw-r--r--src/statemachine/doc/snippets/code/src_corelib_statemachine_qstatemachine.cpp18
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/Button.qml51
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/basicstate.qml18
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/finalstate.qml26
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/guardcondition.qml31
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/historystate.qml48
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/signaltransition.qml40
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/signaltransitionsignal.qml25
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/simplestatemachine.qml31
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/statemachine-button-history.qml112
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml97
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested.qml89
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/statemachine-button.qml63
-rw-r--r--src/statemachine/doc/snippets/qml/statemachine/timeouttransition.qml32
-rw-r--r--src/statemachine/doc/snippets/statemachine/eventtest.cpp37
-rw-r--r--src/statemachine/doc/snippets/statemachine/main.cpp52
-rw-r--r--src/statemachine/doc/snippets/statemachine/main2.cpp57
-rw-r--r--src/statemachine/doc/snippets/statemachine/main3.cpp24
-rw-r--r--src/statemachine/doc/snippets/statemachine/main4.cpp75
-rw-r--r--src/statemachine/doc/snippets/statemachine/main5.cpp136
-rw-r--r--src/statemachine/doc/src/images/moveblocks-example.pngbin0 -> 4532 bytes
-rw-r--r--src/statemachine/doc/src/images/rogue-example.pngbin0 -> 10364 bytes
-rw-r--r--src/statemachine/doc/src/images/trafficlight-example.pngbin0 -> 5325 bytes
-rw-r--r--src/statemachine/gui/qbasickeyeventtransition.cpp175
-rw-r--r--src/statemachine/gui/qbasickeyeventtransition_p.h60
-rw-r--r--src/statemachine/gui/qbasicmouseeventtransition.cpp182
-rw-r--r--src/statemachine/gui/qbasicmouseeventtransition_p.h63
-rw-r--r--src/statemachine/gui/qkeyeventtransition.cpp151
-rw-r--r--src/statemachine/gui/qkeyeventtransition.h45
-rw-r--r--src/statemachine/gui/qmouseeventtransition.cpp180
-rw-r--r--src/statemachine/gui/qmouseeventtransition.h49
-rw-r--r--src/statemachine/qabstractstate.cpp203
-rw-r--r--src/statemachine/qabstractstate.h54
-rw-r--r--src/statemachine/qabstractstate_p.h70
-rw-r--r--src/statemachine/qabstracttransition.cpp400
-rw-r--r--src/statemachine/qabstracttransition.h84
-rw-r--r--src/statemachine/qabstracttransition_p.h62
-rw-r--r--src/statemachine/qeventtransition.cpp230
-rw-r--r--src/statemachine/qeventtransition.h53
-rw-r--r--src/statemachine/qeventtransition_p.h57
-rw-r--r--src/statemachine/qfinalstate.cpp105
-rw-r--r--src/statemachine/qfinalstate.h37
-rw-r--r--src/statemachine/qfinalstate_p.h36
-rw-r--r--src/statemachine/qhistorystate.cpp310
-rw-r--r--src/statemachine/qhistorystate.h64
-rw-r--r--src/statemachine/qhistorystate_p.h60
-rw-r--r--src/statemachine/qsignaleventgenerator_p.h44
-rw-r--r--src/statemachine/qsignaltransition.cpp266
-rw-r--r--src/statemachine/qsignaltransition.h67
-rw-r--r--src/statemachine/qsignaltransition_p.h60
-rw-r--r--src/statemachine/qstate.cpp574
-rw-r--r--src/statemachine/qstate.h105
-rw-r--r--src/statemachine/qstate_p.h110
-rw-r--r--src/statemachine/qstatemachine.cpp3188
-rw-r--r--src/statemachine/qstatemachine.h168
-rw-r--r--src/statemachine/qstatemachine_p.h305
-rw-r--r--src/statemachine/qstatemachineglobal.h16
-rw-r--r--src/statemachine/qt_cmdline.cmake0
-rw-r--r--src/statemachineqml/CMakeLists.txt30
-rw-r--r--src/statemachineqml/childrenprivate_p.h164
-rw-r--r--src/statemachineqml/finalstate.cpp68
-rw-r--r--src/statemachineqml/finalstate_p.h59
-rw-r--r--src/statemachineqml/qstatemachineqmlglobals_p.h27
-rw-r--r--src/statemachineqml/signaltransition.cpp346
-rw-r--r--src/statemachineqml/signaltransition_p.h101
-rw-r--r--src/statemachineqml/state.cpp221
-rw-r--r--src/statemachineqml/state_p.h63
-rw-r--r--src/statemachineqml/statemachine.cpp214
-rw-r--r--src/statemachineqml/statemachine_p.h78
-rw-r--r--src/statemachineqml/statemachineforeign_p.h61
-rw-r--r--src/statemachineqml/timeouttransition.cpp80
-rw-r--r--src/statemachineqml/timeouttransition_p.h53
187 files changed, 13614 insertions, 3703 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..5fbfbd9
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+add_subdirectory(scxml)
+add_subdirectory(statemachine)
+if(TARGET Qt::Qml)
+ add_subdirectory(statemachineqml)
+ add_subdirectory(scxmlqml)
+endif()
+add_subdirectory(plugins)
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
deleted file mode 100644
index 60a0bd2..0000000
--- a/src/imports/imports.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-TEMPLATE = subdirs
-SUBDIRS = scxmlstatemachine
-
diff --git a/src/imports/scxmlstatemachine/eventconnection.cpp b/src/imports/scxmlstatemachine/eventconnection.cpp
deleted file mode 100644
index 2a073bd..0000000
--- a/src/imports/scxmlstatemachine/eventconnection.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "eventconnection_p.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \qmltype EventConnection
- \instantiates QScxmlEventConnection
- \inqmlmodule QtScxml
- \since QtScxml 5.8
-
- \brief Connects to events sent out by state machines.
-
- To receive a notification when a state machine sends out an event, a
- connection can be created to the corresponding signal.
-*/
-
-/*!
- \qmlproperty stringlist EventConnection::events
-
- The list of SCXML event specifiers that describe the events to listen for.
-
- Even though spaces are allowed in event specifications in SCXML documents,
- they are not allowed in this list. However, the list can contain multiple
- specifiers, to the same effect.
-*/
-
-/*!
- \qmlproperty ScxmlStateMachine EventConnection::stateMachine
-
- The state machine that sends out the event.
-*/
-
-/*!
- \qmlsignal EventConnection::occurred(event)
-
- This signal is emitted when the event \a event occurrs.
-
- The corresponding signal handler is \c onOccurred.
-
- \sa QScxmlEvent
-*/
-
-
-QScxmlEventConnection::QScxmlEventConnection(QObject *parent) :
- QObject(parent), m_stateMachine(nullptr)
-{
-}
-
-QStringList QScxmlEventConnection::events() const
-{
- return m_events;
-}
-
-void QScxmlEventConnection::setEvents(const QStringList &events)
-{
- if (events != m_events) {
- m_events = events;
- doConnect();
- emit eventsChanged();
- }
-}
-
-QScxmlStateMachine *QScxmlEventConnection::stateMachine() const
-{
- return m_stateMachine;
-}
-
-void QScxmlEventConnection::setStateMachine(QScxmlStateMachine *stateMachine)
-{
- if (stateMachine != m_stateMachine) {
- m_stateMachine = stateMachine;
- doConnect();
- emit stateMachineChanged();
- }
-}
-
-void QScxmlEventConnection::doConnect()
-{
- for (const QMetaObject::Connection &connection : qAsConst(m_connections))
- disconnect(connection);
- m_connections.clear();
- if (m_stateMachine) {
- for (const QString &event : qAsConst(m_events)) {
- m_connections.append(m_stateMachine->connectToEvent(event, this,
- &QScxmlEventConnection::occurred));
- }
-
- }
-
-}
-
-void QScxmlEventConnection::classBegin()
-{
-}
-
-void QScxmlEventConnection::componentComplete()
-{
- if (!m_stateMachine) {
- if ((m_stateMachine = qobject_cast<QScxmlStateMachine *>(parent())))
- doConnect();
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/imports/scxmlstatemachine/eventconnection_p.h b/src/imports/scxmlstatemachine/eventconnection_p.h
deleted file mode 100644
index 5fea645..0000000
--- a/src/imports/scxmlstatemachine/eventconnection_p.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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$
-**
-****************************************************************************/
-
-#ifndef EVENTCONNECTION_P_H
-#define EVENTCONNECTION_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtScxml/qscxmlstatemachine.h>
-#include <QtCore/qobject.h>
-#include <QtQml/qqmlparserstatus.h>
-
-QT_BEGIN_NAMESPACE
-
-class QScxmlEventConnection : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(QStringList events READ events WRITE setEvents NOTIFY eventsChanged)
- Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine WRITE setStateMachine
- NOTIFY stateMachineChanged)
- Q_INTERFACES(QQmlParserStatus)
-
-public:
- QScxmlEventConnection(QObject *parent = nullptr);
-
- QStringList events() const;
- void setEvents(const QStringList &events);
-
- QScxmlStateMachine *stateMachine() const;
- void setStateMachine(QScxmlStateMachine *stateMachine);
-
-Q_SIGNALS:
- void eventsChanged();
- void stateMachineChanged();
-
- void occurred(const QScxmlEvent &event);
-
-private:
- QScxmlStateMachine *m_stateMachine;
- QStringList m_events;
-
- QList<QMetaObject::Connection> m_connections;
-
- void doConnect();
- void classBegin() override;
- void componentComplete() override;
-};
-
-QT_END_NAMESPACE
-
-#endif // EVENTCONNECTION_P_H
diff --git a/src/imports/scxmlstatemachine/invokedservices.cpp b/src/imports/scxmlstatemachine/invokedservices.cpp
deleted file mode 100644
index 6011557..0000000
--- a/src/imports/scxmlstatemachine/invokedservices.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "invokedservices_p.h"
-#include <QtScxml/qscxmlinvokableservice.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \qmltype InvokedServices
- \instantiates QScxmlInvokedServices
- \inqmlmodule QtScxml
- \since QtScxml 5.8
-
- \brief Provices access to the services invoked by state machines.
-
- Makes the invoked services easily accessible by their names, without
- constantly iterating through QScxmlStateMachine::invokedServices.
-
- The services are called from state machines via the mechanism described in
- \l{SCXML Specification - 6.4 <invoke>}.
-*/
-
-QScxmlInvokedServices::QScxmlInvokedServices(QObject *parent) : QObject(parent)
-{
-}
-
-/*!
- \qmlproperty var InvokedServices::children
-
- The services invoked by the state machine.
-*/
-
-QVariantMap QScxmlInvokedServices::children()
-{
- QVariantMap ret;
- if (m_stateMachine) {
- const QVector<QScxmlInvokableService *> children = m_stateMachine->invokedServices();
- for (QScxmlInvokableService *service : children)
- ret.insertMulti(service->name(), QVariant::fromValue(service));
- }
- return ret;
-}
-
-void QScxmlInvokedServices::classBegin()
-{
-}
-
-/*!
- \qmlproperty ScxmlStateMachine InvokedServices::stateMachine
-
- The state machine that invoked the services.
-*/
-
-QScxmlStateMachine *QScxmlInvokedServices::stateMachine() const
-{
- return m_stateMachine;
-}
-
-void QScxmlInvokedServices::setStateMachine(QScxmlStateMachine *stateMachine)
-{
- if (stateMachine != m_stateMachine) {
- if (m_stateMachine) {
- disconnect(m_stateMachine, &QScxmlStateMachine::invokedServicesChanged,
- this, &QScxmlInvokedServices::childrenChanged);
- }
- m_stateMachine = stateMachine;
- connect(m_stateMachine, &QScxmlStateMachine::invokedServicesChanged,
- this, &QScxmlInvokedServices::childrenChanged);
- emit stateMachineChanged();
- emit childrenChanged();
- }
-}
-
-/*!
- \qmlproperty list<QtObject> InvokedServices::qmlChildren
-
- A list of additional QtObject types nested in this type.
-*/
-
-QQmlListProperty<QObject> QScxmlInvokedServices::qmlChildren()
-{
- return QQmlListProperty<QObject>(this, m_qmlChildren);
-}
-
-
-void QScxmlInvokedServices::componentComplete()
-{
- if (!m_stateMachine) {
- if ((m_stateMachine = qobject_cast<QScxmlStateMachine *>(parent()))) {
- connect(m_stateMachine, &QScxmlStateMachine::invokedServicesChanged,
- this, &QScxmlInvokedServices::childrenChanged);
- }
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/imports/scxmlstatemachine/invokedservices_p.h b/src/imports/scxmlstatemachine/invokedservices_p.h
deleted file mode 100644
index 5a6dac7..0000000
--- a/src/imports/scxmlstatemachine/invokedservices_p.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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$
-**
-****************************************************************************/
-
-#ifndef INVOKEDSERVICES_P_H
-#define INVOKEDSERVICES_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtQml/qqmlparserstatus.h>
-#include <QtQml/qqmllist.h>
-#include <QtScxml/qscxmlstatemachine.h>
-
-QT_BEGIN_NAMESPACE
-
-class QScxmlInvokedServices : public QObject, public QQmlParserStatus
-{
- Q_OBJECT
- Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine WRITE setStateMachine
- NOTIFY stateMachineChanged)
- Q_PROPERTY(QVariantMap children READ children NOTIFY childrenChanged)
- Q_PROPERTY(QQmlListProperty<QObject> qmlChildren READ qmlChildren)
- Q_INTERFACES(QQmlParserStatus)
- Q_CLASSINFO("DefaultProperty", "qmlChildren")
-public:
- QScxmlInvokedServices(QObject *parent = nullptr);
- QVariantMap children();
-
- QScxmlStateMachine *stateMachine() const;
- void setStateMachine(QScxmlStateMachine *stateMachine);
-
- QQmlListProperty<QObject> qmlChildren();
-
-Q_SIGNALS:
- void childrenChanged();
- void stateMachineChanged();
-
-private:
- void classBegin() override;
- void componentComplete() override;
-
- QScxmlStateMachine *m_stateMachine = nullptr;
- QList<QObject *> m_qmlChildren;
-};
-
-QT_END_NAMESPACE
-
-#endif // INVOKEDSERVICES_P_H
diff --git a/src/imports/scxmlstatemachine/plugin.cpp b/src/imports/scxmlstatemachine/plugin.cpp
deleted file mode 100644
index 1d6c8a1..0000000
--- a/src/imports/scxmlstatemachine/plugin.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "statemachineloader_p.h"
-#include "eventconnection_p.h"
-#include "qscxmlevent.h"
-#include "statemachineextended_p.h"
-#include "invokedservices_p.h"
-
-#include <qqmlextensionplugin.h>
-#include <qqml.h>
-
-QT_BEGIN_NAMESPACE
-
-class QScxmlStateMachinePlugin : public QQmlExtensionPlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
-
-public:
- QScxmlStateMachinePlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { }
- void registerTypes(const char *uri)
- {
- // @uri QtScxml
- Q_ASSERT(uri == QStringLiteral("QtScxml"));
-
- int major = 5;
- int minor = 8;
- // Do not rely on RegisterMethodArgumentMetaType meta-call to register the QScxmlEvent type.
- // This registration is required for the receiving end of the signal emission that carries
- // parameters of this type to be able to treat them correctly as a gadget. This is because the
- // receiving end of the signal is a generic method in the QML engine, at which point it's too late
- // to do a meta-type registration.
- static const int qScxmlEventMetaTypeId = qMetaTypeId<QScxmlEvent>();
- Q_UNUSED(qScxmlEventMetaTypeId)
- qmlRegisterType<QScxmlStateMachineLoader>(uri, major, minor, "StateMachineLoader");
- qmlRegisterType<QScxmlEventConnection>(uri, major, minor, "EventConnection");
- qmlRegisterType<QScxmlInvokedServices>(uri, major, minor, "InvokedServices");
- qmlRegisterExtendedUncreatableType<QScxmlStateMachine, QScxmlStateMachineExtended>(
- uri, major, minor, "StateMachine", "Only created through derived types");
-
- // The minor version used to be the current Qt 5 minor. For compatibility it is the last
- // Qt 5 release.
- qmlRegisterModule(uri, major, 15);
-
- qmlProtectModule(uri, 1);
- }
-};
-
-QT_END_NAMESPACE
-
-#include "plugin.moc"
diff --git a/src/imports/scxmlstatemachine/plugins.qmltypes b/src/imports/scxmlstatemachine/plugins.qmltypes
deleted file mode 100644
index 1b6c469..0000000
--- a/src/imports/scxmlstatemachine/plugins.qmltypes
+++ /dev/null
@@ -1,140 +0,0 @@
-import QtQuick.tooling 1.2
-
-// This file describes the plugin-supplied types contained in the library.
-// It is used for QML tooling purposes only.
-//
-// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtScxml 5.14'
-
-Module {
- dependencies: ["QtQuick 2.0"]
- Component {
- name: "QScxmlEventConnection"
- prototype: "QObject"
- exports: ["QtScxml/EventConnection 5.8"]
- exportMetaObjectRevisions: [0]
- Property { name: "events"; type: "QStringList" }
- Property { name: "stateMachine"; type: "QScxmlStateMachine"; isPointer: true }
- Signal {
- name: "occurred"
- Parameter { name: "event"; type: "QScxmlEvent" }
- }
- }
- Component {
- name: "QScxmlInvokedServices"
- defaultProperty: "qmlChildren"
- prototype: "QObject"
- exports: ["QtScxml/InvokedServices 5.8"]
- exportMetaObjectRevisions: [0]
- Property { name: "stateMachine"; type: "QScxmlStateMachine"; isPointer: true }
- Property { name: "children"; type: "QVariantMap"; isReadonly: true }
- Property { name: "qmlChildren"; type: "QObject"; isList: true; isReadonly: true }
- }
- Component {
- name: "QScxmlStateMachine"
- defaultProperty: "children"
- prototype: "QObject"
- exports: ["QtScxml/StateMachine 5.8"]
- isCreatable: false
- exportMetaObjectRevisions: [508]
- Property { name: "running"; type: "bool" }
- Property { name: "initialized"; type: "bool"; isReadonly: true }
- Property { name: "dataModel"; type: "QScxmlDataModel"; isPointer: true }
- Property { name: "initialValues"; type: "QVariantMap" }
- Property { name: "invokedServices"; type: "QVector<QScxmlInvokableService*>"; isReadonly: true }
- Property { name: "sessionId"; type: "string"; isReadonly: true }
- Property { name: "name"; type: "string"; isReadonly: true }
- Property { name: "invoked"; type: "bool"; isReadonly: true }
- Property { name: "parseErrors"; type: "QVector<QScxmlError>"; isReadonly: true }
- Property { name: "loader"; type: "QScxmlCompiler::Loader"; isPointer: true }
- Property { name: "tableData"; type: "QScxmlTableData"; isPointer: true }
- Signal {
- name: "runningChanged"
- Parameter { name: "running"; type: "bool" }
- }
- Signal {
- name: "invokedServicesChanged"
- Parameter { name: "invokedServices"; type: "QVector<QScxmlInvokableService*>" }
- }
- Signal {
- name: "log"
- Parameter { name: "label"; type: "string" }
- Parameter { name: "msg"; type: "string" }
- }
- Signal { name: "reachedStableState" }
- Signal { name: "finished" }
- Signal {
- name: "dataModelChanged"
- Parameter { name: "model"; type: "QScxmlDataModel"; isPointer: true }
- }
- Signal {
- name: "initialValuesChanged"
- Parameter { name: "initialValues"; type: "QVariantMap" }
- }
- Signal {
- name: "initializedChanged"
- Parameter { name: "initialized"; type: "bool" }
- }
- Signal {
- name: "loaderChanged"
- Parameter { name: "loader"; type: "QScxmlCompiler::Loader"; isPointer: true }
- }
- Signal {
- name: "tableDataChanged"
- Parameter { name: "tableData"; type: "QScxmlTableData"; isPointer: true }
- }
- Method { name: "start" }
- Method { name: "stop" }
- Method { name: "init"; type: "bool" }
- Method {
- name: "stateNames"
- type: "QStringList"
- Parameter { name: "compress"; type: "bool" }
- }
- Method { name: "stateNames"; type: "QStringList" }
- Method {
- name: "activeStateNames"
- type: "QStringList"
- Parameter { name: "compress"; type: "bool" }
- }
- Method { name: "activeStateNames"; type: "QStringList" }
- Method {
- name: "isActive"
- type: "bool"
- Parameter { name: "scxmlStateName"; type: "string" }
- }
- Method {
- name: "submitEvent"
- Parameter { name: "event"; type: "QScxmlEvent"; isPointer: true }
- }
- Method {
- name: "submitEvent"
- Parameter { name: "eventName"; type: "string" }
- }
- Method {
- name: "submitEvent"
- Parameter { name: "eventName"; type: "string" }
- Parameter { name: "data"; type: "QVariant" }
- }
- Method {
- name: "cancelDelayedEvent"
- Parameter { name: "sendId"; type: "string" }
- }
- Method {
- name: "isDispatchableTarget"
- type: "bool"
- Parameter { name: "target"; type: "string" }
- }
- Property { name: "children"; revision: 508; type: "QObject"; isList: true; isReadonly: true }
- }
- Component {
- name: "QScxmlStateMachineLoader"
- prototype: "QObject"
- exports: ["QtScxml/StateMachineLoader 5.8"]
- exportMetaObjectRevisions: [0]
- Property { name: "source"; type: "QUrl" }
- Property { name: "stateMachine"; type: "QScxmlStateMachine"; isReadonly: true; isPointer: true }
- Property { name: "initialValues"; type: "QVariantMap" }
- Property { name: "dataModel"; type: "QScxmlDataModel"; isPointer: true }
- }
-}
diff --git a/src/imports/scxmlstatemachine/qmldir b/src/imports/scxmlstatemachine/qmldir
deleted file mode 100644
index e836ddd..0000000
--- a/src/imports/scxmlstatemachine/qmldir
+++ /dev/null
@@ -1,5 +0,0 @@
-module QtScxml
-plugin declarative_scxml
-classname QScxmlStateMachinePlugin
-typeinfo plugins.qmltypes
-
diff --git a/src/imports/scxmlstatemachine/scxmlstatemachine.pro b/src/imports/scxmlstatemachine/scxmlstatemachine.pro
deleted file mode 100644
index 9bc7c72..0000000
--- a/src/imports/scxmlstatemachine/scxmlstatemachine.pro
+++ /dev/null
@@ -1,23 +0,0 @@
-TARGET = scxml
-TARGETPATH = QtScxml
-IMPORT_VERSION = 5.$$QT_MINOR_VERSION
-
-QT = scxml qml-private core-private
-
-SOURCES = \
- $$PWD/plugin.cpp \
- $$PWD/statemachineloader.cpp \
- $$PWD/eventconnection.cpp \
- $$PWD/statemachineextended.cpp \
- $$PWD/invokedservices.cpp
-
-HEADERS = \
- $$PWD/eventconnection_p.h \
- $$PWD/invokedservices_p.h \
- $$PWD/statemachineextended_p.h \
- $$PWD/statemachineloader_p.h
-
-
-load(qml_plugin)
-
-OTHER_FILES += plugins.qmltypes qmldir
diff --git a/src/imports/scxmlstatemachine/statemachineextended.cpp b/src/imports/scxmlstatemachine/statemachineextended.cpp
deleted file mode 100644
index 6b1b13b..0000000
--- a/src/imports/scxmlstatemachine/statemachineextended.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "statemachineextended_p.h"
-
-#include <QtScxml/qscxmlglobals.h>
-#include <QtScxml/qscxmlstatemachine.h>
-
-QT_BEGIN_NAMESPACE
-
-QScxmlStateMachineExtended::QScxmlStateMachineExtended(QObject *extendee) :
- QObject(extendee)
-{
-}
-
-QQmlListProperty<QObject> QScxmlStateMachineExtended::children()
-{
- return QQmlListProperty<QObject>(this, m_children);
-}
-
-QT_END_NAMESPACE
diff --git a/src/imports/scxmlstatemachine/statemachineextended_p.h b/src/imports/scxmlstatemachine/statemachineextended_p.h
deleted file mode 100644
index ab069b1..0000000
--- a/src/imports/scxmlstatemachine/statemachineextended_p.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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$
-**
-****************************************************************************/
-
-#ifndef STATEMACHINEEXTENDED_P_H
-#define STATEMACHINEEXTENDED_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtScxml/qscxmlglobals.h>
-#include <QtCore/qobject.h>
-#include <QtQml/qqmllist.h>
-
-QT_BEGIN_NAMESPACE
-
-/* Allow State Machines created from QML to have children. */
-class QScxmlStateMachineExtended : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QQmlListProperty<QObject> children READ children)
- Q_CLASSINFO("DefaultProperty", "children")
-public:
- QScxmlStateMachineExtended(QObject *extendee);
- QQmlListProperty<QObject> children();
-
-private:
- QObjectList m_children;
-};
-
-QT_END_NAMESPACE
-
-#endif // STATEMACHINEEXTENDED_P_H
diff --git a/src/imports/scxmlstatemachine/statemachineloader.cpp b/src/imports/scxmlstatemachine/statemachineloader.cpp
deleted file mode 100644
index 1d312a5..0000000
--- a/src/imports/scxmlstatemachine/statemachineloader.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "statemachineloader_p.h"
-
-#include <QtScxml/qscxmlstatemachine.h>
-#include <qqmlcontext.h>
-#include <qqmlengine.h>
-#include <qqmlinfo.h>
-#include <qqmlfile.h>
-#include <qbuffer.h>
-
-/*!
- \qmltype StateMachineLoader
- \instantiates QScxmlStateMachineLoader
- \inqmlmodule QtScxml
-
- \brief Dynamically loads an SCXML document and instantiates the state machine.
-
- \since QtScxml 5.7
- */
-
-QScxmlStateMachineLoader::QScxmlStateMachineLoader(QObject *parent)
- : QObject(parent)
- , m_dataModel(nullptr)
- , m_implicitDataModel(nullptr)
- , m_stateMachine(nullptr)
-{
-}
-
-/*!
- \qmlproperty ScxmlStateMachine StateMachineLoader::stateMachine
-
- The state machine instance.
- */
-QT_PREPEND_NAMESPACE(QScxmlStateMachine) *QScxmlStateMachineLoader::stateMachine() const
-{
- return m_stateMachine;
-}
-
-/*!
- \qmlproperty url StateMachineLoader::source
-
- The URL of the SCXML document to load. Only synchronously accessible URLs
- are supported.
- */
-QUrl QScxmlStateMachineLoader::source()
-{
- return m_source;
-}
-
-void QScxmlStateMachineLoader::setSource(const QUrl &source)
-{
- if (!source.isValid())
- return;
-
- QUrl oldSource = m_source;
- if (m_stateMachine) {
- delete m_stateMachine;
- m_stateMachine = nullptr;
- m_implicitDataModel = nullptr;
- }
-
- if (parse(source)) {
- m_source = source;
- emit sourceChanged();
- } else {
- m_source.clear();
- if (!oldSource.isEmpty()) {
- emit sourceChanged();
- }
- }
-}
-
-QVariantMap QScxmlStateMachineLoader::initialValues() const
-{
- return m_initialValues;
-}
-
-void QScxmlStateMachineLoader::setInitialValues(const QVariantMap &initialValues)
-{
- if (initialValues != m_initialValues) {
- m_initialValues = initialValues;
- if (m_stateMachine)
- m_stateMachine->setInitialValues(initialValues);
- emit initialValuesChanged();
- }
-}
-
-QScxmlDataModel *QScxmlStateMachineLoader::dataModel() const
-{
- return m_dataModel;
-}
-
-void QScxmlStateMachineLoader::setDataModel(QScxmlDataModel *dataModel)
-{
- if (dataModel != m_dataModel) {
- m_dataModel = dataModel;
- if (m_stateMachine) {
- if (dataModel)
- m_stateMachine->setDataModel(dataModel);
- else
- m_stateMachine->setDataModel(m_implicitDataModel);
- }
- emit dataModelChanged();
- }
-}
-
-bool QScxmlStateMachineLoader::parse(const QUrl &source)
-{
- if (!QQmlFile::isSynchronous(source)) {
- qmlWarning(this) << QStringLiteral("Cannot open '%1' for reading: only synchronous access is supported.")
- .arg(source.url());
- return false;
- }
- QQmlFile scxmlFile(QQmlEngine::contextForObject(this)->engine(), source);
- if (scxmlFile.isError()) {
- // the synchronous case can only fail when the file is not found (or not readable).
- qmlWarning(this) << QStringLiteral("Cannot open '%1' for reading.").arg(source.url());
- return false;
- }
-
- QByteArray data(scxmlFile.dataByteArray());
- QBuffer buf(&data);
- if (!buf.open(QIODevice::ReadOnly)) {
- qmlWarning(this) << QStringLiteral("Cannot open input buffer for reading");
- return false;
- }
-
- QString fileName;
- if (source.isLocalFile()) {
- fileName = source.toLocalFile();
- } else if (source.scheme() == QStringLiteral("qrc")) {
- fileName = ":" + source.path();
- } else {
- qmlWarning(this) << QStringLiteral("%1 is neither a local nor a resource URL.")
- .arg(source.url())
- << QStringLiteral("Invoking services by relative path will not work.");
- }
-
- m_stateMachine = QScxmlStateMachine::fromData(&buf, fileName);
- m_stateMachine->setParent(this);
- m_implicitDataModel = m_stateMachine->dataModel();
-
- if (m_stateMachine->parseErrors().isEmpty()) {
- if (m_dataModel)
- m_stateMachine->setDataModel(m_dataModel);
- m_stateMachine->setInitialValues(m_initialValues);
- emit stateMachineChanged();
-
- // as this is deferred any pending property updates to m_dataModel and m_initialValues
- // should still occur before start().
- QMetaObject::invokeMethod(m_stateMachine, "start", Qt::QueuedConnection);
- return true;
- } else {
- qmlWarning(this) << QStringLiteral("Something went wrong while parsing '%1':")
- .arg(source.url())
- << Qt::endl;
- const auto errors = m_stateMachine->parseErrors();
- for (const QScxmlError &error : errors) {
- qmlWarning(this) << error.toString();
- }
-
- emit stateMachineChanged();
- return false;
- }
-}
diff --git a/src/imports/scxmlstatemachine/statemachineloader_p.h b/src/imports/scxmlstatemachine/statemachineloader_p.h
deleted file mode 100644
index 88ed445..0000000
--- a/src/imports/scxmlstatemachine/statemachineloader_p.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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$
-**
-****************************************************************************/
-
-#ifndef STATEMACHINELOADER_P_H
-#define STATEMACHINELOADER_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qurl.h>
-#include <QtScxml/qscxmlstatemachine.h>
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QScxmlStateMachineLoader: public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
- Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine DESIGNABLE false NOTIFY stateMachineChanged)
- Q_PROPERTY(QVariantMap initialValues READ initialValues WRITE setInitialValues NOTIFY initialValuesChanged)
- Q_PROPERTY(QScxmlDataModel *dataModel READ dataModel WRITE setDataModel NOTIFY dataModelChanged)
-
-
-public:
- explicit QScxmlStateMachineLoader(QObject *parent = nullptr);
-
- QScxmlStateMachine *stateMachine() const;
-
- QUrl source();
- void setSource(const QUrl &source);
-
- QVariantMap initialValues() const;
- void setInitialValues(const QVariantMap &initialValues);
-
- QScxmlDataModel *dataModel() const;
- void setDataModel(QScxmlDataModel *dataModel);
-
-Q_SIGNALS:
- void sourceChanged();
- void initialValuesChanged();
- void stateMachineChanged();
- void dataModelChanged();
-
-private:
- bool parse(const QUrl &source);
-
-private:
- QUrl m_source;
- QVariantMap m_initialValues;
- QScxmlDataModel *m_dataModel;
- QScxmlDataModel *m_implicitDataModel;
- QScxmlStateMachine *m_stateMachine;
-};
-
-QT_END_NAMESPACE
-
-#endif // STATEMACHINELOADER_P_H
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
new file mode 100644
index 0000000..71256c5
--- /dev/null
+++ b/src/plugins/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(QT_FEATURE_scxml_ecmascriptdatamodel)
+ add_subdirectory(ecmascriptdatamodel)
+endif()
diff --git a/src/plugins/ecmascriptdatamodel/CMakeLists.txt b/src/plugins/ecmascriptdatamodel/CMakeLists.txt
new file mode 100644
index 0000000..7babe22
--- /dev/null
+++ b/src/plugins/ecmascriptdatamodel/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## EcmaScript SCXML DataModel Plugin:
+#####################################################################
+
+qt_internal_include_in_repo_target_set(qtscxmlqml)
+
+qt_internal_add_plugin(QScxmlEcmaScriptDataModelPlugin
+ OUTPUT_NAME qscxmlecmascriptdatamodel
+ PLUGIN_TYPE scxmldatamodel
+ SOURCES
+ qscxmlecmascriptdatamodelplugin.cpp qscxmlecmascriptdatamodelplugin_p.h
+ qscxmlecmascriptdatamodel_p.h qscxmlecmascriptdatamodel.cpp
+ qscxmlecmascriptplatformproperties.cpp qscxmlecmascriptplatformproperties_p.h
+ LIBRARIES
+ Qt::Core
+ Qt::Scxml
+ Qt::Qml
+ INCLUDE_DIRECTORIES
+ $<TARGET_PROPERTY:Qt::QmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:Qt::Scxml,INTERFACE_INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:Qt::ScxmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
+)
+
+# OTHER_FILES = "ecmascriptdatamodel_plugin.json"
diff --git a/src/plugins/ecmascriptdatamodel/ecmascriptdatamodelplugin.json b/src/plugins/ecmascriptdatamodel/ecmascriptdatamodelplugin.json
new file mode 100644
index 0000000..09b76e2
--- /dev/null
+++ b/src/plugins/ecmascriptdatamodel/ecmascriptdatamodelplugin.json
@@ -0,0 +1,3 @@
+{
+ "Keys": ["ecmascriptdatamodel"]
+}
diff --git a/src/scxml/qscxmlecmascriptdatamodel.cpp b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodel.cpp
index da4fe84..031d6be 100644
--- a/src/scxml/qscxmlecmascriptdatamodel.cpp
+++ b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodel.cpp
@@ -1,48 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlglobals_p.h"
-#include "qscxmlecmascriptdatamodel.h"
+// 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 <QtScxml/private/qscxmlglobals_p.h>
+#include "qscxmlecmascriptdatamodel_p.h"
#include "qscxmlecmascriptplatformproperties_p.h"
-#include "qscxmlexecutablecontent_p.h"
-#include "qscxmlstatemachine_p.h"
-#include "qscxmldatamodel_p.h"
+#include <QtScxml/private/qscxmlexecutablecontent_p.h>
+#include <QtScxml/private/qscxmlstatemachine_p.h>
+#include <QtScxml/private/qscxmldatamodel_p.h>
#include <qjsengine.h>
#include <qjsondocument.h>
@@ -53,6 +17,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(qscxmlEsLog, "qt.scxml.statemachine")
+
using namespace QScxmlExecutableContent;
typedef std::function<QString (bool *)> ToStringEvaluator;
@@ -121,7 +87,7 @@ public:
QJSEngine *engine = assertEngine();
dataModel = engine->globalObject();
- qCDebug(qscxmlLog) << m_stateMachine << "initializing the datamodel";
+ qCDebug(qscxmlEsLog) << m_stateMachine << "initializing the datamodel";
setupSystemVariables();
}
@@ -192,7 +158,7 @@ public:
return data;
}
- if (eventData == QVariant(QMetaType::VoidStar, 0)) {
+ if (eventData == QVariant(QMetaType(QMetaType::VoidStar), nullptr)) {
return QJSValue(QJSValue::NullValue);
}
@@ -268,17 +234,17 @@ public:
private: // Uses private API
static void setReadonlyProperty(QJSValue *object, const QString &name, const QJSValue &value)
{
- qCDebug(qscxmlLog) << "setting read-only property" << name;
+ qCDebug(qscxmlEsLog) << "setting read-only property" << name;
QV4::ExecutionEngine *engine = QJSValuePrivate::engine(object);
Q_ASSERT(engine);
QV4::Scope scope(engine);
- QV4::ScopedObject o(scope, QJSValuePrivate::getValue(object));
+ QV4::ScopedObject o(scope, QJSValuePrivate::asManagedType<QV4::Object>(object));
if (!o)
return;
if (!QJSValuePrivate::checkEngine(engine, value)) {
- qCWarning(qscxmlLog, "EcmaScriptDataModel::setReadonlyProperty(%s) failed: cannot set value created in a different engine", name.toUtf8().constData());
+ qCWarning(qscxmlEsLog, "EcmaScriptDataModel::setReadonlyProperty(%s) failed: cannot set value created in a different engine", name.toUtf8().constData());
return;
}
@@ -289,7 +255,7 @@ private: // Uses private API
return;
}
- QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value));
+ QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(engine, value));
o->defineReadonlyProperty(s, v);
if (engine->hasException)
engine->catchException();
@@ -310,7 +276,7 @@ private: // Uses private API
return SetPropertyFailedForAnotherReason;
QV4::Scope scope(engine);
- QV4::ScopedObject o(scope, QJSValuePrivate::getValue(object));
+ QV4::ScopedObject o(scope, QJSValuePrivate::asManagedType<QV4::Object>(object));
if (o == nullptr) {
return SetPropertyFailedForAnotherReason;
}
@@ -324,7 +290,7 @@ private: // Uses private API
QV4::PropertyAttributes attrs = o->getOwnProperty(s->toPropertyKey());
if (attrs.isWritable() || attrs.isEmpty()) {
- QV4::ScopedValue v(scope, QJSValuePrivate::convertedToValue(engine, value));
+ QV4::ScopedValue v(scope, QJSValuePrivate::convertToReturnedValue(engine, value));
o->insertMember(s, v);
if (engine->hasException) {
engine->catchException();
@@ -342,30 +308,24 @@ private:
QJSValue dataModel;
};
-/*!
- * \class QScxmlEcmaScriptDataModel
- * \brief The QScxmlEcmaScriptDataModel class is the ECMAScript data model for
+/*
+ * The QScxmlEcmaScriptDataModel class is the ECMAScript data model for
* a Qt SCXML state machine.
- * \since 5.7
- * \inmodule QtScxml
*
* This class implements the ECMAScript data model as described in
- * \l {SCXML Specification - B.2 The ECMAScript Data Model}. It can be
+ * "SCXML Specification - B.2 The ECMAScript Data Model". It can be
* subclassed to perform custom initialization.
*
- * \sa QScxmlStateMachine QScxmlDataModel
+ * See also QScxmlStateMachine QScxmlDataModel
*/
-/*!
- * Creates a new ECMAScript data model, with the parent object \a parent.
+/*
+ * Creates a new ECMAScript data model, with the parent object parent.
*/
QScxmlEcmaScriptDataModel::QScxmlEcmaScriptDataModel(QObject *parent)
: QScxmlDataModel(*(new QScxmlEcmaScriptDataModelPrivate), parent)
{}
-/*!
- \reimp
- */
bool QScxmlEcmaScriptDataModel::setup(const QVariantMap &initialDataValues)
{
Q_D(QScxmlEcmaScriptDataModel);
@@ -392,9 +352,6 @@ bool QScxmlEcmaScriptDataModel::setup(const QVariantMap &initialDataValues)
return ok;
}
-/*!
- \reimp
- */
QString QScxmlEcmaScriptDataModel::evaluateToString(QScxmlExecutableContent::EvaluatorId id,
bool *ok)
{
@@ -404,9 +361,6 @@ QString QScxmlEcmaScriptDataModel::evaluateToString(QScxmlExecutableContent::Eva
return d->evalStr(d->string(info.expr), d->string(info.context), ok);
}
-/*!
- \reimp
- */
bool QScxmlEcmaScriptDataModel::evaluateToBool(QScxmlExecutableContent::EvaluatorId id,
bool *ok)
{
@@ -416,9 +370,6 @@ bool QScxmlEcmaScriptDataModel::evaluateToBool(QScxmlExecutableContent::Evaluato
return d->evalBool(d->string(info.expr), d->string(info.context), ok);
}
-/*!
- \reimp
- */
QVariant QScxmlEcmaScriptDataModel::evaluateToVariant(QScxmlExecutableContent::EvaluatorId id,
bool *ok)
{
@@ -428,9 +379,6 @@ QVariant QScxmlEcmaScriptDataModel::evaluateToVariant(QScxmlExecutableContent::E
return d->evalJSValue(d->string(info.expr), d->string(info.context), ok).toVariant();
}
-/*!
- \reimp
- */
void QScxmlEcmaScriptDataModel::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id,
bool *ok)
{
@@ -440,9 +388,6 @@ void QScxmlEcmaScriptDataModel::evaluateToVoid(QScxmlExecutableContent::Evaluato
d->eval(d->string(info.expr), d->string(info.context), ok);
}
-/*!
- \reimp
- */
void QScxmlEcmaScriptDataModel::evaluateAssignment(QScxmlExecutableContent::EvaluatorId id,
bool *ok)
{
@@ -464,9 +409,6 @@ void QScxmlEcmaScriptDataModel::evaluateAssignment(QScxmlExecutableContent::Eval
}
}
-/*!
- \reimp
- */
void QScxmlEcmaScriptDataModel::evaluateInitialization(QScxmlExecutableContent::EvaluatorId id,
bool *ok)
{
@@ -481,9 +423,6 @@ void QScxmlEcmaScriptDataModel::evaluateInitialization(QScxmlExecutableContent::
evaluateAssignment(id, ok);
}
-/*!
- \reimp
- */
void QScxmlEcmaScriptDataModel::evaluateForeach(QScxmlExecutableContent::EvaluatorId id, bool *ok,
ForeachLoopBody *body)
{
@@ -531,36 +470,24 @@ void QScxmlEcmaScriptDataModel::evaluateForeach(QScxmlExecutableContent::Evaluat
*ok = true;
}
-/*!
- * \reimp
- */
void QScxmlEcmaScriptDataModel::setScxmlEvent(const QScxmlEvent &event)
{
Q_D(QScxmlEcmaScriptDataModel);
d->assignEvent(event);
}
-/*!
- * \reimp
- */
QVariant QScxmlEcmaScriptDataModel::scxmlProperty(const QString &name) const
{
Q_D(const QScxmlEcmaScriptDataModel);
return d->property(name).toVariant();
}
-/*!
- * \reimp
- */
bool QScxmlEcmaScriptDataModel::hasScxmlProperty(const QString &name) const
{
Q_D(const QScxmlEcmaScriptDataModel);
return d->hasProperty(name);
}
-/*!
- * \reimp
- */
bool QScxmlEcmaScriptDataModel::setScxmlProperty(const QString &name, const QVariant &value,
const QString &context)
{
diff --git a/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodel_p.h b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodel_p.h
new file mode 100644
index 0000000..a449ae5
--- /dev/null
+++ b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodel_p.h
@@ -0,0 +1,52 @@
+// 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
+
+#ifndef QSCXMLECMASCRIPTDATAMODEL_P_H
+#define QSCXMLECMASCRIPTDATAMODEL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QObject>
+#include <QtScxml/qscxmlglobals.h>
+#include <QtScxml/qscxmldatamodel.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QScxmlEcmaScriptDataModelPrivate;
+class QScxmlEcmaScriptDataModel: public QScxmlDataModel
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QScxmlEcmaScriptDataModel)
+public:
+ explicit QScxmlEcmaScriptDataModel(QObject *parent = nullptr);
+
+ Q_INVOKABLE bool setup(const QVariantMap &initialDataValues) override;
+
+ QString evaluateToString(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
+ bool evaluateToBool(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
+ QVariant evaluateToVariant(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
+ void evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
+ void evaluateAssignment(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
+ void evaluateInitialization(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
+ void evaluateForeach(QScxmlExecutableContent::EvaluatorId id, bool *ok, ForeachLoopBody *body) override final;
+
+ void setScxmlEvent(const QScxmlEvent &event) override;
+
+ QVariant scxmlProperty(const QString &name) const override;
+ bool hasScxmlProperty(const QString &name) const override;
+ bool setScxmlProperty(const QString &name, const QVariant &value, const QString &context) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSCXMLECMASCRIPTDATAMODEL_P_H
diff --git a/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin.cpp b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin.cpp
new file mode 100644
index 0000000..8f8ec2e
--- /dev/null
+++ b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2021 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 "QtScxml/qscxmldatamodel.h"
+#include "qscxmlecmascriptdatamodel_p.h"
+#include "qscxmlecmascriptdatamodelplugin_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QScxmlDataModel *QScxmlEcmaScriptDataModelPlugin::createScxmlDataModel() const
+{
+ return new QScxmlEcmaScriptDataModel;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin_p.h b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin_p.h
new file mode 100644
index 0000000..da169dd
--- /dev/null
+++ b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptdatamodelplugin_p.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2021 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
+
+#ifndef QSCXMLECMASCRIPTDATAMODELPLUGIN_P_H
+#define QSCXMLECMASCRIPTDATAMODELPLUGIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtScxml/private/qscxmldatamodelplugin_p.h>
+#include <QtCore/QObject>
+
+QT_BEGIN_NAMESPACE
+
+class QScxmlEcmaScriptDataModelPlugin : public QScxmlDataModelPlugin
+{
+ Q_OBJECT
+ Q_INTERFACES(QScxmlDataModelPlugin)
+ Q_PLUGIN_METADATA(IID QScxmlDataModelPluginInterface_iid FILE "ecmascriptdatamodelplugin.json")
+
+public:
+ QScxmlDataModel *createScxmlDataModel() const override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSCXMLECMASCRIPTDATAMODELPLUGIN_P_H
diff --git a/src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties.cpp b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties.cpp
new file mode 100644
index 0000000..03b4986
--- /dev/null
+++ b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties.cpp
@@ -0,0 +1,65 @@
+// 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 "qscxmlecmascriptplatformproperties_p.h"
+#include "qscxmlstatemachine.h"
+
+#include <qjsengine.h>
+
+QT_BEGIN_NAMESPACE
+class QScxmlPlatformProperties::Data
+{
+public:
+ Data()
+ : m_stateMachine(nullptr)
+ {}
+
+ QScxmlStateMachine *m_stateMachine;
+ QJSValue m_jsValue;
+};
+
+QScxmlPlatformProperties::QScxmlPlatformProperties(QObject *parent)
+ : QObject(parent)
+ , data(new Data)
+{}
+
+QScxmlPlatformProperties *QScxmlPlatformProperties::create(QJSEngine *engine, QScxmlStateMachine *stateMachine)
+{
+ QScxmlPlatformProperties *pp = new QScxmlPlatformProperties(engine);
+ pp->data->m_stateMachine = stateMachine;
+ pp->data->m_jsValue = engine->newQObject(pp);
+ return pp;
+}
+
+QScxmlPlatformProperties::~QScxmlPlatformProperties()
+{
+ delete data;
+}
+
+QJSEngine *QScxmlPlatformProperties::engine() const
+{
+ return qobject_cast<QJSEngine *>(parent());
+}
+
+QScxmlStateMachine *QScxmlPlatformProperties::stateMachine() const
+{
+ return data->m_stateMachine;
+}
+
+QJSValue QScxmlPlatformProperties::jsValue() const
+{
+ return data->m_jsValue;
+}
+
+/// _x.marks === "the spot"
+QString QScxmlPlatformProperties::marks() const
+{
+ return QStringLiteral("the spot");
+}
+
+bool QScxmlPlatformProperties::inState(const QString &stateName)
+{
+ return stateMachine()->isActive(stateName);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties_p.h b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties_p.h
new file mode 100644
index 0000000..f30f388
--- /dev/null
+++ b/src/plugins/ecmascriptdatamodel/qscxmlecmascriptplatformproperties_p.h
@@ -0,0 +1,55 @@
+// 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
+
+#ifndef QSCXMLECMASCRIPTPLATFORMPROPERTIES_P_H
+#define QSCXMLECMASCRIPTPLATFORMPROPERTIES_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qscxmlglobals.h"
+
+#include <QtCore/qobject.h>
+
+QT_FORWARD_DECLARE_CLASS(QJSEngine)
+QT_FORWARD_DECLARE_CLASS(QJSValue)
+
+QT_BEGIN_NAMESPACE
+
+class QScxmlStateMachine;
+class QScxmlPlatformProperties: public QObject
+{
+ Q_OBJECT
+
+ QScxmlPlatformProperties(QObject *parent);
+
+ Q_PROPERTY(QString marks READ marks CONSTANT)
+
+public:
+ static QScxmlPlatformProperties *create(QJSEngine *engine, QScxmlStateMachine *stateMachine);
+ ~QScxmlPlatformProperties();
+
+ QJSEngine *engine() const;
+ QScxmlStateMachine *stateMachine() const;
+ QJSValue jsValue() const;
+
+ QString marks() const;
+
+ Q_INVOKABLE bool inState(const QString &stateName);
+
+private:
+ class Data;
+ Data *data;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSCXMLECMASCRIPTPLATFORMPROPERTIES_P_H
diff --git a/src/scxml/CMakeLists.txt b/src/scxml/CMakeLists.txt
new file mode 100644
index 0000000..ee5b743
--- /dev/null
+++ b/src/scxml/CMakeLists.txt
@@ -0,0 +1,56 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+#####################################################################
+## Scxml Module:
+#####################################################################
+
+qt_internal_include_in_repo_target_set(qtscxml)
+
+qt_internal_add_module(Scxml
+ QMAKE_MODULE_CONFIG c++11 qscxmlc
+ PLUGIN_TYPES scxmldatamodel
+ SOURCES
+ qscxmlcompiler.cpp qscxmlcompiler.h qscxmlcompiler_p.h
+ qscxmlcppdatamodel.cpp qscxmlcppdatamodel.h qscxmlcppdatamodel_p.h
+ qscxmldatamodel.cpp qscxmldatamodel.h qscxmldatamodel_p.h
+ qscxmlerror.cpp qscxmlerror.h
+ qscxmlevent.cpp qscxmlevent.h qscxmlevent_p.h
+ qscxmlexecutablecontent.cpp qscxmlexecutablecontent.h qscxmlexecutablecontent_p.h
+ qscxmlglobals.h qscxmlglobals_p.h
+ qscxmlinvokableservice.cpp qscxmlinvokableservice.h qscxmlinvokableservice_p.h
+ qscxmlnulldatamodel.cpp qscxmlnulldatamodel.h
+ qscxmlstatemachine.cpp qscxmlstatemachine.h qscxmlstatemachine_p.h
+ qscxmlstatemachineinfo.cpp qscxmlstatemachineinfo_p.h
+ qscxmltabledata.cpp qscxmltabledata.h qscxmltabledata_p.h
+ qscxmldatamodelplugin_p.h qscxmldatamodelplugin.cpp
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+)
+
+# Install the public qscxlmc.prf file that is used by the qmake
+set(scxml_mkspecs "${CMAKE_CURRENT_SOURCE_DIR}/../../mkspecs/features/qscxmlc.prf")
+set(mkspecs_install_dir "${INSTALL_MKSPECSDIR}")
+qt_path_join(mkspecs_install_dir "${QT_INSTALL_DIR}" "${mkspecs_install_dir}" "features")
+qt_copy_or_install(FILES "${scxml_mkspecs}" DESTINATION ${mkspecs_install_dir})
+
+#### Keys ignored in scope 3:.:.:scxml.pro:NOT force_independent AND ( NOT debug_and_release OR NOT build_all OR CONFIG(release,debug OR release) ):
+# QMAKE_EXTRA_COMPILERS = "prf2build"
+# prf2build.CONFIG = "no_link" "no_clean" "target_predeps"
+# prf2build.commands = "$$QMAKE_COPY" "${QMAKE_FILE_IN}" "${QMAKE_FILE_OUT}"
+# prf2build.input = "FEATURES"
+# prf2build.name = "COPY" "${QMAKE_FILE_IN}"
+# prf2build.output = "$$[QT_INSTALL_DATA/get]/mkspecs/features/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT}"
+qt_internal_add_docs(Scxml
+ doc/qtscxml.qdocconf
+)
+
+include(Qt6ScxmlMacros.cmake)
diff --git a/src/scxml/Qt5ScxmlConfigExtras.cmake.in b/src/scxml/Qt5ScxmlConfigExtras.cmake.in
index edb320a..716c64e 100644
--- a/src/scxml/Qt5ScxmlConfigExtras.cmake.in
+++ b/src/scxml/Qt5ScxmlConfigExtras.cmake.in
@@ -1,40 +1,5 @@
-#
# Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
-# Contact: https://www.qt.io/licensing/
-#
-# This file is part of the QtScxml 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$
-
-if (NOT TARGET Qt5::qscxmlc)
+# SPDX-License-Identifier: BSD-3-Clause
add_executable(Qt5::qscxmlc IMPORTED)
!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE)
@@ -49,3 +14,14 @@ if (NOT TARGET Qt5::qscxmlc)
)
get_target_property(Qt5Scxml_QSCXMLC_EXECUTABLE Qt5::qscxmlc LOCATION)
endif()
+
+# Create versionless tool targets.
+foreach(__qt_tool qscxmlc)
+ if(NOT \"${QT_NO_CREATE_VERSIONLESS_TARGETS}\" AND NOT TARGET Qt::${__qt_tool}
+ AND TARGET Qt5::${__qt_tool})
+ add_executable(Qt::${__qt_tool} IMPORTED)
+ get_target_property(__qt_imported_location Qt5::${__qt_tool} IMPORTED_LOCATION)
+ set_target_properties(Qt::${__qt_tool}
+ PROPERTIES IMPORTED_LOCATION \"${__qt_imported_location}\")
+ endif()
+endforeach()
diff --git a/src/scxml/Qt5ScxmlMacros.cmake b/src/scxml/Qt5ScxmlMacros.cmake
deleted file mode 100644
index c4454ec..0000000
--- a/src/scxml/Qt5ScxmlMacros.cmake
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
-# Contact: https://www.qt.io/licensing/
-#
-# This file is part of the QtScxml 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$
-
-if(NOT Qt5Scxml_QSCXMLC_EXECUTABLE)
- message(FATAL_ERROR "qscxmlc executable not found -- Check installation.")
-endif()
-
-# qt5_add_statecharts(outfiles inputfile ... )
-
-function(qt5_add_statecharts outfiles)
- set(options)
- set(oneValueArgs)
- set(multiValueArgs OPTIONS)
-
- cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
-
- set(scxml_files ${ARGS_UNPARSED_ARGUMENTS})
-
- foreach(it ${scxml_files})
- get_filename_component(outfilename ${it} NAME_WE)
- get_filename_component(infile ${it} ABSOLUTE)
- set(outfile ${CMAKE_CURRENT_BINARY_DIR}/${outfilename})
- set(outfile_cpp ${CMAKE_CURRENT_BINARY_DIR}/${outfilename}.cpp)
- set(outfile_h ${CMAKE_CURRENT_BINARY_DIR}/${outfilename}.h)
-
- add_custom_command(OUTPUT ${outfile_cpp} ${outfile_h}
- COMMAND ${Qt5Scxml_QSCXMLC_EXECUTABLE}
- ARGS ${ARGS_OPTIONS} --output ${outfile} ${infile}
- MAIN_DEPENDENCY ${infile}
- VERBATIM)
- list(APPEND ${outfiles} ${outfile_cpp})
- endforeach()
- set_source_files_properties(${outfiles} PROPERTIES SKIP_AUTOMOC TRUE)
- set(${outfiles} ${${outfiles}} PARENT_SCOPE)
-endfunction()
diff --git a/src/scxml/Qt6ScxmlMacros.cmake b/src/scxml/Qt6ScxmlMacros.cmake
new file mode 100644
index 0000000..c99d845
--- /dev/null
+++ b/src/scxml/Qt6ScxmlMacros.cmake
@@ -0,0 +1,79 @@
+# Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+function(qt6_add_statecharts target_or_outfiles)
+ set(options)
+ set(oneValueArgs OUTPUT_DIR OUTPUT_DIRECTORY NAMESPACE)
+ set(multiValueArgs QSCXMLC_ARGUMENTS OPTIONS)
+
+ cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ set(scxml_files ${ARGS_UNPARSED_ARGUMENTS})
+ set(outfiles)
+
+ if (ARGS_NAMESPACE)
+ set(namespace "--namespace" ${ARGS_NAMESPACE})
+ endif()
+
+ if (ARGS_OUTPUT_DIR)
+ message(AUTHOR_WARNING
+ "OUTPUT_DIR is deprecated. Please use OUTPUT_DIRECTORY instead.")
+ set(ARGS_OUTPUT_DIRECTORY ${ARGS_OUTPUT_DIR})
+ endif()
+
+ if (ARGS_QSCXMLC_ARGUMENTS)
+ message(AUTHOR_WARNING
+ "QSCXMLC_ARGUMENTS is deprecated. Please use OPTIONS instead.")
+ set(ARGS_OPTIONS ${ARGS_QSCXMLC_ARGUMENTS})
+ endif()
+
+ set(qscxmlcOutputDir ${CMAKE_CURRENT_BINARY_DIR})
+ if (ARGS_OUTPUT_DIRECTORY)
+ set(qscxmlcOutputDir ${ARGS_OUTPUT_DIRECTORY})
+ if (NOT EXISTS "${qscxmlcOutputDir}" OR NOT IS_DIRECTORY "${qscxmlcOutputDir}")
+ message(WARNING
+ "qt6_add_statecharts: output dir does not exist: \"" ${qscxmlcOutputDir} "\". "
+ "Statechart code generation may fail on some platforms." )
+ endif()
+ endif()
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(qscxmlc_bin "${tool_wrapper}" "$<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::qscxmlc>")
+
+ set(outfiles)
+ foreach(it ${scxml_files})
+ get_filename_component(outfilename ${it} NAME_WE)
+ get_filename_component(infile ${it} ABSOLUTE)
+ set(outfile ${qscxmlcOutputDir}/${outfilename})
+ set(outfile_cpp ${outfile}.cpp)
+ set(outfile_h ${outfile}.h)
+
+ add_custom_command(OUTPUT ${outfile_cpp} ${outfile_h}
+ COMMAND
+ ${qscxmlc_bin} ${namespace} ${ARGS_OPTIONS}
+ --output ${outfile} ${infile}
+ DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::qscxmlc
+ MAIN_DEPENDENCY ${infile}
+ VERBATIM)
+ set_source_files_properties(${outfile_cpp} ${outfile_h} PROPERTIES SKIP_AUTOGEN TRUE)
+ list(APPEND outfiles ${outfile_cpp})
+ endforeach()
+ if (TARGET ${target_or_outfiles})
+ target_include_directories(${target_or_outfiles} PRIVATE ${qscxmlcOutputDir})
+ target_sources(${target_or_outfiles} PRIVATE ${outfiles})
+ else()
+ set(${target_or_outfiles} ${outfiles} PARENT_SCOPE)
+ endif()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_add_statecharts outfiles)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
+ qt5_add_statecharts("${outfiles}" ${ARGN})
+ elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_add_statecharts("${outfiles}" ${ARGN})
+ endif()
+ set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
+ endfunction()
+endif()
diff --git a/src/scxml/configure.cmake b/src/scxml/configure.cmake
new file mode 100644
index 0000000..55fc1d5
--- /dev/null
+++ b/src/scxml/configure.cmake
@@ -0,0 +1,28 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+
+
+#### Tests
+
+
+
+#### Features
+
+qt_feature("scxml-ecmascriptdatamodel" PUBLIC
+ SECTION "SCXML"
+ LABEL "ECMAScript data model for QtScxml"
+ PURPOSE "Enables the usage of ecmascript data models in SCXML state machines."
+ CONDITION TARGET Qt::Qml # special case
+)
+qt_configure_add_summary_section(NAME "Qt Scxml")
+qt_configure_add_summary_entry(ARGS "scxml-ecmascriptdatamodel")
+qt_configure_end_summary_section() # end of "Qt Scxml" section
diff --git a/src/scxml/configure.json b/src/scxml/configure.json
deleted file mode 100644
index 288373d..0000000
--- a/src/scxml/configure.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "module": "scxml",
-
- "features": {
- "scxml-ecmascriptdatamodel": {
- "label": "ECMAScript data model for QtScxml",
- "purpose": "Enables the usage of ecmascript data models in SCXML state machines.",
- "section": "SCXML",
- "output": [ "publicFeature" ]
- }
- },
-
- "summary": [
- {
- "section": "Qt Scxml",
- "entries": [
- "scxml-ecmascriptdatamodel"
- ]
- }
- ]
-}
diff --git a/src/scxml/doc/external-resources.qdoc b/src/scxml/doc/external-resources.qdoc
index 39a1c3b..10650fa 100644
--- a/src/scxml/doc/external-resources.qdoc
+++ b/src/scxml/doc/external-resources.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\externalpage http://www.w3.org/TR/scxml/
\title SCXML Specification
diff --git a/src/scxml/doc/qt6-changes.qdoc b/src/scxml/doc/qt6-changes.qdoc
new file mode 100644
index 0000000..da14af4
--- /dev/null
+++ b/src/scxml/doc/qt6-changes.qdoc
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtscxml-changes-qt6.html
+ \title Changes to Qt SCXML
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt SCXML to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain binary and source compatibility for all the public
+ APIs in each release. But some changes were inevitable in an effort to
+ make Qt a better framework.
+
+ In this topic we summarize those changes in Qt SCXML module, and provide
+ guidance to handle them.
+
+ \section1 Changes overview
+
+ The Qt SCXML module is largely source compatible with the Qt5
+ version and users of the library should be able to continue with no or
+ minor changes to their project.
+
+ \section1 API changes
+
+ \section2 QScxmlEcmaScriptDataModel API removal
+
+ The ecmascript datamodel, when enabled, introduces a dependency to the Qt QML library.
+ In Qt5 this depedendency is created at build time, whereas in Qt6 the dependency
+ is moved to runtime (internally a plugin). As a consequence the
+ QScxmlEcmaScriptDataModel class is no longer part of the public API.
+
+ \section1 Build system
+
+ As with Qt6 in general, the Qt SCXML module has cmake support in addition
+ to qmake.
+
+ \section1 QML imports
+
+ The QML import versioning is optional unless one has a specific
+ reason for not using the latest. Generally speaking the versioned imports
+ work from version 5.8 to 6.x, where 'x' is the current minor release.
+*/
diff --git a/src/scxml/doc/qtscxml-cmake-macros.qdoc b/src/scxml/doc/qtscxml-cmake-macros.qdoc
new file mode 100644
index 0000000..1a182cb
--- /dev/null
+++ b/src/scxml/doc/qtscxml-cmake-macros.qdoc
@@ -0,0 +1,29 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qtscxml-cmake-qt-add-statecharts.html
+\ingroup cmake-macros-qtscxml
+
+\title qt_add_statecharts
+\target qt6_add_statecharts
+
+\cmakecommandsince 6.1
+
+\section1 Description
+
+The \c qt6_add_statecharts macro instructs CMake to invoke the qscxmlc tool to
+read the provided .scxml files and produce C++ source and header files,
+that contain the classes that implement the state machines as defined in SCXML.
+
+\section1 Synopsis
+
+\badcode
+qt6_add_statecharts(<TARGET> file1.scxml [file2.scxml ...]
+ [OPTIONS ...])
+\endcode
+
+For further instructions, options and examples please refer to
+\l {Using the Qt SCXML Compiler (qscxmlc)}
+
+*/
diff --git a/src/scxml/doc/qtscxml-examples.qdoc b/src/scxml/doc/qtscxml-examples.qdoc
index cc0b6c4..e645bd6 100644
--- a/src/scxml/doc/qtscxml-examples.qdoc
+++ b/src/scxml/doc/qtscxml-examples.qdoc
@@ -1,49 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\group examples-qtscxml
\title Qt SCXML Examples
\brief Examples for the Qt SCXML module.
-\ingroup all-examples
The Qt SCXML example applications demonstrate the functionality provided by the
\l{Qt SCXML} module.
-There are multiple versions of the \e Invoke, \e {Media Player}, and
-\e {Traffic Light} example applications. Each application has some common files
-that are stored in a common folder, in addition to the files stored in the
-example version folder.
+There are multiple versions of the \e {Traffic Light} example application.
+The application has shared common files, and in addition specific files for
+each version of the application, under their respective folders. They demonstrate
+the different options for creating user interfaces (using \l {Qt Widgets}
+or \l {Qt Quick}) and for loading the SCXML dynamically versus first compiling
+it to a C++ class (the \e static versions).
-All versions of an example application have the same appearance and
-fuctionality. They demonstrate the different options for creating user
-interfaces (using \l {Qt Widgets} or \l {Qt Quick}) and for loading the SCXML
-dynamically versus first compiling it to a C++ class (the \e static versions).
-
-In addition, the Media Player example versions demonstrate how to access the C++
-and ECMAScript data models.
*/
diff --git a/src/scxml/doc/qtscxml-index.qdoc b/src/scxml/doc/qtscxml-index.qdoc
index b65a1c2..ca088e0 100644
--- a/src/scxml/doc/qtscxml-index.qdoc
+++ b/src/scxml/doc/qtscxml-index.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtscxml-index.html
@@ -39,24 +15,20 @@
\section1 Getting Started
- To include the definitions of the module's classes, use the following directive:
-
- \code
- #include <QScxmlStateMachine>
- \endcode
-
To import the QML types into your application, use the following import statement
in your .qml file:
- \qml \QtMinorVersion
- import QtScxml 5.\1
+ \qml
+ import QtScxml
\endqml
- To link against the module, add this line to your qmake .pro file:
+ To link against the module:
+
+ Using cmake:
+ \include qtscxml-module-use.qdocinc cmakebuild
- \code
- QT += scxml
- \endcode
+ Using qmake:
+ \include qtscxml-module-use.qdocinc qmakebuild
\section1 Articles and Guides
@@ -79,4 +51,16 @@
\li \l {Qt SCXML C++ Classes} {C++ Classes and Namespaces}
\li \l {Qt SCXML QML Types} {QML Types}
\endlist
+
+ \section1 Module Evolution
+ \l{Changes to Qt SCXML} lists important changes in the module API
+ and functionality that were done for the Qt 6 series of Qt.
+
+ \section1 Licenses and Trademarks
+
+ The Qt SCXML module is available under commercial licenses from
+ \l{The Qt Company}. In addition, it is available under free software licenses:
+ The \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
*/
diff --git a/src/scxml/doc/qtscxml-instantiating-state-machines.qdoc b/src/scxml/doc/qtscxml-instantiating-state-machines.qdoc
index 37cff10..51c51e2 100644
--- a/src/scxml/doc/qtscxml-instantiating-state-machines.qdoc
+++ b/src/scxml/doc/qtscxml-instantiating-state-machines.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtscxml-instantiating-state-machines.html
@@ -43,7 +19,7 @@
Or, in QML:
\qml
- import QtScxml 5.8
+ import QtScxml
Item {
property StateMachine stateMachine: scxmlLoader.stateMachine
@@ -71,7 +47,12 @@
To use a compiled state machine in QML, you can register it as a QML type:
\code
- qmlRegisterType<MyStateMachine>("MyStateMachine", 1, 0, "MyStateMachine");
+ struct MyStateMachineRegistration {
+ Q_GADGET
+ QML_NAMED_ELEMENT(MyStateMachine)
+ QML_FOREIGN(MyStateMachine)
+ QML_ADDED_IN_VERSION(1, 0)
+ };
\endcode
Then you can instantiate it in QML, like this:
@@ -84,19 +65,25 @@
}
\endqml
- To compile a state machine, the following lines have to be added to a
- .pro file:
+ To compile a state machine, the following lines have to be added to the
+ project build file:
- \badcode
- QT += scxml
- STATECHARTS = MyStatemachine.scxml
- \endcode
+ When using cmake:
+
+ \include qtscxml-module-use.qdocinc cmakebuild
+ \include qtscxml-module-use.qdocinc cmakestatecharts
+
+ When using qmake:
+
+ \include qtscxml-module-use.qdocinc qmakebuild
+ \include qtscxml-module-use.qdocinc qmakestatecharts
This will tell qmake to run \e qscxmlc which generates MyStatemachine.h
- and MyStatemachine.cpp, and adds them to \l [QMake] HEADERS and
- \l [QMake] SOURCES variables. By default, the generated files are saved in
- the build directory. The \e QSCXMLC_DIR variable can be set to specify
- another directory. The \e QSCXMLC_NAMESPACE variable can be set to put the
+ and MyStatemachine.cpp, and adds them to appropriately to the project
+ headers and sources. By default, the generated files are saved in
+ the build directory. The qmake \e QSCXMLC_DIR or cmake \e OUTPUT_DIRECTORY
+ variable can be set to specify another directory. The qmake
+ \e QSCXMLC_NAMESPACE or cmake \e NAMESPACE variable can be set to put the
state machine code into a C++ namespace.
After instantiating a state machine, you can connect to any state's
@@ -107,6 +94,7 @@
\code
stateMachine->connectToState("red", [](bool active) {
qDebug() << (active ? "entered" : "exited") << "the red state";
+ });
\endcode
And in QML:
@@ -133,7 +121,7 @@
And in QML:
\qml
- import QtScxml 5.8
+ import QtScxml
EventConnection {
stateMachine: stateMachine
@@ -148,7 +136,7 @@
stateMachine->submitEvent("tap", QVariantMap({
{ "artist", "Fatboy Slim" },
{ "title", "The Rockafeller Skank" }
- });
+ }));
\endcode
This will generate a "tap" event with the map contents available in
diff --git a/src/scxml/doc/qtscxml-module-cpp.qdoc b/src/scxml/doc/qtscxml-module-cpp.qdoc
index 88002ca..2161f08 100644
--- a/src/scxml/doc/qtscxml-module-cpp.qdoc
+++ b/src/scxml/doc/qtscxml-module-cpp.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\module QtScxml
@@ -33,18 +9,15 @@
\ingroup modules
\ingroup technology-apis
\qtvariable scxml
+ \qtcmakepackage Scxml
- To include the definitions of the module's classes, use the following directive:
+ To use the module with cmake, use the \c{find_package()} command to locate the
+ needed module components in the \c{Qt6} package:
+ \include qtscxml-module-use.qdocinc cmakebuild
- \code
- #include <QScxmlStateMachine>
- \endcode
-
- To link against the module, add this line to your qmake .pro file:
-
- \code
- QT += scxml
- \endcode
+ To configure the module for building with qmake, add the module as a value
+ of the \c QT variable in the project's .pro file:
+ \include qtscxml-module-use.qdocinc qmakebuild
For more information, see \l{Instantiating State Machines}.
*/
diff --git a/src/scxml/doc/qtscxml-module-qml.qdoc b/src/scxml/doc/qtscxml-module-qml.qdoc
index 5fdae36..5bddabc 100644
--- a/src/scxml/doc/qtscxml-module-qml.qdoc
+++ b/src/scxml/doc/qtscxml-module-qml.qdoc
@@ -1,32 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
- \qmlmodule QtScxml 5.\QtMinorVersion
+ \qmlmodule QtScxml 6.\QtMinorVersion
\title Qt SCXML QML Types
\ingroup qmlmodules
\brief Enables the use of SCXML state machines with QML.
@@ -34,9 +10,9 @@
To import the QML types into your application, use the following import statement
in your .qml file:
- \code \QtMinorVersion
- import QtScxml 5.\1
- \endcode
+ \qml
+ import QtScxml
+ \endqml
For more information, see \l{Instantiating State Machines}.
*/
diff --git a/src/scxml/doc/qtscxml-module-use.qdocinc b/src/scxml/doc/qtscxml-module-use.qdocinc
new file mode 100644
index 0000000..ba48db0
--- /dev/null
+++ b/src/scxml/doc/qtscxml-module-use.qdocinc
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+//! [cmakebuild]
+ \code
+ find_package(Qt6 REQUIRED COMPONENTS Scxml)
+ target_link_libraries(mytarget PRIVATE Qt6::Scxml)
+ \endcode
+//! [cmakebuild]
+
+//! [qmakebuild]
+ \code
+ QT += scxml
+ \endcode
+//! [qmakebuild]
+
+//! [qmakestatecharts]
+ \code
+ STATECHARTS = MyStatemachine.scxml
+ \endcode
+//! [qmakestatecharts]
+
+//! [cmakestatecharts]
+ \code
+ qt6_add_statecharts(mytarget
+ MyStatemachine.scxml
+ )
+ \endcode
+//! [cmakestatecharts]
+
diff --git a/src/scxml/doc/qtscxml-overview.qdoc b/src/scxml/doc/qtscxml-overview.qdoc
index dfecb0a..dfbe0bf 100644
--- a/src/scxml/doc/qtscxml-overview.qdoc
+++ b/src/scxml/doc/qtscxml-overview.qdoc
@@ -1,34 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtscxml-overview.html
\title Qt SCXML Overview
\brief Describes the Qt SCXML module.
+ \ingroup explanation
The Qt SCXML module provides classes for embedding state machines created
from State Chart XML (SCXML) files in Qt applications. The SCXML files
@@ -40,8 +17,8 @@
file. This enables creating a clear division between the application logic
and the user interface implementation by using Qt Quick or Qt Widgets.
- The Qt SCXML module differs from the \l {The State Machine Framework}
- {State Machine framework} in the Qt Core module in that Qt SCXML provides a
+ The Qt SCXML module differs from the \l {Qt State Machine Overview}
+ {State Machine framework} in the \l{Qt State Machine} module in that Qt SCXML provides a
\e {conforming processor} that can parse and process \e {conforming SCXML
documents}. In Qt SCXML, state machines are read from separate SCXML files
and integrated to Qt applications by instantiating the QScxmlStateMachine
diff --git a/src/scxml/doc/qtscxml-scxml-compliance.qdoc b/src/scxml/doc/qtscxml-scxml-compliance.qdoc
index ab1d730..6721c38 100644
--- a/src/scxml/doc/qtscxml-scxml-compliance.qdoc
+++ b/src/scxml/doc/qtscxml-scxml-compliance.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qtscxml-scxml-compliance.html
diff --git a/src/scxml/doc/qtscxml.qdocconf b/src/scxml/doc/qtscxml.qdocconf
index 6d90bd1..b8211e6 100644
--- a/src/scxml/doc/qtscxml.qdocconf
+++ b/src/scxml/doc/qtscxml.qdocconf
@@ -2,30 +2,27 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
include($QT_INSTALL_DOCS/config/exampleurl-qtscxml.qdocconf)
project = QtScxml
-description = Qt Scxml Reference Documentation
+description = Qt SCXML Reference Documentation
version = $QT_VERSION
-# Install path for the examples. For Qt 5.6, the convention
-# is to use the repository name as the install location
-# under QT_INSTALL_EXAMPLES.
+# Install path for the examples
examplesinstallpath = scxml
exampledirs = ../../../examples/scxml
-imagedirs = ../../../examples/doc/images
examples.fileextensions += "*.scxml"
qhp.QtScxml.subprojects = classes qmltypes examples
qhp.QtScxml.subprojects.classes.title = C++ Classes
qhp.QtScxml.subprojects.classes.indexTitle = Qt SCXML C++ Classes
-qhp.QtScxml.subprojects.classes.selectors = class fake:headerfile
+qhp.QtScxml.subprojects.classes.selectors = class headerfile
qhp.QtScxml.subprojects.classes.sortPages = true
qhp.QtScxml.subprojects.qmltypes.title = QML Types
qhp.QtScxml.subprojects.qmltypes.indexTitle = Qt SCXML QML Types
-qhp.QtScxml.subprojects.qmltypes.selectors = qmlclass
+qhp.QtScxml.subprojects.qmltypes.selectors = qmltype
qhp.QtScxml.subprojects.qmltypes.sortPages = true
qhp.QtScxml.subprojects.examples.title = Examples
qhp.QtScxml.subprojects.examples.indexTitle = Qt SCXML Examples
-qhp.QtScxml.subprojects.examples.selectors = fake:example
+qhp.QtScxml.subprojects.examples.selectors = doc:example
qhp.projects = QtScxml
@@ -35,21 +32,24 @@ qhp.QtScxml.virtualFolder = qtscxml
qhp.QtScxml.indexTitle = Qt SCXML
qhp.QtScxml.indexRoot =
-depends += qtcore qtdoc qmake qtquick qtwidgets
+depends += qtcore qtdoc qmake qtquick qtwidgets qtstatemachine qtcmake
+
+headerdirs = .. \
+ ../../scxmlqml \
+ ../../plugins/ecmascriptdatamodel
-headerdirs = .. ../../imports/scxmlstatemachine
sourcedirs += .. \
- ../../imports/scxmlstatemachine \
+ ../../scxmlqml \
../../../tools/qscxmlc/doc \
- ../../../examples/scxml
+ ../../plugins/ecmascriptdatamodel
excludefiles += "../qscxmlexecutablecontent_p.h"
tagfile = qtscxml.tags
-manifestmeta.highlighted.names = "QtScxml/Qt SCXML Calculator QML Example" \
- "QtScxml/Qt SCXML Traffic Light QML Example (Dynamic)"
-
navigation.landingpage = "Qt SCXML"
navigation.cppclassespage = "Qt SCXML C++ Classes"
navigation.qmltypespage = "Qt SCXML QML Types"
+
+# Highlighted examples in Data Processing & IO category
+manifestmeta.highlighted.names = "QtScxml/SCXML Sudoku"
diff --git a/src/scxml/qscxmlcompiler.cpp b/src/scxml/qscxmlcompiler.cpp
index 36967d1..eaf7171 100644
--- a/src/scxml/qscxmlcompiler.cpp
+++ b/src/scxml/qscxmlcompiler.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlcompiler_p.h"
#include "qscxmlexecutablecontent_p.h"
@@ -43,7 +7,7 @@
#include <qxmlstream.h>
#include <qloggingcategory.h>
#include <qfile.h>
-#include <qvector.h>
+#include <qlist.h>
#include <qstring.h>
#ifndef BUILD_QSCXMLC
@@ -56,6 +20,8 @@
#include <private/qmetaobjectbuilder_p.h>
#endif // BUILD_QSCXMLC
+#include <QtCore/qmap.h>
+
#include <functional>
namespace {
@@ -87,7 +53,7 @@ public:
doc->isVerified = true;
m_doc = doc;
- for (DocumentModel::AbstractState *state : qAsConst(doc->allStates)) {
+ for (DocumentModel::AbstractState *state : std::as_const(doc->allStates)) {
if (state->id.isEmpty()) {
continue;
#ifndef QT_NO_DEBUG
@@ -117,8 +83,8 @@ private:
scxml->initialTransition = createInitialTransition({firstChild});
}
} else {
- QVector<DocumentModel::AbstractState *> initialStates;
- for (const QString &initial : qAsConst(scxml->initial)) {
+ QList<DocumentModel::AbstractState *> initialStates;
+ for (const QString &initial : std::as_const(scxml->initial)) {
if (DocumentModel::AbstractState *s = m_stateById.value(initial))
initialStates.append(s);
else
@@ -155,8 +121,8 @@ private:
}
} else {
Q_ASSERT(state->type == DocumentModel::State::Normal);
- QVector<DocumentModel::AbstractState *> initialStates;
- for (const QString &initialState : qAsConst(state->initial)) {
+ QList<DocumentModel::AbstractState *> initialStates;
+ for (const QString &initialState : std::as_const(state->initial)) {
if (DocumentModel::AbstractState *s = m_stateById.value(initialState)) {
initialStates.append(s);
} else {
@@ -207,7 +173,7 @@ private:
if (int size = transition->targets.size())
transition->targetStates.reserve(size);
- for (const QString &target : qAsConst(transition->targets)) {
+ for (const QString &target : std::as_const(transition->targets)) {
if (DocumentModel::AbstractState *s = m_stateById.value(target)) {
if (transition->targetStates.contains(s)) {
error(transition->xmlLocation, QStringLiteral("duplicate target '%1'").arg(target));
@@ -218,7 +184,7 @@ private:
error(transition->xmlLocation, QStringLiteral("unknown state '%1' in target").arg(target));
}
}
- for (const QString &event : qAsConst(transition->events))
+ for (const QString &event : std::as_const(transition->events))
checkEvent(event, transition->xmlLocation, AllowWildCards);
m_parentNodes.append(transition);
@@ -233,7 +199,7 @@ private:
bool visit(DocumentModel::HistoryState *state) override
{
bool seenTransition = false;
- for (DocumentModel::StateOrTransition *sot : qAsConst(state->children)) {
+ for (DocumentModel::StateOrTransition *sot : std::as_const(state->children)) {
if (DocumentModel::State *s = sot->asState()) {
error(s->xmlLocation, QStringLiteral("history state cannot have substates"));
} else if (DocumentModel::Transition *t = sot->asTransition()) {
@@ -298,7 +264,7 @@ private:
if (!isLetter(c) && c != QLatin1Char('_'))
return false;
}
- for (int ei = id.length(); i != ei; ++i) {
+ for (int ei = id.size(); i != ei; ++i) {
const QChar c = id.at(i);
if (isLetter(c) || c.isDigit() || c == QLatin1Char('.') || c == QLatin1Char('-')
|| c == QLatin1Char('_') || isNameTail(c))
@@ -370,12 +336,12 @@ private:
if (part.isEmpty())
return false;
- if (wildCardMode == AllowWildCards && part.length() == 1
+ if (wildCardMode == AllowWildCards && part.size() == 1
&& part.at(0) == QLatin1Char('*')) {
continue;
}
- for (int i = 0, ei = part.length(); i != ei; ++i) {
+ for (int i = 0, ei = part.size(); i != ei; ++i) {
const QChar c = part.at(i);
if (!isLetter(c) && !c.isDigit() && c != QLatin1Char('-') && c != QLatin1Char('_')
&& c != QLatin1Char(':')) {
@@ -387,7 +353,7 @@ private:
return true;
}
- static const QVector<DocumentModel::StateOrTransition *> &allChildrenOfContainer(
+ static const QList<DocumentModel::StateOrTransition *> &allChildrenOfContainer(
DocumentModel::StateContainer *container)
{
if (auto state = container->asState())
@@ -402,8 +368,8 @@ private:
{
const auto &allChildren = allChildrenOfContainer(container);
- QVector<DocumentModel::AbstractState *> childStates;
- for (DocumentModel::StateOrTransition *child : qAsConst(allChildren)) {
+ QList<DocumentModel::AbstractState *> childStates;
+ for (DocumentModel::StateOrTransition *child : std::as_const(allChildren)) {
if (DocumentModel::State *s = child->asState())
return s;
else if (DocumentModel::HistoryState *h = child->asHistoryState())
@@ -412,13 +378,13 @@ private:
return nullptr;
}
- static QVector<DocumentModel::AbstractState *> allAbstractStates(
+ static QList<DocumentModel::AbstractState *> allAbstractStates(
DocumentModel::StateContainer *container)
{
const auto &allChildren = allChildrenOfContainer(container);
- QVector<DocumentModel::AbstractState *> childStates;
- for (DocumentModel::StateOrTransition *child : qAsConst(allChildren)) {
+ QList<DocumentModel::AbstractState *> childStates;
+ for (DocumentModel::StateOrTransition *child : std::as_const(allChildren)) {
if (DocumentModel::State *s = child->asState())
childStates.append(s);
else if (DocumentModel::HistoryState *h = child->asHistoryState())
@@ -428,7 +394,7 @@ private:
}
DocumentModel::Transition *createInitialTransition(
- const QVector<DocumentModel::AbstractState *> &states)
+ const QList<DocumentModel::AbstractState *> &states)
{
auto *newTransition = m_doc->newTransition(nullptr, DocumentModel::XmlLocation(-1, -1));
newTransition->type = DocumentModel::Transition::Synthetic;
@@ -460,7 +426,7 @@ private:
DocumentModel::ScxmlDocument *m_doc;
bool m_hasErrors;
QHash<QString, DocumentModel::AbstractState *> m_stateById;
- QVector<DocumentModel::Node *> m_parentNodes;
+ QList<DocumentModel::Node *> m_parentNodes;
};
#ifndef BUILD_QSCXMLC
@@ -469,8 +435,8 @@ class InvokeDynamicScxmlFactory: public QScxmlInvokableServiceFactory
Q_OBJECT
public:
InvokeDynamicScxmlFactory(const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &namelist,
- const QVector<QScxmlExecutableContent::ParameterInfo> &params)
+ const QList<QScxmlExecutableContent::StringId> &namelist,
+ const QList<QScxmlExecutableContent::ParameterInfo> &params)
: QScxmlInvokableServiceFactory(invokeInfo, namelist, params)
{}
@@ -485,9 +451,31 @@ private:
class DynamicStateMachinePrivate : public QScxmlStateMachinePrivate
{
+ struct DynamicMetaObject : public QAbstractDynamicMetaObject
+ {
+ QMetaObject *toDynamicMetaObject(QObject *) override
+ {
+ return this;
+ }
+
+ int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) override
+ {
+ return o->qt_metacall(c, id, a);
+ }
+ };
+
public:
DynamicStateMachinePrivate() :
- QScxmlStateMachinePrivate(&QScxmlStateMachine::staticMetaObject) {}
+ QScxmlStateMachinePrivate(&QScxmlStateMachine::staticMetaObject)
+ {
+ metaObject = new DynamicMetaObject;
+ }
+
+ void setDynamicMetaObject(const QMetaObject *m) {
+ // Prevent the QML engine from creating a property cache for this thing.
+ static_cast<DynamicMetaObject *>(metaObject)->d = m->d;
+ m_metaObject = m;
+ }
};
class DynamicStateMachine: public QScxmlStateMachine, public QScxmlInternal::GeneratedTableData
@@ -544,7 +532,7 @@ private:
b.setClassName("DynamicStateMachine");
b.setSuperClass(&QScxmlStateMachine::staticMetaObject);
b.setStaticMetacallFunction(qt_static_metacall);
- d->m_metaObject = b.toMetaObject();
+ d->setDynamicMetaObject(b.toMetaObject());
}
void initDynamicParts(const MetaDataInfo &info)
@@ -553,7 +541,7 @@ private:
// Release the temporary QMetaObject.
Q_ASSERT(d->m_metaObject != &QScxmlStateMachine::staticMetaObject);
free(const_cast<QMetaObject *>(d->m_metaObject));
- d->m_metaObject = &QScxmlStateMachine::staticMetaObject;
+ d->setDynamicMetaObject(&QScxmlStateMachine::staticMetaObject);
// Build the real one.
QMetaObjectBuilder b;
@@ -579,7 +567,7 @@ private:
}
// And we're done
- d->m_metaObject = b.toMetaObject();
+ d->setDynamicMetaObject(b.toMetaObject());
}
public:
@@ -588,7 +576,7 @@ public:
Q_D(DynamicStateMachine);
if (d->m_metaObject != &QScxmlStateMachine::staticMetaObject) {
free(const_cast<QMetaObject *>(d->m_metaObject));
- d->m_metaObject = &QScxmlStateMachine::staticMetaObject;
+ d->setDynamicMetaObject(&QScxmlStateMachine::staticMetaObject);
}
}
@@ -602,8 +590,8 @@ public:
DataModelInfo dm;
auto factoryIdCreator = [stateMachine](
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &namelist,
- const QVector<QScxmlExecutableContent::ParameterInfo> &params,
+ const QList<QScxmlExecutableContent::StringId> &namelist,
+ const QList<QScxmlExecutableContent::ParameterInfo> &params,
const QSharedPointer<DocumentModel::ScxmlDocument> &content) -> int {
auto factory = new InvokeDynamicScxmlFactory(invokeInfo, namelist, params);
factory->setContent(content);
@@ -629,7 +617,7 @@ private:
}
private:
- QVector<QScxmlInvokableServiceFactory *> m_allFactoriesById;
+ QList<QScxmlInvokableServiceFactory *> m_allFactoriesById;
int m_propertyCount;
};
@@ -840,7 +828,7 @@ QScxmlStateMachine *QScxmlCompilerPrivate::instantiateStateMachine() const
void QScxmlCompilerPrivate::instantiateDataModel(QScxmlStateMachine *stateMachine) const
{
#ifdef BUILD_QSCXMLC
- Q_UNUSED(stateMachine)
+ Q_UNUSED(stateMachine);
#else
if (!m_errors.isEmpty()) {
qWarning() << "SCXML document has errors";
@@ -864,7 +852,7 @@ void QScxmlCompilerPrivate::instantiateDataModel(QScxmlStateMachine *stateMachin
/*!
* Returns the list of parse errors.
*/
-QVector<QScxmlError> QScxmlCompiler::errors() const
+QList<QScxmlError> QScxmlCompiler::errors() const
{
return d->errors();
}
@@ -1008,7 +996,7 @@ bool QScxmlCompilerPrivate::ParserState::isExecutableContent(ParserState::Kind k
return false;
}
-QScxmlCompilerPrivate::ParserState::Kind QScxmlCompilerPrivate::ParserState::nameToParserStateKind(const QStringRef &name)
+QScxmlCompilerPrivate::ParserState::Kind QScxmlCompilerPrivate::ParserState::nameToParserStateKind(QStringView name)
{
static QMap<QString, ParserState::Kind> nameToKind;
if (nameToKind.isEmpty()) {
@@ -1173,7 +1161,7 @@ void DocumentModel::Param::accept(DocumentModel::NodeVisitor *visitor)
void DocumentModel::DoneData::accept(DocumentModel::NodeVisitor *visitor)
{
if (visitor->visit(this)) {
- for (Param *param : qAsConst(params))
+ for (Param *param : std::as_const(params))
param->accept(visitor);
}
visitor->endVisit(this);
@@ -1246,7 +1234,7 @@ void DocumentModel::State::accept(DocumentModel::NodeVisitor *visitor)
visitor->visit(onExit);
if (doneData)
doneData->accept(visitor);
- for (Invoke *invoke : qAsConst(invokes))
+ for (Invoke *invoke : std::as_const(invokes))
invoke->accept(visitor);
}
visitor->endVisit(this);
@@ -1333,7 +1321,7 @@ bool QScxmlCompilerPrivate::verifyDocument()
this->addError(location, msg);
};
- if (ScxmlVerifier(handler).verify(m_doc.data()))
+ if (ScxmlVerifier(handler).verify(m_doc.get()))
return true;
else
return false;
@@ -1341,7 +1329,7 @@ bool QScxmlCompilerPrivate::verifyDocument()
DocumentModel::ScxmlDocument *QScxmlCompilerPrivate::scxmlDocument() const
{
- return m_doc && m_errors.isEmpty() ? m_doc.data() : nullptr;
+ return m_doc && m_errors.isEmpty() ? m_doc.get() : nullptr;
}
QString QScxmlCompilerPrivate::fileName() const
@@ -1372,7 +1360,7 @@ void QScxmlCompilerPrivate::parseSubDocument(DocumentModel::Invoke *parentInvoke
p.setFileName(fileName);
p.setLoader(loader());
p.d->readDocument();
- parentInvoke->content.reset(p.d->m_doc.take());
+ parentInvoke->content.reset(p.d->m_doc.release());
m_doc->allSubDocuments.append(parentInvoke->content.data());
m_errors.append(p.errors());
}
@@ -1386,7 +1374,7 @@ bool QScxmlCompilerPrivate::parseSubElement(DocumentModel::Invoke *parentInvoke,
p.setLoader(loader());
p.d->resetDocument();
bool ok = p.d->readElement();
- parentInvoke->content.reset(p.d->m_doc.take());
+ parentInvoke->content.reset(p.d->m_doc.release());
m_doc->allSubDocuments.append(parentInvoke->content.data());
m_errors.append(p.errors());
return ok;
@@ -1404,10 +1392,10 @@ bool QScxmlCompilerPrivate::preReadElementScxml()
const QXmlStreamAttributes attributes = m_reader->attributes();
if (attributes.hasAttribute(QStringLiteral("initial"))) {
const QString initial = attributes.value(QStringLiteral("initial")).toString();
- scxml->initial += initial.split(QChar::Space, QString::SkipEmptyParts);
+ scxml->initial += initial.split(QChar::Space, Qt::SkipEmptyParts);
}
- const QStringRef datamodel = attributes.value(QLatin1String("datamodel"));
+ const QStringView datamodel = attributes.value(QLatin1String("datamodel"));
if (datamodel.isEmpty() || datamodel == QLatin1String("null")) {
scxml->dataModel = DocumentModel::Scxml::NullDataModel;
} else if (datamodel == QLatin1String("ecmascript")) {
@@ -1421,7 +1409,7 @@ bool QScxmlCompilerPrivate::preReadElementScxml()
} else {
int lastColon = datamodel.lastIndexOf(QLatin1Char(':'));
if (lastColon == -1) {
- lastColon = datamodel.length();
+ lastColon = datamodel.size();
} else {
scxml->cppDataModelHeaderName = datamodel.mid(lastColon + 1).toString();
}
@@ -1431,7 +1419,7 @@ bool QScxmlCompilerPrivate::preReadElementScxml()
addError(QStringLiteral("Unsupported data model '%1' in scxml")
.arg(datamodel.toString()));
}
- const QStringRef binding = attributes.value(QLatin1String("binding"));
+ const QStringView binding = attributes.value(QLatin1String("binding"));
if (binding.isEmpty() || binding == QLatin1String("early")) {
scxml->binding = DocumentModel::Scxml::EarlyBinding;
} else if (binding == QLatin1String("late")) {
@@ -1441,7 +1429,7 @@ bool QScxmlCompilerPrivate::preReadElementScxml()
.arg(binding.toString()));
return false;
}
- const QStringRef name = attributes.value(QLatin1String("name"));
+ const QStringView name = attributes.value(QLatin1String("name"));
if (!name.isEmpty()) {
scxml->name = name.toString();
}
@@ -1460,7 +1448,7 @@ bool QScxmlCompilerPrivate::preReadElementState()
if (attributes.hasAttribute(QStringLiteral("initial"))) {
const QString initial = attributes.value(QStringLiteral("initial")).toString();
- newState->initial += initial.split(QChar::Space, QString::SkipEmptyParts);
+ newState->initial += initial.split(QChar::Space, Qt::SkipEmptyParts);
}
m_currentState = newState;
return true;
@@ -1525,11 +1513,11 @@ bool QScxmlCompilerPrivate::preReadElementTransition()
}
const QXmlStreamAttributes attributes = m_reader->attributes();
- transition->events = attributes.value(QLatin1String("event")).toString().split(QLatin1Char(' '), QString::SkipEmptyParts);
- transition->targets = attributes.value(QLatin1String("target")).toString().split(QLatin1Char(' '), QString::SkipEmptyParts);
+ transition->events = attributes.value(QLatin1String("event")).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
+ transition->targets = attributes.value(QLatin1String("target")).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
if (attributes.hasAttribute(QStringLiteral("cond")))
transition->condition.reset(new QString(attributes.value(QLatin1String("cond")).toString()));
- QStringRef type = attributes.value(QLatin1String("type"));
+ QStringView type = attributes.value(QLatin1String("type"));
if (type.isEmpty() || type == QLatin1String("external")) {
transition->type = DocumentModel::Transition::External;
} else if (type == QLatin1String("internal")) {
@@ -1565,7 +1553,7 @@ bool QScxmlCompilerPrivate::preReadElementHistory()
if (!maybeId(attributes, &newState->id))
return false;
- const QStringRef type = attributes.value(QLatin1String("type"));
+ const QStringView type = attributes.value(QLatin1String("type"));
if (type.isEmpty() || type == QLatin1String("shallow")) {
newState->type = DocumentModel::HistoryState::Shallow;
} else if (type == QLatin1String("deep")) {
@@ -1813,7 +1801,7 @@ bool QScxmlCompilerPrivate::preReadElementSend()
send->target = attributes.value(QLatin1String("target")).toString();
send->targetexpr = attributes.value(QLatin1String("targetexpr")).toString();
if (attributes.hasAttribute(QLatin1String("namelist")))
- send->namelist = attributes.value(QLatin1String("namelist")).toString().split(QLatin1Char(' '), QString::SkipEmptyParts);
+ send->namelist = attributes.value(QLatin1String("namelist")).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
current().instruction = send;
return true;
}
@@ -1845,16 +1833,16 @@ bool QScxmlCompilerPrivate::preReadElementInvoke()
invoke->idLocation = attributes.value(QLatin1String("idlocation")).toString();
invoke->type = attributes.value(QLatin1String("type")).toString();
invoke->typeexpr = attributes.value(QLatin1String("typeexpr")).toString();
- QStringRef autoforwardS = attributes.value(QLatin1String("autoforward"));
- if (QStringRef::compare(autoforwardS, QLatin1String("true"), Qt::CaseInsensitive) == 0
- || QStringRef::compare(autoforwardS, QLatin1String("yes"), Qt::CaseInsensitive) == 0
- || QStringRef::compare(autoforwardS, QLatin1String("t"), Qt::CaseInsensitive) == 0
- || QStringRef::compare(autoforwardS, QLatin1String("y"), Qt::CaseInsensitive) == 0
+ QStringView autoforwardS = attributes.value(QLatin1String("autoforward"));
+ if (autoforwardS.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0
+ || autoforwardS.compare(QLatin1String("yes"), Qt::CaseInsensitive) == 0
+ || autoforwardS.compare(QLatin1String("t"), Qt::CaseInsensitive) == 0
+ || autoforwardS.compare(QLatin1String("y"), Qt::CaseInsensitive) == 0
|| autoforwardS == QLatin1String("1"))
invoke->autoforward = true;
else
invoke->autoforward = false;
- invoke->namelist = attributes.value(QLatin1String("namelist")).toString().split(QLatin1Char(' '), QString::SkipEmptyParts);
+ invoke->namelist = attributes.value(QLatin1String("namelist")).toString().split(QLatin1Char(' '), Qt::SkipEmptyParts);
current().instruction = invoke;
return true;
}
@@ -2060,6 +2048,9 @@ bool QScxmlCompilerPrivate::postReadElementScript()
scriptI->content = QString::fromUtf8(data);
}
}
+ } else {
+ addError(scriptI->xmlLocation,
+ QStringLiteral("neither src nor any content has been given in the script tag"));
}
return flushInstruction();
}
@@ -2113,7 +2104,7 @@ bool QScxmlCompilerPrivate::readDocument()
for (bool finished = false; !finished && !m_reader->hasError();) {
switch (m_reader->readNext()) {
case QXmlStreamReader::StartElement : {
- const QStringRef newTag = m_reader->name();
+ const QStringView newTag = m_reader->name();
const ParserState::Kind newElementKind = ParserState::nameToParserStateKind(newTag);
auto ns = m_reader->namespaceUri();
@@ -2154,7 +2145,7 @@ bool QScxmlCompilerPrivate::readDocument()
bool QScxmlCompilerPrivate::readElement()
{
- const QStringRef currentTag = m_reader->name();
+ const QStringView currentTag = m_reader->name();
const QXmlStreamAttributes attributes = m_reader->attributes();
const ParserState::Kind elementKind = ParserState::nameToParserStateKind(currentTag);
@@ -2177,7 +2168,7 @@ bool QScxmlCompilerPrivate::readElement()
return parseSubElement(i, m_reader, m_fileName);
}
- if (elementKind != ParserState::Scxml && !m_stack.count()) {
+ if (elementKind != ParserState::Scxml && !m_stack.size()) {
addError(QStringLiteral("misplaced %1").arg(currentTag.toString()));
return false;
}
@@ -2219,7 +2210,7 @@ bool QScxmlCompilerPrivate::readElement()
for (bool finished = false; !finished && !m_reader->hasError();) {
switch (m_reader->readNext()) {
case QXmlStreamReader::StartElement : {
- const QStringRef newTag = m_reader->name();
+ const QStringView newTag = m_reader->name();
const ParserState::Kind newElementKind = ParserState::nameToParserStateKind(newTag);
auto ns = m_reader->namespaceUri();
@@ -2327,7 +2318,7 @@ QByteArray QScxmlCompilerPrivate::load(const QString &name, bool *ok)
return result;
}
-QVector<QScxmlError> QScxmlCompilerPrivate::errors() const
+QList<QScxmlError> QScxmlCompilerPrivate::errors() const
{
return m_errors;
}
@@ -2394,12 +2385,12 @@ QScxmlCompilerPrivate::ParserState &QScxmlCompilerPrivate::current()
QScxmlCompilerPrivate::ParserState &QScxmlCompilerPrivate::previous()
{
- return m_stack[m_stack.count() - 2];
+ return m_stack[m_stack.size() - 2];
}
bool QScxmlCompilerPrivate::hasPrevious() const
{
- return m_stack.count() > 1;
+ return m_stack.size() > 1;
}
bool QScxmlCompilerPrivate::checkAttributes(const QXmlStreamAttributes &attributes,
@@ -2416,7 +2407,7 @@ bool QScxmlCompilerPrivate::checkAttributes(const QXmlStreamAttributes &attribut
{
QStringList required = requiredNames;
for (const QXmlStreamAttribute &attribute : attributes) {
- const QStringRef ns = attribute.namespaceUri();
+ const QStringView ns = attribute.namespaceUri();
if (!ns.isEmpty() && ns != scxmlNamespace && ns != qtScxmlNamespace)
continue;
@@ -2451,7 +2442,7 @@ QByteArray QScxmlCompilerPrivate::DefaultLoader::load(const QString &name, const
const QUrl url(name);
if (!url.isLocalFile() && !url.isRelative())
errs << QStringLiteral("src attribute is not a local file (%1)").arg(name);
- QFileInfo fInfo = url.isLocalFile() ? url.toLocalFile() : name;
+ QFileInfo fInfo(url.isLocalFile() ? url.toLocalFile() : name);
#endif // BUILD_QSCXMLC
if (fInfo.isRelative())
fInfo = QFileInfo(QDir(baseDir).filePath(fInfo.filePath()));
diff --git a/src/scxml/qscxmlcompiler.h b/src/scxml/qscxmlcompiler.h
index 411dfde..3eecca5 100644
--- a/src/scxml/qscxmlcompiler.h
+++ b/src/scxml/qscxmlcompiler.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLCOMPILER_H
#define QSCXMLCOMPILER_H
@@ -72,7 +36,7 @@ public:
void setLoader(Loader *newLoader);
QScxmlStateMachine *compile();
- QVector<QScxmlError> errors() const;
+ QList<QScxmlError> errors() const;
private:
friend class QScxmlCompilerPrivate;
diff --git a/src/scxml/qscxmlcompiler_p.h b/src/scxml/qscxmlcompiler_p.h
index 4b270f8..498018c 100644
--- a/src/scxml/qscxmlcompiler_p.h
+++ b/src/scxml/qscxmlcompiler_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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) 2021 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
#ifndef QSCXMLCOMPILER_P_H
#define QSCXMLCOMPILER_P_H
@@ -60,6 +24,9 @@
#include <QtCore/qstringlist.h>
#include <QtCore/qstring.h>
#include <QtCore/qxmlstream.h>
+#include <QtCore/private/qglobal_p.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
@@ -129,7 +96,7 @@ struct DoneData: public Node
{
QString contents;
QString expr;
- QVector<Param *> params;
+ QList<Param *> params;
DoneData(const XmlLocation &xmlLocation): Node(xmlLocation) {}
void accept(NodeVisitor *visitor) override;
@@ -141,8 +108,8 @@ struct Instruction: public Node
virtual ~Instruction() {}
};
-typedef QVector<Instruction *> InstructionSequence;
-typedef QVector<InstructionSequence *> InstructionSequences;
+typedef QList<Instruction *> InstructionSequence;
+typedef QList<InstructionSequence *> InstructionSequences;
struct Send: public Instruction
{
@@ -157,7 +124,7 @@ struct Send: public Instruction
QString delay;
QString delayexpr;
QStringList namelist;
- QVector<Param *> params;
+ QList<Param *> params;
QString content;
QString contentexpr;
@@ -177,7 +144,7 @@ struct Invoke: public Instruction
QString idLocation;
QStringList namelist;
bool autoforward;
- QVector<Param *> params;
+ QList<Param *> params;
InstructionSequence finalize;
QSharedPointer<ScxmlDocument> content;
@@ -285,12 +252,12 @@ struct State: public AbstractState, public StateOrTransition
enum Type { Normal, Parallel, Final };
QStringList initial;
- QVector<DataElement *> dataElements;
- QVector<StateOrTransition *> children;
+ QList<DataElement *> dataElements;
+ QList<StateOrTransition *> children;
InstructionSequences onEntry;
InstructionSequences onExit;
DoneData *doneData;
- QVector<Invoke *> invokes;
+ QList<Invoke *> invokes;
Type type;
Transition *initialTransition; // when not set, it is filled during verification
@@ -322,7 +289,7 @@ struct Transition: public StateOrTransition
InstructionSequence instructionsOnTransition;
Type type;
- QVector<AbstractState *> targetStates; // when not set, it is filled during verification
+ QList<AbstractState *> targetStates; // when not set, it is filled during verification
Transition(const XmlLocation &xmlLocation)
: StateOrTransition(xmlLocation)
@@ -338,7 +305,7 @@ struct HistoryState: public AbstractState, public StateOrTransition
{
enum Type { Deep, Shallow };
Type type;
- QVector<StateOrTransition *> children;
+ QList<StateOrTransition *> children;
HistoryState(const XmlLocation &xmlLocation)
: StateOrTransition(xmlLocation)
@@ -376,8 +343,8 @@ struct Scxml: public StateContainer, public Node
QString cppDataModelClassName;
QString cppDataModelHeaderName;
BindingMethod binding;
- QVector<StateOrTransition *> children;
- QVector<DataElement *> dataElements;
+ QList<StateOrTransition *> children;
+ QList<DataElement *> dataElements;
QScopedPointer<Script> script;
InstructionSequence initialSetup;
@@ -405,11 +372,11 @@ struct ScxmlDocument
{
const QString fileName;
Scxml *root;
- QVector<AbstractState *> allStates;
- QVector<Transition *> allTransitions;
- QVector<Node *> allNodes;
- QVector<InstructionSequence *> allSequences;
- QVector<ScxmlDocument *> allSubDocuments; // weak pointers
+ QList<AbstractState *> allStates;
+ QList<Transition *> allTransitions;
+ QList<Node *> allNodes;
+ QList<InstructionSequence *> allSequences;
+ QList<ScxmlDocument *> allSubDocuments; // weak pointers
bool isVerified;
ScxmlDocument(const QString &fileName)
@@ -508,13 +475,13 @@ public:
void visit(InstructionSequence *sequence)
{
Q_ASSERT(sequence);
- for (Instruction *instruction : qAsConst(*sequence)) {
+ for (Instruction *instruction : std::as_const(*sequence)) {
Q_ASSERT(instruction);
instruction->accept(this);
}
}
- void visit(const QVector<DataElement *> &dataElements)
+ void visit(const QList<DataElement *> &dataElements)
{
for (DataElement *dataElement : dataElements) {
Q_ASSERT(dataElement);
@@ -522,7 +489,7 @@ public:
}
}
- void visit(const QVector<StateOrTransition *> &children)
+ void visit(const QList<StateOrTransition *> &children)
{
for (StateOrTransition *child : children) {
Q_ASSERT(child);
@@ -538,7 +505,7 @@ public:
}
}
- void visit(const QVector<Param *> &params)
+ void visit(const QList<Param *> &params)
{
for (Param *param : params) {
Q_ASSERT(param);
@@ -574,7 +541,7 @@ public:
const QString &fileName);
QByteArray load(const QString &name, bool *ok);
- QVector<QScxmlError> errors() const;
+ QList<QScxmlError> errors() const;
void addError(const QString &msg);
void addError(const DocumentModel::XmlLocation &location, const QString &msg);
@@ -694,7 +661,7 @@ private:
bool validChild(ParserState::Kind child) const;
static bool validChild(ParserState::Kind parent, ParserState::Kind child);
static bool isExecutableContent(ParserState::Kind kind);
- static Kind nameToParserStateKind(const QStringRef &name);
+ static Kind nameToParserStateKind(QStringView name);
static QStringList requiredAttributes(Kind kind);
static QStringList optionalAttributes(Kind kind);
};
@@ -719,14 +686,14 @@ private:
QString m_fileName;
QSet<QString> m_allIds;
- QScopedPointer<DocumentModel::ScxmlDocument> m_doc;
+ std::unique_ptr<DocumentModel::ScxmlDocument> m_doc;
DocumentModel::StateContainer *m_currentState;
DefaultLoader m_defaultLoader;
QScxmlCompiler::Loader *m_loader;
QXmlStreamReader *m_reader;
- QVector<ParserState> m_stack;
- QVector<QScxmlError> m_errors;
+ QList<ParserState> m_stack;
+ QList<QScxmlError> m_errors;
};
QT_END_NAMESPACE
diff --git a/src/scxml/qscxmlcppdatamodel.cpp b/src/scxml/qscxmlcppdatamodel.cpp
index ba18cc7..f357eae 100644
--- a/src/scxml/qscxmlcppdatamodel.cpp
+++ b/src/scxml/qscxmlcppdatamodel.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlcppdatamodel_p.h"
#include "qscxmlstatemachine.h"
@@ -64,12 +28,12 @@ using namespace QScxmlExecutableContent;
The format of the \e datamodel attribute is: \c{cplusplus:<class-name>:<classdef-header>}.
So, for the example above, there should be a file \e thedatamodel.h containing a subclass of
QScxmlCppDataModel, containing at least the following:
- \code
+ \badcode
#include "qscxmlcppdatamodel.h"
class TheDataModel: public QScxmlCppDataModel
{
- Q_OBJECT
+ \Q_OBJECT
Q_SCXML_DATAMODEL
};
\endcode
@@ -123,7 +87,7 @@ void TheDataModel::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool
statements, and in \e cond or \e expr attributes you can use any C++ expression that can be
converted to the respective bool or QVariant. And, as the \c this pointer is also captured, you
can call or access the data model (the \e media attribute in the example above). For the full
- example, see \l {Qt SCXML: Media Player QML Example (C++ Data Model)}.
+ example, see \l {SCXML Media Player}.
*/
/*!
@@ -138,6 +102,8 @@ QScxmlCppDataModel::QScxmlCppDataModel(QObject *parent)
* for data model variables specified by their keys, \a initialDataValues. These
* are the values specified by \c <param> tags in an \c <invoke> element.
*
+ * Returns \c true on success.
+ *
* \sa QScxmlStateMachine::init
*/
bool QScxmlCppDataModel::setup(const QVariantMap &initialDataValues)
diff --git a/src/scxml/qscxmlcppdatamodel.h b/src/scxml/qscxmlcppdatamodel.h
index 8f71229..0fd4ba4 100644
--- a/src/scxml/qscxmlcppdatamodel.h
+++ b/src/scxml/qscxmlcppdatamodel.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLCPPDATAMODEL_H
#define QSCXMLCPPDATAMODEL_H
diff --git a/src/scxml/qscxmlcppdatamodel_p.h b/src/scxml/qscxmlcppdatamodel_p.h
index b342e39..2168d02 100644
--- a/src/scxml/qscxmlcppdatamodel_p.h
+++ b/src/scxml/qscxmlcppdatamodel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLCPPDATAMODEL_P_H
#define QSCXMLCPPDATAMODEL_P_H
diff --git a/src/scxml/qscxmldatamodel.cpp b/src/scxml/qscxmldatamodel.cpp
index ab0ae7c..eaa15e8 100644
--- a/src/scxml/qscxmldatamodel.cpp
+++ b/src/scxml/qscxmldatamodel.cpp
@@ -1,51 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmldatamodel_p.h"
#include "qscxmlnulldatamodel.h"
-#if QT_CONFIG(scxml_ecmascriptdatamodel)
-#include "qscxmlecmascriptdatamodel.h"
-#endif
#include "qscxmlstatemachine_p.h"
+#include <QtCore/private/qfactoryloader_p.h>
+#include "qscxmldatamodelplugin_p.h"
+
QT_BEGIN_NAMESPACE
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ ("org.qt-project.qt.scxml.datamodel.plugin",
+ QStringLiteral("/scxmldatamodel")))
+
/*!
\class QScxmlDataModel::ForeachLoopBody
\brief The ForeachLoopBody class represents a function to be executed on
@@ -85,7 +53,7 @@ QScxmlDataModel::ForeachLoopBody::~ForeachLoopBody()
*
* One data model can only belong to one state machine.
*
- * \sa QScxmlStateMachine QScxmlCppDataModel QScxmlEcmaScriptDataModel QScxmlNullDataModel
+ * \sa QScxmlStateMachine QScxmlCppDataModel QScxmlNullDataModel
*/
/*!
@@ -127,11 +95,13 @@ void QScxmlDataModel::setStateMachine(QScxmlStateMachine *stateMachine)
{
Q_D(QScxmlDataModel);
- if (d->m_stateMachine == nullptr && stateMachine != nullptr) {
- d->m_stateMachine = stateMachine;
- if (stateMachine)
- stateMachine->setDataModel(this);
- emit stateMachineChanged(stateMachine);
+ if (d->m_stateMachine.valueBypassingBindings() == nullptr && stateMachine != nullptr) {
+ // the binding is removed only on the first valid set
+ // as the later attempts are ignored
+ d->m_stateMachine.removeBindingUnlessInWrapper();
+ d->m_stateMachine.setValueBypassingBindings(stateMachine);
+ stateMachine->setDataModel(this);
+ d->m_stateMachine.notify();
}
}
@@ -144,6 +114,37 @@ QScxmlStateMachine *QScxmlDataModel::stateMachine() const
return d->m_stateMachine;
}
+QBindable<QScxmlStateMachine*> QScxmlDataModel::bindableStateMachine()
+{
+ Q_D(QScxmlDataModel);
+ return &d->m_stateMachine;
+}
+
+/*!
+ * Creates a data model from a plugin specified by a \a pluginKey.
+ */
+QScxmlDataModel *QScxmlDataModel::createScxmlDataModel(const QString& pluginKey)
+{
+ QScxmlDataModel *model = nullptr;
+
+ int pluginIndex = loader()->indexOf(pluginKey);
+
+ if (QObject *object = loader()->instance(pluginIndex)) {
+ if (auto *plugin = qobject_cast<QScxmlDataModelPlugin *>(object)) {
+ model = plugin->createScxmlDataModel();
+ if (!model)
+ qWarning() << pluginKey << " data model was not instantiated, createScxmlDataModel() returned null.";
+
+ } else {
+ qWarning() << "plugin object for" << pluginKey << "is not a QScxmlDatModelPlugin.";
+ }
+ delete object;
+ } else {
+ qWarning() << pluginKey << " plugin not found." ;
+ }
+ return model;
+}
+
QScxmlDataModel *QScxmlDataModelPrivate::instantiateDataModel(DocumentModel::Scxml::DataModelType type)
{
QScxmlDataModel *dataModel = nullptr;
@@ -152,16 +153,13 @@ QScxmlDataModel *QScxmlDataModelPrivate::instantiateDataModel(DocumentModel::Scx
dataModel = new QScxmlNullDataModel;
break;
case DocumentModel::Scxml::JSDataModel:
-#if QT_CONFIG(scxml_ecmascriptdatamodel)
- dataModel = new QScxmlEcmaScriptDataModel;
-#endif
+ dataModel = QScxmlDataModel::createScxmlDataModel(QStringLiteral("ecmascriptdatamodel"));
break;
case DocumentModel::Scxml::CppDataModel:
break;
default:
Q_UNREACHABLE();
}
-
return dataModel;
}
diff --git a/src/scxml/qscxmldatamodel.h b/src/scxml/qscxmldatamodel.h
index 0c9e666..5c1811d 100644
--- a/src/scxml/qscxmldatamodel.h
+++ b/src/scxml/qscxmldatamodel.h
@@ -1,63 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLDATAMODEL_H
#define QSCXMLDATAMODEL_H
#include <QtScxml/qscxmlexecutablecontent.h>
+#include <QtCore/qobject.h>
#include <QtCore/qvariant.h>
-#include <QtCore/qvector.h>
+
+Q_MOC_INCLUDE(qscxmlstatemachine.h)
QT_BEGIN_NAMESPACE
class QScxmlEvent;
class QScxmlStateMachine;
-class QScxmlTableData;
class QScxmlDataModelPrivate;
class Q_SCXML_EXPORT QScxmlDataModel : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QScxmlDataModel)
- Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine WRITE setStateMachine NOTIFY stateMachineChanged)
+ Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine WRITE setStateMachine
+ NOTIFY stateMachineChanged BINDABLE bindableStateMachine)
public:
class Q_SCXML_EXPORT ForeachLoopBody
@@ -72,8 +38,11 @@ public:
public:
explicit QScxmlDataModel(QObject *parent = nullptr);
+ static QScxmlDataModel *createScxmlDataModel(const QString& pluginKey);
+
void setStateMachine(QScxmlStateMachine *stateMachine);
QScxmlStateMachine *stateMachine() const;
+ QBindable<QScxmlStateMachine*> bindableStateMachine();
Q_INVOKABLE virtual bool setup(const QVariantMap &initialDataValues) = 0;
diff --git a/src/scxml/qscxmldatamodel_p.h b/src/scxml/qscxmldatamodel_p.h
index b91c63c..2432959 100644
--- a/src/scxml/qscxmldatamodel_p.h
+++ b/src/scxml/qscxmldatamodel_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLDATAMODEL_P_H
#define QSCXMLDATAMODEL_P_H
@@ -54,18 +18,31 @@
#include "qscxmldatamodel.h"
#include "qscxmlcompiler_p.h"
#include <private/qobject_p.h>
+#include <private/qproperty_p.h>
QT_BEGIN_NAMESPACE
class QScxmlDataModelPrivate : public QObjectPrivate
{
+ Q_DECLARE_PUBLIC(QScxmlDataModel)
public:
- QScxmlDataModelPrivate() : m_stateMachine(nullptr) {}
+ QScxmlDataModelPrivate() = default;
static QScxmlDataModel *instantiateDataModel(DocumentModel::Scxml::DataModelType type);
-public:
- QScxmlStateMachine *m_stateMachine;
+ void setStateMachine(QScxmlStateMachine* stateMachine)
+ {
+ q_func()->setStateMachine(stateMachine);
+ }
+
+ void emitStateMachineChanged(QScxmlStateMachine* newValue)
+ {
+ emit q_func()->stateMachineChanged(newValue);
+ }
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QScxmlDataModelPrivate, QScxmlStateMachine*, m_stateMachine,
+ &QScxmlDataModelPrivate::setStateMachine,
+ &QScxmlDataModelPrivate::emitStateMachineChanged, nullptr)
};
QT_END_NAMESPACE
diff --git a/src/scxml/qscxmldatamodelplugin.cpp b/src/scxml/qscxmldatamodelplugin.cpp
new file mode 100644
index 0000000..d60db70
--- /dev/null
+++ b/src/scxml/qscxmldatamodelplugin.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2021 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 "qscxmldatamodelplugin_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QScxmlDataModel *QScxmlDataModelPlugin::createScxmlDataModel() const
+{
+ return nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/scxml/qscxmldatamodelplugin_p.h b/src/scxml/qscxmldatamodelplugin_p.h
new file mode 100644
index 0000000..be00ea9
--- /dev/null
+++ b/src/scxml/qscxmldatamodelplugin_p.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2021 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
+
+#ifndef QSCXMLDATAMODELPLUGIN_P_H
+#define QSCXMLDATAMODELPLUGIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtScxml/private/qscxmlglobals_p.h>
+#include <QtScxml/qscxmldatamodel.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QScxmlDataModelPluginInterface_iid "org.qt-project.qt.scxml.datamodel.plugin"
+
+class Q_SCXML_EXPORT QScxmlDataModelPlugin : public QObject
+{
+ Q_OBJECT
+public:
+ virtual QScxmlDataModel *createScxmlDataModel() const;
+};
+
+Q_DECLARE_INTERFACE(QScxmlDataModelPlugin, QScxmlDataModelPluginInterface_iid)
+QT_END_NAMESPACE
+
+#endif // QSCXMLDATAMODELPLUGIN_P_H
diff --git a/src/scxml/qscxmlecmascriptdatamodel.h b/src/scxml/qscxmlecmascriptdatamodel.h
deleted file mode 100644
index 16f29d4..0000000
--- a/src/scxml/qscxmlecmascriptdatamodel.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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$
-**
-****************************************************************************/
-
-#ifndef QSCXMLECMASCRIPTDATAMODEL_H
-#define QSCXMLECMASCRIPTDATAMODEL_H
-
-#include <QtScxml/qscxmlglobals.h>
-#include <QtScxml/qscxmldatamodel.h>
-
-QT_BEGIN_NAMESPACE
-
-// We cannot use QT_REQUIRE_CONFIG here, because the feature name contains a dash.
-#if QT_CONFIG(scxml_ecmascriptdatamodel)
-
-class QScxmlEcmaScriptDataModelPrivate;
-class Q_SCXML_EXPORT QScxmlEcmaScriptDataModel: public QScxmlDataModel
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QScxmlEcmaScriptDataModel)
-public:
- explicit QScxmlEcmaScriptDataModel(QObject *parent = nullptr);
-
- Q_INVOKABLE bool setup(const QVariantMap &initialDataValues) override;
-
- QString evaluateToString(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
- bool evaluateToBool(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
- QVariant evaluateToVariant(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
- void evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
- void evaluateAssignment(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
- void evaluateInitialization(QScxmlExecutableContent::EvaluatorId id, bool *ok) override final;
- void evaluateForeach(QScxmlExecutableContent::EvaluatorId id, bool *ok, ForeachLoopBody *body) override final;
-
- void setScxmlEvent(const QScxmlEvent &event) override;
-
- QVariant scxmlProperty(const QString &name) const override;
- bool hasScxmlProperty(const QString &name) const override;
- bool setScxmlProperty(const QString &name, const QVariant &value, const QString &context) override;
-};
-
-#endif // QT_CONFIG(scxml_ecmascriptdatamodel)
-
-QT_END_NAMESPACE
-
-#endif // QSCXMLECMASCRIPTDATAMODEL_H
diff --git a/src/scxml/qscxmlecmascriptplatformproperties.cpp b/src/scxml/qscxmlecmascriptplatformproperties.cpp
deleted file mode 100644
index 95e3b4f..0000000
--- a/src/scxml/qscxmlecmascriptplatformproperties.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlecmascriptplatformproperties_p.h"
-#include "qscxmlstatemachine.h"
-
-#include <qjsengine.h>
-
-QT_BEGIN_NAMESPACE
-class QScxmlPlatformProperties::Data
-{
-public:
- Data()
- : m_stateMachine(nullptr)
- {}
-
- QScxmlStateMachine *m_stateMachine;
- QJSValue m_jsValue;
-};
-
-QScxmlPlatformProperties::QScxmlPlatformProperties(QObject *parent)
- : QObject(parent)
- , data(new Data)
-{}
-
-QScxmlPlatformProperties *QScxmlPlatformProperties::create(QJSEngine *engine, QScxmlStateMachine *stateMachine)
-{
- QScxmlPlatformProperties *pp = new QScxmlPlatformProperties(engine);
- pp->data->m_stateMachine = stateMachine;
- pp->data->m_jsValue = engine->newQObject(pp);
- return pp;
-}
-
-QScxmlPlatformProperties::~QScxmlPlatformProperties()
-{
- delete data;
-}
-
-QJSEngine *QScxmlPlatformProperties::engine() const
-{
- return qobject_cast<QJSEngine *>(parent());
-}
-
-QScxmlStateMachine *QScxmlPlatformProperties::stateMachine() const
-{
- return data->m_stateMachine;
-}
-
-QJSValue QScxmlPlatformProperties::jsValue() const
-{
- return data->m_jsValue;
-}
-
-/// _x.marks === "the spot"
-QString QScxmlPlatformProperties::marks() const
-{
- return QStringLiteral("the spot");
-}
-
-bool QScxmlPlatformProperties::inState(const QString &stateName)
-{
- return stateMachine()->isActive(stateName);
-}
-
-QT_END_NAMESPACE
diff --git a/src/scxml/qscxmlecmascriptplatformproperties_p.h b/src/scxml/qscxmlecmascriptplatformproperties_p.h
deleted file mode 100644
index e7b8a09..0000000
--- a/src/scxml/qscxmlecmascriptplatformproperties_p.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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$
-**
-****************************************************************************/
-
-#ifndef QSCXMLECMASCRIPTPLATFORMPROPERTIES_P_H
-#define QSCXMLECMASCRIPTPLATFORMPROPERTIES_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qscxmlglobals.h"
-
-#include <QtCore/qobject.h>
-
-QT_FORWARD_DECLARE_CLASS(QJSEngine)
-QT_FORWARD_DECLARE_CLASS(QJSValue)
-
-QT_REQUIRE_CONFIG(scxml_ecmascriptdatamodel);
-
-QT_BEGIN_NAMESPACE
-
-class QScxmlStateMachine;
-class QScxmlPlatformProperties: public QObject
-{
- Q_OBJECT
-
- QScxmlPlatformProperties(QObject *parent);
-
- Q_PROPERTY(QString marks READ marks CONSTANT)
-
-public:
- static QScxmlPlatformProperties *create(QJSEngine *engine, QScxmlStateMachine *stateMachine);
- ~QScxmlPlatformProperties();
-
- QJSEngine *engine() const;
- QScxmlStateMachine *stateMachine() const;
- QJSValue jsValue() const;
-
- QString marks() const;
-
- Q_INVOKABLE bool inState(const QString &stateName);
-
-private:
- class Data;
- Data *data;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSCXMLECMASCRIPTPLATFORMPROPERTIES_P_H
diff --git a/src/scxml/qscxmlerror.cpp b/src/scxml/qscxmlerror.cpp
index 3033040..b5b541b 100644
--- a/src/scxml/qscxmlerror.cpp
+++ b/src/scxml/qscxmlerror.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlerror.h"
diff --git a/src/scxml/qscxmlerror.h b/src/scxml/qscxmlerror.h
index 6e6e459..8b1201b 100644
--- a/src/scxml/qscxmlerror.h
+++ b/src/scxml/qscxmlerror.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLERROR_H
#define QSCXMLERROR_H
diff --git a/src/scxml/qscxmlevent.cpp b/src/scxml/qscxmlevent.cpp
index 2ec7566..3d4795f 100644
--- a/src/scxml/qscxmlevent.cpp
+++ b/src/scxml/qscxmlevent.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlexecutablecontent_p.h"
#include "qscxmlevent_p.h"
@@ -71,7 +35,7 @@ QScxmlEvent *QScxmlEventBuilder::buildEvent()
}
if (!ok) {
// expr evaluation failure results in the data property of the event being set to null. See e.g. test528.
- data = QVariant(QMetaType::VoidStar, 0);
+ data = QVariant(QMetaType(QMetaType::VoidStar), nullptr);
}
} else {
QVariantMap keyValues;
@@ -86,7 +50,7 @@ QScxmlEvent *QScxmlEventBuilder::buildEvent()
} else {
// If the evaluation of the <param> tags fails, set _event.data to an empty string.
// See test343.
- data = QVariant(QMetaType::VoidStar, 0);
+ data = QVariant(QMetaType(QMetaType::VoidStar), nullptr);
}
}
diff --git a/src/scxml/qscxmlevent.h b/src/scxml/qscxmlevent.h
index e07da7a..566f0c3 100644
--- a/src/scxml/qscxmlevent.h
+++ b/src/scxml/qscxmlevent.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLEVENT_H
#define QSCXMLEVENT_H
diff --git a/src/scxml/qscxmlevent_p.h b/src/scxml/qscxmlevent_p.h
index cf4e26a..b177b30 100644
--- a/src/scxml/qscxmlevent_p.h
+++ b/src/scxml/qscxmlevent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLEVENT_P_H
#define QSCXMLEVENT_P_H
diff --git a/src/scxml/qscxmlexecutablecontent.cpp b/src/scxml/qscxmlexecutablecontent.cpp
index 45079d7..eae7c4a 100644
--- a/src/scxml/qscxmlexecutablecontent.cpp
+++ b/src/scxml/qscxmlexecutablecontent.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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) 2018 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 "qscxmlglobals_p.h"
#include "qscxmlexecutablecontent_p.h"
@@ -234,7 +198,7 @@ using namespace QScxmlExecutableContent;
#ifndef BUILD_QSCXMLC
-static int parseTime(const QString &t, bool *ok = nullptr)
+static int parseTime(QStringView t, bool *ok = nullptr)
{
if (t.isEmpty()) {
if (ok)
@@ -250,7 +214,7 @@ static int parseTime(const QString &t, bool *ok = nullptr)
++startPos;
}
int pos = startPos;
- for (int endPos = t.length(); pos < endPos; ++pos) {
+ for (int endPos = t.size(); pos < endPos; ++pos) {
auto c = t[pos];
if (c < QLatin1Char('0') || c > QLatin1Char('9'))
break;
@@ -259,11 +223,11 @@ static int parseTime(const QString &t, bool *ok = nullptr)
if (ok) *ok = false;
return -1;
}
- int value = t.midRef(startPos, pos - startPos).toInt(ok);
+ int value = t.mid(startPos, pos - startPos).toInt(ok);
if (ok && !*ok) return -1;
- if (t.length() == pos + 1 && t[pos] == QLatin1Char('s')) {
+ if (t.size() == pos + 1 && t[pos] == QLatin1Char('s')) {
value *= 1000;
- } else if (t.length() != pos + 2 || t[pos] != QLatin1Char('m') || t[pos + 1] != QLatin1Char('s')) {
+ } else if (t.size() != pos + 2 || t[pos] != QLatin1Char('m') || t[pos + 1] != QLatin1Char('s')) {
if (ok) *ok = false;
return -1;
}
diff --git a/src/scxml/qscxmlexecutablecontent.h b/src/scxml/qscxmlexecutablecontent.h
index 8d2ef13..9d456c2 100644
--- a/src/scxml/qscxmlexecutablecontent.h
+++ b/src/scxml/qscxmlexecutablecontent.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLEXECUTABLECONTENT_H
#define QSCXMLEXECUTABLECONTENT_H
diff --git a/src/scxml/qscxmlexecutablecontent_p.h b/src/scxml/qscxmlexecutablecontent_p.h
index 5980330..90f779f 100644
--- a/src/scxml/qscxmlexecutablecontent_p.h
+++ b/src/scxml/qscxmlexecutablecontent_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLEXECUTABLECONTENT_P_H
#define QSCXMLEXECUTABLECONTENT_P_H
@@ -404,11 +368,17 @@ struct StateTable {
return *(start + idx + 1);
}
- struct const_iterator: public std::iterator<std::forward_iterator_tag, int, ptrdiff_t,
- const int *, const int &>
+ struct const_iterator
{
const_iterator(const Array &a, int pos): a(a), pos(pos) {}
+ // std::iterator_traits
+ using value_type = int;
+ using pointer = const int*;
+ using reference = const int&;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category = std::forward_iterator_tag;
+
const_iterator &operator++() {
if (pos < a.size()) ++pos;
return *this;
diff --git a/src/scxml/qscxmlglobals.h b/src/scxml/qscxmlglobals.h
index da45a2b..64169d2 100644
--- a/src/scxml/qscxmlglobals.h
+++ b/src/scxml/qscxmlglobals.h
@@ -1,59 +1,19 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLGLOBALS_H
#define QSCXMLGLOBALS_H
#include <QtCore/qglobal.h>
#include <QtScxml/qtscxml-config.h>
-QT_BEGIN_NAMESPACE
-
-#if defined(QT_STATIC) || defined(BUILD_QSCXMLC)
+#if defined(BUILD_QSCXMLC)
# define Q_SCXML_EXPORT
#else
-# ifdef QT_BUILD_SCXML_LIB
-# define Q_SCXML_EXPORT Q_DECL_EXPORT
-# else
-# define Q_SCXML_EXPORT Q_DECL_IMPORT
-# endif
+# include <QtScxml/qtscxmlexports.h>
#endif
+// Silence syncqt
+QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
#endif // QSCXMLGLOBALS_H
diff --git a/src/scxml/qscxmlglobals_p.h b/src/scxml/qscxmlglobals_p.h
index fac74dc..ba82405 100644
--- a/src/scxml/qscxmlglobals_p.h
+++ b/src/scxml/qscxmlglobals_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLGLOBALS_P_H
#define QSCXMLGLOBALS_P_H
@@ -52,7 +16,6 @@
//
#include "qscxmlglobals.h"
-
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
diff --git a/src/scxml/qscxmlinvokableservice.cpp b/src/scxml/qscxmlinvokableservice.cpp
index 912be00..0665406 100644
--- a/src/scxml/qscxmlinvokableservice.cpp
+++ b/src/scxml/qscxmlinvokableservice.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlglobals_p.h"
#include "qscxmlinvokableservice_p.h"
@@ -158,8 +122,8 @@ QScxmlInvokableServicePrivate::QScxmlInvokableServicePrivate(QScxmlStateMachine
QScxmlInvokableServiceFactoryPrivate::QScxmlInvokableServiceFactoryPrivate(
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &namelist,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters)
+ const QList<QScxmlExecutableContent::StringId> &namelist,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters)
: invokeInfo(invokeInfo)
, names(namelist)
, parameters(parameters)
@@ -168,8 +132,8 @@ QScxmlInvokableServiceFactoryPrivate::QScxmlInvokableServiceFactoryPrivate(
QScxmlStaticScxmlServiceFactoryPrivate::QScxmlStaticScxmlServiceFactoryPrivate(
const QMetaObject *metaObject,
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters)
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters)
: QScxmlInvokableServiceFactoryPrivate(invokeInfo, names, parameters), metaObject(metaObject)
{
}
@@ -188,8 +152,8 @@ QScxmlStateMachine *QScxmlInvokableService::parentStateMachine() const
QScxmlInvokableServiceFactory::QScxmlInvokableServiceFactory(
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
QObject *parent)
: QObject(*(new QScxmlInvokableServiceFactoryPrivate(invokeInfo, names, parameters)), parent)
{}
@@ -200,14 +164,14 @@ const QScxmlExecutableContent::InvokeInfo &QScxmlInvokableServiceFactory::invoke
return d->invokeInfo;
}
-const QVector<QScxmlExecutableContent::ParameterInfo> &
+const QList<QScxmlExecutableContent::ParameterInfo> &
QScxmlInvokableServiceFactory::parameters() const
{
Q_D(const QScxmlInvokableServiceFactory);
return d->parameters;
}
-const QVector<QScxmlExecutableContent::StringId> &QScxmlInvokableServiceFactory::names() const
+const QList<QScxmlExecutableContent::StringId> &QScxmlInvokableServiceFactory::names() const
{
Q_D(const QScxmlInvokableServiceFactory);
return d->names;
@@ -259,8 +223,8 @@ QString QScxmlInvokableServicePrivate::calculateId(
QVariantMap QScxmlInvokableServicePrivate::calculateData(
QScxmlStateMachine *parent,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
- const QVector<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &names,
bool *ok) const
{
Q_ASSERT(ok);
@@ -404,8 +368,8 @@ QScxmlStateMachine *QScxmlScxmlService::stateMachine() const
*/
QScxmlDynamicScxmlServiceFactory::QScxmlDynamicScxmlServiceFactory(
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
QObject *parent)
: QScxmlInvokableServiceFactory(invokeInfo, names, parameters, parent)
{}
@@ -427,8 +391,8 @@ QScxmlInvokableService *QScxmlDynamicScxmlServiceFactory::invoke(
QScxmlStaticScxmlServiceFactory::QScxmlStaticScxmlServiceFactory(
const QMetaObject *metaObject,
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &nameList,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &nameList,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
QObject *parent)
: QScxmlInvokableServiceFactory(*(new QScxmlStaticScxmlServiceFactoryPrivate(
metaObject, invokeInfo, nameList, parameters)), parent)
diff --git a/src/scxml/qscxmlinvokableservice.h b/src/scxml/qscxmlinvokableservice.h
index 65ce4fc..fdf7dad 100644
--- a/src/scxml/qscxmlinvokableservice.h
+++ b/src/scxml/qscxmlinvokableservice.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLINVOKABLESERVICE_H
#define QSCXMLINVOKABLESERVICE_H
@@ -76,20 +40,20 @@ class Q_SCXML_EXPORT QScxmlInvokableServiceFactory : public QObject
Q_OBJECT
Q_DECLARE_PRIVATE(QScxmlInvokableServiceFactory)
Q_PROPERTY(QScxmlExecutableContent::InvokeInfo invokeInfo READ invokeInfo CONSTANT)
- Q_PROPERTY(QVector<QScxmlExecutableContent::ParameterInfo> parameters READ parameters CONSTANT)
- Q_PROPERTY(QVector<QScxmlExecutableContent::StringId> names READ names CONSTANT)
+ Q_PROPERTY(QList<QScxmlExecutableContent::ParameterInfo> parameters READ parameters CONSTANT)
+ Q_PROPERTY(QList<QScxmlExecutableContent::StringId> names READ names CONSTANT)
public:
QScxmlInvokableServiceFactory(
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
QObject *parent = nullptr);
virtual QScxmlInvokableService *invoke(QScxmlStateMachine *parentStateMachine) = 0;
const QScxmlExecutableContent::InvokeInfo &invokeInfo() const;
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters() const;
- const QVector<QScxmlExecutableContent::StringId> &names() const;
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters() const;
+ const QList<QScxmlExecutableContent::StringId> &names() const;
protected:
QScxmlInvokableServiceFactory(QScxmlInvokableServiceFactoryPrivate &dd, QObject *parent);
@@ -104,8 +68,8 @@ public:
QScxmlStaticScxmlServiceFactory(
const QMetaObject *metaObject,
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &nameList,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &nameList,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
QObject *parent = nullptr);
QScxmlInvokableService *invoke(QScxmlStateMachine *parentStateMachine) override;
@@ -117,8 +81,8 @@ class Q_SCXML_EXPORT QScxmlDynamicScxmlServiceFactory: public QScxmlInvokableSer
public:
QScxmlDynamicScxmlServiceFactory(
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
QObject *parent = nullptr);
QScxmlInvokableService *invoke(QScxmlStateMachine *parentStateMachine) override;
diff --git a/src/scxml/qscxmlinvokableservice_p.h b/src/scxml/qscxmlinvokableservice_p.h
index dce1d64..a334c5a 100644
--- a/src/scxml/qscxmlinvokableservice_p.h
+++ b/src/scxml/qscxmlinvokableservice_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLINVOKABLESERVICE_P_H
#define QSCXMLINVOKABLESERVICE_P_H
@@ -64,8 +28,8 @@ public:
QString calculateId(QScxmlStateMachine *parent,
const QScxmlExecutableContent::InvokeInfo &invokeInfo, bool *ok) const;
QVariantMap calculateData(QScxmlStateMachine *parent,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
- const QVector<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &names,
bool *ok) const;
QScxmlStateMachine *parentStateMachine;
@@ -76,12 +40,12 @@ class QScxmlInvokableServiceFactoryPrivate : public QObjectPrivate
public:
QScxmlInvokableServiceFactoryPrivate(
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters);
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters);
QScxmlExecutableContent::InvokeInfo invokeInfo;
- QVector<QScxmlExecutableContent::StringId> names;
- QVector<QScxmlExecutableContent::ParameterInfo> parameters;
+ QList<QScxmlExecutableContent::StringId> names;
+ QList<QScxmlExecutableContent::ParameterInfo> parameters;
};
class Q_SCXML_EXPORT QScxmlScxmlService: public QScxmlInvokableService
@@ -111,8 +75,8 @@ public:
QScxmlStaticScxmlServiceFactoryPrivate(
const QMetaObject *metaObject,
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters);
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters);
const QMetaObject *metaObject;
};
diff --git a/src/scxml/qscxmlnulldatamodel.cpp b/src/scxml/qscxmlnulldatamodel.cpp
index 4759d22..c62226f 100644
--- a/src/scxml/qscxmlnulldatamodel.cpp
+++ b/src/scxml/qscxmlnulldatamodel.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlnulldatamodel.h"
#include "qscxmlevent.h"
@@ -99,7 +63,7 @@ public:
ResolvedEvaluatorInfo resolved;
if (expr.startsWith(QStringLiteral("In(")) && expr.endsWith(QLatin1Char(')'))) {
resolved.error = false;
- resolved.str = expr.mid(3, expr.length() - 4);
+ resolved.str = expr.mid(3, expr.size() - 4);
} else {
resolved.error = true;
resolved.str = QStringLiteral("%1 in %2").arg(expr, td->string(info.context));
diff --git a/src/scxml/qscxmlnulldatamodel.h b/src/scxml/qscxmlnulldatamodel.h
index b34428d..f999cf2 100644
--- a/src/scxml/qscxmlnulldatamodel.h
+++ b/src/scxml/qscxmlnulldatamodel.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLNULLDATAMODEL_H
#define QSCXMLNULLDATAMODEL_H
diff --git a/src/scxml/qscxmlstatemachine.cpp b/src/scxml/qscxmlstatemachine.cpp
index 23f8a71..04d3726 100644
--- a/src/scxml/qscxmlstatemachine.cpp
+++ b/src/scxml/qscxmlstatemachine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlstatemachine_p.h"
#include "qscxmlexecutablecontent_p.h"
@@ -94,16 +58,21 @@ Q_LOGGING_CATEGORY(scxmlLog, "scxml.statemachine")
*/
/*!
- \fn template<typename PointerToMemberFunction> QMetaObject::Connection QScxmlStateMachine::connectToEvent(
- const QString &scxmlEventSpec,
- const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
- PointerToMemberFunction method,
- Qt::ConnectionType type)
+ \fn template<typename Functor> QMetaObject::Connection QScxmlStateMachine::connectToEvent(
+ const QString &scxmlEventSpec,
+ const QObject *context,
+ Functor &&functor,
+ Qt::ConnectionType type)
+ \fn template<typename Functor> QMetaObject::Connection QScxmlStateMachine::connectToEvent(
+ const QString &scxmlEventSpec,
+ Functor &&functor,
+ Qt::ConnectionType type)
Creates a connection of the given \a type from the event specified by
- \a scxmlEventSpec to \a method in the \a receiver object.
+ \a scxmlEventSpec to \a functor, which can be a functor or a member function of
+ the optional \a context object.
- The receiver's \a method must take a QScxmlEvent as a parameter.
+ The receiver's \a functor must take a QScxmlEvent as a parameter.
In contrast to event specifications in SCXML documents, spaces are not
allowed in the \a scxmlEventSpec here. In order to connect to multiple
@@ -114,93 +83,28 @@ Q_LOGGING_CATEGORY(scxmlLog, "scxml.statemachine")
*/
/*!
- \fn template<typename Functor> typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction && !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type QScxmlStateMachine::connectToEvent(
- const QString &scxmlEventSpec,
- Functor functor,
- Qt::ConnectionType type)
-
- Creates a connection of the given \a type from the event specified by
- \a scxmlEventSpec to \a functor.
-
- The \a functor must take a QScxmlEvent as a parameter.
-
- In contrast to event specifications in SCXML documents, spaces are not
- allowed in the \a scxmlEventSpec here. In order to connect to multiple
- events with different prefixes, connectToEvent() has to be called multiple
- times.
-
- Returns a handle to the connection, which can be used later to disconnect.
-*/
-
-/*!
- \fn template<typename Functor> typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction && !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type QScxmlStateMachine::connectToEvent(
- const QString &scxmlEventSpec,
- const QObject *context,
- Functor functor,
- Qt::ConnectionType type)
-
- Creates a connection of the given \a type from the event specified by
- \a scxmlEventSpec to \a functor using \a context as context.
-
- The \a functor must take a QScxmlEvent as a parameter.
-
- In contrast to event specifications in SCXML documents, spaces are not
- allowed in the \a scxmlEventSpec here. In order to connect to multiple
- events with different prefixes, connectToEvent() has to be called multiple
- times.
-
- Returns a handle to the connection, which can be used later to disconnect.
-*/
-
-/*!
- \fn template<typename PointerToMemberFunction> QMetaObject::Connection QScxmlStateMachine::connectToState(
- const QString &scxmlStateName,
- const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
- PointerToMemberFunction method,
- Qt::ConnectionType type)
+ \fn template<typename Functor> QMetaObject::Connection QScxmlStateMachine::connectToState(
+ const QString &scxmlStateName,
+ const QObject *context,
+ Functor &&functor,
+ Qt::ConnectionType type)
+ \fn template<typename Functor> QMetaObject::Connection QScxmlStateMachine::connectToState(
+ const QString &scxmlStateName,
+ Functor &&functor,
+ Qt::ConnectionType type)
Creates a connection of the given \a type from the state specified by
- \a scxmlStateName to \a method in the \a receiver object.
+ \a scxmlStateName to \a functor, which can be a functor or a member function of
+ the optional \a context object.
- The receiver's \a method must take a boolean argument that indicates
+ The receiver's \a functor must take a boolean argument that indicates
whether the state connected became active or inactive.
Returns a handle to the connection, which can be used later to disconnect.
*/
/*!
- \fn template<typename Functor> typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction && !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type QScxmlStateMachine::connectToState(
- const QString &scxmlStateName,
- Functor functor,
- Qt::ConnectionType type)
-
- Creates a connection of the given \a type from the state specified by
- \a scxmlStateName to \a functor.
-
- The \a functor must take a boolean argument that indicates whether the
- state connected became active or inactive.
-
- Returns a handle to the connection, which can be used later to disconnect.
-*/
-
-/*!
- \fn template<typename Functor> typename QtPrivate::QEnableIf<!QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction && !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type QScxmlStateMachine::connectToState(
- const QString &scxmlStateName,
- const QObject *context,
- Functor functor,
- Qt::ConnectionType type)
-
- Creates a connection of the given \a type from the state specified by
- \a scxmlStateName to \a functor using \a context as context.
-
- The \a functor must take a boolean argument that indicates whether the
- state connected became active or inactive.
-
- Returns a handle to the connection, which can be used later to disconnect.
-*/
-
-/*!
- \fn std::function<void(bool)> QScxmlStateMachine::onEntry(
+ \fn [onentry] std::function<void(bool)> QScxmlStateMachine::onEntry(
const QObject *receiver, const char *method)
Returns a functor that accepts a boolean argument and calls the given
@@ -215,7 +119,7 @@ Q_LOGGING_CATEGORY(scxmlLog, "scxml.statemachine")
*/
/*!
- \fn std::function<void(bool)> QScxmlStateMachine::onExit(
+ \fn [onexit] std::function<void(bool)> QScxmlStateMachine::onExit(
const QObject *receiver, const char *method)
Returns a functor that accepts a boolean argument and calls the given
@@ -230,7 +134,7 @@ Q_LOGGING_CATEGORY(scxmlLog, "scxml.statemachine")
*/
/*!
- \fn template<typename Functor> std::function<void(bool)> QScxmlStateMachine::onEntry(
+ \fn [onentry-functor] template<typename Functor> std::function<void(bool)> QScxmlStateMachine::onEntry(
Functor functor)
Returns a functor that accepts a boolean argument and calls the given
@@ -242,7 +146,7 @@ Q_LOGGING_CATEGORY(scxmlLog, "scxml.statemachine")
*/
/*!
- \fn template<typename Functor> std::function<void(bool)> QScxmlStateMachine::onExit(Functor functor)
+ \fn [onexit-functor] template<typename Functor> std::function<void(bool)> QScxmlStateMachine::onExit(Functor functor)
Returns a functor that accepts a boolean argument and calls the given
\a functor if that argument is \c false. The given \a functor must not
@@ -253,7 +157,7 @@ Q_LOGGING_CATEGORY(scxmlLog, "scxml.statemachine")
*/
/*!
- \fn template<typename PointerToMemberFunction> std::function<void(bool)> QScxmlStateMachine::onEntry(
+ \fn [onentry-template] template<typename PointerToMemberFunction> std::function<void(bool)> QScxmlStateMachine::onEntry(
const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
PointerToMemberFunction method)
@@ -267,7 +171,7 @@ Q_LOGGING_CATEGORY(scxmlLog, "scxml.statemachine")
*/
/*!
- \fn template<typename PointerToMemberFunction> std::function<void(bool)> QScxmlStateMachine::onExit(
+ \fn [onexit-template] template<typename PointerToMemberFunction> std::function<void(bool)> QScxmlStateMachine::onExit(
const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
PointerToMemberFunction method)
@@ -429,12 +333,8 @@ QScxmlStateMachinePrivate::QScxmlStateMachinePrivate(const QMetaObject *metaObje
: QObjectPrivate()
, m_sessionId(QScxmlStateMachinePrivate::generateSessionId(QStringLiteral("session-")))
, m_isInvoked(false)
- , m_isInitialized(false)
, m_isProcessingEvents(false)
- , m_dataModel(nullptr)
- , m_loader(&m_defaultLoader)
, m_executionEngine(nullptr)
- , m_tableData(nullptr)
, m_parentStateMachine(nullptr)
, m_eventLoopHook(this)
, m_metaObject(metaObject)
@@ -442,6 +342,7 @@ QScxmlStateMachinePrivate::QScxmlStateMachinePrivate(const QMetaObject *metaObje
{
static int metaType = qRegisterMetaType<QScxmlStateMachine *>();
Q_UNUSED(metaType);
+ m_loader.setValueBypassingBindings(&m_defaultLoader);
}
QScxmlStateMachinePrivate::~QScxmlStateMachinePrivate()
@@ -502,13 +403,13 @@ QScxmlInvokableServiceFactory *QScxmlStateMachinePrivate::serviceFactory(int id)
Q_ASSERT(id <= m_stateTable->maxServiceId && id >= 0);
QScxmlInvokableServiceFactory *& factory = m_cachedFactories[size_t(id)];
if (factory == nullptr)
- factory = m_tableData->serviceFactory(id);
+ factory = m_tableData.value()->serviceFactory(id);
return factory;
}
bool QScxmlStateMachinePrivate::executeInitialSetup()
{
- return m_executionEngine->execute(m_tableData->initialSetup());
+ return m_executionEngine->execute(m_tableData.value()->initialSetup());
}
void QScxmlStateMachinePrivate::routeEvent(QScxmlEvent *event)
@@ -529,7 +430,7 @@ void QScxmlStateMachinePrivate::routeEvent(QScxmlEvent *event)
}
} else if (origin.startsWith(QStringLiteral("#_")) && origin != QStringLiteral("#_internal")) {
// route to children
- auto originId = origin.midRef(2);
+ auto originId = QStringView{origin}.mid(2);
for (const auto &invokedService : m_invokedServices) {
auto service = invokedService.service;
if (service == nullptr)
@@ -727,12 +628,12 @@ void QScxmlStateMachinePrivate::processEvents()
void QScxmlStateMachinePrivate::setEvent(QScxmlEvent *event)
{
Q_ASSERT(event);
- m_dataModel->setScxmlEvent(*event);
+ m_dataModel.value()->setScxmlEvent(*event);
}
void QScxmlStateMachinePrivate::resetEvent()
{
- m_dataModel->setScxmlEvent(QScxmlEvent());
+ m_dataModel.value()->setScxmlEvent(QScxmlEvent());
}
void QScxmlStateMachinePrivate::emitStateActive(int stateIndex, bool active)
@@ -747,6 +648,7 @@ void QScxmlStateMachinePrivate::emitStateActive(int stateIndex, bool active)
void QScxmlStateMachinePrivate::emitInvokedServicesChanged()
{
Q_Q(QScxmlStateMachine);
+ m_invokedServicesComputedProperty.notify();
emit q->invokedServicesChanged(q->invokedServices());
}
@@ -767,10 +669,14 @@ void QScxmlStateMachinePrivate::attach(QScxmlStateMachineInfo *info)
void QScxmlStateMachinePrivate::updateMetaCache()
{
+ // This function creates a mapping from state index/name to their signal indexes.
+ // The state index may differ from its signal index as we don't generate history
+ // and invalid states, effectively skipping them
m_stateIndexToSignalIndex.clear();
m_stateNameToSignalIndex.clear();
- if (!m_tableData)
+ const QScxmlTableData *tableData = m_tableData.valueBypassingBindings();
+ if (!tableData)
return;
if (!m_stateTable)
@@ -782,7 +688,7 @@ void QScxmlStateMachinePrivate::updateMetaCache()
const auto &s = m_stateTable->state(i);
if (!s.isHistoryState() && s.type != StateTable::State::Invalid) {
m_stateIndexToSignalIndex.insert(i, signalIndex);
- m_stateNameToSignalIndex.insert(m_tableData->string(s.name),
+ m_stateNameToSignalIndex.insert(tableData->string(s.name),
signalIndex + methodOffset);
++signalIndex;
@@ -794,7 +700,7 @@ QStringList QScxmlStateMachinePrivate::stateNames(const std::vector<int> &stateI
{
QStringList names;
for (int idx : stateIndexes)
- names.append(m_tableData->string(m_stateTable->state(idx).name));
+ names.append(m_tableData.value()->string(m_stateTable->state(idx).name));
return names;
}
@@ -852,7 +758,7 @@ bool QScxmlStateMachinePrivate::nameMatch(const StateTable::Array &patterns,
const QString eventName = event->name();
bool selected = false;
for (int eventSelectorIter = 0; eventSelectorIter < patterns.size(); ++eventSelectorIter) {
- QString eventStr = m_tableData->string(patterns[eventSelectorIter]);
+ QString eventStr = m_tableData.value()->string(patterns[eventSelectorIter]);
if (eventStr == QStringLiteral("*")) {
selected = true;
break;
@@ -913,7 +819,7 @@ void QScxmlStateMachinePrivate::selectTransitions(OrderedSet &enabledTransitions
enabled = true;
} else {
bool ok = false;
- enabled = m_dataModel->evaluateToBool(t.condition, &ok) && ok;
+ enabled = m_dataModel.value()->evaluateToBool(t.condition, &ok) && ok;
}
}
} else {
@@ -922,7 +828,7 @@ void QScxmlStateMachinePrivate::selectTransitions(OrderedSet &enabledTransitions
enabled = true;
} else {
bool ok = false;
- enabled = m_dataModel->evaluateToBool(t.condition, &ok) && ok;
+ enabled = m_dataModel.value()->evaluateToBool(t.condition, &ok) && ok;
}
}
}
@@ -1037,13 +943,13 @@ void QScxmlStateMachinePrivate::microstep(const OrderedSet &enabledTransitions)
const auto &transition = m_stateTable->transition(t);
QString from = QStringLiteral("(none)");
if (transition.source != StateTable::InvalidIndex)
- from = m_tableData->string(m_stateTable->state(transition.source).name);
+ from = m_tableData.value()->string(m_stateTable->state(transition.source).name);
QStringList to;
if (transition.targets == StateTable::InvalidIndex) {
to.append(QStringLiteral("(none)"));
} else {
for (int t : m_stateTable->array(transition.targets))
- to.append(m_tableData->string(m_stateTable->state(t).name));
+ to.append(m_tableData.value()->string(m_stateTable->state(t).name));
}
qCDebug(qscxmlLog) << q_func() << "\t" << t << ":" << from << "->"
<< to.join(QLatin1Char(','));
@@ -1073,7 +979,7 @@ void QScxmlStateMachinePrivate::exitStates(const OrderedSet &enabledTransitions)
for (int s : statesToExitSorted) {
for (int h : historyStates(s)) {
const auto &hState = m_stateTable->state(h);
- QVector<int> history;
+ QList<int> history;
for (int s0 : m_configuration) {
const auto &s0State = m_stateTable->state(s0);
@@ -1100,7 +1006,7 @@ void QScxmlStateMachinePrivate::exitStates(const OrderedSet &enabledTransitions)
if (m_infoSignalProxy) {
emit m_infoSignalProxy->statesExited(
- QVector<QScxmlStateMachineInfo::StateId>(statesToExitSorted.begin(),
+ QList<QScxmlStateMachineInfo::StateId>(statesToExitSorted.begin(),
statesToExitSorted.end()));
}
}
@@ -1132,7 +1038,7 @@ void QScxmlStateMachinePrivate::executeTransitionContent(const OrderedSet &enabl
if (m_infoSignalProxy) {
emit m_infoSignalProxy->transitionsTriggered(
- QVector<QScxmlStateMachineInfo::TransitionId>(enabledTransitions.list().begin(),
+ QList<QScxmlStateMachineInfo::TransitionId>(enabledTransitions.list().begin(),
enabledTransitions.list().end()));
}
}
@@ -1176,7 +1082,7 @@ void QScxmlStateMachinePrivate::enterStates(const OrderedSet &enabledTransitions
emit q->runningChanged(false);
} else {
const auto &parent = m_stateTable->state(state.parent);
- m_executionEngine->execute(state.doneData, m_tableData->string(parent.name));
+ m_executionEngine->execute(state.doneData, m_tableData.value()->string(parent.name));
if (parent.parent != StateTable::InvalidIndex) {
const auto &grandParent = m_stateTable->state(parent.parent);
if (grandParent.isParallel()) {
@@ -1184,7 +1090,7 @@ void QScxmlStateMachinePrivate::enterStates(const OrderedSet &enabledTransitions
auto e = new QScxmlEvent;
e->setEventType(QScxmlEvent::InternalEvent);
e->setName(QStringLiteral("done.state.")
- + m_tableData->string(grandParent.name));
+ + m_tableData.value()->string(grandParent.name));
q->submitEvent(e);
}
}
@@ -1196,7 +1102,7 @@ void QScxmlStateMachinePrivate::enterStates(const OrderedSet &enabledTransitions
emitStateActive(s, true);
if (m_infoSignalProxy) {
emit m_infoSignalProxy->statesEntered(
- QVector<QScxmlStateMachineInfo::StateId>(sortedStates.begin(),
+ QList<QScxmlStateMachineInfo::StateId>(sortedStates.begin(),
sortedStates.end()));
}
}
@@ -1247,7 +1153,15 @@ void QScxmlStateMachinePrivate::addDescendantStatesToEnter(
addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry,
defaultHistoryContent);
} else {
- const auto transitionIdx = m_stateTable->array(state.transitions)[0];
+ int transitionIdx = StateTable::InvalidIndex;
+ if (state.transitions == StateTable::InvalidIndex) {
+ int parentInitialTransition = m_stateTable->state(state.parent).initialTransition;
+ if (parentInitialTransition == StateTable::InvalidIndex)
+ return;
+ transitionIdx = parentInitialTransition;
+ } else {
+ transitionIdx = m_stateTable->array(state.transitions)[0];
+ }
const auto &defaultHistoryTransition = m_stateTable->transition(transitionIdx);
defaultHistoryContent->operator[](state.parent) =
defaultHistoryTransition.transitionInstructions;
@@ -1457,7 +1371,7 @@ void QScxmlStateMachinePrivate::getEffectiveTargetStates(OrderedSet *targets,
for (int historyState : historyValueIter.value()) {
targets->add(historyState);
}
- } else {
+ } else if (state.transitions != StateTable::InvalidIndex) {
getEffectiveTargetStates(targets, m_stateTable->array(state.transitions)[0]);
}
} else {
@@ -1507,10 +1421,10 @@ QScxmlStateMachine *QScxmlStateMachine::fromData(QIODevice *data, const QString
return compiler.compile();
}
-QVector<QScxmlError> QScxmlStateMachine::parseErrors() const
+QList<QScxmlError> QScxmlStateMachine::parseErrors() const
{
Q_D(const QScxmlStateMachine);
- return d->m_parserData ? d->m_parserData->m_errors : QVector<QScxmlError>();
+ return d->m_parserData ? d->m_parserData->m_errors : QList<QScxmlError>();
}
QScxmlStateMachine::QScxmlStateMachine(const QMetaObject *metaObject, QObject *parent)
@@ -1553,8 +1467,7 @@ QScxmlStateMachine::QScxmlStateMachine(QScxmlStateMachinePrivate &dd, QObject *p
Changing the data model when the state machine has been \c initialized is
not specified in the SCXML standard and leads to undefined behavior.
- \sa QScxmlDataModel, QScxmlNullDataModel, QScxmlEcmaScriptDataModel,
- QScxmlCppDataModel
+ \sa QScxmlDataModel, QScxmlNullDataModel, QScxmlCppDataModel
*/
/*!
@@ -1569,8 +1482,7 @@ QScxmlStateMachine::QScxmlStateMachine(QScxmlStateMachinePrivate &dd, QObject *p
Changing the data model when the state machine has been \l initialized is
not specified in the SCXML standard and leads to undefined behavior.
- \sa QScxmlDataModel, QScxmlNullDataModel, QScxmlEcmaScriptDataModel,
- QScxmlCppDataModel
+ \sa QScxmlDataModel, QScxmlNullDataModel, QScxmlCppDataModel
*/
/*!
@@ -1723,6 +1635,12 @@ bool QScxmlStateMachine::isInitialized() const
return d->m_isInitialized;
}
+QBindable<bool> QScxmlStateMachine::bindableInitialized() const
+{
+ Q_D(const QScxmlStateMachine);
+ return &d->m_isInitialized;
+}
+
/*!
* Sets the data model for this state machine to \a model. There is a 1:1
* relation between state machines and models. After setting the model once you
@@ -1733,10 +1651,13 @@ void QScxmlStateMachine::setDataModel(QScxmlDataModel *model)
{
Q_D(QScxmlStateMachine);
- if (d->m_dataModel == nullptr && model != nullptr) {
- d->m_dataModel = model;
- if (model)
- model->setStateMachine(this);
+ if (d->m_dataModel.valueBypassingBindings() == nullptr && model != nullptr) {
+ // the binding is removed only on the first valid set
+ // as the later attempts are ignored
+ d->m_dataModel.removeBindingUnlessInWrapper();
+ d->m_dataModel.setValueBypassingBindings(model);
+ model->setStateMachine(this);
+ d->m_dataModel.notify();
emit dataModelChanged(model);
}
}
@@ -1751,14 +1672,16 @@ QScxmlDataModel *QScxmlStateMachine::dataModel() const
return d->m_dataModel;
}
-void QScxmlStateMachine::setLoader(QScxmlCompiler::Loader *loader)
+QBindable<QScxmlDataModel*> QScxmlStateMachine::bindableDataModel()
{
Q_D(QScxmlStateMachine);
+ return &d->m_dataModel;
+}
- if (loader != d->m_loader) {
- d->m_loader = loader;
- emit loaderChanged(loader);
- }
+void QScxmlStateMachine::setLoader(QScxmlCompiler::Loader *loader)
+{
+ Q_D(QScxmlStateMachine);
+ d->m_loader.setValue(loader);
}
QScxmlCompiler::Loader *QScxmlStateMachine::loader() const
@@ -1768,6 +1691,12 @@ QScxmlCompiler::Loader *QScxmlStateMachine::loader() const
return d->m_loader;
}
+QBindable<QScxmlCompiler::Loader*> QScxmlStateMachine::bindableLoader()
+{
+ Q_D(QScxmlStateMachine);
+ return &d->m_loader;
+}
+
QScxmlTableData *QScxmlStateMachine::tableData() const
{
Q_D(const QScxmlStateMachine);
@@ -1779,14 +1708,18 @@ void QScxmlStateMachine::setTableData(QScxmlTableData *tableData)
{
Q_D(QScxmlStateMachine);
- if (d->m_tableData == tableData)
+ d->m_tableData.removeBindingUnlessInWrapper();
+ if (d->m_tableData.valueBypassingBindings() == tableData)
return;
- d->m_tableData = tableData;
+ d->m_tableData.setValueBypassingBindings(tableData);
if (tableData) {
d->m_stateTable = reinterpret_cast<const QScxmlExecutableContent::StateTable *>(
tableData->stateMachineTable());
- if (objectName().isEmpty()) {
+ // cannot use objectName() here, because it creates binding loop
+ const QString currentObjectName = d->extraData
+ ? d->extraData->objectName.valueBypassingBindings() : QString();
+ if (currentObjectName.isEmpty()) {
setObjectName(tableData->name());
}
if (d->m_stateTable->maxServiceId != QScxmlExecutableContent::StateTable::InvalidIndex) {
@@ -1806,9 +1739,16 @@ void QScxmlStateMachine::setTableData(QScxmlTableData *tableData)
d->updateMetaCache();
+ d->m_tableData.notify();
emit tableDataChanged(tableData);
}
+QBindable<QScxmlTableData*> QScxmlStateMachine::bindableTableData()
+{
+ Q_D(QScxmlStateMachine);
+ return &d->m_tableData;
+}
+
/*!
\qmlmethod ScxmlStateMachine::stateNames(bool compress)
@@ -1845,7 +1785,7 @@ QStringList QScxmlStateMachine::stateNames(bool compress) const
for (int i = 0; i < d->m_stateTable->stateCount; ++i) {
const auto &state = d->m_stateTable->state(i);
if (!compress || state.isAtomic())
- names.append(d->m_tableData->string(state.name));
+ names.append(d->m_tableData.value()->string(state.name));
}
return names;
}
@@ -1876,7 +1816,7 @@ QStringList QScxmlStateMachine::activeStateNames(bool compress) const
for (int stateIdx : d->m_configuration) {
const auto &state = d->m_stateTable->state(stateIdx);
if (state.isAtomic() || !compress)
- result.append(d->m_tableData->string(state.name));
+ result.append(d->m_tableData.value()->string(state.name));
}
return result;
}
@@ -1897,7 +1837,7 @@ bool QScxmlStateMachine::isActive(const QString &scxmlStateName) const
for (int stateIndex : d->m_configuration) {
const auto &state = d->m_stateTable->state(stateIndex);
- if (d->m_tableData->string(state.name) == scxmlStateName)
+ if (d->m_tableData.value()->string(state.name) == scxmlStateName)
return true;
}
@@ -1914,7 +1854,7 @@ QMetaObject::Connection QScxmlStateMachine::connectToStateImpl(const QString &sc
types = QtPrivate::ConnectionTypes<QtPrivate::List<bool> >::types();
Q_D(QScxmlStateMachine);
- const int signalIndex = d->m_stateNameToSignalIndex.value(scxmlStateName);
+ const int signalIndex = d->m_stateNameToSignalIndex.value(scxmlStateName, -1);
return signalIndex < 0 ? QMetaObject::Connection()
: QObjectPrivate::connectImpl(this, signalIndex, receiver, slot, slotObj,
type, types, d->m_metaObject);
@@ -2003,20 +1943,19 @@ bool QScxmlStateMachine::init()
{
Q_D(QScxmlStateMachine);
- if (d->m_isInitialized)
+ if (d->m_isInitialized.value())
return false;
if (!parseErrors().isEmpty())
return false;
- if (!dataModel() || !dataModel()->setup(d->m_initialValues))
+ if (!dataModel() || !dataModel()->setup(d->m_initialValues.value()))
return false;
if (!d->executeInitialSetup())
return false;
- d->m_isInitialized = true;
- emit initializedChanged(true);
+ d->m_isInitialized.setValue(true);
return true;
}
@@ -2054,10 +1993,13 @@ QVariantMap QScxmlStateMachine::initialValues()
void QScxmlStateMachine::setInitialValues(const QVariantMap &initialValues)
{
Q_D(QScxmlStateMachine);
- if (initialValues != d->m_initialValues) {
- d->m_initialValues = initialValues;
- emit initialValuesChanged(initialValues);
- }
+ d->m_initialValues.setValue(initialValues);
+}
+
+QBindable<QVariantMap> QScxmlStateMachine::bindableInitialValues()
+{
+ Q_D(QScxmlStateMachine);
+ return &d->m_initialValues;
}
QString QScxmlStateMachine::name() const
@@ -2206,7 +2148,7 @@ bool QScxmlStateMachine::isDispatchableTarget(const QString &target) const
return true; // that's the current state machine
if (target.startsWith(QStringLiteral("#_"))) {
- QStringRef targetId = target.midRef(2);
+ QStringView targetId = QStringView{target}.mid(2);
for (auto invokedService : d->m_invokedServices) {
if (invokedService.service && invokedService.service->id() == targetId)
return true;
@@ -2229,16 +2171,16 @@ bool QScxmlStateMachine::isDispatchableTarget(const QString &target) const
state machine (possibly recursively).
*/
-QVector<QScxmlInvokableService *> QScxmlStateMachine::invokedServices() const
+QList<QScxmlInvokableService *> QScxmlStateMachine::invokedServices() const
{
Q_D(const QScxmlStateMachine);
+ return d->m_invokedServicesComputedProperty;
+}
- QVector<QScxmlInvokableService *> result;
- for (int i = 0, ei = int(d->m_invokedServices.size()); i != ei; ++i) {
- if (auto service = d->m_invokedServices[size_t(i)].service)
- result.append(service);
- }
- return result;
+QBindable<QList<QScxmlInvokableService*>> QScxmlStateMachine::bindableInvokedServices()
+{
+ Q_D(QScxmlStateMachine);
+ return &d->m_invokedServicesComputedProperty;
}
/*!
@@ -2310,20 +2252,28 @@ QVector<QScxmlInvokableService *> QScxmlStateMachine::invokedServices() const
*/
/*!
- Starts this state machine. The machine will reset its configuration and
- transition to the initial state. When a final top-level state
+ Starts this state machine. When a final top-level state
is entered, the machine will emit the finished() signal.
\note A state machine will not run without a running event loop, such as
the main application event loop started with QCoreApplication::exec() or
QApplication::exec().
+ \note Calling start() after stop() will not result in a full reset of its
+ configuration yet, hence it is strongly advised not to do it.
+
+ \note Starting a finished machine yields a warning.
+
\sa runningChanged(), setRunning(), stop(), finished()
*/
void QScxmlStateMachine::start()
{
Q_D(QScxmlStateMachine);
+ if (d->isFinished()) {
+ qCWarning(qscxmlLog) << this << "Can't start finished machine";
+ }
+
if (!parseErrors().isEmpty())
return;
@@ -2366,7 +2316,11 @@ void QScxmlStateMachine::stop()
bool QScxmlStateMachine::isActive(int stateIndex) const
{
Q_D(const QScxmlStateMachine);
- return d->m_configuration.contains(stateIndex);
+ // Here we need to find the actual internal state index that corresponds with the
+ // index of the compiled metaobject (which is same as its mapped signal index).
+ // See updateMetaCache()
+ const int mappedStateIndex = d->m_stateIndexToSignalIndex.key(stateIndex, -1);
+ return d->m_configuration.contains(mappedStateIndex);
}
QT_END_NAMESPACE
diff --git a/src/scxml/qscxmlstatemachine.h b/src/scxml/qscxmlstatemachine.h
index a0a4e8b..a63a602 100644
--- a/src/scxml/qscxmlstatemachine.h
+++ b/src/scxml/qscxmlstatemachine.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLSTATEMACHINE_H
#define QSCXMLSTATEMACHINE_H
@@ -46,18 +10,21 @@
#include <QtScxml/qscxmlcompiler.h>
#include <QtScxml/qscxmlinvokableservice.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qpointer.h>
#include <QtCore/qstring.h>
-#include <QtCore/qvector.h>
#include <QtCore/qurl.h>
#include <QtCore/qvariant.h>
-#include <QtCore/qpointer.h>
#include <functional>
+Q_MOC_INCLUDE(qscxmltabledata.h)
+
QT_BEGIN_NAMESPACE
class QIODevice;
class QXmlStreamWriter;
class QTextStream;
+class QScxmlTableData;
class QScxmlStateMachinePrivate;
class Q_SCXML_EXPORT QScxmlStateMachine: public QObject
@@ -65,16 +32,22 @@ class Q_SCXML_EXPORT QScxmlStateMachine: public QObject
Q_DECLARE_PRIVATE(QScxmlStateMachine)
Q_OBJECT
Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
- Q_PROPERTY(bool initialized READ isInitialized NOTIFY initializedChanged)
- Q_PROPERTY(QScxmlDataModel *dataModel READ dataModel WRITE setDataModel NOTIFY dataModelChanged)
- Q_PROPERTY(QVariantMap initialValues READ initialValues WRITE setInitialValues NOTIFY initialValuesChanged)
- Q_PROPERTY(QVector<QScxmlInvokableService*> invokedServices READ invokedServices NOTIFY invokedServicesChanged)
+ Q_PROPERTY(bool initialized READ isInitialized
+ NOTIFY initializedChanged BINDABLE bindableInitialized)
+ Q_PROPERTY(QScxmlDataModel *dataModel READ dataModel WRITE setDataModel
+ NOTIFY dataModelChanged BINDABLE bindableDataModel)
+ Q_PROPERTY(QVariantMap initialValues READ initialValues WRITE setInitialValues
+ NOTIFY initialValuesChanged BINDABLE bindableInitialValues)
+ Q_PROPERTY(QList<QScxmlInvokableService*> invokedServices READ invokedServices
+ NOTIFY invokedServicesChanged BINDABLE bindableInvokedServices)
Q_PROPERTY(QString sessionId READ sessionId CONSTANT)
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(bool invoked READ isInvoked CONSTANT)
- Q_PROPERTY(QVector<QScxmlError> parseErrors READ parseErrors CONSTANT)
- Q_PROPERTY(QScxmlCompiler::Loader *loader READ loader WRITE setLoader NOTIFY loaderChanged)
- Q_PROPERTY(QScxmlTableData *tableData READ tableData WRITE setTableData NOTIFY tableDataChanged)
+ Q_PROPERTY(QList<QScxmlError> parseErrors READ parseErrors CONSTANT)
+ Q_PROPERTY(QScxmlCompiler::Loader *loader READ loader WRITE setLoader
+ NOTIFY loaderChanged BINDABLE bindableLoader)
+ Q_PROPERTY(QScxmlTableData *tableData READ tableData WRITE setTableData
+ NOTIFY tableDataChanged BINDABLE bindableTableData)
protected:
explicit QScxmlStateMachine(const QMetaObject *metaObject, QObject *parent = nullptr);
@@ -83,24 +56,28 @@ protected:
public:
static QScxmlStateMachine *fromFile(const QString &fileName);
static QScxmlStateMachine *fromData(QIODevice *data, const QString &fileName = QString());
- QVector<QScxmlError> parseErrors() const;
+ QList<QScxmlError> parseErrors() const;
QString sessionId() const;
bool isInvoked() const;
bool isInitialized() const;
+ QBindable<bool> bindableInitialized() const;
void setDataModel(QScxmlDataModel *model);
QScxmlDataModel *dataModel() const;
+ QBindable<QScxmlDataModel*> bindableDataModel();
void setLoader(QScxmlCompiler::Loader *loader);
QScxmlCompiler::Loader *loader() const;
+ QBindable<QScxmlCompiler::Loader*> bindableLoader();
bool isRunning() const;
void setRunning(bool running);
QVariantMap initialValues();
void setInitialValues(const QVariantMap &initialValues);
+ QBindable<QVariantMap> bindableInitialValues();
QString name() const;
Q_INVOKABLE QStringList stateNames(bool compress = true) const;
@@ -111,48 +88,46 @@ public:
const QObject *receiver, const char *method,
Qt::ConnectionType type = Qt::AutoConnection);
- // connect state to a QObject slot
- template <typename PointerToMemberFunction>
- inline QMetaObject::Connection connectToState(
+ // connect state with context
+ template <typename Functor>
+#ifdef Q_QDOC
+ QMetaObject::Connection
+#else
+ inline std::enable_if_t<!std::is_same_v<const char*, Functor>, QMetaObject::Connection>
+#endif
+ connectToState(
const QString &scxmlStateName,
- const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
- PointerToMemberFunction method,
+#ifdef Q_QDOC
+ const QObject *context,
+#else
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *context,
+#endif
+ Functor &&functor,
Qt::ConnectionType type = Qt::AutoConnection)
{
- typedef QtPrivate::FunctionPointer<PointerToMemberFunction> SlotType;
+ using Prototype = void(*)(bool);
return connectToStateImpl(
- scxmlStateName, receiver, nullptr,
- new QtPrivate::QSlotObject<PointerToMemberFunction,
- typename SlotType::Arguments, void>(method),
+ scxmlStateName, context, nullptr,
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(functor)),
type);
}
- // connect state to a functor or function pointer (without context)
- template <typename Functor>
- inline typename QtPrivate::QEnableIf<
- !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
- connectToState(const QString &scxmlStateName, Functor functor,
- Qt::ConnectionType type = Qt::AutoConnection)
- {
- // Use this as context
- return connectToState(scxmlStateName, this, functor, type);
- }
-
- // connectToState to a functor or function pointer (with context)
+ // connect state without context
template <typename Functor>
- inline typename QtPrivate::QEnableIf<
- !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
- connectToState(const QString &scxmlStateName, const QObject *context, Functor functor,
- Qt::ConnectionType type = Qt::AutoConnection)
+#ifdef Q_QDOC
+ QMetaObject::Connection
+#else
+ inline std::enable_if_t<!std::is_same_v<const char*, Functor>, QMetaObject::Connection>
+#endif
+ connectToState(
+ const QString &scxmlStateName,
+ Functor &&functor,
+ Qt::ConnectionType type = Qt::AutoConnection)
{
- QtPrivate::QSlotObjectBase *slotObj = new QtPrivate::QFunctorSlotObject<Functor, 1,
- QtPrivate::List<bool>, void>(functor);
- return connectToStateImpl(scxmlStateName, context, reinterpret_cast<void **>(&functor),
- slotObj, type);
+ return connectToState(scxmlStateName, this, std::forward<Functor>(functor), type);
}
+ //! [onentry]
static std::function<void(bool)> onEntry(const QObject *receiver, const char *method)
{
const QPointer<QObject> receiverPointer(const_cast<QObject *>(receiver));
@@ -162,6 +137,7 @@ public:
};
}
+ //! [onexit]
static std::function<void(bool)> onExit(const QObject *receiver, const char *method)
{
const QPointer<QObject> receiverPointer(const_cast<QObject *>(receiver));
@@ -171,6 +147,7 @@ public:
};
}
+ //! [onentry-functor]
template<typename Functor>
static std::function<void(bool)> onEntry(Functor functor)
{
@@ -180,6 +157,7 @@ public:
};
}
+ //! [onexit-functor]
template<typename Functor>
static std::function<void(bool)> onExit(Functor functor)
{
@@ -189,6 +167,7 @@ public:
};
}
+ //! [onentry-template]
template<typename PointerToMemberFunction>
static std::function<void(bool)> onEntry(
const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
@@ -202,6 +181,7 @@ public:
};
}
+ //! [onexit-template]
template<typename PointerToMemberFunction>
static std::function<void(bool)> onExit(
const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
@@ -219,46 +199,42 @@ public:
const QObject *receiver, const char *method,
Qt::ConnectionType type = Qt::AutoConnection);
- // connect state to a QObject slot
- template <typename PointerToMemberFunction>
- inline QMetaObject::Connection connectToEvent(
+ // connect event with context
+ template <typename Functor>
+#ifdef Q_QDOC
+ QMetaObject::Connection
+#else
+ inline std::enable_if_t<!std::is_same_v<const char*, Functor>, QMetaObject::Connection>
+#endif
+ connectToEvent(
const QString &scxmlEventSpec,
- const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
- PointerToMemberFunction method,
+#ifdef Q_QDOC
+ const QObject *context,
+#else
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *context,
+#endif
+ Functor &&functor,
Qt::ConnectionType type = Qt::AutoConnection)
{
- typedef QtPrivate::FunctionPointer<PointerToMemberFunction> SlotType;
+ using Prototype = void(*)(QScxmlEvent);
return connectToEventImpl(
- scxmlEventSpec, receiver, nullptr,
- new QtPrivate::QSlotObject<PointerToMemberFunction,
- typename SlotType::Arguments, void>(method),
+ scxmlEventSpec, context, nullptr,
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(functor)),
type);
}
- // connect state to a functor or function pointer (without context)
+ // connect event without context
template <typename Functor>
- inline typename QtPrivate::QEnableIf<
- !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
- connectToEvent(const QString &scxmlEventSpec, Functor functor,
+#ifdef Q_QDOC
+ QMetaObject::Connection
+#else
+ inline std::enable_if_t<!std::is_same_v<const char*, Functor>, QMetaObject::Connection>
+#endif
+ connectToEvent(const QString &scxmlEventSpec, Functor &&functor,
Qt::ConnectionType type = Qt::AutoConnection)
{
// Use this as context
- return connectToEvent(scxmlEventSpec, this, functor, type);
- }
-
- // connectToEvent to a functor or function pointer (with context)
- template <typename Functor>
- inline typename QtPrivate::QEnableIf<
- !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
- connectToEvent(const QString &scxmlEventSpec, const QObject *context, Functor functor,
- Qt::ConnectionType type = Qt::AutoConnection)
- {
- QtPrivate::QSlotObjectBase *slotObj = new QtPrivate::QFunctorSlotObject<Functor, 1,
- QtPrivate::List<QScxmlEvent>, void>(functor);
- return connectToEventImpl(scxmlEventSpec, context, reinterpret_cast<void **>(&functor),
- slotObj, type);
+ return connectToEvent(scxmlEventSpec, this, std::forward<Functor>(functor), type);
}
Q_INVOKABLE void submitEvent(QScxmlEvent *event);
@@ -268,14 +244,16 @@ public:
Q_INVOKABLE bool isDispatchableTarget(const QString &target) const;
- QVector<QScxmlInvokableService *> invokedServices() const;
+ QList<QScxmlInvokableService *> invokedServices() const;
+ QBindable<QList<QScxmlInvokableService*>> bindableInvokedServices();
QScxmlTableData *tableData() const;
void setTableData(QScxmlTableData *tableData);
+ QBindable<QScxmlTableData*> bindableTableData();
Q_SIGNALS:
void runningChanged(bool running);
- void invokedServicesChanged(const QVector<QScxmlInvokableService *> &invokedServices);
+ void invokedServicesChanged(const QList<QScxmlInvokableService *> &invokedServices);
void log(const QString &label, const QString &msg);
void reachedStableState();
void finished();
@@ -313,6 +291,6 @@ private:
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QScxmlStateMachine *)
-Q_DECLARE_METATYPE(QVector<QScxmlInvokableService *>)
+Q_DECLARE_METATYPE(QList<QScxmlInvokableService *>)
#endif // QSCXMLSTATEMACHINE_H
diff --git a/src/scxml/qscxmlstatemachine_p.h b/src/scxml/qscxmlstatemachine_p.h
index 1c354fa..3d18ffc 100644
--- a/src/scxml/qscxmlstatemachine_p.h
+++ b/src/scxml/qscxmlstatemachine_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLSTATEMACHINE_P_H
#define QSCXMLSTATEMACHINE_P_H
@@ -56,7 +20,12 @@
#include <QtScxml/private/qscxmlstatemachineinfo_p.h>
#include <QtCore/private/qobject_p.h>
#include <QtCore/private/qmetaobject_p.h>
+#include <QtCore/private/qproperty_p.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qmetaobject.h>
+#include "qscxmlglobals_p.h"
QT_BEGIN_NAMESPACE
@@ -113,14 +82,14 @@ public:
{}
Q_SIGNALS:
- void statesEntered(const QVector<QScxmlStateMachineInfo::StateId> &states);
- void statesExited(const QVector<QScxmlStateMachineInfo::StateId> &states);
- void transitionsTriggered(const QVector<QScxmlStateMachineInfo::TransitionId> &transitions);
+ void statesEntered(const QList<QScxmlStateMachineInfo::StateId> &states);
+ void statesExited(const QList<QScxmlStateMachineInfo::StateId> &states);
+ void transitionsTriggered(const QList<QScxmlStateMachineInfo::TransitionId> &transitions);
};
} // QScxmlInternal namespace
class QScxmlInvokableService;
-class QScxmlStateMachinePrivate: public QObjectPrivate
+class Q_SCXML_EXPORT QScxmlStateMachinePrivate: public QObjectPrivate
{
Q_DECLARE_PUBLIC(QScxmlStateMachine)
@@ -152,7 +121,7 @@ public: // types
{
public:
QScopedPointer<QScxmlDataModel> m_ownedDataModel;
- QVector<QScxmlError> m_errors;
+ QList<QScxmlError> m_errors;
};
// The OrderedSet is a set where it elements are in insertion order. See
@@ -216,7 +185,7 @@ public: // types
class Queue
{
- QVector<QScxmlEvent *> storage;
+ QList<QScxmlEvent *> storage;
public:
Queue()
@@ -328,14 +297,46 @@ private:
public: // types & data fields:
QString m_sessionId;
bool m_isInvoked;
- bool m_isInitialized;
+
+ void isInitializedChanged()
+ {
+ emit q_func()->initializedChanged(m_isInitialized.value());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QScxmlStateMachinePrivate,
+ bool, m_isInitialized, false,
+ &QScxmlStateMachinePrivate::isInitializedChanged);
+
+ void initialValuesChanged()
+ {
+ emit q_func()->initialValuesChanged(m_initialValues.value());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY(QScxmlStateMachinePrivate, QVariantMap, m_initialValues,
+ &QScxmlStateMachinePrivate::initialValuesChanged);
+
+ void loaderChanged()
+ {
+ emit q_func()->loaderChanged(m_loader.value());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY(QScxmlStateMachinePrivate, QScxmlCompiler::Loader*, m_loader,
+ &QScxmlStateMachinePrivate::loaderChanged);
+
+ void setDataModel(QScxmlDataModel* loader)
+ {
+ q_func()->setDataModel(loader);
+ }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QScxmlStateMachinePrivate, QScxmlDataModel*, m_dataModel,
+ &QScxmlStateMachinePrivate::setDataModel, nullptr);
+
+ void setTableData(QScxmlTableData* tableData)
+ {
+ q_func()->setTableData(tableData);
+ }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QScxmlStateMachinePrivate, QScxmlTableData*, m_tableData,
+ &QScxmlStateMachinePrivate::setTableData, nullptr);
+
bool m_isProcessingEvents;
- QVariantMap m_initialValues;
- QScxmlDataModel *m_dataModel;
QScxmlCompilerPrivate::DefaultLoader m_defaultLoader;
- QScxmlCompiler::Loader *m_loader;
QScxmlExecutionEngine *m_executionEngine;
- QScxmlTableData *m_tableData;
const StateTable *m_stateTable;
QScxmlStateMachine *m_parentStateMachine;
QScxmlInternal::EventLoopHook m_eventLoopHook;
@@ -346,7 +347,7 @@ public: // types & data fields:
private:
QScopedPointer<ParserData> m_parserData; // used when created by StateMachine::fromFile.
- typedef QHash<int, QVector<int>> HistoryValues;
+ typedef QHash<int, QList<int>> HistoryValues;
struct InvokedService {
int invokingState;
QScxmlInvokableService *service;
@@ -360,6 +361,18 @@ private:
Queue m_externalQueue;
QSet<int> m_statesToInvoke;
std::vector<InvokedService> m_invokedServices;
+ QList<QScxmlInvokableService*> invokedServicesActualCalculation() const
+ {
+ QList<QScxmlInvokableService *> result;
+ for (size_t i = 0, ei = m_invokedServices.size(); i != ei; ++i) {
+ if (auto service = m_invokedServices[i].service)
+ result.append(service);
+ }
+ return result;
+ }
+ Q_OBJECT_COMPUTED_PROPERTY(QScxmlStateMachinePrivate, QList<QScxmlInvokableService*>,
+ m_invokedServicesComputedProperty,
+ &QScxmlStateMachinePrivate::invokedServicesActualCalculation);
std::vector<bool> m_isFirstStateEntry;
std::vector<QScxmlInvokableServiceFactory *> m_cachedFactories;
enum { Invalid = 0, Starting, Running, Paused, Finished } m_runningState = Invalid;
@@ -378,6 +391,7 @@ private:
}
bool isPaused() const { return m_runningState == Paused; }
+ bool isFinished() const { return m_runningState == Finished; }
QScxmlInternal::StateMachineInfoProxy *m_infoSignalProxy;
diff --git a/src/scxml/qscxmlstatemachineinfo.cpp b/src/scxml/qscxmlstatemachineinfo.cpp
index 4fbbecf..b485f64 100644
--- a/src/scxml/qscxmlstatemachineinfo.cpp
+++ b/src/scxml/qscxmlstatemachineinfo.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmlstatemachineinfo_p.h"
#include "qscxmlstatemachine_p.h"
@@ -71,22 +35,22 @@ QScxmlStateMachine *QScxmlStateMachineInfo::stateMachine() const
return d->stateMachine();
}
-QVector<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::allStates() const
+QList<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::allStates() const
{
Q_D(const QScxmlStateMachineInfo);
- QVector<QScxmlStateMachineInfo::StateId> all;
+ QList<QScxmlStateMachineInfo::StateId> all;
for (int i = 0, ei = d->stateTable()->stateCount; i < ei; ++i) {
all.append(i);
}
return all;
}
-QVector<QScxmlStateMachineInfo::TransitionId> QScxmlStateMachineInfo::allTransitions() const
+QList<QScxmlStateMachineInfo::TransitionId> QScxmlStateMachineInfo::allTransitions() const
{
Q_D(const QScxmlStateMachineInfo);
- QVector<QScxmlStateMachineInfo::TransitionId> all;
+ QList<QScxmlStateMachineInfo::TransitionId> all;
for (int i = 0, ei = d->stateTable()->transitionCount; i < ei; ++i) {
all.append(i);
}
@@ -136,7 +100,7 @@ QScxmlStateMachineInfo::StateType QScxmlStateMachineInfo::stateType(StateId stat
}
}
-QVector<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::stateChildren(StateId stateId) const
+QList<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::stateChildren(StateId stateId) const
{
Q_D(const QScxmlStateMachineInfo);
@@ -146,7 +110,7 @@ QVector<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::stateChildren(S
if (stateId >= 0 && stateId < d->stateTable()->stateCount)
childStates = d->stateTable()->state(stateId).childStates;
- QVector<QScxmlStateMachineInfo::StateId> all;
+ QList<QScxmlStateMachineInfo::StateId> all;
if (childStates == QScxmlExecutableContent::StateTable::InvalidIndex)
return all;
@@ -199,11 +163,11 @@ QScxmlStateMachineInfo::StateId QScxmlStateMachineInfo::transitionSource(Transit
return transition.source;
}
-QVector<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::transitionTargets(TransitionId transitionId) const
+QList<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::transitionTargets(TransitionId transitionId) const
{
Q_D(const QScxmlStateMachineInfo);
- QVector<QScxmlStateMachineInfo::StateId> targets;
+ QList<QScxmlStateMachineInfo::StateId> targets;
if (transitionId < 0 || transitionId >= d->stateTable()->transitionCount)
return targets;
@@ -218,11 +182,11 @@ QVector<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::transitionTarge
return targets;
}
-QVector<QString> QScxmlStateMachineInfo::transitionEvents(TransitionId transitionId) const
+QList<QString> QScxmlStateMachineInfo::transitionEvents(TransitionId transitionId) const
{
Q_D(const QScxmlStateMachineInfo);
- QVector<QString> events;
+ QList<QString> events;
if (transitionId < 0 || transitionId >= d->stateTable()->transitionCount)
return events;
@@ -239,11 +203,11 @@ QVector<QString> QScxmlStateMachineInfo::transitionEvents(TransitionId transitio
return events;
}
-QVector<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::configuration() const
+QList<QScxmlStateMachineInfo::StateId> QScxmlStateMachineInfo::configuration() const
{
Q_D(const QScxmlStateMachineInfo);
const auto &list = d->stateMachinePrivate()->configuration().list();
- return QVector<StateId>(list.cbegin(), list.cend());
+ return QList<StateId>(list.cbegin(), list.cend());
}
QT_END_NAMESPACE
diff --git a/src/scxml/qscxmlstatemachineinfo_p.h b/src/scxml/qscxmlstatemachineinfo_p.h
index 4fa0ca0..8b746a5 100644
--- a/src/scxml/qscxmlstatemachineinfo_p.h
+++ b/src/scxml/qscxmlstatemachineinfo_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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) 2020 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
#ifndef QSCXMLSTATEMACHINEINFO_H
#define QSCXMLSTATEMACHINEINFO_H
@@ -53,6 +17,7 @@
#include <QtScxml/qscxmlglobals.h>
#include <QtCore/qobject.h>
+#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -91,23 +56,23 @@ public: // methods
QScxmlStateMachine *stateMachine() const;
- QVector<StateId> allStates() const;
- QVector<TransitionId> allTransitions() const;
+ QList<StateId> allStates() const;
+ QList<TransitionId> allTransitions() const;
QString stateName(int stateId) const;
StateId stateParent(StateId stateId) const;
StateType stateType(int stateId) const;
- QVector<StateId> stateChildren(StateId stateId) const;
+ QList<StateId> stateChildren(StateId stateId) const;
TransitionId initialTransition(StateId stateId) const;
TransitionType transitionType(TransitionId transitionId) const;
StateId transitionSource(TransitionId transitionId) const;
- QVector<StateId> transitionTargets(TransitionId transitionId) const;
- QVector<QString> transitionEvents(TransitionId transitionId) const;
- QVector<StateId> configuration() const;
+ QList<StateId> transitionTargets(TransitionId transitionId) const;
+ QList<QString> transitionEvents(TransitionId transitionId) const;
+ QList<StateId> configuration() const;
Q_SIGNALS:
- void statesEntered(const QVector<QScxmlStateMachineInfo::StateId> &states);
- void statesExited(const QVector<QScxmlStateMachineInfo::StateId> &states);
- void transitionsTriggered(const QVector<QScxmlStateMachineInfo::TransitionId> &transitions);
+ void statesEntered(const QList<QScxmlStateMachineInfo::StateId> &states);
+ void statesExited(const QList<QScxmlStateMachineInfo::StateId> &states);
+ void transitionsTriggered(const QList<QScxmlStateMachineInfo::TransitionId> &transitions);
private:
Q_DECLARE_PRIVATE(QScxmlStateMachineInfo)
diff --git a/src/scxml/qscxmltabledata.cpp b/src/scxml/qscxmltabledata.cpp
index ab63696..81de319 100644
--- a/src/scxml/qscxmltabledata.cpp
+++ b/src/scxml/qscxmltabledata.cpp
@@ -1,46 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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 "qscxmltabledata_p.h"
#include "qscxmlcompiler_p.h"
#include "qscxmlexecutablecontent_p.h"
+#include <QtCore/qmap.h>
+
QT_USE_NAMESPACE
/*!
@@ -146,13 +112,13 @@ public:
m_parents.reserve(32);
m_allTransitions.resize(doc->allTransitions.size());
m_docTransitionIndices.reserve(doc->allTransitions.size());
- for (auto *t : qAsConst(doc->allTransitions)) {
+ for (auto *t : std::as_const(doc->allTransitions)) {
m_docTransitionIndices.insert(t, m_docTransitionIndices.size());
}
m_docStatesIndices.reserve(doc->allStates.size());
m_transitionsForState.resize(doc->allStates.size());
m_allStates.resize(doc->allStates.size());
- for (DocumentModel::AbstractState *s : qAsConst(doc->allStates)) {
+ for (DocumentModel::AbstractState *s : std::as_const(doc->allStates)) {
m_docStatesIndices.insert(s, m_docStatesIndices.size());
}
@@ -183,7 +149,7 @@ public:
+ (m_allTransitions.size() * transitionSize)
+ m_arrays.size()
+ 1;
- QVector<qint32> data(dataSize, -1);
+ QList<qint32> data(dataSize, -1);
qint32 *ptr = data.data();
memcpy(ptr, &m_stateTable, sizeof(m_stateTable));
@@ -260,8 +226,8 @@ protected: // visitor
endSequence();
}
- QVector<DocumentModel::AbstractState *> childStates;
- for (DocumentModel::StateOrTransition *sot : qAsConst(node->children)) {
+ QList<DocumentModel::AbstractState *> childStates;
+ for (DocumentModel::StateOrTransition *sot : std::as_const(node->children)) {
if (DocumentModel::AbstractState *s = sot->asAbstractState()) {
childStates.append(s);
}
@@ -317,14 +283,14 @@ protected: // visitor
newState.entryInstructions = generate(state->onEntry);
newState.exitInstructions = generate(state->onExit);
if (!state->invokes.isEmpty()) {
- QVector<int> factoryIds;
- for (DocumentModel::Invoke *invoke : qAsConst(state->invokes)) {
+ QList<int> factoryIds;
+ for (DocumentModel::Invoke *invoke : std::as_const(state->invokes)) {
auto ctxt = createContext(QStringLiteral("invoke"));
- QVector<QScxmlExecutableContent::StringId> namelist;
- for (const QString &name : qAsConst(invoke->namelist))
+ QList<QScxmlExecutableContent::StringId> namelist;
+ for (const QString &name : std::as_const(invoke->namelist))
namelist += addString(name);
- QVector<QScxmlExecutableContent::ParameterInfo> params;
- for (DocumentModel::Param *param : qAsConst(invoke->params)) {
+ QList<QScxmlExecutableContent::ParameterInfo> params;
+ for (DocumentModel::Param *param : std::as_const(invoke->params)) {
QScxmlExecutableContent::ParameterInfo p;
p.name = addString(param->name);
p.expr = createEvaluatorVariant(QStringLiteral("param"), QStringLiteral("expr"),
@@ -361,8 +327,8 @@ protected: // visitor
visit(state->children);
- QVector<DocumentModel::AbstractState *> childStates;
- for (DocumentModel::StateOrTransition *sot : qAsConst(state->children)) {
+ QList<DocumentModel::AbstractState *> childStates;
+ for (DocumentModel::StateOrTransition *sot : std::as_const(state->children)) {
if (auto s = sot->asAbstractState()) {
childStates.append(s);
}
@@ -419,8 +385,8 @@ protected: // visitor
newTransition.targets = addStates(transition->targetStates);
- QVector<int> eventIds;
- for (const QString &event : qAsConst(transition->events))
+ QList<int> eventIds;
+ for (const QString &event : std::as_const(transition->events))
eventIds.push_back(addString(event));
newTransition.events = addArray(eventIds);
@@ -582,7 +548,7 @@ protected:
return addString(createContextString(instrName));
}
- void generate(const QVector<DocumentModel::DataElement *> &dataElements)
+ void generate(const QList<DocumentModel::DataElement *> &dataElements)
{
for (DocumentModel::DataElement *el : dataElements) {
auto ctxt = createContext(QStringLiteral("data"), QStringLiteral("expr"), el->expr);
@@ -605,7 +571,7 @@ protected:
return id;
}
- void generate(Array<ParameterInfo> *out, const QVector<DocumentModel::Param *> &in)
+ void generate(Array<ParameterInfo> *out, const QList<DocumentModel::Param *> &in)
{
out->count = in.size();
ParameterInfo *it = out->data();
@@ -742,7 +708,7 @@ protected:
return NoEvaluator;
}
- GeneratedTableData *tableData(const QVector<int> &stateMachineTable);
+ GeneratedTableData *tableData(const QList<int> &stateMachineTable);
StringId addString(const QString &str)
{ return str.isEmpty() ? NoString : m_stringTable.add(str); }
@@ -756,9 +722,9 @@ protected:
bool isCppDataModel() const
{ return m_isCppDataModel; }
- int addStates(const QVector<DocumentModel::AbstractState *> &states)
+ int addStates(const QList<DocumentModel::AbstractState *> &states)
{
- QVector<int> array;
+ QList<int> array;
for (auto *s : states) {
int si = m_docStatesIndices.value(s, -1);
Q_ASSERT(si != -1);
@@ -768,7 +734,7 @@ protected:
return addArray(array);
}
- int addArray(const QVector<int> &array)
+ int addArray(const QList<int> &array)
{
if (array.isEmpty())
return -1;
@@ -894,7 +860,7 @@ private:
class InstructionStorage {
public:
- InstructionStorage(QVector<qint32> &storage)
+ InstructionStorage(QList<qint32> &storage)
: m_instr(storage)
, m_info(nullptr)
{}
@@ -932,36 +898,36 @@ private:
}
private:
- QVector<qint32> &m_instr;
+ QList<qint32> &m_instr;
SequenceInfo *m_info;
};
- QVector<SequenceInfo> m_activeSequences;
+ QList<SequenceInfo> m_activeSequences;
GeneratedTableData::CreateFactoryId createFactoryId;
GeneratedTableData &m_tableData;
GeneratedTableData::DataModelInfo &m_dataModelInfo;
Table<QStringList, QString, StringId> m_stringTable;
InstructionStorage m_instructions;
- Table<QVector<EvaluatorInfo>, EvaluatorInfo, EvaluatorId> m_evaluators;
- Table<QVector<AssignmentInfo>, AssignmentInfo, EvaluatorId> m_assignments;
- Table<QVector<ForeachInfo>, ForeachInfo, EvaluatorId> m_foreaches;
- QVector<StringId> &m_dataIds;
+ Table<QList<EvaluatorInfo>, EvaluatorInfo, EvaluatorId> m_evaluators;
+ Table<QList<AssignmentInfo>, AssignmentInfo, EvaluatorId> m_assignments;
+ Table<QList<ForeachInfo>, ForeachInfo, EvaluatorId> m_foreaches;
+ QList<StringId> &m_dataIds;
bool m_isCppDataModel = false;
StateTable m_stateTable;
- QVector<int> m_parents;
- QVector<qint32> m_arrays;
+ QList<int> m_parents;
+ QList<qint32> m_arrays;
- QVector<StateTable::Transition> m_allTransitions;
+ QList<StateTable::Transition> m_allTransitions;
QHash<DocumentModel::Transition *, int> m_docTransitionIndices;
- QVector<StateTable::State> m_allStates;
+ QList<StateTable::State> m_allStates;
QHash<DocumentModel::AbstractState *, int> m_docStatesIndices;
- QVector<QVector<int>> m_transitionsForState;
+ QList<QList<int>> m_transitionsForState;
int m_currentTransition = StateTable::InvalidIndex;
bool m_bindLate = false;
- QVector<DocumentModel::DataElement *> m_dataElements;
+ QList<DocumentModel::DataElement *> m_dataElements;
Table<QStringList, QString, int> m_stateNames;
};
diff --git a/src/scxml/qscxmltabledata.h b/src/scxml/qscxmltabledata.h
index 5c0d345..ca56627 100644
--- a/src/scxml/qscxmltabledata.h
+++ b/src/scxml/qscxmltabledata.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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
#ifndef QSCXMLTABLEDATA_H
#define QSCXMLTABLEDATA_H
@@ -44,7 +8,7 @@
#include <QtCore/qstring.h>
#ifndef Q_QSCXMLC_OUTPUT_REVISION
-#define Q_QSCXMLC_OUTPUT_REVISION 1
+#define Q_QSCXMLC_OUTPUT_REVISION 2
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/scxml/qscxmltabledata_p.h b/src/scxml/qscxmltabledata_p.h
index 47d8bac..6f147b7 100644
--- a/src/scxml/qscxmltabledata_p.h
+++ b/src/scxml/qscxmltabledata_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml 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) 2020 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
#ifndef QSCXMLTABLEDATA_P_H
#define QSCXMLTABLEDATA_P_H
@@ -52,9 +16,10 @@
//
#include <QtScxml/qscxmltabledata.h>
-#include <QtCore/qsharedpointer.h>
#include <QtCore/qhash.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtCore/private/qglobal_p.h>
#include <functional>
@@ -72,8 +37,8 @@ class Q_SCXML_EXPORT GeneratedTableData: public QScxmlTableData
public:
typedef std::function<
int(const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &namelist,
- const QVector<QScxmlExecutableContent::ParameterInfo> &params,
+ const QList<QScxmlExecutableContent::StringId> &namelist,
+ const QList<QScxmlExecutableContent::ParameterInfo> &params,
QSharedPointer<DocumentModel::ScxmlDocument> content)
> CreateFactoryId;
@@ -110,13 +75,13 @@ public:
QScxmlInvokableServiceFactory *serviceFactory(int id) const override;
public:
- QVector<qint32> theStateMachineTable;
+ QList<qint32> theStateMachineTable;
QStringList theStrings;
- QVector<qint32> theInstructions;
- QVector<QScxmlExecutableContent::EvaluatorInfo> theEvaluators;
- QVector<QScxmlExecutableContent::AssignmentInfo> theAssignments;
- QVector<QScxmlExecutableContent::ForeachInfo> theForeaches;
- QVector<QScxmlExecutableContent::StringId> theDataNameIds;
+ QList<qint32> theInstructions;
+ QList<QScxmlExecutableContent::EvaluatorInfo> theEvaluators;
+ QList<QScxmlExecutableContent::AssignmentInfo> theAssignments;
+ QList<QScxmlExecutableContent::ForeachInfo> theForeaches;
+ QList<QScxmlExecutableContent::StringId> theDataNameIds;
QScxmlExecutableContent::ContainerId theInitialSetup;
int theName;
};
diff --git a/src/scxml/qt_cmdline.cmake b/src/scxml/qt_cmdline.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/scxml/qt_cmdline.cmake
diff --git a/src/scxml/scxml.pro b/src/scxml/scxml.pro
deleted file mode 100644
index fe55769..0000000
--- a/src/scxml/scxml.pro
+++ /dev/null
@@ -1,73 +0,0 @@
-TARGET = QtScxml
-QT = core-private
-MODULE_CONFIG += c++11 qscxmlc
-
-QMAKE_DOCS = $$PWD/doc/qtscxml.qdocconf
-
-CONFIG += $$MODULE_CONFIG
-DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
-
-HEADERS += \
- qscxmlcompiler.h \
- qscxmlcompiler_p.h \
- qscxmlstatemachine.h \
- qscxmlstatemachine_p.h \
- qscxmlglobals.h \
- qscxmlglobals_p.h \
- qscxmlnulldatamodel.h \
- qscxmlexecutablecontent.h \
- qscxmlexecutablecontent_p.h \
- qscxmlevent.h \
- qscxmlevent_p.h \
- qscxmldatamodel.h \
- qscxmldatamodel_p.h \
- qscxmlcppdatamodel_p.h \
- qscxmlcppdatamodel.h \
- qscxmlerror.h \
- qscxmlinvokableservice_p.h \
- qscxmlinvokableservice.h \
- qscxmltabledata.h \
- qscxmltabledata_p.h \
- qscxmlstatemachineinfo_p.h
-
-SOURCES += \
- qscxmlcompiler.cpp \
- qscxmlstatemachine.cpp \
- qscxmlnulldatamodel.cpp \
- qscxmlexecutablecontent.cpp \
- qscxmlevent.cpp \
- qscxmldatamodel.cpp \
- qscxmlcppdatamodel.cpp \
- qscxmlerror.cpp \
- qscxmlinvokableservice.cpp \
- qscxmltabledata.cpp \
- qscxmlstatemachineinfo.cpp
-
-qtConfig(scxml-ecmascriptdatamodel) {
- QT += qml-private
-
- HEADERS += \
- qscxmlecmascriptdatamodel.h \
- qscxmlecmascriptplatformproperties_p.h
-
- SOURCES += \
- qscxmlecmascriptdatamodel.cpp \
- qscxmlecmascriptplatformproperties.cpp
-}
-
-load(qt_module)
-
-FEATURES += ../../mkspecs/features/qscxmlc.prf
-features.files = $$FEATURES
-features.path = $$[QT_HOST_DATA]/mkspecs/features/
-INSTALLS += features
-
-!force_independent:if(!debug_and_release|!build_all|CONFIG(release, debug|release)) {
- # Copy qscxmlc.prf to the qtbase build directory (for non-installed developer builds)
- prf2build.input = FEATURES
- prf2build.output = $$[QT_INSTALL_DATA/get]/mkspecs/features/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT}
- prf2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
- prf2build.name = COPY ${QMAKE_FILE_IN}
- prf2build.CONFIG = no_link no_clean target_predeps
- QMAKE_EXTRA_COMPILERS += prf2build
-}
diff --git a/src/scxmlqml/CMakeLists.txt b/src/scxmlqml/CMakeLists.txt
new file mode 100644
index 0000000..27cd9b2
--- /dev/null
+++ b/src/scxmlqml/CMakeLists.txt
@@ -0,0 +1,27 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_include_in_repo_target_set(qtscxmlqml)
+
+qt_internal_add_qml_module(ScxmlQml
+ URI "QtScxml"
+ VERSION "${PROJECT_VERSION}"
+ PLUGIN_TARGET declarative_scxml
+ CLASS_NAME QScxmlStateMachinePlugin
+ SOURCES
+ eventconnection.cpp eventconnection_p.h
+ invokedservices.cpp invokedservices_p.h
+ statemachineextended.cpp statemachineextended_p.h
+ statemachineloader.cpp statemachineloader_p.h
+ qscxmlqmlglobals_p.h
+ DEFINES
+ QT_BUILD_SCXMLQML_LIB
+ DEPENDENCIES
+ QtQml
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Qml
+ Qt::Scxml
+ LIBRARIES
+ Qt::CorePrivate
+)
diff --git a/src/scxmlqml/eventconnection.cpp b/src/scxmlqml/eventconnection.cpp
new file mode 100644
index 0000000..c7d65b0
--- /dev/null
+++ b/src/scxmlqml/eventconnection.cpp
@@ -0,0 +1,117 @@
+// 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 "eventconnection_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype EventConnection
+//! \instantiates QScxmlEventConnection
+ \inqmlmodule QtScxml
+ \since QtScxml 5.8
+
+ \brief Connects to events sent out by state machines.
+
+ To receive a notification when a state machine sends out an event, a
+ connection can be created to the corresponding signal.
+*/
+
+/*!
+ \qmlproperty stringlist EventConnection::events
+
+ The list of SCXML event specifiers that describe the events to listen for.
+
+ Even though spaces are allowed in event specifications in SCXML documents,
+ they are not allowed in this list. However, the list can contain multiple
+ specifiers, to the same effect.
+*/
+
+/*!
+ \qmlproperty ScxmlStateMachine EventConnection::stateMachine
+
+ The state machine that sends out the event.
+*/
+
+/*!
+ \qmlsignal EventConnection::occurred(event)
+
+ This signal is emitted when the SCXML event \a event occurs.
+
+ \sa QScxmlEvent
+*/
+
+
+QScxmlEventConnection::QScxmlEventConnection(QObject *parent) :
+ QObject(parent)
+{
+}
+
+QStringList QScxmlEventConnection::events() const
+{
+ return m_events;
+}
+
+void QScxmlEventConnection::setEvents(const QStringList &events)
+{
+ m_events.removeBindingUnlessInWrapper();
+ if (events == m_events.valueBypassingBindings()) {
+ return;
+ }
+ m_events.setValueBypassingBindings(events);
+ doConnect();
+ m_events.notify();
+}
+
+QBindable<QStringList> QScxmlEventConnection::bindableEvents()
+{
+ return &m_events;
+}
+
+QScxmlStateMachine *QScxmlEventConnection::stateMachine() const
+{
+ return m_stateMachine;
+}
+
+void QScxmlEventConnection::setStateMachine(QScxmlStateMachine *stateMachine)
+{
+ m_stateMachine.removeBindingUnlessInWrapper();
+ if (stateMachine == m_stateMachine.valueBypassingBindings())
+ return;
+ m_stateMachine.setValueBypassingBindings(stateMachine);
+ doConnect();
+ m_stateMachine.notify();
+}
+
+QBindable<QScxmlStateMachine*> QScxmlEventConnection::bindableStateMachine()
+{
+ return &m_stateMachine;
+}
+
+void QScxmlEventConnection::doConnect()
+{
+ for (const QMetaObject::Connection &connection : std::as_const(m_connections))
+ disconnect(connection);
+ m_connections.clear();
+ const auto stateMachine = m_stateMachine.valueBypassingBindings();
+ if (stateMachine) {
+ const auto events = m_events.valueBypassingBindings();
+ for (const QString &event : events) {
+ m_connections.append(stateMachine->connectToEvent(event, this,
+ &QScxmlEventConnection::occurred));
+ }
+ }
+}
+
+void QScxmlEventConnection::classBegin()
+{
+}
+
+void QScxmlEventConnection::componentComplete()
+{
+ auto parentStateMachine = qobject_cast<QScxmlStateMachine *>(parent());
+ if (!m_stateMachine.value() && parentStateMachine)
+ setStateMachine(parentStateMachine);
+}
+
+QT_END_NAMESPACE
diff --git a/src/scxmlqml/eventconnection_p.h b/src/scxmlqml/eventconnection_p.h
new file mode 100644
index 0000000..1dd36d3
--- /dev/null
+++ b/src/scxmlqml/eventconnection_p.h
@@ -0,0 +1,84 @@
+// 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
+
+#ifndef EVENTCONNECTION_P_H
+#define EVENTCONNECTION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qscxmlqmlglobals_p.h"
+
+#include <QtScxml/qscxmlstatemachine.h>
+#include <QtScxml/qscxmlevent.h>
+#include <QtCore/qobject.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqml.h>
+#include "QtCore/qproperty.h"
+#include <private/qproperty_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// QScxmlEvent is used as signal parameter, and defined in the cpp lib
+struct Q_SCXMLQML_EXPORT QScxmlEventForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QScxmlEvent)
+ QML_ADDED_IN_VERSION(5,8)
+};
+
+class Q_SCXMLQML_EXPORT QScxmlEventConnection : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QStringList events READ events WRITE setEvents NOTIFY eventsChanged
+ BINDABLE bindableEvents)
+ Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine WRITE setStateMachine
+ NOTIFY stateMachineChanged BINDABLE bindableStateMachine)
+ Q_INTERFACES(QQmlParserStatus)
+ QML_NAMED_ELEMENT(EventConnection)
+ QML_ADDED_IN_VERSION(5,8)
+
+public:
+ QScxmlEventConnection(QObject *parent = nullptr);
+
+ QStringList events() const;
+ void setEvents(const QStringList &events);
+ QBindable<QStringList> bindableEvents();
+
+ QScxmlStateMachine *stateMachine() const;
+ void setStateMachine(QScxmlStateMachine *stateMachine);
+ QBindable<QScxmlStateMachine*> bindableStateMachine();
+
+Q_SIGNALS:
+ void eventsChanged();
+ void stateMachineChanged();
+
+ void occurred(const QScxmlEvent &event);
+
+private:
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QScxmlEventConnection, QScxmlStateMachine*, m_stateMachine,
+ &QScxmlEventConnection::setStateMachine,
+ &QScxmlEventConnection::stateMachineChanged, nullptr);
+ Q_OBJECT_COMPAT_PROPERTY(QScxmlEventConnection, QStringList, m_events,
+ &QScxmlEventConnection::setEvents,
+ &QScxmlEventConnection::eventsChanged);
+
+ QList<QMetaObject::Connection> m_connections;
+
+ void doConnect();
+ void classBegin() override;
+ void componentComplete() override;
+};
+
+QT_END_NAMESPACE
+
+#endif // EVENTCONNECTION_P_H
diff --git a/src/scxmlqml/invokedservices.cpp b/src/scxmlqml/invokedservices.cpp
new file mode 100644
index 0000000..27b939b
--- /dev/null
+++ b/src/scxmlqml/invokedservices.cpp
@@ -0,0 +1,114 @@
+// 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 "invokedservices_p.h"
+#include <QtScxml/qscxmlinvokableservice.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype InvokedServices
+//! \instantiates QScxmlInvokedServices
+ \inqmlmodule QtScxml
+ \since QtScxml 5.8
+
+ \brief Provices access to the services invoked by state machines.
+
+ Makes the invoked services easily accessible by their names, without
+ constantly iterating through QScxmlStateMachine::invokedServices.
+
+ The services are called from state machines via the mechanism described in
+ \l{SCXML Specification - 6.4 <invoke>}.
+*/
+
+QScxmlInvokedServices::QScxmlInvokedServices(QObject *parent) : QObject(parent)
+{
+}
+
+/*!
+ \qmlproperty var InvokedServices::children
+
+ The services invoked by the state machine.
+*/
+
+QVariantMap QScxmlInvokedServices::children()
+{
+ return m_children.value();
+}
+
+QVariantMap QScxmlInvokedServices::childrenActualCalculation() const
+{
+ QVariantMap ret;
+ if (m_stateMachine.value()) {
+ const QList<QScxmlInvokableService *> children = m_stateMachine->invokedServices();
+ for (QScxmlInvokableService *service : children)
+ ret.insert(service->name(), QVariant::fromValue(service));
+ }
+ return ret;
+}
+
+QBindable<QVariantMap> QScxmlInvokedServices::bindableChildren()
+{
+ return &m_children;
+}
+
+void QScxmlInvokedServices::classBegin()
+{
+}
+
+/*!
+ \qmlproperty ScxmlStateMachine InvokedServices::stateMachine
+
+ The state machine that invoked the services.
+*/
+
+QScxmlStateMachine *QScxmlInvokedServices::stateMachine() const
+{
+ return m_stateMachine;
+}
+
+void QScxmlInvokedServices::setStateMachine(QScxmlStateMachine *stateMachine)
+{
+ m_stateMachine.removeBindingUnlessInWrapper();
+ if (stateMachine == m_stateMachine.valueBypassingBindings())
+ return;
+
+ QObject::disconnect(m_serviceConnection);
+ m_stateMachine.setValueBypassingBindings(stateMachine);
+
+ if (stateMachine) {
+ m_serviceConnection =
+ QObject::connect(stateMachine,
+ &QScxmlStateMachine::invokedServicesChanged, this, [this]() {
+ m_children.notify();
+ emit childrenChanged();
+ });
+ }
+ m_stateMachine.notify();
+ m_children.notify();
+ emit childrenChanged();
+}
+
+QBindable<QScxmlStateMachine*> QScxmlInvokedServices::bindableStateMachine()
+{
+ return &m_stateMachine;
+}
+
+/*!
+ \qmlproperty list<QtObject> InvokedServices::qmlChildren
+
+ A list of additional QtObject types nested in this type.
+*/
+
+QQmlListProperty<QObject> QScxmlInvokedServices::qmlChildren()
+{
+ return QQmlListProperty<QObject>(this, &m_qmlChildren);
+}
+
+void QScxmlInvokedServices::componentComplete()
+{
+ if (!m_stateMachine.value())
+ setStateMachine(qobject_cast<QScxmlStateMachine *>(parent()));
+}
+
+QT_END_NAMESPACE
diff --git a/src/scxmlqml/invokedservices_p.h b/src/scxmlqml/invokedservices_p.h
new file mode 100644
index 0000000..2b5a728
--- /dev/null
+++ b/src/scxmlqml/invokedservices_p.h
@@ -0,0 +1,73 @@
+// 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
+
+#ifndef INVOKEDSERVICES_P_H
+#define INVOKEDSERVICES_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qscxmlqmlglobals_p.h"
+
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+#include <QtScxml/qscxmlstatemachine.h>
+#include <QtCore/qproperty.h>
+#include <private/qproperty_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_SCXMLQML_EXPORT QScxmlInvokedServices : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine WRITE setStateMachine
+ NOTIFY stateMachineChanged BINDABLE bindableStateMachine)
+ Q_PROPERTY(QVariantMap children READ children NOTIFY childrenChanged BINDABLE bindableChildren)
+ Q_PROPERTY(QQmlListProperty<QObject> qmlChildren READ qmlChildren)
+ Q_INTERFACES(QQmlParserStatus)
+ Q_CLASSINFO("DefaultProperty", "qmlChildren")
+ QML_NAMED_ELEMENT(InvokedServices)
+ QML_ADDED_IN_VERSION(5,8)
+
+public:
+ QScxmlInvokedServices(QObject *parent = nullptr);
+
+ QVariantMap children();
+ QBindable<QVariantMap> bindableChildren();
+
+ QScxmlStateMachine *stateMachine() const;
+ void setStateMachine(QScxmlStateMachine *stateMachine);
+ QBindable<QScxmlStateMachine*> bindableStateMachine();
+
+ QQmlListProperty<QObject> qmlChildren();
+
+Q_SIGNALS:
+ void childrenChanged();
+ void stateMachineChanged();
+
+private:
+ void classBegin() override;
+ void componentComplete() override;
+ QVariantMap childrenActualCalculation() const;
+
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QScxmlInvokedServices, QScxmlStateMachine*, m_stateMachine,
+ &QScxmlInvokedServices::setStateMachine,
+ &QScxmlInvokedServices::stateMachineChanged, nullptr);
+ Q_OBJECT_COMPUTED_PROPERTY(QScxmlInvokedServices, QVariantMap,
+ m_children, &QScxmlInvokedServices::childrenActualCalculation);
+ QMetaObject::Connection m_serviceConnection;
+ QList<QObject *> m_qmlChildren;
+};
+
+QT_END_NAMESPACE
+
+#endif // INVOKEDSERVICES_P_H
diff --git a/src/scxmlqml/qscxmlqmlglobals_p.h b/src/scxmlqml/qscxmlqmlglobals_p.h
new file mode 100644
index 0000000..b2b07fe
--- /dev/null
+++ b/src/scxmlqml/qscxmlqmlglobals_p.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2021 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
+
+#ifndef QSCXMLQMLGLOBALS_P_H
+#define QSCXMLQMLGLOBALS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtScxmlQml/qtscxmlqmlexports.h>
+
+QT_BEGIN_NAMESPACE
+
+void Q_SCXMLQML_EXPORT qml_register_types_QtScxml();
+
+QT_END_NAMESPACE
+
+#endif // QSCXMLQMLGLOBALS_P_H
diff --git a/src/scxmlqml/statemachineextended.cpp b/src/scxmlqml/statemachineextended.cpp
new file mode 100644
index 0000000..7a7f990
--- /dev/null
+++ b/src/scxmlqml/statemachineextended.cpp
@@ -0,0 +1,21 @@
+// 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 "statemachineextended_p.h"
+
+#include <QtScxml/qscxmlglobals.h>
+#include <QtScxml/qscxmlstatemachine.h>
+
+QT_BEGIN_NAMESPACE
+
+QScxmlStateMachineExtended::QScxmlStateMachineExtended(QObject *extendee) :
+ QObject(extendee)
+{
+}
+
+QQmlListProperty<QObject> QScxmlStateMachineExtended::children()
+{
+ return QQmlListProperty<QObject>(this, &m_children);
+}
+
+QT_END_NAMESPACE
diff --git a/src/scxmlqml/statemachineextended_p.h b/src/scxmlqml/statemachineextended_p.h
new file mode 100644
index 0000000..4ca68f0
--- /dev/null
+++ b/src/scxmlqml/statemachineextended_p.h
@@ -0,0 +1,54 @@
+// 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
+
+#ifndef STATEMACHINEEXTENDED_P_H
+#define STATEMACHINEEXTENDED_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qscxmlqmlglobals_p.h"
+
+#include <QtScxml/qscxmlstatemachine.h>
+#include <QtCore/qobject.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+/* Allow State Machines created from QML to have children. */
+class Q_SCXMLQML_EXPORT QScxmlStateMachineExtended : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<QObject> children READ children)
+ Q_CLASSINFO("DefaultProperty", "children")
+public:
+ QScxmlStateMachineExtended(QObject *extendee);
+ QQmlListProperty<QObject> children();
+
+private:
+ QObjectList m_children;
+};
+
+// The QScxmlStateMachine is defined in the scxml library
+struct Q_SCXMLQML_EXPORT QScxmlStateMachineForeign
+{
+ Q_GADGET
+ QML_UNCREATABLE("Only created through derived types")
+ QML_NAMED_ELEMENT(StateMachine)
+ QML_FOREIGN(QScxmlStateMachine)
+ QML_EXTENDED(QScxmlStateMachineExtended)
+ QML_ADDED_IN_VERSION(5,8)
+};
+
+QT_END_NAMESPACE
+
+#endif // STATEMACHINEEXTENDED_P_H
diff --git a/src/scxmlqml/statemachineloader.cpp b/src/scxmlqml/statemachineloader.cpp
new file mode 100644
index 0000000..33e3172
--- /dev/null
+++ b/src/scxmlqml/statemachineloader.cpp
@@ -0,0 +1,198 @@
+// 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 "statemachineloader_p.h"
+
+#include <QtScxml/qscxmlstatemachine.h>
+#include <qqmlcontext.h>
+#include <qqmlengine.h>
+#include <qqmlinfo.h>
+#include <qqmlfile.h>
+#include <qbuffer.h>
+
+/*!
+ \qmltype StateMachineLoader
+//! \instantiates QScxmlStateMachineLoader
+ \inqmlmodule QtScxml
+
+ \brief Dynamically loads an SCXML document and instantiates the state machine.
+
+ \since QtScxml 5.7
+ */
+
+QScxmlStateMachineLoader::QScxmlStateMachineLoader(QObject *parent)
+ : QObject(parent)
+ , m_implicitDataModel(nullptr)
+{
+}
+
+/*!
+ \qmlproperty ScxmlStateMachine StateMachineLoader::stateMachine
+
+ The state machine instance.
+ */
+QT_PREPEND_NAMESPACE(QScxmlStateMachine) *QScxmlStateMachineLoader::stateMachine() const
+{
+ return m_stateMachine;
+}
+
+void QScxmlStateMachineLoader::setStateMachine(QScxmlStateMachine* stateMachine)
+{
+ if (m_stateMachine.valueBypassingBindings() != stateMachine) {
+ delete m_stateMachine.valueBypassingBindings();
+ m_stateMachine.setValueBypassingBindings(stateMachine);
+ }
+}
+
+QBindable<QScxmlStateMachine*> QScxmlStateMachineLoader::bindableStateMachine()
+{
+ return &m_stateMachine;
+}
+
+/*!
+ \qmlproperty url StateMachineLoader::source
+
+ The URL of the SCXML document to load. Only synchronously accessible URLs
+ are supported.
+ */
+QUrl QScxmlStateMachineLoader::source()
+{
+ return m_source;
+}
+
+void QScxmlStateMachineLoader::setSource(const QUrl &source)
+{
+ if (!source.isValid())
+ return;
+
+ m_source.removeBindingUnlessInWrapper();
+
+ const QUrl oldSource = m_source.valueBypassingBindings();
+ const auto *oldStateMachine = m_stateMachine.valueBypassingBindings();
+ setStateMachine(nullptr);
+ m_implicitDataModel = nullptr;
+
+ if (parse(source))
+ m_source.setValueBypassingBindings(source);
+ else
+ m_source.setValueBypassingBindings(QUrl());
+
+ if (oldSource != m_source.valueBypassingBindings())
+ m_source.notify();
+
+ if (oldStateMachine != m_stateMachine.valueBypassingBindings())
+ m_stateMachine.notify();
+}
+
+QBindable<QUrl> QScxmlStateMachineLoader::bindableSource()
+{
+ return &m_source;
+}
+
+QVariantMap QScxmlStateMachineLoader::initialValues() const
+{
+ return m_initialValues;
+}
+
+void QScxmlStateMachineLoader::setInitialValues(const QVariantMap &initialValues)
+{
+ m_initialValues.removeBindingUnlessInWrapper();
+ if (initialValues == m_initialValues.valueBypassingBindings())
+ return;
+
+ m_initialValues.setValueBypassingBindings(initialValues);
+
+ const auto stateMachine = m_stateMachine.valueBypassingBindings();
+ if (stateMachine)
+ stateMachine->setInitialValues(initialValues);
+ m_initialValues.notify();
+}
+
+QBindable<QVariantMap> QScxmlStateMachineLoader::bindableInitialValues()
+{
+ return &m_initialValues;
+}
+
+QScxmlDataModel *QScxmlStateMachineLoader::dataModel() const
+{
+ return m_dataModel;
+}
+
+void QScxmlStateMachineLoader::setDataModel(QScxmlDataModel *dataModel)
+{
+ m_dataModel.removeBindingUnlessInWrapper();
+ if (dataModel == m_dataModel.valueBypassingBindings()) {
+ return;
+ }
+ m_dataModel.setValueBypassingBindings(dataModel);
+ const auto stateMachine = m_stateMachine.valueBypassingBindings();
+ if (stateMachine) {
+ if (dataModel)
+ stateMachine->setDataModel(dataModel);
+ else
+ stateMachine->setDataModel(m_implicitDataModel);
+ }
+ m_dataModel.notify();
+}
+
+QBindable<QScxmlDataModel*> QScxmlStateMachineLoader::bindableDataModel()
+{
+ return &m_dataModel;
+}
+
+bool QScxmlStateMachineLoader::parse(const QUrl &source)
+{
+ if (!QQmlFile::isSynchronous(source)) {
+ qmlWarning(this) << QStringLiteral("Cannot open '%1' for reading: only synchronous access is supported.")
+ .arg(source.url());
+ return false;
+ }
+ QQmlFile scxmlFile(QQmlEngine::contextForObject(this)->engine(), source);
+ if (scxmlFile.isError()) {
+ // the synchronous case can only fail when the file is not found (or not readable).
+ qmlWarning(this) << QStringLiteral("Cannot open '%1' for reading.").arg(source.url());
+ return false;
+ }
+
+ QByteArray data(scxmlFile.dataByteArray());
+ QBuffer buf(&data);
+ if (!buf.open(QIODevice::ReadOnly)) {
+ qmlWarning(this) << QStringLiteral("Cannot open input buffer for reading");
+ return false;
+ }
+
+ QString fileName;
+ if (source.isLocalFile()) {
+ fileName = source.toLocalFile();
+ } else if (source.scheme() == QStringLiteral("qrc")) {
+ fileName = QStringLiteral(":") + source.path();
+ } else {
+ qmlWarning(this) << QStringLiteral("%1 is neither a local nor a resource URL.")
+ .arg(source.url())
+ << QStringLiteral("Invoking services by relative path will not work.");
+ }
+
+ auto stateMachine = QScxmlStateMachine::fromData(&buf, fileName);
+ stateMachine->setParent(this);
+ m_implicitDataModel = stateMachine->dataModel();
+
+ if (stateMachine->parseErrors().isEmpty()) {
+ if (m_dataModel.value())
+ stateMachine->setDataModel(m_dataModel.value());
+ stateMachine->setInitialValues(m_initialValues.value());
+ setStateMachine(stateMachine);
+ // as this is deferred any pending property updates to m_dataModel and m_initialValues
+ // should still occur before start().
+ QMetaObject::invokeMethod(m_stateMachine.valueBypassingBindings(), "start", Qt::QueuedConnection);
+ return true;
+ } else {
+ qmlWarning(this) << QStringLiteral("Something went wrong while parsing '%1':")
+ .arg(source.url())
+ << Qt::endl;
+ const auto errors = stateMachine->parseErrors();
+ for (const QScxmlError &error : errors) {
+ qmlWarning(this) << error.toString();
+ }
+ return false;
+ }
+}
diff --git a/src/scxmlqml/statemachineloader_p.h b/src/scxmlqml/statemachineloader_p.h
new file mode 100644
index 0000000..46a228c
--- /dev/null
+++ b/src/scxmlqml/statemachineloader_p.h
@@ -0,0 +1,87 @@
+// 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
+
+#ifndef STATEMACHINELOADER_P_H
+#define STATEMACHINELOADER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qscxmlqmlglobals_p.h"
+
+#include <QtCore/qurl.h>
+#include <QtScxml/qscxmlstatemachine.h>
+
+#include <QtCore/private/qproperty_p.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_SCXMLQML_EXPORT QScxmlStateMachineLoader: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource
+ NOTIFY sourceChanged BINDABLE bindableSource)
+ Q_PROPERTY(QScxmlStateMachine *stateMachine READ stateMachine DESIGNABLE false
+ NOTIFY stateMachineChanged BINDABLE bindableStateMachine)
+ Q_PROPERTY(QVariantMap initialValues READ initialValues WRITE setInitialValues
+ NOTIFY initialValuesChanged BINDABLE bindableInitialValues)
+ Q_PROPERTY(QScxmlDataModel *dataModel READ dataModel
+ WRITE setDataModel NOTIFY dataModelChanged BINDABLE bindableDataModel)
+ QML_NAMED_ELEMENT(StateMachineLoader)
+ QML_ADDED_IN_VERSION(5,8)
+
+public:
+ explicit QScxmlStateMachineLoader(QObject *parent = nullptr);
+
+ QScxmlStateMachine *stateMachine() const;
+ QBindable<QScxmlStateMachine*> bindableStateMachine();
+
+ QUrl source();
+ void setSource(const QUrl &source);
+ QBindable<QUrl> bindableSource();
+
+ QVariantMap initialValues() const;
+ void setInitialValues(const QVariantMap &initialValues);
+ QBindable<QVariantMap> bindableInitialValues();
+
+ QScxmlDataModel *dataModel() const;
+ void setDataModel(QScxmlDataModel *dataModel);
+ QBindable<QScxmlDataModel*> bindableDataModel();
+
+Q_SIGNALS:
+ void sourceChanged();
+ void initialValuesChanged();
+ void stateMachineChanged();
+ void dataModelChanged();
+
+private:
+ bool parse(const QUrl &source);
+ void setStateMachine(QScxmlStateMachine* stateMachine);
+
+private:
+ Q_OBJECT_COMPAT_PROPERTY(QScxmlStateMachineLoader, QUrl,
+ m_source, &QScxmlStateMachineLoader::setSource,
+ &QScxmlStateMachineLoader::sourceChanged);
+ Q_OBJECT_COMPAT_PROPERTY(QScxmlStateMachineLoader, QVariantMap,
+ m_initialValues, &QScxmlStateMachineLoader::setInitialValues,
+ &QScxmlStateMachineLoader::initialValuesChanged);
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QScxmlStateMachineLoader, QScxmlDataModel*,
+ m_dataModel, &QScxmlStateMachineLoader::setDataModel,
+ &QScxmlStateMachineLoader::dataModelChanged, nullptr);
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QScxmlStateMachineLoader, QScxmlStateMachine*,
+ m_stateMachine, nullptr, &QScxmlStateMachineLoader::stateMachineChanged);
+ QScxmlDataModel *m_implicitDataModel;
+};
+
+QT_END_NAMESPACE
+
+#endif // STATEMACHINELOADER_P_H
diff --git a/src/src.pro b/src/src.pro
deleted file mode 100644
index e1073fb..0000000
--- a/src/src.pro
+++ /dev/null
@@ -1,8 +0,0 @@
-TEMPLATE = subdirs
-
-SUBDIRS += scxml
-
-qtHaveModule(qml) {
- SUBDIRS += imports
- imports.depends = scxml
-}
diff --git a/src/statemachine/CMakeLists.txt b/src/statemachine/CMakeLists.txt
new file mode 100644
index 0000000..e68c571
--- /dev/null
+++ b/src/statemachine/CMakeLists.txt
@@ -0,0 +1,53 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+#####################################################################
+## StateMachine Module:
+#####################################################################
+
+qt_internal_include_in_repo_target_set(qtstatemachine)
+
+qt_internal_add_module(StateMachine
+ SOURCES
+ qabstractstate.cpp qabstractstate.h qabstractstate_p.h
+ qabstracttransition.cpp qabstracttransition.h qabstracttransition_p.h
+ qfinalstate.cpp qfinalstate.h qfinalstate_p.h
+ qhistorystate.cpp qhistorystate.h qhistorystate_p.h
+ qsignaleventgenerator_p.h
+ qsignaltransition.cpp qsignaltransition.h qsignaltransition_p.h
+ qstate.cpp qstate.h qstate_p.h
+ qstatemachine.cpp qstatemachine.h qstatemachine_p.h
+ qstatemachineglobal.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ PRIVATE_MODULE_INTERFACE
+ Qt::CorePrivate
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(StateMachine CONDITION QT_FEATURE_qeventtransition
+ SOURCES
+ gui/qbasickeyeventtransition.cpp gui/qbasickeyeventtransition_p.h
+ gui/qbasicmouseeventtransition.cpp gui/qbasicmouseeventtransition_p.h
+ gui/qkeyeventtransition.cpp gui/qkeyeventtransition.h
+ gui/qmouseeventtransition.cpp gui/qmouseeventtransition.h
+ qeventtransition.cpp qeventtransition.h qeventtransition_p.h
+ LIBRARIES
+ Qt::GuiPrivate
+ PUBLIC_LIBRARIES
+ Qt::Gui
+ PRIVATE_MODULE_INTERFACE
+ Qt::GuiPrivate
+)
+
+qt_internal_add_docs(StateMachine
+ doc/qtstatemachine.qdocconf
+)
diff --git a/src/statemachine/configure.cmake b/src/statemachine/configure.cmake
new file mode 100644
index 0000000..c6cda82
--- /dev/null
+++ b/src/statemachine/configure.cmake
@@ -0,0 +1,29 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+
+
+#### Tests
+
+
+
+#### Features
+
+qt_feature("statemachine" PUBLIC
+ SECTION "Utilities"
+ LABEL "State machine"
+ PURPOSE "Provides hierarchical finite state machines."
+)
+qt_feature_definition("statemachine" "QT_NO_STATEMACHINE" NEGATE VALUE "1")
+qt_feature("qeventtransition" PUBLIC
+ LABEL "QEventTransition class"
+ CONDITION QT_FEATURE_statemachine AND TARGET Qt::Gui # special case
+)
diff --git a/src/statemachine/doc/images/animations-architecture.png b/src/statemachine/doc/images/animations-architecture.png
new file mode 100644
index 0000000..9b581af
--- /dev/null
+++ b/src/statemachine/doc/images/animations-architecture.png
Binary files differ
diff --git a/src/statemachine/doc/images/move-blocks-chart.png b/src/statemachine/doc/images/move-blocks-chart.png
new file mode 100644
index 0000000..fd0c165
--- /dev/null
+++ b/src/statemachine/doc/images/move-blocks-chart.png
Binary files differ
diff --git a/src/statemachine/doc/images/rogue-statechart.png b/src/statemachine/doc/images/rogue-statechart.png
new file mode 100644
index 0000000..c5f4048
--- /dev/null
+++ b/src/statemachine/doc/images/rogue-statechart.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-button-history.png b/src/statemachine/doc/images/statemachine-button-history.png
new file mode 100644
index 0000000..7f51cae
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-button-history.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-button-nested.png b/src/statemachine/doc/images/statemachine-button-nested.png
new file mode 100644
index 0000000..762ac14
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-button-nested.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-button.png b/src/statemachine/doc/images/statemachine-button.png
new file mode 100644
index 0000000..10102bd
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-button.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-customevents.png b/src/statemachine/doc/images/statemachine-customevents.png
new file mode 100644
index 0000000..62a4222
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-customevents.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-customevents2.png b/src/statemachine/doc/images/statemachine-customevents2.png
new file mode 100644
index 0000000..57b37ef
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-customevents2.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-examples.png b/src/statemachine/doc/images/statemachine-examples.png
new file mode 100644
index 0000000..b2ec66e
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-examples.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-finished.png b/src/statemachine/doc/images/statemachine-finished.png
new file mode 100644
index 0000000..0ac081d
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-finished.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-nonparallel.png b/src/statemachine/doc/images/statemachine-nonparallel.png
new file mode 100644
index 0000000..f9850a7
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-nonparallel.png
Binary files differ
diff --git a/src/statemachine/doc/images/statemachine-parallel.png b/src/statemachine/doc/images/statemachine-parallel.png
new file mode 100644
index 0000000..a65c297
--- /dev/null
+++ b/src/statemachine/doc/images/statemachine-parallel.png
Binary files differ
diff --git a/src/statemachine/doc/qstatemachine-qml-guide.qdoc b/src/statemachine/doc/qstatemachine-qml-guide.qdoc
new file mode 100644
index 0000000..deb9d94
--- /dev/null
+++ b/src/statemachine/doc/qstatemachine-qml-guide.qdoc
@@ -0,0 +1,293 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qmlstatemachine-qml-guide.html
+ \title Qt State Machine QML Guide
+ \brief Overview of the Qt State Machine QML for constructing and executing state graphs.
+ \ingroup technology-apis
+ \ingroup explanation
+
+ \tableofcontents
+
+ Qt State Machine QML APIs provide types for creating and
+ executing state graphs in QML. It is similar to the C++ State Machine
+ framework based on Harel's
+ \l{Statecharts: A visual formalism for complex systems}, which
+ is also the basis for UML state diagrams. Like its
+ \l{Qt State Machine C++ Classes}{C++ counterpart}, the framework provides an
+ API and execution model based on \l{State Chart XML: State Machine Notation for
+ Control Abstraction}{State Chart XML (SCXML)}
+ to embed the elements and semantics of statecharts in QML applications.
+
+ For user interfaces with multiple visual states, independent of the
+ application's logical state, consider using QML States and Transitions.
+
+ For the full list of QML types provided by the framework to create event-driven
+ state machines, see: \l {Qt State Machine QML Types}
+
+ \section1 Using Both QtQuick and QtQml.StateMachine Imports
+
+ \warning If you're attempting to import both \l{QtQuick} and
+ \e{QtQml.StateMachine} in one single QML file, make sure to import
+ \e{QtQml.StateMachine} \e{last}. This way, the \e{State} type is provided
+ by the Declarative State Machine Framework and not by \l{QtQuick}:
+
+ \qml
+ import QtQuick
+ import QtQml.StateMachine
+
+ StateMachine {
+ State {
+ // okay, is of type QtQml.StateMachine.State
+ }
+ }
+ \endqml
+
+ Alternatively, you can import \e{QtQml.StateMachine} into a separate
+ namespace to avoid any ambiguity with QtQuick's \e{State} item:
+
+ \qml \QtMinorVersion
+ import QtQuick
+ import QtQml.StateMachine as DSM
+
+ DSM.StateMachine {
+ DSM.State {
+ // ...
+ }
+ }
+ \endqml
+
+ \section1 A Simple State Machine
+
+ To demonstrate the core functionality of the State Machine API, let's look
+ at an example: A state machine with three states, \c s1, \c s2 and \c
+ s3. The state machine is controlled by a single Button; when the button
+ is clicked, the machine transitions to another state. Initially, the state
+ machine is in state \c s1. The following is a state chart showing the
+ different states in our example.
+
+ \image statemachine-button.png
+
+ The following snippet shows the code needed to create such a state machine.
+
+ \snippet qml/statemachine/statemachine-button.qml 0
+
+ The state machine runs asynchronously to become part of your application's
+ event loop.
+
+ \section1 State Machines That Finish
+
+ The state machine defined in the previous section never finishes. In order
+ for a state machine to be able to finish, it needs to have a top-level \e
+ final state (FinalState object). When the state machine enters the top-level
+ final state, the machine emits the \l{State::finished}{finished}
+ signal and halts.
+
+ All you need to do to introduce a final state in the graph is create a
+ FinalState object and use it as the target of one or more transitions.
+
+ \section1 Sharing Transitions
+
+ Assume we wanted the user to be able to quit the application at any time by
+ clicking a Quit button. In order to achieve this, we need to create a final
+ state and make it the target of a transition associated with the Quit
+ button's \e clicked() signal. We could add a transition for each state;
+ however, this seems redundant and one would also have to
+ remember to add such a transition from every new state that is added in the
+ future.
+
+ We can achieve the same behavior (namely that clicking the Quit button quits
+ the state machine, regardless of which state the state machine is in) by
+ grouping states \c s1, \c s2 and \c s3. This is done by creating a new
+ top-level state and making the three original states children of the new
+ state. The following diagram shows the new state machine.
+
+ \image statemachine-button-nested.png
+
+ The three original states have been renamed \c s11, \c s12 and \c s13 to
+ reflect that they are now childrens of the new top-level state, \c s1. Child
+ states implicitly inherit the transitions of their parent state. This means
+ it is now sufficient to add a single transition from \c s1 to the final
+ state, \c s2. New states added to \c s1 will automatically inherit this
+ transition.
+
+ All that's needed to group states is to specify the proper parent when the
+ state is created. You also need to specify which of the child states is the
+ initial one (the child state the state machine should enter when the
+ parent state is the target of a transition).
+
+ \snippet qml/statemachine/statemachine-button-nested.qml 0
+
+ In this case we want the application to quit when the state machine is
+ finished, so the machine's \e finished() signal is connected to the
+ application's \e quit() slot.
+
+ A child state can override an inherited transition. For example, the
+ following code adds a transition that effectively causes the Quit button to
+ be ignored when the state machine is in state, \c s12.
+
+ \snippet qml/statemachine/statemachine-button-nested-ignore-quit.qml 0
+
+ A transition can have any state as its target irrespective of where the
+ target state is in the state hierarchy.
+
+ \section1 Using History States
+
+ Imagine that we wanted to add an "interrupt" mechanism to the example
+ discussed in the previous section; the user should be able to click a button
+ to have the state machine perform some non-related task, after which the
+ state machine should resume whatever it was doing before (i.e. return to the
+ old state, which is one of the three states in this case).
+
+ Such behavior can easily be modeled using \e{history states}. A history
+ state (HistoryState object) is a pseudo-state that represents the child
+ state that the parent state was in before it exited last.
+
+ A history state is created as a child of the state for which we wish to
+ record the current child state; when the state machine detects the presence
+ of such a state at runtime, it automatically records the current (real)
+ child state when the parent state exits. A transition to the history
+ state is in fact a transition to the child state that the state machine had
+ previously saved; the state machine automatically "forwards" the transition
+ to the real child state.
+
+ The following diagram shows the state machine after the interrupt mechanism
+ has been added.
+
+ \image statemachine-button-history.png
+
+ The following code shows how it can be implemented; in this example we
+ simply display a message box when \c s3 is entered, then immediately return
+ to the previous child state of \c s1 via the history state.
+
+ \snippet qml/statemachine/statemachine-button-history.qml 0
+
+ \section1 Using Parallel States
+
+ Assume that you wanted to model a set of mutually exclusive properties of a
+ car in a single state machine. Let's say the properties we are interested in
+ are Clean vs Dirty, and Moving vs Not moving. It would take four mutually
+ exclusive states and eight transitions to represent the states and freely
+ move between all possible combinations as shown in the following state chart.
+
+ \image statemachine-nonparallel.png
+
+ If we added a third property (say, Red vs Blue), the total number of states
+ would double, to eight; and if we added a fourth property (say, Enclosed vs
+ Convertible), the total number of states would double again, to 16.
+
+ This exponential increase can be reduced using parallel states, which enables
+ linear growth in the number of states and transitions as we add more
+ properties. Furthermore, states can be added to or removed from the parallel
+ state without affecting any of their sibling states. The following state
+ chart shows the different paralles states for the car example.
+
+ \image statemachine-parallel.png
+
+ To create a parallel state group, set childMode to QState.ParallelStates.
+
+ \qml
+ State {
+ id: s1
+ childMode: QState.ParallelStates
+ State {
+ id: s11
+ }
+ State {
+ id: s12
+ }
+ }
+ \endqml
+
+ When a parallel state group is entered, all its child states will be
+ simultaneously entered. Transitions within the individual child states
+ operate normally. However, any of the child states may take a transition
+ which exits the parent state. When this happens, the parent state and all of
+ its child states are exited.
+
+ The parallelism in the State Machine framework follows an interleaved
+ semantics. All parallel operations will be executed in a single, atomic step
+ of the event processing, so no event can interrupt the parallel operations.
+ However, events will still be processed sequentially, as the machine itself
+ is single threaded. For example, consider the situation where there are two
+ transitions that exit the same parallel state group, and their conditions
+ become true simultaneously. In this case, the event that is processed last
+ of the two will not have any effect.
+
+ \section1 Exiting a Composite State
+
+ A child state can be final (a FinalState object); when a final child state
+ is entered, the parent state emits the State::finished signal. The
+ following diagram shows a composite state \c s1 which does some processing
+ before entering a final state:
+
+ \image statemachine-finished.png
+
+ When \c s1 's final state is entered, \c s1 will automatically emit
+ \l{State::finished}{finished}. We use a signal transition to cause this event to
+ trigger a state change:
+
+ \qml
+ State {
+ id: s1
+ SignalTransition {
+ targetState: s2
+ signal: s1.finished
+ }
+ }
+ \endqml
+
+ Using final states in composite states is useful when you want to hide the
+ internal details of a composite state. The outside world should be able to
+ enter the state and get a notification when the state has completed its work,
+ without the need to know the internal details. This is a very powerful
+ abstraction and encapsulation mechanism when building complex (deeply nested)
+ state machines. (In the above example, you could of course create a transition
+ directly from \c s1 's \c done state rather than relying on \c s1 's
+ finished() signal, but with the consequence that implementation details of
+ \c s1 are exposed and depended on).
+
+ For parallel state groups, the State::finished signal is emitted when \e
+ all the child states have entered final states.
+
+ \section1 Targetless Transitions
+
+ A transition need not have a target state. A transition without a target can
+ be triggered the same way as any other transition; the difference is that
+ it doesn't cause any state changes. This allows you to react to a signal or
+ event when your machine is in a certain state, without having to leave that
+ state. For example:
+
+ \qml
+ Button {
+ id: button
+ text: "button"
+ StateMachine {
+ id: stateMachine
+ initialState: s1
+ running: true
+ State {
+ id: s1
+ SignalTransition {
+ signal: button.clicked
+ onTriggered: console.log("button pressed")
+ }
+ }
+ }
+ }
+ \endqml
+
+ The "button pressed" message will be displayed each time the button is clicked, but the
+ state machine will remain in its current state (s1). If the target state
+ were explicitly set to s1, s1 would be exited and re-entered each
+ time (the QAbstractState::entered and QAbstractState::exited
+ signals would be emitted).
+
+ \section1 Related Information
+
+ \list
+ \li \l{Qt State Machine QML Types}
+ \li \l{Qt State Machine Overview}
+ \endlist
+*/
diff --git a/src/statemachine/doc/qt6-changes.qdoc b/src/statemachine/doc/qt6-changes.qdoc
new file mode 100644
index 0000000..c7f6efe
--- /dev/null
+++ b/src/statemachine/doc/qt6-changes.qdoc
@@ -0,0 +1,43 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtstatemachine-changes-qt6.html
+ \title Changes to Qt State Machine
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt State Machine to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain binary and source compatibility for all the public
+ APIs in each release. But some changes were inevitable in an effort to
+ make Qt a better framework.
+
+ In this topic we summarize those changes in Qt State Machine module, and provide
+ guidance to handle them.
+
+ \section1 Changes
+
+ The Qt StateMachine module is generally speaking source compatible with the Qt5
+ version and users of the library should be able to continue with no or
+ minor changes to their project.
+
+ \section2 QSignalTransition
+
+ The \l [CPP] QSignalTransition::senderObject() getter and the related
+ Q_PROPERTY now also use const QObject*. These are now better aligned
+ with the setter \l [CPP] QSignalTransition::setSenderObject(const QObject*) that takes a
+ const QObject* as a parameter.
+
+ \section1 Build system
+
+ As with Qt 6 in general, the Qt State Machine module has cmake support in addition
+ to qmake.
+
+ \section1 QML imports
+
+ The QML import versioning is optional unless one has a specific
+ reason for not using the latest. Generally speaking the versioned imports
+ work from version 5.8 to 6.x, where 'x' is the current minor release.
+*/
diff --git a/src/statemachine/doc/qtstatemachine-cpp-guide.qdoc b/src/statemachine/doc/qtstatemachine-cpp-guide.qdoc
new file mode 100644
index 0000000..a898ba4
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine-cpp-guide.qdoc
@@ -0,0 +1,511 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtstatemachine-cpp-guide.html
+ \title Qt State Machine C++ Guide
+ \brief An overview of the State Machine framework for constructing and
+ executing state graphs with the C++ API.
+ \ingroup technology-apis
+ \ingroup explanation
+
+ \tableofcontents
+
+ The State Machine framework provides classes for creating and executing
+ state graphs. This page illustrates the framework's key features in C++.
+
+ \sa {Qt State Machine Overview}
+ \sa {Qt State Machine QML Guide}
+
+ \section1 C++ Classes in the State Machine Framework
+
+ For the full list of C++ classes in the State Machine framework see
+ \l {Qt State Machine C++ Classes}
+
+ \section1 A Simple State Machine
+
+ To demonstrate the core functionality of the State Machine API, let's look
+ at a small example: A state machine with three states, \c s1, \c s2 and \c
+ s3. The state machine is controlled by a single QPushButton; when the button
+ is clicked, the machine transitions to another state. Initially, the state
+ machine is in state \c s1. The statechart for this machine is as follows:
+
+ \image statemachine-button.png
+
+ The following snippet shows the code needed to create such a state machine.
+ First, we create the state machine and states:
+
+ \snippet statemachine/main.cpp 0
+
+ Then, we create the transitions by using the QState::addTransition()
+ function:
+
+ \snippet statemachine/main.cpp 1
+
+ Next, we add the states to the machine and set the machine's initial state:
+
+ \snippet statemachine/main.cpp 2
+
+ Finally, we start the state machine:
+
+ \snippet statemachine/main.cpp 3
+
+ The state machine executes asynchronously, i.e. it becomes part of your
+ application's event loop.
+
+ \section1 Doing Useful Work on State Entry and Exit
+
+ The above state machine merely transitions from one state to another, it
+ doesn't perform any operations. The QState::assignProperty() function can be
+ used to have a state set a property of a QObject when the state is
+ entered. In the following snippet, the value that should be assigned to a
+ QLabel's text property is specified for each state:
+
+ \snippet statemachine/main.cpp 4
+
+ When any of the states is entered, the label's text will be changed
+ accordingly.
+
+ The QState::entered() signal is emitted when the state is entered, and the
+ QState::exited() signal is emitted when the state is exited. In the
+ following snippet, the button's \l {QPushButton::}{showMaximized()} slot
+ will be called when state \c s3 is entered, and the button's \l {QPushButton::}{showMinimized()}
+ slot will be called when \c s3 is exited:
+
+ \snippet statemachine/main.cpp 5
+
+ Custom states can reimplement QAbstractState::onEntry() and
+ QAbstractState::onExit().
+
+ \section1 State Machines That Finish
+
+ The state machine defined in the previous section never finishes. In order
+ for a state machine to be able to finish, it needs to have a top-level \e
+ final state (QFinalState object). When the state machine enters a top-level
+ final state, the machine will emit the QStateMachine::finished() signal and
+ halt.
+
+ All you need to do to introduce a final state in the graph is create a
+ QFinalState object and use it as the target of one or more transitions.
+
+ \section1 Sharing Transitions By Grouping States
+
+ Assume we wanted the user to be able to quit the application at any time by
+ clicking a Quit button. In order to achieve this, we need to create a final
+ state and make it the target of a transition associated with the Quit
+ button's \l{QPushButton::}{clicked()} signal. We could add a transition from each of \c s1, \c
+ s2 and \c s3; however, this seems redundant, and one would also have to
+ remember to add such a transition from every new state that is added in the
+ future.
+
+ We can achieve the same behavior (namely that clicking the Quit button quits
+ the state machine, regardless of which state the state machine is in) by
+ grouping states \c s1, \c s2 and \c s3. This is done by creating a new
+ top-level state and making the three original states children of the new
+ state. The following diagram shows the new state machine.
+
+ \image statemachine-button-nested.png
+
+ The three original states have been renamed \c s11, \c s12 and \c s13 to
+ reflect that they are now children of the new top-level state, \c s1. Child
+ states implicitly inherit the transitions of their parent state. This means
+ it is now sufficient to add a single transition from \c s1 to the final
+ state \c s2. New states added to \c s1 will also automatically inherit this
+ transition.
+
+ All that's needed to group states is to specify the proper parent when the
+ state is created. You also need to specify which of the child states is the
+ initial one (i.e. which child state the state machine should enter when the
+ parent state is the target of a transition).
+
+ \snippet statemachine/main2.cpp 0
+
+ \snippet statemachine/main2.cpp 1
+
+ In this case we want the application to quit when the state machine is
+ finished, so the machine's \l {QStateMachine::}{finished()} signal is connected to the
+ application's \l {QCoreApplication::}{quit()} slot.
+
+ A child state can override an inherited transition. For example, the
+ following code adds a transition that effectively causes the Quit button to
+ be ignored when the state machine is in state \c s12.
+
+ \snippet statemachine/main2.cpp 2
+
+ A transition can have any state as its target, i.e. the target state does
+ not have to be on the same level in the state hierarchy as the source state.
+
+ \section1 Using History States to Save and Restore the Current State
+
+ Imagine that we wanted to add an "interrupt" mechanism to the example
+ discussed in the previous section; the user should be able to click a button
+ to have the state machine perform some non-related task, after which the
+ state machine should resume whatever it was doing before (i.e. return to the
+ old state, which is one of \c s11, \c s12 and \c s13 in this case).
+
+ Such behavior can easily be modeled using \e{history states}. A history
+ state (QHistoryState object) is a pseudo-state that represents the child
+ state that the parent state was in the last time the parent state was
+ exited.
+
+ A history state is created as a child of the state for which we wish to
+ record the current child state; when the state machine detects the presence
+ of such a state at runtime, it automatically records the current (real)
+ child state when the parent state is exited. A transition to the history
+ state is in fact a transition to the child state that the state machine had
+ previously saved; the state machine automatically "forwards" the transition
+ to the real child state.
+
+ The following diagram shows the state machine after the interrupt mechanism
+ has been added.
+
+ \image statemachine-button-history.png
+
+ The following code shows how it can be implemented; in this example we
+ simply display a message box when \c s3 is entered, then immediately return
+ to the previous child state of \c s1 via the history state.
+
+ \snippet statemachine/main2.cpp 3
+
+ \section1 Using Parallel States to Avoid a Combinatorial Explosion of States
+
+ Assume that you wanted to model a set of mutually exclusive properties of a
+ car in a single state machine. Let's say the properties we are interested in
+ are Clean vs Dirty, and Moving vs Not moving. It would take four mutually
+ exclusive states and eight transitions to be able to represent and freely
+ move between all possible combinations.
+
+ \image statemachine-nonparallel.png
+
+ If we added a third property (say, Red vs Blue), the total number of states
+ would double, to eight; and if we added a fourth property (say, Enclosed vs
+ Convertible), the total number of states would double again, to 16.
+
+ Using parallel states, the total number of states and transitions grows
+ linearly as we add more properties, instead of exponentially. Furthermore,
+ states can be added to or removed from the parallel state without affecting
+ any of their sibling states.
+
+ \image statemachine-parallel.png
+
+ To create a parallel state group, pass QState::ParallelStates to the QState
+ constructor.
+
+ \snippet statemachine/main3.cpp 0
+
+ When a parallel state group is entered, all its child states will be
+ simultaneously entered. Transitions within the individual child states
+ operate normally. However, any of the child states may take a transition which exits the parent
+ state. When this happens, the parent state and all of its child states are exited.
+
+ The parallelism in the State Machine framework follows an interleaved semantics. All parallel
+ operations will be executed in a single, atomic step of the event processing, so no event can
+ interrupt the parallel operations. However, events will still be processed sequentially, since
+ the machine itself is single threaded. As an example: Consider the situation where there are two
+ transitions that exit the same parallel state group, and their conditions become true
+ simultaneously. In this case, the event that is processed last of the two will not have any
+ effect, since the first event will already have caused the machine to exit from the parallel
+ state.
+
+ \section1 Detecting that a Composite State has Finished
+
+ A child state can be final (a QFinalState object); when a final child state
+ is entered, the parent state emits the QState::finished() signal. The
+ following diagram shows a composite state \c s1 which does some processing
+ before entering a final state:
+
+ \image statemachine-finished.png
+
+ When \c s1 's final state is entered, \c s1 will automatically emit
+ \l {QState::}{finished()}. We use a signal transition to cause this event to trigger a
+ state change:
+
+ \snippet statemachine/main3.cpp 1
+
+ Using final states in composite states is useful when you want to hide the
+ internal details of a composite state; i.e. the only thing the outside world
+ should be able to do is enter the state, and get a notification when the
+ state has completed its work. This is a very powerful abstraction and
+ encapsulation mechanism when building complex (deeply nested) state
+ machines. (In the above example, you could of course create a transition
+ directly from \c s1 's \c done state rather than relying on \c s1 's
+ \l {QState::}{finished()} signal, but with the consequence that implementation details of
+ \c s1 are exposed and depended on).
+
+ For parallel state groups, the QState::finished() signal is emitted when \e
+ all the child states have entered final states.
+
+ \section1 Targetless Transitions
+
+ A transition need not have a target state. A transition without a target can
+ be triggered the same way as any other transition; the difference is that
+ when a targetless transition is triggered, it doesn't cause any state
+ changes. This allows you to react to a signal or event when your machine is
+ in a certain state, without having to leave that state. Example:
+
+ \code
+ QStateMachine machine;
+ QState *s1 = new QState(&machine);
+
+ QPushButton button;
+ QSignalTransition *trans = new QSignalTransition(&button, &QPushButton::clicked);
+ s1->addTransition(trans);
+
+ QMessageBox msgBox;
+ msgBox.setText("The button was clicked; carry on.");
+ QObject::connect(trans, QSignalTransition::triggered, &msgBox, &QMessageBox::exec);
+
+ machine.setInitialState(s1);
+ \endcode
+
+ The message box will be displayed each time the button is clicked, but the
+ state machine will remain in its current state (s1). If the target state
+ were explicitly set to s1, however, s1 would be exited and re-entered each
+ time (e.g. the QAbstractState::entered() and QAbstractState::exited()
+ signals would be emitted).
+
+ \section1 Events, Transitions and Guards
+
+ A QStateMachine runs its own event loop. For signal transitions
+ (QSignalTransition objects), QStateMachine automatically posts a
+ QStateMachine::SignalEvent to itself when it intercepts the corresponding
+ signal; similarly, for QObject event transitions (QEventTransition objects)
+ a QStateMachine::WrappedEvent is posted.
+
+ You can post your own events to the state machine using
+ QStateMachine::postEvent().
+
+ When posting a custom event to the state machine, you typically also have
+ one or more custom transitions that can be triggered from events of that
+ type. To create such a transition, you subclass QAbstractTransition and
+ reimplement \l [CPP] {QAbstractTransition::}{eventTest()}, where you check if an event
+ matches your event type (and optionally other criteria, e.g. attributes of
+ the event object).
+
+ Here we define our own custom event type, \c StringEvent, for posting
+ strings to the state machine:
+
+ \snippet statemachine/main4.cpp 0
+
+ Next, we define a transition that only triggers when the event's string
+ matches a particular string (a \e guarded transition):
+
+ \snippet statemachine/main4.cpp 1
+
+ In the \l [CPP] {QAbstractTransition::}{eventTest()} reimplementation, we first check if the event type is the
+ desired one; if so, we cast the event to a \c StringEvent and perform the
+ string comparison.
+
+ The following is a statechart that uses the custom event and transition:
+
+ \image statemachine-customevents.png
+
+ Here's what the implementation of the statechart looks like:
+
+ \snippet statemachine/main4.cpp 2
+
+ Once the machine is started, we can post events to it.
+
+ \snippet statemachine/main4.cpp 3
+
+ An event that is not handled by any relevant transition will be silently
+ consumed by the state machine. It can be useful to group states and provide
+ a default handling of such events; for example, as illustrated in the
+ following statechart:
+
+ \image statemachine-customevents2.png
+
+ For deeply nested statecharts, you can add such "fallback" transitions at
+ the level of granularity that's most appropriate.
+
+ \section1 Using Restore Policy To Automatically Restore Properties
+
+ In some state machines it can be useful to focus the attention on assigning properties in states,
+ not on restoring them when the state is no longer active. If you know that a property should
+ always be restored to its initial value when the machine enters a state that does not explicitly
+ give the property a value, you can set the global restore policy to
+ QStateMachine::RestoreProperties.
+
+ \code
+ QStateMachine machine;
+ machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
+ \endcode
+
+ When this restore policy is set, the machine will automatically restore all properties. If it
+ enters a state where a given property is not set, it will first search the hierarchy of ancestors
+ to see if the property is defined there. If it is, the property will be restored to the value
+ defined by the closest ancestor. If not, it will be restored to its initial value (i.e. the
+ value of the property before any property assignments in states were executed.)
+
+ Take the following code:
+
+ \snippet statemachine/main5.cpp 0
+
+ Lets say the property \c fooBar is 0.0 when the machine starts. When the machine is in state
+ \c s1, the property will be 1.0, since the state explicitly assigns this value to it. When the
+ machine is in state \c s2, no value is explicitly defined for the property, so it will implicitly
+ be restored to 0.0.
+
+ If we are using nested states, the parent defines a value for the property which is inherited by
+ all descendants that do not explicitly assign a value to the property.
+
+ \snippet statemachine/main5.cpp 2
+
+ Here \c s1 has two children: \c s2 and \c s3. When \c s2 is entered, the property \c fooBar
+ will have the value 2.0, since this is explicitly defined for the state. When the machine is in
+ state \c s3, no value is defined for the state, but \c s1 defines the property to be 1.0, so this
+ is the value that will be assigned to \c fooBar.
+
+ \section1 Animations and States Machines
+
+ The State Machine API connects with the \l {The Animation Framework} to allow automatically
+ animating properties as they are assigned in states.
+
+ The state machine provides a special state that can play an animation.
+ A QState can also set properties when the state is entered or exited, and
+ this special animation state will interpolate between these values when given a
+ QPropertyAnimation.
+
+ We can associate one or more animations to a transition between states
+ using a QSignalTransition or QEventTransition class. These classes
+ are both derived from QAbstractTransition, which defines the
+ convenience function \l [CPP] {QAbstractTransition::}{addAnimation()} that
+ enables the appending of one or more animations triggered when the
+ transition occurs.
+
+ We also have the possibility to associate properties with the
+ states rather than setting the start and end values ourselves.
+
+ Say we have the following code:
+
+ \snippet statemachine/main5.cpp 3
+
+ Here we define two states of a user interface. In \c s1 the \c button is small, and in \c s2
+ it is bigger. If we click the button to transition from \c s1 to \c s2, the geometry of the button
+ will be set immediately when a given state has been entered. If we want the transition to be
+ smooth, however, all we need to do is make a QPropertyAnimation and add this to the transition
+ object.
+
+ \snippet statemachine/main5.cpp 4
+
+ Adding an animation for the property in question means that the property assignment will no
+ longer take immediate effect when the state has been entered. Instead, the animation will start
+ playing when the state has been entered and smoothly animate the property assignment. Since we
+ do not set the start value or end value of the animation, these will be set implicitly. The
+ start value of the animation will be the property's current value when the animation starts, and
+ the end value will be set based on the property assignments defined for the state.
+
+ If the global restore policy of the state machine is set to QStateMachine::RestoreProperties,
+ it is possible to also add animations for the property restorations.
+
+ \section1 Detecting That All Properties Have Been Set In A State
+
+ When animations are used to assign properties, a state no longer defines the exact values that a
+ property will have when the machine is in the given state. While the animation is running, the
+ property can potentially have any value, depending on the animation.
+
+ In some cases, it can be useful to be able to detect when the property has actually been assigned
+ the value defined by a state.
+
+ Say we have the following code:
+
+ \snippet statemachine/main5.cpp 5
+
+ When \c button is clicked, the machine will transition into state \c s2, which will set the
+ geometry of the button, and then pop up a message box to alert the user that the geometry has
+ been changed.
+
+ In the normal case, where animations are not used, this will operate as expected. However, if
+ an animation for the \c geometry of \c button is set on the transition between \c s1 and \c s2,
+ the animation will be started when \c s2 is entered, but the \c geometry property will not
+ actually reach its defined value before the animation is finished running. In this case, the
+ message box will pop up before the geometry of the button has actually been set.
+
+ To ensure that the message box does not pop up until the geometry actually reaches its final
+ value, we can use the state's \l {QState::}{propertiesAssigned()} signal.
+ The \l {QState::}{propertiesAssigned()} signal will be emitted when the property is assigned
+ its final value, whether this is done immediately or after the animation has finished playing.
+
+ \snippet statemachine/main5.cpp 6
+
+ In this example, when \c button is clicked, the machine will enter \c s2. It will remain in state
+ \c s2 until the \c geometry property has been set to \c QRect(0, 0, 50, 50). Then it will
+ transition into \c s3. When \c s3 is entered, the message box will pop up. If the transition into
+ \c s2 has an animation for the \c geometry property, then the machine will stay in \c s2 until the
+ animation has finished playing. If there is no such animation, it will simply set the property and
+ immediately enter state \c s3.
+
+ Either way, when the machine is in state \c s3, you are guaranteed that the property \c geometry
+ has been assigned the defined value.
+
+ If the global restore policy is set to QStateMachine::RestoreProperties, the state will not emit
+ the \l {QState::}{propertiesAssigned()} signal until these have been executed as well.
+
+ \section1 What Happens If A State Is Exited Before The Animation Has Finished
+
+ If a state has property assignments, and the transition into the state has animations for the
+ properties, the state can potentially be exited before the properties have been assigned to the
+ values defines by the state. This is true in particular when there are transitions out from the
+ state that do not depend on the \l {QState::}{propertiesAssigned()} signal, as described in the previous section.
+
+ The State Machine API guarantees that a property assigned by the state machine either:
+ \list
+ \li Has a value explicitly assigned to the property.
+ \li Is currently being animated into a value explicitly assigned to the property.
+ \endlist
+
+ When a state is exited prior to the animation finishing, the behavior of the state machine depends
+ on the target state of the transition. If the target state explicitly assigns a value to the
+ property, no additional action will be taken. The property will be assigned the value defined by
+ the target state.
+
+ If the target state does not assign any value to the property, there are two
+ options: By default, the property will be assigned the value defined by the state it is leaving
+ (the value it would have been assigned if the animation had been permitted to finish playing). If
+ a global restore policy is set, however, this will take precedence, and the property will be
+ restored as usual.
+
+ \section1 Default Animations
+
+ As described earlier, you can add animations to transitions to make sure property assignments
+ in the target state are animated. If you want a specific animation to be used for a given property
+ regardless of which transition is taken, you can add it as a default animation to the state
+ machine. This is in particular useful when the properties assigned (or restored) by specific
+ states is not known when the machine is constructed.
+
+ \code
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+
+ s2->assignProperty(object, "fooBar", 2.0);
+ s1->addTransition(s2);
+
+ QStateMachine machine;
+ machine.setInitialState(s1);
+ machine.addDefaultAnimation(new QPropertyAnimation(object, "fooBar"));
+ \endcode
+
+ When the machine is in state \c s2, the machine will play the default animation for the
+ property \c fooBar since this property is assigned by \c s2.
+
+ Note that animations explicitly set on transitions will take precedence over any default
+ animation for the given property.
+
+ \section1 Nesting State Machines
+
+ QStateMachine is a subclass of QState. This allows for a state machine to be a child state of
+ another machine. QStateMachine reimplements QState::onEntry() and calls QStateMachine::start(),
+ so that when the child state machine is entered, it will automatically start running.
+
+ The parent state machine treats the child machine as an \e atomic state in the state machine
+ algorithm. The child state machine is self-contained; it maintains its own event queue and
+ configuration. In particular, note that the \l{QStateMachine::}{configuration()}
+ of the child machine is not part of the parent machine's configuration (only the child machine
+ itself is).
+
+ States of the child state machine cannot be specified as targets of transitions in the parent
+ state machine; only the child state machine itself can. Conversely, states of the parent state
+ machine cannot be specified as targets of transitions in the child state machine. The child
+ state machine's \l{QState::}{finished}() signal can be used to trigger a transition
+ in the parent machine.
+*/
diff --git a/src/statemachine/doc/qtstatemachine-examples.qdoc b/src/statemachine/doc/qtstatemachine-examples.qdoc
new file mode 100644
index 0000000..7794b6e
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine-examples.qdoc
@@ -0,0 +1,12 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\group examples-qtstatemachine
+\title Qt State Machine Examples
+\brief Examples for the Qt State Machine module.
+
+The Qt State Machine example applications demonstrate the functionality provided by the
+\l{Qt State Machine} module.
+
+*/
diff --git a/src/statemachine/doc/qtstatemachine-index.qdoc b/src/statemachine/doc/qtstatemachine-index.qdoc
new file mode 100644
index 0000000..0557efa
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine-index.qdoc
@@ -0,0 +1,68 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtstatemachine-index.html
+ \title Qt State Machine
+ \brief Provides functionality to create and execute state graphs.
+
+ The State Machine framework provides classes for creating and executing
+ state graphs.
+
+ \section1 Using the Module
+
+ \section2 QML API
+
+ \include {module-use.qdocinc} {using the qml api} {QtQml.StateMachine}
+
+ \section2 C++ API
+
+ \include {module-use.qdocinc} {using the c++ api}
+
+ \section3 Building with CMake
+
+ \include {module-use.qdocinc} {building with cmake} {StateMachine}
+
+ \section3 Building with qmake
+
+ \include {module-use.qdocinc} {building_with_qmake} {statemachine}
+
+ \section1 Articles and Guides
+
+ \list
+ \li \l {Qt State Machine Overview}
+ \li \l {Qt State Machine C++ Guide}
+ \li \l {Qt State Machine QML Guide}
+ \endlist
+
+ \section1 Examples
+
+ \list
+ \li \l {Qt State Machine Examples}
+ \endlist
+
+ \section1 Reference
+
+ \list
+ \li \l {Qt State Machine C++ Classes} {C++ Classes and Namespaces}
+ \li \l {Qt State Machine QML Types} {QML Types}
+ \endlist
+
+ \section1 Module Evolution
+ \l{Changes to Qt State Machine} lists important changes in the module API
+ and functionality that were done for the Qt 6 series of Qt.
+
+ \section1 Licenses and Trademarks
+
+ The Qt State Machine module is available under commercial licenses from
+ \l{The Qt Company}. In addition, it is available under free software licenses:
+ The \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
+
+ Furthermore, Qt State Machine in Qt \QtVersion may contain third party
+ modules under following permissive licenses:
+
+ \generatelist{groupsbymodule attributions-qtstatemachine}
+
+*/
diff --git a/src/statemachine/doc/qtstatemachine-module-cpp.qdoc b/src/statemachine/doc/qtstatemachine-module-cpp.qdoc
new file mode 100644
index 0000000..fc81267
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine-module-cpp.qdoc
@@ -0,0 +1,16 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \module QtStateMachine
+ \title Qt State Machine C++ Classes
+ \ingroup modules
+ \ingroup technology-apis
+ \qtvariable statemachine
+ \qtcmakepackage StateMachine
+
+ \brief The Qt State Machine module provides classes for creating and executing state graphs.
+
+ The \l {Qt State Machine} page contains information about how to use the module.
+
+*/
diff --git a/src/statemachine/doc/qtstatemachine-module-qml.qdoc b/src/statemachine/doc/qtstatemachine-module-qml.qdoc
new file mode 100644
index 0000000..d9f84bf
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine-module-qml.qdoc
@@ -0,0 +1,18 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \qmlmodule QtQml.StateMachine 6.\QtMinorVersion
+ \title Qt State Machine QML Types
+ \ingroup qmlmodules
+ \brief Enables the use of State Machine with QML.
+
+ To import the QML types into your application, use the following import statement
+ in your .qml file:
+
+ \qml
+ import QtQml.StateMachine
+ \endqml
+
+ For more information, see \l {Qt State Machine QML Guide}.
+ */
diff --git a/src/statemachine/doc/qtstatemachine-module-use.qdocinc b/src/statemachine/doc/qtstatemachine-module-use.qdocinc
new file mode 100644
index 0000000..fb3101d
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine-module-use.qdocinc
@@ -0,0 +1,15 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+//! [cmakebuild]
+ \code
+ find_package(Qt6 REQUIRED COMPONENTS StateMachine)
+ target_link_libraries(mytarget PRIVATE Qt6::StateMachine)
+ \endcode
+//! [cmakebuild]
+
+//! [qmakebuild]
+ \code
+ QT += statemachine
+ \endcode
+//! [qmakebuild]
diff --git a/src/statemachine/doc/qtstatemachine-overview.qdoc b/src/statemachine/doc/qtstatemachine-overview.qdoc
new file mode 100644
index 0000000..3438d86
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine-overview.qdoc
@@ -0,0 +1,42 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtstatemachine-overview.html
+ \title Qt State Machine Overview
+ \brief An overview of the State Machine framework for constructing and executing state graphs.
+ \ingroup technology-apis
+ \ingroup explanation
+
+ \tableofcontents
+
+ The State Machine framework provides classes for creating and executing
+ state graphs. The concepts and notation are based on those from Harel's
+ \l{http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf}{Statecharts: A visual formalism for complex systems}, which
+ is also the basis of UML state diagrams. The semantics of state machine
+ execution are based on \l{State Chart XML: State Machine Notation for
+ Control Abstraction}{State Chart XML (SCXML)}.
+
+ Statecharts provide a graphical way of modeling how a system reacts to
+ stimuli. This is done by defining the possible \e states that the system can
+ be in, and how the system can move from one state to another (\e transitions
+ between states). A key characteristic of event-driven systems (such as Qt
+ applications) is that behavior often depends not only on the last or current
+ event, but also the events that preceded it. With statecharts, this
+ information is easy to express.
+
+ The State Machine framework provides an API and execution model that can be
+ used to effectively embed the elements and semantics of statecharts in Qt
+ applications. The framework integrates tightly with Qt's meta-object system;
+ for example, transitions between states can be triggered by signals, and
+ states can be configured to set properties and invoke methods on {QObject}s.
+ Qt's event system is used to drive the state machines.
+
+ The state graph in the State Machine framework is hierarchical. States can be nested inside of
+ other states, and the current configuration of the state machine consists of the set of states
+ which are currently active. All the states in a valid configuration of the state machine will
+ have a common ancestor.
+
+ \sa {Qt State Machine C++ Guide}, {Qt State Machine QML Guide}, {Qt SCXML Overview}
+
+ */
diff --git a/src/statemachine/doc/qtstatemachine.qdocconf b/src/statemachine/doc/qtstatemachine.qdocconf
new file mode 100644
index 0000000..7736501
--- /dev/null
+++ b/src/statemachine/doc/qtstatemachine.qdocconf
@@ -0,0 +1,55 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtscxml.qdocconf)
+
+project = QtStateMachine
+description = Qt State Machine Reference Documentation
+version = $QT_VERSION
+
+imagedirs = images src/images
+
+# Install path for the examples
+examplesinstallpath = statemachine
+exampledirs = ../../../examples/statemachine \
+ snippets
+
+qhp.QtStateMachine.subprojects = classes qmltypes examples
+qhp.QtStateMachine.subprojects.classes.title = C++ Classes
+qhp.QtStateMachine.subprojects.classes.indexTitle = Qt State Machine C++ Classes
+qhp.QtStateMachine.subprojects.classes.selectors = class headerfile
+qhp.QtStateMachine.subprojects.classes.sortPages = true
+qhp.QtStateMachine.subprojects.qmltypes.title = QML Types
+qhp.QtStateMachine.subprojects.qmltypes.indexTitle = Qt State Machine QML Types
+qhp.QtStateMachine.subprojects.qmltypes.selectors = qmltype
+qhp.QtStateMachine.subprojects.qmltypes.sortPages = true
+qhp.QtStateMachine.subprojects.examples.title = Examples
+qhp.QtStateMachine.subprojects.examples.indexTitle = Qt State Machine Examples
+qhp.QtStateMachine.subprojects.examples.selectors = doc:example
+
+qhp.projects = QtStateMachine
+
+qhp.QtStateMachine.file = qtstatemachine.qhp
+qhp.QtStateMachine.namespace = org.qt-project.qtstatemachine.$QT_VERSION_TAG
+qhp.QtStateMachine.virtualFolder = qtstatemachine
+qhp.QtStateMachine.indexTitle = Qt StateMachine
+qhp.QtStateMachine.indexRoot =
+
+depends += qtcore qtdoc qmake qtquick qtwidgets qtgui qtqml qtscxml qtcmake
+
+headerdirs = .. \
+ ../gui \
+ ../../statemachineqml \
+ ../../../examples/statemachine
+
+sourcedirs += .. \
+ ../gui \
+ ../../statemachineqml \
+ ../../../examples/statemachine
+
+tagfile = qtstatemachine.tags
+
+navigation.landingpage = "Qt State Machine"
+navigation.cppclassespage = "Qt State Machine C++ Classes"
+navigation.qmltypespage = "Qt State Machine QML Types"
+
+# Highlighted examples in Data Processing & IO category
+manifestmeta.highlighted.names = "QtStateMachine/Traffic Light"
diff --git a/src/statemachine/doc/snippets/code/src_corelib_statemachine_qstatemachine.cpp b/src/statemachine/doc/snippets/code/src_corelib_statemachine_qstatemachine.cpp
new file mode 100644
index 0000000..4c9a0a5
--- /dev/null
+++ b/src/statemachine/doc/snippets/code/src_corelib_statemachine_qstatemachine.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [simple state machine]
+QPushButton button;
+
+QStateMachine machine;
+QState *s1 = new QState();
+s1->assignProperty(&button, "text", "Click me");
+
+QFinalState *s2 = new QFinalState();
+s1->addTransition(&button, &QPushButton::clicked, s2);
+
+machine.addState(s1);
+machine.addState(s2);
+machine.setInitialState(s1);
+machine.start();
+//! [simple state machine]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/Button.qml b/src/statemachine/doc/snippets/qml/statemachine/Button.qml
new file mode 100644
index 0000000..b968a18
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/Button.qml
@@ -0,0 +1,51 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Window
+
+Item {
+ id: container
+
+ property alias text: buttonLabel.text
+ property alias label: buttonLabel
+ signal clicked
+ property alias containsMouse: mouseArea.containsMouse
+ property alias pressed: mouseArea.pressed
+ implicitHeight: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2)
+ implicitWidth: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3)
+ height: implicitHeight
+ width: implicitWidth
+ property bool checkable: false
+ property bool checked: false
+
+ SystemPalette { id: palette }
+
+ Rectangle {
+ id: frame
+ anchors.fill: parent
+ color: palette.button
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: mouseArea.pressed ? Qt.darker(palette.button, 1.3) : palette.button }
+ GradientStop { position: 1.0; color: Qt.darker(palette.button, 1.3) }
+ }
+ antialiasing: true
+ radius: height / 6
+ border.color: Qt.darker(palette.button, 1.5)
+ border.width: 1
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ onClicked: container.clicked()
+ hoverEnabled: true
+ }
+
+ Text {
+ id: buttonLabel
+ text: container.text
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+}
diff --git a/src/statemachine/doc/snippets/qml/statemachine/basicstate.qml b/src/statemachine/doc/snippets/qml/statemachine/basicstate.qml
new file mode 100644
index 0000000..dac2914
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/basicstate.qml
@@ -0,0 +1,18 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ DSM.StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ DSM.State {
+ id: state
+ }
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/finalstate.qml b/src/statemachine/doc/snippets/qml/statemachine/finalstate.qml
new file mode 100644
index 0000000..160419a
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/finalstate.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ DSM.StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ DSM.State {
+ id: state
+ DSM.TimeoutTransition {
+ targetState: finalState
+ timeout: 200
+ }
+ }
+ DSM.FinalState {
+ id: finalState
+ }
+ onFinished: console.log("state finished")
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/guardcondition.qml b/src/statemachine/doc/snippets/qml/statemachine/guardcondition.qml
new file mode 100644
index 0000000..9bacea3
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/guardcondition.qml
@@ -0,0 +1,31 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ DSM.StateMachine {
+ DSM.State {
+ DSM.SignalTransition {
+ targetState: finalState
+ signal: button.mysignal
+ // the guard condition uses the mystr string argument from mysignal
+ guard: mystr == "test"
+ }
+ }
+ DSM.FinalState {
+ id: finalState
+ }
+ }
+ // define the signal the SignalTransition is connected with
+ signal mysignal(mystr: string)
+ // on clicking the button emit the signal with a single string argument
+ onClicked: button.mysignal("test")
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/historystate.qml b/src/statemachine/doc/snippets/qml/statemachine/historystate.qml
new file mode 100644
index 0000000..e3e7a43
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/historystate.qml
@@ -0,0 +1,48 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ text: "Press me"
+ DSM.StateMachine {
+ id: stateMachine
+ initialState: parentState
+ running: true
+ DSM.State {
+ id: parentState
+ initialState: child2
+ onEntered: console.log("parentState entered")
+ onExited: console.log("parentState exited")
+ DSM.State {
+ id: child1
+ onEntered: console.log("child1 entered")
+ onExited: console.log("child1 exited")
+ }
+ DSM.State {
+ id: child2
+ onEntered: console.log("child2 entered")
+ onExited: console.log("child2 exited")
+ }
+ DSM.HistoryState {
+ id: historyState
+ defaultState: child1
+ }
+ DSM.SignalTransition {
+ targetState: historyState
+
+ // Clicking the button will cause the state machine to enter the child state
+ // that parentState was in the last time parentState was exited, or the history state's default
+ // state if parentState has never been entered.
+ signal: button.clicked
+ }
+ }
+ }
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/signaltransition.qml b/src/statemachine/doc/snippets/qml/statemachine/signaltransition.qml
new file mode 100644
index 0000000..3d7b4b0
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/signaltransition.qml
@@ -0,0 +1,40 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ DSM.StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ DSM.State {
+ id: state
+ DSM.SignalTransition {
+ targetState: finalState
+ signal: button.clicked
+ guard: guardButton.checked
+ }
+ }
+ DSM.FinalState {
+ id: finalState
+ }
+ onFinished: Qt.quit()
+ }
+ Row {
+ spacing: 2
+ Button {
+ id: button
+ text: "Finish state"
+ }
+
+ Button {
+ id: guardButton
+ checkable: true
+ text: checked ? "Press to block the SignalTransition" : "Press to unblock the SignalTransition"
+ }
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/signaltransitionsignal.qml b/src/statemachine/doc/snippets/qml/statemachine/signaltransitionsignal.qml
new file mode 100644
index 0000000..2aeae2a
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/signaltransitionsignal.qml
@@ -0,0 +1,25 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ DSM.StateMachine {
+ DSM.State {
+ DSM.SignalTransition {
+ targetState: finalState
+ signal: button.clicked
+ }
+ }
+ DSM.FinalState {
+ id: finalState
+ }
+ }
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/simplestatemachine.qml b/src/statemachine/doc/snippets/qml/statemachine/simplestatemachine.qml
new file mode 100644
index 0000000..cd7e01e
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/simplestatemachine.qml
@@ -0,0 +1,31 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ text: "Finish state"
+ DSM.StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ DSM.State {
+ id: state
+ DSM.SignalTransition {
+ targetState: finalState
+ signal: button.clicked
+ }
+ }
+ DSM.FinalState {
+ id: finalState
+ }
+ onFinished: Qt.quit()
+ }
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-history.qml b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-history.qml
new file mode 100644
index 0000000..e5947ae
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-history.qml
@@ -0,0 +1,112 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine
+
+Rectangle {
+//![0]
+ Row {
+ anchors.fill: parent
+ spacing: 2
+ Button {
+ id: button
+ // change the button label to the active state id
+ text: s11.active ? "s11" : s12.active ? "s12" : s13.active ? "s13" : "s3"
+ }
+ Button {
+ id: interruptButton
+ text: s1.active ? "Interrupt" : "Resume"
+ }
+ Button {
+ id: quitButton
+ text: "quit"
+ }
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ State {
+ id: s1
+ // set the initial state
+ initialState: s11
+
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: quitButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ State {
+ id: s11
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s12
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s11 entered")
+ onExited: console.log("s11 exited")
+ }
+
+ State {
+ id: s12
+ // create a transition from s2 to s3 when the button is clicked
+ SignalTransition {
+ targetState: s13
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s12 entered")
+ onExited: console.log("s12 exited")
+ }
+ State {
+ id: s13
+ // create a transition from s3 to s1 when the button is clicked
+ SignalTransition {
+ targetState: s1
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s13 entered")
+ onExited: console.log("s13 exited")
+ }
+
+ // create a transition from s1 to s3 when the button is clicked
+ SignalTransition {
+ targetState: s3
+ signal: interruptButton.clicked
+ }
+ HistoryState {
+ id: s1h
+ }
+ }
+ FinalState {
+ id: s2
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ State {
+ id: s3
+ SignalTransition {
+ targetState: s1h
+ signal: interruptButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s3 entered")
+ onExited: console.log("s3 exited")
+ }
+ onFinished: Qt.quit()
+ }
+//![0]
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml
new file mode 100644
index 0000000..db40f79
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested-ignore-quit.qml
@@ -0,0 +1,97 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine
+
+Rectangle {
+ Row {
+ anchors.fill: parent
+ spacing: 2
+ Button {
+ id: button
+ // change the button label to the active state id
+ text: s11.active ? "s11" : s12.active ? "s12" : "s13"
+ }
+ Button {
+ id: quitButton
+ text: "quit"
+ }
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ State {
+ id: s1
+ // set the initial state
+ initialState: s11
+
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: quitButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ State {
+ id: s11
+ // create a transition from s11 to s12 when the button is clicked
+ SignalTransition {
+ targetState: s12
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s11 entered")
+ onExited: console.log("s11 exited")
+ }
+
+//![0]
+ State {
+ id: s12
+ // create a transition from s12 to s13 when the button is clicked
+ SignalTransition {
+ targetState: s13
+ signal: button.clicked
+ }
+
+ // ignore Quit button when we are in state 12
+ SignalTransition {
+ targetState: s12
+ signal: quitButton.clicked
+ }
+
+ // do something when the state enters/exits
+ onEntered: console.log("s12 entered")
+ onExited: console.log("s12 exited")
+ }
+//![0]
+
+ State {
+ id: s13
+ // create a transition from s13 to s11 when the button is clicked
+ SignalTransition {
+ targetState: s11
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s13 entered")
+ onExited: console.log("s13 exited")
+ }
+ }
+ FinalState {
+ id: s2
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ onFinished: Qt.quit()
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested.qml b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested.qml
new file mode 100644
index 0000000..eae7427
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button-nested.qml
@@ -0,0 +1,89 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine
+
+Rectangle {
+//![0]
+ Row {
+ anchors.fill: parent
+ spacing: 2
+ Button {
+ id: button
+ // change the button label to the active state id
+ text: s11.active ? "s11" : s12.active ? "s12" : "s13"
+ }
+ Button {
+ id: quitButton
+ text: "quit"
+ }
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ State {
+ id: s1
+ // set the initial state
+ initialState: s11
+
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: quitButton.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ State {
+ id: s11
+ // create a transition from s11 to s12 when the button is clicked
+ SignalTransition {
+ targetState: s12
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s11 entered")
+ onExited: console.log("s11 exited")
+ }
+
+ State {
+ id: s12
+ // create a transition from s12 to s13 when the button is clicked
+ SignalTransition {
+ targetState: s13
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s12 entered")
+ onExited: console.log("s12 exited")
+ }
+ State {
+ id: s13
+ // create a transition from s13 to s11 when the button is clicked
+ SignalTransition {
+ targetState: s11
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s13 entered")
+ onExited: console.log("s13 exited")
+ }
+ }
+ FinalState {
+ id: s2
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ onFinished: Qt.quit()
+ }
+//![0]
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/statemachine-button.qml b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button.qml
new file mode 100644
index 0000000..8873117
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/statemachine-button.qml
@@ -0,0 +1,63 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine
+
+Rectangle {
+//![0]
+ Button {
+ anchors.fill: parent
+ id: button
+
+ // change the button label to the active state id
+ text: s1.active ? "s1" : s2.active ? "s2" : "s3"
+ }
+
+ StateMachine {
+ id: stateMachine
+ // set the initial state
+ initialState: s1
+
+ // start the state machine
+ running: true
+
+ State {
+ id: s1
+ // create a transition from s1 to s2 when the button is clicked
+ SignalTransition {
+ targetState: s2
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s1 entered")
+ onExited: console.log("s1 exited")
+ }
+
+ State {
+ id: s2
+ // create a transition from s2 to s3 when the button is clicked
+ SignalTransition {
+ targetState: s3
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s2 entered")
+ onExited: console.log("s2 exited")
+ }
+ State {
+ id: s3
+ // create a transition from s3 to s1 when the button is clicked
+ SignalTransition {
+ targetState: s1
+ signal: button.clicked
+ }
+ // do something when the state enters/exits
+ onEntered: console.log("s3 entered")
+ onExited: console.log("s3 exited")
+ }
+ }
+//![0]
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/qml/statemachine/timeouttransition.qml b/src/statemachine/doc/snippets/qml/statemachine/timeouttransition.qml
new file mode 100644
index 0000000..60bd420
--- /dev/null
+++ b/src/statemachine/doc/snippets/qml/statemachine/timeouttransition.qml
@@ -0,0 +1,32 @@
+// Copyright (C) 2014 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [document]
+import QtQuick
+import QtQml.StateMachine as DSM
+
+Rectangle {
+ Button {
+ anchors.fill: parent
+ id: button
+ text: "Finish state"
+ enabled: !stateMachine.running
+ onClicked: stateMachine.running = true
+ DSM.StateMachine {
+ id: stateMachine
+ initialState: state
+ running: true
+ DSM.State {
+ id: state
+ DSM.TimeoutTransition {
+ targetState: finalState
+ timeout: 1000
+ }
+ }
+ DSM.FinalState {
+ id: finalState
+ }
+ }
+ }
+}
+//! [document]
diff --git a/src/statemachine/doc/snippets/statemachine/eventtest.cpp b/src/statemachine/doc/snippets/statemachine/eventtest.cpp
new file mode 100644
index 0000000..14cb48b
--- /dev/null
+++ b/src/statemachine/doc/snippets/statemachine/eventtest.cpp
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtGui>
+#include <QtStateMachine>
+
+class MyTransition : public QAbstractTransition
+{
+ Q_OBJECT
+public:
+ MyTransition() {}
+
+protected:
+//![0]
+ bool eventTest(QEvent *event) override
+ {
+ if (event->type() == QEvent::Wrapped) {
+ QEvent *wrappedEvent = static_cast<QStateMachine::WrappedEvent *>(event)->event();
+ if (wrappedEvent->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(wrappedEvent);
+ // Do your event test
+ }
+ }
+ return false;
+ }
+//![0]
+
+ void onTransition(QEvent *event) override
+ {
+
+ }
+};
+
+int main(int argv, char **args)
+{
+ return 0;
+}
diff --git a/src/statemachine/doc/snippets/statemachine/main.cpp b/src/statemachine/doc/snippets/statemachine/main.cpp
new file mode 100644
index 0000000..3cbeb5d
--- /dev/null
+++ b/src/statemachine/doc/snippets/statemachine/main.cpp
@@ -0,0 +1,52 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtStateMachine>
+#include <QtWidgets>
+
+int main(int argv, char **args)
+{
+ QApplication app(argv, args);
+
+ QLabel *label = new QLabel;
+ QPushButton *button = new QPushButton;
+
+//![0]
+ QStateMachine machine;
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+ QState *s3 = new QState();
+//![0]
+
+//![4]
+ s1->assignProperty(label, "text", "In state s1");
+ s2->assignProperty(label, "text", "In state s2");
+ s3->assignProperty(label, "text", "In state s3");
+//![4]
+
+//![5]
+ QObject::connect(s3, &QState::entered, button, &QPushButton:showMaximized);
+ QObject::connect(s3, &QState::exited, button, &QPushButton::showMinimized);
+//![5]
+
+//![1]
+ s1->addTransition(button, &QPushButton::clicked, s2);
+ s2->addTransition(button, &QPushButton::clicked, s3);
+ s3->addTransition(button, &QPushButton::clicked, s1);
+//![1]
+
+//![2]
+ machine.addState(s1);
+ machine.addState(s2);
+ machine.addState(s3);
+ machine.setInitialState(s1);
+//![2]
+
+//![3]
+ machine.start();
+//![3]
+
+ label->show();
+
+ return app.exec();
+}
diff --git a/src/statemachine/doc/snippets/statemachine/main2.cpp b/src/statemachine/doc/snippets/statemachine/main2.cpp
new file mode 100644
index 0000000..4fe4c19
--- /dev/null
+++ b/src/statemachine/doc/snippets/statemachine/main2.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtStateMachine>
+#include <QtWidgets>
+
+int main(int argv, char **args)
+{
+ QApplication app(argv, args);
+
+ QStateMachine machine;
+
+//![0]
+ QState *s1 = new QState();
+ QState *s11 = new QState(s1);
+ QState *s12 = new QState(s1);
+ QState *s13 = new QState(s1);
+ s1->setInitialState(s11);
+ machine.addState(s1);
+//![0]
+
+//![2]
+ s12->addTransition(quitButton, &QPushButton::clicked, s12);
+//![2]
+
+//![1]
+ QFinalState *s2 = new QFinalState();
+ s1->addTransition(quitButton, &QPushButton::clicked, s2);
+ machine.addState(s2);
+ machine.setInitialState(s1);
+
+ QObject::connect(&machine, &QStateMachine::finished,
+ QCoreApplication::instance(), &QCoreApplication::quit);
+//![1]
+
+ QButton *interruptButton = new QPushButton("Interrupt Button");
+ QWidget *mainWindow = new QWidget();
+
+//![3]
+ QHistoryState *s1h = new QHistoryState(s1);
+
+ QState *s3 = new QState();
+ s3->assignProperty(label, "text", "In s3");
+ QMessageBox *mbox = new QMessageBox(mainWindow);
+ mbox->addButton(QMessageBox::Ok);
+ mbox->setText("Interrupted!");
+ mbox->setIcon(QMessageBox::Information);
+ QObject::connect(s3, &QState::entered, mbox, &QMessageBox::exec);
+ s3->addTransition(s1h);
+ machine.addState(s3);
+
+ s1->addTransition(interruptButton, &QPushButton::clicked, s3);
+//![3]
+
+ return app.exec();
+}
+
diff --git a/src/statemachine/doc/snippets/statemachine/main3.cpp b/src/statemachine/doc/snippets/statemachine/main3.cpp
new file mode 100644
index 0000000..7bae11f
--- /dev/null
+++ b/src/statemachine/doc/snippets/statemachine/main3.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtGui>
+#include <QtStateMachine>
+
+int main(int argv, char **args)
+{
+ QApplication app(argv, args);
+
+//![0]
+ QState *s1 = new QState(QState::ParallelStates);
+ // s11 and s12 will be entered in parallel
+ QState *s11 = new QState(s1);
+ QState *s12 = new QState(s1);
+//![0]
+
+//![1]
+ s1->addTransition(s1, &QState::finished, s2);
+//![1]
+
+ return app.exec();
+}
+
diff --git a/src/statemachine/doc/snippets/statemachine/main4.cpp b/src/statemachine/doc/snippets/statemachine/main4.cpp
new file mode 100644
index 0000000..bac255a
--- /dev/null
+++ b/src/statemachine/doc/snippets/statemachine/main4.cpp
@@ -0,0 +1,75 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtGui>
+#include <QtStateMachine>
+
+//![0]
+struct StringEvent : public QEvent
+{
+ StringEvent(const QString &val)
+ : QEvent(QEvent::Type(QEvent::User+1)),
+ value(val) {}
+
+ QString value;
+};
+//![0]
+
+//![1]
+class StringTransition : public QAbstractTransition
+{
+ Q_OBJECT
+
+public:
+ StringTransition(const QString &value)
+ : m_value(value) {}
+
+protected:
+ bool eventTest(QEvent *e) override
+ {
+ if (e->type() != QEvent::Type(QEvent::User+1)) // StringEvent
+ return false;
+ StringEvent *se = static_cast<StringEvent*>(e);
+ return (m_value == se->value);
+ }
+
+ void onTransition(QEvent *) override {}
+
+private:
+ QString m_value;
+};
+//![1]
+
+int main(int argv, char **args)
+{
+ QApplication app(argv, args);
+
+//![2]
+ QStateMachine machine;
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+ QFinalState *done = new QFinalState();
+
+ StringTransition *t1 = new StringTransition("Hello");
+ t1->setTargetState(s2);
+ s1->addTransition(t1);
+ StringTransition *t2 = new StringTransition("world");
+ t2->setTargetState(done);
+ s2->addTransition(t2);
+
+ machine.addState(s1);
+ machine.addState(s2);
+ machine.addState(done);
+ machine.setInitialState(s1);
+//![2]
+
+//![3]
+ machine.postEvent(new StringEvent("Hello"));
+ machine.postEvent(new StringEvent("world"));
+//![3]
+
+ return app.exec();
+}
+
+#include "main4.moc"
+
diff --git a/src/statemachine/doc/snippets/statemachine/main5.cpp b/src/statemachine/doc/snippets/statemachine/main5.cpp
new file mode 100644
index 0000000..3b1b7e9
--- /dev/null
+++ b/src/statemachine/doc/snippets/statemachine/main5.cpp
@@ -0,0 +1,136 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtGui>
+#include <QtStateMachine>
+
+int main(int argv, char **args)
+{
+ QApplication app(argv, args);
+ QWidget *button;
+
+ {
+//![0]
+ QStateMachine machine;
+ machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
+
+ QState *s1 = new QState();
+ s1->assignProperty(object, "fooBar", 1.0);
+ machine.addState(s1);
+ machine.setInitialState(s1);
+
+ QState *s2 = new QState();
+ machine.addState(s2);
+//![0]
+ }
+
+ {
+
+//![2]
+ QStateMachine machine;
+ machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties);
+
+ QState *s1 = new QState();
+ s1->assignProperty(object, "fooBar", 1.0);
+ machine.addState(s1);
+ machine.setInitialState(s1);
+
+ QState *s2 = new QState(s1);
+ s2->assignProperty(object, "fooBar", 2.0);
+ s1->setInitialState(s2);
+
+ QState *s3 = new QState(s1);
+//![2]
+
+ }
+
+ {
+//![3]
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+
+ s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50));
+ s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100));
+
+ s1->addTransition(button, &QPushButton::clicked, s2);
+//![3]
+
+ }
+
+ {
+//![4]
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+
+ s1->assignProperty(button, "geometry", QRectF(0, 0, 50, 50));
+ s2->assignProperty(button, "geometry", QRectF(0, 0, 100, 100));
+
+ QSignalTransition *transition = s1->addTransition(button, &QPushButton::clicked, s2);
+ transition->addAnimation(new QPropertyAnimation(button, "geometry"));
+//![4]
+
+ }
+
+ {
+ QMainWindow *mainWindow = 0;
+
+//![5]
+ QMessageBox *messageBox = new QMessageBox(mainWindow);
+ messageBox->addButton(QMessageBox::Ok);
+ messageBox->setText("Button geometry has been set!");
+ messageBox->setIcon(QMessageBox::Information);
+
+ QState *s1 = new QState();
+
+ QState *s2 = new QState();
+ s2->assignProperty(button, "geometry", QRectF(0, 0, 50, 50));
+ connect(s2, &QState::entered, messageBox, SLOT(exec()));
+
+ s1->addTransition(button, &QPushButton::clicked, s2);
+//![5]
+ }
+
+ {
+ QMainWindow *mainWindow = 0;
+
+//![6]
+ QMessageBox *messageBox = new QMessageBox(mainWindow);
+ messageBox->addButton(QMessageBox::Ok);
+ messageBox->setText("Button geometry has been set!");
+ messageBox->setIcon(QMessageBox::Information);
+
+ QState *s1 = new QState();
+
+ QState *s2 = new QState();
+ s2->assignProperty(button, "geometry", QRectF(0, 0, 50, 50));
+
+ QState *s3 = new QState();
+ connect(s3, &QState::entered, messageBox, SLOT(exec()));
+
+ s1->addTransition(button, &QPushButton::clicked, s2);
+ s2->addTransition(s2, &QState::propertiesAssigned, s3);
+//![6]
+
+ }
+
+ {
+
+//![7]
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+
+ s2->assignProperty(object, "fooBar", 2.0);
+ s1->addTransition(s2);
+
+ QStateMachine machine;
+ machine.setInitialState(s1);
+ machine.addDefaultAnimation(new QPropertyAnimation(object, "fooBar"));
+//![7]
+
+ }
+
+
+
+ return app.exec();
+}
+
diff --git a/src/statemachine/doc/src/images/moveblocks-example.png b/src/statemachine/doc/src/images/moveblocks-example.png
new file mode 100644
index 0000000..56353d1
--- /dev/null
+++ b/src/statemachine/doc/src/images/moveblocks-example.png
Binary files differ
diff --git a/src/statemachine/doc/src/images/rogue-example.png b/src/statemachine/doc/src/images/rogue-example.png
new file mode 100644
index 0000000..7aeb0e5
--- /dev/null
+++ b/src/statemachine/doc/src/images/rogue-example.png
Binary files differ
diff --git a/src/statemachine/doc/src/images/trafficlight-example.png b/src/statemachine/doc/src/images/trafficlight-example.png
new file mode 100644
index 0000000..3431542
--- /dev/null
+++ b/src/statemachine/doc/src/images/trafficlight-example.png
Binary files differ
diff --git a/src/statemachine/gui/qbasickeyeventtransition.cpp b/src/statemachine/gui/qbasickeyeventtransition.cpp
new file mode 100644
index 0000000..cace92b
--- /dev/null
+++ b/src/statemachine/gui/qbasickeyeventtransition.cpp
@@ -0,0 +1,175 @@
+// 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 "qbasickeyeventtransition_p.h"
+
+#include <QtGui/qevent.h>
+
+#include <private/qabstracttransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QBasicKeyEventTransition
+ \since 4.6
+ \ingroup statemachine
+
+ \brief The QBasicKeyEventTransition class provides a transition for Qt key events.
+*/
+
+class QBasicKeyEventTransitionPrivate : public QAbstractTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QBasicKeyEventTransition)
+public:
+ QBasicKeyEventTransitionPrivate() = default;
+
+ static QBasicKeyEventTransitionPrivate *get(QBasicKeyEventTransition *q);
+
+ QEvent::Type eventType = QEvent::None;
+
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QBasicKeyEventTransitionPrivate, int, key, 0);
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QBasicKeyEventTransitionPrivate, Qt::KeyboardModifiers,
+ modifierMask, Qt::NoModifier);
+};
+
+QBasicKeyEventTransitionPrivate *QBasicKeyEventTransitionPrivate::get(QBasicKeyEventTransition *q)
+{
+ return q->d_func();
+}
+
+/*!
+ Constructs a new key event transition with the given \a sourceState.
+*/
+QBasicKeyEventTransition::QBasicKeyEventTransition(QState *sourceState)
+ : QAbstractTransition(*new QBasicKeyEventTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new event transition for events of the given \a type for the
+ given \a key, with the given \a sourceState.
+*/
+QBasicKeyEventTransition::QBasicKeyEventTransition(QEvent::Type type, int key,
+ QState *sourceState)
+ : QAbstractTransition(*new QBasicKeyEventTransitionPrivate, sourceState)
+{
+ Q_D(QBasicKeyEventTransition);
+ d->eventType = type;
+ d->key = key;
+}
+
+/*!
+ Constructs a new event transition for events of the given \a type for the
+ given \a key, with the given \a modifierMask and \a sourceState.
+*/
+QBasicKeyEventTransition::QBasicKeyEventTransition(QEvent::Type type, int key,
+ Qt::KeyboardModifiers modifierMask,
+ QState *sourceState)
+ : QAbstractTransition(*new QBasicKeyEventTransitionPrivate, sourceState)
+{
+ Q_D(QBasicKeyEventTransition);
+ d->eventType = type;
+ d->key = key;
+ d->modifierMask = modifierMask;
+}
+
+/*!
+ Destroys this event transition.
+*/
+QBasicKeyEventTransition::~QBasicKeyEventTransition()
+{
+}
+
+/*!
+ Returns the event type that this key event transition is associated with.
+*/
+QEvent::Type QBasicKeyEventTransition::eventType() const
+{
+ Q_D(const QBasicKeyEventTransition);
+ return d->eventType;
+}
+
+/*!
+ Sets the event \a type that this key event transition is associated with.
+*/
+void QBasicKeyEventTransition::setEventType(QEvent::Type type)
+{
+ Q_D(QBasicKeyEventTransition);
+ d->eventType = type;
+}
+
+/*!
+ Returns the key that this key event transition checks for.
+*/
+int QBasicKeyEventTransition::key() const
+{
+ Q_D(const QBasicKeyEventTransition);
+ return d->key;
+}
+
+/*!
+ Sets the key that this key event transition will check for.
+*/
+void QBasicKeyEventTransition::setKey(int key)
+{
+ Q_D(QBasicKeyEventTransition);
+ d->key = key;
+}
+
+QBindable<int> QBasicKeyEventTransition::bindableKey()
+{
+ Q_D(QBasicKeyEventTransition);
+ return &d->key;
+}
+
+/*!
+ Returns the keyboard modifier mask that this key event transition checks
+ for.
+*/
+Qt::KeyboardModifiers QBasicKeyEventTransition::modifierMask() const
+{
+ Q_D(const QBasicKeyEventTransition);
+ return d->modifierMask;
+}
+
+/*!
+ Sets the keyboard modifier mask that this key event transition will check
+ for.
+*/
+void QBasicKeyEventTransition::setModifierMask(Qt::KeyboardModifiers modifierMask)
+{
+ Q_D(QBasicKeyEventTransition);
+ d->modifierMask = modifierMask;
+}
+
+QBindable<Qt::KeyboardModifiers> QBasicKeyEventTransition::bindableModifierMask()
+{
+ Q_D(QBasicKeyEventTransition);
+ return &d->modifierMask;
+}
+
+/*!
+ \reimp
+*/
+bool QBasicKeyEventTransition::eventTest(QEvent *event)
+{
+ Q_D(const QBasicKeyEventTransition);
+ if (event->type() == d->eventType) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(event);
+ return (ke->key() == d->key)
+ && ((ke->modifiers() & d->modifierMask.value()) == d->modifierMask.value());
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QBasicKeyEventTransition::onTransition(QEvent *)
+{
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qbasickeyeventtransition_p.cpp"
diff --git a/src/statemachine/gui/qbasickeyeventtransition_p.h b/src/statemachine/gui/qbasickeyeventtransition_p.h
new file mode 100644
index 0000000..ebb746c
--- /dev/null
+++ b/src/statemachine/gui/qbasickeyeventtransition_p.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 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
+
+#ifndef QBASICKEYEVENTTRANSITION_P_H
+#define QBASICKEYEVENTTRANSITION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qevent.h>
+#include <QtStateMachine/qabstracttransition.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_REQUIRE_CONFIG(qeventtransition);
+
+QT_BEGIN_NAMESPACE
+
+class QBasicKeyEventTransitionPrivate;
+class Q_AUTOTEST_EXPORT QBasicKeyEventTransition : public QAbstractTransition
+{
+ Q_OBJECT
+public:
+ QBasicKeyEventTransition(QState *sourceState = nullptr);
+ QBasicKeyEventTransition(QEvent::Type type, int key, QState *sourceState = nullptr);
+ QBasicKeyEventTransition(QEvent::Type type, int key,
+ Qt::KeyboardModifiers modifierMask,
+ QState *sourceState = nullptr);
+ ~QBasicKeyEventTransition();
+
+ QEvent::Type eventType() const;
+ void setEventType(QEvent::Type type);
+
+ int key() const;
+ void setKey(int key);
+ QBindable<int> bindableKey();
+
+ Qt::KeyboardModifiers modifierMask() const;
+ void setModifierMask(Qt::KeyboardModifiers modifiers);
+ QBindable<Qt::KeyboardModifiers> bindableModifierMask();
+
+protected:
+ bool eventTest(QEvent *event) override;
+ void onTransition(QEvent *) override;
+
+private:
+ Q_DISABLE_COPY_MOVE(QBasicKeyEventTransition)
+ Q_DECLARE_PRIVATE(QBasicKeyEventTransition)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/gui/qbasicmouseeventtransition.cpp b/src/statemachine/gui/qbasicmouseeventtransition.cpp
new file mode 100644
index 0000000..b880594
--- /dev/null
+++ b/src/statemachine/gui/qbasicmouseeventtransition.cpp
@@ -0,0 +1,182 @@
+// 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 "qbasicmouseeventtransition_p.h"
+
+#include <QtGui/qevent.h>
+#include <QtGui/qpainterpath.h>
+
+#include <private/qabstracttransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QBasicMouseEventTransition
+ \since 4.6
+ \ingroup statemachine
+
+ \brief The QBasicMouseEventTransition class provides a transition for Qt mouse events.
+*/
+
+class QBasicMouseEventTransitionPrivate : public QAbstractTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QBasicMouseEventTransition)
+public:
+ QBasicMouseEventTransitionPrivate() = default;
+
+ static QBasicMouseEventTransitionPrivate *get(QBasicMouseEventTransition *q);
+
+ QEvent::Type eventType = QEvent::None;
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QBasicMouseEventTransitionPrivate, Qt::MouseButton,
+ button, Qt::NoButton);
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QBasicMouseEventTransitionPrivate, Qt::KeyboardModifiers,
+ modifierMask, Qt::NoModifier);
+ QPainterPath path;
+};
+
+QBasicMouseEventTransitionPrivate *QBasicMouseEventTransitionPrivate::get(QBasicMouseEventTransition *q)
+{
+ return q->d_func();
+}
+
+/*!
+ Constructs a new mouse event transition with the given \a sourceState.
+*/
+QBasicMouseEventTransition::QBasicMouseEventTransition(QState *sourceState)
+ : QAbstractTransition(*new QBasicMouseEventTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new mouse event transition for events of the given \a type.
+*/
+QBasicMouseEventTransition::QBasicMouseEventTransition(QEvent::Type type,
+ Qt::MouseButton button,
+ QState *sourceState)
+ : QAbstractTransition(*new QBasicMouseEventTransitionPrivate, sourceState)
+{
+ Q_D(QBasicMouseEventTransition);
+ d->eventType = type;
+ d->button = button;
+}
+
+/*!
+ Destroys this mouse event transition.
+*/
+QBasicMouseEventTransition::~QBasicMouseEventTransition()
+{
+}
+
+/*!
+ Returns the event type that this mouse event transition is associated with.
+*/
+QEvent::Type QBasicMouseEventTransition::eventType() const
+{
+ Q_D(const QBasicMouseEventTransition);
+ return d->eventType;
+}
+
+/*!
+ Sets the event \a type that this mouse event transition is associated with.
+*/
+void QBasicMouseEventTransition::setEventType(QEvent::Type type)
+{
+ Q_D(QBasicMouseEventTransition);
+ d->eventType = type;
+}
+
+/*!
+ Returns the button that this mouse event transition checks for.
+*/
+Qt::MouseButton QBasicMouseEventTransition::button() const
+{
+ Q_D(const QBasicMouseEventTransition);
+ return d->button;
+}
+
+/*!
+ Sets the button that this mouse event transition will check for.
+*/
+void QBasicMouseEventTransition::setButton(Qt::MouseButton button)
+{
+ Q_D(QBasicMouseEventTransition);
+ d->button = button;
+}
+
+QBindable<Qt::MouseButton> QBasicMouseEventTransition::bindableButton()
+{
+ Q_D(QBasicMouseEventTransition);
+ return &d->button;
+}
+
+/*!
+ Returns the keyboard modifier mask that this mouse event transition checks
+ for.
+*/
+Qt::KeyboardModifiers QBasicMouseEventTransition::modifierMask() const
+{
+ Q_D(const QBasicMouseEventTransition);
+ return d->modifierMask;
+}
+
+/*!
+ Sets the keyboard modifier mask that this mouse event transition will check
+ for.
+*/
+void QBasicMouseEventTransition::setModifierMask(Qt::KeyboardModifiers modifierMask)
+{
+ Q_D(QBasicMouseEventTransition);
+ d->modifierMask = modifierMask;
+}
+
+QBindable<Qt::KeyboardModifiers> QBasicMouseEventTransition::bindableModifierMask()
+{
+ Q_D(QBasicMouseEventTransition);
+ return &d->modifierMask;
+}
+
+
+/*!
+ Returns the hit test path for this mouse event transition.
+*/
+QPainterPath QBasicMouseEventTransition::hitTestPath() const
+{
+ Q_D(const QBasicMouseEventTransition);
+ return d->path;
+}
+
+/*!
+ Sets the hit test path for this mouse event transition.
+*/
+void QBasicMouseEventTransition::setHitTestPath(const QPainterPath &path)
+{
+ Q_D(QBasicMouseEventTransition);
+ d->path = path;
+}
+
+/*!
+ \reimp
+*/
+bool QBasicMouseEventTransition::eventTest(QEvent *event)
+{
+ Q_D(const QBasicMouseEventTransition);
+ if (event->type() == d->eventType) {
+ QMouseEvent *me = static_cast<QMouseEvent*>(event);
+ return (me->button() == d->button)
+ && ((me->modifiers() & d->modifierMask.value()) == d->modifierMask.value())
+ && (d->path.isEmpty() || d->path.contains(me->position().toPoint()));
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QBasicMouseEventTransition::onTransition(QEvent *)
+{
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qbasicmouseeventtransition_p.cpp"
diff --git a/src/statemachine/gui/qbasicmouseeventtransition_p.h b/src/statemachine/gui/qbasicmouseeventtransition_p.h
new file mode 100644
index 0000000..21d7ed3
--- /dev/null
+++ b/src/statemachine/gui/qbasicmouseeventtransition_p.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2020 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
+
+#ifndef QBASICMOUSEEVENTTRANSITION_P_H
+#define QBASICMOUSEEVENTTRANSITION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qevent.h>
+#include <QtStateMachine/qabstracttransition.h>
+#include <QtCore/private/qglobal_p.h>
+
+QT_REQUIRE_CONFIG(qeventtransition);
+
+QT_BEGIN_NAMESPACE
+
+class QPainterPath;
+
+class QBasicMouseEventTransitionPrivate;
+class Q_AUTOTEST_EXPORT QBasicMouseEventTransition : public QAbstractTransition
+{
+ Q_OBJECT
+public:
+ QBasicMouseEventTransition(QState *sourceState = nullptr);
+ QBasicMouseEventTransition(QEvent::Type type, Qt::MouseButton button,
+ QState *sourceState = nullptr);
+ ~QBasicMouseEventTransition();
+
+ QEvent::Type eventType() const;
+ void setEventType(QEvent::Type type);
+
+ Qt::MouseButton button() const;
+ void setButton(Qt::MouseButton button);
+ QBindable<Qt::MouseButton> bindableButton();
+
+ Qt::KeyboardModifiers modifierMask() const;
+ void setModifierMask(Qt::KeyboardModifiers modifiers);
+ QBindable<Qt::KeyboardModifiers> bindableModifierMask();
+
+ QPainterPath hitTestPath() const;
+ void setHitTestPath(const QPainterPath &path);
+
+protected:
+ bool eventTest(QEvent *event) override;
+ void onTransition(QEvent *) override;
+
+private:
+ Q_DISABLE_COPY_MOVE(QBasicMouseEventTransition)
+ Q_DECLARE_PRIVATE(QBasicMouseEventTransition)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/gui/qkeyeventtransition.cpp b/src/statemachine/gui/qkeyeventtransition.cpp
new file mode 100644
index 0000000..205e22f
--- /dev/null
+++ b/src/statemachine/gui/qkeyeventtransition.cpp
@@ -0,0 +1,151 @@
+// 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 "qkeyeventtransition.h"
+#include "qbasickeyeventtransition_p.h"
+#include "qstatemachine.h"
+
+#include <private/qeventtransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QKeyEventTransition
+
+ \brief The QKeyEventTransition class provides a transition for key events.
+
+ \since 4.6
+ \ingroup statemachine
+ \inmodule QtStateMachine
+
+ QKeyEventTransition is part of \l{Qt State Machine Overview}{Qt State Machine Framework}.
+
+ \sa QState::addTransition()
+*/
+
+/*!
+ \property QKeyEventTransition::key
+
+ \brief the key that this key event transition is associated with
+*/
+
+/*!
+ \property QKeyEventTransition::modifierMask
+
+ \brief the keyboard modifier mask that this key event transition checks for
+*/
+
+class QKeyEventTransitionPrivate : public QEventTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QKeyEventTransition)
+public:
+ QKeyEventTransitionPrivate() {}
+
+ QBasicKeyEventTransition *transition;
+};
+
+/*!
+ Constructs a new key event transition with the given \a sourceState.
+*/
+QKeyEventTransition::QKeyEventTransition(QState *sourceState)
+ : QEventTransition(*new QKeyEventTransitionPrivate, sourceState)
+{
+ Q_D(QKeyEventTransition);
+ d->transition = new QBasicKeyEventTransition();
+}
+
+/*!
+ Constructs a new key event transition for events of the given \a type for
+ the given \a object, with the given \a key and \a sourceState.
+*/
+QKeyEventTransition::QKeyEventTransition(QObject *object, QEvent::Type type,
+ int key, QState *sourceState)
+ : QEventTransition(*new QKeyEventTransitionPrivate, object, type, sourceState)
+{
+ Q_D(QKeyEventTransition);
+ d->transition = new QBasicKeyEventTransition(type, key);
+}
+
+/*!
+ Destroys this key event transition.
+*/
+QKeyEventTransition::~QKeyEventTransition()
+{
+ Q_D(QKeyEventTransition);
+ delete d->transition;
+}
+
+/*!
+ Returns the key that this key event transition checks for.
+*/
+int QKeyEventTransition::key() const
+{
+ Q_D(const QKeyEventTransition);
+ return d->transition->key();
+}
+
+/*!
+ Sets the \a key that this key event transition will check for.
+*/
+void QKeyEventTransition::setKey(int key)
+{
+ Q_D(QKeyEventTransition);
+ d->transition->setKey(key);
+}
+
+QBindable<int> QKeyEventTransition::bindableKey()
+{
+ Q_D(QKeyEventTransition);
+ return d->transition->bindableKey();
+}
+
+/*!
+ Returns the keyboard modifier mask that this key event transition checks
+ for.
+*/
+Qt::KeyboardModifiers QKeyEventTransition::modifierMask() const
+{
+ Q_D(const QKeyEventTransition);
+ return d->transition->modifierMask();
+}
+
+/*!
+ Sets the keyboard modifier mask that this key event transition will
+ check for to \a modifierMask.
+*/
+void QKeyEventTransition::setModifierMask(Qt::KeyboardModifiers modifierMask)
+{
+ Q_D(QKeyEventTransition);
+ d->transition->setModifierMask(modifierMask);
+}
+
+QBindable<Qt::KeyboardModifiers> QKeyEventTransition::bindableModifierMask()
+{
+ Q_D(QKeyEventTransition);
+ return d->transition->bindableModifierMask();
+}
+
+/*!
+ \reimp
+*/
+bool QKeyEventTransition::eventTest(QEvent *event)
+{
+ Q_D(const QKeyEventTransition);
+ if (!QEventTransition::eventTest(event))
+ return false;
+ QStateMachine::WrappedEvent *we = static_cast<QStateMachine::WrappedEvent*>(event);
+ d->transition->setEventType(we->event()->type());
+ return QAbstractTransitionPrivate::get(d->transition)->callEventTest(we->event());
+}
+
+/*!
+ \reimp
+*/
+void QKeyEventTransition::onTransition(QEvent *event)
+{
+ QEventTransition::onTransition(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qkeyeventtransition.cpp"
diff --git a/src/statemachine/gui/qkeyeventtransition.h b/src/statemachine/gui/qkeyeventtransition.h
new file mode 100644
index 0000000..e1362e5
--- /dev/null
+++ b/src/statemachine/gui/qkeyeventtransition.h
@@ -0,0 +1,45 @@
+// 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
+
+#ifndef QKEYEVENTTRANSITION_H
+#define QKEYEVENTTRANSITION_H
+
+#include <QtStateMachine/qeventtransition.h>
+
+QT_REQUIRE_CONFIG(qeventtransition);
+
+QT_BEGIN_NAMESPACE
+
+class QKeyEventTransitionPrivate;
+class Q_STATEMACHINE_EXPORT QKeyEventTransition : public QEventTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(int key READ key WRITE setKey BINDABLE bindableKey)
+ Q_PROPERTY(Qt::KeyboardModifiers modifierMask READ modifierMask WRITE setModifierMask
+ BINDABLE bindableModifierMask)
+public:
+ QKeyEventTransition(QState *sourceState = nullptr);
+ QKeyEventTransition(QObject *object, QEvent::Type type, int key,
+ QState *sourceState = nullptr);
+ ~QKeyEventTransition();
+
+ int key() const;
+ void setKey(int key);
+ QBindable<int> bindableKey();
+
+ Qt::KeyboardModifiers modifierMask() const;
+ void setModifierMask(Qt::KeyboardModifiers modifiers);
+ QBindable<Qt::KeyboardModifiers> bindableModifierMask();
+
+protected:
+ void onTransition(QEvent *event) override;
+ bool eventTest(QEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QKeyEventTransition)
+ Q_DECLARE_PRIVATE(QKeyEventTransition)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/gui/qmouseeventtransition.cpp b/src/statemachine/gui/qmouseeventtransition.cpp
new file mode 100644
index 0000000..6a1e715
--- /dev/null
+++ b/src/statemachine/gui/qmouseeventtransition.cpp
@@ -0,0 +1,180 @@
+// 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 "qmouseeventtransition.h"
+#include "qbasicmouseeventtransition_p.h"
+#include "qstatemachine.h"
+
+#include <QtGui/qpainterpath.h>
+#include <private/qeventtransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QMouseEventTransition
+
+ \brief The QMouseEventTransition class provides a transition for mouse events.
+
+ \since 4.6
+ \ingroup statemachine
+ \inmodule QtStateMachine
+
+ QMouseEventTransition is part of \l{Qt State Machine Overview}{Qt State Machine Framework}.
+
+ \sa QState::addTransition()
+*/
+
+/*!
+ \property QMouseEventTransition::button
+
+ \brief the button that this mouse event transition is associated with
+*/
+
+/*!
+ \property QMouseEventTransition::modifierMask
+
+ \brief the keyboard modifier mask that this mouse event transition checks for
+*/
+
+class QMouseEventTransitionPrivate : public QEventTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QMouseEventTransition)
+public:
+ QMouseEventTransitionPrivate();
+
+ QBasicMouseEventTransition *transition;
+};
+
+QMouseEventTransitionPrivate::QMouseEventTransitionPrivate()
+{
+}
+
+/*!
+ Constructs a new mouse event transition with the given \a sourceState.
+*/
+QMouseEventTransition::QMouseEventTransition(QState *sourceState)
+ : QEventTransition(*new QMouseEventTransitionPrivate, sourceState)
+{
+ Q_D(QMouseEventTransition);
+ d->transition = new QBasicMouseEventTransition();
+}
+
+/*!
+ Constructs a new mouse event transition for events of the given \a type for
+ the given \a object, with the given \a button and \a sourceState.
+*/
+QMouseEventTransition::QMouseEventTransition(QObject *object, QEvent::Type type,
+ Qt::MouseButton button,
+ QState *sourceState)
+ : QEventTransition(*new QMouseEventTransitionPrivate, object, type, sourceState)
+{
+ Q_D(QMouseEventTransition);
+ d->transition = new QBasicMouseEventTransition(type, button);
+}
+
+/*!
+ Destroys this mouse event transition.
+*/
+QMouseEventTransition::~QMouseEventTransition()
+{
+ Q_D(QMouseEventTransition);
+ delete d->transition;
+}
+
+/*!
+ Returns the button that this mouse event transition checks for.
+*/
+Qt::MouseButton QMouseEventTransition::button() const
+{
+ Q_D(const QMouseEventTransition);
+ return d->transition->button();
+}
+
+/*!
+ Sets the \a button that this mouse event transition will check for.
+*/
+void QMouseEventTransition::setButton(Qt::MouseButton button)
+{
+ Q_D(QMouseEventTransition);
+ d->transition->setButton(button);
+}
+
+QBindable<Qt::MouseButton> QMouseEventTransition::bindableButton()
+{
+ Q_D(QMouseEventTransition);
+ return d->transition->bindableButton();
+}
+
+/*!
+ Returns the keyboard modifier mask that this mouse event transition checks
+ for.
+*/
+Qt::KeyboardModifiers QMouseEventTransition::modifierMask() const
+{
+ Q_D(const QMouseEventTransition);
+ return d->transition->modifierMask();
+}
+
+/*!
+ Sets the keyboard modifier mask that this mouse event transition will
+ check for to \a modifierMask.
+*/
+void QMouseEventTransition::setModifierMask(Qt::KeyboardModifiers modifierMask)
+{
+ Q_D(QMouseEventTransition);
+ d->transition->setModifierMask(modifierMask);
+}
+
+QBindable<Qt::KeyboardModifiers> QMouseEventTransition::bindableModifierMask()
+{
+ Q_D(QMouseEventTransition);
+ return d->transition->bindableModifierMask();
+}
+
+
+/*!
+ Returns the hit test path for this mouse event transition.
+*/
+QPainterPath QMouseEventTransition::hitTestPath() const
+{
+ Q_D(const QMouseEventTransition);
+ return d->transition->hitTestPath();
+}
+
+/*!
+ Sets the hit test path for this mouse event transition to \a path.
+ If a valid path has been set, the transition will only trigger if the mouse
+ event position (QMouseEvent::pos()) is inside the path.
+
+ \sa QPainterPath::contains()
+*/
+void QMouseEventTransition::setHitTestPath(const QPainterPath &path)
+{
+ Q_D(QMouseEventTransition);
+ d->transition->setHitTestPath(path);
+}
+
+/*!
+ \reimp
+*/
+bool QMouseEventTransition::eventTest(QEvent *event)
+{
+ Q_D(const QMouseEventTransition);
+ if (!QEventTransition::eventTest(event))
+ return false;
+ QStateMachine::WrappedEvent *we = static_cast<QStateMachine::WrappedEvent*>(event);
+ d->transition->setEventType(we->event()->type());
+ return QAbstractTransitionPrivate::get(d->transition)->callEventTest(we->event());
+}
+
+/*!
+ \reimp
+*/
+void QMouseEventTransition::onTransition(QEvent *event)
+{
+ QEventTransition::onTransition(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qmouseeventtransition.cpp"
diff --git a/src/statemachine/gui/qmouseeventtransition.h b/src/statemachine/gui/qmouseeventtransition.h
new file mode 100644
index 0000000..e02295b
--- /dev/null
+++ b/src/statemachine/gui/qmouseeventtransition.h
@@ -0,0 +1,49 @@
+// 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
+
+#ifndef QMOUSEEVENTTRANSITION_H
+#define QMOUSEEVENTTRANSITION_H
+
+#include <QtStateMachine/qeventtransition.h>
+
+QT_REQUIRE_CONFIG(qeventtransition);
+
+QT_BEGIN_NAMESPACE
+
+class QMouseEventTransitionPrivate;
+class QPainterPath;
+class Q_STATEMACHINE_EXPORT QMouseEventTransition : public QEventTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::MouseButton button READ button WRITE setButton BINDABLE bindableButton)
+ Q_PROPERTY(Qt::KeyboardModifiers modifierMask READ modifierMask WRITE setModifierMask
+ BINDABLE bindableModifierMask)
+public:
+ QMouseEventTransition(QState *sourceState = nullptr);
+ QMouseEventTransition(QObject *object, QEvent::Type type,
+ Qt::MouseButton button, QState *sourceState = nullptr);
+ ~QMouseEventTransition();
+
+ Qt::MouseButton button() const;
+ void setButton(Qt::MouseButton button);
+ QBindable<Qt::MouseButton> bindableButton();
+
+ Qt::KeyboardModifiers modifierMask() const;
+ void setModifierMask(Qt::KeyboardModifiers modifiers);
+ QBindable<Qt::KeyboardModifiers> bindableModifierMask();
+
+ QPainterPath hitTestPath() const;
+ void setHitTestPath(const QPainterPath &path);
+
+protected:
+ void onTransition(QEvent *event) override;
+ bool eventTest(QEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QMouseEventTransition)
+ Q_DECLARE_PRIVATE(QMouseEventTransition)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qabstractstate.cpp b/src/statemachine/qabstractstate.cpp
new file mode 100644
index 0000000..8e511c9
--- /dev/null
+++ b/src/statemachine/qabstractstate.cpp
@@ -0,0 +1,203 @@
+// 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 "qabstractstate.h"
+#include "qabstractstate_p.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractState
+ \inmodule QtStateMachine
+
+ \brief The QAbstractState class is the base class of states of a QStateMachine.
+
+ \since 4.6
+ \ingroup statemachine
+
+ The QAbstractState class is the abstract base class of states that are part
+ of a QStateMachine. It defines the interface that all state objects have in
+ common. QAbstractState is part of \l{Qt State Machine Overview}{Qt State Machine Framework}.
+
+ The entered() signal is emitted when the state has been entered. The
+ exited() signal is emitted when the state has been exited.
+
+ The parentState() function returns the state's parent state. The machine()
+ function returns the state machine that the state is part of.
+
+ \section1 Subclassing
+
+ The onEntry() function is called when the state is entered; reimplement this
+ function to perform custom processing when the state is entered.
+
+ The onExit() function is called when the state is exited; reimplement this
+ function to perform custom processing when the state is exited.
+*/
+
+/*!
+ \property QAbstractState::active
+ \since 5.4
+
+ \brief the active property of this state. A state is active between
+ entered() and exited() signals.
+*/
+
+
+QAbstractStatePrivate::QAbstractStatePrivate(StateType type)
+ : stateType(type), isMachine(false), active(false), parentState(nullptr)
+{
+}
+
+QStateMachine *QAbstractStatePrivate::machine() const
+{
+ QObject *par = parent;
+ while (par != nullptr) {
+ if (QStateMachine *mach = qobject_cast<QStateMachine*>(par))
+ return mach;
+ par = par->parent();
+ }
+ return nullptr;
+}
+
+void QAbstractStatePrivate::callOnEntry(QEvent *e)
+{
+ Q_Q(QAbstractState);
+ q->onEntry(e);
+}
+
+void QAbstractStatePrivate::callOnExit(QEvent *e)
+{
+ Q_Q(QAbstractState);
+ q->onExit(e);
+}
+
+void QAbstractStatePrivate::emitEntered()
+{
+ Q_Q(QAbstractState);
+ emit q->entered(QAbstractState::QPrivateSignal());
+ active.setValue(true);
+}
+
+void QAbstractStatePrivate::emitExited()
+{
+ Q_Q(QAbstractState);
+ active.setValue(false);
+ emit q->exited(QAbstractState::QPrivateSignal());
+}
+
+/*!
+ Constructs a new state with the given \a parent state.
+*/
+QAbstractState::QAbstractState(QState *parent)
+ : QObject(*new QAbstractStatePrivate(QAbstractStatePrivate::AbstractState), parent)
+{
+}
+
+/*!
+ \internal
+*/
+QAbstractState::QAbstractState(QAbstractStatePrivate &dd, QState *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ Destroys this state.
+*/
+QAbstractState::~QAbstractState()
+{
+}
+
+/*!
+ Returns this state's parent state, or \nullptr if the state has no
+ parent state.
+*/
+QState *QAbstractState::parentState() const
+{
+ Q_D(const QAbstractState);
+ if (d->parentState != parent())
+ d->parentState = qobject_cast<QState*>(parent());
+ return d->parentState;
+}
+
+/*!
+ Returns the state machine that this state is part of, or \nullptr if
+ the state is not part of a state machine.
+*/
+QStateMachine *QAbstractState::machine() const
+{
+ Q_D(const QAbstractState);
+ return d->machine();
+}
+
+/*!
+ Returns whether this state is active.
+
+ \sa activeChanged(bool), entered(), exited()
+*/
+bool QAbstractState::active() const
+{
+ Q_D(const QAbstractState);
+ return d->active;
+}
+
+QBindable<bool> QAbstractState::bindableActive()
+{
+ Q_D(QAbstractState);
+ return &d->active;
+}
+
+/*!
+ \fn QAbstractState::onExit(QEvent *event)
+
+ This function is called when the state is exited. The given \a event is what
+ caused the state to be exited. Reimplement this function to perform custom
+ processing when the state is exited.
+*/
+
+/*!
+ \fn QAbstractState::onEntry(QEvent *event)
+
+ This function is called when the state is entered. The given \a event is
+ what caused the state to be entered. Reimplement this function to perform
+ custom processing when the state is entered.
+*/
+
+/*!
+ \fn QAbstractState::entered()
+
+ This signal is emitted when the state has been entered (after onEntry() has
+ been called).
+*/
+
+/*!
+ \fn QAbstractState::exited()
+
+ This signal is emitted when the state has been exited (after onExit() has
+ been called).
+*/
+
+/*!
+ \fn QAbstractState::activeChanged(bool active)
+ \since 5.4
+
+ This signal is emitted when the active property is changed with \a active as argument.
+
+ \sa QAbstractState::active, entered(), exited()
+*/
+
+/*!
+ \reimp
+*/
+bool QAbstractState::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qabstractstate.cpp"
diff --git a/src/statemachine/qabstractstate.h b/src/statemachine/qabstractstate.h
new file mode 100644
index 0000000..6e79fcf
--- /dev/null
+++ b/src/statemachine/qabstractstate.h
@@ -0,0 +1,54 @@
+// 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
+
+#ifndef QABSTRACTSTATE_H
+#define QABSTRACTSTATE_H
+
+#include <QtCore/qobject.h>
+#include <QtStateMachine/qstatemachineglobal.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QState;
+class QStateMachine;
+
+class QAbstractStatePrivate;
+class Q_STATEMACHINE_EXPORT QAbstractState : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged BINDABLE bindableActive)
+public:
+ ~QAbstractState();
+
+ QState *parentState() const;
+ QStateMachine *machine() const;
+
+ bool active() const;
+ QBindable<bool> bindableActive();
+
+Q_SIGNALS:
+ void entered(QPrivateSignal);
+ void exited(QPrivateSignal);
+ void activeChanged(bool active);
+
+protected:
+ QAbstractState(QState *parent = nullptr);
+
+ virtual void onEntry(QEvent *event) = 0;
+ virtual void onExit(QEvent *event) = 0;
+
+ bool event(QEvent *e) override;
+
+protected:
+ QAbstractState(QAbstractStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QAbstractState)
+ Q_DECLARE_PRIVATE(QAbstractState)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qabstractstate_p.h b/src/statemachine/qabstractstate_p.h
new file mode 100644
index 0000000..6bfb54c
--- /dev/null
+++ b/src/statemachine/qabstractstate_p.h
@@ -0,0 +1,70 @@
+// 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
+
+#ifndef QABSTRACTSTATE_P_H
+#define QABSTRACTSTATE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qobject_p.h>
+#include <QtStateMachine/qabstractstate.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QStateMachine;
+
+class QState;
+class QAbstractStatePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractState)
+
+public:
+ enum StateType {
+ AbstractState,
+ StandardState,
+ FinalState,
+ HistoryState
+ };
+
+ QAbstractStatePrivate(StateType type);
+
+ static QAbstractStatePrivate *get(QAbstractState *q)
+ { return q->d_func(); }
+ static const QAbstractStatePrivate *get(const QAbstractState *q)
+ { return q->d_func(); }
+
+ QStateMachine *machine() const;
+
+ void callOnEntry(QEvent *e);
+ void callOnExit(QEvent *e);
+
+ void emitEntered();
+ void emitExited();
+
+ quint16 stateType;
+ bool isMachine;
+
+ void activeChanged()
+ {
+ emit q_func()->activeChanged(active.value());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY(QAbstractStatePrivate, bool, active,
+ &QAbstractStatePrivate::activeChanged);
+
+ mutable QState *parentState;
+};
+
+QT_END_NAMESPACE
+
+#endif // QABSTRACTSTATE_P_H
diff --git a/src/statemachine/qabstracttransition.cpp b/src/statemachine/qabstracttransition.cpp
new file mode 100644
index 0000000..957091a
--- /dev/null
+++ b/src/statemachine/qabstracttransition.cpp
@@ -0,0 +1,400 @@
+// 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 "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qabstractstate.h"
+#include "qhistorystate.h"
+#include "qstate.h"
+#include "qstatemachine.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractTransition
+ \inmodule QtStateMachine
+
+ \brief The QAbstractTransition class is the base class of transitions between QAbstractState objects.
+
+ \since 4.6
+ \ingroup statemachine
+
+ The QAbstractTransition class is the abstract base class of transitions
+ between states (QAbstractState objects) of a
+ QStateMachine. QAbstractTransition is part of \l{Qt State Machine Overview}
+ {Qt State Machine Framework}.
+
+ The sourceState() function returns the source of the transition. The
+ targetStates() function returns the targets of the transition. The machine()
+ function returns the state machine that the transition is part of.
+
+ The triggered() signal is emitted when the transition has been triggered.
+
+ Transitions can cause animations to be played. Use the addAnimation()
+ function to add an animation to the transition.
+
+ \section1 Subclassing
+
+ The eventTest() function is called by the state machine to determine whether
+ an event should trigger the transition. In your reimplementation you
+ typically check the event type and cast the event object to the proper type,
+ and check that one or more properties of the event meet your criteria.
+
+ The onTransition() function is called when the transition is triggered;
+ reimplement this function to perform custom processing for the transition.
+*/
+
+/*!
+ \property QAbstractTransition::sourceState
+
+ \brief the source state (parent) of this transition
+*/
+
+/*!
+ \property QAbstractTransition::targetState
+
+ \brief the target state of this transition
+
+ If a transition has no target state, the transition may still be
+ triggered, but this will not cause the state machine's configuration to
+ change (i.e. the current state will not be exited and re-entered).
+*/
+
+/*!
+ \property QAbstractTransition::targetStates
+
+ \brief the target states of this transition
+
+ If multiple states are specified, all must be descendants of the same
+ parallel group state.
+*/
+
+/*!
+ \property QAbstractTransition::transitionType
+
+ \brief indicates whether this transition is an internal transition, or an external transition.
+
+ Internal and external transitions behave the same, except for the case of a transition whose
+ source state is a compound state and whose target(s) is a descendant of the source. In such a
+ case, an internal transition will not exit and re-enter its source state, while an external one
+ will.
+
+ By default, the type is an external transition.
+*/
+
+/*!
+ \enum QAbstractTransition::TransitionType
+
+ This enum specifies the kind of transition. By default, the type is an external transition.
+
+ \value ExternalTransition Any state that is the source state of a transition (which is not a
+ target-less transition) is left, and re-entered when necessary.
+ \value InternalTransition If the target state of a transition is a sub-state of a compound state,
+ and that compound state is the source state, an internal transition will
+ not leave the source state.
+
+ \sa QAbstractTransition::transitionType
+*/
+
+QStateMachine *QAbstractTransitionPrivate::machine() const
+{
+ if (QState *source = sourceState())
+ return source->machine();
+ Q_Q(const QAbstractTransition);
+ if (QHistoryState *parent = qobject_cast<QHistoryState *>(q->parent()))
+ return parent->machine();
+ return nullptr;
+}
+
+bool QAbstractTransitionPrivate::callEventTest(QEvent *e)
+{
+ Q_Q(QAbstractTransition);
+ return q->eventTest(e);
+}
+
+void QAbstractTransitionPrivate::callOnTransition(QEvent *e)
+{
+ Q_Q(QAbstractTransition);
+ q->onTransition(e);
+}
+
+QState *QAbstractTransitionPrivate::sourceState() const
+{
+ return qobject_cast<QState*>(parent);
+}
+
+void QAbstractTransitionPrivate::emitTriggered()
+{
+ Q_Q(QAbstractTransition);
+ emit q->triggered(QAbstractTransition::QPrivateSignal());
+}
+
+/*!
+ Constructs a new QAbstractTransition object with the given \a sourceState.
+*/
+QAbstractTransition::QAbstractTransition(QState *sourceState)
+ : QObject(*new QAbstractTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ \internal
+*/
+QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
+ QState *parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
+ Destroys this transition.
+*/
+QAbstractTransition::~QAbstractTransition()
+{
+}
+
+/*!
+ Returns the source state of this transition, or \nullptr if this
+ transition has no source state.
+*/
+QState *QAbstractTransition::sourceState() const
+{
+ Q_D(const QAbstractTransition);
+ return d->sourceState();
+}
+
+/*!
+ Returns the target state of this transition, or \nullptr if the
+ transition has no target.
+*/
+QAbstractState *QAbstractTransition::targetState() const
+{
+ Q_D(const QAbstractTransition);
+ if (d->targetStates.isEmpty())
+ return nullptr;
+ return d->targetStates.first().data();
+}
+
+/*!
+ Sets the \a target state of this transition.
+*/
+void QAbstractTransition::setTargetState(QAbstractState* target)
+{
+ Q_D(QAbstractTransition);
+ if ((d->targetStates.size() == 1 && target == d->targetStates.at(0).data()) ||
+ (d->targetStates.isEmpty() && target == nullptr)) {
+ return;
+ }
+ if (!target)
+ d->targetStates.clear();
+ else
+ setTargetStates(QList<QAbstractState*>() << target);
+ emit targetStateChanged(QPrivateSignal());
+}
+
+/*!
+ Returns the target states of this transition, or an empty list if this
+ transition has no target states.
+*/
+QList<QAbstractState*> QAbstractTransition::targetStates() const
+{
+ Q_D(const QAbstractTransition);
+ QList<QAbstractState*> result;
+ for (int i = 0; i < d->targetStates.size(); ++i) {
+ QAbstractState *target = d->targetStates.at(i).data();
+ if (target)
+ result.append(target);
+ }
+ return result;
+}
+
+/*!
+ Sets the target states of this transition to be the given \a targets.
+*/
+void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets)
+{
+ Q_D(QAbstractTransition);
+
+ // Verify if any of the new target states is a null-pointer:
+ for (int i = 0; i < targets.size(); ++i) {
+ if (targets.at(i) == nullptr) {
+ qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null");
+ return;
+ }
+ }
+
+ // First clean out any target states that got destroyed, but for which we still have a QPointer
+ // around.
+ for (int i = 0; i < d->targetStates.size(); ) {
+ if (d->targetStates.at(i).isNull()) {
+ d->targetStates.remove(i);
+ } else {
+ ++i;
+ }
+ }
+
+ // Easy check: if both lists are empty, we're done.
+ if (targets.isEmpty() && d->targetStates.isEmpty())
+ return;
+
+ bool sameList = true;
+
+ if (targets.size() != d->targetStates.size()) {
+ // If the sizes of the lists are different, we don't need to be smart: they're different. So
+ // we can just set the new list as the targetStates.
+ sameList = false;
+ } else {
+ QList<QPointer<QAbstractState>> copy(d->targetStates);
+ for (int i = 0; i < targets.size(); ++i) {
+ sameList &= copy.removeOne(targets.at(i));
+ if (!sameList)
+ break; // ok, we now know the lists are not the same, so stop the loop.
+ }
+
+ sameList &= copy.isEmpty();
+ }
+
+ if (sameList)
+ return;
+
+ d->targetStates.resize(targets.size());
+ for (int i = 0; i < targets.size(); ++i) {
+ d->targetStates[i] = targets.at(i);
+ }
+
+ emit targetStatesChanged(QPrivateSignal());
+}
+
+/*!
+ Returns the type of the transition.
+*/
+QAbstractTransition::TransitionType QAbstractTransition::transitionType() const
+{
+ Q_D(const QAbstractTransition);
+ return d->transitionType;
+}
+
+/*!
+ Sets the type of the transition to \a type.
+*/
+void QAbstractTransition::setTransitionType(TransitionType type)
+{
+ Q_D(QAbstractTransition);
+ d->transitionType = type;
+}
+
+QBindable<QAbstractTransition::TransitionType> QAbstractTransition::bindableTransitionType()
+{
+ Q_D(QAbstractTransition);
+ return &d->transitionType;
+}
+
+/*!
+ Returns the state machine that this transition is part of, or
+ \nullptr if the transition is not part of a state machine.
+*/
+QStateMachine *QAbstractTransition::machine() const
+{
+ Q_D(const QAbstractTransition);
+ return d->machine();
+}
+
+#if QT_CONFIG(animation)
+
+/*!
+ Adds the given \a animation to this transition.
+ The transition does not take ownership of the animation.
+
+ \sa removeAnimation(), animations()
+*/
+void QAbstractTransition::addAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAbstractTransition);
+ if (!animation) {
+ qWarning("QAbstractTransition::addAnimation: cannot add null animation");
+ return;
+ }
+ d->animations.append(animation);
+}
+
+/*!
+ Removes the given \a animation from this transition.
+
+ \sa addAnimation()
+*/
+void QAbstractTransition::removeAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QAbstractTransition);
+ if (!animation) {
+ qWarning("QAbstractTransition::removeAnimation: cannot remove null animation");
+ return;
+ }
+ d->animations.removeOne(animation);
+}
+
+/*!
+ Returns the list of animations associated with this transition, or an empty
+ list if it has no animations.
+
+ \sa addAnimation()
+*/
+QList<QAbstractAnimation*> QAbstractTransition::animations() const
+{
+ Q_D(const QAbstractTransition);
+ return d->animations;
+}
+
+#endif
+
+/*!
+ \fn QAbstractTransition::eventTest(QEvent *event)
+
+ This function is called to determine whether the given \a event should cause
+ this transition to trigger. Reimplement this function and return true if the
+ event should trigger the transition, otherwise return false.
+*/
+
+/*!
+ \fn QAbstractTransition::onTransition(QEvent *event)
+
+ This function is called when the transition is triggered. The given \a event
+ is what caused the transition to trigger. Reimplement this function to
+ perform custom processing when the transition is triggered.
+*/
+
+/*!
+ \fn QAbstractTransition::triggered()
+
+ This signal is emitted when the transition has been triggered (after
+ onTransition() has been called).
+*/
+
+/*!
+ \fn QAbstractTransition::targetStateChanged()
+ \since 5.4
+
+ This signal is emitted when the targetState property is changed.
+
+ \sa QAbstractTransition::targetState
+*/
+
+/*!
+ \fn QAbstractTransition::targetStatesChanged()
+ \since 5.4
+
+ This signal is emitted when the targetStates property is changed.
+
+ \sa QAbstractTransition::targetStates
+*/
+
+/*!
+ \reimp
+*/
+bool QAbstractTransition::event(QEvent *e)
+{
+ return QObject::event(e);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qabstracttransition.cpp"
diff --git a/src/statemachine/qabstracttransition.h b/src/statemachine/qabstracttransition.h
new file mode 100644
index 0000000..816c1b0
--- /dev/null
+++ b/src/statemachine/qabstracttransition.h
@@ -0,0 +1,84 @@
+// 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
+
+#ifndef QABSTRACTTRANSITION_H
+#define QABSTRACTTRANSITION_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+
+#include <QtStateMachine/qstatemachineglobal.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+class QAbstractState;
+class QState;
+class QStateMachine;
+
+#if QT_CONFIG(animation)
+class QAbstractAnimation;
+#endif
+
+class QAbstractTransitionPrivate;
+class Q_STATEMACHINE_EXPORT QAbstractTransition : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QState* sourceState READ sourceState)
+ Q_PROPERTY(QAbstractState* targetState READ targetState WRITE setTargetState NOTIFY targetStateChanged)
+ Q_PROPERTY(QList<QAbstractState*> targetStates READ targetStates WRITE setTargetStates NOTIFY targetStatesChanged)
+ Q_PROPERTY(TransitionType transitionType READ transitionType WRITE setTransitionType
+ BINDABLE bindableTransitionType REVISION(1, 1))
+public:
+ enum TransitionType {
+ ExternalTransition,
+ InternalTransition
+ };
+ Q_ENUM(TransitionType)
+
+ QAbstractTransition(QState *sourceState = nullptr);
+ virtual ~QAbstractTransition();
+
+ QState *sourceState() const;
+ QAbstractState *targetState() const;
+ void setTargetState(QAbstractState* target);
+ QList<QAbstractState*> targetStates() const;
+ void setTargetStates(const QList<QAbstractState*> &targets);
+
+ TransitionType transitionType() const;
+ void setTransitionType(TransitionType type);
+ QBindable<QAbstractTransition::TransitionType> bindableTransitionType();
+
+ QStateMachine *machine() const;
+
+#if QT_CONFIG(animation)
+ void addAnimation(QAbstractAnimation *animation);
+ void removeAnimation(QAbstractAnimation *animation);
+ QList<QAbstractAnimation*> animations() const;
+#endif
+
+Q_SIGNALS:
+ void triggered(QPrivateSignal);
+ void targetStateChanged(QPrivateSignal);
+ void targetStatesChanged(QPrivateSignal);
+
+protected:
+ virtual bool eventTest(QEvent *event) = 0;
+
+ virtual void onTransition(QEvent *event) = 0;
+
+ bool event(QEvent *e) override;
+
+protected:
+ QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QAbstractTransition)
+ Q_DECLARE_PRIVATE(QAbstractTransition)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qabstracttransition_p.h b/src/statemachine/qabstracttransition_p.h
new file mode 100644
index 0000000..08ac45d
--- /dev/null
+++ b/src/statemachine/qabstracttransition_p.h
@@ -0,0 +1,62 @@
+// 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
+
+#ifndef QABSTRACTTRANSITION_P_H
+#define QABSTRACTTRANSITION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qobject_p.h>
+
+#include <QtCore/qlist.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qsharedpointer.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractState;
+class QState;
+class QStateMachine;
+
+class QAbstractTransition;
+class Q_STATEMACHINE_EXPORT QAbstractTransitionPrivate
+ : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractTransition)
+public:
+ QAbstractTransitionPrivate() = default;
+
+ static QAbstractTransitionPrivate *get(QAbstractTransition *q)
+ { return q->d_func(); }
+
+ bool callEventTest(QEvent *e);
+ virtual void callOnTransition(QEvent *e);
+ QState *sourceState() const;
+ QStateMachine *machine() const;
+ void emitTriggered();
+
+ QList<QPointer<QAbstractState>> targetStates;
+
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QAbstractTransitionPrivate,
+ QAbstractTransition::TransitionType, transitionType,
+ QAbstractTransition::ExternalTransition);
+
+#if QT_CONFIG(animation)
+ QList<QAbstractAnimation*> animations;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qeventtransition.cpp b/src/statemachine/qeventtransition.cpp
new file mode 100644
index 0000000..460010a
--- /dev/null
+++ b/src/statemachine/qeventtransition.cpp
@@ -0,0 +1,230 @@
+// 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 "qeventtransition.h"
+#include "qeventtransition_p.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QEventTransition
+ \inmodule QtStateMachine
+
+ \brief The QEventTransition class provides a QObject-specific transition for Qt events.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A QEventTransition object binds an event to a particular QObject.
+ QEventTransition is part of \l{Qt State Machine Overview}{Qt State Machine Framework}.
+
+ Example:
+
+ \code
+ QPushButton *button = ...;
+ QState *s1 = ...;
+ QState *s2 = ...;
+ // If in s1 and the button receives an Enter event, transition to s2
+ QEventTransition *enterTransition = new QEventTransition(button, QEvent::Enter);
+ enterTransition->setTargetState(s2);
+ s1->addTransition(enterTransition);
+ // If in s2 and the button receives an Exit event, transition back to s1
+ QEventTransition *leaveTransition = new QEventTransition(button, QEvent::Leave);
+ leaveTransition->setTargetState(s1);
+ s2->addTransition(leaveTransition);
+ \endcode
+
+ \section1 Subclassing
+
+ When reimplementing the eventTest() function, you should first call the base
+ implementation to verify that the event is a QStateMachine::WrappedEvent for
+ the proper object and event type. You may then cast the event to a
+ QStateMachine::WrappedEvent and get the original event by calling
+ QStateMachine::WrappedEvent::event(), and perform additional checks on that
+ object.
+
+ \sa QState::addTransition()
+*/
+
+/*!
+ \property QEventTransition::eventSource
+
+ \brief the event source that this event transition is associated with
+*/
+
+/*!
+ \property QEventTransition::eventType
+
+ \brief the type of event that this event transition is associated with
+*/
+
+QEventTransitionPrivate::~QEventTransitionPrivate()
+{
+}
+
+void QEventTransitionPrivate::unregister()
+{
+ Q_Q(QEventTransition);
+ if (!registered || !machine())
+ return;
+ QStateMachinePrivate::get(machine())->unregisterEventTransition(q);
+}
+
+void QEventTransitionPrivate::maybeRegister()
+{
+ Q_Q(QEventTransition);
+ if (QStateMachine *mach = machine())
+ QStateMachinePrivate::get(mach)->maybeRegisterEventTransition(q);
+}
+
+/*!
+ Constructs a new QEventTransition object with the given \a sourceState.
+*/
+QEventTransition::QEventTransition(QState *sourceState)
+ : QAbstractTransition(*new QEventTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new QEventTransition object associated with events of the given
+ \a type for the given \a object, and with the given \a sourceState.
+*/
+QEventTransition::QEventTransition(QObject *object, QEvent::Type type,
+ QState *sourceState)
+ : QAbstractTransition(*new QEventTransitionPrivate, sourceState)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object.setValueBypassingBindings(object);
+ d->eventType.setValueBypassingBindings(type);
+ d->maybeRegister();
+}
+
+/*!
+ \internal
+*/
+QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QState *parent)
+ : QAbstractTransition(dd, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, QState *parent)
+ : QAbstractTransition(dd, parent)
+{
+ Q_D(QEventTransition);
+ d->registered = false;
+ d->object.setValueBypassingBindings(object);
+ d->eventType.setValueBypassingBindings(type);
+ d->maybeRegister();
+}
+
+/*!
+ Destroys this QObject event transition.
+*/
+QEventTransition::~QEventTransition()
+{
+}
+
+/*!
+ Returns the event type that this event transition is associated with.
+*/
+QEvent::Type QEventTransition::eventType() const
+{
+ Q_D(const QEventTransition);
+ return d->eventType;
+}
+
+/*!
+ Sets the event \a type that this event transition is associated with.
+*/
+void QEventTransition::setEventType(QEvent::Type type)
+{
+ Q_D(QEventTransition);
+ d->eventType.removeBindingUnlessInWrapper();
+ if (d->eventType.valueBypassingBindings() == type)
+ return;
+ d->unregister();
+ d->eventType.setValueBypassingBindings(type);
+ d->maybeRegister();
+ d->eventType.notify();
+}
+
+QBindable<QEvent::Type> QEventTransition::bindableEventType()
+{
+ Q_D(QEventTransition);
+ return &d->eventType;
+}
+
+/*!
+ Returns the event source associated with this event transition.
+*/
+QObject *QEventTransition::eventSource() const
+{
+ Q_D(const QEventTransition);
+ return d->object;
+}
+
+/*!
+ Sets the event source associated with this event transition to be the given
+ \a object.
+*/
+void QEventTransition::setEventSource(QObject *object)
+{
+ Q_D(QEventTransition);
+ d->object.removeBindingUnlessInWrapper();
+ if (d->object.valueBypassingBindings() == object)
+ return;
+ d->unregister();
+ d->object.setValueBypassingBindings(object);
+ d->maybeRegister();
+ d->object.notify();
+}
+
+QBindable<QObject*> QEventTransition::bindableEventSource()
+{
+ Q_D(QEventTransition);
+ return &d->object;
+}
+
+/*!
+ \reimp
+*/
+bool QEventTransition::eventTest(QEvent *event)
+{
+ Q_D(const QEventTransition);
+ if (event->type() == QEvent::StateMachineWrapped) {
+ QStateMachine::WrappedEvent *we = static_cast<QStateMachine::WrappedEvent*>(event);
+ return (we->object() == d->object)
+ && (we->event()->type() == d->eventType.value());
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QEventTransition::onTransition(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QEventTransition::event(QEvent *e)
+{
+ return QAbstractTransition::event(e);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qeventtransition.cpp"
diff --git a/src/statemachine/qeventtransition.h b/src/statemachine/qeventtransition.h
new file mode 100644
index 0000000..0de066e
--- /dev/null
+++ b/src/statemachine/qeventtransition.h
@@ -0,0 +1,53 @@
+// 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
+
+#ifndef QEVENTTRANSITION_H
+#define QEVENTTRANSITION_H
+
+#include <QtCore/qcoreevent.h>
+#include <QtStateMachine/qabstracttransition.h>
+
+QT_REQUIRE_CONFIG(qeventtransition);
+
+QT_BEGIN_NAMESPACE
+
+class QEventTransitionPrivate;
+class Q_STATEMACHINE_EXPORT QEventTransition : public QAbstractTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(QObject* eventSource READ eventSource WRITE setEventSource
+ BINDABLE bindableEventSource)
+ Q_PROPERTY(QEvent::Type eventType READ eventType WRITE setEventType
+ BINDABLE bindableEventType)
+public:
+ QEventTransition(QState *sourceState = nullptr);
+ QEventTransition(QObject *object, QEvent::Type type, QState *sourceState = nullptr);
+ ~QEventTransition();
+
+ QObject *eventSource() const;
+ void setEventSource(QObject *object);
+ QBindable<QObject*> bindableEventSource();
+
+ QEvent::Type eventType() const;
+ void setEventType(QEvent::Type type);
+ QBindable<QEvent::Type> bindableEventType();
+
+protected:
+ bool eventTest(QEvent *event) override;
+ void onTransition(QEvent *event) override;
+
+ bool event(QEvent *e) override;
+
+protected:
+ QEventTransition(QEventTransitionPrivate &dd, QState *parent);
+ QEventTransition(QEventTransitionPrivate &dd, QObject *object,
+ QEvent::Type type, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QEventTransition)
+ Q_DECLARE_PRIVATE(QEventTransition)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qeventtransition_p.h b/src/statemachine/qeventtransition_p.h
new file mode 100644
index 0000000..a632394
--- /dev/null
+++ b/src/statemachine/qeventtransition_p.h
@@ -0,0 +1,57 @@
+// 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
+
+#ifndef QEVENTTRANSITION_P_H
+#define QEVENTTRANSITION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qabstracttransition_p.h"
+#include <QtCore/private/qproperty_p.h>
+
+QT_REQUIRE_CONFIG(qeventtransition);
+
+QT_BEGIN_NAMESPACE
+
+class QEventTransition;
+class Q_STATEMACHINE_EXPORT QEventTransitionPrivate : public QAbstractTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QEventTransition)
+public:
+ QEventTransitionPrivate() = default;
+ ~QEventTransitionPrivate();
+
+ static QEventTransitionPrivate *get(QEventTransition *q)
+ { return q->d_func(); }
+
+ void unregister();
+ void maybeRegister();
+
+ void setEventSource(QObject* eventSource)
+ {
+ q_func()->setEventSource(eventSource);
+ }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QEventTransitionPrivate, QObject*, object,
+ &QEventTransitionPrivate::setEventSource, nullptr);
+
+ void setEventType(QEvent::Type eventType)
+ {
+ q_func()->setEventType(eventType);
+ }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QEventTransitionPrivate, QEvent::Type, eventType,
+ &QEventTransitionPrivate::setEventType, QEvent::None);
+ bool registered = false;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qfinalstate.cpp b/src/statemachine/qfinalstate.cpp
new file mode 100644
index 0000000..8dace42
--- /dev/null
+++ b/src/statemachine/qfinalstate.cpp
@@ -0,0 +1,105 @@
+// 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 "qfinalstate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QFinalState
+ \inmodule QtStateMachine
+
+ \brief The QFinalState class provides a final state.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A final state is used to communicate that (part of) a QStateMachine has
+ finished its work. When a final top-level state is entered, the state
+ machine's \l{QStateMachine::finished()}{finished}() signal is emitted. In
+ general, when a final substate (a child of a QState) is entered, the parent
+ state's \l{QState::finished()}{finished}() signal is emitted. QFinalState
+ is part of \l{Qt State Machine Overview}{Qt State Machine Framework}.
+
+ To use a final state, you create a QFinalState object and add a transition
+ to it from another state. Example:
+
+ \code
+ QPushButton button;
+
+ QStateMachine machine;
+ QState *s1 = new QState();
+ QFinalState *s2 = new QFinalState();
+ s1->addTransition(&button, SIGNAL(clicked()), s2);
+ machine.addState(s1);
+ machine.addState(s2);
+
+ QObject::connect(&machine, SIGNAL(finished()), QApplication::instance(), SLOT(quit()));
+ machine.setInitialState(s1);
+ machine.start();
+ \endcode
+
+ \sa QState::finished()
+*/
+
+QFinalStatePrivate::QFinalStatePrivate()
+ : QAbstractStatePrivate(FinalState)
+{
+}
+
+QFinalStatePrivate::~QFinalStatePrivate()
+{
+ // to prevent vtables being generated in every file that includes the private header
+}
+
+/*!
+ Constructs a new QFinalState object with the given \a parent state.
+*/
+QFinalState::QFinalState(QState *parent)
+ : QAbstractState(*new QFinalStatePrivate, parent)
+{
+}
+
+/*!
+ \internal
+ */
+QFinalState::QFinalState(QFinalStatePrivate &dd, QState *parent)
+ : QAbstractState(dd, parent)
+{
+}
+
+
+/*!
+ Destroys this final state.
+*/
+QFinalState::~QFinalState()
+{
+}
+
+/*!
+ \reimp
+*/
+void QFinalState::onEntry(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QFinalState::onExit(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QFinalState::event(QEvent *e)
+{
+ return QAbstractState::event(e);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qfinalstate.cpp"
diff --git a/src/statemachine/qfinalstate.h b/src/statemachine/qfinalstate.h
new file mode 100644
index 0000000..78b6758
--- /dev/null
+++ b/src/statemachine/qfinalstate.h
@@ -0,0 +1,37 @@
+// 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
+
+#ifndef QFINALSTATE_H
+#define QFINALSTATE_H
+
+#include <QtStateMachine/qabstractstate.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QFinalStatePrivate;
+class Q_STATEMACHINE_EXPORT QFinalState : public QAbstractState
+{
+ Q_OBJECT
+public:
+ QFinalState(QState *parent = nullptr);
+ ~QFinalState();
+
+protected:
+ void onEntry(QEvent *event) override;
+ void onExit(QEvent *event) override;
+
+ bool event(QEvent *e) override;
+
+protected:
+ explicit QFinalState(QFinalStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QFinalState)
+ Q_DECLARE_PRIVATE(QFinalState)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qfinalstate_p.h b/src/statemachine/qfinalstate_p.h
new file mode 100644
index 0000000..4aa8aec
--- /dev/null
+++ b/src/statemachine/qfinalstate_p.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2017 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
+
+#ifndef QFINALSTATE_P_H
+#define QFINALSTATE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfinalstate.h"
+#include "private/qabstractstate_p.h"
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class Q_STATEMACHINE_EXPORT QFinalStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QFinalState)
+
+public:
+ QFinalStatePrivate();
+ ~QFinalStatePrivate();
+};
+
+QT_END_NAMESPACE
+
+#endif // QFINALSTATE_P_H
diff --git a/src/statemachine/qhistorystate.cpp b/src/statemachine/qhistorystate.cpp
new file mode 100644
index 0000000..19eab72
--- /dev/null
+++ b/src/statemachine/qhistorystate.cpp
@@ -0,0 +1,310 @@
+// 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 "qhistorystate.h"
+#include "qhistorystate_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QHistoryState
+ \inmodule QtStateMachine
+
+ \brief The QHistoryState class provides a means of returning to a previously active substate.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A history state is a pseudo-state that represents the child state that the
+ parent state was in the last time the parent state was exited. A transition
+ with a history state as its target is in fact a transition to one or more
+ other child states of the parent state. QHistoryState is part of \l{Qt State Machine Overview}
+ {Qt State Machine Framework}.
+
+ Use the setDefaultState() function to set the state that should be entered
+ if the parent state has never been entered. Example:
+
+ \code
+ QStateMachine machine;
+
+ QState *s1 = new QState();
+ QState *s11 = new QState(s1);
+ QState *s12 = new QState(s1);
+
+ QHistoryState *s1h = new QHistoryState(s1);
+ s1h->setDefaultState(s11);
+
+ machine.addState(s1);
+
+ QState *s2 = new QState();
+ machine.addState(s2);
+
+ QPushButton *button = new QPushButton();
+ // Clicking the button will cause the state machine to enter the child state
+ // that s1 was in the last time s1 was exited, or the history state's default
+ // state if s1 has never been entered.
+ s1->addTransition(button, SIGNAL(clicked()), s1h);
+ \endcode
+
+ If more than one default state has to be entered, or if the transition to the default state(s)
+ has to be acted upon, the defaultTransition should be set instead. Note that the eventTest()
+ method of that transition will never be called: the selection and execution of the transition is
+ done automatically when entering the history state.
+
+ By default a history state is shallow, meaning that it won't remember nested
+ states. This can be configured through the historyType property.
+*/
+
+/*!
+ \property QHistoryState::defaultTransition
+
+ \brief the default transition of this history state
+*/
+
+/*!
+ \property QHistoryState::defaultState
+
+ \brief the default state of this history state
+*/
+
+/*!
+ \property QHistoryState::historyType
+
+ \brief the type of history that this history state records
+
+ The default value of this property is QHistoryState::ShallowHistory.
+*/
+
+/*!
+ \enum QHistoryState::HistoryType
+
+ This enum specifies the type of history that a QHistoryState records.
+
+ \value ShallowHistory Only the immediate child states of the parent state
+ are recorded. In this case a transition with the history state as its
+ target will end up in the immediate child state that the parent was in the
+ last time it was exited. This is the default.
+
+ \value DeepHistory Nested states are recorded. In this case a transition
+ with the history state as its target will end up in the most deeply nested
+ descendant state the parent was in the last time it was exited.
+*/
+
+namespace {
+class DefaultStateTransition: public QAbstractTransition
+{
+ Q_OBJECT
+
+public:
+ DefaultStateTransition(QHistoryState *source, QAbstractState *target);
+
+protected:
+ // It doesn't matter whether this transition matches any event or not. It is always associated
+ // with a QHistoryState, and as soon as the state-machine detects that it enters a history
+ // state, it will handle this transition as a special case. The history state itself is never
+ // entered either: either the stored configuration will be used, or the target(s) of this
+ // transition are used.
+ bool eventTest(QEvent *event) override { Q_UNUSED(event); return false; }
+ void onTransition(QEvent *event) override { Q_UNUSED(event); }
+};
+}
+
+QHistoryStatePrivate::QHistoryStatePrivate()
+ : QAbstractStatePrivate(HistoryState)
+ , defaultTransition(nullptr)
+ , historyType(QHistoryState::ShallowHistory)
+{
+}
+
+DefaultStateTransition::DefaultStateTransition(QHistoryState *source, QAbstractState *target)
+ : QAbstractTransition()
+{
+ setParent(source);
+ setTargetState(target);
+}
+
+/*!
+ Constructs a new shallow history state with the given \a parent state.
+*/
+QHistoryState::QHistoryState(QState *parent)
+ : QAbstractState(*new QHistoryStatePrivate, parent)
+{
+}
+/*!
+ Constructs a new history state of the given \a type, with the given \a
+ parent state.
+*/
+QHistoryState::QHistoryState(HistoryType type, QState *parent)
+ : QAbstractState(*new QHistoryStatePrivate, parent)
+{
+ Q_D(QHistoryState);
+ d->historyType = type;
+}
+
+/*!
+ Destroys this history state.
+*/
+QHistoryState::~QHistoryState()
+{
+}
+
+/*!
+ Returns this history state's default transition. The default transition is
+ taken when the history state has never been entered before. The target states
+ of the default transition therefore make up the default state.
+
+ \since 5.6
+*/
+QAbstractTransition *QHistoryState::defaultTransition() const
+{
+ Q_D(const QHistoryState);
+ return d->defaultTransition;
+}
+
+/*!
+ Sets this history state's default transition to be the given \a transition.
+ This will set the source state of the \a transition to the history state.
+
+ Note that the eventTest method of the \a transition will never be called.
+
+ \since 5.6
+*/
+void QHistoryState::setDefaultTransition(QAbstractTransition *transition)
+{
+ Q_D(QHistoryState);
+ d->defaultTransition.removeBindingUnlessInWrapper();
+ if (d->defaultTransition.valueBypassingBindings() == transition)
+ return;
+ d->defaultTransition.setValueBypassingBindings(transition);
+ if (transition)
+ transition->setParent(this);
+ d->defaultTransition.notify();
+ emit defaultTransitionChanged(QHistoryState::QPrivateSignal());
+}
+
+QBindable<QAbstractTransition*> QHistoryState::bindableDefaultTransition()
+{
+ Q_D(QHistoryState);
+ return &d->defaultTransition;
+}
+
+/*!
+ Returns this history state's default state. The default state indicates the
+ state to transition to if the parent state has never been entered before.
+*/
+QAbstractState *QHistoryState::defaultState() const
+{
+ Q_D(const QHistoryState);
+ return d->defaultTransition.value() ? d->defaultTransition->targetState() : nullptr;
+}
+
+static inline bool isSoleEntry(const QList<QAbstractState*> &states, const QAbstractState * state)
+{
+ return states.size() == 1 && states.first() == state;
+}
+
+/*!
+ Sets this history state's default state to be the given \a state.
+ \a state must be a sibling of this history state.
+
+ Note that this function does not set \a state as the initial state
+ of its parent.
+*/
+void QHistoryState::setDefaultState(QAbstractState *state)
+{
+ Q_D(QHistoryState);
+ if (state && state->parentState() != parentState()) {
+ qWarning("QHistoryState::setDefaultState: state %p does not belong "
+ "to this history state's group (%p)", state, parentState());
+ return;
+ }
+ // evaluate the binding once
+ auto *defaultTransition = d->defaultTransition.value();
+ if (!defaultTransition || !isSoleEntry(defaultTransition->targetStates(), state)) {
+ if (!defaultTransition || !qobject_cast<DefaultStateTransition*>(defaultTransition))
+ d->defaultTransition.setValue(new DefaultStateTransition(this, state));
+ else
+ defaultTransition->setTargetState(state);
+ emit defaultStateChanged(QHistoryState::QPrivateSignal());
+ }
+}
+
+/*!
+ Returns the type of history that this history state records.
+*/
+QHistoryState::HistoryType QHistoryState::historyType() const
+{
+ Q_D(const QHistoryState);
+ return d->historyType;
+}
+
+/*!
+ Sets the \a type of history that this history state records.
+*/
+void QHistoryState::setHistoryType(HistoryType type)
+{
+ Q_D(QHistoryState);
+ d->historyType = type;
+}
+
+QBindable<QHistoryState::HistoryType> QHistoryState::bindableHistoryType()
+{
+ Q_D(QHistoryState);
+ return &d->historyType;
+}
+
+/*!
+ \reimp
+*/
+void QHistoryState::onEntry(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QHistoryState::onExit(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QHistoryState::event(QEvent *e)
+{
+ return QAbstractState::event(e);
+}
+
+/*!
+ \fn QHistoryState::defaultStateChanged()
+ \since 5.4
+
+ This signal is emitted when the defaultState property is changed.
+
+ \sa QHistoryState::defaultState
+*/
+
+/*!
+ \fn QHistoryState::historyTypeChanged()
+ \since 5.4
+
+ This signal is emitted when the historyType property is changed.
+
+ \sa QHistoryState::historyType
+*/
+
+/*!
+ \fn QHistoryState::defaultTransitionChanged()
+ \since 5.6
+
+ This signal is emitted when the defaultTransition property is changed.
+
+ \sa QHistoryState::defaultTransition
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qhistorystate.cpp"
+#include "qhistorystate.moc"
diff --git a/src/statemachine/qhistorystate.h b/src/statemachine/qhistorystate.h
new file mode 100644
index 0000000..a089f88
--- /dev/null
+++ b/src/statemachine/qhistorystate.h
@@ -0,0 +1,64 @@
+// 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
+
+#ifndef QHISTORYSTATE_H
+#define QHISTORYSTATE_H
+
+#include <QtStateMachine/qabstractstate.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractTransition;
+class QHistoryStatePrivate;
+class Q_STATEMACHINE_EXPORT QHistoryState : public QAbstractState
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractState* defaultState READ defaultState WRITE setDefaultState NOTIFY defaultStateChanged)
+ Q_PROPERTY(QAbstractTransition* defaultTransition READ defaultTransition
+ WRITE setDefaultTransition NOTIFY defaultTransitionChanged
+ BINDABLE bindableDefaultTransition)
+ Q_PROPERTY(HistoryType historyType READ historyType WRITE setHistoryType
+ NOTIFY historyTypeChanged BINDABLE bindableHistoryType)
+public:
+ enum HistoryType {
+ ShallowHistory,
+ DeepHistory
+ };
+ Q_ENUM(HistoryType)
+
+ QHistoryState(QState *parent = nullptr);
+ QHistoryState(HistoryType type, QState *parent = nullptr);
+ ~QHistoryState();
+
+ QAbstractTransition *defaultTransition() const;
+ void setDefaultTransition(QAbstractTransition *transition);
+ QBindable<QAbstractTransition*> bindableDefaultTransition();
+
+ QAbstractState *defaultState() const;
+ void setDefaultState(QAbstractState *state);
+
+ HistoryType historyType() const;
+ void setHistoryType(HistoryType type);
+ QBindable<QHistoryState::HistoryType> bindableHistoryType();
+
+Q_SIGNALS:
+ void defaultTransitionChanged(QPrivateSignal);
+ void defaultStateChanged(QPrivateSignal);
+ void historyTypeChanged(QPrivateSignal);
+
+protected:
+ void onEntry(QEvent *event) override;
+ void onExit(QEvent *event) override;
+
+ bool event(QEvent *e) override;
+
+private:
+ Q_DISABLE_COPY(QHistoryState)
+ Q_DECLARE_PRIVATE(QHistoryState)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qhistorystate_p.h b/src/statemachine/qhistorystate_p.h
new file mode 100644
index 0000000..d6958b6
--- /dev/null
+++ b/src/statemachine/qhistorystate_p.h
@@ -0,0 +1,60 @@
+// 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
+
+#ifndef QHISTORYSTATE_P_H
+#define QHISTORYSTATE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qabstractstate_p.h"
+
+#include <QtCore/qlist.h>
+
+#include <QtStateMachine/qabstracttransition.h>
+#include <QtStateMachine/qhistorystate.h>
+#include <QtCore/private/qproperty_p.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QHistoryStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QHistoryState)
+
+public:
+ QHistoryStatePrivate();
+
+ static QHistoryStatePrivate *get(QHistoryState *q)
+ { return q->d_func(); }
+
+ void setDefaultTransition(QAbstractTransition* transition)
+ {
+ q_func()->setDefaultTransition(transition);
+ }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QHistoryStatePrivate,
+ QAbstractTransition*, defaultTransition,
+ &QHistoryStatePrivate::setDefaultTransition, nullptr);
+
+ void historyTypeChanged()
+ {
+ emit q_func()->historyTypeChanged(QHistoryState::QPrivateSignal());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY(QHistoryStatePrivate, QHistoryState::HistoryType,
+ historyType, &QHistoryStatePrivate::historyTypeChanged);
+
+ QList<QAbstractState*> configuration;
+};
+
+QT_END_NAMESPACE
+
+#endif // QHISTORYSTATE_P_H
diff --git a/src/statemachine/qsignaleventgenerator_p.h b/src/statemachine/qsignaleventgenerator_p.h
new file mode 100644
index 0000000..0a46b1c
--- /dev/null
+++ b/src/statemachine/qsignaleventgenerator_p.h
@@ -0,0 +1,44 @@
+// 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
+
+#ifndef QSIGNALEVENTGENERATOR_P_H
+#define QSIGNALEVENTGENERATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qobject.h>
+
+#include <QtStateMachine/qstatemachineglobal.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QStateMachine;
+
+class QSignalEventGenerator : public QObject
+{
+ Q_OBJECT
+public:
+ QSignalEventGenerator(QStateMachine *parent);
+
+private Q_SLOTS:
+ void execute(QMethodRawArguments a);
+
+private:
+ Q_DISABLE_COPY_MOVE(QSignalEventGenerator)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qsignaltransition.cpp b/src/statemachine/qsignaltransition.cpp
new file mode 100644
index 0000000..46e67dc
--- /dev/null
+++ b/src/statemachine/qsignaltransition.cpp
@@ -0,0 +1,266 @@
+// 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 "qsignaltransition.h"
+#include "qsignaltransition_p.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSignalTransition
+ \inmodule QtStateMachine
+
+ \brief The QSignalTransition class provides a transition based on a Qt signal.
+
+ \since 4.6
+ \ingroup statemachine
+
+ Typically you would use the overload of QState::addTransition() that takes a
+ sender and signal as arguments, rather than creating QSignalTransition
+ objects directly. QSignalTransition is part of \l{Qt State Machine Overview}
+ {Qt State Machine Framework}.
+
+ You can subclass QSignalTransition and reimplement eventTest() to make a
+ signal transition conditional; the event object passed to eventTest() will
+ be a QStateMachine::SignalEvent object. Example:
+
+ \code
+ class CheckedTransition : public QSignalTransition
+ {
+ public:
+ CheckedTransition(QCheckBox *check)
+ : QSignalTransition(check, SIGNAL(stateChanged(int))) {}
+ protected:
+ bool eventTest(QEvent *e) {
+ if (!QSignalTransition::eventTest(e))
+ return false;
+ QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e);
+ return (se->arguments().at(0).toInt() == Qt::Checked);
+ }
+ };
+
+ ...
+
+ QCheckBox *check = new QCheckBox();
+ check->setTristate(true);
+
+ QState *s1 = new QState();
+ QState *s2 = new QState();
+ CheckedTransition *t1 = new CheckedTransition(check);
+ t1->setTargetState(s2);
+ s1->addTransition(t1);
+ \endcode
+*/
+
+/*!
+ \property QSignalTransition::senderObject
+
+ \brief the sender object that this signal transition is associated with
+*/
+
+/*!
+ \property QSignalTransition::signal
+
+ \brief the signal that this signal transition is associated with
+*/
+
+QSignalTransitionPrivate::QSignalTransitionPrivate()
+{
+ signalIndex = -1;
+}
+
+void QSignalTransitionPrivate::unregister()
+{
+ Q_Q(QSignalTransition);
+ if ((signalIndex == -1) || !machine())
+ return;
+ QStateMachinePrivate::get(machine())->unregisterSignalTransition(q);
+}
+
+void QSignalTransitionPrivate::maybeRegister()
+{
+ Q_Q(QSignalTransition);
+ if (QStateMachine *mach = machine())
+ QStateMachinePrivate::get(mach)->maybeRegisterSignalTransition(q);
+}
+
+/*!
+ Constructs a new signal transition with the given \a sourceState.
+*/
+QSignalTransition::QSignalTransition(QState *sourceState)
+ : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
+{
+}
+
+/*!
+ Constructs a new signal transition associated with the given \a signal of
+ the given \a sender, and with the given \a sourceState.
+*/
+QSignalTransition::QSignalTransition(const QObject *sender, const char *signal,
+ QState *sourceState)
+ : QAbstractTransition(*new QSignalTransitionPrivate, sourceState)
+{
+ Q_D(QSignalTransition);
+ d->senderObject.setValueBypassingBindings(sender);
+ d->signal.setValueBypassingBindings(signal);
+ d->maybeRegister();
+}
+
+/*!
+ \fn template <typename PointerToMemberFunction> QSignalTransition::QSignalTransition(const QObject *sender, PointerToMemberFunction signal, QState *sourceState)
+ \since 5.7
+ \overload
+
+ Constructs a new signal transition associated with the given \a signal of
+ the given \a sender object and with the given \a sourceState.
+ This constructor is enabled if the compiler supports delegating constructors,
+ as indicated by the presence of the macro Q_COMPILER_DELEGATING_CONSTRUCTORS.
+*/
+
+/*!
+ Destroys this signal transition.
+*/
+QSignalTransition::~QSignalTransition()
+{
+}
+
+/*!
+ Returns the sender object associated with this signal transition.
+*/
+const QObject *QSignalTransition::senderObject() const
+{
+ Q_D(const QSignalTransition);
+ return d->senderObject;
+}
+
+/*!
+ Sets the \a sender object associated with this signal transition.
+*/
+void QSignalTransition::setSenderObject(const QObject *sender)
+{
+ Q_D(QSignalTransition);
+ d->senderObject.removeBindingUnlessInWrapper();
+ if (sender == d->senderObject.valueBypassingBindings())
+ return;
+ d->unregister();
+ d->senderObject.setValueBypassingBindings(sender);
+ d->maybeRegister();
+ d->senderObject.notify();
+ emit senderObjectChanged(QPrivateSignal());
+}
+
+QBindable<const QObject*> QSignalTransition::bindableSenderObject()
+{
+ Q_D(QSignalTransition);
+ return &d->senderObject;
+}
+
+/*!
+ Returns the signal associated with this signal transition.
+*/
+QByteArray QSignalTransition::signal() const
+{
+ Q_D(const QSignalTransition);
+ return d->signal;
+}
+
+/*!
+ Sets the \a signal associated with this signal transition.
+*/
+void QSignalTransition::setSignal(const QByteArray &signal)
+{
+ Q_D(QSignalTransition);
+ d->signal.removeBindingUnlessInWrapper();
+ if (signal == d->signal.valueBypassingBindings())
+ return;
+ d->unregister();
+ d->signal.setValueBypassingBindings(signal);
+ d->maybeRegister();
+ d->signal.notify();
+ emit signalChanged(QPrivateSignal());
+}
+
+QBindable<QByteArray> QSignalTransition::bindableSignal()
+{
+ Q_D(QSignalTransition);
+ return &d->signal;
+}
+
+/*!
+ \reimp
+
+ The default implementation returns \c true if the \a event is a
+ QStateMachine::SignalEvent object and the event's sender and signal index
+ match this transition, and returns \c false otherwise.
+*/
+bool QSignalTransition::eventTest(QEvent *event)
+{
+ Q_D(const QSignalTransition);
+ if (event->type() == QEvent::StateMachineSignal) {
+ if (d->signalIndex == -1)
+ return false;
+ QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(event);
+ return (se->sender() == d->senderObject.value())
+ && (se->signalIndex() == d->signalIndex);
+ }
+ return false;
+}
+
+/*!
+ \reimp
+*/
+void QSignalTransition::onTransition(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+bool QSignalTransition::event(QEvent *e)
+{
+ return QAbstractTransition::event(e);
+}
+
+/*!
+ \fn QSignalTransition::senderObjectChanged()
+ \since 5.4
+
+ This signal is emitted when the senderObject property is changed.
+
+ \sa QSignalTransition::senderObject
+*/
+
+/*!
+ \fn QSignalTransition::signalChanged()
+ \since 5.4
+
+ This signal is emitted when the signal property is changed.
+
+ \sa QSignalTransition::signal
+*/
+
+void QSignalTransitionPrivate::callOnTransition(QEvent *e)
+{
+ Q_Q(QSignalTransition);
+
+ if (e->type() == QEvent::StateMachineSignal) {
+ QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent *>(e);
+ int savedSignalIndex = se->m_signalIndex;
+ se->m_signalIndex = originalSignalIndex;
+ q->onTransition(e);
+ se->m_signalIndex = savedSignalIndex;
+ } else {
+ q->onTransition(e);
+ }
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qsignaltransition.cpp"
diff --git a/src/statemachine/qsignaltransition.h b/src/statemachine/qsignaltransition.h
new file mode 100644
index 0000000..2bfe191
--- /dev/null
+++ b/src/statemachine/qsignaltransition.h
@@ -0,0 +1,67 @@
+// 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
+
+#ifndef QSIGNALTRANSITION_H
+#define QSIGNALTRANSITION_H
+
+#include <QtCore/qmetaobject.h>
+#include <QtStateMachine/qabstracttransition.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QSignalTransitionPrivate;
+class Q_STATEMACHINE_EXPORT QSignalTransition : public QAbstractTransition
+{
+ Q_OBJECT
+ Q_PROPERTY(const QObject* senderObject READ senderObject WRITE setSenderObject
+ NOTIFY senderObjectChanged BINDABLE bindableSenderObject)
+ Q_PROPERTY(QByteArray signal READ signal WRITE setSignal
+ NOTIFY signalChanged BINDABLE bindableSignal)
+
+public:
+ QSignalTransition(QState *sourceState = nullptr);
+ QSignalTransition(const QObject *sender, const char *signal,
+ QState *sourceState = nullptr);
+#ifdef Q_QDOC
+ template<typename PointerToMemberFunction>
+ QSignalTransition(const QObject *object, PointerToMemberFunction signal,
+ QState *sourceState = nullptr);
+#elif defined(Q_COMPILER_DELEGATING_CONSTRUCTORS)
+ template <typename Func>
+ QSignalTransition(const typename QtPrivate::FunctionPointer<Func>::Object *obj,
+ Func sig, QState *srcState = nullptr)
+ : QSignalTransition(obj, QMetaMethod::fromSignal(sig).methodSignature().constData(), srcState)
+ {
+ }
+#endif
+
+ ~QSignalTransition();
+
+ const QObject *senderObject() const;
+ void setSenderObject(const QObject *sender);
+ QBindable<const QObject*> bindableSenderObject();
+
+ QByteArray signal() const;
+ void setSignal(const QByteArray &signal);
+ QBindable<QByteArray> bindableSignal();
+
+protected:
+ bool eventTest(QEvent *event) override;
+ void onTransition(QEvent *event) override;
+
+ bool event(QEvent *e) override;
+
+Q_SIGNALS:
+ void senderObjectChanged(QPrivateSignal);
+ void signalChanged(QPrivateSignal);
+
+private:
+ Q_DISABLE_COPY(QSignalTransition)
+ Q_DECLARE_PRIVATE(QSignalTransition)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qsignaltransition_p.h b/src/statemachine/qsignaltransition_p.h
new file mode 100644
index 0000000..2da77e6
--- /dev/null
+++ b/src/statemachine/qsignaltransition_p.h
@@ -0,0 +1,60 @@
+// 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
+
+#ifndef QSIGNALTRANSITION_P_H
+#define QSIGNALTRANSITION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qabstracttransition_p.h"
+#include <QtCore/private/qproperty_p.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QSignalTransition;
+class QSignalTransitionPrivate : public QAbstractTransitionPrivate
+{
+ Q_DECLARE_PUBLIC(QSignalTransition)
+public:
+ QSignalTransitionPrivate();
+
+ static QSignalTransitionPrivate *get(QSignalTransition *q)
+ { return q->d_func(); }
+
+ void unregister();
+ void maybeRegister();
+
+ void callOnTransition(QEvent *e) override;
+
+ void setSenderObject(const QObject* sender)
+ {
+ q_func()->setSenderObject(sender);
+ }
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QSignalTransitionPrivate, const QObject*,
+ senderObject, &QSignalTransitionPrivate::setSenderObject,
+ nullptr);
+
+ void setSignal(const QByteArray& signal)
+ {
+ q_func()->setSignal(signal);
+ }
+ Q_OBJECT_COMPAT_PROPERTY(QSignalTransitionPrivate, QByteArray,
+ signal, &QSignalTransitionPrivate::setSignal);
+ int signalIndex;
+ int originalSignalIndex;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qstate.cpp b/src/statemachine/qstate.cpp
new file mode 100644
index 0000000..dc8d173
--- /dev/null
+++ b/src/statemachine/qstate.cpp
@@ -0,0 +1,574 @@
+// 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 "qstate_p.h"
+#include "qhistorystate.h"
+#include "qhistorystate_p.h"
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qsignaltransition.h"
+#include "qstatemachine.h"
+#include "qstatemachine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QState
+ \inmodule QtStateMachine
+
+ \brief The QState class provides a general-purpose state for QStateMachine.
+
+ \since 4.6
+ \ingroup statemachine
+
+ QState objects can have child states, and can have transitions to other
+ states. QState is part of \l{Qt State Machine Overview}{Qt State Machine Framework}.
+
+ The addTransition() function adds a transition. The removeTransition()
+ function removes a transition. The transitions() function returns the
+ state's outgoing transitions.
+
+ The assignProperty() function is used for defining property assignments that
+ should be performed when a state is entered.
+
+ Top-level states must be passed a QStateMachine object as their parent
+ state, or added to a state machine using QStateMachine::addState().
+
+ \section1 States with Child States
+
+ The childMode property determines how child states are treated. For
+ non-parallel state groups, the setInitialState() function must be called to
+ set the initial state. The child states are mutually exclusive states, and
+ the state machine needs to know which child state to enter when the parent
+ state is the target of a transition.
+
+ The state emits the QState::finished() signal when a final child state
+ (QFinalState) is entered.
+
+ The setErrorState() sets the state's error state. The error state is the
+ state that the state machine will transition to if an error is detected when
+ attempting to enter the state (e.g. because no initial state has been set).
+
+*/
+
+/*!
+ \property QState::initialState
+
+ \brief the initial state of this state (one of its child states)
+*/
+
+/*!
+ \property QState::errorState
+
+ \brief the error state of this state
+*/
+
+/*!
+ \property QState::childMode
+
+ \brief the child mode of this state
+
+ The default value of this property is QState::ExclusiveStates.
+*/
+
+/*!
+ \enum QState::ChildMode
+
+ This enum specifies how a state's child states are treated.
+
+ \value ExclusiveStates The child states are mutually exclusive and an
+ initial state must be set by calling QState::setInitialState().
+
+ \value ParallelStates The child states are parallel. When the parent state
+ is entered, all its child states are entered in parallel.
+*/
+
+/*!
+ \enum QState::RestorePolicy
+
+ This enum specifies the restore policy type. The restore policy
+ takes effect when the machine enters a state which sets one or more
+ properties. If the restore policy is set to RestoreProperties,
+ the state machine will save the original value of the property before the
+ new value is set.
+
+ Later, when the machine either enters a state which does not set
+ a value for the given property, the property will automatically be restored
+ to its initial value.
+
+ Only one initial value will be saved for any given property. If a value for a property has
+ already been saved by the state machine, it will not be overwritten until the property has been
+ successfully restored.
+
+ \value DontRestoreProperties The state machine should not save the initial values of properties
+ and restore them later.
+ \value RestoreProperties The state machine should save the initial values of properties
+ and restore them later.
+
+ \sa QStateMachine::globalRestorePolicy, QState::assignProperty()
+*/
+
+QStatePrivate::QStatePrivate()
+ : QAbstractStatePrivate(StandardState),
+ childStatesListNeedsRefresh(true), transitionsListNeedsRefresh(true)
+{
+}
+
+QStatePrivate::~QStatePrivate()
+{
+}
+
+void QStatePrivate::emitFinished()
+{
+ Q_Q(QState);
+ emit q->finished(QState::QPrivateSignal());
+}
+
+void QStatePrivate::emitPropertiesAssigned()
+{
+ Q_Q(QState);
+ emit q->propertiesAssigned(QState::QPrivateSignal());
+}
+
+/*!
+ Constructs a new state with the given \a parent state.
+*/
+QState::QState(QState *parent)
+ : QAbstractState(*new QStatePrivate, parent)
+{
+}
+
+/*!
+ Constructs a new state with the given \a childMode and the given \a parent
+ state.
+*/
+QState::QState(ChildMode childMode, QState *parent)
+ : QAbstractState(*new QStatePrivate, parent)
+{
+ Q_D(QState);
+ d->childMode = childMode;
+}
+
+/*!
+ \internal
+*/
+QState::QState(QStatePrivate &dd, QState *parent)
+ : QAbstractState(dd, parent)
+{
+}
+
+/*!
+ Destroys this state.
+*/
+QState::~QState()
+{
+}
+
+QList<QAbstractState*> QStatePrivate::childStates() const
+{
+ if (childStatesListNeedsRefresh) {
+ childStatesList.clear();
+ QList<QObject*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QAbstractState *s = qobject_cast<QAbstractState*>(*it);
+ if (!s || qobject_cast<QHistoryState*>(s))
+ continue;
+ childStatesList.append(s);
+ }
+ childStatesListNeedsRefresh = false;
+ }
+ return childStatesList;
+}
+
+QList<QHistoryState*> QStatePrivate::historyStates() const
+{
+ QList<QHistoryState*> result;
+ QList<QObject*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QHistoryState *h = qobject_cast<QHistoryState*>(*it);
+ if (h)
+ result.append(h);
+ }
+ return result;
+}
+
+QList<QAbstractTransition*> QStatePrivate::transitions() const
+{
+ if (transitionsListNeedsRefresh) {
+ transitionsList.clear();
+ QList<QObject*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ QAbstractTransition *t = qobject_cast<QAbstractTransition*>(*it);
+ if (t)
+ transitionsList.append(t);
+ }
+ transitionsListNeedsRefresh = false;
+ }
+ return transitionsList;
+}
+
+#ifndef QT_NO_PROPERTIES
+
+/*!
+ Instructs this state to set the property with the given \a name of the given
+ \a object to the given \a value when the state is entered.
+
+ \sa propertiesAssigned()
+*/
+void QState::assignProperty(QObject *object, const char *name,
+ const QVariant &value)
+{
+ Q_D(QState);
+ if (!object) {
+ qWarning("QState::assignProperty: cannot assign property '%s' of null object", name);
+ return;
+ }
+ for (int i = 0; i < d->propertyAssignments.size(); ++i) {
+ QPropertyAssignment &assn = d->propertyAssignments[i];
+ if (assn.hasTarget(object, name)) {
+ assn.value = value;
+ return;
+ }
+ }
+ d->propertyAssignments.append(QPropertyAssignment(object, name, value));
+}
+
+#endif // QT_NO_PROPERTIES
+
+/*!
+ Returns this state's error state.
+
+ \sa QStateMachine::error()
+*/
+QAbstractState *QState::errorState() const
+{
+ Q_D(const QState);
+ return d->errorState;
+}
+
+/*!
+ Sets this state's error state to be the given \a state. If the error state
+ is not set, or if it is set to \nullptr, the state will inherit its parent's error
+ state recursively. If no error state is set for the state itself or any of
+ its ancestors, an error will cause the machine to stop executing and an error
+ will be printed to the console.
+*/
+void QState::setErrorState(QAbstractState *state)
+{
+ Q_D(QState);
+ if (state != nullptr && qobject_cast<QStateMachine*>(state)) {
+ qWarning("QStateMachine::setErrorState: root state cannot be error state");
+ return;
+ }
+ if (state != nullptr && (!state->machine() || ((state->machine() != machine()) && !qobject_cast<QStateMachine*>(this)))) {
+ qWarning("QState::setErrorState: error state cannot belong "
+ "to a different state machine");
+ return;
+ }
+ d->errorState = state;
+}
+
+QBindable<QAbstractState*> QState::bindableErrorState()
+{
+ Q_D(QState);
+ return &d->errorState;
+}
+
+/*!
+ Adds the given \a transition. The transition has this state as the source.
+ This state takes ownership of the transition.
+*/
+void QState::addTransition(QAbstractTransition *transition)
+{
+ Q_D(QState);
+ if (!transition) {
+ qWarning("QState::addTransition: cannot add null transition");
+ return ;
+ }
+
+ transition->setParent(this);
+ const QList<QPointer<QAbstractState>> &targets = QAbstractTransitionPrivate::get(transition)->targetStates;
+ for (int i = 0; i < targets.size(); ++i) {
+ QAbstractState *t = targets.at(i).data();
+ if (!t) {
+ qWarning("QState::addTransition: cannot add transition to null state");
+ return ;
+ }
+ if ((QAbstractStatePrivate::get(t)->machine() != d->machine())
+ && QAbstractStatePrivate::get(t)->machine() && d->machine()) {
+ qWarning("QState::addTransition: cannot add transition "
+ "to a state in a different state machine");
+ return ;
+ }
+ }
+ if (QStateMachine *mach = machine())
+ QStateMachinePrivate::get(mach)->maybeRegisterTransition(transition);
+}
+
+/*!
+ \fn template <typename PointerToMemberFunction> QState::addTransition(const QObject *sender, PointerToMemberFunction signal, QAbstractState *target);
+ \since 5.5
+ \overload
+
+ Adds a transition associated with the given \a signal of the given \a sender
+ object, and returns the new QSignalTransition object. The transition has
+ this state as the source, and the given \a target as the target state.
+*/
+
+/*!
+ Adds a transition associated with the given \a signal of the given \a sender
+ object, and returns the new QSignalTransition object. The transition has
+ this state as the source, and the given \a target as the target state.
+*/
+QSignalTransition *QState::addTransition(const QObject *sender, const char *signal,
+ QAbstractState *target)
+{
+ if (!sender) {
+ qWarning("QState::addTransition: sender cannot be null");
+ return nullptr;
+ }
+ if (!signal) {
+ qWarning("QState::addTransition: signal cannot be null");
+ return nullptr;
+ }
+ if (!target) {
+ qWarning("QState::addTransition: cannot add transition to null state");
+ return nullptr;
+ }
+ int offset = (*signal == '0'+QSIGNAL_CODE) ? 1 : 0;
+ const QMetaObject *meta = sender->metaObject();
+ if (meta->indexOfSignal(signal+offset) == -1) {
+ if (meta->indexOfSignal(QMetaObject::normalizedSignature(signal+offset)) == -1) {
+ qWarning("QState::addTransition: no such signal %s::%s",
+ meta->className(), signal+offset);
+ return nullptr;
+ }
+ }
+ QSignalTransition *trans = new QSignalTransition(sender, signal);
+ trans->setTargetState(target);
+ addTransition(trans);
+ return trans;
+}
+
+namespace {
+
+// ### Make public?
+class UnconditionalTransition : public QAbstractTransition
+{
+public:
+ UnconditionalTransition(QAbstractState *target)
+ : QAbstractTransition()
+ { setTargetState(target); }
+protected:
+ void onTransition(QEvent *) override {}
+ bool eventTest(QEvent *) override { return true; }
+};
+
+} // namespace
+
+/*!
+ Adds an unconditional transition from this state to the given \a target
+ state, and returns then new transition object.
+*/
+QAbstractTransition *QState::addTransition(QAbstractState *target)
+{
+ if (!target) {
+ qWarning("QState::addTransition: cannot add transition to null state");
+ return nullptr;
+ }
+ UnconditionalTransition *trans = new UnconditionalTransition(target);
+ addTransition(trans);
+ return trans;
+}
+
+/*!
+ Removes the given \a transition from this state. The state releases
+ ownership of the transition.
+
+ \sa addTransition()
+*/
+void QState::removeTransition(QAbstractTransition *transition)
+{
+ Q_D(QState);
+ if (!transition) {
+ qWarning("QState::removeTransition: cannot remove null transition");
+ return;
+ }
+ if (transition->sourceState() != this) {
+ qWarning("QState::removeTransition: transition %p's source state (%p)"
+ " is different from this state (%p)",
+ transition, transition->sourceState(), this);
+ return;
+ }
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(d->machine());
+ if (mach)
+ mach->unregisterTransition(transition);
+ transition->setParent(nullptr);
+}
+
+/*!
+ \since 4.7
+
+ Returns this state's outgoing transitions (i.e. transitions where
+ this state is the \l [CPP] {QAbstractTransition::sourceState()}{source
+ state}), or an empty list if this state has no outgoing transitions.
+
+ \sa addTransition()
+*/
+QList<QAbstractTransition*> QState::transitions() const
+{
+ Q_D(const QState);
+ return d->transitions();
+}
+
+/*!
+ \reimp
+*/
+void QState::onEntry(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+*/
+void QState::onExit(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ Returns this state's initial state, or \nullptr if the state has no
+ initial state.
+*/
+QAbstractState *QState::initialState() const
+{
+ Q_D(const QState);
+ return d->initialState;
+}
+
+/*!
+ Sets this state's initial state to be the given \a state.
+ \a state has to be a child of this state.
+*/
+void QState::setInitialState(QAbstractState *state)
+{
+ Q_D(QState);
+ if (d->childMode == QState::ParallelStates) {
+ qWarning("QState::setInitialState: ignoring attempt to set initial state "
+ "of parallel state group %p", this);
+ return;
+ }
+ if (state && (state->parentState() != this)) {
+ qWarning("QState::setInitialState: state %p is not a child of this state (%p)",
+ state, this);
+ return;
+ }
+ d->initialState = state;
+}
+
+QBindable<QAbstractState*> QState::bindableInitialState()
+{
+ Q_D(QState);
+ return &d->initialState;
+}
+
+/*!
+ Returns the child mode of this state.
+*/
+QState::ChildMode QState::childMode() const
+{
+ Q_D(const QState);
+ return d->childMode;
+}
+
+/*!
+ Sets the child \a mode of this state.
+*/
+void QState::setChildMode(ChildMode mode)
+{
+ Q_D(QState);
+
+ if (mode == QState::ParallelStates && d->initialState.value()) {
+ qWarning("QState::setChildMode: setting the child-mode of state %p to "
+ "parallel removes the initial state", this);
+ d->initialState.setValue(nullptr);
+ }
+ d->childMode = mode;
+}
+
+QBindable<QState::ChildMode> QState::bindableChildMode()
+{
+ Q_D(QState);
+ return &d->childMode;
+}
+
+/*!
+ \reimp
+*/
+bool QState::event(QEvent *e)
+{
+ Q_D(QState);
+ if ((e->type() == QEvent::ChildAdded) || (e->type() == QEvent::ChildRemoved)) {
+ d->childStatesListNeedsRefresh = true;
+ d->transitionsListNeedsRefresh = true;
+ if ((e->type() == QEvent::ChildRemoved)
+ && (static_cast<QChildEvent *>(e)->child() == d->initialState.value())) {
+ d->initialState.setValue(nullptr);
+ }
+ }
+ return QAbstractState::event(e);
+}
+
+/*!
+ \fn QState::finished()
+
+ This signal is emitted when a final child state of this state is entered.
+
+ \sa QFinalState
+*/
+
+/*!
+ \fn QState::propertiesAssigned()
+
+ This signal is emitted when all properties have been assigned their final value. If the state
+ assigns a value to one or more properties for which an animation exists (either set on the
+ transition or as a default animation on the state machine), then the signal will not be emitted
+ until all such animations have finished playing.
+
+ If there are no relevant animations, or no property assignments defined for the state, then
+ the signal will be emitted immediately before the state is entered.
+
+ \b {See also} \l QState::assignProperty() and \l [CPP] {QAbstractTransition::addAnimation()}
+*/
+
+/*!
+ \fn QState::childModeChanged()
+ \since 5.4
+
+ This signal is emitted when the childMode property is changed.
+
+ \sa QState::childMode
+*/
+
+/*!
+ \fn QState::initialStateChanged()
+ \since 5.4
+
+ This signal is emitted when the initialState property is changed.
+
+ \sa QState::initialState
+*/
+
+/*!
+ \fn QState::errorStateChanged()
+ \since 5.4
+
+ This signal is emitted when the errorState property is changed.
+
+ \sa QState::errorState
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qstate.cpp"
diff --git a/src/statemachine/qstate.h b/src/statemachine/qstate.h
new file mode 100644
index 0000000..312c995
--- /dev/null
+++ b/src/statemachine/qstate.h
@@ -0,0 +1,105 @@
+// 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
+
+#ifndef QSTATE_H
+#define QSTATE_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+
+#include <QtStateMachine/qabstractstate.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractTransition;
+class QSignalTransition;
+
+class QStatePrivate;
+class Q_STATEMACHINE_EXPORT QState : public QAbstractState
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState
+ NOTIFY initialStateChanged BINDABLE bindableInitialState)
+ Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState
+ NOTIFY errorStateChanged BINDABLE bindableErrorState)
+ Q_PROPERTY(ChildMode childMode READ childMode WRITE setChildMode
+ NOTIFY childModeChanged BINDABLE bindableChildMode)
+public:
+ enum ChildMode {
+ ExclusiveStates,
+ ParallelStates
+ };
+ Q_ENUM(ChildMode)
+
+ enum RestorePolicy {
+ DontRestoreProperties,
+ RestoreProperties
+ };
+ Q_ENUM(RestorePolicy)
+
+ QState(QState *parent = nullptr);
+ QState(ChildMode childMode, QState *parent = nullptr);
+ ~QState();
+
+ QAbstractState *errorState() const;
+ void setErrorState(QAbstractState *state);
+ QBindable<QAbstractState*> bindableErrorState();
+
+ void addTransition(QAbstractTransition *transition);
+ QSignalTransition *addTransition(const QObject *sender, const char *signal, QAbstractState *target);
+#ifdef Q_QDOC
+ template<typename PointerToMemberFunction>
+ QSignalTransition *addTransition(const QObject *sender, PointerToMemberFunction signal,
+ QAbstractState *target);
+#else
+ template <typename Func>
+ QSignalTransition *addTransition(const typename QtPrivate::FunctionPointer<Func>::Object *obj,
+ Func signal, QAbstractState *target)
+ {
+ const QMetaMethod signalMetaMethod = QMetaMethod::fromSignal(signal);
+ return addTransition(obj, signalMetaMethod.methodSignature().constData(), target);
+ }
+#endif // Q_QDOC
+ QAbstractTransition *addTransition(QAbstractState *target);
+ void removeTransition(QAbstractTransition *transition);
+ QList<QAbstractTransition*> transitions() const;
+
+ QAbstractState *initialState() const;
+ void setInitialState(QAbstractState *state);
+ QBindable<QAbstractState*> bindableInitialState();
+
+ ChildMode childMode() const;
+ void setChildMode(ChildMode mode);
+ QBindable<QState::ChildMode> bindableChildMode();
+
+#ifndef QT_NO_PROPERTIES
+ void assignProperty(QObject *object, const char *name,
+ const QVariant &value);
+#endif
+
+Q_SIGNALS:
+ void finished(QPrivateSignal);
+ void propertiesAssigned(QPrivateSignal);
+ void childModeChanged(QPrivateSignal);
+ void initialStateChanged(QPrivateSignal);
+ void errorStateChanged(QPrivateSignal);
+
+protected:
+ void onEntry(QEvent *event) override;
+ void onExit(QEvent *event) override;
+
+ bool event(QEvent *e) override;
+
+protected:
+ QState(QStatePrivate &dd, QState *parent);
+
+private:
+ Q_DISABLE_COPY(QState)
+ Q_DECLARE_PRIVATE(QState)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qstate_p.h b/src/statemachine/qstate_p.h
new file mode 100644
index 0000000..7d54d6d
--- /dev/null
+++ b/src/statemachine/qstate_p.h
@@ -0,0 +1,110 @@
+// 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
+
+#ifndef QSTATE_P_H
+#define QSTATE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstate.h"
+#include "private/qabstractstate_p.h"
+
+#include <QtCore/qlist.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/private/qproperty_p.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PROPERTIES
+
+struct QPropertyAssignment
+{
+ QPropertyAssignment()
+ : object(nullptr), explicitlySet(true) {}
+ QPropertyAssignment(QObject *o, const QByteArray &n,
+ const QVariant &v, bool es = true)
+ : object(o), propertyName(n), value(v), explicitlySet(es)
+ {}
+
+ bool objectDeleted() const { return !object; }
+ void write() const { Q_ASSERT(object != nullptr); object->setProperty(propertyName, value); }
+ bool hasTarget(QObject *o, const QByteArray &pn) const
+ { return object == o && propertyName == pn; }
+
+ QPointer<QObject> object;
+ QByteArray propertyName;
+ QVariant value;
+ bool explicitlySet; // false means the property is being restored to its old value
+};
+Q_DECLARE_TYPEINFO(QPropertyAssignment, Q_RELOCATABLE_TYPE);
+
+#endif // QT_NO_PROPERTIES
+
+class QAbstractTransition;
+class QHistoryState;
+
+class QState;
+class Q_STATEMACHINE_EXPORT QStatePrivate : public QAbstractStatePrivate
+{
+ Q_DECLARE_PUBLIC(QState)
+public:
+ QStatePrivate();
+ ~QStatePrivate();
+
+ static QStatePrivate *get(QState *q) { return q ? q->d_func() : nullptr; }
+ static const QStatePrivate *get(const QState *q) { return q? q->d_func() : nullptr; }
+
+ QList<QAbstractState*> childStates() const;
+ QList<QHistoryState*> historyStates() const;
+ QList<QAbstractTransition*> transitions() const;
+
+ void emitFinished();
+ void emitPropertiesAssigned();
+
+ void initialStateChanged()
+ {
+ emit q_func()->initialStateChanged(QState::QPrivateSignal());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QStatePrivate, QAbstractState*, initialState,
+ nullptr, &QStatePrivate::initialStateChanged);
+
+ void errorStateChanged()
+ {
+ emit q_func()->errorStateChanged(QState::QPrivateSignal());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QStatePrivate, QAbstractState*, errorState,
+ nullptr, &QStatePrivate::errorStateChanged);
+
+ void childModeChanged()
+ {
+ emit q_func()->childModeChanged(QState::QPrivateSignal());
+ }
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QStatePrivate, QState::ChildMode, childMode,
+ QState::ExclusiveStates, &QStatePrivate::childModeChanged);
+
+ mutable bool childStatesListNeedsRefresh;
+ mutable bool transitionsListNeedsRefresh;
+ mutable QList<QAbstractState*> childStatesList;
+ mutable QList<QAbstractTransition*> transitionsList;
+
+#ifndef QT_NO_PROPERTIES
+ QList<QPropertyAssignment> propertyAssignments;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qstatemachine.cpp b/src/statemachine/qstatemachine.cpp
new file mode 100644
index 0000000..acf5b4b
--- /dev/null
+++ b/src/statemachine/qstatemachine.cpp
@@ -0,0 +1,3188 @@
+// 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 "qstatemachine.h"
+#include "qstate.h"
+#include "qstate_p.h"
+#include "qstatemachine_p.h"
+#include "qabstracttransition.h"
+#include "qabstracttransition_p.h"
+#include "qsignaltransition.h"
+#include "qsignaltransition_p.h"
+#include "qsignaleventgenerator_p.h"
+#include "qabstractstate.h"
+#include "qabstractstate_p.h"
+#include "qfinalstate.h"
+#include "qhistorystate.h"
+#include "qhistorystate_p.h"
+
+#include "private/qcoreapplication_p.h"
+#include "private/qobject_p.h"
+#include "private/qthread_p.h"
+
+#if QT_CONFIG(qeventtransition)
+#include "qeventtransition.h"
+#include "qeventtransition_p.h"
+#endif
+
+#if QT_CONFIG(animation)
+#include "qpropertyanimation.h"
+#include "qanimationgroup.h"
+#include <private/qvariantanimation_p.h>
+#endif
+
+#include <QtCore/qmetaobject.h>
+#include <qdebug.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+enum {
+ Offset0 = 0x00000000,
+ Offset1 = 0x00008000,
+ Offset2 = 0x00080000,
+ Offset3 = 0x00800000,
+
+ Size0 = Offset1 - Offset0,
+ Size1 = Offset2 - Offset1,
+ Size2 = Offset3 - Offset2,
+ Size3 = QStateMachinePrivate::FreeListDefaultConstants::MaxIndex - Offset3
+};
+
+const int QStateMachinePrivate::FreeListDefaultConstants::Sizes[FreeListDefaultConstants::BlockCount] = {
+ Size0,
+ Size1,
+ Size2,
+ Size3
+};
+
+/*!
+ \class QStateMachine
+ \inmodule QtStateMachine
+ \reentrant
+
+ \brief The QStateMachine class provides a hierarchical finite state machine.
+
+ \since 4.6
+ \ingroup statemachine
+
+ QStateMachine is based on the concepts and notation of
+ \l{http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf}{Statecharts}.
+ QStateMachine is part of \l{Qt State Machine Overview}{Qt State Machine Framework}.
+
+ A state machine manages a set of states (classes that inherit from
+ QAbstractState) and transitions (descendants of
+ QAbstractTransition) between those states; these states and
+ transitions define a state graph. Once a state graph has been
+ built, the state machine can execute it. QStateMachine's
+ execution algorithm is based on the \l{http://www.w3.org/TR/scxml/}{State Chart XML (SCXML)}
+ algorithm. The framework's \l{Qt State Machine Overview}{overview} gives several state
+ graphs and the code to build them.
+
+ Use the addState() function to add a top-level state to the state machine.
+ States are removed with the removeState() function. Removing states while
+ the machine is running is discouraged.
+
+ Before the machine can be started, the \l{initialState}{initial
+ state} must be set. The initial state is the state that the
+ machine enters when started. You can then start() the state
+ machine. The started() signal is emitted when the initial state is
+ entered.
+
+ The machine is event driven and keeps its own event loop. Events
+ are posted to the machine through postEvent(). Note that this
+ means that it executes asynchronously, and that it will not
+ progress without a running event loop. You will normally not have
+ to post events to the machine directly as Qt's transitions, e.g.,
+ QEventTransition and its subclasses, handle this. But for custom
+ transitions triggered by events, postEvent() is useful.
+
+ The state machine processes events and takes transitions until a
+ top-level final state is entered; the state machine then emits the
+ finished() signal. You can also stop() the state machine
+ explicitly. The stopped() signal is emitted in this case.
+
+ The following snippet shows a state machine that will finish when a button
+ is clicked:
+
+ \snippet code/src_corelib_statemachine_qstatemachine.cpp simple state machine
+
+ This code example uses QState, which inherits QAbstractState. The
+ QState class provides a state that you can use to set properties
+ and invoke methods on \l{QObject}s when the state is entered or
+ exited. It also contains convenience functions for adding
+ transitions, e.g., \l{QSignalTransition}s as in this example. See
+ the QState class description for further details.
+
+ If an error is encountered, the machine will look for an
+ \l{errorState}{error state}, and if one is available, it will
+ enter this state. The types of errors possible are described by the
+ \l{QStateMachine::}{Error} enum. After the error state is entered,
+ the type of the error can be retrieved with error(). The execution
+ of the state graph will not stop when the error state is entered. If
+ no error state applies to the erroneous state, the machine will stop
+ executing and an error message will be printed to the console.
+
+ \note Important: setting the \l{ChildMode} of a state machine to parallel (\l{ParallelStates})
+ results in an invalid state machine. It can only be set to (or kept as)
+ \l{ExclusiveStates}.
+
+ \sa QAbstractState, QAbstractTransition, QState, {Qt State Machine Overview}
+*/
+
+/*!
+ \property QStateMachine::errorString
+
+ \brief the error string of this state machine
+*/
+
+/*!
+ \property QStateMachine::globalRestorePolicy
+
+ \brief the restore policy for states of this state machine.
+
+ The default value of this property is
+ QState::DontRestoreProperties.
+*/
+
+/*!
+ \property QStateMachine::running
+ \since 5.4
+
+ \brief the running state of this state machine
+
+ \sa start(), stop(), started(), stopped(), runningChanged()
+*/
+
+#if QT_CONFIG(animation)
+/*!
+ \property QStateMachine::animated
+
+ \brief whether animations are enabled
+
+ The default value of this property is \c true.
+
+ \b {See also} \l [CPP] QAbstractTransition::addAnimation()
+*/
+#endif
+
+// #define QSTATEMACHINE_DEBUG
+// #define QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+
+struct CalculationCache {
+ struct TransitionInfo {
+ QList<QAbstractState*> effectiveTargetStates;
+ QSet<QAbstractState*> exitSet;
+ QAbstractState *transitionDomain;
+
+ bool effectiveTargetStatesIsKnown: 1;
+ bool exitSetIsKnown : 1;
+ bool transitionDomainIsKnown : 1;
+
+ TransitionInfo()
+ : transitionDomain(nullptr)
+ , effectiveTargetStatesIsKnown(false)
+ , exitSetIsKnown(false)
+ , transitionDomainIsKnown(false)
+ {}
+ };
+
+ typedef QHash<QAbstractTransition *, TransitionInfo> TransitionInfoCache;
+ TransitionInfoCache cache;
+
+ bool effectiveTargetStates(QAbstractTransition *t, QList<QAbstractState *> *targets) const
+ {
+ Q_ASSERT(targets);
+
+ TransitionInfoCache::const_iterator cacheIt = cache.find(t);
+ if (cacheIt == cache.end() || !cacheIt->effectiveTargetStatesIsKnown)
+ return false;
+
+ *targets = cacheIt->effectiveTargetStates;
+ return true;
+ }
+
+ void insert(QAbstractTransition *t, const QList<QAbstractState *> &targets)
+ {
+ TransitionInfoCache::iterator cacheIt = cache.find(t);
+ TransitionInfo &ti = cacheIt == cache.end()
+ ? *cache.insert(t, TransitionInfo())
+ : *cacheIt;
+
+ Q_ASSERT(!ti.effectiveTargetStatesIsKnown);
+ ti.effectiveTargetStates = targets;
+ ti.effectiveTargetStatesIsKnown = true;
+ }
+
+ bool exitSet(QAbstractTransition *t, QSet<QAbstractState *> *exits) const
+ {
+ Q_ASSERT(exits);
+
+ TransitionInfoCache::const_iterator cacheIt = cache.find(t);
+ if (cacheIt == cache.end() || !cacheIt->exitSetIsKnown)
+ return false;
+
+ *exits = cacheIt->exitSet;
+ return true;
+ }
+
+ void insert(QAbstractTransition *t, const QSet<QAbstractState *> &exits)
+ {
+ TransitionInfoCache::iterator cacheIt = cache.find(t);
+ TransitionInfo &ti = cacheIt == cache.end()
+ ? *cache.insert(t, TransitionInfo())
+ : *cacheIt;
+
+ Q_ASSERT(!ti.exitSetIsKnown);
+ ti.exitSet = exits;
+ ti.exitSetIsKnown = true;
+ }
+
+ bool transitionDomain(QAbstractTransition *t, QAbstractState **domain) const
+ {
+ Q_ASSERT(domain);
+
+ TransitionInfoCache::const_iterator cacheIt = cache.find(t);
+ if (cacheIt == cache.end() || !cacheIt->transitionDomainIsKnown)
+ return false;
+
+ *domain = cacheIt->transitionDomain;
+ return true;
+ }
+
+ void insert(QAbstractTransition *t, QAbstractState *domain)
+ {
+ TransitionInfoCache::iterator cacheIt = cache.find(t);
+ TransitionInfo &ti = cacheIt == cache.end()
+ ? *cache.insert(t, TransitionInfo())
+ : *cacheIt;
+
+ Q_ASSERT(!ti.transitionDomainIsKnown);
+ ti.transitionDomain = domain;
+ ti.transitionDomainIsKnown = true;
+ }
+};
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function isDescendant(state1, state2)
+
+Returns 'true' if state1 is a descendant of state2 (a child, or a child of a child, or a child of a
+child of a child, etc.) Otherwise returns 'false'.
+*/
+static inline bool isDescendant(const QAbstractState *state1, const QAbstractState *state2)
+{
+ Q_ASSERT(state1 != nullptr);
+
+ for (QAbstractState *it = state1->parentState(); it != nullptr; it = it->parentState()) {
+ if (it == state2)
+ return true;
+ }
+
+ return false;
+}
+
+static bool containsDecendantOf(const QSet<QAbstractState *> &states, const QAbstractState *node)
+{
+ for (QAbstractState *s : states)
+ if (isDescendant(s, node))
+ return true;
+
+ return false;
+}
+
+static int descendantDepth(const QAbstractState *state, const QAbstractState *ancestor)
+{
+ int depth = 0;
+ for (const QAbstractState *it = state; it != nullptr; it = it->parentState()) {
+ if (it == ancestor)
+ break;
+ ++depth;
+ }
+ return depth;
+}
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function getProperAncestors(state1, state2)
+
+If state2 is null, returns the set of all ancestors of state1 in ancestry order (state1's parent
+followed by the parent's parent, etc. up to an including the <scxml> element). If state2 is
+non-null, returns in ancestry order the set of all ancestors of state1, up to but not including
+state2. (A "proper ancestor" of a state is its parent, or the parent's parent, or the parent's
+parent's parent, etc.))If state2 is state1's parent, or equal to state1, or a descendant of state1,
+this returns the empty set.
+*/
+static QList<QState *> getProperAncestors(const QAbstractState *state, const QAbstractState *upperBound)
+{
+ Q_ASSERT(state != nullptr);
+ QList<QState *> result;
+ result.reserve(16);
+ for (QState *it = state->parentState(); it && it != upperBound; it = it->parentState()) {
+ result.append(it);
+ }
+ return result;
+}
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function getEffectiveTargetStates(transition)
+
+Returns the states that will be the target when 'transition' is taken, dereferencing any history states.
+
+function getEffectiveTargetStates(transition)
+ targets = new OrderedSet()
+ for s in transition.target
+ if isHistoryState(s):
+ if historyValue[s.id]:
+ targets.union(historyValue[s.id])
+ else:
+ targets.union(getEffectiveTargetStates(s.transition))
+ else:
+ targets.add(s)
+ return targets
+*/
+static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *transition, CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ QList<QAbstractState *> targetsList;
+ if (cache->effectiveTargetStates(transition, &targetsList))
+ return targetsList;
+
+ QSet<QAbstractState *> targets;
+ const auto targetStates = transition->targetStates();
+ for (QAbstractState *s : targetStates) {
+ if (QHistoryState *historyState = QStateMachinePrivate::toHistoryState(s)) {
+ QList<QAbstractState*> historyConfiguration = QHistoryStatePrivate::get(historyState)->configuration;
+ if (!historyConfiguration.isEmpty()) {
+ // There is a saved history, so apply that.
+ targets.unite(QSet<QAbstractState *>(historyConfiguration.constBegin(), historyConfiguration.constEnd()));
+ } else if (QAbstractTransition *defaultTransition = historyState->defaultTransition()) {
+ // No saved history, take all default transition targets.
+ const auto &targetStates = defaultTransition->targetStates();
+ targets.unite(QSet<QAbstractState *>(targetStates.constBegin(), targetStates.constEnd()));
+ } else {
+ // Woops, we found a history state without a default state. That's not valid!
+ QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine());
+ m->setError(QStateMachine::NoDefaultStateInHistoryStateError, historyState);
+ }
+ } else {
+ targets.insert(s);
+ }
+ }
+
+ targetsList = targets.values();
+ cache->insert(transition, targetsList);
+ return targetsList;
+}
+
+QStateMachinePrivate::QStateMachinePrivate()
+{
+ isMachine = true;
+
+ state = NotRunning;
+ processing = false;
+ processingScheduled = false;
+ stop = false;
+ stopProcessingReason = EventQueueEmpty;
+ error = QStateMachine::NoError;
+ signalEventGenerator = nullptr;
+}
+
+QStateMachinePrivate::~QStateMachinePrivate()
+{
+ qDeleteAll(internalEventQueue);
+ qDeleteAll(externalEventQueue);
+
+ for (QHash<int, DelayedEvent>::const_iterator it = delayedEvents.cbegin(), eit = delayedEvents.cend(); it != eit; ++it) {
+ delete it.value().event;
+ }
+}
+
+QState *QStateMachinePrivate::rootState() const
+{
+ return const_cast<QStateMachine*>(q_func());
+}
+
+static int indexOfDescendant(QState *s, QAbstractState *desc)
+{
+ QList<QAbstractState*> childStates = QStatePrivate::get(s)->childStates();
+ for (int i = 0; i < childStates.size(); ++i) {
+ QAbstractState *c = childStates.at(i);
+ if ((c == desc) || isDescendant(desc, c)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+bool QStateMachinePrivate::transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2)
+{
+ QState *s1 = t1->sourceState(), *s2 = t2->sourceState();
+ if (s1 == s2) {
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(s1)->transitions();
+ return transitions.indexOf(t1) < transitions.indexOf(t2);
+ } else if (isDescendant(s1, s2)) {
+ return true;
+ } else if (isDescendant(s2, s1)) {
+ return false;
+ } else {
+ Q_ASSERT(s1->machine() != nullptr);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(lca != nullptr);
+ int s1Depth = descendantDepth(s1, lca);
+ int s2Depth = descendantDepth(s2, lca);
+ if (s1Depth == s2Depth)
+ return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
+ else
+ return s1Depth > s2Depth;
+ }
+}
+
+bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2)
+{
+ if (s1->parent() == s2->parent()) {
+ return s1->parent()->children().indexOf(s1)
+ < s2->parent()->children().indexOf(s2);
+ } else if (isDescendant(s1, s2)) {
+ return false;
+ } else if (isDescendant(s2, s1)) {
+ return true;
+ } else {
+ Q_ASSERT(s1->machine() != nullptr);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(lca != nullptr);
+ return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
+ }
+}
+
+bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState *s2)
+{
+ if (s1->parent() == s2->parent()) {
+ return s2->parent()->children().indexOf(s2)
+ < s1->parent()->children().indexOf(s1);
+ } else if (isDescendant(s1, s2)) {
+ return true;
+ } else if (isDescendant(s2, s1)) {
+ return false;
+ } else {
+ Q_ASSERT(s1->machine() != nullptr);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(lca != nullptr);
+ return (indexOfDescendant(lca, s2) < indexOfDescendant(lca, s1));
+ }
+}
+
+QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states, bool onlyCompound)
+{
+ if (states.isEmpty())
+ return nullptr;
+ QList<QState *> ancestors = getProperAncestors(states.at(0), rootState()->parentState());
+ for (int i = 0; i < ancestors.size(); ++i) {
+ QState *anc = ancestors.at(i);
+ if (onlyCompound && !isCompound(anc))
+ continue;
+
+ bool ok = true;
+ for (int j = states.size() - 1; (j > 0) && ok; --j) {
+ const QAbstractState *s = states.at(j);
+ if (!isDescendant(s, anc))
+ ok = false;
+ }
+ if (ok)
+ return anc;
+ }
+
+ // Oops, this should never happen! The state machine itself is a common ancestor of all states,
+ // no matter what. But, for the onlyCompound case: we probably have a state machine whose
+ // childMode is set to parallel, which is illegal. However, we're stuck with it (and with
+ // exposing this invalid/dangerous API to users), so recover in the least horrible way.
+ setError(QStateMachine::StateMachineChildModeSetToParallelError, q_func());
+ return q_func(); // make the statemachine the LCA/LCCA (which it should have been anyway)
+}
+
+QState *QStateMachinePrivate::findLCCA(const QList<QAbstractState*> &states)
+{
+ return findLCA(states, true);
+}
+
+QList<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event, CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+ Q_Q(const QStateMachine);
+
+ QVarLengthArray<QAbstractState *> configuration_sorted;
+ for (QAbstractState *s : std::as_const(configuration)) {
+ if (isAtomic(s))
+ configuration_sorted.append(s);
+ }
+ std::sort(configuration_sorted.begin(), configuration_sorted.end(), stateEntryLessThan);
+
+ QList<QAbstractTransition*> enabledTransitions;
+ const_cast<QStateMachine *>(q)->beginSelectTransitions(event);
+ for (QAbstractState *state : std::as_const(configuration_sorted)) {
+ QList<QState *> lst = getProperAncestors(state, nullptr);
+ if (QState *grp = toStandardState(state))
+ lst.prepend(grp);
+ bool found = false;
+ for (int j = 0; (j < lst.size()) && !found; ++j) {
+ QState *s = lst.at(j);
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(s)->transitions();
+ for (int k = 0; k < transitions.size(); ++k) {
+ QAbstractTransition *t = transitions.at(k);
+ if (QAbstractTransitionPrivate::get(t)->callEventTest(event)) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": selecting transition" << t;
+#endif
+ enabledTransitions.append(t);
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!enabledTransitions.isEmpty()) {
+ removeConflictingTransitions(enabledTransitions, cache);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": enabled transitions after removing conflicts:" << enabledTransitions;
+#endif
+ }
+ const_cast<QStateMachine*>(q)->endSelectTransitions(event);
+ return enabledTransitions;
+}
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function removeConflictingTransitions(enabledTransitions):
+ filteredTransitions = new OrderedSet()
+ // toList sorts the transitions in the order of the states that selected them
+ for t1 in enabledTransitions.toList():
+ t1Preempted = false;
+ transitionsToRemove = new OrderedSet()
+ for t2 in filteredTransitions.toList():
+ if computeExitSet([t1]).hasIntersection(computeExitSet([t2])):
+ if isDescendant(t1.source, t2.source):
+ transitionsToRemove.add(t2)
+ else:
+ t1Preempted = true
+ break
+ if not t1Preempted:
+ for t3 in transitionsToRemove.toList():
+ filteredTransitions.delete(t3)
+ filteredTransitions.add(t1)
+
+ return filteredTransitions
+
+Note: the implementation below does not build the transitionsToRemove, but removes them in-place.
+*/
+void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ if (enabledTransitions.size() < 2)
+ return; // There is no transition to conflict with.
+
+ QList<QAbstractTransition*> filteredTransitions;
+ filteredTransitions.reserve(enabledTransitions.size());
+ std::sort(enabledTransitions.begin(), enabledTransitions.end(), transitionStateEntryLessThan);
+
+ for (QAbstractTransition *t1 : std::as_const(enabledTransitions)) {
+ bool t1Preempted = false;
+ const QSet<QAbstractState*> exitSetT1 = computeExitSet_Unordered(t1, cache);
+ QList<QAbstractTransition*>::iterator t2It = filteredTransitions.begin();
+ while (t2It != filteredTransitions.end()) {
+ QAbstractTransition *t2 = *t2It;
+ if (t1 == t2) {
+ // Special case: someone added the same transition object to a state twice. In this
+ // case, t2 (which is already in the list) "preempts" t1.
+ t1Preempted = true;
+ break;
+ }
+
+ QSet<QAbstractState*> exitSetT2 = computeExitSet_Unordered(t2, cache);
+ if (!exitSetT1.intersects(exitSetT2)) {
+ // No conflict, no cry. Next patient please.
+ ++t2It;
+ } else {
+ // Houston, we have a conflict. Check which transition can be removed.
+ if (isDescendant(t1->sourceState(), t2->sourceState())) {
+ // t1 preempts t2, so we can remove t2
+ t2It = filteredTransitions.erase(t2It);
+ } else {
+ // t2 preempts t1, so there's no use in looking further and we don't need to add
+ // t1 to the list.
+ t1Preempted = true;
+ break;
+ }
+ }
+ }
+ if (!t1Preempted)
+ filteredTransitions.append(t1);
+ }
+
+ enabledTransitions = filteredTransitions;
+}
+
+void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')';
+ qDebug() << q_func() << ": configuration before exiting states:" << configuration;
+#endif
+ QList<QAbstractState*> exitedStates = computeExitSet(enabledTransitions, cache);
+ QHash<RestorableId, QVariant> pendingRestorables = computePendingRestorables(exitedStates);
+
+ QSet<QAbstractState*> statesForDefaultEntry;
+ QList<QAbstractState*> enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry, cache);
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": computed exit set:" << exitedStates;
+ qDebug() << q_func() << ": computed entry set:" << enteredStates;
+#endif
+
+ QHash<QAbstractState *, QList<QPropertyAssignment>> assignmentsForEnteredStates =
+ computePropertyAssignments(enteredStates, pendingRestorables);
+ if (!pendingRestorables.isEmpty()) {
+ // Add "implicit" assignments for restored properties to the first
+ // (outermost) entered state
+ Q_ASSERT(!enteredStates.isEmpty());
+ QAbstractState *s = enteredStates.constFirst();
+ assignmentsForEnteredStates[s] << restorablesToPropertyList(pendingRestorables);
+ }
+
+ exitStates(event, exitedStates, assignmentsForEnteredStates);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": configuration after exiting states:" << configuration;
+#endif
+
+ executeTransitionContent(event, enabledTransitions);
+
+#if QT_CONFIG(animation)
+ QList<QAbstractAnimation *> selectedAnimations = selectAnimations(enabledTransitions);
+#endif
+
+ enterStates(event, exitedStates, enteredStates, statesForDefaultEntry, assignmentsForEnteredStates
+#if QT_CONFIG(animation)
+ , selectedAnimations
+#endif
+ );
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": configuration after entering states:" << configuration;
+ qDebug() << q_func() << ": end microstep";
+#endif
+}
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+procedure computeExitSet(enabledTransitions)
+
+For each transition t in enabledTransitions, if t is targetless then do nothing, else compute the
+transition's domain. (This will be the source state in the case of internal transitions) or the
+least common compound ancestor state of the source state and target states of t (in the case of
+external transitions. Add to the statesToExit set all states in the configuration that are
+descendants of the domain.
+
+function computeExitSet(transitions)
+ statesToExit = new OrderedSet
+ for t in transitions:
+ if (t.target):
+ domain = getTransitionDomain(t)
+ for s in configuration:
+ if isDescendant(s,domain):
+ statesToExit.add(s)
+ return statesToExit
+*/
+QList<QAbstractState*> QStateMachinePrivate::computeExitSet(const QList<QAbstractTransition*> &enabledTransitions,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ QList<QAbstractState*> statesToExit_sorted = computeExitSet_Unordered(enabledTransitions, cache).values();
+ std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
+ return statesToExit_sorted;
+}
+
+QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ QSet<QAbstractState*> statesToExit;
+ for (QAbstractTransition *t : enabledTransitions)
+ statesToExit.unite(computeExitSet_Unordered(t, cache));
+ return statesToExit;
+}
+
+QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(QAbstractTransition *t,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ QSet<QAbstractState*> statesToExit;
+ if (cache->exitSet(t, &statesToExit))
+ return statesToExit;
+
+ QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
+ QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates, cache);
+ if (domain == nullptr && !t->targetStates().isEmpty()) {
+ // So we didn't find the least common ancestor for the source and target states of the
+ // transition. If there were not target states, that would be fine: then the transition
+ // will fire any events or signals, but not exit the state.
+ //
+ // However, there are target states, so it's either a node without a parent (or parent's
+ // parent, etc), or the state belongs to a different state machine. Either way, this
+ // makes the state machine invalid.
+ if (error == QStateMachine::NoError)
+ setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState());
+ QList<QAbstractState *> lst = pendingErrorStates.values();
+ lst.prepend(t->sourceState());
+
+ domain = findLCCA(lst);
+ Q_ASSERT(domain != nullptr);
+ }
+
+ for (QAbstractState* s : std::as_const(configuration)) {
+ if (isDescendant(s, domain))
+ statesToExit.insert(s);
+ }
+
+ cache->insert(t, statesToExit);
+ return statesToExit;
+}
+
+void QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractState *> &statesToExit_sorted,
+ const QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates)
+{
+ for (int i = 0; i < statesToExit_sorted.size(); ++i) {
+ QAbstractState *s = statesToExit_sorted.at(i);
+ if (QState *grp = toStandardState(s)) {
+ QList<QHistoryState*> hlst = QStatePrivate::get(grp)->historyStates();
+ for (int j = 0; j < hlst.size(); ++j) {
+ QHistoryState *h = hlst.at(j);
+ QHistoryStatePrivate::get(h)->configuration.clear();
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ QAbstractState *s0 = *it;
+ if (QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) {
+ if (isAtomic(s0) && isDescendant(s0, s))
+ QHistoryStatePrivate::get(h)->configuration.append(s0);
+ } else if (s0->parentState() == s) {
+ QHistoryStatePrivate::get(h)->configuration.append(s0);
+ }
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": recorded" << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
+ << "history for" << s << "in" << h << ':' << QHistoryStatePrivate::get(h)->configuration;
+#endif
+ }
+ }
+ }
+ for (int i = 0; i < statesToExit_sorted.size(); ++i) {
+ QAbstractState *s = statesToExit_sorted.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": exiting" << s;
+#endif
+ QAbstractStatePrivate::get(s)->callOnExit(event);
+
+#if QT_CONFIG(animation)
+ terminateActiveAnimations(s, assignmentsForEnteredStates);
+#else
+ Q_UNUSED(assignmentsForEnteredStates);
+#endif
+
+ configuration.remove(s);
+ QAbstractStatePrivate::get(s)->emitExited();
+ }
+}
+
+void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
+{
+ for (int i = 0; i < enabledTransitions.size(); ++i) {
+ QAbstractTransition *t = enabledTransitions.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": triggering" << t;
+#endif
+ QAbstractTransitionPrivate::get(t)->callOnTransition(event);
+ QAbstractTransitionPrivate::get(t)->emitTriggered();
+ }
+}
+
+QList<QAbstractState*> QStateMachinePrivate::computeEntrySet(const QList<QAbstractTransition *> &enabledTransitions,
+ QSet<QAbstractState *> &statesForDefaultEntry,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ QSet<QAbstractState*> statesToEnter;
+ if (pendingErrorStates.isEmpty()) {
+ for (QAbstractTransition *t : enabledTransitions) {
+ const auto targetStates = t->targetStates();
+ for (QAbstractState *s : targetStates)
+ addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
+
+ const QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
+ QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates, cache);
+ for (QAbstractState *s : effectiveTargetStates)
+ addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry);
+ }
+ }
+
+ // Did an error occur while selecting transitions? Then we enter the error state.
+ if (!pendingErrorStates.isEmpty()) {
+ statesToEnter.clear();
+ statesToEnter = pendingErrorStates;
+ statesForDefaultEntry = pendingErrorStatesForDefaultEntry;
+ pendingErrorStates.clear();
+ pendingErrorStatesForDefaultEntry.clear();
+ }
+
+ QList<QAbstractState*> statesToEnter_sorted = statesToEnter.values();
+ std::sort(statesToEnter_sorted.begin(), statesToEnter_sorted.end(), stateEntryLessThan);
+ return statesToEnter_sorted;
+}
+
+/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function getTransitionDomain(transition)
+
+Return the compound state such that 1) all states that are exited or entered as a result of taking
+'transition' are descendants of it 2) no descendant of it has this property.
+
+function getTransitionDomain(t)
+ tstates = getEffectiveTargetStates(t)
+ if not tstates:
+ return null
+ elif t.type == "internal" and isCompoundState(t.source) and tstates.every(lambda s: isDescendant(s,t.source)):
+ return t.source
+ else:
+ return findLCCA([t.source].append(tstates))
+*/
+QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t,
+ const QList<QAbstractState *> &effectiveTargetStates,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ if (effectiveTargetStates.isEmpty())
+ return nullptr;
+
+ QAbstractState *domain = nullptr;
+ if (cache->transitionDomain(t, &domain))
+ return domain;
+
+ if (t->transitionType() == QAbstractTransition::InternalTransition) {
+ if (QState *tSource = t->sourceState()) {
+ if (isCompound(tSource)) {
+ bool allDescendants = true;
+ for (QAbstractState *s : effectiveTargetStates) {
+ if (!isDescendant(s, tSource)) {
+ allDescendants = false;
+ break;
+ }
+ }
+
+ if (allDescendants)
+ return tSource;
+ }
+ }
+ }
+
+ QList<QAbstractState *> states(effectiveTargetStates);
+ if (QAbstractState *src = t->sourceState())
+ states.prepend(src);
+ domain = findLCCA(states);
+ cache->insert(t, domain);
+ return domain;
+}
+
+void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState *> &exitedStates_sorted,
+ const QList<QAbstractState *> &statesToEnter_sorted,
+ const QSet<QAbstractState *> &statesForDefaultEntry,
+ QHash<QAbstractState *, QList<QPropertyAssignment>> &propertyAssignmentsForState
+#if QT_CONFIG(animation)
+ , const QList<QAbstractAnimation *> &selectedAnimations
+#endif
+ )
+{
+#ifdef QSTATEMACHINE_DEBUG
+ Q_Q(QStateMachine);
+#endif
+ for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
+ QAbstractState *s = statesToEnter_sorted.at(i);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": entering" << s;
+#endif
+ configuration.insert(s);
+ registerTransitions(s);
+
+#if QT_CONFIG(animation)
+ initializeAnimations(s, selectedAnimations, exitedStates_sorted, propertyAssignmentsForState);
+#endif
+
+ // Immediately set the properties that are not animated.
+ {
+ const auto assignments = propertyAssignmentsForState.value(s);
+ for (const auto &assn : assignments) {
+ if (globalRestorePolicy == QState::RestoreProperties) {
+ if (assn.explicitlySet) {
+ if (!hasRestorable(s, assn.object, assn.propertyName)) {
+ QVariant value = savedValueForRestorable(exitedStates_sorted, assn.object, assn.propertyName);
+ unregisterRestorables(exitedStates_sorted, assn.object, assn.propertyName);
+ registerRestorable(s, assn.object, assn.propertyName, value);
+ }
+ } else {
+ // The property is being restored, hence no need to
+ // save the current value. Discard any saved values in
+ // exited states, since those are now stale.
+ unregisterRestorables(exitedStates_sorted, assn.object, assn.propertyName);
+ }
+ }
+ assn.write();
+ }
+ }
+
+ QAbstractStatePrivate::get(s)->callOnEntry(event);
+ QAbstractStatePrivate::get(s)->emitEntered();
+
+ // FIXME:
+ // See the "initial transitions" comment in addDescendantStatesToEnter first, then implement:
+// if (statesForDefaultEntry.contains(s)) {
+// // ### executeContent(s.initial.transition.children())
+// }
+ Q_UNUSED(statesForDefaultEntry);
+
+ if (QHistoryState *h = toHistoryState(s))
+ QAbstractTransitionPrivate::get(h->defaultTransition())->callOnTransition(event);
+
+ // Emit propertiesAssigned signal if the state has no animated properties.
+ {
+ QState *ss = toStandardState(s);
+ if (ss
+ #if QT_CONFIG(animation)
+ && !animationsForState.contains(s)
+ #endif
+ )
+ QStatePrivate::get(ss)->emitPropertiesAssigned();
+ }
+
+ if (isFinal(s)) {
+ QState *parent = s->parentState();
+ if (parent) {
+ if (parent != rootState()) {
+ QFinalState *finalState = qobject_cast<QFinalState *>(s);
+ Q_ASSERT(finalState);
+ emitStateFinished(parent, finalState);
+ }
+ QState *grandparent = parent->parentState();
+ if (grandparent && isParallel(grandparent)) {
+ bool allChildStatesFinal = true;
+ QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates();
+ for (int j = 0; j < childStates.size(); ++j) {
+ QAbstractState *cs = childStates.at(j);
+ if (!isInFinalState(cs)) {
+ allChildStatesFinal = false;
+ break;
+ }
+ }
+ if (allChildStatesFinal && (grandparent != rootState())) {
+ QFinalState *finalState = qobject_cast<QFinalState *>(s);
+ Q_ASSERT(finalState);
+ emitStateFinished(grandparent, finalState);
+ }
+ }
+ }
+ }
+ }
+ {
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ if (isFinal(*it)) {
+ QState *parent = (*it)->parentState();
+ if (((parent == rootState())
+ && (rootState()->childMode() == QState::ExclusiveStates))
+ || ((parent->parentState() == rootState())
+ && (rootState()->childMode() == QState::ParallelStates)
+ && isInFinalState(rootState()))) {
+ processing = false;
+ stopProcessingReason = Finished;
+ break;
+ }
+ }
+ }
+ }
+// qDebug() << "configuration:" << configuration.toList();
+}
+
+/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ has a bug. See
+ * QTBUG-44963 for details. The algorithm here is as described in
+ * http://www.w3.org/Voice/2013/scxml-irp/SCXML.htm as of Friday March 13, 2015.
+
+procedure addDescendantStatesToEnter(state,statesToEnter,statesForDefaultEntry, defaultHistoryContent):
+ if isHistoryState(state):
+ if historyValue[state.id]:
+ for s in historyValue[state.id]:
+ addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+ for s in historyValue[state.id]:
+ addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ else:
+ defaultHistoryContent[state.parent.id] = state.transition.content
+ for s in state.transition.target:
+ addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+ for s in state.transition.target:
+ addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ else:
+ statesToEnter.add(state)
+ if isCompoundState(state):
+ statesForDefaultEntry.add(state)
+ for s in state.initial.transition.target:
+ addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+ for s in state.initial.transition.target:
+ addAncestorStatesToEnter(s, state, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ else:
+ if isParallelState(state):
+ for child in getChildStates(state):
+ if not statesToEnter.some(lambda s: isDescendant(s,child)):
+ addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+*/
+void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry)
+{
+ if (QHistoryState *h = toHistoryState(state)) {
+ const QList<QAbstractState*> historyConfiguration = QHistoryStatePrivate::get(h)->configuration;
+ if (!historyConfiguration.isEmpty()) {
+ for (QAbstractState *s : historyConfiguration)
+ addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
+ for (QAbstractState *s : historyConfiguration)
+ addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry);
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": restoring"
+ << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
+ << "history from" << state << ':' << historyConfiguration;
+#endif
+ } else {
+ QList<QAbstractState*> defaultHistoryContent;
+ if (QAbstractTransition *t = QHistoryStatePrivate::get(h)->defaultTransition)
+ defaultHistoryContent = t->targetStates();
+
+ if (defaultHistoryContent.isEmpty()) {
+ setError(QStateMachine::NoDefaultStateInHistoryStateError, h);
+ } else {
+ for (QAbstractState *s : std::as_const(defaultHistoryContent))
+ addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
+ for (QAbstractState *s : std::as_const(defaultHistoryContent))
+ addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": initial history targets for" << state << ':' << defaultHistoryContent;
+#endif
+ }
+ }
+ } else {
+ if (state == rootState()) {
+ // Error has already been set by exitStates().
+ Q_ASSERT(error != QStateMachine::NoError);
+ return;
+ }
+ statesToEnter.insert(state);
+ if (isCompound(state)) {
+ statesForDefaultEntry.insert(state);
+ if (QAbstractState *initial = toStandardState(state)->initialState()) {
+ Q_ASSERT(initial->machine() == q_func());
+
+ // FIXME:
+ // Qt does not support initial transitions (which is a problem for parallel states).
+ // The way it simulates this for other states, is by having a single initial state.
+ // See also the FIXME in enterStates.
+ statesForDefaultEntry.insert(initial);
+
+ addDescendantStatesToEnter(initial, statesToEnter, statesForDefaultEntry);
+ addAncestorStatesToEnter(initial, state, statesToEnter, statesForDefaultEntry);
+ } else {
+ setError(QStateMachine::NoInitialStateError, state);
+ return;
+ }
+ } else if (isParallel(state)) {
+ QState *grp = toStandardState(state);
+ const auto childStates = QStatePrivate::get(grp)->childStates();
+ for (QAbstractState *child : childStates) {
+ if (!containsDecendantOf(statesToEnter, child))
+ addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+}
+
+
+/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+procedure addAncestorStatesToEnter(state, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ for anc in getProperAncestors(state,ancestor):
+ statesToEnter.add(anc)
+ if isParallelState(anc):
+ for child in getChildStates(anc):
+ if not statesToEnter.some(lambda s: isDescendant(s,child)):
+ addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+*/
+void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry)
+{
+ const auto properAncestors = getProperAncestors(s, ancestor);
+ for (QState *anc : properAncestors) {
+ if (!anc->parentState())
+ continue;
+ statesToEnter.insert(anc);
+ if (isParallel(anc)) {
+ const auto childStates = QStatePrivate::get(anc)->childStates();
+ for (QAbstractState *child : childStates) {
+ if (!containsDecendantOf(statesToEnter, child))
+ addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+}
+
+bool QStateMachinePrivate::isFinal(const QAbstractState *s)
+{
+ return s && (QAbstractStatePrivate::get(s)->stateType == QAbstractStatePrivate::FinalState);
+}
+
+bool QStateMachinePrivate::isParallel(const QAbstractState *s)
+{
+ const QState *ss = toStandardState(s);
+ return ss && (QStatePrivate::get(ss)->childMode == QState::ParallelStates);
+}
+
+bool QStateMachinePrivate::isCompound(const QAbstractState *s) const
+{
+ const QState *group = toStandardState(s);
+ if (!group)
+ return false;
+ bool isMachine = QStatePrivate::get(group)->isMachine;
+ // Don't treat the machine as compound if it's a sub-state of this machine
+ if (isMachine && (group != rootState()))
+ return false;
+ return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty());
+}
+
+bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const
+{
+ const QState *ss = toStandardState(s);
+ return (ss && QStatePrivate::get(ss)->childStates().isEmpty())
+ || isFinal(s)
+ // Treat the machine as atomic if it's a sub-state of this machine
+ || (ss && QStatePrivate::get(ss)->isMachine && (ss != rootState()));
+}
+
+QState *QStateMachinePrivate::toStandardState(QAbstractState *state)
+{
+ if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::StandardState))
+ return static_cast<QState*>(state);
+ return nullptr;
+}
+
+const QState *QStateMachinePrivate::toStandardState(const QAbstractState *state)
+{
+ if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::StandardState))
+ return static_cast<const QState*>(state);
+ return nullptr;
+}
+
+QFinalState *QStateMachinePrivate::toFinalState(QAbstractState *state)
+{
+ if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::FinalState))
+ return static_cast<QFinalState*>(state);
+ return nullptr;
+}
+
+QHistoryState *QStateMachinePrivate::toHistoryState(QAbstractState *state)
+{
+ if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::HistoryState))
+ return static_cast<QHistoryState*>(state);
+ return nullptr;
+}
+
+bool QStateMachinePrivate::isInFinalState(QAbstractState* s) const
+{
+ if (isCompound(s)) {
+ QState *grp = toStandardState(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *cs = lst.at(i);
+ if (isFinal(cs) && configuration.contains(cs))
+ return true;
+ }
+ return false;
+ } else if (isParallel(s)) {
+ QState *grp = toStandardState(s);
+ QList<QAbstractState*> lst = QStatePrivate::get(grp)->childStates();
+ for (int i = 0; i < lst.size(); ++i) {
+ QAbstractState *cs = lst.at(i);
+ if (!isInFinalState(cs))
+ return false;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+#ifndef QT_NO_PROPERTIES
+
+/*!
+ \internal
+ Returns \c true if the given state has saved the value of the given property,
+ otherwise returns \c false.
+*/
+bool QStateMachinePrivate::hasRestorable(QAbstractState *state, QObject *object,
+ const QByteArray &propertyName) const
+{
+ RestorableId id(object, propertyName);
+ return registeredRestorablesForState.value(state).contains(id);
+}
+
+/*!
+ \internal
+ Returns the value to save for the property identified by \a id.
+ If an exited state (member of \a exitedStates_sorted) has saved a value for
+ the property, the saved value from the last (outermost) state that will be
+ exited is returned (in practice carrying the saved value on to the next
+ state). Otherwise, the current value of the property is returned.
+*/
+QVariant QStateMachinePrivate::savedValueForRestorable(const QList<QAbstractState*> &exitedStates_sorted,
+ QObject *object, const QByteArray &propertyName) const
+{
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ qDebug() << q_func() << ": savedValueForRestorable(" << exitedStates_sorted << object << propertyName << ')';
+#endif
+ for (int i = exitedStates_sorted.size() - 1; i >= 0; --i) {
+ QAbstractState *s = exitedStates_sorted.at(i);
+ QHash<RestorableId, QVariant> restorables = registeredRestorablesForState.value(s);
+ QHash<RestorableId, QVariant>::const_iterator it = restorables.constFind(RestorableId(object, propertyName));
+ if (it != restorables.constEnd()) {
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ qDebug() << q_func() << ": using" << it.value() << "from" << s;
+#endif
+ return it.value();
+ }
+ }
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ qDebug() << q_func() << ": falling back to current value";
+#endif
+ return object->property(propertyName);
+}
+
+void QStateMachinePrivate::registerRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName,
+ const QVariant &value)
+{
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ qDebug() << q_func() << ": registerRestorable(" << state << object << propertyName << value << ')';
+#endif
+ RestorableId id(object, propertyName);
+ QHash<RestorableId, QVariant> &restorables = registeredRestorablesForState[state];
+ if (!restorables.contains(id))
+ restorables.insert(id, value);
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ else
+ qDebug() << q_func() << ": (already registered)";
+#endif
+}
+
+void QStateMachinePrivate::unregisterRestorables(const QList<QAbstractState *> &states, QObject *object,
+ const QByteArray &propertyName)
+{
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ qDebug() << q_func() << ": unregisterRestorables(" << states << object << propertyName << ')';
+#endif
+ RestorableId id(object, propertyName);
+ for (int i = 0; i < states.size(); ++i) {
+ QAbstractState *s = states.at(i);
+ QHash<QAbstractState*, QHash<RestorableId, QVariant> >::iterator it;
+ it = registeredRestorablesForState.find(s);
+ if (it == registeredRestorablesForState.end())
+ continue;
+ QHash<RestorableId, QVariant> &restorables = it.value();
+ const auto it2 = restorables.constFind(id);
+ if (it2 == restorables.cend())
+ continue;
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ qDebug() << q_func() << ": unregistered for" << s;
+#endif
+ restorables.erase(it2);
+ if (restorables.isEmpty())
+ registeredRestorablesForState.erase(it);
+ }
+}
+
+QList<QPropertyAssignment> QStateMachinePrivate::restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const
+{
+ QList<QPropertyAssignment> result;
+ QHash<RestorableId, QVariant>::const_iterator it;
+ for (it = restorables.constBegin(); it != restorables.constEnd(); ++it) {
+ const RestorableId &id = it.key();
+ if (!id.object()) {
+ // Property object was deleted
+ continue;
+ }
+#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+ qDebug() << q_func() << ": restoring" << id.object() << id.proertyName() << "to" << it.value();
+#endif
+ result.append(QPropertyAssignment(id.object(), id.propertyName(), it.value(), /*explicitlySet=*/false));
+ }
+ return result;
+}
+
+/*!
+ \internal
+ Computes the set of properties whose values should be restored given that
+ the states \a statesToExit_sorted will be exited.
+
+ If a particular (object, propertyName) pair occurs more than once (i.e.,
+ because nested states are being exited), the value from the last (outermost)
+ exited state takes precedence.
+
+ The result of this function must be filtered according to the explicit
+ property assignments (QState::assignProperty()) of the entered states
+ before the property restoration is actually performed; i.e., if an entered
+ state assigns to a property that would otherwise be restored, that property
+ should not be restored after all, but the saved value from the exited state
+ should be remembered by the entered state (see registerRestorable()).
+*/
+QHash<QStateMachinePrivate::RestorableId, QVariant> QStateMachinePrivate::computePendingRestorables(
+ const QList<QAbstractState*> &statesToExit_sorted) const
+{
+ QHash<QStateMachinePrivate::RestorableId, QVariant> restorables;
+ for (int i = statesToExit_sorted.size() - 1; i >= 0; --i) {
+ QAbstractState *s = statesToExit_sorted.at(i);
+ QHash<QStateMachinePrivate::RestorableId, QVariant> rs = registeredRestorablesForState.value(s);
+ QHash<QStateMachinePrivate::RestorableId, QVariant>::const_iterator it;
+ for (it = rs.constBegin(); it != rs.constEnd(); ++it) {
+ if (!restorables.contains(it.key()))
+ restorables.insert(it.key(), it.value());
+ }
+ }
+ return restorables;
+}
+
+/*!
+ \internal
+ Computes the ordered sets of property assignments for the states to be
+ entered, \a statesToEnter_sorted. Also filters \a pendingRestorables (removes
+ properties that should not be restored because they are assigned by an
+ entered state).
+*/
+QHash<QAbstractState *, QList<QPropertyAssignment>> QStateMachinePrivate::computePropertyAssignments(
+ const QList<QAbstractState*> &statesToEnter_sorted, QHash<RestorableId, QVariant> &pendingRestorables) const
+{
+ QHash<QAbstractState *, QList<QPropertyAssignment>> assignmentsForState;
+ for (int i = 0; i < statesToEnter_sorted.size(); ++i) {
+ QState *s = toStandardState(statesToEnter_sorted.at(i));
+ if (!s)
+ continue;
+
+ QList<QPropertyAssignment> &assignments = QStatePrivate::get(s)->propertyAssignments;
+ for (int j = 0; j < assignments.size(); ++j) {
+ const QPropertyAssignment &assn = assignments.at(j);
+ if (assn.objectDeleted()) {
+ assignments.removeAt(j--);
+ } else {
+ pendingRestorables.remove(RestorableId(assn.object, assn.propertyName));
+ assignmentsForState[s].append(assn);
+ }
+ }
+ }
+ return assignmentsForState;
+}
+
+#endif // QT_NO_PROPERTIES
+
+QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context)
+{
+ // Find error state recursively in parent hierarchy if not set explicitly for context state
+ QAbstractState *errorState = nullptr;
+ if (context != nullptr) {
+ QState *s = toStandardState(context);
+ if (s != nullptr)
+ errorState = s->errorState();
+
+ if (errorState == nullptr)
+ errorState = findErrorState(context->parentState());
+ }
+
+ return errorState;
+}
+
+void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractState *currentContext)
+{
+ Q_Q(QStateMachine);
+
+ error = errorCode;
+ switch (errorCode) {
+ case QStateMachine::NoInitialStateError:
+ Q_ASSERT(currentContext != nullptr);
+
+ errorString = QStateMachine::tr("Missing initial state in compound state '%1'")
+ .arg(currentContext->objectName());
+
+ break;
+ case QStateMachine::NoDefaultStateInHistoryStateError:
+ Q_ASSERT(currentContext != nullptr);
+
+ errorString = QStateMachine::tr("Missing default state in history state '%1'")
+ .arg(currentContext->objectName());
+ break;
+
+ case QStateMachine::NoCommonAncestorForTransitionError:
+ Q_ASSERT(currentContext != nullptr);
+
+ errorString = QStateMachine::tr("No common ancestor for targets and source of transition from state '%1'")
+ .arg(currentContext->objectName());
+ break;
+
+ case QStateMachine::StateMachineChildModeSetToParallelError:
+ Q_ASSERT(currentContext != nullptr);
+
+ errorString = QStateMachine::tr("Child mode of state machine '%1' is not 'ExclusiveStates'.")
+ .arg(currentContext->objectName());
+ break;
+
+ default:
+ errorString = QStateMachine::tr("Unknown error");
+ };
+
+ pendingErrorStates.clear();
+ pendingErrorStatesForDefaultEntry.clear();
+
+ QAbstractState *currentErrorState = findErrorState(currentContext);
+
+ // Avoid infinite loop if the error state itself has an error
+ if (currentContext == currentErrorState)
+ currentErrorState = nullptr;
+
+ Q_ASSERT(currentErrorState != rootState());
+
+ if (currentErrorState != nullptr) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": entering error state" << currentErrorState << "from" << currentContext;
+#endif
+ pendingErrorStates.insert(currentErrorState);
+ addDescendantStatesToEnter(currentErrorState, pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ addAncestorStatesToEnter(currentErrorState, rootState(), pendingErrorStates, pendingErrorStatesForDefaultEntry);
+ pendingErrorStates -= configuration;
+ } else {
+ qWarning("Unrecoverable error detected in running state machine: %ls",
+ qUtf16Printable(errorString));
+ q->stop();
+ }
+}
+
+#if QT_CONFIG(animation)
+
+QStateMachinePrivate::InitializeAnimationResult
+QStateMachinePrivate::initializeAnimation(QAbstractAnimation *abstractAnimation,
+ const QPropertyAssignment &prop)
+{
+ InitializeAnimationResult result;
+ QAnimationGroup *group = qobject_cast<QAnimationGroup*>(abstractAnimation);
+ if (group) {
+ for (int i = 0; i < group->animationCount(); ++i) {
+ QAbstractAnimation *animationChild = group->animationAt(i);
+ const auto ret = initializeAnimation(animationChild, prop);
+ result.handledAnimations << ret.handledAnimations;
+ result.localResetEndValues << ret.localResetEndValues;
+ }
+ } else {
+ QPropertyAnimation *animation = qobject_cast<QPropertyAnimation *>(abstractAnimation);
+ if (animation != nullptr
+ && prop.object == animation->targetObject()
+ && prop.propertyName == animation->propertyName()) {
+
+ // Only change end value if it is undefined
+ if (!animation->endValue().isValid()) {
+ animation->setEndValue(prop.value);
+ result.localResetEndValues.append(animation);
+ }
+ result.handledAnimations.append(animation);
+ }
+ }
+ return result;
+}
+
+void QStateMachinePrivate::_q_animationFinished()
+{
+ Q_Q(QStateMachine);
+ QAbstractAnimation *anim = qobject_cast<QAbstractAnimation*>(q->sender());
+ Q_ASSERT(anim != nullptr);
+ QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished()));
+ if (resetAnimationEndValues.contains(anim)) {
+ qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize
+ resetAnimationEndValues.remove(anim);
+ }
+
+ QAbstractState *state = stateForAnimation.take(anim);
+ Q_ASSERT(state != nullptr);
+
+#ifndef QT_NO_PROPERTIES
+ // Set the final property value.
+ QPropertyAssignment assn = propertyForAnimation.take(anim);
+ assn.write();
+ if (!assn.explicitlySet)
+ unregisterRestorables(QList<QAbstractState*>() << state, assn.object, assn.propertyName);
+#endif
+
+ QHash<QAbstractState*, QList<QAbstractAnimation*> >::iterator it;
+ it = animationsForState.find(state);
+ Q_ASSERT(it != animationsForState.end());
+ QList<QAbstractAnimation*> &animations = it.value();
+ animations.removeOne(anim);
+ if (animations.isEmpty()) {
+ animationsForState.erase(it);
+ QStatePrivate::get(toStandardState(state))->emitPropertiesAssigned();
+ }
+}
+
+QList<QAbstractAnimation *> QStateMachinePrivate::selectAnimations(const QList<QAbstractTransition *> &transitionList) const
+{
+ QList<QAbstractAnimation *> selectedAnimations;
+ if (animated) {
+ for (int i = 0; i < transitionList.size(); ++i) {
+ QAbstractTransition *transition = transitionList.at(i);
+
+ selectedAnimations << transition->animations();
+ selectedAnimations << defaultAnimationsForSource.values(transition->sourceState());
+
+ QList<QAbstractState *> targetStates = transition->targetStates();
+ for (int j=0; j<targetStates.size(); ++j)
+ selectedAnimations << defaultAnimationsForTarget.values(targetStates.at(j));
+ }
+ selectedAnimations << defaultAnimations;
+ }
+ return selectedAnimations;
+}
+
+void QStateMachinePrivate::terminateActiveAnimations(QAbstractState *state,
+ const QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates)
+{
+ Q_Q(QStateMachine);
+ QList<QAbstractAnimation*> animations = animationsForState.take(state);
+ for (int i = 0; i < animations.size(); ++i) {
+ QAbstractAnimation *anim = animations.at(i);
+ QObject::disconnect(anim, SIGNAL(finished()), q, SLOT(_q_animationFinished()));
+ stateForAnimation.remove(anim);
+
+ // Stop the (top-level) animation.
+ // ### Stopping nested animation has weird behavior.
+ QAbstractAnimation *topLevelAnim = anim;
+ while (QAnimationGroup *group = topLevelAnim->group())
+ topLevelAnim = group;
+ topLevelAnim->stop();
+
+ if (resetAnimationEndValues.contains(anim)) {
+ qobject_cast<QVariantAnimation*>(anim)->setEndValue(QVariant()); // ### generalize
+ resetAnimationEndValues.remove(anim);
+ }
+ QPropertyAssignment assn = propertyForAnimation.take(anim);
+ Q_ASSERT(assn.object != nullptr);
+ // If there is no property assignment that sets this property,
+ // set the property to its target value.
+ bool found = false;
+ for (auto it = assignmentsForEnteredStates.constBegin(); it != assignmentsForEnteredStates.constEnd(); ++it) {
+ const QList<QPropertyAssignment> &assignments = it.value();
+ for (int j = 0; j < assignments.size(); ++j) {
+ if (assignments.at(j).hasTarget(assn.object, assn.propertyName)) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ assn.write();
+ if (!assn.explicitlySet)
+ unregisterRestorables(QList<QAbstractState*>() << state, assn.object, assn.propertyName);
+ }
+ }
+}
+
+void QStateMachinePrivate::initializeAnimations(QAbstractState *state, const QList<QAbstractAnimation *> &selectedAnimations,
+ const QList<QAbstractState*> &exitedStates_sorted,
+ QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates)
+{
+ Q_Q(QStateMachine);
+ if (!assignmentsForEnteredStates.contains(state))
+ return;
+ QList<QPropertyAssignment> &assignments = assignmentsForEnteredStates[state];
+ for (int i = 0; i < selectedAnimations.size(); ++i) {
+ QAbstractAnimation *anim = selectedAnimations.at(i);
+ for (auto it = assignments.begin(); it != assignments.end(); ) {
+ const QPropertyAssignment &assn = *it;
+ const auto ret = initializeAnimation(anim, assn);
+ if (!ret.handledAnimations.isEmpty()) {
+ for (int j = 0; j < ret.handledAnimations.size(); ++j) {
+ QAbstractAnimation *a = ret.handledAnimations.at(j);
+ propertyForAnimation.insert(a, assn);
+ stateForAnimation.insert(a, state);
+ animationsForState[state].append(a);
+ // ### connect to just the top-level animation?
+ QObject::connect(a, SIGNAL(finished()), q, SLOT(_q_animationFinished()), Qt::UniqueConnection);
+ }
+ if ((globalRestorePolicy == QState::RestoreProperties)
+ && !hasRestorable(state, assn.object, assn.propertyName)) {
+ QVariant value = savedValueForRestorable(exitedStates_sorted, assn.object, assn.propertyName);
+ unregisterRestorables(exitedStates_sorted, assn.object, assn.propertyName);
+ registerRestorable(state, assn.object, assn.propertyName, value);
+ }
+ it = assignments.erase(it);
+ } else {
+ ++it;
+ }
+ for (int j = 0; j < ret.localResetEndValues.size(); ++j)
+ resetAnimationEndValues.insert(ret.localResetEndValues.at(j));
+ }
+ // We require that at least one animation is valid.
+ // ### generalize
+ QList<QVariantAnimation*> variantAnims = anim->findChildren<QVariantAnimation*>();
+ if (QVariantAnimation *va = qobject_cast<QVariantAnimation*>(anim))
+ variantAnims.append(va);
+
+ bool hasValidEndValue = false;
+ for (int j = 0; j < variantAnims.size(); ++j) {
+ if (variantAnims.at(j)->endValue().isValid()) {
+ hasValidEndValue = true;
+ break;
+ }
+ }
+
+ if (hasValidEndValue) {
+ if (anim->state() == QAbstractAnimation::Running) {
+ // The animation is still running. This can happen if the
+ // animation is a group, and one of its children just finished,
+ // and that caused a state to emit its propertiesAssigned() signal, and
+ // that triggered a transition in the machine.
+ // Just stop the animation so it is correctly restarted again.
+ anim->stop();
+ }
+ anim->start();
+ }
+
+ if (assignments.isEmpty()) {
+ assignmentsForEnteredStates.remove(state);
+ break;
+ }
+ }
+}
+
+#endif // animation
+
+QAbstractTransition *QStateMachinePrivate::createInitialTransition() const
+{
+ class InitialTransition : public QAbstractTransition
+ {
+ public:
+ InitialTransition(const QList<QAbstractState *> &targets)
+ : QAbstractTransition()
+ { setTargetStates(targets); }
+ protected:
+ bool eventTest(QEvent *) override { return true; }
+ void onTransition(QEvent *) override {}
+ };
+
+ QState *root = rootState();
+ Q_ASSERT(root != nullptr);
+ QList<QAbstractState *> targets;
+ switch (root->childMode()) {
+ case QState::ExclusiveStates:
+ targets.append(root->initialState());
+ break;
+ case QState::ParallelStates:
+ targets = QStatePrivate::get(root)->childStates();
+ break;
+ }
+ return new InitialTransition(targets);
+}
+
+void QStateMachinePrivate::clearHistory()
+{
+ Q_Q(QStateMachine);
+ QList<QHistoryState*> historyStates = q->findChildren<QHistoryState*>();
+ for (int i = 0; i < historyStates.size(); ++i) {
+ QHistoryState *h = historyStates.at(i);
+ QHistoryStatePrivate::get(h)->configuration.clear();
+ }
+}
+
+/*!
+ \internal
+
+ Registers all signal transitions whose sender object lives in another thread.
+
+ Normally, signal transitions are lazily registered (when a state becomes
+ active). But if the sender is in a different thread, the transition must be
+ registered early to keep the state machine from "dropping" signals; e.g.,
+ a second (transition-bound) signal could be emitted on the sender thread
+ before the state machine gets to process the first signal.
+*/
+void QStateMachinePrivate::registerMultiThreadedSignalTransitions()
+{
+ Q_Q(QStateMachine);
+ QList<QSignalTransition*> transitions = rootState()->findChildren<QSignalTransition*>();
+ for (int i = 0; i < transitions.size(); ++i) {
+ QSignalTransition *t = transitions.at(i);
+ if ((t->machine() == q) && t->senderObject() && (t->senderObject()->thread() != q->thread()))
+ registerSignalTransition(t);
+ }
+}
+
+void QStateMachinePrivate::_q_start()
+{
+ Q_Q(QStateMachine);
+ Q_ASSERT(state == Starting);
+ // iterate over a copy, since we emit signals which may cause
+ // 'configuration' to change, resulting in undefined behavior when
+ // iterating at the same time:
+ const auto config = configuration;
+ for (QAbstractState *state : config) {
+ QAbstractStatePrivate *abstractStatePrivate = QAbstractStatePrivate::get(state);
+ abstractStatePrivate->active.setValue(false);
+ }
+ configuration.clear();
+ qDeleteAll(internalEventQueue);
+ internalEventQueue.clear();
+ qDeleteAll(externalEventQueue);
+ externalEventQueue.clear();
+ clearHistory();
+
+ registerMultiThreadedSignalTransitions();
+
+ startupHook();
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": starting";
+#endif
+ state = Running;
+ processingScheduled = true; // we call _q_process() below
+
+ QList<QAbstractTransition*> transitions;
+ CalculationCache calculationCache;
+ QAbstractTransition *initialTransition = createInitialTransition();
+ transitions.append(initialTransition);
+
+ QEvent nullEvent(QEvent::None);
+ executeTransitionContent(&nullEvent, transitions);
+ QList<QAbstractState*> exitedStates = QList<QAbstractState*>();
+ QSet<QAbstractState*> statesForDefaultEntry;
+ QList<QAbstractState*> enteredStates = computeEntrySet(transitions, statesForDefaultEntry, &calculationCache);
+ QHash<RestorableId, QVariant> pendingRestorables;
+ QHash<QAbstractState *, QList<QPropertyAssignment>> assignmentsForEnteredStates =
+ computePropertyAssignments(enteredStates, pendingRestorables);
+#if QT_CONFIG(animation)
+ QList<QAbstractAnimation *> selectedAnimations = selectAnimations(transitions);
+#endif
+ // enterStates() will set stopProcessingReason to Finished if a final
+ // state is entered.
+ stopProcessingReason = EventQueueEmpty;
+ enterStates(&nullEvent, exitedStates, enteredStates, statesForDefaultEntry,
+ assignmentsForEnteredStates
+#if QT_CONFIG(animation)
+ , selectedAnimations
+#endif
+ );
+ delete initialTransition;
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": initial configuration:" << configuration;
+#endif
+
+ emit q->started(QStateMachine::QPrivateSignal());
+ emit q->runningChanged(true);
+
+ if (stopProcessingReason == Finished) {
+ // The state machine immediately reached a final state.
+ processingScheduled = false;
+ state = NotRunning;
+ unregisterAllTransitions();
+ emitFinished();
+ emit q->runningChanged(false);
+ exitInterpreter();
+ } else {
+ _q_process();
+ }
+}
+
+void QStateMachinePrivate::_q_process()
+{
+ Q_Q(QStateMachine);
+ Q_ASSERT(state == Running);
+ Q_ASSERT(!processing);
+ processing = true;
+ processingScheduled = false;
+ beginMacrostep();
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": starting the event processing loop";
+#endif
+ bool didChange = false;
+ while (processing) {
+ if (stop) {
+ processing = false;
+ break;
+ }
+ QList<QAbstractTransition*> enabledTransitions;
+ CalculationCache calculationCache;
+
+ QEvent *e = new QEvent(QEvent::None);
+ enabledTransitions = selectTransitions(e, &calculationCache);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = nullptr;
+ }
+ while (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != nullptr)) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": dequeued internal event" << e << "of type" << e->type();
+#endif
+ enabledTransitions = selectTransitions(e, &calculationCache);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = nullptr;
+ }
+ }
+ while (enabledTransitions.isEmpty() && ((e = dequeueExternalEvent()) != nullptr)) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": dequeued external event" << e << "of type" << e->type();
+#endif
+ enabledTransitions = selectTransitions(e, &calculationCache);
+ if (enabledTransitions.isEmpty()) {
+ delete e;
+ e = nullptr;
+ }
+ }
+ if (enabledTransitions.isEmpty()) {
+ if (isInternalEventQueueEmpty()) {
+ processing = false;
+ stopProcessingReason = EventQueueEmpty;
+ noMicrostep();
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": no transitions enabled";
+#endif
+ }
+ } else {
+ didChange = true;
+ q->beginMicrostep(e);
+ microstep(e, enabledTransitions, &calculationCache);
+ q->endMicrostep(e);
+ }
+ delete e;
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": finished the event processing loop";
+#endif
+ if (stop) {
+ stop = false;
+ stopProcessingReason = Stopped;
+ }
+
+ switch (stopProcessingReason) {
+ case EventQueueEmpty:
+ processedPendingEvents(didChange);
+ break;
+ case Finished:
+ state = NotRunning;
+ cancelAllDelayedEvents();
+ unregisterAllTransitions();
+ emitFinished();
+ emit q->runningChanged(false);
+ break;
+ case Stopped:
+ state = NotRunning;
+ cancelAllDelayedEvents();
+ unregisterAllTransitions();
+ emit q->stopped(QStateMachine::QPrivateSignal());
+ emit q->runningChanged(false);
+ break;
+ }
+ endMacrostep(didChange);
+ if (stopProcessingReason == Finished)
+ exitInterpreter();
+}
+
+void QStateMachinePrivate::_q_startDelayedEventTimer(int id, int delay)
+{
+ Q_Q(QStateMachine);
+ QMutexLocker locker(&delayedEventsMutex);
+ QHash<int, DelayedEvent>::iterator it = delayedEvents.find(id);
+ if (it != delayedEvents.end()) {
+ DelayedEvent &e = it.value();
+ Q_ASSERT(!e.timerId);
+ e.timerId = q->startTimer(delay);
+ if (!e.timerId) {
+ qWarning("QStateMachine::postDelayedEvent: failed to start timer (id=%d, delay=%d)", id, delay);
+ delete e.event;
+ delayedEvents.erase(it);
+ delayedEventIdFreeList.release(id);
+ } else {
+ timerIdToDelayedEventId.insert(e.timerId, id);
+ }
+ } else {
+ // It's been cancelled already
+ delayedEventIdFreeList.release(id);
+ }
+}
+
+void QStateMachinePrivate::_q_killDelayedEventTimer(int id, int timerId)
+{
+ Q_Q(QStateMachine);
+ q->killTimer(timerId);
+ QMutexLocker locker(&delayedEventsMutex);
+ delayedEventIdFreeList.release(id);
+}
+
+void QStateMachinePrivate::postInternalEvent(QEvent *e)
+{
+ QMutexLocker locker(&internalEventMutex);
+ internalEventQueue.append(e);
+}
+
+void QStateMachinePrivate::postExternalEvent(QEvent *e)
+{
+ QMutexLocker locker(&externalEventMutex);
+ externalEventQueue.append(e);
+}
+
+QEvent *QStateMachinePrivate::dequeueInternalEvent()
+{
+ QMutexLocker locker(&internalEventMutex);
+ if (internalEventQueue.isEmpty())
+ return nullptr;
+ return internalEventQueue.takeFirst();
+}
+
+QEvent *QStateMachinePrivate::dequeueExternalEvent()
+{
+ QMutexLocker locker(&externalEventMutex);
+ if (externalEventQueue.isEmpty())
+ return nullptr;
+ return externalEventQueue.takeFirst();
+}
+
+bool QStateMachinePrivate::isInternalEventQueueEmpty()
+{
+ QMutexLocker locker(&internalEventMutex);
+ return internalEventQueue.isEmpty();
+}
+
+bool QStateMachinePrivate::isExternalEventQueueEmpty()
+{
+ QMutexLocker locker(&externalEventMutex);
+ return externalEventQueue.isEmpty();
+}
+
+void QStateMachinePrivate::processEvents(EventProcessingMode processingMode)
+{
+ Q_Q(QStateMachine);
+ if ((state != Running) || processing || processingScheduled)
+ return;
+ switch (processingMode) {
+ case DirectProcessing:
+ if (QThread::currentThread() == q->thread()) {
+ _q_process();
+ break;
+ }
+ // processing must be done in the machine thread, so:
+ Q_FALLTHROUGH();
+ case QueuedProcessing:
+ processingScheduled = true;
+ QMetaObject::invokeMethod(q, "_q_process", Qt::QueuedConnection);
+ break;
+ }
+}
+
+void QStateMachinePrivate::cancelAllDelayedEvents()
+{
+ Q_Q(QStateMachine);
+ QMutexLocker locker(&delayedEventsMutex);
+ QHash<int, DelayedEvent>::const_iterator it;
+ for (it = delayedEvents.constBegin(); it != delayedEvents.constEnd(); ++it) {
+ const DelayedEvent &e = it.value();
+ if (e.timerId) {
+ timerIdToDelayedEventId.remove(e.timerId);
+ q->killTimer(e.timerId);
+ delayedEventIdFreeList.release(it.key());
+ } else {
+ // Cancellation will be detected in pending _q_startDelayedEventTimer() call
+ }
+ delete e.event;
+ }
+ delayedEvents.clear();
+}
+
+/*
+ This function is called when the state machine is performing no
+ microstep because no transition is enabled (i.e. an event is ignored).
+
+ The default implementation does nothing.
+*/
+void QStateMachinePrivate::noMicrostep()
+{ }
+
+/*
+ This function is called when the state machine has reached a stable
+ state (no pending events), and has not finished yet.
+ For each event the state machine receives it is guaranteed that
+ 1) beginMacrostep is called
+ 2) selectTransition is called at least once
+ 3) begin/endMicrostep is called at least once or noMicrostep is called
+ at least once (possibly both, but at least one)
+ 4) the state machine either enters an infinite loop, or stops (runningChanged(false),
+ and either finished or stopped are emitted), or processedPendingEvents() is called.
+ 5) if the machine is not in an infinite loop endMacrostep is called
+ 6) when the machine is finished and all processing (like signal emission) is done,
+ exitInterpreter() is called. (This is the same name as the SCXML specification uses.)
+
+ didChange is set to true if at least one microstep was performed, it is possible
+ that the machine returned to exactly the same state as before, but some transitions
+ were triggered.
+
+ The default implementation does nothing.
+*/
+void QStateMachinePrivate::processedPendingEvents(bool didChange)
+{
+ Q_UNUSED(didChange);
+}
+
+void QStateMachinePrivate::beginMacrostep()
+{ }
+
+void QStateMachinePrivate::endMacrostep(bool didChange)
+{
+ Q_UNUSED(didChange);
+}
+
+void QStateMachinePrivate::exitInterpreter()
+{
+}
+
+void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guiltyState)
+{
+ Q_UNUSED(guiltyState);
+ Q_ASSERT(guiltyState);
+
+#ifdef QSTATEMACHINE_DEBUG
+ Q_Q(QStateMachine);
+ qDebug() << q << ": emitting finished signal for" << forState;
+#endif
+
+ QStatePrivate::get(forState)->emitFinished();
+}
+
+void QStateMachinePrivate::startupHook()
+{
+}
+
+namespace _QStateMachine_Internal{
+
+class GoToStateTransition : public QAbstractTransition
+{
+ Q_OBJECT
+public:
+ GoToStateTransition(QAbstractState *target)
+ : QAbstractTransition()
+ { setTargetState(target); }
+protected:
+ void onTransition(QEvent *) override { deleteLater(); }
+ bool eventTest(QEvent *) override { return true; }
+};
+
+} // namespace
+// mingw compiler tries to export QObject::findChild<GoToStateTransition>(),
+// which doesn't work if its in an anonymous namespace.
+using namespace _QStateMachine_Internal;
+/*!
+ \internal
+
+ Causes this state machine to unconditionally transition to the given
+ \a targetState.
+
+ Provides a backdoor for using the state machine "imperatively"; i.e. rather
+ than defining explicit transitions, you drive the machine's execution by
+ calling this function. It breaks the whole integrity of the
+ transition-driven model, but is provided for pragmatic reasons.
+*/
+void QStateMachinePrivate::goToState(QAbstractState *targetState)
+{
+ if (!targetState) {
+ qWarning("QStateMachine::goToState(): cannot go to null state");
+ return;
+ }
+
+ if (configuration.contains(targetState))
+ return;
+
+ Q_ASSERT(state == Running);
+ QState *sourceState = nullptr;
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ sourceState = toStandardState(*it);
+ if (sourceState != nullptr)
+ break;
+ }
+
+ Q_ASSERT(sourceState != nullptr);
+ // Reuse previous GoToStateTransition in case of several calls to
+ // goToState() in a row.
+ GoToStateTransition *trans = sourceState->findChild<GoToStateTransition*>();
+ if (!trans) {
+ trans = new GoToStateTransition(targetState);
+ sourceState->addTransition(trans);
+ } else {
+ trans->setTargetState(targetState);
+ }
+
+ processEvents(QueuedProcessing);
+}
+
+void QStateMachinePrivate::registerTransitions(QAbstractState *state)
+{
+ QState *group = toStandardState(state);
+ if (!group)
+ return;
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(group)->transitions();
+ for (int i = 0; i < transitions.size(); ++i) {
+ QAbstractTransition *t = transitions.at(i);
+ registerTransition(t);
+ }
+}
+
+void QStateMachinePrivate::maybeRegisterTransition(QAbstractTransition *transition)
+{
+ if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
+ maybeRegisterSignalTransition(st);
+ }
+#if QT_CONFIG(qeventtransition)
+ else if (QEventTransition *et = qobject_cast<QEventTransition*>(transition)) {
+ maybeRegisterEventTransition(et);
+ }
+#endif
+}
+
+void QStateMachinePrivate::registerTransition(QAbstractTransition *transition)
+{
+ if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
+ registerSignalTransition(st);
+ }
+#if QT_CONFIG(qeventtransition)
+ else if (QEventTransition *oet = qobject_cast<QEventTransition*>(transition)) {
+ registerEventTransition(oet);
+ }
+#endif
+}
+
+void QStateMachinePrivate::unregisterTransition(QAbstractTransition *transition)
+{
+ if (QSignalTransition *st = qobject_cast<QSignalTransition*>(transition)) {
+ unregisterSignalTransition(st);
+ }
+#if QT_CONFIG(qeventtransition)
+ else if (QEventTransition *oet = qobject_cast<QEventTransition*>(transition)) {
+ unregisterEventTransition(oet);
+ }
+#endif
+}
+
+void QStateMachinePrivate::maybeRegisterSignalTransition(QSignalTransition *transition)
+{
+ Q_Q(QStateMachine);
+ const QObject *senderObject =
+ QSignalTransitionPrivate::get(transition)->senderObject.valueBypassingBindings();
+ if ((state == Running) && (configuration.contains(transition->sourceState())
+ || (senderObject && (senderObject->thread() != q->thread())))) {
+ registerSignalTransition(transition);
+ }
+}
+
+void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (QSignalTransitionPrivate::get(transition)->signalIndex != -1)
+ return; // already registered
+ const QObject *sender =
+ QSignalTransitionPrivate::get(transition)->senderObject.valueBypassingBindings();
+ if (!sender)
+ return;
+ QByteArray signal = QSignalTransitionPrivate::get(transition)->signal.valueBypassingBindings();
+ if (signal.isEmpty())
+ return;
+ if (signal.startsWith('0'+QSIGNAL_CODE))
+ signal.remove(0, 1);
+ const QMetaObject *meta = sender->metaObject();
+ int signalIndex = meta->indexOfSignal(signal);
+ int originalSignalIndex = signalIndex;
+ if (signalIndex == -1) {
+ signalIndex = meta->indexOfSignal(QMetaObject::normalizedSignature(signal));
+ if (signalIndex == -1) {
+ qWarning("QSignalTransition: no such signal: %s::%s",
+ meta->className(), signal.constData());
+ return;
+ }
+ originalSignalIndex = signalIndex;
+ }
+ // The signal index we actually want to connect to is the one
+ // that is going to be sent, i.e. the non-cloned original index.
+ while (meta->method(signalIndex).attributes() & QMetaMethod::Cloned)
+ --signalIndex;
+
+ connectionsMutex.lock();
+ QList<int> &connectedSignalIndexes = connections[sender];
+ if (connectedSignalIndexes.size() <= signalIndex)
+ connectedSignalIndexes.resize(signalIndex+1);
+ if (connectedSignalIndexes.at(signalIndex) == 0) {
+ if (!signalEventGenerator)
+ signalEventGenerator = new QSignalEventGenerator(q);
+ static const int generatorMethodOffset = QSignalEventGenerator::staticMetaObject.methodOffset();
+ bool ok = QMetaObject::connect(sender, signalIndex, signalEventGenerator, generatorMethodOffset);
+ if (!ok) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": FAILED to add signal transition from" << transition->sourceState()
+ << ": ( sender =" << sender << ", signal =" << signal
+ << ", targets =" << transition->targetStates() << ')';
+#endif
+ return;
+ }
+ }
+ ++connectedSignalIndexes[signalIndex];
+ connectionsMutex.unlock();
+
+ QSignalTransitionPrivate::get(transition)->signalIndex = signalIndex;
+ QSignalTransitionPrivate::get(transition)->originalSignalIndex = originalSignalIndex;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": added signal transition from" << transition->sourceState()
+ << ": ( sender =" << sender << ", signal =" << signal
+ << ", targets =" << transition->targetStates() << ')';
+#endif
+}
+
+void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transition)
+{
+ int signalIndex = QSignalTransitionPrivate::get(transition)->signalIndex;
+ if (signalIndex == -1)
+ return; // not registered
+ const QObject *sender =
+ QSignalTransitionPrivate::get(transition)->senderObject.valueBypassingBindings();
+ QSignalTransitionPrivate::get(transition)->signalIndex = -1;
+
+ connectionsMutex.lock();
+ QList<int> &connectedSignalIndexes = connections[sender];
+ Q_ASSERT(connectedSignalIndexes.size() > signalIndex);
+ Q_ASSERT(connectedSignalIndexes.at(signalIndex) != 0);
+ if (--connectedSignalIndexes[signalIndex] == 0) {
+ Q_ASSERT(signalEventGenerator != nullptr);
+ static const int generatorMethodOffset = QSignalEventGenerator::staticMetaObject.methodOffset();
+ QMetaObject::disconnect(sender, signalIndex, signalEventGenerator, generatorMethodOffset);
+ int sum = 0;
+ for (int i = 0; i < connectedSignalIndexes.size(); ++i)
+ sum += connectedSignalIndexes.at(i);
+ if (sum == 0)
+ connections.remove(sender);
+ }
+ connectionsMutex.unlock();
+}
+
+void QStateMachinePrivate::unregisterAllTransitions()
+{
+ Q_Q(QStateMachine);
+ {
+ QList<QSignalTransition*> transitions = rootState()->findChildren<QSignalTransition*>();
+ for (int i = 0; i < transitions.size(); ++i) {
+ QSignalTransition *t = transitions.at(i);
+ if (t->machine() == q)
+ unregisterSignalTransition(t);
+ }
+ }
+#if QT_CONFIG(qeventtransition)
+ {
+ QList<QEventTransition*> transitions = rootState()->findChildren<QEventTransition*>();
+ for (int i = 0; i < transitions.size(); ++i) {
+ QEventTransition *t = transitions.at(i);
+ if (t->machine() == q)
+ unregisterEventTransition(t);
+ }
+ }
+#endif
+}
+
+#if QT_CONFIG(qeventtransition)
+void QStateMachinePrivate::maybeRegisterEventTransition(QEventTransition *transition)
+{
+ if ((state == Running) && configuration.contains(transition->sourceState()))
+ registerEventTransition(transition);
+}
+
+void QStateMachinePrivate::registerEventTransition(QEventTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (QEventTransitionPrivate::get(transition)->registered)
+ return;
+ const QEvent::Type eventType =
+ QEventTransitionPrivate::get(transition)->eventType.valueBypassingBindings();
+ if (eventType >= QEvent::User) {
+ qWarning("QObject event transitions are not supported for custom types");
+ return;
+ }
+ QObject *object = QEventTransitionPrivate::get(transition)->object.valueBypassingBindings();
+ if (!object)
+ return;
+ QObjectPrivate *od = QObjectPrivate::get(object);
+ if (!od->extraData || !od->extraData->eventFilters.contains(q))
+ object->installEventFilter(q);
+ ++qobjectEvents[object][eventType];
+ QEventTransitionPrivate::get(transition)->registered = true;
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": added event transition from" << transition->sourceState()
+ << ": ( object =" << object << ", event =" << eventType
+ << ", targets =" << transition->targetStates() << ')';
+#endif
+}
+
+void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transition)
+{
+ Q_Q(QStateMachine);
+ if (!QEventTransitionPrivate::get(transition)->registered)
+ return;
+ QObject *object = QEventTransitionPrivate::get(transition)->object.valueBypassingBindings();
+ QHash<QEvent::Type, int> &events = qobjectEvents[object];
+ const QEvent::Type eventType =
+ QEventTransitionPrivate::get(transition)->eventType.valueBypassingBindings();
+ Q_ASSERT(events.value(eventType) > 0);
+ if (--events[eventType] == 0) {
+ events.remove(eventType);
+ int sum = 0;
+ QHash<QEvent::Type, int>::const_iterator it;
+ for (it = events.constBegin(); it != events.constEnd(); ++it)
+ sum += it.value();
+ if (sum == 0) {
+ qobjectEvents.remove(object);
+ object->removeEventFilter(q);
+ }
+ }
+ QEventTransitionPrivate::get(transition)->registered = false;
+}
+
+void QStateMachinePrivate::handleFilteredEvent(QObject *watched, QEvent *event)
+{
+ if (qobjectEvents.value(watched).contains(event->type())) {
+ postInternalEvent(new QStateMachine::WrappedEvent(watched, event->clone()));
+ processEvents(DirectProcessing);
+ }
+}
+#endif
+
+void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalIndex,
+ void **argv)
+{
+#ifndef QT_NO_DEBUG
+ connectionsMutex.lock();
+ Q_ASSERT(connections[sender].at(signalIndex) != 0);
+ connectionsMutex.unlock();
+#endif
+ const QMetaObject *meta = sender->metaObject();
+ QMetaMethod method = meta->method(signalIndex);
+ int argc = method.parameterCount();
+ QList<QVariant> vargs;
+ vargs.reserve(argc);
+ for (int i = 0; i < argc; ++i) {
+ auto type = method.parameterMetaType(i);
+ vargs.append(QVariant(type, argv[i+1]));
+ }
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": sending signal event ( sender =" << sender
+ << ", signal =" << method.methodSignature().constData() << ')';
+#endif
+ postInternalEvent(new QStateMachine::SignalEvent(sender, signalIndex, vargs));
+ processEvents(DirectProcessing);
+}
+
+/*!
+ Constructs a new state machine with the given \a parent.
+*/
+QStateMachine::QStateMachine(QObject *parent)
+ : QState(*new QStateMachinePrivate, /*parentState=*/nullptr)
+{
+ // Can't pass the parent to the QState constructor, as it expects a QState
+ // But this works as expected regardless of whether parent is a QState or not
+ setParent(parent);
+}
+
+/*!
+ \since 5.0
+ \deprecated
+
+ Constructs a new state machine with the given \a childMode
+ and \a parent.
+
+ \warning Do not set the \a childMode to anything else than \l{ExclusiveStates}, otherwise the
+ state machine is invalid, and might work incorrectly.
+*/
+QStateMachine::QStateMachine(QState::ChildMode childMode, QObject *parent)
+ : QState(*new QStateMachinePrivate, /*parentState=*/nullptr)
+{
+ Q_D(QStateMachine);
+ d->childMode = childMode;
+ setParent(parent); // See comment in constructor above
+
+ if (childMode != ExclusiveStates) {
+ //### FIXME for Qt6: remove this constructor completely, and hide the childMode property.
+ // Yes, the StateMachine itself is conceptually a state, but it should only expose a limited
+ // number of properties. The execution algorithm (in the URL below) treats a state machine
+ // as a state, but from an API point of view, it's questionable if the QStateMachine should
+ // inherit from QState.
+ //
+ // See function findLCCA in https://www.w3.org/TR/2014/WD-scxml-20140529/#AlgorithmforSCXMLInterpretation
+ // to see where setting childMode to parallel will break down.
+ qWarning() << "Invalid childMode for QStateMachine" << this;
+ }
+}
+
+/*!
+ \internal
+*/
+QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent)
+ : QState(dd, /*parentState=*/nullptr)
+{
+ setParent(parent);
+}
+
+/*!
+ Destroys this state machine.
+*/
+QStateMachine::~QStateMachine()
+{
+}
+
+/*!
+ \enum QStateMachine::EventPriority
+
+ This enum type specifies the priority of an event posted to the state
+ machine using postEvent().
+
+ Events of high priority are processed before events of normal priority.
+
+ \value NormalPriority The event has normal priority.
+ \value HighPriority The event has high priority.
+*/
+
+/*! \enum QStateMachine::Error
+
+ This enum type defines errors that can occur in the state machine at run time. When the state
+ machine encounters an unrecoverable error at run time, it will set the error code returned
+ by error(), the error message returned by errorString(), and enter an error state based on
+ the context of the error.
+
+ \value NoError No error has occurred.
+ \value NoInitialStateError The machine has entered a QState with children which does not have an
+ initial state set. The context of this error is the state which is missing an initial
+ state.
+ \value NoDefaultStateInHistoryStateError The machine has entered a QHistoryState which does not have
+ a default state set. The context of this error is the QHistoryState which is missing a
+ default state.
+ \value NoCommonAncestorForTransitionError The machine has selected a transition whose source
+ and targets are not part of the same tree of states, and thus are not part of the same
+ state machine. Commonly, this could mean that one of the states has not been given
+ any parent or added to any machine. The context of this error is the source state of
+ the transition.
+ \value StateMachineChildModeSetToParallelError The machine's \l childMode
+ property was set to \l{QState::ParallelStates}. This is illegal.
+ Only states may be declared as parallel, not the state machine
+ itself. This enum value was added in Qt 5.14.
+
+ \sa setErrorState()
+*/
+
+/*!
+ Returns the error code of the last error that occurred in the state machine.
+*/
+QStateMachine::Error QStateMachine::error() const
+{
+ Q_D(const QStateMachine);
+ return d->error;
+}
+
+/*!
+ Returns the error string of the last error that occurred in the state machine.
+*/
+QString QStateMachine::errorString() const
+{
+ Q_D(const QStateMachine);
+ return d->errorString;
+}
+
+/*!
+ Clears the error string and error code of the state machine.
+*/
+void QStateMachine::clearError()
+{
+ Q_D(QStateMachine);
+ d->error = NoError;
+ d->errorString = QString();
+}
+
+QBindable<QString> QStateMachine::bindableErrorString() const
+{
+ Q_D(const QStateMachine);
+ return &d->errorString;
+}
+
+/*!
+ Returns the restore policy of the state machine.
+
+ \sa setGlobalRestorePolicy()
+*/
+QState::RestorePolicy QStateMachine::globalRestorePolicy() const
+{
+ Q_D(const QStateMachine);
+ return d->globalRestorePolicy;
+}
+
+/*!
+ Sets the restore policy of the state machine to \a restorePolicy. The default
+ restore policy is QState::DontRestoreProperties.
+
+ \sa globalRestorePolicy()
+*/
+void QStateMachine::setGlobalRestorePolicy(QState::RestorePolicy restorePolicy)
+{
+ Q_D(QStateMachine);
+ d->globalRestorePolicy = restorePolicy;
+}
+
+QBindable<QState::RestorePolicy> QStateMachine::bindableGlobalRestorePolicy()
+{
+ Q_D(QStateMachine);
+ return &d->globalRestorePolicy;
+}
+
+/*!
+ Adds the given \a state to this state machine. The state becomes a top-level
+ state and the state machine takes ownership of the state.
+
+ If the state is already in a different machine, it will first be removed
+ from its old machine, and then added to this machine.
+
+ \sa removeState(), setInitialState()
+*/
+void QStateMachine::addState(QAbstractState *state)
+{
+ if (!state) {
+ qWarning("QStateMachine::addState: cannot add null state");
+ return;
+ }
+ if (QAbstractStatePrivate::get(state)->machine() == this) {
+ qWarning("QStateMachine::addState: state has already been added to this machine");
+ return;
+ }
+ state->setParent(this);
+}
+
+/*!
+ Removes the given \a state from this state machine. The state machine
+ releases ownership of the state.
+
+ \sa addState()
+*/
+void QStateMachine::removeState(QAbstractState *state)
+{
+ if (!state) {
+ qWarning("QStateMachine::removeState: cannot remove null state");
+ return;
+ }
+ if (QAbstractStatePrivate::get(state)->machine() != this) {
+ qWarning("QStateMachine::removeState: state %p's machine (%p)"
+ " is different from this machine (%p)",
+ state, QAbstractStatePrivate::get(state)->machine(), this);
+ return;
+ }
+ state->setParent(nullptr);
+}
+
+bool QStateMachine::isRunning() const
+{
+ Q_D(const QStateMachine);
+ return (d->state == QStateMachinePrivate::Running);
+}
+
+/*!
+ Starts this state machine. The machine will reset its configuration and
+ transition to the initial state. When a final top-level state (QFinalState)
+ is entered, the machine will emit the finished() signal.
+
+ \note A state machine will not run without a running event loop, such as
+ the main application event loop started with QCoreApplication::exec() or
+ QApplication::exec().
+
+ \sa started(), finished(), stop(), initialState(), setRunning()
+*/
+void QStateMachine::start()
+{
+ Q_D(QStateMachine);
+
+ if ((childMode() == QState::ExclusiveStates) && (initialState() == nullptr)) {
+ qWarning("QStateMachine::start: No initial state set for machine. Refusing to start.");
+ return;
+ }
+
+ switch (d->state) {
+ case QStateMachinePrivate::NotRunning:
+ d->state = QStateMachinePrivate::Starting;
+ QMetaObject::invokeMethod(this, "_q_start", Qt::QueuedConnection);
+ break;
+ case QStateMachinePrivate::Starting:
+ break;
+ case QStateMachinePrivate::Running:
+ qWarning("QStateMachine::start(): already running");
+ break;
+ }
+}
+
+/*!
+ Stops this state machine. The state machine will stop processing events and
+ then emit the stopped() signal.
+
+ \sa stopped(), start(), setRunning()
+*/
+void QStateMachine::stop()
+{
+ Q_D(QStateMachine);
+ switch (d->state) {
+ case QStateMachinePrivate::NotRunning:
+ break;
+ case QStateMachinePrivate::Starting:
+ // the machine will exit as soon as it enters the event processing loop
+ d->stop = true;
+ break;
+ case QStateMachinePrivate::Running:
+ d->stop = true;
+ d->processEvents(QStateMachinePrivate::QueuedProcessing);
+ break;
+ }
+}
+
+void QStateMachine::setRunning(bool running)
+{
+ if (running)
+ start();
+ else
+ stop();
+}
+
+/*!
+ \threadsafe
+
+ Posts the given \a event of the given \a priority for processing by this
+ state machine.
+
+ This function returns immediately. The event is added to the state machine's
+ event queue. Events are processed in the order posted. The state machine
+ takes ownership of the event and deletes it once it has been processed.
+
+ You can only post events when the state machine is running or when it is starting up.
+
+ \sa postDelayedEvent()
+*/
+void QStateMachine::postEvent(QEvent *event, EventPriority priority)
+{
+ Q_D(QStateMachine);
+ switch (d->state) {
+ case QStateMachinePrivate::Running:
+ case QStateMachinePrivate::Starting:
+ break;
+ default:
+ qWarning("QStateMachine::postEvent: cannot post event when the state machine is not running");
+ return;
+ }
+ if (!event) {
+ qWarning("QStateMachine::postEvent: cannot post null event");
+ return;
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << this << ": posting event" << event;
+#endif
+ switch (priority) {
+ case NormalPriority:
+ d->postExternalEvent(event);
+ break;
+ case HighPriority:
+ d->postInternalEvent(event);
+ break;
+ }
+ d->processEvents(QStateMachinePrivate::QueuedProcessing);
+}
+
+/*!
+ \threadsafe
+
+ Posts the given \a event for processing by this state machine, with the
+ given \a delay in milliseconds. Returns an identifier associated with the
+ delayed event, or -1 if the event could not be posted.
+
+ This function returns immediately. When the delay has expired, the event
+ will be added to the state machine's event queue for processing. The state
+ machine takes ownership of the event and deletes it once it has been
+ processed.
+
+ You can only post events when the state machine is running.
+
+ \sa cancelDelayedEvent(), postEvent()
+*/
+int QStateMachine::postDelayedEvent(QEvent *event, int delay)
+{
+ Q_D(QStateMachine);
+ if (d->state != QStateMachinePrivate::Running) {
+ qWarning("QStateMachine::postDelayedEvent: cannot post event when the state machine is not running");
+ return -1;
+ }
+ if (!event) {
+ qWarning("QStateMachine::postDelayedEvent: cannot post null event");
+ return -1;
+ }
+ if (delay < 0) {
+ qWarning("QStateMachine::postDelayedEvent: delay cannot be negative");
+ return -1;
+ }
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << this << ": posting event" << event << "with delay" << delay;
+#endif
+ QMutexLocker locker(&d->delayedEventsMutex);
+ int id = d->delayedEventIdFreeList.next();
+ bool inMachineThread = (QThread::currentThread() == thread());
+ int timerId = inMachineThread ? startTimer(delay) : 0;
+ if (inMachineThread && !timerId) {
+ qWarning("QStateMachine::postDelayedEvent: failed to start timer with interval %d", delay);
+ d->delayedEventIdFreeList.release(id);
+ return -1;
+ }
+ QStateMachinePrivate::DelayedEvent delayedEvent(event, timerId);
+ d->delayedEvents.insert(id, delayedEvent);
+ if (timerId) {
+ d->timerIdToDelayedEventId.insert(timerId, id);
+ } else {
+ Q_ASSERT(!inMachineThread);
+ QMetaObject::invokeMethod(this, "_q_startDelayedEventTimer",
+ Qt::QueuedConnection,
+ Q_ARG(int, id),
+ Q_ARG(int, delay));
+ }
+ return id;
+}
+
+/*!
+ \threadsafe
+
+ Cancels the delayed event identified by the given \a id. The id should be a
+ value returned by a call to postDelayedEvent(). Returns \c true if the event
+ was successfully cancelled, otherwise returns \c false.
+
+ \sa postDelayedEvent()
+*/
+bool QStateMachine::cancelDelayedEvent(int id)
+{
+ Q_D(QStateMachine);
+ if (d->state != QStateMachinePrivate::Running) {
+ qWarning("QStateMachine::cancelDelayedEvent: the machine is not running");
+ return false;
+ }
+ QMutexLocker locker(&d->delayedEventsMutex);
+ QStateMachinePrivate::DelayedEvent e = d->delayedEvents.take(id);
+ if (!e.event)
+ return false;
+ if (e.timerId) {
+ d->timerIdToDelayedEventId.remove(e.timerId);
+ bool inMachineThread = (QThread::currentThread() == thread());
+ if (inMachineThread) {
+ killTimer(e.timerId);
+ d->delayedEventIdFreeList.release(id);
+ } else {
+ QMetaObject::invokeMethod(this, "_q_killDelayedEventTimer",
+ Qt::QueuedConnection,
+ Q_ARG(int, id),
+ Q_ARG(int, e.timerId));
+ }
+ } else {
+ // Cancellation will be detected in pending _q_startDelayedEventTimer() call
+ }
+ delete e.event;
+ return true;
+}
+
+/*!
+ Returns the maximal consistent set of states (including parallel and final
+ states) that this state machine is currently in. If a state \c s is in the
+ configuration, it is always the case that the parent of \c s is also in
+ c. Note, however, that the machine itself is not an explicit member of the
+ configuration.
+*/
+QSet<QAbstractState*> QStateMachine::configuration() const
+{
+ Q_D(const QStateMachine);
+ return d->configuration;
+}
+
+/*!
+ \fn QStateMachine::started()
+
+ This signal is emitted when the state machine has entered its initial state
+ (QStateMachine::initialState).
+
+ \sa QStateMachine::finished(), QStateMachine::start()
+*/
+
+/*!
+ \fn QStateMachine::stopped()
+
+ This signal is emitted when the state machine has stopped.
+
+ \sa QStateMachine::stop(), QStateMachine::finished()
+*/
+
+/*!
+ \reimp
+*/
+bool QStateMachine::event(QEvent *e)
+{
+ Q_D(QStateMachine);
+ if (e->type() == QEvent::Timer) {
+ QTimerEvent *te = static_cast<QTimerEvent*>(e);
+ int tid = te->timerId();
+ if (d->state != QStateMachinePrivate::Running) {
+ // This event has been cancelled already
+ QMutexLocker locker(&d->delayedEventsMutex);
+ Q_ASSERT(!d->timerIdToDelayedEventId.contains(tid));
+ return true;
+ }
+ d->delayedEventsMutex.lock();
+ int id = d->timerIdToDelayedEventId.take(tid);
+ QStateMachinePrivate::DelayedEvent ee = d->delayedEvents.take(id);
+ if (ee.event != nullptr) {
+ Q_ASSERT(ee.timerId == tid);
+ killTimer(tid);
+ d->delayedEventIdFreeList.release(id);
+ d->delayedEventsMutex.unlock();
+ d->postExternalEvent(ee.event);
+ d->processEvents(QStateMachinePrivate::DirectProcessing);
+ return true;
+ } else {
+ d->delayedEventsMutex.unlock();
+ }
+ }
+ return QState::event(e);
+}
+
+#if QT_CONFIG(qeventtransition)
+/*!
+ \reimp
+*/
+bool QStateMachine::eventFilter(QObject *watched, QEvent *event)
+{
+ Q_D(QStateMachine);
+ d->handleFilteredEvent(watched, event);
+ return false;
+}
+#endif
+
+/*!
+ \internal
+
+ This function is called when the state machine is about to select
+ transitions based on the given \a event.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::beginSelectTransitions(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine has finished selecting
+ transitions based on the given \a event.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::endSelectTransitions(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine is about to do a microstep.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::beginMicrostep(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \internal
+
+ This function is called when the state machine has finished doing a
+ microstep.
+
+ The default implementation does nothing.
+*/
+void QStateMachine::endMicrostep(QEvent *event)
+{
+ Q_UNUSED(event);
+}
+
+/*!
+ \reimp
+ This function will call start() to start the state machine.
+*/
+void QStateMachine::onEntry(QEvent *event)
+{
+ start();
+ QState::onEntry(event);
+}
+
+/*!
+ \reimp
+ This function will call stop() to stop the state machine and
+ subsequently emit the stopped() signal.
+*/
+void QStateMachine::onExit(QEvent *event)
+{
+ stop();
+ QState::onExit(event);
+}
+
+#if QT_CONFIG(animation)
+
+/*!
+ Returns whether animations are enabled for this state machine.
+*/
+bool QStateMachine::isAnimated() const
+{
+ Q_D(const QStateMachine);
+ return d->animated;
+}
+
+/*!
+ Sets whether animations are \a enabled for this state machine.
+*/
+void QStateMachine::setAnimated(bool enabled)
+{
+ Q_D(QStateMachine);
+ d->animated = enabled;
+}
+
+QBindable<bool> QStateMachine::bindableAnimated()
+{
+ Q_D(QStateMachine);
+ return &d->animated;
+}
+
+/*!
+ Adds a default \a animation to be considered for any transition.
+*/
+void QStateMachine::addDefaultAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QStateMachine);
+ d->defaultAnimations.append(animation);
+}
+
+/*!
+ Returns the list of default animations that will be considered for any transition.
+*/
+QList<QAbstractAnimation*> QStateMachine::defaultAnimations() const
+{
+ Q_D(const QStateMachine);
+ return d->defaultAnimations;
+}
+
+/*!
+ Removes \a animation from the list of default animations.
+*/
+void QStateMachine::removeDefaultAnimation(QAbstractAnimation *animation)
+{
+ Q_D(QStateMachine);
+ d->defaultAnimations.removeAll(animation);
+}
+
+#endif // animation
+
+void QSignalEventGenerator::execute(QMethodRawArguments a)
+{
+ auto machinePrivate = QStateMachinePrivate::get(qobject_cast<QStateMachine*>(parent()));
+ if (machinePrivate->state != QStateMachinePrivate::Running)
+ return;
+ int signalIndex = senderSignalIndex();
+ Q_ASSERT(signalIndex != -1);
+ machinePrivate->handleTransitionSignal(sender(), signalIndex, a.arguments);
+}
+
+QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ \class QStateMachine::SignalEvent
+ \inmodule QtStateMachine
+
+ \brief The SignalEvent class represents a Qt signal event.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A signal event is generated by a QStateMachine in response to a Qt
+ signal. The QSignalTransition class provides a transition associated with a
+ signal event. QStateMachine::SignalEvent is part of \l{Qt State Machine Overview}
+ {Qt State Machine Framework}.
+
+ The sender() function returns the object that generated the signal. The
+ signalIndex() function returns the index of the signal. The arguments()
+ function returns the arguments of the signal.
+
+ \sa QSignalTransition
+*/
+
+/*!
+ \internal
+
+ Constructs a new SignalEvent object with the given \a sender, \a
+ signalIndex and \a arguments.
+*/
+QStateMachine::SignalEvent::SignalEvent(QObject *sender, int signalIndex,
+ const QList<QVariant> &arguments)
+ : QEvent(QEvent::StateMachineSignal), m_sender(sender),
+ m_signalIndex(signalIndex), m_arguments(arguments)
+{
+}
+
+/*!
+ Destroys this SignalEvent.
+*/
+QStateMachine::SignalEvent::~SignalEvent()
+{
+}
+
+/*!
+ \fn QStateMachine::SignalEvent::sender() const
+
+ Returns the object that emitted the signal.
+
+ \sa QObject::sender()
+*/
+
+/*!
+ \fn QStateMachine::SignalEvent::signalIndex() const
+
+ Returns the index of the signal.
+
+ \sa QMetaObject::indexOfSignal(), QMetaObject::method()
+*/
+
+/*!
+ \fn QStateMachine::SignalEvent::arguments() const
+
+ Returns the arguments of the signal.
+*/
+
+
+/*!
+ \class QStateMachine::WrappedEvent
+ \inmodule QtStateMachine
+
+ \brief The WrappedEvent class inherits QEvent and holds a clone of an event associated with a QObject.
+
+ \since 4.6
+ \ingroup statemachine
+
+ A wrapped event is generated by a QStateMachine in response to a Qt
+ event. The QEventTransition class provides a transition associated with a
+ such an event. QStateMachine::WrappedEvent is part of \l{Qt State Machine Overview}.
+
+ The object() function returns the object that generated the event. The
+ event() function returns a clone of the original event.
+
+ \sa QEventTransition
+*/
+
+/*!
+ \internal
+
+ Constructs a new WrappedEvent object with the given \a object
+ and \a event.
+
+ The WrappedEvent object takes ownership of \a event.
+*/
+QStateMachine::WrappedEvent::WrappedEvent(QObject *object, QEvent *event)
+ : QEvent(QEvent::StateMachineWrapped), m_object(object), m_event(event)
+{
+}
+
+/*!
+ Destroys this WrappedEvent.
+*/
+QStateMachine::WrappedEvent::~WrappedEvent()
+{
+ delete m_event;
+}
+
+/*!
+ \fn QStateMachine::WrappedEvent::object() const
+
+ Returns the object that the event is associated with.
+*/
+
+/*!
+ \fn QStateMachine::WrappedEvent::event() const
+
+ Returns a clone of the original event.
+*/
+
+/*!
+ \fn QStateMachine::runningChanged(bool running)
+ \since 5.4
+
+ This signal is emitted when the running property is changed with \a running as argument.
+
+ \sa QStateMachine::running
+*/
+
+/*!
+ \fn QStateMachine::postDelayedEvent(QEvent *event, std::chrono::milliseconds delay)
+ \since 5.15
+ \overload
+ \threadsafe
+
+ Posts the given \a event for processing by this state machine, with the
+ given \a delay in milliseconds. Returns an identifier associated with the
+ delayed event, or -1 if the event could not be posted.
+
+ This function returns immediately. When the delay has expired, the event
+ will be added to the state machine's event queue for processing. The state
+ machine takes ownership of the event and deletes it once it has been
+ processed.
+
+ You can only post events when the state machine is running.
+
+ \sa cancelDelayedEvent(), postEvent()
+*/
+
+QT_END_NAMESPACE
+
+#include "qstatemachine.moc"
+#include "moc_qstatemachine.cpp"
diff --git a/src/statemachine/qstatemachine.h b/src/statemachine/qstatemachine.h
new file mode 100644
index 0000000..4483e80
--- /dev/null
+++ b/src/statemachine/qstatemachine.h
@@ -0,0 +1,168 @@
+// 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
+
+#ifndef QSTATEMACHINE_H
+#define QSTATEMACHINE_H
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qset.h>
+#include <QtCore/qvariant.h>
+
+#include <QtStateMachine/qstate.h>
+
+#if __has_include(<chrono>)
+# include <chrono>
+#endif
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QStateMachinePrivate;
+class QAbstractAnimation;
+class Q_STATEMACHINE_EXPORT QStateMachine : public QState
+{
+ Q_OBJECT
+ Q_PROPERTY(QString errorString READ errorString BINDABLE bindableErrorString)
+ Q_PROPERTY(QState::RestorePolicy globalRestorePolicy READ globalRestorePolicy
+ WRITE setGlobalRestorePolicy BINDABLE bindableGlobalRestorePolicy)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
+#if QT_CONFIG(animation)
+ Q_PROPERTY(bool animated READ isAnimated WRITE setAnimated BINDABLE bindableAnimated)
+#endif
+public:
+ class Q_STATEMACHINE_EXPORT SignalEvent : public QEvent
+ {
+ public:
+ SignalEvent(QObject *sender, int signalIndex,
+ const QList<QVariant> &arguments);
+ ~SignalEvent();
+
+ inline QObject *sender() const { return m_sender; }
+ inline int signalIndex() const { return m_signalIndex; }
+ inline QList<QVariant> arguments() const { return m_arguments; }
+
+ private:
+ QObject *m_sender;
+ int m_signalIndex;
+ QList<QVariant> m_arguments;
+
+ friend class QSignalTransitionPrivate;
+ };
+
+ class Q_STATEMACHINE_EXPORT WrappedEvent : public QEvent
+ {
+ public:
+ WrappedEvent(QObject *object, QEvent *event);
+ ~WrappedEvent();
+
+ inline QObject *object() const { return m_object; }
+ inline QEvent *event() const { return m_event; }
+
+ private:
+ QObject *m_object;
+ QEvent *m_event;
+ };
+
+ enum EventPriority {
+ NormalPriority,
+ HighPriority
+ };
+
+ enum Error {
+ NoError,
+ NoInitialStateError,
+ NoDefaultStateInHistoryStateError,
+ NoCommonAncestorForTransitionError,
+ StateMachineChildModeSetToParallelError
+ };
+
+ explicit QStateMachine(QObject *parent = nullptr);
+ explicit QStateMachine(QState::ChildMode childMode, QObject *parent = nullptr);
+ ~QStateMachine();
+
+ void addState(QAbstractState *state);
+ void removeState(QAbstractState *state);
+
+ Error error() const;
+
+ QString errorString() const;
+ void clearError();
+ QBindable<QString> bindableErrorString() const;
+
+ bool isRunning() const;
+
+#if QT_CONFIG(animation)
+ bool isAnimated() const;
+ void setAnimated(bool enabled);
+ QBindable<bool> bindableAnimated();
+
+ void addDefaultAnimation(QAbstractAnimation *animation);
+ QList<QAbstractAnimation *> defaultAnimations() const;
+ void removeDefaultAnimation(QAbstractAnimation *animation);
+#endif // animation
+
+ QState::RestorePolicy globalRestorePolicy() const;
+ void setGlobalRestorePolicy(QState::RestorePolicy restorePolicy);
+ QBindable<QState::RestorePolicy> bindableGlobalRestorePolicy();
+
+ void postEvent(QEvent *event, EventPriority priority = NormalPriority);
+ int postDelayedEvent(QEvent *event, int delay);
+ bool cancelDelayedEvent(int id);
+
+ QSet<QAbstractState*> configuration() const;
+
+#if QT_CONFIG(qeventtransition)
+ bool eventFilter(QObject *watched, QEvent *event) override;
+#endif
+
+#if __has_include(<chrono>) || defined(Q_QDOC)
+ int postDelayedEvent(QEvent *event, std::chrono::milliseconds delay)
+ {
+ return postDelayedEvent(event, int(delay.count()));
+ }
+#endif
+
+public Q_SLOTS:
+ void start();
+ void stop();
+ void setRunning(bool running);
+
+Q_SIGNALS:
+ void started(QPrivateSignal);
+ void stopped(QPrivateSignal);
+ void runningChanged(bool running);
+
+
+protected:
+ void onEntry(QEvent *event) override;
+ void onExit(QEvent *event) override;
+
+ virtual void beginSelectTransitions(QEvent *event);
+ virtual void endSelectTransitions(QEvent *event);
+
+ virtual void beginMicrostep(QEvent *event);
+ virtual void endMicrostep(QEvent *event);
+
+ bool event(QEvent *e) override;
+
+protected:
+ QStateMachine(QStateMachinePrivate &dd, QObject *parent);
+
+private:
+ Q_DISABLE_COPY(QStateMachine)
+ Q_DECLARE_PRIVATE(QStateMachine)
+ Q_PRIVATE_SLOT(d_func(), void _q_start())
+ Q_PRIVATE_SLOT(d_func(), void _q_process())
+#if QT_CONFIG(animation)
+ Q_PRIVATE_SLOT(d_func(), void _q_animationFinished())
+#endif
+ Q_PRIVATE_SLOT(d_func(), void _q_startDelayedEventTimer(int, int))
+ Q_PRIVATE_SLOT(d_func(), void _q_killDelayedEventTimer(int, int))
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qstatemachine_p.h b/src/statemachine/qstatemachine_p.h
new file mode 100644
index 0000000..8f5201e
--- /dev/null
+++ b/src/statemachine/qstatemachine_p.h
@@ -0,0 +1,305 @@
+// 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
+
+#ifndef QSTATEMACHINE_P_H
+#define QSTATEMACHINE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qstate_p.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qset.h>
+
+#include <QtCore/private/qfreelist_p.h>
+
+QT_REQUIRE_CONFIG(statemachine);
+
+QT_BEGIN_NAMESPACE
+
+class QEvent;
+#if QT_CONFIG(qeventtransition)
+class QEventTransition;
+#endif
+class QSignalEventGenerator;
+class QSignalTransition;
+class QAbstractState;
+class QAbstractTransition;
+class QFinalState;
+class QHistoryState;
+class QState;
+
+#if QT_CONFIG(animation)
+class QAbstractAnimation;
+#endif
+
+struct CalculationCache;
+class QStateMachine;
+class Q_STATEMACHINE_EXPORT QStateMachinePrivate : public QStatePrivate
+{
+ Q_DECLARE_PUBLIC(QStateMachine)
+public:
+ enum State {
+ NotRunning,
+ Starting,
+ Running
+ };
+ enum EventProcessingMode {
+ DirectProcessing,
+ QueuedProcessing
+ };
+ enum StopProcessingReason {
+ EventQueueEmpty,
+ Finished,
+ Stopped
+ };
+
+ QStateMachinePrivate();
+ ~QStateMachinePrivate();
+
+ static QStateMachinePrivate *get(QStateMachine *q)
+ { return q ? q->d_func() : nullptr; }
+
+ QState *findLCA(const QList<QAbstractState*> &states, bool onlyCompound = false);
+ QState *findLCCA(const QList<QAbstractState*> &states);
+
+ static bool transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2);
+ static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2);
+ static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2);
+
+ QAbstractState *findErrorState(QAbstractState *context);
+ void setError(QStateMachine::Error error, QAbstractState *currentContext);
+
+ // private slots
+ void _q_start();
+ void _q_process();
+#if QT_CONFIG(animation)
+ void _q_animationFinished();
+#endif
+ void _q_startDelayedEventTimer(int id, int delay);
+ void _q_killDelayedEventTimer(int id, int timerId);
+
+ QState *rootState() const;
+
+ void clearHistory();
+ QAbstractTransition *createInitialTransition() const;
+
+ void removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
+ void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList, CalculationCache *cache);
+ QList<QAbstractTransition *> selectTransitions(QEvent *event, CalculationCache *cache);
+ virtual void noMicrostep();
+ virtual void processedPendingEvents(bool didChange);
+ virtual void beginMacrostep();
+ virtual void endMacrostep(bool didChange);
+ virtual void exitInterpreter();
+ virtual void exitStates(QEvent *event, const QList<QAbstractState *> &statesToExit_sorted,
+ const QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates);
+ QList<QAbstractState*> computeExitSet(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
+ QSet<QAbstractState*> computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
+ QSet<QAbstractState*> computeExitSet_Unordered(QAbstractTransition *t, CalculationCache *cache);
+ void executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &transitionList);
+ virtual void enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
+ const QList<QAbstractState*> &statesToEnter_sorted,
+ const QSet<QAbstractState*> &statesForDefaultEntry,
+ QHash<QAbstractState *, QList<QPropertyAssignment>> &propertyAssignmentsForState
+#if QT_CONFIG(animation)
+ , const QList<QAbstractAnimation*> &selectedAnimations
+#endif
+ );
+ QList<QAbstractState*> computeEntrySet(const QList<QAbstractTransition*> &enabledTransitions,
+ QSet<QAbstractState*> &statesForDefaultEntry, CalculationCache *cache);
+ QAbstractState *getTransitionDomain(QAbstractTransition *t,
+ const QList<QAbstractState *> &effectiveTargetStates,
+ CalculationCache *cache);
+ void addDescendantStatesToEnter(QAbstractState *state,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry);
+ void addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry);
+
+ static QState *toStandardState(QAbstractState *state);
+ static const QState *toStandardState(const QAbstractState *state);
+ static QFinalState *toFinalState(QAbstractState *state);
+ static QHistoryState *toHistoryState(QAbstractState *state);
+
+ bool isInFinalState(QAbstractState *s) const;
+ static bool isFinal(const QAbstractState *s);
+ static bool isParallel(const QAbstractState *s);
+ bool isCompound(const QAbstractState *s) const;
+ bool isAtomic(const QAbstractState *s) const;
+
+ void goToState(QAbstractState *targetState);
+
+ void registerTransitions(QAbstractState *state);
+ void maybeRegisterTransition(QAbstractTransition *transition);
+ void registerTransition(QAbstractTransition *transition);
+ void maybeRegisterSignalTransition(QSignalTransition *transition);
+ void registerSignalTransition(QSignalTransition *transition);
+ void unregisterSignalTransition(QSignalTransition *transition);
+ void registerMultiThreadedSignalTransitions();
+#if QT_CONFIG(qeventtransition)
+ void maybeRegisterEventTransition(QEventTransition *transition);
+ void registerEventTransition(QEventTransition *transition);
+ void unregisterEventTransition(QEventTransition *transition);
+ void handleFilteredEvent(QObject *watched, QEvent *event);
+#endif
+ void unregisterTransition(QAbstractTransition *transition);
+ void unregisterAllTransitions();
+ void handleTransitionSignal(QObject *sender, int signalIndex,
+ void **args);
+
+ void postInternalEvent(QEvent *e);
+ void postExternalEvent(QEvent *e);
+ QEvent *dequeueInternalEvent();
+ QEvent *dequeueExternalEvent();
+ bool isInternalEventQueueEmpty();
+ bool isExternalEventQueueEmpty();
+ void processEvents(EventProcessingMode processingMode);
+ void cancelAllDelayedEvents();
+
+ virtual void emitStateFinished(QState *forState, QFinalState *guiltyState);
+ virtual void startupHook();
+
+#ifndef QT_NO_PROPERTIES
+ class RestorableId {
+ QPointer<QObject> guard;
+ QObject *obj;
+ QByteArray prop;
+ friend size_t qHash(const RestorableId &key, size_t seed)
+ noexcept(noexcept(qHash(std::declval<QByteArray>())))
+ { return qHash(qMakePair(key.obj, key.prop), seed); }
+ friend bool operator==(const RestorableId &lhs, const RestorableId &rhs) noexcept
+ { return lhs.obj == rhs.obj && lhs.prop == rhs.prop; }
+ friend bool operator!=(const RestorableId &lhs, const RestorableId &rhs) noexcept
+ { return !operator==(lhs, rhs); }
+ public:
+ explicit RestorableId(QObject *o, QByteArray p) noexcept : guard(o), obj(o), prop(std::move(p)) {}
+ QObject *object() const noexcept { return guard; }
+ QByteArray propertyName() const noexcept { return prop; }
+ };
+ QHash<QAbstractState*, QHash<RestorableId, QVariant> > registeredRestorablesForState;
+ bool hasRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName) const;
+ QVariant savedValueForRestorable(const QList<QAbstractState*> &exitedStates_sorted,
+ QObject *object, const QByteArray &propertyName) const;
+ void registerRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName,
+ const QVariant &value);
+ void unregisterRestorables(const QList<QAbstractState*> &states, QObject *object,
+ const QByteArray &propertyName);
+ QList<QPropertyAssignment> restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const;
+ QHash<RestorableId, QVariant> computePendingRestorables(const QList<QAbstractState*> &statesToExit_sorted) const;
+ QHash<QAbstractState *, QList<QPropertyAssignment>> computePropertyAssignments(
+ const QList<QAbstractState*> &statesToEnter_sorted,
+ QHash<RestorableId, QVariant> &pendingRestorables) const;
+#endif
+
+ State state;
+ bool processing;
+ bool processingScheduled;
+ bool stop;
+ StopProcessingReason stopProcessingReason;
+ QSet<QAbstractState*> configuration;
+ QList<QEvent*> internalEventQueue;
+ QList<QEvent*> externalEventQueue;
+ QMutex internalEventMutex;
+ QMutex externalEventMutex;
+
+ QStateMachine::Error error;
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QStateMachinePrivate, QState::RestorePolicy,
+ globalRestorePolicy, QState::DontRestoreProperties);
+ Q_OBJECT_BINDABLE_PROPERTY(QStateMachinePrivate, QString, errorString);
+
+ QSet<QAbstractState *> pendingErrorStates;
+ QSet<QAbstractState *> pendingErrorStatesForDefaultEntry;
+
+#if QT_CONFIG(animation)
+ Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QStateMachinePrivate, bool, animated, true);
+
+ struct InitializeAnimationResult {
+ QList<QAbstractAnimation*> handledAnimations;
+ QList<QAbstractAnimation*> localResetEndValues;
+
+ void swap(InitializeAnimationResult &other) noexcept
+ {
+ qSwap(handledAnimations, other.handledAnimations);
+ qSwap(localResetEndValues, other.localResetEndValues);
+ }
+ };
+
+ InitializeAnimationResult
+ initializeAnimation(QAbstractAnimation *abstractAnimation,
+ const QPropertyAssignment &prop);
+
+ QHash<QAbstractState*, QList<QAbstractAnimation*> > animationsForState;
+ QHash<QAbstractAnimation*, QPropertyAssignment> propertyForAnimation;
+ QHash<QAbstractAnimation*, QAbstractState*> stateForAnimation;
+ QSet<QAbstractAnimation*> resetAnimationEndValues;
+
+ QList<QAbstractAnimation *> defaultAnimations;
+ QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForSource;
+ QMultiHash<QAbstractState *, QAbstractAnimation *> defaultAnimationsForTarget;
+
+ QList<QAbstractAnimation *> selectAnimations(const QList<QAbstractTransition *> &transitionList) const;
+ void terminateActiveAnimations(QAbstractState *state,
+ const QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates);
+ void initializeAnimations(QAbstractState *state, const QList<QAbstractAnimation*> &selectedAnimations,
+ const QList<QAbstractState *> &exitedStates_sorted,
+ QHash<QAbstractState *, QList<QPropertyAssignment>> &assignmentsForEnteredStates);
+#endif // animation
+
+ QSignalEventGenerator *signalEventGenerator;
+
+ QHash<const QObject *, QList<int>> connections;
+ QMutex connectionsMutex;
+#if QT_CONFIG(qeventtransition)
+ QHash<QObject*, QHash<QEvent::Type, int> > qobjectEvents;
+#endif
+ struct FreeListDefaultConstants
+ {
+ // used by QFreeList, make sure to define all of when customizing
+ enum {
+ InitialNextValue = 0,
+ IndexMask = 0x00ffffff,
+ SerialMask = ~IndexMask & ~0x80000000,
+ SerialCounter = IndexMask + 1,
+ MaxIndex = IndexMask,
+ BlockCount = 4
+ };
+
+ static const int Sizes[BlockCount];
+ };
+ QFreeList<void, FreeListDefaultConstants> delayedEventIdFreeList;
+
+ struct DelayedEvent {
+ QEvent *event;
+ int timerId;
+ DelayedEvent(QEvent *e, int tid)
+ : event(e), timerId(tid) {}
+ DelayedEvent()
+ : event(nullptr), timerId(0) {}
+ };
+ QHash<int, DelayedEvent> delayedEvents;
+ QHash<int, int> timerIdToDelayedEventId;
+ QMutex delayedEventsMutex;
+};
+#if QT_CONFIG(animation)
+Q_DECLARE_SHARED(QStateMachinePrivate::InitializeAnimationResult)
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachine/qstatemachineglobal.h b/src/statemachine/qstatemachineglobal.h
new file mode 100644
index 0000000..47860b7
--- /dev/null
+++ b/src/statemachine/qstatemachineglobal.h
@@ -0,0 +1,16 @@
+// 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
+
+#ifndef QSTATEMACHINEGLOBAL_H
+#define QSTATEMACHINEGLOBAL_H
+
+#include <QtCore/qglobal.h>
+#include <QtStateMachine/qtstatemachine-config.h>
+
+#if defined(BUILD_QSTATEMACHINE)
+# define Q_STATEMACHINE_EXPORT
+#else
+# include <QtStateMachine/qtstatemachineexports.h>
+#endif
+
+#endif // QSTATEMACHINEGLOBAL_H
diff --git a/src/statemachine/qt_cmdline.cmake b/src/statemachine/qt_cmdline.cmake
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/statemachine/qt_cmdline.cmake
diff --git a/src/statemachineqml/CMakeLists.txt b/src/statemachineqml/CMakeLists.txt
new file mode 100644
index 0000000..1eae461
--- /dev/null
+++ b/src/statemachineqml/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_include_in_repo_target_set(qtstatemachineqml)
+
+qt_internal_add_qml_module(StateMachineQml
+ URI "QtQml.StateMachine"
+ VERSION "${PROJECT_VERSION}"
+ PLUGIN_TARGET qtqmlstatemachine
+ CLASS_NAME QtQmlStateMachinePlugin
+ SOURCES
+ qstatemachineqmlglobals_p.h
+ finalstate_p.h finalstate.cpp
+ signaltransition_p.h signaltransition.cpp
+ state_p.h state.cpp
+ statemachine_p.h statemachine.cpp
+ timeouttransition_p.h timeouttransition.cpp
+ childrenprivate_p.h
+ statemachineforeign_p.h
+ DEFINES
+ QT_BUILD_STATEMACHINEQML_LIB
+ DEPENDENCIES
+ QtQml
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Qml
+ Qt::StateMachine
+ LIBRARIES
+ Qt::QmlPrivate
+)
diff --git a/src/statemachineqml/childrenprivate_p.h b/src/statemachineqml/childrenprivate_p.h
new file mode 100644
index 0000000..c6de691
--- /dev/null
+++ b/src/statemachineqml/childrenprivate_p.h
@@ -0,0 +1,164 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLCHILDRENPRIVATE_H
+#define QQMLCHILDRENPRIVATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QAbstractState>
+#include <QAbstractTransition>
+#include <QStateMachine>
+#include <QQmlInfo>
+#include <QQmlListProperty>
+#include <private/qglobal_p.h>
+
+enum class ChildrenMode {
+ None = 0x0,
+ State = 0x1,
+ Transition = 0x2,
+ StateOrTransition = State | Transition
+};
+
+template<typename T>
+static T *parentObject(QQmlListProperty<QObject> *prop) { return static_cast<T *>(prop->object); }
+
+template<class T, ChildrenMode Mode>
+struct ParentHandler
+{
+ static bool unparentItem(QQmlListProperty<QObject> *prop, QObject *oldItem);
+ static bool parentItem(QQmlListProperty<QObject> *prop, QObject *item);
+};
+
+template<class T>
+struct ParentHandler<T, ChildrenMode::None>
+{
+ static bool unparentItem(QQmlListProperty<QObject> *, QObject *) { return true; }
+ static bool parentItem(QQmlListProperty<QObject> *, QObject *) { return true; }
+};
+
+template<class T>
+struct ParentHandler<T, ChildrenMode::State>
+{
+ static bool parentItem(QQmlListProperty<QObject> *prop, QObject *item)
+ {
+ if (QAbstractState *state = qobject_cast<QAbstractState *>(item)) {
+ state->setParent(parentObject<T>(prop));
+ return true;
+ }
+ return false;
+ }
+
+ static bool unparentItem(QQmlListProperty<QObject> *, QObject *oldItem)
+ {
+ if (QAbstractState *state = qobject_cast<QAbstractState *>(oldItem)) {
+ state->setParent(nullptr);
+ return true;
+ }
+ return false;
+ }
+};
+
+template<class T>
+struct ParentHandler<T, ChildrenMode::Transition>
+{
+ static bool parentItem(QQmlListProperty<QObject> *prop, QObject *item)
+ {
+ if (QAbstractTransition *trans = qobject_cast<QAbstractTransition *>(item)) {
+ parentObject<T>(prop)->addTransition(trans);
+ return true;
+ }
+ return false;
+ }
+
+ static bool unparentItem(QQmlListProperty<QObject> *prop, QObject *oldItem)
+ {
+ if (QAbstractTransition *trans = qobject_cast<QAbstractTransition *>(oldItem)) {
+ parentObject<T>(prop)->removeTransition(trans);
+ return true;
+ }
+ return false;
+ }
+};
+
+template<class T>
+struct ParentHandler<T, ChildrenMode::StateOrTransition>
+{
+ static bool parentItem(QQmlListProperty<QObject> *prop, QObject *oldItem)
+ {
+ return ParentHandler<T, ChildrenMode::State>::parentItem(prop, oldItem)
+ || ParentHandler<T, ChildrenMode::Transition>::parentItem(prop, oldItem);
+ }
+
+ static bool unparentItem(QQmlListProperty<QObject> *prop, QObject *oldItem)
+ {
+ return ParentHandler<T, ChildrenMode::State>::unparentItem(prop, oldItem)
+ || ParentHandler<T, ChildrenMode::Transition>::unparentItem(prop, oldItem);
+ }
+};
+
+template <class T, ChildrenMode Mode>
+class ChildrenPrivate
+{
+public:
+ static void append(QQmlListProperty<QObject> *prop, QObject *item)
+ {
+ Handler::parentItem(prop, item);
+ static_cast<Self *>(prop->data)->children.append(item);
+ parentObject<T>(prop)->childrenContentChanged();
+ }
+
+ static qsizetype count(QQmlListProperty<QObject> *prop)
+ {
+ return static_cast<Self *>(prop->data)->children.size();
+ }
+
+ static QObject *at(QQmlListProperty<QObject> *prop, qsizetype index)
+ {
+ return static_cast<Self *>(prop->data)->children.at(index);
+ }
+
+ static void clear(QQmlListProperty<QObject> *prop)
+ {
+ auto &children = static_cast<Self *>(prop->data)->children;
+ for (QObject *oldItem : std::as_const(children))
+ Handler::unparentItem(prop, oldItem);
+
+ children.clear();
+ parentObject<T>(prop)->childrenContentChanged();
+ }
+
+ static void replace(QQmlListProperty<QObject> *prop, qsizetype index, QObject *item)
+ {
+ auto &children = static_cast<Self *>(prop->data)->children;
+
+ Handler::unparentItem(prop, children.at(index));
+ Handler::parentItem(prop, item);
+
+ children.replace(index, item);
+ parentObject<T>(prop)->childrenContentChanged();
+ }
+
+ static void removeLast(QQmlListProperty<QObject> *prop)
+ {
+ Handler::unparentItem(prop, static_cast<Self *>(prop->data)->children.takeLast());
+ parentObject<T>(prop)->childrenContentChanged();
+ }
+
+private:
+ using Self = ChildrenPrivate<T, Mode>;
+ using Handler = ParentHandler<T, Mode>;
+
+ QList<QObject *> children;
+};
+
+#endif
diff --git a/src/statemachineqml/finalstate.cpp b/src/statemachineqml/finalstate.cpp
new file mode 100644
index 0000000..ffc8d88
--- /dev/null
+++ b/src/statemachineqml/finalstate.cpp
@@ -0,0 +1,68 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "finalstate_p.h"
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+
+FinalState::FinalState(QState *parent)
+ : QFinalState(parent)
+{
+}
+
+QQmlListProperty<QObject> FinalState::childrenActualCalculation() const
+{
+ // Mutating accesses to m_children only happen in the QML thread,
+ // so there are no thread-safety issues.
+ // The engine only creates non-const instances of the class anyway
+ return QQmlListProperty<QObject>(const_cast<FinalState*>(this), &m_children,
+ m_children.append, m_children.count, m_children.at,
+ m_children.clear, m_children.replace, m_children.removeLast);
+}
+
+QQmlListProperty<QObject> FinalState::children()
+{
+ return m_childrenComputedProperty;
+}
+
+void FinalState::childrenContentChanged()
+{
+ m_childrenComputedProperty.notify();
+ emit childrenChanged();
+}
+
+QBindable<QQmlListProperty<QObject>> FinalState::bindableChildren() const
+{
+ return &m_childrenComputedProperty;
+}
+
+/*!
+ \qmltype FinalState
+ \inqmlmodule QtQml.StateMachine
+ \inherits QAbstractState
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief Provides a final state.
+
+
+ A final state is used to communicate that (part of) a StateMachine has
+ finished its work. When a final top-level state is entered, the state
+ machine's \l{State::finished}{finished}() signal is emitted. In
+ general, when a final substate (a child of a State) is entered, the parent
+ state's \l{State::finished}{finished}() signal is emitted. FinalState
+ is part of \l{Qt State Machine QML Guide}{Qt State Machine QML API}
+
+ To use a final state, you create a FinalState object and add a transition
+ to it from another state.
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/finalstate.qml document
+
+ \clearfloat
+
+ \sa StateMachine, State
+*/
diff --git a/src/statemachineqml/finalstate_p.h b/src/statemachineqml/finalstate_p.h
new file mode 100644
index 0000000..c7147c9
--- /dev/null
+++ b/src/statemachineqml/finalstate_p.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QQMLFINALSTATE_H
+#define QQMLFINALSTATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstatemachineqmlglobals_p.h"
+#include "childrenprivate_p.h"
+#include "statemachine_p.h"
+
+#include <QtCore/private/qproperty_p.h>
+#include <QtStateMachine/QFinalState>
+#include <QtQml/QQmlListProperty>
+#include <QtQml/qqml.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class Q_STATEMACHINEQML_EXPORT FinalState : public QFinalState
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlListProperty<QObject> children READ children
+ NOTIFY childrenChanged BINDABLE bindableChildren)
+ Q_CLASSINFO("DefaultProperty", "children")
+ QML_ELEMENT
+ QML_ADDED_IN_VERSION(1, 0)
+
+public:
+ explicit FinalState(QState *parent = 0);
+
+ QQmlListProperty<QObject> children();
+ QBindable<QQmlListProperty<QObject>> bindableChildren() const;
+
+Q_SIGNALS:
+ void childrenChanged();
+
+private:
+ // See the childrenActualCalculation for the mutable explanation
+ mutable ChildrenPrivate<FinalState, ChildrenMode::State> m_children;
+ friend ChildrenPrivate<FinalState, ChildrenMode::State>;
+ void childrenContentChanged();
+ QQmlListProperty<QObject> childrenActualCalculation() const;
+ Q_OBJECT_COMPUTED_PROPERTY(FinalState, QQmlListProperty<QObject>, m_childrenComputedProperty,
+ &FinalState::childrenActualCalculation);
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/statemachineqml/qstatemachineqmlglobals_p.h b/src/statemachineqml/qstatemachineqmlglobals_p.h
new file mode 100644
index 0000000..57229b1
--- /dev/null
+++ b/src/statemachineqml/qstatemachineqmlglobals_p.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2021 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
+
+#ifndef QSTATEMACHINEQMLGLOBALS_P_H
+#define QSTATEMACHINEQMLGLOBALS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtStateMachineQml/qtstatemachineqmlexports.h>
+
+QT_BEGIN_NAMESPACE
+
+void Q_STATEMACHINEQML_EXPORT qml_register_types_QtQml_StateMachine();
+
+QT_END_NAMESPACE
+
+#endif // QSTATEMACHINEQMLGLOBALS_P_H
diff --git a/src/statemachineqml/signaltransition.cpp b/src/statemachineqml/signaltransition.cpp
new file mode 100644
index 0000000..311edda
--- /dev/null
+++ b/src/statemachineqml/signaltransition.cpp
@@ -0,0 +1,346 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "signaltransition_p.h"
+
+#include <QStateMachine>
+#include <QMetaProperty>
+#include <QQmlInfo>
+#include <QQmlEngine>
+#include <QQmlContext>
+#include <QQmlExpression>
+
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qv4scopedvalue_p.h>
+#include <private/qqmlcontext_p.h>
+
+SignalTransition::SignalTransition(QState *parent)
+ : QSignalTransition(this, SIGNAL(invokeYourself()), parent), m_complete(false), m_signalExpression(nullptr)
+{
+ connect(this, &SignalTransition::signalChanged, this, [this](){ m_signal.notify(); });
+}
+
+bool SignalTransition::eventTest(QEvent *event)
+{
+ Q_ASSERT(event);
+ if (!QSignalTransition::eventTest(event))
+ return false;
+
+ if (m_guard.value().isEmpty())
+ return true;
+
+ QQmlContext *outerContext = QQmlEngine::contextForObject(this);
+ QQmlContext context(outerContext);
+ QQmlContextData::get(&context)->setImports(QQmlContextData::get(outerContext)->imports());
+
+ QStateMachine::SignalEvent *e = static_cast<QStateMachine::SignalEvent*>(event);
+
+ // Set arguments as context properties
+ int count = e->arguments().size();
+ QMetaMethod metaMethod = e->sender()->metaObject()->method(e->signalIndex());
+ const auto parameterNames = metaMethod.parameterNames();
+ for (int i = 0; i < count; i++)
+ context.setContextProperty(QString::fromUtf8(parameterNames[i]), QVariant::fromValue(e->arguments().at(i)));
+
+ QQmlExpression expr(m_guard.value(), &context, this);
+ QVariant result = expr.evaluate();
+
+ return result.toBool();
+}
+
+void SignalTransition::onTransition(QEvent *event)
+{
+ if (QQmlEnginePrivate *engine = m_signalExpression
+ ? QQmlEnginePrivate::get(m_signalExpression->engine())
+ : nullptr) {
+
+ QStateMachine::SignalEvent *e = static_cast<QStateMachine::SignalEvent*>(event);
+
+ QVarLengthArray<void *, 2> argValues;
+ QVarLengthArray<QMetaType, 2> argTypes;
+
+ QVariantList eventArguments = e->arguments();
+ const int argCount = eventArguments.size();
+ argValues.reserve(argCount + 1);
+ argTypes.reserve(argCount + 1);
+
+ // We're not interested in the return value
+ argValues.append(nullptr);
+ argTypes.append(QMetaType());
+
+ for (QVariant &arg : eventArguments) {
+ argValues.append(arg.data());
+ argTypes.append(arg.metaType());
+ }
+
+ engine->referenceScarceResources();
+ m_signalExpression->QQmlJavaScriptExpression::evaluate(
+ argValues.data(), argTypes.constData(), argCount);
+ engine->dereferenceScarceResources();
+ }
+ QSignalTransition::onTransition(event);
+}
+
+const QJSValue& SignalTransition::signal()
+{
+ return m_signal;
+}
+
+void SignalTransition::setSignal(const QJSValue &signal)
+{
+ m_signal.removeBindingUnlessInWrapper();
+ if (m_signal.valueBypassingBindings().strictlyEquals(signal))
+ return;
+
+ QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle();
+ QV4::Scope scope(jsEngine);
+
+ QObject *sender;
+ QMetaMethod signalMethod;
+
+ m_signal.setValueBypassingBindings(signal);
+ QV4::ScopedValue value(scope, QJSValuePrivate::asReturnedValue(&signal));
+
+ // Did we get the "slot" that can be used to invoke the signal?
+ if (QV4::QObjectMethod *signalSlot = value->as<QV4::QObjectMethod>()) {
+ sender = signalSlot->object();
+ Q_ASSERT(sender);
+ signalMethod = sender->metaObject()->method(signalSlot->methodIndex());
+ } else if (QV4::QmlSignalHandler *signalObject = value->as<QV4::QmlSignalHandler>()) {
+ // or did we get the signal object (the one with the connect()/disconnect() functions) ?
+ sender = signalObject->object();
+ Q_ASSERT(sender);
+ signalMethod = sender->metaObject()->method(signalObject->signalIndex());
+ } else {
+ qmlWarning(this) << tr("Specified signal does not exist.");
+ return;
+ }
+
+ QSignalTransition::setSenderObject(sender);
+ // the call below will emit change signal, and the interceptor lambda in ctor will notify()
+ QSignalTransition::setSignal(signalMethod.methodSignature());
+
+ connectTriggered();
+}
+
+QBindable<QJSValue> SignalTransition::bindableSignal()
+{
+ return &m_signal;
+}
+
+QQmlScriptString SignalTransition::guard() const
+{
+ return m_guard;
+}
+
+void SignalTransition::setGuard(const QQmlScriptString &guard)
+{
+ m_guard = guard;
+}
+
+QBindable<QQmlScriptString> SignalTransition::bindableGuard()
+{
+ return &m_guard;
+}
+
+void SignalTransition::invoke()
+{
+ emit invokeYourself();
+}
+
+void SignalTransition::connectTriggered()
+{
+ if (!m_complete || !m_compilationUnit)
+ return;
+
+ const QObject *target = senderObject();
+ QQmlData *ddata = QQmlData::get(this);
+ QQmlRefPointer<QQmlContextData> ctxtdata = ddata ? ddata->outerContext : nullptr;
+
+ Q_ASSERT(m_bindings.size() == 1);
+ const QV4::CompiledData::Binding *binding = m_bindings.at(0);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
+
+ QV4::ExecutionEngine *jsEngine = QQmlEngine::contextForObject(this)->engine()->handle();
+ QV4::Scope scope(jsEngine);
+ QV4::Scoped<QV4::QObjectMethod> qobjectSignal(
+ scope, QJSValuePrivate::asReturnedValue(&m_signal.value()));
+ if (!qobjectSignal) {
+ m_signalExpression.adopt(nullptr);
+ return;
+ }
+
+ QMetaMethod metaMethod = target->metaObject()->method(qobjectSignal->methodIndex());
+ int signalIndex = QMetaObjectPrivate::signalIndex(metaMethod);
+
+ auto f = m_compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
+ if (ctxtdata) {
+ QQmlRefPointer<QQmlBoundSignalExpression> expression(
+ new QQmlBoundSignalExpression(target, signalIndex, ctxtdata, this, f),
+ QQmlRefPointer<QQmlBoundSignalExpression>::Adopt);
+ expression->setNotifyOnValueChanged(false);
+ m_signalExpression = expression;
+ } else {
+ m_signalExpression.adopt(nullptr);
+ }
+}
+
+void SignalTransitionParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props)
+{
+ for (int ii = 0; ii < props.size(); ++ii) {
+ const QV4::CompiledData::Binding *binding = props.at(ii);
+
+ QString propName = compilationUnit->stringAt(binding->propertyNameIndex);
+
+ if (propName != QLatin1String("onTriggered")) {
+ error(props.at(ii), SignalTransition::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
+ return;
+ }
+
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script) {
+ error(binding, SignalTransition::tr("SignalTransition: script expected"));
+ return;
+ }
+ }
+}
+
+void SignalTransitionParser::applyBindings(
+ QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
+ const QList<const QV4::CompiledData::Binding *> &bindings)
+{
+ SignalTransition *st = qobject_cast<SignalTransition*>(object);
+ st->m_compilationUnit = compilationUnit;
+ st->m_bindings = bindings;
+}
+
+/*!
+ \qmltype QAbstractTransition
+ \inqmlmodule QtQml.StateMachine
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief The QAbstractTransition type is the base type of transitions between QAbstractState objects.
+
+ The QAbstractTransition type is the abstract base type of transitions
+ between states (QAbstractState objects) of a StateMachine.
+ QAbstractTransition is part of \l{Qt State Machine QML Guide}{Qt State Machine QML API}
+
+
+ The sourceState() property has the source of the transition. The
+ targetState and targetStates properties return the target(s) of the
+ transition.
+
+ The triggered() signal is emitted when the transition has been triggered.
+
+ Do not use QAbstractTransition directly; use SignalTransition or
+ TimeoutTransition instead.
+
+ \sa SignalTransition, TimeoutTransition
+*/
+
+/*!
+ \qmlproperty bool QAbstractTransition::sourceState
+ \readonly sourceState
+
+ \brief The source state (parent) of this transition.
+*/
+
+/*!
+ \qmlproperty QAbstractState QAbstractTransition::targetState
+
+ \brief The target state of this transition.
+
+ If a transition has no target state, the transition may still be
+ triggered, but this will not cause the state machine's configuration to
+ change (i.e. the current state will not be exited and re-entered).
+*/
+
+/*!
+ \qmlproperty list<QAbstractState> QAbstractTransition::targetStates
+
+ \brief The target states of this transition.
+
+ If multiple states are specified, they all must be descendants of the
+ same parallel group state.
+*/
+
+/*!
+ \qmlsignal QAbstractTransition::triggered()
+
+ This signal is emitted when the transition has been triggered.
+*/
+
+/*!
+ \qmltype QSignalTransition
+ \inqmlmodule QtQml.StateMachine
+ \inherits QAbstractTransition
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief The QSignalTransition type provides a transition based on a Qt signal.
+
+ Do not use QSignalTransition directly; use SignalTransition or
+ TimeoutTransition instead.
+
+ \sa SignalTransition, TimeoutTransition
+*/
+
+/*!
+ \qmlproperty string QSignalTransition::signal
+
+ \brief The signal which is associated with this signal transition.
+*/
+
+/*!
+ \qmlproperty QObject QSignalTransition::senderObject
+
+ \brief The sender object which is associated with this signal transition.
+*/
+
+
+/*!
+ \qmltype SignalTransition
+ \inqmlmodule QtQml.StateMachine
+ \inherits QSignalTransition
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief The SignalTransition type provides a transition based on a Qt signal.
+
+ SignalTransition is part of \l{Qt State Machine QML Guide}{Qt State Machine QML API}.
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/signaltransition.qml document
+
+ \clearfloat
+
+ \sa StateMachine, FinalState, TimeoutTransition
+*/
+
+/*!
+ \qmlproperty signal SignalTransition::signal
+
+ \brief The signal which is associated with this signal transition.
+
+ \snippet qml/statemachine/signaltransitionsignal.qml document
+*/
+
+/*!
+ \qmlproperty bool SignalTransition::guard
+
+ Guard conditions affect the behavior of a state machine by enabling
+ transitions only when they evaluate to true and disabling them when
+ they evaluate to false.
+
+ When the signal associated with this signal transition is emitted the
+ guard condition is evaluated. In the guard condition the arguments
+ of the signal can be used as demonstrated in the example below.
+
+ \snippet qml/statemachine/guardcondition.qml document
+
+ \sa signal
+*/
+
+#include "moc_signaltransition_p.cpp"
diff --git a/src/statemachineqml/signaltransition_p.h b/src/statemachineqml/signaltransition_p.h
new file mode 100644
index 0000000..2107a09
--- /dev/null
+++ b/src/statemachineqml/signaltransition_p.h
@@ -0,0 +1,101 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef SIGNALTRANSITION_H
+#define SIGNALTRANSITION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstatemachineqmlglobals_p.h"
+
+#include <QtStateMachine/QSignalTransition>
+#include <QtCore/QVariant>
+#include <QtQml/QJSValue>
+
+#include <QtQml/qqmlscriptstring.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <private/qqmlcustomparser_p.h>
+#include <private/qqmlrefcount_p.h>
+#include <private/qqmlboundsignal_p.h>
+#include <QtCore/private/qproperty_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_STATEMACHINEQML_EXPORT SignalTransition : public QSignalTransition, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QJSValue signal READ signal WRITE setSignal
+ NOTIFY qmlSignalChanged BINDABLE bindableSignal)
+ Q_PROPERTY(QQmlScriptString guard READ guard WRITE setGuard
+ NOTIFY guardChanged BINDABLE bindableGuard)
+ QML_ELEMENT
+ QML_ADDED_IN_VERSION(1, 0)
+ QML_CUSTOMPARSER
+
+public:
+ explicit SignalTransition(QState *parent = nullptr);
+
+ QQmlScriptString guard() const;
+ void setGuard(const QQmlScriptString &guard);
+ QBindable<QQmlScriptString> bindableGuard();
+
+ bool eventTest(QEvent *event) override;
+ void onTransition(QEvent *event) override;
+
+ const QJSValue &signal();
+ void setSignal(const QJSValue &signal);
+ QBindable<QJSValue> bindableSignal();
+
+ Q_INVOKABLE void invoke();
+
+Q_SIGNALS:
+ void guardChanged();
+ void invokeYourself();
+ /*!
+ * \internal
+ */
+ void qmlSignalChanged();
+
+private:
+ void classBegin() override { m_complete = false; }
+ void componentComplete() override { m_complete = true; connectTriggered(); }
+ void connectTriggered();
+
+ friend class SignalTransitionParser;
+
+ Q_OBJECT_COMPAT_PROPERTY(SignalTransition, QJSValue, m_signal, &SignalTransition::setSignal,
+ &SignalTransition::qmlSignalChanged);
+ Q_OBJECT_BINDABLE_PROPERTY(SignalTransition, QQmlScriptString,
+ m_guard, &SignalTransition::guardChanged);
+ bool m_complete;
+ QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
+ QList<const QV4::CompiledData::Binding *> m_bindings;
+ QQmlRefPointer<QQmlBoundSignalExpression> m_signalExpression;
+};
+
+class SignalTransitionParser : public QQmlCustomParser
+{
+public:
+ void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override;
+ void applyBindings(QObject *object, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override;
+};
+
+template<>
+inline QQmlCustomParser *qmlCreateCustomParser<SignalTransition>()
+{
+ return new SignalTransitionParser;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachineqml/state.cpp b/src/statemachineqml/state.cpp
new file mode 100644
index 0000000..1701bfa
--- /dev/null
+++ b/src/statemachineqml/state.cpp
@@ -0,0 +1,221 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "state_p.h"
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+
+State::State(QState *parent)
+ : QState(parent)
+{
+}
+
+QQmlListProperty<QObject> State::childrenActualCalculation() const
+{
+ // Mutating accesses to m_children only happen in the QML thread,
+ // so there are no thread-safety issues.
+ // The engine only creates non-const instances of the class anyway
+ return QQmlListProperty<QObject>(const_cast<State*>(this), &m_children,
+ m_children.append, m_children.count, m_children.at,
+ m_children.clear, m_children.replace, m_children.removeLast);
+}
+
+void State::componentComplete()
+{
+ if (this->machine() == nullptr) {
+ static bool once = false;
+ if (!once) {
+ once = true;
+ qmlWarning(this) << "No top level StateMachine found. Nothing will run without a StateMachine.";
+ }
+ }
+}
+
+QQmlListProperty<QObject> State::children()
+{
+ return m_childrenComputedProperty;
+}
+
+void State::childrenContentChanged()
+{
+ m_childrenComputedProperty.notify();
+ emit childrenChanged();
+}
+
+QBindable<QQmlListProperty<QObject>> State::bindableChildren() const
+{
+ return &m_childrenComputedProperty;
+}
+
+/*!
+ \qmltype QAbstractState
+ \inqmlmodule QtQml.StateMachine
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief The QAbstractState type is the base type of States of a StateMachine.
+
+ Do not use QAbstractState directly; use State, FinalState or
+ StateMachine instead.
+
+ \sa StateMachine, State
+*/
+
+/*!
+ \qmlproperty bool QAbstractState::active
+ \readonly active
+
+ The active property of this state. A state is active between
+ entered() and exited() signals. This property is readonly.
+
+ \sa entered, exited
+*/
+
+/*!
+ \qmlsignal QAbstractState::entered()
+
+ This signal is emitted when the State becomes active.
+
+ \sa active, exited
+*/
+
+/*!
+ \qmlsignal QAbstractState::exited()
+
+ This signal is emitted when the State becomes inactive.
+
+ \sa active, entered
+*/
+
+/*!
+ \qmltype State
+ \inqmlmodule QtQml.StateMachine
+ \inherits QAbstractState
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief Provides a general-purpose state for StateMachine.
+
+ State objects can have child states as well as transitions to other
+ states. State is part of \l{Qt State Machine QML Guide}{Qt State Machine QML API}
+
+ \section1 States with Child States
+
+ The childMode property determines how child states are treated. For
+ non-parallel state groups, the initialState property must be used to
+ set the initial state. The child states are mutually exclusive states,
+ and the state machine needs to know which child state to enter when the
+ parent state is the target of a transition.
+
+ The state emits the State::finished() signal when a final child state
+ (FinalState) is entered.
+
+ The errorState sets the state's error state. The error state is the state
+ that the state machine will transition to if an error is detected when
+ attempting to enter the state (e.g. because no initial state has been set).
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/basicstate.qml document
+
+ \clearfloat
+
+ \sa StateMachine, FinalState
+*/
+
+/*!
+ \qmlproperty enumeration State::childMode
+
+ \brief The child mode of this state
+
+ The default value of this property is QState.ExclusiveStates.
+
+ This enum specifies how a state's child states are treated:
+ \list
+ \li QState.ExclusiveStates The child states are mutually exclusive and an initial state must be set by setting initialState property.
+ \li QState.ParallelStates The child states are parallel. When the parent state is entered, all its child states are entered in parallel.
+ \endlist
+*/
+
+/*!
+ \qmlproperty QAbstractState State::errorState
+
+ \brief The error state of this state.
+*/
+
+/*!
+ \qmlproperty QAbstractState State::initialState
+
+ \brief The initial state of this state (one of its child states).
+*/
+
+/*!
+ \qmlsignal State::finished()
+
+ This signal is emitted when a final child state of this state is entered.
+
+ \sa QAbstractState::active, QAbstractState::entered, QAbstractState::exited
+*/
+
+/*!
+ \qmltype HistoryState
+ \inqmlmodule QtQml.StateMachine
+ \inherits QAbstractState
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief The HistoryState type provides a means of returning to a previously active substate.
+
+ A history state is a pseudo-state that represents the child state that the
+ parent state was in the last time the parent state was exited. A transition
+ with a history state as its target is in fact a transition to one of the
+ other child states of the parent state.
+ HistoryState is part of \l{Qt State Machine QML Guide}{Qt State Machine QML API}.
+
+ Use the defaultState property to set the state that should be entered
+ if the parent state has never been entered.
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/historystate.qml document
+
+ \clearfloat
+
+ By default, a history state is shallow, meaning that it will not remember
+ nested states. This can be configured through the historyType property.
+
+ \sa StateMachine, State
+*/
+
+/*!
+ \qmlproperty QAbstractState HistoryState::defaultState
+
+ \brief The default state of this history state.
+
+ The default state indicates the state to transition to if the parent
+ state has never been entered before.
+*/
+
+/*!
+ \qmlproperty enumeration HistoryState::historyType
+
+ \brief The type of history that this history state records.
+
+ The default value of this property is HistoryState.ShallowHistory.
+
+ This enum specifies the type of history that a HistoryState records.
+ \list
+ \li HistoryState.ShallowHistory Only the immediate child states of the
+ parent state are recorded. In this case, a transition with the history
+ state as its target will end up in the immediate child state that the
+ parent was in the last time it was exited. This is the default.
+ \li HistoryState.DeepHistory Nested states are recorded. In this case
+ a transition with the history state as its target will end up in the
+ most deeply nested descendant state the parent was in the last time
+ it was exited.
+ \endlist
+*/
+
+#include "moc_state_p.cpp"
diff --git a/src/statemachineqml/state_p.h b/src/statemachineqml/state_p.h
new file mode 100644
index 0000000..2f5595e
--- /dev/null
+++ b/src/statemachineqml/state_p.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef STATE_H
+#define STATE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstatemachineqmlglobals_p.h"
+#include "childrenprivate_p.h"
+
+#include <QtCore/qproperty.h>
+#include <QtStateMachine/QState>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlListProperty>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_STATEMACHINEQML_EXPORT State : public QState, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> children READ children
+ NOTIFY childrenChanged BINDABLE bindableChildren)
+ Q_CLASSINFO("DefaultProperty", "children")
+ QML_ELEMENT
+ QML_ADDED_IN_VERSION(1, 0)
+
+public:
+ explicit State(QState *parent = 0);
+
+ void classBegin() override {}
+ void componentComplete() override;
+
+ QQmlListProperty<QObject> children();
+ QBindable<QQmlListProperty<QObject>> bindableChildren() const;
+
+Q_SIGNALS:
+ void childrenChanged();
+
+private:
+ // See the childrenActualCalculation for the mutable explanation
+ mutable ChildrenPrivate<State, ChildrenMode::StateOrTransition> m_children;
+ friend ChildrenPrivate<State, ChildrenMode::StateOrTransition>;
+ void childrenContentChanged();
+ QQmlListProperty<QObject> childrenActualCalculation() const;
+ Q_OBJECT_COMPUTED_PROPERTY(State, QQmlListProperty<QObject>, m_childrenComputedProperty,
+ &State::childrenActualCalculation);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachineqml/statemachine.cpp b/src/statemachineqml/statemachine.cpp
new file mode 100644
index 0000000..3b55817
--- /dev/null
+++ b/src/statemachineqml/statemachine.cpp
@@ -0,0 +1,214 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "statemachine_p.h"
+
+#include <QAbstractTransition>
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQmlInfo>
+
+StateMachine::StateMachine(QObject *parent)
+ : QStateMachine(parent), m_completed(false), m_running(false)
+{
+ connect(this, SIGNAL(runningChanged(bool)), SIGNAL(qmlRunningChanged()));
+ connect(this, SIGNAL(childModeChanged()), SLOT(checkChildMode()));
+}
+
+QQmlListProperty<QObject> StateMachine::childrenActualCalculation() const
+{
+ // Mutating accesses to m_children only happen in the QML thread,
+ // so there are no thread-safety issues.
+ // The engine only creates non-const instances of the class anyway
+ return QQmlListProperty<QObject>(const_cast<StateMachine*>(this), &m_children,
+ m_children.append, m_children.count, m_children.at,
+ m_children.clear, m_children.replace, m_children.removeLast);
+}
+
+bool StateMachine::isRunning() const
+{
+ return QStateMachine::isRunning();
+}
+
+void StateMachine::setRunning(bool running)
+{
+ if (m_completed)
+ QStateMachine::setRunning(running);
+ else
+ m_running = running;
+}
+
+void StateMachine::checkChildMode()
+{
+ if (childMode() != QState::ExclusiveStates) {
+ qmlWarning(this) << "Setting the childMode of a StateMachine to anything else than\n"
+ "QState.ExclusiveStates will result in an invalid state machine,\n"
+ "and can lead to incorrect behavior!";
+ }
+}
+
+void StateMachine::componentComplete()
+{
+ if (QStateMachine::initialState() == nullptr && childMode() == QState::ExclusiveStates)
+ qmlWarning(this) << "No initial state set for StateMachine";
+
+ // Everything is proper setup, now start the state-machine if we got
+ // asked to do so.
+ m_completed = true;
+ if (m_running)
+ setRunning(true);
+}
+
+QQmlListProperty<QObject> StateMachine::children()
+{
+ return m_childrenComputedProperty;
+}
+
+void StateMachine::childrenContentChanged()
+{
+ m_childrenComputedProperty.notify();
+ emit childrenChanged();
+}
+
+QBindable<QQmlListProperty<QObject>> StateMachine::bindableChildren() const
+{
+ return &m_childrenComputedProperty;
+}
+
+/*!
+ \qmltype StateMachine
+ \inqmlmodule QtQml.StateMachine
+ \inherits State
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief Provides a hierarchical finite state machine.
+
+ StateMachine is based on the concepts and notation of
+ \l{http://www.wisdom.weizmann.ac.il/~dharel/SCANNED.PAPERS/Statecharts.pdf}{Statecharts}.
+ StateMachine is part of \l{Qt State Machine QML Guide}{Qt State Machine QML API}
+
+ A state machine manages a set of states and transitions between those
+ states; these states and transitions define a state graph. Once a state
+ graph has been built, the state machine can execute it. StateMachine's
+ execution algorithm is based on the \l{http://www.w3.org/TR/scxml/}{State Chart XML (SCXML)}
+ algorithm. The framework's \l{Qt State Machine QML Guide}{overview}
+ gives several state graphs and the code to build them.
+
+ Before the machine can be started, the \l{State::initialState}{initialState}
+ must be set. The initial state is the state that the
+ machine enters when started. You can then set running property to true
+ or start() the state machine. The started signal is emitted when the
+ initial state is entered.
+
+ The state machine processes events and takes transitions until a
+ top-level final state is entered; the state machine then emits the
+ finished() signal. You can also stop() the state machine
+ explicitly (you can also set running property to false).
+ The stopped signal is emitted in this case.
+
+ \section1 Example Usage
+ The following snippet shows a state machine that will finish when a button
+ is clicked:
+
+ \snippet qml/statemachine/simplestatemachine.qml document
+
+ If an error is encountered, the machine will look for an
+ \l{State::errorState}{errorState}, and if one is available, it will
+ enter this state. After the error state is entered, the type of the error
+ can be retrieved with error(). The execution of the state graph will not
+ stop when the error state is entered. If no error state applies to the
+ erroneous state, the machine will stop executing and an error message will
+ be printed to the console.
+
+ \warning Setting the childMode of a StateMachine to anything else than QState::ExclusiveStates
+ will result in an invalid state machine, and can lead to incorrect behavior.
+
+ \clearfloat
+
+ \sa QAbstractState, State, SignalTransition, TimeoutTransition, HistoryState {Qt State Machine QML Guide}
+*/
+
+/*!
+ \qmlproperty enumeration StateMachine::globalRestorePolicy
+
+ \brief The restore policy for states of this state machine.
+
+ The default value of this property is QState.DontRestoreProperties.
+
+ This enum specifies the restore policy type. The restore policy
+ takes effect when the machine enters a state which sets one or more
+ properties. If the restore policy is set to QState.RestoreProperties,
+ the state machine will save the original value of the property before the
+ new value is set.
+
+ Later, when the machine either enters a state which does not set a
+ value for the given property, the property will automatically be restored
+ to its initial value.
+
+ Only one initial value will be saved for any given property. If a value
+ for a property has already been saved by the state machine, it will not be
+ overwritten until the property has been successfully restored.
+
+ \list
+ \li QState.DontRestoreProperties The state machine should not save the initial values of properties and restore them later.
+ \li QState.RestoreProperties The state machine should save the initial values of properties and restore them later.
+ \endlist
+*/
+
+/*!
+ \qmlproperty bool StateMachine::running
+
+ \brief The running state of this state machine.
+ \sa start(), stop()
+*/
+
+/*!
+ \qmlproperty string StateMachine::errorString
+ \readonly errorString
+
+ \brief The error string of this state machine.
+*/
+
+
+/*!
+ \qmlmethod StateMachine::start()
+
+ Starts this state machine. The machine will reset its configuration and
+ transition to the initial state. When a final top-level state (FinalState)
+ is entered, the machine will emit the finished() signal.
+
+ \note A state machine will not run without a running event loop, such as
+ the main application event loop started with QCoreApplication::exec() or
+ QApplication::exec().
+
+ \sa started, State::finished, stop(), State::initialState, running
+*/
+
+/*!
+ \qmlsignal StateMachine::started()
+
+ This signal is emitted when the state machine has entered its initial state
+ (State::initialState).
+
+ \sa running, start(), State::finished
+*/
+
+/*!
+ \qmlmethod StateMachine::stop()
+
+ Stops this state machine. The state machine will stop processing events
+ and then emit the stopped signal.
+
+ \sa stopped, start(), running
+*/
+
+/*!
+ \qmlsignal StateMachine::stopped()
+
+ This signal is emitted when the state machine has stopped.
+
+ \sa running, stop(), State::finished
+*/
+
+#include "moc_statemachine_p.cpp"
diff --git a/src/statemachineqml/statemachine_p.h b/src/statemachineqml/statemachine_p.h
new file mode 100644
index 0000000..7356f34
--- /dev/null
+++ b/src/statemachineqml/statemachine_p.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef STATEMACHINE_H
+#define STATEMACHINE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstatemachineqmlglobals_p.h"
+#include "childrenprivate_p.h"
+
+#include <QtCore/private/qproperty_p.h>
+#include <QtStateMachine/QStateMachine>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/QQmlListProperty>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_STATEMACHINEQML_EXPORT StateMachine : public QStateMachine, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> children READ children
+ NOTIFY childrenChanged BINDABLE bindableChildren)
+
+ // Override to delay execution after componentComplete()
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY qmlRunningChanged)
+
+ Q_CLASSINFO("DefaultProperty", "children")
+ QML_ELEMENT
+ QML_ADDED_IN_VERSION(1, 0)
+
+public:
+ explicit StateMachine(QObject *parent = 0);
+
+ void classBegin() override {}
+ void componentComplete() override;
+ QQmlListProperty<QObject> children();
+ QBindable<QQmlListProperty<QObject>> bindableChildren() const;
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+private Q_SLOTS:
+ void checkChildMode();
+
+Q_SIGNALS:
+ void childrenChanged();
+ /*!
+ * \internal
+ */
+ void qmlRunningChanged();
+
+private:
+ // See the childrenActualCalculation for the mutable explanation
+ mutable ChildrenPrivate<StateMachine, ChildrenMode::StateOrTransition> m_children;
+ friend ChildrenPrivate<StateMachine, ChildrenMode::StateOrTransition>;
+ void childrenContentChanged();
+ QQmlListProperty<QObject> childrenActualCalculation() const;
+ Q_OBJECT_COMPUTED_PROPERTY(StateMachine, QQmlListProperty<QObject>, m_childrenComputedProperty,
+ &StateMachine::childrenActualCalculation);
+ bool m_completed;
+ bool m_running;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/statemachineqml/statemachineforeign_p.h b/src/statemachineqml/statemachineforeign_p.h
new file mode 100644
index 0000000..8a05042
--- /dev/null
+++ b/src/statemachineqml/statemachineforeign_p.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2019 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
+
+#ifndef STATEMACHINEFOREIGN_H
+#define STATEMACHINEFOREIGN_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstatemachineqmlglobals_p.h"
+
+#include <QtQml/qqml.h>
+#include <QtStateMachine/qhistorystate.h>
+#include <QtStateMachine/qstate.h>
+#include <QtStateMachine/qabstractstate.h>
+#include <QtStateMachine/qsignaltransition.h>
+
+struct Q_STATEMACHINEQML_EXPORT QHistoryStateForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QHistoryState)
+ QML_NAMED_ELEMENT(HistoryState)
+ QML_ADDED_IN_VERSION(1, 0)
+};
+
+struct Q_STATEMACHINEQML_EXPORT QStateForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QState)
+ QML_NAMED_ELEMENT(QState)
+ QML_ADDED_IN_VERSION(1, 0)
+ QML_UNCREATABLE("Don't use this, use State instead.")
+};
+
+struct Q_STATEMACHINEQML_EXPORT QAbstractStateForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QAbstractState)
+ QML_NAMED_ELEMENT(QAbstractState)
+ QML_ADDED_IN_VERSION(1, 0)
+ QML_UNCREATABLE("Don't use this, use State instead.")
+};
+
+struct Q_STATEMACHINEQML_EXPORT QSignalTransitionForeign
+{
+ Q_GADGET
+ QML_FOREIGN(QSignalTransition)
+ QML_NAMED_ELEMENT(QSignalTransition)
+ QML_ADDED_IN_VERSION(1, 0)
+ QML_UNCREATABLE("Don't use this, use SignalTransition instead.")
+};
+
+#endif // STATEMACHINEFOREIGN_H
diff --git a/src/statemachineqml/timeouttransition.cpp b/src/statemachineqml/timeouttransition.cpp
new file mode 100644
index 0000000..29bfd45
--- /dev/null
+++ b/src/statemachineqml/timeouttransition.cpp
@@ -0,0 +1,80 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "timeouttransition_p.h"
+
+#include <QQmlInfo>
+#include <QTimer>
+#include <QState>
+
+TimeoutTransition::TimeoutTransition(QState* parent)
+ : QSignalTransition((m_timer = new QTimer), SIGNAL(timeout()), parent)
+{
+ m_timer->setSingleShot(true);
+ m_timer->setInterval(1000);
+}
+
+TimeoutTransition::~TimeoutTransition()
+{
+ delete m_timer;
+}
+
+int TimeoutTransition::timeout() const
+{
+ return m_timer->interval();
+}
+
+void TimeoutTransition::setTimeout(int timeout)
+{
+ m_timer->setInterval(timeout);
+}
+
+QBindable<int> TimeoutTransition::bindableTimeout()
+{
+ return m_timer->bindableInterval();
+}
+
+void TimeoutTransition::componentComplete()
+{
+ QState *state = qobject_cast<QState*>(parent());
+ if (!state) {
+ qmlWarning(this) << "Parent needs to be a State";
+ return;
+ }
+
+ connect(state, SIGNAL(entered()), m_timer, SLOT(start()));
+ connect(state, SIGNAL(exited()), m_timer, SLOT(stop()));
+ if (state->active())
+ m_timer->start();
+}
+
+/*!
+ \qmltype TimeoutTransition
+ \inqmlmodule QtQml.StateMachine
+ \inherits QSignalTransition
+ \ingroup statemachine-qmltypes
+ \since 5.4
+
+ \brief The TimeoutTransition type provides a transition based on a timer.
+
+ \l {QtQml::Timer}{Timer} type can be combined with SignalTransition to enact more complex
+ timeout based transitions.
+
+ TimeoutTransition is part of \l{Qt State Machine QML Guide}{Qt State Machine QML API}
+
+ \section1 Example Usage
+
+ \snippet qml/statemachine/timeouttransition.qml document
+
+ \clearfloat
+
+ \sa StateMachine, SignalTransition, FinalState, HistoryState
+*/
+
+/*!
+ \qmlproperty int TimeoutTransition::timeout
+
+ \brief The timeout interval in milliseconds.
+*/
+
+#include "moc_timeouttransition_p.cpp"
diff --git a/src/statemachineqml/timeouttransition_p.h b/src/statemachineqml/timeouttransition_p.h
new file mode 100644
index 0000000..5c8388e
--- /dev/null
+++ b/src/statemachineqml/timeouttransition_p.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2016 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef TIMEOUTTRANSITION_H
+#define TIMEOUTTRANSITION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstatemachineqmlglobals_p.h"
+
+#include <QtStateMachine/QSignalTransition>
+#include <QtQml/QQmlParserStatus>
+#include <QtQml/qqml.h>
+#include <QtCore/private/qproperty_p.h>
+
+QT_BEGIN_NAMESPACE
+class QTimer;
+
+class Q_STATEMACHINEQML_EXPORT TimeoutTransition : public QSignalTransition, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(int timeout READ timeout WRITE setTimeout BINDABLE bindableTimeout)
+ Q_INTERFACES(QQmlParserStatus)
+ QML_ELEMENT
+ QML_ADDED_IN_VERSION(1, 0)
+
+public:
+ TimeoutTransition(QState *parent = nullptr);
+ ~TimeoutTransition();
+
+ int timeout() const;
+ void setTimeout(int timeout);
+ QBindable<int> bindableTimeout();
+
+ void classBegin() override {}
+ void componentComplete() override;
+
+private:
+ QTimer *m_timer;
+};
+
+QT_END_NAMESPACE
+
+#endif