diff options
author | Olivier Goffart <ogoffart@woboq.com> | 2011-11-23 15:06:30 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-11-25 01:12:14 +0100 |
commit | 583c55b243d9894d93d32fbe15bece2a9beb1d10 (patch) | |
tree | db6237144cfb511cac1468bf851cf66639a84367 /tests/auto/corelib/kernel/qobject | |
parent | 79f675a1e0f628bbc25345ebc1eb1f5809166c6b (diff) |
New QObject connection syntax
In addition to the old connection syntax, you can now connect using function pointers.
connect(sender, &Sender::valueChanged,
receiver, &Receiver::updateValue );
You can connect also to functor or C++11 lambdas
The connections are now type safe (no more problems with namespaces
or typedefs). Implicit type conversion is also supported.
The new syntax forces us to change the meaning of signal form
protected to public, in order to be able to access the signal's
address everywhere
The way it works is by introducing new overload of QObject::connect
that take function pointer as parametter. Those new overload are template
function, that are implemented inline. The actual implementation is
in QObject::connectImpl which take a QObject::QSlotObject* as parametter
for the slot. That slot object contains a virtual function which call
the slot which has to be implemented in the header as it depends on the
template parametter. So the internals of QObjectPrivate::Connection
will store this QObjectSlot* in order to be able to make the call.
You can read a full description here:
http://developer.qt.nokia.com/wiki/New_Signal_Slot_Syntax
History of commits before it was imported on gerrit:
https://qt.gitorious.org/~ogoffart/qt/ogoffarts-qtbase/commits/qobject_connect_ptr
Thread on the mailing list:
http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-August/000796.html
http://lists.qt.nokia.com/pipermail/qt5-feedback/2011-September/001248.html
(The discussions on the mailing list were about trying to find a
solution that do not need making signals public, but no user friendly
solution was found)
Note: support for QueuedConnection, and the symetric QObject::disconnect is
added in another commit.
Qt::UniqueConnection is not supported yet in the new overload.
Change-Id: I67d08436b0720e7f2992be9f7e34770960fa58fa
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'tests/auto/corelib/kernel/qobject')
-rw-r--r-- | tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 3d8bef5274..a00171571b 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -121,6 +121,12 @@ private slots: void disconnectNotSignalMetaMethod(); void autoConnectionBehavior(); void baseDestroyed(); + void pointerConnect(); + void emitInDefinedOrderPointer(); + void customTypesPointer(); + void connectConvert(); + void connectWithReference(); + void connectManyArguments(); }; class SenderObject : public QObject @@ -1094,6 +1100,14 @@ void tst_QObject::emitInDefinedOrder() static int instanceCount = 0; +struct CheckInstanceCount +{ + const int saved; + CheckInstanceCount() : saved(instanceCount) {} + ~CheckInstanceCount() { QCOMPARE(saved, instanceCount); } +}; + + struct CustomType { CustomType(int l1 = 0, int l2 = 0, int l3 = 0): i1(l1), i2(l2), i3(l3) @@ -1107,6 +1121,7 @@ struct CustomType }; Q_DECLARE_METATYPE(CustomType*) +Q_DECLARE_METATYPE(CustomType) class QCustomTypeChecker: public QObject { @@ -4010,5 +4025,399 @@ void tst_QObject::baseDestroyed() // already been destroyed while ~QObject emit destroyed } +void tst_QObject::pointerConnect() +{ + 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 ) ); + QVERIFY( connect( s, &SenderObject::signal1 , r2, &ReceiverObject::slot1 ) ); + QVERIFY( connect( s, &SenderObject::signal1 , r1, &ReceiverObject::slot3 ) ); + QVERIFY( connect( s, &SenderObject::signal3 , r1, &ReceiverObject::slot3 ) ); + + 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 ) ); + QVERIFY( connect( s, &SenderObject::signal4, r2, &ReceiverObject::slot4 ) ); + QVERIFY( connect( s, &SenderObject::signal1, r2, &ReceiverObject::slot4 ) ); + + 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 ); + + QMetaObject::Connection con; + QVERIFY(!con); + QVERIFY(!QObject::disconnect(con)); + + //connect a slot to a signal (== error) + QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject"); + con = connect(r1, &ReceiverObject::slot4 , s, &SenderObject::signal4 ); + QVERIFY(!con); + QVERIFY(!QObject::disconnect(con)); + + delete s; + delete r1; + delete r2; +} + +void tst_QObject::emitInDefinedOrderPointer() +{ + SenderObject sender; + ReceiverObject receiver1, receiver2, receiver3, receiver4; + + QMetaObject::Connection h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot1); + QMetaObject::Connection h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot1); + QVERIFY(h0); + QVERIFY(h1); + connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot1); + connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::slot1); + connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot2); + connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot2); + connect(&sender, &SenderObject::signal1, &receiver3, &SequenceObject::slot2); + connect(&sender, &SenderObject::signal1, &receiver4, &SequenceObject::slot2); + + int sequence; + ReceiverObject::sequence = sequence = 0; + sender.emitSignal1(); + QCOMPARE(receiver1.sequence_slot1, ++sequence); + QCOMPARE(receiver2.sequence_slot1, ++sequence); + QCOMPARE(receiver3.sequence_slot1, ++sequence); + QCOMPARE(receiver4.sequence_slot1, ++sequence); + QCOMPARE(receiver1.sequence_slot2, ++sequence); + QCOMPARE(receiver2.sequence_slot2, ++sequence); + QCOMPARE(receiver3.sequence_slot2, ++sequence); + QCOMPARE(receiver4.sequence_slot2, ++sequence); + + QObject::disconnect(h1); + h1 = connect(&sender, &SenderObject::signal1, &receiver2, &SequenceObject::slot1); + + ReceiverObject::sequence = sequence = 0; + sender.emitSignal1(); + QCOMPARE(receiver1.sequence_slot1, ++sequence); + QCOMPARE(receiver3.sequence_slot1, ++sequence); + QCOMPARE(receiver4.sequence_slot1, ++sequence); + QCOMPARE(receiver1.sequence_slot2, ++sequence); + QCOMPARE(receiver2.sequence_slot2, ++sequence); + QCOMPARE(receiver3.sequence_slot2, ++sequence); + QCOMPARE(receiver4.sequence_slot2, ++sequence); + QCOMPARE(receiver2.sequence_slot1, ++sequence); + + QObject::disconnect(h0); + h0 = connect(&sender, &SenderObject::signal1, &receiver1, &SequenceObject::slot1); + + ReceiverObject::sequence = sequence = 0; + sender.emitSignal1(); + QCOMPARE(receiver3.sequence_slot1, ++sequence); + QCOMPARE(receiver4.sequence_slot1, ++sequence); + QCOMPARE(receiver1.sequence_slot2, ++sequence); + QCOMPARE(receiver2.sequence_slot2, ++sequence); + QCOMPARE(receiver3.sequence_slot2, ++sequence); + QCOMPARE(receiver4.sequence_slot2, ++sequence); + QCOMPARE(receiver2.sequence_slot1, ++sequence); + QCOMPARE(receiver1.sequence_slot1, ++sequence); + + QVERIFY(QObject::disconnect(h0)); + QVERIFY(!QObject::disconnect(h0)); +} + + +void tst_QObject::customTypesPointer() +{ + CustomType t0; + CustomType t1(1, 2, 3); + CustomType t2(2, 3, 4); + + { + QCustomTypeChecker checker; + QCOMPARE(instanceCount, 4); + + connect(&checker, &QCustomTypeChecker::signal1, &checker, &QCustomTypeChecker::slot1, + Qt::DirectConnection); + QCOMPARE(checker.received.value(), 0); + checker.doEmit(t1); + QCOMPARE(checker.received.value(), t1.value()); + } + QCOMPARE(instanceCount, 3); +} + +class StringVariant : public QObject +{ Q_OBJECT +signals: + void stringSignal(const QString &str); +public slots: + void variantSlot(const QVariant &v) { var = v; } +public: + QVariant var; + friend class tst_QObject; +}; + +struct Functor { + QVariant *var; + void operator() (const QVariant &v) { + *var = v; + } +}; + +void tst_QObject::connectConvert() +{ + StringVariant obj; + QVERIFY(connect(&obj, &StringVariant::stringSignal, &obj, &StringVariant::variantSlot)); + QString s = QString::fromLatin1("Hello World"); + emit obj.stringSignal(s); + QCOMPARE(obj.var.toString(), s); + QVERIFY(obj.var.toString().isSharedWith(s)); + + QVariant var; + Functor f; + f.var = &var; + QVERIFY(connect(&obj, &StringVariant::stringSignal, f)); + s = QString::fromLatin1("GoodBye"); + emit obj.stringSignal(s); + QCOMPARE(obj.var.toString(), s); + QVERIFY(obj.var.toString().isSharedWith(s)); + QCOMPARE(var, obj.var); +} + +class ConnectWithReferenceObject : public QObject { + Q_OBJECT + friend class tst_QObject; +signals: + void boolRef(bool &, bool); + void stringRef(QString &, const QString &); + void boolPtr(bool *, bool); + void stringPtr(QString *, const QString &); +public slots: + void boolRefSlot(bool &b1, bool b2) { b1 = b2; } + void stringRefSlot(QString &s1, const QString &s2) { s1 = s2; } + void boolPtrSlot(bool *b1, bool b2) { *b1 = b2; } + void stringPtrSlot(QString *s1, const QString &s2) { *s1 = s2; } + + void stringSlot1(QString s) { last = s; } + void stringSlot2(const QString &s) { last = s; } + void stringSlot3(QString &s) { last = s; } +public: + QString last; +}; + +void tst_QObject::connectWithReference() +{ + ConnectWithReferenceObject o; + bool b1 = true; + QString s1 = QString::fromLatin1("str1"); + const QString s2 = QString::fromLatin1("str2"); + const QString s3 = QString::fromLatin1("str3"); + o.boolRef(b1, false); + o.stringRef(s1, s2); + QCOMPARE(b1, true); + QCOMPARE(s1, QString::fromLatin1("str1")); + o.boolPtr(&b1, false); + o.stringPtr(&s1, s2); + QCOMPARE(b1, true); + QCOMPARE(s1, QString::fromLatin1("str1")); + + QVERIFY(connect(&o, &ConnectWithReferenceObject::boolRef, &o, &ConnectWithReferenceObject::boolRefSlot)); + QVERIFY(connect(&o, &ConnectWithReferenceObject::stringRef, &o, &ConnectWithReferenceObject::stringRefSlot)); + QVERIFY(connect(&o, &ConnectWithReferenceObject::boolPtr, &o, &ConnectWithReferenceObject::boolPtrSlot)); + QVERIFY(connect(&o, &ConnectWithReferenceObject::stringPtr, &o, &ConnectWithReferenceObject::stringPtrSlot)); + o.boolRef(b1, false); + o.stringRef(s1, s2); + QCOMPARE(b1, false); + QCOMPARE(s1, QString::fromLatin1("str2")); + + o.boolPtr(&b1, true); + o.stringPtr(&s1, s3); + QCOMPARE(b1, true); + QCOMPARE(s1, QString::fromLatin1("str3")); + + { + ConnectWithReferenceObject o2; + QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot1)); + o2.stringRef(s1, s2); + QCOMPARE(s1, s3); + QCOMPARE(o2.last, s3); + } + { + ConnectWithReferenceObject o2; + QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot2)); + o2.stringRef(s1, s2); + QCOMPARE(s1, s3); + QCOMPARE(o2.last, s3); + } + { + ConnectWithReferenceObject o2; + QVERIFY(connect(&o2, &ConnectWithReferenceObject::stringRef, &o2, &ConnectWithReferenceObject::stringSlot3)); + o2.stringRef(s1, s2); + QCOMPARE(s1, s3); + QCOMPARE(o2.last, s3); + } +} + +class ManyArgumentObject : public QObject { + Q_OBJECT +signals: + void signal1(const QString &); + void signal2(const QString &, const QString &); + void signal3(const QString &, const QString &, const QString &); + void signal4(const QString &, const QString &, const QString &, const QString&); + void signal5(const QString &, const QString &, const QString &, const QString&, const QString&); + void signal6(const QString &, const QString &, const QString &, const QString&, const QString&, const QString&); + +public slots: +#define MANYARGUMENT_COMPARE(L) QCOMPARE(L, QString(#L)) + void slot1(const QString &a) { + MANYARGUMENT_COMPARE(a); + count++; + } + void slot2(const QString &a, const QString &b) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); + count++; + } + void slot3(const QString &a, const QString &b, const QString &c) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + count++; + } + void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + MANYARGUMENT_COMPARE(d); + count++; + } + void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); + count++; + } + void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); + count++; + } +public: + int count; + +}; + +namespace ManyArgumentNamespace { + int count; + void slot1(const QString &a) { + MANYARGUMENT_COMPARE(a); + count++; + } + void slot2(const QString &a, const QString &b) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); + count++; + } + void slot3(const QString &a, const QString &b, const QString &c) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + count++; + } + void slot4(const QString &a, const QString &b, const QString &c, const QString&d) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + MANYARGUMENT_COMPARE(d); + count++; + } + void slot5(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); + count++; + } + void slot6(const QString &a, const QString &b, const QString &c, const QString&d, const QString&e, const QString&f) { + MANYARGUMENT_COMPARE(a); MANYARGUMENT_COMPARE(b); MANYARGUMENT_COMPARE(c); + MANYARGUMENT_COMPARE(d); MANYARGUMENT_COMPARE(e); MANYARGUMENT_COMPARE(f); + count++; + } +} + +void tst_QObject::connectManyArguments() +{ +#ifdef Q_COMPILER_VARIADIC_TEMPLATES + ManyArgumentObject ob; + ob.count = 0; + ManyArgumentNamespace::count = 0; + connect(&ob, &ManyArgumentObject::signal1, &ob, &ManyArgumentObject::slot1); + connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::slot2); + connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::slot3); + connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::slot4); + connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::slot5); + connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::slot6); + connect(&ob, &ManyArgumentObject::signal1, ManyArgumentNamespace::slot1); + connect(&ob, &ManyArgumentObject::signal2, ManyArgumentNamespace::slot2); + connect(&ob, &ManyArgumentObject::signal3, ManyArgumentNamespace::slot3); + connect(&ob, &ManyArgumentObject::signal4, ManyArgumentNamespace::slot4); + connect(&ob, &ManyArgumentObject::signal5, ManyArgumentNamespace::slot5); + connect(&ob, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); + + + connect(&ob, &ManyArgumentObject::signal6, &ob, &ManyArgumentObject::signal5); + connect(&ob, &ManyArgumentObject::signal5, &ob, &ManyArgumentObject::signal4); + connect(&ob, &ManyArgumentObject::signal4, &ob, &ManyArgumentObject::signal3); + connect(&ob, &ManyArgumentObject::signal3, &ob, &ManyArgumentObject::signal2); + connect(&ob, &ManyArgumentObject::signal2, &ob, &ManyArgumentObject::signal1); + + emit ob.signal6("a", "b", "c", "d", "e", "f"); + QCOMPARE(ob.count, 6); + QCOMPARE(ManyArgumentNamespace::count, 6); + + + ManyArgumentObject ob2; + ob2.count = 0; + ManyArgumentNamespace::count = 0; + connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot1); + connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot2); + connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot3); + connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot4); + connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot5); + connect(&ob2, &ManyArgumentObject::signal6, &ob2, &ManyArgumentObject::slot6); + connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot1); + connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot2); + connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot3); + connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot4); + connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot5); + connect(&ob2, &ManyArgumentObject::signal6, ManyArgumentNamespace::slot6); + + emit ob2.signal6("a", "b", "c", "d", "e", "f"); + QCOMPARE(ob2.count, 6); + QCOMPARE(ManyArgumentNamespace::count, 6); +#endif +} + + + QTEST_MAIN(tst_QObject) #include "tst_qobject.moc" |