public
Created

Calling QMetaMethods with QVariant arguments and best-effort type conversion

  • Download Gist
main.cpp
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
#include <QtCore>
#include <QtDebug>
 
QVariant call(QObject* object, QMetaMethod metaMethod, QVariantList args)
{
// Convert the arguments
 
QVariantList converted;
 
// We need enough arguments to perform the conversion.
 
QList<QByteArray> methodTypes = metaMethod.parameterTypes();
if (methodTypes.size() < args.size()) {
qWarning() << "Insufficient arguments to call" << metaMethod.signature();
return QVariant();
}
 
for (int i = 0; i < methodTypes.size(); i++) {
const QVariant& arg = args.at(i);
QByteArray methodTypeName = methodTypes.at(i);
QByteArray argTypeName = arg.typeName();
 
QVariant::Type methodType = QVariant::nameToType(methodTypeName);
QVariant::Type argType = arg.type();
 
QVariant copy = QVariant(arg);
 
// If the types are not the same, attempt a conversion. If it
// fails, we cannot proceed.
 
if (copy.type() != methodType) {
if (copy.canConvert(methodType)) {
if (!copy.convert(methodType)) {
qWarning() << "Cannot convert" << argTypeName
<< "to" << methodTypeName;
return QVariant();
}
}
}
 
converted << copy;
}
 
QList<QGenericArgument> arguments;
 
for (int i = 0; i < converted.size(); i++) {
 
// Notice that we have to take a reference to the argument, else
// we'd be pointing to a copy that will be destroyed when this
// loop exits.
 
QVariant& argument = converted[i];
 
// A const_cast is needed because calling data() would detach
// the QVariant.
 
QGenericArgument genericArgument(
QMetaType::typeName(argument.userType()),
const_cast<void*>(argument.constData())
);
 
arguments << genericArgument;
}
 
QVariant returnValue(QMetaType::type(metaMethod.typeName()),
static_cast<void*>(NULL));
 
QGenericReturnArgument returnArgument(
metaMethod.typeName(),
const_cast<void*>(returnValue.constData())
);
 
// Perform the call
 
bool ok = metaMethod.invoke(
object,
Qt::DirectConnection,
returnArgument,
arguments.value(0),
arguments.value(1),
arguments.value(2),
arguments.value(3),
arguments.value(4),
arguments.value(5),
arguments.value(6),
arguments.value(7),
arguments.value(8),
arguments.value(9)
);
 
if (!ok) {
qWarning() << "Calling" << metaMethod.signature() << "failed.";
return QVariant();
} else {
return returnValue;
}
}
 
class Target : public QObject
{
Q_OBJECT;
 
public:
 
explicit Target(QObject* parent = 0) : QObject(parent) {
}
 
Q_INVOKABLE virtual void foo(qulonglong val) {
qDebug() << "Value:" << val;
}
};
 
int main(int argc, char** argv) {
QCoreApplication a(argc, argv);
 
Target* t = new Target();
 
int index = t->metaObject()->indexOfMethod("foo(qulonglong)");
QMetaMethod metaMethod = t->metaObject()->method(index);
 
QVariantList list;
list << QVariant("10");
 
call(t, metaMethod, list);
 
a.exec();
}
 
#include <main.moc>
project.pro
IDL
1 2 3 4 5
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
SOURCES += main.cpp

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.