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

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