summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Dohmen <psykai1993@googlemail.com>2016-04-11 19:38:50 +0200
committerMilian Wolff <milian.wolff@kdab.com>2016-06-21 09:50:33 +0000
commitf48e8c9711fbeb350ccf70f852ce3732844d4287 (patch)
tree43756259e8794b89801cdc2aa936840af92c5d98
parent3be67a7799aa1960d459548a43ddf54044f80ec1 (diff)
downloadqtwebchannel-f48e8c9711fbeb350ccf70f852ce3732844d4287.tar.gz
Make passing objects from website to server possible
If you get an object from the server and want to pass it back to the server via a function the id of the object is passed instead of the whole json object. On the server side QMetaObjectPublisher::invokeMethod now looks up the object in QMetaObjectPublisher::wrappedObjects by the passed object-id. Task-number: QTBUG-50075 Change-Id: Id0df2dfaa79bcba12ca48391ae7537ac1a086898 Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp63
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h4
-rw-r--r--src/webchannel/qwebchannel.js16
-rw-r--r--tests/auto/webchannel/tst_webchannel.cpp50
-rw-r--r--tests/auto/webchannel/tst_webchannel.h16
5 files changed, 122 insertions, 27 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index 0fa4ae2..b3fc53d 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -87,29 +87,6 @@ QJsonObject createResponse(const QJsonValue &id, const QJsonValue &data)
/// TODO: what is the proper value here?
const int PROPERTY_UPDATE_INTERVAL = 50;
-
-QVariant toVariant(const QJsonValue &value, int targetType)
-{
- if (targetType == QMetaType::QJsonValue) {
- return QVariant::fromValue(value);
- } else if (targetType == QMetaType::QJsonArray) {
- if (!value.isArray())
- qWarning() << "Cannot not convert non-array argument" << value << "to QJsonArray.";
- return QVariant::fromValue(value.toArray());
- } else if (targetType == QMetaType::QJsonObject) {
- if (!value.isObject())
- qWarning() << "Cannot not convert non-object argument" << value << "to QJsonObject.";
- return QVariant::fromValue(value.toObject());
- }
-
- // this converts QJsonObjects to QVariantMaps, which is not desired when
- // we want to get a QJsonObject or QJsonValue (see above)
- QVariant variant = value.toVariant();
- if (targetType != QMetaType::QVariant && !variant.convert(targetType)) {
- qWarning() << "Could not convert argument" << value << "to target type" << QVariant::typeToName(targetType) << '.';
- }
- return variant;
-}
}
QMetaObjectPublisher::QMetaObjectPublisher(QWebChannel *webChannel)
@@ -472,6 +449,46 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object)
pendingPropertyUpdates.remove(object);
}
+QObject *QMetaObjectPublisher::unwrapObject(const QString &objectId) const
+{
+ if (!objectId.isEmpty()) {
+ ObjectInfo objectInfo = wrappedObjects.value(objectId);
+ if (objectInfo.object && !objectInfo.classinfo.isEmpty())
+ return objectInfo.object;
+ }
+
+ qWarning() << "No wrapped object" << objectId;
+ return Q_NULLPTR;
+}
+
+QVariant QMetaObjectPublisher::toVariant(const QJsonValue &value, int targetType) const
+{
+ if (targetType == QMetaType::QJsonValue) {
+ return QVariant::fromValue(value);
+ } else if (targetType == QMetaType::QJsonArray) {
+ if (!value.isArray())
+ qWarning() << "Cannot not convert non-array argument" << value << "to QJsonArray.";
+ return QVariant::fromValue(value.toArray());
+ } else if (targetType == QMetaType::QJsonObject) {
+ if (!value.isObject())
+ qWarning() << "Cannot not convert non-object argument" << value << "to QJsonObject.";
+ return QVariant::fromValue(value.toObject());
+ } else if (QMetaType::typeFlags(targetType) & QMetaType::PointerToQObject) {
+ QObject *unwrappedObject = unwrapObject(value.toObject()[KEY_ID].toString());
+ if (unwrappedObject == Q_NULLPTR)
+ qWarning() << "Cannot not convert non-object argument" << value << "to QObject*.";
+ return QVariant::fromValue(unwrappedObject);
+ }
+
+ // this converts QJsonObjects to QVariantMaps, which is not desired when
+ // we want to get a QJsonObject or QJsonValue (see above)
+ QVariant variant = value.toVariant();
+ if (targetType != QMetaType::QVariant && !variant.convert(targetType)) {
+ qWarning() << "Could not convert argument" << value << "to target type" << QVariant::typeToName(targetType) << '.';
+ }
+ return variant;
+}
+
// NOTE: transport can be a nullptr
// in such a case, we need to ensure that the property is registered to
// the target transports of the parentObjectId
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index b0ebd84..048a33c 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -166,6 +166,10 @@ public:
*/
void objectDestroyed(const QObject *object);
+ QObject *unwrapObject(const QString &objectId) const;
+
+ QVariant toVariant(const QJsonValue &value, int targetType) const;
+
/**
* Given a QVariant containing a QObject*, wrap the object and register for property updates
* return the objects class information.
diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js
index d8c28bc..148e70d 100644
--- a/src/webchannel/qwebchannel.js
+++ b/src/webchannel/qwebchannel.js
@@ -324,10 +324,15 @@ function QObject(name, data, webChannel)
var args = [];
var callback;
for (var i = 0; i < arguments.length; ++i) {
- if (typeof arguments[i] === "function")
- callback = arguments[i];
+ var argument = arguments[i];
+ if (typeof argument === "function")
+ callback = argument;
+ else if (argument instanceof QObject && webChannel.objects[argument.__id__] !== undefined)
+ args.push({
+ "id": argument.__id__
+ });
else
- args.push(arguments[i]);
+ args.push(argument);
}
webChannel.exec({
@@ -381,11 +386,14 @@ function QObject(name, data, webChannel)
return;
}
object.__propertyCache__[propertyIndex] = value;
+ var valueToSend = value;
+ if (valueToSend instanceof QObject && webChannel.objects[valueToSend.__id__] !== undefined)
+ valueToSend = { "id": valueToSend.__id__ };
webChannel.exec({
"type": QWebChannelMessageTypes.setProperty,
"object": object.__id__,
"property": propertyIndex,
- "value": value
+ "value": valueToSend
});
}
});
diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp
index 93c7aa8..7ae6f78 100644
--- a/tests/auto/webchannel/tst_webchannel.cpp
+++ b/tests/auto/webchannel/tst_webchannel.cpp
@@ -345,6 +345,12 @@ void TestWebChannel::testInfoForObject()
}
{
QJsonArray method;
+ method.append(QStringLiteral("setReturnedObject"));
+ method.append(obj.metaObject()->indexOfMethod("setReturnedObject(TestObject*)"));
+ expected.append(method);
+ }
+ {
+ QJsonArray method;
method.append(QStringLiteral("setObjectProperty"));
method.append(obj.metaObject()->indexOfMethod("setObjectProperty(QObject*)"));
expected.append(method);
@@ -446,6 +452,19 @@ void TestWebChannel::testInfoForObject()
property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.objectProperty())));
expected.append(property);
}
+ {
+ QJsonArray property;
+ property.append(obj.metaObject()->indexOfProperty("returnedObject"));
+ property.append(QStringLiteral("returnedObject"));
+ {
+ QJsonArray signal;
+ signal.append(1);
+ signal.append(obj.metaObject()->indexOfMethod("returnedObjectChanged()"));
+ property.append(signal);
+ }
+ property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.returnedObject())));
+ expected.append(property);
+ }
QCOMPARE(info["properties"].toArray(), expected);
}
}
@@ -587,6 +606,36 @@ void TestWebChannel::testWrapRegisteredObject()
QCOMPARE(obj.objectName(), returnedId);
}
+void TestWebChannel::testPassWrappedObjectBack()
+{
+ QWebChannel channel;
+ TestObject registeredObj;
+ TestObject returnedObjMethod;
+ TestObject returnedObjProperty;
+
+ registeredObj.setObjectName("registeredObject");
+
+ channel.registerObject(registeredObj.objectName(), &registeredObj);
+ channel.connectTo(m_dummyTransport);
+ channel.d_func()->publisher->initializeClient(m_dummyTransport);
+
+ QMetaObjectPublisher *pub = channel.d_func()->publisher;
+ QJsonObject returnedObjMethodInfo = pub->wrapResult(QVariant::fromValue(&returnedObjMethod), m_dummyTransport).toObject();
+ QJsonObject returnedObjPropertyInfo = pub->wrapResult(QVariant::fromValue(&returnedObjProperty), m_dummyTransport).toObject();
+
+ QJsonArray argsMethod;
+ QJsonObject argMethod0;
+ argMethod0["id"] = returnedObjMethodInfo["id"];
+ argsMethod << argMethod0;
+ QJsonObject argProperty;
+ argProperty["id"] = returnedObjPropertyInfo["id"];
+
+ pub->invokeMethod(&registeredObj, registeredObj.metaObject()->indexOfSlot("setReturnedObject(TestObject*)"), argsMethod);
+ QCOMPARE(registeredObj.mReturnedObject, &returnedObjMethod);
+ pub->setProperty(&registeredObj, registeredObj.metaObject()->indexOfProperty("returnedObject"), argProperty);
+ QCOMPARE(registeredObj.mReturnedObject, &returnedObjProperty);
+}
+
void TestWebChannel::testInfiniteRecursion()
{
QWebChannel channel;
@@ -739,6 +788,7 @@ void TestWebChannel::qtbug46548_overriddenProperties()
#endif // WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE
}
+
QTEST_MAIN(TestWebChannel)
#include "tst_webchannel.moc"
diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h
index 13294c2..5a9fa11 100644
--- a/tests/auto/webchannel/tst_webchannel.h
+++ b/tests/auto/webchannel/tst_webchannel.h
@@ -73,11 +73,13 @@ class TestObject : public QObject
Q_PROPERTY(int asdf READ asdf NOTIFY asdfChanged)
Q_PROPERTY(QString bar READ bar NOTIFY theBarHasChanged)
Q_PROPERTY(QObject * objectProperty READ objectProperty WRITE setObjectProperty NOTIFY objectPropertyChanged)
+ Q_PROPERTY(TestObject * returnedObject READ returnedObject WRITE setReturnedObject NOTIFY returnedObjectChanged)
public:
explicit TestObject(QObject *parent = 0)
: QObject(parent)
, mObjectProperty(0)
+ , mReturnedObject(Q_NULLPTR)
{ }
enum Foo {
@@ -94,6 +96,11 @@ public:
return mObjectProperty;
}
+ TestObject *returnedObject() const
+ {
+ return mReturnedObject;
+ }
+
Q_INVOKABLE void method1() {}
protected:
@@ -108,11 +115,18 @@ signals:
void asdfChanged();
void theBarHasChanged();
void objectPropertyChanged();
+ void returnedObjectChanged();
public slots:
void slot1() {}
void slot2(const QString&) {}
+ void setReturnedObject(TestObject *obj)
+ {
+ mReturnedObject = obj;
+ emit returnedObjectChanged();
+ }
+
void setObjectProperty(QObject *object)
{
mObjectProperty = object;
@@ -127,6 +141,7 @@ private slots:
public:
QObject *mObjectProperty;
+ TestObject *mReturnedObject;
};
class BenchObject : public QObject
@@ -264,6 +279,7 @@ private slots:
void testSetPropertyConversion();
void testDisconnect();
void testWrapRegisteredObject();
+ void testPassWrappedObjectBack();
void testInfiniteRecursion();
void benchClassInfo();