Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

319 Zeilen
13 KiB

  1. unit uutlEvent;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, syncobjs,
  6. uutlTypes, uutlCommon, uutlGenerics, uutlInterfaces;
  7. type
  8. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. IutlEventArgs = interface(IUnknown)
  10. ['{FC7AA96D-9C2C-42AD-A680-DE55341F2B35}']
  11. end;
  12. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  13. IutlEventListener = interface(IUnknown)
  14. ['{BC45E26B-96F7-4151-87F1-C330C8C668E5}']
  15. procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  16. end;
  17. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  18. TutlEventHandler = procedure (constref aSender: TObject; constref aEventArgs: IutlEventArgs) of object;
  19. TutlEventArgs = class(TutlInterfacedObject, IutlEventArgs)
  20. public
  21. constructor Create;
  22. end;
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. IutlObservable = interface(IUnknown)
  25. ['{C54BD844-8273-4ACF-90C5-05DACF4359AF}']
  26. procedure RegisterEventListener (constref aListener: IutlEventListener);
  27. procedure UnregisterEventListener(constref aListener: IutlEventListener);
  28. end;
  29. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  30. generic TutlEventList<T> = class(specialize TutlCustomHashSet<T>)
  31. private type
  32. TComparer = class(TInterfacedObject, IComparer)
  33. public
  34. function EqualityCompare(constref i1, i2: T): Boolean;
  35. function Compare (constref i1, i2: T): Integer;
  36. end;
  37. public
  38. constructor Create;
  39. end;
  40. TutlNotifyEventList = specialize TutlEventList<TNotifyEvent>;
  41. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  42. TutlEventHandlerList = class(
  43. specialize TutlEventList<TutlEventHandler>
  44. , IutlEventListener)
  45. public { IutlEventListener }
  46. procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  47. public
  48. constructor Create;
  49. end;
  50. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  51. TutlEventListenerSet = class(
  52. specialize TutlCustomHashSet<IutlEventListener>
  53. , IutlEventListener)
  54. private type
  55. TComparer = class(TInterfacedObject, IComparer)
  56. public
  57. function EqualityCompare(constref i1, i2: IutlEventListener): Boolean;
  58. function Compare (constref i1, i2: IutlEventListener): Integer;
  59. end;
  60. public { IutlEventListener }
  61. procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  62. public
  63. constructor Create; reintroduce;
  64. end;
  65. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. TutlEventListenerCallback = class(
  67. TInterfacedObject
  68. , IutlEventListener)
  69. private
  70. fHandler: TutlEventHandler;
  71. public { IEventListener }
  72. procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  73. public
  74. constructor Create(const aHandler: TutlEventHandler);
  75. end;
  76. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  77. TutlEventListenerAsync = class(
  78. TInterfacedObject
  79. , IutlEventListener)
  80. private type
  81. TEventPair = specialize TutlPair<TObject, IutlEventArgs>;
  82. TEventList = class(specialize TutlSimpleList<TEventPair>)
  83. protected
  84. procedure Release(var aItem: TEventPair; const aFreeItem: Boolean); override;
  85. end;
  86. private
  87. fEventLock: TCriticalSection;
  88. fEvents: TEventList;
  89. fListener: IutlEventListener;
  90. function PopEventPair(out aPair: TEventPair): Boolean;
  91. public { IEventListener }
  92. procedure DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  93. public
  94. procedure DispatchEvents;
  95. constructor Create(const aListener: IutlEventListener);
  96. destructor Destroy; override;
  97. end;
  98. implementation
  99. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  100. //TutlEventArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  102. constructor TutlEventArgs.Create;
  103. begin
  104. inherited Create;
  105. AutoFree := true;
  106. end;
  107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  108. //TutlEventList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  110. function TutlEventList.TComparer.EqualityCompare(constref i1, i2: T): Boolean;
  111. begin
  112. result := (TMethod(i1).Data = TMethod(i2).Data)
  113. and (TMethod(i1).Code = TMethod(i2).Code);
  114. end;
  115. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  116. function TutlEventList.TComparer.Compare(constref i1, i2: T): Integer;
  117. var
  118. m1, m2: TMethod;
  119. begin
  120. m1 := TMethod(i1);
  121. m2 := TMethod(i2);
  122. if (m1.Data < m2.Data) then
  123. result := -1
  124. else if (m1.Data > m2.Data) then
  125. result := 1
  126. else if (m1.Code < m2.Code) then
  127. result := -1
  128. else if (m1.Code > m2.Code) then
  129. result := 1
  130. else
  131. result := 0;
  132. end;
  133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  134. constructor TutlEventList.Create;
  135. begin
  136. inherited Create(TComparer.Create, true);
  137. end;
  138. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  139. //TutlEventHandlerList///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  141. procedure TutlEventHandlerList.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  142. var
  143. e: TutlEventHandler;
  144. begin
  145. for e in self do
  146. e(aSender, aEventArgs);
  147. end;
  148. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149. constructor TutlEventHandlerList.Create;
  150. begin
  151. inherited Create;
  152. AutoFree := true;
  153. end;
  154. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. //TutlEventListenerSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  156. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  157. function TutlEventListenerSet.TComparer.EqualityCompare(constref i1, i2: IutlEventListener): Boolean;
  158. begin
  159. result := (i1 = i2);
  160. end;
  161. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  162. function TutlEventListenerSet.TComparer.Compare(constref i1, i2: IutlEventListener): Integer;
  163. begin
  164. if (Pointer(i1) < Pointer(i2)) then
  165. result := -1
  166. else if (Pointer(i1) > Pointer(i2)) then
  167. result := 1
  168. else
  169. result := 0;
  170. end;
  171. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  172. //TutlEventListenerSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  173. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. procedure TutlEventListenerSet.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  175. var
  176. e: IutlEventListener;
  177. begin
  178. for e in self do
  179. e.DispatchEvent(aSender, aEventArgs);
  180. end;
  181. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  182. constructor TutlEventListenerSet.Create;
  183. begin
  184. inherited Create(TComparer.Create, true);
  185. end;
  186. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  187. //TutlEventListenerCallback//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  188. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  189. procedure TutlEventListenerCallback.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  190. begin
  191. fHandler(aSender, aEventArgs);
  192. end;
  193. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  194. constructor TutlEventListenerCallback.Create(const aHandler: TutlEventHandler);
  195. begin
  196. inherited Create;
  197. if not Assigned(aHandler) then
  198. raise EArgumentNilException.Create('aHandler is not assigned');
  199. fHandler := aHandler;
  200. end;
  201. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  202. //TutlEventListenerAsync.TEventList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  203. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  204. procedure TutlEventListenerAsync.TEventList.Release(var aItem: TEventPair; const aFreeItem: Boolean);
  205. begin
  206. aItem.first := nil;
  207. aItem.second := nil;
  208. inherited Release(aItem, aFreeItem);
  209. end;
  210. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  211. //TutlEventListenerAsync/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  212. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. function TutlEventListenerAsync.PopEventPair(out aPair: TEventPair): Boolean;
  214. begin
  215. fEventLock.Enter;
  216. try
  217. result := not fEvents.IsEmpty;
  218. if result
  219. then aPair := fEvents.PopFirst(false)
  220. else FillByte(aPair, SizeOf(aPair), 0);
  221. finally
  222. fEventLock.Leave;
  223. end;
  224. end;
  225. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  226. procedure TutlEventListenerAsync.DispatchEvent(constref aSender: TObject; constref aEventArgs: IutlEventArgs);
  227. var
  228. p: TEventPair;
  229. begin
  230. p.first := aSender;
  231. p.second := aEventArgs;
  232. fEventLock.Enter;
  233. try
  234. fEvents.Add(p);
  235. finally
  236. fEventLock.Leave;
  237. end;
  238. end;
  239. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  240. procedure TutlEventListenerAsync.DispatchEvents;
  241. var
  242. p: TEventPair;
  243. begin
  244. while PopEventPair(p) do
  245. fListener.DispatchEvent(p.first, p.second);
  246. end;
  247. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  248. constructor TutlEventListenerAsync.Create(const aListener: IutlEventListener);
  249. begin
  250. if not Assigned(aListener) then
  251. raise EArgumentNilException.Create('aListener');
  252. inherited Create;
  253. fEventLock := TCriticalSection.Create;
  254. fEvents := TEventList.Create(true);
  255. fListener := aListener;
  256. end;
  257. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  258. destructor TutlEventListenerAsync.Destroy;
  259. begin
  260. fEventLock.Enter;
  261. try
  262. FreeAndNil(fEvents);
  263. fListener := nil;
  264. finally
  265. fEventLock.Leave;
  266. end;
  267. FreeAndNil(fEventLock);
  268. inherited Destroy;
  269. end;
  270. end.