diff options
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4include.cpp | 50 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4include_p.h | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 59 | ||||
-rw-r--r-- | src/qml/qml/qqmldelayedcallqueue.cpp | 29 | ||||
-rw-r--r-- | src/qml/qml/qqmldelayedcallqueue_p.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlglobal.cpp | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlglobal_p.h | 6 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 1050 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions_p.h | 208 | ||||
-rw-r--r-- | src/quick/util/qquickglobal.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 34 | ||||
-rw-r--r-- | tests/auto/qml/qqmlqt/data/qtObjectContents.qml | 10 | ||||
-rw-r--r-- | tests/auto/qml/qqmlqt/data/resolvedUrl.qml | 2 | ||||
-rw-r--r-- | tests/auto/qml/qqmlqt/tst_qqmlqt.cpp | 310 |
17 files changed, 835 insertions, 961 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 923d458feb..fe34207ddc 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2048,10 +2048,7 @@ void ExecutionEngine::initQmlGlobalObject() void ExecutionEngine::initializeGlobal() { - QV4::Scope scope(this); - - QV4::ScopedObject qt(scope, memoryManager->allocate<QV4::QtObject>(qmlEngine())); - globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); + createQtObject(); QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions); @@ -2078,6 +2075,15 @@ void ExecutionEngine::initializeGlobal() } } +void ExecutionEngine::createQtObject() +{ + QV4::Scope scope(this); + QtObject *qtObject = new QtObject(this); + QJSEngine::setObjectOwnership(qtObject, QJSEngine::JavaScriptOwnership); + QV4::ScopedObject qt(scope, QV4::QObjectWrapper::wrap(this, qtObject)); + globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); +} + const QSet<QString> &ExecutionEngine::illegalNames() const { return m_illegalNames; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 92bd3a0627..bf24663920 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -689,6 +689,7 @@ public: QV4::ReturnedValue global(); void initQmlGlobalObject(); void initializeGlobal(); + void createQtObject(); void freezeObject(const QV4::Value &value); diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 17512cf4ff..c185894ab3 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -59,20 +59,21 @@ QT_BEGIN_NAMESPACE QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback) - : v4(engine), m_url(url) + : QObject(engine->jsEngine()) + , v4(engine), m_url(url) #if QT_CONFIG(qml_network) , m_redirectCount(0), m_network(nullptr) , m_reply(nullptr) #endif { if (qmlContext) - m_qmlContext.set(engine, *qmlContext); + m_qmlContext.set(v4, *qmlContext); if (callback.as<QV4::FunctionObject>()) - m_callbackFunction.set(engine, callback); + m_callbackFunction.set(v4, callback); m_resultObject.set(v4, resultValue(v4)); #if QT_CONFIG(qml_network) - if (QQmlEngine *qmlEngine = engine->qmlEngine()) { + if (QQmlEngine *qmlEngine = v4->qmlEngine()) { m_network = qmlEngine->networkAccessManager(); QNetworkRequest request; @@ -202,37 +203,40 @@ void QV4Include::finished() /* Documented in qv4engine.cpp */ -QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc) +QJSValue QV4Include::method_include(QV4::ExecutionEngine *engine, const QUrl &url, + const QJSValue &callbackFunction) { - QV4::Scope scope(b); - if (!argc) - RETURN_UNDEFINED(); + QQmlRefPointer<QQmlContextData> context = engine->callingQmlContext(); - QQmlRefPointer<QQmlContextData> context = scope.engine->callingQmlContext(); - - if ((!context || !context->isJSContext()) && scope.engine->qmlEngine()) - RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files"))); + if ((!context || !context->isJSContext()) && engine->qmlEngine()) { + return QJSValuePrivate::fromReturnedValue( + engine->throwError( + QString::fromUtf8( + "Qt.include(): Can only be called from JavaScript files"))); + } - QV4::ScopedValue callbackFunction(scope, QV4::Value::undefinedValue()); - if (argc >= 2 && argv[1].as<QV4::FunctionObject>()) - callbackFunction = argv[1]; - QUrl url(scope.engine->resolvedUrl(argv[0].toQStringNoThrow())); - if (const QQmlEngine *qmlEngine = scope.engine->qmlEngine()) - url = qmlEngine->interceptUrl(url, QQmlAbstractUrlInterceptor::JavaScriptFile); + QV4::Scope scope(engine); + QV4::ScopedValue scopedCallbackFunction(scope, QV4::Value::undefinedValue()); + if (auto function = QJSValuePrivate::asManagedType<QV4::FunctionObject>(&callbackFunction)) + scopedCallbackFunction = *function; - QString localFile = QQmlFile::urlToLocalFileOrQrc(url); + const QQmlEngine *qmlEngine = engine->qmlEngine(); + const QUrl intercepted = qmlEngine + ? qmlEngine->interceptUrl(url, QQmlAbstractUrlInterceptor::JavaScriptFile) + : url; + QString localFile = QQmlFile::urlToLocalFileOrQrc(intercepted); QV4::ScopedValue result(scope); QV4::Scoped<QV4::QmlContext> qmlcontext(scope, scope.engine->qmlContext()); if (localFile.isEmpty()) { #if QT_CONFIG(qml_network) - QV4Include *i = new QV4Include(url, scope.engine, qmlcontext, callbackFunction); + QV4Include *i = new QV4Include(url, engine, qmlcontext, scopedCallbackFunction); result = i->result(); #else result = resultValue(scope.engine, NetworkError); - callback(callbackFunction, result); + callback(scopedCallbackFunction, result); #endif } else { QScopedPointer<QV4::Script> script; @@ -255,10 +259,10 @@ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, cons result = resultValue(scope.engine, NetworkError, error); } - callback(callbackFunction, result); + callback(scopedCallbackFunction, result); } - return result->asReturnedValue(); + return QJSValuePrivate::fromReturnedValue(result->asReturnedValue()); } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 9d0a17a5cc..d375abf20a 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -61,7 +61,8 @@ QT_BEGIN_NAMESPACE -class QQmlEngine; +class QJSEngine; +class QJSValue; #if QT_CONFIG(qml_network) class QNetworkAccessManager; #endif @@ -77,13 +78,15 @@ public: Exception = 3 }; - static QV4::ReturnedValue method_include(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QJSValue method_include(QV4::ExecutionEngine *engine, const QUrl &url, + const QJSValue &callbackFunction); private Q_SLOTS: void finished(); private: - QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback); + QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, + const QV4::Value &callback); ~QV4Include(); QV4::ReturnedValue result(); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index cabe48dbef..1bf3a01f03 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1554,6 +1554,16 @@ static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object, } } +static int numDefinedArguments(QV4::CallData *callArgs) +{ + int numDefinedArguments = callArgs->argc(); + while (numDefinedArguments > 0 + && callArgs->args[numDefinedArguments - 1].type() == QV4::StaticValue::Undefined_Type) { + --numDefinedArguments; + } + return numDefinedArguments; +} + static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPropertyData &data, QV4::ExecutionEngine *engine, QV4::CallData *callArgs, QMetaObject::Call callType = QMetaObject::InvokeMetaMethod) @@ -1567,6 +1577,35 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ + QLatin1String(unknownTypeError)); } + auto handleTooManyArguments = [&](int expectedArguments) { + const QMetaObject *metaObject = object.metaObject(); + const int indexOfClassInfo = metaObject->indexOfClassInfo("QML.StrictArguments"); + if (indexOfClassInfo != -1 + && QString::fromUtf8(metaObject->classInfo(indexOfClassInfo).value()) + == QStringLiteral("true")) { + engine->throwError(QStringLiteral("Too many arguments")); + return false; + } + + const auto stackTrace = engine->stackTrace(); + if (stackTrace.isEmpty()) { + qWarning().nospace().noquote() + << "When matching arguments for " + << object.className() << "::" << data.name(object.metaObject()) << "():"; + } else { + const StackFrame frame = engine->stackTrace().first(); + qWarning().noquote() << frame.function + QLatin1Char('@') + frame.source + + (frame.line > 0 ? (QLatin1Char(':') + QString::number(frame.line)) + : QString()); + } + + qWarning().noquote() << QStringLiteral("Too many arguments, ignoring %1") + .arg(callArgs->argc() - expectedArguments); + return true; + }; + + const int definedArgumentCount = numDefinedArguments(callArgs); + if (data.hasArguments()) { int *args = nullptr; @@ -1588,24 +1627,19 @@ static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQ return engine->throwError(error); } - if (args[0] < callArgs->argc()) { - Q_ASSERT(!engine->stackTrace().isEmpty()); + if (args[0] < definedArgumentCount) { + if (!handleTooManyArguments(args[0])) + return Encode::undefined(); - const StackFrame frame = engine->stackTrace().first(); - qWarning().noquote() << frame.function + QLatin1Char('@') + frame.source - + (frame.line > 0 ? (QLatin1Char(':') + QString::number(frame.line)) - : QString()); - - qWarning().noquote() << QStringLiteral("Too many arguments, ignoring %1") - .arg(callArgs->argc() - args[0]); } return CallMethod(object, data.coreIndex(), returnType, args[0], args + 1, engine, callArgs, callType); } else { + if (definedArgumentCount > 0 && !handleTooManyArguments(0)) + return Encode::undefined(); return CallMethod(object, data.coreIndex(), returnType, 0, nullptr, engine, callArgs, callType); - } } @@ -1626,7 +1660,8 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const QV4::ExecutionEngine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache, QMetaObject::Call callType = QMetaObject::InvokeMetaMethod) { - int argumentCount = callArgs->argc(); + const int argumentCount = callArgs->argc(); + const int definedArgumentCount = numDefinedArguments(callArgs); QQmlPropertyData best; int bestParameterScore = INT_MAX; @@ -1654,7 +1689,7 @@ static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const if (methodArgumentCount > argumentCount) continue; // We don't have sufficient arguments to call this method - int methodParameterScore = argumentCount - methodArgumentCount; + int methodParameterScore = definedArgumentCount - methodArgumentCount; if (methodParameterScore > bestParameterScore) continue; // We already have a better option diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp index 02fde97b3d..141c55c0ec 100644 --- a/src/qml/qml/qqmldelayedcallqueue.cpp +++ b/src/qml/qml/qqmldelayedcallqueue.cpp @@ -108,6 +108,9 @@ void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine) QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc) { + QV4::ExecutionEngine *engine = b->engine(); + QQmlDelayedCallQueue *self = engine->delayedCallQueue(); + QV4::Scope scope(b); if (argc == 0) THROW_GENERIC_ERROR("Qt.callLater: no arguments given"); @@ -123,8 +126,8 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F QVector<DelayedFunctionCall>::Iterator iter; if (functionData.second != -1) { // This is a QObject function wrapper - iter = m_delayedFunctionCalls.begin(); - while (iter != m_delayedFunctionCalls.end()) { + iter = self->m_delayedFunctionCalls.begin(); + while (iter != self->m_delayedFunctionCalls.end()) { DelayedFunctionCall& dfc = *iter; QPair<QObject *, int> storedFunctionData = QV4::QObjectMethod::extractQtMethod(dfc.m_function.as<QV4::FunctionObject>()); if (storedFunctionData == functionData) { @@ -134,8 +137,8 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F } } else { // This is a JavaScript function (dynamic slot on VMEMO) - iter = m_delayedFunctionCalls.begin(); - while (iter != m_delayedFunctionCalls.end()) { + iter = self->m_delayedFunctionCalls.begin(); + while (iter != self->m_delayedFunctionCalls.end()) { DelayedFunctionCall& dfc = *iter; if (arg0 == dfc.m_function.value()) { break; // Already stored! @@ -144,16 +147,16 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F } } - const bool functionAlreadyStored = (iter != m_delayedFunctionCalls.end()); + const bool functionAlreadyStored = (iter != self->m_delayedFunctionCalls.end()); if (functionAlreadyStored) { DelayedFunctionCall dfc = *iter; - m_delayedFunctionCalls.erase(iter); - m_delayedFunctionCalls.append(dfc); + self->m_delayedFunctionCalls.erase(iter); + self->m_delayedFunctionCalls.append(dfc); } else { - m_delayedFunctionCalls.append(QV4::PersistentValue(m_engine, arg0)); + self->m_delayedFunctionCalls.append(QV4::PersistentValue(engine, arg0)); } - DelayedFunctionCall& dfc = m_delayedFunctionCalls.last(); + DelayedFunctionCall& dfc = self->m_delayedFunctionCalls.last(); if (dfc.m_objectGuard.isNull()) { if (functionData.second != -1) { // if it's a qobject function wrapper, guard against qobject deletion @@ -166,11 +169,11 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::F dfc.m_guarded = true; } } - storeAnyArguments(dfc, argv, argc, 1, m_engine); + self->storeAnyArguments(dfc, argv, argc, 1, engine); - if (!m_callbackOutstanding) { - m_tickedMethod.invoke(this, Qt::QueuedConnection); - m_callbackOutstanding = true; + if (!self->m_callbackOutstanding) { + self->m_tickedMethod.invoke(self, Qt::QueuedConnection); + self->m_callbackOutstanding = true; } return QV4::Encode::undefined(); } diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h index 7962318561..48ee38bbb9 100644 --- a/src/qml/qml/qqmldelayedcallqueue_p.h +++ b/src/qml/qml/qqmldelayedcallqueue_p.h @@ -69,7 +69,9 @@ public: void init(QV4::ExecutionEngine *); - QV4::ReturnedValue addUniquelyAndExecuteLater(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc); + static QV4::ReturnedValue addUniquelyAndExecuteLater( + const QV4::FunctionObject *, const QV4::Value *thisObject, + const QV4::Value *argv, int argc); public Q_SLOTS: void ticked(); diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index e3a5df382e..d4473b7020 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -149,9 +149,12 @@ Q_AUTOTEST_EXPORT QQmlColorProvider *QQml_colorProvider(void) QQmlGuiProvider::~QQmlGuiProvider() {} -QObject *QQmlGuiProvider::application(QObject *) { return new QQmlApplication(); } +QQmlApplication *QQmlGuiProvider::application(QObject *parent) +{ + return new QQmlApplication(parent); +} QStringList QQmlGuiProvider::fontFamilies() { return QStringList(); } -bool QQmlGuiProvider::openUrlExternally(QUrl &) { return false; } +bool QQmlGuiProvider::openUrlExternally(const QUrl &) { return false; } QObject *QQmlGuiProvider::inputMethod() { diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 5634ada7d1..d32641c10c 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -248,16 +248,16 @@ public: Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_setColorProvider(QQmlColorProvider *); Q_QML_PRIVATE_EXPORT QQmlColorProvider *QQml_colorProvider(); - +class QQmlApplication; class Q_QML_PRIVATE_EXPORT QQmlGuiProvider { public: virtual ~QQmlGuiProvider(); - virtual QObject *application(QObject *parent); + virtual QQmlApplication *application(QObject *parent); virtual QObject *inputMethod(); virtual QObject *styleHints(); virtual QStringList fontFamilies(); - virtual bool openUrlExternally(QUrl &); + virtual bool openUrlExternally(const QUrl &); virtual QString pluginName() const; }; 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); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index 65c68503e3..4ab982d579 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -54,29 +54,21 @@ #include <private/qqmlglobal_p.h> #include <private/qv4functionobject_p.h> #include <private/qjsengine_p.h> +#include <private/qqmlplatform_p.h> #include <QtCore/qnamespace.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qsize.h> +#include <QtCore/qrect.h> +#include <QtCore/qpoint.h> +#include <QtQml/qqmlcomponent.h> +#include <QtQml/qqmlengine.h> QT_BEGIN_NAMESPACE -class QQmlEngine; - namespace QV4 { namespace Heap { -struct QtObject : Object { - void init(QQmlEngine *qmlEngine); - QObject *platform; - QObject *application; - - enum { Finished = -1 }; - int enumeratorIterator; - int keyIterator; - - bool isComplete() const - { return enumeratorIterator == Finished; } -}; - struct ConsoleObject : Object { void init(); }; @@ -90,73 +82,139 @@ DECLARE_HEAP_OBJECT(QQmlBindingFunction, FunctionObject) { } -namespace QtInQml { -Q_NAMESPACE -QML_FOREIGN_NAMESPACE(Qt) -QML_NAMED_ELEMENT(Qt) -QML_ADDED_IN_VERSION(2, 0) -Q_CLASSINFO("QML.ManualRegistration", "true") -// should add the functions defined below... -} - -struct QtObject : Object +class Q_QML_EXPORT QtObject : public QObject { - V4_OBJECT2(QtObject, Object) - - static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty); - static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target); - - static ReturnedValue method_isQtObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_color(const FunctionObject *b, const Value *thisObject, - const Value *argv, int argc); - static ReturnedValue method_rgba(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_hsla(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_hsva(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_colorEqual(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_font(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_rect(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_point(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_size(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_vector2d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_vector3d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_vector4d(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_quaternion(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_matrix4x4(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_lighter(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_darker(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_alpha(const FunctionObject *b, const Value *thisObject, - const Value *argv, int argc); - static ReturnedValue method_tint(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_formatDate(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_formatTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_formatDateTime(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_openUrlExternally(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_fontFamilies(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_md5(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_btoa(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_atob(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_quit(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_exit(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_resolvedUrl(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_createQmlObject(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_createComponent(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_get_uiLanguage(const FunctionObject *b, const Value *, const Value *, int); - static ReturnedValue method_set_uiLanguage(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); + Q_OBJECT + Q_PROPERTY(QQmlApplication *application READ application CONSTANT) + Q_PROPERTY(QQmlPlatform *platform READ platform CONSTANT) + Q_PROPERTY(QObject *inputMethod READ inputMethod CONSTANT) + Q_PROPERTY(QObject *styleHints READ styleHints CONSTANT) + Q_PROPERTY(QJSValue callLater READ callLater CONSTANT) + +#if QT_CONFIG(translation) + Q_PROPERTY(QString uiLanguage READ uiLanguage WRITE setUiLanguage BINDABLE uiLanguageBindable) +#endif + + QML_NAMED_ELEMENT(Qt) + QML_SINGLETON + QML_EXTENDED_NAMESPACE(QT_PREPEND_NAMESPACE(Qt)) + QML_ADDED_IN_VERSION(2, 0) + + Q_CLASSINFO("QML.StrictArguments", "true") + +public: + enum LoadingMode { Asynchronous = 0, Synchronous = 1 }; + Q_ENUM(LoadingMode); + + static QtObject *create(QQmlEngine *, QJSEngine *jsEngine); + + Q_INVOKABLE QJSValue include(const QString &url, const QJSValue &callback = QJSValue()) const; + Q_INVOKABLE bool isQtObject(const QJSValue &value) const; + + Q_INVOKABLE QVariant color(const QString &name) const; + Q_INVOKABLE QVariant rgba(double r, double g, double b, double a = 1) const; + Q_INVOKABLE QVariant hsla(double h, double s, double l, double a = 1) const; + Q_INVOKABLE QVariant hsva(double h, double s, double v, double a = 1) const; + Q_INVOKABLE bool colorEqual(const QVariant &lhs, const QVariant &rhs) const; + + Q_INVOKABLE QRectF rect(double x, double y, double width, double height) const; + Q_INVOKABLE QPointF point(double x, double y) const; + Q_INVOKABLE QSizeF size(double width, double height) const; + Q_INVOKABLE QVariant vector2d(double x, double y) const; + Q_INVOKABLE QVariant vector3d(double x, double y, double z) const; + Q_INVOKABLE QVariant vector4d(double x, double y, double z, double w) const; + Q_INVOKABLE QVariant quaternion(double scalar, double x, double y, double z) const; + + Q_INVOKABLE QVariant matrix4x4() const; + Q_INVOKABLE QVariant 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; + Q_INVOKABLE QVariant matrix4x4(const QJSValue &value) const; + + Q_INVOKABLE QVariant lighter(const QJSValue &color, double factor = 1.5) const; + Q_INVOKABLE QVariant darker(const QJSValue &color, double factor = 2.0) const; + Q_INVOKABLE QVariant alpha(const QJSValue &baseColor, double value) const; + Q_INVOKABLE QVariant tint(const QJSValue &baseColor, const QJSValue &tintColor) const; + + Q_INVOKABLE QString formatDate(const QDate &date, const QString &format) const; + Q_INVOKABLE QString formatDate(const QDate &date, Qt::DateFormat format) const; + + Q_INVOKABLE QString formatTime(const QTime &time, const QString &format) const; + Q_INVOKABLE QString formatTime(const QString &time, const QString &format) const; + Q_INVOKABLE QString formatTime(const QTime &time, Qt::DateFormat format) const; + Q_INVOKABLE QString formatTime(const QString &time, Qt::DateFormat format) const; + + Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QString &format) const; + Q_INVOKABLE QString formatDateTime(const QDateTime &date, Qt::DateFormat format) const; + #if QT_CONFIG(qml_locale) - static ReturnedValue method_locale(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); + Q_INVOKABLE QString formatDate(const QDate &date, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QString formatTime(const QTime &time, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QString formatTime(const QString &time, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QString formatDateTime(const QDateTime &date, const QLocale &locale = QLocale(), + QLocale::FormatType formatType = QLocale::ShortFormat) const; + Q_INVOKABLE QLocale locale() const; + Q_INVOKABLE QLocale locale(const QString &name) const; +#endif + + Q_INVOKABLE QUrl resolvedUrl(const QUrl &url) const; + Q_INVOKABLE bool openUrlExternally(const QUrl &url) const; + + Q_INVOKABLE QVariant font(const QJSValue &fontSpecifier) const; + Q_INVOKABLE QStringList fontFamilies() const; + + Q_INVOKABLE QString md5(const QString &data) const; + Q_INVOKABLE QString btoa(const QString &data) const; + Q_INVOKABLE QString atob(const QString &data) const; + + Q_INVOKABLE void quit() const; + Q_INVOKABLE void exit(int retCode) const; + + Q_INVOKABLE QObject *createQmlObject(const QString &qml, QObject *parent, + const QUrl &url = QUrl(QStringLiteral("inline"))) const; + Q_INVOKABLE QQmlComponent *createComponent(const QUrl &url, QObject *parent) const; + Q_INVOKABLE QQmlComponent *createComponent( + const QUrl &url, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous, + QObject *parent = nullptr) const; + + Q_INVOKABLE QJSValue binding(const QJSValue &function) const; + + // We can't make this invokable as it uses actual varargs + static ReturnedValue method_callLater(const FunctionObject *b, const Value *thisObject, + const Value *argv, int argc); + +#if QT_CONFIG(translation) + QString uiLanguage() const; + void setUiLanguage(const QString &uiLanguage); + QBindable<QString> uiLanguageBindable(); #endif - static ReturnedValue method_binding(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_get_platform(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_get_application(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_get_inputMethod(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_get_styleHints(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc); + // Not const because created on first use, and parented to this. + QQmlPlatform *platform(); + QQmlApplication *application(); - static ReturnedValue method_callLater(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + QObject *inputMethod() const; + QObject *styleHints() const; + QJSValue callLater() const; private: - void addAll(); - ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const; + friend struct ExecutionEngine; + + QtObject(QV4::ExecutionEngine *engine); + + QQmlEngine *qmlEngine() const { return m_engine->qmlEngine(); } + QJSEngine *jsEngine() const { return m_engine->jsEngine(); } + QV4::ExecutionEngine *v4Engine() const { return m_engine; } + + QQmlPlatform *m_platform = nullptr; + QQmlApplication *m_application = nullptr; + + QV4::ExecutionEngine *m_engine = nullptr; + QJSValue m_callLater; }; struct ConsoleObject : Object diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 0639533bac..afee2c3878 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -314,7 +314,7 @@ public: return QFontDatabase::families(); } - bool openUrlExternally(QUrl &url) override + bool openUrlExternally(const QUrl &url) override { #ifndef QT_NO_DESKTOPSERVICES return QDesktopServices::openUrl(url); diff --git a/tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml b/tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml index b323b49662..33b94d753c 100644 --- a/tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml +++ b/tests/auto/qml/qqmlecmascript/data/registeredFlagMethod.qml @@ -1,3 +1,4 @@ +import QtQml import Qt.test 1.0 MyQmlObject { diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 985b8c7a98..03fc8e5ad4 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -1782,15 +1782,15 @@ void tst_qqmlecmascript::componentCreation_data() << "null"; QTest::newRow("invalidSecondArg") << "invalidSecondArg" - << ":40: Error: Qt.createComponent(): Invalid arguments" + << "" // We cannot catch this case as coercing a string to a number is valid in JavaScript << ""; QTest::newRow("invalidThirdArg") << "invalidThirdArg" - << ":45: Error: Qt.createComponent(): Invalid parent object" + << ":45: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed." << ""; QTest::newRow("invalidMode") << "invalidMode" - << ":50: Error: Qt.createComponent(): Invalid arguments" + << ":50: Error: Invalid compilation mode -666" << ""; } @@ -3448,6 +3448,9 @@ void tst_qqmlecmascript::scriptConnect() QVERIFY(object != nullptr); QCOMPARE(object->methodCalled(), false); + + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("When matching arguments for MyQmlObject_QML_[0-9]+::methodNoArgs\\(\\):")); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Too many arguments, ignoring 5")); emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton); QCOMPARE(object->methodCalled(), true); @@ -3461,6 +3464,8 @@ void tst_qqmlecmascript::scriptConnect() QVERIFY(object != nullptr); QCOMPARE(object->methodCalled(), false); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("When matching arguments for MyQmlObject_QML_[0-9]+::methodNoArgs\\(\\):")); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Too many arguments, ignoring 5")); emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton); QCOMPARE(object->methodCalled(), true); @@ -6365,7 +6370,7 @@ void tst_qqmlecmascript::include() // Non-library relative include { QQmlComponent component(&engine, testFileUrl("include.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test0").toInt(), 99); @@ -6375,13 +6380,12 @@ void tst_qqmlecmascript::include() QCOMPARE(o->property("test3").toBool(), true); QCOMPARE(o->property("test3_1").toBool(), true); - delete o; } // Library relative include { QQmlComponent component(&engine, testFileUrl("include_shared.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test0").toInt(), 99); @@ -6391,13 +6395,12 @@ void tst_qqmlecmascript::include() QCOMPARE(o->property("test3").toBool(), true); QCOMPARE(o->property("test3_1").toBool(), true); - delete o; } // Callback { QQmlComponent component(&engine, testFileUrl("include_callback.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test1").toBool(), true); @@ -6407,17 +6410,15 @@ void tst_qqmlecmascript::include() QCOMPARE(o->property("test5").toBool(), true); QCOMPARE(o->property("test6").toBool(), true); - delete o; } // Including file with ".pragma library" { QQmlComponent component(&engine, testFileUrl("include_pragma.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test1").toInt(), 100); - delete o; } // Including file with ".pragma library", shadowing a global var @@ -6435,7 +6436,7 @@ void tst_qqmlecmascript::include() server.serveDirectory(dataDirectory()); QQmlComponent component(&engine, testFileUrl("include_remote_missing.qml")); - QObject *o = component.beginCreate(engine.rootContext()); + QScopedPointer<QObject> o(component.beginCreate(engine.rootContext())); QVERIFY(o != nullptr); o->setProperty("serverBaseUrl", server.baseUrl().toString()); component.completeCreate(); @@ -6446,13 +6447,12 @@ void tst_qqmlecmascript::include() QCOMPARE(o->property("test2").toBool(), true); QCOMPARE(o->property("test3").toBool(), true); - delete o; } // include from resources { QQmlComponent component(&engine, QUrl("qrc:///data/include.qml")); - QObject *o = component.create(); + QScopedPointer<QObject> o(component.create()); QVERIFY(o != nullptr); QCOMPARE(o->property("test0").toInt(), 99); @@ -6462,7 +6462,6 @@ void tst_qqmlecmascript::include() QCOMPARE(o->property("test3").toBool(), true); QCOMPARE(o->property("test3_1").toBool(), true); - delete o; } } @@ -7495,14 +7494,13 @@ void tst_qqmlecmascript::registeredFlagMethod() { QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("registeredFlagMethod.qml")); - MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create()); + QScopedPointer<QObject> o(component.create()); + MyQmlObject *object = qobject_cast<MyQmlObject *>(o.data()); QVERIFY(object != nullptr); QCOMPARE(object->buttons(), 0); emit object->basicSignal(); QCOMPARE(object->buttons(), Qt::RightButton); - - delete object; } // QTBUG-23138 diff --git a/tests/auto/qml/qqmlqt/data/qtObjectContents.qml b/tests/auto/qml/qqmlqt/data/qtObjectContents.qml deleted file mode 100644 index c85e7986e9..0000000000 --- a/tests/auto/qml/qqmlqt/data/qtObjectContents.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.0 - -QtObject { - property var values: Object() - Component.onCompleted: { - for (var key in Qt) { - values[key] = Qt[key] - } - } -} diff --git a/tests/auto/qml/qqmlqt/data/resolvedUrl.qml b/tests/auto/qml/qqmlqt/data/resolvedUrl.qml index 06ef48b82b..aa57c73627 100644 --- a/tests/auto/qml/qqmlqt/data/resolvedUrl.qml +++ b/tests/auto/qml/qqmlqt/data/resolvedUrl.qml @@ -3,11 +3,13 @@ import QtQuick 2.0 QtObject { property string result property bool isString: false + property bool isObject: false Component.onCompleted: { var a = Qt.resolvedUrl("resolvedUrl.qml"); result = a; isString = (typeof a) == "string" + isObject = (typeof a) == "object" } } diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index a6d8a52e0e..9406ba5d6a 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -180,9 +180,9 @@ void tst_qqmlqt::rgba() { QQmlComponent component(&engine, testFileUrl("rgba.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.rgba(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.rgba(): Invalid arguments"; - QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QString warning1 = "rgba.qml:6: Error: Unable to determine callable overload"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QScopedPointer<QObject> object(component.create()); @@ -201,9 +201,9 @@ void tst_qqmlqt::hsla() { QQmlComponent component(&engine, testFileUrl("hsla.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.hsla(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.hsla(): Invalid arguments"; - QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QString warning1 = "hsla.qml:6: Error: Unable to determine callable overload"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QScopedPointer<QObject> object(component.create()); @@ -221,9 +221,9 @@ void tst_qqmlqt::hsva() { QQmlComponent component(&engine, testFileUrl("hsva.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.hsva(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.hsva(): Invalid arguments"; - QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QString warning1 = "hsva.qml:6: Error: Unable to determine callable overload"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QScopedPointer<QObject> object(component.create()); @@ -241,8 +241,8 @@ void tst_qqmlqt::colorEqual() { QQmlComponent component(&engine, testFileUrl("colorEqual.qml")); - QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":6: Error: Qt.colorEqual(): Invalid arguments")); - QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":7: Error: Qt.colorEqual(): Invalid arguments")); + QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":6: Error: Insufficient arguments")); + QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":7: Error: Insufficient arguments")); QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":9: Error: Qt.colorEqual(): Invalid color name")); QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":10: Error: Qt.colorEqual(): Invalid color name")); QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + ":12: Error: Qt.colorEqual(): Invalid arguments")); @@ -322,8 +322,8 @@ void tst_qqmlqt::rect() { QQmlComponent component(&engine, testFileUrl("rect.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.rect(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.rect(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -341,8 +341,8 @@ void tst_qqmlqt::point() { QQmlComponent component(&engine, testFileUrl("point.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.point(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.point(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -359,8 +359,8 @@ void tst_qqmlqt::size() { QQmlComponent component(&engine, testFileUrl("size.qml")); - QString warning1 = component.url().toString() + ":7: Error: Qt.size(): Invalid arguments"; - QString warning2 = component.url().toString() + ":8: Error: Qt.size(): Invalid arguments"; + QString warning1 = component.url().toString() + ":7: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":8: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -378,8 +378,8 @@ void tst_qqmlqt::vector2d() { QQmlComponent component(&engine, testFileUrl("vector2.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.vector2d(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.vector2d(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -396,8 +396,8 @@ void tst_qqmlqt::vector3d() { QQmlComponent component(&engine, testFileUrl("vector.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.vector3d(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.vector3d(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -414,8 +414,8 @@ void tst_qqmlqt::vector4d() { QQmlComponent component(&engine, testFileUrl("vector4.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.vector4d(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.vector4d(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -432,8 +432,8 @@ void tst_qqmlqt::quaternion() { QQmlComponent component(&engine, testFileUrl("quaternion.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.quaternion(): Invalid arguments"; - QString warning2 = component.url().toString() + ":7: Error: Qt.quaternion(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":7: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -450,7 +450,7 @@ void tst_qqmlqt::matrix4x4() { QQmlComponent component(&engine, testFileUrl("matrix4x4.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.matrix4x4(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Too many arguments"; QString warning2 = component.url().toString() + ":7: Error: Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"; QString warning3 = component.url().toString() + ":8: Error: Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); @@ -471,7 +471,7 @@ void tst_qqmlqt::font() { QQmlComponent component(&engine, testFileUrl("font.qml")); - QString warning1 = component.url().toString() + ":6: Error: Qt.font(): Invalid arguments"; + QString warning1 = component.url().toString() + ":6: Error: Too many arguments"; QString warning2 = component.url().toString() + ":7: Error: Qt.font(): Invalid argument: no valid font subproperties specified"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -495,9 +495,9 @@ void tst_qqmlqt::lighter() { QQmlComponent component(&engine, testFileUrl("lighter.qml")); - QString warning1 = component.url().toString() + ":5: Error: Qt.lighter(): Invalid arguments"; - QString warning2 = component.url().toString() + ":10: Error: Qt.lighter(): Invalid arguments"; - QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QString warning1 = "lighter.qml:5: Error: Unable to determine callable overload"; + QString warning2 = component.url().toString() + ":10: Error: Too many arguments"; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QScopedPointer<QObject> object(component.create()); @@ -520,9 +520,9 @@ void tst_qqmlqt::darker() { QQmlComponent component(&engine, testFileUrl("darker.qml")); - QString warning1 = component.url().toString() + ":5: Error: Qt.darker(): Invalid arguments"; - QString warning2 = component.url().toString() + ":10: Error: Qt.darker(): Invalid arguments"; - QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QString warning1 = "darker.qml:5: Error: Unable to determine callable overload"; + QString warning2 = component.url().toString() + ":10: Error: Too many arguments"; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QScopedPointer<QObject> object(component.create()); @@ -545,8 +545,8 @@ void tst_qqmlqt::alpha() { QQmlComponent component(&engine, testFileUrl("alpha.qml")); - QString warning1 = component.url().toString() + ":5: Error: Qt.alpha(): Wrong number of arguments provided"; - QString warning2 = component.url().toString() + ":10: Error: Qt.alpha(): Wrong number of arguments provided"; + QString warning1 = component.url().toString() + ":5: Error: Insufficient arguments"; + QString warning2 = component.url().toString() + ":10: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); @@ -576,8 +576,8 @@ void tst_qqmlqt::tint() { QQmlComponent component(&engine, testFileUrl("tint.qml")); - QString warning1 = component.url().toString() + ":7: Error: Qt.tint(): Invalid arguments"; - QString warning2 = component.url().toString() + ":8: Error: Qt.tint(): Invalid arguments"; + QString warning1 = component.url().toString() + ":7: Error: Too many arguments"; + QString warning2 = component.url().toString() + ":8: Error: Insufficient arguments"; QString warning3 = component.url().toString() + ":13: Error: Insufficient arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); @@ -604,9 +604,10 @@ void tst_qqmlqt::color() { QQmlComponent component(&engine, testFileUrl("color.qml")); - QStringList warnings = { ":7: Error: Qt.color(): Argument must be a string", - ":8: Error: Qt.color(): Qt.color takes exactly one argument", - ":9: Error: Qt.color(): Qt.color takes exactly one argument" }; + QStringList warnings = { ":6: Error: \"taint\" is not a valid color name", + ":7: Error: \"0.5\" is not a valid color name", + ":8: Error: Insufficient arguments", + ":9: Error: Too many arguments" }; for (const QString &warning : warnings) QTest::ignoreMessage(QtWarningMsg, qPrintable(component.url().toString() + warning)); @@ -682,7 +683,7 @@ void tst_qqmlqt::md5() { QQmlComponent component(&engine, testFileUrl("md5.qml")); - QString warning1 = component.url().toString() + ":4: Error: Qt.md5(): Invalid arguments"; + QString warning1 = component.url().toString() + ":4: Error: Insufficient arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QScopedPointer<QObject> object(component.create()); @@ -696,9 +697,9 @@ void tst_qqmlqt::createComponent() { QQmlComponent component(&engine, testFileUrl("createComponent.qml")); - QString warning1 = component.url().toString() + ":9: Error: Qt.createComponent(): Invalid arguments"; - QString warning2 = component.url().toString() + ":10: Error: Qt.createComponent(): Invalid arguments"; - QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QString warning1 = "createComponent.qml:9: Error: Unable to determine callable overload"; + QString warning2 = component.url().toString() + ":10: Error: Invalid compilation mode 10"; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QScopedPointer<QObject> object(component.create()); @@ -733,18 +734,22 @@ void tst_qqmlqt::createQmlObject() { QQmlComponent component(&engine, testFileUrl("createQmlObject.qml")); - QString warning1 = component.url().toString() + ":7: Error: Qt.createQmlObject(): Invalid arguments"; + QString warning1 = "createQmlObject.qml:7: Error: Unable to determine callable overload"; QString warning2 = component.url().toString()+ ":10: Error: Qt.createQmlObject(): failed to create object: \n " + testFileUrl("inline").toString() + ":2:10: Blah is not a type"; QString warning3 = component.url().toString()+ ":11: Error: Qt.createQmlObject(): failed to create object: \n " + testFileUrl("main.qml").toString() + ":4:14: Duplicate property name"; - QString warning4 = component.url().toString()+ ":9: Error: Qt.createQmlObject(): Missing parent object"; - QString warning5 = component.url().toString()+ ":8: Error: Qt.createQmlObject(): Invalid arguments"; + QString warning4 = component.url().toString()+ ":9: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed."; + QString warning5 = component.url().toString()+ ":8: Error: Too many arguments"; QString warning6 = "RunTimeError: Qt.createQmlObject(): failed to create object: \n " + testFileUrl("inline").toString() + ":3:16: Cannot assign object type QObject with no default method"; - QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); + QString warning7 = "Could not convert argument 1 at"; + QString warning8 = "expression for noParent@"; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning1)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning3)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning4)); QTest::ignoreMessage(QtWarningMsg, qPrintable(warning5)); QTest::ignoreMessage(QtDebugMsg, qPrintable(warning6)); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning7)); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning8)); QScopedPointer<QObject> object(component.create()); QVERIFY(object != nullptr); @@ -808,28 +813,41 @@ void tst_qqmlqt::dateTimeFormatting() QQmlComponent component(&eng, testFileUrl("formatting.qml")); QStringList warnings; - warnings << component.url().toString() + ":37: Error: Qt.formatDate(): Bad second argument (must be either string, number or locale)" - << component.url().toString() + ":36: Error: Qt.formatDate(): Missing argument" - << component.url().toString() + ":40: Error: Qt.formatTime(): Bad second argument (must be either string, number or locale)" - << component.url().toString() + ":39: Error: Qt.formatTime(): Missing argument" - << component.url().toString() + ":43: Error: Qt.formatDateTime(): Bad second argument (must be either string, number or locale)" - << component.url().toString() + ":42: Error: Qt.formatDateTime(): Missing argument"; + warnings + << component.url().toString() + ":37: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed." + << component.url().toString() + ":40: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed." + << component.url().toString() + ":43: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed."; foreach (const QString &warning, warnings) QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); - QObject *object = component.createWithInitialProperties({ + warnings.clear(); + warnings + << "formatting.qml:36: Error: Unable to determine callable overload" + << "formatting.qml:39: Error: Unable to determine callable overload" + << "formatting.qml:42: Error: Unable to determine callable overload" + << "Could not convert argument 1 at" + << "expression for err_date2@" + << "Could not convert argument 1 at" + << "expression for err_time2@" + << "Could not convert argument 1 at" + << "expression for err_dateTime2@"; + + foreach (const QString &warning, warnings) + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning)); + + QScopedPointer<QObject> object(component.createWithInitialProperties({ {"qdate", date}, {"qtime", time}, {"qdatetime", dateTime} - }); + })); QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString())); QVERIFY(object != nullptr); QVERIFY(inputProperties.count() > 0); QVariant result; foreach(const QString &prop, inputProperties) { - QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(), + QVERIFY(QMetaObject::invokeMethod(object.data(), method.toUtf8().constData(), Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, prop))); QStringList output = result.toStringList(); @@ -837,8 +855,6 @@ void tst_qqmlqt::dateTimeFormatting() for (int i=0; i<output.count(); i++) QCOMPARE(output[i], expectedResults[i]); } - - delete object; } void tst_qqmlqt::dateTimeFormatting_data() @@ -884,28 +900,63 @@ void tst_qqmlqt::dateTimeFormattingVariants() QQmlComponent component(&eng, testFileUrl("formatting.qml")); QStringList warnings; - warnings << component.url().toString() + ":37: Error: Qt.formatDate(): Bad second argument (must be either string, number or locale)" - << component.url().toString() + ":36: Error: Qt.formatDate(): Missing argument" - << component.url().toString() + ":40: Error: Qt.formatTime(): Bad second argument (must be either string, number or locale)" - << component.url().toString() + ":39: Error: Qt.formatTime(): Missing argument" - << component.url().toString() + ":43: Error: Qt.formatDateTime(): Bad second argument (must be either string, number or locale)" - << component.url().toString() + ":42: Error: Qt.formatDateTime(): Missing argument"; + warnings << component.url().toString() + ":37: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed." + << component.url().toString() + ":40: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed." + << component.url().toString() + ":43: TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed."; - foreach (const QString &warning, warnings) + for (const QString &warning : qAsConst(warnings)) QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); - QObject *object = component.createWithInitialProperties({{"qvariant", variant}}); + warnings.clear(); + warnings << "formatting.qml:36: Error: Unable to determine callable overload." + << "formatting.qml:39: Error: Unable to determine callable overload." + << "formatting.qml:42: Error: Unable to determine callable overload." + << "Could not convert argument 1 at" + << "expression for err_date2@" + << "Could not convert argument 1 at" + << "expression for err_time2@" + << "Could not convert argument 1 at" + << "expression for err_dateTime2@"; + + for (const QString &warning : qAsConst(warnings)) + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning)); + + warnings.clear(); + if (method == QStringLiteral("formatTime") && variant.typeId() == QMetaType::QString) { + for (int i = 0; i < 4; ++i) { + QTest::ignoreMessage(QtWarningMsg, + "\"2011/05/31 11:16:39.755\" is a " + "date/time string being passed to formatTime(). You should only " + "pass time strings to formatTime()."); + } + } + + if (variant.typeId() == QMetaType::QColor || variant.typeId() == QMetaType::Int) { + if (method == "formatTime") { + // formatTime has special error handling as it parses the strings itself. + QTest::ignoreMessage(QtWarningMsg, QRegularExpression( + "formatting.qml:18: Error: Invalid argument passed to " + "formatTime")); + } else { + QTest::ignoreMessage(QtWarningMsg, + QRegularExpression("Could not convert argument 0 at")); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression(method + "@")); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression( + "TypeError: Passing incompatible arguments to " + "C.. functions from JavaScript is not allowed.")); + } + } + + QScopedPointer<QObject> object(component.createWithInitialProperties({{"qvariant", variant}})); QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString())); QVERIFY(object != nullptr); QVariant result; - QVERIFY(QMetaObject::invokeMethod(object, method.toUtf8().constData(), + QVERIFY(QMetaObject::invokeMethod(object.data(), method.toUtf8().constData(), Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, QString(QLatin1String("qvariant"))))); QStringList output = result.toStringList(); QCOMPARE(output, expectedResults); - - delete object; } void tst_qqmlqt::dateTimeFormattingVariants_data() @@ -997,45 +1048,25 @@ void tst_qqmlqt::dateTimeFormattingVariants_data() temporary = QVariant::fromValue(color).toDateTime(); QTest::newRow("formatDate, qcolor") << "formatDate" << QVariant::fromValue(color) - << (QStringList() - << QLocale().toString(temporary.date(), QLocale::ShortFormat) - << QLocale().toString(temporary.date(), QLocale::LongFormat) - << temporary.date().toString("ddd MMMM d yy")); + << QStringList(); QTest::newRow("formatDateTime, qcolor") << "formatDateTime" << QVariant::fromValue(color) - << (QStringList() - << QLocale().toString(temporary, QLocale::ShortFormat) - << QLocale().toString(temporary, QLocale::LongFormat) - << temporary.toString("M/d/yy H:m:s a")); + << QStringList(); QTest::newRow("formatTime, qcolor") << "formatTime" << QVariant::fromValue(color) - << (QStringList() - << QLocale().toString(temporary.time(), QLocale::ShortFormat) - << QLocale().toString(temporary.time(), QLocale::LongFormat) - << temporary.time().toString("H:m:s a") - << temporary.time().toString("hh:mm:ss.zzz")); + << QStringList(); int integer(4); temporary = QVariant::fromValue(integer).toDateTime(); QTest::newRow("formatDate, int") << "formatDate" << QVariant::fromValue(integer) - << (QStringList() - << QLocale().toString(temporary.date(), QLocale::ShortFormat) - << QLocale().toString(temporary.date(), QLocale::LongFormat) - << temporary.date().toString("ddd MMMM d yy")); + << QStringList(); QTest::newRow("formatDateTime, int") << "formatDateTime" << QVariant::fromValue(integer) - << (QStringList() - << QLocale().toString(temporary, QLocale::ShortFormat) - << QLocale().toString(temporary, QLocale::LongFormat) - << temporary.toString("M/d/yy H:m:s a")); + << QStringList(); QTest::newRow("formatTime, int") << "formatTime" << QVariant::fromValue(integer) - << (QStringList() - << QLocale().toString(temporary.time(), QLocale::ShortFormat) - << QLocale().toString(temporary.time(), QLocale::LongFormat) - << temporary.time().toString("H:m:s a") - << temporary.time().toString("hh:mm:ss.zzz")); + << QStringList(); } void tst_qqmlqt::dateTimeFormattingWithLocale() @@ -1054,8 +1085,13 @@ void tst_qqmlqt::dateTimeFormattingWithLocale() auto dateString = o->property("dateString").toString(); QCOMPARE(dateString, QLocale("de_DE").toString(date, QLocale::ShortFormat)); - QString warningMsg = url.toString() + QLatin1String(":11: Error: Qt.formatTime(): Third argument must be a Locale format option"); - QTest::ignoreMessage(QtMsgType::QtWarningMsg, warningMsg.toUtf8().constData()); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Could not convert argument 1 at")); + QTest::ignoreMessage(QtWarningMsg, QRegularExpression("invalidUsage@")); + QTest::ignoreMessage( + QtWarningMsg, + qPrintable(url.toString() + QStringLiteral(":11: TypeError: Passing incompatible " + "arguments to C++ functions from " + "JavaScript is not allowed."))); QMetaObject::invokeMethod(o.get(), "invalidUsage"); } @@ -1076,7 +1112,7 @@ void tst_qqmlqt::btoa() { QQmlComponent component(&engine, testFileUrl("btoa.qml")); - QString warning1 = component.url().toString() + ":4: Error: Qt.btoa(): Invalid arguments"; + QString warning1 = component.url().toString() + ":4: Error: Insufficient arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QScopedPointer<QObject> object(component.create()); @@ -1089,7 +1125,7 @@ void tst_qqmlqt::atob() { QQmlComponent component(&engine, testFileUrl("atob.qml")); - QString warning1 = component.url().toString() + ":4: Error: Qt.atob(): Invalid arguments"; + QString warning1 = component.url().toString() + ":4: Error: Insufficient arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QScopedPointer<QObject> object(component.create()); @@ -1102,7 +1138,7 @@ void tst_qqmlqt::fontFamilies() { QQmlComponent component(&engine, testFileUrl("fontFamilies.qml")); - QString warning1 = component.url().toString() + ":4: Error: Qt.fontFamilies(): Invalid arguments"; + QString warning1 = component.url().toString() + ":4: Error: Too many arguments"; QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1)); QScopedPointer<QObject> object(component.create()); @@ -1141,7 +1177,8 @@ void tst_qqmlqt::resolvedUrl() QVERIFY(object != nullptr); QCOMPARE(object->property("result").toString(), component.url().toString()); - QCOMPARE(object->property("isString").toBool(), true); + QCOMPARE(object->property("isString").toBool(), false); + QCOMPARE(object->property("isObject").toBool(), true); } void tst_qqmlqt::later_data() @@ -1245,39 +1282,56 @@ void tst_qqmlqt::later() void tst_qqmlqt::qtObjectContents() { - QQmlComponent component(&engine, testFileUrl("qtObjectContents.qml")); + QByteArray qml = + "import QtQml\n" + "QtObject {\n" + " property int vLoadingModeAsynchronous: Qt.Asynchronous\n" + " property int vLoadingModeSynchronous: Qt.Synchronous\n"; - QScopedPointer<QObject> object(component.create()); - QVERIFY(object != nullptr); + const QMetaObject *qtMetaObject = &Qt::staticMetaObject; + for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { + const QMetaEnum enumerator = qtMetaObject->enumerator(ii); + for (int jj = 0; jj < enumerator.keyCount(); ++jj) { + const QByteArray key = enumerator.key(jj); + QVERIFY(!key.isEmpty()); - QVERIFY(object->property("values").canConvert<QJSValue>()); - QVariantMap values = object->property("values").value<QJSValue>().toVariant().toMap(); + // We don't want to check for Qt.green and things like that. + // They're nonsensical + if (QChar::fromLatin1(key.front()).isLower()) + continue; - QSet<const char *> keys; - int uniqueKeys = 0; - const QMetaObject *qtMetaObject = &Qt::staticMetaObject; + qml += QByteArray(" property int v") + enumerator.name() + key + + QByteArray(": Qt.") + key + '\n'; + } + } + + qml += "}\n"; + + QQmlComponent component(&engine); + component.setData(qml, QUrl()); + + QScopedPointer<QObject> object(component.create()); + QVERIFY2(object != nullptr, qPrintable(component.errorString())); + + bool ok = false; for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { - QMetaEnum enumerator = qtMetaObject->enumerator(ii); + const QMetaEnum enumerator = qtMetaObject->enumerator(ii); for (int jj = 0; jj < enumerator.keyCount(); ++jj) { - auto key = enumerator.key(jj); -// qDebug() << "key:" << key; - if (!keys.contains(key)) { - ++uniqueKeys; - keys.insert(key); - } - QVERIFY(values.contains(key)); - QVariant value = values.value(key); - QVERIFY(value.canConvert<int>()); - QCOMPARE(value.toInt(), enumerator.value(jj)); + const QByteArray key = enumerator.key(jj); + + if (QChar::fromLatin1(key.front()).isLower()) + continue; + + QCOMPARE(object->property(QByteArray("v") + enumerator.name() + key).toInt(&ok), + enumerator.value(jj)); + QVERIFY(ok); } } - QVERIFY(values.contains("Asynchronous")); - QCOMPARE(values.value("Asynchronous").toInt(), 0); - ++uniqueKeys; - QVERIFY(values.contains("Synchronous")); - QCOMPARE(values.value("Synchronous").toInt(), 1); - ++uniqueKeys; - QCOMPARE(values.count(), uniqueKeys); + + QCOMPARE(object->property("vLoadingModeAsynchronous").toInt(&ok), 0); + QVERIFY(ok); + QCOMPARE(object->property("vLoadingModeSynchronous").toInt(&ok), 1); + QVERIFY(ok); } class TimeProvider: public QObject |