From e73e37b587e51b2dd5816390d278835ac5071a30 Mon Sep 17 00:00:00 2001 From: cuke Date: Sun, 20 Sep 2015 11:39:25 +0200 Subject: [PATCH] Refactored the code for making the DynamicQObject testable and reusable --- src/BaseQAbstractListModel.h | 18 +++--- src/CMakeLists.txt | 10 +++ src/DOtherSide.cpp | 11 ++-- src/DynamicProperty.cpp | 111 +++++++++++++++++++++++++++++++++ src/DynamicProperty.h | 113 +--------------------------------- src/DynamicQObject.h | 60 ++++-------------- src/DynamicSignal.cpp | 89 ++++++++++++++++++++++++++ src/DynamicSignal.h | 91 +-------------------------- src/DynamicSlot.cpp | 96 +++++++++++++++++++++++++++++ src/DynamicSlot.h | 99 +---------------------------- src/IDynamicQObject.h | 6 -- src/OnSlotExecutedHandler.cpp | 31 ++++++++++ src/OnSlotExecutedHandler.h | 19 ++++++ test/CMakeLists.txt | 2 +- test/test_dynamicqobject.cpp | 47 ++++++++++++-- 15 files changed, 427 insertions(+), 376 deletions(-) create mode 100644 src/DynamicProperty.cpp create mode 100644 src/DynamicSignal.cpp create mode 100644 src/DynamicSlot.cpp create mode 100644 src/OnSlotExecutedHandler.cpp create mode 100644 src/OnSlotExecutedHandler.h diff --git a/src/BaseQAbstractListModel.h b/src/BaseQAbstractListModel.h index 73c76eb..b9b238d 100644 --- a/src/BaseQAbstractListModel.h +++ b/src/BaseQAbstractListModel.h @@ -77,13 +77,13 @@ private: }; BaseQAbstractListModel::BaseQAbstractListModel(void* modelObject, - RowCountCallback rowCountCallback, - ColumnCountCallback columnCountCallback, - DataCallback dataCallback, - SetDataCallback setDataCallback, - RoleNamesCallback roleNamesCallback, - FlagsCallback flagsCallback, - HeaderDataCallback headerDataCallback) + RowCountCallback rowCountCallback, + ColumnCountCallback columnCountCallback, + DataCallback dataCallback, + SetDataCallback setDataCallback, + RoleNamesCallback roleNamesCallback, + FlagsCallback flagsCallback, + HeaderDataCallback headerDataCallback) : m_modelObject(modelObject) , m_rowCountCallback(rowCountCallback) , m_columnCountCallback(columnCountCallback) @@ -192,8 +192,8 @@ void BaseQAbstractListModel::publicEndResetModel() } void BaseQAbstractListModel::publicDataChanged(const QModelIndex& topLeft, - const QModelIndex& bottomRight, - const QVector& roles) + const QModelIndex& bottomRight, + const QVector& roles) { emit dataChanged(topLeft, bottomRight, roles); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 68cd220..674fb7f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,11 +27,21 @@ set(HEADERS_LIST DOtherSide.h DynamicQObject.h IDynamicQObject.h + OnSlotExecutedHandler.h ) set(SRC_LIST DOtherSide.cpp + OnSlotExecutedHandler.cpp + DynamicSlot.cpp + DynamicSignal.cpp + DynamicProperty.cpp ) +# Shared version for distributing add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${HEADERS_LIST}) target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick) + +# Static version for testing +add_library("${PROJECT_NAME}Static" STATIC ${SRC_LIST} ${HEADERS_LIST}) +target_link_libraries("${PROJECT_NAME}Static" PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick) diff --git a/src/DOtherSide.cpp b/src/DOtherSide.cpp index 459bf32..224cd30 100644 --- a/src/DOtherSide.cpp +++ b/src/DOtherSide.cpp @@ -15,6 +15,7 @@ #include "DynamicQObject.h" #include "BaseQAbstractListModel.h" #include "BaseQObject.h" +#include "OnSlotExecutedHandler.h" void convert_to_cstring(const QString& source, char** destination) { @@ -298,8 +299,7 @@ void dos_qobject_create(void** vptr, void* dObjectPointer, DObjectCallback dObje { auto dynamicQObject = new BaseQObject(); QQmlEngine::setObjectOwnership(dynamicQObject, QQmlEngine::CppOwnership); - dynamicQObject->setDObjectPointer(dObjectPointer); - dynamicQObject->setDObjectCallback(dObjectCallback); + dynamicQObject->setOnSlotExecutedHandler(OnSlotExecutedHandler(dObjectPointer, dObjectCallback)); *vptr = dynamicQObject; } @@ -428,7 +428,7 @@ void dos_qmodelindex_sibling(void* vptr, int row, int column, void* sibling) } void dos_qabstractlistmodel_create(void** vptr, - void* modelObject, + void* dObjectPointer, DObjectCallback dObjectCallback, RowCountCallback rowCountCallback, ColumnCountCallback columnCountCallback, @@ -438,7 +438,7 @@ void dos_qabstractlistmodel_create(void** vptr, FlagsCallback flagsCallback, HeaderDataCallback headerDataCallback) { - auto model = new BaseQAbstractListModel(modelObject, + auto model = new BaseQAbstractListModel(dObjectPointer, rowCountCallback, columnCountCallback, dataCallback, @@ -446,8 +446,7 @@ void dos_qabstractlistmodel_create(void** vptr, roleNamesCallaback, flagsCallback, headerDataCallback); - model->setDObjectPointer(modelObject); - model->setDObjectCallback(dObjectCallback); + model->setOnSlotExecutedHandler(OnSlotExecutedHandler(dObjectPointer, dObjectCallback)); *vptr = model; } diff --git a/src/DynamicProperty.cpp b/src/DynamicProperty.cpp new file mode 100644 index 0000000..c6d80da --- /dev/null +++ b/src/DynamicProperty.cpp @@ -0,0 +1,111 @@ +#include "DynamicProperty.h" + +struct DynamicProperty::PropertyData final +{ + PropertyData(const QString& name, + QMetaType::Type type, + const QString& readSlotName, + const QString& writeSlotName, + const QString& notifySignalName) + : name(name) + , type(type) + , readSlotName(readSlotName) + , writeSlotName(writeSlotName) + , notifySignalName(notifySignalName) + {} + + PropertyData(const PropertyData& other) + : name(other.name) + , type(other.type) + , readSlotName(other.readSlotName) + , writeSlotName(other.writeSlotName) + , notifySignalName(other.notifySignalName) + {} + + PropertyData& operator=(const PropertyData& other) + { + name = other.name; + type = other.type; + readSlotName = other.readSlotName; + writeSlotName = other.writeSlotName; + notifySignalName = other.notifySignalName; + return *this; + } + + QString name; + QMetaType::Type type; + QString readSlotName; + QString writeSlotName; + QString notifySignalName; +}; + +DynamicProperty::DynamicProperty() + : d(nullptr) +{} + +DynamicProperty::DynamicProperty(const QString& name, QMetaType::Type type, const QString& readSlotName, const QString& writeSlotName, const QString& notifySignalName) + : d(new PropertyData(name, type, readSlotName, writeSlotName, notifySignalName)) +{ +} + +DynamicProperty::DynamicProperty(const DynamicProperty& other) + : d(nullptr) +{ + if (other.d) + d.reset(new PropertyData(*other.d)); +} + +DynamicProperty& DynamicProperty::operator=(const DynamicProperty& other) +{ + if (!other.d && d) + d.reset(); + else if (other.d && !d) + d.reset(new PropertyData(*other.d)); + else if (other.d && d) + *d = *other.d; + + return *this; +} + +DynamicProperty::~DynamicProperty() +{} + +QString DynamicProperty::name() const +{ + return d->name; +} + +QMetaType::Type DynamicProperty::type() const +{ + return d->type; +} + +bool DynamicProperty::isReadable() const +{ + return !d->readSlotName.isEmpty(); +} + +bool DynamicProperty::isWriteable() const +{ + return !d->writeSlotName.isEmpty(); +} + +bool DynamicProperty::hasNotifySignal() const +{ + return !d->notifySignalName.isEmpty(); +} + +QString DynamicProperty::readSlot() const +{ + return d->readSlotName; +} + +QString DynamicProperty::writeSlot() const +{ + return d->writeSlotName; +} + +QString DynamicProperty::notifySignal() const +{ + return d->notifySignalName; +} diff --git a/src/DynamicProperty.h b/src/DynamicProperty.h index 1fd03a8..c580c14 100644 --- a/src/DynamicProperty.h +++ b/src/DynamicProperty.h @@ -4,8 +4,6 @@ #include #include -struct PropertyData; - class DynamicProperty final { public: @@ -35,115 +33,6 @@ public: QString notifySignal() const; private: + struct PropertyData; std::unique_ptr d; }; - -struct PropertyData final -{ - PropertyData(const QString& name, - QMetaType::Type type, - const QString& readSlotName, - const QString& writeSlotName, - const QString& notifySignalName) - : name(name) - , type(type) - , readSlotName(readSlotName) - , writeSlotName(writeSlotName) - , notifySignalName(notifySignalName) - {} - - PropertyData(const PropertyData& other) - : name(other.name) - , type(other.type) - , readSlotName(other.readSlotName) - , writeSlotName(other.writeSlotName) - , notifySignalName(other.notifySignalName) - {} - - PropertyData& operator=(const PropertyData& other) - { - name = other.name; - type = other.type; - readSlotName = other.readSlotName; - writeSlotName = other.writeSlotName; - notifySignalName = other.notifySignalName; - return *this; - } - - QString name; - QMetaType::Type type; - QString readSlotName; - QString writeSlotName; - QString notifySignalName; -}; - -DynamicProperty::DynamicProperty() - : d(nullptr) -{} - -DynamicProperty::DynamicProperty(const QString& name, QMetaType::Type type, const QString& readSlotName, const QString& writeSlotName, const QString& notifySignalName) - : d(new PropertyData(name, type, readSlotName, writeSlotName, notifySignalName)) -{ -} - -DynamicProperty::DynamicProperty(const DynamicProperty& other) - : d(nullptr) -{ - if (other.d) - d.reset(new PropertyData(*other.d)); -} - -DynamicProperty& DynamicProperty::operator=(const DynamicProperty& other) -{ - if (!other.d && d) - d.reset(); - else if (other.d && !d) - d.reset(new PropertyData(*other.d)); - else if (other.d && d) - *d = *other.d; - - return *this; -} - -DynamicProperty::~DynamicProperty() -{} - -QString DynamicProperty::name() const -{ - return d->name; -} - -QMetaType::Type DynamicProperty::type() const -{ - return d->type; -} - -bool DynamicProperty::isReadable() const -{ - return !d->readSlotName.isEmpty(); -} - -bool DynamicProperty::isWriteable() const -{ - return !d->writeSlotName.isEmpty(); -} - -bool DynamicProperty::hasNotifySignal() const -{ - return !d->notifySignalName.isEmpty(); -} - -QString DynamicProperty::readSlot() const -{ - return d->readSlotName; -} - -QString DynamicProperty::writeSlot() const -{ - return d->writeSlotName; -} - -QString DynamicProperty::notifySignal() const -{ - return d->notifySignalName; -} diff --git a/src/DynamicQObject.h b/src/DynamicQObject.h index 7a22bb5..63be15e 100644 --- a/src/DynamicQObject.h +++ b/src/DynamicQObject.h @@ -17,6 +17,7 @@ template class DynamicQObject : public T, public IDynamicQObject { using SafeQMetaObjectPtr = std::unique_ptr; + using OnSlotExecutedHandler = std::function&)>; public: /// Constructor @@ -25,11 +26,8 @@ public: /// Destructor virtual ~DynamicQObject(); - /// Sets the function to be called from C++ to D or Nimrod - void setDObjectCallback(IDynamicQObject::Callback callback) override; - - /// Sets the D or Nimrod object that owns this DynamicQObject - void setDObjectPointer(void* dObjectPointer) override; + /// Sets the on slot executed handler + void setOnSlotExecutedHandler(const OnSlotExecutedHandler& handler); /// Register a new signal bool registerSignal(const QString& name, @@ -61,8 +59,6 @@ public: private: bool executeSlot(const DynamicSlot& slot, void** args); - QVariant executeSlot(const DynamicSlot& slot, const std::vector &args); - bool readProperty(const DynamicProperty& property, void** args); bool writeProperty(const DynamicProperty& property, void** args); @@ -81,16 +77,13 @@ private: QHash m_slotsByName; QHash m_slotsBySignature; QHash m_propertiesByName; - void* m_dObjectPointer; - IDynamicQObject::Callback m_dObjectCallback; + OnSlotExecutedHandler m_onSlotExecutedHandler; }; template DynamicQObject::DynamicQObject() : T() , m_metaObject(nullptr, ::free) - , m_dObjectPointer(nullptr) - , m_dObjectCallback(nullptr) { QMetaObjectBuilder builder; builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); @@ -100,15 +93,9 @@ DynamicQObject::DynamicQObject() } template -void DynamicQObject::setDObjectCallback(IDynamicQObject::Callback callback) +void DynamicQObject::setOnSlotExecutedHandler(const DynamicQObject::OnSlotExecutedHandler &handler) { - m_dObjectCallback = callback; -} - -template -void DynamicQObject::setDObjectPointer(void* dObjectPointer) -{ - m_dObjectPointer = dObjectPointer; + m_onSlotExecutedHandler = handler; } template @@ -284,15 +271,12 @@ bool DynamicQObject::executeSlot(const DynamicSlot& slot, void** args) if (!slot.isValid()) return false; - if (!m_dObjectCallback || !m_dObjectPointer) - return false; - std::vector arguments; arguments.reserve(slot.argumentsTypes().size()); for (int i = 0; i < slot.argumentsTypes().count(); ++i) arguments.emplace_back(QVariant(slot.argumentTypeAt(i), args[i + 1])); - QVariant result = executeSlot(slot, arguments); + QVariant result = m_onSlotExecutedHandler(slot, arguments); if (slot.returnType() != QMetaType::Void && result.isValid()) { @@ -303,30 +287,6 @@ bool DynamicQObject::executeSlot(const DynamicSlot& slot, void** args) return true; } -template -QVariant DynamicQObject::executeSlot(const DynamicSlot& slot, const std::vector& args) -{ - QVariant result; - - if (!m_dObjectCallback || !m_dObjectPointer) - return result; - - // prepare slot name - QVariant slotName(slot.name()); - - // prepare void* for the QVariants - std::vector argumentsAsVoidPointers; - argumentsAsVoidPointers.reserve(args.size() + 1); - argumentsAsVoidPointers.emplace_back(&result); - for (size_t i = 0; i < args.size(); ++i) - argumentsAsVoidPointers.emplace_back((void*)(&args[i])); - - // send them to the binding handler - m_dObjectCallback(m_dObjectPointer, &slotName, argumentsAsVoidPointers.size(), &argumentsAsVoidPointers[0]); - - return result; -} - template bool DynamicQObject::readProperty(const DynamicProperty& property, void** args) { @@ -370,8 +330,10 @@ bool DynamicQObject::writeProperty(const DynamicProperty& property, void** ar if (writeSlot.returnType() != QMetaType::Void) return false; - QVariant newValue(writeSlot.argumentTypeAt(0), args[0]); - executeSlot(writeSlot, {newValue}); + void* sortedArgs[2]; // The write property is peculiar because it has + sortedArgs[0] = args[2]; // the actual value in pos 0 and result in 2 + sortedArgs[1] = args[0]; // We reorder it for having the result in 0 and + executeSlot(writeSlot, sortedArgs); // first arg in 1 return true; } diff --git a/src/DynamicSignal.cpp b/src/DynamicSignal.cpp new file mode 100644 index 0000000..81b3e42 --- /dev/null +++ b/src/DynamicSignal.cpp @@ -0,0 +1,89 @@ +#include "DynamicSignal.h" + +struct DynamicSignal::SignalData +{ + QString name; + QList argumentsTypes; + QByteArray signature; +}; + +DynamicSignal::DynamicSignal() + : d(nullptr) +{ +} + +DynamicSignal::DynamicSignal(const QString& name, const QList& arguments) + : d(new SignalData()) +{ + d->name = name; + d->signature = QByteArray(); + d->argumentsTypes = arguments; + _initSignature(); +} + +DynamicSignal::DynamicSignal(const DynamicSignal& signal) +{ + if (signal.isValid()) + { + d.reset(new SignalData()); + *d = *signal.d; + } + else + d.reset(nullptr); +} + +DynamicSignal& DynamicSignal::operator=(const DynamicSignal& signal) +{ + if (signal.isValid()) + { + d.reset(new SignalData()); + *d = *signal.d; + } + else + d.reset(nullptr); + + return *this; +} + +DynamicSignal::~DynamicSignal() +{ +} + +bool DynamicSignal::isValid() const +{ + return d != nullptr; +} + +QString DynamicSignal::name() const +{ + return isValid() ? d->name : QString(); +} + +QByteArray DynamicSignal::signature() const +{ + return isValid() ? d->signature : QByteArray(); +} + +bool DynamicSignal::validate(const QVariantList& arguments) +{ + // TODO: here we should test if the given arguments + // match this signal signature + // This is important because a class could have multiple + // signals with the same name but different arguments + Q_UNUSED(arguments); + return true; +} + +void DynamicSignal::_initSignature() +{ + QString signature("%1(%2)"); + QString arguments; + for (int i = 0; i < d->argumentsTypes.size(); ++i) + { + if (i != 0) + arguments += ','; + arguments += QMetaType::typeName(d->argumentsTypes[i]); + } + + d->signature = signature.arg(d->name, arguments).toUtf8(); +} diff --git a/src/DynamicSignal.h b/src/DynamicSignal.h index a608abb..d2c2dff 100644 --- a/src/DynamicSignal.h +++ b/src/DynamicSignal.h @@ -7,8 +7,6 @@ #include #include -struct SignalData; - class DynamicSignal final { public: @@ -28,93 +26,6 @@ public: private: void _initSignature(); + struct SignalData; std::unique_ptr d; }; - -struct SignalData -{ - QString name; - QList argumentsTypes; - QByteArray signature; -}; - -DynamicSignal::DynamicSignal() - : d(nullptr) -{ -} - -DynamicSignal::DynamicSignal(const QString& name, const QList& arguments) - : d(new SignalData()) -{ - d->name = name; - d->signature = QByteArray(); - d->argumentsTypes = arguments; - _initSignature(); -} - -DynamicSignal::DynamicSignal(const DynamicSignal& signal) -{ - if (signal.isValid()) - { - d.reset(new SignalData()); - *d = *signal.d; - } - else - d.reset(nullptr); -} - -DynamicSignal& DynamicSignal::operator=(const DynamicSignal& signal) -{ - if (signal.isValid()) - { - d.reset(new SignalData()); - *d = *signal.d; - } - else - d.reset(nullptr); - - return *this; -} - -DynamicSignal::~DynamicSignal() -{ -} - -bool DynamicSignal::isValid() const -{ - return d != nullptr; -} - -QString DynamicSignal::name() const -{ - return isValid() ? d->name : QString(); -} - -QByteArray DynamicSignal::signature() const -{ - return isValid() ? d->signature : QByteArray(); -} - -bool DynamicSignal::validate(const QVariantList& arguments) -{ - // TODO: here we should test if the given arguments - // match this signal signature - // This is important because a class could have multiple - // signals with the same name but different arguments - Q_UNUSED(arguments); - return true; -} - -void DynamicSignal::_initSignature() -{ - QString signature("%1(%2)"); - QString arguments; - for (int i = 0; i < d->argumentsTypes.size(); ++i) - { - if (i != 0) - arguments += ','; - arguments += QMetaType::typeName(d->argumentsTypes[i]); - } - - d->signature = signature.arg(d->name, arguments).toUtf8(); -} diff --git a/src/DynamicSlot.cpp b/src/DynamicSlot.cpp new file mode 100644 index 0000000..9b25818 --- /dev/null +++ b/src/DynamicSlot.cpp @@ -0,0 +1,96 @@ +#include "DynamicSlot.h" + +struct DynamicSlot::SlotData +{ + QString name; + QMetaType::Type returnType; + QList argumentsTypes; + QByteArray signature; +}; + +DynamicSlot::DynamicSlot() + : d(nullptr) +{} + +DynamicSlot::DynamicSlot(const QString& name, + QMetaType::Type returnType, + const QList& argumentsTypes) + : d(new SlotData()) +{ + d->name = name; + d->returnType = returnType; + d->argumentsTypes = argumentsTypes; + _initSignature(); +} + +DynamicSlot::DynamicSlot(const DynamicSlot& slot) +{ + if (slot.isValid()) + { + d.reset(new SlotData()); + *d = *slot.d; + } + else + d.reset(nullptr); +} + +DynamicSlot& DynamicSlot::operator=(const DynamicSlot& slot) +{ + if (slot.isValid()) + { + d.reset(new SlotData()); + *d = *slot.d; + } + else + d.reset(nullptr); + + return *this; +} + +DynamicSlot::~DynamicSlot() +{ +} + +QString DynamicSlot::name() const +{ + return isValid() ? d->name : QString(); +} + +bool DynamicSlot::isValid() const +{ + return d != nullptr; +} + +QByteArray DynamicSlot::signature() const +{ + return isValid() ? d->signature : QByteArray(); +} + +QMetaType::Type DynamicSlot::returnType() const +{ + return isValid() ? d->returnType : QMetaType::UnknownType; +} + +QList DynamicSlot::argumentsTypes() const +{ + return isValid() ? d->argumentsTypes : QList(); +} + +QMetaType::Type DynamicSlot::argumentTypeAt(int i) const +{ + return isValid() ? d->argumentsTypes.at(i) : QMetaType::UnknownType; +} + +void DynamicSlot::_initSignature() +{ + QString signature("%1(%2)"); + QString arguments = ""; + for (int i = 0; i < d->argumentsTypes.size(); ++i) + { + if (i != 0) + arguments += ','; + arguments += QMetaType::typeName(d->argumentsTypes[i]); + } + + d->signature = signature.arg(d->name, arguments).toUtf8(); +} diff --git a/src/DynamicSlot.h b/src/DynamicSlot.h index 24b6abc..b1b8ee6 100644 --- a/src/DynamicSlot.h +++ b/src/DynamicSlot.h @@ -13,7 +13,6 @@ #include "private/qmetaobjectbuilder_p.h" -struct SlotData; class QString; class DynamicSlot final @@ -37,102 +36,6 @@ public: private: void _initSignature(); + struct SlotData; std::unique_ptr d; }; - -struct SlotData -{ - QString name; - QMetaType::Type returnType; - QList argumentsTypes; - QByteArray signature; -}; - -DynamicSlot::DynamicSlot() - : d(nullptr) -{ - -} - -DynamicSlot::DynamicSlot(const QString& name, - QMetaType::Type returnType, - const QList& argumentsTypes) - : d(new SlotData()) -{ - d->name = name; - d->returnType = returnType; - d->argumentsTypes = argumentsTypes; - _initSignature(); -} - -DynamicSlot::DynamicSlot(const DynamicSlot& slot) -{ - if (slot.isValid()) - { - d.reset(new SlotData()); - *d = *slot.d; - } - else - d.reset(nullptr); -} - -DynamicSlot& DynamicSlot::operator=(const DynamicSlot& slot) -{ - if (slot.isValid()) - { - d.reset(new SlotData()); - *d = *slot.d; - } - else - d.reset(nullptr); - - return *this; -} - -DynamicSlot::~DynamicSlot() -{ -} - -QString DynamicSlot::name() const -{ - return isValid() ? d->name : QString(); -} - -bool DynamicSlot::isValid() const -{ - return d != nullptr; -} - -QByteArray DynamicSlot::signature() const -{ - return isValid() ? d->signature : QByteArray(); -} - -QMetaType::Type DynamicSlot::returnType() const -{ - return isValid() ? d->returnType : QMetaType::UnknownType; -} - -QList DynamicSlot::argumentsTypes() const -{ - return isValid() ? d->argumentsTypes : QList(); -} - -QMetaType::Type DynamicSlot::argumentTypeAt(int i) const -{ - return isValid() ? d->argumentsTypes.at(i) : QMetaType::UnknownType; -} - -void DynamicSlot::_initSignature() -{ - QString signature("%1(%2)"); - QString arguments = ""; - for (int i = 0; i < d->argumentsTypes.size(); ++i) - { - if (i != 0) - arguments += ','; - arguments += QMetaType::typeName(d->argumentsTypes[i]); - } - - d->signature = signature.arg(d->name, arguments).toUtf8(); -} diff --git a/src/IDynamicQObject.h b/src/IDynamicQObject.h index 81f9e33..1568fb5 100644 --- a/src/IDynamicQObject.h +++ b/src/IDynamicQObject.h @@ -8,12 +8,6 @@ public: /// Destructor virtual ~IDynamicQObject() = default; - /// Sets the function to be called from C++ to D or Nimrod - virtual void setDObjectCallback(Callback callback) = 0; - - /// Sets the D or Nimrod object that owns this DynamicQObject - virtual void setDObjectPointer(void* dObjectPointer) = 0; - /// Register a new signal virtual bool registerSignal(const QString& name, const QList& argumentsTypes, diff --git a/src/OnSlotExecutedHandler.cpp b/src/OnSlotExecutedHandler.cpp new file mode 100644 index 0000000..738ad57 --- /dev/null +++ b/src/OnSlotExecutedHandler.cpp @@ -0,0 +1,31 @@ +#include "OnSlotExecutedHandler.h" +#include "DynamicSlot.h" + +OnSlotExecutedHandler::OnSlotExecutedHandler(void *dObjectPointer, + IDynamicQObject::Callback dObjectCallback) + : m_dObjectPointer(dObjectPointer) + , m_dObjectCallback(dObjectCallback) +{} + +QVariant OnSlotExecutedHandler::operator()(const DynamicSlot& slot, const std::vector &args) +{ + QVariant result; + + if (!m_dObjectCallback || !m_dObjectPointer) + return result; + + // prepare slot name + QVariant slotName(slot.name()); + + // prepare void* for the QVariants + std::vector argumentsAsVoidPointers; + argumentsAsVoidPointers.reserve(args.size() + 1); + argumentsAsVoidPointers.emplace_back(&result); + for (size_t i = 0; i < args.size(); ++i) + argumentsAsVoidPointers.emplace_back((void*)(&args[i])); + + // send them to the binding handler + m_dObjectCallback(m_dObjectPointer, &slotName, argumentsAsVoidPointers.size(), &argumentsAsVoidPointers[0]); + + return result; +} diff --git a/src/OnSlotExecutedHandler.h b/src/OnSlotExecutedHandler.h new file mode 100644 index 0000000..0aa0d56 --- /dev/null +++ b/src/OnSlotExecutedHandler.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include "IDynamicQObject.h" + +class DynamicSlot; + +class OnSlotExecutedHandler +{ +public: + OnSlotExecutedHandler(void* dObjectPointer, IDynamicQObject::Callback dObjectCallback); + + QVariant operator()(const DynamicSlot& slot, std::vector const& args); + +private: + void* m_dObjectPointer; + IDynamicQObject::Callback m_dObjectCallback; +}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 51756ef..bb4c616 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,4 +11,4 @@ find_package(Qt5Test REQUIRED) add_executable(${PROJECT_NAME} test_dynamicqobject.cpp) -target_link_libraries(${PROJECT_NAME} Qt5::Test) +target_link_libraries(${PROJECT_NAME} DOtherSideStatic Qt5::Test) diff --git a/test/test_dynamicqobject.cpp b/test/test_dynamicqobject.cpp index 231d146..350c6f6 100644 --- a/test/test_dynamicqobject.cpp +++ b/test/test_dynamicqobject.cpp @@ -1,7 +1,22 @@ #include #include +#include +#include +#include +#include "../src/BaseQObject.h" #include "../src/DynamicQObject.h" +// Templates that convers a T to a string +template +struct TypeName +{ + static const char* Get() { return typeid(T).name(); } +}; +template <> struct TypeName { static const char* Get() { return "int"; } }; +template <> struct TypeName { static const char* Get() { return "QString"; } }; +template <> struct TypeName { static const char* Get() { return "bool"; } }; +template <> struct TypeName { static const char* Get() { return "QVariant"; } }; + class TestDynamicQObject : public QObject { Q_OBJECT @@ -9,6 +24,7 @@ class TestDynamicQObject : public QObject private slots: void memoryLeakTest() { DynamicQObject dynamicQObject; + BaseQObject baseQObject; } void testRegisterSignal() { @@ -22,11 +38,11 @@ private slots: QCOMPARE(signalSpy.count(), 1); } - void testRegisterSlot() { - DynamicQObject dynamicQObject; - int index; - dynamicQObject.registerSlot("fooSlot", QMetaType::Void, {}, index); - QCOMPARE(index != -1, true); + void testSlotExecution() { + testSlotExecutionForType(10); + testSlotExecutionForType("foo"); + testSlotExecutionForType(false); + testSlotExecutionForType(QVariant(40)); } void testRegisterProperty() { @@ -45,6 +61,27 @@ private slots: result = dynamicQObject.registerProperty("foo", QMetaType::Int, "foo", "setFoo", "fooChanged"); QCOMPARE(result, true); } + +private: + template + void testSlotExecutionForType(ReturnType expectedReturnValue) { + DynamicQObject dynamicQObject; + int index; + dynamicQObject.registerSlot("fooSlot", (QMetaType::Type)qMetaTypeId(), {}, index); + QCOMPARE(index != -1, true); + + // Call the slot and check return value + bool called = false; + auto handler = [&called, expectedReturnValue](const DynamicSlot &slot, const std::vector &args) -> QVariant { + called = true; + return expectedReturnValue; + }; + dynamicQObject.setOnSlotExecutedHandler(handler); + ReturnType result; + QMetaObject::invokeMethod(&dynamicQObject, "fooSlot", QReturnArgument(TypeName::Get(), result)); + QCOMPARE(called, true); + QCOMPARE(result, expectedReturnValue); + } }; QTEST_MAIN(TestDynamicQObject)