mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
678 lines
24 KiB
ObjectPascal
678 lines
24 KiB
ObjectPascal
{
|
|
Double Commander
|
|
-------------------------------------------------------------------------
|
|
Implements custom commands for a component
|
|
|
|
Copyright (C) 2011-2012 Przemyslaw Nagay (cobines@gmail.com)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
}
|
|
|
|
unit uFormCommands;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, StringHashList, ActnList, Menus;
|
|
|
|
type
|
|
TCommandFuncResult = (cfrSuccess, cfrDisabled, cfrNotFound);
|
|
TCommandFunc = procedure(const Params: array of string) of object;
|
|
TCommandCaptionType = (cctShort, cctLong);
|
|
TCommandCategorySortOrder = (ccsLegacy, ccsAlphabetical);
|
|
TCommandSortOrder = (csLegacy, csAlphabetical);
|
|
|
|
(*
|
|
The commands are 'user' functions which can be assigned to toolbar
|
|
button, hotkey, menu item, executed by scripts, etc.
|
|
Only published functions and procedures can by found by MethodAddress.
|
|
|
|
How to set up a form to handle hotkeys:
|
|
1. Specify that the form class implements IFormCommands (class (TForm, IFormCommands)).
|
|
2. Add private FCommands: TFormCommands that will implement the interface.
|
|
3. Add property that will specify that FCommands implements the interface in place of the form.
|
|
property Commands: TFormCommands read FCommands{$IF FPC_FULLVERSION >= 020501} implements IFormCommands{$ENDIF};
|
|
For FPC < 2.5.1 "implements" does not work correctly so the form must
|
|
implement the interface itself. For example see fViewer.
|
|
{$IF FPC_FULLVERSION < 020501}
|
|
// "implements" does not work in FPC < 2.5.1
|
|
function ExecuteCommand(Command: string; Param: String=''): TCommandFuncResult;
|
|
function GetCommandCaption(Command: String; CaptionType: TCommandCaptionType): String;
|
|
procedure GetCommandsList(List: TStrings);
|
|
{$ENDIF}
|
|
4. Make sure a default constructor Create(TheOwner: TComponent) is present which
|
|
will create the FCommands on demand when it is needed to read the hotkeys
|
|
when the form is not currently created.
|
|
5. Register the form and action list in HotkeyManager somewhere in constructor:
|
|
const
|
|
HotkeysCategory = <unique_name>;
|
|
HMForm := HotMan.Register(Self, HotkeysCategory);
|
|
HMForm.RegisterActionList(actionList);
|
|
And unregister in destructor:
|
|
HotMan.UnRegister(Self);
|
|
6. Register form as commands form so that it is displayed in Options:
|
|
initialization
|
|
TFormCommands.RegisterCommandsForm(Tfrm..., HotkeysCategory, @rsHotkeyCategory...);
|
|
|
|
|
|
*)
|
|
|
|
{ IFormCommands }
|
|
|
|
{$interfaces corba}
|
|
// If a form/object implements this interface then it can execute custom
|
|
// commands with parameters.
|
|
IFormCommands = interface
|
|
['{0464B1C0-BA98-4258-A286-F0F726FF66C4}']
|
|
function ExecuteCommand(Command: String; const Params: array of string): TCommandFuncResult;
|
|
function GetCommandCaption(Command: String; CaptionType: TCommandCaptionType = cctShort): String;
|
|
procedure GetCommandsList(List: TStrings);
|
|
function GetCommandAction(const Command: String): TAction;
|
|
procedure GetCommandCategoriesList(List: TStringList; CommandCategorySortOrder:TCommandCategorySortOrder);
|
|
procedure GetCommandsListForACommandCategory(List: TStringList; sCategoryName:String; CommandSortOrder: TCommandSortOrder);
|
|
procedure ExtractCommandFields(ItemInList: string; var sCategory:string; var sCommand: string; var sHint: string; var sHotKey: string; var FlagCategoryTitle: boolean);
|
|
end;
|
|
{$interfaces default}
|
|
|
|
// Used to filter out commands. If this function returns True the command
|
|
// is not included in the commands list.
|
|
TCommandFilterFunc = function (Command: String): Boolean of object;
|
|
|
|
TCommandRec = record
|
|
Address: Pointer; //<en Address of the command function in the class.
|
|
Action: TAction; //<en If a TAction is assigned to a named action it is cached here.
|
|
end;
|
|
PCommandRec = ^TCommandRec;
|
|
|
|
{en
|
|
Stores association between method name and its address.
|
|
|
|
StringHashList is used for this purpose, which may be faster
|
|
than linear scanning by using MethodAddress on the given object.
|
|
}
|
|
|
|
{ TFormCommands }
|
|
|
|
TFormCommands = class(TComponent, IFormCommands)
|
|
private
|
|
FFilterFunc: TCommandFilterFunc;
|
|
FInstanceObject: TObject;
|
|
FMethods: TStringHashList;
|
|
FTranslatableCommandCategory: TStringList;
|
|
|
|
class procedure GetMethodsList(Instance: TObject; MethodsList: TStringHashList; ActionList: TActionList);
|
|
|
|
public
|
|
{en
|
|
Creates methods list.
|
|
@param(TheOwner
|
|
Object of which we want the list of methods.
|
|
It will also be the owner component.)
|
|
@param(ActionList
|
|
Optional. If contains actions corresponding to commands names
|
|
(but prefixed with "act" instead of "cm_") then actions hints or
|
|
captions will be used as descriptions for the commands.)
|
|
}
|
|
constructor Create(TheOwner: TComponent; ActionList: TActionList = nil); reintroduce;
|
|
destructor Destroy; override;
|
|
|
|
function ExecuteCommand(Command: string; const Params: array of string): TCommandFuncResult;
|
|
|
|
{en
|
|
Enables/disables command.
|
|
@param(CommandName
|
|
Name of the command. Include prefix if exists, like 'cm_'.)
|
|
@param(Enable
|
|
Whether to enable or disable the command.)
|
|
}
|
|
procedure EnableCommand(Command: String; Enable: Boolean);
|
|
|
|
function GetCommandCaption(Command: String; CaptionType: TCommandCaptionType): String;
|
|
function GetCommandName(Index: Integer): String;
|
|
function GetCommandRec(Command: String): PCommandRec;
|
|
procedure GetCommandsList(List: TStrings);
|
|
function GetCommandAction(const Command: String): TAction;
|
|
procedure GetCommandCategoriesList(List: TStringList; CommandCategorySortOrder:TCommandCategorySortOrder);
|
|
procedure GetCommandsListForACommandCategory(List: TStringList; sCategoryName:String; CommandSortOrder: TCommandSortOrder);
|
|
procedure ExtractCommandFields(ItemInList: string; var sCategory: string; var sCommand: string; var sHint: string; var sHotKey: string; var FlagCategoryTitle: boolean);
|
|
|
|
class procedure GetCategoriesList(List: TStrings; Translated: TStrings);
|
|
class function GetCommandsForm(CategoryName: String): TComponentClass;
|
|
class procedure RegisterCommandsForm(AClass: TClass; CategoryName: String; TranslatedName: PResStringRec);
|
|
|
|
property FilterFunc: TCommandFilterFunc read FFilterFunc write FFilterFunc;
|
|
end;
|
|
|
|
function GetDefaultParam(const Params: array of String): String;
|
|
{en
|
|
Searches for parameters starting with "Key=" and sets Value to the
|
|
the rest of the parameter string (Key=Value).
|
|
If the key is not found it sets Value to empty string and returns @false.
|
|
@returns(@true if the key was found, @false if it was not found)
|
|
}
|
|
function GetParamValue(const Params: array of String; Key: String; out Value: String): Boolean;
|
|
function GetParamValue(const Param: String; Key: String; out Value: String): Boolean;
|
|
function GetParamBoolValue(const Param: String; Key: String; out BoolValue: Boolean): Boolean;
|
|
{en
|
|
If StrValue matches any value that can be translated into boolean then
|
|
it returns @true and sets Value appropriately. Otherwise returns @false.
|
|
}
|
|
function GetBoolValue(StrValue: string; out BoolValue: Boolean): Boolean;
|
|
function CloneMainAction(AMainAction:TAction; ATargetActionList:TActionList; AMenuToInsert:TMenuItem=nil; APositionToInsert:integer=-1):TAction;
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
uGlobs, uHotkeyManager, DCStrUtils, uLng;
|
|
|
|
type
|
|
TCommandsFormRec = record
|
|
AClass: TComponentClass;
|
|
Name: String;
|
|
TranslatedName: PResStringRec; // Until FPC 2.7.1 resource strings translation
|
|
// is not applied after assining so pointer is used here.
|
|
// It is OK because the address doesn't change after translation.
|
|
end;
|
|
|
|
var
|
|
CommandsForms: array of TCommandsFormRec;
|
|
|
|
constructor TFormCommands.Create(TheOwner: TComponent; ActionList: TActionList);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
FInstanceObject := TheOwner;
|
|
FMethods := TStringHashList.Create(False); // False = not case-sensitive
|
|
GetMethodsList(FInstanceObject, FMethods, ActionList);
|
|
FTranslatableCommandCategory:=TStringList.Create;
|
|
ParseLineToList(rsCmdCategoryListInOrder, FTranslatableCommandCategory);
|
|
end;
|
|
|
|
destructor TFormCommands.Destroy;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
for Index := 0 to FMethods.Count - 1 do
|
|
Dispose(PCommandRec(FMethods.List[Index]^.Data));
|
|
FreeAndNil(FMethods);
|
|
FTranslatableCommandCategory.Free;
|
|
inherited;
|
|
end;
|
|
|
|
function TFormCommands.ExecuteCommand(Command: String; const Params: array of string): TCommandFuncResult;
|
|
var
|
|
Method: TMethod;
|
|
CommandRec: PCommandRec;
|
|
begin
|
|
CommandRec := GetCommandRec(Command);
|
|
if Assigned(CommandRec) then
|
|
begin
|
|
if Assigned(CommandRec^.Action) and not CommandRec^.Action.Enabled then
|
|
Result := cfrDisabled
|
|
else
|
|
begin
|
|
Method.Code := CommandRec^.Address; // address of method
|
|
Method.Data := FInstanceObject; // pointer to instance
|
|
TCommandFunc(Method)(Params);
|
|
Result := cfrSuccess;
|
|
end;
|
|
end
|
|
else
|
|
Result := cfrNotFound;
|
|
end;
|
|
|
|
procedure TFormCommands.EnableCommand(Command: String; Enable: Boolean);
|
|
var
|
|
CommandRec: PCommandRec;
|
|
begin
|
|
CommandRec := GetCommandRec(Command);
|
|
if Assigned(CommandRec) then
|
|
begin
|
|
if Assigned(CommandRec^.Action) then
|
|
CommandRec^.Action.Enabled := Enable;
|
|
end
|
|
else
|
|
raise Exception.Create('Invalid command name: ' + Command);
|
|
end;
|
|
|
|
function TFormCommands.GetCommandCaption(Command: String; CaptionType: TCommandCaptionType): String;
|
|
var
|
|
CommandRec: PCommandRec;
|
|
begin
|
|
CommandRec := GetCommandRec(Command);
|
|
if Assigned(CommandRec) and Assigned(CommandRec^.Action) then
|
|
begin
|
|
if (CaptionType = cctLong) and (CommandRec^.Action.Hint <> EmptyStr) then
|
|
Result := CommandRec^.Action.Hint
|
|
else
|
|
Result := StringReplace(CommandRec^.Action.Caption, '&', '', [rfReplaceAll]);
|
|
end
|
|
else
|
|
Result:= '';
|
|
end;
|
|
|
|
function TFormCommands.GetCommandName(Index: Integer): String;
|
|
begin
|
|
if (Index >= 0) and (Index < FMethods.Count) then
|
|
Result := FMethods.List[Index]^.Key
|
|
else
|
|
raise ERangeError.Create('Invalid command index');
|
|
end;
|
|
|
|
function TFormCommands.GetCommandRec(Command: String): PCommandRec;
|
|
var
|
|
Index: Integer;
|
|
begin
|
|
Index := FMethods.Find(Command);
|
|
if Index = -1 then
|
|
Result := nil
|
|
else
|
|
Result := PCommandRec(FMethods.List[Index]^.Data);
|
|
end;
|
|
|
|
procedure TFormCommands.GetCommandsList(List: TStrings);
|
|
var
|
|
Index: Integer;
|
|
Command: String;
|
|
begin
|
|
List.Clear;
|
|
List.BeginUpdate;
|
|
try
|
|
for Index := 0 to FMethods.Count - 1 do
|
|
begin
|
|
Command := FMethods.List[Index]^.Key;
|
|
if not (Assigned(FilterFunc) and FilterFunc(Command)) then
|
|
List.Add(Command);
|
|
end;
|
|
finally
|
|
List.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TFormCommands.GetCommandAction(const Command: String): TAction;
|
|
var
|
|
CommandRec: PCommandRec;
|
|
begin
|
|
CommandRec := GetCommandRec(Command);
|
|
if Assigned(CommandRec) then
|
|
Result:= CommandRec^.Action
|
|
else begin
|
|
Result:= nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TFormCommands.GetCommandCategoriesList(List: TStringList; CommandCategorySortOrder:TCommandCategorySortOrder);
|
|
var
|
|
Index: Integer;
|
|
Command, Category: String;
|
|
begin
|
|
List.Clear;
|
|
List.BeginUpdate;
|
|
try
|
|
for Index := 0 to FMethods.Count - 1 do
|
|
begin
|
|
Command := FMethods.List[Index]^.Key;
|
|
if not (Assigned(FilterFunc) and FilterFunc(Command)) then
|
|
begin
|
|
if TCommandRec(FMethods.List[Index]^.Data^).Action.Tag <> 0 then
|
|
begin
|
|
case CommandCategorySortOrder of
|
|
ccsLegacy: Category:=Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag])+FTranslatableCommandCategory.Strings[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag];
|
|
else Category:=FTranslatableCommandCategory.Strings[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag];
|
|
end;
|
|
if List.IndexOf(Category)=-1 then
|
|
List.Add(Category);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
List.Sort;
|
|
if CommandCategorySortOrder=ccsLegacy then
|
|
for Index:=0 to pred(List.count) do List.Strings[Index]:=RightStr(List.Strings[Index],length(List.Strings[Index])-2);
|
|
List.Insert(0,'('+rsSimpleWordAll+')');
|
|
finally
|
|
List.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
{ TFormCommands.GetCommandsListForACommandCategory }
|
|
{
|
|
Routine is in fact going through all the commands present in the main form.
|
|
They will store them into a list passed in parameter "List".
|
|
Each item of the list will be a string with information separate between pipe "|" symbol.
|
|
These info will be command name|shortcut|hint|category number.
|
|
For example: cm_ChangeDirToHome|Ctrl+Alt+H|Change directory to home|14
|
|
While building the list, if the wanted sort method is "csLegacy", each item will preceeded with category index on two digt and by command index on three digits.
|
|
This is to help to sort the element. We'll simply sort calling "TStringList.Sort" since the beginning of the string have the legacy reference order.
|
|
For example: 14106cm_ChangeDirToHome|Ctrl+Alt+H|Change directory to home|14
|
|
At the end, when exiting, these 5 digits which help to sort will simply be removed.
|
|
ALSO, the routine has the parameter "sCategoryName" to determine the command from which category should be in the list OR if all the commands from ALL the catagory must be returned.
|
|
When the commands from ALL the category are requested, category header will be inserted in the returned list.
|
|
These command will have the prefix for the command index set to '000' to make sure it appear at the beginning of the category command name.
|
|
For these category identifier, the other fields are empty so that's why pipe are following with nothing between.
|
|
Example: 14000Navigation||||
|
|
No special "class" has been created for all this. It seem simple like that.
|
|
}
|
|
procedure TFormCommands.GetCommandsListForACommandCategory(List: TStringList; sCategoryName:String; CommandSortOrder: TCommandSortOrder);
|
|
var
|
|
Index, iHotKey, iControl: Integer;
|
|
Command, Category, sHotKey, LocalHint, HeaderSortedHelper, HeaderCategorySortedHelper: String;
|
|
HMForm: THMForm;
|
|
HMControl: THMControl;
|
|
hotkey: THotkey;
|
|
begin
|
|
List.Clear;
|
|
List.BeginUpdate;
|
|
try
|
|
HeaderSortedHelper:='';
|
|
HMForm := HotMan.Forms.Find('main');
|
|
|
|
for Index := 0 to FMethods.Count - 1 do
|
|
begin
|
|
Command := FMethods.List[Index]^.Key;
|
|
if not (Assigned(FilterFunc) and FilterFunc(Command)) then
|
|
begin
|
|
Category:=FTranslatableCommandCategory.Strings[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag];
|
|
|
|
if (Category = sCategoryName) OR (sCategoryName=('('+rsSimpleWordAll+')')) then
|
|
begin
|
|
sHotKey := '';
|
|
|
|
iHotKey := 0;
|
|
while (iHotKey < HMForm.Hotkeys.Count) and (sHotKey = '') do
|
|
begin
|
|
hotkey := HMForm.Hotkeys[iHotKey];
|
|
if hotkey.Command = Command then
|
|
sHotKey := ShortcutsToText(hotkey.Shortcuts);
|
|
Inc(iHotKey);
|
|
end;
|
|
|
|
if sHotKey='' then
|
|
begin
|
|
iControl:=0;
|
|
while (iControl<HMForm.Controls.Count) and (sHotKey='') do
|
|
begin
|
|
HMControl := HMForm.Controls[iControl];
|
|
iHotKey:=0;
|
|
while (iHotKey < HMControl.Hotkeys.Count) and (sHotKey = '') do
|
|
begin
|
|
hotkey := HMControl.Hotkeys[iHotKey];
|
|
if hotkey.Command = Command then
|
|
sHotKey := ShortcutsToText(hotkey.Shortcuts);
|
|
Inc(iHotKey);
|
|
end;
|
|
inc(iControl);
|
|
end;
|
|
end;
|
|
|
|
if CommandSortOrder=csLegacy then
|
|
begin
|
|
HeaderSortedHelper:=Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag])+
|
|
Format('%3.3d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Index+1]);
|
|
|
|
if sCategoryName=('('+rsSimpleWordAll+')') then
|
|
begin
|
|
HeaderCategorySortedHelper:=Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag])+'000';
|
|
if List.IndexOf(HeaderCategorySortedHelper+Category+'||||')=-1 then
|
|
List.Add(HeaderCategorySortedHelper+Category+'||||');
|
|
end;
|
|
end;
|
|
|
|
if TCommandRec(FMethods.List[Index]^.Data^).Action.Hint <> EmptyStr then
|
|
LocalHint := TCommandRec(FMethods.List[Index]^.Data^).Action.Hint
|
|
else
|
|
LocalHint := StringReplace(TCommandRec(FMethods.List[Index]^.Data^).Action.Caption, '&', '', [rfReplaceAll]);
|
|
|
|
if LocalHint<>EmptyStr then Command:=Command+'|'+sHotKey+'|'+LocalHint+'|'+Format('%2.2d',[TCommandRec(FMethods.List[Index]^.Data^).Action.Tag]);
|
|
|
|
List.Add(HeaderSortedHelper+Command);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
List.Sort;
|
|
if CommandSortOrder=csLegacy then
|
|
for Index:=0 to pred(List.count) do List.Strings[Index]:=RightStr(List.Strings[Index],length(List.Strings[Index])-(2+3));
|
|
finally
|
|
List.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TFormCommands.ExtractCommandFields(ItemInList: string; var sCategory: string; var sCommand: string; var sHint: string; var sHotKey: string; var FlagCategoryTitle: boolean);
|
|
var
|
|
PosPipe: longint;
|
|
sWorkingString: String;
|
|
begin
|
|
FlagCategoryTitle := False;
|
|
sCommand := '';
|
|
sHint := '';
|
|
sHotKey := '';
|
|
sCategory := '';
|
|
PosPipe := Pos('|', ItemInList);
|
|
if PosPipe <> 0 then
|
|
begin
|
|
if pos('||||', ItemInList) = 0 then
|
|
begin
|
|
sCommand := Copy(ItemInList, 1, pred(PosPipe));
|
|
sWorkingString := RightStr(ItemInList, length(ItemInList) - PosPipe);
|
|
PosPipe := pos('|', sWorkingString);
|
|
if PosPipe <> 0 then
|
|
begin
|
|
sHotKey := copy(sWorkingString, 1, pred(PosPipe));
|
|
sWorkingString := rightStr(sWorkingString, length(sWorkingString) - PosPipe);
|
|
PosPipe := pos('|', sWorkingString);
|
|
if PosPipe <> 0 then
|
|
begin
|
|
sHint := copy(sWorkingString, 1, pred(PosPipe));
|
|
sCategory := rightStr(sWorkingString, length(sWorkingString) - PosPipe);
|
|
sCategory := FTranslatableCommandCategory.Strings[StrToIntDef(sCategory,0)];
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
sCommand := Copy(ItemInList, 1, pred(PosPipe));
|
|
FlagCategoryTitle := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
class procedure TFormCommands.GetMethodsList(Instance: TObject; MethodsList: TStringHashList; ActionList: TActionList);
|
|
type
|
|
pmethodnamerec = ^tmethodnamerec;
|
|
tmethodnamerec = packed record
|
|
name : pshortstring;
|
|
addr : pointer;
|
|
end;
|
|
|
|
tmethodnametable = packed record
|
|
count : dword;
|
|
entries : tmethodnamerec; // first entry
|
|
// subsequent tmethodnamerec records follow
|
|
end;
|
|
|
|
pmethodnametable = ^tmethodnametable;
|
|
|
|
var
|
|
methodtable : pmethodnametable;
|
|
i : dword;
|
|
vmt : PVmt;
|
|
pentry: pmethodnamerec;
|
|
CommandRec: PCommandRec;
|
|
Command: String;
|
|
Action: TContainedAction;
|
|
begin
|
|
vmt := PVmt(Instance.ClassType);
|
|
while assigned(vmt) do
|
|
begin
|
|
methodtable := pmethodnametable(vmt^.vMethodTable);
|
|
if assigned(methodtable) then
|
|
begin
|
|
pentry := @methodtable^.entries;
|
|
for i := 0 to methodtable^.count - 1 do
|
|
begin
|
|
Command := pentry[i].name^;
|
|
if StrBegins(Command, 'cm_') then
|
|
// TODO: Match functions parameter too.
|
|
begin
|
|
New(CommandRec);
|
|
MethodsList.Add(Command, CommandRec);
|
|
CommandRec^.Address := pentry[i].addr;
|
|
CommandRec^.Action := nil;
|
|
if Assigned(ActionList) then
|
|
begin
|
|
Action := ActionList.ActionByName('act' + Copy(Command, 4, Length(Command) - 3));
|
|
if Action is TAction then
|
|
CommandRec^.Action := TAction(Action);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
vmt := vmt^.vParent;
|
|
end;
|
|
end;
|
|
|
|
class procedure TFormCommands.GetCategoriesList(List: TStrings; Translated: TStrings);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
List.Clear;
|
|
Translated.Clear;
|
|
for i := Low(CommandsForms) to High(CommandsForms) do
|
|
begin
|
|
List.Add(CommandsForms[i].Name);
|
|
Translated.Add(CommandsForms[i].TranslatedName^);
|
|
end;
|
|
end;
|
|
|
|
class function TFormCommands.GetCommandsForm(CategoryName: String): TComponentClass;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := Low(CommandsForms) to High(CommandsForms) do
|
|
if CommandsForms[i].Name = CategoryName then
|
|
begin
|
|
Exit(CommandsForms[i].AClass);
|
|
end;
|
|
Result := nil;
|
|
end;
|
|
|
|
class procedure TFormCommands.RegisterCommandsForm(AClass: TClass; CategoryName: String; TranslatedName: PResStringRec);
|
|
begin
|
|
SetLength(CommandsForms, Length(CommandsForms) + 1);
|
|
CommandsForms[High(CommandsForms)].AClass := TComponentClass(AClass);
|
|
CommandsForms[High(CommandsForms)].Name := CategoryName;
|
|
CommandsForms[High(CommandsForms)].TranslatedName := TranslatedName;
|
|
end;
|
|
|
|
function GetDefaultParam(const Params: array of String): String;
|
|
begin
|
|
if Length(Params) > 0 then
|
|
Result := Params[0]
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function GetParamValue(const Params: array of String; Key: String; out Value: String): Boolean;
|
|
var
|
|
Param: String;
|
|
begin
|
|
Key := Key + '=';
|
|
for Param in Params do
|
|
if StrBegins(Param, Key) then
|
|
begin
|
|
Value := Copy(Param, Length(Key) + 1, MaxInt);
|
|
Exit(True);
|
|
end;
|
|
Value := '';
|
|
Result := False;
|
|
end;
|
|
|
|
function GetParamValue(const Param: String; Key: String; out Value: String): Boolean;
|
|
begin
|
|
Key := Key + '=';
|
|
if StrBegins(Param, Key) then
|
|
begin
|
|
Value := Copy(Param, Length(Key) + 1, MaxInt);
|
|
Exit(True);
|
|
end;
|
|
Value := '';
|
|
Result := False;
|
|
end;
|
|
|
|
function GetParamBoolValue(const Param: String; Key: String; out BoolValue: Boolean): Boolean;
|
|
var
|
|
sValue: String;
|
|
begin
|
|
Result := GetParamValue(Param, Key, sValue) and
|
|
GetBoolValue(sValue, BoolValue);
|
|
end;
|
|
|
|
function GetBoolValue(StrValue: string; out BoolValue: Boolean): Boolean;
|
|
begin
|
|
StrValue := upcase(StrValue);
|
|
if (StrValue = 'TRUE') or
|
|
(StrValue = 'YES') or
|
|
(StrValue = 'ON') or
|
|
(StrValue = '1') then
|
|
begin
|
|
BoolValue := True;
|
|
Result := True;
|
|
end
|
|
else
|
|
if (StrValue = 'FALSE') or
|
|
(StrValue = 'NO') or
|
|
(StrValue = 'OFF') or
|
|
(StrValue = '0') then
|
|
begin
|
|
BoolValue := False;
|
|
Result := True;
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
{ CloneMainAction }
|
|
// Useful to implement an action in sub window form that will invoke a main action
|
|
function CloneMainAction(AMainAction:TAction; ATargetActionList:TActionList; AMenuToInsert:TMenuItem=nil; APositionToInsert:integer=-1):TAction;
|
|
var
|
|
AMenuItem:TMenuItem;
|
|
begin
|
|
result:= TAction.Create(ATargetActionList);
|
|
result.Name := AMainAction.Name;
|
|
result.Caption := AMainAction.Caption;
|
|
result.Hint := AMainAction.Hint;
|
|
result.Category := AMainAction.Category;
|
|
result.GroupIndex := AMainAction.GroupIndex;
|
|
result.ShortCut:= AMainAction.ShortCut;
|
|
result.Enabled := AMainAction.Enabled;
|
|
result.ActionList := ATargetActionList;
|
|
result.OnExecute := AMainAction.OnExecute;
|
|
|
|
if AMenuToInsert<>nil then
|
|
begin
|
|
AMenuItem:=TMenuItem.Create(AMenuToInsert);
|
|
AMenuItem.Action:=result;
|
|
if APositionToInsert=-1 then
|
|
AMenuToInsert.Add(AMenuItem)
|
|
else
|
|
AMenuToInsert.Insert(APositionToInsert,AMenuItem);
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|