Finish 0.3.0

This commit is contained in:
Filippo Cucchetto 2015-02-15 14:46:55 +01:00
commit c600544551
46 changed files with 3060 additions and 1352 deletions

3
.gitignore vendored
View File

@ -4,4 +4,5 @@ build
*.o
.directory
#*#
nimcache
nimcache
*.kdev4

16
CHANGELOG.md Normal file
View File

@ -0,0 +1,16 @@
# Version 3.0
* [NimQml] Added support for QAbstractListModel subclasses
* [NimQml] Fixed QtObject macro wrong reorder of the methods and proc declaration (thanks to Will)
* [NimQml] Added new ContactApp example
* [NimQml] Added optional support for finalizers
* [DOtherSide] Added support for injecting the DynamicQObject as behaviour to QObject subclasses
* [DotherSide] Added support for QAbstractListModel subclasses
# Version 2.0
* [DQml] Initial support for properties creation
* [NimQml] Added new macro syntax for creating QObject derived object (thanks to Will)
# Version 1.0
* [DOtherSide] Initial version with support for QObject Slot, Signal and Properties creation
* [DQml] Initial support for Slot and Signal creation
* [NimQml] Initial support for Slot, Signal and Properties creation

View File

@ -1,3 +1,3 @@
add_subdirectory(DOtherSide)
add_subdirectory(DynamicQObject)
add_subdirectory(IntegrationTest)
#add_subdirectory(DynamicQObject)
#add_subdirectory(IntegrationTest)

View File

@ -0,0 +1,202 @@
#ifndef BASEQABSTRACTLISTMODEL_H
#define BASEQABSTRACTLISTMODEL_H
#include "DOtherSideTypes.h"
#include "DynamicQObject.h"
#include <QAbstractListModel>
/// This class act as a base class for D and Nim QAbstractListModel
class BaseQAbstractListModel : public DynamicQObject<QAbstractListModel>
{
public:
/// Constructor
BaseQAbstractListModel(void* modelObject,
RowCountCallback rowCountCallback,
ColumnCountCallback columnCountCallback,
DataCallback dataCallback,
SetDataCallback setDataCallback,
RoleNamesCallback roleNamesCallback,
FlagsCallback flagsCallback,
HeaderDataCallback headerDataCallback);
/// Return the model's row count
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override;
/// Return the model's column count
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
/// Return the QVariant at the given index
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
/// Sets the QVariant value at the given index and role
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
/// Return the item flags for the given index
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
/// Return the data for the given role and section in the header with the specified orientation
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
/// Return the dModelPointer
void* modelObject();
/// Return the roleNames
virtual QHash<int, QByteArray> roleNames() const override;
/// Expose beginInsertRows
void publicBeginInsertRows(const QModelIndex& index, int first, int last);
/// Expose endInsertRows
void publicEndInsertRows();
/// Expose beginRemoveRows
void publicBeginRemoveRows(const QModelIndex& index, int first, int last);
/// Expose endInsertRows
void publicEndRemoveRows();
/// Expose beginResetModel
void publicBeginResetModel();
/// Expose endResetModel
void publicEndResetModel();
/// Expose dataChanged
void publicDataChanged(const QModelIndex& topLeft,
const QModelIndex& bottomRight,
const QVector<int>& roles = QVector<int>());
private:
void* m_modelObject;
RowCountCallback m_rowCountCallback;
ColumnCountCallback m_columnCountCallback;
DataCallback m_dataCallback;
SetDataCallback m_setDataCallback;
RoleNamesCallback m_roleNamesCallback;
FlagsCallback m_flagsCallback;
HeaderDataCallback m_headerDataCallback;
};
BaseQAbstractListModel::BaseQAbstractListModel(void* modelObject,
RowCountCallback rowCountCallback,
ColumnCountCallback columnCountCallback,
DataCallback dataCallback,
SetDataCallback setDataCallback,
RoleNamesCallback roleNamesCallback,
FlagsCallback flagsCallback,
HeaderDataCallback headerDataCallback)
: m_modelObject(modelObject)
, m_rowCountCallback(rowCountCallback)
, m_columnCountCallback(columnCountCallback)
, m_dataCallback(dataCallback)
, m_setDataCallback(setDataCallback)
, m_roleNamesCallback(roleNamesCallback)
, m_flagsCallback(flagsCallback)
, m_headerDataCallback(headerDataCallback)
{
}
int BaseQAbstractListModel::rowCount(const QModelIndex& parent) const
{
auto parentIndex = new QModelIndex();
*parentIndex = parent;
int result;
m_rowCountCallback(m_modelObject, parentIndex, &result);
return result;
}
int BaseQAbstractListModel::columnCount(const QModelIndex& parent) const
{
auto parentIndex = new QModelIndex();
*parentIndex = parent;
int result;
m_columnCountCallback(m_modelObject, parentIndex, &result);
return result;
}
QVariant BaseQAbstractListModel::data(const QModelIndex& index, int role) const
{
auto newIndex = new QModelIndex();
*newIndex = index;
QVariant result;
m_dataCallback(m_modelObject, newIndex, role, &result);
return result;
}
bool BaseQAbstractListModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
auto newIndex = new QModelIndex(index);
*newIndex = index;
auto newValue = new QVariant();
*newValue = value;
bool result = false;
m_setDataCallback(m_modelObject, newIndex, newValue, role, &result);
return result;
}
Qt::ItemFlags BaseQAbstractListModel::flags(const QModelIndex& index) const
{
auto newIndex = new QModelIndex(index);
*newIndex = index;
int result;
m_flagsCallback(m_modelObject, newIndex, &result);
return Qt::ItemFlags(result);
}
QVariant BaseQAbstractListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant result;
m_headerDataCallback(m_modelObject, section, orientation, role, &result);
return result;
}
void* BaseQAbstractListModel::modelObject()
{
return m_modelObject;
}
QHash<int, QByteArray> BaseQAbstractListModel::roleNames() const
{
QHash<int, QByteArray> result;
m_roleNamesCallback(m_modelObject, &result);
return result;
}
void BaseQAbstractListModel::publicBeginInsertRows(const QModelIndex& index, int first, int last)
{
beginInsertRows(index, first, last);
}
void BaseQAbstractListModel::publicEndInsertRows()
{
return endInsertRows();
}
void BaseQAbstractListModel::publicBeginRemoveRows(const QModelIndex& index, int first, int last)
{
beginRemoveRows(index, first, last);
}
void BaseQAbstractListModel::publicEndRemoveRows()
{
return endRemoveRows();
}
void BaseQAbstractListModel::publicBeginResetModel()
{
beginResetModel();
}
void BaseQAbstractListModel::publicEndResetModel()
{
endResetModel();
}
void BaseQAbstractListModel::publicDataChanged(const QModelIndex& topLeft,
const QModelIndex& bottomRight,
const QVector<int>& roles)
{
emit dataChanged(topLeft, bottomRight, roles);
}
#endif

View File

@ -0,0 +1,8 @@
#ifndef BASEQOBJECT_H
#define BASEQOBJECT_H
#include "DynamicQObject.h"
class BaseQObject : public DynamicQObject<QObject> {};
#endif

View File

@ -8,9 +8,13 @@ find_package(Qt5Core)
find_package(Qt5Qml)
find_package(Qt5Gui)
find_package(Qt5Quick)
find_package(Qt5Widgets)
set(HEADERS_LIST
DOtherSide.h
DOtherSideTypes.h
BaseQAbstractListModel.h
BaseQObject.h
)
set(SRC_LIST
@ -18,5 +22,5 @@ set(SRC_LIST
)
add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${HEADERS_LIST})
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Qml Qt5::Quick DynamicQObject)
target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../DynamicQObject)

View File

@ -1,19 +1,25 @@
#include "DOtherSide.h"
#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickView>
#include <QtQml/QQmlContext>
#include <iostream>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QModelIndex>
#include <QtGui/QGuiApplication>
#include <QtQml/QQmlContext>
#include <QtQml/QQmlApplicationEngine>
#include <QtQuick/QQuickView>
#include <QtWidgets/QApplication>
#include "DynamicQObject.h"
#include "BaseQAbstractListModel.h"
#include "BaseQObject.h"
void convert_to_cstring(const QString& source, CharPtr& destination, int& length)
void convert_to_cstring(const QString& source, char** destination, int* length)
{
QByteArray array = source.toUtf8();
destination = qstrdup(array.data());
length = qstrlen(array.data());
*destination = qstrdup(array.data());
*length = qstrlen(array.data());
}
void dos_qguiapplication_create()
@ -34,12 +40,40 @@ void dos_qguiapplication_exec()
qApp->exec();
}
void dos_qqmlapplicationengine_create(void **vptr)
void dos_qguiapplication_quit()
{
qApp->quit();
}
void dos_qapplication_create()
{
static int argc = 1;
static char empty[1] = {0};
static char* argv[] = {empty};
new QApplication(argc, argv);
}
void dos_qapplication_delete()
{
delete qApp;
}
void dos_qapplication_exec()
{
qApp->exec();
}
void dos_qapplication_quit()
{
qApp->quit();
}
void dos_qqmlapplicationengine_create(void** vptr)
{
*vptr = new QQmlApplicationEngine();
}
void dos_qqmlapplicationengine_load(void *vptr, const char *filename)
void dos_qqmlapplicationengine_load(void* vptr, const char* filename)
{
QQmlApplicationEngine* engine = reinterpret_cast<QQmlApplicationEngine*>(vptr);
engine->load(QUrl::fromLocalFile(QCoreApplication::applicationDirPath() + QDir::separator() + QString(filename)));
@ -75,7 +109,7 @@ void dos_qquickview_delete(void* vptr)
delete view;
}
void dos_qquickview_source(void *vptr, CharPtr& result, int& length)
void dos_qquickview_source(void* vptr, char** result, int* length)
{
QQuickView* view = reinterpret_cast<QQuickView*>(vptr);
QUrl url = view->source();
@ -94,25 +128,25 @@ void dos_qquickview_rootContext(void* vptr, void** context)
*context = view->rootContext();
}
void dos_chararray_create(CharPtr& ptr)
void dos_chararray_create(char** ptr)
{
ptr = 0;
*ptr = 0;
}
void dos_chararray_create(CharPtr& ptr, int size)
void dos_chararray_create(char** ptr, int size)
{
if (size > 0)
ptr = new char[size];
*ptr = new char[size];
else
ptr = 0;
*ptr = 0;
}
void dos_chararray_delete(CharPtr ptr)
void dos_chararray_delete(char* ptr)
{
if (ptr) delete[] ptr;
}
void dos_qqmlcontext_baseUrl(void* vptr, CharPtr& result, int& length)
void dos_qqmlcontext_baseUrl(void* vptr, char** result, int* length)
{
QQmlContext* context = reinterpret_cast<QQmlContext*>(vptr);
QUrl url = context->baseUrl();
@ -126,17 +160,17 @@ void dos_qqmlcontext_setcontextproperty(void* vptr, const char* name, void* valu
context->setContextProperty(QString::fromUtf8(name), *variant);
}
void dos_qvariant_create(void **vptr)
void dos_qvariant_create(void** vptr)
{
*vptr = new QVariant();
}
void dos_qvariant_create_int(void **vptr, int value)
void dos_qvariant_create_int(void** vptr, int value)
{
*vptr = new QVariant(value);
}
void dos_qvariant_create_bool(void **vptr, bool value)
void dos_qvariant_create_bool(void** vptr, bool value)
{
*vptr = new QVariant(value);
}
@ -146,7 +180,15 @@ void dos_qvariant_create_string(void** vptr, const char* value)
*vptr = new QVariant(value);
}
void dos_qvariant_create_qobject(void **vptr, void* value)
void dos_qvariant_create_qvariant(void** vptr, void* other)
{
auto newQVariant = new QVariant();
auto otherQVariant = reinterpret_cast<QVariant*>(other);
*newQVariant = *otherQVariant;
*vptr = newQVariant;
}
void dos_qvariant_create_qobject(void** vptr, void* value)
{
auto qobject = reinterpret_cast<QObject*>(value);
auto variant = new QVariant();
@ -154,31 +196,68 @@ void dos_qvariant_create_qobject(void **vptr, void* value)
*vptr = variant;
}
void dos_qvariant_isnull(void* vptr, bool& isNull)
void dos_qvariant_create_float(void** vptr, float value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
isNull = variant->isNull();
*vptr = new QVariant(value);
}
void dos_qvariant_delete(void *vptr)
void dos_qvariant_create_double(void** vptr, double value)
{
*vptr = new QVariant(value);
}
void dos_qvariant_create_qabstractlistmodel(void** vptr, void* value)
{
auto qobject = reinterpret_cast<QObject*>(value);
auto variant = new QVariant();
variant->setValue<QObject*>(qobject);
*vptr = variant;
}
void dos_qvariant_isnull(void* vptr, bool* isNull)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
*isNull = variant->isNull();
}
void dos_qvariant_delete(void* vptr)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
delete variant;
}
void dos_qvariant_toInt(void* vptr, int& value)
void dos_qvariant_assign(void* vptr, void* other)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
value = variant->toInt();
auto leftQVariant = reinterpret_cast<QVariant*>(vptr);
auto rightQVariant = reinterpret_cast<QVariant*>(other);
*leftQVariant = *rightQVariant;
}
void dos_qvariant_toBool(void* vptr, bool& value)
void dos_qvariant_toInt(void* vptr, int* value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
value = variant->toBool();
*value = variant->toInt();
}
void dos_qvariant_toString(void* vptr, CharPtr& ptr, int& size)
void dos_qvariant_toBool(void* vptr, bool* value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
*value = variant->toBool();
}
void dos_qvariant_toFloat(void* vptr, float* value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
*value = variant->toFloat();
}
void dos_qvariant_toDouble(void* vptr, double* value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
*value = variant->toDouble();
}
void dos_qvariant_toString(void* vptr, char** ptr, int* size)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
convert_to_cstring(variant->toString(), ptr, size);
@ -196,24 +275,50 @@ void dos_qvariant_setBool(void* vptr, bool value)
*variant = value;
}
void dos_qvariant_setFloat(void* vptr, float value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
*variant = value;
}
void dos_qvariant_setDouble(void* vptr, double value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
*variant = value;
}
void dos_qvariant_setString(void* vptr, const char* value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
*variant = value;
}
void dos_qvariant_setQObject(void* vptr, void* value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
auto qobject = reinterpret_cast<QObject*>(value);
variant->setValue<QObject*>(qobject);
}
void dos_qvariant_setQAbstractListModel(void* vptr, void* value)
{
auto variant = reinterpret_cast<QVariant*>(vptr);
auto qobject = reinterpret_cast<QObject*>(value);
variant->setValue<QObject*>(qobject);
}
void dos_qobject_create(void** vptr, void* dObjectPointer, DObjectCallback dObjectCallback)
{
auto dynamicQObject = new DynamicQObject();
auto dynamicQObject = new BaseQObject();
QQmlEngine::setObjectOwnership(dynamicQObject, QQmlEngine::CppOwnership);
dynamicQObject->setDObjectPointer(dObjectPointer);
dynamicQObject->setDObjectCallback(dObjectCallback);
*vptr = dynamicQObject;
}
void dos_qobject_delete(void *vptr)
void dos_qobject_delete(void* vptr)
{
auto dynamicQObject = reinterpret_cast<DynamicQObject*>(vptr);
auto dynamicQObject = reinterpret_cast<BaseQObject*>(vptr);
dynamicQObject->disconnect();
delete dynamicQObject;
}
@ -223,7 +328,8 @@ void dos_qobject_slot_create(void* vptr, const char* name, int parametersCount,
if (parametersCount <= 0)
return;
auto dynamicQObject = reinterpret_cast<DynamicQObject*>(vptr);
auto qobject = reinterpret_cast<QObject*>(vptr);
auto dynamicQObject = dynamic_cast<IDynamicQObject*>(qobject);
QMetaType::Type returnType = static_cast<QMetaType::Type>(parametersMetaTypes[0]);
QList<QMetaType::Type> argumentsTypes;
@ -238,7 +344,8 @@ void dos_qobject_signal_create(void* vptr, const char* name, int parametersCount
if (parametersCount <= 0)
return;
auto dynamicQObject = reinterpret_cast<DynamicQObject*>(vptr);
auto qobject = reinterpret_cast<QObject*>(vptr);
auto dynamicQObject = dynamic_cast<IDynamicQObject*>(qobject);
QList<QMetaType::Type> argumentsTypes;
for (int i = 0; i < parametersCount; ++i)
@ -249,14 +356,16 @@ void dos_qobject_signal_create(void* vptr, const char* name, int parametersCount
void dos_qobject_signal_emit(void* vptr, const char* name, int parametersCount, void** parameters)
{
auto dynamicQObject = reinterpret_cast<DynamicQObject*>(vptr);
auto qobject = reinterpret_cast<QObject*>(vptr);
auto dynamicQObject = dynamic_cast<IDynamicQObject*>(qobject);
QVariantList arguments;
for (int i = 0; i < parametersCount; ++i)
arguments << *(reinterpret_cast<QVariant*>(parameters[i]));
dynamicQObject->emitSignal(QString::fromStdString(name), arguments);
}
void dos_qobject_property_create(void* vptr,
const char* name,
int type,
@ -264,10 +373,175 @@ void dos_qobject_property_create(void* vptr,
const char* writeSlot,
const char* notifySignal)
{
auto dynamicQObject = reinterpret_cast<DynamicQObject*>(vptr);
auto qobject = reinterpret_cast<QObject*>(vptr);
auto dynamicQObject = dynamic_cast<IDynamicQObject*>(qobject);
dynamicQObject->registerProperty(QString(name),
QMetaType::Type(type),
QString(readSlot),
QString(writeSlot),
QString(notifySignal));
}
void dos_qmodelindex_create(void** vptr)
{
auto index = new QModelIndex();
*vptr = index;
}
void dos_qmodelindex_delete(void* vptr)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
delete index;
}
void dos_qmodelindex_row(void* vptr, int* row)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
*row = index->row();
}
void dos_qmodelindex_column(void* vptr, int* column)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
*column = index->column();
}
void dos_qmodelindex_isValid(void* vptr, bool* isValid)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
*isValid = index->isValid();
}
void dos_qmodelindex_data(void* vptr, int role, void* data)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
auto result = reinterpret_cast<QVariant*>(data);
*result = index->data(role);
}
void dos_qmodelindex_parent(void* vptr, void* parent)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
auto parentIndex = reinterpret_cast<QModelIndex*>(parent);
*parentIndex = index->parent();
}
void dos_qmodelindex_child(void* vptr, int row, int column, void* child)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
auto childIndex = reinterpret_cast<QModelIndex*>(child);
*childIndex = index->child(row, column);
}
void dos_qmodelindex_sibling(void* vptr, int row, int column, void* sibling)
{
auto index = reinterpret_cast<QModelIndex*>(vptr);
auto siblingIndex = reinterpret_cast<QModelIndex*>(sibling);
*siblingIndex = index->sibling(row, column);
}
void dos_qabstractlistmodel_create(void** vptr,
void* modelObject,
DObjectCallback dObjectCallback,
RowCountCallback rowCountCallback,
ColumnCountCallback columnCountCallback,
DataCallback dataCallback,
SetDataCallback setDataCallback,
RoleNamesCallback roleNamesCallaback,
FlagsCallback flagsCallback,
HeaderDataCallback headerDataCallback)
{
auto model = new BaseQAbstractListModel(modelObject,
rowCountCallback,
columnCountCallback,
dataCallback,
setDataCallback,
roleNamesCallaback,
flagsCallback,
headerDataCallback);
model->setDObjectPointer(modelObject);
model->setDObjectCallback(dObjectCallback);
*vptr = model;
}
void dos_qabstractlistmodel_delete(void* vptr)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
delete model;
}
void dos_qabstractlistmodel_beginInsertRows(void* vptr, QModelIndexVoidPtr parentIndex, int first, int last)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
auto index = reinterpret_cast<QModelIndex*>(parentIndex);
model->publicBeginInsertRows(*index, first, last);
}
void dos_qabstractlistmodel_endInsertRows(void* vptr)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
model->publicEndInsertRows();
}
void dos_qabstractlistmodel_beginRemoveRows(void* vptr, QModelIndexVoidPtr parentIndex, int first, int last)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
auto index = reinterpret_cast<QModelIndex*>(parentIndex);
model->publicBeginRemoveRows(*index, first, last);
}
void dos_qabstractlistmodel_endRemoveRows(void* vptr)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
model->publicEndRemoveRows();
}
void dos_qabstractlistmodel_beginResetModel(void* vptr)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
model->publicBeginResetModel();
}
void dos_qabstractlistmodel_endResetModel(void* vptr)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
model->publicEndResetModel();
}
void dos_qabstractlistmodel_dataChanged(void* vptr,
QModelIndexVoidPtr topLeftIndex,
QModelIndexVoidPtr bottomRightIndex,
int* rolesArrayPtr,
int rolesArrayLength)
{
auto model = reinterpret_cast<BaseQAbstractListModel*>(vptr);
auto topLeft = reinterpret_cast<QModelIndex*>(topLeftIndex);
auto bottomRight = reinterpret_cast<QModelIndex*>(bottomRightIndex);
auto roles = QVector<int>::fromStdVector(std::vector<int>(rolesArrayPtr, rolesArrayPtr + rolesArrayLength));
model->publicDataChanged(*topLeft, *bottomRight, roles);
}
void dos_qhash_int_qbytearray_create(QHashIntQByteArrayVoidPtr* vptr)
{
*vptr = new QHash<int, QByteArray>();
}
void dos_qhash_int_qbytearray_delete(QHashIntQByteArrayVoidPtr vptr)
{
auto qHash = reinterpret_cast<QHash<int, QByteArray>*>(vptr);
delete qHash;
}
void dos_qhash_int_qbytearray_insert(QHashIntQByteArrayVoidPtr vptr, int key, const char* value)
{
auto qHash = reinterpret_cast<QHash<int, QByteArray>*>(vptr);
qHash->insert(key, QByteArray(value));
}
void dos_qhash_int_qbytearray_value(QHashIntQByteArrayVoidPtr vptr, int key, char** result)
{
auto qHash = reinterpret_cast<QHash<int, QByteArray>*>(vptr);
QByteArray value = qHash->value(key);
*result = qstrdup(value.data());
}

