From bcd477e0bc48bb028193d7707d1ecfbd61b5bdc1 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 24 Apr 2012 15:01:47 +0200 Subject: [PATCH] Introduce QObject::isSignalConnected(QMetaMethod) This is much more performant than calling QObject::receivers(const char*) Can be used instead of connectNotify in some cases. Change-Id: I19e0933f678f171f515d9a0f69f0ad4fb7d894b4 Reviewed-by: Kent Hansen --- .../code/src_corelib_kernel_qobject.cpp | 8 +++ src/corelib/kernel/qobject.cpp | 59 ++++++++++++++++++- src/corelib/kernel/qobject.h | 1 + .../corelib/kernel/qobject/tst_qobject.cpp | 31 ++++++++++ 4 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp index 2367bfd724e..95c54169ce0 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp @@ -479,6 +479,14 @@ QObject::disconnect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText); //! [48] +//! [49] +if (isSignalConnected(QMethaMethod::fromSignal(&MyObject::valueChanged))) { + QByteArray data; + data = get_the_value(); // expensive operation + emit valueChanged(data); +} +//! [49] + //! [meta data] //: This is a comment for the translator. //= qtn_foo_bar diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index e0dc5bcd9dc..49a9beb298c 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -2157,13 +2157,12 @@ int QObject::senderSignalIndex() const \snippet code/src_corelib_kernel_qobject.cpp 21 - As the code snippet above illustrates, you can use this function - to avoid emitting a signal that nobody listens to. - \warning This function violates the object-oriented principle of modularity. However, it might be useful when you need to perform expensive initialization only if something is connected to a signal. + + \sa isSignalConnected() */ int QObject::receivers(const char *signal) const @@ -2209,6 +2208,60 @@ int QObject::receivers(const char *signal) const return receivers; } +/*! + \since 5.0 + Returns true if the \a signal is connected to at least one receiver, + otherwise returns false. + + \a signal must be a signal member of this object, otherwise the behaviour + is undefined. + + \snippet code/src_corelib_kernel_qobject.cpp 21 + + As the code snippet above illustrates, you can use this function + to avoid emitting a signal that nobody listens to. + + \warning This function violates the object-oriented principle of + modularity. However, it might be useful when you need to perform + expensive initialization only if something is connected to a + signal. +*/ +bool QObject::isSignalConnected(const QMetaMethod &signal) const +{ + Q_D(const QObject); + if (!signal.mobj) + return false; + + Q_ASSERT_X(signal.mobj->cast(this) && signal.methodType() == QMetaMethod::Signal, + "QObject::isSignalConnected" , "the parametter must be a signal member of the object"); + uint signalIndex = (signal.handle - QMetaObjectPrivate::get(signal.mobj)->methodData)/5; + + if (signal.mobj->d.data[signal.handle + 4] & MethodCloned) + signalIndex = QMetaObjectPrivate::originalClone(signal.mobj, signalIndex); + + int signalOffset; + int methodOffset; + computeOffsets(signal.mobj, &signalOffset, &methodOffset); + signalIndex += signalOffset; + + if (signalIndex < sizeof(d->connectedSignals) * 8) + return d->isSignalConnected(signalIndex); + + QMutexLocker locker(signalSlotLock(this)); + if (d->connectionLists) { + if (signalIndex < uint(d->connectionLists->count())) { + const QObjectPrivate::Connection *c = + d->connectionLists->at(signalIndex).first; + while (c) { + if (c->receiver) + return true; + c = c->nextConnectionList; + } + } + } + return false; +} + /*! \internal diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index d840d9184fb..5e969d67f6a 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -365,6 +365,7 @@ protected: QObject *sender() const; int senderSignalIndex() const; int receivers(const char* signal) const; + bool isSignalConnected(const QMetaMethod &signal) const; virtual void timerEvent(QTimerEvent *); virtual void childEvent(QChildEvent *); diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 54704bf5d95..e5da03c890e 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -3774,6 +3774,7 @@ public: void tst_QObject::isSignalConnected() { ManySignals o; + const QMetaObject *meta = o.metaObject(); o.rec = 0; #ifdef QT_BUILD_INTERNAL QObjectPrivate *priv = QObjectPrivate::get(&o); @@ -3784,6 +3785,13 @@ void tst_QObject::isSignalConnected() QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig29()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig60()"))); #endif + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig60()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); QObject::connect(&o, SIGNAL(sig00()), &o, SIGNAL(sig69())); QObject::connect(&o, SIGNAL(sig34()), &o, SIGNAL(sig03())); @@ -3802,6 +3810,18 @@ void tst_QObject::isSignalConnected() QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig18()"))); #endif + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig05()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig15()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig29()")))); + + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig00()")))); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig03()")))); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig34()")))); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()")))); + QObject::connect(&o, SIGNAL(sig18()), &o, SIGNAL(sig29())); QObject::connect(&o, SIGNAL(sig29()), &o, SIGNAL(sig62())); @@ -3815,6 +3835,11 @@ void tst_QObject::isSignalConnected() QVERIFY(priv->isSignalConnected(priv->signalIndex("sig69()"))); QVERIFY(!priv->isSignalConnected(priv->signalIndex("sig27()"))); #endif + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig18()")))); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig62()")))); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig28()")))); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("sig69()")))); + QVERIFY(!o.isSignalConnected(meta->method(meta->indexOfSignal("sig27()")))); QCOMPARE(o.rec, 0); emit o.sig01(); @@ -3845,6 +3870,12 @@ void tst_QObject::isSignalConnected() QCOMPARE(o.rec, 2); emit o.sig36(); QCOMPARE(o.rec, 2); + + QObject::connect(&o, &QObject::destroyed, qt_noop); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed()")))); + QVERIFY(o.isSignalConnected(meta->method(meta->indexOfSignal("destroyed(QObject*)")))); + + QVERIFY(!o.isSignalConnected(QMetaMethod())); } void tst_QObject::qMetaObjectConnect()