[DQml] Refactored the macros and put them in its own file

This commit is contained in:
Filippo Cucchetto 2015-05-10 11:48:49 +02:00
parent 81e2b3d6b3
commit afb08fe225
4 changed files with 257 additions and 246 deletions

View File

@ -12,5 +12,6 @@ add_library(${PROJECT_NAME} STATIC
qapplication.d
qmodelindex.d
qabstractlistmodel.d
qobjectgenerators.d
)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -8,3 +8,7 @@ public import qquickview;
public import qmetatype;
public import qmodelindex;
public import qabstractlistmodel;
public import qobjectgenerators;
public import std.traits;
public import std.algorithm;
public import std.stdio;

247
D/DQml/qobjectgenerators.d Normal file
View File

@ -0,0 +1,247 @@
import std.traits;
import std.algorithm;
import std.string;
import std.stdio;
struct QtProperty
{
public string type;
public string name;
public string read;
public string write;
public string notify;
this(string type, string name, string read, string write, string notify)
{
this.type = type;
this.name = name;
this.read = read;
this.write = write;
this.notify = notify;
}
}
struct QtSlot {};
struct QtSignal {};
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(FunctionInfo 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(FunctionInfo info)
{
string result = "";
result ~= format("case \"%s\":\n", info.name);
result ~= format("%s;\n", GenerateSlotCall(info));
result ~= "break;\n";
return result;
}
string GenerateOnSlotCalled(QtInfo info)
{
string result = "protected override void onSlotCalled(QVariant slotName, QVariant[] arguments)\n";
result ~= "{\n";
result ~= "switch(slotName.toString())\n";
result ~= "{\n";
foreach (slot; info.slots)
result ~= GenerateCaseBlock(slot);
result ~= "default: super.onSlotCalled(slotName, arguments);\n";
result ~= "}\n"; //
result ~= "}";
return result;
}
string GenerateSignalCall(FunctionInfo info)
{
string args = "";
string vars = "";
for (int i = 0; i < info.parameterTypes.length; ++i) {
if (i > 0) {
args ~= ",";
vars ~= ",";
}
args ~= format("%s val%d", info.parameterTypes[i], i);
vars ~= format("val%d", i);
}
auto result = format("public %s %s(%s) { emit(\"%s\", %s); }", info.returnType, info.name, args, info.name, vars);
return result;
}
string GenerateQtSignals(QtInfo info)
{
string result = "";
foreach (signal; info.signals)
result ~= GenerateSignalCall(signal) ~ "\n";
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 GenerateMetaTypesListForSlot(FunctionInfo info)
{
string result = GenerateMetaType(info.returnType);
result ~= ", ";
result ~= GenerateMetaTypesListForSignal(info);
return result;
}
string GenerateMetaTypesListForSignal(FunctionInfo info)
{
string result = "";
for (int i = 0; i < info.parameterTypes.length; ++i)
{
if (i > 0)
result ~= ", ";
result ~= GenerateMetaType(info.parameterTypes[i]);
}
return result;
}
string GenerateQObjectInit(QtInfo info)
{
string result = "";
result ~= "protected override void qobjectInit()\n";
result ~= "{\n writeln(\"OK\");\n";
foreach (slot; info.slots)
{
auto metaTypes = GenerateMetaTypesListForSlot(slot);
result ~= format("registerSlot(\"%s\", [%s]);\n", slot.name, metaTypes);
}
foreach (signal; info.signals)
{
auto metaTypes = GenerateMetaTypesListForSignal(signal);
result ~= format("registerSignal(\"%s\", [%s]);\n", signal.name, metaTypes);
}
foreach (property; info.properties)
{
result ~= format("registerProperty(\"%s\", %s, \"%s\", \"%s\", \"%s\");\n", property.name, GenerateMetaType(property.type), property.read, property.write, property.notify);
}
result ~= "super.qobjectInit();\n";
result ~= "}";
return result;
}
struct FunctionInfo
{
string name;
string returnType;
string[] parameterTypes;
}
struct QtInfo
{
FunctionInfo[] slots;
FunctionInfo[] signals;
QtProperty[] properties;
}
mixin template InjectQObjectMacro()
{
private static QtInfo GetQtUDA(T)()
{
QtInfo result;
foreach (attribute; __traits(getAttributes, T)) {
static if (is (typeof(attribute) == QtProperty)) {
result.properties ~= attribute;
}
}
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;
bool isSlot = attributeNames.canFind("QtSlot");
bool isSignal = attributeNames.canFind("QtSignal");
// Extract the Function Return Type and Arguments
if (isSlot || isSignal)
{
FunctionInfo info;
info.name = member;
info.returnType = ReturnType!(__traits(getMember, T, member)).stringof;
foreach (param; ParameterTypeTuple!(__traits(getMember, T, member)))
info.parameterTypes ~= param.stringof;
if (isSlot)
result.slots ~= info;
if (isSignal)
result.signals ~= info;
}
}
}
return result;
}
private static string Q_OBJECT(T)()
{
string result = "";
auto info = T.GetQtUDA!(T);
result ~= GenerateOnSlotCalled(info) ~ "\n";
result ~= GenerateQObjectInit(info) ~ "\n";
result ~= GenerateQtSignals(info) ~ "\n";
return result;
}
}