View File

@ -1,86 +1,154 @@
#ifndef DOTHERSIDE_H
#define DOTHERSIDE_H
#include "DOtherSideTypes.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef char* CharPtr;
typedef void(*Function)(void*);
typedef void(*DObjectCallback)(void*, void*, int, void**);
typedef char* CharPtr;
typedef void(*Function)(void*);
typedef void(*DObjectCallback)(void*, void*, int, void**);
// QGuiApplication
void dos_qguiapplication_create();
void dos_qguiapplication_exec();
void dos_qguiapplication_delete();
// QGuiApplication
void dos_qguiapplication_create();
void dos_qguiapplication_exec();
void dos_qguiapplication_quit();
void dos_qguiapplication_delete();
/// QQmlApplicationEngine
void dos_qqmlapplicationengine_create(void** vptr);
void dos_qqmlapplicationengine_load(void* vptr, const char* filename);
void dos_qqmlapplicationengine_context(void* vptr, void** context);
void dos_qqmlapplicationengine_delete(void* vptr);
// QApplication
void dos_qapplication_create();
void dos_qapplication_exec();
void dos_qapplication_quit();
void dos_qapplication_delete();
// QQuickView
void dos_qquickview_create(void** vptr);
void dos_qquickview_show(void* vptr);
void dos_qquickview_source(void* vptr, CharPtr& result, int& length);
void dos_qquickview_set_source(void* vptr, const char* filename);
void dos_qquickview_delete(void* vptr);
void dos_qquickview_rootContext(void* vptr, void** context);
// QQmlApplicationEngine
void dos_qqmlapplicationengine_create(void** vptr);
void dos_qqmlapplicationengine_load(void* vptr, const char* filename);
void dos_qqmlapplicationengine_context(void* vptr, void** context);
void dos_qqmlapplicationengine_delete(void* vptr);
// QQmlContext
void dos_qqmlcontext_baseUrl(void* vptr, CharPtr& result, int& length);
void dos_qqmlcontext_setcontextproperty(void* vptr, const char* name, void* value);
// QQuickView
void dos_qquickview_create(void** vptr);
void dos_qquickview_show(void* vptr);
void dos_qquickview_source(void* vptr, char** result, int* length);
void dos_qquickview_set_source(void* vptr, const char* filename);
void dos_qquickview_delete(void* vptr);
void dos_qquickview_rootContext(void* vptr, void** context);
// CharArray
void dos_chararray_create(CharPtr& ptr, int size);
void dos_chararray_delete(CharPtr ptr);
// QQmlContext
void dos_qqmlcontext_baseUrl(void* vptr, char** result, int* length);
void dos_qqmlcontext_setcontextproperty(void* vptr, const char* name, void* value);
// QVariant
void dos_qvariant_create(void **vptr);
void dos_qvariant_create_int(void **vptr, int value);
void dos_qvariant_create_bool(void **vptr, bool value);
void dos_qvariant_create_string(void **vptr, const char* value);
void dos_qvariant_create_qobject(void **vptr, void* value);
void dos_qvariant_toInt(void* vptr, int& value);
void dos_qvariant_setInt(void* vptr, int value);
void dos_qvariant_toBool(void* vptr, bool& value);
void dos_qvariant_setBool(void* vptr, bool value);
void dos_qvariant_toString(void* vptr, CharPtr& ptr, int& size);
void dos_qvariant_setString(void* vptr, const char* value);
void dos_qvariant_isnull(void *vptr, bool& isNull);
void dos_qvariant_delete(void *vptr);
// CharArray
void dos_chararray_create(char** ptr, int size);
void dos_chararray_delete(char* ptr);
// QObject
void dos_qobject_create(void **vptr,
void *dObjectPointer,
DObjectCallback dObjectCallback);
// QVariant
void dos_qvariant_create(void** vptr);
void dos_qvariant_create_int(void** vptr, int value);
void dos_qvariant_create_bool(void** vptr, bool value);
void dos_qvariant_create_string(void** vptr, const char* value);
void dos_qvariant_create_qobject(void** vptr, void* value);
void dos_qvariant_create_qvariant(void** vptr, void* value);
void dos_qvariant_create_float(void** vptr, float value);
void dos_qvariant_create_double(void** vptr, double value);
void dos_qvariant_create_qabstractlistmodel(void** vptr, void* value);
void dos_qvariant_toInt(void* vptr, int* value);
void dos_qvariant_setInt(void* vptr, int value);
void dos_qvariant_toBool(void* vptr, bool* value);
void dos_qvariant_setBool(void* vptr, bool value);
void dos_qvariant_toFloat(void* vptr, float* value);
void dos_qvariant_setFloat(void* vptr, float value);
void dos_qvariant_toDouble(void* vptr, double* value);
void dos_qvariant_setDouble(void* vptr, double value);
void dos_qvariant_toString(void* vptr, char** ptr, int* size);
void dos_qvariant_setString(void* vptr, const char* value);
void dos_qvariant_setQObject(void* vptr, void* value);
void dos_qvariant_setQAbstractListModel(void* vptr, void* value);
void dos_qvariant_isnull(void* vptr, bool* isNull);
void dos_qvariant_delete(void* vptr);
void dos_qvariant_assign(void* vptr, void* other);
void dos_qobject_slot_create(void* vptr,
const char* name,
int parametersCount,
int* parametersMetaTypes,
int* slotIndex);
// QObject
void dos_qobject_create(void** vptr,
void* dObjectPointer,
DObjectCallback dObjectCallback);
void dos_qobject_signal_create(void* vptr,
const char* name,
int parametersCount,
int* parametersMetaTypes,
int* signalIndex);
void dos_qobject_slot_create(void* vptr,
const char* name,
int parametersCount,
int* parametersMetaTypes,
int* slotIndex);
void dos_qobject_signal_emit(void* vptr,
const char* name,
int parametersCount,
void** parameters);
void dos_qobject_signal_create(void* vptr,
const char* name,
int parametersCount,
int* parametersMetaTypes,
int* signalIndex);
void dos_qobject_property_create(void* vptr,
const char* name,
int propertyMetaType,
const char* readSlot,
const char* writeSlot,
const char* notifySignal);
void dos_qobject_delete(void *vptr);
void dos_qobject_signal_emit(void* vptr,
const char* name,
int parametersCount,
void** parameters);
void dos_qobject_property_create(void* vptr,
const char* name,
int propertyMetaType,
const char* readSlot,
const char* writeSlot,
const char* notifySignal);
void dos_qobject_delete(void* vptr);
// QModelIndex
void dos_qmodelindex_create(void** vptr);
void dos_qmodelindex_delete(void* vptr);
void dos_qmodelindex_row(void* vptr, int* row);
void dos_qmodelindex_column(void* vptr, int* column);
void dos_qmodelindex_isValid(void* vptr, bool* isValid);
void dos_qmodelindex_data(void* vptr, int role, void* data);
void dos_qmodelindex_parent(void* vptr, void* parent);
void dos_qmodelindex_child(void* vptr, int row, int column, void* child);
void dos_qmodelindex_sibling(void* vptr, int row, int column, void* sibling);
// QHash<int, QByteArray>
void dos_qhash_int_qbytearray_create(QHashIntQByteArrayVoidPtr* vptr);
void dos_qhash_int_qbytearray_delete(QHashIntQByteArrayVoidPtr vptr);
void dos_qhash_int_qbytearray_insert(QHashIntQByteArrayVoidPtr vptr, int key, const char* value);
void dos_qhash_int_qbytearray_value(QHashIntQByteArrayVoidPtr vptr, int key, char** result);
// QAbstractListModel
void dos_qabstractlistmodel_create(void** vptr,
void* callbackObject,
DObjectCallback dObjectCallback,
RowCountCallback rowCountCallback,
ColumnCountCallback columnCountCallback,
DataCallback dataCallback,
SetDataCallback setDataCallback,
RoleNamesCallback roleNamesCallback,
FlagsCallback flagsCallback,
HeaderDataCallback headerDataCallback);
void dos_qabstractlistmodel_beginInsertRows(void* vptr,
QModelIndexVoidPtr parentIndex,
int first,
int last);
void dos_qabstractlistmodel_endInsertRows(void* vptr);
void dos_qabstractlistmodel_beginRemoveRows(void* vptr,
QModelIndexVoidPtr parentIndex,
int first,
int last);
void dos_qabstractlistmodel_endRemoveRows(void* vptr);
void dos_qabstractlistmodel_beginResetModel(void* vptr);
void dos_qabstractlistmodel_endResetModel(void* vptr);
void dos_qabstractlistmodel_dataChanged(void* vptr,
QModelIndexVoidPtr topLeftIndex,
QModelIndexVoidPtr bottomRightIndex,
int* rolesArrayPtr,
int rolesArrayLength);
void dos_qabstractlistmodel_delete(void* vptr);
#ifdef __cplusplus
}

View File

@ -0,0 +1,27 @@
#ifndef DOTHERSIDETYPES_H
#define DOTHERSIDETYPES_H
// Raw data types
typedef bool* BoolPtr;
typedef int* IntPtr;
typedef char* CharPtr;
typedef const char* ConstCharPtr;
typedef void* QVariantVoidPtr;
typedef void* QModelIndexVoidPtr;
typedef void* QAbstractListModelVoidPtr;
typedef void* QQmlApplicationEngineVoidPtr;
typedef void* QQuickViewVoidPtr;
typedef void* QQmlContextVoidPtr;
typedef void* QHashIntQByteArrayVoidPtr;
// Raw function types
typedef void (*Function)(void*);
typedef void (*DObjectCallback)(void*, void*, int, void**);
typedef void (*RowCountCallback)(void* model, QModelIndexVoidPtr index, IntPtr result);
typedef void (*ColumnCountCallback)(void* model, QModelIndexVoidPtr index, IntPtr result);
typedef void (*DataCallback)(void* model, QModelIndexVoidPtr index, int role, QVariantVoidPtr result);
typedef void (*SetDataCallback) (void* model, QModelIndexVoidPtr index, QVariantVoidPtr value, int role, BoolPtr result);
typedef void (*RoleNamesCallback)(void* model, QHashIntQByteArrayVoidPtr result);
typedef void (*FlagsCallback) (void* model, QModelIndexVoidPtr index, IntPtr result);
typedef void (*HeaderDataCallback) (void* model, int section, int orientation, int role, QVariantVoidPtr result);
#endif

View File

@ -15,7 +15,6 @@ set(HEADERS_LIST
set(SRC_LIST
DynamicProperty.cpp
DynamicQObject.cpp
DynamicSignal.cpp
DynamicSlot.cpp
)

View File

@ -1,119 +0,0 @@
#include "DynamicProperty.h"
#include <QtCore/QString>
struct PropertyData
{
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;
}

View File

@ -1,10 +1,10 @@
#pragma once
#ifndef DYNAMICPROPERTY_H
#define DYNAMICPROPERTY_H
#include <memory>
#include <QtCore/QString>
#include <QtCore/QMetaType>
#include <memory>
class QString;
class PropertyData;
class DynamicProperty
@ -23,7 +23,9 @@ public:
QString name() const;
QMetaType::Type type() const;
bool isValid() const { return d != nullptr; }
bool isValid() const {
return d != nullptr;
}
bool isReadable() const;
bool isWriteable() const;
@ -36,3 +38,115 @@ public:
private:
std::unique_ptr<PropertyData> d;
};
struct PropertyData
{
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;
}
#endif

View File

@ -1,345 +0,0 @@
#include "DynamicQObject.h"
#include <QDebug>
#include <memory>
#include <array>
#include "private/qmetaobjectbuilder_p.h"
DynamicQObject::DynamicQObject()
: m_dObjectPointer(nullptr)
, m_dObjectCallback(nullptr)
{
QMetaObjectBuilder builder;
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
builder.setClassName("DynamicQObject");
builder.setSuperClass(&QObject::staticMetaObject);
m_metaObject.reset(builder.toMetaObject());
}
DynamicQObject::~DynamicQObject() = default;
bool DynamicQObject::registerSlot(const QString& name,
const QMetaType::Type returnType,
const QList<QMetaType::Type>& argumentsTypes,
int& slotIndex)
{
DynamicSlot slot (name, returnType, argumentsTypes);
if (m_slotsBySignature.contains(slot.signature()))
return false;
m_slotsByName.insertMulti(slot.name(), slot);
m_slotsBySignature[slot.signature()] = slot;
auto afterSignalAdded = [](QMetaObjectBuilder&) {};
auto afterPropertyAdded = afterSignalAdded;
auto afterSlotAdded = [&slot, returnType](QMetaObjectBuilder& metaObjectBuilder) {
QMetaMethodBuilder methodBuilder = metaObjectBuilder.addSlot(slot.signature());
methodBuilder.setReturnType(QMetaType::typeName(returnType));
methodBuilder.setAttributes(QMetaMethod::Scriptable);
};
auto newMetaObject = recreateMetaObjectBuilder(m_metaObject.data()
, afterSignalAdded
, afterSlotAdded
, afterPropertyAdded);
m_metaObject.reset(newMetaObject);
slotIndex = m_metaObject->indexOfSlot(QMetaObject::normalizedSignature(slot.signature()));
return slotIndex != -1;
}
bool DynamicQObject::registerSignal(const QString& name, const QList<QMetaType::Type>& arguments, int& signalIndex)
{
DynamicSignal signal(name, arguments);
if (m_signalsBySignature.contains(signal.signature()))
return false;
m_signalsByName.insertMulti(signal.name(), signal);
m_signalsBySignature[signal.signature()] = signal;
auto afterSignalAdded = [&signal](QMetaObjectBuilder& metaObjectBuilder) {
QMetaMethodBuilder methodBuilder = metaObjectBuilder.addSignal(signal.signature());
methodBuilder.setReturnType(QMetaType::typeName(QMetaType::Void));
methodBuilder.setAccess(QMetaMethod::Public);
};
auto afterSlotAdded = [](QMetaObjectBuilder&) { };
auto afterPropertyAdded = afterSlotAdded;
auto newMetaObject = recreateMetaObjectBuilder(m_metaObject.data()
, afterSignalAdded
, afterSlotAdded
, afterPropertyAdded);
m_metaObject.reset(newMetaObject);
signalIndex = m_metaObject->indexOfSignal(QMetaObject::normalizedSignature(signal.signature()));
return signalIndex != -1;
}
bool DynamicQObject::registerProperty(const QString& name,
QMetaType::Type type,
const QString& readSlotName,
const QString& writeSlotName,
const QString& notifySignalName)
{
DynamicProperty property(name, type, readSlotName, writeSlotName, notifySignalName);
DynamicSignal notifySignal;
if (!notifySignalName.isEmpty())
{
notifySignal = m_signalsByName.value(notifySignalName, DynamicSignal());
if (!notifySignal.isValid())
return false;
}
m_propertiesByName.insert(name.toUtf8(), property);
auto afterSignalAdded = [](QMetaObjectBuilder& metaObjectBuilder) {};
auto afterSlotAdded = [](QMetaObjectBuilder& metaObjectBuilder) {};
auto afterPropertyAdded = [name, type, notifySignal](QMetaObjectBuilder& metaObjectBuilder)
{
int signalIndex = -1;
if (notifySignal.isValid())
{
for (int i = 0; i < metaObjectBuilder.methodCount(); ++i)
{
QMetaMethodBuilder methodBuilder = metaObjectBuilder.method(i);
if (methodBuilder.methodType() == QMetaMethod::Signal)
{
if (methodBuilder.signature() == QMetaObject::normalizedSignature(notifySignal.signature()));
{
signalIndex = i;
break;
}
}
}
}
auto typeName = QMetaType::typeName(type);
auto builder = metaObjectBuilder.addProperty(name.toUtf8(),
QMetaObject::normalizedType(typeName),
signalIndex);
};
auto newMetaObject = recreateMetaObjectBuilder(m_metaObject.data()
, afterSignalAdded
, afterSlotAdded
, afterPropertyAdded);
m_metaObject.reset(newMetaObject);
return true;
}
bool DynamicQObject::emitSignal(const QString& name, const QList<QVariant>& args)
{
DynamicSignal signal;
for (DynamicSignal currentSignal : m_signalsByName.values(name))
{
if (currentSignal.validate(args))
{
signal = currentSignal;
break;
}
}
if (!signal.isValid())
return false;
int index = m_metaObject->indexOfSignal(QMetaObject::normalizedSignature(signal.signature()));
if (index < 0)
return false;
QVariantList argsCopy = args;
QVector<void*> arguments(argsCopy.size() + 1 ,0);
arguments[0] = 0;
for (int i = 0; i < argsCopy.size(); ++i)
arguments[i + 1] = &argsCopy[i];
QMetaObject::activate(this, index, arguments.data());
return true;
}
const QMetaObject* DynamicQObject::metaObject() const
{
return m_metaObject.data();
}
bool DynamicQObject::executeSlot(const DynamicSlot& slot, void** args)
{
if (!slot.isValid())
return false;
QList<QVariant> arguments;
for (int i = 0; i < slot.argumentsTypes().count(); ++i)
arguments << QVariant(slot.argumentTypeAt(i), args[i+1]);
QVariant result = executeSlot(slot, arguments);
if (slot.returnType() != QMetaType::Void && result.isValid())
{
QMetaType metatype(slot.returnType());
metatype.construct(args[0], result.constData());
}
return true;
}
QVariant DynamicQObject::executeSlot(const DynamicSlot& slot, const QList<QVariant>& args)
{
QVariant slotName(slot.name());
const int numParametersPlusReturn = slot.argumentsTypes().count() + 1;
std::vector<QVariant> argumentsAsVariants(numParametersPlusReturn);
std::vector<void*> argumentsAsVoidPointers(numParametersPlusReturn);
for (int i = 0; i < numParametersPlusReturn; ++i) {
argumentsAsVariants[i] = i == 0 ? QVariant() : args[i-1];
argumentsAsVoidPointers[i] = &argumentsAsVariants[i];
}
if (m_dObjectCallback && m_dObjectPointer)
m_dObjectCallback(m_dObjectPointer, &slotName, numParametersPlusReturn, &argumentsAsVoidPointers[0]);
return argumentsAsVariants[0];
}
bool DynamicQObject::readProperty(const DynamicProperty& property, void** args)
{
if (!property.isValid())
return false;
if (!property.isReadable())
return false;
DynamicSlot readSlot = m_slotsByName.value(property.readSlot(), DynamicSlot());
if (!readSlot.isValid())
return false;
if (readSlot.argumentsTypes().count() > 0)
return false;
if (readSlot.returnType() != property.type())
return false;
return executeSlot(readSlot, args);
}
bool DynamicQObject::writeProperty(const DynamicProperty& property, void** args)
{
if (!property.isValid())
return false;
if (!property.isWriteable())
return false;
DynamicSlot writeSlot = m_slotsByName.value(property.writeSlot(), DynamicSlot());
if (!writeSlot.isValid())
return false;
if (writeSlot.argumentsTypes().count() != 1)
return false;
if (writeSlot.returnType() != QMetaType::Void)
return false;
QVariant newValue (writeSlot.argumentTypeAt(0), args[0]);
executeSlot(writeSlot, {newValue});
}
int DynamicQObject::qt_metacall(QMetaObject::Call callType, int index, void** args)
{
if (callType == QMetaObject::InvokeMetaMethod)
{
QMetaMethod method = m_metaObject->method(index);
if (!method.isValid())
return -1;
DynamicSlot slot = m_slotsBySignature[method.methodSignature()];
return executeSlot(slot, args) ? 1 : -1;
}
else if (callType == QMetaObject::ReadProperty)
{
QMetaProperty metaProperty = m_metaObject->property(index);
if (!metaProperty.isValid())
return -1;
DynamicProperty dynamicProperty = m_propertiesByName.value(metaProperty.name(), DynamicProperty());
return readProperty(dynamicProperty, args) ? 1 : -1;
}
else if (callType == QMetaObject::WriteProperty)
{
QMetaProperty metaProperty = m_metaObject->property(index);
if (!metaProperty.isValid())
return -1;
DynamicProperty dynamicProperty = m_propertiesByName.value(metaProperty.name(), DynamicProperty());
return writeProperty(dynamicProperty, args) ? 1 : -1;
}
return -1;
}
QMetaObject* DynamicQObject::recreateMetaObjectBuilder(QMetaObject* currentMetaObject,
const std::function<void(QMetaObjectBuilder&)>& afterSignalAdded,
const std::function<void(QMetaObjectBuilder&)>& afterSlotAdded,
const std::function<void(QMetaObjectBuilder&)>& afterPropertyAdded)
{
// Collect the current methods and signals
QList<QMetaMethod> signalsList;
QList<QMetaMethod> methodsList;
QList<QMetaProperty> propertiesList;
for (int i = currentMetaObject->methodOffset(); i < currentMetaObject->methodCount(); ++i)
{
QMetaMethod method = currentMetaObject->method(i);
if (method.methodType() == QMetaMethod::Signal)
signalsList.append(method);
else
methodsList.append(method);
}
for (int i = currentMetaObject->propertyOffset(); i < currentMetaObject->propertyCount(); ++i)
{
QMetaProperty property = currentMetaObject->property(i);
propertiesList.append(property);
}
QMetaObjectBuilder metaObjectBuilder;
metaObjectBuilder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
metaObjectBuilder.setClassName(currentMetaObject->className());
metaObjectBuilder.setSuperClass(currentMetaObject->superClass());
foreach(auto& method, signalsList)
metaObjectBuilder.addMethod(method);
// Call custom code to be executed after signal have been added
afterSignalAdded(metaObjectBuilder);
foreach (auto& method, methodsList)
metaObjectBuilder.addMethod(method);
// Call custom code to be executed after slots have been added
afterSlotAdded(metaObjectBuilder);
foreach (auto& property, propertiesList)
metaObjectBuilder.addProperty(property);
afterPropertyAdded(metaObjectBuilder);
return metaObjectBuilder.toMetaObject();
}

