Refactored the code for making the DynamicQObject testable and reusable
This commit is contained in:
parent
52a893577f
commit
e73e37b587
|
@ -77,13 +77,13 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseQAbstractListModel::BaseQAbstractListModel(void* modelObject,
|
BaseQAbstractListModel::BaseQAbstractListModel(void* modelObject,
|
||||||
RowCountCallback rowCountCallback,
|
RowCountCallback rowCountCallback,
|
||||||
ColumnCountCallback columnCountCallback,
|
ColumnCountCallback columnCountCallback,
|
||||||
DataCallback dataCallback,
|
DataCallback dataCallback,
|
||||||
SetDataCallback setDataCallback,
|
SetDataCallback setDataCallback,
|
||||||
RoleNamesCallback roleNamesCallback,
|
RoleNamesCallback roleNamesCallback,
|
||||||
FlagsCallback flagsCallback,
|
FlagsCallback flagsCallback,
|
||||||
HeaderDataCallback headerDataCallback)
|
HeaderDataCallback headerDataCallback)
|
||||||
: m_modelObject(modelObject)
|
: m_modelObject(modelObject)
|
||||||
, m_rowCountCallback(rowCountCallback)
|
, m_rowCountCallback(rowCountCallback)
|
||||||
, m_columnCountCallback(columnCountCallback)
|
, m_columnCountCallback(columnCountCallback)
|
||||||
|
@ -192,8 +192,8 @@ void BaseQAbstractListModel::publicEndResetModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseQAbstractListModel::publicDataChanged(const QModelIndex& topLeft,
|
void BaseQAbstractListModel::publicDataChanged(const QModelIndex& topLeft,
|
||||||
const QModelIndex& bottomRight,
|
const QModelIndex& bottomRight,
|
||||||
const QVector<int>& roles)
|
const QVector<int>& roles)
|
||||||
{
|
{
|
||||||
emit dataChanged(topLeft, bottomRight, roles);
|
emit dataChanged(topLeft, bottomRight, roles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,21 @@ set(HEADERS_LIST
|
||||||
DOtherSide.h
|
DOtherSide.h
|
||||||
DynamicQObject.h
|
DynamicQObject.h
|
||||||
IDynamicQObject.h
|
IDynamicQObject.h
|
||||||
|
OnSlotExecutedHandler.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SRC_LIST
|
set(SRC_LIST
|
||||||
DOtherSide.cpp
|
DOtherSide.cpp
|
||||||
|
OnSlotExecutedHandler.cpp
|
||||||
|
DynamicSlot.cpp
|
||||||
|
DynamicSignal.cpp
|
||||||
|
DynamicProperty.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Shared version for distributing
|
||||||
add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${HEADERS_LIST})
|
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)
|
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)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "DynamicQObject.h"
|
#include "DynamicQObject.h"
|
||||||
#include "BaseQAbstractListModel.h"
|
#include "BaseQAbstractListModel.h"
|
||||||
#include "BaseQObject.h"
|
#include "BaseQObject.h"
|
||||||
|
#include "OnSlotExecutedHandler.h"
|
||||||
|
|
||||||
void convert_to_cstring(const QString& source, char** destination)
|
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();
|
auto dynamicQObject = new BaseQObject();
|
||||||
QQmlEngine::setObjectOwnership(dynamicQObject, QQmlEngine::CppOwnership);
|
QQmlEngine::setObjectOwnership(dynamicQObject, QQmlEngine::CppOwnership);
|
||||||
dynamicQObject->setDObjectPointer(dObjectPointer);
|
dynamicQObject->setOnSlotExecutedHandler(OnSlotExecutedHandler(dObjectPointer, dObjectCallback));
|
||||||
dynamicQObject->setDObjectCallback(dObjectCallback);
|
|
||||||
*vptr = dynamicQObject;
|
*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 dos_qabstractlistmodel_create(void** vptr,
|
||||||
void* modelObject,
|
void* dObjectPointer,
|
||||||
DObjectCallback dObjectCallback,
|
DObjectCallback dObjectCallback,
|
||||||
RowCountCallback rowCountCallback,
|
RowCountCallback rowCountCallback,
|
||||||
ColumnCountCallback columnCountCallback,
|
ColumnCountCallback columnCountCallback,
|
||||||
|
@ -438,7 +438,7 @@ void dos_qabstractlistmodel_create(void** vptr,
|
||||||
FlagsCallback flagsCallback,
|
FlagsCallback flagsCallback,
|
||||||
HeaderDataCallback headerDataCallback)
|
HeaderDataCallback headerDataCallback)
|
||||||
{
|
{
|
||||||
auto model = new BaseQAbstractListModel(modelObject,
|
auto model = new BaseQAbstractListModel(dObjectPointer,
|
||||||
rowCountCallback,
|
rowCountCallback,
|
||||||
columnCountCallback,
|
columnCountCallback,
|
||||||
dataCallback,
|
dataCallback,
|
||||||
|
@ -446,8 +446,7 @@ void dos_qabstractlistmodel_create(void** vptr,
|
||||||
roleNamesCallaback,
|
roleNamesCallaback,
|
||||||
flagsCallback,
|
flagsCallback,
|
||||||
headerDataCallback);
|
headerDataCallback);
|
||||||
model->setDObjectPointer(modelObject);
|
model->setOnSlotExecutedHandler(OnSlotExecutedHandler(dObjectPointer, dObjectCallback));
|
||||||
model->setDObjectCallback(dObjectCallback);
|
|
||||||
*vptr = model;
|
*vptr = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -4,8 +4,6 @@
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <QtCore/QMetaType>
|
#include <QtCore/QMetaType>
|
||||||
|
|
||||||
struct PropertyData;
|
|
||||||
|
|
||||||
class DynamicProperty final
|
class DynamicProperty final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -35,115 +33,6 @@ public:
|
||||||
QString notifySignal() const;
|
QString notifySignal() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct PropertyData;
|
||||||
std::unique_ptr<PropertyData> d;
|
std::unique_ptr<PropertyData> 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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ template <class T>
|
||||||
class DynamicQObject : public T, public IDynamicQObject
|
class DynamicQObject : public T, public IDynamicQObject
|
||||||
{
|
{
|
||||||
using SafeQMetaObjectPtr = std::unique_ptr<QMetaObject, void(*)(void*)>;
|
using SafeQMetaObjectPtr = std::unique_ptr<QMetaObject, void(*)(void*)>;
|
||||||
|
using OnSlotExecutedHandler = std::function<QVariant(const DynamicSlot&, const std::vector<QVariant>&)>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
@ -25,11 +26,8 @@ public:
|
||||||
/// Destructor
|
/// Destructor
|
||||||
virtual ~DynamicQObject();
|
virtual ~DynamicQObject();
|
||||||
|
|
||||||
/// Sets the function to be called from C++ to D or Nimrod
|
/// Sets the on slot executed handler
|
||||||
void setDObjectCallback(IDynamicQObject::Callback callback) override;
|
void setOnSlotExecutedHandler(const OnSlotExecutedHandler& handler);
|
||||||
|
|
||||||
/// Sets the D or Nimrod object that owns this DynamicQObject
|
|
||||||
void setDObjectPointer(void* dObjectPointer) override;
|
|
||||||
|
|
||||||
/// Register a new signal
|
/// Register a new signal
|
||||||
bool registerSignal(const QString& name,
|
bool registerSignal(const QString& name,
|
||||||
|
@ -61,8 +59,6 @@ public:
|
||||||
private:
|
private:
|
||||||
bool executeSlot(const DynamicSlot& slot, void** args);
|
bool executeSlot(const DynamicSlot& slot, void** args);
|
||||||
|
|
||||||
QVariant executeSlot(const DynamicSlot& slot, const std::vector<QVariant> &args);
|
|
||||||
|
|
||||||
bool readProperty(const DynamicProperty& property, void** args);
|
bool readProperty(const DynamicProperty& property, void** args);
|
||||||
|
|
||||||
bool writeProperty(const DynamicProperty& property, void** args);
|
bool writeProperty(const DynamicProperty& property, void** args);
|
||||||
|
@ -81,16 +77,13 @@ private:
|
||||||
QHash<QString, DynamicSlot> m_slotsByName;
|
QHash<QString, DynamicSlot> m_slotsByName;
|
||||||
QHash<QByteArray, DynamicSlot> m_slotsBySignature;
|
QHash<QByteArray, DynamicSlot> m_slotsBySignature;
|
||||||
QHash<QByteArray, DynamicProperty> m_propertiesByName;
|
QHash<QByteArray, DynamicProperty> m_propertiesByName;
|
||||||
void* m_dObjectPointer;
|
OnSlotExecutedHandler m_onSlotExecutedHandler;
|
||||||
IDynamicQObject::Callback m_dObjectCallback;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DynamicQObject<T>::DynamicQObject()
|
DynamicQObject<T>::DynamicQObject()
|
||||||
: T()
|
: T()
|
||||||
, m_metaObject(nullptr, ::free)
|
, m_metaObject(nullptr, ::free)
|
||||||
, m_dObjectPointer(nullptr)
|
|
||||||
, m_dObjectCallback(nullptr)
|
|
||||||
{
|
{
|
||||||
QMetaObjectBuilder builder;
|
QMetaObjectBuilder builder;
|
||||||
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
|
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
|
||||||
|
@ -100,15 +93,9 @@ DynamicQObject<T>::DynamicQObject()
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void DynamicQObject<T>::setDObjectCallback(IDynamicQObject::Callback callback)
|
void DynamicQObject<T>::setOnSlotExecutedHandler(const DynamicQObject::OnSlotExecutedHandler &handler)
|
||||||
{
|
{
|
||||||
m_dObjectCallback = callback;
|
m_onSlotExecutedHandler = handler;
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void DynamicQObject<T>::setDObjectPointer(void* dObjectPointer)
|
|
||||||
{
|
|
||||||
m_dObjectPointer = dObjectPointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -284,15 +271,12 @@ bool DynamicQObject<T>::executeSlot(const DynamicSlot& slot, void** args)
|
||||||
if (!slot.isValid())
|
if (!slot.isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_dObjectCallback || !m_dObjectPointer)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::vector<QVariant> arguments;
|
std::vector<QVariant> arguments;
|
||||||
arguments.reserve(slot.argumentsTypes().size());
|
arguments.reserve(slot.argumentsTypes().size());
|
||||||
for (int i = 0; i < slot.argumentsTypes().count(); ++i)
|
for (int i = 0; i < slot.argumentsTypes().count(); ++i)
|
||||||
arguments.emplace_back(QVariant(slot.argumentTypeAt(i), args[i + 1]));
|
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())
|
if (slot.returnType() != QMetaType::Void && result.isValid())
|
||||||
{
|
{
|
||||||
|
@ -303,30 +287,6 @@ bool DynamicQObject<T>::executeSlot(const DynamicSlot& slot, void** args)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
QVariant DynamicQObject<T>::executeSlot(const DynamicSlot& slot, const std::vector<QVariant>& args)
|
|
||||||
{
|
|
||||||
QVariant result;
|
|
||||||
|
|
||||||
if (!m_dObjectCallback || !m_dObjectPointer)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
// prepare slot name
|
|
||||||
QVariant slotName(slot.name());
|
|
||||||
|
|
||||||
// prepare void* for the QVariants
|
|
||||||
std::vector<void*> 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 <typename T>
|
template <typename T>
|
||||||
bool DynamicQObject<T>::readProperty(const DynamicProperty& property, void** args)
|
bool DynamicQObject<T>::readProperty(const DynamicProperty& property, void** args)
|
||||||
{
|
{
|
||||||
|
@ -370,8 +330,10 @@ bool DynamicQObject<T>::writeProperty(const DynamicProperty& property, void** ar
|
||||||
if (writeSlot.returnType() != QMetaType::Void)
|
if (writeSlot.returnType() != QMetaType::Void)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QVariant newValue(writeSlot.argumentTypeAt(0), args[0]);
|
void* sortedArgs[2]; // The write property is peculiar because it has
|
||||||
executeSlot(writeSlot, {newValue});
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include "DynamicSignal.h"
|
||||||
|
|
||||||
|
struct DynamicSignal::SignalData
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
QList<QMetaType::Type> argumentsTypes;
|
||||||
|
QByteArray signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
DynamicSignal::DynamicSignal()
|
||||||
|
: d(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicSignal::DynamicSignal(const QString& name, const QList<QMetaType::Type>& 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();
|
||||||
|
}
|
|
@ -7,8 +7,6 @@
|
||||||
#include <QtCore/QMetaType>
|
#include <QtCore/QMetaType>
|
||||||
#include <QtCore/QList>
|
#include <QtCore/QList>
|
||||||
|
|
||||||
struct SignalData;
|
|
||||||
|
|
||||||
class DynamicSignal final
|
class DynamicSignal final
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -28,93 +26,6 @@ public:
|
||||||
private:
|
private:
|
||||||
void _initSignature();
|
void _initSignature();
|
||||||
|
|
||||||
|
struct SignalData;
|
||||||
std::unique_ptr<SignalData> d;
|
std::unique_ptr<SignalData> d;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SignalData
|
|
||||||
{
|
|
||||||
QString name;
|
|
||||||
QList<QMetaType::Type> argumentsTypes;
|
|
||||||
QByteArray signature;
|
|
||||||
};
|
|
||||||
|
|
||||||
DynamicSignal::DynamicSignal()
|
|
||||||
: d(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicSignal::DynamicSignal(const QString& name, const QList<QMetaType::Type>& 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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
#include "DynamicSlot.h"
|
||||||
|
|
||||||
|
struct DynamicSlot::SlotData
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
QMetaType::Type returnType;
|
||||||
|
QList<QMetaType::Type> argumentsTypes;
|
||||||
|
QByteArray signature;
|
||||||
|
};
|
||||||
|
|
||||||
|
DynamicSlot::DynamicSlot()
|
||||||
|
: d(nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DynamicSlot::DynamicSlot(const QString& name,
|
||||||
|
QMetaType::Type returnType,
|
||||||
|
const QList<QMetaType::Type>& 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<QMetaType::Type> DynamicSlot::argumentsTypes() const
|
||||||
|
{
|
||||||
|
return isValid() ? d->argumentsTypes : QList<QMetaType::Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include "private/qmetaobjectbuilder_p.h"
|
#include "private/qmetaobjectbuilder_p.h"
|
||||||
|
|
||||||
struct SlotData;
|
|
||||||
class QString;
|
class QString;
|
||||||
|
|
||||||
class DynamicSlot final
|
class DynamicSlot final
|
||||||
|
@ -37,102 +36,6 @@ public:
|
||||||
private:
|
private:
|
||||||
void _initSignature();
|
void _initSignature();
|
||||||
|
|
||||||
|
struct SlotData;
|
||||||
std::unique_ptr<SlotData> d;
|
std::unique_ptr<SlotData> d;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SlotData
|
|
||||||
{
|
|
||||||
QString name;
|
|
||||||
QMetaType::Type returnType;
|
|
||||||
QList<QMetaType::Type> argumentsTypes;
|
|
||||||
QByteArray signature;
|
|
||||||
};
|
|
||||||
|
|
||||||
DynamicSlot::DynamicSlot()
|
|
||||||
: d(nullptr)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicSlot::DynamicSlot(const QString& name,
|
|
||||||
QMetaType::Type returnType,
|
|
||||||
const QList<QMetaType::Type>& 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<QMetaType::Type> DynamicSlot::argumentsTypes() const
|
|
||||||
{
|
|
||||||
return isValid() ? d->argumentsTypes : QList<QMetaType::Type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,12 +8,6 @@ public:
|
||||||
/// Destructor
|
/// Destructor
|
||||||
virtual ~IDynamicQObject() = default;
|
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
|
/// Register a new signal
|
||||||
virtual bool registerSignal(const QString& name,
|
virtual bool registerSignal(const QString& name,
|
||||||
const QList<QMetaType::Type>& argumentsTypes,
|
const QList<QMetaType::Type>& argumentsTypes,
|
||||||
|
|
|
@ -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<QVariant> &args)
|
||||||
|
{
|
||||||
|
QVariant result;
|
||||||
|
|
||||||
|
if (!m_dObjectCallback || !m_dObjectPointer)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// prepare slot name
|
||||||
|
QVariant slotName(slot.name());
|
||||||
|
|
||||||
|
// prepare void* for the QVariants
|
||||||
|
std::vector<void*> 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;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
#include <vector>
|
||||||
|
#include "IDynamicQObject.h"
|
||||||
|
|
||||||
|
class DynamicSlot;
|
||||||
|
|
||||||
|
class OnSlotExecutedHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OnSlotExecutedHandler(void* dObjectPointer, IDynamicQObject::Callback dObjectCallback);
|
||||||
|
|
||||||
|
QVariant operator()(const DynamicSlot& slot, std::vector<QVariant> const& args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* m_dObjectPointer;
|
||||||
|
IDynamicQObject::Callback m_dObjectCallback;
|
||||||
|
};
|
|
@ -11,4 +11,4 @@ find_package(Qt5Test REQUIRED)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} test_dynamicqobject.cpp)
|
add_executable(${PROJECT_NAME} test_dynamicqobject.cpp)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} Qt5::Test)
|
target_link_libraries(${PROJECT_NAME} DOtherSideStatic Qt5::Test)
|
||||||
|
|
|
@ -1,7 +1,22 @@
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
|
#include <tuple>
|
||||||
|
#include <iostream>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "../src/BaseQObject.h"
|
||||||
#include "../src/DynamicQObject.h"
|
#include "../src/DynamicQObject.h"
|
||||||
|
|
||||||
|
// Templates that convers a T to a string
|
||||||
|
template <typename T>
|
||||||
|
struct TypeName
|
||||||
|
{
|
||||||
|
static const char* Get() { return typeid(T).name(); }
|
||||||
|
};
|
||||||
|
template <> struct TypeName<int> { static const char* Get() { return "int"; } };
|
||||||
|
template <> struct TypeName<QString> { static const char* Get() { return "QString"; } };
|
||||||
|
template <> struct TypeName<bool> { static const char* Get() { return "bool"; } };
|
||||||
|
template <> struct TypeName<QVariant> { static const char* Get() { return "QVariant"; } };
|
||||||
|
|
||||||
class TestDynamicQObject : public QObject
|
class TestDynamicQObject : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -9,6 +24,7 @@ class TestDynamicQObject : public QObject
|
||||||
private slots:
|
private slots:
|
||||||
void memoryLeakTest() {
|
void memoryLeakTest() {
|
||||||
DynamicQObject<QObject> dynamicQObject;
|
DynamicQObject<QObject> dynamicQObject;
|
||||||
|
BaseQObject baseQObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testRegisterSignal() {
|
void testRegisterSignal() {
|
||||||
|
@ -22,11 +38,11 @@ private slots:
|
||||||
QCOMPARE(signalSpy.count(), 1);
|
QCOMPARE(signalSpy.count(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testRegisterSlot() {
|
void testSlotExecution() {
|
||||||
DynamicQObject<QObject> dynamicQObject;
|
testSlotExecutionForType<int>(10);
|
||||||
int index;
|
testSlotExecutionForType<QString>("foo");
|
||||||
dynamicQObject.registerSlot("fooSlot", QMetaType::Void, {}, index);
|
testSlotExecutionForType<bool>(false);
|
||||||
QCOMPARE(index != -1, true);
|
testSlotExecutionForType<QVariant>(QVariant(40));
|
||||||
}
|
}
|
||||||
|
|
||||||
void testRegisterProperty() {
|
void testRegisterProperty() {
|
||||||
|
@ -45,6 +61,27 @@ private slots:
|
||||||
result = dynamicQObject.registerProperty("foo", QMetaType::Int, "foo", "setFoo", "fooChanged");
|
result = dynamicQObject.registerProperty("foo", QMetaType::Int, "foo", "setFoo", "fooChanged");
|
||||||
QCOMPARE(result, true);
|
QCOMPARE(result, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename ReturnType>
|
||||||
|
void testSlotExecutionForType(ReturnType expectedReturnValue) {
|
||||||
|
DynamicQObject<QObject> dynamicQObject;
|
||||||
|
int index;
|
||||||
|
dynamicQObject.registerSlot("fooSlot", (QMetaType::Type)qMetaTypeId<ReturnType>(), {}, 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<QVariant> &args) -> QVariant {
|
||||||
|
called = true;
|
||||||
|
return expectedReturnValue;
|
||||||
|
};
|
||||||
|
dynamicQObject.setOnSlotExecutedHandler(handler);
|
||||||
|
ReturnType result;
|
||||||
|
QMetaObject::invokeMethod(&dynamicQObject, "fooSlot", QReturnArgument<ReturnType>(TypeName<ReturnType>::Get(), result));
|
||||||
|
QCOMPARE(called, true);
|
||||||
|
QCOMPARE(result, expectedReturnValue);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QTEST_MAIN(TestDynamicQObject)
|
QTEST_MAIN(TestDynamicQObject)
|
||||||
|
|
Loading…
Reference in New Issue