// 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 #include #include #include #include #include #include #include #include #include #include #include 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 { Q_DECLARE_PRIVATE(QScxmlStateMachine) Q_OBJECT Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) 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 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(QList 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); QScxmlStateMachine(QScxmlStateMachinePrivate &dd, QObject *parent = nullptr); public: static QScxmlStateMachine *fromFile(const QString &fileName); static QScxmlStateMachine *fromData(QIODevice *data, const QString &fileName = QString()); QList parseErrors() const; QString sessionId() const; bool isInvoked() const; bool isInitialized() const; QBindable bindableInitialized() const; void setDataModel(QScxmlDataModel *model); QScxmlDataModel *dataModel() const; QBindable bindableDataModel(); void setLoader(QScxmlCompiler::Loader *loader); QScxmlCompiler::Loader *loader() const; QBindable bindableLoader(); bool isRunning() const; void setRunning(bool running); QVariantMap initialValues(); void setInitialValues(const QVariantMap &initialValues); QBindable bindableInitialValues(); QString name() const; Q_INVOKABLE QStringList stateNames(bool compress = true) const; Q_INVOKABLE QStringList activeStateNames(bool compress = true) const; Q_INVOKABLE bool isActive(const QString &scxmlStateName) const; QMetaObject::Connection connectToState(const QString &scxmlStateName, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection); // connect state with context template #ifdef Q_QDOC QMetaObject::Connection #else inline std::enable_if_t, QMetaObject::Connection> #endif connectToState( const QString &scxmlStateName, #ifdef Q_QDOC const QObject *context, #else const typename QtPrivate::ContextTypeForFunctor::ContextType *context, #endif Functor &&functor, Qt::ConnectionType type = Qt::AutoConnection) { using Prototype = void(*)(bool); return connectToStateImpl( scxmlStateName, context, nullptr, QtPrivate::makeCallableObject(std::forward(functor)), type); } // connect state without context template #ifdef Q_QDOC QMetaObject::Connection #else inline std::enable_if_t, QMetaObject::Connection> #endif connectToState( const QString &scxmlStateName, Functor &&functor, Qt::ConnectionType type = Qt::AutoConnection) { return connectToState(scxmlStateName, this, std::forward(functor), type); } //! [onentry] static std::function onEntry(const QObject *receiver, const char *method) { const QPointer receiverPointer(const_cast(receiver)); return [receiverPointer, method](bool isEnteringState) { if (isEnteringState && !receiverPointer.isNull()) QMetaObject::invokeMethod(const_cast(receiverPointer.data()), method); }; } //! [onexit] static std::function onExit(const QObject *receiver, const char *method) { const QPointer receiverPointer(const_cast(receiver)); return [receiverPointer, method](bool isEnteringState) { if (!isEnteringState && !receiverPointer.isNull()) QMetaObject::invokeMethod(receiverPointer.data(), method); }; } //! [onentry-functor] template static std::function onEntry(Functor functor) { return [functor](bool isEnteringState) { if (isEnteringState) functor(); }; } //! [onexit-functor] template static std::function onExit(Functor functor) { return [functor](bool isEnteringState) { if (!isEnteringState) functor(); }; } //! [onentry-template] template static std::function onEntry( const typename QtPrivate::FunctionPointer::Object *receiver, PointerToMemberFunction method) { typedef typename QtPrivate::FunctionPointer::Object Object; const QPointer receiverPointer(const_cast(receiver)); return [receiverPointer, method](bool isEnteringState) { if (isEnteringState && !receiverPointer.isNull()) (receiverPointer->*method)(); }; } //! [onexit-template] template static std::function onExit( const typename QtPrivate::FunctionPointer::Object *receiver, PointerToMemberFunction method) { typedef typename QtPrivate::FunctionPointer::Object Object; const QPointer receiverPointer(const_cast(receiver)); return [receiverPointer, method](bool isEnteringState) { if (!isEnteringState && !receiverPointer.isNull()) (receiverPointer->*method)(); }; } QMetaObject::Connection connectToEvent(const QString &scxmlEventSpec, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection); // connect event with context template #ifdef Q_QDOC QMetaObject::Connection #else inline std::enable_if_t, QMetaObject::Connection> #endif connectToEvent( const QString &scxmlEventSpec, #ifdef Q_QDOC const QObject *context, #else const typename QtPrivate::ContextTypeForFunctor::ContextType *context, #endif Functor &&functor, Qt::ConnectionType type = Qt::AutoConnection) { using Prototype = void(*)(QScxmlEvent); return connectToEventImpl( scxmlEventSpec, context, nullptr, QtPrivate::makeCallableObject(std::forward(functor)), type); } // connect event without context template #ifdef Q_QDOC QMetaObject::Connection #else inline std::enable_if_t, QMetaObject::Connection> #endif connectToEvent(const QString &scxmlEventSpec, Functor &&functor, Qt::ConnectionType type = Qt::AutoConnection) { // Use this as context return connectToEvent(scxmlEventSpec, this, std::forward(functor), type); } Q_INVOKABLE void submitEvent(QScxmlEvent *event); Q_INVOKABLE void submitEvent(const QString &eventName); Q_INVOKABLE void submitEvent(const QString &eventName, const QVariant &data); Q_INVOKABLE void cancelDelayedEvent(const QString &sendId); Q_INVOKABLE bool isDispatchableTarget(const QString &target) const; QList invokedServices() const; QBindable> bindableInvokedServices(); QScxmlTableData *tableData() const; void setTableData(QScxmlTableData *tableData); QBindable bindableTableData(); Q_SIGNALS: void runningChanged(bool running); void invokedServicesChanged(const QList &invokedServices); void log(const QString &label, const QString &msg); void reachedStableState(); void finished(); void dataModelChanged(QScxmlDataModel *model); void initialValuesChanged(const QVariantMap &initialValues); void initializedChanged(bool initialized); void loaderChanged(QScxmlCompiler::Loader *loader); void tableDataChanged(QScxmlTableData *tableData); public Q_SLOTS: void start(); void stop(); bool init(); protected: // methods for friends: friend class QScxmlDataModel; friend class QScxmlEventBuilder; friend class QScxmlInvokableServicePrivate; friend class QScxmlExecutionEngine; // The methods below are used by the compiled state machines. bool isActive(int stateIndex) const; private: QMetaObject::Connection connectToStateImpl(const QString &scxmlStateName, const QObject *receiver, void **slot, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type = Qt::AutoConnection); QMetaObject::Connection connectToEventImpl(const QString &scxmlEventSpec, const QObject *receiver, void **slot, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type = Qt::AutoConnection); }; QT_END_NAMESPACE Q_DECLARE_METATYPE(QScxmlStateMachine *) Q_DECLARE_METATYPE(QList) #endif // QSCXMLSTATEMACHINE_H