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
|
/**
* @file lleventdispatcher.h
* @author Nat Goodspeed
* @date 2009-06-18
* @brief Central mechanism for dispatching events by string name. This is
* useful when you have a single LLEventPump listener on which you can
* request different operations, vs. instantiating a different
* LLEventPump for each such operation.
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
* Copyright (c) 2009, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_LLEVENTDISPATCHER_H)
#define LL_LLEVENTDISPATCHER_H
#include <string>
#include <map>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <typeinfo>
#include "llevents.h"
class LLSD;
/**
* Given an LLSD map, examine a string-valued key and call a corresponding
* callable. This class is designed to be contained by an LLEventPump
* listener class that will register some of its own methods, though any
* callable can be used.
*/
class LL_COMMON_API LLEventDispatcher
{
public:
LLEventDispatcher(const std::string& desc, const std::string& key);
virtual ~LLEventDispatcher();
/// Accept any C++ callable, typically a boost::bind() expression
typedef boost::function<void(const LLSD&)> Callable;
/**
* Register a @a callable by @a name. The optional @a required parameter
* is used to validate the structure of each incoming event (see
* llsd_matches()).
*/
void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD());
/**
* Special case: a subclass of this class can pass an unbound member
* function pointer without explicitly specifying the
* <tt>boost::bind()</tt> expression.
*/
template <class CLASS>
void add(const std::string& name, void (CLASS::*method)(const LLSD&),
const LLSD& required=LLSD())
{
addMethod<CLASS>(name, method, required);
}
/// Overload for both const and non-const methods
template <class CLASS>
void add(const std::string& name, void (CLASS::*method)(const LLSD&) const,
const LLSD& required=LLSD())
{
addMethod<CLASS>(name, method, required);
}
/// Unregister a callable
bool remove(const std::string& name);
/// Call a registered callable with an explicitly-specified name. If no
/// such callable exists, die with LL_ERRS. If the @a event fails to match
/// the @a required prototype specified at add() time, die with LL_ERRS.
void operator()(const std::string& name, const LLSD& event) const;
/// Extract the @a key value from the incoming @a event, and call the
/// callable whose name is specified by that map @a key. If no such
/// callable exists, die with LL_ERRS. If the @a event fails to match the
/// @a required prototype specified at add() time, die with LL_ERRS.
void operator()(const LLSD& event) const;
private:
template <class CLASS, typename METHOD>
void addMethod(const std::string& name, const METHOD& method, const LLSD& required)
{
CLASS* downcast = dynamic_cast<CLASS*>(this);
if (! downcast)
{
addFail(name, typeid(CLASS).name());
}
else
{
add(name, boost::bind(method, downcast, _1), required);
}
}
void addFail(const std::string& name, const std::string& classname) const;
/// try to dispatch, return @c true if success
bool attemptCall(const std::string& name, const LLSD& event) const;
std::string mDesc, mKey;
typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap;
DispatchMap mDispatch;
};
/**
* Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
* that contains (or derives from) LLDispatchListener need only specify the
* LLEventPump name and dispatch key, and add() its methods. Incoming events
* will automatically be dispatched.
*/
class LL_COMMON_API LLDispatchListener: public LLEventDispatcher
{
public:
LLDispatchListener(const std::string& pumpname, const std::string& key);
std::string getPumpName() const { return mPump.getName(); }
private:
bool process(const LLSD& event);
LLEventStream mPump;
LLTempBoundListener mBoundListener;
};
#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */
|