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 "qscxmldatamodel_p.h" |
5 | #include "qscxmlnulldatamodel.h" |
6 | #include "qscxmlstatemachine_p.h" |
7 | |
8 | #include <QtCore/private/qfactoryloader_p.h> |
9 | #include "qscxmldatamodelplugin_p.h" |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, |
14 | ("org.qt-project.qt.scxml.datamodel.plugin" , |
15 | QStringLiteral("/scxmldatamodel" ))) |
16 | |
17 | /*! |
18 | \class QScxmlDataModel::ForeachLoopBody |
19 | \brief The ForeachLoopBody class represents a function to be executed on |
20 | each iteration of an SCXML foreach loop. |
21 | \since 5.8 |
22 | \inmodule QtScxml |
23 | */ |
24 | |
25 | /*! |
26 | Creates a new foreach loop body. |
27 | */ |
28 | QScxmlDataModel::ForeachLoopBody::ForeachLoopBody() |
29 | {} |
30 | /*! |
31 | Destroys a foreach loop body. |
32 | */ |
33 | QScxmlDataModel::ForeachLoopBody::~ForeachLoopBody() |
34 | {} |
35 | |
36 | /*! |
37 | \fn QScxmlDataModel::ForeachLoopBody::run(bool *ok) |
38 | |
39 | This function is executed on each iteration. If the execution fails, \a ok is |
40 | set to \c false, otherwise it is set to \c true. |
41 | */ |
42 | |
43 | /*! |
44 | * \class QScxmlDataModel |
45 | * \brief The QScxmlDataModel class is the data model base class for a Qt SCXML |
46 | * state machine. |
47 | * \since 5.7 |
48 | * \inmodule QtScxml |
49 | * |
50 | * SCXML data models are described in |
51 | * \l {SCXML Specification - 5 Data Model and Data Manipulation}. For more |
52 | * information about supported data models, see \l {SCXML Compliance}. |
53 | * |
54 | * One data model can only belong to one state machine. |
55 | * |
56 | * \sa QScxmlStateMachine QScxmlCppDataModel QScxmlNullDataModel |
57 | */ |
58 | |
59 | /*! |
60 | \property QScxmlDataModel::stateMachine |
61 | |
62 | \brief The state machine this data model belongs to. |
63 | |
64 | A data model can only belong to a single state machine and a state machine |
65 | can only have one data model. This relation needs to be set up before the |
66 | state machine is started. Setting this property on a data model will |
67 | automatically set the corresponding \c dataModel property on the |
68 | \a stateMachine. |
69 | */ |
70 | |
71 | /*! |
72 | * Creates a new data model, with the parent object \a parent. |
73 | */ |
74 | QScxmlDataModel::QScxmlDataModel(QObject *parent) |
75 | : QObject(*(new QScxmlDataModelPrivate), parent) |
76 | { |
77 | } |
78 | |
79 | /*! |
80 | Creates a new data model from the private object \a dd, with the parent |
81 | object \a parent. |
82 | */ |
83 | QScxmlDataModel::QScxmlDataModel(QScxmlDataModelPrivate &dd, QObject *parent) : |
84 | QObject(dd, parent) |
85 | { |
86 | } |
87 | |
88 | /*! |
89 | * Sets the state machine this model belongs to to \a stateMachine. There is a |
90 | * 1:1 relation between state machines and models. After setting the state |
91 | * machine once you cannot change it anymore. Any further attempts to set the |
92 | * state machine using this method will be ignored. |
93 | */ |
94 | void QScxmlDataModel::setStateMachine(QScxmlStateMachine *stateMachine) |
95 | { |
96 | Q_D(QScxmlDataModel); |
97 | |
98 | if (d->m_stateMachine.value() == nullptr && stateMachine != nullptr) { |
99 | // the binding is removed only on the first valid set |
100 | // as the later attempts are ignored (removed when value is set below) |
101 | d->m_stateMachine = stateMachine; |
102 | stateMachine->setDataModel(this); |
103 | d->m_stateMachine.notify(); |
104 | } |
105 | } |
106 | |
107 | /*! |
108 | * Returns the state machine associated with the data model. |
109 | */ |
110 | QScxmlStateMachine *QScxmlDataModel::stateMachine() const |
111 | { |
112 | Q_D(const QScxmlDataModel); |
113 | return d->m_stateMachine; |
114 | } |
115 | |
116 | QBindable<QScxmlStateMachine*> QScxmlDataModel::bindableStateMachine() |
117 | { |
118 | Q_D(QScxmlDataModel); |
119 | return &d->m_stateMachine; |
120 | } |
121 | |
122 | /*! |
123 | * Creates a data model from a plugin specified by a \a pluginKey. |
124 | */ |
125 | QScxmlDataModel *QScxmlDataModel::createScxmlDataModel(const QString& pluginKey) |
126 | { |
127 | QScxmlDataModel *model = nullptr; |
128 | |
129 | int pluginIndex = loader()->indexOf(needle: pluginKey); |
130 | |
131 | if (QObject *object = loader()->instance(index: pluginIndex)) { |
132 | if (auto *plugin = qobject_cast<QScxmlDataModelPlugin *>(object)) { |
133 | model = plugin->createScxmlDataModel(); |
134 | if (!model) |
135 | qWarning() << pluginKey << " data model was not instantiated, createScxmlDataModel() returned null." ; |
136 | |
137 | } else { |
138 | qWarning() << "plugin object for" << pluginKey << "is not a QScxmlDatModelPlugin." ; |
139 | } |
140 | delete object; |
141 | } else { |
142 | qWarning() << pluginKey << " plugin not found." ; |
143 | } |
144 | return model; |
145 | } |
146 | |
147 | QScxmlDataModel *QScxmlDataModelPrivate::instantiateDataModel(DocumentModel::Scxml::DataModelType type) |
148 | { |
149 | QScxmlDataModel *dataModel = nullptr; |
150 | switch (type) { |
151 | case DocumentModel::Scxml::NullDataModel: |
152 | dataModel = new QScxmlNullDataModel; |
153 | break; |
154 | case DocumentModel::Scxml::JSDataModel: |
155 | dataModel = QScxmlDataModel::createScxmlDataModel(QStringLiteral("ecmascriptdatamodel" )); |
156 | break; |
157 | case DocumentModel::Scxml::CppDataModel: |
158 | break; |
159 | default: |
160 | Q_UNREACHABLE(); |
161 | } |
162 | return dataModel; |
163 | } |
164 | |
165 | /*! |
166 | * \fn QScxmlDataModel::setup(const QVariantMap &initialDataValues) |
167 | * |
168 | * Initializes the data model with the initial values specified by |
169 | * \a initialDataValues. |
170 | * |
171 | * Returns \c false if parse errors occur or if any of the initialization steps |
172 | * fail. Returns \c true otherwise. |
173 | */ |
174 | |
175 | /*! |
176 | * \fn QScxmlDataModel::setScxmlEvent(const QScxmlEvent &event) |
177 | * |
178 | * Sets the \a event to use in the subsequent executable content execution. |
179 | */ |
180 | |
181 | /*! |
182 | * \fn QScxmlDataModel::scxmlProperty(const QString &name) const |
183 | * |
184 | * Returns the value of the property \a name. |
185 | */ |
186 | |
187 | /*! |
188 | * \fn QScxmlDataModel::hasScxmlProperty(const QString &name) const |
189 | * |
190 | * Returns \c true if a property with the given \a name exists, \c false |
191 | * otherwise. |
192 | */ |
193 | |
194 | /*! |
195 | * \fn QScxmlDataModel::setScxmlProperty(const QString &name, |
196 | * const QVariant &value, |
197 | * const QString &context) |
198 | * |
199 | * Sets a the value \a value for the property \a name. |
200 | * |
201 | * The \a context is a string that is used in error messages to indicate the |
202 | * location in the SCXML file where the error occurred. |
203 | * |
204 | * Returns \c true if successful or \c false if an error occurred. |
205 | */ |
206 | |
207 | /*! |
208 | * \fn QScxmlDataModel::evaluateToString( |
209 | * QScxmlExecutableContent::EvaluatorId id, bool *ok) |
210 | * Evaluates the executable content pointed to by \a id and sets \a ok to |
211 | * \c false if there was an error or to \c true if there was not. |
212 | * Returns the result of the evaluation as a QString. |
213 | */ |
214 | |
215 | /*! |
216 | * \fn QScxmlDataModel::evaluateToBool(QScxmlExecutableContent::EvaluatorId id, |
217 | * bool *ok) |
218 | * Evaluates the executable content pointed to by \a id and sets \a ok to |
219 | * \c false if there was an error or to \c true if there was not. |
220 | * Returns the result of the evaluation as a boolean value. |
221 | */ |
222 | |
223 | /*! |
224 | * \fn QScxmlDataModel::evaluateToVariant( |
225 | * QScxmlExecutableContent::EvaluatorId id, bool *ok) |
226 | * Evaluates the executable content pointed to by \a id and sets \a ok to |
227 | * \c false if there was an error or to \c true if there was not. |
228 | * Returns the result of the evaluation as a QVariant. |
229 | */ |
230 | |
231 | /*! |
232 | * \fn QScxmlDataModel::evaluateToVoid(QScxmlExecutableContent::EvaluatorId id, |
233 | * bool *ok) |
234 | * Evaluates the executable content pointed to by \a id and sets \a ok to |
235 | * \c false if there was an error or to \c true if there was not. |
236 | * The execution is expected to return no result. |
237 | */ |
238 | |
239 | /*! |
240 | * \fn QScxmlDataModel::evaluateAssignment( |
241 | * QScxmlExecutableContent::EvaluatorId id, bool *ok) |
242 | * Evaluates the assignment pointed to by \a id and sets \a ok to |
243 | * \c false if there was an error or to \c true if there was not. |
244 | */ |
245 | |
246 | /*! |
247 | * \fn QScxmlDataModel::evaluateInitialization( |
248 | * QScxmlExecutableContent::EvaluatorId id, bool *ok) |
249 | * Evaluates the initialization pointed to by \a id and sets \a ok to |
250 | * \c false if there was an error or to \c true if there was not. |
251 | */ |
252 | |
253 | /*! |
254 | * \fn QScxmlDataModel::evaluateForeach( |
255 | * QScxmlExecutableContent::EvaluatorId id, bool *ok, |
256 | * ForeachLoopBody *body) |
257 | * Evaluates the foreach loop pointed to by \a id and sets \a ok to |
258 | * \c false if there was an error or to \c true if there was not. The |
259 | * \a body is executed on each iteration. |
260 | */ |
261 | |
262 | QT_END_NAMESPACE |
263 | |