View File

@ -1,19 +1,22 @@
#pragma once
#ifndef DYNAMICQOBJECT_H
#define DYNAMICQOBJECT_H
#include <QObject>
#include <QScopedPointer>
#include <memory>
#include <array>
#include <QtCore/QObject>
#include <QtCore/QScopedPointer>
#include <QtCore/QDebug>
#include "private/qmetaobjectbuilder_p.h"
#include "DynamicSignal.h"
#include "DynamicSlot.h"
#include "DynamicProperty.h"
class QMetaObjectBuilder;
#include "IDynamicQObject.h"
/// This class implements a QObject to which signals, slots and properties can be added dynamically
class DynamicQObject : public QObject
template <class T>
class DynamicQObject : public T, public IDynamicQObject
{
typedef void (*Callback)(void*, void*, int, void **);
public:
/// Constructor
DynamicQObject();
@ -22,37 +25,37 @@ public:
virtual ~DynamicQObject();
/// Sets the function to be called from C++ to D or Nimrod
void setDObjectCallback(Callback callback) { m_dObjectCallback = callback; }
virtual void setDObjectCallback(IDynamicQObject::Callback callback) override;
/// Sets the D or Nimrod object that owns this DynamicQObject
void setDObjectPointer(void* dObjectPointer) { m_dObjectPointer = dObjectPointer; }
virtual void setDObjectPointer(void* dObjectPointer) override;
/// Register a new signal
bool registerSignal(const QString& name,
const QList<QMetaType::Type>& argumentsTypes,
int& signalIndex);
virtual bool registerSignal(const QString& name,
const QList<QMetaType::Type>& argumentsTypes,
int& signalIndex) override;
/// Register a new slot
bool registerSlot(const QString& name,
const QMetaType::Type returnType,
const QList<QMetaType::Type>& argumentsTypes,
int& slotIndex);
virtual bool registerSlot(const QString& name,
const QMetaType::Type returnType,
const QList<QMetaType::Type>& argumentsTypes,
int& slotIndex) override;
/// Register a new property
bool registerProperty(const QString& name,
QMetaType::Type type,
const QString& readSlotName,
const QString& writeSlotName = "",
const QString& notifySignalName = "");
virtual bool registerProperty(const QString& name,
QMetaType::Type type,
const QString& readSlotName,
const QString& writeSlotName = "",
const QString& notifySignalName = "") override;
/// Emit the signal with the given name and arguments
bool emitSignal(const QString& name, const QList<QVariant>& argumentsValues);
virtual bool emitSignal(const QString& name, const QList<QVariant>& argumentsValues) override;
/// Return the QMetaObject for this DynamicQObject
virtual const QMetaObject *metaObject() const;
virtual const QMetaObject* metaObject() const;
/// The qt metacall. Called from Qt when a signals, slot or property is invoked
int qt_metacall(QMetaObject::Call, int, void **);
int qt_metacall(QMetaObject::Call, int, void**);
private:
bool executeSlot(const DynamicSlot& slot, void** args);
@ -67,9 +70,9 @@ private:
/// The creation is customizable by injecting custom code after signals and slots have
/// been added
static QMetaObject* recreateMetaObjectBuilder(QMetaObject* currentMetaObject,
const std::function<void(QMetaObjectBuilder&)>& afterSignalAdded,
const std::function<void(QMetaObjectBuilder&)>& afterSlotAdded,
const std::function<void(QMetaObjectBuilder&)>& afterPropertyAdded);
const std::function<void(QMetaObjectBuilder&)>& afterSignalAdded,
const std::function<void(QMetaObjectBuilder&)>& afterSlotAdded,
const std::function<void(QMetaObjectBuilder&)>& afterPropertyAdded);
QHash<QString, DynamicSignal> m_signalsByName;
QHash<QByteArray, DynamicSignal> m_signalsBySignature;
@ -78,5 +81,380 @@ private:
QHash<QByteArray, DynamicProperty> m_propertiesByName;
QScopedPointer<QMetaObject> m_metaObject;
void* m_dObjectPointer;
Callback m_dObjectCallback;
IDynamicQObject::Callback m_dObjectCallback;
};
template <typename T>
DynamicQObject<T>::DynamicQObject()
: T()
, m_dObjectPointer(nullptr)
, m_dObjectCallback(nullptr)
{
QMetaObjectBuilder builder;
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
builder.setClassName("DynamicQObject");
builder.setSuperClass(&T::staticMetaObject);
m_metaObject.reset(builder.toMetaObject());
}
template <typename T>
void DynamicQObject<T>::setDObjectCallback(IDynamicQObject::Callback callback)
{
m_dObjectCallback = callback;
}
template <typename T>
void DynamicQObject<T>::setDObjectPointer(void* dObjectPointer)
{
m_dObjectPointer = dObjectPointer;
}
template <typename T>
DynamicQObject<T>::~DynamicQObject() = default;
template <typename T>
bool DynamicQObject<T>::registerSlot(const QString& name,
const QMetaType::Type returnType,
const QList<QMetaType::Type>& argumentsTypes,
int& slotIndex)
{
DynamicSlot slot(name, returnType, argumentsTypes);
if (m_slotsBySignature.contains(slot.signature()))
return false;
m_slotsByName.insertMulti(slot.name(), slot);
m_slotsBySignature[slot.signature()] = slot;
auto afterSignalAdded = [](QMetaObjectBuilder&) {};
auto afterPropertyAdded = afterSignalAdded;
auto afterSlotAdded = [&slot, returnType](QMetaObjectBuilder & metaObjectBuilder) {
QMetaMethodBuilder methodBuilder = metaObjectBuilder.addSlot(slot.signature());
methodBuilder.setReturnType(QMetaType::typeName(returnType));
methodBuilder.setAttributes(QMetaMethod::Scriptable);
};
auto newMetaObject = recreateMetaObjectBuilder(m_metaObject.data(),
afterSignalAdded,
afterSlotAdded,
afterPropertyAdded);
m_metaObject.reset(newMetaObject);
slotIndex = m_metaObject->indexOfSlot(QMetaObject::normalizedSignature(slot.signature()));
return slotIndex != -1;
}
template <typename T>
bool DynamicQObject<T>::registerSignal(const QString& name, const QList<QMetaType::Type>& arguments, int& signalIndex)
{
DynamicSignal signal(name, arguments);
if (m_signalsBySignature.contains(signal.signature()))
return false;
m_signalsByName.insertMulti(signal.name(), signal);
m_signalsBySignature[signal.signature()] = signal;
auto afterSignalAdded = [&signal](QMetaObjectBuilder & metaObjectBuilder) {
QMetaMethodBuilder methodBuilder = metaObjectBuilder.addSignal(signal.signature());
methodBuilder.setReturnType(QMetaType::typeName(QMetaType::Void));
methodBuilder.setAccess(QMetaMethod::Public);
};
auto afterSlotAdded = [](QMetaObjectBuilder&) {};
auto afterPropertyAdded = afterSlotAdded;
auto newMetaObject = recreateMetaObjectBuilder(m_metaObject.data(),
afterSignalAdded,
afterSlotAdded,
afterPropertyAdded);
m_metaObject.reset(newMetaObject);
signalIndex = m_metaObject->indexOfSignal(QMetaObject::normalizedSignature(signal.signature()));
return signalIndex != -1;
}
template <typename T>
bool DynamicQObject<T>::registerProperty(const QString& name,
QMetaType::Type type,
const QString& readSlotName,
const QString& writeSlotName,
const QString& notifySignalName)
{
DynamicProperty property(name, type, readSlotName, writeSlotName, notifySignalName);
DynamicSignal notifySignal;
if (!notifySignalName.isEmpty())
{
notifySignal = m_signalsByName.value(notifySignalName, DynamicSignal());
if (!notifySignal.isValid())
return false;
}
m_propertiesByName.insert(name.toUtf8(), property);
auto afterSignalAdded = [](QMetaObjectBuilder & metaObjectBuilder) {};
auto afterSlotAdded = [](QMetaObjectBuilder & metaObjectBuilder) {};
auto afterPropertyAdded = [name, type, notifySignal](QMetaObjectBuilder & metaObjectBuilder)
{
int signalIndex = -1;
if (notifySignal.isValid())
{
for (int i = 0; i < metaObjectBuilder.methodCount(); ++i)
{
QMetaMethodBuilder methodBuilder = metaObjectBuilder.method(i);
if (methodBuilder.methodType() == QMetaMethod::Signal)
{
if (methodBuilder.signature() == QMetaObject::normalizedSignature(notifySignal.signature()));
{
signalIndex = i;
break;
}
}
}
}
auto typeName = QMetaType::typeName(type);
auto builder = metaObjectBuilder.addProperty(name.toUtf8(),
QMetaObject::normalizedType(typeName),
signalIndex);
if (signalIndex == -1)
builder.setConstant(true);
};
auto newMetaObject = recreateMetaObjectBuilder(m_metaObject.data()
, afterSignalAdded
, afterSlotAdded
, afterPropertyAdded);
m_metaObject.reset(newMetaObject);
return true;
}
template <typename T>
bool DynamicQObject<T>::emitSignal(const QString& name, const QList<QVariant>& args)
{
DynamicSignal signal;
for (DynamicSignal currentSignal : m_signalsByName.values(name))
{
if (currentSignal.validate(args))
{
signal = currentSignal;
break;
}
}
if (!signal.isValid())
return false;
int index = m_metaObject->indexOfSignal(QMetaObject::normalizedSignature(signal.signature()));
if (index < 0)
return false;
QVariantList argsCopy = args;
QVector<void*> arguments(argsCopy.size() + 1 , 0);
arguments[0] = 0;
for (int i = 0; i < argsCopy.size(); ++i)
arguments[i + 1] = &argsCopy[i];
QMetaObject::activate(this, index, arguments.data());
return true;
}
template <typename T>
const QMetaObject* DynamicQObject<T>::metaObject() const
{
return m_metaObject.data();
}
template <typename T>
bool DynamicQObject<T>::executeSlot(const DynamicSlot& slot, void** args)
{
if (!slot.isValid())
return false;
QList<QVariant> arguments;
for (int i = 0; i < slot.argumentsTypes().count(); ++i)
arguments << QVariant(slot.argumentTypeAt(i), args[i + 1]);
QVariant result = executeSlot(slot, arguments);
if (slot.returnType() != QMetaType::Void && result.isValid())
{
QMetaType metatype(slot.returnType());
metatype.construct(args[0], result.constData());
}
return true;
}
template <typename T>
QVariant DynamicQObject<T>::executeSlot(const DynamicSlot& slot, const QList<QVariant>& args)
{
QVariant slotName(slot.name());
const int numParametersPlusReturn = slot.argumentsTypes().count() + 1;
std::vector<QVariant> argumentsAsVariants(numParametersPlusReturn);
std::vector<void*> argumentsAsVoidPointers(numParametersPlusReturn);
for (int i = 0; i < numParametersPlusReturn; ++i) {
argumentsAsVariants[i] = i == 0 ? QVariant() : args[i - 1];
argumentsAsVoidPointers[i] = &argumentsAsVariants[i];
}
if (m_dObjectCallback && m_dObjectPointer)
m_dObjectCallback(m_dObjectPointer, &slotName, numParametersPlusReturn, &argumentsAsVoidPointers[0]);
return argumentsAsVariants[0];
}
template <typename T>
bool DynamicQObject<T>::readProperty(const DynamicProperty& property, void** args)
{
if (!property.isValid())
return false;
if (!property.isReadable())
return false;
DynamicSlot readSlot = m_slotsByName.value(property.readSlot(), DynamicSlot());
if (!readSlot.isValid())
return false;
if (readSlot.argumentsTypes().count() > 0)
return false;
if (readSlot.returnType() != property.type())
return false;
return executeSlot(readSlot, args);
}
template <typename T>
bool DynamicQObject<T>::writeProperty(const DynamicProperty& property, void** args)
{
if (!property.isValid())
return false;
if (!property.isWriteable())
return false;
DynamicSlot writeSlot = m_slotsByName.value(property.writeSlot(), DynamicSlot());
if (!writeSlot.isValid())
return false;
if (writeSlot.argumentsTypes().count() != 1)
return false;
if (writeSlot.returnType() != QMetaType::Void)
return false;
QVariant newValue(writeSlot.argumentTypeAt(0), args[0]);
executeSlot(writeSlot, {newValue});
}
template <typename T>
int DynamicQObject<T>::qt_metacall(QMetaObject::Call callType, int index, void** args)
{
switch (callType)
{
case QMetaObject::InvokeMetaMethod: {
QMetaMethod method = m_metaObject->method(index);
if (!method.isValid())
return -1;
DynamicSlot slot = m_slotsBySignature[method.methodSignature()];
return executeSlot(slot, args) ? 1 : -1;
}
case QMetaObject::ReadProperty: {
QMetaProperty metaProperty = m_metaObject->property(index);
if (!metaProperty.isValid())
return -1;
DynamicProperty dynamicProperty = m_propertiesByName.value(metaProperty.name(), DynamicProperty());
return readProperty(dynamicProperty, args) ? 1 : -1;
}
case QMetaObject::WriteProperty: {
QMetaProperty metaProperty = m_metaObject->property(index);
if (!metaProperty.isValid())
return -1;
DynamicProperty dynamicProperty = m_propertiesByName.value(metaProperty.name(), DynamicProperty());
return writeProperty(dynamicProperty, args) ? 1 : -1;
}
default:
return T::qt_metacall(callType, index, args);
}
return -1;
}
template <typename T>
QMetaObject* DynamicQObject<T>::recreateMetaObjectBuilder(QMetaObject* currentMetaObject,
const std::function<void(QMetaObjectBuilder&)>& afterSignalAdded,
const std::function<void(QMetaObjectBuilder&)>& afterSlotAdded,
const std::function<void(QMetaObjectBuilder&)>& afterPropertyAdded)
{
// Collect the current methods and signals
QList<QMetaMethod> signalsList;
QList<QMetaMethod> methodsList;
QList<QMetaProperty> propertiesList;
for (int i = currentMetaObject->methodOffset(); i < currentMetaObject->methodCount(); ++i)
{
QMetaMethod method = currentMetaObject->method(i);
if (method.methodType() == QMetaMethod::Signal)
signalsList.append(method);
else
methodsList.append(method);
}
for (int i = currentMetaObject->propertyOffset(); i < currentMetaObject->propertyCount(); ++i)
{
QMetaProperty property = currentMetaObject->property(i);
propertiesList.append(property);
}
QMetaObjectBuilder metaObjectBuilder;
metaObjectBuilder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
metaObjectBuilder.setClassName(currentMetaObject->className());
metaObjectBuilder.setSuperClass(currentMetaObject->superClass());
for (auto& method : signalsList)
metaObjectBuilder.addMethod(method);
// Call custom code to be executed after signal have been added
afterSignalAdded(metaObjectBuilder);
for (auto& method : methodsList)
metaObjectBuilder.addMethod(method);
// Call custom code to be executed after slots have been added
afterSlotAdded(metaObjectBuilder);
for (auto& property : propertiesList)
metaObjectBuilder.addProperty(property);
afterPropertyAdded(metaObjectBuilder);
return metaObjectBuilder.toMetaObject();
}
#endif

