From bf4abef06ebc23e06280ad656c5777468e429b79 Mon Sep 17 00:00:00 2001 From: Paul Knopf Date: Sun, 23 Sep 2018 18:21:48 -0400 Subject: [PATCH] Added supprot for setting/getting context properties. --- .../QmlNet/qml/NetValueMetaObjectPacker.cpp | 47 +------------ src/native/QmlNet/QmlNet/qml/NetVariant.cpp | 66 +++++++++++++++++++ src/native/QmlNet/QmlNet/qml/NetVariant.h | 2 + .../QmlNet/qml/QQmlApplicationEngine.cpp | 18 +++++ .../Qml/QQmlApplicationEngineTests.cs | 29 ++++++++ src/net/Qml.Net/QQmlApplicationEngine.cs | 39 +++++++++++ 6 files changed, 155 insertions(+), 46 deletions(-) create mode 100644 src/net/Qml.Net.Tests/Qml/QQmlApplicationEngineTests.cs diff --git a/src/native/QmlNet/QmlNet/qml/NetValueMetaObjectPacker.cpp b/src/native/QmlNet/QmlNet/qml/NetValueMetaObjectPacker.cpp index f94c5002..a0e22bd9 100644 --- a/src/native/QmlNet/QmlNet/qml/NetValueMetaObjectPacker.cpp +++ b/src/native/QmlNet/QmlNet/qml/NetValueMetaObjectPacker.cpp @@ -153,52 +153,7 @@ void NetValueTypePacker::unpack(QSharedPointer destination, void* so break; } - switch(sourceVariant->type()) { - case QVariant::Invalid: - destination->clear(); - break; - case QVariant::Bool: - destination->setBool(sourceVariant->value()); - break; - case QVariant::Char: - destination->setChar(sourceVariant->toChar()); - break; - case QVariant::Int: - destination->setInt(sourceVariant->value()); - break; - case QVariant::UInt: - destination->setUInt(sourceVariant->value()); - break; - case QVariant::Double: - destination->setDouble(sourceVariant->value()); - break; - case QVariant::String: - { - QString stringValue = sourceVariant->toString(); - destination->setString(&stringValue); - break; - } - case QVariant::DateTime: - { - QDateTime dateTimeValue = sourceVariant->toDateTime(); - destination->setDateTime(dateTimeValue); - break; - } - default: - - if(sourceVariant->userType() == qMetaTypeId()) { - // TODO: Either serialize this type to a string, to be deserialized in .NET, or - // pass raw value to .NET to be dynamically invoked (using dynamic). - // See qtdeclarative\src\plugins\qmltooling\qmldbg_debugger\qqmlenginedebugservice.cpp:184 - // for serialization methods. - QSharedPointer netJsValue = QSharedPointer(new NetJSValue(sourceVariant->value())); - destination->setJsValue(netJsValue); - break; - } - - qDebug() << "Unsupported variant type: " << sourceVariant->type(); - break; - } + NetVariant::fromQVariant(sourceVariant, destination); } class StringValueTypePacker : public NetValueTypePacker diff --git a/src/native/QmlNet/QmlNet/qml/NetVariant.cpp b/src/native/QmlNet/QmlNet/qml/NetVariant.cpp index c5c0e9b3..f4b3d4b8 100644 --- a/src/native/QmlNet/QmlNet/qml/NetVariant.cpp +++ b/src/native/QmlNet/QmlNet/qml/NetVariant.cpp @@ -253,6 +253,72 @@ QJSValue NetVariant::toQJSValue(QJSEngine* jsEngine) } } +void NetVariant::fromQVariant(const QVariant* variant, QSharedPointer destination) +{ + switch(variant->type()) { + case QVariant::Invalid: + destination->clear(); + break; + case QVariant::Bool: + destination->setBool(variant->value()); + break; + case QVariant::Char: + destination->setChar(variant->toChar()); + break; + case QVariant::Int: + destination->setInt(variant->value()); + break; + case QVariant::UInt: + destination->setUInt(variant->value()); + break; + case QVariant::Double: + destination->setDouble(variant->value()); + break; + case QVariant::String: + { + QString stringValue = variant->toString(); + destination->setString(&stringValue); + break; + } + case QVariant::DateTime: + { + QDateTime dateTimeValue = variant->toDateTime(); + destination->setDateTime(dateTimeValue); + break; + } + default: + + if(variant->userType() == qMetaTypeId()) { + // TODO: Either serialize this type to a string, to be deserialized in .NET, or + // pass raw value to .NET to be dynamically invoked (using dynamic). + // See qtdeclarative\src\plugins\qmltooling\qmldbg_debugger\qqmlenginedebugservice.cpp:184 + // for serialization methods. + QSharedPointer netJsValue = QSharedPointer(new NetJSValue(variant->value())); + destination->setJsValue(netJsValue); + break; + } + + if(variant->userType() == QMetaType::QObjectStar) { + QObject* value = variant->value(); + NetValueInterface* netValue = qobject_cast(value); + if(netValue) { + destination->setNetReference(netValue->getNetReference()); + break; + } + } + + qDebug() << "Unsupported variant type: " << variant->type(); + break; + } +} + +QSharedPointer NetVariant::fromQVariant(const QVariant* variant) +{ + QSharedPointer result = QSharedPointer(new NetVariant()); + fromQVariant(variant, result); + return result; +} + QVariant NetVariant::toQVariant() { QVariant result; diff --git a/src/native/QmlNet/QmlNet/qml/NetVariant.h b/src/native/QmlNet/QmlNet/qml/NetVariant.h index 5988d4a8..bcbc30bb 100644 --- a/src/native/QmlNet/QmlNet/qml/NetVariant.h +++ b/src/native/QmlNet/QmlNet/qml/NetVariant.h @@ -34,6 +34,8 @@ public: void clear(); static QSharedPointer fromQJSValue(const QJSValue& qJsValue); QJSValue toQJSValue(QJSEngine* jsEngine); + static void fromQVariant(const QVariant* variant, QSharedPointer destination); + static QSharedPointer fromQVariant(const QVariant* variant); QVariant toQVariant(); QString getDisplayValue(); private: diff --git a/src/native/QmlNet/QmlNet/qml/QQmlApplicationEngine.cpp b/src/native/QmlNet/QmlNet/qml/QQmlApplicationEngine.cpp index f449ce9a..85852d4c 100644 --- a/src/native/QmlNet/QmlNet/qml/QQmlApplicationEngine.cpp +++ b/src/native/QmlNet/QmlNet/qml/QQmlApplicationEngine.cpp @@ -198,4 +198,22 @@ Q_DECL_EXPORT QQmlApplicationEngine* qqmlapplicationengine_internalPointer(QQmlA return container->qmlEngine; } +Q_DECL_EXPORT NetVariantContainer* qqmlapplicationengine_getContextProperty(QQmlApplicationEngineContainer* container, LPWCSTR name) +{ + QVariant result = container->qmlEngine->rootContext()->contextProperty(QString::fromUtf16(name)); + return new NetVariantContainer { + NetVariant::fromQVariant(&result) + }; +} + +Q_DECL_EXPORT void qqmlapplicationengine_setContextProperty(QQmlApplicationEngineContainer* container, LPWCSTR name, NetVariantContainer* valueContainer) +{ + if(valueContainer == nullptr) { + container->qmlEngine->rootContext()->setContextProperty(QString::fromUtf16(name), nullptr); + } else { + QSharedPointer value = valueContainer->variant; + container->qmlEngine->rootContext()->setContextProperty(QString::fromUtf16(name), value->toQVariant()); + } +} + } diff --git a/src/net/Qml.Net.Tests/Qml/QQmlApplicationEngineTests.cs b/src/net/Qml.Net.Tests/Qml/QQmlApplicationEngineTests.cs new file mode 100644 index 00000000..4748d384 --- /dev/null +++ b/src/net/Qml.Net.Tests/Qml/QQmlApplicationEngineTests.cs @@ -0,0 +1,29 @@ +using System; +using FluentAssertions; +using Xunit; + +namespace Qml.Net.Tests.Qml +{ + public class QQmlApplicationEngineTests : BaseQmlTests + { + public class QQmlApplicationEngineQml + { + public Guid Guid { get; set; } + } + + [Fact] + public void Can_set_context_property() + { + var propName = Guid.NewGuid().ToString().Replace("-", ""); + qmlApplicationEngine.GetContextProperty(propName).Should().BeNull(); + qmlApplicationEngine.SetContextProperty(propName, 2); + qmlApplicationEngine.GetContextProperty(propName).Should().Be(2); + qmlApplicationEngine.SetContextProperty(propName, null); + qmlApplicationEngine.GetContextProperty(propName).Should().BeNull(); + var o = new QQmlApplicationEngineQml(); + o.Guid = Guid.NewGuid(); + qmlApplicationEngine.SetContextProperty(propName, o); + ((QQmlApplicationEngineQml) qmlApplicationEngine.GetContextProperty(propName)).Guid.Should().Be(o.Guid); + } + } +} \ No newline at end of file diff --git a/src/net/Qml.Net/QQmlApplicationEngine.cs b/src/net/Qml.Net/QQmlApplicationEngine.cs index c447df5f..288b921e 100644 --- a/src/net/Qml.Net/QQmlApplicationEngine.cs +++ b/src/net/Qml.Net/QQmlApplicationEngine.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using AdvancedDLSupport; using Qml.Net.Internal; using Qml.Net.Internal.Behaviors; +using Qml.Net.Internal.Qml; using Qml.Net.Internal.Types; namespace Qml.Net @@ -35,6 +36,38 @@ namespace Qml.Net { Interop.QQmlApplicationEngine.AddImportPath(Handle, path); } + + public object GetContextProperty(string name) + { + var result = Interop.QQmlApplicationEngine.GetContextProperty(Handle, name); + if (result == IntPtr.Zero) + { + return null; + } + + using (var variant = new NetVariant(result)) + { + object r = null; + Helpers.Unpackvalue(ref r, variant); + return r; + } + } + + public void SetContextProperty(string name, object value) + { + if (value == null) + { + Interop.QQmlApplicationEngine.SetContextProperty(Handle, name, IntPtr.Zero); + } + else + { + using (var variant = new NetVariant()) + { + Helpers.PackValue(value, variant); + Interop.QQmlApplicationEngine.SetContextProperty(Handle, name, variant.Handle); + } + } + } internal IntPtr InternalPointer => Interop.QQmlApplicationEngine.InternalPointer(Handle); @@ -90,5 +123,11 @@ namespace Qml.Net [NativeSymbol(Entrypoint = "qqmlapplicationengine_internalPointer")] IntPtr InternalPointer(IntPtr app); + + [NativeSymbol(Entrypoint = "qqmlapplicationengine_getContextProperty")] + IntPtr GetContextProperty(IntPtr app, [MarshalAs(UnmanagedType.LPWStr), CallerFree]string name); + + [NativeSymbol(Entrypoint = "qqmlapplicationengine_setContextProperty")] + void SetContextProperty(IntPtr app, [MarshalAs(UnmanagedType.LPWStr), CallerFree]string path, IntPtr value); } } \ No newline at end of file