Mega Code Archive

 
Categories / Delphi / Files
 

Most recently used files

Title: Most recently used files Question: Many programs provide a list of the most recently used (MRU) files. How can this be done? Answer: Administration of the most recently files of an application is a quite easy task, however, a bit annoying if this is repeated from project to project. Therefore, I wrote a little component (TMRUManager) which simplifies this task: (******************************************************************************* MRU Manager -------------------------------------------------------------------------------- a component to get access to the most recently used (MRU) files. Usage: - Drop the component on the form which opens files, usually this is the main form of an application. - If the form has a toolbar with a "file open" tool button: drop a popup menu and change the button style to "tbsDrowpDown". Set the property "DropdownMenu" of the toolbutton to point to the popup menu. - In the procedure that opens the file add a call to the "Add" method of the MRU Manager and pass the filename as a parameter. This adds the filename to the MRU list. The MRU list will be appended to the file menu of the form and will appear also in to popup menu. - Write an event handler for the MRU manager event "OnSelected". This event is fired when the user has selected a most recently used file either from the file or the popup menu. The event handler gets the name of the requested file as a parameter. It should open this file. Also, the event handler should call the Add method of the MRU Manager again, if the file should be re-positioned at the top of the MRU list. - If you want to save the MRU items in an ini file, call "SaveToIni" in the OnDestroy event and "LoadFromIni" in the OnCreateEvent of the main form. - That's all. Properties: - MaxCount : integer Maximum number of most recently used items. Default: 10. If the MRU list gets longer, the oldest item will be deleted. - ItemCount : integer Current count of MRU items in the list. - ReverseOrder: boolean if false (default) the oldest items are at the bottom of the menus, if true, they are at the top. - FileMenu : TMenuItem points to the menu of the form's main menu to which the MRU items will be appended. Normally this is the "file" menu. - PopupMenu: TPopupMenu points to a TPopupMenu component that will be expanded with the MRU items. As shown above, this popup menu can be connected to a DropDown toolbutton in the form's toolbar. - AddNumbersToFileMenu, AddNumbersToPopupMenu : boolean each MRU item in the file or popup menu is preceded by a sequential number. - IniKey : string; A string to label the sections in the ini file where the MRU items are written to (see: SaveToIni, LoadFromIni). - FileMustExist : boolean if true, files that do not exist are not added to the MRU list. - OnSelected: Event handler for processing of the user selecting an MRU item in the file or the dropdown menu. Usually the event handler should load the file whose name is passed as a parameter. Methods: - function Add(item:string) : boolean; adds a filename to the MRU list. To be called from the main form whenever a file is to be opened. The result is false when the filename could not be appended, e.g. when the file does not exist (and FileMustExist is true). - SaveToIni(ini:TIniFile) writes the MRU items to an ini file. To be called from the form's OnCloseQuery or OnDestroy event handler. - LoadFromIni(ini:TIniFile) load the MRU items saved in a previous session from the ini file. To be called from the form's OnCreate event handler. - Create, Destroy constructor and destructor, as usual. (c) W.Pamler, June 2001 *******************************************************************************) unit MRUManager; interface uses Classes, Menus, IniFiles; type TMRUEvent = procedure(Sender:TObject; const MRUItem:string) of object; TMRUManager = class(TComponent) private FItems : TStringList; FAddNumbersToFileMenu : boolean; FAddNumbersToPopupMenu : boolean; FMaxCount : integer; FReverseOrder : boolean; FFileMenu : TMenuItem; FPopupMenu : TPopupMenu; FFilesMustExist : boolean; FIniKey : string; FOnSelected : TMRUEvent; procedure AddToMenu(menu:TMenuItem; AddNumbers:boolean); procedure ClearMenu(menu:TMenuItem); function GetItemCount : integer; procedure MenuClicked(Sender:TObject); procedure SetAddNumbersToFileMenu(value:boolean); procedure SetAddNumbersToPopupMenu(value:boolean); procedure SetFileMenu(value:TMenuItem); procedure SetIniKey(value:string); procedure SetMaxCount(value:integer); procedure SetPopupMenu(value:TPopupMenu); procedure SetReverseOrder(value:boolean); procedure UpdateMenus; public constructor Create(AOwner:TComponent); override; destructor Destroy; override; function Add(const AItem:string) : boolean; procedure LoadFromIni(ini:TIniFile); procedure SaveToIni(ini:TIniFile); published property AddNumbersToFileMenu : boolean read FAddNumbersToFileMenu write SetAddNumbersToFileMenu default true; property AddNumbersToPopupMenu : boolean read FAddNumbersToPopupMenu write SetAddNumbersToPopupMenu default true; property MaxCount : integer read FMaxCount write SetMaxCount default 10; property Itemcount : integer read GetItemCount; property ReverseOrder : boolean read FReverseOrder write SetReverseOrder; property FileMenu : TMenuItem read FFileMenu write SetFileMenu; property PopupMenu : TPopupMenu read FPopupMenu write SetPopupMenu; property IniKey : string read FIniKey write SetIniKey; property FilesMustExist : boolean read FFilesMustExist write FFilesMustExist default true; property OnSelected : TMRUEvent read FOnSelected write FOnSelected; end; procedure Register; //============================================================================== implementation //============================================================================== uses SysUtils; const MRU_Tag = 20010607; // Note: the menu items that the MRU manger has appended to the menus will // be marked by tags ranging between MRU_Tag and MRU_Tag+n+1, where n is the // value of the MRU Mangager MaxCount property resourcestring SNoIniKey = 'Property "IniKey" cannot be empty.'; SNoIni = 'TMRUManger''s ini file is not initialized.'; //============================================================================== constructor TMRUManager.Create(AOwner:TComponent); begin inherited Create(AOwner); FItems := TStringList.Create; FMaxCount := 10; FIniKey := 'MRU'; FFilesMustExist := true; FAddNumbersToFileMenu := true; FAddNumbersToPopupMenu := true; end; //------------------------------------------------------------------------------ destructor TMRUManager.Destroy; begin FItems.Free; inherited Destroy; end; //------------------------------------------------------------------------------ function TMRUManager.Add(const AItem:string) : boolean; var i : integer; begin result := false; if (FilesMustExist and FileExists(AItem)) or (not FilesMustExist) then begin // if new item is already in list put it at the last position. for i:=0 to FItems.Count-1 do begin if UpperCase(FItems[i])=Uppercase(AItem) then begin FItems.Exchange(i, FItems.Count-1); UpdateMenus; exit; end; end; if FItems.Count=FMaxCount then FItems.Delete(0); FItems.Add(AItem); UpdateMenus; result := true; end; end; //------------------------------------------------------------------------------ procedure TMRUManager.AddToMenu(menu:TMenuItem; AddNumbers:boolean); var newItem: TMenuItem; i,j : integer; begin if FItems.Count0 then begin // Remove old MRU menu items ClearMenu(menu); // Add separator if menu.Count0 then begin newItem := TMenuItem.Create(self); with NewItem do begin caption := '-'; tag := MRU_Tag; end; Menu.Add(NewItem); end; // Append MRU list to the menu if FReverseOrder then begin for i:=0 to FItems.Count-1 do begin newItem := TMenuItem.Create(self); with newItem do begin if AddNumbers then Caption := Format('&%d - %s ', [i+1, FItems[i]]) else Caption := FItems[i]; Tag := MRU_Tag+i+1; OnClick := MenuClicked; end; Menu.Add(NewItem); end; end else begin for i:=FItems.Count-1 downto 0 do begin j := FItems.Count-i; newItem := TMenuItem.Create(self); with NewItem do begin if AddNumbers then Caption := Format('&%d - %s ', [j, FItems[i]]) else Caption := FItems[i]; Tag := MRU_Tag+i+1; OnClick := MenuClicked; end; Menu.Add(NewItem); end; end; end; end; //------------------------------------------------------------------------------ procedure TMRUManager.ClearMenu(menu:TMenuItem); var i : integer; begin with menu do begin for i:=count-1 downto 0 do begin if (Items[i].Tag=MRU_Tag) and (Items[i].Tag then Delete(i); end; end; end; //------------------------------------------------------------------------------ function TMRUManager.GetItemCount : integer; begin result := FItems.Count; end; //------------------------------------------------------------------------------ procedure TMRUManager.LoadFromIni(ini:TIniFile); var n, i : integer; begin if FIniKey='' then raise Exception.Create(SNoIniKey); if Assigned(ini) then begin n := ini.ReadInteger(FIniKey, 'Count', 0); if n0 then begin for i:=1 to n do Add(ini.ReadString(FIniKey, Format('Item%d', [i]), '')); UpdateMenus; end; end else raise Exception.Create(SNoIni); end; //------------------------------------------------------------------------------ procedure TMRUManager.MenuClicked(Sender:TObject); var i : integer; begin if (Sender is TMenuItem) then begin i := (Sender as TMenuItem).Tag - MRU_Tag - 1; if (i=0) and ( i then FOnSelected(Sender, FItems[i]); end; end; //------------------------------------------------------------------------------ procedure TMRUManager.SaveToIni(ini:TIniFile); var i : integer; begin if FIniKey='' then raise Exception.Create(SNoIniKey); if Assigned(ini) then begin ini.WriteInteger(FIniKey, 'Count', FItems.Count); for i:=0 to FItems.Count-1 do ini.WriteString(FIniKey, Format('Item%d', [i+1]), FItems[i]); end else raise Exception.Create(SNoIni); end; //------------------------------------------------------------------------------ procedure TMRUManager.SetAddNumbersToFileMenu(value:boolean); begin FAddNumbersToFileMenu := value; if Assigned(FFileMenu) then AddToMenu(FFileMenu, value); end; //------------------------------------------------------------------------------ procedure TMRUManager.SetAddNumbersToPopupMenu(value:boolean); begin FAddNumbersToPopupMenu := value; if Assigned(FPopupMenu) then AddToMenu(FPopupMenu.Items, value); end; //------------------------------------------------------------------------------ procedure TMRUManager.SetFileMenu(value:TMenuItem); begin if Assigned(FFileMenu) and (valueFFileMenu) then ClearMenu(FFileMenu); FFileMenu := value; if Assigned(FFileMenu) then AddToMenu(FFileMenu, FAddNumbersToFileMenu); end; //------------------------------------------------------------------------------ procedure TMRUManager.SetIniKey(value:string); begin if value='' then raise Exception.Create(SNoIniKey); FIniKey := value; end; //------------------------------------------------------------------------------ procedure TMRUManager.SetMaxCount(value:integer); // Set maximum number of MRU items. var i : integer; begin if value if FReverseOrder then for i:=FItems.Count-value-1 downto 0 do FItems.Delete(i) else for i:=FItems.Count-1 downto value do FItems.Delete(i); end; FMaxCount := value; end; //------------------------------------------------------------------------------ procedure TMRUManager.SetPopupMenu(value:TPopupMenu); begin if Assigned(FPopupMenu) and (value FPopupMenu) then ClearMenu(FPopupMenu.Items); FPopupMenu := value; if Assigned(FPopupMenu) then AddToMenu(FPopupMenu.Items, FAddNumbersToPopupMenu); end; //------------------------------------------------------------------------------ procedure TMRUManager.SetReverseOrder(value:boolean); // Change the order of the items (oldest items at the bottom or at the top). var i : integer; begin if (valueFReverseOrder) and (FItems.Count0) then begin for i:=0 to (FItems.Count-1) div 2 do FItems.Exchange(i, FItems.Count-i-1); UpdateMenus; end; FReverseOrder := value; end; //------------------------------------------------------------------------------ procedure TMRUManager.UpdateMenus; begin if Assigned(FFileMenu) then AddToMenu(FFileMenu, FAddNumbersToFileMenu); if Assigned(FPopupMenu) then AddToMenu(FPopupMenu.Items, FAddNumbersToPopupMenu); end; //============================================================================== procedure Register; begin RegisterComponents('Your Components', [TMRUManager]); end; //============================================================================== end.