summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/kernel/qobject
diff options
context:
space:
mode:
authorOlivier Goffart <ogoffart@woboq.com>2011-11-23 15:06:30 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-25 01:12:14 +0100
commit583c55b243d9894d93d32fbe15bece2a9beb1d10 (patch)
treedb6237144cfb511cac1468bf851cf66639a84367 /tests/auto/corelib/kernel/qobject
parent79f675a1e0f628bbc25345ebc1eb1f5809166c6b (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.cpp409
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"