XPEvent.pas
上传用户:yjb1804
上传日期:2021-01-30
资源大小:3105k
文件大小:9k
源码类别:

Email服务器

开发平台:

Delphi

  1. unit XPEvent;
  2. {
  3.  $Source: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPEvent.pas,v $
  4.  $Revision: 1.2 $
  5.  $Date: 2004/05/03 15:07:15 $
  6.  Last amended by $Author: pvspain $
  7.  $State: Exp $
  8.  XPEvent:  Base interfaces and classes for management of events with
  9.               multiple listeners (event handlers)
  10.  Events covered: TXPEvent (no arguments)
  11. Unit entry points:
  12.   function CreateIXPEventMulticaster: IXPEventMulticaster;
  13.  Copyright (c) 2001 by The Excellent Programming Company Pty Ltd
  14.  (Australia) (ABN 27 005 394 918).
  15.  Contact Paul Spain via email: paul@xpro.com.au
  16.  This unit is free software; you can redistribute it and/or
  17.  modify it under the terms of the GNU Lesser General Public
  18.  License as published by the Free Software Foundation; either
  19.  version 2.1 of the License, or (at your option) any later version.
  20.  This unit is distributed in the hope that it will be useful,
  21.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  23.  Lesser General Public License for more details.
  24.  You should have received a copy of the GNU Lesser General Public
  25.  License along with this unit; if not, the license can be viewed at:
  26.  http://www.gnu.org/copyleft/lesser.html
  27.  or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  28.  Boston, MA  02111-1307  USA
  29. }
  30. interface
  31. type
  32.   // Base interface
  33.   IXPCount = interface(IUnknown)
  34.     ['{50D5B041-28A7-11D5-A292-00608CF441D9}']
  35.     function Count: integer;
  36.     end;
  37. /////////////////////////////////////////////////////////////////////////////
  38. ///   Base classes TXPEventMulticaster, TXPRefEventMulticaster declaration
  39. /////////////////////////////////////////////////////////////////////////////
  40. type
  41.   TXPEvent = procedure of object;
  42.   TXPEvents = array of TXPEvent;
  43.   IXPEventMulticaster = interface(IXPCount)
  44.     ['{ADE449D1-294B-11D5-8CAD-0080ADB62643}']
  45.     procedure Add(const Handler: TXPEvent);
  46.     function Insert(const Handler: TXPEvent;
  47.       const idx: integer): integer;
  48.     procedure Delete(const Handler: TXPEvent);
  49.     function Handler: TXPEvent;
  50.     end;
  51. function CreateIXPEventMulticaster: IXPEventMulticaster;
  52. type
  53.   // Class to manage multiple event handlers for a single event
  54.   // <TXPEvent> is a necessarily generic method pointer
  55.   //
  56.   // Users should subclass from TXPEventMulticaster for each event type to
  57.   // be handled:
  58.   // * Overwrite Add(), Insert() and Delete() with wrappers taking
  59.   //   arguments of the correct event type for the subclass and invoking
  60.   //   the inherited namesake method with a TXPEvent-cast
  61.   //   argument.
  62.   // * Overwrite Notify() with a method of the same signature
  63.   //   as the subclass event type. This method must iterate over the content
  64.   //   of Events, casting each item to the subclass event type and
  65.   //   executing with the arguments passed in to subclassed Notify().
  66.   //   Typically, the base class Notify is never called. It is provided
  67.   //   as a minimal template, and the off-chance someone needs a Multicaster
  68.   //   with an event signature of TXPEvent.
  69.   // * Implement Handler(), which returns the address of subclassed Notify()
  70.   //
  71.   // Users of the subclass must:
  72.   // * Call the subclasses' Notify() with appropriate arguments to trigger
  73.   //   the event. When plugging into a standard component event, this can
  74.   //   be done indirectly by assigning Handler to the event,
  75.   //   eg Button1.OnClick := FNotifyMulticaster.Handler
  76.   //
  77.   // Clients of a subclass object must:
  78.   // * Register/deregister interest in the event by calling Add() or Insert()
  79.   //   and Delete() respectively with an appropriately typed event handler
  80.   //   argument.
  81.   TXPEventMulticaster = class(TInterfacedObject, IXPCount, IXPEventMulticaster)
  82.     private
  83.     FEvents: TXPEvents;
  84.     FCount: integer;
  85.     FIncSize: integer;
  86.     procedure DeleteIdx(const idx: integer);
  87.     function Find(const Handler: TXPEvent; out idx: integer): boolean;
  88.     protected
  89.     function Count: integer;
  90.     // Returns 0-based resultant index of inserted <Handler>;
  91.     // -1 for nil <Handler>
  92.     function Insert(const Handler: TXPEvent; const idx: integer): integer;
  93.     // Append <Handler> to array elements
  94.     procedure Add(const Handler: TXPEvent);
  95.     procedure Delete(const Handler: TXPEvent);
  96.     // Fire all event handlers in array
  97.     procedure Notify;
  98.     function Handler: TXPEvent;
  99.     procedure Clear;
  100.     property Events: TXPEvents read FEvents;
  101.     public
  102.     constructor Create(const InitSize: integer = 4;
  103.       const IncSize: integer = 4);
  104.     destructor Destroy; override;
  105.     end;
  106.   // Behaviour for events with arguments passed by reference
  107.   // raShortCircuit:
  108.   //   Event propagation stops with first handler to modify argument(s).
  109.   // raIsolationFirstChanged:
  110.   //   Every handler gets the original arguments. The values from
  111.   //   the first handler to *modify* the arguments (else original
  112.   //   arguments) are returned to the event origin.
  113.   // raIsolationFirst:
  114.   //   Every handler gets the original arguments. The values from
  115.   //   the first handler are returned to the event origin.
  116.   // raPropagation:
  117.   //   The (modified) arguments are propagated from handler to
  118.   //   handler. The resultant values are returned to the event
  119.   //   origin.
  120.   TXPRefArgs = (raShortCircuit, raIsolationFirstChanged, raIsolationFirst,
  121.     raPropagation);
  122.   TXPRefEventMulticaster = class(TXPEventMulticaster)
  123.     protected
  124.     FBehaviour: TXPRefArgs;
  125.     public
  126.     constructor Create(const Behaviour: TXPRefArgs = raShortCircuit;
  127.       InitSize: integer = 4; const IncSize: integer = 4);
  128.     end;
  129. implementation
  130. uses
  131.   SysUtils;
  132.   
  133. const
  134.   CVSID = '$Header: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPEvent.pas,v 1.2 2004/05/03 15:07:15 pvspain Exp $';
  135. /////////////////////////////////////////////////////////////////////////////
  136. ///           TXPEventMulticaster implementation
  137. /////////////////////////////////////////////////////////////////////////////
  138. constructor TXPEventMulticaster.Create(const InitSize, IncSize: integer);
  139.   begin
  140.   inherited Create;
  141.   FIncSize := IncSize;
  142.   System.SetLength(FEvents, InitSize);
  143.   end;
  144. destructor TXPEventMulticaster.Destroy;
  145.   begin
  146.   FEvents := nil; // dealloc array
  147.   inherited;
  148.   end;
  149. procedure TXPEventMulticaster.Add(const Handler: TXPEvent);
  150.   begin
  151.   Insert(Handler, FCount);
  152.   end;
  153. procedure TXPEventMulticaster.Delete(const Handler: TXPEvent);
  154.   var
  155.   idx: integer;
  156.   begin
  157.   if Find(Handler, idx) then
  158.     DeleteIdx(idx);
  159.   end;
  160. procedure TXPEventMulticaster.Notify;
  161.   var
  162.   idx: integer;
  163.   begin
  164.   // Iterate over all handlers and execute
  165.   // Subclass versions of Notify() must type-cast the handler (Events[idx])
  166.   // and supply arguments as necessary.
  167.     for idx := 0 to FCount - 1 do
  168.       Events[idx];
  169.   end;
  170. procedure TXPEventMulticaster.DeleteIdx(const idx: integer);
  171.   begin
  172.   if idx < FCount - 1 then
  173.     begin
  174.     // Move remainder of array down to cover 'empty' slot
  175.     System.Move(FEvents[idx + 1], FEvents[idx],
  176.       (FCount - idx - 1) * System.SizeOf(TXPEvent));
  177.     end;
  178.   System.Dec(FCount);
  179.   end;
  180. function TXPEventMulticaster.Find(const Handler: TXPEvent;
  181.   out idx: integer): boolean;
  182.   begin
  183.   idx := 0;
  184.   // Comparing by @Method only compares first pointer <Code> of a
  185.   // method procedural type. Need to compare both <Code> and <Data>
  186.   while (idx < FCount)
  187.     and ((TMethod(Handler).Code <> TMethod(FEvents[idx]).Code)
  188.       or (TMethod(Handler).Data <> TMethod(FEvents[idx]).Data)) do
  189.     System.Inc(idx);
  190.   Result := (idx < FCount);
  191.   end;
  192. function TXPEventMulticaster.Insert(const Handler: TXPEvent;
  193.   const idx: integer): integer;
  194.   begin
  195.   // This check will bail and return the index of the handler
  196.   // if present
  197.   if (not Find(Handler, Result)) and Assigned(Handler) then
  198.     begin
  199.     // Check if we've hit the ceiling, and increment array size if
  200.     // necessary.
  201.     if FCount > High(FEvents) then
  202.       SetLength(FEvents, Length(FEvents) + FIncSize);
  203.     // Check for insertion point outside range
  204.     // and clip if necessary.
  205.     if idx < 0 then
  206.       Result := 0
  207.     else if idx < FCount then
  208.       Result := idx
  209.     else
  210.       Result := FCount;
  211.     if Result < FCount then
  212.       begin
  213.       // Move remainder of array up to make an  empty slot at <Result>.
  214.       System.Move(FEvents[Result], FEvents[Result + 1],
  215.         (FCount - Result) * SizeOf(TXPEvent));
  216.       end;
  217.     // Insert handler and increase array entries count.
  218.     FEvents[Result] := Handler;
  219.     System.Inc(FCount);
  220.     end;
  221.   end;
  222. function TXPEventMulticaster.Count: integer;
  223.   begin
  224.   Result := FCount;
  225.   end;
  226. function TXPEventMulticaster.Handler: TXPEvent;
  227.   begin
  228.   Result := Notify;
  229.   end;
  230. procedure TXPEventMulticaster.Clear;
  231.   begin
  232.   FCount := 0;
  233.   end;
  234. function CreateIXPEventMulticaster: IXPEventMulticaster;
  235.   begin
  236.   Result := TXPEventMulticaster.Create;
  237.   end;
  238. /////////////////////////////////////////////////////////////////////////////
  239. ///           TXPRefEventMulticaster implementation
  240. /////////////////////////////////////////////////////////////////////////////
  241. constructor TXPRefEventMulticaster.Create(const Behaviour: TXPRefArgs;
  242.   InitSize: integer; const IncSize: integer);
  243.   begin
  244.   inherited Create(InitSize, IncSize);
  245.   FBehaviour := Behaviour;
  246.   end;
  247. end.