Support Qt::UniqueConnection in the new connection syntax

This commit also improves the related documentation a bit.

The test is copied from the test with the old syntax, but all the
connection statement are changed to use the new syntax

Change-Id: Ia5630ca4335b9f8ca6d724ae3c8750d6f0804d8e
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
Olivier Goffart 2011-11-25 22:35:32 +01:00 committed by Qt by Nokia
parent 8350d91245
commit 0dec6250f7
3 changed files with 124 additions and 13 deletions

View File

@ -2366,7 +2366,7 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
If you pass the Qt::UniqueConnection \a type, the connection will only If you pass the Qt::UniqueConnection \a type, the connection will only
be made if it is not a duplicate. If there is already a duplicate be made if it is not a duplicate. If there is already a duplicate
(exact same signal to the exact same slot on the same objects), (exact same signal to the exact same slot on the same objects),
the connection will fail and connect will return false. the connection will fail and connect will return an invalid QMetaObject::Connection.
The optional \a type parameter describes the type of connection The optional \a type parameter describes the type of connection
to establish. In particular, it determines whether a particular to establish. In particular, it determines whether a particular
@ -4089,6 +4089,14 @@ void qDeleteInEventHandler(QObject *o)
to verify the existence of \a signal (if it was not declared as a signal) to verify the existence of \a signal (if it was not declared as a signal)
You can check if the QMetaObject::Connection is valid by casting it to a bool. You can check if the QMetaObject::Connection is valid by casting it to a bool.
By default, a signal is emitted for every connection you make;
two signals are emitted for duplicate connections. You can break
all of these connections with a single disconnect() call.
If you pass the Qt::UniqueConnection \a type, the connection will only
be made if it is not a duplicate. If there is already a duplicate
(exact same signal to the exact same slot on the same objects),
the connection will fail and connect will return an invalid QMetaObject::Connection.
The optional \a type parameter describes the type of connection The optional \a type parameter describes the type of connection
to establish. In particular, it determines whether a particular to establish. In particular, it determines whether a particular
signal is delivered to a slot immediately or queued for delivery signal is delivered to a slot immediately or queued for delivery
@ -4136,9 +4144,35 @@ void qDeleteInEventHandler(QObject *o)
The connection will automatically disconnect if the sender is destroyed. The connection will automatically disconnect if the sender is destroyed.
*/ */
QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal, const QObject *receiver, QObject::QSlotObjectBase *slotObj,
Qt::ConnectionType type, const int* types, const QMetaObject* senderMetaObject) /** \internal
Implementation of the template version of connect
\a sender is the sender object
\a signal is a pointer to a pointer to a member signal of the sender
\a receiver is the receiver object, may not be null, will be equal to sender when
connecting to a static function or a functor
\a slot a pointer only used when using Qt::UniqueConnection
\a type the Qt::ConnctionType passed as argument to connect
\a types an array of integer with the metatype id of the parametter of the signal
to be used with queued connection
must stay valid at least for the whole time of the connection, this function
do not take ownership. typically static data.
If null, then the types will be computed when the signal is emit in a queued
connection from the types from the signature.
\a senderMetaObject is the metaobject used to lookup the signal, the signal must be in
this metaobject
*/
QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
const QObject *receiver, void **slot,
QObject::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject)
{ {
if (!sender || !signal || !slotObj || !senderMetaObject) {
qWarning("QObject::connect: invalid null parametter");
return QMetaObject::Connection();
}
int signal_index = -1; int signal_index = -1;
void *args[] = { &signal_index, signal }; void *args[] = { &signal_index, signal };
senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args); senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args);
@ -4157,8 +4191,18 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
signalSlotLock(receiver)); signalSlotLock(receiver));
if (type & Qt::UniqueConnection) { if (type & Qt::UniqueConnection) {
qWarning() << "QObject::connect: Qt::UniqueConnection not supported when connecting function pointers"; QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists;
type = static_cast<Qt::ConnectionType>(type & (Qt::UniqueConnection - 1)); if (connectionLists && connectionLists->count() > signal_index) {
const QObjectPrivate::Connection *c2 =
(*connectionLists)[signal_index].first;
while (c2) {
if (c2->receiver == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
return QMetaObject::Connection();
c2 = c2->nextConnectionList;
}
}
type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection);
} }
QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection); QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);

View File

