Menu

[r3207]: / trunk / Src / UMultiCastEvents.pas  Maximize  Restore  History

Download this file

312 lines (273 with data), 9.5 kB

  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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
{
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/
*
* Copyright (C) 2008-2012, Peter Johnson (www.delphidabbler.com).
*
* $Rev$
* $Date$
*
* Implements class that maintains, and can trigger, a list of event handlers.
}
unit UMultiCastEvents;
interface
uses
// Delphi
Classes, Generics.Collections;
type
{
TNotifyEventInfo:
Type of event that passes an object describing the event to the handler.
@param Sender [in] Reference to object triggering event.
@param EvtInfo [in] IInterface of an object that describes the event.
}
TNotifyEventInfo = procedure(Sender: TObject; const EvtInfo: IInterface)
of object;
{
TEventWrapper:
Abstract base class for classes that wrap event handler methods in order to
be able to store them in an object list.
}
TEventWrapper = class abstract(TObject)
strict private
fOwner: TObject;
{Owner of event handler. Used as Sender parameter when calling event
handler}
fHandler: TMethod;
{Reference to event handler}
public
constructor Create(const Owner: TObject; const Handler: TMethod);
{Constructor. Sets up wrapper object for an event handler method.
@param Owner [in] Reference to object that is to passed as Sender
parameter of triggered event.
@param Handler [in] Reference to event handler to be wrapped.
}
procedure Trigger(const EvtInfo: IInterface); virtual; abstract;
{Triggers event.
@param EvtInfo [in] Interface to object that provides information about
the event. May be nil.
}
property Handler: TMethod read fHandler;
{Reference to wrapped event handler}
property Owner: TObject read fOwner;
{Owner of event handler. Used as Sender parameter when calling event
handler}
end;
{
TMultiCastEvents:
Class that maintains, and can trigger, a list of event handlers.
}
TMultiCastEvents = class(TObject)
strict private
var
fOwner: TObject; // Object that triggers events
fHandlers: TObjectList<TEventWrapper>; // Stores list of event handlers
function IndexOfHandler(const Handler: TMethod): Integer;
{Finds index of a registered event handler in list of handlers.
@param Handler [in] Reference to event handler to find.
@return Index of event handler in list or -1 if handler not found.
}
public
constructor Create(AOwner: TObject = nil);
{Constructor. Sets up object.
@param AOwner [in] Object that owns this object and that triggers
events. Passed as Sender param to event handlers. May by nil.
}
destructor Destroy; override;
{Destructor. Tears down object.
}
procedure AddHandler(const Handler: TNotifyEvent); overload;
{Adds a TNotifyEvent event handler to end of event handler list.
@param Handler [in] Reference to event handler being added.
}
procedure AddHandler(const Handler: TNotifyEventInfo); overload;
{Adds a TNotifyEventInfo event handler to end of event handler list.
@param Handler [in] Reference to event handler being added.
}
procedure RemoveHandler(const Handler: TNotifyEvent); overload;
{Removes a TNotifyEvent event handler from list. Does nothing if handler
is not in list.
@param Reference to event handler to be removed.
}
procedure RemoveHandler(const Handler: TNotifyEventInfo); overload;
{Removes a TNotifyEventInfo event handler from list. Does nothing if
handler is not in list.
@param Reference to event handler to be removed.
}
procedure TriggerEvents(const EvtInfo: IInterface = nil);
{Triggers all registered event handlers in order they were added.
@param EvtInfo [in] Interface to object that provides information about
the event. May be nil. Passed to event handler if it is of type
TNotifyEventInfo.
}
function Count: Integer;
{Gets number of registered event handlers.
@return Number of handlers.
}
end;
implementation
uses
// Delphi
SysUtils;
type
{
TNotifyEventWrapper:
Class used to wrap a TNotifyEvent method in order to be able to store it in
an object list.
}
TNotifyEventWrapper = class(TEventWrapper)
public
procedure Trigger(const EvtInfo: IInterface); override;
{Triggers event.
@param EvtInfo [in] Ignored.
}
end;
{
TNotifyEventInfoWrapper:
Class used to wrap a TNotifyEventInfo method in order to be able to store it
in an object list.
}
TNotifyEventInfoWrapper = class(TEventWrapper)
public
procedure Trigger(const EvtInfo: IInterface); override;
{Triggers event.
@param EvtInfo [in] Interface to object that provides information about
the event. May be nil.
}
end;
function IsEqualMethod(const M1, M2: TMethod): Boolean;
{Checks if two methods are equal, i.e. both methods refer to the same method
in same object.
@param M1 [in] Reference to first method.
@parma M2 [in] Reference to second method.
@return True if methods are equal and False if methods not equal.
}
begin
Result := (M1.Code = M2.Code) and (M1.Data = M2.Data);
end;
{ TMultiCastEvents }
procedure TMultiCastEvents.AddHandler(const Handler: TNotifyEvent);
{Adds a TNotifyEvent event handler to end of event handler list.
@param Handler [in] Reference to event handler being added.
}
begin
if IndexOfHandler(TMethod(Handler)) = -1 then
fHandlers.Add(TNotifyEventWrapper.Create(fOwner, TMethod(Handler)));
end;
procedure TMultiCastEvents.AddHandler(const Handler: TNotifyEventInfo);
{Adds a TNotifyEventInfo event handler to end of event handler list.
@param Handler [in] Reference to event handler being added.
}
begin
if IndexOfHandler(TMethod(Handler)) = -1 then
fHandlers.Add(TNotifyEventInfoWrapper.Create(fOwner, TMethod(Handler)));
end;
function TMultiCastEvents.Count: Integer;
{Gets number of registered event handlers.
@return Number of handlers.
}
begin
Result := fHandlers.Count;
end;
constructor TMultiCastEvents.Create(AOwner: TObject);
{Constructor. Sets up object.
@param AOwner [in] Object that owns this object and that triggers events.
Passed as Sender param to event handlers. May by nil.
}
begin
inherited Create;
fOwner := AOwner;
fHandlers := TObjectList<TEventWrapper>.Create(True);
end;
destructor TMultiCastEvents.Destroy;
{Destructor. Tears down object.
}
begin
FreeAndNil(fHandlers); // frees contained objects
inherited;
end;
function TMultiCastEvents.IndexOfHandler(const Handler: TMethod): Integer;
{Finds index of a registered event handler in list of handlers.
@param Handler [in] Reference to event handler to find.
@return Index of event handler in list or -1 if handler not found.
}
var
Idx: Integer; // loops thru all event handlers in list
begin
Result := -1;
for Idx := 0 to Pred(fHandlers.Count) do
begin
if IsEqualMethod(fHandlers[Idx].Handler, Handler) then
begin
Result := Idx;
Break;
end;
end;
end;
procedure TMultiCastEvents.RemoveHandler(const Handler: TNotifyEventInfo);
{Removes a TNotifyEventInfo event handler from list. Does nothing if handler
is not in list.
@param Reference to event handler to be removed.
}
var
Idx: Integer; // index of handler in list (-1 if not in list)
begin
Idx := IndexOfHandler(TMethod(Handler));
if Idx >= 0 then
fHandlers.Delete(Idx); // frees deleted object
end;
procedure TMultiCastEvents.RemoveHandler(const Handler: TNotifyEvent);
{Removes a TNotifyEvent event handler from list. Does nothing if handler is
not in list.
@param Reference to event handler to be removed.
}
var
Idx: Integer; // index of handler in list (-1 if not in list)
begin
Idx := IndexOfHandler(TMethod(Handler));
if Idx >= 0 then
fHandlers.Delete(Idx); // frees deleted object
end;
procedure TMultiCastEvents.TriggerEvents(const EvtInfo: IInterface = nil);
{Triggers all registered event handlers in order they were added.
@param EvtInfo [in] Interface to object that provides information about the
event. May be nil. Passed to event handler if it is of type
TNotifyEventInfo.
}
var
HandlerWrapper: TEventWrapper; // enumerates event handler wrappers
begin
for HandlerWrapper in fHandlers do
HandlerWrapper.Trigger(EvtInfo);
end;
{ TEventWrapper }
constructor TEventWrapper.Create(const Owner: TObject; const Handler: TMethod);
{Constructor. Sets up wrapper object for an event handler method.
@param Owner [in] Reference to object that is to passed as Sender parameter
of triggered event.
@param Handler [in] Reference to event handler to be wrapped.
}
begin
inherited Create;
fOwner := Owner;
fHandler := Handler;
end;
{ TNotifyEventWrapper }
procedure TNotifyEventWrapper.Trigger(const EvtInfo: IInterface);
{Triggers event.
@param EvtInfo [in] Ignored.
}
begin
TNotifyEvent(Handler)(Owner);
end;
{ TNotifyEventInfoWrapper }
procedure TNotifyEventInfoWrapper.Trigger(const EvtInfo: IInterface);
{Triggers event.
@param EvtInfo [in] Interface to object that provides information about
the event. May be nil.
}
begin
TNotifyEventInfo(Handler)(Owner, EvtInfo);
end;
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.