1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtScxml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QSCXMLSTATEMACHINE_H
41#define QSCXMLSTATEMACHINE_H
42
43#include <QtScxml/qscxmldatamodel.h>
44#include <QtScxml/qscxmlerror.h>
45#include <QtScxml/qscxmlevent.h>
46#include <QtScxml/qscxmlcompiler.h>
47#include <QtScxml/qscxmlinvokableservice.h>
48
49#include <QtCore/qstring.h>
50#include <QtCore/qvector.h>
51#include <QtCore/qurl.h>
52#include <QtCore/qvariant.h>
53#include <QtCore/qpointer.h>
54
55#include <functional>
56
57QT_BEGIN_NAMESPACE
58class QIODevice;
59class QXmlStreamWriter;
60class QTextStream;
61
62class QScxmlStateMachinePrivate;
63class Q_SCXML_EXPORT QScxmlStateMachine: public QObject
64{
65 Q_DECLARE_PRIVATE(QScxmlStateMachine)
66 Q_OBJECT
67 Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
68 Q_PROPERTY(bool initialized READ isInitialized NOTIFY initializedChanged)
69 Q_PROPERTY(QScxmlDataModel *dataModel READ dataModel WRITE setDataModel NOTIFY dataModelChanged)
70 Q_PROPERTY(QVariantMap initialValues READ initialValues WRITE setInitialValues NOTIFY initialValuesChanged)
71 Q_PROPERTY(QVector<QScxmlInvokableService*> invokedServices READ invokedServices NOTIFY invokedServicesChanged)
72 Q_PROPERTY(QString sessionId READ sessionId CONSTANT)
73 Q_PROPERTY(QString name READ name CONSTANT)
74 Q_PROPERTY(bool invoked READ isInvoked CONSTANT)
75 Q_PROPERTY(QVector<QScxmlError> parseErrors READ parseErrors CONSTANT)
76 Q_PROPERTY(QScxmlCompiler::Loader *loader READ loader WRITE setLoader NOTIFY loaderChanged)
77 Q_PROPERTY(QScxmlTableData *tableData READ tableData WRITE setTableData NOTIFY tableDataChanged)
78
79protected:
80 explicit QScxmlStateMachine(const QMetaObject *metaObject, QObject *parent = nullptr);
81 QScxmlStateMachine(QScxmlStateMachinePrivate &dd, QObject *parent = nullptr);
82
83public:
84 static QScxmlStateMachine *fromFile(const QString &fileName);
85 static QScxmlStateMachine *fromData(QIODevice *data, const QString &fileName = QString());
86 QVector<QScxmlError> parseErrors() const;
87
88 QString sessionId() const;
89
90 bool isInvoked() const;
91 bool isInitialized() const;
92
93 void setDataModel(QScxmlDataModel *model);
94 QScxmlDataModel *dataModel() const;
95
96 void setLoader(QScxmlCompiler::Loader *loader);
97 QScxmlCompiler::Loader *loader() const;
98
99 bool isRunning() const;
100 void setRunning(bool running);
101
102 QVariantMap initialValues();
103 void setInitialValues(const QVariantMap &initialValues);
104
105 QString name() const;
106 Q_INVOKABLE QStringList stateNames(bool compress = true) const;
107 Q_INVOKABLE QStringList activeStateNames(bool compress = true) const;
108 Q_INVOKABLE bool isActive(const QString &scxmlStateName) const;
109
110 QMetaObject::Connection connectToState(const QString &scxmlStateName,
111 const QObject *receiver, const char *method,
112 Qt::ConnectionType type = Qt::AutoConnection);
113
114 // connect state to a QObject slot
115 template <typename PointerToMemberFunction>
116 inline QMetaObject::Connection connectToState(
117 const QString &scxmlStateName,
118 const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
119 PointerToMemberFunction method,
120 Qt::ConnectionType type = Qt::AutoConnection)
121 {
122 typedef QtPrivate::FunctionPointer<PointerToMemberFunction> SlotType;
123 return connectToStateImpl(
124 scxmlStateName, receiver, slot: nullptr,
125 slotObj: new QtPrivate::QSlotObject<PointerToMemberFunction,
126 typename SlotType::Arguments, void>(method),
127 type);
128 }
129
130 // connect state to a functor or function pointer (without context)
131 template <typename Functor>
132 inline typename QtPrivate::QEnableIf<
133 !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
134 !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
135 connectToState(const QString &scxmlStateName, Functor functor,
136 Qt::ConnectionType type = Qt::AutoConnection)
137 {
138 // Use this as context
139 return connectToState(scxmlStateName, this, functor, type);
140 }
141
142 // connectToState to a functor or function pointer (with context)
143 template <typename Functor>
144 inline typename QtPrivate::QEnableIf<
145 !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
146 !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
147 connectToState(const QString &scxmlStateName, const QObject *context, Functor functor,
148 Qt::ConnectionType type = Qt::AutoConnection)
149 {
150 QtPrivate::QSlotObjectBase *slotObj = new QtPrivate::QFunctorSlotObject<Functor, 1,
151 QtPrivate::List<bool>, void>(functor);
152 return connectToStateImpl(scxmlStateName, receiver: context, slot: reinterpret_cast<void **>(&functor),
153 slotObj, type);
154 }
155
156 static std::function<void(bool)> onEntry(const QObject *receiver, const char *method)
157 {
158 const QPointer<QObject> receiverPointer(const_cast<QObject *>(receiver));
159 return [receiverPointer, method](bool isEnteringState) {
160 if (isEnteringState && !receiverPointer.isNull())
161 QMetaObject::invokeMethod(obj: const_cast<QObject *>(receiverPointer.data()), member: method);
162 };
163 }
164
165 static std::function<void(bool)> onExit(const QObject *receiver, const char *method)
166 {
167 const QPointer<QObject> receiverPointer(const_cast<QObject *>(receiver));
168 return [receiverPointer, method](bool isEnteringState) {
169 if (!isEnteringState && !receiverPointer.isNull())
170 QMetaObject::invokeMethod(obj: receiverPointer.data(), member: method);
171 };
172 }
173
174 template<typename Functor>
175 static std::function<void(bool)> onEntry(Functor functor)
176 {
177 return [functor](bool isEnteringState) {
178 if (isEnteringState)
179 functor();
180 };
181 }
182
183 template<typename Functor>
184 static std::function<void(bool)> onExit(Functor functor)
185 {
186 return [functor](bool isEnteringState) {
187 if (!isEnteringState)
188 functor();
189 };
190 }
191
192 template<typename PointerToMemberFunction>
193 static std::function<void(bool)> onEntry(
194 const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
195 PointerToMemberFunction method)
196 {
197 typedef typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object Object;
198 const QPointer<Object> receiverPointer(const_cast<Object *>(receiver));
199 return [receiverPointer, method](bool isEnteringState) {
200 if (isEnteringState && !receiverPointer.isNull())
201 (receiverPointer->*method)();
202 };
203 }
204
205 template<typename PointerToMemberFunction>
206 static std::function<void(bool)> onExit(
207 const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
208 PointerToMemberFunction method)
209 {
210 typedef typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object Object;
211 const QPointer<Object> receiverPointer(const_cast<Object *>(receiver));
212 return [receiverPointer, method](bool isEnteringState) {
213 if (!isEnteringState && !receiverPointer.isNull())
214 (receiverPointer->*method)();
215 };
216 }
217
218 QMetaObject::Connection connectToEvent(const QString &scxmlEventSpec,
219 const QObject *receiver, const char *method,
220 Qt::ConnectionType type = Qt::AutoConnection);
221
222 // connect state to a QObject slot
223 template <typename PointerToMemberFunction>
224 inline QMetaObject::Connection connectToEvent(
225 const QString &scxmlEventSpec,
226 const typename QtPrivate::FunctionPointer<PointerToMemberFunction>::Object *receiver,
227 PointerToMemberFunction method,
228 Qt::ConnectionType type = Qt::AutoConnection)
229 {
230 typedef QtPrivate::FunctionPointer<PointerToMemberFunction> SlotType;
231 return connectToEventImpl(
232 scxmlEventSpec, receiver, slot: nullptr,
233 slotObj: new QtPrivate::QSlotObject<PointerToMemberFunction,
234 typename SlotType::Arguments, void>(method),
235 type);
236 }
237
238 // connect state to a functor or function pointer (without context)
239 template <typename Functor>
240 inline typename QtPrivate::QEnableIf<
241 !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
242 !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
243 connectToEvent(const QString &scxmlEventSpec, Functor functor,
244 Qt::ConnectionType type = Qt::AutoConnection)
245 {
246 // Use this as context
247 return connectToEvent(scxmlEventSpec, this, functor, type);
248 }
249
250 // connectToEvent to a functor or function pointer (with context)
251 template <typename Functor>
252 inline typename QtPrivate::QEnableIf<
253 !QtPrivate::FunctionPointer<Functor>::IsPointerToMemberFunction &&
254 !std::is_same<const char*, Functor>::value, QMetaObject::Connection>::Type
255 connectToEvent(const QString &scxmlEventSpec, const QObject *context, Functor functor,
256 Qt::ConnectionType type = Qt::AutoConnection)
257 {
258 QtPrivate::QSlotObjectBase *slotObj = new QtPrivate::QFunctorSlotObject<Functor, 1,
259 QtPrivate::List<QScxmlEvent>, void>(functor);
260 return connectToEventImpl(scxmlEventSpec, receiver: context, slot: reinterpret_cast<void **>(&functor),
261 slotObj, type);
262 }
263
264 Q_INVOKABLE void submitEvent(QScxmlEvent *event);
265 Q_INVOKABLE void submitEvent(const QString &eventName);
266 Q_INVOKABLE void submitEvent(const QString &eventName, const QVariant &data);
267 Q_INVOKABLE void cancelDelayedEvent(const QString &sendId);
268
269 Q_INVOKABLE bool isDispatchableTarget(const QString &target) const;
270
271 QVector<QScxmlInvokableService *> invokedServices() const;
272
273 QScxmlTableData *tableData() const;
274 void setTableData(QScxmlTableData *tableData);
275
276Q_SIGNALS:
277 void runningChanged(bool running);
278 void invokedServicesChanged(const QVector<QScxmlInvokableService *> &invokedServices);
279 void log(const QString &label, const QString &msg);
280 void reachedStableState();
281 void finished();
282 void dataModelChanged(QScxmlDataModel *model);
283 void initialValuesChanged(const QVariantMap &initialValues);
284 void initializedChanged(bool initialized);
285 void loaderChanged(QScxmlCompiler::Loader *loader);
286 void tableDataChanged(QScxmlTableData *tableData);
287
288public Q_SLOTS:
289 void start();
290 void stop();
291 bool init();
292
293protected: // methods for friends:
294 friend class QScxmlDataModel;
295 friend class QScxmlEventBuilder;
296 friend class QScxmlInvokableServicePrivate;
297 friend class QScxmlExecutionEngine;
298
299 // The methods below are used by the compiled state machines.
300 bool isActive(int stateIndex) const;
301
302private:
303 QMetaObject::Connection connectToStateImpl(const QString &scxmlStateName,
304 const QObject *receiver, void **slot,
305 QtPrivate::QSlotObjectBase *slotObj,
306 Qt::ConnectionType type = Qt::AutoConnection);
307 QMetaObject::Connection connectToEventImpl(const QString &scxmlEventSpec,
308 const QObject *receiver, void **slot,
309 QtPrivate::QSlotObjectBase *slotObj,
310 Qt::ConnectionType type = Qt::AutoConnection);
311};
312
313QT_END_NAMESPACE
314
315Q_DECLARE_METATYPE(QScxmlStateMachine *)
316Q_DECLARE_METATYPE(QVector<QScxmlInvokableService *>)
317
318#endif // QSCXMLSTATEMACHINE_H
319

source code of qtscxml/src/scxml/qscxmlstatemachine.h