Add QMetaMethod::fromSignal() function

Given a member function that's a signal, returns the corresponding
QMetaMethod. Inspired by the implementation of the template-based
QObject::connect().

The primary use case for this function is to have an effective and
exact (not subject to shadowing) way of checking whether a known
signal was connected to in reimplementations of
QObject::connectNotify(QMetaMethod), avoiding string comparisons.
Example:

void MyObject::connectNotify(const QMetaMethod &signal)
{
    if (signal == QMetaMethod::fromSignal(&MyObject::mySignal)) {
        // Someone connected to mySignal ...
    }
}

Change-Id: I5e4de434275fe543c004d569dcaa9ceda3442f03
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
Kent Hansen 2012-04-22 22:44:58 +02:00 committed by Qt by Nokia
parent 56d4d97852
commit dac23b9a57
4 changed files with 81 additions and 0 deletions

View File

@ -133,4 +133,8 @@ method.invoke(obj,
Q_ARG(double, 9.7));
//! [8]
//! [9]
QMetaMethod destroyedSignal = QMetaMethod::fromSignal(&QObject::destroyed);
//! [9]
}

View File

@ -1856,6 +1856,41 @@ QMetaMethod::MethodType QMetaMethod::methodType() const
return (QMetaMethod::MethodType)((mobj->d.data[handle + 4] & MethodTypeMask)>>2);
}
/*!
\fn QMetaMethod QMetaMethod::fromSignal(PointerToMemberFunction signal)
\since 5.0
Returns the meta-method that corresponds to the given \a signal, or an
invalid QMetaMethod if \a signal is not a signal of the class.
Example:
\snippet code/src_corelib_kernel_qmetaobject.cpp 9
*/
/*! \internal
Implementation of the fromSignal() function.
\a metaObject is the class's meta-object
\a signal is a pointer to a pointer to a member signal of the class
*/
QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal)
{
int i = -1;
void *args[] = { &i, signal };
QMetaMethod result;
for (const QMetaObject *m = metaObject; m; m = m->d.superdata) {
m->static_metacall(QMetaObject::IndexOfMethod, 0, args);
if (i >= 0) {
result.mobj = m;
result.handle = priv(m->d.data)->methodData + 5*i;
break;
}
}
return result;
}
/*!
Invokes this method on the object \a object. Returns true if the member could be invoked.
Returns false if there is no such member or the parameters did not match.

View File

@ -141,6 +141,20 @@ public:
inline bool isValid() const { return mobj != 0; }
#ifdef Q_QDOC
static QMetaMethod fromSignal(PointerToMemberFunction signal);
#else
template <typename Func>
static inline QMetaMethod fromSignal(Func signal)
{
typedef QtPrivate::FunctionPointer<Func> SignalType;
reinterpret_cast<typename SignalType::Object *>(0)->qt_check_for_QOBJECT_macro(
*reinterpret_cast<typename SignalType::Object *>(0));
return fromSignalImpl(&SignalType::Object::staticMetaObject,
reinterpret_cast<void **>(&signal));
}
#endif
private:
#if QT_DEPRECATED_SINCE(5,0)
// signature() has been renamed to methodSignature() in Qt 5.
@ -148,6 +162,7 @@ private:
// you convert to char*.
char *signature(struct renamedInQt5_warning_checkTheLifeTime * = 0) Q_DECL_EQ_DELETE;
#endif
static QMetaMethod fromSignalImpl(const QMetaObject *, void **);
const QMetaObject *mobj;
uint handle;

View File

@ -56,6 +56,8 @@ private slots:
void invalidMethod();
void comparisonOperators();
void fromSignal();
};
struct CustomType { };
@ -709,5 +711,30 @@ void tst_QMetaMethod::comparisonOperators()
}
}
void tst_QMetaMethod::fromSignal()
{
#define FROMSIGNAL_HELPER(ObjectType, Name, Arguments) { \
void (ObjectType::*signal)Arguments = &ObjectType::Name; \
const QMetaObject *signalMeta = &ObjectType::staticMetaObject; \
QCOMPARE(QMetaMethod::fromSignal(signal), \
signalMeta->method(signalMeta->indexOfSignal(QMetaObject::normalizedSignature(#Name #Arguments)))); \
}
FROMSIGNAL_HELPER(MethodTestObject, voidSignal, ())
FROMSIGNAL_HELPER(MethodTestObject, voidSignalQString, (const QString&))
FROMSIGNAL_HELPER(QObject, destroyed, (QObject*))
FROMSIGNAL_HELPER(QObject, objectNameChanged, (const QString &))
// Inherited from QObject
FROMSIGNAL_HELPER(MethodTestObject, destroyed, (QObject*))
FROMSIGNAL_HELPER(MethodTestObject, objectNameChanged, (const QString &))
// Methods that are not signals; fromSignal should return invalid method
FROMSIGNAL_HELPER(MethodTestObject, voidSlot, ())
FROMSIGNAL_HELPER(QObject, deleteLater, ())
#undef FROMSIGNAL_HELPER
}
QTEST_MAIN(tst_QMetaMethod)
#include "tst_qmetamethod.moc"