uconnprogress.pas

来自「FMA is a free1 powerful phone editing to」· PAS 代码 · 共 496 行

PAS
496
字号
unit uConnProgress;

{
*******************************************************************************
* Descriptions: Main Unit for FMA
* $Source: /cvsroot/fma/fma/uConnProgress.pas,v $
* $Locker:  $
*
* Todo:
*
* Change Log:
* $Log: uConnProgress.pas,v $
*
}

interface

uses
  Windows, Variants, 
  TntWindows, Messages, SysUtils, TntSysUtils, Classes, TntClasses, Graphics, TntGraphics, Controls, TntControls, Forms, TntForms,
  Dialogs, TntDialogs, ExtCtrls, TntExtCtrls, StdCtrls, TntStdCtrls, ComCtrls, TntComCtrls, UniTntCtrls, Buttons, TntButtons,
  SEProgress, jpeg, VirtualTrees, StrUtils;

type
  TTaskData = record
    Captions: TTntStringList;
    ProgressBar: TSEProgress;
    ListNode: PVirtualNode;
    Initialized: boolean;
  end;
  PTaskData = ^TTaskData;

  { Do not create/destroy this form by yourself!!!
    Instead use two methods bellow:
      - GetProgressDialog
      - FreeProgressDialog }
  TfrmConnect = class(TTntForm)
    AbortButton: TTntButton;
    Timer2: TTimer;
    Timer1: TTimer;
    HideButton: TTntButton;
    ListTasks: TVirtualDrawTree;
    cbDontShow: TTntCheckBox;
    procedure AbortButtonClick(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure HideButtonClick(Sender: TObject);
    procedure ListTasksFreeNode(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure ListTasksDrawNode(Sender: TBaseVirtualTree;
      const PaintInfo: TVTPaintInfo);
    procedure FormShow(Sender: TObject);
    procedure FormHide(Sender: TObject);
  private
    { Private declarations }
    procedure NotifyStatusBar;
    function HasUnknownMaxTask: boolean;
    function GetCurrentTask: PTaskData;
    function GetTask(ID: Integer): PTaskData;
    function Get_TaskID: Integer;
  protected
    procedure CreateTask(AName: WideString; MaxProgress: Integer = -1);
    procedure DeleteCurrentTask;
  public
    { Public declarations }
    procedure ShowProgress(Delayed: boolean = False);

    procedure Initialize(MaxProgress: integer; Descr: WideString = '');
    procedure InitializeLoop(Descr: WideString = ''); // Unknown Max
    procedure SetDescr(Descr: WideString; TaskID: Integer = -1);
    procedure IncProgress(Delta: integer; TaskID: Integer = -1);

    procedure SetMaxProgress(MaxProgress: integer);
    procedure ClearMaxProgress;

    property CurrentTaskID: Integer read Get_TaskID;
  end;

var
  frmConnect: TfrmConnect;

{ Returns the current progress form and creates a new progres task into it.
  WARNING!!! Should not free it manually! Instead call FreeProgressDialog! }
function GetProgressDialog(AllowCreateNew: Boolean = True): TfrmConnect;

{ Release progress form usage. }
procedure FreeProgressDialog;

implementation

uses
  gnugettext, gnugettexthelpers,
  Unit1, Types;

{$R *.dfm}

resourcestring
  sDefaultTaskName = 'Working...';

const
  ProgressUsage: integer = 0;

function GetProgressDialog(AllowCreateNew: Boolean): TfrmConnect;
var
  i: integer;
begin
  Result := nil;
  for i := 0 to Screen.FormCount-1 do
    if Screen.Forms[i] is TfrmConnect then begin
      Result := Screen.Forms[i] as TfrmConnect;
      break;
    end;
  if AllowCreateNew and not Assigned(Result) then begin
    frmConnect := TfrmConnect.Create(Application);
    Result := frmConnect;
  end;
  if Assigned(Result) then begin
    Result.CreateTask(sDefaultTaskName);
    inc(ProgressUsage);
  end;
end;

procedure FreeProgressDialog;
begin
  if Assigned(frmConnect) then begin
    frmConnect.DeleteCurrentTask;
    dec(ProgressUsage);
    if ProgressUsage = 0 then begin
      frmConnect.Free;
      frmConnect := nil;
    end;
  end;
end;

{ TfrmConnect }

procedure TfrmConnect.Initialize(MaxProgress: integer; Descr: WideString);
var
  t: PTaskData;
begin
  t := GetCurrentTask;
  if not Assigned(t) then exit;

  if Descr <> '' then
    t^.Captions.Text := Descr;
  t^.ProgressBar.Position := 0;
  t^.ProgressBar.Max := MaxProgress;
  if Visible then
    ListTasks.InvalidateNode(t^.ListNode);
  Timer1.Enabled := HasUnknownMaxTask;
end;

procedure TfrmConnect.AbortButtonClick(Sender: TObject);
begin
  Form1.ActionConnectionAbort.Execute;
end;

procedure TfrmConnect.SetDescr(Descr: WideString; TaskID: Integer = -1);
var
  t: PTaskData;
begin
  if TaskID = -1 then
    t := GetCurrentTask
  else
    t := GetTask(TaskID);
  if not Assigned(t) then exit;

  t^.Captions.Text := Descr;
  if Visible then
    ListTasks.InvalidateNode(t^.ListNode);
end;

procedure TfrmConnect.IncProgress(Delta: integer; TaskID: Integer = -1);
var
  t: PTaskData;
begin
  if TaskID = -1 then
    t := GetCurrentTask
  else
    t := GetTask(TaskID);
  if not Assigned(t) then exit;

  t^.ProgressBar.Position := t^.ProgressBar.Position + Delta;
  if Visible then
    ListTasks.InvalidateNode(t^.ListNode);
  NotifyStatusBar;
end;

procedure TfrmConnect.ShowProgress(Delayed: boolean = False);
var
  t: PTaskData;
begin
  t := GetCurrentTask;
  if not Assigned(t) then exit;

  Form1.SetTaskPercentage(0); // show indicator in status bar at start/zero position
  if Form1.CanShowProgressDialog then
    if Delayed and not Visible then
      Timer2.Enabled := True
    else
      Timer2Timer(nil);
end;

procedure TfrmConnect.Timer2Timer(Sender: TObject);
begin
  Timer2.Enabled := False;
  Show;
  Update;
end;

procedure TfrmConnect.FormCreate(Sender: TObject);
begin
  gghTranslateComponent(self);

  //Image1.Picture.Assign(Form1.CommonBitmaps.Bitmap[1]);
  ListTasks.NodeDataSize := SizeOf(TTaskData);
end;

procedure TfrmConnect.NotifyStatusBar;
var
  t: PTaskData;
begin
  t := GetCurrentTask;
  if not Assigned(t) then exit;

  with t^.ProgressBar do
    Form1.SetTaskPercentage(Position,Max,UnknownMax);
end;

procedure TfrmConnect.FormDestroy(Sender: TObject);
begin
  Timer2.Enabled := False;
  Timer1.Enabled := False;
  Form1.SetTaskPercentage(-1); // hide indicator in status bar
  ListTasks.Clear;
end;

procedure TfrmConnect.Timer1Timer(Sender: TObject);
const
  Sem: boolean = False;
var
  t: PTaskData;
  i,k: Integer;
begin
  if not Sem then begin
    Sem := True;
    k := ListTasks.ChildCount[nil]-1;
    for i := k downto 0 do begin
      t := GetTask(i);
      if Assigned(t) and t^.ProgressBar.UnknownMax then begin
        t^.ProgressBar.StepForward;
        if Visible then
          ListTasks.InvalidateNode(t^.ListNode);
        if i = k then
          NotifyStatusBar;
      end;
    end;
    Sem := False;
  end;
end;

procedure TfrmConnect.InitializeLoop(Descr: WideString);
var
  t: PTaskData;
begin
  t := GetCurrentTask;
  if not Assigned(t) then exit;

  if Descr <> '' then
    t^.Captions.Text := Descr;
  t^.ProgressBar.Position := 0;
  t^.ProgressBar.UnknownMax := True;
  if Visible then
    ListTasks.InvalidateNode(t^.ListNode);
  Timer1.Enabled := HasUnknownMaxTask;
end;

procedure TfrmConnect.CreateTask(AName: WideString; MaxProgress: Integer);
var
  t: PTaskData;
  n: PVirtualNode;
begin
  ListTasks.NodeDataSize := SizeOf(TTaskData);
  n := ListTasks.AddChild(nil);
  t := ListTasks.GetNodeData(n);
  try
    t^.ListNode := n;
    t^.Captions := TTntStringList.Create;
    t^.Captions.Text := AName;
    t^.ProgressBar := TSEProgress.Create(Self);
    t^.ProgressBar.Visible := False; // hide outside parent visible area
    t^.ProgressBar.Parent := ListTasks;
    t^.ProgressBar.Frame := 1;
    t^.ProgressBar.ShowBorder := False;
    t^.ProgressBar.BarColor := clHighlight;
    t^.ProgressBar.Color := clDkGray;
    t^.ProgressBar.UnknownWidth := 25;
    if MaxProgress <> -1 then
      t^.ProgressBar.Max := MaxProgress;
    t^.Initialized := True;  
    Timer1.Enabled := HasUnknownMaxTask;
  except
    ListTasks.DeleteNode(n);
  end;
end;

procedure TfrmConnect.DeleteCurrentTask;
var
  n: PVirtualNode;
begin
  n := ListTasks.GetLast(nil);
  if Assigned(n) then begin
    ListTasks.DeleteNode(n);
    Timer1.Enabled := HasUnknownMaxTask;
  end;
end;

function TfrmConnect.GetCurrentTask: PTaskData;
begin
  Result := GetTask(ListTasks.ChildCount[nil]-1);
end;

procedure TfrmConnect.ClearMaxProgress;
var
  t: PTaskData;
begin
  t := GetCurrentTask;
  if not Assigned(t) then exit;

  t^.ProgressBar.UnknownMax := True;
end;

procedure TfrmConnect.SetMaxProgress(MaxProgress: integer);
var
  t: PTaskData;
begin
  t := GetCurrentTask;
  if not Assigned(t) then exit;

  t^.ProgressBar.Max := MaxProgress;
end;

function TfrmConnect.HasUnknownMaxTask: boolean;
var
  t: PTaskData;
  i: Integer;
begin
  Result := False;
  for i := ListTasks.ChildCount[nil]-1 downto 0 do begin
    t := GetTask(i);
    if Assigned(t) and t^.ProgressBar.UnknownMax then begin
      Result := True;
      break;
    end;
  end;
end;

procedure TfrmConnect.HideButtonClick(Sender: TObject);
begin
  Hide;
end;

procedure TfrmConnect.ListTasksFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  t: PTaskData;
begin
  t := ListTasks.GetNodeData(Node);
  if Assigned(t) then begin
    t^.Initialized := False;
    if Assigned(t^.Captions) then begin
      t^.Captions.Text := '';
      t^.Captions.Free;
      t^.Captions := nil;
    end;
    if Assigned(t^.ProgressBar) then begin
      t^.ProgressBar.Parent := nil;
      t^.ProgressBar.Free;
      t^.ProgressBar := nil;
    end;
  end;
end;

procedure TfrmConnect.ListTasksDrawNode(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo);
const
  Sem: boolean = False;
var
  t: PTaskData;
  w: WideString;
  i: Integer;
  function GetTextLeft(AText: WideString): Integer;
  begin
    { BiDi support here }
    if IsRightToLeft then begin
      Result := PaintInfo.ContentRect.Right-PaintInfo.Canvas.TextWidth(AText)-ListTasks.TextMargin;
    end
    else
      Result := PaintInfo.ContentRect.Left+ListTasks.TextMargin-2;
  end;
begin
  if Sem then exit; // avoid StackOverflow exception and application shutdown issue !!! SOLVED
  Sem := True;
  try
    PaintInfo.Canvas.FillRect(PaintInfo.CellRect);
    t := ListTasks.GetNodeData(PaintInfo.Node);
    if not Assigned(t) or not t^.Initialized then
      exit;

    if PaintInfo.Column = 0 then begin
      with PaintInfo do begin
        Canvas.Font.Assign(ListTasks.Font);
        if Canvas.Brush.Color = clHighlight then
          Canvas.Font.Color := clHighlightText
        else
          Canvas.Font.Color := clWindowText;
        { Paint text }
        if t^.Captions.Count >= 1 then
          Canvas.TextOut(GetTextLeft(t^.Captions[0]),ContentRect.Top+2,t^.Captions[0]);
        if Canvas.Font.Color = clWindowText then
          Canvas.Font.Color := clDkGray;
        w := '';
        if t^.Captions.Count >= 2 then begin
          w := t^.Captions[1];
          for i := 2 to t^.Captions.Count-1 do
            w := w + ' ' + t^.Captions[i];
        end
        else
        if not t^.ProgressBar.UnknownMax and (t^.ProgressBar.Max <> 0) then
          w := WideFormat(_('%d%% ready'),[100 * t^.ProgressBar.Position div t^.ProgressBar.Max])
        else
          if WideCompareStr(sDefaultTaskName,t^.Captions[0]) <> 0 then w := sDefaultTaskName;
        if w <> '' then
          Canvas.TextOut(GetTextLeft(w),ContentRect.Top+15,w);
      end;
    end
    else
    if PaintInfo.Column = 1 then begin
      { Paint progress bar }
      t^.ProgressBar.Width := PaintInfo.ContentRect.Right-PaintInfo.ContentRect.Left-ListTasks.TextMargin-4;
      t^.ProgressBar.Height := ListTasks.DefaultNodeHeight-17;
      { PaintTo() will trigger reccursive call to this handler, so we use a Semafor }
      t^.ProgressBar.PaintTo(PaintInfo.Canvas,PaintInfo.ContentRect.Left+2,PaintInfo.ContentRect.Top+8);
    end;
  finally
    Sem := False;
  end;
end;

procedure TfrmConnect.FormShow(Sender: TObject);
begin
  cbDontShow.Checked := False;
  HideButton.SetFocus;
end;

procedure TfrmConnect.FormHide(Sender: TObject);
begin
  if cbDontShow.Checked then begin
    Form1.FProgressIndicatorOnly := True;
    Form1.FormStorage1.StoredValue['Progress Indicator'] := True; // do not localize
  end;
end;

function TfrmConnect.Get_TaskID: Integer;
var
  n: PVirtualNode;
begin
  Result := -1;
  n := ListTasks.GetLast(nil);
  if Assigned(n) then
    Result := n.Index;
end;

function TfrmConnect.GetTask(ID: Integer): PTaskData;
var
  Node: PVirtualNode;
  Data: PTaskData;
begin
  Result := nil;
  if ID < 0 then exit;
  Node := ListTasks.GetFirst;
  while Assigned(Node) do begin
    if Node.Index = cardinal(ID) then begin
      Data := ListTasks.GetNodeData(Node);
      if Assigned(Data) and Data^.Initialized then
        Result := Data;
      break;
    end;
    Node := ListTasks.GetNext(Node);
  end;
end;

end.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?