From 97c876a1353f29ed0129360f013f2529bed69d98 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 25 May 2016 16:42:01 +0200 Subject: Enable calling C++ functions taking QJson arguments via webchannel. We used to convert the QJsonValue arguments to QVariants, which then failed to call a C++ function which expected on of the three QJson data types, i.e. QJsonValue, QJsonObject or QJsonArray. Instead, we now detect these three cases and manually convert the QJsonValue as needed. [ChangeLog] C++ functions taking arguments of type QJsonValue, QJsonArray or QJsonObject can now be called via the Qt WebChannel. Change-Id: I94e0c8937ca35e2ecd3554f7ddf2d4e5a3328570 Task-number: QTBUG-48198 Reviewed-by: Simon Hausmann --- src/webchannel/qmetaobjectpublisher.cpp | 29 ++++++++++++++++++---- tests/auto/webchannel/tst_webchannel.cpp | 41 ++++++++++++++++++++++++++++++++ tests/auto/webchannel/tst_webchannel.h | 5 ++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index 324191e..e85bc76 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -87,6 +87,29 @@ 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) @@ -366,11 +389,7 @@ QVariant QMetaObjectPublisher::invokeMethod(QObject *const object, const int met // construct converter objects of QVariant to QGenericArgument VariantArgument arguments[10]; for (int i = 0; i < qMin(args.size(), method.parameterCount()); ++i) { - QVariant arg = args.at(i).toVariant(); - if (method.parameterType(i) != QMetaType::QVariant && !arg.convert(method.parameterType(i))) { - qWarning() << "Could not convert argument" << args.at(i) << "to target type" << method.parameterTypes().at(i) << '.'; - } - arguments[i].value = arg; + arguments[i].value = toVariant(args.at(i), method.parameterType(i)); } // construct QGenericReturnArgument diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index f1911e5..4db8bae 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -216,6 +216,21 @@ void TestWebChannel::setVariant(const QVariant &v) m_lastVariant = v; } +void TestWebChannel::setJsonValue(const QJsonValue& v) +{ + m_lastJsonValue = v; +} + +void TestWebChannel::setJsonObject(const QJsonObject& v) +{ + m_lastJsonValue = v; +} + +void TestWebChannel::setJsonArray(const QJsonArray& v) +{ + m_lastJsonValue = v; +} + void TestWebChannel::testRegisterObjects() { QWebChannel channel; @@ -426,6 +441,32 @@ void TestWebChannel::testInvokeMethodConversion() channel.d_func()->publisher->invokeMethod(this, method, args); QCOMPARE(m_lastVariant, args.at(0).toVariant()); } + { + int method = metaObject()->indexOfMethod("setJsonValue(QJsonValue)"); + QVERIFY(method != -1); + channel.d_func()->publisher->invokeMethod(this, method, args); + QCOMPARE(m_lastJsonValue, args.at(0)); + } + { + int method = metaObject()->indexOfMethod("setJsonObject(QJsonObject)"); + QVERIFY(method != -1); + QJsonObject object; + object["foo"] = QJsonValue(123); + object["bar"] = QJsonValue(4.2); + args[0] = object; + channel.d_func()->publisher->invokeMethod(this, method, args); + QCOMPARE(m_lastJsonValue.toObject(), object); + } + { + int method = metaObject()->indexOfMethod("setJsonArray(QJsonArray)"); + QVERIFY(method != -1); + QJsonArray array; + array << QJsonValue(123); + array << QJsonValue(4.2); + args[0] = array; + channel.d_func()->publisher->invokeMethod(this, method, args); + QCOMPARE(m_lastJsonValue.toArray(), array); + } } void TestWebChannel::testDisconnect() diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index b2a1040..e551458 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -36,6 +36,7 @@ #include #include +#include #include @@ -229,6 +230,9 @@ public: Q_INVOKABLE void setInt(int i); Q_INVOKABLE void setDouble(double d); Q_INVOKABLE void setVariant(const QVariant &v); + Q_INVOKABLE void setJsonValue(const QJsonValue &v); + Q_INVOKABLE void setJsonObject(const QJsonObject &v); + Q_INVOKABLE void setJsonArray(const QJsonArray &v); private slots: void testRegisterObjects(); @@ -252,6 +256,7 @@ private: int m_lastInt; double m_lastDouble; QVariant m_lastVariant; + QJsonValue m_lastJsonValue; }; QT_END_NAMESPACE -- cgit v1.2.1