[Back to DELPHI SWAG index] [Back to Main SWAG index] [Original]

    unit MRUFList;

    (*    Implements a Recently-Used Files List     *)

    (*  Constructed by Robert R. Marsh, S.J., 1995  *)
    (* Use freely, distribute widely, charge nothing*)
    (* If you like it you could always give some    *)
    (* money to your favorite charity.              *)

    (*  Comments, bug-reports, praise and blame to: *)
    (*              RobMarsh@AOL.COM                *)

    interface

    uses
      SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
      Forms, Dialogs, Menus, IniFiles;

    type
      TRecentFileEvent = procedure(Sender: TObject; LatestFile: string) of object;

    type
      TRecentFiles = class(TComponent)
      private
        FMenu       : TMenuItem;
        Divider     : TMenuItem;
        FMaxFiles   : integer;
        FIniFileName: string;
        FLatestFile : string;
        FOnClick    : TRecentFileEvent;
        procedure SetLatestFile(value: string);
        procedure SetMenu(value: TMenuItem);
        procedure SetMaxFiles(value: integer);
        procedure MenuOnClick(Sender: TObject);
        function DividerPlace: integer;
      protected
        procedure Click(RecentFile: string);
      public
        constructor Create(AOwner: TComponent); override;
        procedure SaveToIniFile;
        procedure LoadFromIniFile;
        property LatestFile: string read FLatestFile write SetLatestFile;
      published
        property Menu       : TMenuItem read FMenu write SetMenu;
        property MaxFiles   : integer read FMaxFiles write SetMaxFiles;
        property IniFileName: string read FIniFileName write FIniFileName;
        property OnClick    : TRecentFileEvent read FOnClick write FOnClick;
      end;

    procedure Register;

    implementation

    procedure Register;
    begin
      RegisterComponents('Mine', [TRecentFiles]);
    end;

    {we frequently need to know both if the Divider}
    {has been added and, if so, where it is}
    function TRecentFiles.DividerPlace: integer;
    begin
    Result:=-1;
    if FMenu <> nil then
      begin
      Result:=Menu.IndexOf(Divider);
      end;
    end;

    procedure TRecentFiles.SetMenu(value: TMenuItem);
    begin
    FMenu:=value;
    end;

    procedure TRecentFiles.SetMaxFiles(value: integer);
    var
      n: integer;
    begin
    {the Max value of MaxFiles is 9}
    if value <=9 then
      begin
      FMaxFiles:=value;
      end
    else
      begin
      FMaxFiles:=9;
      end;
    if (FMenu <> nil) and (DividerPlace <> -1) then
      begin
      {trim off any entries more MaxFiles}
      while Menu.Count > DividerPlace + FMaxFiles + 1 do
        begin
        Menu.Delete(Menu.Count-1);
        end;
      {if neccesary delete the divider too}
      if FMaxFiles = 0 then
        begin
        Menu.Delete(Menu.Count-1);
        end;
      end;
    end;

    procedure TRecentFiles.SetLatestFile(value: string);
    var
      NewMenuItem: TMenuItem;
      n          : integer;
      Thiscaption: string;
      OldPlace   : integer;
      DividerPos : integer;
    begin
    FLatestFile:=value;
    if (Menu <> nil) and (MaxFiles > 0) and
       (FLatestFile <> '') then
      begin
      {special case - the divider}
      if DividerPlace < 0 then
        begin
        Menu.Add(Divider);
        end;
      {is the new Name already there?}
      DividerPos:=DividerPlace;
      n:=DividerPos+1;
      while (n < Menu.Count) do
        begin
        if FLatestFile = Copy(Menu.Items[n].Caption,4,high(string)) then
          begin
          OldPlace:=n;
          Break;
          end
        else
          begin
          inc(n);
          end;
      end;
      if n >= Menu.Count then {we add}
        begin
        NewMenuItem:=TMenuItem.Create(Self);
        NewMenuItem.Caption:='&1 '+FLatestFile;
        {what happens if we click it}
        NewMenuItem.OnClick:=MenuOnClick;
        Menu.Insert(DividerPos+1,NewMenuItem);
        end
      else                 {we insert}
        begin
        NewMenuItem:=Menu.Items[OldPlace];
        Menu.Delete(OldPlace);
        Menu.Insert(DividerPos+1,NewMenuItem);
        end;
      {now change the 'hot' keys}
      for n:=DividerPos+1 to Menu.Count - 1 do
        begin
        ThisCaption:=Menu.Items[n].Caption;
        ThisCaption[2]:=Chr(n - DividerPos + Ord('1') -1);
        Menu.Items[n].Caption:=ThisCaption;
        end;
      {delete any excess items}
      if Menu.Count > DividerPos + MaxFiles + 1 then
        begin
        Menu.Delete(Menu.Count-1);
        end;
      end;
    end;

    procedure TRecentFiles.Click(RecentFile: string);
    begin
    if Assigned(FOnClick) then FOnClick(Self,RecentFile);
    end;

    procedure TRecentFiles.SaveToIniFile;
    var
      IniFile   : TIniFile;
      n         : integer;
      DividerPos: integer;
    begin
    if Menu <> nil then
      begin
      {if this property is blank we use the default}
      if IniFileName = '' then
        begin
        IniFileName:=ChangeFileExt(ExtractFileName(Application.ExeName),'.INI')
        end;
      IniFile:=TIniFile.Create(IniFileName);
      IniFile.EraseSection('FileHistory');
      IniFile.WriteInteger('FileHistory','MaxFiles',MaxFiles);
      if (Menu <> nil) and (DividerPlace <> -1) then
        begin
        DividerPos:=DividerPlace;
        n:=DividerPos+1;
        while n < Menu.Count do
          begin
          IniFile.WriteString('FileHistory','File'+Chr(n+Ord('1')-1-DividerPos),Copy(Menu.Items[n].Caption,4,high(string)));
          inc(n);
          end;
        IniFile.Free;
        end;
      end;
    end;

    procedure TRecentFiles.LoadFromIniFile;
    var
      IniFile: TIniFile;
      n      : integer;
      Name   : string;
    begin
    if Menu <> nil then
      begin
      if IniFileName = '' then
        begin
        IniFileName:=ChangeFileExt(ExtractFileName(Application.ExeName),'.INI')
        end;
      IniFile:=TIniFile.Create(IniFileName);
      MaxFiles:=0;
      MaxFiles:=IniFile.ReadInteger('FileHistory','MaxFiles',MaxFiles);
      n:=1;
      while true do
        begin
        Name:=IniFile.ReadString('FileHistory','File'+Chr(n+Ord('1')-1),'');
        if Name = '' then
          begin
          Break;
          end;
        LatestFile:=Name;
        inc(n);
        end;
      end;
    end;

    constructor TRecentFiles.Create(AOwner: TComponent);
    begin
    inherited Create(AOwner);
    FMaxFiles:=0;
    FMenu:=nil;
    Divider:=TMenuItem.Create(Self);
    Divider.Caption:='-';
    end;

    procedure TRecentFiles.MenuOnClick(Sender: TObject);
    var
      Name: string;
    begin
      begin
      Name:=Copy(TMenuItem(Sender).Caption,4,high(string));
      Click(Name);
      end;
    end;

    end.

[Back to DELPHI SWAG index] [Back to Main SWAG index] [Original]