Introduce QObject::isSignalConnected(QMetaMethod)
authorOlivier Goffart <ogoffart@woboq.com>
Tue, 24 Apr 2012 13:01:47 +0000 (15:01 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 2 May 2012 08:59:41 +0000 (10:59 +0200)
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 <kent.hansen@nokia.com>
src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
src/corelib/kernel/qobject.cpp
src/corelib/kernel/qobject.h
tests/auto/corelib/kernel/qobject/tst_qobject.cpp

index 2367bfd..95c5416 100644 (file)
@@ -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
index e0dc5bc..49a9beb 100644 (file)
@@ -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
@@ -2210,6 +2209,60 @@ int QObject::receivers(const char *signal) const
 }
 
 /*!
+    \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
 
     This helper function calculates signal and method index for the given
index d840d91..5e969d6 100644 (file)
@@ -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 *);
index 54704bf..e5da03c 100644 (file)
@@ -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()