Menu

Commit [r3025]  Maximize  Restore  History

Added OnProgress event to TFileUpdater that is used in TDBUpdateDlg, via TDBUpdateMgr, to display a progress bar while database files are being updated.

Fixes bug #79 "Update From Web Dialogue appears to freeze when updating database" (https://sourceforge.net/p/codesnip/bugs/79/)

delphidabbler 2013-05-12

changed /branches/4/4.5/Src/FmDBUpdateDlg.pas
changed /branches/4/4.5/Src/UDBUpdateMgr.pas
changed /branches/4/4.5/Src/UFileUpdater.pas
/branches/4/4.5/Src/FmDBUpdateDlg.pas Diff Switch to side-by-side view
--- a/branches/4/4.5/Src/FmDBUpdateDlg.pas
+++ b/branches/4/4.5/Src/FmDBUpdateDlg.pas
@@ -94,9 +94,9 @@
     procedure UpdateStatusHandler(Sender: TObject; Status: TDBUpdateMgr.TStatus;
       var Cancel: Boolean);
 
-    ///  <summary>Handles OnProgress event triggered by the update manager when
-    ///  downloading the database. Displays progress in a progress bar.
-    ///  </summary>
+    ///  <summary>Handles OnProgress event triggered by the database update
+    ///  manager when downloading the database. Displays progress in a progress
+    ///  bar.</summary>
     ///  <param name="Sender">TObject [in] Object triggering event.</param>
     ///  <param name="BytesReceived">Int64 [in] Total number of bytes received
     ///  to date.</param>
@@ -109,6 +109,19 @@
     ///  the download completes.</remarks>
     procedure DownloadProgressHandler(Sender: TObject; const BytesReceived,
       BytesExpected: Int64; var Cancel: Boolean);
+
+    ///  <summary>Handles OnProgress event triggered by the file updater when
+    ///  when downloading the database. Displays progress in a progress bar.
+    ///  </summary>
+    ///  <param name="Sender">TObject [in] Object triggering event.</param>
+    ///  <param name="Progress">Bytes [in] Pecentage progress to date.</param>
+    ///  <param name="Cancel">Boolean [in,out] Flag that event handler can set
+    ///  True to abort the update.</param>
+    ///  <remarks>NOTE: Setting cancel to True does not cancel the file update,
+    ///  which runs to completion. Instead the update process is cancelled after
+    ///  the file update completes.</remarks>
+    procedure FileUpdateProgressHandler(Sender: TObject; const Percent: Byte;
+      var Cancel: Boolean);
 
     ///  <summary>Displays the given progress message.</summary>
     procedure ProgressMsg(const Msg: string);
@@ -211,6 +224,7 @@
   try
     fUpdateMgr.OnStatus := UpdateStatusHandler;
     fUpdateMgr.OnDownloadProgress := DownloadProgressHandler;
+    fUpdateMgr.OnFileUpdateProgress := FileUpdateProgressHandler;
     // Update control visibility
     lblUpdateFromWeb.Visible := False;
     lblError.Visible := False;
@@ -286,6 +300,16 @@
     end;
 end;
 
+procedure TDBUpdateDlg.FileUpdateProgressHandler(Sender: TObject;
+  const Percent: Byte; var Cancel: Boolean);
+begin
+  if Percent = 0 then
+    fProgressBarMgr.Max := 100;
+  fProgressBarMgr.Position := Percent;
+  Cancel := fCancelled;
+  Application.ProcessMessages;
+end;
+
 procedure TDBUpdateDlg.FormCloseQuery(Sender: TObject;
   var CanClose: Boolean);
 begin
@@ -385,13 +409,19 @@
       ProgressMsg(sDownloaded);
     end;
     usUpdating:
-      ProgressMsg(sUpdating);
+    begin
+      ProgressMsg(sUpdating + '  ');
+      fProgressBarMgr.Show(edProgress.Lines.Count - 1);
+    end;
     usNoUpdate:
       ProgressMsg(sUpToDate);
     usLogOff:
       ProgressMsg(sLoggingOff);
     usCompleted:
+    begin
+      fProgressBarMgr.Hide;
       ProgressMsg(sCompleted);
+    end;
     usCancelled:
       ProgressMsg(sCancelled);
   end;
/branches/4/4.5/Src/UDBUpdateMgr.pas Diff Switch to side-by-side view
--- a/branches/4/4.5/Src/UDBUpdateMgr.pas
+++ b/branches/4/4.5/Src/UDBUpdateMgr.pas
@@ -90,11 +90,21 @@
       ///  <param name="BytesHandled">Int64 [in] Number of bytes downloaded so
       ///  far.</param>
       ///  <param name="TotalBytes">Int64 [in] Total number of bytes to be
