From 819409fa941cf7ee0484b25fcfb84db381fc95b3 Mon Sep 17 00:00:00 2001 From: Filippo Cucchetto Date: Mon, 4 Jul 2016 18:20:02 +0200 Subject: [PATCH] Closed #39 Add support for QVariantList This adds support for marshalling arrays of QVariant (QVariantList) in/out from DosQVariant. We added the following 3 API: dos_qvariant_create_array dos_qvariant_setArray dos_qvariant_toArray Support for QVariantList in property definition of QObjects is already enabled. The end user should use the QVariantList metatype. --- lib/include/DOtherSide/DOtherSide.h | 6 ++ lib/include/DOtherSide/DOtherSideTypes.h | 5 ++ lib/src/DOtherSide.cpp | 46 ++++++++++++ test/MockQObject.cpp | 94 ++++++++++++++++++++++-- test/MockQObject.h | 6 ++ test/testQObject.qml | 10 +++ test/test_dotherside.cpp | 29 ++++++++ 7 files changed, 190 insertions(+), 6 deletions(-) diff --git a/lib/include/DOtherSide/DOtherSide.h b/lib/include/DOtherSide/DOtherSide.h index 80bf8a2..011b518 100644 --- a/lib/include/DOtherSide/DOtherSide.h +++ b/lib/include/DOtherSide/DOtherSide.h @@ -64,6 +64,9 @@ DOS_API void DOS_CALL dos_qqmlcontext_setcontextproperty(DosQQmlContext *vptr, /// @param ptr The string DOS_API void DOS_CALL dos_chararray_delete(char *ptr); +/// Delete a DosQVariantArray +DOS_API void DOS_CALL dos_qvariantarray_delete(DosQVariantArray *ptr); + // QVariant DOS_API DosQVariant *DOS_CALL dos_qvariant_create(); DOS_API DosQVariant *DOS_CALL dos_qvariant_create_int(int value); @@ -73,12 +76,14 @@ DOS_API DosQVariant *DOS_CALL dos_qvariant_create_qobject(DosQObject *value); DOS_API DosQVariant *DOS_CALL dos_qvariant_create_qvariant(const DosQVariant *value); DOS_API DosQVariant *DOS_CALL dos_qvariant_create_float(float value); DOS_API DosQVariant *DOS_CALL dos_qvariant_create_double(double value); +DOS_API DosQVariant *DOS_CALL dos_qvariant_create_array(int size, DosQVariant** array); DOS_API void DOS_CALL dos_qvariant_setInt (DosQVariant *vptr, int value); DOS_API void DOS_CALL dos_qvariant_setBool (DosQVariant *vptr, bool value); DOS_API void DOS_CALL dos_qvariant_setFloat (DosQVariant *vptr, float value); DOS_API void DOS_CALL dos_qvariant_setDouble (DosQVariant *vptr, double value); DOS_API void DOS_CALL dos_qvariant_setString (DosQVariant *vptr, const char *value); DOS_API void DOS_CALL dos_qvariant_setQObject(DosQVariant *vptr, DosQObject *value); +DOS_API void DOS_CALL dos_qvariant_setArray (DosQVariant *vptr, int size, DosQVariant** array); DOS_API bool DOS_CALL dos_qvariant_isnull (const DosQVariant *vptr); DOS_API void DOS_CALL dos_qvariant_delete (DosQVariant *vptr); DOS_API void DOS_CALL dos_qvariant_assign (DosQVariant *vptr, const DosQVariant *other); @@ -87,6 +92,7 @@ DOS_API bool DOS_CALL dos_qvariant_toBool (const DosQVariant *vptr); DOS_API char *DOS_CALL dos_qvariant_toString (const DosQVariant *vptr); DOS_API float DOS_CALL dos_qvariant_toFloat (const DosQVariant *vptr); DOS_API double DOS_CALL dos_qvariant_toDouble (const DosQVariant *vptr); +DOS_API DosQVariantArray* DOS_CALL dos_qvariant_toArray(const DosQVariant *vptr); DOS_API DosQObject *DOS_CALL dos_qvariant_toQObject(const DosQVariant *vptr); // QMetaObject diff --git a/lib/include/DOtherSide/DOtherSideTypes.h b/lib/include/DOtherSide/DOtherSideTypes.h index ebb00d2..9fb81d8 100644 --- a/lib/include/DOtherSide/DOtherSideTypes.h +++ b/lib/include/DOtherSide/DOtherSideTypes.h @@ -62,6 +62,11 @@ typedef void (DOS_CALL *HeaderDataCallback) (void *self, int section, int orie typedef void (DOS_CALL *CreateDObject)(int, void *, void **, void **); typedef void (DOS_CALL *DeleteDObject)(int, void *); +struct DosQVariantArray { + int size; + DosQVariant** data; +}; + struct QmlRegisterType { int major; int minor; diff --git a/lib/src/DOtherSide.cpp b/lib/src/DOtherSide.cpp index 3c18c6d..de65b9a 100644 --- a/lib/src/DOtherSide.cpp +++ b/lib/src/DOtherSide.cpp @@ -179,6 +179,21 @@ void dos_chararray_delete(char *ptr) if (ptr) delete[] ptr; } +void dos_qvariantarray_delete(DosQVariantArray *ptr) +{ + if (!ptr || !ptr->data) + return; + // Delete each variant + for (int i = 0; i < ptr->size; ++i) + dos_qvariant_delete(ptr->data[i]); + // Delete the array + delete[] ptr->data; + ptr->data = nullptr; + ptr->size = 0; + // Delete the wrapped struct + delete ptr; +} + char *dos_qqmlcontext_baseUrl(const ::DosQQmlContext *vptr) { auto context = static_cast(vptr); @@ -239,6 +254,15 @@ void dos_qqmlcontext_setcontextproperty(::DosQQmlContext *vptr, const char *name return new QVariant(value); } +::DosQVariant *dos_qvariant_create_array(int size, ::DosQVariant** array) +{ + QList data; + data.reserve(size); + for (int i = 0; i < size; ++i) + data << *(static_cast(array[i])); + return new QVariant(data); +} + bool dos_qvariant_isnull(const DosQVariant *vptr) { auto variant = static_cast(vptr); @@ -288,6 +312,18 @@ char *dos_qvariant_toString(const DosQVariant *vptr) return convert_to_cstring(variant->toString()); } +DosQVariantArray *dos_qvariant_toArray(const DosQVariant *vptr) +{ + auto variant = static_cast(vptr); + QVariantList data = variant->toList(); + auto result = new DosQVariantArray(); + result->size = data.size(); + result->data = new DosQVariant*[result->size]; + for (int i = 0; i < result->size; ++i) + result->data[i] = new QVariant(data[i]); + return result; +} + ::DosQObject *dos_qvariant_toQObject(const DosQVariant *vptr) { auto variant = static_cast(vptr); @@ -331,6 +367,16 @@ void dos_qvariant_setQObject(::DosQVariant *vptr, ::DosQObject *value) variant->setValue(qobject); } +void dos_qvariant_setArray(::DosQVariant *vptr, int size, ::DosQVariant **array) +{ + auto variant = static_cast(vptr); + QVariantList data; + data.reserve(size); + for (int i = 0; i < size; ++i) + data << *(static_cast(array[i])); + variant->setValue(data); +} + ::DosQMetaObject *dos_qobject_qmetaobject() { return new DOS::DosIQMetaObjectHolder(std::make_shared()); diff --git a/test/MockQObject.cpp b/test/MockQObject.cpp index 2898591..3b4b459 100644 --- a/test/MockQObject.cpp +++ b/test/MockQObject.cpp @@ -14,19 +14,28 @@ namespace { { void* superClassMetaObject = dos_qobject_qmetaobject(); // Signals - ::SignalDefinition signalDefinitionArray[1]; + ::SignalDefinition signalDefinitionArray[2]; + + // nameChanged signalDefinitionArray[0].name = "nameChanged"; signalDefinitionArray[0].parametersCount = 1; int nameChanged[1]; nameChanged[0] = QMetaType::QString; signalDefinitionArray[0].parametersMetaTypes = nameChanged; + // arrayPropertyChanged + signalDefinitionArray[1].name = "arrayPropertyChanged"; + signalDefinitionArray[1].parametersCount = 1; + int arrayPropertyChanged[1]; + arrayPropertyChanged[0] = QMetaType::QVariantList; + signalDefinitionArray[1].parametersMetaTypes = arrayPropertyChanged; + ::SignalDefinitions signalDefinitions; - signalDefinitions.count = 1; + signalDefinitions.count = 2; signalDefinitions.definitions = signalDefinitionArray; // Slots - ::SlotDefinition slotDefinitionArray[2]; + ::SlotDefinition slotDefinitionArray[4]; slotDefinitionArray[0].name = "name"; slotDefinitionArray[0].returnMetaType = QMetaType::QString; @@ -40,20 +49,38 @@ namespace { slotDefinitionArray[1].parametersCount = 1; slotDefinitionArray[1].parametersMetaTypes = setNameParameters; + slotDefinitionArray[2].name = "arrayProperty"; + slotDefinitionArray[2].returnMetaType = QMetaType::QVariantList; + slotDefinitionArray[2].parametersCount = 0; + slotDefinitionArray[2].parametersMetaTypes = nullptr; + + slotDefinitionArray[3].name = "setArrayProperty"; + slotDefinitionArray[3].returnMetaType = QMetaType::Void; + int setArrayPropertyParameters[1]; + setArrayPropertyParameters[0] = QMetaType::QVariantList; + slotDefinitionArray[3].parametersCount = 1; + slotDefinitionArray[3].parametersMetaTypes = setArrayPropertyParameters; + ::SlotDefinitions slotDefinitions; - slotDefinitions.count = 2; + slotDefinitions.count = 4; slotDefinitions.definitions = slotDefinitionArray; // Properties - ::PropertyDefinition propertyDefinitionArray[1]; + ::PropertyDefinition propertyDefinitionArray[2]; propertyDefinitionArray[0].name = "name"; propertyDefinitionArray[0].notifySignal = "nameChanged"; propertyDefinitionArray[0].propertyMetaType = QMetaType::QString; propertyDefinitionArray[0].readSlot = "name"; propertyDefinitionArray[0].writeSlot = "setName"; + propertyDefinitionArray[1].name = "arrayProperty"; + propertyDefinitionArray[1].notifySignal = "arrayPropertyChanged"; + propertyDefinitionArray[1].propertyMetaType = QMetaType::QVariantList; + propertyDefinitionArray[1].readSlot = "arrayProperty"; + propertyDefinitionArray[1].writeSlot = "setArrayProperty"; + ::PropertyDefinitions propertyDefinitions; - propertyDefinitions.count = 1; + propertyDefinitions.count = 2; propertyDefinitions.definitions = propertyDefinitionArray; return VoidPointer(dos_qmetaobject_create(superClassMetaObject, "MockQObject", &signalDefinitions, &slotDefinitions, &propertyDefinitions), @@ -64,6 +91,7 @@ namespace { MockQObject::MockQObject() : m_vptr(dos_qobject_create(this, metaObject(), &onSlotCalled), &dos_qobject_delete) + , m_arrayProperty({10, 5.3, false}) {} MockQObject::~MockQObject() = default; @@ -122,6 +150,35 @@ void MockQObject::nameChanged(const string &name) dos_qvariant_delete(argv[0]); } +std::tuple MockQObject::arrayProperty() const +{ + return m_arrayProperty; +} + +void MockQObject::setArrayProperty(std::tuple value) +{ + if (m_arrayProperty == value) + return; + m_arrayProperty = std::move(value); + arrayPropertyChanged(value); +} + +void MockQObject::arrayPropertyChanged(const std::tuple &value) +{ + std::vector valueAsDosQVariant ({ + dos_qvariant_create_int(std::get<0>(value)), + dos_qvariant_create_double(std::get<1>(value)), + dos_qvariant_create_bool(std::get<2>(value)) + }); + + int argc = 1; + DosQVariant* argv[1]; + argv[0] = dos_qvariant_create_array(valueAsDosQVariant.size(), &valueAsDosQVariant[0]); + dos_qobject_signal_emit(m_vptr.get(), "arrayPropertyChanged", argc, argv); + dos_qvariant_delete(argv[0]); + std::for_each(valueAsDosQVariant.begin(), valueAsDosQVariant.end(), &dos_qvariant_delete); +} + void MockQObject::onSlotCalled(void *selfVPtr, DosQVariant *dosSlotNameVariant, int dosSlotArgc, DosQVariant **dosSlotArgv) { MockQObject* self = static_cast(selfVPtr); @@ -136,4 +193,29 @@ void MockQObject::onSlotCalled(void *selfVPtr, DosQVariant *dosSlotNameVariant, self->setName(toStringFromQVariant(dosSlotArgv[1])); return; } + + if (slotName == "arrayProperty") { + auto value = self->arrayProperty(); + + std::vector data { + dos_qvariant_create_int(std::get<0>(value)), + dos_qvariant_create_double(std::get<1>(value)), + dos_qvariant_create_bool(std::get<2>(value)) + }; + VoidPointer arrayProperty(dos_qvariant_create_array(data.size(), &data[0]), &dos_qvariant_delete); + dos_qvariant_assign(dosSlotArgv[0], arrayProperty.get()); + std::for_each(data.begin(), data.end(), &dos_qvariant_delete); + return; + } + + if (slotName == "setArrayProperty") { + std::tuple value; + DosQVariantArray* array = dos_qvariant_toArray(dosSlotArgv[1]); + std::get<0>(value) = dos_qvariant_toInt(array->data[0]); + std::get<1>(value) = dos_qvariant_toDouble(array->data[1]); + std::get<2>(value) = dos_qvariant_toBool(array->data[2]); + dos_qvariantarray_delete(array); + self->setArrayProperty(std::move(value)); + return; + } } diff --git a/test/MockQObject.h b/test/MockQObject.h index de5bd68..4740ede 100644 --- a/test/MockQObject.h +++ b/test/MockQObject.h @@ -1,5 +1,6 @@ #pragma once +#include #include class MockQObject @@ -21,9 +22,14 @@ public: void setName(const std::string& name); void nameChanged(const std::string& name); + std::tuple arrayProperty() const; + void setArrayProperty(std::tuple value); + void arrayPropertyChanged(const std::tuple& value); + private: static void onSlotCalled(void *selfVPtr, DosQVariant *dosSlotNameVariant, int dosSlotArgc, DosQVariant **dosSlotArgv); VoidPointer m_vptr; std::string m_name; + std::tuple m_arrayProperty; }; diff --git a/test/testQObject.qml b/test/testQObject.qml index 46fc33d..52f2a8f 100644 --- a/test/testQObject.qml +++ b/test/testQObject.qml @@ -29,4 +29,14 @@ QtObject { testObject.name = "bar" return result } + + function testArrayProperty() { + if (!testObject) + return false + var values = testObject.arrayProperty + if (values[0] != 10 || values[1] != 5.3 || values[2] != false) + return false + testObject.arrayProperty = [404, 6.3, true] + return values[0] != 404 || values[1] != 6.3 || values[2] != true + } } diff --git a/test/test_dotherside.cpp b/test/test_dotherside.cpp index a6927e6..30cbd45 100644 --- a/test/test_dotherside.cpp +++ b/test/test_dotherside.cpp @@ -184,6 +184,26 @@ private slots: QVERIFY(value == nullptr); } + void testArray() { + std::vector data ({ + dos_qvariant_create_int(10), + dos_qvariant_create_double(4.3), + dos_qvariant_create_bool(false), + dos_qvariant_create_string("FooBar") + }); + + VoidPointer variant (dos_qvariant_create_array(data.size(), &data[0]), &dos_qvariant_delete); + + DosQVariantArray* array = dos_qvariant_toArray(variant.get()); + QVERIFY(array); + QCOMPARE(int(data.size()), array->size); + QCOMPARE(dos_qvariant_toInt(array->data[0]), int(10)); + QCOMPARE(dos_qvariant_toDouble(array->data[1]), double(4.3)); + QCOMPARE(dos_qvariant_toBool(array->data[2]), false); + dos_qvariantarray_delete(array); + + std::for_each(data.begin(), data.end(), &dos_qvariant_delete); + } }; /* @@ -388,6 +408,15 @@ private slots: QVERIFY(result.toBool()); } + void testArrayProperty() { + QObject* testCase = engine->rootObjects().first(); + QVERIFY(testCase); + QVariant result; + QVERIFY(QMetaObject::invokeMethod(testCase, "testArrayProperty", Q_RETURN_ARG(QVariant, result))); + QVERIFY(result.type() == QVariant::Bool); + QVERIFY(result.toBool()); + } + private: QString value; unique_ptr testObject;