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

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