Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qjsengine.h
Go to the documentation of this file.
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#ifndef QJSENGINE_H
5#define QJSENGINE_H
6
7#include <QtCore/qmetatype.h>
8
9#include <QtCore/qvariant.h>
10#include <QtCore/qsharedpointer.h>
11#include <QtCore/qobject.h>
12#include <QtCore/qtimezone.h>
13#include <QtQml/qjsvalue.h>
14#include <QtQml/qjsmanagedvalue.h>
15#include <QtQml/qqmldebug.h>
16
17QT_BEGIN_NAMESPACE
18
19
20template <typename T>
21inline T qjsvalue_cast(const QJSValue &);
22
23class QJSEnginePrivate;
24class Q_QML_EXPORT QJSEngine
25 : public QObject
26{
27 Q_OBJECT
28 Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage NOTIFY uiLanguageChanged)
29public:
30 QJSEngine();
31 explicit QJSEngine(QObject *parent);
32 ~QJSEngine() override;
33
34 QJSValue globalObject() const;
35
36 QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1, QStringList *exceptionStackTrace = nullptr);
37
38 QJSValue importModule(const QString &fileName);
39 bool registerModule(const QString &moduleName, const QJSValue &value);
40
41 QJSValue newObject();
42 QJSValue newSymbol(const QString &name);
43 QJSValue newArray(uint length = 0);
44
45 QJSValue newQObject(QObject *object);
46
47 QJSValue newQMetaObject(const QMetaObject* metaObject);
48
49 template <typename T>
50 QJSValue newQMetaObject()
51 {
52 return newQMetaObject(&T::staticMetaObject);
53 }
54
55 QJSValue newErrorObject(QJSValue::ErrorType errorType, const QString &message = QString());
56
57 template <typename T>
58 inline QJSValue toScriptValue(const T &value)
59 {
60 return create(QMetaType::fromType<T>(), &value);
61 }
62
63 template <typename T>
64 inline QJSManagedValue toManagedValue(const T &value)
65 {
66 return createManaged(QMetaType::fromType<T>(), &value);
67 }
68
69 template <typename T>
70 inline QJSPrimitiveValue toPrimitiveValue(const T &value)
71 {
72 // In the common case that the argument fits into QJSPrimitiveValue, use it.
73 if constexpr (std::disjunction_v<
74 std::is_same<T, int>,
75 std::is_same<T, bool>,
76 std::is_same<T, double>,
77 std::is_same<T, QString>>) {
78 return QJSPrimitiveValue(value);
79 } else {
80 return createPrimitive(QMetaType::fromType<T>(), &value);
81 }
82 }
83
84 template <typename T>
85 inline T fromScriptValue(const QJSValue &value)
86 {
87 return qjsvalue_cast<T>(value);
88 }
89
90 template <typename T>
91 inline T fromManagedValue(const QJSManagedValue &value)
92 {
93 return qjsvalue_cast<T>(value);
94 }
95
96 template <typename T>
97 inline T fromPrimitiveValue(const QJSPrimitiveValue &value)
98 {
99 if constexpr (std::is_same_v<T, int>)
100 return value.toInteger();
101 if constexpr (std::is_same_v<T, bool>)
102 return value.toBoolean();
103 if constexpr (std::is_same_v<T, double>)
104 return value.toDouble();
105 if constexpr (std::is_same_v<T, QString>)
106 return value.toString();
107 if constexpr (std::is_same_v<T, QVariant>)
108 return value.toVariant();
109 if constexpr (std::is_pointer_v<T>)
110 return nullptr;
111 return qjsvalue_cast<T>(value);
112 }
113
114 template <typename T>
115 inline T fromVariant(const QVariant &value)
116 {
117 if constexpr (std::is_same_v<T, QVariant>)
118 return value;
119
120 const QMetaType sourceType = value.metaType();
121 const QMetaType targetType = QMetaType::fromType<T>();
122 if (sourceType == targetType)
123 return *reinterpret_cast<const T *>(value.constData());
124
125 if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
126 using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
127 const QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
128 if (value.metaType() == nonConstTargetType)
129 return *reinterpret_cast<const nonConstT *>(value.constData());
130 }
131
132 if constexpr (std::is_same_v<T, QJSValue>)
133 return toScriptValue(value);
134
135 if constexpr (std::is_same_v<T, QJSManagedValue>)
136 return toManagedValue(value);
137
138 if constexpr (std::is_same_v<T, QJSPrimitiveValue>)
139 return toPrimitiveValue(value);
140
141 if constexpr (std::is_same_v<T, QString>) {
142 if (sourceType.flags() & QMetaType::PointerToQObject) {
143 return convertQObjectToString(
144 *reinterpret_cast<QObject *const *>(value.constData()));
145 }
146 }
147
148 if constexpr (std::is_same_v<T, double>) {
149 if (sourceType == QMetaType::fromType<int>())
150 return double(*static_cast<const int *>(value.constData()));
151 }
152
153 if constexpr (std::is_same_v<T, int>) {
154 if (sourceType == QMetaType::fromType<double>()) {
155 return QJSNumberCoercion::toInteger(
156 *static_cast<const double *>(value.constData()));
157 }
158 }
159
160 if constexpr (std::is_same_v<QObject, std::remove_const_t<std::remove_pointer_t<T>>>) {
161 if (sourceType.flags() & QMetaType::PointerToQObject) {
162 return *static_cast<QObject *const *>(value.constData());
163
164 // We should not access source->metaObject() here since that may trigger some
165 // rather involved code. convertVariant() can do this using property caches.
166 }
167 }
168
169 if (sourceType == QMetaType::fromType<QJSValue>())
170 return fromScriptValue<T>(*reinterpret_cast<const QJSValue *>(value.constData()));
171
172 if (sourceType == QMetaType::fromType<QJSManagedValue>()) {
173 return fromManagedValue<T>(
174 *reinterpret_cast<const QJSManagedValue *>(value.constData()));
175 }
176
177 if (sourceType == QMetaType::fromType<QJSPrimitiveValue>()) {
178 return fromPrimitiveValue<T>(
179 *reinterpret_cast<const QJSPrimitiveValue *>(value.constData()));
180 }
181
182 {
183 T t{};
184 if (value.metaType() == QMetaType::fromType<QString>()) {
185 if (convertString(value.toString(), targetType, &t))
186 return t;
187 } else if (convertVariant(value, targetType, &t)) {
188 return t;
189 }
190
191 QMetaType::convert(value.metaType(), value.constData(), targetType, &t);
192 return t;
193 }
194 }
195
196 template<typename From, typename To>
197 inline To coerceValue(const From &from)
198 {
199 if constexpr (std::is_base_of_v<To, From>)
200 return from;
201
202 if constexpr (std::is_same_v<To, QJSValue>)
203 return toScriptValue(from);
204
205 if constexpr (std::is_same_v<From, QJSValue>)
206 return fromScriptValue<To>(from);
207
208 if constexpr (std::is_same_v<To, QJSManagedValue>)
209 return toManagedValue(from);
210
211 if constexpr (std::is_same_v<From, QJSManagedValue>)
212 return fromManagedValue<To>(from);
213
214 if constexpr (std::is_same_v<To, QJSPrimitiveValue>)
215 return toPrimitiveValue(from);
216
217 if constexpr (std::is_same_v<From, QJSPrimitiveValue>)
218 return fromPrimitiveValue<To>(from);
219
220 if constexpr (std::is_same_v<From, QVariant>)
221 return fromVariant<To>(from);
222
223 if constexpr (std::is_same_v<To, QVariant>)
224 return QVariant::fromValue(from);
225
226 if constexpr (std::is_same_v<To, QString>) {
227 if constexpr (std::is_base_of_v<QObject, std::remove_const_t<std::remove_pointer_t<From>>>)
228 return convertQObjectToString(from);
229 }
230
231 if constexpr (std::is_same_v<From, QDateTime>) {
232 if constexpr (std::is_same_v<To, QDate>)
233 return convertDateTimeToDate(from.toLocalTime());
234 if constexpr (std::is_same_v<To, QTime>)
235 return from.toLocalTime().time();
236 if constexpr (std::is_same_v<To, QString>)
237 return convertDateTimeToString(from.toLocalTime());
238 if constexpr (std::is_same_v<To, double>)
239 return convertDateTimeToNumber(from.toLocalTime());
240 }
241
242 if constexpr (std::is_same_v<From, QDate>) {
243 if constexpr (std::is_same_v<To, QDateTime>)
244 return from.startOfDay(QTimeZone::UTC);
245 if constexpr (std::is_same_v<To, QTime>) {
246 // This is the current time zone offset, for better or worse
247 return coerceValue<QDateTime, QTime>(coerceValue<QDate, QDateTime>(from));
248 }
249 if constexpr (std::is_same_v<To, QString>)
250 return convertDateTimeToString(coerceValue<QDate, QDateTime>(from));
251 if constexpr (std::is_same_v<To, double>)
252 return convertDateTimeToNumber(coerceValue<QDate, QDateTime>(from));
253 }
254
255 if constexpr (std::is_same_v<From, QTime>) {
256 if constexpr (std::is_same_v<To, QDate>) {
257 // Yes. April Fools' 1971. See qv4dateobject.cpp.
258 return from.isValid() ? QDate(1971, 4, 1) : QDate();
259 }
260
261 if constexpr (std::is_same_v<To, QDateTime>)
262 return QDateTime(coerceValue<QTime, QDate>(from), from, QTimeZone::LocalTime);
263 if constexpr (std::is_same_v<To, QString>)
264 return convertDateTimeToString(coerceValue<QTime, QDateTime>(from));
265 if constexpr (std::is_same_v<To, double>)
266 return convertDateTimeToNumber(coerceValue<QTime, QDateTime>(from));
267 }
268
269 if constexpr (std::is_same_v<To, std::remove_const_t<std::remove_pointer_t<To>> const *>) {
270 using nonConstTo = std::remove_const_t<std::remove_pointer_t<To>> *;
271 if constexpr (std::is_same_v<From, nonConstTo>)
272 return from;
273 }
274
275 if constexpr (std::is_same_v<To, double>) {
276 if constexpr (std::is_same_v<From, int>)
277 return double(from);
278 }
279
280 if constexpr (std::is_same_v<To, int>) {
281 if constexpr (std::is_same_v<From, double>)
282 return QJSNumberCoercion::toInteger(from);
283 }
284
285 {
286 const QMetaType sourceType = QMetaType::fromType<From>();
287 const QMetaType targetType = QMetaType::fromType<To>();
288 To to{};
289 if constexpr (std::is_same_v<From, QString>) {
290 if (convertString(from, targetType, &to))
291 return to;
292 } else if (convertMetaType(sourceType, &from, targetType, &to)) {
293 return to;
294 }
295
296 QMetaType::convert(sourceType, &from, targetType, &to);
297 return to;
298 }
299 }
300
301 void collectGarbage();
302
303 enum ObjectOwnership { CppOwnership, JavaScriptOwnership };
304 static void setObjectOwnership(QObject *, ObjectOwnership);
305 static ObjectOwnership objectOwnership(QObject *);
306
307 enum Extension {
308 TranslationExtension = 0x1,
309 ConsoleExtension = 0x2,
310 GarbageCollectionExtension = 0x4,
311 AllExtensions = 0xffffffff
312 };
313 Q_DECLARE_FLAGS(Extensions, Extension)
314
315 void installExtensions(Extensions extensions, const QJSValue &object = QJSValue());
316
317 void setInterrupted(bool interrupted);
318 bool isInterrupted() const;
319
320 QV4::ExecutionEngine *handle() const { return m_v4Engine; }
321
322 void throwError(const QString &message);
323 void throwError(QJSValue::ErrorType errorType, const QString &message = QString());
324 void throwError(const QJSValue &error);
325 bool hasError() const;
326 QJSValue catchError();
327
328 QString uiLanguage() const;
329 void setUiLanguage(const QString &language);
330
331Q_SIGNALS:
332 void uiLanguageChanged();
333
334private:
335 QJSPrimitiveValue createPrimitive(QMetaType type, const void *ptr);
336 QJSManagedValue createManaged(QMetaType type, const void *ptr);
337 QJSValue create(QMetaType type, const void *ptr);
338#if QT_QML_REMOVED_SINCE(6, 5)
339 QJSValue create(int id, const void *ptr); // only there for BC reasons
340#endif
341
342 static bool convertPrimitive(const QJSPrimitiveValue &value, QMetaType type, void *ptr);
343 static bool convertManaged(const QJSManagedValue &value, int type, void *ptr);
344 static bool convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr);
345#if QT_QML_REMOVED_SINCE(6, 5)
346 static bool convertV2(const QJSValue &value, int type, void *ptr); // only there for BC reasons
347#endif
348 static bool convertV2(const QJSValue &value, QMetaType metaType, void *ptr);
349 static bool convertString(const QString &string, QMetaType metaType, void *ptr);
350
351 bool convertVariant(const QVariant &value, QMetaType metaType, void *ptr);
352 bool convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to);
353
354 QString convertQObjectToString(QObject *object);
355 QString convertDateTimeToString(const QDateTime &dateTime);
356 double convertDateTimeToNumber(const QDateTime &dateTime);
357 static QDate convertDateTimeToDate(const QDateTime &dateTime);
358
359 template<typename T>
360 friend inline T qjsvalue_cast(const QJSValue &);
361
362 template<typename T>
363 friend inline T qjsvalue_cast(const QJSManagedValue &);
364
365 template<typename T>
366 friend inline T qjsvalue_cast(const QJSPrimitiveValue &);
367
368protected:
369 QJSEngine(QJSEnginePrivate &dd, QObject *parent = nullptr);
370
371private:
372 QV4::ExecutionEngine *m_v4Engine;
373 Q_DISABLE_COPY(QJSEngine)
374 Q_DECLARE_PRIVATE(QJSEngine)
375};
376
377Q_DECLARE_OPERATORS_FOR_FLAGS(QJSEngine::Extensions)
378
379template<typename T>
380T qjsvalue_cast(const QJSValue &value)
381{
382 if (T t; QJSEngine::convertV2(value, QMetaType::fromType<T>(), &t))
383 return t;
384 return qvariant_cast<T>(value.toVariant());
385}
386
387template<typename T>
388T qjsvalue_cast(const QJSManagedValue &value)
389{
390 if (T t; QJSEngine::convertManaged(value, QMetaType::fromType<T>(), &t))
391 return t;
392
393 return qvariant_cast<T>(value.toVariant());
394}
395
396template<typename T>
397T qjsvalue_cast(const QJSPrimitiveValue &value)
398{
399 if (T t; QJSEngine::convertPrimitive(value, QMetaType::fromType<T>(), &t))
400 return t;
401
402 return qvariant_cast<T>(value.toVariant());
403}
404
405template <>
406inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value)
407{
408 return value.toVariant();
409}
410
411template <>
412inline QVariant qjsvalue_cast<QVariant>(const QJSManagedValue &value)
413{
414 return value.toVariant();
415}
416
417template <>
418inline QVariant qjsvalue_cast<QVariant>(const QJSPrimitiveValue &value)
419{
420 return value.toVariant();
421}
422
423Q_QML_EXPORT QJSEngine *qjsEngine(const QObject *);
424
425QT_END_NAMESPACE
426
427#endif // QJSENGINE_H
The QJSEngine class provides an environment for evaluating JavaScript code.
Definition qjsengine.h:26
QJSEngine * qjsEngine(const QObject *object)
T qjsvalue_cast(const QJSManagedValue &value)
Definition qjsengine.h:388