Added support for associated signals with properties.

This commit is contained in:
Paul Knopf 2018-07-20 04:17:29 -04:00
parent ee7ac16c5f
commit 79bd19d6df
11 changed files with 245 additions and 71 deletions

View file

@ -199,54 +199,13 @@ QMetaObject *metaObjectFor(QSharedPointer<NetTypeInfo> typeInfo)
for(uint index = 0; index <= typeInfo->getSignalCount() - 1; index++)
{
QSharedPointer<NetSignalInfo> signalInfo = typeInfo->getSignal(index);
QString signature = signalInfo->getName();
signature.append("(");
if(signalInfo->getParameterCount() > 0) {
for(uint parameterIndex = 0; parameterIndex <= signalInfo->getParameterCount() - 1; parameterIndex++)
{
if(parameterIndex > 0) {
signature.append(", ");
}
signature.append("QVariant");
}
}
signature.append(")");
mob.addSignal(signature.toLocal8Bit().constData());
QString signature = signalInfo->getSignature();
mob.addSignal(QMetaObject::normalizedSignature(signature.toLocal8Bit().constData()));
}
}
if(typeInfo->getMethodCount() > 0) {
for(uint index = 0; index <= typeInfo->getMethodCount() - 1; index++)
{
QSharedPointer<NetMethodInfo> methodInfo = typeInfo->getMethodInfo(index);
QSharedPointer<NetTypeInfo> returnType = methodInfo->getReturnType();
QString signature = methodInfo->getMethodName();
signature.append("(");
if(methodInfo->getParameterCount() > 0) {
for(uint parameterIndex = 0; parameterIndex <= methodInfo->getParameterCount() - 1; parameterIndex++)
{
if(parameterIndex > 0) {
signature.append(", ");
}
signature.append("QVariant");
}
}
signature.append(")");
if(returnType != NULL) {
mob.addMethod(signature.toLocal8Bit().constData(), "QVariant");
} else {
mob.addMethod(signature.toLocal8Bit().constData());
}
}
}
// NOTE: It is important to register properties after the signals (before methods)
// because of the assumptions we make about getting the "notifySignal" by index.
if(typeInfo->getPropertyCount() > 0) {
for(uint index = 0; index <= typeInfo->getPropertyCount() - 1; index++)
@ -255,11 +214,37 @@ QMetaObject *metaObjectFor(QSharedPointer<NetTypeInfo> typeInfo)
QMetaPropertyBuilder propb = mob.addProperty(propertyInfo->getPropertyName().toLatin1(),
"QVariant",
index);
QSharedPointer<NetSignalInfo> notifySignal = propertyInfo->getNotifySignal();
if(notifySignal != NULL) {
// The signal was previously registered, find the index.
for(uint signalIndex = 0; signalIndex <= typeInfo->getSignalCount() - 1; signalIndex++)
{
if(typeInfo->getSignal(signalIndex) == notifySignal) {
QMetaMethodBuilder notifySignalBuilder = mob.method(signalIndex);
propb.setNotifySignal(notifySignalBuilder);
break;
}
}
}
propb.setWritable(propertyInfo->canWrite());
propb.setReadable(propertyInfo->canRead());
}
}
if(typeInfo->getMethodCount() > 0) {
for(uint index = 0; index <= typeInfo->getMethodCount() - 1; index++)
{
QSharedPointer<NetMethodInfo> methodInfo = typeInfo->getMethodInfo(index);
QSharedPointer<NetTypeInfo> returnType = methodInfo->getReturnType();
QString signature = methodInfo->getSignature();
if(returnType != NULL) {
mob.addMethod(QMetaObject::normalizedSignature(signature.toLocal8Bit().constData()), "QVariant");
} else {
mob.addMethod(QMetaObject::normalizedSignature(signature.toLocal8Bit().constData()));
}
}
}
QMetaObject *mo = mob.toMetaObject();
typeInfo->metaObject = mo;
return mo;

View file

