Mrulist.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:16k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1997, 1998 Master-Bank          }
  6. {                                                       }
  7. {*******************************************************}
  8. unit MRUList;
  9. {$I RX.INC}
  10. {$R-,B-}
  11. interface
  12. uses SysUtils, Classes, Menus, IniFiles {$IFDEF WIN32}, Registry {$ENDIF},
  13.   Placemnt;
  14. type
  15.   TRecentStrings = class;
  16. { TMRUManager }
  17.   TGetItemEvent = procedure (Sender: TObject; var Caption: string;
  18.     var ShortCut: TShortCut; UserData: Longint) of object;
  19.   TReadItemEvent = procedure (Sender: TObject; IniFile: TObject;
  20.     const Section: string; Index: Integer; var RecentName: string;
  21.     var UserData: Longint) of object;
  22.   TWriteItemEvent = procedure (Sender: TObject; IniFile: TObject;
  23.     const Section: string; Index: Integer; const RecentName: string;
  24.     UserData: Longint) of object;
  25.   TClickMenuEvent = procedure (Sender: TObject; const RecentName,
  26.     Caption: string; UserData: Longint) of object;
  27.   TAccelDelimiter = (adTab, adSpace);
  28.   TRecentMode = (rmInsert, rmAppend);
  29.   TMRUManager = class(TComponent)
  30.   private
  31.     FList: TStrings;
  32.     FItems: TList;
  33.     FIniLink: TIniLink;
  34.     FSeparateSize: Word;
  35.     FAutoEnable: Boolean;
  36.     FAutoUpdate: Boolean;
  37.     FShowAccelChar: Boolean;
  38.     FRemoveOnSelect: Boolean;
  39.     FStartAccel: Cardinal;
  40.     FAccelDelimiter: TAccelDelimiter;
  41.     FRecentMenu: TMenuItem;
  42.     FOnChange: TNotifyEvent;
  43.     FOnGetItem: TGetItemEvent;
  44.     FOnClick: TClickMenuEvent;
  45.     FOnReadItem: TReadItemEvent;
  46.     FOnWriteItem: TWriteItemEvent;
  47.     procedure ListChanged(Sender: TObject);
  48.     procedure ClearRecentMenu;
  49.     procedure SetRecentMenu(Value: TMenuItem);
  50.     procedure SetSeparateSize(Value: Word);
  51.     function GetStorage: TFormPlacement;
  52.     procedure SetStorage(Value: TFormPlacement);
  53.     function GetCapacity: Integer;
  54.     procedure SetCapacity(Value: Integer);
  55.     function GetMode: TRecentMode;
  56.     procedure SetMode(Value: TRecentMode);
  57.     procedure SetStartAccel(Value: Cardinal);
  58.     procedure SetShowAccelChar(Value: Boolean);
  59.     procedure SetAccelDelimiter(Value: TAccelDelimiter);
  60.     procedure SetAutoEnable(Value: Boolean);
  61.     procedure AddMenuItem(Item: TMenuItem);
  62.     procedure MenuItemClick(Sender: TObject);
  63.     procedure IniSave(Sender: TObject);
  64.     procedure IniLoad(Sender: TObject);
  65.     procedure InternalLoad(Ini: TObject; const Section: string);
  66.     procedure InternalSave(Ini: TObject; const Section: string);
  67.   protected
  68.     procedure Change; dynamic;
  69.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  70.     procedure DoReadItem(Ini: TObject; const Section: string;
  71.       Index: Integer; var RecentName: string; var UserData: Longint); dynamic;
  72.     procedure DoWriteItem(Ini: TObject; const Section: string; Index: Integer;
  73.       const RecentName: string; UserData: Longint); dynamic;
  74.     procedure GetItemData(var Caption: string; var ShortCut: TShortCut;
  75.       UserData: Longint); dynamic;
  76.     procedure DoClick(const RecentName, Caption: string; UserData: Longint); dynamic;
  77.   public
  78.     constructor Create(AOwner: TComponent); override;
  79.     destructor Destroy; override;
  80.     procedure Add(const RecentName: string; UserData: Longint);
  81.     procedure Clear;
  82.     procedure Remove(const RecentName: string);
  83.     procedure UpdateRecentMenu;
  84. {$IFDEF WIN32}
  85.     procedure LoadFromRegistry(Ini: TRegIniFile; const Section: string);
  86.     procedure SaveToRegistry(Ini: TRegIniFile; const Section: string);
  87. {$ENDIF WIN32}
  88.     procedure LoadFromIni(Ini: TIniFile; const Section: string);
  89.     procedure SaveToIni(Ini: TIniFile; const Section: string);
  90.     property Strings: TStrings read FList;
  91.   published
  92.     property AccelDelimiter: TAccelDelimiter read FAccelDelimiter write SetAccelDelimiter default adTab;
  93.     property AutoEnable: Boolean read FAutoEnable write SetAutoEnable default True;
  94.     property AutoUpdate: Boolean read FAutoUpdate write FAutoUpdate default True;
  95.     property Capacity: Integer read GetCapacity write SetCapacity default 10;
  96.     property Mode: TRecentMode read GetMode write SetMode default rmInsert;
  97.     property RemoveOnSelect: Boolean read FRemoveOnSelect write FRemoveOnSelect default False;
  98.     property IniStorage: TFormPlacement read GetStorage write SetStorage;
  99.     property SeparateSize: Word read FSeparateSize write SetSeparateSize default 0;
  100.     property RecentMenu: TMenuItem read FRecentMenu write SetRecentMenu;
  101.     property ShowAccelChar: Boolean read FShowAccelChar write SetShowAccelChar default True;
  102.     property StartAccel: Cardinal read FStartAccel write SetStartAccel default 1;
  103.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  104.     property OnClick: TClickMenuEvent read FOnClick write FOnClick;
  105.     property OnGetItemData: TGetItemEvent read FOnGetItem write FOnGetItem;
  106.     property OnReadItem: TReadItemEvent read FOnReadItem write FOnReadItem;
  107.     property OnWriteItem: TWriteItemEvent read FOnWriteItem write FOnWriteItem;
  108.   end;
  109. { TRecentStrings }
  110.   TRecentStrings = class(TStringList)
  111.   private
  112.     FMaxSize: Integer;
  113.     FMode: TRecentMode;
  114.     procedure SetMaxSize(Value: Integer);
  115.   public
  116.     constructor Create;
  117.     function Add(const S: string): Integer; override;
  118.     procedure AddStrings(Strings: TStrings); override;
  119.     procedure DeleteExceed;
  120.     procedure Remove(const S: String);
  121.     property MaxSize: Integer read FMaxSize write SetMaxSize;
  122.     property Mode: TRecentMode read FMode write FMode;
  123.   end;
  124. implementation
  125. uses Controls, MaxMin, AppUtils;
  126. const
  127.   siRecentItem = 'Item_%d';
  128.   siRecentData = 'User_%d';
  129. { TMRUManager }
  130. constructor TMRUManager.Create(AOwner: TComponent);
  131. begin
  132.   inherited Create(AOwner);
  133.   FList := TRecentStrings.Create;
  134.   FItems := TList.Create;
  135.   TRecentStrings(FList).OnChange := ListChanged;
  136.   FIniLink := TIniLink.Create;
  137.   FIniLink.OnSave := IniSave;
  138.   FIniLink.OnLoad := IniLoad;
  139.   FAutoUpdate := True;
  140.   FAutoEnable := True;
  141.   FShowAccelChar := True;
  142.   FStartAccel := 1;
  143. end;
  144. destructor TMRUManager.Destroy;
  145. begin
  146.   ClearRecentMenu;
  147.   FIniLink.Free;
  148.   TRecentStrings(FList).OnChange := nil;
  149.   FList.Free;
  150.   FItems.Free;
  151.   FItems := nil;
  152.   inherited Destroy;
  153. end;
  154. procedure TMRUManager.Notification(AComponent: TComponent; Operation: TOperation);
  155. begin
  156.   inherited Notification(AComponent, Operation);
  157.   if (AComponent = RecentMenu) and (Operation = opRemove) then
  158.     RecentMenu := nil;
  159. end;
  160. procedure TMRUManager.GetItemData(var Caption: string; var ShortCut: TShortCut;
  161.   UserData: Longint);
  162. begin
  163.   if Assigned(FOnGetItem) then FOnGetItem(Self, Caption, ShortCut, UserData);
  164. end;
  165. procedure TMRUManager.DoClick(const RecentName, Caption: string; UserData: Longint);
  166. begin
  167.   if Assigned(FOnClick) then FOnClick(Self, RecentName, Caption, UserData);
  168. end;
  169. procedure TMRUManager.MenuItemClick(Sender: TObject);
  170. var
  171.   I: Integer;
  172. begin
  173.   if Sender is TMenuItem then begin
  174.     I := TMenuItem(Sender).Tag;
  175.     if (I >= 0) and (I < FList.Count) then
  176.       try
  177.         DoClick(FList[I], TMenuItem(Sender).Caption, Longint(FList.Objects[I]));
  178.       finally
  179.         if RemoveOnSelect then Remove(FList[I]);
  180.       end;
  181.   end;
  182. end;
  183. function TMRUManager.GetCapacity: Integer;
  184. begin
  185.   Result := TRecentStrings(FList).MaxSize;
  186. end;
  187. procedure TMRUManager.SetCapacity(Value: Integer);
  188. begin
  189.   TRecentStrings(FList).MaxSize := Value;
  190. end;
  191. function TMRUManager.GetMode: TRecentMode;
  192. begin
  193.   Result := TRecentStrings(FList).Mode;
  194. end;
  195. procedure TMRUManager.SetMode(Value: TRecentMode);
  196. begin
  197.   TRecentStrings(FList).Mode := Value;
  198. end;
  199. function TMRUManager.GetStorage: TFormPlacement;
  200. begin
  201.   Result := FIniLink.Storage;
  202. end;
  203. procedure TMRUManager.SetStorage(Value: TFormPlacement);
  204. begin
  205.   FIniLink.Storage := Value;
  206. end;
  207. procedure TMRUManager.SetAutoEnable(Value: Boolean);
  208. begin
  209.   if FAutoEnable <> Value then begin
  210.     FAutoEnable := Value;
  211.     if Assigned(FRecentMenu) and FAutoEnable then
  212.       FRecentMenu.Enabled := FRecentMenu.Count > 0;
  213.   end;
  214. end;
  215. procedure TMRUManager.SetStartAccel(Value: Cardinal);
  216. begin
  217.   if FStartAccel <> Value then begin
  218.     FStartAccel := Value;
  219.     if FAutoUpdate then UpdateRecentMenu;
  220.   end;
  221. end;
  222. procedure TMRUManager.SetAccelDelimiter(Value: TAccelDelimiter);
  223. begin
  224.   if FAccelDelimiter <> Value then begin
  225.     FAccelDelimiter := Value;
  226.     if FAutoUpdate and ShowAccelChar then UpdateRecentMenu;
  227.   end;
  228. end;
  229. procedure TMRUManager.SetShowAccelChar(Value: Boolean);
  230. begin
  231.   if FShowAccelChar <> Value then begin
  232.     FShowAccelChar := Value;
  233.     if FAutoUpdate then UpdateRecentMenu;
  234.   end;
  235. end;
  236. procedure TMRUManager.Add(const RecentName: string; UserData: Longint);
  237. begin
  238.   FList.AddObject(RecentName, TObject(UserData));
  239. end;
  240. procedure TMRUManager.Clear;
  241. begin
  242.   FList.Clear;
  243. end;
  244. procedure TMRUManager.Remove(const RecentName: string);
  245. begin
  246.   TRecentStrings(FList).Remove(RecentName);
  247. end;
  248. procedure TMRUManager.AddMenuItem(Item: TMenuItem);
  249. begin
  250.   if Assigned(Item) then begin
  251.     FRecentMenu.Add(Item);
  252.     FItems.Add(Item);
  253.   end;
  254. end;
  255. procedure TMRUManager.UpdateRecentMenu;
  256. const
  257.   AccelDelimChars: array[TAccelDelimiter] of Char = (#9, ' ');
  258. var
  259.   I: Integer;
  260.   L: Cardinal;
  261.   S: string;
  262.   C: string[2];
  263.   ShortCut: TShortCut;
  264.   Item: TMenuItem;
  265. begin
  266.   ClearRecentMenu;
  267.   if Assigned(FRecentMenu) then begin
  268.     if (FList.Count > 0) and (FRecentMenu.Count > 0) then
  269.       AddMenuItem(NewLine);
  270.     for I := 0 to FList.Count - 1 do begin
  271.       if (FSeparateSize > 0) and (I > 0) and (I mod FSeparateSize = 0) then
  272.         AddMenuItem(NewLine);
  273.       S := FList[I];
  274.       ShortCut := scNone;
  275.       GetItemData(S, ShortCut, Longint(FList.Objects[I]));
  276.       Item := NewItem(GetShortHint(S), ShortCut, False, True,
  277.         MenuItemClick, 0, '');
  278.       Item.Hint := GetLongHint(S);
  279.       if FShowAccelChar then begin
  280.         L := Cardinal(I) + FStartAccel;
  281.         if L < 10 then
  282.           C := '&' + Char(Ord('0') + L)
  283.         else if L <= (Ord('Z') + 10) then
  284.           C := '&' + Char(L + Ord('A') - 10)
  285.         else
  286.           C := ' ';
  287.         Item.Caption := C + AccelDelimChars[FAccelDelimiter] + Item.Caption;
  288.       end;
  289.       Item.Tag := I;
  290.       AddMenuItem(Item);
  291.     end;
  292.     if AutoEnable then FRecentMenu.Enabled := FRecentMenu.Count > 0;
  293.   end;
  294. end;
  295. procedure TMRUManager.ClearRecentMenu;
  296. var
  297.   Item: TMenuItem;
  298. begin
  299.   while FItems.Count > 0 do begin
  300.     Item := TMenuItem(FItems.Last);
  301.     if Assigned(FRecentMenu) and (FRecentMenu.IndexOf(Item) >= 0) then
  302.       Item.Free;
  303.     FItems.Remove(Item);
  304.   end;
  305.   if Assigned(FRecentMenu) and AutoEnable then
  306.     FRecentMenu.Enabled := FRecentMenu.Count > 0;
  307. end;
  308. procedure TMRUManager.SetRecentMenu(Value: TMenuItem);
  309. begin
  310.   ClearRecentMenu;
  311.   FRecentMenu := Value;
  312. {$IFDEF WIN32}
  313.   if Value <> nil then Value.FreeNotification(Self);
  314. {$ENDIF}
  315.   UpdateRecentMenu;
  316. end;
  317. procedure TMRUManager.SetSeparateSize(Value: Word);
  318. begin
  319.   if FSeparateSize <> Value then begin
  320.     FSeparateSize := Value;
  321.     if FAutoUpdate then UpdateRecentMenu;
  322.   end;
  323. end;
  324. procedure TMRUManager.ListChanged(Sender: TObject);
  325. begin
  326.   Change;
  327.   if FAutoUpdate then UpdateRecentMenu;
  328. end;
  329. procedure TMRUManager.IniSave(Sender: TObject);
  330. begin
  331.   if (Name <> '') and (FIniLink.IniObject <> nil) then
  332.     InternalSave(FIniLink.IniObject, FIniLink.RootSection +
  333.       GetDefaultSection(Self));
  334. end;
  335. procedure TMRUManager.IniLoad(Sender: TObject);
  336. begin
  337.   if (Name <> '') and (FIniLink.IniObject <> nil) then
  338.     InternalLoad(FIniLink.IniObject, FIniLink.RootSection +
  339.       GetDefaultSection(Self));
  340. end;
  341. procedure TMRUManager.Change;
  342. begin
  343.   if Assigned(FOnChange) then FOnChange(Self);
  344. end;
  345. procedure TMRUManager.DoReadItem(Ini: TObject; const Section: string;
  346.   Index: Integer; var RecentName: string; var UserData: Longint);
  347. begin
  348.   if Assigned(FOnReadItem) then
  349.     FOnReadItem(Self, Ini, Section, Index, RecentName, UserData)
  350.   else begin
  351.     RecentName := IniReadString(Ini, Section, Format(siRecentItem, [Index]), RecentName);
  352.     UserData := IniReadInteger(Ini, Section, Format(siRecentData, [Index]), UserData);
  353.   end;
  354. end;
  355. procedure TMRUManager.DoWriteItem(Ini: TObject; const Section: string;
  356.   Index: Integer; const RecentName: string; UserData: Longint);
  357. begin
  358.   if Assigned(FOnWriteItem) then
  359.     FOnWriteItem(Self, Ini, Section, Index, RecentName, UserData)
  360.   else begin
  361.     IniWriteString(Ini, Section, Format(siRecentItem, [Index]), RecentName);
  362.     if UserData = 0 then
  363.       IniDeleteKey(Ini, Section, Format(siRecentData, [Index]))
  364.     else
  365.       IniWriteInteger(Ini, Section, Format(siRecentData, [Index]), UserData);
  366.   end;
  367. end;
  368. procedure TMRUManager.InternalLoad(Ini: TObject; const Section: string);
  369. var
  370.   I: Integer;
  371.   S: string;
  372.   UserData: Longint;
  373.   AMode: TRecentMode;
  374. begin
  375.   AMode := Mode;
  376.   FList.BeginUpdate;
  377.   try
  378.     FList.Clear;
  379.     Mode := rmInsert;
  380.     for I := TRecentStrings(FList).MaxSize - 1 downto 0 do begin
  381.       S := '';
  382.       UserData := 0;
  383.       DoReadItem(Ini, Section, I, S, UserData);
  384.       if S <> '' then Add(S, UserData);
  385.     end;
  386.   finally
  387.     Mode := AMode;
  388.     FList.EndUpdate;
  389.   end;
  390. end;
  391. procedure TMRUManager.InternalSave(Ini: TObject; const Section: string);
  392. var
  393.   I: Integer;
  394. begin
  395.   IniEraseSection(Ini, Section);
  396.   for I := 0 to FList.Count - 1 do
  397.     DoWriteItem(Ini, Section, I, FList[I], Longint(FList.Objects[I]));
  398. end;
  399. {$IFDEF WIN32}
  400. procedure TMRUManager.LoadFromRegistry(Ini: TRegIniFile; const Section: string);
  401. begin
  402.   InternalLoad(Ini, Section);
  403. end;
  404. procedure TMRUManager.SaveToRegistry(Ini: TRegIniFile; const Section: string);
  405. begin
  406.   InternalSave(Ini, Section);
  407. end;
  408. {$ENDIF WIN32}
  409. procedure TMRUManager.LoadFromIni(Ini: TIniFile; const Section: string);
  410. begin
  411.   InternalLoad(Ini, Section);
  412. end;
  413. procedure TMRUManager.SaveToIni(Ini: TIniFile; const Section: string);
  414. begin
  415.   InternalSave(Ini, Section);
  416. end;
  417. { TRecentStrings }
  418. constructor TRecentStrings.Create;
  419. begin
  420.   inherited Create;
  421.   FMaxSize := 10;
  422.   FMode := rmInsert;
  423. end;
  424. procedure TRecentStrings.SetMaxSize(Value: Integer);
  425. begin
  426.   if FMaxSize <> Value then begin
  427.     FMaxSize := Max(1, Value);
  428.     DeleteExceed;
  429.   end;
  430. end;
  431. procedure TRecentStrings.DeleteExceed;
  432. var
  433.   I: Integer;
  434. begin
  435.   BeginUpdate;
  436.   try
  437.     if FMode = rmInsert then begin
  438.       for I := Count - 1 downto FMaxSize do Delete(I);
  439.     end
  440.     else begin { rmAppend }
  441.       while Count > FMaxSize do Delete(0);
  442.     end;
  443.   finally
  444.     EndUpdate;
  445.   end;
  446. end;
  447. procedure TRecentStrings.Remove(const S: String);
  448. var
  449.   I: Integer;
  450. begin
  451.   I := IndexOf(S);
  452.   if I >= 0 then Delete(I);
  453. end;
  454. function TRecentStrings.Add(const S: String): Integer;
  455. begin
  456.   Result := IndexOf(S);
  457.   if Result >= 0 then begin
  458.     if FMode = rmInsert then Move(Result, 0)
  459.     else { rmAppend } Move(Result, Count - 1);
  460.   end
  461.   else begin
  462.     BeginUpdate;
  463.     try
  464.       if FMode = rmInsert then Insert(0, S)
  465.       else { rmAppend } Insert(Count, S);
  466.       DeleteExceed;
  467.     finally
  468.       EndUpdate;
  469.     end;
  470.   end;
  471.   if FMode = rmInsert then Result := 0
  472.   else { rmAppend } Result := Count - 1;
  473. end;
  474. procedure TRecentStrings.AddStrings(Strings: TStrings);
  475. var
  476.   I: Integer;
  477. begin
  478.   BeginUpdate;
  479.   try
  480.     if FMode = rmInsert then begin
  481.       for I := Min(Strings.Count, FMaxSize) - 1 downto 0 do
  482.         AddObject(Strings[I], Strings.Objects[I]);
  483.     end
  484.     else begin { rmAppend }
  485.       for I := 0 to Min(Strings.Count, FMaxSize) - 1 do
  486.         AddObject(Strings[I], Strings.Objects[I]);
  487.     end;
  488.     DeleteExceed;
  489.   finally
  490.     EndUpdate;
  491.   end;
  492. end;
  493. end.