| Paste number 87422: | QtSignalHandlerS |
| Pasted by: | Ken |
| When: | 5 months, 4 weeks ago |
| Share: | Tweet this! | http://paste.lisp.org/+1VGE |
| Channel: | None |
| Paste contents: |
// file qt_signal_handler.hpp
#ifndef _QT_SIGNAL_HANDLER_H_
#define _QT_SIGNAL_HANDLER_H_
/*!
\file qt_signal_handler.hpp
\author Ken Wu<abawwu@gmail.com>
\brief This file includes a QtSignalHandlerS class template to handle QT signals using boost:function.
The idea is inspired by http://uint32t.blogspot.com/2008/11/using-boost-bind-and-boost-function.html .
And some codes are taken from QSignalSpy. Currently we supports up to 2 arguments, if more arguments are desired, adding
more overloading functions for QtSignalHandlerBase::getFunctorTypes() and QtSignalHandlerBase::fireS()
Example usage:
QtSignalHandlerS<void(qint64,qint64)>::connect(qftp, SIGNAL(dataTransferProgress(qint64,qint64), boost::bind(&Foo::bar, foo));
*/
#include <QtCore/QObject>
#include <boost/function.hpp>
#include <boost/mpl/identity.hpp>
class QtSignalHandlerBase : public QObject
{
protected:
//! find the index of \a aSignal in \a obj. return negtive number if it is not found
static int findSignalIndex(QObject *obj, const char *aSignal);
//! check if the paramters' types of the given signal match the functor's parameters' types or not. return true if they are perfectly matched.
static bool checkTypes(QObject *obj, int sigIndex, int *functorTypes, int nofFunctorTypes);
//@{
//! filling qt types
template <typename T1>
static void getFunctorTypes(const boost::mpl::identity<void(T1)>&, int *types);
template <typename T1, typename T2>
static void getFunctorTypes(const boost::mpl::identity<void(T1,T2)>&, int *types);
//@}
//@{
//! invoke the given boost::function with arguments
template <typename T1>
static void fireS(boost::function<void(T1)> const& f, void **a);
template <typename T1, typename T2>
static void fireS(boost::function<void(T1,T2)> const& f, void **a);
//@}
public:
QtSignalHandlerBase(QObject *parent);
virtual ~QtSignalHandlerBase();
//! connect to \a aSignal of \a obj with connection type \a connectionType
bool connectSignal(QObject *obj, const char *aSignal, Qt::ConnectionType connectionType = Qt::AutoConnection);
//! used for the QT's meta object system
int qt_metacall(QMetaObject::Call call, int methodId, void **a);
protected:
//! this function is called when the signal is emitted. subclasses should implement this function.
virtual void fire(void **args) = 0;
//! this function is called when we want to check the paramters types of the given signal.
/*!
subclasses should implement this function if they want to do some checking. the default implementation is just returning true.
\param obj
\param sigIndex the index of the signal
\return true on success
*/
virtual bool doCheckTypes(QObject *obj, int sigIndex);
};
#include "qt_signal_handler_impl.hpp"
//! This class is used to handle QT signals without slots
/*!
To handle QT signals, you often need to add new slots in some classes or even to add a new class.
This class provides the ability to handle QT signals without adding new slots or adding classes.
You can pass a boost::function to an object of this class and then using connectSignal() to connect to some QObject's signal.
When the connected signal is emitted, the given boost::function will be called.
\param Signature the function signature
*/
template <typename Signature = void()>
class QtSignalHandlerS : public QtSignalHandlerImpl<Signature>
{
public:
QtSignalHandlerS(typename QtSignalHandlerImpl<Signature>::FUNCTOR const& f, QObject *parent = 0) : QtSignalHandlerImpl<Signature>(f, parent)
{
}
//! convient function to connect signal, using \a sender as the parent of the created QtSignalHandlerS object.
static bool connect(QObject *sender, const char *signal, boost::function<Signature> const & f)
{
return connect(sender, signal, f, sender);
}
//! convient function to connect signal, using \a parent as the parent of the created QtSignalHandlerS object.
static bool connect(QObject *sender, const char *signal, boost::function<Signature> const & f, QObject *parent)
{
return (new QtSignalHandlerS<Signature>(f, parent))->connectSignal(sender, signal);
}
};
//! for backward compatibility
typedef QtSignalHandlerS<> QtSignalHandler;
template <typename T1>
void QtSignalHandlerBase::getFunctorTypes(const boost::mpl::identity<void(T1)>&, int *types)
{
types[0] = qMetaTypeId<T1>();
}
template <typename T1, typename T2>
void QtSignalHandlerBase::getFunctorTypes(const boost::mpl::identity<void(T1,T2)>&, int *types)
{
types[0] = qMetaTypeId<T1>();
types[1] = qMetaTypeId<T2>();
}
template <typename T1>
void QtSignalHandlerBase::fireS(boost::function<void(T1)> const& f, void **a)
{
f(*static_cast<T1*>(a[1]));
}
template <typename T1, typename T2>
void QtSignalHandlerBase::fireS(boost::function<void(T1,T2)> const& f, void **a)
{
f(*static_cast<T1*>(a[1]), *static_cast<T2*>(a[2]));
}
#endif /* _QT_SIGNAL_HANDLER_H_ */
// file qt_signal_handler_impl.hpp
#include <QtCore/QMetaType>
template <typename Signature>
class QtSignalHandlerImpl : public QtSignalHandlerBase
{
public:
typedef boost::function<Signature> FUNCTOR;
QtSignalHandlerImpl(FUNCTOR const& f, QObject *parent) : QtSignalHandlerBase(parent), f_(f)
{
Q_ASSERT(!f_.empty());
}
protected:
void fire(void **a)
{
fireS(f_, a);
}
bool doCheckTypes(QObject *obj, int sigIndex)
{
int functorTypes[FUNCTOR::arity];
getFunctorTypes(boost::mpl::identity<Signature>(), functorTypes);
if (!this->checkTypes(obj, sigIndex, functorTypes, sizeof(functorTypes)/sizeof(functorTypes[0])))
return false;
return true;
}
private:
FUNCTOR f_;
};
template <>
class QtSignalHandlerImpl<void()> : public QtSignalHandlerBase
{
public:
typedef boost::function<void()> FUNCTOR;
QtSignalHandlerImpl(FUNCTOR const& f, QObject *parent) : QtSignalHandlerBase(parent), f_(f)
{
Q_ASSERT(!f_.empty());
}
protected:
void fire(void**)
{
f_();
}
private:
FUNCTOR f_;
};
// file qt_signal_handler.cpp
#include "qt_signal_handler.hpp"
#include <QtCore/QMetaMethod>
// most of QT meta object related code are taken from QSignalSpy
int QtSignalHandlerBase::findSignalIndex(QObject *obj, const char *aSignal)
{
Q_ASSERT(obj);
Q_ASSERT(aSignal);
if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
qWarning("%s(): Not a valid signal, use the SIGNAL macro", __PRETTY_FUNCTION__);
return -1;
}
QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
const QMetaObject *mo = obj->metaObject();
int sigIndex = mo->indexOfMethod(ba.constData());
if (sigIndex < 0)
qWarning("%s(): No such signal: '%s'", __PRETTY_FUNCTION__, ba.constData());
return sigIndex;
}
bool QtSignalHandlerBase::checkTypes(QObject *obj, int sigIndex, int *functorTypes, int nofFunctorTypes)
{
Q_ASSERT(obj);
Q_ASSERT(sigIndex >= 0);
Q_ASSERT(functorTypes);
QList<QByteArray> signalParams = obj->metaObject()->method(sigIndex).parameterTypes();
if (signalParams.size() != nofFunctorTypes)
{
qWarning("%s(): number of types are different(%d,%d).", __PRETTY_FUNCTION__, signalParams.size(), nofFunctorTypes);
return false;
}
for (int i = 0; i < nofFunctorTypes; i++)
{
int tp = QMetaType::type(signalParams.at(i).constData());
if (tp != functorTypes[i])
{
qWarning("%s(): type-%d %s is wrong.", __PRETTY_FUNCTION__, i, signalParams.at(i).constData());
return false;
}
}
return true;
}
QtSignalHandlerBase::QtSignalHandlerBase(QObject *parent) : QObject(parent)
{
}
QtSignalHandlerBase::~QtSignalHandlerBase()
{
}
int QtSignalHandlerBase::qt_metacall(QMetaObject::Call call, int methodId, void **a)
{
methodId = QObject::qt_metacall(call, methodId, a);
if (methodId < 0)
return methodId;
if (call == QMetaObject::InvokeMetaMethod) {
if (methodId == 0) {
fire(a);
}
--methodId;
}
return methodId;
}
bool QtSignalHandlerBase::connectSignal(QObject *obj, const char *aSignal, Qt::ConnectionType connectionType)
{
static const int memberOffset = QObject::staticMetaObject.methodCount();
Q_ASSERT(obj);
Q_ASSERT(aSignal);
int sigIndex = findSignalIndex(obj, aSignal);
if (sigIndex < 0)
return false;
if (!doCheckTypes(obj, sigIndex))
return false;
if (!QMetaObject::connect(obj, sigIndex, this, memberOffset,
connectionType, 0)) {
qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
return false;
}
return true;
}
bool QtSignalHandlerBase::doCheckTypes(QObject *, int)
{
return true;
}
This paste has no annotations.