#ifndef _DISPATCHER_H_
#define _DISPATCHER_H_
#include <list>
#include <QString>
#include <iostream>
#include <map>
//****************************************************************************************************/
// EventDispatcher && EventIdentDispatcher //
/***************************************************************************************************/
// This handy class(es) act as very simple signals/events.
// Its OOP-only, so dont even try to add static functions
// or C-like methods!
//
// :: Return Types ::
//
// at the moment only callbacks for void methods with a parameter
// count of one ( whos type is the primary template parameter)
//
// :: callback signature ::
//
// typedef void (T::*callback)(U); // with <U, T> as template
//
// :: Usage Example ::
//
// *creating a Dispatcher
//
// -- EventDispatcher<Type A>* nameYourDispatcher = new EventDispatcher<Type A>; // simple Dispatcher
// -- EventIdentDispatcher<Type A>* nameYourIdentDispatcher = new EventIdentDispatcher<Type A>; // ident dispatcher
//
// *difference between simple and ident
//
// a simple dispatcher features only one type of signal, so you can only call all
// attached listeners at once or none at all
//
// an ident dispatcher uses an ident string to hold and fire more than one event type at once
// but is limited to the one defined parameter type for its methods
//
// *subscribung to a dispatcher
//
// -- nameYourDispatcher->addListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); // simple Dispatcher
// -- nameYourIdentDispatcher->addListener(<string-as-ident>, <pointer-to-object-of-Type-myClass>, &myClass::myMethod); // ident dispatcher//
//
// you can add the same method/instance to different dispatchers oder differnt ident-distinguished dispatchers in a identdispatcher.
// you can also add the same method/instance to the same dispatchers all over again, which is not recommended
//
//
// *firing a dispatcher
//
// -- nameYourDispatcher->fire(Type_A Object); // simple Dispatcher
// -- nameYourIdentDispatcher->fire(<string-as-ident>, Type_A Object); // ident dispatcher//
//
// All respective attached callbacks are called in the order they were added
//
//
// *unsubscribing
//
// -- nameYourDispatcher->removeListener(<pointer-to-object-of-Type-myClass>, &myClass::myMethod); // simple Dispatcher
// -- nameYourIdentDispatcher->removeListener(<string-as-ident>, <pointer-to-object-of-Type-myClass>, &myClass::myMethod); // ident dispatcher//
//
// just the reverse of addListener. currently no removeAll() available
//
//
//
/***************************************************************************************************/
class CallbackHandle
{
};
template<class U>
class CallbackBase : public CallbackHandle
{
public:
virtual void fire(U u) {};
private:
};
template<class T, class U>
class Callback : public CallbackBase<U>
{
public:
virtual void fire(U u)
{
if (cbVU)
(callee->*cbVU)(u);
};
typedef void (T::*callbackVU)(U);
Callback(T* who, callbackVU cb)
{
cbVU = cb;
callee = who;
};
T* getCallee()
{
return callee;
};
callbackVU getCBVU()
{
return cbVU;
};
private:
callbackVU cbVU;
T* callee;
};
template<class U>
class EventDispatcher
{
public:
template<class T> void addListener(T *who, void (T :: *func)(U))
{
Callback<T, U> *tmp = new Callback<T, U>(who, func);
_listener.push_back(dynamic_cast<CallbackBase<U>*>(tmp));
};
void fire(U u)
{
for (typename std::list<CallbackBase<U>*>::iterator it = _listener.begin(); it != _listener.end(); it++)
{
if (*it)
{
(*it)->fire(u);
}
}
};
template<class T> void removeListener(T* who, void (T :: *func)(U))
{
if (_listener.size())
{
for (typename std::list<CallbackBase<U>*>::iterator it = _listener.begin(); it != _listener.end(); it++)
{
CallbackBase<U>* pro = (*it);
Callback<T, U> *probe = dynamic_cast<Callback<T,U>*>(pro);
if (probe)
{
if (probe->getCallee() == who && probe->getCBVU() == func )
{
delete (probe);
_listener.remove((*it));
return;
}
}
}
}
};
private:
std::list<CallbackBase<U>*> _listener;
};
template<class U>
class EventIdentDispatcher
{
public:
template<class T> void addListener(QString ident, T* who, void (T :: *func)(U))
{
Callback<T, U>* tmp = new Callback<T, U>(who, func);
_listener.push_back(std::pair<QString, CallbackBase<U>*>(ident, dynamic_cast<CallbackBase<U>*>(tmp)));
};
void fire(QString ident, U u)
{
for ( typename std::list<std::pair<QString, CallbackBase<U>* > >::iterator it = _listener.begin(); it != _listener.end(); it++)
{
if ((*it).first.compare(ident) == 0 || QString("*").compare((*it).first) == 0)
{
if ((*it).second)
{
(*it).second->fire(u);
}
}
}
};
template<class T> void removeListener(QString ident, T* who, void (T :: *func)(U))
{
if (_listener.size())
{
for (std::list<std::pair <QString, CallbackHandle*> >::iterator it = _listener.begin(); it != _listener.end(); it++)
{
if ((*it).first.compare(ident) == 0)
{
CallbackBase<U>* pro = (*it).second;
Callback<T, U> *probe = dynamic_cast<Callback<T,U>*>(pro);
if (probe)
{
if (probe->getCallee() == who && probe->getVoidCB == func)
{
delete (*it).second;
_listener.remove((*it));
return;
}
}
}
}
}
};
private:
std::list<std::pair<QString, CallbackBase<U>* > > _listener;
};
#endif