-      ///  downloaded.</param>///////////
+      ///  downloaded.</param>
       ///  <param name="Cancel">Boolean [in,out] Flag that event handler can set
       ///  True to abort the update.</param>
       TDownloadEvent = procedure(Sender: TObject; const BytesHandled,
         TotalBytes: Int64; var Cancel: Boolean) of object;
+    type
+      ///  <summary>Type of event triggered to report progress when updating
+      ///  local database files.</summary>
+      ///  <param name="Sender">TObject [in] Object that triggered event.
+      ///  </param>
+      ///  <param name="Progress">Bytes [in] Pecentage progress to date.</param>
+      ///  <param name="Cancel">Boolean [in,out] Flag that event handler can set
+      ///  True to abort the update.</param>
+      TProgressEvent = procedure(Sender: TObject; const Progress: Byte;
+        var Cancel: Boolean) of object;
   strict private
     var
       ///  <summary>Flag that indicates if an update request was cancelled.
@@ -114,19 +124,30 @@
       fOnStatus: TStatusEvent;
       ///  <summary>Event handler for OnDownloadProgress event.</summary>
       fOnDownloadProgress: TDownloadEvent;
+      ///  <summary>Event handler for OnFileUpdateProgress event.</summary>
+      fOnFileUpdateProgress: TProgressEvent;
       ///  <summary>Information specific to the code using this object.
       ///  </summary>
       fCallerInfo: string;
 
-    ///  <summary>Handles database download manager's OnPregress event.
+    ///  <summary>Handles database download manager's OnProgress event.
     ///  </summary>
     ///  <param name="Sender">TObject [in] Object that triggered event.</param>
     ///  <param name="BytesToDate">Int64 [in] Number of bytes downloaded so
     ///  far.</param>
     ///  <param name="ExpectedBytes">Int64 [in] Total number of bytes to be
     ///  downloaded.</param>
