From 5f92bc9dd9f05f4824711b03406bdbe222ff73e9 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 Jan 2010 16:28:49 +1000 Subject: QMetaObject::disconnectOne() Adds a disconnectOne() method that allows a single signal/slot connection to be disconnected, as required by QTBUG-6781. Reviewed-by: Warwick Allison Reviewed-by: Olivier Goffart --- src/corelib/kernel/qmetaobject_p.h | 6 ++-- src/corelib/kernel/qobject.cpp | 28 ++++++++++++--- src/corelib/kernel/qobjectdefs.h | 2 ++ tests/auto/qobject/tst_qobject.cpp | 73 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 7 deletions(-) diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index 79a7304..3bbb050 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -124,14 +124,16 @@ struct QMetaObjectPrivate #ifndef QT_NO_QOBJECT //defined in qobject.cpp + enum DisconnectType { DisconnectAll, DisconnectOne }; static bool connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type = 0, int *types = 0); static bool disconnect(const QObject *sender, int signal_index, - const QObject *receiver, int method_index); + const QObject *receiver, int method_index, + DisconnectType = DisconnectAll); static inline bool disconnectHelper(QObjectPrivate::Connection *c, const QObject *receiver, int method_index, - QMutex *senderMutex); + QMutex *senderMutex, DisconnectType); #endif }; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 8346fe4..5298fff 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -2945,7 +2945,6 @@ bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index, return true; } - /*!\internal */ bool QMetaObject::disconnect(const QObject *sender, int signal_index, @@ -2956,12 +2955,27 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, receiver, method_index); } +/*!\internal + +Disconnect a single signal connection. If QMetaObject::connect() has been called +multiple times for the same sender, signal_index, receiver and method_index only +one of these connections will be removed. + */ +bool QMetaObject::disconnectOne(const QObject *sender, int signal_index, + const QObject *receiver, int method_index) +{ + signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index); + return QMetaObjectPrivate::disconnect(sender, signal_index, + receiver, method_index, + QMetaObjectPrivate::DisconnectOne); +} + /*! \internal Helper function to remove the connection from the senders list and setting the receivers to 0 */ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, const QObject *receiver, int method_index, - QMutex *senderMutex) + QMutex *senderMutex, DisconnectType disconnectType) { bool success = false; while (c) { @@ -2987,6 +3001,9 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, c->receiver = 0; success = true; + + if (disconnectType == DisconnectOne) + return success; } c = c->nextConnectionList; } @@ -2997,7 +3014,8 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, Same as the QMetaObject::disconnect, but \a signal_index must be the result of QObjectPrivate::signalIndex */ bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, - const QObject *receiver, int method_index) + const QObject *receiver, int method_index, + DisconnectType disconnectType) { if (!sender) return false; @@ -3021,7 +3039,7 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, for (signal_index = -1; signal_index < connectionLists->count(); ++signal_index) { QObjectPrivate::Connection *c = (*connectionLists)[signal_index].first; - if (disconnectHelper(c, receiver, method_index, senderMutex)) { + if (disconnectHelper(c, receiver, method_index, senderMutex, disconnectType)) { success = true; connectionLists->dirty = true; } @@ -3029,7 +3047,7 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index, } else if (signal_index < connectionLists->count()) { QObjectPrivate::Connection *c = (*connectionLists)[signal_index].first; - if (disconnectHelper(c, receiver, method_index, senderMutex)) { + if (disconnectHelper(c, receiver, method_index, senderMutex, disconnectType)) { success = true; connectionLists->dirty = true; } diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h index a0d9cf3..8ed7f3f 100644 --- a/src/corelib/kernel/qobjectdefs.h +++ b/src/corelib/kernel/qobjectdefs.h @@ -334,6 +334,8 @@ struct Q_CORE_EXPORT QMetaObject // internal index-based disconnect static bool disconnect(const QObject *sender, int signal_index, const QObject *receiver, int method_index); + static bool disconnectOne(const QObject *sender, int signal_index, + const QObject *receiver, int method_index); // internal slot-name based connect static void connectSlotsByName(QObject *o); diff --git a/tests/auto/qobject/tst_qobject.cpp b/tests/auto/qobject/tst_qobject.cpp index d342581..4fa6aaa 100644 --- a/tests/auto/qobject/tst_qobject.cpp +++ b/tests/auto/qobject/tst_qobject.cpp @@ -127,6 +127,7 @@ private slots: void overloads(); void isSignalConnected(); void qMetaObjectConnect(); + void qMetaObjectDisconnectOne(); protected: }; @@ -3269,5 +3270,77 @@ void tst_QObject::qMetaObjectConnect() } +void tst_QObject::qMetaObjectDisconnectOne() +{ + SenderObject *s = new SenderObject; + ReceiverObject *r1 = new ReceiverObject; + + int signal1Index = s->metaObject()->indexOfSignal("signal1()"); + int signal3Index = s->metaObject()->indexOfSignal("signal3()"); + int slot1Index = r1->metaObject()->indexOfSlot("slot1()"); + int slot2Index = r1->metaObject()->indexOfSlot("slot2()"); + + QVERIFY(signal1Index > 0); + QVERIFY(signal3Index > 0); + QVERIFY(slot1Index > 0); + QVERIFY(slot2Index > 0); + + QVERIFY( QMetaObject::connect(s, signal1Index, r1, slot1Index) ); + QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) ); + QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) ); + QVERIFY( QMetaObject::connect(s, signal3Index, r1, slot2Index) ); + + r1->reset(); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 0 ); + + s->emitSignal1(); + QCOMPARE( r1->count_slot1, 1 ); + QCOMPARE( r1->count_slot2, 0 ); + + s->emitSignal3(); + QCOMPARE( r1->count_slot1, 1 ); + QCOMPARE( r1->count_slot2, 3 ); + + r1->reset(); + QVERIFY( QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) ); + QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) ); + + s->emitSignal1(); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 0 ); + + s->emitSignal3(); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 2 ); + + r1->reset(); + QVERIFY( false == QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) ); + QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) ); + + s->emitSignal1(); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 0 ); + + s->emitSignal3(); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 1 ); + + r1->reset(); + QVERIFY( false == QMetaObject::disconnectOne(s, signal1Index, r1, slot1Index) ); + QVERIFY( QMetaObject::disconnectOne(s, signal3Index, r1, slot2Index) ); + + s->emitSignal1(); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 0 ); + + s->emitSignal3(); + QCOMPARE( r1->count_slot1, 0 ); + QCOMPARE( r1->count_slot2, 0 ); + + delete s; + delete r1; +} + QTEST_MAIN(tst_QObject) #include "tst_qobject.moc" -- cgit v0.12