summaryrefslogtreecommitdiffstats
path: root/src/util/dispatcher.h
blob: 490a3be967cad9a3103663e3cb433152b4811270 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#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