View File

@ -1,258 +1,17 @@
import dqml;
import std.traits;
import std.algorithm;
import std.string;
import std.stdio;
struct QtProperty
{
public string type;
public string name;
public string read;
public string write;
public string notify;
this(string type, string name, string read, string write, string notify)
{
this.type = type;
this.name = name;
this.read = read;
this.write = write;
this.notify = notify;
}
}
struct QtSlot {};
struct QtSignal {};
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(FunctionInfo 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(FunctionInfo info)
{
string result = "";
result ~= format("case \"%s\":\n", info.name);
result ~= format("%s;\n", GenerateSlotCall(info));
result ~= "break;\n";
return result;
}
string GenerateOnSlotCalled(QtInfo info)
{
string result = "protected override void onSlotCalled(QVariant slotName, QVariant[] arguments)\n";
result ~= "{\n";
result ~= "switch(slotName.toString())\n";
result ~= "{\n";
foreach (slot; info.slots)
result ~= GenerateCaseBlock(slot);
result ~= "default: super.onSlotCalled(slotName, arguments);\n";
result ~= "}\n"; //
result ~= "}";
return result;
}
string GenerateSignalCall(FunctionInfo info)
{
string args = "";
string vars = "";
for (int i = 0; i < info.parameterTypes.length; ++i) {
if (i > 0) {
args ~= ",";
vars ~= ",";
}
args ~= format("%s val%d", info.parameterTypes[i], i);
vars ~= format("val%d", i);
}
auto result = format("%s %s(%s) { emit(\"%s\", %s); }", info.returnType, info.name, args, info.name, vars);
return result;
}
string GenerateQtSignals(QtInfo info)
{
string result = "";
foreach (signal; info.signals)
result ~= GenerateSignalCall(signal) ~ "\n";
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 GenerateMetaTypesListForSlot(FunctionInfo info)
{
string result = GenerateMetaType(info.returnType);
result ~= ", ";
result ~= GenerateMetaTypesListForSignal(info);
return result;
}
string GenerateMetaTypesListForSignal(FunctionInfo info)
{
string result = "";
for (int i = 0; i < info.parameterTypes.length; ++i)
{
if (i > 0)
result ~= ", ";
result ~= GenerateMetaType(info.parameterTypes[i]);
}
return result;
}
string GenerateQObjectInit(QtInfo info)
{
string result = "";
result ~= "protected override void qobjectInit()\n";
result ~= "{\n";
foreach (slot; info.slots)
{
auto metaTypes = GenerateMetaTypesListForSlot(slot);
result ~= format("registerSlot(\"%s\", [%s]);\n", slot.name, metaTypes);
}
foreach (signal; info.signals)
{
auto metaTypes = GenerateMetaTypesListForSignal(signal);
result ~= format("registerSignal(\"%s\", [%s]);\n", signal.name, metaTypes);
}
foreach (property; info.properties)
{
result ~= format("registerProperty(\"%s\", %s, \"%s\", \"%s\", \"%s\");\n", property.name, GenerateMetaType(property.type), property.read, property.write, property.notify);
}
result ~= "super.qobjectInit();\n";
result ~= "}";
return result;
}
string Q_OBJECT(T)()
{
string result = "";
auto info = IterateUDA!(T);
result ~= GenerateOnSlotCalled(info) ~ "\n";
result ~= GenerateQObjectInit(info) ~ "\n";
result ~= GenerateQtSignals(info) ~ "\n";
return result;
}
struct FunctionInfo
{
string name;
string returnType;
string[] parameterTypes;
}
struct QtInfo
{
FunctionInfo[] slots;
FunctionInfo[] signals;
QtProperty[] properties;
}
QtInfo IterateUDA(T)()
{
QtInfo result;
foreach (attribute; __traits(getAttributes, T)) {
static if (is (typeof(attribute) == QtProperty)) {
result.properties ~= attribute;
}
}
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;
bool isSlot = attributeNames.canFind("QtSlot");
bool isSignal = attributeNames.canFind("QtSignal");
// Extract the Function Return Type and Arguments
if (isSlot || isSignal)
{
FunctionInfo info;
info.name = member;
info.returnType = ReturnType!(__traits(getMember, T, member)).stringof;
foreach (param; ParameterTypeTuple!(__traits(getMember, T, member)))
info.parameterTypes ~= param.stringof;
if (isSlot)
result.slots ~= info;
if (isSignal)
result.signals ~= info;
}
}
}
return result;
}
@QtProperty(string.stringof, "name", "getName", "setName", "nameChanged")
@QtProperty(string.stringof, "surname", "getSurname", "setSurname", "surnameChanged")
class Contact : QObject
{
mixin InjectQObjectMacro;
mixin(Q_OBJECT!(Contact));
this()
{}
~this() {}
~this()
{}
@QtSlot()
public string getName()