@ -44,6 +44,26 @@ QSharedPointer<NetMethodInfoArguement> NetMethodInfo::getParameter(uint index) {
return _parameters.at(index);
}
QString NetMethodInfo::getSignature() {
QString signature = _methodName;
signature.append("(");
if(_parameters.size() > 0) {
for(int parameterIndex = 0; parameterIndex <= _parameters.size() - 1; parameterIndex++)
{
if(parameterIndex > 0) {
signature.append(",");
}
signature.append("QVariant");
}
}
signature.append(")");
return signature;
}
extern "C" {
Q_DECL_EXPORT void method_info_parameter_destroy(NetMethodInfoArguementContainer* container) {

View file

@ -30,6 +30,8 @@ public:
uint getParameterCount();
QSharedPointer<NetMethodInfoArguement> getParameter(uint index);
QString getSignature();
private:
QSharedPointer<NetTypeInfo> _parentTypeInfo;
QString _methodName;

View file

@ -1,15 +1,18 @@
#include <QtNetCoreQml/types/NetPropertyInfo.h>
#include <QtNetCoreQml/types/NetSignalInfo.h>
NetPropertyInfo::NetPropertyInfo(QSharedPointer<NetTypeInfo> parentType,
QString name,
QSharedPointer<NetTypeInfo> returnType,
bool canRead,
bool canWrite) :
bool canWrite,
QSharedPointer<NetSignalInfo> notifySignal) :
_parentType(parentType),
_name(name),
_returnType(returnType),
_canRead(canRead),
_canWrite(canWrite)
_canWrite(canWrite),
_notifySignal(notifySignal)
{
}
@ -39,19 +42,30 @@ bool NetPropertyInfo::canWrite()
return _canWrite;
}
QSharedPointer<NetSignalInfo> NetPropertyInfo::getNotifySignal()
{
return _notifySignal;
}
extern "C" {
Q_DECL_EXPORT NetPropertyInfoContainer* property_info_create(NetTypeInfoContainer* parentType,
Q_DECL_EXPORT NetPropertyInfoContainer* property_info_create(NetTypeInfoContainer* parentTypeContainer,
LPWSTR name,
NetTypeInfoContainer* returnType,
bool canRead,
bool canWrite) {
bool canWrite,
NetSignalInfoContainer* notifySignalContainer) {
NetPropertyInfoContainer* result = new NetPropertyInfoContainer();
NetPropertyInfo* instance = new NetPropertyInfo(parentType->netTypeInfo,
QSharedPointer<NetSignalInfo> notifySignal;
if(notifySignalContainer != NULL) {
notifySignal = notifySignalContainer->signal;
}
NetPropertyInfo* instance = new NetPropertyInfo(parentTypeContainer->netTypeInfo,
QString::fromUtf16((const char16_t*)name),
returnType->netTypeInfo,
canRead,
canWrite);
canWrite,
notifySignal);
result->property = QSharedPointer<NetPropertyInfo>(instance);
return result;
}
@ -85,4 +99,12 @@ Q_DECL_EXPORT bool property_info_canWrite(NetPropertyInfoContainer* container) {
return container->property->canWrite();
}
Q_DECL_EXPORT NetSignalInfoContainer* property_info_getNotifySignal(NetPropertyInfoContainer* container) {
QSharedPointer<NetSignalInfo> notifySignal = container->property->getNotifySignal();
if(notifySignal == NULL) {
return NULL;
}
return new NetSignalInfoContainer{notifySignal};
}
}

View file

@ -9,18 +9,21 @@ public:
QString name,
QSharedPointer<NetTypeInfo> returnType,
bool canRead,
bool canWrite);
bool canWrite,
QSharedPointer<NetSignalInfo> notifySignal);
QSharedPointer<NetTypeInfo> getParentType();
QString getPropertyName();
QSharedPointer<NetTypeInfo> getReturnType();
bool canRead();
bool canWrite();
QSharedPointer<NetSignalInfo> getNotifySignal();
private:
QSharedPointer<NetTypeInfo> _parentType;
QString _name;
QSharedPointer<NetTypeInfo> _returnType;
bool _canRead;
bool _canWrite;
QSharedPointer<NetSignalInfo> _notifySignal;
};
struct NetPropertyInfoContainer {

View file

@ -28,6 +28,27 @@ NetVariantTypeEnum NetSignalInfo::getParameter(uint index) {
return _parameters.at(index);
}
QString NetSignalInfo::getSignature() {
QString signature = _name;
signature.append("(");
if(_parameters.size() > 0) {
for(int parameterIndex = 0; parameterIndex <= _parameters.size() - 1; parameterIndex++)
{
if(parameterIndex > 0) {
signature.append(",");
}
signature.append("QVariant");
}
}
signature.append(")");
return signature;
}
extern "C" {
Q_DECL_EXPORT NetSignalInfoContainer* signal_info_create(NetTypeInfoContainer* parentTypeContainer, LPWSTR name) {

View file

@ -13,6 +13,7 @@ public:
void addParameter(NetVariantTypeEnum type);
uint getParameterCount();
NetVariantTypeEnum getParameter(uint index);
QString getSignature();
private:
QSharedPointer<NetTypeInfo> _parentType;
QString _name;

View file

@ -1,4 +1,5 @@
using FluentAssertions;
using System;
using FluentAssertions;
using Qt.NetCore.Types;
using Xunit;
@ -128,6 +129,7 @@ namespace Qt.NetCore.Tests.Types
property.CanWrite.Should().BeTrue();
property.ReturnType.ClassName.Should().Be("String");
property.ParentType.ClassName.Should().Be("TestType6");
property.NotifySignal.Should().BeNull();
}
[Signal("testSignal", NetVariantType.DateTime, NetVariantType.Object)]
@ -149,6 +151,58 @@ namespace Qt.NetCore.Tests.Types
signal.GetParameter(1).Should().Be(NetVariantType.Object);
}
[Signal("signalName")]
public class TestType8
{
[NotifySignal("signalName")]
public string Property { get; set; }
}
[Fact]
public void Can_get_notifiy_signal_for_property()
{
var type = NetTypeManager.GetTypeInfo<TestType8>();
type.SignalCount.Should().Be(1);
type.PropertyCount.Should().Be(1);
type.GetProperty(0).Name.Should().Be("Property");
type.GetProperty(0).NotifySignal.Should().NotBeNull();
type.GetProperty(0).NotifySignal.Name.Should().Be("signalName");
}
public class TestType9
{
[NotifySignal("signalName")]
public string Property { get; set; }
}
[Fact]
public void Can_auto_add_signal_for_property_notification()
{
var type = NetTypeManager.GetTypeInfo<TestType9>();
type.SignalCount.Should().Be(1);
type.PropertyCount.Should().Be(1);
type.GetProperty(0).Name.Should().Be("Property");
type.GetProperty(0).NotifySignal.Should().NotBeNull();
type.GetProperty(0).NotifySignal.Name.Should().Be("signalName");
}
public class TestType10
{
[NotifySignal]
public string Property { get; set; }
}
[Fact]
public void Can_auto_create_signal_with_property_name_if_no_name_given()
{
var type = NetTypeManager.GetTypeInfo<TestType10>();
type.SignalCount.Should().Be(1);
type.PropertyCount.Should().Be(1);
type.GetProperty(0).Name.Should().Be("Property");
type.GetProperty(0).NotifySignal.Should().NotBeNull();
type.GetProperty(0).NotifySignal.Name.Should().Be("PropertyChanged");
}
[Fact]
public void Null_type_returned_for_invalid_type()
{

View file

@ -68,32 +68,61 @@ namespace Qt.NetCore.Internal
type.AddMethod(method);
}
var signals = new Dictionary<string, NetSignalInfo>();
foreach (var signalAttribute in typeInfo.GetCustomAttributes().OfType<SignalAttribute>())
{
var signal = new NetSignalInfo(type, signalAttribute.Name);
foreach (var parameter in signalAttribute.Parameters)
{
signal.AddParameter(parameter);
}
type.AddSignal(signal);
signals.Add(signal.Name, signal);
}
foreach (var propertyInfo in typeInfo.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (Helpers.IsPrimitive(propertyInfo.DeclaringType)) continue;
NetSignalInfo notifySignal = null;
var notifySignalAttribute = propertyInfo.GetCustomAttribute<NotifySignalAttribute>();
if (notifySignalAttribute != null)
{
var name = notifySignalAttribute.Name;
if (string.IsNullOrEmpty(name))
{
name = $"{propertyInfo.Name}Changed";
}
if (signals.ContainsKey(name))
{
notifySignal = signals[name];
// Make sure the signal we are referencing has no parameters.
if (notifySignal.ParameterCount != 0)
{
// TODO: They can actually of parameters, but not implemented yet.
throw new Exception("Notify signals must have no parameters.");
}
}
else
{
notifySignal = new NetSignalInfo(type, name);
type.AddSignal(notifySignal);
}
}
using (var property = new NetPropertyInfo(
type,
propertyInfo.Name,
NetTypeManager.GetTypeInfo(propertyInfo.PropertyType.AssemblyQualifiedName),
propertyInfo.CanRead,
propertyInfo.CanWrite))
propertyInfo.CanWrite,
notifySignal))
{
type.AddProperty(property);
}
}
foreach (var signalAttribute in typeInfo.GetCustomAttributes().OfType<SignalAttribute>())
{
using (var signal = new NetSignalInfo(type, signalAttribute.Name))
{
foreach (var parameter in signalAttribute.Parameters)
{
signal.AddParameter(parameter);
}
type.AddSignal(signal);
}
}
}
}

