Make Q_INVOKABLE work on Q_GADGET

Methods can be invoked with QMetaMethod::invokeOnGadget

Change-Id: Id734868bb530b02587daf0f62bce01798ade2ac2
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
bb10
Olivier Goffart 2014-08-16 11:38:30 +02:00
parent d9e8571f4d
commit 8c77a7f77a
3 changed files with 183 additions and 0 deletions

View File

@ -2298,6 +2298,112 @@ bool QMetaMethod::invoke(QObject *object,
connection type Qt::AutoConnection and ignores return values.
*/
/*!
\since 5.5
Invokes this method on a Q_GADGET. Returns \c true if the member could be invoked.
Returns \c false if there is no such member or the parameters did not match.
The pointer \a gadget must point to an instance of the gadget class.
The invocation is always synchronous.
The return value of this method call is placed in \a
returnValue. You can pass up to ten arguments (\a val0, \a val1,
\a val2, \a val3, \a val4, \a val5, \a val6, \a val7, \a val8,
and \a val9) to this method call.
\warning this method will not test the validity of the arguments: \a gadget
must be an instance of the class of the QMetaObject of which this QMetaMethod
has been constructed with. The arguments must have the same type as the ones
expected by the method, else, the behavior is undefined.
\sa Q_ARG(), Q_RETURN_ARG(), qRegisterMetaType(), QMetaObject::invokeMethod()
*/
bool QMetaMethod::invokeOnGadget(void* gadget, QGenericReturnArgument returnValue, QGenericArgument val0, QGenericArgument val1, QGenericArgument val2, QGenericArgument val3, QGenericArgument val4, QGenericArgument val5, QGenericArgument val6, QGenericArgument val7, QGenericArgument val8, QGenericArgument val9) const
{
if (!gadget || !mobj)
return false;
// check return type
if (returnValue.data()) {
const char *retType = typeName();
if (qstrcmp(returnValue.name(), retType) != 0) {
// normalize the return value as well
QByteArray normalized = QMetaObject::normalizedType(returnValue.name());
if (qstrcmp(normalized.constData(), retType) != 0) {
// String comparison failed, try compare the metatype.
int t = returnType();
if (t == QMetaType::UnknownType || t != QMetaType::type(normalized))
return false;
}
}
}
// check argument count (we don't allow invoking a method if given too few arguments)
const char *typeNames[] = {
returnValue.name(),
val0.name(),
val1.name(),
val2.name(),
val3.name(),
val4.name(),
val5.name(),
val6.name(),
val7.name(),
val8.name(),
val9.name()
};
int paramCount;
for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
if (qstrlen(typeNames[paramCount]) <= 0)
break;
}
if (paramCount <= QMetaMethodPrivate::get(this)->parameterCount())
return false;
// invoke!
void *param[] = {
returnValue.data(),
val0.data(),
val1.data(),
val2.data(),
val3.data(),
val4.data(),
val5.data(),
val6.data(),
val7.data(),
val8.data(),
val9.data()
};
int idx_relative = QMetaMethodPrivate::get(this)->ownMethodIndex();
Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6);
QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;
if (!callFunction)
return false;
callFunction(reinterpret_cast<QObject*>(gadget), QMetaObject::InvokeMetaMethod, idx_relative, param);
return true;
}
/*!
\fn bool QMetaMethod::invokeOnGadget(void *gadget,
QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const
\overload
\since 5.5
This overload invokes this method for a \a gadget and ignores return values.
*/
/*!
\class QMetaEnum
\inmodule QtCore

View File

@ -132,6 +132,34 @@ public:
val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
bool invokeOnGadget(void *gadget,
QGenericReturnArgument returnValue,
QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const;
inline bool invokeOnGadget(void *gadget,
QGenericArgument val0 = QGenericArgument(0),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const
{
return invokeOnGadget(gadget, QGenericReturnArgument(),
val0, val1, val2, val3, val4, val5, val6, val7, val8, val9);
}
inline bool isValid() const { return mobj != 0; }
#ifdef Q_QDOC

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
@ -50,6 +51,8 @@ private slots:
void comparisonOperators();
void fromSignal();
void gadget();
};
struct CustomType { };
@ -727,5 +730,51 @@ void tst_QMetaMethod::fromSignal()
#undef FROMSIGNAL_HELPER
}
class MyGadget {
Q_GADGET
public:
QString m_value;
Q_INVOKABLE void setValue(const QString &value) { m_value = value; }
Q_INVOKABLE QString getValue() { return m_value; }
};
void tst_QMetaMethod::gadget()
{
int idx;
idx = MyGadget::staticMetaObject.indexOfMethod("setValue(QString)");
QVERIFY(idx >= 0);
QMetaMethod setValueMethod = MyGadget::staticMetaObject.method(idx);
QVERIFY(setValueMethod.isValid());
idx = MyGadget::staticMetaObject.indexOfMethod("getValue()");
QVERIFY(idx >= 0);
QMetaMethod getValueMethod = MyGadget::staticMetaObject.method(idx);
QVERIFY(getValueMethod.isValid());
{
MyGadget gadget;
QString string;
QVERIFY(getValueMethod.invokeOnGadget(&gadget, Q_RETURN_ARG(QString, string)));
QCOMPARE(string, gadget.m_value);
QVERIFY(setValueMethod.invokeOnGadget(&gadget, Q_ARG(QString, QLatin1String("hello"))));
QCOMPARE(gadget.m_value, QLatin1String("hello"));
QVERIFY(getValueMethod.invokeOnGadget(&gadget, Q_RETURN_ARG(QString, string)));
QCOMPARE(string, gadget.m_value);
}
{
// Call with null should not crash
MyGadget *gadget = Q_NULLPTR;
QString string;
QVERIFY(!setValueMethod.invokeOnGadget(gadget, Q_ARG(QString, QLatin1String("hi"))));
QVERIFY(!getValueMethod.invokeOnGadget(gadget, Q_RETURN_ARG(QString, string)));
}
}
QTEST_MAIN(tst_QMetaMethod)
#include "tst_qmetamethod.moc"