Android: Support multi-arg signal generation in androiddeployqt
This commit introduces support for generating Java code for multi-argument QML signals. Pre-existing code remains unchanged, and the new code is only executed when the number of params in a signal is above 1. Multi-arg signals are handled with a new generated interface type, named after the signal, which has a default method that takes an Object[] array and calls the user-implemented signal method with the arguments cast to the desired types. For example, a QML signal with the following signature: signal manyTypeArgSignal(intValue: int, boolValue: bool, doubleValue: double, stringValue: string) Is generated into this Java code: @FunctionalInterface public interface manyTypeArgSignalListener { default void onSignalEmitted(Object[] args) { onSignalEmitted((Integer) args[0], (Boolean) args[1], (Double) args[2], (String) args[3]); } void onManyTypeArgSignal(Integer intValue, Boolean boolValue, Double doubleValue, String stringValue); } public int connectManyTypeArgSignalListener(manyTypeArgSignalListener signalListener) { return connectSignalListener("manyTypeArgSignal", new Class[]{ Integer.class, Boolean.class, Double.class, String.class }, signalListener); } Task-number: QTBUG-124489 Change-Id: I94e3e88e807017bcbeba16cf0e34263e28e5885f Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
parent
8d5db24c14
commit
2c6be851ae
@ -3773,25 +3773,84 @@ int generateJavaQmlComponents(const Options &options)
|
|||||||
if (methodData["methodType"_L1] != 0)
|
if (methodData["methodType"_L1] != 0)
|
||||||
return;
|
return;
|
||||||
const QJsonArray parameters = methodData["parameters"_L1].toArray();
|
const QJsonArray parameters = methodData["parameters"_L1].toArray();
|
||||||
if (parameters.size() > 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QString methodName = methodData["name"_L1].toString();
|
const QString methodName = methodData["name"_L1].toString();
|
||||||
if (methodName.isEmpty())
|
if (methodName.isEmpty())
|
||||||
return;
|
return;
|
||||||
const QString upperMethodName = firstCharToUpper(methodName);
|
|
||||||
const QString typeName = !parameters.isEmpty()
|
|
||||||
? parameters[0].toObject()["typeName"_L1].toString()
|
|
||||||
: "void"_L1;
|
|
||||||
|
|
||||||
const QString javaTypeName = qmlToJavaType.value(typeName, "Object"_L1);
|
const QString upperMethodName = firstCharToUpper(methodName);
|
||||||
stream << indent
|
if (parameters.size() <= 1) { // Generate a QtSignalListener<T> API for this property/signal
|
||||||
<< "public int connect%1Listener(QtSignalListener<%2> signalListener) {\n"_L1.arg(
|
const QString typeName = !parameters.isEmpty()
|
||||||
upperMethodName, javaTypeName)
|
? parameters[0].toObject()["typeName"_L1].toString()
|
||||||
<< indent
|
: "void"_L1;
|
||||||
<< " return connectSignalListener(\"%1\", %2.class, signalListener);\n"_L1.arg(
|
const QString javaTypeName = qmlToJavaType.value(typeName, "Object"_L1);
|
||||||
methodName, javaTypeName)
|
stream << indent
|
||||||
<< indent << "}\n";
|
<< "public int connect%1Listener(QtSignalListener<%2> signalListener) {\n"_L1
|
||||||
|
.arg(upperMethodName, javaTypeName)
|
||||||
|
<< indent
|
||||||
|
<< " return connectSignalListener(\"%1\", %2.class, signalListener);\n"_L1
|
||||||
|
.arg(methodName, javaTypeName)
|
||||||
|
<< indent << "}\n";
|
||||||
|
} else { // Multi-arg signal; Generate a custom listener interface for this signal
|
||||||
|
// Returns a comma-separated parameter list of java types deduced from the QML DOM array
|
||||||
|
const auto getJavaArgsString = [¶meters]() -> QString {
|
||||||
|
QList<QString> javaArgsList;
|
||||||
|
for (const auto param : parameters) {
|
||||||
|
const auto typeName = param["typeName"_L1].toString();
|
||||||
|
const auto javaTypeName = qmlToJavaType.value(typeName, "Object"_L1);
|
||||||
|
const auto qmlParamName = param["name"_L1].toString();
|
||||||
|
|
||||||
|
javaArgsList.emplace_back(
|
||||||
|
QStringLiteral("%1%2").arg(javaTypeName, " %1"_L1.arg(qmlParamName)));
|
||||||
|
}
|
||||||
|
return javaArgsList.join(", "_L1);
|
||||||
|
};
|
||||||
|
// Returns a comma-separated parameter list of java classes deduced from QML DOM array
|
||||||
|
const auto getJavaClassesString = [¶meters]() -> QString {
|
||||||
|
QList<QString> javaArgsList;
|
||||||
|
for (const auto param : parameters) {
|
||||||
|
const auto typeName = param["typeName"_L1].toString();
|
||||||
|
const auto javaTypeName = qmlToJavaType.value(typeName, "Object"_L1);
|
||||||
|
|
||||||
|
javaArgsList.emplace_back(
|
||||||
|
QStringLiteral("%1%2").arg(javaTypeName, ".class"_L1));
|
||||||
|
}
|
||||||
|
return javaArgsList.join(", "_L1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto javaParamsString = getJavaArgsString();
|
||||||
|
const auto javaParamsClassesString = getJavaClassesString();
|
||||||
|
|
||||||
|
// e.g. "{(String) args[0], (Integer) args[1], (Boolean) args[2]}"
|
||||||
|
QList<QString> objectToTypeConversion;
|
||||||
|
for (auto i = 0; i < parameters.size(); ++i) {
|
||||||
|
const auto typeName = parameters.at(i).toObject().value("typeName"_L1).toString();
|
||||||
|
objectToTypeConversion.emplace_back("(%1) args[%2]"_L1.arg(
|
||||||
|
qmlToJavaType.value(typeName, "Object"_L1), QString::number(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new interface type for this signal
|
||||||
|
const auto signalInterfaceName = "%1Listener"_L1.arg(methodName);
|
||||||
|
const auto objectToTypeConversionString = objectToTypeConversion.join(", "_L1);
|
||||||
|
stream << indent << "@FunctionalInterface\n"
|
||||||
|
<< indent << "public interface %1 {\n"_L1.arg(signalInterfaceName) << indent
|
||||||
|
<< " default void onSignalEmitted(Object[] args) {\n"
|
||||||
|
<< indent
|
||||||
|
<< " on%1(%2);\n"_L1.arg(upperMethodName, objectToTypeConversionString)
|
||||||
|
<< indent << " }\n"
|
||||||
|
<< indent
|
||||||
|
<< " void on%1(%2);\n"_L1.arg(upperMethodName, javaParamsString);
|
||||||
|
stream << indent << "}\n"_L1;
|
||||||
|
|
||||||
|
// Generate the connection function with this new interface type
|
||||||
|
stream << indent
|
||||||
|
<< "public int connect%1(%2 signalListener) {\n"_L1.arg(
|
||||||
|
firstCharToUpper(signalInterfaceName), signalInterfaceName)
|
||||||
|
<< indent
|
||||||
|
<< " return connectSignalListener(\"%1\", new Class[]{ %2 }, signalListener);\n"_L1
|
||||||
|
.arg(methodName, javaParamsClassesString)
|
||||||
|
<< indent << "}\n\n";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr static auto markerFileName = "qml_java_contents"_L1;
|
constexpr static auto markerFileName = "qml_java_contents"_L1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user