home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / TIMERLST.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  16.0 KB  |  596 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 2001,2002 SGB Software          }
  6. {         Copyright (c) 1997, 1998 Fedor Koshevnikov,   }
  7. {                        Igor Pavluk and Serge Korolev  }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit TimerLst;
  12.  
  13. {$I RX.INC}
  14.  
  15. interface
  16.  
  17. uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  18.   Messages, Classes;
  19.  
  20. const
  21.   DefaultInterval = 1000;
  22.   HInvalidEvent = -1;
  23.  
  24. type
  25.   TAllTimersEvent = procedure(Sender: TObject; Handle: Longint) of object;
  26.  
  27.   TRxTimerEvent = class;
  28.  
  29.   TRxTimerList = class(TComponent)
  30.   private
  31.     FEvents: TList;
  32.     FWndHandle: hWnd;
  33.     FActive: Boolean;
  34.     FInterval: Longint;
  35.     FSequence: Longint;
  36.     FStartInterval: Longint;
  37.     FOnFinish: TNotifyEvent;
  38.     FOnTimers: TAllTimersEvent;
  39.     procedure CalculateInterval(StartTicks: Longint);
  40.     function CreateNewEvent: TRxTimerEvent;
  41.     function GetCount: Integer;
  42.     function GetEnabledCount: Integer;
  43.     function ProcessEvents: Boolean;
  44.     procedure RemoveItem(Item: TRxTimerEvent);
  45.     procedure SetActive(Value: Boolean);
  46.     procedure SetEvents(StartTicks: Longint);
  47.     procedure Sort;
  48.     procedure TimerWndProc(var Msg: TMessage);
  49.     procedure UpdateTimer;
  50.   protected
  51. {$IFDEF WIN32}
  52.     procedure GetChildren(Proc: TGetChildProc {$IFDEF RX_D3};
  53.       Root: TComponent {$ENDIF}); override;
  54. {$ELSE}
  55.     procedure WriteComponents(Writer: TWriter); override;
  56. {$ENDIF WIN32}
  57.     procedure DoTimer(Event: TRxTimerEvent); dynamic;
  58.     function NextHandle: Longint; virtual;
  59.   public
  60.     constructor Create(AOwner: TComponent); override;
  61.     destructor Destroy; override;
  62.     function Add(AOnTimer: TNotifyEvent; AInterval: Longint;
  63.       ACycled: Boolean): Longint; virtual;
  64.     function AddItem(Item: TRxTimerEvent): Longint;
  65.     procedure Clear;
  66.     procedure Delete(AHandle: Longint); virtual;
  67.     procedure Activate;
  68.     procedure Deactivate;
  69.     function ItemByHandle(AHandle: Longint): TRxTimerEvent;
  70.     function ItemIndexByHandle(AHandle: Longint): Integer;
  71.     property Count: Integer read GetCount;
  72.     property EnabledCount: Integer read GetEnabledCount;
  73.   published
  74.     property Active: Boolean read FActive write SetActive default False;
  75.     property Events: TList read FEvents;
  76.     property OnFinish: TNotifyEvent read FOnFinish write FOnFinish;
  77.     property OnTimers: TAllTimersEvent read FOnTimers write FOnTimers;
  78.   end;
  79.  
  80.   TRxTimerEvent = class(TComponent)
  81.   private
  82.     FCycled: Boolean;
  83.     FEnabled: Boolean;
  84.     FExecCount: Integer;
  85.     FHandle: Longint;
  86.     FInterval: Longint;
  87.     FLastExecute: Longint;
  88.     FParentList: TRxTimerList;
  89.     FRepeatCount: Integer;
  90.     FOnTimer: TNotifyEvent;
  91.     function GetAsSeconds: Cardinal;
  92.     procedure SetAsSeconds(Value: Cardinal);
  93.     procedure SetRepeatCount(Value: Integer);
  94.     procedure SetEnabled(Value: Boolean);
  95.     procedure SetInterval(Value: Longint);
  96. {$IFNDEF WIN32}
  97.     procedure SetParentList(Value: TRxTimerList);
  98. {$ENDIF WIN32}
  99.   protected
  100. {$IFDEF WIN32}
  101.     procedure SetParentComponent(Value: TComponent); override;
  102. {$ELSE}
  103.     procedure ReadState(Reader: TReader); override;
  104. {$ENDIF}
  105.   public
  106.     constructor Create(AOwner: TComponent); override;
  107.     destructor Destroy; override;
  108.     function HasParent: Boolean; override;
  109. {$IFDEF WIN32}
  110.     function GetParentComponent: TComponent; override;
  111. {$ENDIF}
  112.     property AsSeconds: Cardinal read GetAsSeconds write SetAsSeconds;
  113.     property Handle: Longint read FHandle;
  114.     property ExecCount: Integer read FExecCount;
  115.     property TimerList: TRxTimerList read FParentList;
  116.   published
  117.     property Cycled: Boolean read FCycled write FCycled default True;
  118.     property RepeatCount: Integer read FRepeatCount write SetRepeatCount default 0;
  119.     property Enabled: Boolean read FEnabled write SetEnabled default True;
  120.     property Interval: Longint read FInterval write SetInterval default DefaultInterval;
  121.     property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  122.   end;
  123.  
  124. implementation
  125.  
  126. uses Consts, Controls, Forms, SysUtils, VCLUtils, MaxMin;
  127.  
  128. const
  129.   MinInterval = 100; { 0.1 sec }
  130. {$IFDEF RX_D4}
  131.   MaxTimerInterval: Longint = High(Longint);
  132. {$ELSE}
  133.   MaxTimerInterval: Longint = High(Cardinal);
  134. {$ENDIF}
  135. {$IFNDEF WIN32}
  136.   INVALID_HANDLE_VALUE = 0;
  137. {$ENDIF}
  138.   Registered: Boolean = False;
  139.  
  140. { TRxTimerEvent }
  141.  
  142. constructor TRxTimerEvent.Create(AOwner: TComponent);
  143. begin
  144.   inherited Create(AOwner);
  145.   FParentList := nil;
  146.   FCycled := True;
  147.   FRepeatCount := 0;
  148.   FEnabled := True;
  149.   FExecCount := 0;
  150.   FInterval := DefaultInterval;
  151.   FLastExecute := GetTickCount;
  152.   FHandle := HInvalidEvent;
  153. end;
  154.  
  155. destructor TRxTimerEvent.Destroy;
  156. begin
  157.   FOnTimer := nil;
  158.   inherited Destroy;
  159. end;
  160.  
  161. {$IFNDEF WIN32}
  162. procedure TRxTimerEvent.SetParentList(Value: TRxTimerList);
  163. begin
  164.   if FParentList <> nil then FParentList.RemoveItem(Self);
  165.   if Value <> nil then Value.AddItem(Self);
  166. end;
  167. {$ENDIF}
  168.  
  169. function TRxTimerEvent.HasParent: Boolean;
  170. begin
  171.   Result := True;
  172. end;
  173.  
  174. {$IFDEF WIN32}
  175.  
  176. function TRxTimerEvent.GetParentComponent: TComponent;
  177. begin
  178.   Result := FParentList;
  179. end;
  180.  
  181. procedure TRxTimerEvent.SetParentComponent(Value: TComponent);
  182. begin
  183.   if FParentList <> nil then FParentList.RemoveItem(Self);
  184.   if (Value <> nil) and (Value is TRxTimerList) then
  185.     TRxTimerList(Value).AddItem(Self);
  186. end;
  187.  
  188. {$ELSE}
  189.  
  190. procedure TRxTimerEvent.ReadState(Reader: TReader);
  191. begin
  192.   inherited ReadState(Reader);
  193.   if Reader.Parent is TRxTimerList then
  194.     SetParentList(TRxTimerList(Reader.Parent));
  195. end;
  196.  
  197. {$ENDIF WIN32}
  198.  
  199. procedure TRxTimerEvent.SetEnabled(Value: Boolean);
  200. begin
  201.   if Value <> FEnabled then begin
  202.     FEnabled := Value;
  203.     if FEnabled then begin
  204.       FExecCount := 0;
  205.       FLastExecute := GetTickCount;
  206.       if FParentList <> nil then
  207.         with FParentList do begin
  208.           CalculateInterval(GetTickCount);
  209.           UpdateTimer;
  210.         end;
  211.     end;
  212.   end;
  213. end;
  214.  
  215. procedure TRxTimerEvent.SetInterval(Value: Longint);
  216. begin
  217.   if Value <> FInterval then begin
  218.     FInterval := Value;
  219.     if FParentList <> nil then
  220.       with FParentList do begin
  221.         CalculateInterval(GetTickCount);
  222.         UpdateTimer;
  223.       end;
  224.   end;
  225. end;
  226.  
  227. procedure TRxTimerEvent.SetRepeatCount(Value: Integer);
  228. begin
  229.   if FRepeatCount <> Value then begin
  230.     Value := Max(Value, Integer(not FCycled));
  231.     if not (csDesigning in ComponentState) then
  232.       if FEnabled and (Value <= FExecCount) then Enabled := False;
  233.     FRepeatCount := Value;
  234.   end;
  235. end;
  236.  
  237. function TRxTimerEvent.GetAsSeconds: Cardinal;
  238. begin
  239.   Result := Interval div 1000;
  240. end;
  241.  
  242. procedure TRxTimerEvent.SetAsSeconds(Value: Cardinal);
  243. begin
  244.   Interval := Value * 1000;
  245. end;
  246.  
  247. { TRxTimerList }
  248.  
  249. constructor TRxTimerList.Create(AOwner: TComponent);
  250. begin
  251.   inherited Create(AOwner);
  252.   FEvents := TList.Create;
  253.   FWndHandle := INVALID_HANDLE_VALUE;
  254.   FSequence := 0;
  255.   FStartInterval := 0;
  256.   Deactivate;
  257.   if not Registered then begin
  258.     RegisterClasses([TRxTimerEvent]);
  259.     Registered := True;
  260.   end;
  261. end;
  262.  
  263. destructor TRxTimerList.Destroy;
  264. begin
  265.   OnFinish := nil;
  266.   OnTimers := nil;
  267.   Deactivate;
  268.   Clear;
  269.   FEvents.Free;
  270.   inherited Destroy;
  271. end;
  272.  
  273. procedure TRxTimerList.Activate;
  274. begin
  275.   Active := True;
  276. end;
  277.  
  278. procedure TRxTimerList.Deactivate;
  279. begin
  280.   if not (csLoading in ComponentState) then Active := False;
  281. end;
  282.  
  283. procedure TRxTimerList.SetEvents(StartTicks: Longint);
  284. var
  285.   I: Integer;
  286. begin
  287.   for I := 0 to FEvents.Count - 1 do
  288.     if TRxTimerEvent(FEvents[I]).Enabled then
  289.       TRxTimerEvent(FEvents[I]).FLastExecute := StartTicks;
  290. end;
  291.  
  292. procedure TRxTimerList.SetActive(Value: Boolean);
  293. var
  294.   StartTicks: Longint;
  295. begin
  296.   if FActive <> Value then begin
  297.     if not (csDesigning in ComponentState) then begin
  298.       if Value then begin
  299.         FWndHandle := Classes.AllocateHWnd(TimerWndProc);
  300.         StartTicks := GetTickCount;
  301.         SetEvents(StartTicks);
  302.         CalculateInterval(StartTicks);
  303.         Sort;
  304.         UpdateTimer;
  305.       end
  306.       else begin
  307.         KillTimer(FWndHandle, 1);
  308.         Classes.DeallocateHWnd(FWndHandle);
  309.         FWndHandle := INVALID_HANDLE_VALUE;
  310.         if Assigned(FOnFinish) then FOnFinish(Self);
  311.       end;
  312.       FStartInterval := 0;
  313.     end;
  314.     FActive := Value;
  315.   end;
  316. end;
  317.  
  318. {$IFDEF WIN32}
  319. procedure TRxTimerList.GetChildren(Proc: TGetChildProc {$IFDEF RX_D3};
  320.   Root: TComponent {$ENDIF});
  321. var
  322.   I: Integer;
  323. begin
  324.   inherited GetChildren(Proc {$IFDEF RX_D3}, Root {$ENDIF});
  325.   for I := 0 to FEvents.Count - 1 do
  326.     Proc(TRxTimerEvent(FEvents[I]));
  327. end;
  328. {$ELSE}
  329. procedure TRxTimerList.WriteComponents(Writer: TWriter);
  330. var
  331.   I: Integer;
  332.   Item: TRxTimerEvent;
  333. begin
  334.   inherited WriteComponents(Writer);
  335.   for I := 0 to FEvents.Count - 1 do begin
  336.     Item := TRxTimerEvent(FEvents[I]);
  337.     if Item.Owner = Writer.Root then Writer.WriteComponent(Item);
  338.   end;
  339. end;
  340. {$ENDIF WIN32}
  341.  
  342. procedure TRxTimerList.Sort;
  343. var
  344.   I: Integer;
  345.   ExitLoop: Boolean;
  346. begin
  347.   if not (csDesigning in ComponentState) then
  348.     repeat
  349.       ExitLoop := True;
  350.       for I := 0 to Count - 2 do begin
  351.         if TRxTimerEvent(FEvents[I]).Interval > TRxTimerEvent(FEvents[I + 1]).Interval then
  352.         begin
  353.           FEvents.Exchange(I, I + 1);
  354.           ExitLoop := False;
  355.         end;
  356.       end;
  357.     until ExitLoop;
  358. end;
  359.  
  360. function TRxTimerList.NextHandle: Longint;
  361. begin
  362.   Inc(FSequence);
  363.   Result := FSequence;
  364. end;
  365.  
  366. function TRxTimerList.CreateNewEvent: TRxTimerEvent;
  367. begin
  368.   Result := TRxTimerEvent.Create(Owner);
  369. end;
  370.  
  371. function TRxTimerList.AddItem(Item: TRxTimerEvent): Longint;
  372. begin
  373.   if FEvents.Add(Item) >= 0 then begin
  374.     Item.FHandle := NextHandle;
  375.     Item.FParentList := Self;
  376.     Result := Item.FHandle;
  377.     CalculateInterval(GetTickCount);
  378.     Sort;
  379.     UpdateTimer;
  380.   end
  381.   else Result := HInvalidEvent; { invalid handle }
  382. end;
  383.  
  384. { Create a new timer event and returns a handle }
  385. function TRxTimerList.Add(AOnTimer: TNotifyEvent; AInterval: Longint;
  386.   ACycled: Boolean): Longint;
  387. var
  388.   T: TRxTimerEvent;
  389. begin
  390.   T := CreateNewEvent;
  391.   if (FEvents.Add(T) >= 0) then begin
  392.     with T do begin
  393.       OnTimer := AOnTimer;
  394.       FParentList := Self;
  395.       FHandle := NextHandle;
  396.       Interval := AInterval;
  397.       Cycled := ACycled;
  398.       Result := FHandle;
  399.     end;
  400.     CalculateInterval(GetTickCount);
  401.     Sort;
  402.     UpdateTimer;
  403.   end
  404.   else begin
  405.     T.Free;
  406.     Result := HInvalidEvent; { invalid handle }
  407.   end;
  408. end;
  409.  
  410. function TRxTimerList.ItemIndexByHandle(AHandle: Longint): Integer;
  411. begin
  412.   for Result := 0 to FEvents.Count - 1 do
  413.     if TRxTimerEvent(FEvents[Result]).Handle = AHandle then Exit;
  414.   Result := -1;
  415. end;
  416.  
  417. function TRxTimerList.ItemByHandle(AHandle: Longint): TRxTimerEvent;
  418. var
  419.   I: Integer;
  420. begin
  421.   I := ItemIndexByHandle(AHandle);
  422.   if I >= 0 then Result := TRxTimerEvent(FEvents[I])
  423.   else Result := nil;
  424. end;
  425.  
  426. procedure TRxTimerList.Delete(AHandle: Longint);
  427. var
  428.   I: Integer;
  429.   Item: TRxTimerEvent;
  430. begin
  431.   I := ItemIndexByHandle(AHandle);
  432.   if I >= 0 then begin
  433.     Item := TRxTimerEvent(FEvents[I]);
  434.     RemoveItem(Item);
  435.     if not (csDestroying in Item.ComponentState) then Item.Free;
  436.     if Active then begin
  437.       CalculateInterval(GetTickCount);
  438.       UpdateTimer;
  439.     end;
  440.   end;
  441. end;
  442.  
  443. function TRxTimerList.GetCount: Integer;
  444. begin
  445.   Result := FEvents.Count;
  446. end;
  447.  
  448. function TRxTimerList.GetEnabledCount: Integer;
  449. var
  450.   I: Integer;
  451. begin
  452.   Result := 0;
  453.   for I := 0 to Count - 1 do
  454.     if TRxTimerEvent(FEvents[I]).Enabled then Inc(Result);
  455. end;
  456.  
  457. procedure TRxTimerList.RemoveItem(Item: TRxTimerEvent);
  458. begin
  459.   FEvents.Remove(Item);
  460.   Item.FParentList := nil;
  461. end;
  462.  
  463. procedure TRxTimerList.Clear;
  464. var
  465.   I: Integer;
  466.   Item: TRxTimerEvent;
  467. begin
  468.   for I := FEvents.Count - 1 downto 0 do begin
  469.     Item := TRxTimerEvent(FEvents[I]);
  470.     RemoveItem(Item);
  471.     if not (csDestroying in Item.ComponentState) then Item.Free;
  472.   end;
  473. end;
  474.  
  475. procedure TRxTimerList.DoTimer(Event: TRxTimerEvent);
  476. begin
  477.   with Event do 
  478.     if Assigned(FOnTimer) then FOnTimer(Event);
  479.   if Assigned(FOnTimers) then FOnTimers(Self, Event.Handle);
  480. end;
  481.  
  482. function TRxTimerList.ProcessEvents: Boolean;
  483. var
  484.   I: Integer;
  485.   Item: TRxTimerEvent;
  486.   StartTicks: Longint;
  487. begin
  488.   Result := False;
  489.   if not (csDesigning in ComponentState) then begin
  490.     StartTicks := GetTickCount;
  491.     for I := Count - 1 downto 0 do begin
  492.       Item := TRxTimerEvent(FEvents[I]);
  493.       if (Item <> nil) and Item.Enabled then
  494.         with Item do
  495.           if (StartTicks - FLastExecute) >= (Interval - (MinInterval div 2)) then
  496.           begin
  497.             FLastExecute := StartTicks;
  498.             Inc(FExecCount);
  499.             Enabled := not ((not Cycled) and (FExecCount >= RepeatCount));
  500.             if not Enabled then Result := True;
  501.             DoTimer(Item);
  502.           end;
  503.     end;
  504.   end;
  505. end;
  506.  
  507. procedure TRxTimerList.TimerWndProc(var Msg: TMessage);
  508. begin
  509.   if not (csDesigning in ComponentState) then begin
  510.     with Msg do
  511.       if Msg = WM_TIMER then
  512.         try
  513.           if (not (csDesigning in ComponentState)) and
  514.             (FStartInterval = 0) and Active then 
  515.           begin
  516.             if ProcessEvents then begin
  517.               if EnabledCount = 0 then Deactivate
  518.               else begin
  519.                 CalculateInterval(GetTickCount);
  520.                 UpdateTimer;
  521.               end;
  522.             end;
  523.           end else
  524.             UpdateTimer;
  525.         except
  526.           Application.HandleException(Self);
  527.         end
  528.       else Result := DefWindowProc(FWndHandle, Msg, wParam, lParam);
  529.   end;
  530. end;
  531.  
  532. procedure TRxTimerList.CalculateInterval(StartTicks: Longint);
  533. var
  534.   I: Integer;
  535.   ExitLoop: Boolean;
  536. begin
  537.   if not (csDesigning in ComponentState) then begin
  538.     if Count = 0 then FInterval := 0
  539.     else begin
  540.       FStartInterval := 0;
  541.       FInterval := MaxLongInt;
  542.       for I := 0 to Count - 1 do
  543.         with TRxTimerEvent(FEvents[I]) do
  544.           if Enabled and (Interval > 0) then begin
  545.             if Interval < Self.FInterval then Self.FInterval := Interval;
  546.             if Self.FInterval > (Interval - (StartTicks - FLastExecute)) then
  547.               Self.FInterval := (Interval - (StartTicks - FLastExecute));
  548.           end;
  549.       if FInterval < MinInterval then FInterval := MinInterval;
  550.       if FInterval = MaxLongint then FInterval := 0
  551.       else begin
  552.         repeat
  553.           ExitLoop := True;
  554.           for I := 0 to Count - 1 do
  555.             with TRxTimerEvent(FEvents[I]) do
  556.               if (Interval mod Self.FInterval) <> 0 then begin
  557.                 Dec(Self.FInterval, Interval mod Self.FInterval);
  558.                 ExitLoop := False;
  559.                 Break;
  560.               end;
  561.         until ExitLoop or (FInterval <= MinInterval);
  562.         if FInterval < MinInterval then FInterval := MinInterval;
  563.       end;
  564.     end;
  565.   end;
  566. end;
  567.  
  568. procedure TRxTimerList.UpdateTimer;
  569. var
  570.   FTimerInterval: Cardinal;
  571. begin
  572.   if not (csDesigning in ComponentState) then begin
  573.     if FInterval <= MaxTimerInterval then FTimerInterval := FInterval
  574.     else
  575.       if (FInterval - FStartInterval) <= MaxTimerInterval then begin
  576.         FTimerInterval := Cardinal(FInterval - FStartInterval);
  577.         FStartInterval := 0;
  578.       end
  579.       else begin
  580.         FTimerInterval := MaxTimerInterval;
  581.         FStartInterval := FStartInterval + MaxTimerInterval;
  582.       end;
  583.     if not (csDesigning in ComponentState) and (FWndHandle <> INVALID_HANDLE_VALUE) then
  584.     begin
  585.       KillTimer(FWndHandle, 1);
  586.       if EnabledCount = 0 then Deactivate
  587.       else if FInterval > 0 then
  588.         if SetTimer(FWndHandle, 1, FTimerInterval, nil) = 0 then begin
  589.           Deactivate;
  590.           raise EOutOfResources.Create(ResStr(SNoTimers));
  591.         end;
  592.     end;
  593.   end;
  594. end;
  595.  
  596. end.