diff options
Diffstat (limited to 'src/qml/jsapi/qjsengine.h')
-rw-r--r-- | src/qml/jsapi/qjsengine.h | 349 |
1 files changed, 293 insertions, 56 deletions
diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h index 6300842341..b1c99db220 100644 --- a/src/qml/jsapi/qjsengine.h +++ b/src/qml/jsapi/qjsengine.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QJSENGINE_H #define QJSENGINE_H @@ -45,8 +9,9 @@ #include <QtCore/qvariant.h> #include <QtCore/qsharedpointer.h> #include <QtCore/qobject.h> +#include <QtCore/qtimezone.h> #include <QtQml/qjsvalue.h> - +#include <QtQml/qjsmanagedvalue.h> #include <QtQml/qqmldebug.h> QT_BEGIN_NAMESPACE @@ -60,6 +25,7 @@ class Q_QML_EXPORT QJSEngine : public QObject { Q_OBJECT + Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage NOTIFY uiLanguageChanged) public: QJSEngine(); explicit QJSEngine(QObject *parent); @@ -67,11 +33,13 @@ public: QJSValue globalObject() const; - QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1, QStringList *exceptionStackTrace = nullptr); QJSValue importModule(const QString &fileName); + bool registerModule(const QString &moduleName, const QJSValue &value); QJSValue newObject(); + QJSValue newSymbol(const QString &name); QJSValue newArray(uint length = 0); QJSValue newQObject(QObject *object); @@ -89,19 +57,230 @@ public: template <typename T> inline QJSValue toScriptValue(const T &value) { - return create(qMetaTypeId<T>(), &value); + return create(QMetaType::fromType<T>(), &value); + } + + template <typename T> + inline QJSManagedValue toManagedValue(const T &value) + { + return createManaged(QMetaType::fromType<T>(), &value); + } + + template <typename T> + inline QJSPrimitiveValue toPrimitiveValue(const T &value) + { + // In the common case that the argument fits into QJSPrimitiveValue, use it. + if constexpr (std::disjunction_v< + std::is_same<T, int>, + std::is_same<T, bool>, + std::is_same<T, double>, + std::is_same<T, QString>>) { + return QJSPrimitiveValue(value); + } else { + return createPrimitive(QMetaType::fromType<T>(), &value); + } } + template <typename T> inline T fromScriptValue(const QJSValue &value) { return qjsvalue_cast<T>(value); } + template <typename T> + inline T fromManagedValue(const QJSManagedValue &value) + { + return qjsvalue_cast<T>(value); + } + + template <typename T> + inline T fromPrimitiveValue(const QJSPrimitiveValue &value) + { + if constexpr (std::is_same_v<T, int>) + return value.toInteger(); + if constexpr (std::is_same_v<T, bool>) + return value.toBoolean(); + if constexpr (std::is_same_v<T, double>) + return value.toDouble(); + if constexpr (std::is_same_v<T, QString>) + return value.toString(); + if constexpr (std::is_same_v<T, QVariant>) + return value.toVariant(); + if constexpr (std::is_pointer_v<T>) + return nullptr; + return qjsvalue_cast<T>(value); + } + + template <typename T> + inline T fromVariant(const QVariant &value) + { + if constexpr (std::is_same_v<T, QVariant>) + return value; + + const QMetaType sourceType = value.metaType(); + const QMetaType targetType = QMetaType::fromType<T>(); + if (sourceType == targetType) + return *reinterpret_cast<const T *>(value.constData()); + + if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) { + using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *; + const QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>(); + if (value.metaType() == nonConstTargetType) + return *reinterpret_cast<const nonConstT *>(value.constData()); + } + + if constexpr (std::is_same_v<T, QJSValue>) + return toScriptValue(value); + + if constexpr (std::is_same_v<T, QJSManagedValue>) + return toManagedValue(value); + + if constexpr (std::is_same_v<T, QJSPrimitiveValue>) + return toPrimitiveValue(value); + + if constexpr (std::is_same_v<T, QString>) { + if (sourceType.flags() & QMetaType::PointerToQObject) { + return convertQObjectToString( + *reinterpret_cast<QObject *const *>(value.constData())); + } + } + + if constexpr (std::is_same_v<QObject, std::remove_const_t<std::remove_pointer_t<T>>>) { + if (sourceType.flags() & QMetaType::PointerToQObject) { + return *static_cast<QObject *const *>(value.constData()); + + // We should not access source->metaObject() here since that may trigger some + // rather involved code. convertVariant() can do this using property caches. + } + } + + if (sourceType == QMetaType::fromType<QJSValue>()) + return fromScriptValue<T>(*reinterpret_cast<const QJSValue *>(value.constData())); + + if (sourceType == QMetaType::fromType<QJSManagedValue>()) { + return fromManagedValue<T>( + *reinterpret_cast<const QJSManagedValue *>(value.constData())); + } + + if (sourceType == QMetaType::fromType<QJSPrimitiveValue>()) { + return fromPrimitiveValue<T>( + *reinterpret_cast<const QJSPrimitiveValue *>(value.constData())); + } + + { + T t{}; + if (value.metaType() == QMetaType::fromType<QString>()) { + if (convertString(value.toString(), targetType, &t)) + return t; + } else if (convertVariant(value, targetType, &t)) { + return t; + } + + QMetaType::convert(value.metaType(), value.constData(), targetType, &t); + return t; + } + } + + template<typename From, typename To> + inline To coerceValue(const From &from) + { + if constexpr (std::is_base_of_v<To, From>) + return from; + + if constexpr (std::is_same_v<To, QJSValue>) + return toScriptValue(from); + + if constexpr (std::is_same_v<From, QJSValue>) + return fromScriptValue<To>(from); + + if constexpr (std::is_same_v<To, QJSManagedValue>) + return toManagedValue(from); + + if constexpr (std::is_same_v<From, QJSManagedValue>) + return fromManagedValue<To>(from); + + if constexpr (std::is_same_v<To, QJSPrimitiveValue>) + return toPrimitiveValue(from); + + if constexpr (std::is_same_v<From, QJSPrimitiveValue>) + return fromPrimitiveValue<To>(from); + + if constexpr (std::is_same_v<From, QVariant>) + return fromVariant<To>(from); + + if constexpr (std::is_same_v<To, QVariant>) + return QVariant::fromValue(from); + + if constexpr (std::is_same_v<To, QString>) { + if constexpr (std::is_base_of_v<QObject, std::remove_const_t<std::remove_pointer_t<From>>>) + return convertQObjectToString(from); + } + + if constexpr (std::is_same_v<From, QDateTime>) { + if constexpr (std::is_same_v<To, QDate>) + return convertDateTimeToDate(from.toLocalTime()); + if constexpr (std::is_same_v<To, QTime>) + return from.toLocalTime().time(); + if constexpr (std::is_same_v<To, QString>) + return convertDateTimeToString(from.toLocalTime()); + if constexpr (std::is_same_v<To, double>) + return convertDateTimeToNumber(from.toLocalTime()); + } + + if constexpr (std::is_same_v<From, QDate>) { + if constexpr (std::is_same_v<To, QDateTime>) + return from.startOfDay(QTimeZone::UTC); + if constexpr (std::is_same_v<To, QTime>) { + // This is the current time zone offset, for better or worse + return coerceValue<QDateTime, QTime>(coerceValue<QDate, QDateTime>(from)); + } + if constexpr (std::is_same_v<To, QString>) + return convertDateTimeToString(coerceValue<QDate, QDateTime>(from)); + if constexpr (std::is_same_v<To, double>) + return convertDateTimeToNumber(coerceValue<QDate, QDateTime>(from)); + } + + if constexpr (std::is_same_v<From, QTime>) { + if constexpr (std::is_same_v<To, QDate>) { + // Yes. April Fools' 1971. See qv4dateobject.cpp. + return from.isValid() ? QDate(1971, 4, 1) : QDate(); + } + + if constexpr (std::is_same_v<To, QDateTime>) + return QDateTime(coerceValue<QTime, QDate>(from), from, QTimeZone::LocalTime); + if constexpr (std::is_same_v<To, QString>) + return convertDateTimeToString(coerceValue<QTime, QDateTime>(from)); + if constexpr (std::is_same_v<To, double>) + return convertDateTimeToNumber(coerceValue<QTime, QDateTime>(from)); + } + + if constexpr (std::is_same_v<To, std::remove_const_t<std::remove_pointer_t<To>> const *>) { + using nonConstTo = std::remove_const_t<std::remove_pointer_t<To>> *; + if constexpr (std::is_same_v<From, nonConstTo>) + return from; + } + + { + const QMetaType sourceType = QMetaType::fromType<From>(); + const QMetaType targetType = QMetaType::fromType<To>(); + To to{}; + if constexpr (std::is_same_v<From, QString>) { + if (convertString(from, targetType, &to)) + return to; + } else if (convertMetaType(sourceType, &from, targetType, &to)) { + return to; + } + + QMetaType::convert(sourceType, &from, targetType, &to); + return to; + } + } + void collectGarbage(); -#if QT_DEPRECATED_SINCE(5, 6) - QT_DEPRECATED void installTranslatorFunctions(const QJSValue &object = QJSValue()); -#endif + enum ObjectOwnership { CppOwnership, JavaScriptOwnership }; + static void setObjectOwnership(QObject *, ObjectOwnership); + static ObjectOwnership objectOwnership(QObject *); enum Extension { TranslationExtension = 0x1, @@ -113,17 +292,56 @@ public: void installExtensions(Extensions extensions, const QJSValue &object = QJSValue()); + void setInterrupted(bool interrupted); + bool isInterrupted() const; + QV4::ExecutionEngine *handle() const { return m_v4Engine; } void throwError(const QString &message); void throwError(QJSValue::ErrorType errorType, const QString &message = QString()); + void throwError(const QJSValue &error); + bool hasError() const; + QJSValue catchError(); + + QString uiLanguage() const; + void setUiLanguage(const QString &language); + +Q_SIGNALS: + void uiLanguageChanged(); private: - QJSValue create(int type, const void *ptr); + QJSPrimitiveValue createPrimitive(QMetaType type, const void *ptr); + QJSManagedValue createManaged(QMetaType type, const void *ptr); + QJSValue create(QMetaType type, const void *ptr); +#if QT_QML_REMOVED_SINCE(6, 5) + QJSValue create(int id, const void *ptr); // only there for BC reasons +#endif + + static bool convertPrimitive(const QJSPrimitiveValue &value, QMetaType type, void *ptr); + static bool convertManaged(const QJSManagedValue &value, int type, void *ptr); + static bool convertManaged(const QJSManagedValue &value, QMetaType type, void *ptr); +#if QT_QML_REMOVED_SINCE(6, 5) + static bool convertV2(const QJSValue &value, int type, void *ptr); // only there for BC reasons +#endif + static bool convertV2(const QJSValue &value, QMetaType metaType, void *ptr); + static bool convertString(const QString &string, QMetaType metaType, void *ptr); + + bool convertVariant(const QVariant &value, QMetaType metaType, void *ptr); + bool convertMetaType(QMetaType fromType, const void *from, QMetaType toType, void *to); - static bool convertV2(const QJSValue &value, int type, void *ptr); + QString convertQObjectToString(QObject *object); + QString convertDateTimeToString(const QDateTime &dateTime); + double convertDateTimeToNumber(const QDateTime &dateTime); + static QDate convertDateTimeToDate(const QDateTime &dateTime); - friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *); + template<typename T> + friend inline T qjsvalue_cast(const QJSValue &); + + template<typename T> + friend inline T qjsvalue_cast(const QJSManagedValue &); + + template<typename T> + friend inline T qjsvalue_cast(const QJSPrimitiveValue &); protected: QJSEngine(QJSEnginePrivate &dd, QObject *parent = nullptr); @@ -136,23 +354,30 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(QJSEngine::Extensions) -inline bool qjsvalue_cast_helper(const QJSValue &value, int type, void *ptr) +template<typename T> +T qjsvalue_cast(const QJSValue &value) { - return QJSEngine::convertV2(value, type, ptr); + if (T t; QJSEngine::convertV2(value, QMetaType::fromType<T>(), &t)) + return t; + return qvariant_cast<T>(value.toVariant()); } template<typename T> -T qjsvalue_cast(const QJSValue &value) +T qjsvalue_cast(const QJSManagedValue &value) { - T t; - const int id = qMetaTypeId<T>(); + if (T t; QJSEngine::convertManaged(value, QMetaType::fromType<T>(), &t)) + return t; - if (qjsvalue_cast_helper(value, id, &t)) + return qvariant_cast<T>(value.toVariant()); +} + +template<typename T> +T qjsvalue_cast(const QJSPrimitiveValue &value) +{ + if (T t; QJSEngine::convertPrimitive(value, QMetaType::fromType<T>(), &t)) return t; - else if (value.isVariant()) - return qvariant_cast<T>(value.toVariant()); - return T(); + return qvariant_cast<T>(value.toVariant()); } template <> @@ -161,6 +386,18 @@ inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value) return value.toVariant(); } +template <> +inline QVariant qjsvalue_cast<QVariant>(const QJSManagedValue &value) +{ + return value.toVariant(); +} + +template <> +inline QVariant qjsvalue_cast<QVariant>(const QJSPrimitiveValue &value) +{ + return value.toVariant(); +} + Q_QML_EXPORT QJSEngine *qjsEngine(const QObject *); QT_END_NAMESPACE |