aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-10-29 19:34:24 +0100
committerUlf Hermann <ulf.hermann@qt.io>2020-11-09 18:10:38 +0100
commitcbe1869fbe7048f34513b201a1d9111a0a64257a (patch)
tree5c36cdf60a064f661551c8cf6a11a9716db4aa3f /src/qml/qml/v8/qqmlbuiltinfunctions.cpp
parentd7008c79d4ec023527ebfc118ad47f40075f244d (diff)
QML: Rewrite Qt object in actual C++
Quite obviously, the Qt object is a singleton, extended with a namespace, backed by a member of the JavaScript global object. Defining all the methods as JavaScript functions is unnecessary and duplicates the general type transformation code. Also, it makes it hard to use those same methods from a C++ context as we cannot properly set up the arguments outside the JS engine. Rewriting the Qt object reveals some deficiencies in the old implementation that we need to fix now: 1. The enums of the Qt type were listed as properties of the Qt object, which means you could iterate them with a for..in loop in in JavaScript. This is just wrong. Enums are not properties. This functionality is deleted and the test adapted to check for each enum value separately. The commit message for the change that introduced the iterability already mentioned that the author had failed to find any occurrence of this in the real world. 2. Parsing time objects from strings was done by parsing the string as a date/time and then picking the time from that. We still support that for now, but output a (categorized) warning. Parsing the time directly is preferred where possible. 3. Previously you could create (invalid) dates and times from various kinds of QML types, like int and color. This does not work anymore as we now validate the types before calling the functions. 4. Passing more arguments to a function than the function accepted was unconditionally ignored before. Now, a Q_CLASSINFO on the surrounding class can specify that the arguments should be checked, in which case a JavaScript error is thrown if too many arguments are passed. In order for this to work correctly we also have to ignore JS undefined values as trailing arguments for overload resolution. This way, if a method matching the defined arguments exists, it will be preferred over a method that matches the full argument count, but possibly cannot accept undefined as parameter. Consequently a number of error messages change, which is reflected in the qqmlqt test. [ChangeLog][QtQMl][Important Behavior Changes] You can not iterate the enumerations of the Qt object in JavaScript anymore. This does not work with any other enumeration type either. You can of course still access them by name, for example as Qt.LeftButton or similar. [ChangeLog][QtQMl][Important Behavior Changes] The time formatting functions of the Qt object in QML now allow you to pass an actual time string, rather than a date/time string as argument. Passing a date/time string results in a warning now. [ChangeLog][QtQml][Important Behavior Changes] Functions in the Qt object for formatting date and time will now throw a JavaScript error when presented with a value of an incompatible type, such as int or color. [ChangeLog][QtQml][Important Behavior Changes] The Qt.resolvedUrl() function now returns a URL rather than a string. This follows the documentation. [ChangeLog][QtQml][Important Behavior Changes] The GlobalColor enum of the Qt namespace is not exposed to QML anymore. It did not make any sense before as the enum values could not be used as colors. Change-Id: I7fc2f24377eb2fde8f63a1ffac5548d652de7b12 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/qml/v8/qqmlbuiltinfunctions.cpp')
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp1050
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);
}