zoukankan      html  css  js  c++  java
  • Most Recently Used (MRU) menu component

    {
      Article: Most Recently Used (MRU) menu component - TMRU
    
      http://delphi.about.com/library/weekly/aa112503a.htm
    
      Full source code of a TMRU component, a non-visual component
      which simplifies implementing a "Most Recently Used" file list
      in a menu (or a popup menu). The TMRU component allows for
      quick selection of a file that was recently accessed (opened)
      in an application.
    
      MRU - Most Recently Used
    
      Many applications offer a list of most recently used files
      (like Delphi's File | Reopen menu) - a list that reflects the user's most
      recently accessed files in an application.
    
      The MRU list allows for quick selection of a file that was recently opened
      without having to select an Open menu item and search to locate a specific
      lately accessed file.
    
      The TMRU Delphi component is a non-visual component which simplifies
      implementing a "Most Recently Used" file list in a menu (or a popup menu).
      Here are the TadpMRU component's features:
    
      MRU menu items are attached to a "ParentMenuItem"
      Dynamic, supports *unlimited* number of MRU items.
      A maximum number of MRU entries can be defined.
      Files can be added or removed from the list.
      The files are listed with the most recently used at the top of the list
      (from the "most recent" to "least recent.")
      Each file can be displayed using the full path name or just the file name.
      The MRU list is saved to the Registry upon application termination and
      loaded upon application startup.
      Enables more Registry storage areas by providing the RegistryPath property
      Exposes an OnClick event with the Filename as a parameter.
      and more...
    
      http://www.angusj.com/delphi/mruunit.html for <IniFile>
      Copyright 2003 Angus Johnson
    }
    
    unit uMRU;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Menus, IniFiles, Registry;
    
    const
      MRU_MAX_ITEMS = 16;
      MRU_NAME = 'MRU';
    
    type
    
      // riggered when a "MRU menu item" is clicked.
      TMRUClickEvent = procedure( Sender : TObject; const FileName : String )
        of object;
    
      TMRU = class( TComponent )
      private
        FItems : TStringList;
    
        FMaxItems : cardinal;
        FShowFullPath : boolean;
        FRegistryPath : string;
        FIniFileName : string;
        FParentMenuItem : TMenuItem;
        FOnClick : TMRUClickEvent;
        procedure SetMaxItems( const Value : cardinal );
        procedure SetShowFullPath( const Value : boolean );
        procedure SetParentMenuItem( const Value : TMenuItem );
    
        procedure SetIniFileName( const Value : string );
        procedure SetRegistryPath( const Value : string );
    
        procedure LoadMRU;
        procedure SaveMRU;
        procedure LoadFromRegistry;
        procedure SaveToRegistry;
        procedure LoadFromIniFile;
        procedure SaveToIniFile;
    
        procedure ItemsChange( Sender : TObject );
        procedure ClearParentMenu;
      protected
        procedure Loaded; override;
        procedure Notification( AComponent : TComponent;
          Operation : TOperation ); override;
        procedure DoClick( Sender : TObject );
    
      public
        constructor Create( AOwner : TComponent ); override;
        destructor Destroy; override;
    
        // Adds the Filename to the MRU list, as the first item.
        procedure AddItem( const FileName : string );
        // Removes a MRU item provided with a file name.
        // Returns true if an existing item was removed; false otherwise.
        function RemoveItem( const FileName : string ) : boolean;
    
      published
        // Gets or sets the string value representing the key in Registry
        // where MRU entries are saved.
        // If omitted the MRU list is NOT saved upon application termination.
        // The root key used is HKEY_CURRENT_USER
        property RegistryPath : string read FRegistryPath write SetRegistryPath;
        // Gets or sets the string value representing the Ini FileName
        // where MRU entries are saved.
        // If omitted the MRU list is NOT saved upon application termination.
        property IniFileName : string read FIniFileName write SetIniFileName;
    
        // Gets or sets the maximum number of files in the MRU list.
        property MaxItems : cardinal read FMaxItems write SetMaxItems
          default MRU_MAX_ITEMS;
    
        // Gets or sets the value that indicates whether files as menu items
        // are displayed with full file name (or just using the file name).
        property ShowFullPath : boolean read FShowFullPath write SetShowFullPath
          default True;
    
        // Determines the menu item that the MRU items will be
        // added to as child menu items.
        property ParentMenuItem : TMenuItem read FParentMenuItem
          write SetParentMenuItem;
    
        // riggered when a "MRU menu item" is clicked.
        property OnClick : TMRUClickEvent read FOnClick write FOnClick;
      end;
    
    procedure Register;
    
    implementation
    
    type
      // to be able to recognize MRU menu item when deleting
      TMRUMenuItem = class( TMenuItem );
    
    procedure Register;
    begin
      RegisterComponents( 'delphi.about.com', [ TMRU ] );
    end;
    
    { TMRU }
    
    constructor TMRU.Create( AOwner : TComponent );
    begin
      inherited;
      FParentMenuItem := nil;
      FItems := TStringList.Create;
      FItems.OnChange := ItemsChange;
    
      FMaxItems := MRU_MAX_ITEMS;
      FShowFullPath := True;
    end; (* Create *)
    
    destructor TMRU.Destroy;
    begin
      if not( csDesigning in ComponentState ) then
        SaveMRU;
    
      FItems.OnChange := nil;
      FItems.Free;
    
      inherited;
    end; (* Destroy *)
    
    procedure TMRU.Loaded;
    begin
      inherited Loaded;
      if not( csDesigning in ComponentState ) then
        LoadMRU;
    end; (* Loaded *)
    
    procedure TMRU.Notification( AComponent : TComponent; Operation : TOperation );
    begin
      inherited;
      if ( Operation = opRemove ) and ( AComponent = FParentMenuItem ) then
        FParentMenuItem := nil;
    end; (* Notification *)
    
    procedure TMRU.AddItem( const FileName : string );
    begin
      if FileName <> '' then
      begin
        FItems.BeginUpdate;
        try
          if FItems.IndexOf( FileName ) > -1 then
            FItems.Delete( FItems.IndexOf( FileName ) );
          FItems.Insert( 0, FileName );
    
          while FItems.Count > MaxItems do
            FItems.Delete( MaxItems );
        finally
          FItems.EndUpdate;
        end;
      end;
    end; (* AddItem *)
    
    function TMRU.RemoveItem( const FileName : string ) : boolean;
    begin
      if FItems.IndexOf( FileName ) > -1 then
      begin
        FItems.Delete( FItems.IndexOf( FileName ) );
        Result := True;
      end
      else
        Result := False;
    end; (* RemoveItem *)
    
    procedure TMRU.SetMaxItems( const Value : cardinal );
    begin
      if Value <> FMaxItems then
      begin
        if Value < 1 then
          FMaxItems := 1
        else if Value > MaxInt then
          FMaxItems := MaxInt - 1
        else
        begin
          FMaxItems := Value;
          FItems.BeginUpdate;
          try
            while FItems.Count > MaxItems do
              FItems.Delete( FItems.Count - 1 );
          finally
            FItems.EndUpdate;
          end;
        end;
      end;
    end; (* SetMaxItems *)
    
    procedure TMRU.SetIniFileName( const Value : string );
    begin
      if FIniFileName <> Value then
      begin
        FIniFileName := Value;
        LoadMRU;
      end;
    end;
    
    procedure TMRU.SetRegistryPath( const Value : string );
    begin
      if FRegistryPath <> Value then
      begin
        FRegistryPath := Value;
        LoadMRU;
      end;
    end; (* SetRegistryPath *)
    
    procedure TMRU.SetShowFullPath( const Value : boolean );
    begin
      if FShowFullPath <> Value then
      begin
        FShowFullPath := Value;
        ItemsChange( Self );
      end;
    end; (* SetShowFullPath *)
    
    procedure TMRU.LoadFromRegistry;
    var
      i : cardinal;
    begin
      with TRegistry.Create do
        try
          RootKey := HKEY_CURRENT_USER;
          if OpenKey( FRegistryPath, False ) then
          begin
            FItems.BeginUpdate;
            FItems.Clear;
            try
              for i := 1 to FMaxItems do
                if ValueExists( MRU_NAME + IntToStr( i ) ) then
                  FItems.Add( ReadString( MRU_NAME + IntToStr( i ) ) );
            finally
              FItems.EndUpdate;
            end;
            CloseKey;
          end;
        finally
          Free;
        end;
    end; (* LoadFromRegistry *)
    
    procedure TMRU.SaveToRegistry;
    var
      i : integer;
    begin
      with TRegistry.Create do
        try
          RootKey := HKEY_CURRENT_USER;
          if OpenKey( FRegistryPath, True ) then
          begin
            // delete old mru
            i := 1;
            while ValueExists( MRU_NAME + IntToStr( i ) ) do
            begin
              DeleteValue( MRU_NAME + IntToStr( i ) );
              Inc( i );
            end;
    
            // write new mru
            for i := 0 to -1 + FItems.Count do
              WriteString( MRU_NAME + IntToStr( i + 1 ), FItems[ i ] );
            CloseKey;
          end;
        finally
          Free;
        end;
    end;
    
    procedure TMRU.LoadFromIniFile;
    var
      i : cardinal;
      LItemName : string;
      IniFilePath : string;
      IniFileName : string;
    begin
      IniFilePath := ExtractFilePath( FIniFileName );
    
      if IniFilePath <> '' then
        IniFileName := FIniFileName // Valid IniFile with path
      else if FIniFileName = '' then
        IniFileName := ChangeFileExt( paramStr( 0 ), '.ini' ) // default IniFile
      else // FIniFileName <> ''
        IniFileName := ExtractFilePath( paramStr( 0 ) ) + FIniFileName;
    
      if FileExists( IniFileName ) then
      begin
        with TIniFile.Create( IniFileName ) do
        begin
          try
            FItems.BeginUpdate;
            FItems.Clear;
            try
              for i := 1 to FMaxItems do
              begin
                LItemName := ReadString( MRU_NAME, IntToStr( i ), '' );
                if LItemName = '' then
                  break;
                FItems.Add( LItemName );
              end;
            finally
              FItems.EndUpdate;
            end;
          finally
            Free;
          end;
        end;
      end;
    end;
    
    procedure TMRU.SaveToIniFile;
    var
      i : cardinal;
      IniFilePath : string;
      IniFileName : string;
    begin
      IniFilePath := ExtractFilePath( FIniFileName );
    
      if IniFilePath <> '' then
        IniFileName := FIniFileName // Valid IniFile with path
      else if FIniFileName = '' then
        IniFileName := ChangeFileExt( paramStr( 0 ), '.ini' ) // default IniFile
      else // FIniFileName <> ''
        IniFileName := ExtractFilePath( paramStr( 0 ) ) + FIniFileName;
    
      with TIniFile.Create( IniFileName ) do
      begin
        try
          for i := 1 to FMaxItems do
          begin
            if i <= FItems.Count then
              WriteString( MRU_NAME, IntToStr( i ), FItems[ i - 1 ] );
          end;
        finally
          Free;
        end;
      end;
    end;
    
    procedure TMRU.LoadMRU;
    begin
      if FRegistryPath <> '' then
        LoadFromRegistry
      else
        LoadFromIniFile;
    end;
    
    procedure TMRU.SaveMRU;
    begin
      if FRegistryPath <> '' then
        SaveToRegistry
      else
        SaveToIniFile;
    end;
    
    (* SaveMRU *)
    
    procedure TMRU.ItemsChange( Sender : TObject );
    var
      i : integer;
      NewMenuItem : TMenuItem;
      FileName : String;
    begin
      if ParentMenuItem <> nil then
      begin
        ClearParentMenu;
        for i := 0 to -1 + FItems.Count do
        begin
          if ShowFullPath then
            FileName := StringReplace( FItems[ i ], '&', '&&',
              [ rfReplaceAll, rfIgnoreCase ] )
          else
            FileName := StringReplace( ExtractFileName( FItems[ i ] ), '&', '&&',
              [ rfReplaceAll, rfIgnoreCase ] );
    
          NewMenuItem := TMRUMenuItem.Create( Self );
          NewMenuItem.Caption := Format( '%s', [ FileName ] );
          NewMenuItem.Tag := i;
          NewMenuItem.OnClick := DoClick;
          ParentMenuItem.Add( NewMenuItem );
        end;
      end;
    end; (* ItemsChange *)
    
    procedure TMRU.ClearParentMenu;
    var
      i : integer;
    begin
      if Assigned( ParentMenuItem ) then
        for i := -1 + ParentMenuItem.Count downto 0 do
          if ParentMenuItem.Items[ i ] is TMRUMenuItem then
            ParentMenuItem.Delete( i );
    end; (* ClearParentMenu *)
    
    procedure TMRU.DoClick( Sender : TObject );
    begin
      if Assigned( FOnClick ) and ( Sender is TMRUMenuItem ) then
        FOnClick( Self, FItems[ TMRUMenuItem( Sender ).Tag ] );
    end; (* DoClick *)
    
    procedure TMRU.SetParentMenuItem( const Value : TMenuItem );
    begin
      if FParentMenuItem <> Value then
      begin
        ClearParentMenu;
        FParentMenuItem := Value;
        ItemsChange( Self );
      end;
    end; (* SetParentMenuItem *)
    
    end. (* MRU.pas *)
    
    {
      ********************************************
      Zarko Gajic
      About.com Guide to Delphi Programming
      http://delphi.about.com
      email: delphi@aboutguide.com
      free newsletter: http://delphi.about.com/library/blnewsletter.htm
      forum: http://forums.about.com/ab-delphi/start/
      ********************************************
    }

  • 相关阅读:
    求10个随机数的最大值、最小值、和、平均值
    设计并编写代码自动格斗类游戏
    用while实现阶乘
    安卓第三次作业
    第二次作业
    第一次作业
    第四次作业
    dialog
    用画图的方法理解原型对象和原型链,事半功倍今晚不加班
    【学习笔记】浅析Promise函数
  • 原文地址:https://www.cnblogs.com/shangdawei/p/3060793.html
Copyright © 2011-2022 走看看