@ -225,8 +225,8 @@ public:
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(); types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
return connectImpl(sender, reinterpret_cast<void **>(&signal), return connectImpl(sender, reinterpret_cast<void **>(&signal),
receiver, new QSlotObject<Func2, receiver, reinterpret_cast<void **>(&slot),
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, new QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot), typename SignalType::ReturnType>(slot),
type, types, &SignalType::Object::staticMetaObject); type, types, &SignalType::Object::staticMetaObject);
} }
@ -243,7 +243,7 @@ public:
typedef typename QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::IncompatibleSignalSlotArguments EnsureCompatibleArguments; typedef typename QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::IncompatibleSignalSlotArguments EnsureCompatibleArguments;
typedef typename QtPrivate::QEnableIf<(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount))>::Type EnsureArgumentsCount; typedef typename QtPrivate::QEnableIf<(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount))>::Type EnsureArgumentsCount;
return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, 0,
new QStaticSlotObject<Func2, new QStaticSlotObject<Func2,
typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot), typename SignalType::ReturnType>(slot),
@ -257,8 +257,8 @@ public:
{ {
typedef QtPrivate::FunctionPointer<Func1> SignalType; typedef QtPrivate::FunctionPointer<Func1> SignalType;
return connectImpl(sender, reinterpret_cast<void **>(&signal), return connectImpl(sender, reinterpret_cast<void **>(&signal), sender, 0,
sender, new QFunctorSlotObject<Func2, SignalType::ArgumentCount, typename SignalType::Arguments, typename SignalType::ReturnType>(slot), new QFunctorSlotObject<Func2, SignalType::ArgumentCount, typename SignalType::Arguments, typename SignalType::ReturnType>(slot),
Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject); Qt::DirectConnection, 0, &SignalType::Object::staticMetaObject);
} }
@ -407,8 +407,10 @@ private:
} }
}; };
static QMetaObject::Connection connectImpl(const QObject *sender, void **signal, const QObject *receiver, QSlotObjectBase *slot, static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,
Qt::ConnectionType type, const int *types, const QMetaObject *senderMetaObject); const QObject *receiver, void **slotPtr,
QSlotObjectBase *slot, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject);
static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot, static bool disconnectImpl(const QObject *sender, void **signal, const QObject *receiver, void **slot,
const QMetaObject *senderMetaObject); const QMetaObject *senderMetaObject);

View File

@ -107,6 +107,7 @@ private slots:
void connectToSender(); void connectToSender();
void qobjectConstCast(); void qobjectConstCast();
void uniqConnection(); void uniqConnection();
void uniqConnectionPtr();
void interfaceIid(); void interfaceIid();
void deleteQObjectWhenDeletingEvent(); void deleteQObjectWhenDeletingEvent();
void overloads(); void overloads();
@ -3269,6 +3270,70 @@ void tst_QObject::uniqConnection()
delete r2; delete r2;
} }
void tst_QObject::uniqConnectionPtr()
{
SenderObject *s = new SenderObject;
ReceiverObject *r1 = new ReceiverObject;
ReceiverObject *r2 = new ReceiverObject;
r1->reset();
r2->reset();
ReceiverObject::sequence = 0;
QVERIFY( connect( s, &SenderObject::signal1, r1, &ReceiverObject::slot1 , Qt::UniqueConnection) );
QVERIFY( connect( s, &SenderObject::signal1, r2, &ReceiverObject::slot1 , Qt::UniqueConnection) );
QVERIFY( connect( s, &SenderObject::signal1, r1, &ReceiverObject::slot3 , Qt::UniqueConnection) );
QVERIFY( connect( s, &SenderObject::signal3, r1, &ReceiverObject::slot3 , Qt::UniqueConnection) );
s->emitSignal1();
s->emitSignal2();
s->emitSignal3();
s->emitSignal4();
QCOMPARE( r1->count_slot1, 1 );
QCOMPARE( r1->count_slot2, 0 );
QCOMPARE( r1->count_slot3, 2 );
QCOMPARE( r1->count_slot4, 0 );
QCOMPARE( r2->count_slot1, 1 );
QCOMPARE( r2->count_slot2, 0 );
QCOMPARE( r2->count_slot3, 0 );
QCOMPARE( r2->count_slot4, 0 );
QCOMPARE( r1->sequence_slot1, 1 );
QCOMPARE( r2->sequence_slot1, 2 );
QCOMPARE( r1->sequence_slot3, 4 );
r1->reset();
r2->reset();
ReceiverObject::sequence = 0;
QVERIFY( connect( s, &SenderObject::signal4, r1, &ReceiverObject::slot4 , Qt::UniqueConnection) );
QVERIFY( connect( s, &SenderObject::signal4, r2, &ReceiverObject::slot4 , Qt::UniqueConnection) );
QVERIFY(!connect( s, &SenderObject::signal4, r2, &ReceiverObject::slot4 , Qt::UniqueConnection) );
QVERIFY( connect( s, &SenderObject::signal1, r2, &ReceiverObject::slot4 , Qt::UniqueConnection) );
QVERIFY(!connect( s, &SenderObject::signal4, r1, &ReceiverObject::slot4 , Qt::UniqueConnection) );
s->emitSignal4();
QCOMPARE( r1->count_slot4, 1 );
QCOMPARE( r2->count_slot4, 1 );
QCOMPARE( r1->sequence_slot4, 1 );
QCOMPARE( r2->sequence_slot4, 2 );
r1->reset();
r2->reset();
ReceiverObject::sequence = 0;
connect( s, &SenderObject::signal4, r1, &ReceiverObject::slot4 );
s->emitSignal4();
QCOMPARE( r1->count_slot4, 2 );
QCOMPARE( r2->count_slot4, 1 );
QCOMPARE( r1->sequence_slot4, 3 );
QCOMPARE( r2->sequence_slot4, 2 );
delete s;
delete r1;
delete r2;
}
void tst_QObject::interfaceIid() void tst_QObject::interfaceIid()
{ {
QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bleh *>()), QCOMPARE(QByteArray(qobject_interface_iid<Foo::Bleh *>()),