-    procedure DownloadProgresshandler(Sender: TObject; const BytesToDate,
+    procedure DownloadProgressHandler(Sender: TObject; const BytesToDate,
       ExpectedBytes: Int64);
+
+    ///  <summary>Handles file updater's OnProgress event.</summary>
+    ///  <param name="Sender">TObject [in] Object that triggered event.</param>
+    ///  <param name="FilesHandled">Cardinal [in] Number of files updated to
+    ///  date.</param>
+    ///  <param name="TotalFiles">Cardinal [in] Total number of files to be
+    ///  updated.</param>
+    procedure FileUpdateProgressHandler(Sender: TObject; const AFilesHandled,
+      ATotalFiles: Cardinal);
 
     ///  <summary>Returns the number of files in the local copy of the Code
     ///  Snippets database.</summary>
@@ -228,6 +249,11 @@
     ///  the online database.</summary>
     property OnDownloadProgress: TDownloadEvent
       read fOnDownloadProgress write fOnDownloadProgress;
+
+    ///  <summary>Event triggered to report progress when updating local
+    ///  database files.</summary>
+    property OnFileUpdateProgress: TProgressEvent
+      read fOnFileUpdateProgress write fOnFileUpdateProgress;
   end;
 
 
@@ -236,7 +262,7 @@
 
 uses
   // Delphi
-  Classes,
+  Classes, Math,
   // Project
   IntfCommon, UConsts, UFileUpdater, UUtils, UExceptions;
 
@@ -350,6 +376,22 @@
   end;
 end;
 
+procedure TDBUpdateMgr.FileUpdateProgressHandler(Sender: TObject;
+  const AFilesHandled, ATotalFiles: Cardinal);
+var
+  FilesHandled: Cardinal;
+  TotalFiles: Cardinal;
+  Percent: Byte;
+begin
+  if not Assigned(fOnFileUpdateProgress) then
+    Exit;
+  // Ensure TotalFiles > 0 and 0 <= FilesHandled <= TotalFiles
+  TotalFiles := Max(1, ATotalFiles);
+  FilesHandled := Min(AFilesHandled, ATotalFiles);
+  Percent := Round(100 * FilesHandled / TotalFiles);
+  fOnFileUpdateProgress(Self, Percent, fCancelled);
+end;
+
 function TDBUpdateMgr.HandleException(const E: Exception): Boolean;
 begin
   if E is EDBDownloadMgr then
@@ -457,6 +499,7 @@
     Exit;
   Updater := TFileUpdater.Create(fLocalDir, Data);
   try
+    Updater.OnProgress := FileUpdateProgressHandler;
     Updater.Execute;
     Result := True;
   finally
/branches/4/4.5/Src/UFileUpdater.pas Diff Switch to side-by-side view
--- a/branches/4/4.5/Src/UFileUpdater.pas
+++ b/branches/4/4.5/Src/UFileUpdater.pas
@@ -3,7 +3,7 @@
  * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  * obtain one at http://mozilla.org/MPL/2.0/
  *
- * Copyright (C) 2006-2012, Peter Johnson (www.delphidabbler.com).
+ * Copyright (C) 2006-2013, Peter Johnson (www.delphidabbler.com).
  *
  * $Rev$
  * $Date$
@@ -32,14 +32,28 @@
   ///  data.
   ///  </summary>
   TFileUpdater = class(TObject)
+  public
+    type
+      ///  <summary>Type of event triggered when reporting progress in updating
+      ///  data files.</summary>
+      ///  <param name="Sender">TObject [in] Object instance that triggered the
+      ///  event.</param>
+      ///  <param name="FilesHandled">Cardinal [in] Number of files updated to
+      ///  date.</param>
+      ///  <param name="TotalFiles">Cardinal [in] Total number of files to be
+      ///  updated.</param>
+      TProgressEvent = procedure(Sender: TObject; const FilesHandled,
+        TotalFiles: Cardinal) of object;
   strict private
     var
       ///  <summary>Used to read formatted text data stream.</summary>
       fReader: TTextStreamReader;
       ///  <summary>Local data directory.</summary>
       fLocalDir: string;
-    ///  <summary>
-    ///  Reverts data file to state they were in before update.
+      ///  <summary>Reference to any OnProgess event handler.</summary>
+      fOnProgress: TProgressEvent;
+    ///  <summary>
+    ///  Reverts data files to state they were in before update.
     ///  </summary>
     procedure UndoUpdate;
     ///  <summary>
@@ -54,6 +68,15 @@
     ///  <param name="UnixDate">Int64 [in] Unix format GMT date stamp to be
     ///  applied to file.</param>
     procedure WriteFile(const Name, Content: string; const UnixDate: Int64);
+    ///  <summary>
+    ///  Triggers any assigned OnProgress event handler with information about
+    ///  file update progress to date.
+    ///  </summary>
+    ///  <param name="FilesHandled">Cardinal [in] Number of files updated to
+    ///  date.</param>
+    ///  <param name="TotalFiles">Cardinal [in] Total number of files to be
+    ///  updated.</param>
+    procedure ReportProgress(const FilesHandled, TotalFiles: Cardinal);
   public
     ///  <summary>Object constructor. Initialises object.</summary>
     ///  <param name="LocalDir">string [in] Directory storing local data files
@@ -64,6 +87,10 @@
     destructor Destroy; override;
     ///  <summary>Performs file updates.</summary>
     procedure Execute;
+    ///  <summary>Event that reports progress when updating local files.
+    ///  </summary>
+    ///  <remarks>Triggered once for each file processed.</remarks>
+    property OnProgress: TProgressEvent read fOnProgress write fOnProgress;
   end;
 
 type
@@ -140,6 +167,7 @@
 procedure TFileUpdater.Execute;
 var
   FileCount: Integer;   // number of files to copy to local directory
+  CopiedCount: Integer; // number of files copied
 begin
   TDataBackupMgr.Backup;
   try
@@ -147,10 +175,12 @@
     UUtils.DeleteFiles(fLocalDir, '*.*');
     // Copy in new files
     FileCount := fReader.ReadInt16;
-    while FileCount > 0 do
+    CopiedCount := 0;
+    while CopiedCount < FileCount do
     begin
       UpdateFile;
-      Dec(FileCount);
+      Inc(CopiedCount);
+      ReportProgress(CopiedCount, FileCount);
     end;
   except
     // Error: restore backup
@@ -161,6 +191,12 @@
   TDataBackupMgr.DeleteBackup;
 end;
 
+procedure TFileUpdater.ReportProgress(const FilesHandled, TotalFiles: Cardinal);
+begin
+  if Assigned(fOnProgress) then
+    fOnProgress(Self, FilesHandled, TotalFiles);
+end;
+
 procedure TFileUpdater.UndoUpdate;
 begin
   TDataBackupMgr.RestoreBackup;
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.