View File

@ -1,90 +0,0 @@
#include "DynamicSignal.h"
#include "DynamicQObject.h"
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)
{
return true;
}
bool DynamicSignal::validate(const QList<QMetaType::Type>& argumentsTypes, const QVariantList& argumentsValues)
{
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();
}

View File

@ -1,10 +1,14 @@
#pragma once
#ifndef DYNAMICSIGNAL_H
#define DYNAMICSIGNAL_H
#include <QtCore/QMetaType>
#include <memory>
#include <QtCore/QMetaType>
#include <QtCore/QString>
#include <QtCore/QMetaType>
#include <QtCore/QList>
class SignalData;
class DynamicQObject;
class DynamicSignal
{
@ -28,3 +32,93 @@ private:
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)
{
return true;
}
bool DynamicSignal::validate(const QList<QMetaType::Type>& argumentsTypes, const QVariantList& argumentsValues)
{
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();
}
#endif

View File

@ -1,111 +0,0 @@
#include "DynamicSlot.h"
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include <QtCore/QMetaType>
#include <functional>
#include "private/qmetaobjectbuilder_p.h"
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();
}
bool DynamicSlot::validate(const QVariantList& argumentsValues)
{
return true;
}
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();
qDebug() << "C++: slot signature is " << d->signature;
}

View File

@ -1,4 +1,5 @@
#pragma once
#ifndef DYNAMICSLOT_H
#define DYNAMICSLOT_H
#include <memory>
#include <functional>
@ -6,6 +7,12 @@
#include <QtCore/QList>
#include <QtCore/QMetaType>
#include <QtCore/QVariant>
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <QtCore/QVariant>
#include <QtCore/QMetaType>
#include "private/qmetaobjectbuilder_p.h"
class SlotData;
class QString;
@ -34,3 +41,107 @@ private:
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();
}
bool DynamicSlot::validate(const QVariantList& argumentsValues)
{
return true;
}
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();
}
#endif

View File

@ -0,0 +1,40 @@
#ifndef IDYNAMICQOBJECT_H
#define IDYNAMICQOBJECT_H
class IDynamicQObject
{
public:
typedef void (*Callback)(void*, void*, int, void**);
/// 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<QMetaType::Type>& argumentsTypes,
int& signalIndex) = 0;
/// Register a new slot
virtual bool registerSlot(const QString& name,
const QMetaType::Type returnType,
const QList<QMetaType::Type>& argumentsTypes,
int& slotIndex) = 0;
/// Register a new property
virtual bool registerProperty(const QString& name,
QMetaType::Type type,
const QString& readSlotName,
const QString& writeSlotName = "",
const QString& notifySignalName = "") = 0;
/// Emit the signal with the given name and arguments
virtual bool emitSignal(const QString& name, const QList<QVariant>& argumentsValues) = 0;
};
#endif

View File

@ -114,7 +114,7 @@ enum MetaDataFlags {
TypeNameIndexMask = 0x7FFFFFFF
};
extern int qMetaTypeTypeInternal(const char *);
extern int qMetaTypeTypeInternal(const char*);
class QArgumentType
{
@ -122,21 +122,23 @@ public:
QArgumentType(int type)
: _type(type)
{}
QArgumentType(const QByteArray &name)
QArgumentType(const QByteArray& name)
: _type(qMetaTypeTypeInternal(name.constData())), _name(name)
{}
QArgumentType()
: _type(0)
{}
int type() const
{ return _type; }
{
return _type;
}
QByteArray name() const
{
if (_type && _name.isEmpty())
const_cast<QArgumentType *>(this)->_name = QMetaType::typeName(_type);
const_cast<QArgumentType*>(this)->_name = QMetaType::typeName(_type);
return _name;
}
bool operator==(const QArgumentType &other) const
bool operator==(const QArgumentType& other) const
{
if (_type)
return _type == other._type;
@ -145,7 +147,7 @@ public:
else
return _name == other._name;
}
bool operator!=(const QArgumentType &other) const
bool operator!=(const QArgumentType& other) const
{
if (_type)
return _type != other._type;
@ -182,55 +184,57 @@ struct QMetaObjectPrivate
// revision 6 added qt_static_metacall as a member of each Q_OBJECT and inside QMetaObject itself
// revision 7 is Qt 5
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
static inline const QMetaObjectPrivate* get(const QMetaObject* metaobject)
{
return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data);
}
static int originalClone(const QMetaObject *obj, int local_method_index);
static int originalClone(const QMetaObject* obj, int local_method_index);
static QByteArray decodeMethodSignature(const char *signature,
QArgumentTypeArray &types);
static int indexOfSignalRelative(const QMetaObject **baseObject,
const QByteArray &name, int argc,
const QArgumentType *types);
static int indexOfSlotRelative(const QMetaObject **m,
const QByteArray &name, int argc,
const QArgumentType *types);
static int indexOfSignal(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
static int indexOfSlot(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
static int indexOfMethod(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
static int indexOfConstructor(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
Q_CORE_EXPORT static QMetaMethod signal(const QMetaObject *m, int signal_index);
Q_CORE_EXPORT static int signalOffset(const QMetaObject *m);
Q_CORE_EXPORT static int absoluteSignalCount(const QMetaObject *m);
Q_CORE_EXPORT static int signalIndex(const QMetaMethod &m);
static bool checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
int methodArgc, const QArgumentType *methodTypes);
static bool checkConnectArgs(const QMetaMethodPrivate *signal,
const QMetaMethodPrivate *method);
static QByteArray decodeMethodSignature(const char* signature,
QArgumentTypeArray& types);
static int indexOfSignalRelative(const QMetaObject** baseObject,
const QByteArray& name, int argc,
const QArgumentType* types);
static int indexOfSlotRelative(const QMetaObject** m,
const QByteArray& name, int argc,
const QArgumentType* types);
static int indexOfSignal(const QMetaObject* m, const QByteArray& name,
int argc, const QArgumentType* types);
static int indexOfSlot(const QMetaObject* m, const QByteArray& name,
int argc, const QArgumentType* types);
static int indexOfMethod(const QMetaObject* m, const QByteArray& name,
int argc, const QArgumentType* types);
static int indexOfConstructor(const QMetaObject* m, const QByteArray& name,
int argc, const QArgumentType* types);
Q_CORE_EXPORT static QMetaMethod signal(const QMetaObject* m, int signal_index);
Q_CORE_EXPORT static int signalOffset(const QMetaObject* m);
Q_CORE_EXPORT static int absoluteSignalCount(const QMetaObject* m);
Q_CORE_EXPORT static int signalIndex(const QMetaMethod& m);
static bool checkConnectArgs(int signalArgc, const QArgumentType* signalTypes,
int methodArgc, const QArgumentType* methodTypes);
static bool checkConnectArgs(const QMetaMethodPrivate* signal,
const QMetaMethodPrivate* method);
static QList<QByteArray> parameterTypeNamesFromSignature(const char *signature);
static QList<QByteArray> parameterTypeNamesFromSignature(const char* signature);
#ifndef QT_NO_QOBJECT
//defined in qobject.cpp
enum DisconnectType { DisconnectAll, DisconnectOne };
static void memberIndexes(const QObject *obj, const QMetaMethod &member,
int *signalIndex, int *methodIndex);
static QObjectPrivate::Connection *connect(const QObject *sender, int signal_index,
const QMetaObject *smeta,
const QObject *receiver, int method_index_relative,
const QMetaObject *rmeta = 0,
int type = 0, int *types = 0);
static bool disconnect(const QObject *sender, int signal_index,
const QMetaObject *smeta,
const QObject *receiver, int method_index, void **slot,
static void memberIndexes(const QObject* obj, const QMetaMethod& member,
int* signalIndex, int* methodIndex);
static QObjectPrivate::Connection* connect(const QObject* sender, int signal_index,
const QMetaObject* smeta,
const QObject* receiver, int method_index_relative,
const QMetaObject* rmeta = 0,
int type = 0, int* types = 0);
static bool disconnect(const QObject* sender, int signal_index,
const QMetaObject* smeta,
const QObject* receiver, int method_index, void** slot,
DisconnectType = DisconnectAll);
static inline bool disconnectHelper(QObjectPrivate::Connection *c,
const QObject *receiver, int method_index, void **slot,
QMutex *senderMutex, DisconnectType = DisconnectAll);
static inline bool disconnectHelper(QObjectPrivate::Connection* c,
const QObject* receiver, int method_index, void** slot,
QMutex* senderMutex, DisconnectType = DisconnectAll);
#endif
};
@ -246,7 +250,7 @@ static inline bool is_ident_char(char s)
|| (s >= 'A' && s <= 'Z')
|| (s >= '0' && s <= '9')
|| s == '_'
);
);
}
static inline bool is_space(char s)

View File

@ -100,14 +100,14 @@ public:
Q_DECLARE_FLAGS(MetaObjectFlags, MetaObjectFlag)
QMetaObjectBuilder();
explicit QMetaObjectBuilder(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
explicit QMetaObjectBuilder(const QMetaObject* prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
virtual ~QMetaObjectBuilder();
QByteArray className() const;
void setClassName(const QByteArray& name);
const QMetaObject *superClass() const;
void setSuperClass(const QMetaObject *meta);
const QMetaObject* superClass() const;
void setSuperClass(const QMetaObject* meta);
MetaObjectFlags flags() const;
void setFlags(MetaObjectFlags);
@ -129,7 +129,7 @@ public:
QMetaMethodBuilder addConstructor(const QByteArray& signature);
QMetaMethodBuilder addConstructor(const QMetaMethod& prototype);
QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId=-1);
QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId = -1);
QMetaPropertyBuilder addProperty(const QMetaProperty& prototype);
QMetaEnumBuilder addEnumerator(const QByteArray& name);
@ -137,15 +137,15 @@ public:
int addClassInfo(const QByteArray& name, const QByteArray& value);
int addRelatedMetaObject(const QMetaObject *meta);
int addRelatedMetaObject(const QMetaObject* meta);
void addMetaObject(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
void addMetaObject(const QMetaObject* prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
QMetaMethodBuilder method(int index) const;
QMetaMethodBuilder constructor(int index) const;
QMetaPropertyBuilder property(int index) const;
QMetaEnumBuilder enumerator(int index) const;
const QMetaObject *relatedMetaObject(int index) const;
const QMetaObject* relatedMetaObject(int index) const;
QByteArray classInfoName(int index) const;
QByteArray classInfoValue(int index) const;
@ -165,26 +165,26 @@ public:
int indexOfEnumerator(const QByteArray& name);
int indexOfClassInfo(const QByteArray& name);
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
typedef void (*StaticMetacallFunction)(QObject*, QMetaObject::Call, int, void**);
QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction() const;
void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value);
QMetaObject *toMetaObject() const;
QByteArray toRelocatableData(bool * = 0) const;
static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &);
QMetaObject* toMetaObject() const;
QByteArray toRelocatableData(bool* = 0) const;
static void fromRelocatableData(QMetaObject*, const QMetaObject*, const QByteArray&);
#ifndef QT_NO_DATASTREAM
void serialize(QDataStream& stream) const;
void deserialize
(QDataStream& stream,
const QMap<QByteArray, const QMetaObject *>& references);
(QDataStream& stream,
const QMap<QByteArray, const QMetaObject*>& references);
#endif
private:
Q_DISABLE_COPY(QMetaObjectBuilder)
QMetaObjectBuilderPrivate *d;
QMetaObjectBuilderPrivate* d;
friend class QMetaMethodBuilder;
friend class QMetaPropertyBuilder;
@ -221,16 +221,16 @@ public:
void setRevision(int revision);
private:
const QMetaObjectBuilder *_mobj;
const QMetaObjectBuilder* _mobj;
int _index;
friend class QMetaObjectBuilder;
friend class QMetaPropertyBuilder;
QMetaMethodBuilder(const QMetaObjectBuilder *mobj, int index)
QMetaMethodBuilder(const QMetaObjectBuilder* mobj, int index)
: _mobj(mobj), _index(index) {}
QMetaMethodBuilderPrivate *d_func() const;
QMetaMethodBuilderPrivate* d_func() const;
};
class Q_CORE_EXPORT QMetaPropertyBuilder
@ -238,7 +238,9 @@ class Q_CORE_EXPORT QMetaPropertyBuilder
public:
QMetaPropertyBuilder() : _mobj(0), _index(0) {}
int index() const { return _index; }
int index() const {
return _index;
}
QByteArray name() const;
QByteArray type() const;
@ -278,15 +280,15 @@ public:
void setRevision(int revision);
private:
const QMetaObjectBuilder *_mobj;
const QMetaObjectBuilder* _mobj;
int _index;
friend class QMetaObjectBuilder;
QMetaPropertyBuilder(const QMetaObjectBuilder *mobj, int index)
QMetaPropertyBuilder(const QMetaObjectBuilder* mobj, int index)
: _mobj(mobj), _index(index) {}
QMetaPropertyBuilderPrivate *d_func() const;
QMetaPropertyBuilderPrivate* d_func() const;
};
class Q_CORE_EXPORT QMetaEnumBuilder
@ -294,7 +296,9 @@ class Q_CORE_EXPORT QMetaEnumBuilder
public:
QMetaEnumBuilder() : _mobj(0), _index(0) {}
int index() const { return _index; }
int index() const {
return _index;
}
QByteArray name() const;
@ -309,27 +313,27 @@ public:
void removeKey(int index);
private:
const QMetaObjectBuilder *_mobj;
const QMetaObjectBuilder* _mobj;
int _index;
friend class QMetaObjectBuilder;
QMetaEnumBuilder(const QMetaObjectBuilder *mobj, int index)
QMetaEnumBuilder(const QMetaObjectBuilder* mobj, int index)
: _mobj(mobj), _index(index) {}
QMetaEnumBuilderPrivate *d_func() const;
QMetaEnumBuilderPrivate* d_func() const;
};
class Q_CORE_EXPORT QMetaStringTable
{
public:
explicit QMetaStringTable(const QByteArray &className);
explicit QMetaStringTable(const QByteArray& className);
int enter(const QByteArray &value);
int enter(const QByteArray& value);
static int preferredAlignment();
int blobSize() const;
void writeBlob(char *out) const;
void writeBlob(char* out) const;
private:
typedef QHash<QByteArray, int> Entries; // string --> index mapping

View File

@ -68,19 +68,21 @@ QT_BEGIN_NAMESPACE
class QVariant;
class QThreadData;
class QObjectConnectionListVector;
namespace QtSharedPointer { struct ExternalRefCountData; }
namespace QtSharedPointer {
struct ExternalRefCountData;
}
/* for Qt Test */
struct QSignalSpyCallbackSet
{
typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
typedef void (*BeginCallback)(QObject* caller, int signal_or_method_index, void** argv);
typedef void (*EndCallback)(QObject* caller, int signal_or_method_index);
BeginCallback signal_begin_callback,
slot_begin_callback;
slot_begin_callback;
EndCallback signal_end_callback,
slot_end_callback;
};
void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet &callback_set);
void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet& callback_set);
extern QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set;
@ -89,19 +91,19 @@ enum { QObjectPrivateVersion = QT_VERSION };
class Q_CORE_EXPORT QAbstractDeclarativeData
{
public:
static void (*destroyed)(QAbstractDeclarativeData *, QObject *);
static void (*destroyed_qml1)(QAbstractDeclarativeData *, QObject *);
static void (*parentChanged)(QAbstractDeclarativeData *, QObject *, QObject *);
static void (*signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **);
static int (*receivers)(QAbstractDeclarativeData *, const QObject *, int);
static bool (*isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int);
static void (*destroyed)(QAbstractDeclarativeData*, QObject*);
static void (*destroyed_qml1)(QAbstractDeclarativeData*, QObject*);
static void (*parentChanged)(QAbstractDeclarativeData*, QObject*, QObject*);
static void (*signalEmitted)(QAbstractDeclarativeData*, QObject*, int, void**);
static int (*receivers)(QAbstractDeclarativeData*, const QObject*, int);
static bool (*isSignalConnected)(QAbstractDeclarativeData*, const QObject*, int);
};
// This is an implementation of QAbstractDeclarativeData that is identical with
// the implementation in QtDeclarative and QtQml for the first bit
struct QAbstractDeclarativeDataImpl : public QAbstractDeclarativeData
{
quint32 ownedByQml1:1;
quint32 ownedByQml1: 1;
quint32 unused: 31;
};
@ -113,9 +115,9 @@ public:
struct ExtraData
{
ExtraData() {}
#ifndef QT_NO_USERDATA
QVector<QObjectUserData *> userData;
#endif
#ifndef QT_NO_USERDATA
QVector<QObjectUserData*> userData;
#endif
QList<QByteArray> propertyNames;
QList<QVariant> propertyValues;
QVector<int> runningTimers;
@ -123,20 +125,20 @@ public:
QString objectName;
};
typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
typedef void (*StaticMetaCallFunction)(QObject*, QMetaObject::Call, int, void**);
struct Connection
{
QObject *sender;
QObject *receiver;
QObject* sender;
QObject* receiver;
union {
StaticMetaCallFunction callFunction;
QtPrivate::QSlotObjectBase *slotObj;
QtPrivate::QSlotObjectBase* slotObj;
};
// The next pointer for the singly-linked ConnectionList
Connection *nextConnectionList;
Connection* nextConnectionList;
//senders linked list
Connection *next;
Connection **prev;
Connection* next;
Connection** prev;
QAtomicPointer<const int> argumentTypes;
QAtomicInt ref_;
ushort method_offset;
@ -149,8 +151,12 @@ public:
//ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
}
~Connection();
int method() const { return method_offset + method_relative; }
void ref() { ref_.ref(); }
int method() const {
return method_offset + method_relative;
}
void ref() {
ref_.ref();
}
void deref() {
if (!ref_.deref()) {
Q_ASSERT(!receiver);
@ -161,13 +167,13 @@ public:
// ConnectionList is a singly-linked list
struct ConnectionList {
ConnectionList() : first(0), last(0) {}
Connection *first;
Connection *last;
Connection* first;
Connection* last;
};
struct Sender
{
QObject *sender;
QObject* sender;
int signal;
int ref;
};
@ -177,64 +183,64 @@ public:
virtual ~QObjectPrivate();
void deleteChildren();
void setParent_helper(QObject *);
void setParent_helper(QObject*);
void moveToThread_helper();
void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
void _q_reregisterTimers(void *pointer);
void setThreadData_helper(QThreadData* currentData, QThreadData* targetData);
void _q_reregisterTimers(void* pointer);
bool isSender(const QObject *receiver, const char *signal) const;
QObjectList receiverList(const char *signal) const;
bool isSender(const QObject* receiver, const char* signal) const;
QObjectList receiverList(const char* signal) const;
QObjectList senderList() const;
void addConnection(int signal, Connection *c);
void addConnection(int signal, Connection* c);
void cleanConnectionLists();
static inline Sender *setCurrentSender(QObject *receiver,
Sender *sender);
static inline void resetCurrentSender(QObject *receiver,
Sender *currentSender,
Sender *previousSender);
static inline Sender* setCurrentSender(QObject* receiver,
Sender* sender);
static inline void resetCurrentSender(QObject* receiver,
Sender* currentSender,
Sender* previousSender);
static QObjectPrivate *get(QObject *o) {
static QObjectPrivate* get(QObject* o) {
return o->d_func();
}
int signalIndex(const char *signalName, const QMetaObject **meta = 0) const;
int signalIndex(const char* signalName, const QMetaObject** meta = 0) const;
inline bool isSignalConnected(uint signalIdx) const;
// To allow abitrary objects to call connectNotify()/disconnectNotify() without making
// the API public in QObject. This is used by QQmlNotifierEndpoint.
inline void connectNotify(const QMetaMethod &signal);
inline void disconnectNotify(const QMetaMethod &signal);
inline void connectNotify(const QMetaMethod& signal);
inline void disconnectNotify(const QMetaMethod& signal);
template <typename Func1, typename Func2>
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection);
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object* receiverPrivate, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection);
template <typename Func1, typename Func2>
static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object* receiverPrivate, Func2 slot);
static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
const QObject *receiver, void **slot,
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject);
static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
static bool disconnect(const QObject *sender, int signal_index, void **slot);
static QMetaObject::Connection connectImpl(const QObject* sender, int signal_index,
const QObject* receiver, void** slot,
QtPrivate::QSlotObjectBase* slotObj, Qt::ConnectionType type,
const int* types, const QMetaObject* senderMetaObject);
static QMetaObject::Connection connect(const QObject* sender, int signal_index, QtPrivate::QSlotObjectBase* slotObj, Qt::ConnectionType type);
static bool disconnect(const QObject* sender, int signal_index, void** slot);
public:
ExtraData *extraData; // extra data set by the user
QThreadData *threadData; // id of the thread that owns the object
ExtraData* extraData; // extra data set by the user
QThreadData* threadData; // id of the thread that owns the object
QObjectConnectionListVector *connectionLists;
QObjectConnectionListVector* connectionLists;
Connection *senders; // linked list of connections connected to this object
Sender *currentSender; // object currently activating the object
Connection* senders; // linked list of connections connected to this object
Sender* currentSender; // object currently activating the object
mutable quint32 connectedSignals[2];
union {
QObject *currentChildBeingDeleted;
QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
QObject* currentChildBeingDeleted;
QAbstractDeclarativeData* declarativeData; //extra data used by the declarative module
};
// these objects are all used to indicate that a QObject was deleted
@ -254,22 +260,22 @@ public:
inline bool QObjectPrivate::isSignalConnected(uint signal_index) const
{
return signal_index >= sizeof(connectedSignals) * 8
|| (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f))
|| (declarativeData && QAbstractDeclarativeData::isSignalConnected
&& QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index)));
|| (connectedSignals[signal_index >> 5] & (1 << (signal_index & 0x1f))
|| (declarativeData && QAbstractDeclarativeData::isSignalConnected
&& QAbstractDeclarativeData::isSignalConnected(declarativeData, q_func(), signal_index)));
}
inline QObjectPrivate::Sender *QObjectPrivate::setCurrentSender(QObject *receiver,
Sender *sender)
inline QObjectPrivate::Sender* QObjectPrivate::setCurrentSender(QObject* receiver,
Sender* sender)
{
Sender *previousSender = receiver->d_func()->currentSender;
Sender* previousSender = receiver->d_func()->currentSender;
receiver->d_func()->currentSender = sender;
return previousSender;
}
inline void QObjectPrivate::resetCurrentSender(QObject *receiver,
Sender *currentSender,
Sender *previousSender)
inline void QObjectPrivate::resetCurrentSender(QObject* receiver,
Sender* currentSender,
Sender* previousSender)
{
// ref is set to zero when this object is deleted during the metacall
if (currentSender->ref == 1)
@ -279,46 +285,47 @@ inline void QObjectPrivate::resetCurrentSender(QObject *receiver,
previousSender->ref = currentSender->ref;
}
inline void QObjectPrivate::connectNotify(const QMetaMethod &signal)
inline void QObjectPrivate::connectNotify(const QMetaMethod& signal)
{
q_ptr->connectNotify(signal);
}
inline void QObjectPrivate::disconnectNotify(const QMetaMethod &signal)
inline void QObjectPrivate::disconnectNotify(const QMetaMethod& signal)
{
q_ptr->disconnectNotify(signal);
}
namespace QtPrivate {
template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
{
typedef QtPrivate::FunctionPointer<Func> FuncType;
Func function;
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
template<typename Func, typename Args, typename R> class QPrivateSlotObject : public QSlotObjectBase
{
switch (which) {
typedef QtPrivate::FunctionPointer<Func> FuncType;
Func function;
static void impl(int which, QSlotObjectBase* this_, QObject* r, void** a, bool* ret)
{
switch (which) {
case Destroy:
delete static_cast<QPrivateSlotObject*>(this_);
break;
case Call:
FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->function,
static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
static_cast<typename FuncType::Object*>(QObjectPrivate::get(r)), a);
break;
case Compare:
*ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
*ret = *reinterpret_cast<Func*>(a) == static_cast<QPrivateSlotObject*>(this_)->function;
break;
case NumOperations: ;
case NumOperations:
;
}
}
}
public:
explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
};
public:
explicit QPrivateSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
};
} //namespace QtPrivate
template <typename Func1, typename Func2>
inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
Qt::ConnectionType type)
inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate::FunctionPointer<Func1>::Object* sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object* receiverPrivate, Func2 slot,
Qt::ConnectionType type)
{
typedef QtPrivate::FunctionPointer<Func1> SignalType;
typedef QtPrivate::FunctionPointer<Func2> SlotType;
@ -333,15 +340,15 @@ inline QMetaObject::Connection QObjectPrivate::connect(const typename QtPrivate:
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
"Return type of the slot is not compatible with the return type of the signal.");
const int *types = 0;
const int* types = 0;
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
return QObject::connectImpl(sender, reinterpret_cast<void **>(&signal),
receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
type, types, &SignalType::Object::staticMetaObject);
return QObject::connectImpl(sender, reinterpret_cast<void**>(&signal),
receiverPrivate->q_ptr, reinterpret_cast<void**>(&slot),
new QtPrivate::QPrivateSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot),
type, types, &SignalType::Object::staticMetaObject);
}
template <typename Func1, typename Func2>
@ -355,9 +362,9 @@ bool QObjectPrivate::disconnect(const typename QtPrivate::FunctionPointer< Func1
//compilation error if the arguments does not match.
Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
"Signal and slot arguments are not compatible.");
return QObject::disconnectImpl(sender, reinterpret_cast<void **>(&signal),
receiverPrivate->q_ptr, reinterpret_cast<void **>(&slot),
&SignalType::Object::staticMetaObject);
return QObject::disconnectImpl(sender, reinterpret_cast<void**>(&signal),
receiverPrivate->q_ptr, reinterpret_cast<void**>(&slot),
&SignalType::Object::staticMetaObject);
}
Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
@ -367,31 +374,39 @@ class QSemaphore;
class Q_CORE_EXPORT QMetaCallEvent : public QEvent
{
public:
QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject *sender, int signalId,
int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0);
QMetaCallEvent(ushort method_offset, ushort method_relative, QObjectPrivate::StaticMetaCallFunction callFunction , const QObject* sender, int signalId,
int nargs = 0, int* types = 0, void** args = 0, QSemaphore* semaphore = 0);
/*! \internal
\a signalId is in the signal index range (see QObjectPrivate::signalIndex()).
*/
QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender, int signalId,
int nargs = 0, int *types = 0, void **args = 0, QSemaphore *semaphore = 0);
QMetaCallEvent(QtPrivate::QSlotObjectBase* slotObj, const QObject* sender, int signalId,
int nargs = 0, int* types = 0, void** args = 0, QSemaphore* semaphore = 0);
~QMetaCallEvent();
inline int id() const { return method_offset_ + method_relative_; }
inline const QObject *sender() const { return sender_; }
inline int signalId() const { return signalId_; }
inline void **args() const { return args_; }
inline int id() const {
return method_offset_ + method_relative_;
}
inline const QObject* sender() const {
return sender_;
}
inline int signalId() const {
return signalId_;
}
inline void** args() const {
return args_;
}
virtual void placeMetaCall(QObject *object);
virtual void placeMetaCall(QObject* object);
private:
QtPrivate::QSlotObjectBase *slotObj_;
const QObject *sender_;
QtPrivate::QSlotObjectBase* slotObj_;
const QObject* sender_;
int signalId_;
int nargs_;
int *types_;
void **args_;
QSemaphore *semaphore_;
int* types_;
void** args_;
QSemaphore* semaphore_;
QObjectPrivate::StaticMetaCallFunction callFunction_;
ushort method_offset_;
ushort method_relative_;
@ -401,32 +416,46 @@ class QBoolBlocker
{
Q_DISABLE_COPY(QBoolBlocker)
public:
explicit inline QBoolBlocker(bool &b, bool value=true):block(b), reset(b){block = value;}
inline ~QBoolBlocker(){block = reset; }
explicit inline QBoolBlocker(bool& b, bool value = true): block(b), reset(b) {
block = value;
}
inline ~QBoolBlocker() {
block = reset;
}
private:
bool &block;
bool& block;
bool reset;
};
void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
void Q_CORE_EXPORT qDeleteInEventHandler(QObject* o);
struct QAbstractDynamicMetaObject;
struct Q_CORE_EXPORT QDynamicMetaObjectData
{
virtual ~QDynamicMetaObjectData() {}
virtual void objectDestroyed(QObject *) { delete this; }
virtual void objectDestroyed(QObject*) {
delete this;
}
virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) = 0;
virtual int metaCall(QObject *, QMetaObject::Call, int _id, void **) = 0;
virtual QAbstractDynamicMetaObject* toDynamicMetaObject(QObject*) = 0;
virtual int metaCall(QObject*, QMetaObject::Call, int _id, void**) = 0;
};
struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QDynamicMetaObjectData, public QMetaObject
{
virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *) { return this; }
virtual int createProperty(const char *, const char *) { return -1; }
virtual int metaCall(QObject *, QMetaObject::Call c, int _id, void **a)
{ return metaCall(c, _id, a); }
virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; } // Compat overload
virtual QAbstractDynamicMetaObject* toDynamicMetaObject(QObject*) {
return this;
}
virtual int createProperty(const char*, const char*) {
return -1;
}
virtual int metaCall(QObject*, QMetaObject::Call c, int _id, void** a)
{
return metaCall(c, _id, a);
}
virtual int metaCall(QMetaObject::Call, int _id, void**) {
return _id; // Compat overload
}
};
QT_END_NAMESPACE

