{
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;
interfaceuses
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 )
ofobject;
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;
protectedprocedure Loaded; override;
procedure Notification( AComponent : TComponent;
Operation : TOperation ); override;
procedure DoClick( Sender : TObject );
publicconstructor 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 : stringread 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 : stringread 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 toas 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;
implementationtype
// 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 );
begininherited;
FParentMenuItem := nil;
FItems := TStringList.Create;
FItems.OnChange := ItemsChange;
FMaxItems := MRU_MAX_ITEMS;
FShowFullPath := True;
end; (* Create *)destructor TMRU.Destroy;
beginifnot( csDesigning in ComponentState ) then
SaveMRU;
FItems.OnChange := nil;
FItems.Free;
inherited;
end; (* Destroy *)procedure TMRU.Loaded;
begininherited Loaded;
ifnot( csDesigning in ComponentState ) then
LoadMRU;
end; (* Loaded *)procedure TMRU.Notification( AComponent : TComponent; Operation : TOperation );
begininherited;
if ( Operation = opRemove ) and ( AComponent = FParentMenuItem ) then
FParentMenuItem := nil;
end; (* Notification *)procedure TMRU.AddItem( const FileName : string );
beginif FileName <> ''thenbegin
FItems.BeginUpdate;
tryif FItems.IndexOf( FileName ) > -1then
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;
beginif FItems.IndexOf( FileName ) > -1thenbegin
FItems.Delete( FItems.IndexOf( FileName ) );
Result := True;
endelse
Result := False;
end; (* RemoveItem *)procedure TMRU.SetMaxItems( const Value : cardinal );
beginif Value <> FMaxItems thenbeginif Value < 1then
FMaxItems := 1elseif Value > MaxInt then
FMaxItems := MaxInt - 1elsebegin
FMaxItems := Value;
FItems.BeginUpdate;
trywhile FItems.Count > MaxItems do
FItems.Delete( FItems.Count - 1 );
finally
FItems.EndUpdate;
end;
end;
end;
end; (* SetMaxItems *)procedure TMRU.SetIniFileName( const Value : string );
beginif FIniFileName <> Value thenbegin
FIniFileName := Value;
LoadMRU;
end;
end;
procedure TMRU.SetRegistryPath( const Value : string );
beginif FRegistryPath <> Value thenbegin
FRegistryPath := Value;
LoadMRU;
end;
end; (* SetRegistryPath *)procedure TMRU.SetShowFullPath( const Value : boolean );
beginif FShowFullPath <> Value thenbegin
FShowFullPath := Value;
ItemsChange( Self );
end;
end; (* SetShowFullPath *)procedure TMRU.LoadFromRegistry;
var
i : cardinal;
beginwith TRegistry.Create dotry
RootKey := HKEY_CURRENT_USER;
if OpenKey( FRegistryPath, False ) thenbegin
FItems.BeginUpdate;
FItems.Clear;
tryfor i := 1to FMaxItems doif 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;
beginwith TRegistry.Create dotry
RootKey := HKEY_CURRENT_USER;
if OpenKey( FRegistryPath, True ) thenbegin
// delete old mru
i := 1;
while ValueExists( MRU_NAME + IntToStr( i ) ) dobegin
DeleteValue( MRU_NAME + IntToStr( i ) );
Inc( i );
end;
// write new mru
for i := 0to -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
elseif FIniFileName = ''then
IniFileName := ChangeFileExt( paramStr( 0 ), '.ini' ) // default IniFile
else // FIniFileName <> ''
IniFileName := ExtractFilePath( paramStr( 0 ) ) + FIniFileName;
if FileExists( IniFileName ) thenbeginwith TIniFile.Create( IniFileName ) dobegintry
FItems.BeginUpdate;
FItems.Clear;
tryfor i := 1to FMaxItems dobegin
LItemName := ReadString( MRU_NAME, IntToStr( i ), '' );
if LItemName = ''thenbreak;
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
elseif FIniFileName = ''then
IniFileName := ChangeFileExt( paramStr( 0 ), '.ini' ) // default IniFile
else // FIniFileName <> ''
IniFileName := ExtractFilePath( paramStr( 0 ) ) + FIniFileName;
with TIniFile.Create( IniFileName ) dobegintryfor i := 1to FMaxItems dobeginif i <= FItems.Count then
WriteString( MRU_NAME, IntToStr( i ), FItems[ i - 1 ] );
end;
finally
Free;
end;
end;
end;
procedure TMRU.LoadMRU;
beginif FRegistryPath <> ''then
LoadFromRegistry
else
LoadFromIniFile;
end;
procedure TMRU.SaveMRU;
beginif FRegistryPath <> ''then
SaveToRegistry
else
SaveToIniFile;
end;
(* SaveMRU *)procedure TMRU.ItemsChange( Sender : TObject );
var
i : integer;
NewMenuItem : TMenuItem;
FileName : String;
beginif ParentMenuItem <> nilthenbegin
ClearParentMenu;
for i := 0to -1 + FItems.Count dobeginif 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;
beginif Assigned( ParentMenuItem ) thenfor i := -1 + ParentMenuItem.Count downto0doif ParentMenuItem.Items[ i ] is TMRUMenuItem then
ParentMenuItem.Delete( i );
end; (* ClearParentMenu *)procedure TMRU.DoClick( Sender : TObject );
beginif Assigned( FOnClick ) and ( Sender is TMRUMenuItem ) then
FOnClick( Self, FItems[ TMRUMenuItem( Sender ).Tag ] );
end; (* DoClick *)procedure TMRU.SetParentMenuItem( const Value : TMenuItem );
beginif FParentMenuItem <> Value thenbegin
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/
********************************************
}