diff options
Diffstat (limited to 'src/qml/qml/v8/qqmlbuiltinfunctions.cpp')
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 1050 |
1 files changed, 382 insertions, 668 deletions
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 7061cf1c86..0610bf0ccc 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -84,145 +84,42 @@ QT_BEGIN_NAMESPACE -using namespace QV4; +Q_LOGGING_CATEGORY(lcRootProperties, "qml.rootObjectProperties"); -DEFINE_OBJECT_VTABLE(QtObject); +using namespace QV4; #define THROW_TYPE_ERROR_WITH_MESSAGE(msg) \ do { \ return scope.engine->throwTypeError(QString::fromUtf8(msg)); \ } while (false) -void Heap::QtObject::init(QQmlEngine *qmlEngine) +QtObject::QtObject(ExecutionEngine *engine) + : m_engine(engine) { - Heap::Object::init(); - enumeratorIterator = 0; - keyIterator = 0; - Scope scope(internalClass->engine); - ScopedObject o(scope, this); - - { - ScopedString str(scope); - ScopedValue v(scope); - o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Value::fromInt32(0))); - o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Value::fromInt32(1))); - } - - o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include); - o->defineDefaultProperty(QStringLiteral("isQtObject"), QV4::QtObject::method_isQtObject); - o->defineDefaultProperty(QStringLiteral("color"), QV4::QtObject::method_color); - o->defineDefaultProperty(QStringLiteral("rgba"), QV4::QtObject::method_rgba); - o->defineDefaultProperty(QStringLiteral("hsla"), QV4::QtObject::method_hsla); - o->defineDefaultProperty(QStringLiteral("hsva"), QV4::QtObject::method_hsva); - o->defineDefaultProperty(QStringLiteral("colorEqual"), QV4::QtObject::method_colorEqual); - o->defineDefaultProperty(QStringLiteral("rect"), QV4::QtObject::method_rect); - o->defineDefaultProperty(QStringLiteral("point"), QV4::QtObject::method_point); - o->defineDefaultProperty(QStringLiteral("size"), QV4::QtObject::method_size); - o->defineDefaultProperty(QStringLiteral("font"), QV4::QtObject::method_font); - - o->defineDefaultProperty(QStringLiteral("vector2d"), QV4::QtObject::method_vector2d); - o->defineDefaultProperty(QStringLiteral("vector3d"), QV4::QtObject::method_vector3d); - o->defineDefaultProperty(QStringLiteral("vector4d"), QV4::QtObject::method_vector4d); - o->defineDefaultProperty(QStringLiteral("quaternion"), QV4::QtObject::method_quaternion); - o->defineDefaultProperty(QStringLiteral("matrix4x4"), QV4::QtObject::method_matrix4x4); - - o->defineDefaultProperty(QStringLiteral("formatDate"), QV4::QtObject::method_formatDate); - o->defineDefaultProperty(QStringLiteral("formatTime"), QV4::QtObject::method_formatTime); - o->defineDefaultProperty(QStringLiteral("formatDateTime"), QV4::QtObject::method_formatDateTime); - - o->defineDefaultProperty(QStringLiteral("openUrlExternally"), QV4::QtObject::method_openUrlExternally); - o->defineDefaultProperty(QStringLiteral("fontFamilies"), QV4::QtObject::method_fontFamilies); - o->defineDefaultProperty(QStringLiteral("md5"), QV4::QtObject::method_md5); - o->defineDefaultProperty(QStringLiteral("btoa"), QV4::QtObject::method_btoa); - o->defineDefaultProperty(QStringLiteral("atob"), QV4::QtObject::method_atob); - o->defineDefaultProperty(QStringLiteral("resolvedUrl"), QV4::QtObject::method_resolvedUrl); -#if QT_CONFIG(qml_locale) - o->defineDefaultProperty(QStringLiteral("locale"), QV4::QtObject::method_locale); -#endif - o->defineDefaultProperty(QStringLiteral("binding"), QV4::QtObject::method_binding); - - if (qmlEngine) { - o->defineDefaultProperty(QStringLiteral("alpha"), QV4::QtObject::method_alpha); - o->defineDefaultProperty(QStringLiteral("lighter"), QV4::QtObject::method_lighter); - o->defineDefaultProperty(QStringLiteral("darker"), QV4::QtObject::method_darker); - o->defineDefaultProperty(QStringLiteral("tint"), QV4::QtObject::method_tint); - o->defineDefaultProperty(QStringLiteral("quit"), QV4::QtObject::method_quit); - o->defineDefaultProperty(QStringLiteral("exit"), QV4::QtObject::method_exit); - o->defineDefaultProperty(QStringLiteral("createQmlObject"), QV4::QtObject::method_createQmlObject); - o->defineDefaultProperty(QStringLiteral("createComponent"), QV4::QtObject::method_createComponent); - } - - o->defineAccessorProperty(QStringLiteral("platform"), QV4::QtObject::method_get_platform, nullptr); - o->defineAccessorProperty(QStringLiteral("application"), QV4::QtObject::method_get_application, nullptr); - o->defineAccessorProperty(QStringLiteral("inputMethod"), QV4::QtObject::method_get_inputMethod, nullptr); - o->defineAccessorProperty(QStringLiteral("styleHints"), QV4::QtObject::method_get_styleHints, nullptr); + QV4::Scope scope(engine); + QV4::ScopedString callLaterName(scope, engine->newIdentifier(QStringLiteral("callLater"))); - o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater); -} + QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createBuiltinFunction( + engine, callLaterName, QQmlDelayedCallQueue::addUniquelyAndExecuteLater, 1)); -void QtObject::addAll() -{ - bool dummy = false; - findAndAdd(nullptr, dummy); + m_callLater = QJSValuePrivate::fromReturnedValue(function.asReturnedValue()); } -ReturnedValue QtObject::findAndAdd(const QString *name, bool &foundProperty) const +QtObject *QtObject::create(QQmlEngine *, QJSEngine *jsEngine) { - Scope scope(engine()); - ScopedObject o(scope, this); - ScopedString key(scope); - ScopedValue value(scope); - - const QMetaObject *qtMetaObject = &Qt::staticMetaObject; - for (int enumCount = qtMetaObject->enumeratorCount(); d()->enumeratorIterator < enumCount; - ++d()->enumeratorIterator) { - QMetaEnum enumerator = qtMetaObject->enumerator(d()->enumeratorIterator); - for (int keyCount = enumerator.keyCount(); d()->keyIterator < keyCount; ++d()->keyIterator) { - key = scope.engine->newString(QString::fromUtf8(enumerator.key(d()->keyIterator))); - value = QV4::Value::fromInt32(enumerator.value(d()->keyIterator)); - o->put(key, value); - if (name && key->toQString() == *name) { - ++d()->keyIterator; - foundProperty = true; - return value->asReturnedValue(); - } - } - d()->keyIterator = 0; - } - d()->enumeratorIterator = Heap::QtObject::Finished; - foundProperty = false; - return Encode::undefined(); + QV4::ExecutionEngine *v4 = jsEngine->handle(); + QV4::Scope scope(v4); + ScopedObject globalObject(scope, v4->globalObject); + ScopedString qtName(scope, v4->newString(QStringLiteral("Qt"))); + QV4::ScopedValue result(scope, globalObject->get(qtName->toPropertyKey())); + return qobject_cast<QtObject *>(result->as<QV4::QObjectWrapper>()->object()); } -ReturnedValue QtObject::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty) +QJSValue QtObject::include(const QString &url, const QJSValue &callback) const { - bool hasProp = false; - if (hasProperty == nullptr) { - hasProperty = &hasProp; - } - - ReturnedValue ret = QV4::Object::virtualGet(m, id, receiver, hasProperty); - if (*hasProperty) { - return ret; - } - - auto that = static_cast<const QtObject*>(m); - if (!that->d()->isComplete()) { - const QString key = id.toQString(); - ret = that->findAndAdd(&key, *hasProperty); - } - - return ret; + return QV4Include::method_include(v4Engine(), v4Engine()->resolvedUrl(url), callback); } -OwnPropertyKeyIterator *QtObject::virtualOwnPropertyKeys(const Object *m, Value *target) -{ - auto that = static_cast<const QtObject*>(m); - if (!that->d()->isComplete()) - const_cast<QtObject *>(that)->addAll(); - - return Object::virtualOwnPropertyKeys(m, target); -} /*! \qmlmethod bool Qt::isQtObject(object) @@ -230,12 +127,9 @@ OwnPropertyKeyIterator *QtObject::virtualOwnPropertyKeys(const Object *m, Value Returns \c true if \a object is a valid reference to a Qt or QML object, \c false otherwise. */ -ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *, const Value *argv, int argc) +bool QtObject::isQtObject(const QJSValue &value) const { - if (argc == 0) - RETURN_RESULT(QV4::Encode(false)); - - return QV4::Encode(argv[0].as<QV4::QObjectWrapper>() != nullptr); + return qjsvalue_cast<QObject *>(value) != nullptr; } /*! @@ -244,25 +138,15 @@ ReturnedValue QtObject::method_isQtObject(const FunctionObject *, const Value *, Returns the color corresponding to the given \a name (i.e. red or #ff0000). If there is no such color, \c null is returned. */ -ReturnedValue QtObject::method_color(const FunctionObject *f, const Value *, const Value *argv, - int argc) +QVariant QtObject::color(const QString &name) const { - QV4::Scope scope(f); - if (argc != 1) - THROW_GENERIC_ERROR("Qt.color(): Qt.color takes exactly one argument"); - - QVariant v = scope.engine->toVariant(argv[0], -1); - if (v.userType() == QMetaType::QString) { - bool ok = false; - v = QQmlStringConverters::colorFromString(v.toString(), &ok); - if (!ok) { - return QV4::Encode::null(); - } - } else { - THROW_GENERIC_ERROR("Qt.color(): Argument must be a string"); - } + bool ok = false; + const QVariant v = QQmlStringConverters::colorFromString(name, &ok); + if (ok) + return v; - return scope.engine->fromVariant(v); + v4Engine()->throwError(QStringLiteral("\"%1\" is not a valid color name").arg(name)); + return QVariant::fromValue(nullptr); } /*! @@ -271,17 +155,8 @@ ReturnedValue QtObject::method_color(const FunctionObject *f, const Value *, con Returns a color with the specified \a red, \a green, \a blue, and \a alpha components. All components should be in the range 0-1 (inclusive). */ -ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, const Value *argv, int argc) +QVariant QtObject::rgba(double r, double g, double b, double a) const { - QV4::Scope scope(f); - if (argc < 3 || argc > 4) - THROW_GENERIC_ERROR("Qt.rgba(): Invalid arguments"); - - double r = argv[0].toNumber(); - double g = argv[1].toNumber(); - double b = argv[2].toNumber(); - double a = (argc == 4) ? argv[3].toNumber() : 1; - if (r < 0.0) r=0.0; if (r > 1.0) r=1.0; if (g < 0.0) g=0.0; @@ -291,7 +166,7 @@ ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, cons if (a < 0.0) a=0.0; if (a > 1.0) a=1.0; - return scope.engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a)); + return QQml_colorProvider()->fromRgbF(r, g, b, a); } /*! @@ -300,18 +175,8 @@ ReturnedValue QtObject::method_rgba(const FunctionObject *f, const Value *, cons Returns a color with the specified \a hue, \a saturation, \a lightness, and \a alpha components. All components should be in the range 0-1 (inclusive). */ -ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::hsla(double h, double s, double l, double a) const { - QV4::Scope scope(b); - int argCount = argc; - if (argCount < 3 || argCount > 4) - THROW_GENERIC_ERROR("Qt.hsla(): Invalid arguments"); - - double h = argv[0].toNumber(); - double s = argv[1].toNumber(); - double l = argv[2].toNumber(); - double a = (argCount == 4) ? argv[3].toNumber() : 1; - if (h < 0.0) h=0.0; if (h > 1.0) h=1.0; if (s < 0.0) s=0.0; @@ -321,7 +186,7 @@ ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, cons if (a < 0.0) a=0.0; if (a > 1.0) a=1.0; - return scope.engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a)); + return QQml_colorProvider()->fromHslF(h, s, l, a); } /*! @@ -332,24 +197,14 @@ ReturnedValue QtObject::method_hsla(const FunctionObject *b, const Value *, cons components. All components should be in the range 0-1 (inclusive). */ -ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::hsva(double h, double s, double v, double a) const { - QV4::Scope scope(b); - int argCount = argc; - if (argCount < 3 || argCount > 4) - THROW_GENERIC_ERROR("Qt.hsva(): Invalid arguments"); - - double h = argv[0].toNumber(); - double s = argv[1].toNumber(); - double v = argv[2].toNumber(); - double a = (argCount == 4) ? argv[3].toNumber() : 1; - h = qBound(0.0, h, 1.0); s = qBound(0.0, s, 1.0); v = qBound(0.0, v, 1.0); a = qBound(0.0, a, 1.0); - return scope.engine->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a)); + return QQml_colorProvider()->fromHsvF(h, s, v, a); } /*! @@ -360,36 +215,35 @@ ReturnedValue QtObject::method_hsva(const FunctionObject *b, const Value *, cons is supplied it must be convertible to a color, as described for the \l{colorbasictypedocs}{color} basic type. */ -ReturnedValue QtObject::method_colorEqual(const FunctionObject *b, const Value *, const Value *argv, int argc) +bool QtObject::colorEqual(const QVariant &lhs, const QVariant &rhs) const { - QV4::Scope scope(b); - if (argc != 2) - THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments"); - bool ok = false; - QVariant lhs = scope.engine->toVariant(argv[0], -1); - if (lhs.userType() == QMetaType::QString) { - lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok); + QVariant color1 = lhs; + if (color1.userType() == QMetaType::QString) { + color1 = QQmlStringConverters::colorFromString(color1.toString(), &ok); if (!ok) { - THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name"); + v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name")); + return false; } - } else if (lhs.userType() != QMetaType::QColor) { - THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments"); + } else if (color1.userType() != QMetaType::QColor) { + v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments")); + return false; } - QVariant rhs = scope.engine->toVariant(argv[1], -1); - if (rhs.userType() == QMetaType::QString) { - rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok); + QVariant color2 = rhs; + if (color2.userType() == QMetaType::QString) { + color2 = QQmlStringConverters::colorFromString(color2.toString(), &ok); if (!ok) { - THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name"); + v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid color name")); + return false; } - } else if (rhs.userType() != QMetaType::QColor) { - THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments"); + } else if (color2.userType() != QMetaType::QColor) { + v4Engine()->throwError(QStringLiteral("Qt.colorEqual(): Invalid arguments")); + return false; } - bool equal = (lhs == rhs); - return QV4::Encode(equal); + return color1 == color2; } /*! @@ -397,18 +251,9 @@ ReturnedValue QtObject::method_colorEqual(const FunctionObject *b, const Value * Returns a rect with the top-left corner at \a x, \a y and the specified \a width and \a height. */ -ReturnedValue QtObject::method_rect(const FunctionObject *b, const Value *, const Value *argv, int argc) +QRectF QtObject::rect(double x, double y, double width, double height) const { - QV4::Scope scope(b); - if (argc != 4) - THROW_GENERIC_ERROR("Qt.rect(): Invalid arguments"); - - double x = argv[0].toNumber(); - double y = argv[1].toNumber(); - double w = argv[2].toNumber(); - double h = argv[3].toNumber(); - - return scope.engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h))); + return QRectF(x, y, width, height); } /*! @@ -416,16 +261,9 @@ ReturnedValue QtObject::method_rect(const FunctionObject *b, const Value *, cons Returns a point with the specified \a x and \a y coordinates. */ -ReturnedValue QtObject::method_point(const FunctionObject *b, const Value *, const Value *argv, int argc) +QPointF QtObject::point(double x, double y) const { - QV4::Scope scope(b); - if (argc != 2) - THROW_GENERIC_ERROR("Qt.point(): Invalid arguments"); - - double x = argv[0].toNumber(); - double y = argv[1].toNumber(); - - return scope.engine->fromVariant(QVariant::fromValue(QPointF(x, y))); + return QPointF(x, y); } /*! @@ -433,16 +271,9 @@ ReturnedValue QtObject::method_point(const FunctionObject *b, const Value *, con Returns a size with the specified \a width and \a height. */ -ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, const Value *argv, int argc) +QSizeF QtObject::size(double w, double h) const { - QV4::Scope scope(b); - if (argc != 2) - THROW_GENERIC_ERROR("Qt.size(): Invalid arguments"); - - double w = argv[0].toNumber(); - double h = argv[1].toNumber(); - - return scope.engine->fromVariant(QVariant::fromValue(QSizeF(w, h))); + return QSizeF(w, h); } /*! @@ -454,37 +285,53 @@ ReturnedValue QtObject::method_size(const FunctionObject *b, const Value *, cons subproperty names, and the values are valid values for each subproperty. Invalid keys will be ignored. */ -ReturnedValue QtObject::method_font(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::font(const QJSValue &fontSpecifier) const { - QV4::Scope scope(b); - if (argc != 1 || !argv[0].isObject()) - THROW_GENERIC_ERROR("Qt.font(): Invalid arguments"); + if (!fontSpecifier.isObject()) { + v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid arguments")); + return QVariant(); + } - QVariant v; - if (!QQml_valueTypeProvider()->createValueType( - QMetaType::QFont, QJSValuePrivate::fromReturnedValue(argv[0].asReturnedValue()), - v)) { - THROW_GENERIC_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified"); + { + QVariant v; + if (QQml_valueTypeProvider()->createValueType(QMetaType::QFont, fontSpecifier, v)) + return v; } - return scope.engine->fromVariant(v); + + v4Engine()->throwError(QStringLiteral("Qt.font(): Invalid argument: " + "no valid font subproperties specified")); + return QVariant(); } -static ReturnedValue createValueType(const FunctionObject *b, const Value *argv, int argc, - int parameters, QMetaType::Type type, const char *method) +template<typename T> +void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter) { - QV4::Scope scope(b); - if (argc != parameters) { - return scope.engine->throwError(QString::fromUtf8("Qt.%1(): Invalid arguments") - .arg(QString::fromUtf8(method))); - } + result.setProperty(i, e->toScriptValue(parameter)); +} - QJSValue params = scope.engine->jsEngine()->newArray(parameters); - for (int i = 0; i < parameters; ++i) - params.setProperty(i, QJSValuePrivate::fromReturnedValue(argv[i].asReturnedValue())); +template<> +void addParameters<double>(QJSEngine *, QJSValue &result, int i, double parameter) +{ + result.setProperty(i, QJSValue(parameter)); +} + +template<typename T, typename ...Others> +void addParameters(QJSEngine *e, QJSValue &result, int i, T parameter, Others... others) +{ + addParameters<T>(e, result, i, parameter); + addParameters<Others...>(e, result, ++i, others...); +} +template<typename ...T> +static QVariant createValueType(QJSEngine *e, QMetaType::Type type, T... parameters) +{ + if (!e) + return QVariant(); + QJSValue params = e->newArray(sizeof...(parameters)); + addParameters(e, params, 0, parameters...); QVariant variant; QQml_valueTypeProvider()->createValueType(type, params, variant); - return scope.engine->fromVariant(variant); + return variant; } /*! @@ -492,9 +339,9 @@ static ReturnedValue createValueType(const FunctionObject *b, const Value *argv, Returns a vector2d with the specified \a x and \a y values. */ -ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::vector2d(double x, double y) const { - return createValueType(b, argv, argc, 2, QMetaType::QVector2D, "vector2d"); + return createValueType(jsEngine(), QMetaType::QVector2D, x, y); } /*! @@ -502,9 +349,9 @@ ReturnedValue QtObject::method_vector2d(const FunctionObject *b, const Value *, Returns a vector3d with the specified \a x, \a y, and \a z values. */ -ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::vector3d(double x, double y, double z) const { - return createValueType(b, argv, argc, 3, QMetaType::QVector3D, "vector3d"); + return createValueType(jsEngine(), QMetaType::QVector3D, x, y, z); } /*! @@ -512,9 +359,9 @@ ReturnedValue QtObject::method_vector3d(const FunctionObject *b, const Value *, Returns a vector4d with the specified \a x, \a y, \a z, and \a w values. */ -ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::vector4d(double x, double y, double z, double w) const { - return createValueType(b, argv, argc, 4, QMetaType::QVector4D, "vector4d"); + return createValueType(jsEngine(), QMetaType::QVector4D, x, y, z, w); } /*! @@ -522,9 +369,9 @@ ReturnedValue QtObject::method_vector4d(const FunctionObject *b, const Value *, Returns a quaternion with the specified \a scalar, \a x, \a y, and \a z values. */ -ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::quaternion(double scalar, double x, double y, double z) const { - return createValueType(b, argv, argc, 4, QMetaType::QQuaternion, "quaternion"); + return createValueType(jsEngine(), QMetaType::QQuaternion, scalar, x, y, z); } /*! @@ -548,27 +395,53 @@ ReturnedValue QtObject::method_quaternion(const FunctionObject *b, const Value * Finally, the function may be called with no arguments and the resulting matrix will be the identity matrix. */ -ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::matrix4x4() const { - QV4::Scope scope(b); + QVariant variant; + QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, QJSValue(), variant); + return variant; +} - if (argc == 0) { - QVariant variant; - QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, QJSValue(), variant); - return scope.engine->fromVariant(variant); +QVariant QtObject::matrix4x4(const QJSValue &value) const +{ + if (value.isObject()) { + QVariant v; + if (QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, value, v)) + return v; } - if (argc == 1 && argv[0].isObject()) { - QVariant v; - if (!QQml_valueTypeProvider()->createValueType( - QMetaType::QMatrix4x4, - QJSValuePrivate::fromReturnedValue(argv[0].asReturnedValue()), v)) { - THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"); + v4Engine()->throwError(QStringLiteral("Qt.matrix4x4(): Invalid argument: " + "not a valid matrix4x4 values array")); + return QVariant(); +} + +QVariant QtObject::matrix4x4(double m11, double m12, double m13, double m14, + double m21, double m22, double m23, double m24, + double m31, double m32, double m33, double m34, + double m41, double m42, double m43, double m44) const +{ + return createValueType(jsEngine(), QMetaType::QMatrix4x4, + m11, m12, m13, m14, m21, m22, m23, m24, + m31, m32, m33, m34, m41, m42, m43, m44); +} + +static QVariant colorVariantFromJSValue(const QJSValue &color, bool *ok) +{ + QVariant v; + if (color.isString()) { + v = QQmlStringConverters::colorFromString(color.toString(), ok); + if (!(*ok)) + return QVariant::fromValue(nullptr); + } else { + v = color.toVariant(); + if (v.userType() != QMetaType::QColor) { + *ok = false; + return QVariant::fromValue(nullptr); } - return scope.engine->fromVariant(v); } - return createValueType(b, argv, argc, 16, QMetaType::QMatrix4x4, "matrix4x4"); + *ok = true; + return v; } /*! @@ -586,28 +459,11 @@ ReturnedValue QtObject::method_matrix4x4(const FunctionObject *b, const Value *, If \a factor is not supplied, returns a color that is 50% lighter than \a baseColor (factor 1.5). */ -ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::lighter(const QJSValue &color, double factor) const { - QV4::Scope scope(b); - if (argc != 1 && argc != 2) - THROW_GENERIC_ERROR("Qt.lighter(): Invalid arguments"); - - QVariant v = scope.engine->toVariant(argv[0], -1); - if (v.userType() == QMetaType::QString) { - bool ok = false; - v = QQmlStringConverters::colorFromString(v.toString(), &ok); - if (!ok) { - return QV4::Encode::null(); - } - } else if (v.userType() != QMetaType::QColor) { - return QV4::Encode::null(); - } - - qreal factor = 1.5; - if (argc == 2) - factor = argv[1].toNumber(); - - return scope.engine->fromVariant(QQml_colorProvider()->lighter(v, factor)); + bool ok; + const QVariant v = colorVariantFromJSValue(color, &ok); + return ok ? QQml_colorProvider()->lighter(v, factor) : v; } /*! @@ -626,28 +482,11 @@ ReturnedValue QtObject::method_lighter(const FunctionObject *b, const Value *, c If \a factor is not supplied, returns a color that is 50% darker than \a baseColor (factor 2.0). */ -ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::darker(const QJSValue &color, double factor) const { - QV4::Scope scope(b); - if (argc != 1 && argc != 2) - THROW_GENERIC_ERROR("Qt.darker(): Invalid arguments"); - - QVariant v = scope.engine->toVariant(argv[0], -1); - if (v.userType() == QMetaType::QString) { - bool ok = false; - v = QQmlStringConverters::colorFromString(v.toString(), &ok); - if (!ok) { - return QV4::Encode::null(); - } - } else if (v.userType() != QMetaType::QColor) { - return QV4::Encode::null(); - } - - qreal factor = 2.0; - if (argc == 2) - factor = argv[1].toNumber(); - - return scope.engine->fromVariant(QQml_colorProvider()->darker(v, factor)); + bool ok; + const QVariant v = colorVariantFromJSValue(color, &ok); + return ok ? QQml_colorProvider()->darker(v, factor) : v; } /*! @@ -657,26 +496,11 @@ ReturnedValue QtObject::method_darker(const FunctionObject *b, const Value *, co \a value is a real ranging from 0 (completely transparent) to 1 (completely opaque). */ -ReturnedValue QtObject::method_alpha(const FunctionObject *b, const Value *, const Value *argv, - int argc) +QVariant QtObject::alpha(const QJSValue &baseColor, double value) const { - QV4::Scope scope(b); - if (argc != 2) - THROW_GENERIC_ERROR("Qt.alpha(): Wrong number of arguments provided"); - - QVariant v = scope.engine->toVariant(argv[0], -1); - if (v.userType() == QMetaType::QString) { - bool ok = false; - v = QQmlStringConverters::colorFromString(v.toString(), &ok); - if (!ok) - return QV4::Encode::null(); - } else if (v.userType() != QMetaType::QColor) { - return QV4::Encode::null(); - } - - qreal value = argv[1].toNumber(); - - return scope.engine->fromVariant(QQml_colorProvider()->alpha(v, value)); + bool ok; + const QVariant v = colorVariantFromJSValue(baseColor, &ok); + return ok ? QQml_colorProvider()->alpha(v, value) : v; } /*! @@ -705,37 +529,19 @@ ReturnedValue QtObject::method_alpha(const FunctionObject *b, const Value *, con Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color. */ -ReturnedValue QtObject::method_tint(const FunctionObject *b, const Value *, const Value *argv, int argc) +QVariant QtObject::tint(const QJSValue &baseColor, const QJSValue &tintColor) const { - QV4::Scope scope(b); - if (argc != 2) - THROW_GENERIC_ERROR("Qt.tint(): Invalid arguments"); + bool ok; // base color - QVariant v1 = scope.engine->toVariant(argv[0], -1); - if (v1.userType() == QMetaType::QString) { - bool ok = false; - v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok); - if (!ok) { - return QV4::Encode::null(); - } - } else if (v1.userType() != QMetaType::QColor) { - return QV4::Encode::null(); - } + const QVariant v1 = colorVariantFromJSValue(baseColor, &ok); + if (!ok) + return v1; // tint color - QVariant v2 = scope.engine->toVariant(argv[1], -1); - if (v2.userType() == QMetaType::QString) { - bool ok = false; - v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok); - if (!ok) { - return QV4::Encode::null(); - } - } else if (v2.userType() != QMetaType::QColor) { - return QV4::Encode::null(); - } + const QVariant v2 = colorVariantFromJSValue(tintColor, &ok); - return scope.engine->fromVariant(QQml_colorProvider()->tint(v1, v2)); + return ok ? QQml_colorProvider()->tint(v1, v2) : v2; } namespace { @@ -753,46 +559,6 @@ QString formatDateTimeObjectUsingDateFormat(T formatThis, Qt::DateFormat format) // Q_UNREACHABLE(); // ### Qt 6: restore once the default is gone return QString(); } - -template <typename T> -ReturnedValue formatDateTimeObject(const T &formatThis, const QV4::Scope &scope, const QString &functionName, int argc, const Value *argv) { - - QString formatted; - if (argc >= 2) { - QV4::ScopedString s(scope, argv[1]); - if (s) { - if (argc == 3) - scope.engine->throwError(QLatin1String("%1(): Stay argument, third argument can only be used if second argument is a locale").arg(functionName)); - QString format = s->toQString(); - formatted = formatThis.toString(format); - } else if (argv[1].isNumber()) { - if (argc == 3) - scope.engine->throwError(QLatin1String("%1(): Stay argument, third argument can only be used if second argument is a locale").arg(functionName)); - quint32 intFormat = argv[1].asDouble(); - Qt::DateFormat format = Qt::DateFormat(intFormat); - formatted = formatDateTimeObjectUsingDateFormat(formatThis, format); - } else { - QLocale::FormatType formatOptions = QLocale::ShortFormat; - if (argc == 3) { - if (argv[2].isNumber()) - formatOptions = QLocale::FormatType(quint32(argv[2].asDouble())); - else - scope.engine->throwError(QLatin1String("%1(): Third argument must be a Locale format option").arg(functionName)); - } - auto enginePriv = QQmlEnginePrivate::get(scope.engine->qmlEngine()); - auto localeMetaTypeId = qMetaTypeId<QLocale>(); - QVariant locale = enginePriv->v4engine()->toVariant(argv[1], localeMetaTypeId); - if (!locale.canConvert(QMetaType(localeMetaTypeId))) - scope.engine->throwError(QLatin1String("%1(): Bad second argument (must be either string, number or locale)").arg(functionName)); - formatted = locale.value<QLocale>().toString(formatThis, formatOptions); - } - } else { - formatted = QLocale().toString(formatThis, QLocale::ShortFormat); - } - - return Encode(scope.engine->newString(formatted)); -} - } /*! @@ -811,17 +577,23 @@ default locale. \sa Locale */ -ReturnedValue QtObject::method_formatDate(const FunctionObject *b, const Value *, const Value *argv, int argc) +QString QtObject::formatDate(const QDate &date, const QString &format) const { - QV4::Scope scope(b); - if (argc < 1) - THROW_GENERIC_ERROR("Qt.formatDate(): Missing argument"); - if (argc > 3) - THROW_GENERIC_ERROR("Qt.formatDate(): Stray arguments; formatDate takes at most 3 arguments."); + return date.toString(format); +} - QDate date = scope.engine->toVariant(argv[0], -1).toDateTime().date(); - return formatDateTimeObject(date, scope, QLatin1String("Qt.formatDate"), argc, argv); +QString QtObject::formatDate(const QDate &date, Qt::DateFormat format) const +{ + return formatDateTimeObjectUsingDateFormat(date, format); +} + +#if QT_CONFIG(qml_locale) +QString QtObject::formatDate(const QDate &date, const QLocale &locale, + QLocale::FormatType formatType) const +{ + return locale.toString(date, formatType); } +#endif /*! \qmlmethod string Qt::formatTime(datetime time, variant format, variant localeFormatOption) @@ -839,23 +611,73 @@ If \a format is not specified, \a time is formatted using \sa Locale */ -ReturnedValue QtObject::method_formatTime(const FunctionObject *b, const Value *, const Value *argv, int argc) +static std::optional<QTime> timeFromString(const QString &string, QV4::ExecutionEngine *engine) { - QV4::Scope scope(b); - if (argc < 1) - THROW_GENERIC_ERROR("Qt.formatTime(): Missing argument"); - if (argc > 3) - THROW_GENERIC_ERROR("Qt.formatTime(): Stray arguments; formatTime takes at most 3 arguments."); + { + const QTime time = QTime::fromString(string, Qt::ISODate); + if (time.isValid()) + return time; + } + + { + // For historical reasons, the string argument is parsed as datetime, not as only time + const QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + if (dateTime.isValid()) { + qCWarning(lcRootProperties()) + << string << "is a date/time string being passed to formatTime()." + << "You should only pass time strings to formatTime()."; + return dateTime.time(); + } + } + + engine->throwError(QStringLiteral("Invalid argument passed to formatTime(): %1").arg(string)); + return std::nullopt; +} + +QString QtObject::formatTime(const QTime &time, const QString &format) const +{ + return time.toString(format); +} + +QString QtObject::formatTime(const QString &time, const QString &format) const +{ + + if (auto qTime = timeFromString(time, v4Engine())) + return formatTime(qTime.value(), format); + + return QString(); +} + +QString QtObject::formatTime(const QTime &time, Qt::DateFormat format) const +{ + return formatDateTimeObjectUsingDateFormat(time, format); +} - QVariant argVariant = scope.engine->toVariant(argv[0], -1); - QTime time; - if (argv[0].as<DateObject>() || (argVariant.userType() == QMetaType::QString)) - time = argVariant.toDateTime().time(); - else // if (argVariant.type() == QVariant::Time), or invalid. - time = argVariant.toTime(); - return formatDateTimeObject(time, scope, QLatin1String("Qt.formatTime"), argc, argv); +QString QtObject::formatTime(const QString &time, Qt::DateFormat format) const +{ + if (auto qTime = timeFromString(time, v4Engine())) + return formatTime(qTime.value(), format); + + return QString(); +} + +#if QT_CONFIG(qml_locale) +QString QtObject::formatTime(const QTime &time, const QLocale &locale, + QLocale::FormatType formatType) const +{ + return locale.toString(time, formatType); } +QString QtObject::formatTime(const QString &time, const QLocale &locale, + QLocale::FormatType formatType) const +{ + if (auto qTime = timeFromString(time, v4Engine())) + return locale.toString(qTime.value(), formatType); + + return QString(); +} +#endif + /*! \qmlmethod string Qt::formatDateTime(datetime dateTime, variant format, variant localeFormatOption) @@ -954,17 +776,23 @@ with the \a format values below to produce the following results: \sa Locale */ -ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Value *, const Value *argv, int argc) +QString QtObject::formatDateTime(const QDateTime &dateTime, const QString &format) const { - QV4::Scope scope(b); - if (argc < 1) - THROW_GENERIC_ERROR("Qt.formatDateTime(): Missing argument"); - if (argc > 3) - THROW_GENERIC_ERROR("Qt.formatDateTime(): Stray arguments; formatDate takes at most 3 arguments."); + return dateTime.toString(format); +} - QDateTime dt = scope.engine->toVariant(argv[0], -1).toDateTime(); - return formatDateTimeObject(dt, scope, QLatin1String("Qt.formatDateTime"), argc, argv); +QString QtObject::formatDateTime(const QDateTime &dateTime, Qt::DateFormat format) const +{ + return formatDateTimeObjectUsingDateFormat(dateTime, format); +} + +#if QT_CONFIG(qml_locale) +QString QtObject::formatDateTime(const QDateTime &dateTime, const QLocale &locale, + QLocale::FormatType formatType) const +{ + return locale.toString(dateTime, formatType); } +#endif /*! \qmlmethod bool Qt::openUrlExternally(url target) @@ -977,15 +805,9 @@ ReturnedValue QtObject::method_formatDateTime(const FunctionObject *b, const Val still fail to launch or fail to open the requested URL. This result will not be reported back to the application. */ -ReturnedValue QtObject::method_openUrlExternally(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) +bool QtObject::openUrlExternally(const QUrl &url) const { - QV4::Scope scope(b); - if (argc != 1) - return QV4::Encode(false); - - ScopedValue result(scope, method_resolvedUrl(b, thisObject, argv, argc)); - QUrl url(result->toQStringNoThrow()); - return scope.engine->fromVariant(QQml_guiProvider()->openUrlExternally(url)); + return QQml_guiProvider()->openUrlExternally(resolvedUrl(url)); } /*! @@ -993,24 +815,13 @@ ReturnedValue QtObject::method_openUrlExternally(const FunctionObject *b, const Returns \a url resolved relative to the URL of the caller. */ -ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value *, const Value *argv, int argc) +QUrl QtObject::resolvedUrl(const QUrl &url) const { - QV4::Scope scope(b); - if (argc != 1) - return Encode::undefined(); - - QUrl url = scope.engine->toVariant(argv[0], -1).toUrl(); - QQmlEngine *e = scope.engine->qmlEngine(); - QQmlEnginePrivate *p = nullptr; - if (e) p = QQmlEnginePrivate::get(e); - if (p) { - if (QQmlRefPointer<QQmlContextData> ctxt = scope.engine->callingQmlContext()) - return Encode(scope.engine->newString(ctxt->resolvedUrl(url).toString())); - else - return Encode(scope.engine->newString(url.toString())); - } - - return Encode(scope.engine->newString(e->baseUrl().resolved(url).toString())); + if (QQmlRefPointer<QQmlContextData> ctxt = v4Engine()->callingQmlContext()) + return ctxt->resolvedUrl(url); + if (QQmlEngine *engine = qmlEngine()) + return engine->baseUrl().resolved(url); + return url; } /*! @@ -1018,58 +829,36 @@ ReturnedValue QtObject::method_resolvedUrl(const FunctionObject *b, const Value Returns a list of the font families available to the application. */ -ReturnedValue QtObject::method_fontFamilies(const FunctionObject *b, const Value *, const Value *, int argc) +QStringList QtObject::fontFamilies() const { - QV4::Scope scope(b); - if (argc != 0) - THROW_GENERIC_ERROR("Qt.fontFamilies(): Invalid arguments"); - - return scope.engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies())); + return QQml_guiProvider()->fontFamilies(); } /*! \qmlmethod string Qt::md5(data) Returns a hex string of the md5 hash of \a data. */ -ReturnedValue QtObject::method_md5(const FunctionObject *b, const Value *, const Value *argv, int argc) +QString QtObject::md5(const QString &data) const { - QV4::Scope scope(b); - if (argc != 1) - THROW_GENERIC_ERROR("Qt.md5(): Invalid arguments"); - - QByteArray data = argv[0].toQStringNoThrow().toUtf8(); - QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5); - return Encode(scope.engine->newString(QLatin1String(result.toHex()))); + return QLatin1String(QCryptographicHash::hash(data.toUtf8(), QCryptographicHash::Md5).toHex()); } /*! \qmlmethod string Qt::btoa(data) Binary to ASCII - this function returns a base64 encoding of \a data. */ -ReturnedValue QtObject::method_btoa(const FunctionObject *b, const Value *, const Value *argv, int argc) +QString QtObject::btoa(const QString &data) const { - QV4::Scope scope(b); - if (argc != 1) - THROW_GENERIC_ERROR("Qt.btoa(): Invalid arguments"); - - QByteArray data = argv[0].toQStringNoThrow().toUtf8(); - - return Encode(scope.engine->newString(QLatin1String(data.toBase64()))); + return QLatin1String(data.toUtf8().toBase64()); } /*! \qmlmethod string Qt::atob(data) ASCII to binary - this function decodes the base64 encoded \a data string and returns it. */ -ReturnedValue QtObject::method_atob(const FunctionObject *b, const Value *, const Value *argv, int argc) +QString QtObject::atob(const QString &data) const { - QV4::Scope scope(b); - if (argc != 1) - THROW_GENERIC_ERROR("Qt.atob(): Invalid arguments"); - - QByteArray data = argv[0].toQStringNoThrow().toLatin1(); - - return Encode(scope.engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))); + return QString::fromUtf8(QByteArray::fromBase64(data.toLatin1())); } /*! @@ -1081,10 +870,10 @@ QQmlEngine::quit() signal to the QCoreApplication::quit() slot. \sa exit() */ -ReturnedValue QtObject::method_quit(const FunctionObject *b, const Value *, const Value *, int) +void QtObject::quit() const { - QQmlEnginePrivate::get(b->engine()->qmlEngine())->sendQuit(); - return Encode::undefined(); + if (QQmlEngine *engine = qmlEngine()) + QQmlEnginePrivate::get(engine)->sendQuit(); } /*! @@ -1098,16 +887,10 @@ ReturnedValue QtObject::method_quit(const FunctionObject *b, const Value *, cons \sa quit() */ -ReturnedValue QtObject::method_exit(const FunctionObject *b, const Value *, const Value *argv, int argc) +void QtObject::exit(int retCode) const { - QV4::Scope scope(b); - if (argc != 1) - THROW_GENERIC_ERROR("Qt.exit(): Invalid arguments"); - - int retCode = argv[0].toNumber(); - - QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendExit(retCode); - return QV4::Encode::undefined(); + if (QQmlEngine *engine = qmlEngine()) + QQmlEnginePrivate::get(engine)->sendExit(retCode); } /*! @@ -1134,11 +917,14 @@ If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createCo See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function. */ -ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Value *, const Value *argv, int argc) +QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QUrl &url) const { - QV4::Scope scope(b); - if (argc < 2 || argc > 3) - THROW_GENERIC_ERROR("Qt.createQmlObject(): Invalid arguments"); + QQmlEngine *engine = qmlEngine(); + if (!engine) { + v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): " + "Can only be called on a QML engine.")); + return nullptr; + } struct Error { static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) { @@ -1169,14 +955,10 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va } }; - QQmlEngine *engine = scope.engine->qmlEngine(); + QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext(); + if (!context) + context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext); - QQmlRefPointer<QQmlContextData> context = scope.engine->callingQmlContext(); - if (!context) { - QQmlEngine *qmlEngine = scope.engine->qmlEngine(); - if (qmlEngine) - context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext); - } Q_ASSERT(context); QQmlContext *effectiveContext = nullptr; if (context->isPragmaLibraryContext()) @@ -1185,44 +967,42 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va effectiveContext = context->asQQmlContext(); Q_ASSERT(effectiveContext); - QString qml = argv[0].toQStringNoThrow(); if (qml.isEmpty()) - RETURN_RESULT(Encode::null()); - - QUrl url; - if (argc > 2) - url = QUrl(argv[2].toQStringNoThrow()); - else - url = QUrl(QLatin1String("inline")); + return nullptr; + QUrl resolvedUrl = url; if (url.isValid() && url.isRelative()) - url = context->resolvedUrl(url); + resolvedUrl = context->resolvedUrl(url); - QObject *parentArg = nullptr; - QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, argv[1]); - if (!!qobjectWrapper) - parentArg = qobjectWrapper->object(); - if (!parentArg) - THROW_GENERIC_ERROR("Qt.createQmlObject(): Missing parent object"); + if (!parent) { + v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Missing parent object")); + return nullptr; + } QQmlRefPointer<QQmlTypeData> typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType( - qml.toUtf8(), url, QQmlTypeLoader::Synchronous); + qml.toUtf8(), resolvedUrl, QQmlTypeLoader::Synchronous); Q_ASSERT(typeData->isCompleteOrError()); QQmlComponent component(engine); QQmlComponentPrivate *componentPrivate = QQmlComponentPrivate::get(&component); componentPrivate->fromTypeData(typeData); componentPrivate->progress = 1.0; + Scope scope(v4Engine()); if (component.isError()) { ScopedValue v(scope, Error::create(scope.engine, component.errors())); - RETURN_RESULT(scope.engine->throwError(v)); + scope.engine->throwError(v); + return nullptr; } - if (!component.isReady()) - THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready"); + if (!component.isReady()) { + v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Component is not ready")); + return nullptr; + } if (!effectiveContext->isValid()) { - THROW_GENERIC_ERROR("Qt.createQmlObject(): Cannot create a component in an invalid context"); + v4Engine()->throwError(QStringLiteral("Qt.createQmlObject(): Cannot create a component " + "in an invalid context")); + return nullptr; } QObject *obj = component.beginCreate(effectiveContext); @@ -1230,12 +1010,11 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va QQmlData::get(obj, true)->explicitIndestructibleSet = false; QQmlData::get(obj)->indestructible = false; - - obj->setParent(parentArg); + obj->setParent(parent); QList<QQmlPrivate::AutoParentFunction> functions = QQmlMetaType::parentFunctions(); for (int ii = 0; ii < functions.count(); ++ii) { - if (QQmlPrivate::Parented == functions.at(ii)(obj, parentArg)) + if (QQmlPrivate::Parented == functions.at(ii)(obj, parent)) break; } } @@ -1243,12 +1022,12 @@ ReturnedValue QtObject::method_createQmlObject(const FunctionObject *b, const Va if (component.isError()) { ScopedValue v(scope, Error::create(scope.engine, component.errors())); - return scope.engine->throwError(v); + scope.engine->throwError(v); + return nullptr; } Q_ASSERT(obj); - - return QV4::QObjectWrapper::wrap(scope.engine, obj); + return obj; } /*! @@ -1295,101 +1074,59 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi To create a QML object from an arbitrary string of QML (instead of a file), use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}. */ -ReturnedValue QtObject::method_createComponent(const FunctionObject *b, const Value *, const Value *argv, int argc) +QQmlComponent *QtObject::createComponent(const QUrl &url, QObject *parent) const { - QV4::Scope scope(b); - if (argc < 1 || argc > 3) - THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments"); - - QQmlEngine *engine = scope.engine->qmlEngine(); + return createComponent(url, QQmlComponent::PreferSynchronous, parent); +} - QQmlRefPointer<QQmlContextData> context = scope.engine->callingQmlContext(); - if (!context) { - QQmlEngine *qmlEngine = scope.engine->qmlEngine(); - if (qmlEngine) - context = QQmlContextData::get(QQmlEnginePrivate::get(qmlEngine)->rootContext); +QQmlComponent *QtObject::createComponent(const QUrl &url, QQmlComponent::CompilationMode mode, + QObject *parent) const +{ + if (mode != QQmlComponent::Asynchronous && mode != QQmlComponent::PreferSynchronous) { + v4Engine()->throwError(QStringLiteral("Invalid compilation mode %1").arg(mode)); + return nullptr; } + + if (url.isEmpty()) + return nullptr; + + QQmlEngine *engine = qmlEngine(); + if (!engine) + return nullptr; + + QQmlRefPointer<QQmlContextData> context = v4Engine()->callingQmlContext(); + if (!context) + context = QQmlContextData::get(QQmlEnginePrivate::get(engine)->rootContext); + Q_ASSERT(context); QQmlRefPointer<QQmlContextData> effectiveContext = context->isPragmaLibraryContext() ? nullptr : context; - QString arg = argv[0].toQStringNoThrow(); - if (arg.isEmpty()) - RETURN_RESULT(QV4::Encode::null()); - - QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous; - QObject *parentArg = nullptr; - - int consumedCount = 1; - if (argc > 1) { - ScopedValue lastArg(scope, argv[argc-1]); - - // The second argument could be the mode enum - if (argv[1].isInteger()) { - int mode = argv[1].integerValue(); - if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous)) - THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments"); - compileMode = QQmlComponent::CompilationMode(mode); - consumedCount += 1; - } else { - // The second argument could be the parent only if there are exactly two args - if ((argc != 2) || !(lastArg->isObject() || lastArg->isNull())) - THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments"); - } - - if (consumedCount < argc) { - if (lastArg->isObject()) { - Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg); - if (qobjectWrapper) - parentArg = qobjectWrapper->object(); - if (!parentArg) - THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object"); - } else if (lastArg->isNull()) { - parentArg = nullptr; - } else { - THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object"); - } - } - } - - QUrl url = context->resolvedUrl(QUrl(arg)); - QQmlComponent *c = new QQmlComponent(engine, url, compileMode, parentArg); + QQmlComponent *c = new QQmlComponent(engine, context->resolvedUrl(url), mode, parent); QQmlComponentPrivate::get(c)->creationContext = effectiveContext; QQmlData::get(c, true)->explicitIndestructibleSet = false; QQmlData::get(c)->indestructible = false; - - return QV4::QObjectWrapper::wrap(scope.engine, c); + return c; } -ReturnedValue QtObject::method_get_uiLanguage(const FunctionObject *b, const Value * /*thisObject*/, const Value * /*argv*/, int /*argc*/) +QString QtObject::uiLanguage() const { - QV4::Scope scope(b); - QJSEngine *jsEngine = scope.engine->jsEngine(); - if (!jsEngine) - return Encode::null(); - - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(scope.engine); - if (ep && ep->propertyCapture) { - static const QMetaProperty metaProperty - = QQmlEngine::staticMetaObject.property( - QQmlEngine::staticMetaObject.indexOfProperty("uiLanguage")); - QQmlEngine *e = QQmlEnginePrivate::get(ep); - e->captureProperty(e, metaProperty); - } + if (const QJSEngine *e = jsEngine()) + return e->uiLanguage(); + return QString(); +} - return Encode(scope.engine->newString(QJSEnginePrivate::get(jsEngine)->uiLanguage)); +void QtObject::setUiLanguage(const QString &uiLanguage) +{ + if (QJSEngine *e = jsEngine()) + e->setUiLanguage(uiLanguage); } -ReturnedValue QtObject::method_set_uiLanguage(const FunctionObject *b, const Value * /*thisObject*/, const Value *argv, int argc) +QBindable<QString> QtObject::uiLanguageBindable() { - Scope scope(b); - if (!argc) - THROW_TYPE_ERROR(); - QJSEngine *jsEngine = scope.engine->jsEngine(); - if (!jsEngine) - THROW_TYPE_ERROR(); - jsEngine->setUiLanguage(argv[0].toQString()); - return Encode::undefined(); + if (QJSEngine *e = jsEngine()) + return QBindable<QString>(&QJSEnginePrivate::get(e)->uiLanguage); + return QBindable<QString>(); } #if QT_CONFIG(qml_locale) @@ -1413,19 +1150,14 @@ ReturnedValue QtObject::method_set_uiLanguage(const FunctionObject *b, const Val \sa Locale */ -ReturnedValue QtObject::method_locale(const FunctionObject *b, const Value *, const Value *argv, int argc) +QLocale QtObject::locale() const { - QV4::Scope scope(b); - QString code; - if (argc > 1) - THROW_GENERIC_ERROR("locale() requires 0 or 1 argument"); - if (argc == 1 && !argv[0].isString()) - THROW_TYPE_ERROR_WITH_MESSAGE("locale(): argument (locale code) must be a string"); - - if (argc == 1) - code = argv[0].toQStringNoThrow(); + return QLocale(); +} - return QQmlLocale::locale(scope.engine, code); +QLocale QtObject::locale(const QString &name) const +{ + return QLocale(name); } #endif @@ -1489,67 +1221,52 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction); \since 5.0 */ -ReturnedValue QtObject::method_binding(const FunctionObject *b, const Value *, const Value *argv, int argc) -{ - QV4::Scope scope(b); - if (argc != 1) - THROW_GENERIC_ERROR("binding() requires 1 argument"); - const QV4::FunctionObject *f = argv[0].as<FunctionObject>(); - if (!f) - THROW_TYPE_ERROR_WITH_MESSAGE("binding(): argument (binding expression) must be a function"); +QJSValue QtObject::binding(const QJSValue &function) const +{ + const QV4::FunctionObject *f = QJSValuePrivate::asManagedType<FunctionObject>(&function); + QV4::ExecutionEngine *e = v4Engine(); + if (!f) { + return QJSValuePrivate::fromReturnedValue( + e->throwError( + QStringLiteral( + "binding(): argument (binding expression) must be a function"))); + } - return Encode(scope.engine->memoryManager->allocate<QQmlBindingFunction>(f)); + return QJSValuePrivate::fromReturnedValue( + Encode(e->memoryManager->allocate<QQmlBindingFunction>(f))); } -ReturnedValue QtObject::method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *, int) +QQmlPlatform *QtObject::platform() { - QV4::Scope scope(b); - // ### inefficient. Should be just a value based getter - const Object *o = thisObject->as<Object>(); - if (!o) - THROW_TYPE_ERROR(); - const QtObject *qt = o->as<QtObject>(); - if (!qt) - THROW_TYPE_ERROR(); - - if (!qt->d()->platform) - // Only allocate a platform object once - qt->d()->platform = new QQmlPlatform(scope.engine->jsEngine()); - - return QV4::QObjectWrapper::wrap(scope.engine, qt->d()->platform); + if (!m_platform) + m_platform = new QQmlPlatform(this); + return m_platform; } -ReturnedValue QtObject::method_get_application(const FunctionObject *b, const Value *thisObject, const Value *, int) +QQmlApplication *QtObject::application() { - QV4::Scope scope(b); - // ### inefficient. Should be just a value based getter - const Object *o = thisObject->as<Object>(); - if (!o) - THROW_TYPE_ERROR(); - const QtObject *qt = o->as<QtObject>(); - if (!qt) - THROW_TYPE_ERROR(); - - if (!qt->d()->application) + if (!m_application) // Only allocate an application object once - qt->d()->application = QQml_guiProvider()->application(scope.engine->jsEngine()); + m_application = QQml_guiProvider()->application(this); - return QV4::QObjectWrapper::wrap(scope.engine, qt->d()->application); + return m_application; } -ReturnedValue QtObject::method_get_inputMethod(const FunctionObject *b, const Value *, const Value *, int) +QObject *QtObject::inputMethod() const { - QObject *o = QQml_guiProvider()->inputMethod(); - return QV4::QObjectWrapper::wrap(b->engine(), o); + return QQml_guiProvider()->inputMethod(); } -ReturnedValue QtObject::method_get_styleHints(const FunctionObject *b, const Value *, const Value *, int) +QObject *QtObject::styleHints() const { - QObject *o = QQml_guiProvider()->styleHints(); - return QV4::QObjectWrapper::wrap(b->engine(), o); + return QQml_guiProvider()->styleHints(); } +QJSValue QtObject::callLater() const +{ + return m_callLater; +} void QV4::Heap::ConsoleObject::init() { @@ -1873,8 +1590,6 @@ ReturnedValue ConsoleObject::method_exception(const FunctionObject *b, const Val return writeToConsole(b, argv, argc, Error, true); } - - void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions extensions) { ExecutionEngine *v4 = globalObject->engine(); @@ -1889,13 +1604,11 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext globalObject->defineDefaultProperty(QStringLiteral("qsTrId"), QV4::GlobalExtensions::method_qsTrId); globalObject->defineDefaultProperty(QStringLiteral("QT_TRID_NOOP"), QV4::GlobalExtensions::method_qsTrIdNoOp); + // Initialize the Qt global object for the uiLanguage property ScopedString qtName(scope, v4->newString(QStringLiteral("Qt"))); ScopedObject qt(scope, globalObject->get(qtName)); - if (!qt) { - qt = v4->newObject(); - globalObject->defineDefaultProperty(qtName, qt); - } - qt->defineAccessorProperty(QStringLiteral("uiLanguage"), QV4::QtObject::method_get_uiLanguage, QV4::QtObject::method_set_uiLanguage); + if (!qt) + v4->createQtObject(); // string prototype extension scope.engine->stringPrototype()->defineDefaultProperty(QStringLiteral("arg"), QV4::GlobalExtensions::method_string_arg); @@ -2236,7 +1949,8 @@ be passed on to the function invoked. Note that if redundant calls are eliminated, then only the last set of arguments will be passed to the function. */ -ReturnedValue QtObject::method_callLater(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) +ReturnedValue QtObject::method_callLater(const FunctionObject *b, const Value *thisObject, + const Value *argv, int argc) { return b->engine()->delayedCallQueue()->addUniquelyAndExecuteLater(b, thisObject, argv, argc); } |