Freeciv-3.1
Loading...
Searching...
No Matches
client
gui-qt
listener.h
Go to the documentation of this file.
1
/***********************************************************************
2
Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; either version 2, or (at your option)
6
any later version.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
11
***********************************************************************/
12
13
#ifndef FC__LISTENER_H
14
#define FC__LISTENER_H
15
16
#include <set>
17
18
/***************************************************************************
19
Helper template to connect C and C++ code.
20
21
This class is a helper to create Java-like "listeners" for "events"
22
generated in C code. If the C interface defines a callback foo() and
23
you want to use it as an event, you first declare a C++ interface:
24
25
~~~~~{.cpp}
26
class foo_listener : public listener<foo_listener>
27
{
28
public:
29
virtual void foo() = 0;
30
};
31
~~~~~
32
33
The listener needs some static data. Declaring it is as simple as putting
34
a macro in some source file:
35
36
~~~~~{.cpp}
37
FC_CPP_DECLARE_LISTENER(foo_listener)
38
~~~~~
39
40
Then, you call the listeners from the implementation of the C interface:
41
42
~~~~~{.cpp}
43
void foo()
44
{
45
foo_listener::invoke(&foo_listener::foo);
46
}
47
~~~~~
48
49
This will invoke foo() on all foo_listener objects.
50
51
== Listening to events
52
53
Listening to events is done by inheriting from a listener. When your
54
object is ready to receive events, it should call the listener's @c listen
55
function. This will typically be done in the constructor:
56
57
~~~~~{.cpp}
58
class bar : private foo_listener
59
{
60
public:
61
explicit bar();
62
void foo();
63
};
64
65
bar::bar()
66
{
67
// Initialize the object here
68
foo_listener::listen();
69
}
70
~~~~~
71
72
== Passing arguments
73
74
Passing arguments to the listeners is very simple: you write them after
75
the function pointer. For instance, let's say foo() takes an int. It can
76
be passed to the listeners as follows:
77
78
~~~~~{.cpp}
79
void foo(int argument)
80
{
81
foo_listener::invoke(&foo_listener::foo, argument);
82
}
83
~~~~~
84
85
As there may be an arbitrary number of listeners, passing mutable data
86
through invoke() is discouraged.
87
88
== Technical details
89
90
This class achieves its purpose using the Curiously Recurring Template
91
Pattern, hence the weird parent for listeners:
92
93
~~~~~{.cpp}
94
class foo_listener : public listener<foo_listener>
95
~~~~~
96
97
The template argument is used to specialize object storage and member
98
function invocation. Compilers should be able to inline calls to invoke(),
99
leaving only the overhead of looping on all instances.
100
101
@warning Implementation is not thread-safe.
102
***************************************************************************/
103
template
<
class
_type_>
104
class
listener
105
{
106
public
:
107
// The type a given specialization supports.
108
typedef
_type_
type_t
;
109
110
private
:
111
// All instances of type_t that have called listen().
112
static
std::set<type_t *>
instances
;
113
114
protected
:
115
explicit
listener
();
116
virtual
~listener
();
117
118
void
listen
();
119
120
public
:
121
template
<
class
_member_fct_>
122
static
void
invoke
(_member_fct_ function);
123
124
template
<
class
_member_fct_,
class
_arg1_t_>
125
static
void
invoke
(_member_fct_ function, _arg1_t_ arg);
126
127
template
<
class
_member_fct_,
class
_arg1_t_,
class
_arg2_t_>
128
static
void
invoke
(_member_fct_ function, _arg1_t_ arg1, _arg2_t_ arg2);
129
};
130
131
/***********************************************************************/
134
#define FC_CPP_DECLARE_LISTENER(_type_) \
135
template<> \
136
std::set<_type_ *> listener<_type_>::instances = std::set<_type_ *>();
137
138
/***********************************************************************/
141
template
<
class
_type_>
142
listener<_type_>::listener
()
143
{}
144
145
/***********************************************************************/
148
template
<
class
_type_>
149
void
listener<_type_>::listen
()
150
{
151
// If you get an error here, your listener likely doesn't inherit from the
152
// listener<> correctly. See the class documentation.
153
instances.insert(
static_cast<
type_t
*
>
(
this
));
154
}
155
156
/***********************************************************************/
159
template
<
class
_type_>
160
listener<_type_>::~listener
()
161
{
162
instances.erase(
reinterpret_cast<
type_t
*
>
(
this
));
163
}
164
165
/***********************************************************************/
173
template
<
class
_type_>
174
template
<
class
_member_fct_>
175
void
listener<_type_>::invoke
(_member_fct_ function)
176
{
177
typename
std::set<type_t *>::iterator it = instances.begin();
178
typename
std::set<type_t *>::iterator end = instances.end();
179
for
( ; it != end; ++it) {
180
((*it)->*function)();
181
}
182
}
183
184
/***********************************************************************/
193
template
<
class
_type_>
194
template
<
class
_member_fct_,
class
_arg1_t_>
195
void
listener<_type_>::invoke
(_member_fct_ function, _arg1_t_ arg)
196
{
197
typename
std::set<type_t *>::iterator it = instances.begin();
198
typename
std::set<type_t *>::iterator end = instances.end();
199
for
( ; it != end; ++it) {
200
((*it)->*function)(arg);
201
}
202
}
203
204
/***********************************************************************/
214
template
<
class
_type_>
215
template
<
class
_member_fct_,
class
_arg1_t_,
class
_arg2_t_>
216
void
listener<_type_>::invoke
(_member_fct_ function,
217
_arg1_t_ arg1, _arg2_t_ arg2)
218
{
219
typename
std::set<type_t *>::iterator it = instances.begin();
220
typename
std::set<type_t *>::iterator end = instances.end();
221
for
( ; it != end; ++it) {
222
((*it)->*function)(arg1, arg2);
223
}
224
}
225
226
#endif
// FC__LISTENER_H
listener
Definition
listener.h:105
listener::invoke
static void invoke(_member_fct_ function)
Definition
listener.h:175
listener::listener
listener()
Definition
listener.h:142
listener::invoke
static void invoke(_member_fct_ function, _arg1_t_ arg)
Definition
listener.h:195
listener::instances
static std::set< type_t * > instances
Definition
listener.h:112
listener::invoke
static void invoke(_member_fct_ function, _arg1_t_ arg1, _arg2_t_ arg2)
Definition
listener.h:216
listener::type_t
_type_ type_t
Definition
listener.h:108
listener::listen
void listen()
Definition
listener.h:149
listener::~listener
virtual ~listener()
Definition
listener.h:160
Generated on Sun May 19 2024 22:00:55 for Freeciv-3.1 by
1.9.8