100 lines
2.5 KiB
C++
100 lines
2.5 KiB
C++
|
|
|
|
#pragma once
|
|
|
|
#include <QMetaObject>
|
|
#include <QObject>
|
|
#include <QPointer>
|
|
#include <QtGlobal>
|
|
#include <type_traits>
|
|
|
|
namespace LtsUtils {
|
|
|
|
class IConnection {
|
|
public:
|
|
virtual ~IConnection() = default;
|
|
virtual void connect(Qt::ConnectionType = Qt::AutoConnection) = 0;
|
|
virtual void disconnect() = 0;
|
|
};
|
|
|
|
class DummyConnection : public IConnection {
|
|
public:
|
|
void connect(Qt::ConnectionType = Qt::AutoConnection) override {}
|
|
void disconnect() override {}
|
|
};
|
|
|
|
namespace detail {
|
|
|
|
template <class T> struct ExtractClass;
|
|
|
|
template <class T, class Member> struct ExtractClass<Member T::*> {
|
|
using type = T;
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
template <class Signal, class Slot> class Connection : public IConnection {
|
|
static_assert(std::is_member_function_pointer_v<Signal>,
|
|
"Must be a pointer to method");
|
|
static_assert(std::is_member_function_pointer_v<Slot>,
|
|
"Must be a pointer to method");
|
|
|
|
using Emitter = typename detail::ExtractClass<Signal>::type;
|
|
using Target = typename detail::ExtractClass<Slot>::type;
|
|
|
|
static_assert(std::is_base_of_v<QObject, Emitter>,
|
|
"Must be derived from QObject");
|
|
static_assert(std::is_base_of_v<QObject, Target>,
|
|
"Must be derived from QObject");
|
|
|
|
public:
|
|
Connection(Emitter *emitter, Signal signal, Target *target, Slot slot)
|
|
: m_emitter(emitter), m_signal(signal), m_target(target), m_slot(slot) {
|
|
Q_ASSERT(emitter);
|
|
Q_ASSERT(signal);
|
|
Q_ASSERT(target);
|
|
Q_ASSERT(slot);
|
|
}
|
|
|
|
void
|
|
connect(Qt::ConnectionType connectionType = Qt::AutoConnection) override {
|
|
Q_ASSERT(!m_connected);
|
|
|
|
m_connected = true;
|
|
|
|
if (!m_emitter || !m_target)
|
|
return;
|
|
|
|
m_conn = QObject::connect(m_emitter.data(), m_signal, m_target.data(),
|
|
m_slot, connectionType);
|
|
Q_ASSERT(m_conn);
|
|
}
|
|
|
|
void disconnect() override {
|
|
Q_ASSERT(m_connected);
|
|
|
|
if (m_conn)
|
|
QObject::disconnect(m_conn);
|
|
|
|
m_connected = false;
|
|
}
|
|
|
|
private:
|
|
bool m_connected{false};
|
|
QPointer<Emitter> m_emitter;
|
|
Signal m_signal;
|
|
QPointer<Target> m_target;
|
|
Slot m_slot;
|
|
QMetaObject::Connection m_conn;
|
|
};
|
|
|
|
template <class Signal, class Slot>
|
|
Connection<Signal, Slot> *
|
|
createConnection(typename detail::ExtractClass<Signal>::type *emitter,
|
|
Signal signal,
|
|
typename detail::ExtractClass<Slot>::type *target, Slot slot) {
|
|
return new Connection<Signal, Slot>(emitter, signal, target, slot);
|
|
}
|
|
|
|
} // namespace LtsUtils
|