1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qscxmlcppdatamodel_p.h"
5#include "qscxmlstatemachine.h"
6
7QT_BEGIN_NAMESPACE
8
9using namespace QScxmlExecutableContent;
10
11/*!
12 \class QScxmlCppDataModel
13 \brief The QScxmlCppDataModel class is a C++ data model for a Qt SCXML state machine.
14 \since 5.7
15 \inmodule QtScxml
16
17 \sa QScxmlStateMachine QScxmlDataModel
18
19 The C++ data model for SCXML lets you write C++ code for \e expr attributes and \c <script>
20 elements. The \e {data part} of the data model is backed by a subclass of QScxmlCppDataModel, for
21 which the Qt SCXML compiler (\c qscxmlc) will generate the dispatch methods. It cannot be used
22 when loading an SCXML file at runtime.
23
24 Usage is through the \e datamodel attribute of the \c <scxml> element:
25 \code
26 <scxml datamodel="cplusplus:TheDataModel:thedatamodel.h" ....>
27 \endcode
28 The format of the \e datamodel attribute is: \c{cplusplus:<class-name>:<classdef-header>}.
29 So, for the example above, there should be a file \e thedatamodel.h containing a subclass of
30 QScxmlCppDataModel, containing at least the following:
31
32 \snippet snippets/mediaplayer/thedatamodel.h Declaration1
33 \dots
34 \snippet snippets/mediaplayer/thedatamodel.h Declaration2
35
36 The Q_SCXML_DATAMODEL has to appear in the private section of the class definition, for example
37 right after the opening bracket, or after a Q_OBJECT macro.
38 This macro expands to the declaration of some virtual
39 methods whose implementation is generated by the Qt SCXML compiler.
40
41 The Qt SCXML compiler will generate the various \c evaluateTo methods, and convert expressions and
42 scripts into lambdas inside those methods. For example:
43 \code
44<scxml datamodel="cplusplus:TheDataModel:thedatamodel.h" xmlns="http://www.w3.org/2005/07/scxml" version="1.0" name="MediaPlayerStateMachine">
45 <state id="stopped">
46 <transition event="tap" cond="isValidMedia()" target="playing"/>
47 </state>
48
49 <state id="playing">
50 <onentry>
51 <script>
52 media = eventData().value(QStringLiteral(&quot;media&quot;)).toString();
53 </script>
54 <send event="playbackStarted">
55 <param name="media" expr="media"/>
56 </send>
57 </onentry>
58 </state>
59</scxml>
60 \endcode
61 This will result in:
62 \code
63bool TheDataModel::evaluateToBool(QScxmlExecutableContent::EvaluatorId id, bool *ok) {
64 // ....
65 return [this]()->bool{ return isValidMedia(); }();
66 // ....
67}
68
69QVariant TheDataModel::evaluateToVariant(QScxmlExecutableContent::EvaluatorId id, bool *ok) {
70 // ....
71 return [this]()->QVariant{ return media; }();
72 // ....
73}
74
75void TheDataModel::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool *ok) {
76 // ....
77 [this]()->void{ media = eventData().value(QStringLiteral("media")).toString(); }();
78 // ....
79}
80 \endcode
81
82 So, you are not limited to call functions. In a \c <script> element you can put zero or more C++
83 statements, and in \e cond or \e expr attributes you can use any C++ expression that can be
84 converted to the respective bool or QVariant. And, as the \c this pointer is also captured, you
85 can call or access the data model (the \e media attribute in the example above). For the full
86 example, see \l {SCXML Media Player}.
87 */
88
89/*!
90 * Creates a new C++ data model with the parent object \a parent.
91 */
92QScxmlCppDataModel::QScxmlCppDataModel(QObject *parent)
93 : QScxmlDataModel(*(new QScxmlCppDataModelPrivate), parent)
94{}
95
96/*!
97 * Called during state machine initialization to set up a state machine using the initial values
98 * for data model variables specified by their keys, \a initialDataValues. These
99 * are the values specified by \c <param> tags in an \c <invoke> element.
100 *
101 * Returns \c true on success.
102 *
103 * \sa QScxmlStateMachine::init
104 */
105bool QScxmlCppDataModel::setup(const QVariantMap &initialDataValues)
106{
107 Q_UNUSED(initialDataValues);
108
109 return true;
110}
111
112/*!
113 \reimp
114
115 This method does not perform any action, ignores \a id, and sets \a ok to
116 \c false. Override it in your specific data model in order to implement
117 \c <assign>.
118 */
119void QScxmlCppDataModel::evaluateAssignment(QScxmlExecutableContent::EvaluatorId id, bool *ok)
120{
121 Q_UNUSED(id);
122 *ok = false;
123}
124
125/*!
126 \reimp
127
128 This method does not perform any action, ignores \a id, and sets \a ok to
129 \c false. Override it in your specific data model in order to implement
130 \c <data>.
131 */
132void QScxmlCppDataModel::evaluateInitialization(QScxmlExecutableContent::EvaluatorId id, bool *ok)
133{
134 Q_UNUSED(id);
135 *ok = false;
136}
137
138/*!
139 \reimp
140
141 This method does not perform any action, ignores \a id and \a body, and sets
142 \a ok to \c false. Override it in your specific data model in order to
143 implement \c <foreach>.
144 */
145void QScxmlCppDataModel::evaluateForeach(QScxmlExecutableContent::EvaluatorId id, bool *ok,
146 ForeachLoopBody *body)
147{
148 Q_UNUSED(id);
149 Q_UNUSED(body);
150 *ok = false;
151}
152
153/*!
154 \reimp
155
156 Sets the \a event that will be processed next.
157
158 \sa QScxmlCppDataModel::scxmlEvent
159 */
160void QScxmlCppDataModel::setScxmlEvent(const QScxmlEvent &event)
161{
162 Q_D(QScxmlCppDataModel);
163 if (event.name().isEmpty())
164 return;
165
166 d->event = event;
167}
168
169/*!
170 * Holds the current event that is being processed by the
171 * state machine.
172 *
173 * See also \l {SCXML Specification - 5.10 System Variables} for the description
174 * of the \c _event variable.
175 *
176 * Returns the event currently being processed.
177 */
178const QScxmlEvent &QScxmlCppDataModel::scxmlEvent() const
179{
180 Q_D(const QScxmlCppDataModel);
181 return d->event;
182}
183
184/*!
185 \reimp
186
187 This method always returns an empty QVariant and ignores \a name.
188 Override it to implement the lookup of data model properties via the
189 \c location attribute of various elements.
190 */
191QVariant QScxmlCppDataModel::scxmlProperty(const QString &name) const
192{
193 Q_UNUSED(name);
194 return QVariant();
195}
196
197/*!
198 \reimp
199
200 This method always returns \c false and ignores \a name.
201 Override it to implement the lookup of data model properties via the
202 \c location attribute of various elements.
203 */
204bool QScxmlCppDataModel::hasScxmlProperty(const QString &name) const
205{
206 Q_UNUSED(name);
207 return false;
208}
209
210/*!
211 \reimp
212
213 This method always returns \c false and ignores \a name, \a value, and
214 \a context.
215 Override it to implement the lookup of data model properties via the
216 \c location attribute of various elements.
217 */
218bool QScxmlCppDataModel::setScxmlProperty(const QString &name, const QVariant &value,
219 const QString &context)
220{
221 Q_UNUSED(name);
222 Q_UNUSED(value);
223 Q_UNUSED(context);
224 return false;
225}
226
227/*!
228 Returns \c true if the state machine is in the state specified by
229 \a stateName, \c false otherwise.
230 */
231bool QScxmlCppDataModel::inState(const QString &stateName) const
232{
233 return stateMachine()->isActive(scxmlStateName: stateName);
234}
235
236QT_END_NAMESPACE
237

source code of qtscxml/src/scxml/qscxmlcppdatamodel.cpp