View File

@ -5,7 +5,7 @@
#include <DynamicQObject.h>
#include <QDebug>
int main(int argc, char *argv[])
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);

View File

@ -2,8 +2,8 @@
Filippo Cucchetto <filippocucchetto@gmail.com>
Will Szumski <will@cowboycoders.org>
:Version: 0.2.0
:Date: 2015/01/02
:Version: 0.3.0
:Date: 2015/02/15
Introduction
-----------
@ -126,6 +126,7 @@ At the time of writing the QVariant class support the following types:
* int
* string
* bool
* float
* QObject derived classes
Example 3: exposing complex data and procedures to Qml
@ -247,3 +248,57 @@ The ``QtProperty`` macro has the following syntax
.. code-block:: nim
QtProperty[typeOfProperty] nameOfProperty
Example 5: ContactApp
-------------------------
The last example tries to show you all the stuff presented
in the previous chapters and gives you an introduction to how
to expose lists to qml.
Qt models are a huge topic and explaining how they work is
out of scope. For further information please read the official
Qt documentation.
The main file follows the basic logic of creating a qml
engine and exposing a QObject derived object "ApplicationLogic"
through a global "logic" property
``Examples/ContactApp/main.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/main.nim
The qml file shows a simple app with a central tableview
``Examples/ContactApp/main.qml``
.. code-block:: qml
:file: ../Examples/ContactApp/main.qml
The important things to notice are:
1. The menubar load, save and exit items handlers call the logic load, save and exit slots
2. The TableView model is retrieved by the logic.contactList property
3. The delete and add buttons call the del and add slots of the logic.contactList model
The ApplicationLogic object is as follows:
``Examples/ContactApp/ApplicationLogic.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/ApplicationLogic.nim
The ApplicationLogic object,
1. expose some slots for handling the qml menubar triggered signals
2. expose a contactList property that return a QAbstractListModel derived object that manage the list of contacts
The ContactList object is as follows:
``Examples/ContactApp/ContactList.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/ContactList.nim
The ContactList object:
1. overrides the ``rowCount`` method for returning the number of rows stored in the model
2. overrides the ``data`` method for returning the value for the exported roles
3. overrides the ``roleNames`` method for returning the names of the roles of the model. This name are then available in the qml item delegates
4. defines two slots ``add`` and ``del`` that add or delete a Contact. During this operations the model execute the ``beginInsertRows`` and ``beginRemoveRows`` for notifing the view of an upcoming change. Once the add or delete operations are done the model execute the ``endInsertRows`` and ``endRemoveRows``.

View File

@ -0,0 +1,2 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET AbstractItemModel SOURCES main.nim PATHS ../../NimQml)

View File

