/// <summary>
///   This unit will contain some Classes / Interfaces / Methods which can be
///   used to remporary set the Screen Cursor.
/// </summary>
unit Devia.Common.CursorRestorer;

interface

uses
  {$IF CompilerVersion >= 23.0}
    // Delphi XE2 and later -> use "namespace" unit names
    System.UITypes;
  {$ELSE}
    // Delphi XE and sooner -> use "classic" unit names
    Controls;
  {$IFEND}

type
  ICursorController = interface
  ['{090C41F5-A563-4A73-819D-C00FBADD4B99}']

  end;

  TCursorController = class(TInterfacedObject, ICursorController)
  private
    FOldCursor : TCursor;

  public
    constructor Create(ACursor: TCursor);

    procedure BeforeDestruction; override;

  end;

  /// <summary>
  ///   Changes the cursor into the HourGlass to indicate the applicaion is
  ///   busy. The cursor will return to it's previous state once the returined
  ///   ICursorController goes out of scope or is set to Nil.
  /// </summary>
  /// <returns>
  ///   ICursorController
  /// </returns>
  /// <example>
  ///   <para>
  ///     First example is how to use it to make sure the user sees the
  ///     system is execting a DB process.
  ///   </para>
  ///   <code lang="Delphi">procedure TfrmPartialInvoicing.acGetOpenInvoicesExecute(Sender: TObject);
  /// var
  ///   iCursor: ICursorController;
  /// begin
  ///   iCursor := GetSQLWaitCursor;
  ///
  ///   // Execute some long process
  ///
  ///   // Since we stored the result in a local variable iCursor, this variable will go out of
  ///   // scope at the en of the routine and the cursor will return to it's original state
  ///   // once it does.
  /// end;</code>
  ///   <para>
  ///     Second example will combine GetHourGlassCursor and GetSQLWaitCursor
  ///   </para>
  ///   <code lang="Delphi">procedure TfrmPartialInvoicing.acGetOpenInvoicesExecute(Sender: TObject);
  /// var
  ///   iWaitCursor: ICursorController;
  ///   iSQLCursor : ICursorController;
  /// begin
  ///   iWaitCursor : GetHourGlassCursor;
  ///
  ///   // User will see the HourGlass Cursor.
  ///   DoSomeLengthyProcess;
  ///
  ///   iSQLCursor := GetSQLWaitCursor;
  ///   // User will see the SQL Wait Cursor
  ///
  ///   DoSomeDBProcessing;
  ///
  ///   iSQLCursor := Nil;
  ///   // Since we've set the variable to Nil, the cursor will be reset to what it was
  ///   // before, so the HourGlass.
  ///
  ///   DoSomeMoreWork;
  ///   // Since we stored the result in a local variable iWaitCursor, this variable will go
  ///   // out of scope at the en of the routine and the cursor will return to it's original
  ///   // state once it does.
  /// end;</code>
  /// </example>
  function GetHourglassCursor : ICursorController;

  /// <summary>
  ///   Changes the cursor into the SQL Wait Cursor to indicate the applicaion
  ///   is busy doing some DB Processing. The cursor will return to it's
  ///   previous state once the returined ICursorController goes out of scope
  ///   or is set to Nil.
  /// </summary>
  /// <returns>
  ///   ICursorController
  /// </returns>
  /// <seealso cref="GetHourGlassCursor" />
  function GetSQLWaitCursor   : ICursorController;

implementation

uses
  {$IF CompilerVersion >= 23.0}
    // Delphi XE2 and later -> use "namespace" unit names
  Vcl.Forms;
  {$ELSE}
    // Delphi XE and sooner -> use "classic" unit names
    Forms;
  {$IFEND}


function GetHourglassCursor : ICursorController;
begin
  Result := TCursorController.Create( crHourGlass );
end;

function GetSQLWaitCursor   : ICursorController;
begin
  Result := TCursorController.Create( crSQLWait );
end;

{ TCursorController }

procedure TCursorController.BeforeDestruction;
begin
  inherited;

  Screen.Cursor := FOldCursor;
end;

constructor TCursorController.Create(ACursor: TCursor);
begin
  FOldCursor    := Screen.Cursor;
  Screen.Cursor := ACursor;
end;

end.

Leave a Reply