summaryrefslogblamecommitdiffstats
path: root/src/util/dispatcher.h
blob: 490a3be967cad9a3103663e3cb433152b4811270 (plain) (tree)

















































































































































































































                                                                                                                                                  
#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