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 "qscxmlnulldatamodel.h"
5#include "qscxmlevent.h"
6#include "qscxmlstatemachine_p.h"
7#include "qscxmltabledata.h"
8#include "qscxmldatamodel_p.h"
9
10QT_BEGIN_NAMESPACE
11
12class QScxmlNullDataModelPrivate : public QScxmlDataModelPrivate
13{
14 Q_DECLARE_PUBLIC(QScxmlNullDataModel)
15
16 struct ResolvedEvaluatorInfo {
17 bool error;
18 QString str;
19
20 ResolvedEvaluatorInfo()
21 : error(false)
22 {}
23 };
24
25public:
26 bool evalBool(QScxmlExecutableContent::EvaluatorId id, bool *ok)
27 {
28 Q_Q(QScxmlNullDataModel);
29 Q_ASSERT(ok);
30
31 ResolvedEvaluatorInfo info;
32 Resolved::const_iterator it = resolved.find(key: id);
33 if (it == resolved.end()) {
34 info = prepare(id);
35 } else {
36 info = it.value();
37 }
38
39 if (info.error) {
40 *ok = false;
41 QScxmlStateMachinePrivate::get(t: q->stateMachine())->submitError(QStringLiteral("error.execution"), msg: info.str);
42 return false;
43 }
44
45 *ok = true;
46 return q->stateMachine()->isActive(scxmlStateName: info.str);
47 }
48
49 ResolvedEvaluatorInfo prepare(QScxmlExecutableContent::EvaluatorId id)
50 {
51 auto td = m_stateMachine->tableData();
52 const QScxmlExecutableContent::EvaluatorInfo &info = td->evaluatorInfo(evaluatorId: id);
53 QString expr = td->string(id: info.expr);
54 for (int i = 0; i < expr.size(); ) {
55 QChar ch = expr.at(i);
56 if (ch.isSpace()) {
57 expr.remove(i, len: 1);
58 } else {
59 ++i;
60 }
61 }
62
63 ResolvedEvaluatorInfo resolved;
64 if (expr.startsWith(QStringLiteral("In(")) && expr.endsWith(c: QLatin1Char(')'))) {
65 resolved.error = false;
66 resolved.str = expr.mid(position: 3, n: expr.size() - 4);
67 } else {
68 resolved.error = true;
69 resolved.str = QStringLiteral("%1 in %2").arg(args&: expr, args: td->string(id: info.context));
70 }
71 return resolved;
72 }
73
74private:
75 typedef QHash<QScxmlExecutableContent::EvaluatorId, ResolvedEvaluatorInfo> Resolved;
76 Resolved resolved;
77};
78
79/*!
80 * \class QScxmlNullDataModel
81 * \brief The QScxmlNullDataModel class is the null data model for a Qt SCXML
82 * stateMachine.
83 * \since 5.7
84 * \inmodule QtScxml
85 *
86 * This class implements the null data model as described in the
87 * \l {SCXML Specification - B.1 The Null Data Model}. Using the value \c "null"
88 * for the \e datamodel attribute of the \c <scxml> element means that there is
89 * no underlying data model, but some executable content, like \c In(...) or
90 * \c <log> can still be used.
91 *
92 * \sa QScxmlStateMachine QScxmlDataModel
93 */
94
95/*!
96 * Creates a new Qt SCXML null data model, with the parent object \a parent.
97 */
98QScxmlNullDataModel::QScxmlNullDataModel(QObject *parent)
99 : QScxmlDataModel(*(new QScxmlNullDataModelPrivate), parent)
100{}
101
102/*!
103 Destroys the data model.
104 */
105QScxmlNullDataModel::~QScxmlNullDataModel()
106{
107}
108
109/*!
110 \reimp
111 */
112bool QScxmlNullDataModel::setup(const QVariantMap &initialDataValues)
113{
114 Q_UNUSED(initialDataValues);
115
116 return true;
117}
118
119/*!
120 \reimp
121 Evaluates the executable content pointed to by \a id and records in \a ok
122 whether there was an error. Returns the result of the evaluation as a string.
123 The null data model can evaluate the \c <log> element, so this might result in
124 an actual value, rather than an error
125 */
126QString QScxmlNullDataModel::evaluateToString(QScxmlExecutableContent::EvaluatorId id, bool *ok)
127{
128 Q_D(QScxmlNullDataModel);
129 // We do implement this, because <log> is allowed in the Null data model,
130 // and <log> has an expr attribute that needs "evaluation" for it to generate the log message.
131 *ok = true;
132 auto td = d->m_stateMachine->tableData();
133 const QScxmlExecutableContent::EvaluatorInfo &info = td->evaluatorInfo(evaluatorId: id);
134 return td->string(id: info.expr);
135}
136
137/*!
138 \reimp
139 Evaluates the executable content pointed to by \a id and records in \a ok
140 whether there was an error. Returns the result of the evaluation as a boolean
141 value. The null data model can evaluate the instruction \c In(...), so this
142 might result in an actual value, rather than an error.
143 */
144bool QScxmlNullDataModel::evaluateToBool(QScxmlExecutableContent::EvaluatorId id, bool *ok)
145{
146 Q_D(QScxmlNullDataModel);
147 return d->evalBool(id, ok);
148}
149
150/*!
151 \reimp
152 Evaluates the executable content pointed to by \a id and records in \a ok
153 whether there was an error. As this is the null data model, any evaluation will in
154 fact result in an error, with \a ok set to \c false. Returns an empty QVariant.
155 */
156QVariant QScxmlNullDataModel::evaluateToVariant(QScxmlExecutableContent::EvaluatorId id, bool *ok)
157{
158 Q_UNUSED(id);
159 *ok = false;
160 QScxmlStateMachinePrivate::get(t: stateMachine())->submitError(
161 QStringLiteral("error.execution"),
162 QStringLiteral("Cannot evaluate expressions on a null data model"));
163 return QVariant();
164}
165
166/*!
167 \reimp
168 Evaluates the executable content pointed to by \a id and records in \a ok
169 whether there was an error. As this is the null data model, any evaluation will in
170 fact result in an error, with \a ok set to \c false.
171 */
172void QScxmlNullDataModel::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, bool *ok)
173{
174 Q_UNUSED(id);
175 *ok = false;
176 QScxmlStateMachinePrivate::get(t: stateMachine())->submitError(
177 QStringLiteral("error.execution"),
178 QStringLiteral("Cannot evaluate expressions on a null data model"));
179}
180
181/*!
182 \reimp
183 Throws an error and sets \a ok to \c false, because the null data model cannot evaluate
184 assignments.
185 */
186void QScxmlNullDataModel::evaluateAssignment(QScxmlExecutableContent::EvaluatorId id, bool *ok)
187{
188 Q_UNUSED(id);
189 *ok = false;
190 QScxmlStateMachinePrivate::get(t: stateMachine())->submitError(
191 QStringLiteral("error.execution"),
192 QStringLiteral("Cannot assign values on a null data model"));
193}
194
195/*!
196 \reimp
197 Throws an error and sets \a ok to \c false, because the null data model cannot
198 initialize data.
199 */
200void QScxmlNullDataModel::evaluateInitialization(QScxmlExecutableContent::EvaluatorId id, bool *ok)
201{
202 Q_UNUSED(id);
203 *ok = false;
204 QScxmlStateMachinePrivate::get(t: stateMachine())->submitError(
205 QStringLiteral("error.execution"),
206 QStringLiteral("Cannot initialize values on a null data model"));
207}
208
209/*!
210 \reimp
211 Throws an error and sets \a ok to \c false, because the null data model cannot
212 evaluate \c <foreach> blocks.
213 */
214void QScxmlNullDataModel::evaluateForeach(QScxmlExecutableContent::EvaluatorId id, bool *ok,
215 ForeachLoopBody *body)
216{
217 Q_UNUSED(id);
218 Q_UNUSED(body);
219 *ok = false;
220 QScxmlStateMachinePrivate::get(t: stateMachine())->submitError(
221 QStringLiteral("error.execution"),
222 QStringLiteral("Cannot run foreach on a null data model"));
223}
224
225/*!
226 * \reimp
227 * Does not actually set the \a event, because the null data model does not handle events.
228 */
229void QScxmlNullDataModel::setScxmlEvent(const QScxmlEvent &event)
230{
231 Q_UNUSED(event);
232}
233
234/*!
235 * \reimp
236 * Returns an invalid variant, because the null data model does not support
237 * properties.
238 */
239QVariant QScxmlNullDataModel::scxmlProperty(const QString &name) const
240{
241 Q_UNUSED(name);
242 return QVariant();
243}
244
245/*!
246 * \reimp
247 * Returns \c false, because the null data model does not support properties.
248 */
249bool QScxmlNullDataModel::hasScxmlProperty(const QString &name) const
250{
251 Q_UNUSED(name);
252 return false;
253}
254
255/*!
256 * \reimp
257 * Returns \c false, because the null data model does not support properties.
258 */
259bool QScxmlNullDataModel::setScxmlProperty(const QString &name, const QVariant &value, const QString &context)
260{
261 Q_UNUSED(name);
262 Q_UNUSED(value);
263 Q_UNUSED(context);
264 return false;
265}
266
267QT_END_NAMESPACE
268

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