mirror of
https://github.com/qmlnet/qmlnet.git
synced 2026-05-15 14:15:54 -06:00
Added support for interacting with QObjects.
This commit is contained in:
parent
e7a228a36f
commit
a0afc0506f
35 changed files with 2052 additions and 27 deletions
|
|
@ -50,6 +50,7 @@ enum NetVariantTypeEnum {
|
|||
NetVariantTypeEnum_DateTime,
|
||||
NetVariantTypeEnum_Object,
|
||||
NetVariantTypeEnum_JSValue,
|
||||
NetVariantTypeEnum_QObject
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
344
src/native/QmlNet/QmlNet/qml/NetQObject.cpp
Normal file
344
src/native/QmlNet/QmlNet/qml/NetQObject.cpp
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
#include <QmlNet/qml/NetQObject.h>
|
||||
#include <QmlNet/qml/NetQObjectSignalConnection.h>
|
||||
#include <QmlNet/qml/NetQObjectArg.h>
|
||||
#include <QmlNet/types/NetDelegate.h>
|
||||
#include <QmlNet/types/Callbacks.h>
|
||||
#include <QMetaMethod>
|
||||
#include <QDebug>
|
||||
|
||||
NetQObject::NetQObject(QObject* qObject, bool ownsObject) :
|
||||
_qObject(qObject),
|
||||
_ownsObject(ownsObject)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NetQObject::~NetQObject()
|
||||
{
|
||||
if(_ownsObject) {
|
||||
_qObject->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
QObject* NetQObject::getQObject()
|
||||
{
|
||||
return _qObject;
|
||||
}
|
||||
|
||||
QSharedPointer<NetVariant> NetQObject::getProperty(QString propertyName, bool* wasSuccess)
|
||||
{
|
||||
QSharedPointer<NetVariant> netVariant;
|
||||
QByteArray propertyNameLocal = propertyName.toLocal8Bit();
|
||||
|
||||
if(_qObject->metaObject()->indexOfProperty(propertyNameLocal.data()) == -1) {
|
||||
if(wasSuccess) {
|
||||
*wasSuccess = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVariant result = _qObject->property(propertyNameLocal.data());
|
||||
if(!result.isNull()) {
|
||||
netVariant = QSharedPointer<NetVariant>(new NetVariant());
|
||||
NetVariant::fromQVariant(&result, netVariant);
|
||||
}
|
||||
if(wasSuccess) {
|
||||
*wasSuccess = true;
|
||||
}
|
||||
return netVariant;
|
||||
}
|
||||
|
||||
void NetQObject::setProperty(QString propertyName, QSharedPointer<NetVariant> value, bool* wasSuccess)
|
||||
{
|
||||
bool result;
|
||||
if(value == nullptr) {
|
||||
result = _qObject->setProperty(propertyName.toLocal8Bit().data(), QVariant());
|
||||
} else {
|
||||
result = _qObject->setProperty(propertyName.toLocal8Bit().data(), value->toQVariant());
|
||||
}
|
||||
if(wasSuccess) {
|
||||
*wasSuccess = result;
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<NetVariant> NetQObject::invokeMethod(QString methodName, QSharedPointer<NetVariantList> parameters, bool* wasSuccess)
|
||||
{
|
||||
int parameterCount = 0;
|
||||
if(parameters != nullptr) {
|
||||
parameterCount = parameters->count();
|
||||
}
|
||||
|
||||
// Find the best method
|
||||
int methodIndex = -1;
|
||||
QMetaMethod method;
|
||||
for(int x = 0; x < _qObject->metaObject()->methodCount(); x++) {
|
||||
method = _qObject->metaObject()->method(x);
|
||||
if(method.methodType() == QMetaMethod::Slot || method.methodType() == QMetaMethod::Method) {
|
||||
if(methodName.compare(method.name()) == 0) {
|
||||
// make sure number of parameters match
|
||||
if(method.parameterCount() == parameterCount) {
|
||||
methodIndex = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(methodIndex == -1) {
|
||||
if(wasSuccess) {
|
||||
*wasSuccess = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(parameterCount > 10) {
|
||||
qWarning() << "Attempting to invoke a method with too many parameters: current: " << parameters->count() << " expected: <=10";
|
||||
if(wasSuccess) {
|
||||
*wasSuccess = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NetQObjectArg returnValue(method.returnType());
|
||||
NetQObjectArg val0;
|
||||
NetQObjectArg val1;
|
||||
NetQObjectArg val2;
|
||||
NetQObjectArg val3;
|
||||
NetQObjectArg val4;
|
||||
NetQObjectArg val5;
|
||||
NetQObjectArg val6;
|
||||
NetQObjectArg val7;
|
||||
NetQObjectArg val8;
|
||||
NetQObjectArg val9;
|
||||
|
||||
if(parameterCount >= 1) {
|
||||
val0 = NetQObjectArg(method.parameterType(0), parameters->get(0));
|
||||
}
|
||||
if(parameterCount >= 2) {
|
||||
val0 = NetQObjectArg(method.parameterType(1), parameters->get(1));
|
||||
}
|
||||
if(parameterCount >= 3) {
|
||||
val0 = NetQObjectArg(method.parameterType(2), parameters->get(2));
|
||||
}
|
||||
if(parameterCount >= 4) {
|
||||
val0 = NetQObjectArg(method.parameterType(3), parameters->get(3));
|
||||
}
|
||||
if(parameterCount >= 5) {
|
||||
val0 = NetQObjectArg(method.parameterType(4), parameters->get(4));
|
||||
}
|
||||
if(parameterCount >= 6) {
|
||||
val0 = NetQObjectArg(method.parameterType(5), parameters->get(5));
|
||||
}
|
||||
if(parameterCount >= 7) {
|
||||
val0 = NetQObjectArg(method.parameterType(6), parameters->get(6));
|
||||
}
|
||||
if(parameterCount >= 8) {
|
||||
val0 = NetQObjectArg(method.parameterType(7), parameters->get(7));
|
||||
}
|
||||
if(parameterCount >= 9) {
|
||||
val0 = NetQObjectArg(method.parameterType(8), parameters->get(8));
|
||||
}
|
||||
if(parameterCount >= 10) {
|
||||
val0 = NetQObjectArg(method.parameterType(9), parameters->get(9));
|
||||
}
|
||||
|
||||
if(!method.invoke(_qObject,
|
||||
Qt::DirectConnection,
|
||||
returnValue.genericReturnArguemnet(),
|
||||
val0.genericArgument(),
|
||||
val1.genericArgument(),
|
||||
val2.genericArgument(),
|
||||
val3.genericArgument(),
|
||||
val4.genericArgument(),
|
||||
val5.genericArgument(),
|
||||
val6.genericArgument(),
|
||||
val7.genericArgument(),
|
||||
val8.genericArgument(),
|
||||
val9.genericArgument())) {
|
||||
if(wasSuccess) {
|
||||
*wasSuccess = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(wasSuccess) {
|
||||
*wasSuccess = true;
|
||||
}
|
||||
|
||||
returnValue.unpack();
|
||||
return returnValue.getNetVariant();
|
||||
}
|
||||
|
||||
QSharedPointer<NetQObjectSignalConnection> NetQObject::attachSignal(QString signalName, QSharedPointer<NetReference> delegate, bool* wasSucessful)
|
||||
{
|
||||
int signalMethodIndex = -1;
|
||||
QMetaMethod signalMethod;
|
||||
for(int x = 0; x <_qObject->metaObject()->methodCount(); x++) {
|
||||
signalMethod = _qObject->metaObject()->method(x);
|
||||
if(signalMethod.methodType() == QMetaMethod::Signal) {
|
||||
if(signalName.compare(signalMethod.name()) == 0) {
|
||||
signalMethodIndex = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If signal not found, dump the registered signals for debugging.
|
||||
if(signalMethodIndex < 0) {
|
||||
if(wasSucessful) {
|
||||
*wasSucessful = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QSharedPointer<NetQObjectSignalConnection> signalConnection = QSharedPointer<NetQObjectSignalConnection>(new NetQObjectSignalConnection(delegate, _qObject));
|
||||
QMetaObject::Connection connection = QObject::connect(_qObject,
|
||||
signalMethod,
|
||||
signalConnection.data(),
|
||||
signalConnection->getSignalHandler());
|
||||
|
||||
if(!connection) {
|
||||
if(wasSucessful) {
|
||||
*wasSucessful = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(wasSucessful) {
|
||||
*wasSucessful = true;
|
||||
}
|
||||
|
||||
return signalConnection;
|
||||
}
|
||||
|
||||
QSharedPointer<NetQObjectSignalConnection> NetQObject::attachNotifySignal(QString propertyName, QSharedPointer<NetReference> delegate, bool* wasSuccessful)
|
||||
{
|
||||
int propertyIndex = _qObject->metaObject()->indexOfProperty(propertyName.toLocal8Bit().data());
|
||||
if(propertyIndex == -1) {
|
||||
if(wasSuccessful) {
|
||||
*wasSuccessful = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QMetaProperty property = _qObject->metaObject()->property(propertyIndex);
|
||||
|
||||
if(property.notifySignalIndex() == -1) {
|
||||
if(wasSuccessful) {
|
||||
*wasSuccessful = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QSharedPointer<NetQObjectSignalConnection> signalConnection = QSharedPointer<NetQObjectSignalConnection>(new NetQObjectSignalConnection(delegate, _qObject));
|
||||
QMetaObject::Connection connection = QObject::connect(_qObject,
|
||||
property.notifySignal(),
|
||||
signalConnection.data(),
|
||||
signalConnection->getSignalHandler());
|
||||
|
||||
if(!connection) {
|
||||
if(wasSuccessful) {
|
||||
*wasSuccessful = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(wasSuccessful) {
|
||||
*wasSuccessful = true;
|
||||
}
|
||||
|
||||
return signalConnection;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
Q_DECL_EXPORT void net_qobject_destroy(NetQObjectContainer* qObjectContainer)
|
||||
{
|
||||
delete qObjectContainer;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT NetVariantContainer* net_qobject_getProperty(NetQObjectContainer* qObjectContainer, LPWCSTR propertyName, uchar* result)
|
||||
{
|
||||
bool wasSuccesful = false;
|
||||
auto value = qObjectContainer->qObject->getProperty(QString::fromUtf16(propertyName), &wasSuccesful);
|
||||
if(wasSuccesful) {
|
||||
*result = 1;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
if(value == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return new NetVariantContainer{ value };
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void net_qobject_setProperty(NetQObjectContainer* qObjectContainer, LPWCSTR propertyName, NetVariantContainer* netVariantContainer, uchar* result)
|
||||
{
|
||||
bool wasSuccesful = false;
|
||||
if(netVariantContainer == nullptr) {
|
||||
qObjectContainer->qObject->setProperty(QString::fromUtf16(propertyName), nullptr, &wasSuccesful);
|
||||
} else {
|
||||
qObjectContainer->qObject->setProperty(QString::fromUtf16(propertyName), netVariantContainer->variant, &wasSuccesful);
|
||||
}
|
||||
if(wasSuccesful) {
|
||||
*result = 1;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT NetVariantContainer* net_qobject_invokeMethod(NetQObjectContainer* qObjectContainer, LPWCSTR methodName, NetVariantListContainer* parametersContainer, uchar* result)
|
||||
{
|
||||
QSharedPointer<NetVariantList> parameters = nullptr;
|
||||
if(parametersContainer != nullptr) {
|
||||
parameters = parametersContainer->list;
|
||||
}
|
||||
bool wasSuccesful = false;
|
||||
auto value = qObjectContainer->qObject->invokeMethod(QString::fromUtf16(methodName), parameters, &wasSuccesful);
|
||||
if(wasSuccesful) {
|
||||
*result = 1;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
if(value == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return new NetVariantContainer { value };
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT NetQObjectSignalConnectionContainer* net_qobject_attachSignal(NetQObjectContainer* qObjectContainer, LPWCSTR signalName, NetReferenceContainer* delegate, uchar* result)
|
||||
{
|
||||
bool wasSuccesful = false;
|
||||
auto signalConnection = qObjectContainer->qObject->attachSignal(QString::fromUtf16(signalName), delegate->instance, &wasSuccesful);
|
||||
if(wasSuccesful) {
|
||||
*result = 1;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
if(signalConnection == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return new NetQObjectSignalConnectionContainer { signalConnection };
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT NetQObjectSignalConnectionContainer* net_qobject_attachNotifySignal(NetQObjectContainer* qObjectContainer, LPWCSTR propertyName, NetReferenceContainer* delegate, uchar* result)
|
||||
{
|
||||
bool wasSuccesful = false;
|
||||
auto signalConnection = qObjectContainer->qObject->attachNotifySignal(QString::fromUtf16(propertyName), delegate->instance, &wasSuccesful);
|
||||
if(wasSuccesful) {
|
||||
*result = 1;
|
||||
} else {
|
||||
*result = 0;
|
||||
}
|
||||
if(signalConnection == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return new NetQObjectSignalConnectionContainer { signalConnection };
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void net_qobject_signal_handler_destroy(NetQObjectSignalConnectionContainer* signalContainer)
|
||||
{
|
||||
delete signalContainer;
|
||||
}
|
||||
|
||||
}
|
||||
32
src/native/QmlNet/QmlNet/qml/NetQObject.h
Normal file
32
src/native/QmlNet/QmlNet/qml/NetQObject.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef NETQOBJECT_H
|
||||
#define NETQOBJECT_H
|
||||
|
||||
#include <QmlNet.h>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class NetVariant;
|
||||
class NetVariantList;
|
||||
class NetQObjectSignalConnection;
|
||||
class NetReference;
|
||||
|
||||
class NetQObject
|
||||
{
|
||||
public:
|
||||
NetQObject(QObject* qObject, bool ownsObject = false);
|
||||
~NetQObject();
|
||||
QObject* getQObject();
|
||||
QSharedPointer<NetVariant> getProperty(QString propertyName, bool* wasSuccess);
|
||||
void setProperty(QString propertyName, QSharedPointer<NetVariant> value, bool* wasSuccess);
|
||||
QSharedPointer<NetVariant> invokeMethod(QString methodName, QSharedPointer<NetVariantList> parameters, bool* wasSuccess);
|
||||
QSharedPointer<NetQObjectSignalConnection> attachSignal(QString signalName, QSharedPointer<NetReference> delegate, bool* wasSuccess);
|
||||
QSharedPointer<NetQObjectSignalConnection> attachNotifySignal(QString propertyName, QSharedPointer<NetReference> delegate, bool* wasSuccess);
|
||||
private:
|
||||
QObject* _qObject;
|
||||
bool _ownsObject;
|
||||
};
|
||||
|
||||
struct NetQObjectContainer {
|
||||
QSharedPointer<NetQObject> qObject;
|
||||
};
|
||||
|
||||
#endif // NETQOBJECT_H
|
||||
139
src/native/QmlNet/QmlNet/qml/NetQObjectArg.cpp
Normal file
139
src/native/QmlNet/QmlNet/qml/NetQObjectArg.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
#include <QmlNet/qml/NetQObjectArg.h>
|
||||
#include <QmlNet/qml/NetVariant.h>
|
||||
#include <QDebug>
|
||||
|
||||
NetQObjectArg::NetQObjectArg() :
|
||||
_metaTypeId(QMetaType::Void),
|
||||
_data(nullptr)
|
||||
{
|
||||
pack();
|
||||
}
|
||||
|
||||
NetQObjectArg::NetQObjectArg(const int metaTypeId, QSharedPointer<NetVariant> netVariant) :
|
||||
_metaTypeId(metaTypeId),
|
||||
_data(nullptr),
|
||||
_netVariant(netVariant)
|
||||
{
|
||||
pack();
|
||||
}
|
||||
|
||||
NetQObjectArg::~NetQObjectArg()
|
||||
{
|
||||
}
|
||||
|
||||
QGenericArgument NetQObjectArg::genericArgument()
|
||||
{
|
||||
if(_metaTypeId == QMetaType::Void) {
|
||||
return QGenericArgument();
|
||||
}
|
||||
if(_metaTypeId == QMetaType::QVariant) {
|
||||
return QGenericArgument("QVariant", &_variant);
|
||||
}
|
||||
return QGenericArgument(_variant.typeName(), _variant.data());
|
||||
}
|
||||
|
||||
QGenericReturnArgument NetQObjectArg::genericReturnArguemnet()
|
||||
{
|
||||
if(_metaTypeId == QMetaType::Void) {
|
||||
return QGenericReturnArgument();
|
||||
}
|
||||
if(_metaTypeId == QMetaType::QVariant) {
|
||||
return QGenericReturnArgument("QVariant", &_variant);
|
||||
}
|
||||
return QGenericReturnArgument(_variant.typeName(), _variant.data());
|
||||
}
|
||||
|
||||
QSharedPointer<NetVariant> NetQObjectArg::getNetVariant()
|
||||
{
|
||||
return _netVariant;
|
||||
}
|
||||
|
||||
void NetQObjectArg::pack()
|
||||
{
|
||||
if(_netVariant == nullptr) {
|
||||
switch(_metaTypeId) {
|
||||
case QMetaType::Void:
|
||||
break;
|
||||
case QMetaType::QVariant:
|
||||
_variant = QVariant();
|
||||
break;
|
||||
default:
|
||||
_variant = QVariant(_metaTypeId, nullptr);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch(_metaTypeId) {
|
||||
case QMetaType::Void:
|
||||
break;
|
||||
case QMetaType::QVariant:
|
||||
_variant = _netVariant->toQVariant();
|
||||
break;
|
||||
case QMetaType::Bool:
|
||||
_variant = QVariant::fromValue(_netVariant->getBool());
|
||||
break;
|
||||
case QMetaType::QChar:
|
||||
_variant = QVariant::fromValue(_netVariant->getChar());
|
||||
break;
|
||||
case qMetaTypeId<qint32>():
|
||||
_variant = QVariant::fromValue(_netVariant->getInt());
|
||||
break;
|
||||
case qMetaTypeId<quint32>():
|
||||
_variant = QVariant::fromValue(_netVariant->getUInt());
|
||||
break;
|
||||
case qMetaTypeId<qint64>():
|
||||
_variant = QVariant::fromValue(_netVariant->getLong());
|
||||
break;
|
||||
case qMetaTypeId<quint64>():
|
||||
_variant = QVariant::fromValue(_netVariant->getULong());
|
||||
break;
|
||||
case QMetaType::Long:
|
||||
_variant = QVariant::fromValue<long>(static_cast<long>(_netVariant->getLong()));
|
||||
break;
|
||||
case QMetaType::ULong:
|
||||
_variant = QVariant::fromValue<ulong>(static_cast<ulong>(_netVariant->getULong()));
|
||||
break;
|
||||
case QMetaType::Float:
|
||||
_variant = QVariant::fromValue(_netVariant->getFloat());
|
||||
break;
|
||||
case QMetaType::Double:
|
||||
_variant = QVariant::fromValue(_netVariant->getDouble());
|
||||
break;
|
||||
case QMetaType::QString:
|
||||
_variant = QVariant::fromValue(_netVariant->getString());
|
||||
break;
|
||||
case QMetaType::QDateTime:
|
||||
_variant = QVariant::fromValue(_netVariant->getDateTime());
|
||||
break;
|
||||
case QMetaType::QObjectStar:
|
||||
switch(_netVariant->getVariantType()) {
|
||||
case NetVariantTypeEnum_Invalid:
|
||||
_variant = QVariant::fromValue<QObject*>(nullptr);
|
||||
break;
|
||||
case NetVariantTypeEnum_Object:
|
||||
case NetVariantTypeEnum_QObject:
|
||||
_variant = _netVariant->toQVariant();
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unabled to convert " << _netVariant->getVariantType() << " to QObject*";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unsupported type: " << QMetaType::typeName(_metaTypeId);
|
||||
_variant = QVariant(_metaTypeId, nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetQObjectArg::unpack()
|
||||
{
|
||||
if(_metaTypeId == QMetaType::Void) {
|
||||
return;
|
||||
}
|
||||
if(_netVariant == nullptr) {
|
||||
_netVariant = QSharedPointer<NetVariant>(new NetVariant());
|
||||
}
|
||||
NetVariant::fromQVariant(&_variant, _netVariant);
|
||||
}
|
||||
28
src/native/QmlNet/QmlNet/qml/NetQObjectArg.h
Normal file
28
src/native/QmlNet/QmlNet/qml/NetQObjectArg.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef NETQOBJECTARG_H
|
||||
#define NETQOBJECTARG_H
|
||||
|
||||
#include <QMetaMethod>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class NetVariant;
|
||||
|
||||
class NetQObjectArg
|
||||
{
|
||||
public:
|
||||
NetQObjectArg();
|
||||
NetQObjectArg(int metaTypeId, QSharedPointer<NetVariant> netVariant = nullptr);
|
||||
~NetQObjectArg();
|
||||
QGenericArgument genericArgument();
|
||||
QGenericReturnArgument genericReturnArguemnet();
|
||||
QSharedPointer<NetVariant> getNetVariant();
|
||||
void pack();
|
||||
void unpack();
|
||||
private:
|
||||
int _metaTypeId;
|
||||
void* _data;
|
||||
int test;
|
||||
QVariant _variant;
|
||||
QSharedPointer<NetVariant> _netVariant;
|
||||
};
|
||||
|
||||
#endif // NETQOBJECTARG_H
|
||||
65
src/native/QmlNet/QmlNet/qml/NetQObjectSignalConnection.cpp
Normal file
65
src/native/QmlNet/QmlNet/qml/NetQObjectSignalConnection.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#include <QmlNet/qml/NetQObjectSignalConnection.h>
|
||||
#include <QmlNet/qml/NetVariant.h>
|
||||
#include <QmlNet/qml/NetVariantList.h>
|
||||
#include <QmlNet/types/Callbacks.h>
|
||||
#include <QMetaMethod>
|
||||
|
||||
NetQObjectSignalConnectionBase::NetQObjectSignalConnectionBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NetQObjectSignalConnectionBase::~NetQObjectSignalConnectionBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QMetaMethod NetQObjectSignalConnectionBase::getSignalHandler()
|
||||
{
|
||||
return metaObject()->method(metaObject()->methodOffset());
|
||||
}
|
||||
|
||||
void NetQObjectSignalConnectionBase::signalRaised()
|
||||
{
|
||||
// Dummy, handled in NetQObjectSignalConnection::qt_metacall()
|
||||
}
|
||||
|
||||
NetQObjectSignalConnection::NetQObjectSignalConnection(QSharedPointer<NetReference> delegate,
|
||||
QObject* qObject)
|
||||
: _delegate(delegate),
|
||||
_qObject(qObject)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NetQObjectSignalConnection::~NetQObjectSignalConnection()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int NetQObjectSignalConnection::qt_metacall(QMetaObject::Call c, int id, void** a)
|
||||
{
|
||||
if(c == QMetaObject::InvokeMetaMethod) {
|
||||
int offset = this->metaObject()->methodOffset();
|
||||
if(id < offset) {
|
||||
return QObject::qt_metacall(c, id, a);
|
||||
}
|
||||
|
||||
if(this->metaObject()->indexOfSlot("signalRaised()") == id) {
|
||||
QMetaMethod signal = _qObject->metaObject()->method(senderSignalIndex());
|
||||
|
||||
// Convert signal args to QVariantList
|
||||
QSharedPointer<NetVariantList> netParameters = QSharedPointer<NetVariantList>(new NetVariantList());
|
||||
for (int i = 0; i < signal.parameterCount(); ++i) {
|
||||
QVariant arg = QVariant(signal.parameterType(i), a[i+1]);
|
||||
netParameters->add(NetVariant::fromQVariant(&arg));
|
||||
}
|
||||
|
||||
QmlNet::invokeDelegate(_delegate, netParameters);
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
35
src/native/QmlNet/QmlNet/qml/NetQObjectSignalConnection.h
Normal file
35
src/native/QmlNet/QmlNet/qml/NetQObjectSignalConnection.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef NETQOBJECTSIGNALCONNECTION_H
|
||||
#define NETQOBJECTSIGNALCONNECTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class NetReference;
|
||||
|
||||
class NetQObjectSignalConnectionBase : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NetQObjectSignalConnectionBase();
|
||||
~NetQObjectSignalConnectionBase();
|
||||
QMetaMethod getSignalHandler();
|
||||
public slots:
|
||||
void signalRaised();
|
||||
};
|
||||
|
||||
class NetQObjectSignalConnection : public NetQObjectSignalConnectionBase
|
||||
{
|
||||
public:
|
||||
NetQObjectSignalConnection(QSharedPointer<NetReference> delegate, QObject* qObject);
|
||||
~NetQObjectSignalConnection() override;
|
||||
int qt_metacall(QMetaObject::Call c, int id, void** a) override;
|
||||
private:
|
||||
QSharedPointer<NetReference> _delegate;
|
||||
QObject* _qObject;
|
||||
};
|
||||
|
||||
struct NetQObjectSignalConnectionContainer {
|
||||
QSharedPointer<NetQObjectSignalConnection> signalConnection;
|
||||
};
|
||||
|
||||
#endif // NETQOBJECTSIGNALCONNECTION_H
|
||||
|
|
@ -2,12 +2,176 @@
|
|||
#include <QQmlComponent>
|
||||
#include <QDebug>
|
||||
|
||||
TestQObject::TestQObject()
|
||||
: QObject(nullptr),
|
||||
_writeOnly(0),
|
||||
_readAndWrite(0),
|
||||
_propWithSignal(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TestQObject::~TestQObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int TestQObject::getReadOnly()
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
void TestQObject::setWriteOnly(int value)
|
||||
{
|
||||
_writeOnly = value;
|
||||
}
|
||||
|
||||
int TestQObject::getReadAndWrite()
|
||||
{
|
||||
return _readAndWrite;
|
||||
}
|
||||
|
||||
void TestQObject::setReadAndWrite(int value)
|
||||
{
|
||||
_readAndWrite = value;
|
||||
}
|
||||
|
||||
int TestQObject::getPropWithSignal()
|
||||
{
|
||||
return _propWithSignal;
|
||||
}
|
||||
|
||||
void TestQObject::setPropWithSignal(int value)
|
||||
{
|
||||
if(value == _propWithSignal) {
|
||||
return;
|
||||
}
|
||||
_propWithSignal = value;
|
||||
emit propWithSignalChanged(value);
|
||||
}
|
||||
|
||||
QVariant TestQObject::getVariantProperty()
|
||||
{
|
||||
return _variantValue;
|
||||
}
|
||||
|
||||
void TestQObject::setVariantProperty(QVariant value)
|
||||
{
|
||||
_variantValue = value;
|
||||
}
|
||||
|
||||
void TestQObject::testSlot()
|
||||
{
|
||||
emit testSignal();
|
||||
}
|
||||
|
||||
void TestQObject::testSlotWithArg(int arg)
|
||||
{
|
||||
emit testSignalWithArg(arg);
|
||||
}
|
||||
|
||||
QVariant TestQObject::testVariantReturn()
|
||||
{
|
||||
return getVariantProperty();
|
||||
}
|
||||
|
||||
bool TestQObject::testSlotBool(bool value)
|
||||
{
|
||||
emit testSignalBool(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
QChar TestQObject::testSlotChar(QChar value)
|
||||
{
|
||||
emit testSignalChar(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
int TestQObject::testSlotInt(int value)
|
||||
{
|
||||
emit testSignalInt(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
uint TestQObject::testSlotUInt(uint value)
|
||||
{
|
||||
emit testSignalUInt(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
long TestQObject::testSlotLong(long value)
|
||||
{
|
||||
emit testSignalLong(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
ulong TestQObject::testSlotULong(ulong value)
|
||||
{
|
||||
emit testSignalULong(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
float TestQObject::testSlotFloat(float value)
|
||||
{
|
||||
emit testSignalFloat(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
double TestQObject::testSlotDouble(double value)
|
||||
{
|
||||
emit testSignalDouble(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
QString TestQObject::testSlotString(QString value)
|
||||
{
|
||||
emit testSignalString(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
QDateTime TestQObject::testSlotDateTime(QDateTime value)
|
||||
{
|
||||
emit testSignalDateTime(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
QObject* TestQObject::testSlotQObject(QObject* value)
|
||||
{
|
||||
emit testSignalQObject(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
qint32 TestQObject::testSlotQInt32(qint32 value)
|
||||
{
|
||||
emit testSignalQInt32(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
quint32 TestQObject::testSlotQUInt32(quint32 value)
|
||||
{
|
||||
emit testSignalQUInt32(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
qint64 TestQObject::testSlotQInt64(qint64 value)
|
||||
{
|
||||
emit testSignalQInt64(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
quint64 TestQObject::testSlotQUInt64(quint64 value)
|
||||
{
|
||||
emit testSignalQUInt64(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
Q_DECL_EXPORT void net_test_helper_runQml(QQmlApplicationEngineContainer* qmlEngineContainer, LPWSTR qml) {
|
||||
QQmlComponent component(qmlEngineContainer->qmlEngine);
|
||||
QString qmlString = QString::fromUtf16(static_cast<const char16_t*>(qml));
|
||||
component.setData(qmlString.toUtf8(), QUrl());
|
||||
|
||||
QObject *object = component.create();
|
||||
|
||||
if(object == nullptr) {
|
||||
|
|
@ -15,6 +179,10 @@ Q_DECL_EXPORT void net_test_helper_runQml(QQmlApplicationEngineContainer* qmlEng
|
|||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<TestQObject> testQObject = QSharedPointer<TestQObject>(new TestQObject());
|
||||
object->setProperty("testQObject", QVariant::fromValue(testQObject.data()));
|
||||
QMetaObject::invokeMethod(object, "runTest");
|
||||
|
||||
delete object;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,5 +3,72 @@
|
|||
|
||||
#include <QmlNet.h>
|
||||
#include <QmlNet/qml/QQmlApplicationEngine.h>
|
||||
#include <QDateTime>
|
||||
|
||||
class TestQObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int readOnly READ getReadOnly)
|
||||
Q_PROPERTY(int writeOnly WRITE setWriteOnly)
|
||||
Q_PROPERTY(int readAndWrite READ getReadAndWrite WRITE setReadAndWrite)
|
||||
Q_PROPERTY(int propWithSignal READ getPropWithSignal WRITE setPropWithSignal NOTIFY propWithSignalChanged)
|
||||
Q_PROPERTY(QVariant variantProperty READ getVariantProperty WRITE setVariantProperty)
|
||||
public:
|
||||
TestQObject();
|
||||
~TestQObject();
|
||||
int getReadOnly();
|
||||
void setWriteOnly(int value);
|
||||
int getReadAndWrite();
|
||||
void setReadAndWrite(int value);
|
||||
int getPropWithSignal();
|
||||
void setPropWithSignal(int value);
|
||||
QVariant getVariantProperty();
|
||||
void setVariantProperty(QVariant value);
|
||||
|
||||
signals:
|
||||
void propWithSignalChanged(int value);
|
||||
void testSignal();
|
||||
void testSignalWithArg(int arg);
|
||||
void testSignalBool(bool value);
|
||||
void testSignalChar(QChar value);
|
||||
void testSignalInt(int value);
|
||||
void testSignalUInt(uint value);
|
||||
void testSignalLong(long value);
|
||||
void testSignalULong(ulong value);
|
||||
void testSignalFloat(float value);
|
||||
void testSignalDouble(double value);
|
||||
void testSignalString(QString value);
|
||||
void testSignalDateTime(QDateTime value);
|
||||
void testSignalQObject(QObject* qObject);
|
||||
void testSignalQInt32(qint32 value);
|
||||
void testSignalQUInt32(quint32 value);
|
||||
void testSignalQInt64(qint64 value);
|
||||
void testSignalQUInt64(quint64 value);
|
||||
|
||||
public slots:
|
||||
void testSlot();
|
||||
void testSlotWithArg(int arg);
|
||||
QVariant testVariantReturn();
|
||||
bool testSlotBool(bool value);
|
||||
QChar testSlotChar(QChar value);
|
||||
int testSlotInt(int value);
|
||||
uint testSlotUInt(uint value);
|
||||
long testSlotLong(long value);
|
||||
ulong testSlotULong(ulong value);
|
||||
float testSlotFloat(float value);
|
||||
double testSlotDouble(double value);
|
||||
QString testSlotString(QString value);
|
||||
QDateTime testSlotDateTime(QDateTime value);
|
||||
QObject* testSlotQObject(QObject* value);
|
||||
qint32 testSlotQInt32(qint32 value);
|
||||
quint32 testSlotQUInt32(quint32 value);
|
||||
qint64 testSlotQInt64(qint64 value);
|
||||
quint64 testSlotQUInt64(quint64 value);
|
||||
private:
|
||||
int _writeOnly;
|
||||
int _readAndWrite;
|
||||
int _propWithSignal;
|
||||
QVariant _variantValue;
|
||||
};
|
||||
|
||||
#endif // NETTESTHELPER_H
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include <QmlNet/qml/NetValueMetaObjectPacker.h>
|
||||
#include <QmlNet/qml/NetVariant.h>
|
||||
#include <QmlNet/qml/NetValue.h>
|
||||
#include <QmlNet/qml/NetJsValue.h>
|
||||
#include <QmlNet/qml/NetQObject.h>
|
||||
#include <QDebug>
|
||||
|
||||
const char* NetValueTypePacker::getQmlType()
|
||||
|
|
@ -55,6 +57,9 @@ void NetValueTypePacker::pack(const QSharedPointer<NetVariant>& source, void* de
|
|||
case NetVariantTypeEnum_JSValue:
|
||||
destinationVariant->setValue(source->getJsValue()->getJsValue());
|
||||
break;
|
||||
case NetVariantTypeEnum_QObject:
|
||||
destinationVariant->setValue(source->getQObject()->getQObject());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -116,8 +121,11 @@ void NetValueTypePacker::unpack(const QSharedPointer<NetVariant>& destination, v
|
|||
NetValueInterface* netValue = qobject_cast<NetValueInterface*>(value);
|
||||
if(netValue) {
|
||||
destination->setNetReference(netValue->getNetReference());
|
||||
return;
|
||||
} else {
|
||||
QSharedPointer<NetQObject> netQObject(new NetQObject(value));
|
||||
destination->setQObject(netQObject);
|
||||
}
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -131,6 +139,12 @@ void NetValueTypePacker::unpack(const QSharedPointer<NetVariant>& destination, v
|
|||
// TODO: Try to convert other types to JS Value.
|
||||
break;
|
||||
}
|
||||
case NetVariantTypeEnum_QObject:
|
||||
{
|
||||
if(sourceVariant->userType() == QMetaType::QObjectStar) {
|
||||
QSharedPointer<NetQObject> netQObject(new NetQObject(sourceVariant->value<QObject*>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetVariant::fromQVariant(sourceVariant, destination);
|
||||
|
|
@ -192,6 +206,7 @@ NetValueMetaObjectPacker::NetValueMetaObjectPacker()
|
|||
case NetVariantTypeEnum_DateTime:
|
||||
case NetVariantTypeEnum_Object:
|
||||
case NetVariantTypeEnum_JSValue:
|
||||
case NetVariantTypeEnum_QObject:
|
||||
packers[type] = variantPacker;
|
||||
break;
|
||||
case NetVariantTypeEnum_String:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include <QmlNet/types/NetReference.h>
|
||||
#include <QmlNet/qml/NetVariant.h>
|
||||
#include <QmlNet/qml/NetValue.h>
|
||||
#include <QmlNet/qml/NetJsValue.h>
|
||||
#include <QmlNet/qml/NetQObject.h>
|
||||
#include <QmlNetUtilities.h>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
|
@ -18,15 +20,22 @@ struct NetJsValueQmlContainer
|
|||
{
|
||||
QSharedPointer<NetJSValue> jsValue;
|
||||
};
|
||||
|
||||
struct NetQObjectQmlContainer
|
||||
{
|
||||
QSharedPointer<NetQObject> netQObject;
|
||||
};
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(NetReferenceQmlContainer)
|
||||
Q_DECLARE_METATYPE(NetJsValueQmlContainer)
|
||||
Q_DECLARE_METATYPE(NetQObjectQmlContainer)
|
||||
|
||||
namespace
|
||||
{
|
||||
const int NetReferenceQmlContainerTypeId = qMetaTypeId<NetReferenceQmlContainer>();
|
||||
const int NetJsValueQmlContainerTypeId = qMetaTypeId<NetJsValueQmlContainer>();
|
||||
const int NetQObjectQmlContainerTypeId = qMetaTypeId<NetQObjectQmlContainer>();
|
||||
}
|
||||
|
||||
NetVariant::NetVariant() = default;
|
||||
|
|
@ -68,7 +77,11 @@ NetVariantTypeEnum NetVariant::getVariantType() const
|
|||
}
|
||||
else if(type == NetJsValueQmlContainerTypeId) {
|
||||
return NetVariantTypeEnum_JSValue;
|
||||
} else {
|
||||
}
|
||||
else if(type == NetQObjectQmlContainerTypeId) {
|
||||
return NetVariantTypeEnum_QObject;
|
||||
}
|
||||
else {
|
||||
qWarning() << "Unknown type for NetVariant: " << variant.typeName();
|
||||
return NetVariantTypeEnum_Invalid;
|
||||
}
|
||||
|
|
@ -206,6 +219,16 @@ QSharedPointer<NetJSValue> NetVariant::getJsValue() const
|
|||
return getValue<NetJsValueQmlContainer>().jsValue;
|
||||
}
|
||||
|
||||
void NetVariant::setQObject(QSharedPointer<NetQObject> netQObject)
|
||||
{
|
||||
setValue(NetQObjectQmlContainer{ std::move(netQObject) });
|
||||
}
|
||||
|
||||
QSharedPointer<NetQObject> NetVariant::getQObject() const
|
||||
{
|
||||
return getValue<NetQObjectQmlContainer>().netQObject;
|
||||
}
|
||||
|
||||
void NetVariant::clear()
|
||||
{
|
||||
clearNetReference();
|
||||
|
|
@ -274,13 +297,23 @@ void NetVariant::fromQVariant(const QVariant* variant, const QSharedPointer<NetV
|
|||
case QMetaType::QDateTime:
|
||||
destination->setValueVariant(*variant);
|
||||
break;
|
||||
case QMetaType::ULong:
|
||||
destination->setULong(variant->value<quint64>());
|
||||
break;
|
||||
case QMetaType::Long:
|
||||
destination->setLong(variant->value<qint64>());
|
||||
break;
|
||||
case QMetaType::QObjectStar: {
|
||||
QObject* value = variant->value<QObject*>();
|
||||
if(value == nullptr) {
|
||||
destination->clear();
|
||||
return;
|
||||
}
|
||||
NetValueInterface* netValue = qobject_cast<NetValueInterface*>(value);
|
||||
if(netValue) {
|
||||
destination->setNetReference(netValue->getNetReference());
|
||||
} else {
|
||||
qDebug() << "Unsupported variant type: " << variant->type() << variant->typeName();
|
||||
destination->setQObject(QSharedPointer<NetQObject>(new NetQObject(value)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -314,6 +347,8 @@ QVariant NetVariant::toQVariant() const
|
|||
return getJsValue()->getJsValue().toVariant();
|
||||
case NetVariantTypeEnum_Object:
|
||||
return QVariant::fromValue<QObject*>(NetValue::forInstance(getNetReference()));
|
||||
case NetVariantTypeEnum_QObject:
|
||||
return QVariant::fromValue<QObject*>(this->getQObject()->getQObject());
|
||||
default:
|
||||
return variant;
|
||||
}
|
||||
|
|
@ -341,6 +376,10 @@ void NetVariant::clearNetReference()
|
|||
variant.value<NetJsValueQmlContainer>().jsValue.clear();
|
||||
variant.clear();
|
||||
}
|
||||
else if(variant.canConvert<NetQObjectQmlContainer>()) {
|
||||
variant.value<NetQObjectQmlContainer>().netQObject.clear();
|
||||
variant.clear();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -559,6 +598,24 @@ Q_DECL_EXPORT NetJSValueContainer* net_variant_getJsValue(NetVariantContainer* c
|
|||
return result;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void net_variant_setQObject(NetVariantContainer* container, NetQObjectContainer* qObjectContainer) {
|
||||
if(qObjectContainer == nullptr) {
|
||||
container->variant->setQObject(nullptr);
|
||||
} else {
|
||||
container->variant->setQObject(qObjectContainer->qObject);
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT NetQObjectContainer* net_variant_getQObject(NetVariantContainer* container) {
|
||||
const QSharedPointer<NetQObject>& instance = container->variant->getQObject();
|
||||
if(instance == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
NetQObjectContainer* result = new NetQObjectContainer();
|
||||
result->qObject = instance;
|
||||
return result;
|
||||
}
|
||||
|
||||
Q_DECL_EXPORT void net_variant_clear(NetVariantContainer* container) {
|
||||
container->variant->clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
#ifndef NETVARIANT_H
|
||||
#define NETVARIANT_H
|
||||
|
||||
#include <QmlNet/types/NetReference.h>
|
||||
#include <QmlNet/qml/NetJsValue.h>
|
||||
#include <QmlNet.h>
|
||||
#include <QSharedPointer>
|
||||
#include <QVariant>
|
||||
#include <QDateTime>
|
||||
#include <QJSValue>
|
||||
|
||||
class NetJSValue;
|
||||
class NetQObject;
|
||||
class NetReference;
|
||||
|
||||
class NetVariant
|
||||
{
|
||||
public:
|
||||
|
|
@ -38,6 +42,8 @@ public:
|
|||
QDateTime getDateTime() const;
|
||||
void setJsValue(QSharedPointer<NetJSValue> jsValue);
|
||||
QSharedPointer<NetJSValue> getJsValue() const;
|
||||
void setQObject(QSharedPointer<NetQObject> netQObject);
|
||||
QSharedPointer<NetQObject> getQObject() const;
|
||||
void clear();
|
||||
static QSharedPointer<NetVariant> fromQJSValue(const QJSValue& qJsValue);
|
||||
QJSValue toQJSValue() const;
|
||||
|
|
|
|||
|
|
@ -225,6 +225,26 @@ Q_DECL_EXPORT int qqmlapplicationengine_registerType(NetTypeInfoContainer* typeC
|
|||
NETVALUETYPE_CASE(148)
|
||||
NETVALUETYPE_CASE(149)
|
||||
NETVALUETYPE_CASE(150)
|
||||
NETVALUETYPE_CASE(151)
|
||||
NETVALUETYPE_CASE(152)
|
||||
NETVALUETYPE_CASE(153)
|
||||
NETVALUETYPE_CASE(154)
|
||||
NETVALUETYPE_CASE(155)
|
||||
NETVALUETYPE_CASE(156)
|
||||
NETVALUETYPE_CASE(157)
|
||||
NETVALUETYPE_CASE(158)
|
||||
NETVALUETYPE_CASE(159)
|
||||
NETVALUETYPE_CASE(160)
|
||||
NETVALUETYPE_CASE(161)
|
||||
NETVALUETYPE_CASE(162)
|
||||
NETVALUETYPE_CASE(163)
|
||||
NETVALUETYPE_CASE(164)
|
||||
NETVALUETYPE_CASE(165)
|
||||
NETVALUETYPE_CASE(166)
|
||||
NETVALUETYPE_CASE(167)
|
||||
NETVALUETYPE_CASE(168)
|
||||
NETVALUETYPE_CASE(169)
|
||||
NETVALUETYPE_CASE(170)
|
||||
}
|
||||
qFatal("Too many registered types: %d", netValueTypeNumber);
|
||||
return -1;
|
||||
|
|
@ -395,6 +415,26 @@ Q_DECL_EXPORT int qqmlapplicationengine_registerSingletonTypeNet(NetTypeInfoCont
|
|||
NETVALUETYPESINGLETON_CASE(148)
|
||||
NETVALUETYPESINGLETON_CASE(149)
|
||||
NETVALUETYPESINGLETON_CASE(150)
|
||||
NETVALUETYPESINGLETON_CASE(151)
|
||||
NETVALUETYPESINGLETON_CASE(152)
|
||||
NETVALUETYPESINGLETON_CASE(153)
|
||||
NETVALUETYPESINGLETON_CASE(154)
|
||||
NETVALUETYPESINGLETON_CASE(155)
|
||||
NETVALUETYPESINGLETON_CASE(156)
|
||||
NETVALUETYPESINGLETON_CASE(157)
|
||||
NETVALUETYPESINGLETON_CASE(158)
|
||||
NETVALUETYPESINGLETON_CASE(159)
|
||||
NETVALUETYPESINGLETON_CASE(160)
|
||||
NETVALUETYPESINGLETON_CASE(161)
|
||||
NETVALUETYPESINGLETON_CASE(162)
|
||||
NETVALUETYPESINGLETON_CASE(163)
|
||||
NETVALUETYPESINGLETON_CASE(164)
|
||||
NETVALUETYPESINGLETON_CASE(165)
|
||||
NETVALUETYPESINGLETON_CASE(166)
|
||||
NETVALUETYPESINGLETON_CASE(167)
|
||||
NETVALUETYPESINGLETON_CASE(168)
|
||||
NETVALUETYPESINGLETON_CASE(169)
|
||||
NETVALUETYPESINGLETON_CASE(170)
|
||||
}
|
||||
qFatal("Too many registered types: %d", netValueTypeNumber);
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ HEADERS += \
|
|||
$$PWD/NetListModel.h \
|
||||
$$PWD/QtWebEngine.h \
|
||||
$$PWD/QCoreApplication.h \
|
||||
$$PWD/QTest.h
|
||||
$$PWD/QTest.h \
|
||||
$$PWD/NetQObject.h \
|
||||
$$PWD/NetQObjectSignalConnection.h \
|
||||
$$PWD/NetQObjectArg.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/QQmlApplicationEngine.cpp \
|
||||
|
|
@ -34,4 +37,7 @@ SOURCES += \
|
|||
$$PWD/NetListModel.cpp \
|
||||
$$PWD/QtWebEngine.cpp \
|
||||
$$PWD/QCoreApplication.cpp \
|
||||
$$PWD/QTest.cpp
|
||||
$$PWD/QTest.cpp \
|
||||
$$PWD/NetQObject.cpp \
|
||||
$$PWD/NetQObjectSignalConnection.cpp \
|
||||
$$PWD/NetQObjectArg.cpp
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using gcCollectCb = void (*)(int);
|
|||
using raiseNetSignalsCb = uchar (*)(NetReferenceContainer *, LPWCSTR, NetVariantListContainer *);
|
||||
using awaitTaskCb = void (*)(NetReferenceContainer *, NetJSValueContainer *, NetJSValueContainer *);
|
||||
using serializeNetToStringCb = uchar (*)(NetReferenceContainer *, NetVariantContainer *);
|
||||
using invokeDelegateCb = void (*)(NetReferenceContainer *, NetVariantListContainer *);
|
||||
|
||||
struct Q_DECL_EXPORT NetTypeInfoManagerCallbacks {
|
||||
isTypeValidCb isTypeValid;
|
||||
|
|
@ -35,6 +36,7 @@ struct Q_DECL_EXPORT NetTypeInfoManagerCallbacks {
|
|||
raiseNetSignalsCb raiseNetSignals;
|
||||
awaitTaskCb awaitTask;
|
||||
serializeNetToStringCb serializeNetToString;
|
||||
invokeDelegateCb invokeDelegate;
|
||||
};
|
||||
|
||||
static NetTypeInfoManagerCallbacks sharedCallbacks;
|
||||
|
|
@ -175,6 +177,12 @@ bool serializeNetToString(QSharedPointer<NetReference> instance, QSharedPointer<
|
|||
new NetVariantContainer{std::move(result)}) == 1;
|
||||
}
|
||||
|
||||
void invokeDelegate(QSharedPointer<NetReference> del, QSharedPointer<NetVariantList> parameters)
|
||||
{
|
||||
sharedCallbacks.invokeDelegate(new NetReferenceContainer{std::move(del)},
|
||||
new NetVariantListContainer{std::move(parameters)});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <QmlNet/types/NetReference.h>
|
||||
#include <QmlNet/qml/NetVariant.h>
|
||||
#include <QmlNet/qml/NetVariantList.h>
|
||||
#include <QmlNet/qml/NetJsValue.h>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
|
||||
|
|
@ -43,6 +44,8 @@ void awaitTask(QSharedPointer<NetReference> target, QSharedPointer<NetJSValue> s
|
|||
|
||||
bool serializeNetToString(QSharedPointer<NetReference> instance, QSharedPointer<NetVariant> result);
|
||||
|
||||
void invokeDelegate(QSharedPointer<NetReference> del, QSharedPointer<NetVariantList> parameters);
|
||||
|
||||
}
|
||||
|
||||
#endif // NET_TYPE_INFO_MANAGER_H
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ namespace Qml.Net.Tests.Qml
|
|||
import tests 1.0
|
||||
{0} {{
|
||||
id: {1}
|
||||
Component.onCompleted: function() {{
|
||||
property var testQObject: null
|
||||
function runTest() {{
|
||||
{2}
|
||||
}}
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ namespace Qml.Net.Tests.Qml
|
|||
[Fact]
|
||||
public void Can_read_properties_from_js_object()
|
||||
{
|
||||
var testObject = new JsValueTests.JsTestsQml.TestObject();
|
||||
var testObject = new JsTestsQml.TestObject();
|
||||
dynamic result = null;
|
||||
Mock.Setup(x => x.Method(It.IsAny<INetJsValue>())).Callback(new Action<dynamic>(jsValue =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ namespace Qml.Net.Tests.Qml
|
|||
{
|
||||
public virtual void DerivedMethod()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -17,7 +16,6 @@ namespace Qml.Net.Tests.Qml
|
|||
{
|
||||
public virtual void BaseMethod()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
584
src/net/Qml.Net.Tests/Qml/QObjectTests.cs
Normal file
584
src/net/Qml.Net.Tests/Qml/QObjectTests.cs
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using FluentAssertions;
|
||||
using FluentAssertions.Execution;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Qml.Net.Tests.Qml
|
||||
{
|
||||
public class QObjectTests : BaseQmlTests<QObjectTests.QObjectTestsQml>
|
||||
{
|
||||
public class QObjectTestsQml
|
||||
{
|
||||
public virtual void Method(dynamic value)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Exception_throw_when_using_invalid_methods()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
// Valid
|
||||
qObject.InvokeMethod("testSlot");
|
||||
Assert.Throws<Exception>(() => { qObject.InvokeMethod("nonexistant"); });
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Exception_thrown_when_using_invalid_properties()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
// Valid
|
||||
qObject.SetProperty("readAndWrite", 3);
|
||||
Assert.Throws<Exception>(() => { qObject.SetProperty("nonexistant", 3); });
|
||||
Assert.Throws<Exception>(() => { qObject.GetProperty("nonexistant"); });
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Exception_thrown_when_attaching_to_invalid_signal()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
// Valid
|
||||
var handler = qObject.AttachSignal("testSignal", parameters =>
|
||||
{
|
||||
});
|
||||
handler.Dispose();
|
||||
Assert.Throws<Exception>(() =>
|
||||
{
|
||||
qObject.AttachSignal(
|
||||
"nonexistant",
|
||||
parameters =>
|
||||
{
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Exception_thrown_when_attaching_to_invalid_notify_signal()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
// Valid
|
||||
var handler = qObject.AttachNotifySignal("propWithSignal", parameters =>
|
||||
{
|
||||
});
|
||||
handler.Dispose();
|
||||
Assert.Throws<Exception>(() =>
|
||||
{
|
||||
qObject.AttachNotifySignal(
|
||||
"readAndWrite",
|
||||
parameters =>
|
||||
{
|
||||
});
|
||||
});
|
||||
Assert.Throws<Exception>(() =>
|
||||
{
|
||||
qObject.AttachNotifySignal(
|
||||
"nonexistant",
|
||||
parameters =>
|
||||
{
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_get_property_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
qObject.GetProperty("readOnly").Should().Be(3);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_set_property_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
// No real way to test this.
|
||||
// I suppose it doesn't throw, eh?
|
||||
qObject.SetProperty("writeOnly", 3);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_set_and_get_property_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
qObject.SetProperty("readAndWrite", 340);
|
||||
qObject.GetProperty("readAndWrite").Should().Be(340);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_get_set_object_name()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
var d = (dynamic)qObject;
|
||||
d.objectName = "testtt";
|
||||
((string)d.objectName).Should().Be("testtt");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_set_random_types_on_property()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
qObject.GetProperty("variantProperty").Should().BeNull();
|
||||
|
||||
qObject.SetProperty("variantProperty", true);
|
||||
qObject.GetProperty("variantProperty").Should().Be(true);
|
||||
|
||||
qObject.SetProperty("variantProperty", 'T');
|
||||
qObject.GetProperty("variantProperty").Should().Be('T');
|
||||
|
||||
qObject.SetProperty("variantProperty", int.MinValue);
|
||||
qObject.GetProperty("variantProperty").Should().Be(int.MinValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", uint.MaxValue);
|
||||
qObject.GetProperty("variantProperty").Should().Be(uint.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", long.MaxValue);
|
||||
qObject.GetProperty("variantProperty").Should().Be(long.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", ulong.MaxValue);
|
||||
qObject.GetProperty("variantProperty").Should().Be(ulong.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", float.MaxValue);
|
||||
qObject.GetProperty("variantProperty").Should().Be(float.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", double.MaxValue);
|
||||
qObject.GetProperty("variantProperty").Should().Be(double.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", "");
|
||||
qObject.GetProperty("variantProperty").Should().Be("");
|
||||
|
||||
qObject.SetProperty("variantProperty", "test");
|
||||
qObject.GetProperty("variantProperty").Should().Be("test");
|
||||
|
||||
var dateTime = DateTimeOffset.Now;
|
||||
dateTime = new DateTimeOffset(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond, dateTime.Offset);
|
||||
qObject.SetProperty("variantProperty", dateTime);
|
||||
var resultDateTime = (DateTimeOffset)qObject.GetProperty("variantProperty");
|
||||
resultDateTime = new DateTimeOffset(resultDateTime.Year, resultDateTime.Month, resultDateTime.Day, resultDateTime.Hour, resultDateTime.Minute, resultDateTime.Second, resultDateTime.Millisecond, resultDateTime.Offset);
|
||||
resultDateTime.Should().Be(dateTime);
|
||||
|
||||
var o = new object();
|
||||
qObject.SetProperty("variantProperty", o);
|
||||
qObject.GetProperty("variantProperty").Should().BeSameAs(o);
|
||||
|
||||
qObject.SetProperty("objectName", "ttttt");
|
||||
qObject.SetProperty("variantProperty", qObject);
|
||||
var result = qObject.GetProperty("variantProperty");
|
||||
result.Should().NotBeNull();
|
||||
var resultQObject = result as INetQObject;
|
||||
resultQObject.Should().NotBeNull();
|
||||
resultQObject.GetProperty("objectName").Should().Be("ttttt");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_return_random_types_from_method()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(null);
|
||||
|
||||
qObject.SetProperty("variantProperty", true);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(true);
|
||||
|
||||
qObject.SetProperty("variantProperty", 'T');
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be('T');
|
||||
|
||||
qObject.SetProperty("variantProperty", int.MinValue);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(int.MinValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", uint.MaxValue);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(uint.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", long.MaxValue);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(long.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", ulong.MaxValue);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(ulong.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", float.MaxValue);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(float.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", double.MaxValue);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be(double.MaxValue);
|
||||
|
||||
qObject.SetProperty("variantProperty", "");
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be("");
|
||||
|
||||
qObject.SetProperty("variantProperty", "test");
|
||||
qObject.InvokeMethod("testVariantReturn").Should().Be("test");
|
||||
|
||||
var dateTime = DateTimeOffset.Now;
|
||||
dateTime = new DateTimeOffset(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond, dateTime.Offset);
|
||||
qObject.SetProperty("variantProperty", dateTime);
|
||||
var resultDateTime = (DateTimeOffset)qObject.InvokeMethod("testVariantReturn");
|
||||
resultDateTime = new DateTimeOffset(resultDateTime.Year, resultDateTime.Month, resultDateTime.Day, resultDateTime.Hour, resultDateTime.Minute, resultDateTime.Second, resultDateTime.Millisecond, resultDateTime.Offset);
|
||||
resultDateTime.Should().Be(dateTime);
|
||||
|
||||
var o = new object();
|
||||
qObject.SetProperty("variantProperty", o);
|
||||
qObject.InvokeMethod("testVariantReturn").Should().BeSameAs(o);
|
||||
|
||||
qObject.SetProperty("objectName", "ttttt");
|
||||
qObject.SetProperty("variantProperty", qObject);
|
||||
var result = qObject.InvokeMethod("testVariantReturn");
|
||||
result.Should().NotBeNull();
|
||||
var resultQObject = result as INetQObject;
|
||||
resultQObject.Should().NotBeNull();
|
||||
resultQObject.GetProperty("objectName").Should().Be("ttttt");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_set_qobject_on_global_context_property()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
var d = (dynamic)qObject;
|
||||
var property = Guid.NewGuid().ToString().Replace("-", "");
|
||||
d.objectName = property;
|
||||
qmlApplicationEngine.SetContextProperty(property, d);
|
||||
var result = qmlApplicationEngine.GetContextProperty(property);
|
||||
(result is INetQObject).Should().BeTrue();
|
||||
result.Should().NotBeNull();
|
||||
((string)d.objectName).Should().Be(property);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_invoke_method_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
// TODO: Assert
|
||||
qObject.InvokeMethod("testSlot");
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_attach_notify_signal_to_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
var raised = false;
|
||||
var expected = 0;
|
||||
var handler = qObject.AttachNotifySignal("propWithSignal", parameters =>
|
||||
{
|
||||
raised = true;
|
||||
parameters.Count.Should().Be(1);
|
||||
parameters[0].Should().Be(expected);
|
||||
});
|
||||
|
||||
expected = 43;
|
||||
qObject.SetProperty("propWithSignal", 43);
|
||||
raised.Should().BeTrue();
|
||||
|
||||
raised = false;
|
||||
qObject.SetProperty("propWithSignal", 43);
|
||||
raised.Should().BeFalse();
|
||||
|
||||
expected = 44;
|
||||
raised = false;
|
||||
qObject.SetProperty("propWithSignal", 44);
|
||||
raised.Should().BeTrue();
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_attach_signal_to_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
var raised = 0;
|
||||
var handler = qObject.AttachSignal("testSignal", parameters =>
|
||||
{
|
||||
raised++;
|
||||
});
|
||||
handler.Should().NotBeNull();
|
||||
|
||||
qObject.InvokeMethod("testSlot");
|
||||
raised.Should().Be(1);
|
||||
|
||||
handler.Dispose();
|
||||
|
||||
qObject.InvokeMethod("testSlot");
|
||||
raised.Should().Be(1);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_attach_signal_with_arg_to_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
var raised = false;
|
||||
var handler = qObject.AttachSignal("testSignalWithArg", parameters =>
|
||||
{
|
||||
raised = true;
|
||||
parameters.Should().NotBeNull();
|
||||
parameters.Count.Should().Be(1);
|
||||
parameters[0].Should().Be(33);
|
||||
});
|
||||
|
||||
qObject.InvokeMethod("testSlotWithArg", 33);
|
||||
|
||||
handler.Dispose();
|
||||
raised = false;
|
||||
|
||||
qObject.InvokeMethod("testSlotWithArg", 33);
|
||||
raised.Should().BeFalse();
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_bool_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "Bool", true);
|
||||
AssertValue(qObject, "Bool", false);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_char_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "Char", 'T');
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_int_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "Int", int.MinValue);
|
||||
AssertValue(qObject, "Int", int.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_uint_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "UInt", uint.MinValue);
|
||||
AssertValue(qObject, "UInt", uint.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_long_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "Long", -23423);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_ulong_on_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "ULong", 2323);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_float_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "Float", float.MinValue);
|
||||
AssertValue(qObject, "Float", float.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_double_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "Double", double.MinValue);
|
||||
AssertValue(qObject, "Double", double.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_string_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "String", "test");
|
||||
AssertValue(qObject, "String", "");
|
||||
AssertValue(qObject, "String", null);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_datetime_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
var value = DateTimeOffset.Now;
|
||||
value = new DateTimeOffset(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, value.Millisecond, value.Offset);
|
||||
AssertValue(qObject, "DateTime", value);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_qobject_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
qObject.SetProperty("objectName", "testttdd");
|
||||
AssertValue(qObject, "QObject", qObject, result =>
|
||||
{
|
||||
result.Should().BeAssignableTo<INetQObject>()
|
||||
.Subject.GetProperty("objectName").Should().Be("testttdd");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_object_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
var o = new object();
|
||||
AssertValue(qObject, "QObject", o, result =>
|
||||
{
|
||||
result.Should().BeSameAs(o);
|
||||
});
|
||||
|
||||
AssertValue(qObject, "QObject", null, result =>
|
||||
{
|
||||
result.Should().BeNull();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_qint32_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "QInt32", int.MinValue);
|
||||
AssertValue(qObject, "QInt32", int.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_quint32_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "QUInt32", uint.MinValue);
|
||||
AssertValue(qObject, "QUInt32", uint.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_qint64_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "QInt64", long.MinValue);
|
||||
AssertValue(qObject, "QInt64", long.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Can_use_quint64_with_qobject()
|
||||
{
|
||||
AssertQObject(qObject =>
|
||||
{
|
||||
AssertValue(qObject, "QUInt64", ulong.MinValue);
|
||||
AssertValue(qObject, "QUInt64", ulong.MaxValue);
|
||||
});
|
||||
}
|
||||
|
||||
private void AssertValue(INetQObject qObject, string method, object value)
|
||||
{
|
||||
var raised = false;
|
||||
var handler = qObject.AttachSignal($"testSignal{method}", parameters =>
|
||||
{
|
||||
raised = true;
|
||||
parameters.Count.Should().Be(1);
|
||||
parameters[0].Should().Be(value);
|
||||
});
|
||||
using (handler)
|
||||
{
|
||||
var invokeResult = qObject.InvokeMethod($"testSlot{method}", value);
|
||||
invokeResult.Should().Be(value);
|
||||
raised.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertValue(INetQObject qObject, string method, object value, Action<object> assert)
|
||||
{
|
||||
var raised = false;
|
||||
var handler = qObject.AttachSignal($"testSignal{method}", parameters =>
|
||||
{
|
||||
raised = true;
|
||||
parameters.Count.Should().Be(1);
|
||||
assert(parameters[0]);
|
||||
});
|
||||
using (handler)
|
||||
{
|
||||
assert(qObject.InvokeMethod($"testSlot{method}", value));
|
||||
raised.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertQObject(Action<INetQObject> action)
|
||||
{
|
||||
Exception assertException = null;
|
||||
|
||||
Mock.Setup(x => x.Method(It.IsAny<INetQObject>()))
|
||||
.Callback(new Action<dynamic>(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
action(x as INetQObject);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
assertException = ex;
|
||||
}
|
||||
}));
|
||||
|
||||
RunQmlTest(
|
||||
"test",
|
||||
@"
|
||||
test.method(testQObject)
|
||||
");
|
||||
|
||||
Mock.Verify(x => x.Method(It.IsAny<INetQObject>()), Times.Once);
|
||||
if (assertException != null)
|
||||
{
|
||||
throw new Exception(assertException.Message, assertException);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,4 +3,5 @@
|
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OSX/@EntryIndexedValue">OSX</s:String>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=gstream/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pixmaps/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=qobject/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Runtimes/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
@ -10,6 +10,8 @@ namespace Qml.Net
|
|||
|
||||
object GetProperty(string propertyName);
|
||||
|
||||
void SetProperty(string propertyName, object value);
|
||||
|
||||
object GetItemAtIndex(int arrayIndex);
|
||||
|
||||
object Call(params object[] parameters);
|
||||
|
|
|
|||
20
src/net/Qml.Net/INetQObject.cs
Normal file
20
src/net/Qml.Net/INetQObject.cs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Qml.Net
|
||||
{
|
||||
public interface INetQObject : IDisposable
|
||||
{
|
||||
object GetProperty(string propertyName);
|
||||
|
||||
void SetProperty(string propertyName, object value);
|
||||
|
||||
object InvokeMethod(string methodName, params object[] parameters);
|
||||
|
||||
IDisposable AttachSignal(string signalName, SignalHandler handler);
|
||||
|
||||
IDisposable AttachNotifySignal(string propertyName, SignalHandler handler);
|
||||
}
|
||||
|
||||
public delegate void SignalHandler(List<object> parameters);
|
||||
}
|
||||
|
|
@ -248,6 +248,10 @@ namespace Qml.Net.Internal.CodeGen
|
|||
{
|
||||
variant.JsValue = valueJsValue;
|
||||
}
|
||||
else if (value is NetQObject valueQObject)
|
||||
{
|
||||
variant.QObject = valueQObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
variant.Instance = NetReference.CreateForObject(value);
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ namespace Qml.Net.Internal.CodeGen
|
|||
break;
|
||||
case NetVariantType.JsValue:
|
||||
throw new NotImplementedException();
|
||||
case NetVariantType.QObject:
|
||||
throw new NotImplementedException();
|
||||
case NetVariantType.Invalid:
|
||||
throw new Exception("invalid type");
|
||||
default:
|
||||
|
|
@ -224,6 +226,8 @@ namespace Qml.Net.Internal.CodeGen
|
|||
break;
|
||||
case NetVariantType.JsValue:
|
||||
throw new NotImplementedException();
|
||||
case NetVariantType.QObject:
|
||||
throw new NotImplementedException();
|
||||
case NetVariantType.Invalid:
|
||||
throw new Exception("invalid type");
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -462,6 +462,24 @@ namespace Qml.Net.Internal
|
|||
}
|
||||
}
|
||||
|
||||
public void InvokeDelegate(IntPtr del, IntPtr parameters)
|
||||
{
|
||||
using (var netReference = new NetReference(del))
|
||||
{
|
||||
using (var netParameters = new NetVariantList(parameters))
|
||||
{
|
||||
var o = netReference.Instance;
|
||||
var oDel = o as Del;
|
||||
if (oDel == null)
|
||||
{
|
||||
throw new Exception($"NetReferecnce is invalid type: {o.GetType().FullName}");
|
||||
}
|
||||
|
||||
oDel.Raise(netParameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NetVariantType GetPrefVariantType(Type typeInfo)
|
||||
{
|
||||
if (typeInfo == typeof(bool))
|
||||
|
|
|
|||
16
src/net/Qml.Net/Internal/Del.cs
Normal file
16
src/net/Qml.Net/Internal/Del.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using Qml.Net.Internal.Qml;
|
||||
|
||||
namespace Qml.Net.Internal
|
||||
{
|
||||
internal class Del
|
||||
{
|
||||
public event Action<NetVariantList> Invoked;
|
||||
|
||||
public void Raise(NetVariantList parameters)
|
||||
{
|
||||
var handler = Invoked;
|
||||
handler?.Invoke(parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,6 +55,8 @@ namespace Qml.Net.Internal
|
|||
destination.DateTime = ((DateTimeOffset)source).DateTime;
|
||||
else if (typeof(INetJsValue).IsAssignableFrom(type))
|
||||
destination.JsValue = ((NetJsValue.NetJsValueDynamic)source).JsValue;
|
||||
else if (typeof(INetQObject).IsAssignableFrom(type))
|
||||
destination.QObject = ((NetQObject.NetQObjectDynamic)source).QObject;
|
||||
else
|
||||
{
|
||||
if (type.IsEnum)
|
||||
|
|
@ -131,6 +133,9 @@ namespace Qml.Net.Internal
|
|||
case NetVariantType.JsValue:
|
||||
destination = source.JsValue.AsDynamic();
|
||||
break;
|
||||
case NetVariantType.QObject:
|
||||
destination = source.QObject.AsDynamic();
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unsupported variant type.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ namespace Qml.Net.Internal
|
|||
Utilities = LoadInteropType<UtilitiesInterop>(library, loader);
|
||||
QtWebEngine = LoadInteropType<QtWebEngineInterop>(library, loader);
|
||||
QTest = LoadInteropType<QTestInterop>(library, loader);
|
||||
NetQObject = LoadInteropType<NetQObjectInterop>(library, loader);
|
||||
NetQObjectSignalConnection = LoadInteropType<NetQObjectSignalConnectionInterop>(library, loader);
|
||||
|
||||
// RuntimeManager.ConfigureRuntimeDirectory may set these environment variables.
|
||||
// However, they only really work when called with Qt.PutEnv.
|
||||
|
|
@ -122,6 +124,10 @@ namespace Qml.Net.Internal
|
|||
public static QtWebEngineInterop QtWebEngine { get; }
|
||||
|
||||
public static QTestInterop QTest { get; }
|
||||
|
||||
public static NetQObjectInterop NetQObject { get; }
|
||||
|
||||
public static NetQObjectSignalConnectionInterop NetQObjectSignalConnection { get; set; }
|
||||
|
||||
private static T LoadInteropType<T>(IntPtr library, IPlatformLoader loader)
|
||||
where T : new()
|
||||
|
|
|
|||
|
|
@ -121,6 +121,22 @@ namespace Qml.Net.Internal.Qml
|
|||
return unpacked;
|
||||
}
|
||||
|
||||
public void SetProperty(string propertyName, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
_jsValue.SetProperty(propertyName, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var variant = new NetVariant())
|
||||
{
|
||||
Helpers.Pack(value, variant, value.GetType());
|
||||
_jsValue.SetProperty(propertyName, variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object GetItemAtIndex(int arrayIndex)
|
||||
{
|
||||
var result = _jsValue.GetItemAtIndex(arrayIndex);
|
||||
|
|
@ -170,19 +186,7 @@ namespace Qml.Net.Internal.Qml
|
|||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
_jsValue.SetProperty(binder.Name, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var variant = new NetVariant())
|
||||
{
|
||||
Helpers.PackValue(value, variant);
|
||||
_jsValue.SetProperty(binder.Name, variant);
|
||||
}
|
||||
}
|
||||
|
||||
SetProperty(binder.Name, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
270
src/net/Qml.Net/Internal/Qml/NetQObject.cs
Normal file
270
src/net/Qml.Net/Internal/Qml/NetQObject.cs
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Qml.Net.Internal.Types;
|
||||
|
||||
namespace Qml.Net.Internal.Qml
|
||||
{
|
||||
internal class NetQObject : BaseDisposable
|
||||
{
|
||||
public NetQObject(IntPtr handle, bool ownsHandle = true)
|
||||
: base(handle, ownsHandle)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DisposeUnmanaged(IntPtr ptr)
|
||||
{
|
||||
Interop.NetQObject.Destroy(ptr);
|
||||
}
|
||||
|
||||
public NetVariant GetProperty(string propertyName)
|
||||
{
|
||||
byte wasSuccessful = 0;
|
||||
var result = Interop.NetQObject.GetProperty(Handle, propertyName, ref wasSuccessful);
|
||||
if (wasSuccessful == 0)
|
||||
{
|
||||
// Dispose of the type before we throw
|
||||
using (result == IntPtr.Zero ? null : new NetVariant(result)) { }
|
||||
throw new Exception("Getting property failed.");
|
||||
}
|
||||
return result != IntPtr.Zero ? new NetVariant(result) : null;
|
||||
}
|
||||
|
||||
public void SetProperty(string propertyName, NetVariant value)
|
||||
{
|
||||
byte wasSuccessful = 0;
|
||||
Interop.NetQObject.SetProperty(Handle, propertyName, value?.Handle ?? IntPtr.Zero, ref wasSuccessful);
|
||||
if (wasSuccessful == 0)
|
||||
{
|
||||
throw new Exception("Setting property failed.");
|
||||
}
|
||||
}
|
||||
|
||||
public NetVariant InvokeMethod(string methodName, NetVariantList parameters)
|
||||
{
|
||||
byte wasSuccessful = 0;
|
||||
var result = Interop.NetQObject.InvokeMethod(Handle, methodName, parameters?.Handle ?? IntPtr.Zero, ref wasSuccessful);
|
||||
|
||||
if (wasSuccessful == 0)
|
||||
{
|
||||
// Dispose of the type before we throw
|
||||
using (result == IntPtr.Zero ? null : new NetVariant(result)) { }
|
||||
throw new Exception("Invoking method failed.");
|
||||
}
|
||||
|
||||
return result != IntPtr.Zero ? new NetVariant(result) : null;
|
||||
}
|
||||
|
||||
public NetQObjectSignalConnection AttachSignal(string signalName, Del del)
|
||||
{
|
||||
using (var delReference = NetReference.CreateForObject(del))
|
||||
{
|
||||
byte wasSuccessful = 0;
|
||||
var result = Interop.NetQObject.AttachSignal(Handle, signalName, delReference.Handle, ref wasSuccessful);
|
||||
|
||||
if (wasSuccessful == 0)
|
||||
{
|
||||
// Dispose of the type before we throw
|
||||
using (result == IntPtr.Zero ? null : new NetQObjectSignalConnection(result)) { }
|
||||
throw new Exception("Attaching to signal failed.");
|
||||
}
|
||||
|
||||
return result == IntPtr.Zero ? null : new NetQObjectSignalConnection(result);
|
||||
}
|
||||
}
|
||||
|
||||
public NetQObjectSignalConnection AttachNotifySignal(string propertyName, Del del)
|
||||
{
|
||||
using (var delReference = NetReference.CreateForObject(del))
|
||||
{
|
||||
byte wasSuccessful = 0;
|
||||
var result = Interop.NetQObject.AttachNotifySignal(Handle, propertyName, delReference.Handle, ref wasSuccessful);
|
||||
|
||||
if (wasSuccessful == 0)
|
||||
{
|
||||
// Dispose of the type before we throw
|
||||
using (result == IntPtr.Zero ? null : new NetQObjectSignalConnection(result)) { }
|
||||
throw new Exception("Attaching to notify signal failed.");
|
||||
}
|
||||
|
||||
return result == IntPtr.Zero ? null : new NetQObjectSignalConnection(result);
|
||||
}
|
||||
}
|
||||
|
||||
public dynamic AsDynamic()
|
||||
{
|
||||
return new NetQObjectDynamic(this);
|
||||
}
|
||||
|
||||
internal class NetQObjectDynamic : DynamicObject, INetQObject
|
||||
{
|
||||
readonly NetQObject _qObject;
|
||||
|
||||
public NetQObjectDynamic(NetQObject qObject)
|
||||
{
|
||||
_qObject = qObject;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_qObject.Dispose();
|
||||
}
|
||||
|
||||
public NetQObject QObject => _qObject;
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
result = GetProperty(binder.Name);
|
||||
// TODO: Check if this was actually a property
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool TrySetMember(SetMemberBinder binder, object value)
|
||||
{
|
||||
SetProperty(binder.Name, value);
|
||||
// TODO: Check if this was actually a property
|
||||
return true;
|
||||
}
|
||||
|
||||
public object GetProperty(string propertyName)
|
||||
{
|
||||
var property = _qObject.GetProperty(propertyName);
|
||||
if (property == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
object unpacked = null;
|
||||
Helpers.Unpackvalue(ref unpacked, property);
|
||||
property.Dispose();
|
||||
return unpacked;
|
||||
}
|
||||
|
||||
public void SetProperty(string propertyName, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
_qObject.SetProperty(propertyName, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var variant = new NetVariant())
|
||||
{
|
||||
Helpers.PackValue(value, variant);
|
||||
_qObject.SetProperty(propertyName, variant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object InvokeMethod(string methodName, params object[] parameters)
|
||||
{
|
||||
NetVariantList variantParameters = null;
|
||||
if (parameters != null && parameters.Length > 0)
|
||||
{
|
||||
variantParameters = new NetVariantList();
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
using (var variantParameter = NetVariant.From(parameter))
|
||||
{
|
||||
variantParameters.Add(variantParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
using (variantParameters)
|
||||
using (var result = _qObject.InvokeMethod(methodName, variantParameters))
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
object unpacked = null;
|
||||
Helpers.Unpackvalue(ref unpacked, result);
|
||||
result.Dispose();
|
||||
return unpacked;
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable AttachSignal(string signalName, SignalHandler handler)
|
||||
{
|
||||
var del = new Del();
|
||||
del.Invoked += parameters =>
|
||||
{
|
||||
var result = new List<object>();
|
||||
|
||||
var parametersCount = parameters.Count;
|
||||
for (var x = 0; x < parametersCount; x++)
|
||||
{
|
||||
using (var parameter = parameters.Get(x))
|
||||
{
|
||||
object parameterValue = null;
|
||||
Helpers.Unpackvalue(ref parameterValue, parameter);
|
||||
result.Add(parameterValue);
|
||||
}
|
||||
}
|
||||
|
||||
handler(result);
|
||||
};
|
||||
|
||||
return _qObject.AttachSignal(signalName, del);
|
||||
}
|
||||
|
||||
public IDisposable AttachNotifySignal(string propertyName, SignalHandler handler)
|
||||
{
|
||||
var del = new Del();
|
||||
del.Invoked += parameters =>
|
||||
{
|
||||
var result = new List<object>();
|
||||
|
||||
var parametersCount = parameters.Count;
|
||||
for (var x = 0; x < parametersCount; x++)
|
||||
{
|
||||
using (var parameter = parameters.Get(x))
|
||||
{
|
||||
object parameterValue = null;
|
||||
Helpers.Unpackvalue(ref parameterValue, parameter);
|
||||
result.Add(parameterValue);
|
||||
}
|
||||
}
|
||||
|
||||
handler(result);
|
||||
};
|
||||
|
||||
return _qObject.AttachNotifySignal(propertyName, del);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class NetQObjectInterop
|
||||
{
|
||||
[NativeSymbol(Entrypoint = "net_qobject_destroy")]
|
||||
public DestroyDel Destroy { get; set; }
|
||||
|
||||
public delegate void DestroyDel(IntPtr qObject);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_qobject_getProperty")]
|
||||
public GetPropertyDel GetProperty { get; set; }
|
||||
|
||||
public delegate IntPtr GetPropertyDel(IntPtr qObject, [MarshalAs(UnmanagedType.LPWStr)] string propertyName, ref byte result);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_qobject_setProperty")]
|
||||
public SetPropertyDel SetProperty { get; set; }
|
||||
|
||||
public delegate IntPtr SetPropertyDel(IntPtr qObject, [MarshalAs(UnmanagedType.LPWStr)] string propertyName, IntPtr netVariant, ref byte result);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_qobject_invokeMethod")]
|
||||
public InvokeMethodDel InvokeMethod { get; set; }
|
||||
|
||||
public delegate IntPtr InvokeMethodDel(IntPtr qObject, [MarshalAs(UnmanagedType.LPWStr)] string methodName, IntPtr parameters, ref byte result);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_qobject_attachSignal")]
|
||||
public AttachSignalDel AttachSignal { get; set; }
|
||||
|
||||
public delegate IntPtr AttachSignalDel(IntPtr qObject, [MarshalAs(UnmanagedType.LPWStr)] string signalName, IntPtr del, ref byte result);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_qobject_attachNotifySignal")]
|
||||
public AttachNotifySignalDel AttachNotifySignal { get; set; }
|
||||
|
||||
public delegate IntPtr AttachNotifySignalDel(IntPtr qObject, [MarshalAs(UnmanagedType.LPWStr)] string signalName, IntPtr del, ref byte result);
|
||||
}
|
||||
}
|
||||
25
src/net/Qml.Net/Internal/Qml/NetQObjectSignalConnection.cs
Normal file
25
src/net/Qml.Net/Internal/Qml/NetQObjectSignalConnection.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
|
||||
namespace Qml.Net.Internal.Qml
|
||||
{
|
||||
internal class NetQObjectSignalConnection : BaseDisposable
|
||||
{
|
||||
public NetQObjectSignalConnection(IntPtr handle, bool ownsHandle = true)
|
||||
: base(handle, ownsHandle)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DisposeUnmanaged(IntPtr ptr)
|
||||
{
|
||||
Interop.NetQObjectSignalConnection.Destroy(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
internal class NetQObjectSignalConnectionInterop
|
||||
{
|
||||
[NativeSymbol(Entrypoint = "net_qobject_signal_handler_destroy")]
|
||||
public DestroyDel Destroy { get; set; }
|
||||
|
||||
public delegate void DestroyDel(IntPtr signalHandler);
|
||||
}
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ namespace Qml.Net.Internal.Qml
|
|||
get => Utilities.ContainerToString(Interop.NetVariant.GetString(Handle));
|
||||
set => Interop.NetVariant.SetString(Handle, value);
|
||||
}
|
||||
|
||||
|
||||
public DateTimeOffset? DateTime
|
||||
{
|
||||
get
|
||||
|
|
@ -135,6 +135,16 @@ namespace Qml.Net.Internal.Qml
|
|||
set => Interop.NetVariant.SetJsValue(Handle, value?.Handle ?? IntPtr.Zero);
|
||||
}
|
||||
|
||||
public NetQObject QObject
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = Interop.NetVariant.GetQObject(Handle);
|
||||
return result == IntPtr.Zero ? null : new NetQObject(result);
|
||||
}
|
||||
set => Interop.NetVariant.SetQObject(Handle, value?.Handle ?? IntPtr.Zero);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Interop.NetVariant.Clear(Handle);
|
||||
|
|
@ -174,6 +184,8 @@ namespace Qml.Net.Internal.Qml
|
|||
|
||||
case NetVariantType.JsValue:
|
||||
return JsValue.AsDynamic();
|
||||
case NetVariantType.QObject:
|
||||
return QObject.AsDynamic();
|
||||
default:
|
||||
throw new NotImplementedException($"unhandled type {VariantType}");
|
||||
}
|
||||
|
|
@ -187,7 +199,20 @@ namespace Qml.Net.Internal.Qml
|
|||
public static NetVariant From<T>(T value)
|
||||
{
|
||||
var variant = new NetVariant();
|
||||
Helpers.Pack(value, variant, typeof(T));
|
||||
if (value != null)
|
||||
{
|
||||
Helpers.Pack(value, variant, typeof(T));
|
||||
}
|
||||
return variant;
|
||||
}
|
||||
|
||||
public static NetVariant From(object value)
|
||||
{
|
||||
var variant = new NetVariant();
|
||||
if (value != null)
|
||||
{
|
||||
Helpers.Pack(value, variant, value.GetType());
|
||||
}
|
||||
return variant;
|
||||
}
|
||||
}
|
||||
|
|
@ -329,6 +354,16 @@ namespace Qml.Net.Internal.Qml
|
|||
|
||||
public delegate IntPtr GetJsValueDel(IntPtr variant);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_variant_setQObject")]
|
||||
public SetQObjectDel SetQObject { get; set; }
|
||||
|
||||
public delegate void SetQObjectDel(IntPtr variant, IntPtr jsValue);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_variant_getQObject")]
|
||||
public GetQObjectDel GetQObject { get; set; }
|
||||
|
||||
public delegate IntPtr GetQObjectDel(IntPtr variant);
|
||||
|
||||
[NativeSymbol(Entrypoint = "net_variant_clear")]
|
||||
public ClearDel Clear { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Dynamic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -22,6 +23,7 @@ namespace Qml.Net.Internal.Types
|
|||
public IntPtr RaseNetSignals;
|
||||
public IntPtr AwaitTask;
|
||||
public IntPtr Serialize;
|
||||
public IntPtr InvokeDelegate;
|
||||
}
|
||||
|
||||
internal class CallbacksInterop
|
||||
|
|
@ -88,6 +90,8 @@ namespace Qml.Net.Internal.Types
|
|||
Task AwaitTask(IntPtr target, IntPtr succesCallback, IntPtr failureCallback);
|
||||
|
||||
bool Serialize(IntPtr instance, IntPtr result);
|
||||
|
||||
void InvokeDelegate(IntPtr del, IntPtr parameters);
|
||||
}
|
||||
|
||||
internal class CallbacksImpl
|
||||
|
|
@ -108,6 +112,7 @@ namespace Qml.Net.Internal.Types
|
|||
RaiseNetSignalsDelegate _raiseNetSignalsDelegate;
|
||||
AwaitTaskDelegate _awaitTaskDelegate;
|
||||
SerializeDelegate _serializeDelegate;
|
||||
InvokeDelegateDelegate _invokeDelegateDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate byte IsTypeValidDelegate([MarshalAs(UnmanagedType.LPWStr)]string typeName);
|
||||
|
|
@ -153,6 +158,9 @@ namespace Qml.Net.Internal.Types
|
|||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate byte SerializeDelegate(IntPtr instance, IntPtr result);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void InvokeDelegateDelegate(IntPtr del, IntPtr parameters);
|
||||
|
||||
public CallbacksImpl(ICallbacks callbacks)
|
||||
{
|
||||
|
|
@ -202,6 +210,9 @@ namespace Qml.Net.Internal.Types
|
|||
|
||||
_serializeDelegate = Serialize;
|
||||
GCHandle.Alloc(_serializeDelegate);
|
||||
|
||||
_invokeDelegateDelegate = InvokeDelegate;
|
||||
GCHandle.Alloc(_invokeDelegateDelegate);
|
||||
}
|
||||
|
||||
private byte IsTypeValid(string typeName)
|
||||
|
|
@ -282,6 +293,11 @@ namespace Qml.Net.Internal.Types
|
|||
return _callbacks.Serialize(instance, result) ? (byte)1 : (byte)0;
|
||||
}
|
||||
|
||||
private void InvokeDelegate(IntPtr del, IntPtr parameters)
|
||||
{
|
||||
_callbacks.InvokeDelegate(del, parameters);
|
||||
}
|
||||
|
||||
public Callbacks Callbacks()
|
||||
{
|
||||
return new Callbacks
|
||||
|
|
@ -300,7 +316,8 @@ namespace Qml.Net.Internal.Types
|
|||
GCCollect = Marshal.GetFunctionPointerForDelegate(_gcCollectDelegate),
|
||||
RaseNetSignals = Marshal.GetFunctionPointerForDelegate(_raiseNetSignalsDelegate),
|
||||
AwaitTask = Marshal.GetFunctionPointerForDelegate(_awaitTaskDelegate),
|
||||
Serialize = Marshal.GetFunctionPointerForDelegate(_serializeDelegate)
|
||||
Serialize = Marshal.GetFunctionPointerForDelegate(_serializeDelegate),
|
||||
InvokeDelegate = Marshal.GetFunctionPointerForDelegate(_invokeDelegateDelegate)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,5 +15,6 @@
|
|||
DateTime,
|
||||
Object,
|
||||
JsValue,
|
||||
QObject
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue