Refactoring and bug fixing

This commit is contained in:
Filippo Cucchetto 2016-01-07 16:59:51 +01:00
parent e5457adc85
commit 23f795298d
5 changed files with 88 additions and 45 deletions

View File

@ -8,6 +8,7 @@
#include <QtCore/QObject>
#include <QtCore/QString>
#include <QtCore/QHash>
#include <QtCore/QMetaMethod>
// DOtherSide
#include "DOtherSide/DOtherSideTypesCpp.h"
@ -20,9 +21,10 @@ class IDosQMetaObject
public:
virtual ~IDosQMetaObject() = default;
virtual const QMetaObject* metaObject() const = 0;
virtual int signalSlotIndex(const QString& signalName) const = 0;
virtual int readSlotIndex(const char* propertyName) const = 0;
virtual int writeSlotIndex(const char* propertyName) const = 0;
virtual QMetaMethod signal(const QString& signalName) const = 0;
virtual QMetaMethod readSlot(const char* propertyName) const = 0;
virtual QMetaMethod writeSlot(const char* propertyName) const = 0;
virtual const IDosQMetaObject* superClassDosMetaObject() const = 0;
};
/// Base class for any IDosQMetaObject
@ -33,9 +35,10 @@ public:
: m_metaObject(metaObject)
{}
const QMetaObject *metaObject() const override { return m_metaObject; }
int signalSlotIndex(const QString &signalName) const override { return -1; }
int readSlotIndex(const char *propertyName) const override { return -1; }
int writeSlotIndex(const char *propertyName) const override { return -1; }
QMetaMethod signal(const QString &signalName) const override { return QMetaMethod(); }
QMetaMethod readSlot(const char *propertyName) const override { return QMetaMethod(); }
QMetaMethod writeSlot(const char *propertyName) const override { return QMetaMethod(); }
const IDosQMetaObject* superClassDosMetaObject() const { return nullptr; }
private:
SafeQMetaObjectPtr m_metaObject;
@ -59,27 +62,28 @@ public:
class DosQMetaObject : public IDosQMetaObject
{
public:
DosQMetaObject(const IDosQMetaObject& superClassMetaObject,
DosQMetaObject(std::shared_ptr<const IDosQMetaObject> superClassDosMetaObject,
const QString& className,
const SignalDefinitions &signalDefinitions,
const SlotDefinitions &slotDefinitions,
const PropertyDefinitions &propertyDefinitions);
int signalSlotIndex(const QString& signalName) const override;
int readSlotIndex(const char* propertyName) const override;
int writeSlotIndex(const char* propertyName) const override;
QMetaMethod signal(const QString& signalName) const override;
QMetaMethod readSlot(const char* propertyName) const override;
QMetaMethod writeSlot(const char* propertyName) const override;
const QMetaObject *metaObject() const override;
const IDosQMetaObject *superClassDosMetaObject() const override;
private:
QMetaObject *createMetaObject(const IDosQMetaObject &superClassMetaObject,
const QString& className,
QMetaObject *createMetaObject(const QString& className,
const SignalDefinitions &signalDefinitions,
const SlotDefinitions &slotDefinitions,
const PropertyDefinitions &propertyDefinitions);
std::shared_ptr<const IDosQMetaObject> m_superClassDosMetaObject;
QHash<QString, int> m_signalIndexByName;
QHash<QString, QPair<int,int>> m_propertySlots;
SafeQMetaObjectPtr m_metaObject;
std::unordered_map<std::string, int> m_signalIndexByName;
std::unordered_map<std::string, std::pair<int,int>> m_propertySlots;
};
/// This class simply holds a ptr to a IDosQMetaObject

View File

@ -24,7 +24,8 @@ public:
int qt_metacall(QMetaObject::Call callType, int index, void**args) override;
private:
std::shared_ptr<const DOS::IDosQMetaObject> factory() const;
std::shared_ptr<const DOS::IDosQMetaObject> dosMetaObject() const;
bool executeSlot(const QMetaMethod& method, void** args);
bool executeSlot(int index, void** args);
bool readProperty(int index, void** args);
bool writeProperty(int index, void** args);

View File

@ -542,7 +542,7 @@ void dos_qmetaobject_create(void **vptr,
auto data = superClassHolder->data();
Q_ASSERT(data);
auto metaObject = std::make_shared<DosQMetaObject>(*data,
auto metaObject = std::make_shared<DosQMetaObject>(data,
QString::fromUtf8(className),
toVector(signalDefinitions),
toVector(slotDefinitions),

View File

@ -33,7 +33,7 @@ Value valueOrDefault(std::unordered_map<Key,Value> const& map, const Key& k, Val
QMetaObject* createDynamicQObjectMetaObject()
{
QMetaObjectBuilder builder;
builder.setClassName("DynamicQObject");
builder.setClassName("DosQObject");
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
builder.setSuperClass(&QObject::staticMetaObject);
return builder.toMetaObject();
@ -43,7 +43,7 @@ QMetaObject* createDynamicQAbstractListModelMetaObject()
{
QMetaObjectBuilder builder;
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
builder.setClassName("DynamicQAbstractListModel");
builder.setClassName("DosQAbstractListModel");
builder.setSuperClass(&QAbstractListModel::staticMetaObject);
return builder.toMetaObject();
}
@ -61,18 +61,17 @@ DosQAbstractListModelMetaObject::DosQAbstractListModelMetaObject()
: BaseDosQMetaObject(::createDynamicQAbstractListModelMetaObject())
{}
DosQMetaObject::DosQMetaObject(const IDosQMetaObject &superClassMetaObject,
DosQMetaObject::DosQMetaObject(std::shared_ptr<const IDosQMetaObject> superClassMetaObject,
const QString &className,
const SignalDefinitions& signalDefinitions,
const SlotDefinitions& slotDefinitions,
const PropertyDefinitions& propertyDefinitions)
: m_metaObject(nullptr)
: m_superClassDosMetaObject(std::move(superClassMetaObject))
, m_metaObject(createMetaObject(className, signalDefinitions, slotDefinitions, propertyDefinitions))
{
m_metaObject.reset(createMetaObject(superClassMetaObject, className, signalDefinitions, slotDefinitions, propertyDefinitions));
}
QMetaObject *DosQMetaObject::createMetaObject(const IDosQMetaObject &superClassMetaObject,
const QString &className,
QMetaObject *DosQMetaObject::createMetaObject(const QString &className,
const SignalDefinitions& signalDefinitions,
const SlotDefinitions& slotDefinitions,
const PropertyDefinitions& propertyDefinitions)
@ -80,53 +79,68 @@ QMetaObject *DosQMetaObject::createMetaObject(const IDosQMetaObject &superClassM
QMetaObjectBuilder builder;
builder.setClassName(className.toUtf8());
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
builder.setSuperClass(superClassMetaObject.metaObject());
builder.setSuperClass(m_superClassDosMetaObject->metaObject());
for (const SignalDefinition& signal : signalDefinitions)
{
QMetaMethodBuilder signalBuilder = builder.addSignal(::createSignature(signal));
signalBuilder.setReturnType(QMetaType::typeName(QMetaType::Void));
signalBuilder.setAccess(QMetaMethod::Public);
m_signalIndexByName[signal.name.toStdString()] = signalBuilder.index();
m_signalIndexByName[signal.name] = signalBuilder.index();
}
std::unordered_map<std::string, int> methodIndexByName;
QHash<QString, int> methodIndexByName;
for (const SlotDefinition& slot : slotDefinitions)
{
QMetaMethodBuilder methodBuilder = builder.addSlot(::createSignature(slot));
methodBuilder.setReturnType(QMetaType::typeName(slot.returnType));
methodBuilder.setAttributes(QMetaMethod::Scriptable);
methodIndexByName[slot.name.toStdString()] = methodBuilder.index();
methodIndexByName[slot.name] = methodBuilder.index();
}
for (const PropertyDefinition& property : propertyDefinitions)
{
const int notifier = ::valueOrDefault(m_signalIndexByName, property.notifySignal.toStdString(), -1);
const int notifier = m_signalIndexByName.value(property.notifySignal, -1);
const QByteArray name = property.name.toUtf8();
const QByteArray typeName = QMetaObject::normalizedType(QMetaType::typeName(property.type));
QMetaPropertyBuilder propertyBuilder = builder.addProperty(name, typeName, notifier);
if (notifier == -1)
propertyBuilder.setConstant(true);
m_propertySlots[propertyBuilder.name().toStdString()] = std::make_pair(::valueOrDefault(methodIndexByName, property.readSlot.toStdString(), -1),
::valueOrDefault(methodIndexByName, property.writeSlot.toStdString(), -1));
m_propertySlots[property.name] = qMakePair(methodIndexByName.value(property.readSlot, -1),
methodIndexByName.value(property.writeSlot, -1));
}
return builder.toMetaObject();
}
int DosQMetaObject::signalSlotIndex(const QString &signalName) const
{
return metaObject()->methodOffset() + ::valueOrDefault(m_signalIndexByName, signalName.toStdString(), -1);
QMetaMethod DosQMetaObject::signal(const QString &signalName) const
{
const int index = m_signalIndexByName.value(signalName, -1);
if (index != -1)
return metaObject()->method(metaObject()->methodOffset() + index);
if (auto superMetaObject = superClassDosMetaObject())
return superMetaObject->signal(signalName);
return QMetaMethod();
}
int DosQMetaObject::readSlotIndex(const char *propertyName) const
QMetaMethod DosQMetaObject::readSlot(const char *propertyName) const
{
return metaObject()->methodOffset() + ::valueOrDefault(m_propertySlots, std::string(propertyName), std::make_pair(-1,-1)).first;
const auto index = m_propertySlots.value(QString::fromUtf8(propertyName), qMakePair(-1,-1)).first;
if (index != -1)
return metaObject()->method(metaObject()->methodOffset() + index);
if (auto superMetaObject = superClassDosMetaObject())
return superMetaObject->readSlot(propertyName);
return QMetaMethod();
}
int DosQMetaObject::writeSlotIndex(const char *propertyName) const
QMetaMethod DosQMetaObject::writeSlot(const char *propertyName) const
{
return metaObject()->methodOffset() + valueOrDefault(m_propertySlots, std::string(propertyName), std::make_pair(-1,-1)).second;
const auto index = m_propertySlots.value(QString::fromUtf8(propertyName), qMakePair(-1,-1)).second;
if (index != -1)
return metaObject()->method(metaObject()->methodOffset() + index);
if (auto superMetaObject = superClassDosMetaObject())
return superMetaObject->writeSlot(propertyName);
return QMetaMethod();
}
const QMetaObject *DosQMetaObject::metaObject() const
@ -134,4 +148,9 @@ const QMetaObject *DosQMetaObject::metaObject() const
return m_metaObject;
}
const IDosQMetaObject *DosQMetaObject::superClassDosMetaObject() const
{
return m_superClassDosMetaObject.get();
}
} // namespace DOS

View File

@ -2,6 +2,7 @@
#include "DOtherSide/DosQMetaObject.h"
#include <QtCore/QMetaObject>
#include <QtCore/QMetaMethod>
#include <QtCore/QDebug>
namespace DOS
{
@ -17,23 +18,23 @@ DynamicQObjectImpl::DynamicQObjectImpl(QObject* parent,
bool DynamicQObjectImpl::emitSignal(const QString &name, const std::vector<QVariant> &args)
{
const int index = factory()->signalSlotIndex(name);
const QMetaMethod method = metaObject()->method(index);
const QMetaMethod method = dosMetaObject()->signal(name);
if (!method.isValid())
return false;
Q_ASSERT(name.toUtf8() == method.name());
std::vector<void*> arguments(args.size() + 1, nullptr);
arguments.front() = nullptr;
auto func = [](const QVariant& arg) -> void* { return (void*)(&arg); };
std::transform(args.begin(), args.end(), arguments.begin() + 1, func);
QMetaObject::activate(m_parent, index, arguments.data());
QMetaObject::activate(m_parent, method.methodIndex(), arguments.data());
return true;
}
const QMetaObject *DynamicQObjectImpl::metaObject() const
{
return factory()->metaObject();
return dosMetaObject()->metaObject();
}
int DynamicQObjectImpl::qt_metacall(QMetaObject::Call callType, int index, void **args)
@ -55,7 +56,7 @@ int DynamicQObjectImpl::qt_metacall(QMetaObject::Call callType, int index, void
return -1;
}
std::shared_ptr<const IDosQMetaObject> DynamicQObjectImpl::factory() const
std::shared_ptr<const IDosQMetaObject> DynamicQObjectImpl::dosMetaObject() const
{
static std::shared_ptr<const IDosQMetaObject> result = m_onMetaObject()->data();
return result;
@ -64,8 +65,16 @@ std::shared_ptr<const IDosQMetaObject> DynamicQObjectImpl::factory() const
bool DynamicQObjectImpl::executeSlot(int index, void **args)
{
const QMetaMethod method = metaObject()->method(index);
if (!method.isValid())
if (!method.isValid()) {
qDebug() << "C++: executeSlot: invalid method";
return false;
}
executeSlot(method, args);
}
bool DynamicQObjectImpl::executeSlot(const QMetaMethod &method, void **args)
{
Q_ASSERT(method.isValid());
const bool hasReturnType = method.returnType() != QMetaType::Void;
@ -90,7 +99,12 @@ bool DynamicQObjectImpl::readProperty(int index, void **args)
const QMetaProperty property = metaObject()->property(index);
if (!property.isValid() || !property.isReadable())
return false;
return executeSlot(factory()->readSlotIndex(property.name()), args);
QMetaMethod method = dosMetaObject()->readSlot(property.name());
if (!method.isValid()) {
qDebug() << "C++: readProperty: invalid read method for property " << property.name();
return false;
}
return executeSlot(method, args);
}
bool DynamicQObjectImpl::writeProperty(int index, void **args)
@ -98,7 +112,12 @@ bool DynamicQObjectImpl::writeProperty(int index, void **args)
const QMetaProperty property = metaObject()->property(index);
if (!property.isValid() || !property.isWritable())
return false;
return executeSlot(factory()->writeSlotIndex(property.name()), args);
QMetaMethod method = dosMetaObject()->writeSlot(property.name());
if (!method.isValid()) {
qDebug() << "C++: writeProperty: invalid write method for property " << property.name();
return false;
}
return executeSlot(method, args);
}
}