Finish 0.3.0
This commit is contained in:
commit
c600544551
|
@ -4,4 +4,5 @@ build
|
|||
*.o
|
||||
.directory
|
||||
#*#
|
||||
nimcache
|
||||
nimcache
|
||||
*.kdev4
|
|
@ -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
|
|
@ -1,3 +1,3 @@
|
|||
add_subdirectory(DOtherSide)
|
||||
add_subdirectory(DynamicQObject)
|
||||
add_subdirectory(IntegrationTest)
|
||||
#add_subdirectory(DynamicQObject)
|
||||
#add_subdirectory(IntegrationTest)
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef BASEQOBJECT_H
|
||||
#define BASEQOBJECT_H
|
||||
|
||||
#include "DynamicQObject.h"
|
||||
|
||||
class BaseQObject : public DynamicQObject<QObject> {};
|
||||
|
||||
#endif
|
|
@ -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)
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -15,7 +15,6 @@ set(HEADERS_LIST
|
|||
|
||||
set(SRC_LIST
|
||||
DynamicProperty.cpp
|
||||
DynamicQObject.cpp
|
||||
DynamicSignal.cpp
|
||||
DynamicSlot.cpp
|
||||
)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 █
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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``.
|
||||
|
|
|
@ -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)
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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 !== ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -16,5 +16,6 @@ ApplicationWindow
|
|||
SpinBox { value: qVar1}
|
||||
TextField { text: qVar2}
|
||||
CheckBox { checked: qVar3}
|
||||
SpinBox { value: qVar4; decimals: 1 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/ "").
|
||||
|
|
Loading…
Reference in New Issue