878 lines
25 KiB
ObjectPascal
878 lines
25 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvMRUList.PAS, released on 2002-07-04.
|
|
|
|
The Initial Developers of the Original Code are: Fedor Koshevnikov, Igor Pavluk and Serge Korolev
|
|
Copyright (c) 1997, 1998 Fedor Koshevnikov, Igor Pavluk and Serge Korolev
|
|
Copyright (c) 2001,2002 SGB Software
|
|
All Rights Reserved.
|
|
|
|
Contributors:
|
|
Michael Fritz (MenuLocation)
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
* Using a divider as RecentMenu when MenuLocation = mruChild doesn't work
|
|
-----------------------------------------------------------------------------}
|
|
// $Id: JvMRUManager.pas 11057 2006-11-29 14:32:05Z marquardt $
|
|
|
|
unit JvMRUManager;
|
|
|
|
{$I jvcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
SysUtils, Classes,
|
|
{$IFDEF VisualCLX}
|
|
Qt,
|
|
{$ENDIF VisualCLX}
|
|
Windows, Menus, Graphics, Controls, Forms,
|
|
JvFormPlacement, JvAppStorage, JvComponentBase;
|
|
|
|
type
|
|
TJvRecentStrings = class;
|
|
|
|
TGetItemEvent = procedure(Sender: TObject; var Caption: string;
|
|
var ShortCut: TShortCut; UserData: Longint) of object;
|
|
TReadItemEvent = procedure(Sender: TObject; AppStorage: TJvCustomAppStorage;
|
|
const Path: string; Index: Integer; var RecentName: string;
|
|
var UserData: Longint) of object;
|
|
TWriteItemEvent = procedure(Sender: TObject; AppStorage: TJvCustomAppStorage;
|
|
const Path: string; Index: Integer; const RecentName: string;
|
|
UserData: Longint) of object;
|
|
TClickMenuEvent = procedure(Sender: TObject; const RecentName,
|
|
Caption: string; UserData: Longint) of object;
|
|
TGetItemInfoEvent = procedure(Sender: TObject; Item: TMenuItem) of object;
|
|
TGetItemInfoExEvent = procedure(Sender: TObject; Item: TMenuItem; Index: Integer) of object;
|
|
|
|
TAccelDelimiter = (adTab, adSpace);
|
|
TRecentMode = (rmInsert, rmAppend);
|
|
TMenuLocation = (mruChild, mruSibling);
|
|
|
|
TJvRecentStrings = class(TStringList)
|
|
private
|
|
FMaxSize: Integer;
|
|
FMode: TRecentMode;
|
|
procedure SetMaxSize(Value: Integer);
|
|
protected
|
|
procedure SetTextStr(const Value: String); override;
|
|
public
|
|
constructor Create;
|
|
function Add(const S: string): Integer; override;
|
|
procedure AddStrings(Strings: TStrings); override;
|
|
procedure DeleteExceed;
|
|
procedure Remove(const S: string);
|
|
property MaxSize: Integer read FMaxSize write SetMaxSize;
|
|
property Mode: TRecentMode read FMode write FMode;
|
|
end;
|
|
|
|
TJvMRUManager = class(TJvComponent)
|
|
private
|
|
FStrings: TJvRecentStrings;
|
|
FItems: TList;
|
|
FIniLink: TJvIniLink;
|
|
FSeparateSize: Word;
|
|
FAutoEnable: Boolean;
|
|
FAutoUpdate: Boolean;
|
|
FShowAccelChar: Boolean;
|
|
FRemoveOnSelect: Boolean;
|
|
FStartAccel: Cardinal;
|
|
FAccelDelimiter: TAccelDelimiter;
|
|
FRecentMenu: TMenuItem;
|
|
FOnChange: TNotifyEvent;
|
|
FOnGetItem: TGetItemEvent;
|
|
FOnClick: TClickMenuEvent;
|
|
FOnReadItem: TReadItemEvent;
|
|
FOnWriteItem: TWriteItemEvent;
|
|
FOnAfterUpdate: TNotifyEvent;
|
|
FOnBeforeUpdate: TNotifyEvent;
|
|
FOnItemInfo: TGetItemInfoEvent;
|
|
FOnItemInfoEx: TGetItemInfoExEvent;
|
|
FDuplicates: TDuplicates;
|
|
FMenuLocation: TMenuLocation;
|
|
FMaxLength: Integer;
|
|
FCanvas: TCanvas;
|
|
FStartEllipsis: Boolean;
|
|
procedure ListChanged(Sender: TObject);
|
|
procedure ClearRecentMenu;
|
|
procedure SetRecentMenu(Value: TMenuItem);
|
|
procedure SetSeparateSize(Value: Word);
|
|
function GetStorage: TJvFormPlacement;
|
|
procedure SetStorage(Value: TJvFormPlacement);
|
|
function GetCapacity: Integer;
|
|
procedure SetCapacity(Value: Integer);
|
|
function GetMode: TRecentMode;
|
|
procedure SetMode(Value: TRecentMode);
|
|
procedure SetStartAccel(Value: Cardinal);
|
|
procedure SetShowAccelChar(Value: Boolean);
|
|
procedure SetAccelDelimiter(Value: TAccelDelimiter);
|
|
procedure SetAutoEnable(Value: Boolean);
|
|
procedure AddMenuItem(Item: TMenuItem);
|
|
procedure MenuItemClick(Sender: TObject);
|
|
procedure IniSave(Sender: TObject);
|
|
procedure IniLoad(Sender: TObject);
|
|
procedure InternalLoad(const Section: string);
|
|
procedure InternalSave(const Section: string);
|
|
procedure SetDuplicates(const Value: TDuplicates);
|
|
procedure DoDuplicateFixUp;
|
|
function GetStrings: TStrings;
|
|
procedure SetMenuLocation(const Value: TMenuLocation);
|
|
procedure SetMaxLength(const Value: Integer);
|
|
procedure SetStartEllipsis(const Value: Boolean);
|
|
protected
|
|
function GetCanvas: TCanvas;
|
|
function DoMinimizeName(const S: string): string;
|
|
procedure Change; dynamic;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure DoReadItem(AppStorage: TJvCustomAppStorage; const Path: string; Index: Integer;
|
|
var RecentName: string; var UserData: Longint); dynamic;
|
|
procedure DoWriteItem(AppStorage: TJvCustomAppStorage; const Path: string; Index: Integer;
|
|
const RecentName: string; UserData: Longint); dynamic;
|
|
procedure GetItemData(var Caption: string; var ShortCut: TShortCut;
|
|
UserData: Longint); dynamic;
|
|
procedure GetItemInfo(Item: TMenuItem); dynamic;
|
|
procedure GetItemInfoEx(Item: TMenuItem; Index: Integer); dynamic;
|
|
procedure DoClick(const RecentName, Caption: string; UserData: Longint); dynamic;
|
|
procedure DoBeforeUpdate; virtual;
|
|
procedure DoAfterUpdate; virtual;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Add(const RecentName: string; UserData: Longint);
|
|
procedure Clear;
|
|
procedure Remove(const RecentName: string);
|
|
procedure UpdateRecentMenu;
|
|
procedure RemoveInvalid;
|
|
procedure LoadFromAppStorage(const AppStorage: TJvCustomAppStorage; const Path: string);
|
|
procedure SaveToAppStorage(const AppStorage: TJvCustomAppStorage; const Path: string);
|
|
procedure Load;
|
|
procedure Save;
|
|
function IsMenuEnabled: Boolean;
|
|
property Strings: TStrings read GetStrings;
|
|
published
|
|
// Duplicates works just as for TStrings, but the list doesn't need to be sorted
|
|
property Duplicates: TDuplicates read FDuplicates write SetDuplicates;
|
|
property AccelDelimiter: TAccelDelimiter read FAccelDelimiter write SetAccelDelimiter default adTab;
|
|
property AutoEnable: Boolean read FAutoEnable write SetAutoEnable default True;
|
|
property AutoUpdate: Boolean read FAutoUpdate write FAutoUpdate default True;
|
|
property MaxLength: Integer read FMaxLength write SetMaxLength default 0;
|
|
property StartEllipsis: Boolean read FStartEllipsis write SetStartEllipsis default False;
|
|
property Capacity: Integer read GetCapacity write SetCapacity default 10;
|
|
property MenuLocation: TMenuLocation read FMenuLocation write SetMenuLocation default mruChild;
|
|
property Mode: TRecentMode read GetMode write SetMode default rmInsert;
|
|
property RemoveOnSelect: Boolean read FRemoveOnSelect write FRemoveOnSelect default False;
|
|
property IniStorage: TJvFormPlacement read GetStorage write SetStorage;
|
|
property SeparateSize: Word read FSeparateSize write SetSeparateSize default 0;
|
|
property RecentMenu: TMenuItem read FRecentMenu write SetRecentMenu;
|
|
property ShowAccelChar: Boolean read FShowAccelChar write SetShowAccelChar default True;
|
|
property StartAccel: Cardinal read FStartAccel write SetStartAccel default 1;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
property OnClick: TClickMenuEvent read FOnClick write FOnClick;
|
|
// OnGetItemData is called just before the menu item is created
|
|
property OnGetItemData: TGetItemEvent read FOnGetItem write FOnGetItem;
|
|
property OnReadItem: TReadItemEvent read FOnReadItem write FOnReadItem;
|
|
property OnWriteItem: TWriteItemEvent read FOnWriteItem write FOnWriteItem;
|
|
// called just before the menu items are updated
|
|
property OnBeforeUpdate: TNotifyEvent read FOnBeforeUpdate write FOnBeforeUpdate;
|
|
// called just after the menu items have been updated
|
|
property OnAfterUpdate: TNotifyEvent read FOnAfterUpdate write FOnAfterUpdate;
|
|
// called just before the newly created menu item is added to the RecentMenu submenu
|
|
// this makes it easier to set any additional properties of the menu item not
|
|
// handled by OnGetItemData.
|
|
property OnGetItemInfo: TGetItemInfoEvent read FOnItemInfo write FOnItemInfo;
|
|
property OnGetItemInfoEx: TGetItemInfoExEvent read FOnItemInfoEx write FOnItemInfoEx;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvMRUManager.pas $';
|
|
Revision: '$Revision: 11057 $';
|
|
Date: '$Date: 2006-11-29 15:32:05 +0100 (mer., 29 nov. 2006) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Math,
|
|
JclFileUtils,
|
|
JvJVCLUtils, JvConsts, JvResources, JvTypes;
|
|
|
|
const
|
|
siRecentItem = 'Item_%d';
|
|
siRecentData = 'User_%d';
|
|
|
|
//=== { TJvMRUManager } ======================================================
|
|
|
|
constructor TJvMRUManager.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FStrings := TJvRecentStrings.Create;
|
|
FItems := TList.Create;
|
|
FStrings.OnChange := ListChanged;
|
|
FIniLink := TJvIniLink.Create;
|
|
FIniLink.OnSave := IniSave;
|
|
FIniLink.OnLoad := IniLoad;
|
|
FAutoUpdate := True;
|
|
FAutoEnable := True;
|
|
FShowAccelChar := True;
|
|
FStartAccel := 1;
|
|
FMenuLocation := mruChild;
|
|
end;
|
|
|
|
destructor TJvMRUManager.Destroy;
|
|
begin
|
|
ClearRecentMenu;
|
|
FIniLink.Free;
|
|
FStrings.OnChange := nil;
|
|
FStrings.Free;
|
|
FreeAndNil(FItems);
|
|
FreeAndNil(FCanvas);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvMRUManager.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if (AComponent = RecentMenu) and (Operation = opRemove) then
|
|
RecentMenu := nil;
|
|
end;
|
|
|
|
function TJvMRUManager.GetStrings: TStrings;
|
|
begin
|
|
Result := FStrings;
|
|
end;
|
|
|
|
procedure TJvMRUManager.GetItemData(var Caption: string; var ShortCut: TShortCut;
|
|
UserData: Longint);
|
|
begin
|
|
if Assigned(FOnGetItem) then
|
|
FOnGetItem(Self, Caption, ShortCut, UserData);
|
|
end;
|
|
|
|
procedure TJvMRUManager.DoClick(const RecentName, Caption: string; UserData: Longint);
|
|
begin
|
|
if Assigned(FOnClick) then
|
|
FOnClick(Self, RecentName, Caption, UserData);
|
|
end;
|
|
|
|
procedure TJvMRUManager.MenuItemClick(Sender: TObject);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Sender is TMenuItem then
|
|
begin
|
|
I := TMenuItem(Sender).Tag;
|
|
if (I >= 0) and (I < Strings.Count) then
|
|
try
|
|
DoClick(Strings[I], TMenuItem(Sender).Caption, Longint(Strings.Objects[I]));
|
|
finally
|
|
if RemoveOnSelect then
|
|
Remove(Strings[I]);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJvMRUManager.GetCapacity: Integer;
|
|
begin
|
|
Result := FStrings.MaxSize;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetCapacity(Value: Integer);
|
|
begin
|
|
FStrings.MaxSize := Value;
|
|
end;
|
|
|
|
function TJvMRUManager.GetMode: TRecentMode;
|
|
begin
|
|
Result := FStrings.Mode;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetMode(Value: TRecentMode);
|
|
begin
|
|
FStrings.Mode := Value;
|
|
end;
|
|
|
|
function TJvMRUManager.GetStorage: TJvFormPlacement;
|
|
begin
|
|
Result := FIniLink.Storage;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetStorage(Value: TJvFormPlacement);
|
|
begin
|
|
FIniLink.Storage := Value;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetAutoEnable(Value: Boolean);
|
|
begin
|
|
if FAutoEnable <> Value then
|
|
begin
|
|
FAutoEnable := Value;
|
|
if Assigned(FRecentMenu) then
|
|
begin
|
|
if FAutoEnable then
|
|
FRecentMenu.Enabled := IsMenuEnabled
|
|
else
|
|
FRecentMenu.Enabled := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetStartAccel(Value: Cardinal);
|
|
begin
|
|
if FStartAccel <> Value then
|
|
begin
|
|
FStartAccel := Value;
|
|
if FAutoUpdate then
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetAccelDelimiter(Value: TAccelDelimiter);
|
|
begin
|
|
if FAccelDelimiter <> Value then
|
|
begin
|
|
FAccelDelimiter := Value;
|
|
if FAutoUpdate and ShowAccelChar then
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetShowAccelChar(Value: Boolean);
|
|
begin
|
|
if FShowAccelChar <> Value then
|
|
begin
|
|
FShowAccelChar := Value;
|
|
if FAutoUpdate then
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.Add(const RecentName: string; UserData: Longint);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not (Duplicates = dupAccept) and (Strings.IndexOf(RecentName) > -1) then
|
|
begin
|
|
if Duplicates = dupError then
|
|
raise EJVCLException.CreateRes(@RsEDuplicatesNotAllowedInMRUList);
|
|
end
|
|
else
|
|
begin
|
|
I := FStrings.Add(RecentName);
|
|
Strings.Objects[I] := TObject(UserData);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.Clear;
|
|
begin
|
|
Strings.Clear;
|
|
end;
|
|
|
|
procedure TJvMRUManager.Remove(const RecentName: string);
|
|
begin
|
|
FStrings.Remove(RecentName);
|
|
end;
|
|
|
|
procedure TJvMRUManager.AddMenuItem(Item: TMenuItem);
|
|
begin
|
|
if Assigned(Item) then
|
|
begin
|
|
if FMenuLocation = mruSibling then
|
|
begin
|
|
if FRecentMenu.HasParent and (FRecentMenu.Parent.MenuIndex >= 0) then
|
|
FRecentMenu.Parent.Insert(FRecentMenu.MenuIndex + FItems.Count + 1, Item)
|
|
else
|
|
FRecentMenu.Add(Item);
|
|
end
|
|
else
|
|
FRecentMenu.Add(Item);
|
|
FItems.Add(Item);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.DoDuplicateFixUp;
|
|
var
|
|
I, J: Integer;
|
|
Tmp: Boolean;
|
|
begin
|
|
if Duplicates = dupAccept then
|
|
Exit;
|
|
Tmp := AutoUpdate;
|
|
try
|
|
AutoUpdate := False;
|
|
I := Strings.Count - 1;
|
|
while I >= 0 do
|
|
begin
|
|
// we don't raise an error here even if Duplicates is dupError
|
|
J := Strings.IndexOf(Strings[I]);
|
|
while (J > -1) and (J <> I) do
|
|
begin
|
|
Strings.Delete(J);
|
|
Dec(I);
|
|
J := Strings.IndexOf(Strings[I]);
|
|
end;
|
|
Dec(I);
|
|
end;
|
|
finally
|
|
AutoUpdate := Tmp;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.UpdateRecentMenu;
|
|
const
|
|
AccelDelimChars: array[TAccelDelimiter] of Char = (Tab, ' ');
|
|
var
|
|
I: Integer;
|
|
L: Cardinal;
|
|
S: string;
|
|
C: string[2];
|
|
ShortCut: TShortCut;
|
|
Item: TMenuItem;
|
|
begin
|
|
ClearRecentMenu;
|
|
DoDuplicateFixUp;
|
|
DoBeforeUpdate;
|
|
if Assigned(FRecentMenu) then
|
|
begin
|
|
if ((Strings.Count > 0) and (FRecentMenu.Count > 0) and (MenuLocation = mruChild)) then
|
|
AddMenuItem(NewLine);
|
|
for I := 0 to Strings.Count - 1 do
|
|
begin
|
|
if (FSeparateSize > 0) and (I > 0) and (I mod FSeparateSize = 0) then
|
|
AddMenuItem(NewLine)
|
|
else
|
|
if (I = 0) and (MenuLocation = mruSibling) and (FRecentMenu.Count = 0) then
|
|
AddMenuItem(NewLine);
|
|
S := Strings[I];
|
|
ShortCut := scNone;
|
|
GetItemData(S, ShortCut, Longint(Strings.Objects[I]));
|
|
Item := NewItem(GetShortHint(S), ShortCut, False, True,
|
|
MenuItemClick, 0, '');
|
|
Item.Hint := GetLongHint(S);
|
|
if FShowAccelChar then
|
|
begin
|
|
L := Cardinal(I) + FStartAccel;
|
|
if L < 10 then
|
|
C := '&' + Char(Ord('0') + L)
|
|
else
|
|
if L <= (Ord('Z') + 10) then
|
|
C := '&' + Char(L + Ord('A') - 10)
|
|
else
|
|
C := ' ';
|
|
Item.Caption := C + AccelDelimChars[FAccelDelimiter] + DoMinimizeName(S);
|
|
end
|
|
else
|
|
begin
|
|
Item.Caption := DoMinimizeName(S);
|
|
end;
|
|
Item.Tag := I;
|
|
AddMenuItem(Item);
|
|
GetItemInfoEx(Item, I);
|
|
end;
|
|
DoAfterUpdate;
|
|
if AutoEnable then
|
|
FRecentMenu.Enabled := IsMenuEnabled;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.ClearRecentMenu;
|
|
var
|
|
Item: TMenuItem;
|
|
begin
|
|
while FItems.Count > 0 do
|
|
begin
|
|
Item := TMenuItem(FItems[0]);
|
|
FItems.Remove(Item);
|
|
// (p3) it doesn't matter if the item is in FRecentMenu or not - it still needs to be freed
|
|
// this also avoids duplicates when MenuLocation = mruSibling
|
|
// if Assigned(FRecentMenu) and (FRecentMenu.IndexOf(Item) >= 0) then
|
|
Item.Free;
|
|
end;
|
|
if Assigned(FRecentMenu) and AutoEnable then
|
|
FRecentMenu.Enabled := IsMenuEnabled;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetRecentMenu(Value: TMenuItem);
|
|
begin
|
|
ClearRecentMenu;
|
|
FRecentMenu := Value;
|
|
if Value <> nil then
|
|
Value.FreeNotification(Self);
|
|
FreeAndNil(FCanvas);
|
|
UpdateRecentMenu;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetSeparateSize(Value: Word);
|
|
begin
|
|
if FSeparateSize <> Value then
|
|
begin
|
|
FSeparateSize := Value;
|
|
if FAutoUpdate then
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.ListChanged(Sender: TObject);
|
|
begin
|
|
Change;
|
|
if FAutoUpdate then
|
|
UpdateRecentMenu;
|
|
end;
|
|
|
|
procedure TJvMRUManager.IniSave(Sender: TObject);
|
|
begin
|
|
if (Name <> '') and Assigned(IniStorage) then
|
|
InternalSave(GetDefaultSection(Self));
|
|
end;
|
|
|
|
procedure TJvMRUManager.IniLoad(Sender: TObject);
|
|
begin
|
|
if (Name <> '') and Assigned(IniStorage) then
|
|
InternalLoad(GetDefaultSection(Self));
|
|
end;
|
|
|
|
procedure TJvMRUManager.Change;
|
|
begin
|
|
if Assigned(FOnChange) then
|
|
FOnChange(Self);
|
|
end;
|
|
|
|
procedure TJvMRUManager.DoReadItem(AppStorage: TJvCustomAppStorage; const Path: string;
|
|
Index: Integer; var RecentName: string; var UserData: Longint);
|
|
begin
|
|
if Assigned(FOnReadItem) then
|
|
FOnReadItem(Self, AppStorage, Path, Index, RecentName, UserData)
|
|
else
|
|
begin
|
|
RecentName := AppStorage.ReadString(AppStorage.ConcatPaths(
|
|
[Path, Format(siRecentItem, [Index])]), RecentName);
|
|
UserData := AppStorage.ReadInteger(AppStorage.ConcatPaths(
|
|
[Path, Format(siRecentData, [Index])]), UserData);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.DoWriteItem(AppStorage: TJvCustomAppStorage; const Path: string;
|
|
Index: Integer; const RecentName: string; UserData: Longint);
|
|
begin
|
|
if Assigned(FOnWriteItem) then
|
|
FOnWriteItem(Self, AppStorage, Path, Index, RecentName, UserData)
|
|
else
|
|
begin
|
|
AppStorage.WriteString(AppStorage.ConcatPaths(
|
|
[Path, Format(siRecentItem, [Index])]), RecentName);
|
|
if UserData = 0 then
|
|
AppStorage.DeleteValue(AppStorage.ConcatPaths(
|
|
[Path, Format(siRecentData, [Index])]))
|
|
else
|
|
AppStorage.WriteInteger(AppStorage.ConcatPaths(
|
|
[Path, Format(siRecentData, [Index])]), UserData);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.InternalLoad(const Section: string);
|
|
begin
|
|
if Assigned(IniStorage) then
|
|
with IniStorage do
|
|
LoadFromAppStorage(AppStorage, AppStorage.ConcatPaths([AppStoragePath, Section]));
|
|
end;
|
|
|
|
procedure TJvMRUManager.InternalSave(const Section: string);
|
|
begin
|
|
if Assigned(IniStorage) then
|
|
with IniStorage do
|
|
SaveToAppStorage(AppStorage, AppStorage.ConcatPaths([AppStoragePath, Section]));
|
|
end;
|
|
|
|
procedure TJvMRUManager.LoadFromAppStorage(const AppStorage: TJvCustomAppStorage; const Path: string);
|
|
var
|
|
I: Integer;
|
|
S: string;
|
|
UserData: Longint;
|
|
AMode: TRecentMode;
|
|
begin
|
|
AMode := Mode;
|
|
Strings.BeginUpdate;
|
|
try
|
|
Strings.Clear;
|
|
Mode := rmInsert;
|
|
for I := FStrings.MaxSize - 1 downto 0 do
|
|
begin
|
|
S := '';
|
|
UserData := 0;
|
|
DoReadItem(AppStorage, Path, I, S, UserData);
|
|
if S <> '' then
|
|
Add(S, UserData);
|
|
end;
|
|
finally
|
|
Mode := AMode;
|
|
Strings.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SaveToAppStorage(const AppStorage: TJvCustomAppStorage; const Path: string);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
AppStorage.DeleteSubTree(Path);
|
|
for I := 0 to Strings.Count - 1 do
|
|
DoWriteItem(AppStorage, Path, I, Strings[I], Longint(Strings.Objects[I]));
|
|
end;
|
|
|
|
procedure TJvMRUManager.Load;
|
|
begin
|
|
IniLoad(nil);
|
|
end;
|
|
|
|
procedure TJvMRUManager.Save;
|
|
begin
|
|
IniSave(nil);
|
|
end;
|
|
|
|
procedure TJvMRUManager.DoAfterUpdate;
|
|
begin
|
|
if Assigned(FOnAfterUpdate) then
|
|
FOnAfterUpdate(Self);
|
|
end;
|
|
|
|
procedure TJvMRUManager.DoBeforeUpdate;
|
|
begin
|
|
if Assigned(FOnBeforeUpdate) then
|
|
FOnBeforeUpdate(Self);
|
|
end;
|
|
|
|
procedure TJvMRUManager.RemoveInvalid;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := Strings.Count - 1 downto 0 do
|
|
if not FileExists(Strings[I]) then
|
|
Strings.Delete(I);
|
|
end;
|
|
|
|
procedure TJvMRUManager.GetItemInfo(Item: TMenuItem);
|
|
begin
|
|
if Assigned(FOnItemInfo) then
|
|
FOnItemInfo(Self, Item);
|
|
end;
|
|
|
|
procedure TJvMRUManager.GetItemInfoEx(Item: TMenuItem; Index: Integer);
|
|
begin
|
|
GetItemInfo(Item);
|
|
if Assigned(FOnItemInfoEx) then
|
|
FOnItemInfoEx(Self, Item, Index);
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetDuplicates(const Value: TDuplicates);
|
|
begin
|
|
if FDuplicates <> Value then
|
|
begin
|
|
FDuplicates := Value;
|
|
if FAutoUpdate then
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
//=== { TJvRecentStrings } ===================================================
|
|
|
|
constructor TJvRecentStrings.Create;
|
|
begin
|
|
inherited Create;
|
|
FMaxSize := 10;
|
|
FMode := rmInsert;
|
|
end;
|
|
|
|
procedure TJvRecentStrings.SetTextStr(const Value: String);
|
|
var
|
|
LastMode: TRecentMode;
|
|
begin
|
|
{ Temporary change the FMode to rmAppend so the lines in Value will be added
|
|
in the correct ordern. }
|
|
LastMode := FMode;
|
|
try
|
|
FMode := rmAppend;
|
|
inherited SetTextStr(Value);
|
|
finally
|
|
FMode := LastMode;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvRecentStrings.SetMaxSize(Value: Integer);
|
|
begin
|
|
if FMaxSize <> Value then
|
|
begin
|
|
FMaxSize := Max(1, Value);
|
|
DeleteExceed;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvRecentStrings.DeleteExceed;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if FMode = rmInsert then
|
|
for I := Count - 1 downto FMaxSize do
|
|
Delete(I)
|
|
else
|
|
begin { rmAppend }
|
|
while Count > FMaxSize do
|
|
Delete(0);
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvRecentStrings.Remove(const S: string);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
I := IndexOf(S);
|
|
if I >= 0 then
|
|
Delete(I);
|
|
end;
|
|
|
|
function TJvRecentStrings.Add(const S: string): Integer;
|
|
begin
|
|
Result := IndexOf(S);
|
|
if Result >= 0 then
|
|
begin
|
|
if FMode = rmInsert then
|
|
Move(Result, 0)
|
|
else { rmAppend }
|
|
Move(Result, Count - 1);
|
|
end
|
|
else
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if FMode = rmInsert then
|
|
Insert(0, S)
|
|
else { rmAppend }
|
|
Insert(Count, S);
|
|
DeleteExceed;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
if FMode = rmInsert then
|
|
Result := 0
|
|
else { rmAppend }
|
|
Result := Count - 1;
|
|
end;
|
|
|
|
procedure TJvRecentStrings.AddStrings(Strings: TStrings);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if FMode = rmInsert then
|
|
begin
|
|
for I := Min(Strings.Count, FMaxSize) - 1 downto 0 do
|
|
AddObject(Strings[I], Strings.Objects[I]);
|
|
end
|
|
else { rmAppend }
|
|
for I := 0 to Min(Strings.Count, FMaxSize) - 1 do
|
|
AddObject(Strings[I], Strings.Objects[I]);
|
|
DeleteExceed;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetMenuLocation(const Value: TMenuLocation);
|
|
begin
|
|
if FMenuLocation <> Value then
|
|
begin
|
|
FMenuLocation := Value;
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
function TJvMRUManager.IsMenuEnabled: Boolean;
|
|
begin
|
|
Result := ((MenuLocation = mruChild) and (FRecentMenu.Count > 0)) or
|
|
((MenuLocation = mruSibling) and (Strings.Count > 0));
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetMaxLength(const Value: Integer);
|
|
begin
|
|
if FMaxLength <> Value then
|
|
begin
|
|
FMaxLength := Value;
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
function TJvMRUManager.GetCanvas: TCanvas;
|
|
begin
|
|
if FCanvas = nil then
|
|
begin
|
|
FCanvas := TCanvas.Create;
|
|
if RecentMenu <> nil then
|
|
FCanvas.Handle := GetDC(GetDesktopWindow);
|
|
end;
|
|
Result := FCanvas;
|
|
end;
|
|
|
|
function TJvMRUManager.DoMinimizeName(const S: string): string;
|
|
begin
|
|
Result := '';
|
|
if MaxLength > 0 then
|
|
begin
|
|
if not StartEllipsis then
|
|
Result := PathCompactPath(
|
|
{$IFDEF VCL}
|
|
GetCanvas.Handle,
|
|
{$ENDIF VCL}
|
|
{$IFDEF VisualCLX}
|
|
QPainter_handle(GetCanvas.Handle),
|
|
{$ENDIF VisualCLX}
|
|
S, GetCanvas.TextWidth('n') * MaxLength, cpCenter)
|
|
else
|
|
if Length(S) > MaxLength then
|
|
Result := '...' + Copy(S, Length(S) - MaxLength + 1, MaxInt);
|
|
end;
|
|
if (Result = '...') or (Result = '') then
|
|
Result := S;
|
|
end;
|
|
|
|
procedure TJvMRUManager.SetStartEllipsis(const Value: Boolean);
|
|
begin
|
|
if FStartEllipsis <> Value then
|
|
begin
|
|
FStartEllipsis := Value;
|
|
UpdateRecentMenu;
|
|
end;
|
|
end;
|
|
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
|
|
end.
|
|
|