summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKari Oikarinen <kari.oikarinen@qt.io>2019-09-04 12:01:00 +0300
committerKari Oikarinen <kari.oikarinen@qt.io>2019-09-04 12:01:00 +0300
commit402b26efc6903741655bcc42bc777f73c6fbc5ab (patch)
treef65d033a3cbf1e840d651bb5ce7ca7cfc4b0d990
parent37189eee9cbdef8d973b04ed363bfb55480fd0c8 (diff)
parent9ec7a871082800d1af189236f99b67e4d564a966 (diff)
Merge dev into 5.14 (delayed final downmerge)
This replicates the effects of the fast-forward merge that should have been pushed on 2019-08-27 as the final down-merge from dev to 5.14. Task-number: QTBUG-78019 Change-Id: Iccd04fa361959ba0711f41bf20ff3d064065ed7e
-rw-r--r--src/imports/remoteobjects/plugin.cpp80
-rw-r--r--src/imports/remoteobjects/remoteobjects.pro2
-rw-r--r--src/remoteobjects/qremoteobjectpendingcall.h30
-rw-r--r--tests/auto/modelview/modeltest.cpp4
-rw-r--r--tests/auto/modelview/tst_modelview.cpp2
-rw-r--r--tests/auto/qml/usertypes/data/watcher.qml37
-rw-r--r--tests/auto/qml/usertypes/tst_usertypes.cpp43
-rw-r--r--tests/auto/qml/usertypes/usertypes.rep7
-rw-r--r--tools/repc/repcodegenerator.cpp29
-rw-r--r--tools/repc/repcodegenerator.h1
10 files changed, 228 insertions, 7 deletions
diff --git a/src/imports/remoteobjects/plugin.cpp b/src/imports/remoteobjects/plugin.cpp
index 0bec1a9..4032a63 100644
--- a/src/imports/remoteobjects/plugin.cpp
+++ b/src/imports/remoteobjects/plugin.cpp
@@ -39,11 +39,90 @@
#include <QtRemoteObjects/qremoteobjectnode.h>
#include <QtRemoteObjects/qremoteobjectsettingsstore.h>
+#include <QtRemoteObjects/qremoteobjectpendingcall.h>
+#include <QTimer>
#include <QQmlExtensionPlugin>
+#include <QJSValue>
+#include <QtQml/private/qjsvalue_p.h>
+#include <QtQml/qqmlengine.h>
+#include <qqmlinfo.h>
#include <qqml.h>
QT_BEGIN_NAMESPACE
+struct QtQmlRemoteObjectsResponse {
+ QJSValue promise;
+ QTimer *timer;
+};
+
+class QtQmlRemoteObjects : public QObject
+{
+ Q_OBJECT
+public:
+ ~QtQmlRemoteObjects() {
+ auto i = m_callbacks.begin();
+ while (i != m_callbacks.end()) {
+ delete i.key();
+ delete i.value().timer;
+ i = m_callbacks.erase(i);
+ }
+ }
+
+ Q_INVOKABLE QJSValue watch(const QRemoteObjectPendingCall &reply, int timeout = 30000) {
+ if (m_accessiblePromise.isUndefined())
+ m_accessiblePromise = qmlEngine(this)->evaluate("(function() { var obj = {}; obj.promise = new Promise(function(resolve, reject) { obj.resolve = resolve; obj.reject = reject; }); return obj; })");
+
+ QRemoteObjectPendingCallWatcher *watcher = new QRemoteObjectPendingCallWatcher(reply);
+
+ QJSValue promise = m_accessiblePromise.call();
+ QtQmlRemoteObjectsResponse response;
+ response.promise = promise;
+ response.timer = new QTimer();
+ response.timer->setSingleShot(true);
+ m_callbacks.insert(watcher, response);
+
+ // handle timeout
+ connect(response.timer, &QTimer::timeout, [this, watcher]() {
+ auto i = m_callbacks.find(watcher);
+ if (i == m_callbacks.end()) {
+ qmlWarning(this) << "could not find callback for watcher.";
+ return;
+ }
+
+ QJSValue v(QLatin1String("timeout"));
+ i.value().promise.property("reject").call(QJSValueList() << v);
+
+ delete i.key();
+ delete i.value().timer;
+ m_callbacks.erase(i);
+ });
+
+ // handle success
+ connect(watcher, &QRemoteObjectPendingCallWatcher::finished, [this](QRemoteObjectPendingCallWatcher *self) {
+ auto i = m_callbacks.find(self);
+ if (i == m_callbacks.end()) {
+ qmlWarning(this) << "could not find callback for watcher.";
+ return;
+ }
+
+ QJSValue v;
+ QJSValuePrivate::setVariant(&v, self->returnValue());
+ i.value().promise.property("resolve").call(QJSValueList() << v);
+
+ delete i.key();
+ delete i.value().timer;
+ m_callbacks.erase(i);
+ });
+
+ response.timer->start(timeout);
+ return promise.property("promise");
+ }
+
+private:
+ QHash<QRemoteObjectPendingCallWatcher*,QtQmlRemoteObjectsResponse> m_callbacks;
+ QJSValue m_accessiblePromise;
+};
+
class QtRemoteObjectsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
@@ -58,6 +137,7 @@ public:
qmlRegisterType<QRemoteObjectNode>(uri, 5, 12, "Node");
qmlRegisterType<QRemoteObjectSettingsStore>(uri, 5, 12, "SettingsStore");
+ qmlRegisterSingletonType<QtQmlRemoteObjects>(uri, 5, 14, "QtRemoteObjects", [](QQmlEngine *, QJSEngine*){return new QtQmlRemoteObjects();});
qmlProtectModule(uri, 5);
}
};
diff --git a/src/imports/remoteobjects/remoteobjects.pro b/src/imports/remoteobjects/remoteobjects.pro
index ed21fa6..91de192 100644
--- a/src/imports/remoteobjects/remoteobjects.pro
+++ b/src/imports/remoteobjects/remoteobjects.pro
@@ -3,7 +3,7 @@ TARGET = qtremoteobjects
TARGETPATH = QtRemoteObjects
IMPORT_VERSION = 5.$$QT_MINOR_VERSION
-QT += qml remoteobjects
+QT += qml qml-private remoteobjects
SOURCES = \
$$PWD/plugin.cpp \
diff --git a/src/remoteobjects/qremoteobjectpendingcall.h b/src/remoteobjects/qremoteobjectpendingcall.h
index e895842..086e5d8 100644
--- a/src/remoteobjects/qremoteobjectpendingcall.h
+++ b/src/remoteobjects/qremoteobjectpendingcall.h
@@ -130,6 +130,36 @@ public:
};
+// NOTE: manual expansion of Q_DECLARE_METATYPE_TEMPLATE_1ARG, minus the IsSequentialContainer
+template <typename T>
+struct QMetaTypeId< QRemoteObjectPendingReply<T> >
+{
+ enum {
+ Defined = QMetaTypeId2<T>::Defined
+ };
+ static int qt_metatype_id()
+ {
+ static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0);
+ if (const int id = metatype_id.load())
+ return id;
+ const char *tName = QMetaType::typeName(qMetaTypeId<T>());
+ Q_ASSERT(tName);
+ const int tNameLen = int(qstrlen(tName));
+ QByteArray typeName;
+ typeName.reserve(int(sizeof("QRemoteObjectPendingReply")) + 1 + tNameLen + 1 + 1);
+ typeName.append("QRemoteObjectPendingReply", int(sizeof("QRemoteObjectPendingReply")) - 1)
+ .append('<').append(tName, tNameLen);
+ if (typeName.endsWith('>'))
+ typeName.append(' ');
+ typeName.append('>');
+ const int newId = qRegisterNormalizedMetaType< QRemoteObjectPendingReply<T> >(
+ typeName,
+ reinterpret_cast< QRemoteObjectPendingReply<T> *>(quintptr(-1)));
+ metatype_id.storeRelease(newId);
+ return newId;
+ }
+};
+
QT_END_NAMESPACE
#endif
diff --git a/tests/auto/modelview/modeltest.cpp b/tests/auto/modelview/modeltest.cpp
index 9abf878..859d883 100644
--- a/tests/auto/modelview/modeltest.cpp
+++ b/tests/auto/modelview/modeltest.cpp
@@ -443,12 +443,12 @@ void ModelTest::data()
}
// General Purpose roles that should return a QColor
- QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundColorRole );
+ QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundRole );
if ( colorVariant.isValid() ) {
QVERIFY( colorVariant.canConvert<QColor>() );
}
- colorVariant = model->data ( model->index ( 0, 0 ), Qt::TextColorRole );
+ colorVariant = model->data ( model->index ( 0, 0 ), Qt::ForegroundRole );
if ( colorVariant.isValid() ) {
QVERIFY( colorVariant.canConvert<QColor>() );
}
diff --git a/tests/auto/modelview/tst_modelview.cpp b/tests/auto/modelview/tst_modelview.cpp
index da42763..78e75ca 100644
--- a/tests/auto/modelview/tst_modelview.cpp
+++ b/tests/auto/modelview/tst_modelview.cpp
@@ -733,7 +733,7 @@ void TestModelView::testFlags()
for (int i = 10; i < 20; ++i) {
QStandardItem* firstItem = m_sourceModel.item(i, 0);
QStandardItem* secondItem = m_sourceModel.item(i, 1);
- firstItem->setFlags(firstItem->flags() | Qt::ItemIsEnabled | Qt::ItemIsTristate);
+ firstItem->setFlags(firstItem->flags() | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
secondItem->setFlags(firstItem->flags() | Qt::ItemIsEnabled);
}
bool signalsReceived = false;
diff --git a/tests/auto/qml/usertypes/data/watcher.qml b/tests/auto/qml/usertypes/data/watcher.qml
new file mode 100644
index 0000000..b49d824
--- /dev/null
+++ b/tests/auto/qml/usertypes/data/watcher.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+import QtRemoteObjects 5.14
+import usertypes 1.0
+
+TypeWithReplyReplica {
+ property variant result
+ property bool hasError
+
+ node: Node {
+ registryUrl: "local:testWatcher"
+ }
+ onStateChanged: function(state) {
+ if (state != TypeWithReplyReplica.Valid)
+ return;
+ QtRemoteObjects.watch(uppercase("hello"), 1000)
+ .then(function(value) { hasError = false; result = value },
+ function(error) { hasError = true })
+ }
+
+ function callSlowFunction() {
+ result = 0
+ hasError = false
+
+ QtRemoteObjects.watch(slowFunction(), 300)
+ .then(function(value) { hasError = false; result = value },
+ function(error) { hasError = true })
+ }
+
+ function callComplexFunction() {
+ result = null
+ hasError = false
+
+ QtRemoteObjects.watch(complexReturnType(), 300)
+ .then(function(value) { hasError = false; result = value },
+ function(error) { hasError = true })
+ }
+}
diff --git a/tests/auto/qml/usertypes/tst_usertypes.cpp b/tests/auto/qml/usertypes/tst_usertypes.cpp
index 7c554a9..07bed59 100644
--- a/tests/auto/qml/usertypes/tst_usertypes.cpp
+++ b/tests/auto/qml/usertypes/tst_usertypes.cpp
@@ -32,6 +32,21 @@
#include <qqmlcomponent.h>
#include "rep_usertypes_merged.h"
+class TypeWithReply : public TypeWithReplySimpleSource
+{
+public:
+ QString uppercase(const QString & input) override {
+ return input.toUpper();
+ }
+ QMap<QString, QString> complexReturnType() override {
+ return QMap<QString, QString>{{"one","1"}};
+ }
+ int slowFunction() override {
+ QTest::qWait(1000);
+ return 15;
+ }
+};
+
class tst_usertypes : public QObject
{
Q_OBJECT
@@ -46,6 +61,7 @@ private Q_SLOTS:
void subObjectInQml();
void complexInQml_data();
void complexInQml();
+ void watcherInQml();
};
tst_usertypes::tst_usertypes()
@@ -192,6 +208,33 @@ void tst_usertypes::complexInQml()
}
}
+void tst_usertypes::watcherInQml()
+{
+ qmlRegisterType<TypeWithReplyReplica>("usertypes", 1, 0, "TypeWithReplyReplica");
+
+ QRemoteObjectRegistryHost host(QUrl("local:testWatcher"));
+ TypeWithReply source;
+ host.enableRemoting(&source);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, SRCDIR "data/watcher.qml");
+ QObject *obj = c.create();
+ QVERIFY(obj);
+
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("result").value<QString>(), QString::fromLatin1("HELLO"), 300);
+ QCOMPARE(obj->property("hasError").value<bool>(), false);
+
+ QMetaObject::invokeMethod(obj, "callSlowFunction");
+ QTRY_COMPARE_WITH_TIMEOUT(obj->property("hasError").value<bool>(), true, 1000);
+ QVERIFY(obj->property("result").value<int>() != 10);
+
+ QMetaObject::invokeMethod(obj, "callComplexFunction");
+ QTRY_VERIFY_WITH_TIMEOUT(!obj->property("result").isNull(), 300);
+ auto map = obj->property("result").value<QMap<QString,QString>>();
+ QCOMPARE(map.value("one"), QString::fromLatin1("1"));
+ QCOMPARE(obj->property("hasError").value<bool>(), false);
+}
+
QTEST_MAIN(tst_usertypes)
#include "tst_usertypes.moc"
diff --git a/tests/auto/qml/usertypes/usertypes.rep b/tests/auto/qml/usertypes/usertypes.rep
index dff361d..a82d1d9 100644
--- a/tests/auto/qml/usertypes/usertypes.rep
+++ b/tests/auto/qml/usertypes/usertypes.rep
@@ -23,3 +23,10 @@ class ComplexType
CLASS clock(SimpleClock)
PROP(int after = 42)
}
+
+class TypeWithReply
+{
+ SLOT(QString uppercase(const QString &input))
+ SLOT(QMap<QString, QString> complexReturnType())
+ SLOT(int slowFunction())
+};
diff --git a/tools/repc/repcodegenerator.cpp b/tools/repc/repcodegenerator.cpp
index fdb27d7..001103c 100644
--- a/tools/repc/repcodegenerator.cpp
+++ b/tools/repc/repcodegenerator.cpp
@@ -205,6 +205,7 @@ void RepCodeGenerator::generate(const AST &ast, Mode mode, QString fileName)
for (const ASTClass &astClass : ast.classes) {
QSet<QString> classMetaTypes;
+ QSet<QString> pendingMetaTypes;
for (const ASTProperty &property : astClass.properties) {
if (property.isPointer)
continue;
@@ -212,6 +213,7 @@ void RepCodeGenerator::generate(const AST &ast, Mode mode, QString fileName)
}
const auto extractClassMetaTypes = [&](const ASTFunction &function) {
classMetaTypes << function.returnType;
+ pendingMetaTypes << function.returnType;
for (const ASTDeclaration &decl : function.params) {
classMetaTypes << decl.type;
}
@@ -220,15 +222,19 @@ void RepCodeGenerator::generate(const AST &ast, Mode mode, QString fileName)
extractClassMetaTypes(function);
for (const ASTFunction &function : astClass.slotsList)
extractClassMetaTypes(function);
- QString classMetaTypeRegistrationCode = metaTypeRegistrationCode + generateMetaTypeRegistration(classMetaTypes);
+
+ const QString classMetaTypeRegistrationCode = metaTypeRegistrationCode
+ + generateMetaTypeRegistration(classMetaTypes);
+ const QString replicaMetaTypeRegistrationCode = classMetaTypeRegistrationCode
+ + generateMetaTypeRegistrationForPending(pendingMetaTypes);
if (mode == MERGED) {
- generateClass(REPLICA, stream, astClass, classMetaTypeRegistrationCode);
+ generateClass(REPLICA, stream, astClass, replicaMetaTypeRegistrationCode);
generateClass(SOURCE, stream, astClass, classMetaTypeRegistrationCode);
generateClass(SIMPLE_SOURCE, stream, astClass, classMetaTypeRegistrationCode);
generateSourceAPI(stream, astClass);
} else {
- generateClass(mode, stream, astClass, classMetaTypeRegistrationCode);
+ generateClass(mode, stream, astClass, mode == REPLICA ? replicaMetaTypeRegistrationCode : classMetaTypeRegistrationCode);
if (mode == SOURCE) {
generateClass(SIMPLE_SOURCE, stream, astClass, classMetaTypeRegistrationCode);
generateSourceAPI(stream, astClass);
@@ -564,6 +570,23 @@ QString RepCodeGenerator::generateMetaTypeRegistration(const QSet<QString> &meta
return out;
}
+QString RepCodeGenerator::generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes)
+{
+ QString out;
+ if (!metaTypes.isEmpty())
+ out += QLatin1String(" qRegisterMetaType<QRemoteObjectPendingCall>();\n");
+ const QString qRegisterMetaType = QStringLiteral(" qRegisterMetaType<QRemoteObjectPendingReply<%1>>();\n");
+ const QString qRegisterConverterConditional = QStringLiteral(" if (!QMetaType::hasRegisteredConverterFunction<QRemoteObjectPendingReply<%1>, QRemoteObjectPendingCall>())\n");
+ const QString qRegisterConverter = QStringLiteral(" QMetaType::registerConverter<QRemoteObjectPendingReply<%1>, QRemoteObjectPendingCall>();\n");
+ for (const QString &metaType : metaTypes) {
+ out += qRegisterMetaType.arg(metaType);
+ out += qRegisterConverterConditional.arg(metaType);
+ out += qRegisterConverter.arg(metaType);
+ }
+ return out;
+}
+
+
QString RepCodeGenerator::generateMetaTypeRegistrationForEnums(const QVector<QString> &enumUses)
{
QString out;
diff --git a/tools/repc/repcodegenerator.h b/tools/repc/repcodegenerator.h
index d7ec4c8..be3353d 100644
--- a/tools/repc/repcodegenerator.h
+++ b/tools/repc/repcodegenerator.h
@@ -63,6 +63,7 @@ public:
private:
void generateHeader(Mode mode, QTextStream &out, const AST &ast);
QString generateMetaTypeRegistration(const QSet<QString> &metaTypes);
+ QString generateMetaTypeRegistrationForPending(const QSet<QString> &metaTypes);
QString generateMetaTypeRegistrationForEnums(const QVector<QString> &enums);
void generateStreamOperatorsForEnums(QTextStream &out, const QVector<QString> &enums);