diff --git a/D/DQml/qobject.d b/D/DQml/qobject.d index 8ce1550..22343f0 100644 --- a/D/DQml/qobject.d +++ b/D/DQml/qobject.d @@ -119,5 +119,5 @@ public class QObject } protected void* vptr; - private bool disableDosCalls; + protected bool disableDosCalls; } diff --git a/D/Examples/SlotsAndProperties/contact.d b/D/Examples/SlotsAndProperties/contact.d index f92cd2f..0f4f94d 100644 --- a/D/Examples/SlotsAndProperties/contact.d +++ b/D/Examples/SlotsAndProperties/contact.d @@ -1,4 +1,148 @@ import dqml; +import std.traits; +import std.algorithm; +import std.string; +import std.stdio; + +struct Slot {}; +struct Signal {}; + +string GenerateVariantConversionCall(string typeName) +{ + switch (typeName) + { + case "string": + return "toString()"; + case "int": + return "toInt()"; + default: + throw new Exception("error"); + } +} + +string GenerateArgumentList(string[] typeNames) +{ + string result = ""; + for (int i = 0; i < typeNames.length; ++i) + { + auto typeName = typeNames[i]; + auto variantCall = GenerateVariantConversionCall(typeName); + result ~= i > 0 ? "," : ""; + result ~= format("arguments[%d].%s", i+1, variantCall); + } + return result; +} + +string GenerateSlotCall(SlotInfo info) +{ + auto args = GenerateArgumentList(info.parameterTypes); + auto call = format("%s(%s)", info.name, args); + auto formatStr = info.returnType != "void" ? "arguments[0].setValue(%s)" : "%s"; + return format(formatStr, call); +} + +string GenerateCaseBlock(SlotInfo info) +{ + string result = ""; + result ~= format("case \"%s\":\n", info.name); + result ~= format("%s;\n", GenerateSlotCall(info)); + result ~= "break;\n"; + return result; +} + +string GenerateOnSlotCalled(T)() +{ + string result = "protected override void onSlotCalled(QVariant slotName, QVariant[] arguments)\n"; + result ~= "{\n"; + result ~= "switch(slotName.toString())\n"; + result ~= "{\n"; + foreach (info; IterateUDA!(T)()) + result ~= GenerateCaseBlock(info); + result ~= "default: break;\n"; + result ~= "}\n"; // + result ~= "}"; + return result; +} + +string GenerateMetaType(string typeName) +{ + switch(typeName) + { + case "void": + return "QMetaType.Void"; + case "int": + return "QMetaType.Int"; + case "string": + return "QMetaType.String"; + default: + throw new Exception(format("Unknown conversion from %s to QMetaType", typeName)); + } +} + +string GenerateMetaTypesList(SlotInfo info) +{ + string result = GenerateMetaType(info.returnType); + foreach (typeName; info.parameterTypes) + result ~= format(", %s", GenerateMetaType(typeName)); + return result; +} + +string GenerateQObjectInit(T)() +{ + string result = ""; + result ~= "protected void qobjectInit()\n"; + result ~= "{\n"; + + foreach (info; IterateUDA!(T)()) + { + auto metaTypes = GenerateMetaTypesList(info); + result ~= format("registerSlot(\"%s\", [%s]);\n", info.name, metaTypes); + } + + result ~= "}"; + return result; +} + +struct SlotInfo +{ + string name; + string returnType; + string[] parameterTypes; +} + +SlotInfo[] IterateUDA(T)() +{ + SlotInfo[] result; + + foreach (member; __traits(allMembers, T)) + { + static if (isSomeFunction!(__traits(getMember, T, member))) + { + // Retrieve the UDA + auto attributes = __traits(getAttributes, __traits(getMember, T, member)); + + // Turn the tuple in an array of strings + string[] attributeNames; + foreach (attribute; attributes) + attributeNames ~= typeof(attribute).stringof; + + // Extract the Function Return Type and Arguments + if (attributeNames.canFind("Slot")) + { + SlotInfo slotInfo; + slotInfo.name = member; + slotInfo.returnType = ReturnType!(__traits(getMember, T, member)).stringof; + + foreach (param; ParameterTypeTuple!(__traits(getMember, T, member))) + slotInfo.parameterTypes ~= param.stringof; + + result ~= slotInfo; + } + } + } + + return result; +} class Contact : QObject { @@ -8,16 +152,20 @@ class Contact : QObject registerSlot("setName", [QMetaType.Void, QMetaType.String]); registerSignal("nameChanged", [QMetaType.String]); registerProperty("name", QMetaType.String, "getName", "setName", "nameChanged"); + + writeln(GenerateOnSlotCalled!(Contact)); + writeln(GenerateQObjectInit!(Contact)); } ~this() {} - + @Slot() public string getName() { return m_name; } + @Slot() public void setName(string name) { if (m_name != name) @@ -27,20 +175,8 @@ class Contact : QObject } } - protected override void onSlotCalled(QVariant slotName, QVariant[] arguments) - { - switch (slotName.toString()) - { - case "getName": - arguments[0].setValue(getName()); - break; - case "setName": - setName(arguments[1].toString()); - break; - default: - break; - } - } - + mixin(GenerateOnSlotCalled!(Contact)); + mixin(GenerateQObjectInit!(Contact)); + private string m_name; }