@ -0,0 +1,64 @@
import NimQml
import macros
import typeinfo
import tables
type
Roles {.pure.} = enum
Name = cint(0)
MyQAbstractListModel = ref object of QAbstractListModel
m_roleNames: Table[int, cstring]
m_names: seq[string]
proc create(self: MyQAbstractListModel) =
var qAbstractListModel = self.QAbstractListModel
qAbstractListModel.create
self.m_names = @["John", "Max", "Paul", "Anna"]
self.m_roleNames = initTable[int, cstring]()
self.m_roleNames[0] = "name"
proc delete(self: MyQAbstractListModel) =
var qAbstractListModel = self.QAbstractListModel
qAbstractListModel.delete
proc newMyQAbstractListModel(): MyQAbstractListModel =
new(result, delete)
result.create
method rowCount(self: MyQAbstractListModel, index: QModelIndex): cint =
return self.m_names.len.cint
method data(self: MyQAbstractListModel, index: QModelIndex, role: cint): QVariant =
if not index.isValid:
return
if index.row < 0 or index.row >= self.m_names.len:
return
if role == Roles.Name.cint:
return newQVariant(self.m_names[index.row])
method roleNames(self: MyQAbstractListModel): Table[int, cstring] =
return self.m_roleNames
proc mainProc() =
var app = newQApplication()
defer: app.delete
var myListModel = newMyQAbstractListModel()
defer: myListModel.delete
var engine = newQQmlApplicationEngine()
defer: engine.delete
var variant = newQVariant(myListModel)
defer: variant.delete
engine.rootContext.setContextProperty("myListModel", variant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -0,0 +1,25 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow
{
width: 400
height: 300
title: "AbstractItemModel"
Component.onCompleted: visible = true
Component
{
id: myListModelDelegate
Label { text: "Name:" + name }
}
ListView
{
anchors.fill: parent
model: myListModel
delegate: myListModelDelegate
}
}

View File

@ -1,4 +1,6 @@
add_subdirectory(HelloWorld)
add_subdirectory(SimpleData)
add_subdirectory(SlotsAndProperties)
add_subdirectory(QtObjectMacro)
add_subdirectory(QtObjectMacro)
add_subdirectory(ContactApp)
add_subdirectory(AbstractItemModel)

View File

@ -0,0 +1,33 @@
import NimQml, NimQmlMacros, ContactList
QtObject:
type ApplicationLogic* = ref object of QObject
contactList: ContactList
app: QApplication
proc delete*(self: ApplicationLogic) =
let qobject = self.QObject
qobject.delete
self.contactList.delete
proc newApplicationLogic*(app: QApplication): ApplicationLogic =
new(result)
result.contactList = newContactList()
result.app = app
result.create()
method getContactList(self: ApplicationLogic): QVariant {.slot.} =
return newQVariant(self.contactList)
method onLoadTriggered(self: ApplicationLogic) {.slot.} =
echo "Load Triggered"
self.contactList.add("John", "Doo")
method onSaveTriggered(self: ApplicationLogic) {.slot.} =
echo "Save Triggered"
method onExitTriggered(self: ApplicationLogic) {.slot.} =
self.app.quit
QtProperty[QVariant] contactList:
read = getContactList

View File

@ -0,0 +1,2 @@
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_nim_executable(TARGET ContactApp SOURCES main.nim PATHS ../../NimQml)

View File

@ -0,0 +1,51 @@
## Please note we are using templates where ordinarily we would like to use procedures
## due to bug: https://github.com/Araq/Nim/issues/1821
import NimQml, NimQmlMacros
QtObject:
type Contact* = ref object of QObject
name: string
surname: string
proc delete*(self: Contact) =
let qobject = self.QObject
qobject.delete
proc newContact*(): Contact =
new(result)
result.name = ""
result.create
method firstName*(self: Contact): string {.slot.} =
result = self.name
method firstNameChanged*(self: Contact) {.signal.}
method setFirstName(self: Contact, name: string) {.slot.} =
if self.name != name:
self.name = name
self.firstNameChanged()
proc `firstName=`*(self: Contact, name: string) = self.setFirstName(name)
QtProperty[string] firstName:
read = firstName
write = setFirstName
notify = firstNameChanged
method surname*(self: Contact): string {.slot.} =
result = self.surname
method surnameChanged*(self: Contact) {.signal.}
method setSurname(self: Contact, surname: string) {.slot.} =
if self.surname != surname:
self.surname = surname
self.surnameChanged()
proc `surname=`*(self: Contact, surname: string) = self.setSurname(surname)
QtProperty[string] surname:
read = surname
write = setSurname
notify = surnameChanged

View File

@ -0,0 +1,62 @@
import NimQml, NimQmlMacros, Contact, Tables
QtObject:
type
ContactList* = ref object of QAbstractListModel
contacts*: seq[Contact]
ContactRoles {.pure.} = enum
FirstName = 0
Surname = 1
converter toCInt(value: ContactRoles): cint = return value.cint
converter toCInt(value: int): cint = return value.cint
converter toInt(value: ContactRoles): int = return value.int
converter toInt(value: cint): int = return value.int
converter toQVariant(value: string): QVariant = return value.newQVariant
proc delete(self: ContactList) =
let model = self.QAbstractListModel
model.delete
for contact in self.contacts:
contact.delete
self.contacts = @[]
proc newContactList*(): ContactList =
new(result, delete)
result.contacts = @[]
result.create
method rowCount(self: ContactList, index: QModelIndex = nil): cint =
return self.contacts.len
method data(self: ContactList, index: QModelIndex, role: cint): QVariant =
if not index.isValid:
return
if index.row < 0 or index.row >= self.contacts.len:
return
let contact = self.contacts[index.row]
let contactRole = role.ContactRoles
case contactRole:
of ContactRoles.FirstName: return contact.firstName
of ContactRoles.Surname: return contact.surname
else: return
method roleNames(self: ContactList): Table[cint, cstring] =
result = initTable[cint, cstring]()
result[ContactRoles.FirstName] = "firstName"
result[ContactRoles.Surname] = "surname"
method add*(self: ContactList, name: string, surname: string) {.slot.} =
let contact = newContact()
contact.firstName = name
contact.surname = surname
self.beginInsertRows(newQModelIndex(), self.contacts.len, self.contacts.len)
self.contacts.add(contact)
self.endInsertRows()
method del*(self: ContactList, pos: int) {.slot.} =
if pos < 0 or pos >= self.contacts.len:
return
self.beginRemoveRows(newQModelIndex(), pos, pos)
self.contacts.del(pos)
self.endRemoveRows

View File

@ -0,0 +1,17 @@
import NimQml, ApplicationLogic
proc mainProc() =
let app = newQApplication()
defer: app.delete
let logic = newApplicationLogic(app)
defer: logic.delete
let engine = newQQmlApplicationEngine()
defer: engine.delete
let logicVariant = newQVariant(logic)
defer: logicVariant.delete
engine.rootContext.setContextProperty("logic", logicVariant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()

View File

@ -0,0 +1,93 @@
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
ApplicationWindow {
width: 500
height: 300
title: "ContactApp"
visible: true
menuBar: MenuBar {
Menu {
title: "&File"
MenuItem { text: "&Load"; onTriggered: logic.onLoadTriggered() }
MenuItem { text: "&Save"; onTriggered: logic.onSaveTriggered() }
MenuItem { text: "&Exit"; onTriggered: logic.onExitTriggered() }
}
}
ColumnLayout {
anchors.fill: parent
Component {
id: tableTextDelegate
Label {
id: tableTextDelegateInstance
property var styleData: undefined
states: State {
when: styleData !== undefined
PropertyChanges {
target: tableTextDelegateInstance;
text: styleData.value;
color: styleData.textColor
}
}
}
}
Component {
id: tableButtonDelegate
Button {
id: tableButtonDelegateInstance
property var styleData: undefined
text: "Delete"
onClicked: logic.contactList.del(styleData.row)
}
}
Component {
id: tableItemDelegate
Loader {
id: tableItemDelegateInstance
sourceComponent: {
if (styleData.column === 0 || styleData.column === 1)
return tableTextDelegate
else if (styleData.column === 2)
return tableButtonDelegate
else
return tableTextDelegate
}
Binding {
target: tableItemDelegateInstance.item
property: "styleData"
value: styleData
}
}
}
TableView {
model: logic.contactList
Layout.fillWidth: true
Layout.fillHeight: true
TableViewColumn { role: "firstName"; title: "FirstName"; width: 200 }
TableViewColumn { role: "surname"; title: "Surname"; width: 200}
TableViewColumn { width: 100; }
itemDelegate: tableItemDelegate
}
RowLayout {
Label { text: "Name" }
TextField { id: nameTextField; Layout.fillWidth: true; text: "" }
Label { text: "Surname" }
TextField { id: surnameTextField; Layout.fillWidth: true; text: "" }
Button {
text: "Add"
onClicked: logic.contactList.add(nameTextField.text, surnameTextField.text)
enabled: nameTextField.text !== "" && surnameTextField.text !== ""
}
}
}
}

View File

@ -3,12 +3,10 @@ import macros
import typeinfo
proc mainProc() =
var app: QApplication
app.create()
var app = newQApplication()
defer: app.delete()
var engine: QQmlApplicationEngine
engine.create()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
engine.load("main.qml")
@ -16,4 +14,5 @@ proc mainProc() =
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -6,20 +6,24 @@ QtObject:
type Contact* = ref object of QObject
m_name: string
template newContact*(): Contact =
var result = Contact(m_name: "initialName")
result.create
result
method getName*(contact: Contact): string {.slot.} =
result = contact.m_name
proc delete*(self: Contact) =
var qobject = self.QObject
qobject.delete()
method nameChanged*(contact: Contact) {.signal.}
proc newContact*(): Contact =
new(result, delete)
result.m_name = "InitialName"
result.create
method setName*(contact: Contact, name: string) {.slot.} =
if contact.m_name != name:
contact.m_name = name
contact.nameChanged()
method getName*(self: Contact): string {.slot.} =
result = self.m_name
method nameChanged*(self: Contact) {.signal.}
method setName*(self: Contact, name: string) {.slot.} =
if self.m_name != name:
self.m_name = name
self.nameChanged()
QtProperty[string] name:
read = getName

View File

@ -2,26 +2,22 @@ import NimQml
import Contact
proc mainProc() =
var app: QApplication
app.create()
var app = newQApplication()
defer: app.delete()
var contact = newContact()
defer: contact.delete()
var engine: QQmlApplicationEngine
engine.create()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
var variant: QVariant
variant.create(contact)
var variant = newQVariant(contact)
defer: variant.delete()
var rootContext: QQmlContext = engine.rootContext()
rootContext.setContextProperty("contact", variant)
engine.rootContext.setContextProperty("contact", variant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -3,36 +3,32 @@ import macros
import typeinfo
proc mainProc() =
var app: QApplication
app.create()
var app = newQApplication()
defer: app.delete()
var engine: QQmlApplicationEngine
engine.create()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
var qVar1: QVariant
qVar1.create()
var qVar1 = newQVariant(10)
defer: qVar1.delete()
qVar1.intVal = 10
var qVar2: QVariant
qVar2.create()
var qVar2 = newQVariant("Hello World")
defer: qVar2.delete()
qVar2.stringVal = "Hello World"
var qVar3: QVariant
qVar3.create()
var qVar3 = newQVariant(false)
defer: qVar3.delete()
qVar3.boolVal = false
var qVar4 = newQVariant(3.5.float)
defer: qVar4.delete()
engine.rootContext.setContextProperty("qVar1", qVar1)
engine.rootContext.setContextProperty("qVar2", qVar2)
engine.rootContext.setContextProperty("qVar3", qVar2)
engine.rootContext.setContextProperty("qVar3", qVar3)
engine.rootContext.setContextProperty("qVar4", qVar4)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -16,5 +16,6 @@ ApplicationWindow
SpinBox { value: qVar1}
TextField { text: qVar2}
CheckBox { checked: qVar3}
SpinBox { value: qVar4; decimals: 1 }
}
}

View File

@ -4,17 +4,24 @@ import NimQml
type Contact = ref object of QObject
m_name: string
template newContact*(): Contact =
var result = Contact(m_name: "initialName")
result.create()
result.m_name = "InitialName"
result.registerSlot("getName", [QMetaType.QString])
result.registerSlot("setName", [QMetaType.Void, QMetaType.QString])
result.registerSignal("nameChanged", [QMetaType.Void])
result.registerProperty("name", QMetaType.QString, "getName", "setName", "nameChanged")
result
proc delete*(self: Contact) =
var qobject = self.QObject
qobject.delete()
proc create*(self: Contact) =
var qobject = self.QObject
qobject.create()
self.m_name = "InitialName"
self.registerSlot("getName", [QMetaType.QString])
self.registerSlot("setName", [QMetaType.Void, QMetaType.QString])
self.registerSignal("nameChanged", [QMetaType.Void])
self.registerProperty("name", QMetaType.QString, "getName", "setName", "nameChanged")
proc newContact*(): Contact =
new(result, delete)
result.create()
method getName*(self: Contact): string =
result = self.m_name
@ -30,4 +37,4 @@ method onSlotCalled(self: Contact, slotName: string, args: openarray[QVariant])
of "setName":
self.setName(args[1].stringVal)
else:
discard()
discard()

View File

@ -2,26 +2,23 @@ import NimQml
import Contact
proc mainProc() =
var app: QApplication
app.create()
var app = newQApplication()
defer: app.delete()
var contact = newContact()
defer: contact.delete()
var engine: QQmlApplicationEngine
engine.create()
var engine = newQQmlApplicationEngine()
defer: engine.delete()
var variant: QVariant
variant.create(contact)
var variant = newQVariant(contact)
defer: variant.delete()
var rootContext: QQmlContext = engine.rootContext()
rootContext.setContextProperty("contact", variant)
engine.rootContext.setContextProperty("contact", variant)
engine.load("main.qml")
app.exec()
when isMainModule:
mainProc()
GC_fullcollect()

View File

@ -1,13 +1,14 @@
import NimQmlTypes
import tables
include NimQmlTypes
## NimQml aims to provide binding to the QML for the Nim programming language
export QObject
export QApplication
export QVariant
export QQmlApplicationEngine
export QQmlContext
##
## Optional finalizers
## -------------------
## To enable finalizers you must define ``nimqml_use_finalizers`` by passing
## the option, ``-d:nimqml_use_finalizers``, to the Nim compiler. The relevant
## delete method will then be called automatically by the garbage collector.
## Care should be taken when using this approach as there are no guarantees
## when a finalzier will be run, or if, indeed, it will run at all.
type QMetaType* {.pure.} = enum ## \
## Qt metatypes values used for specifing the
@ -19,276 +20,770 @@ type QMetaType* {.pure.} = enum ## \
Int = cint(2),
QString = cint(10),
VoidStar = cint(31),
QObjectStar = cint(39),
QVariant = cint(41),
Void = cint(43)
Void = cint(43),
proc debugMsg(message: string) =
echo "NimQml: ", message
var qobjectRegistry = initTable[ptr QObjectObj, bool]()
proc debugMsg(typeName: string, procName: string) =
var message = typeName
message &= ": "
message &= procName
debugMsg(message)
template debugMsg(message: string) =
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(debug):
{.pop.}
echo "NimQml: ", message
else:
{.pop.}
template debugMsg(typeName: string, procName: string) =
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(debug):
{.pop.}
var message = typeName
message &= ": "
message &= procName
debugMsg(message)
else:
{.pop.}
proc debugMsg(typeName: string, procName: string, userMessage: string) =
var message = typeName
message &= ": "
message &= procName
message &= " "
message &= userMessage
debugMsg(message)
template debugMsg(typeName: string, procName: string, userMessage: string) =
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(debug):
{.pop.}
var message = typeName
message &= ": "
message &= procName
message &= " "
message &= userMessage
debugMsg(message)
else:
{.pop.}
template newWithCondFinalizer(variable: expr, finalizer: expr) =
## calls ``new`` but only setting a finalizer when ``nimqml_use_finalizers``
## is defined
{.push warning[user]: off.} # workaround to remove warnings; this won't be needed soon
when defined(nimqml_use_finalizers):
{.pop.}
new(variable, finalizer)
else:
{.pop.}
new(variable)
# QVariant
proc dos_qvariant_create(variant: var pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_int(variant: var pointer, value: cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_bool(variant: var pointer, value: bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_string(variant: var pointer, value: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_qobject(variant: var pointer, value: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_delete(variant: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_isnull(variant: pointer, isNull: var bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toInt(variant: pointer, value: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toBool(variant: pointer, value: var bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toString(variant: pointer, value: var cstring, length: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setInt(variant: pointer, value: cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setBool(variant: pointer, value: bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setString(variant: pointer, value: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create(variant: var RawQVariant) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_int(variant: var RawQVariant, value: cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_bool(variant: var RawQVariant, value: bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_string(variant: var RawQVariant, value: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_qobject(variant: var RawQVariant, value: RawQObject) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_qvariant(variant: var RawQVariant, value: RawQVariant) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_float(variant: var RawQVariant, value: cfloat) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_create_double(variant: var RawQVariant, value: cdouble) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_delete(variant: RawQVariant) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_isnull(variant: RawQVariant, isNull: var bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toInt(variant: RawQVariant, value: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toBool(variant: RawQVariant, value: var bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toString(variant: RawQVariant, value: var cstring, length: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setInt(variant: RawQVariant, value: cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setBool(variant: RawQVariant, value: bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setString(variant: RawQVariant, value: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_assign(leftValue: RawQVariant, rightValue: RawQVariant) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toFloat(variant: RawQVariant, value: var cfloat) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setFloat(variant: RawQVariant, value: float) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_toDouble(variant: RawQVariant, value: var cdouble) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setDouble(variant: RawQVariant, value: cdouble) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qvariant_setQObject(variant: RawQVariant, value: RawQObject) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_chararray_delete(rawCString: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc create*(variant: var QVariant) =
proc create*(variant: QVariant) =
## Create a new QVariant
var data: pointer
dos_qvariant_create(data)
variant = QVariant(data)
dos_qvariant_create(variant.data)
variant.deleted = false
proc create*(variant: var QVariant, value: cint) =
proc create*(variant: QVariant, value: cint) =
## Create a new QVariant given a cint value
var data: pointer
dos_qvariant_create_int(data, value)
variant = QVariant(data)
dos_qvariant_create_int(variant.data, value)
variant.deleted = false
proc create*(variant: var QVariant, value: bool) =
proc create*(variant: QVariant, value: bool) =
## Create a new QVariant given a bool value
var data: pointer
dos_qvariant_create_bool(data, value)
variant = QVariant(data)
dos_qvariant_create_bool(variant.data, value)
variant.deleted = false
proc create*(variant: var QVariant, value: string) =
proc create*(variant: QVariant, value: string) =
## Create a new QVariant given a string value
var data: pointer
dos_qvariant_create_string(data, value)
variant = QVariant(data)
dos_qvariant_create_string(variant.data, value)
variant.deleted = false
proc create*(variant: var QVariant, value: QObject) =
proc create*(variant: QVariant, value: QObject) =
## Create a new QVariant given a QObject
var data: pointer
dos_qvariant_create_qobject(data, value.data)
variant = QVariant(data)
dos_qvariant_create_qobject(variant.data, value.data.RawQObject)
variant.deleted = false
proc create*(variant: QVariant, value: RawQVariant) =
## Create a new QVariant given another QVariant.
## The inner value of the QVariant is copied
dos_qvariant_create_qvariant(variant.data, value)
variant.deleted = false
proc create*(variant: QVariant, value: cfloat) =
## Create a new QVariant given a cfloat value
dos_qvariant_create_float(variant.data, value)
variant.deleted = false
proc create*(variant: QVariant, value: QVariant) =
## Create a new QVariant given another QVariant.
## The inner value of the QVariant is copied
create(variant, value.data)
proc delete*(variant: QVariant) =
## Delete a QVariant
debugMsg("QVariant", "delete")
dos_qvariant_delete(pointer(variant))
if not variant.deleted:
debugMsg("QVariant", "delete")
dos_qvariant_delete(variant.data)
variant.data = nil.RawQVariant
variant.deleted = true
proc newQVariant*(): QVariant =
## Return a new QVariant
newWithCondFinalizer(result, delete)
result.create()
proc newQVariant*(value: cint): QVariant =
## Return a new QVariant given a cint
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: bool): QVariant =
## Return a new QVariant given a bool
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: string): QVariant =
## Return a new QVariant given a string
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: QObject): QVariant =
## Return a new QVariant given a QObject
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: RawQVariant): QVariant =
## Return a new QVariant given a raw QVariant pointer
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: QVariant): QVariant =
## Return a new QVariant given another QVariant
newWithCondFinalizer(result, delete)
result.create(value)
proc newQVariant*(value: float): QVariant =
## Return a new QVariant given a float
newWithCondFinalizer(result, delete)
result.create(value)
proc isNull*(variant: QVariant): bool =
## Return true if the QVariant value is null, false otherwise
dos_qvariant_isnull(pointer(variant), result)
dos_qvariant_isnull(variant.data, result)
proc intVal*(variant: QVariant): int =
## Return the QVariant value as int
var rawValue: cint
dos_qvariant_toInt(pointer(variant), rawValue)
result = cast[int](rawValue)
dos_qvariant_toInt(variant.data, rawValue)
result = rawValue.cint
proc `intVal=`*(variant: QVariant, value: int) =
## Sets the QVariant value int value
var rawValue = cast[cint](value)
dos_qvariant_setInt(pointer(variant), rawValue)
var rawValue = value.cint
dos_qvariant_setInt(variant.data, rawValue)
proc boolVal*(variant: QVariant): bool =
## Return the QVariant value as bool
dos_qvariant_toBool(pointer(variant), result)
dos_qvariant_toBool(variant.data, result)
proc `boolVal=`*(variant: QVariant, value: bool) =
## Sets the QVariant bool value
dos_qvariant_setBool(pointer(variant), value)
dos_qvariant_setBool(variant.data, value)
proc floatVal*(variant: QVariant): float =
## Return the QVariant value as float
var rawValue: cfloat
dos_qvariant_toFloat(variant.data, rawValue)
result = rawValue.cfloat
proc `floatVal=`*(variant: QVariant, value: float) =
## Sets the QVariant float value
dos_qvariant_setFloat(variant.data, value.cfloat)
proc doubleVal*(variant: QVariant): cdouble =
## Return the QVariant value as double
var rawValue: cdouble
dos_qvariant_toDouble(variant.data, rawValue)
result = rawValue
proc `doubleVal=`*(variant: QVariant, value: cdouble) =
## Sets the QVariant double value
dos_qvariant_setDouble(variant.data, value)
proc stringVal*(variant: QVariant): string =
## Return the QVariant value as string
var rawCString: cstring
var rawCStringLength: cint
dos_qvariant_toString(pointer(variant), rawCString, rawCStringLength)
dos_qvariant_toString(variant.data, rawCString, rawCStringLength)
result = $rawCString
dos_chararray_delete(rawCString)
proc `stringVal=`*(variant: QVariant, value: string) =
## Sets the QVariant string value
dos_qvariant_setString(pointer(variant), value)
dos_qvariant_setString(variant.data, value)
proc `qobjectVal=`*(variant: QVariant, value: QObject) =
## Sets the QVariant qobject value
dos_qvariant_setQObject(variant.data, value.data.RawQObject)
proc assign*(leftValue: QVariant, rightValue: QVariant) =
## Assign a QVariant with another. The inner value of the QVariant is copied
dos_qvariant_assign(leftValue.data, rightValue.data)
# QQmlApplicationEngine
proc dos_qqmlapplicationengine_create(engine: var pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlapplicationengine_load(engine: pointer, filename: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlapplicationengine_context(engine: pointer, context: var pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlapplicationengine_delete(engine: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlapplicationengine_create(engine: var RawQQmlApplicationEngine) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlapplicationengine_load(engine: RawQQmlApplicationEngine, filename: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlapplicationengine_context(engine: RawQQmlApplicationEngine, context: var QQmlContext) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlapplicationengine_delete(engine: RawQQmlApplicationEngine) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc create*(engine: var QQmlApplicationEngine) =
proc create*(engine: QQmlApplicationEngine) =
## Create an new QQmlApplicationEngine
var temp: pointer
dos_qqmlapplicationengine_create(temp)
engine = QQmlApplicationEngine(temp)
dos_qqmlapplicationengine_create(engine.data)
engine.deleted = false
proc load*(engine: QQmlApplicationEngine, filename: cstring) =
## Load the given Qml file
dos_qqmlapplicationengine_load(pointer(engine), filename)
dos_qqmlapplicationengine_load(engine.data, filename)
proc rootContext*(engine: QQmlApplicationEngine): QQmlContext =
## Return the engine root context
var context: pointer
dos_qqmlapplicationengine_context(pointer(engine), context)
result = cast[QQmlContext](context)
dos_qqmlapplicationengine_context(engine.data, result)
proc delete*(engine: QQmlApplicationEngine) =
## Delete the given QQmlApplicationEngine
debugMsg("QQmlApplicationEngine", "delete")
dos_qqmlapplicationengine_delete(pointer(engine))
if not engine.deleted:
debugMsg("QQmlApplicationEngine", "delete")
dos_qqmlapplicationengine_delete(engine.data)
engine.data = nil.RawQQmlApplicationEngine
engine.deleted = true
proc newQQmlApplicationEngine*(): QQmlApplicationEngine =
## Return a new QQmlApplicationEngine
newWithCondFinalizer(result, delete)
result.create()
# QQmlContext
proc dos_qqmlcontext_setcontextproperty(context: pointer, propertyName: cstring, propertyValue: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qqmlcontext_setcontextproperty(context: QQmlContext, propertyName: cstring, propertyValue: RawQVariant) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc setContextProperty*(context: QQmlContext, propertyName: string, propertyValue: QVariant) =
## Sets a new property with the given value
dos_qqmlcontext_setcontextproperty(pointer(context), propertyName, pointer(propertyValue))
dos_qqmlcontext_setcontextproperty(context, propertyName, propertyValue.data)
# QApplication
proc dos_qguiapplication_create() {.cdecl, dynlib: "libDOtherSide.so", importc.}
proc dos_qguiapplication_exec() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qguiapplication_delete() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qapplication_create() {.cdecl, dynlib: "libDOtherSide.so", importc.}
proc dos_qapplication_exec() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qapplication_quit() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qapplication_delete() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc create*(application: QApplication) =
## Create a new QApplication
dos_qguiapplication_create()
dos_qapplication_create()
application.deleted = false
proc exec*(application: QApplication) =
## Start the Qt event loop
dos_qguiapplication_exec()
dos_qapplication_exec()
proc quit*(application: QApplication) =
## Quit the Qt event loop
dos_qapplication_quit()
proc delete*(application: QApplication) =
## Delete the given QApplication
dos_qguiapplication_delete()
if not application.deleted:
debugMsg("QApplication", "delete")
dos_qapplication_delete()
application.deleted = true
proc newQApplication*(): QApplication =
## Return a new QApplication
newWithCondFinalizer(result, delete)
result.create()
# QGuiApplication
proc dos_qguiapplication_create() {.cdecl, dynlib: "libDOtherSide.so", importc.}
proc dos_qguiapplication_exec() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qguiapplication_quit() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qguiapplication_delete() {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc create*(application: QGuiApplication) =
## Create a new QApplication
dos_qguiapplication_create()
application.deleted = false
proc exec*(application: QGuiApplication) =
## Start the Qt event loop
dos_qguiapplication_exec()
proc quit*(application: QGuiApplication) =
## Quit the Qt event loop
dos_qguiapplication_quit()
proc delete*(application: QGuiApplication) =
## Delete the given QApplication
if not application.deleted:
debugMsg("QApplication", "delete")
dos_qguiapplication_delete()
application.deleted = true
proc newQGuiApplication*(): QGuiApplication =
## Return a new QApplication
newWithCondFinalizer(result, delete)
result.create()
# QObject
type QVariantArray {.unchecked.} = array[0..0, QVariant]
type QVariantArrayPtr = ptr QVariantArray
type RawQVariantArray {.unchecked.} = array[0..0, RawQVariant]
type RawQVariantArrayPtr = ptr RawQVariantArray
type RawQVariantSeq = seq[RawQVariant]
proc toVariantSeq(args: QVariantArrayPtr, numArgs: cint): seq[QVariant] =
proc toVariantSeq(args: RawQVariantArrayPtr, numArgs: cint): seq[QVariant] =
result = @[]
for i in 0..numArgs-1:
result.add(args[i])
result.add(newQVariant(args[i]))
proc toRawVariantSeq(args: openarray[QVariant]): RawQVariantSeq =
result = @[]
for variant in args:
result.add(variant.data)
proc delete(sequence: seq[QVariant]) =
for variant in sequence:
variant.delete
proc toCIntSeq(metaTypes: openarray[QMetaType]): seq[cint] =
result = @[]
for metaType in metaTypes:
result.add(cint(metaType))
type QObjectCallBack = proc(nimobject: ptr QObjectObj, slotName: RawQVariant, numArguments: cint, arguments: RawQVariantArrayPtr) {.cdecl.}
proc dos_qobject_create(qobject: var pointer, nimobject: pointer, qobjectCallback: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_delete(qobject: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_slot_create(qobject: pointer, slotName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, slotIndex: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_signal_create(qobject: pointer, signalName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, signalIndex: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_signal_emit(qobject: pointer, signalName: cstring, argumentsCount: cint, arguments: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_property_create(qobject: pointer, propertyName: cstring, propertyType: cint, readSlot: cstring, writeSlot: cstring, notifySignal: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_create(qobject: var RawQObject, nimobject: ptr QObjectObj, qobjectCallback: QObjectCallBack) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_delete(qobject: RawQObject) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_slot_create(qobject: RawQObject, slotName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, slotIndex: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_signal_create(qobject: RawQObject, signalName: cstring, argumentsCount: cint, argumentsMetaTypes: ptr cint, signalIndex: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_signal_emit(qobject: RawQObject, signalName: cstring, argumentsCount: cint, arguments: ptr RawQVariant) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qobject_property_create(qobject: RawQObject, propertyName: cstring, propertyType: cint, readSlot: cstring, writeSlot: cstring, notifySignal: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
method onSlotCalled*(nimobject: QObject, slotName: string, args: openarray[QVariant]) =
## Called from the NimQml bridge when a slot is called from Qml.
## Subclasses can override the given method for handling the slot call
discard()
proc qobjectCallback(nimobject: pointer, slotName: QVariant, numArguments: cint, arguments: QVariantArrayPtr) {.exportc.} =
var nimQObjectCasted = cast[ptr QObject](nimobject)
# forward to the QObject subtype instance
nimQObjectCasted[].onSlotCalled(slotName.stringVal, arguments.toVariantSeq(numArguments))
proc qobjectCallback(nimObject: ptr QObjectObj, slotName: RawQVariant, numArguments: cint, arguments: RawQVariantArrayPtr) {.cdecl, exportc.} =
if qobjectRegistry[nimObject]:
let qobject = cast[QObject](nimObject)
GC_ref(qobject)
let slotNameAsQVariant = newQVariant(slotName)
defer: slotNameAsQVariant.delete
let argumentsAsQVariant = arguments.toVariantSeq(numArguments)
defer: argumentsAsQVariant.delete
# Forward to args to the slot
qobject.onSlotCalled(slotNameAsQVariant.stringVal, argumentsAsQVariant)
# Update the slot return value
dos_qvariant_assign(arguments[0], argumentsAsQVariant[0].data)
GC_unref(qobject)
proc create*(qobject: var QObject) =
proc create*(qobject: QObject) =
## Create a new QObject
qobject.name = "QObject"
debugMsg("QObject", "create")
qobject.deleted = false
qobject.slots = initTable[string,cint]()
qobject.signals = initTable[string, cint]()
dos_qobject_create(qobject.data, addr(qobject), qobjectCallback)
qobject.properties = initTable[string, cint]()
let qobjectPtr = addr(qobject[])
dos_qobject_create(qobject.data, qobjectPtr, qobjectCallback)
qobjectRegistry[qobjectPtr] = true
proc delete*(qobject: QObject) =
## Delete the given QObject
dos_qobject_delete(qobject.data)
if not qobject.deleted:
debugMsg("QObject", "delete")
let qobjectPtr = addr(qobject[])
qobjectRegistry.del qobjectPtr
dos_qobject_delete(qobject.data)
qobject.data = nil.RawQObject
qobject.deleted = true
proc newQObject*(): QObject =
## Return a new QObject
newWithCondFinalizer(result, delete)
result.create()
proc registerSlot*(qobject: var QObject,
proc registerSlot*(qobject: QObject,
slotName: string,
metaTypes: openarray[QMetaType]) =
## Register a slot in the QObject with the given name and signature
# Copy the metatypes array
var copy = toCIntSeq(metatypes)
var index: cint
dos_qobject_slot_create(qobject.data, slotName, cint(copy.len), cast[ptr cint](addr(copy[0])), index)
dos_qobject_slot_create(qobject.data, slotName, cint(copy.len), addr(copy[0].cint), index)
qobject.slots[slotName] = index
proc registerSignal*(qobject: var QObject,
proc registerSignal*(qobject: QObject,
signalName: string,
metatypes: openarray[QMetaType]) =
## Register a signal in the QObject with the given name and signature
var index: cint
if metatypes.len > 0:
var copy = toCIntSeq(metatypes)
dos_qobject_signal_create(qobject.data, signalName, cast[cint](copy.len), cast[ptr cint](addr(copy[0])), index)
dos_qobject_signal_create(qobject.data, signalName, copy.len.cint, addr(copy[0].cint), index)
else:
dos_qobject_signal_create(qobject.data, signalName, 0, cast[ptr cint](0), index)
dos_qobject_signal_create(qobject.data, signalName, 0, nil, index)
qobject.signals[signalName] = index
proc registerProperty*(qobject: var QObject,
proc registerProperty*(qobject: QObject,
propertyName: string,
propertyType: QMetaType,
readSlot: string,
writeSlot: string,
notifySignal: string) =
## Register a property in the QObject with the given name and type.
dos_qobject_property_create(qobject.data, propertyName, cast[cint](propertyType), readSlot, writeSlot, notifySignal)
assert propertyName != nil, "property name cannot be nil"
# don't convert a nil string, else we get a strange memory address
let cReadSlot: cstring = if readSlot == nil: cast[cstring](nil) else: readSlot
let cWriteSlot: cstring = if writeSlot == nil: cast[cstring](nil) else: writeSlot
let cNotifySignal: cstring = if notifySignal == nil: cast[cstring](nil) else: notifySignal
dos_qobject_property_create(qobject.data, propertyName, propertyType.cint, cReadSlot, cWriteSlot, cNotifySignal)
proc emit*(qobject: QObject, signalName: string, args: openarray[QVariant] = []) =
## Emit the signal with the given name and values
if args.len > 0:
var copy: seq[QVariant]
for i in 0..args.len-1:
copy.add(args[i])
dos_qobject_signal_emit(qobject.data, signalName, cast[cint](args.len), cast[pointer](addr(copy[0])))
var copy = args.toRawVariantSeq
dos_qobject_signal_emit(qobject.data, signalName, copy.len.cint, addr(copy[0]))
else:
dos_qobject_signal_emit(qobject.data, signalName, 0, cast[pointer](0))
dos_qobject_signal_emit(qobject.data, signalName, 0, nil)
# QQuickView
proc dos_qquickview_create(view: var pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_delete(view: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_show(view: pointer) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_source(view: pointer, filename: var cstring, length: var int) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_set_source(view: pointer, filename: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_create(view: var RawQQuickView) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_delete(view: RawQQuickView) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_show(view: RawQQuickView) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_source(view: RawQQuickView, filename: var cstring, length: var int) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qquickview_set_source(view: RawQQuickView, filename: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc create(view: var QQuickView) =
## Create a new QQuickView
var temp: pointer
dos_qquickview_create(temp)
view = QQuickView(temp)
dos_qquickview_create(view.data)
view.deleted = false
proc source(view: QQuickView): cstring =
## Return the source Qml file loaded by the view
var length: int
dos_qquickview_source(pointer(view), result, length)
dos_qquickview_source(view.data, result, length)
proc `source=`(view: QQuickView, filename: cstring) =
## Sets the source Qml file laoded by the view
dos_qquickview_set_source(pointer(view), filename)
dos_qquickview_set_source(view.data, filename)
proc show(view: QQuickView) =
## Sets the view visible
dos_qquickview_show(pointer(view))
dos_qquickview_show(view.data)
proc delete(view: QQuickView) =
## Delete the given QQuickView
dos_qquickview_delete(pointer(view))
if not view.deleted:
debugMsg("QQuickView", "delete")
dos_qquickview_delete(view.data)
view.data = nil.RawQQuickView
view.deleted = true
proc newQQuickView*(): QQuickView =
## Return a new QQuickView
newWithCondFinalizer(result, delete)
result.create()
# QModelIndex
proc dos_qmodelindex_create(modelIndex: var RawQModelIndex) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_delete(modelIndex: RawQModelIndex) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_row(modelIndex: RawQModelIndex, row: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_column(modelIndex: RawQModelIndex, column: var cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_isValid(modelIndex: RawQModelIndex, column: var bool) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_data(modelIndex: RawQModelIndex, role: cint, data: RawQVariant) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_parent(modelIndex: RawQModelIndex, parent: RawQModelIndex) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_child(modelIndex: RawQModelIndex, row: cint, column: cint, parent: RawQModelIndex) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qmodelindex_sibling(modelIndex: RawQModelIndex, row: cint, column: cint, sibling: RawQModelIndex) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc create*(modelIndex: var QModelIndex) =
## Create a new QModelIndex
dos_qmodelindex_create(modelIndex.data)
modelIndex.deleted = false
proc create*(modelIndex: var QModelIndex, rawQModelIndex: RawQModelIndex) =
## Create a new QModelIndex
modelIndex.data = rawQModelIndex
modelIndex.deleted = false
proc delete*(modelIndex: QModelIndex) =
## Delete the given QModelIndex
if not modelIndex.deleted:
debugMsg("QModelIndex", "delete")
dos_qmodelindex_delete(modelIndex.data)
modelIndex.data = nil.RawQModelIndex
modelIndex.deleted = true
proc newQModelIndex*(): QModelIndex =
## Return a new QModelIndex
newWithCondFinalizer(result, delete)
result.create()
proc newQModelIndex*(rawQModelIndex: RawQModelIndex): QModelIndex =
## Return a new QModelIndex given a raw index
newWithCondFinalizer(result, delete)
result.create(rawQModelIndex)
proc row*(modelIndex: QModelIndex): cint =
## Return the index row
dos_qmodelindex_row(modelIndex.data, result)
proc column*(modelIndex: QModelIndex): cint =
## Return the index column
dos_qmodelindex_column(modelIndex.data, result)
proc isValid*(modelIndex: QModelIndex): bool =
## Return true if the index is valid, false otherwise
dos_qmodelindex_isValid(modelIndex.data, result)
proc data*(modelIndex: QModelIndex, role: cint): QVariant =
## Return the model data associated to the given role
result = newQVariant()
dos_qmodelindex_data(modelIndex.data, role, result.data)
proc parent*(modelIndex: QModelIndex): QModelIndex =
## Return the parent index
result = newQModelIndex()
dos_qmodelindex_parent(modelIndex.data, result.data)
proc child*(modelIndex: QModelIndex, row: cint, column: cint): QModelIndex =
## Return the child index associated to the given row and column
result = newQModelIndex()
dos_qmodelindex_child(modelIndex.data, row, column, result.data)
proc sibling*(modelIndex: QModelIndex, row: cint, column: cint): QModelIndex =
## Return the sibling index associated to the given row and column
result = newQModelIndex()
dos_qmodelindex_sibling(modelIndex.data, row, column, result.data)
# QHashIntByteArray
proc dos_qhash_int_qbytearray_create(qHash: var RawQHashIntByteArray) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qhash_int_qbytearray_delete(qHash: RawQHashIntByteArray) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qhash_int_qbytearray_insert(qHash: RawQHashIntByteArray, key: int, value: cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qhash_int_qbytearray_value(qHash: RawQHashIntByteArray, key: int, value: var cstring) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc create*(qHash: var QHashIntByteArray) =
## Create the QHash
debugMsg("QHashIntByteArray", "create")
dos_qhash_int_qbytearray_create(qHash.data)
qHash.deleted = false
proc delete*(qHash: QHashIntByteArray) =
## Delete the QHash
if not qHash.deleted:
debugMsg("QHashIntByteArray", "delete")
dos_qhash_int_qbytearray_delete(qHash.data)
qHash.deleted = true
proc insert*(qHash: QHashIntByteArray, key: int, value: cstring) =
## Insert the value at the given key
dos_qhash_int_qbytearray_insert(qHash.data, key, value)
proc value*(qHash: QHashIntByteArray, key: int): string =
## Return the value associated at the given key
var rawString: cstring
dos_qhash_int_qbytearray_value(qHash.data, key, rawString)
result = $rawString
dos_chararray_delete(rawString)
proc newQHashIntQByteArray*(): QHashIntByteArray =
## Create a new QHashIntQByteArray
newWithCondFinalizer(result, delete)
result.create()
# QAbstractListModel
type
RowCountCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl.}
ColumnCountCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl.}
DataCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, role: cint, result: RawQVariant) {.cdecl.}
SetDataCallback = proc(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, value: RawQVariant, role: cint, result: var bool) {.cdecl.}
RoleNamesCallback = proc(modelObject: ptr QAbstractListModelObj, result: RawQHashIntByteArray) {.cdecl.}
FlagsCallback = proc(modelObject: ptr QAbstractListModelObj, index: RawQModelIndex, result: var cint) {.cdecl.}
HeaderDataCallback = proc(modelObject: ptr QAbstractListModelObj, section: cint, orientation: cint, role: cint, result: RawQVariant) {.cdecl.}
proc dos_qabstractlistmodel_create(model: var RawQAbstractListModel,
modelPtr: ptr QAbstractListModelObj,
qobjectCallback: QObjectCallBack,
rowCountCallback: RowCountCallback,
columnCountCallback: ColumnCountCallback,
dataCallback: DataCallback,
setDataCallback: SetDataCallBack,
roleNamesCallback: RoleNamesCallback,
flagsCallback: FlagsCallback,
headerDataCallback: HeaderDataCallback) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_delete(model: RawQAbstractListModel) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_beginInsertRows(model: RawQAbstractListModel,
parentIndex: RawQModelIndex,
first: cint,
last: cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_endInsertRows(model: RawQAbstractListModel) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_beginRemoveRows(model: RawQAbstractListModel,
parentIndex: RawQModelIndex,
first: cint,
last: cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_endRemoveRows(model: RawQAbstractListModel) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_beginResetModel(model: RawQAbstractListModel) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_endResetModel(model: RawQAbstractListModel) {.cdecl, dynlib:"libDOtherSide.so", importc.}
proc dos_qabstractlistmodel_dataChanged(model: RawQAbstractListModel,
parentLeft: RawQModelIndex,
bottomRight: RawQModelIndex,
rolesArrayPtr: ptr cint,
rolesArrayLength: cint) {.cdecl, dynlib:"libDOtherSide.so", importc.}
method rowCount*(model: QAbstractListModel, index: QModelIndex): cint =
## Return the model's row count
return 0
proc rowCountCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "rowCountCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
result = model.rowCount(index)
method columnCount*(model: QAbstractListModel, index: QModelIndex): cint =
## Return the model's column count
return 1
proc columnCountCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "columnCountCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
result = model.columnCount(index)
method data*(model: QAbstractListModel, index: QModelIndex, role: cint): QVariant =
## Return the data at the given model index and role
return nil
proc dataCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, role: cint, result: RawQVariant) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "dataCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
let variant = data(model, index, role)
if variant != nil:
dos_qvariant_assign(result, variant.data)
variant.delete
method setData*(model: QAbstractListModel, index: QModelIndex, value: QVariant, role: cint): bool =
## Sets the data at the given index and role. Return true on success, false otherwise
return false
proc setDataCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, rawQVariant: RawQVariant, role: cint, result: var bool) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "setDataCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
let variant = newQVariant(rawQVariant)
result = model.setData(index, variant, role)
method roleNames*(model: QAbstractListModel): Table[cint, cstring] =
## Return the model role names
result = initTable[cint, cstring]()
proc roleNamesCallback(modelObject: ptr QAbstractListModelObj, hash: RawQHashIntByteArray) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "roleNamesCallback")
let model = cast[QAbstractListModel](modelObject)
let table = model.roleNames()
for pair in table.pairs:
dos_qhash_int_qbytearray_insert(hash, pair.key, pair.val)
method flags*(model: QAbstractListModel, index: QModelIndex): QtItemFlag =
## Return the item flags and the given index
return QtItemFlag.None
proc flagsCallback(modelObject: ptr QAbstractListModelObj, rawIndex: RawQModelIndex, result: var cint) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "flagsCallback")
let model = cast[QAbstractListModel](modelObject)
let index = newQModelIndex(rawIndex)
result = model.flags(index).cint
method headerData*(model: QAbstractListModel, section: cint, orientation: QtOrientation, role: cint): QVariant =
## Returns the data for the given role and section in the header with the specified orientation
return nil
proc headerDataCallback(modelObject: ptr QAbstractListModelObj, section: cint, orientation: cint, role: cint, result: RawQVariant) {.cdecl, exportc.} =
debugMsg("QAbstractListModel", "headerDataCallback")
let model = cast[QAbstractListModel](modelObject)
let variant = model.headerData(section, orientation.QtOrientation, role)
if variant != nil:
dos_qvariant_assign(result, variant.data)
variant.delete
proc create*(model: var QAbstractListModel) =
## Create a new QAbstractListModel
debugMsg("QAbstractListModel", "create")
model.slots = initTable[string,cint]()
model.signals = initTable[string, cint]()
model.properties = initTable[string, cint]()
model.deleted = false
let modelPtr = addr(model[])
dos_qabstractlistmodel_create(model.data.RawQAbstractListModel, modelPtr, qobjectCallback, rowCountCallback, columnCountCallback, dataCallback, setDataCallback, roleNamesCallback, flagsCallback, headerDataCallback)
qobjectRegistry[modelPtr] = true
proc delete*(model: QAbstractListModel) =
## Delete the given QAbstractListModel
if not model.deleted:
debugMsg("QAbstractListModel", "delete")
let modelPtr = addr(model[])
qobjectRegistry.del modelPtr
dos_qabstractlistmodel_delete(model.data.RawQAbstractListModel)
model.data = nil.RawQObject
model.deleted = true
proc newQAbstractListModel*(): QAbstractListModel =
## Return a new QAbstractListModel
newWithCondFinalizer(result, delete)
result.create()
proc beginInsertRows*(model: QAbstractListModel, parentIndex: QModelIndex, first: int, last: int) =
## Notify the view that the model is about to inserting the given number of rows
dos_qabstractlistmodel_beginInsertRows(model.data.RawQAbstractListModel, parentIndex.data, first.cint, last.cint)
proc endInsertRows*(model: QAbstractListModel) =
## Notify the view that the rows have been inserted
dos_qabstractlistmodel_endInsertRows(model.data.RawQAbstractListModel)
proc beginRemoveRows*(model: QAbstractListModel, parentIndex: QModelIndex, first: int, last: int) =
## Notify the view that the model is about to remove the given number of rows
dos_qabstractlistmodel_beginRemoveRows(model.data.RawQAbstractListModel, parentIndex.data, first.cint, last.cint)
proc endRemoveRows*(model: QAbstractListModel) =
## Notify the view that the rows have been removed
dos_qabstractlistmodel_endRemoveRows(model.data.RawQAbstractListModel)
proc beginResetModel*(model: QAbstractListModel) =
## Notify the view that the model is about to resetting
dos_qabstractlistmodel_beginResetModel(model.data.RawQAbstractListModel)
proc endResetModel*(model: QAbstractListModel) =
## Notify the view that model has finished resetting
dos_qabstractlistmodel_endResetModel(model.data.RawQAbstractListModel)
proc dataChanged*(model: QAbstractListModel,
topLeft: QModelIndex,
bottomRight: QModelIndex,
roles: seq[cint]) =
## Notify the view that the model data changed
var copy = roles
dos_qabstractlistmodel_dataChanged(model.data.RawQAbstractListModel, topLeft.data, bottomRight.data, copy[0].addr, copy.len.cint)

View File

@ -1,6 +1,6 @@
[Package]
name = "NimQml"
version = "0.2.0"
version = "0.3.0"
author = "Filippo Cucchetto, Will Szumski"
description = "QML bindings for Nimrod"
license = "GPLv3"

View File

@ -17,6 +17,8 @@ let nimFromQtVariant {.compileTime.} = {
"int" : "intVal",
"string" : "stringVal",
"bool" : "boolVal",
"float" : "floatVal",
"QObject" : "qobjectVal",
}.toTable
let nim2QtMeta {.compileTime.} = {
@ -24,6 +26,7 @@ let nim2QtMeta {.compileTime.} = {
"int" : "Int",
"string" : "QString",
"pointer" : "VoidStar",
"QObject" : "QObjectStar",
"QVariant": "QVariant",
"" : "Void", # no return, which is represented by an nnkEmpty node
}.toTable
@ -210,7 +213,7 @@ proc getArgName*(arg: PNimrodNode): PNimrodNode {.compileTime.} =
proc addSignalBody(signal: PNimrodNode): PNimrodNode {.compileTime.} =
# e.g: produces: emit(MyQObject, "nameChanged")
expectKind signal, nnkMethodDef
assert signal.kind in {nnkMethodDef, nnkProcDef}
result = newStmtList()
# if exported, will use postfix
let name = if signal.name.kind == nnkIdent: signal.name else: signal.name[1]
@ -225,14 +228,18 @@ proc addSignalBody(signal: PNimrodNode): PNimrodNode {.compileTime.} =
args.add getArgName params[i]
result.add newCall("emit", args)
#FIXME: changed typ from typedesc to expr to workaround Nim issue #1874
template declareOnSlotCalled(typ: expr): stmt =
#FIXME: changed typ from typedesc to expr to workaround Nim issue #1874
# This is declared dirty so that identifers are not bound to symbols.
# The alternative is to use `removeOpenSym` as we did for `prototypeCreate`.
# We should decide which method is preferable.
template prototypeOnSlotCalled(typ: expr): stmt {.dirty.} =
method onSlotCalled(myQObject: typ, slotName: string, args: openarray[QVariant]) =
discard
var super = (typ.superType())(myQObject)
procCall onSlotCalled(super, slotName, args)
#FIXME: changed parent, typ from typedesc to expr to workaround Nim issue #1874
template prototypeCreate(typ: expr): stmt =
template create*(myQObject: var typ) =
proc create*(myQObject: var typ) =
var super = (typ.superType())(myQObject)
procCall create(super)
@ -266,137 +273,55 @@ proc getIdentDefName*(a: PNimrodNode): PNimrodNode {.compileTime.} =
elif a[0].kind == nnkPostFix:
return a[0][1]
macro QtObject*(qtDecl: stmt): stmt {.immediate.} =
## Generates boiler plate code for registering signals, slots
## and properties.
##
## Currently generates:
## - create: a method to register signal, slots and properties
## - superType: a template that returns the super type of the
## object defined within the macro body
## - onSlotCalled: a method to dispatch an on slot call to the
## appropiate method.
##
## Current limitations:
## - only one type can be defined within the body of code sent to the
## the macro. It is assumed, but not checked, that somewhere in the
## inheritance hierarchy this object derives from ``QObject``.
## - generics are not currently supported
expectKind(qtDecl, nnkStmtList)
#echo treeRepr qtDecl
result = newStmtList()
var slots = newSeq[PNimrodNode]()
var properties = newSeq[PNimrodNode]()
var signals = newSeq[PNimrodNode]()
# holds all user defined procedures so we can add them after create
var userDefined = newSeq[PNimrodNode]()
# assume only one type per section for now
var typ: PNimrodNode
for it in qtDecl.children():
if it.kind == nnkTypeSection:
let typeDecl = it.findChild(it.kind == nnkTypeDef)
let superType = typeDecl.getSuperType()
if superType.kind == nnkEmpty:
# allow simple types and type aliases
result.add it
else:
# may come in useful if we want to check objects inherit from QObject
#let superName = if superType.kind == nnkIdent: superType
# else: superType.getNodeOf(nnkIdent)
if typ != nil:
error("you may not define more than one type " &
"within the code block passed to this macro")
else: # without this else, it fails to compile
typ = typeDecl
result.add it
result.add genSuperTemplate(typeDecl)
elif it.kind == nnkMethodDef:
if it.hasPragma("slot"):
let pragma = it.pragma()
it.pragma = pragma.removePragma("slot")
slots.add it # we need to gensome code later
result.add it
elif it.hasPragma("signal"):
let pragma = it.pragma()
it.pragma = pragma.removePragma("signal")
it.body = addSignalBody(it)
result.add it
signals.add it
else:
userDefined.add it
elif it.kind == nnkProcDef:
userDefined.add it
elif it.kind == nnkCommand:
let bracket = it[0]
if bracket.kind != nnkBracketExpr:
error("do not know how to handle: \n" & repr(it))
# BracketExpr
# Ident !"QtProperty"
# Ident !"string"
let cmdIdent = bracket[0]
if cmdIdent == nil or cmdIdent.kind != nnkIdent or
($cmdIdent).toLower() != "qtproperty":
error("do not know how to handle: \n" & repr(it))
properties.add it
else:
# everything else should pass through unchanged
result.add it
if typ == nil:
error("you must declare an object that inherits from QObject")
proc tryHandleSigSlot(def: PNimrodNode, signals: var seq[PNimrodNode], slots: var seq[PNimrodNode],
generatedCode: var PNimrodNode): bool {.compileTime.} =
## Checks a method/proc definition for signals and slots. On finding a method/proc with
## a {.signal.} or {.slot.} pragma, it will strip the pragma, add the definition to the
## appropriate seq, append the stripped version to the generated code block and return true
## indicating the definition was a signal or a slot. If the method/proc is not a slot
## or a slot it will return false.
expectKind generatedCode, nnkStmtList
assert (not signals.isNil)
assert (not slots.isNil)
assert def.kind in {nnkMethodDef, nnkProcDef}
result = false
if def.hasPragma("slot"):
let pragma = def.pragma()
def.pragma = pragma.removePragma("slot")
slots.add def # we need to gensome code later
generatedCode.add def
result = true
elif def.hasPragma("signal"):
let pragma = def.pragma()
def.pragma = pragma.removePragma("signal")
def.body = addSignalBody(def)
generatedCode.add def
signals.add def
result = true
proc genCreateDecl(typ: PNimrodNode): PNimrodNode {.compileTime.} =
## generates forward declaration for ``create`` procedure
expectKind typ, nnkTypeDef
let typeName = typ.getTypeName()
## define onSlotCalled
var slotProto = (getAst declareOnSlotCalled(typeName))[0]
var caseStmt = newNimNode(nnkCaseStmt)
caseStmt.add ident("slotName")
for slot in slots:
var ofBranch = newNimNode(nnkOfBranch)
# for exported procedures - strip * marker
let slotName = ($slot.name).replace("*","")
ofBranch.add newLit slotName
let params = slot.params
let hasReturn = not (params[0].kind == nnkEmpty)
var branchStmts = newStmtList()
var args = newSeq[PNimrodNode]()
# first params always the object
args.add ident "myQObject"
for i in 2.. <params.len:
let pType = getArgType params[i]
# function that maps Qvariant type to nim type
let mapper = nimFromQtVariant[$pType]
let argAccess = newNimNode(nnkBracketExpr)
.add (ident "args")
.add newIntLitNode(i-1)
let dot = newDotExpr(argAccess, ident mapper)
args.add dot
var call = newCall(ident slotName, args)
if hasReturn:
# eg: args[0].strVal = getName(myQObject)
let retType = params[0]
let mapper = nimFromQtVariant[$retType]
let argAccess = newNimNode(nnkBracketExpr)
.add (ident "args")
.add newIntLitNode(0)
let dot = newDotExpr(argAccess, ident mapper)
call = newAssignment(dot, call)
branchStmts.add call
ofBranch.add branchStmts
caseStmt.add ofBranch
# add else: discard
caseStmt.add newNimNode(nnkElse)
.add newStmtList().add newNimNode(nnkDiscardStmt).add newNimNode(nnkEmpty)
slotProto.body = newStmtList().add caseStmt
result.add slotProto
# generate create method
var createProto = (getAst prototypeCreate(typeName))[0]
# the template creates loads of openSyms - replace these with idents
createProto = doRemoveOpenSym(createProto)
result = (getAst prototypeCreate(typeName))[0]
result.body = newEmptyNode()
if typ.isExported:
createProto.exportDef()
result.exportDef()
else:
createProto.unexportDef()
var createBody = createProto.templateBody
result.unexportDef()
proc genCreate(typ: PNimrodNode, signals: seq[PNimrodNode], slots: seq[PNimrodNode],
properties: seq[PNimrodNode]): PNimrodNode {.compileTime.} =
expectKind typ, nnkTypeDef
let typeName = typ.getTypeName()
result = (getAst prototypeCreate(typeName))[0]
# the template creates loads of openSyms - replace these with idents
result = doRemoveOpenSym(result)
if typ.isExported:
result.exportDef()
else:
result.unexportDef()
var createBody = result.body
for slot in slots:
let params = slot.params
let regSlotDot = newDotExpr(ident "myQObject", ident "registerSlot")
@ -423,7 +348,7 @@ macro QtObject*(qtDecl: stmt): stmt {.immediate.} =
let nimPropType = bracket[1]
let qtPropMeta = nim2QtMeta[$nimPropType]
if qtPropMeta == nil: error($nimPropType & " not supported")
let metaDot = newDotExpr(ident "QMetaType", ident qtPropMeta)
let metaDot = newDotExpr(ident "QMetaType", ident qtPropMeta)
let propertyName = property[1]
var read, write, notify: PNimrodNode
let stmtList = property[2]
@ -450,11 +375,128 @@ macro QtObject*(qtDecl: stmt): stmt {.immediate.} =
let call = newCall(regPropDot, newLit($propertyName), metaDot, readArg, writeArg, notifyArg)
createBody.add call
#echo repr createProto
result.add createProto
proc genOnSlotCalled(typ: PNimrodNode, slots: seq[PNimrodNode]): PNimrodNode {.compileTime.} =
expectKind typ, nnkTypeDef
let typeName = typ.getTypeName()
result = (getAst prototypeOnSlotCalled(typeName))[0]
var caseStmt = newNimNode(nnkCaseStmt)
caseStmt.add ident("slotName")
for slot in slots:
var ofBranch = newNimNode(nnkOfBranch)
# for exported procedures - strip * marker
let slotName = ($slot.name).replace("*","")
ofBranch.add newLit slotName
let params = slot.params
let hasReturn = not (params[0].kind == nnkEmpty)
var branchStmts = newStmtList()
var args = newSeq[PNimrodNode]()
# first params always the object
args.add ident "myQObject"
for i in 2.. <params.len:
let pType = getArgType params[i]
let argAccess = newNimNode(nnkBracketExpr)
.add (ident "args")
.add newIntLitNode(i-1)
if $pType == "QVariant":
args.add argAccess
else:
# function that maps QVariant type to nim type
let mapper = nimFromQtVariant[$pType]
let dot = newDotExpr(argAccess, ident mapper)
args.add dot
var call = newCall(ident slotName, args)
if hasReturn:
let retType = params[0]
let argAccess = newNimNode(nnkBracketExpr)
.add (ident "args")
.add newIntLitNode(0)
if $retType == "QVariant":
# eg: args[0].assign(getName(myQObject))
let dot = newDotExpr(argAccess, ident "assign")
call = newCall(dot, call)
else:
# eg: args[0].strVal = getName(myQObject)
let mapper = nimFromQtVariant[$retType]
let dot = newDotExpr(argAccess, ident mapper)
call = newAssignment(dot, call)
branchStmts.add call
ofBranch.add branchStmts
caseStmt.add ofBranch
# add else: discard
caseStmt.add newNimNode(nnkElse)
.add newStmtList().add newNimNode(nnkDiscardStmt).add newNimNode(nnkEmpty)
result.body.add caseStmt
for fn in userDefined:
result.add fn
macro QtObject*(qtDecl: stmt): stmt {.immediate.} =
## Generates boiler plate code for registering signals, slots
## and properties.
##
## Currently generates:
## - create: a method to register signal, slots and properties
## - superType: a template that returns the super type of the
## object defined within the macro body
## - onSlotCalled: a method to dispatch an on slot call to the
## appropiate method.
##
## Current limitations:
## - only one type can be defined within the body of code sent to the
## the macro. It is assumed, but not checked, that somewhere in the
## inheritance hierarchy this object derives from ``QObject``.
## - generics are not currently supported
expectKind(qtDecl, nnkStmtList)
#echo treeRepr qtDecl
result = newStmtList()
var slots = newSeq[PNimrodNode]()
var properties = newSeq[PNimrodNode]()
var signals = newSeq[PNimrodNode]()
# assume only one type per section for now
var typ: PNimrodNode
for it in qtDecl.children():
if it.kind == nnkTypeSection:
let typeDecl = it.findChild(it.kind == nnkTypeDef)
let superType = typeDecl.getSuperType()
if superType.kind == nnkEmpty:
# allow simple types and type aliases
result.add it
else:
# may come in useful if we want to check objects inherit from QObject
#let superName = if superType.kind == nnkIdent: superType
# else: superType.getNodeOf(nnkIdent)
if typ != nil:
error("you may not define more than one type " &
"within the code block passed to this macro")
else: # without this else, it fails to compile
typ = typeDecl
result.add it
result.add genSuperTemplate(typeDecl)
result.add genCreateDecl(typeDecl)
elif it.kind == nnkMethodDef:
if tryHandleSigSlot(it, signals, slots, result): continue
result.add it
elif it.kind == nnkProcDef:
if tryHandleSigSlot(it, signals, slots, result): continue
result.add it
elif it.kind == nnkCommand:
let bracket = it[0]
if bracket.kind != nnkBracketExpr:
error("do not know how to handle: \n" & repr(it))
# BracketExpr
# Ident !"QtProperty"
# Ident !"string"
let cmdIdent = bracket[0]
if cmdIdent == nil or cmdIdent.kind != nnkIdent or
($cmdIdent).toLower() != "qtproperty":
error("do not know how to handle: \n" & repr(it))
properties.add it
else:
# everything else should pass through unchanged
result.add it
if typ == nil:
error("you must declare an object that inherits from QObject")
result.add genOnSlotCalled(typ, slots)
result.add genCreate(typ, signals, slots, properties)
debug:
echo repr result

View File

@ -1,14 +1,68 @@
import tables
type
QVariant* = distinct pointer ## A QVariant
QQmlApplicationEngine* = distinct pointer ## A QQmlApplicationEngine
RawQVariant = distinct pointer
QVariant* = ref object of RootObj ## A QVariant
data: RawQVariant
deleted: bool
RawQQmlApplicationEngine = distinct pointer
QQmlApplicationEngine* = ref object of RootObj ## A QQmlApplicationEngine
data: RawQQmlApplicationEngine
deleted: bool
QApplication* = ref object of RootObj ## A QApplication
deleted: bool
QGuiApplication* = ref object of RootObj ## A QGuiApplication
deleted: bool
RawQObject = distinct pointer
QObjectObj = object of RootObj
data: RawQObject
slots: Table[string, cint]
signals: Table[string, cint]
properties: Table[string, cint]
deleted: bool
QObject* = ref QObjectObj
RawBaseQObjectObj = distinct pointer
BaseQObjectObj = object of QObjectObj
BaseQObject* = ref BaseQObjectObj ## A QObject
RawQAbstractListModel = distinct pointer
QAbstractListModelObj = object of QObjectObj
QAbstractListModel* = ref QAbstractListModelObj ## A QAbstractListModel
RawQQuickView = distinct pointer
QQuickView = ref object of RootObj ## A QQuickView
data: RawQQuickView
deleted: bool
QQmlContext* = distinct pointer ## A QQmlContext
QApplication* = distinct pointer ## A QApplication
QObject* {.inheritable.} = ref object of RootObj ## A QObject
name*: string
data*: pointer
slots*: Table[string, cint]
signals*: Table[string, cint]
properties*: Table[string, cint]
QQuickView* = distinct pointer ## A QQuickView
RawQModelIndex = distinct pointer
QModelIndex* = ref object of RootObj ## A QModelIndex
data: RawQModelIndex
deleted: bool
RawQHashIntByteArray = distinct pointer
QHashIntByteArrayObj = object of RootObj
data: RawQHashIntByteArray
deleted: bool
QHashIntByteArray* = ref QHashIntByteArrayObj ## A QHash<int,QByteArray>
QtItemFlag* {.pure.} = enum
None = 0.cint,
IsSelectable = 1.cint,
IsEditable = 2.cint,
IsDragEnabled = 4.cint,
IsDropEnabled = 8.cint,
IsUserCheckable = 16.cint,
IsEnabled = 32.cint,
IsTristate = 64.cint,
NeverHasChildren = 128.cint
QtOrientation {.pure.} = enum
Horizontal = 1.cint,
Vertical = 2.cint

View File

@ -4,6 +4,9 @@ THIS IS UNSTABLE AND ALPHA SOFTWARE
## Description
Qml bindings for both D and Nim programming languages
## Change log
The project change log can be read [here](./CHANGELOG.md).
## Documentation
The documentation for the Nim programming language can be
read [here](http://filcuc.github.io/DOtherSide/ "").