View file

@ -0,0 +1,20 @@
using System;
namespace Qt.NetCore
{
[AttributeUsage(AttributeTargets.Property)]
public class NotifySignalAttribute : Attribute
{
public NotifySignalAttribute()
{
}
public NotifySignalAttribute(string name)
{
Name = name;
}
public string Name { get; set; }
}
}

View file

@ -11,12 +11,14 @@ namespace Qt.NetCore.Types
string name,
NetTypeInfo returnType,
bool canRead,
bool canWrite)
bool canWrite,
NetSignalInfo notifySignal)
: this(Create(parentType,
name,
returnType,
canRead,
canWrite))
canWrite,
notifySignal))
{
}
@ -31,13 +33,15 @@ namespace Qt.NetCore.Types
string name,
NetTypeInfo returnType,
bool canRead,
bool canWrite)
bool canWrite,
NetSignalInfo notifySignal)
{
return Interop.NetPropertyInfo.Create(parentType?.Handle ?? IntPtr.Zero,
name,
returnType?.Handle ?? IntPtr.Zero,
canRead,
canWrite);
canWrite,
notifySignal?.Handle ?? IntPtr.Zero);
}
public NetTypeInfo ParentType => new NetTypeInfo(Interop.NetPropertyInfo.GetParentType(Handle));
@ -49,6 +53,15 @@ namespace Qt.NetCore.Types
public bool CanRead => Interop.NetPropertyInfo.GetCanRead(Handle);
public bool CanWrite => Interop.NetPropertyInfo.GetCanWrite(Handle);
public NetSignalInfo NotifySignal
{
get
{
var result = Interop.NetPropertyInfo.GetNotifySignal(Handle);
return result == IntPtr.Zero ? null : new NetSignalInfo(result);
}
}
protected override void DisposeUnmanaged(IntPtr ptr)
{
@ -63,7 +76,8 @@ namespace Qt.NetCore.Types
[MarshalAs(UnmanagedType.LPWStr)]string methodName,
IntPtr returnType,
bool canRead,
bool canWrite);
bool canWrite,
IntPtr notifySignal);
[NativeSymbol(Entrypoint = "property_info_destroy")]
void Destroy(IntPtr property);
@ -81,5 +95,8 @@ namespace Qt.NetCore.Types
[NativeSymbol(Entrypoint = "property_info_canWrite")]
bool GetCanWrite(IntPtr property);
[NativeSymbol(Entrypoint = "property_info_getNotifySignal")]
IntPtr GetNotifySignal(IntPtr property);
}
}