Dbprgrss.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:16k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995, 1996 AO ROSNO             }
  6. {         Copyright (c) 1997 Master-Bank                }
  7. {                                                       }
  8. {*******************************************************}
  9. unit DbPrgrss;
  10. interface
  11. {$I RX.INC}
  12. {$T-}
  13. uses Classes, {$IFDEF WIN32} Bde, {$ELSE} DbiTypes, DbiProcs, {$ENDIF WIN32}
  14.   Controls, DB, DBTables, RxTimer;
  15. type
  16.   TOnMessageChange = procedure(Sender: TObject; const Msg: string) of object;
  17.   TOnPercentChange = procedure(Sender: TObject; PercentDone: Integer) of object;
  18.   TOnProgressEvent = procedure(Sender: TObject; var AbortQuery: Boolean) of object;
  19. {$IFDEF WIN32}
  20.   TOnTraceEvent = procedure(Sender: TObject; Flag: TTraceFlag;
  21.     const Msg: string) of object;
  22. {$ENDIF WIN32}
  23. { TDBProgress }
  24.   TDBProgress = class(TComponent)
  25.   private
  26.     FActive: Boolean;
  27.     FStartTime: Longint;
  28.     FTimer: TRxTimer;
  29.     FWaitCursor: TCursor;
  30.     FGauge: TControl;
  31.     FMessageControl: TControl;
  32.     FStreamedValue: Boolean;
  33.     FGenProgressCallback: TObject;
  34.     FQryProgressCallback: TObject;
  35.     FOnMessageChange: TOnMessageChange;
  36.     FOnPercentChange: TOnPercentChange;
  37.     FOnProgress: TOnProgressEvent;
  38. {$IFDEF WIN32}
  39.     FTraceFlags: TTraceFlags;
  40.     FTraceCallback: TObject;
  41.     FTrace: Boolean;
  42.     FOnTrace: TOnTraceEvent;
  43.     FSessionName: string;
  44.     FSessionLink: TObject;
  45.     procedure SetTrace(Value: Boolean);
  46.     procedure SetTraceFlags(Value: TTraceFlags);
  47.     function TraceCallBack(CBInfo: Pointer): CBRType;
  48.     function GetDBSession: TSession;
  49.     procedure SetSessionName(const Value: string);
  50.     procedure Activate;
  51.     procedure Deactivate;
  52. {$ENDIF WIN32}
  53.     procedure FreeTimer;
  54.     procedure StartTimer;
  55.     procedure TimerExpired(Sender: TObject);
  56.     function GenProgressCallback(CBInfo: Pointer): CBRType;
  57.     function QryProgressCallback(CBInfo: Pointer): CBRType;
  58.     procedure SetActive(Value: Boolean);
  59.     procedure SetPercent(Value: Integer);
  60.     procedure SetMessage(const Value: string);
  61.     procedure SetMessageControl(Value: TControl);
  62.     procedure SetGauge(Value: TControl);
  63.   protected
  64.     procedure Notification(AComponent: TComponent; AOperation: TOperation); override;
  65.     procedure Loaded; override;
  66.   public
  67.     constructor Create(AOwner: TComponent); override;
  68.     destructor Destroy; override;
  69.     function ProgressMsgValue(const Msg: string): Longint;
  70.   published
  71.     property Active: Boolean read FActive write SetActive default True;
  72.     property WaitCursor: TCursor read FWaitCursor write FWaitCursor default crHourGlass;
  73.     property MessageControl: TControl read FMessageControl write SetMessageControl;
  74.     property Gauge: TControl read FGauge write SetGauge;
  75. {$IFDEF WIN32}
  76.     property SessionName: string read FSessionName write SetSessionName;
  77.     property Trace: Boolean read FTrace write SetTrace default False;
  78.     property TraceFlags: TTraceFlags read FTraceFlags write SetTraceFlags default [];
  79.     property OnTrace: TOnTraceEvent read FOnTrace write FOnTrace;
  80. {$ENDIF WIN32}
  81.     property OnMessageChange: TOnMessageChange read FOnMessageChange write FOnMessageChange;
  82.     property OnPercentChange: TOnPercentChange read FOnPercentChange write FOnPercentChange;
  83.     property OnProgress: TOnProgressEvent read FOnProgress write FOnProgress;
  84.   end;
  85. { TDBCallback - for internal use only }
  86. type
  87.   TDBCallbackEvent = function(CBInfo: Pointer): CBRType of object;
  88.   TDBCallbackChain = (dcOnlyOnce, dcChain, dcReplace);
  89.   TDBCallback = class(TObject)
  90.   private
  91.     FOwner: TObject;
  92.     FCBType: CBType;
  93.     FCBBuf: Pointer;
  94.     FCBBufLen: Cardinal;
  95.     FOldCBData: Longint;
  96.     FOldCBBuf: Pointer;
  97.     FOldCBBufLen: Word;
  98.     FOldCBFunc: Pointer;
  99.     FInstalled: Boolean;
  100.     FChain: TDBCallbackChain;
  101.     FCallbackEvent: TDBCallbackEvent;
  102.   protected
  103.     function Invoke(CallType: CBType; var CBInfo: Pointer): CBRType;
  104.   public
  105.     constructor Create(AOwner: TObject; CBType: CBType;
  106.       CBBufSize: Cardinal; CallbackEvent: TDBCallbackEvent;
  107.       Chain: TDBCallbackChain);
  108.     destructor Destroy; override;
  109.   end;
  110. implementation
  111. uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, Str16, {$ENDIF WIN32}
  112.   Forms, SysUtils, StdCtrls, Dialogs, MaxMin, RxPrgrss, BdeUtils;
  113. const
  114.   cbQRYPROGRESS = cbRESERVED4;
  115. { TDBCallback }
  116. function BdeCallBack(CallType: CBType; Data: Longint;
  117.   {$IFNDEF WIN32} var {$ENDIF} CBInfo: Pointer): CBRType;
  118.   {$IFDEF WIN32} stdcall; {$ELSE} export; {$ENDIF WIN32}
  119. begin
  120.   if Data <> 0 then begin
  121.     Result := TDBCallback(Data).Invoke(CallType, CBInfo);
  122.   end
  123.   else Result := cbrUSEDEF;
  124. end;
  125. constructor TDBCallback.Create(AOwner: TObject; CBType: CBType;
  126.   CBBufSize: Cardinal; CallbackEvent: TDBCallbackEvent;
  127.   Chain: TDBCallbackChain);
  128. begin
  129.   FOwner := AOwner;
  130.   FCBType := CBType;
  131.   FCallbackEvent := CallbackEvent;
  132. {$IFDEF WIN32}
  133.   DbiGetCallBack(nil, FCBType, @FOldCBData, @FOldCBBufLen, @FOldCBBuf,
  134.     pfDBICallBack(FOldCBFunc));
  135. {$ELSE}
  136.   DbiGetCallBack(nil, FCBType, FOldCBData, FOldCBBufLen, FOldCBBuf,
  137.     @FOldCBFunc);
  138. {$ENDIF}
  139.   FChain := Chain;
  140.   if not Assigned(FOldCBFunc) then FOldCBBufLen := 0;
  141.   if not Assigned(FOldCBFunc) or (FChain in [dcChain, dcReplace]) then begin
  142.     FCBBufLen := Max(CBBufSize, FOldCBBufLen);
  143.     FCBBuf := AllocMem(FCBBufLen);
  144.     Check(DbiRegisterCallback(nil, FCBType, Longint(Self), FCBBufLen,
  145.       FCBBuf, BdeCallBack));
  146.     FInstalled := True;
  147.   end;
  148. end;
  149. destructor TDBCallback.Destroy;
  150. begin
  151.   if FInstalled then begin
  152.     if Assigned(FOldCBFunc) and (FChain = dcChain) then
  153.     try
  154.       DbiRegisterCallback(nil, FCBType, FOldCBData, FOldCBBufLen,
  155.         FOldCBBuf, pfDBICallback(FOldCBFunc));
  156.     except
  157.     end
  158.     else DbiRegisterCallback(nil, FCBType, 0, 0, nil, nil);
  159.   end;
  160.   if FCBBuf <> nil then FreeMem(FCBBuf, FCBBufLen);
  161. end;
  162. function TDBCallback.Invoke(CallType: CBType; var CBInfo: Pointer): CBRType;
  163. begin
  164.   Result := cbrUSEDEF;
  165.   if CallType = FCBType then
  166.   try
  167. {$IFDEF WIN32}
  168.     Result := FCallbackEvent(CBInfo);
  169. {$ELSE}
  170.     Result := FCallbackEvent(@CBInfo);
  171. {$ENDIF}
  172.   except
  173.     Application.HandleException(Self);
  174.   end;
  175.   if Assigned(FOldCBFunc) and (FChain = dcChain) then
  176.     Result := pfDBICallBack(FOldCBFunc)(CallType, FOldCBData, CBInfo);
  177. end;
  178. { ProgressList }
  179. const
  180.   ProgressList: TList = nil;
  181. procedure SetWaitCursor;
  182. begin
  183. {$IFDEF WIN32}
  184.   if (GetCurrentThreadID = MainThreadID) then
  185. {$ENDIF}
  186.     Screen.Cursor := TDBProgress(ProgressList.Items[
  187.       ProgressList.Count - 1]).WaitCursor;
  188. end;
  189. procedure AddProgress(Progress: TDBProgress);
  190. begin
  191.   if ProgressList = nil then ProgressList := TList.Create;
  192.   if ProgressList.IndexOf(Progress) = -1 then ProgressList.Add(Progress);
  193. end;
  194. procedure RemoveProgress(Progress: TDBProgress);
  195. begin
  196.   if ProgressList <> nil then begin
  197.     ProgressList.Remove(Progress);
  198.     if ProgressList.Count = 0 then begin
  199.       ProgressList.Free;
  200.       ProgressList := nil;
  201.       Screen.Cursor := crDefault;
  202.     end;
  203.   end;
  204. end;
  205. {$IFDEF WIN32}
  206. { TSessionLink }
  207. type
  208.   TSessionLink = class(TDatabase)
  209.   private
  210.     FProgress: TDBProgress;
  211.   public
  212.     destructor Destroy; override;
  213.   end;
  214. destructor TSessionLink.Destroy;
  215. begin
  216.   if FProgress <> nil then begin
  217.     FProgress.FSessionLink := nil;
  218.     FProgress.Trace := False;
  219.     FProgress.Active := False;
  220.   end;
  221.   inherited Destroy;
  222. end;
  223. {$ENDIF WIN32}
  224. { TDBProgress }
  225. constructor TDBProgress.Create(AOwner: TComponent);
  226. begin
  227.   inherited Create(AOwner);
  228.   FWaitCursor := crHourGlass;
  229.   FActive := True;
  230. end;
  231. destructor TDBProgress.Destroy;
  232. begin
  233. {$IFDEF WIN32}
  234.   FOnTrace := nil;
  235.   Trace := False;
  236. {$ENDIF}
  237.   Active := False;
  238.   FreeTimer;
  239.   FTimer.Free;
  240.   inherited Destroy;
  241. end;
  242. procedure TDBProgress.Loaded;
  243. begin
  244.   inherited Loaded;
  245.   FStreamedValue := True;
  246.   try
  247.     SetActive(FActive);
  248. {$IFDEF WIN32}
  249.     SetTrace(FTrace);
  250. {$ENDIF WIN32}
  251.   finally
  252.     FStreamedValue := False;
  253.   end;
  254. end;
  255. procedure TDBProgress.TimerExpired(Sender: TObject);
  256. begin
  257.   FreeTimer;
  258.   SetPercent(0);
  259.   SetMessage('');
  260. end;
  261. procedure TDBProgress.FreeTimer;
  262. begin
  263.   if FTimer <> nil then begin
  264.     FTimer.Enabled := False;
  265.     FStartTime := 0;
  266.   end;
  267.   Screen.Cursor := crDefault;
  268.   SetCursor(Screen.Cursors[crDefault]); { force update cursor }
  269. end;
  270. procedure TDBProgress.StartTimer;
  271. begin
  272.   if (FTimer = nil) then begin
  273.     FTimer := TRxTimer.Create(Self);
  274.     FTimer.Interval := 500;
  275.   end;
  276.   with FTimer do begin
  277.     if not Enabled then FStartTime := GetTickCount;
  278.     OnTimer := TimerExpired;
  279.     Enabled := True;
  280.   end;
  281. end;
  282. procedure TDBProgress.SetPercent(Value: Integer);
  283. begin
  284.   if Gauge <> nil then begin
  285.     SetProgressMax(Gauge, 100);
  286.     SetProgressValue(Gauge, Value);
  287.   end;
  288.   if Assigned(FOnPercentChange) then FOnPercentChange(Self, Value);
  289. end;
  290. procedure TDBProgress.SetMessage(const Value: string);
  291. begin
  292.   if MessageControl <> nil then begin
  293.     TLabel(MessageControl).Caption := Value;
  294.     MessageControl.Refresh;
  295.   end;
  296.   if Assigned(FOnMessageChange) then FOnMessageChange(Self, Value);
  297. end;
  298. procedure TDBProgress.SetActive(Value: Boolean);
  299. begin
  300.   if (FActive <> Value) or FStreamedValue then begin
  301.     if not (csDesigning in ComponentState) then begin
  302.       if Value then AddProgress(Self) else RemoveProgress(Self);
  303.       if (FGenProgressCallback = nil) and Value then begin
  304. {$IFDEF WIN32}
  305.         Activate;
  306. {$ENDIF}
  307.         FGenProgressCallback := TDBCallback.Create(Self, cbGENPROGRESS,
  308.           Max(SizeOf(CBPROGRESSDesc), SizeOf(DBIPATH) + SizeOf(Integer) * 4),
  309.           GenProgressCallback, dcChain);
  310.         FQryProgressCallback := TDBCallback.Create(Self, cbQRYPROGRESS,
  311.           SizeOf(DBIQryProgress), QryProgressCallback, dcChain);
  312.       end
  313.       else if not Value and (FGenProgressCallback <> nil) then begin
  314. {$IFDEF WIN32}
  315.         Sessions.CurrentSession := GetDBSession;
  316. {$ENDIF}
  317.         FGenProgressCallback.Free;
  318.         FGenProgressCallback := nil;
  319.         FQryProgressCallback.Free;
  320.         FQryProgressCallback := nil;
  321.         FreeTimer;
  322. {$IFDEF WIN32}
  323.         if not Trace then Deactivate;
  324. {$ENDIF}
  325.       end;
  326.     end;
  327.     FActive := Value;
  328.   end;
  329. end;
  330. {$IFDEF WIN32}
  331. procedure TDBProgress.Activate;
  332. var
  333.   S: TSession;
  334. begin
  335.   if FSessionLink = nil then begin
  336.     S := Sessions.List[SessionName];
  337.     S.Open;
  338.     Sessions.CurrentSession := S;
  339.     FSessionLink := TSessionLink.Create(S);
  340.     try
  341.       TSessionLink(FSessionLink).Temporary := True;
  342.       TSessionLink(FSessionLink).KeepConnection := False;
  343.       TSessionLink(FSessionLink).FProgress := Self;
  344.     except
  345.       FSessionLink.Free;
  346.       FSessionLink := nil;
  347.       raise;
  348.     end;
  349.   end
  350.   else Sessions.CurrentSession := TDatabase(FSessionLink).Session;
  351. end;
  352. procedure TDBProgress.Deactivate;
  353. begin
  354.   if FSessionLink <> nil then begin
  355.     TSessionLink(FSessionLink).FProgress := nil;
  356.     FSessionLink.Free;
  357.     FSessionLink := nil;
  358.   end;
  359. end;
  360. function TDBProgress.GetDBSession: TSession;
  361. begin
  362.   Result := Sessions.FindSession(SessionName);
  363.   if Result = nil then
  364. {$IFDEF RX_D3}
  365.     Result := DBTables.Session;
  366. {$ELSE}
  367.     Result := DB.Session;
  368. {$ENDIF}
  369. end;
  370. procedure TDBProgress.SetSessionName(const Value: string);
  371. var
  372.   KeepActive, KeepTrace: Boolean;
  373. begin
  374.   if Value <> SessionName then begin
  375.     if not (csDesigning in ComponentState) then begin
  376.       KeepActive := Active;
  377.       KeepTrace := Trace;
  378.       Active := False;
  379.       Trace := False;
  380.       FSessionName := Value;
  381.       Active := KeepActive;
  382.       Trace := KeepTrace;
  383.     end
  384.     else FSessionName := Value;
  385.   end;
  386. end;
  387. procedure TDBProgress.SetTrace(Value: Boolean);
  388. begin
  389.   if (FTrace <> Value) or (FStreamedValue and Value) then begin
  390.     if not (csDesigning in ComponentState) then begin
  391.       if Value then begin
  392.         Activate;
  393.         GetDBSession.TraceFlags := FTraceFlags;
  394.         FTraceCallback := TDBCallback.Create(Self, cbTRACE,
  395.           smTraceBufSize, TraceCallBack, dcReplace);
  396.       end
  397.       else if (FTraceCallback <> nil) then begin
  398.         Sessions.CurrentSession := GetDBSession;
  399.         FTraceCallback.Free;
  400.         FTraceCallback := nil;
  401.         if not Active then Deactivate;
  402.       end;
  403.       FTrace := (FTraceCallback <> nil);
  404.     end
  405.     else FTrace := Value;
  406.   end;
  407. end;
  408. procedure TDBProgress.SetTraceFlags(Value: TTraceFlags);
  409. begin
  410.   FTraceFlags := Value;
  411.   if Trace then GetDBSession.TraceFlags := FTraceFlags;
  412. end;
  413. function TDBProgress.TraceCallBack(CBInfo: Pointer): CBRType;
  414. var
  415.   CurFlag: TTraceFlag;
  416. begin
  417.   Result := cbrUSEDEF;
  418.   if Trace and Assigned(FOnTrace) then begin
  419.     case PTraceDesc(CBInfo)^.eTraceCat of
  420.       traceQPREPARE: CurFlag := tfQPrepare;
  421.       traceQEXECUTE: CurFlag := tfQExecute;
  422.       traceERROR: CurFlag := tfError;
  423.       traceSTMT: CurFlag := tfStmt;
  424.       traceCONNECT: CurFlag := tfConnect;
  425.       traceTRANSACT: CurFlag := tfTransact;
  426.       traceBLOB: CurFlag := tfBlob;
  427.       traceMISC: CurFlag := tfMisc;
  428.       traceVENDOR: CurFlag := tfVendor;
  429. {$IFDEF RX_D3}
  430.       traceDATAIN: CurFlag := tfDataIn;
  431.       traceDATAOUT: CurFlag := tfDataOut;
  432. {$ENDIF RX_D3}
  433.       else Exit;
  434.     end;
  435.     if (CurFlag in TraceFlags) then
  436.       FOnTrace(Self, CurFlag, StrPas(PTraceDesc(CBInfo)^.pszTrace));
  437.   end;
  438. end;
  439. {$ENDIF WIN32}
  440. procedure TDBProgress.SetMessageControl(Value: TControl);
  441. begin
  442.   FMessageControl := Value;
  443. {$IFDEF WIN32}
  444.   if Value <> nil then Value.FreeNotification(Self);
  445. {$ENDIF}
  446. end;
  447. procedure TDBProgress.SetGauge(Value: TControl);
  448. begin
  449.   FGauge := Value;
  450. {$IFDEF WIN32}
  451.   if Value <> nil then Value.FreeNotification(Self);
  452. {$ENDIF}
  453. end;
  454. procedure TDBProgress.Notification(AComponent: TComponent; AOperation: TOperation);
  455. begin
  456.   inherited Notification(AComponent, AOperation);
  457.   if AOperation = opRemove then begin
  458.     if AComponent = Gauge then Gauge := nil
  459.     else if AComponent = MessageControl then MessageControl := nil;
  460.   end;
  461. end;
  462. function TDBProgress.GenProgressCallback(CBInfo: Pointer): CBRType;
  463. var
  464.   CallInfo: pCBPROGRESSDesc absolute CBInfo;
  465.   AbortOp: Boolean;
  466. begin
  467.   Result := cbrUSEDEF;
  468.   StartTimer;
  469.   if (FTimer <> nil) and FTimer.Enabled {and (GetTickCount > FStartTime)} then
  470.     SetWaitCursor;
  471.   if Assigned(FOnProgress) then begin
  472.     AbortOp := False;
  473.     FOnProgress(Self, AbortOp);
  474.     if AbortOp then Result := cbrABORT;
  475.   end;
  476.   if CallInfo^.iPercentDone >= 0 then SetPercent(CallInfo^.iPercentDone)
  477.   else SetMessage(StrPas(CallInfo^.szMsg));
  478. end;
  479. function TDBProgress.QryProgressCallback(CBInfo: Pointer): CBRType;
  480. var
  481.   CallInfo: pDBIQryProgress absolute CBInfo;
  482.   AbortOp: Boolean;
  483.   PcntDone: Double;
  484. begin
  485.   Result := cbrUSEDEF;
  486.   StartTimer;
  487.   {if (FTimer <> nil) and FTimer.Enabled then SetWaitCursor;}
  488.   if Assigned(FOnProgress) then begin
  489.     AbortOp := False;
  490.     FOnProgress(Self, AbortOp);
  491.     if AbortOp then Result := cbrABORT;
  492.   end;
  493.   with CallInfo^ do begin
  494.     PcntDone := (stepsCompleted / Max(1, stepsInQry)) *
  495.       (elemCompleted / Max(1, totElemInStep));
  496.   end;
  497.   SetPercent(Round(PcntDone * 100));
  498. end;
  499. function TDBProgress.ProgressMsgValue(const Msg: string): Longint;
  500. begin
  501.   if Msg <> '' then
  502.     Result := StrToIntDef(Trim(Copy(Msg, Pos(':', Msg) + 1, MaxInt)), -1)
  503.   else Result := -1;
  504. end;
  505. end.