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>
This commit is contained in:
parent
a482487b9f
commit
ed0b262de9
@ -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.
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user