Commit 3b75498f authored by Tusooa Zhu's avatar Tusooa Zhu 🔼

Add new signal/slot connection syntax to KisSignalAutoConnection

1. Use template to accommodate the new syntax of signal/slot connection.

2. Instead of the four parameters passed to QObject::connect(), we
store the QMetaObject::Connection returned by connect(), and use that
to disconnect() it afterwards.

3. There is a unit test to test the auto-(dis)connection, just to
make sure it works with both syntaxes.

4. There is no need to change any existing code involving
KisSignalAutoConnectionsStore, unless you want to replace the old
syntax with the new one.
parent 3928c0bb
......@@ -23,7 +23,6 @@
#include <QPointer>
#include <QVector>
/**
* A special wrapper class that represents a connection between two QObject objects.
* It creates the connection on the construction and disconnects it on destruction.
......@@ -51,31 +50,24 @@ public:
/**
* Creates a connection object and starts the requested connection
*/
inline KisSignalAutoConnection(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
template<class Sender, class Signal, class Receiver, class Method>
inline KisSignalAutoConnection(Sender sender, Signal signal,
Receiver receiver, Method method,
Qt::ConnectionType type = Qt::AutoConnection)
: m_sender(const_cast<QObject*>(sender)),
m_signal(signal),
m_receiver(const_cast<QObject*>(receiver)),
m_method(method)
: m_connection(QObject::connect(sender, signal, receiver, method, type))
{
QObject::connect(m_sender, m_signal, m_receiver, m_method, type);
}
inline ~KisSignalAutoConnection()
{
if (!m_sender.isNull() && !m_receiver.isNull()) {
QObject::disconnect(m_sender, m_signal, m_receiver, m_method);
}
QObject::disconnect(m_connection);
}
private:
KisSignalAutoConnection(const KisSignalAutoConnection &rhs);
private:
QPointer<QObject> m_sender;
const char *m_signal;
QPointer<QObject> m_receiver;
const char *m_method;
QMetaObject::Connection m_connection;
};
typedef QSharedPointer<KisSignalAutoConnection> KisSignalAutoConnectionSP;
......@@ -97,8 +89,9 @@ public:
*
* \see addUniqueConnection()
*/
inline void addConnection(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
template<class Sender, class Signal, class Receiver, class Method>
inline void addConnection(Sender sender, Signal signal,
Receiver receiver, Method method,
Qt::ConnectionType type = Qt::AutoConnection)
{
m_connections.append(KisSignalAutoConnectionSP(
......@@ -111,8 +104,9 @@ public:
*
* \see addConnection()
*/
inline void addUniqueConnection(const QObject *sender, const char *signal,
const QObject *receiver, const char *method)
template<class Sender, class Signal, class Receiver, class Method>
inline void addUniqueConnection(Sender sender, Signal signal,
Receiver receiver, Method method)
{
m_connections.append(KisSignalAutoConnectionSP(
new KisSignalAutoConnection(sender, signal,
......
......@@ -4,5 +4,6 @@ include(KritaAddBrokenUnitTest)
macro_add_unittest_definitions()
ecm_add_tests(KisSharedThreadPoolAdapterTest.cpp
KisSignalAutoConnectionTest.cpp
NAME_PREFIX libs-global-
LINK_LIBRARIES kritaglobal Qt5::Test)
/*
* Copyright (c) 2019 Tusooa Zhu <tusooa@vista.aero>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "KisSignalAutoConnectionTest.h"
#include <kis_signal_auto_connection.h>
void KisSignalAutoConnectionTest::testMacroConnection()
{
QScopedPointer<TestClass> test1(new TestClass());
QScopedPointer<TestClass> test2(new TestClass());
KisSignalAutoConnectionsStore conn;
conn.addConnection(test1.data(), SIGNAL(sigTest1()), test2.data(), SLOT(slotTest1()));
emit test1->sigTest1();
QVERIFY(test2->m_test1Called);
test2->m_test1Called = false;
conn.clear();
emit test1->sigTest1();
QVERIFY(test2->m_test1Called == false);
}
void KisSignalAutoConnectionTest::testMemberFunctionConnection()
{
QScopedPointer<TestClass> test1(new TestClass());
QScopedPointer<TestClass> test2(new TestClass());
KisSignalAutoConnectionsStore conn;
conn.addConnection(test1.data(), &TestClass::sigTest1, test2.data(), &TestClass::slotTest1);
emit test1->sigTest1();
QVERIFY(test2->m_test1Called);
test2->m_test1Called = false;
conn.clear();
emit test1->sigTest1();
QVERIFY(test2->m_test1Called == false);
}
void KisSignalAutoConnectionTest::testOverloadConnection()
{
QScopedPointer<TestClass> test1(new TestClass());
QScopedPointer<TestClass> test2(new TestClass());
KisSignalAutoConnectionsStore conn;
conn.addConnection(test1.data(), QOverload<const QString &, const QString &>::of(&TestClass::sigTest2),
test2.data(), QOverload<const QString &, const QString &>::of(&TestClass::slotTest2));
conn.addConnection(test1.data(), SIGNAL(sigTest2(int)), test2.data(), SLOT(slotTest2(int)));
emit test1->sigTest2("foo", "bar");
QVERIFY(test2->m_str1 == "foo");
QVERIFY(test2->m_str2 == "bar");
emit test1->sigTest2(5);
QVERIFY(test2->m_number == 5);
conn.clear();
emit test1->sigTest2("1", "2");
QVERIFY(test2->m_str1 == "foo");
QVERIFY(test2->m_str2 == "bar");
conn.addConnection(test1.data(), SIGNAL(sigTest2(const QString &, const QString &)),
test2.data(), SLOT(slotTest2(const QString &)));
emit test1->sigTest2("3", "4");
QVERIFY(test2->m_str1 == "3");
QVERIFY(test2->m_str2 == "");
}
void KisSignalAutoConnectionTest::testSignalToSignalConnection()
{
QScopedPointer<TestClass> test1(new TestClass());
QScopedPointer<TestClass> test2(new TestClass());
KisSignalAutoConnectionsStore conn;
conn.addConnection(test1.data(), QOverload<int>::of(&TestClass::sigTest2),
test2.data(), QOverload<int>::of(&TestClass::sigTest2));
conn.addConnection(test2.data(), SIGNAL(sigTest2(int)), test2.data(), SLOT(slotTest2(int)));
emit test1->sigTest2(10);
QVERIFY(test2->m_number == 10);
conn.clear();
conn.addConnection(test1.data(), SIGNAL(sigTest2(int)), test2.data(), SIGNAL(sigTest2(int)));
conn.addConnection(test2.data(), QOverload<int>::of(&TestClass::sigTest2),
test2.data(), QOverload<int>::of(&TestClass::slotTest2));
emit test1->sigTest2(50);
QVERIFY(test2->m_number == 50);
}
void KisSignalAutoConnectionTest::testDestroyedObject()
{
QScopedPointer<TestClass> test1(new TestClass());
QScopedPointer<TestClass> test2(new TestClass());
KisSignalAutoConnectionsStore conn;
conn.addConnection(test1.data(), QOverload<int>::of(&TestClass::sigTest2),
test2.data(), QOverload<int>::of(&TestClass::slotTest2));
emit test1->sigTest2(10);
QVERIFY(test2->m_number == 10);
test2.reset(0);
conn.clear();
}
TestClass::TestClass(QObject *parent)
: QObject(parent)
, m_test1Called(false)
, m_str1()
, m_str2()
, m_number(0)
{
}
TestClass::~TestClass()
{
}
void TestClass::slotTest1()
{
m_test1Called = true;
}
void TestClass::slotTest2(const QString &arg1, const QString &arg2)
{
m_str1 = arg1;
m_str2 = arg2;
}
void TestClass::slotTest2(const QString &arg)
{
m_str1 = arg;
m_str2 = QString();
}
void TestClass::slotTest2(int arg)
{
m_number = arg;
}
QTEST_MAIN(KisSignalAutoConnectionTest)
/*
* Copyright (c) 2019 Tusooa Zhu <tusooa@vista.aero>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KIS_SIGNAL_AUTO_CONNECTION_TEST_H_
#define KIS_SIGNAL_AUTO_CONNECTION_TEST_H_
#include <QtTest>
class KisSignalAutoConnectionTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testMacroConnection();
void testMemberFunctionConnection();
void testOverloadConnection();
void testSignalToSignalConnection();
void testDestroyedObject();
};
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass(QObject *parent = 0);
~TestClass() override;
Q_SIGNALS:
void sigTest1();
void sigTest2(const QString &arg1, const QString &arg2);
void sigTest2(int arg);
public Q_SLOTS:
void slotTest1();
void slotTest2(const QString &arg1, const QString &arg2);
void slotTest2(const QString &arg);
void slotTest2(int arg);
public:
bool m_test1Called;
QString m_str1;
QString m_str2;
int m_number;
};
#endif // KIS_SIGNAL_AUTO_CONNECTION_TEST_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment