summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2011-11-18 10:57:04 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-29 17:08:39 +0100
commited0b262de97dd92c831127909ea4c059962b86ce (patch)
treeb5ab25866220b0d0a136bd5b77dd227d55fcb0f8
parenta482487b9ff0cf0c47f9c0927c44019d52e2fdf8 (diff)
QObject::disconnect with new syntax
This add an overload to disconnect which is symetrical to the new syntax of connect. It is possible to diconnect connection like this: QObject::connect( sender, &Sender::valueChanged, receiver, &Receiver::updateValue ); QObject::disconnect( sender, &Sender::valueChanged, receiver, &Receiver::updateValue ); This overload only work with pointer to member function, and not static functions or functors. The test is copied from tst_QObject::disconnect(), just changed the syntax of the connection and disconnection Change-Id: Ia8f819100cb12098e32877522b97b732b1e676a8 Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
-rw-r--r--doc/src/snippets/code/src_corelib_kernel_qobject.cpp7
-rw-r--r--src/corelib/kernel/qmetaobject_p.h6
-rw-r--r--src/corelib/kernel/qobject.cpp109
-rw-r--r--src/corelib/kernel/qobject.h35
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp105
5 files changed, 249 insertions, 13 deletions
diff --git a/doc/src/snippets/code/src_corelib_kernel_qobject.cpp b/doc/src/snippets/code/src_corelib_kernel_qobject.cpp
index 11b70cc1ab..b6d0e39ab0 100644
--- a/doc/src/snippets/code/src_corelib_kernel_qobject.cpp
+++ b/doc/src/snippets/code/src_corelib_kernel_qobject.cpp
@@ -470,7 +470,14 @@ QObject::connect(socket, &QTcpSocket::connected, [=] () {
});
//! [46]
+//! [47]
+disconnect(myObject, &MyObject::mySignal(), 0, 0);
+//! [47]
+//! [48]
+QObject::disconnect(lineEdit, &QLineEdit::textChanged,
+ label, &QLabel::setText);
+//! [48]
//! [meta data]
//: This is a comment for the translator.
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index 0476558a92..b99907e822 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -142,11 +142,11 @@ struct QMetaObjectPrivate
const QMetaObject *rmeta = 0,
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, void **slot,
DisconnectType = DisconnectAll);
static inline bool disconnectHelper(QObjectPrivate::Connection *c,
- const QObject *receiver, int method_index,
- QMutex *senderMutex, DisconnectType);
+ const QObject *receiver, int method_index, void **slot,
+ QMutex *senderMutex, DisconnectType = DisconnectAll);
#endif
};
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 2be0a7c759..fc7df79e19 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2758,7 +2758,7 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
}
if (!method) {
- res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1);
+ res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1, 0);
} else {
const QMetaObject *rmeta = receiver->metaObject();
do {
@@ -2768,7 +2768,7 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
rmeta = rmeta->superClass();
if (method_index < 0)
break;
- res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index);
+ res |= QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index, 0);
method_found = true;
} while ((rmeta = rmeta->superClass()));
}
@@ -2881,7 +2881,7 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
return false;
}
- if (!QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index))
+ if (!QMetaObjectPrivate::disconnect(sender, signal_index, receiver, method_index, 0))
return false;
const_cast<QObject*>(sender)->disconnectNotify(method.mobj ? signalSignature.constData() : 0);
@@ -3072,7 +3072,7 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index,
{
signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index);
return QMetaObjectPrivate::disconnect(sender, signal_index,
- receiver, method_index);
+ receiver, method_index, 0);
}
/*!\internal
@@ -3086,7 +3086,7 @@ bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
{
signal_index = methodIndexToSignalIndex(sender->metaObject(), signal_index);
return QMetaObjectPrivate::disconnect(sender, signal_index,
- receiver, method_index,
+ receiver, method_index, 0,
QMetaObjectPrivate::DisconnectOne);
}
@@ -3094,14 +3094,15 @@ bool QMetaObject::disconnectOne(const QObject *sender, int signal_index,
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,
+ const QObject *receiver, int method_index, void **slot,
QMutex *senderMutex, DisconnectType disconnectType)
{
bool success = false;
while (c) {
if (c->receiver
&& (receiver == 0 || (c->receiver == receiver
- && (method_index < 0 || c->method() == method_index)))) {
+ && (method_index < 0 || c->method() == method_index)
+ && (slot == 0 || (c->isSlotObject && c->slotObj->compare(slot)))))) {
bool needToUnlock = false;
QMutex *receiverMutex = 0;
if (!receiver) {
@@ -3134,7 +3135,7 @@ 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, void **slot,
DisconnectType disconnectType)
{
if (!sender)
@@ -3159,7 +3160,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, disconnectType)) {
+ if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) {
success = true;
connectionLists->dirty = true;
}
@@ -3167,7 +3168,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, disconnectType)) {
+ if (disconnectHelper(c, receiver, method_index, slot, senderMutex, disconnectType)) {
success = true;
connectionLists->dirty = true;
}
@@ -4212,6 +4213,88 @@ bool QObject::disconnect(const QMetaObject::Connection &connection)
return true;
}
+/*! \fn bool QObject::disconnect(const QObject *sender, (T::*signal)(...), const Qbject *receiver, (T::*method)(...))
+ \threadsafe
+ \overload
+
+ Disconnects \a signal in object \a sender from \a method in object
+ \a receiver. Returns true if the connection is successfully broken;
+ otherwise returns false.
+
+ A signal-slot connection is removed when either of the objects
+ involved are destroyed.
+
+ disconnect() is typically used in three ways, as the following
+ examples demonstrate.
+ \list 1
+ \i Disconnect everything connected to an object's signals:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 26
+
+ \i Disconnect everything connected to a specific signal:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 47
+
+ \i Disconnect a specific receiver:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 30
+
+ \i Disconnect a connection from one specific signal to a specific slot:
+
+ \snippet doc/src/snippets/code/src_corelib_kernel_qobject.cpp 48
+
+
+ \endlist
+
+ 0 may be used as a wildcard, meaning "any signal", "any receiving
+ object", or "any slot in the receiving object", respectively.
+
+ The \a sender may never be 0. (You cannot disconnect signals from
+ more than one object in a single call.)
+
+ If \a signal is 0, it disconnects \a receiver and \a method from
+ any signal. If not, only the specified signal is disconnected.
+
+ If \a receiver is 0, it disconnects anything connected to \a
+ signal. If not, slots in objects other than \a receiver are not
+ disconnected.
+
+ If \a method is 0, it disconnects anything that is connected to \a
+ receiver. If not, only slots named \a method will be disconnected,
+ and all other slots are left alone. The \a method must be 0 if \a
+ receiver is left out, so you cannot disconnect a
+ specifically-named slot on all objects.
+
+ \note It is not possible to use this overload to diconnect signals
+ connected to functors or lambda expressions. That is because it is not
+ possible to compare them. Instead, use the olverload that take a
+ QMetaObject::Connection
+
+ \sa connect()
+*/
+bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, const QMetaObject *senderMetaObject)
+{
+ if (sender == 0 || (receiver == 0 && slot != 0)) {
+ qWarning("Object::disconnect: Unexpected null parameter");
+ return false;
+ }
+
+ int signal_index = -1;
+ if (signal) {
+ void *args[] = { &signal_index, signal };
+ senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
+ if (signal_index < 0 || signal_index >= QMetaObjectPrivate::get(senderMetaObject)->signalCount) {
+ qWarning("QObject::disconnect: signal not found in %s", senderMetaObject->className());
+ return false;
+ }
+ int signalOffset, methodOffset;
+ computeOffsets(senderMetaObject, &signalOffset, &methodOffset);
+ signal_index += signalOffset;
+ }
+
+ return QMetaObjectPrivate::disconnect(sender, signal_index, receiver, -1, slot);
+}
+
/*! \class QMetaObject::Connection
Represents a handle to a signal-slot connection.
It can be used to disconnect that connection, or check if
@@ -4263,6 +4346,12 @@ QObject::QSlotObjectBase::~QSlotObjectBase()
{
}
+bool QObject::QSlotObjectBase::compare(void** )
+{
+ return false;
+}
+
+
QT_END_NAMESPACE
#include "moc_qobject.cpp"
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 27165cdcc3..3b8803c1a6 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -273,6 +273,33 @@ public:
{ return disconnect(this, 0, receiver, member); }
static bool disconnect(const QMetaObject::Connection &);
+ template <typename Func1, typename Func2>
+ static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
+ const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot)
+ {
+ typedef QtPrivate::FunctionPointer<Func1> SignalType;
+ typedef QtPrivate::FunctionPointer<Func2> SlotType;
+ reinterpret_cast<typename SignalType::Object *>(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast<typename SignalType::Object *>(0));
+
+ //compilation error if the arguments does not match.
+ typedef typename QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::IncompatibleSignalSlotArguments EnsureCompatibleArguments;
+ return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, reinterpret_cast<void **>(&slot),
+ &SignalType::Object::staticMetaObject);
+ }
+ template <typename Func1>
+ static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
+ const QObject *receiver, void **zero)
+ {
+ // This is the overload for when one wish to disconnect a signal from any slot. (slot=0)
+ // Since the function template parametter cannot be deduced from '0', we use a
+ // dummy void ** parametter that must be equal to 0
+ Q_ASSERT(!zero);
+ typedef QtPrivate::FunctionPointer<Func1> SignalType;
+ return disconnectImpl(sender, reinterpret_cast<void **>(&signal), receiver, zero,
+ &SignalType::Object::staticMetaObject);
+ }
+
+
void dumpObjectTree();
void dumpObjectInfo();
@@ -340,6 +367,7 @@ private:
QSlotObjectBase() : ref(1) {}
virtual ~QSlotObjectBase();
virtual void call(QObject *receiver, void **a) = 0;
+ virtual bool compare(void **);
};
// implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
// Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
@@ -351,6 +379,9 @@ private:
virtual void call(QObject *receiver, void **a) {
FuncType::template call<Args, R>(function, static_cast<typename FuncType::Object *>(receiver), a);
}
+ virtual bool compare(void **f) {
+ return *reinterpret_cast<Func *>(f) == function;
+ }
};
// implementation of QSlotObjectBase for which the slot is a static function
// Args and R are the List of arguments and the returntype of the signal to which the slot is connected.
@@ -378,6 +409,10 @@ private:
static QMetaObject::Connection connectImpl(const QObject *sender, void **signal, const QObject *receiver, QSlotObjectBase *slot,
Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject);
+
+ static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot,
+ const QMetaObject *senderMetaObject);
+
};
inline QMetaObject::Connection QObject::connect(const QObject *asender, const char *asignal,
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 77e9a9e42d..f5d06d27ee 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -122,6 +122,7 @@ private slots:
void autoConnectionBehavior();
void baseDestroyed();
void pointerConnect();
+ void pointerDisconnect();
void emitInDefinedOrderPointer();
void customTypesPointer();
void connectCxx0x();
@@ -4104,6 +4105,110 @@ void tst_QObject::pointerConnect()
delete r2;
}
+void tst_QObject::pointerDisconnect()
+{
+ SenderObject *s = new SenderObject;
+ ReceiverObject *r1 = new ReceiverObject;
+ ReceiverObject *r2 = new ReceiverObject;
+
+ connect( s, &SenderObject::signal1, r1, &ReceiverObject::slot1 );
+
+ connect( s, &SenderObject::signal2, r1, &ReceiverObject::slot2 );
+ connect( s, &SenderObject::signal3, r1, &ReceiverObject::slot3 );
+ connect( s, &SenderObject::signal4, r1, &ReceiverObject::slot4 );
+
+ s->emitSignal1();
+ s->emitSignal2();
+ s->emitSignal3();
+ s->emitSignal4();
+
+ QCOMPARE( r1->called(1), TRUE );
+ QCOMPARE( r1->called(2), TRUE );
+ QCOMPARE( r1->called(3), TRUE );
+ QCOMPARE( r1->called(4), TRUE );
+ r1->reset();
+
+ // usual disconnect with all parameters given
+ bool ret = QObject::disconnect( s, &SenderObject::signal1, r1, &ReceiverObject::slot1 );
+
+ s->emitSignal1();
+
+ QCOMPARE( r1->called(1), FALSE );
+ r1->reset();
+
+ QCOMPARE( ret, TRUE );
+ ret = QObject::disconnect( s, &SenderObject::signal1, r1, &ReceiverObject::slot1 );
+ QCOMPARE( ret, FALSE );
+
+ // disconnect all signals from s from all slots from r1
+ QObject::disconnect( s, 0, r1, 0 );
+
+ s->emitSignal2();
+ s->emitSignal3();
+ s->emitSignal4();
+
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r1->called(3), FALSE );
+ QCOMPARE( r1->called(4), FALSE );
+ r1->reset();
+
+ connect( s, &SenderObject::signal1, r1, &ReceiverObject::slot1 );
+ connect( s, &SenderObject::signal1, r1, &ReceiverObject::slot2 );
+ connect( s, &SenderObject::signal1, r1, &ReceiverObject::slot3 );
+ connect( s, &SenderObject::signal2, r1, &ReceiverObject::slot4 );
+
+ // disconnect s's signal1() from all slots of r1
+ QObject::disconnect( s, &SenderObject::signal1, r1, 0 );
+
+ s->emitSignal1();
+ s->emitSignal2();
+
+ QCOMPARE( r1->called(1), FALSE );
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r1->called(3), FALSE );
+ QCOMPARE( r1->called(4), TRUE );
+ r1->reset();
+ // make sure all is disconnected again
+ QObject::disconnect( s, 0, r1, 0 );
+
+ connect( s, &SenderObject::signal1, r1, &ReceiverObject::slot1 );
+ connect( s, &SenderObject::signal1, r2, &ReceiverObject::slot1 );
+ connect( s, &SenderObject::signal2, r1, &ReceiverObject::slot2 );
+ connect( s, &SenderObject::signal2, r2, &ReceiverObject::slot2 );
+ connect( s, &SenderObject::signal3, r1, &ReceiverObject::slot3 );
+ connect( s, &SenderObject::signal3, r2, &ReceiverObject::slot3 );
+
+ // disconnect signal1() from all receivers
+ QObject::disconnect( s, &SenderObject::signal1, 0, 0 );
+ s->emitSignal1();
+ s->emitSignal2();
+ s->emitSignal3();
+
+ QCOMPARE( r1->called(1), FALSE );
+ QCOMPARE( r2->called(1), FALSE );
+ QCOMPARE( r1->called(2), TRUE );
+ QCOMPARE( r2->called(2), TRUE );
+ QCOMPARE( r1->called(2), TRUE );
+ QCOMPARE( r2->called(2), TRUE );
+
+ r1->reset();
+ r2->reset();
+
+ // disconnect all signals of s from all receivers
+ QObject::disconnect( s, 0, 0, 0 );
+
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r2->called(2), FALSE );
+ QCOMPARE( r1->called(2), FALSE );
+ QCOMPARE( r2->called(2), FALSE );
+
+ delete r2;
+ delete r1;
+ delete s;
+
+}
+
+
void tst_QObject::emitInDefinedOrderPointer()
{
SenderObject sender;