lazarus/ideintf/idecommands.pas

1101 lines
37 KiB
ObjectPascal

{
*****************************************************************************
* *
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
* for details about the copyright. *
* *
* 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. *
* *
*****************************************************************************
Abstract:
Interface unit for IDE commands.
IDE commands are functions like open file, save, build, ... .
Every command can have up to two shortcuts. For example:
ecCopy: two shortcuts: Ctrl+C and Ctrl+Insert
ecDeleteChar: one shortcut: Delete
ecInsertDateTime: no shortcut
Commands are sorted into categories. For example:
ecCopy is in the category 'Selection'.
This is only to help the user find commands.
Scopes:
A command can work globally or only in some IDE windows.
For example: When the user presses a key in the source editor, the IDE
first searches in all commands with the Scope IDECmdScopeSrcEdit.
Then it will search in all commands without scope.
}
unit IDECommands;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LCLProc, Forms, LCLType, Menus, TextTools;
const
{ editor commands constants. see syneditkeycmds.pp for more
These values can change from version to version, so DO NOT save them to file!
To add one static key do the following:
1. Add a constant with a unique value in the list below.
2. Add it to GetDefaultKeyForCommand to define the default keys+shiftstates
3. Add it to EditorCommandToDescriptionString to define the description
4. Add it to TKeyCommandRelationList.CreateDefaultMapping to define the
category.
}
ecNone = 0;
ecFirstLazarus = 1001;
// search
ecFind = ecFirstLazarus + 1;
ecFindAgain = ecFirstLazarus + 2;
ecFindNext = ecFindAgain;
ecFindPrevious = ecFirstLazarus + 3;
ecReplace = ecFirstLazarus + 4;
ecIncrementalFind = ecFirstLazarus + 5;
ecFindProcedureDefinition = ecFirstLazarus + 6;
ecFindProcedureMethod = ecFirstLazarus + 7;
ecGotoLineNumber = ecFirstLazarus + 8;
ecFindNextWordOccurrence = ecFirstLazarus + 9;
ecFindPrevWordOccurrence = ecFirstLazarus + 10;
ecFindInFiles = ecFirstLazarus + 11;
ecJumpBack = ecFirstLazarus + 12;
ecJumpForward = ecFirstLazarus + 13;
ecAddJumpPoint = ecFirstLazarus + 14;
ecViewJumpHistory = ecFirstLazarus + 15;
ecJumpToNextError = ecFirstLazarus + 16;
ecJumpToPrevError = ecFirstLazarus + 17;
ecProcedureList = ecFirstLazarus + 18;
// search code
ecFindDeclaration = ecFirstLazarus + 20;
ecFindBlockOtherEnd = ecFirstLazarus + 21;
ecFindBlockStart = ecFirstLazarus + 22;
ecOpenFileAtCursor = ecFirstLazarus + 23;
ecGotoIncludeDirective = ecFirstLazarus + 24;
// edit selection
ecSelectionUpperCase = ecFirstLazarus + 50;
ecSelectionLowerCase = ecFirstLazarus + 51;
ecSelectionTabs2Spaces = ecFirstLazarus + 52;
ecSelectionEnclose = ecFirstLazarus + 53;
ecSelectionComment = ecFirstLazarus + 54;
ecSelectionUncomment = ecFirstLazarus + 55;
ecSelectionSort = ecFirstLazarus + 56;
ecSelectionBreakLines = ecFirstLazarus + 57;
ecSelectToBrace = ecFirstLazarus + 58;
ecSelectCodeBlock = ecFirstLazarus + 59;
ecSelectWord = ecFirstLazarus + 60;
ecSelectLine = ecFirstLazarus + 61;
ecSelectParagraph = ecFirstLazarus + 62;
ecSelectionConditional = ecFirstLazarus + 63;
ecToggleComment = ecFirstLazarus + 64;
// insert text
ecInsertCharacter = ecFirstLazarus + 80;
ecInsertGPLNotice = ecFirstLazarus + 81;
ecInsertLGPLNotice = ecFirstLazarus + 82;
ecInsertUserName = ecFirstLazarus + 83;
ecInsertDateTime = ecFirstLazarus + 84;
ecInsertChangeLogEntry = ecFirstLazarus + 85;
ecInsertCVSAuthor = ecFirstLazarus + 86;
ecInsertCVSDate = ecFirstLazarus + 87;
ecInsertCVSHeader = ecFirstLazarus + 88;
ecInsertCVSID = ecFirstLazarus + 89;
ecInsertCVSLog = ecFirstLazarus + 90;
ecInsertCVSName = ecFirstLazarus + 91;
ecInsertCVSRevision = ecFirstLazarus + 92;
ecInsertCVSSource = ecFirstLazarus + 93;
ecInsertModifiedLGPLNotice= ecFirstLazarus + 94;
ecInsertTodo = ecFirstLazarus + 95;
ecInsertGUID = ecFirstLazarus + 96;
// source tools
ecWordCompletion = ecFirstLazarus + 100;
ecCompleteCode = ecFirstLazarus + 101;
ecIdentCompletion = ecFirstLazarus + 102;
ecSyntaxCheck = ecFirstLazarus + 103;
ecGuessUnclosedBlock = ecFirstLazarus + 104;
ecGuessMisplacedIFDEF = ecFirstLazarus + 105;
ecConvertDFM2LFM = ecFirstLazarus + 106;
ecCheckLFM = ecFirstLazarus + 107;
ecConvertDelphiUnit = ecFirstLazarus + 108;
ecConvertDelphiProject = ecFirstLazarus + 109;
ecConvertDelphiPackage = ecFirstLazarus + 110;
ecConvertEncoding = ecFirstLazarus + 111;
ecMakeResourceString = ecFirstLazarus + 112;
ecDiff = ecFirstLazarus + 113;
ecExtractProc = ecFirstLazarus + 114;
ecFindIdentifierRefs = ecFirstLazarus + 115;
ecRenameIdentifier = ecFirstLazarus + 116;
ecInvertAssignment = ecFirstLazarus + 117;
ecShowCodeContext = ecFirstLazarus + 118;
ecShowAbstractMethods = ecFirstLazarus + 119;
ecRemoveEmptyMethods = ecFirstLazarus + 120;
ecRemoveUnusedUnits = ecFirstLazarus + 121;
ecFindOverloads = ecFirstLazarus + 122;
// file menu
ecNew = ecFirstLazarus + 201;
ecNewUnit = ecFirstLazarus + 202;
ecNewForm = ecFirstLazarus + 203;
ecOpen = ecFirstLazarus + 205;
ecRevert = ecFirstLazarus + 206;
ecSave = ecFirstLazarus + 207;
ecSaveAs = ecFirstLazarus + 208;
ecSaveAll = ecFirstLazarus + 209;
ecClose = ecFirstLazarus + 210;
ecCloseAll = ecFirstLazarus + 211;
ecCleanDirectory = ecFirstLazarus + 212;
ecRestart = ecFirstLazarus + 213;
ecQuit = ecFirstLazarus + 214;
// IDE navigation
ecToggleFormUnit = ecFirstLazarus + 301;
ecToggleObjectInsp = ecFirstLazarus + 302;
ecToggleSourceEditor = ecFirstLazarus + 303;
ecToggleCodeExpl = ecFirstLazarus + 304;
ecToggleFPDocEditor = ecFirstLazarus + 305;
ecToggleMessages = ecFirstLazarus + 306;
ecToggleWatches = ecFirstLazarus + 307;
ecToggleBreakPoints = ecFirstLazarus + 308;
ecToggleDebuggerOut = ecFirstLazarus + 309;
ecViewUnits = ecFirstLazarus + 310;
ecViewForms = ecFirstLazarus + 311;
ecViewUnitDependencies = ecFirstLazarus + 312;
ecViewUnitInfo = ecFirstLazarus + 313;
ecToggleLocals = ecFirstLazarus + 314;
ecToggleCallStack = ecFirstLazarus + 315;
ecToggleSearchResults = ecFirstLazarus + 316;
ecViewAnchorEditor = ecFirstLazarus + 317;
ecToggleCodeBrowser = ecFirstLazarus + 318;
ecToggleCompPalette = ecFirstLazarus + 319;
ecToggleIDESpeedBtns = ecFirstLazarus + 320;
ecViewComponents = ecFirstLazarus + 321;
ecToggleRestrictionBrowser = ecFirstLazarus + 322;
ecViewTodoList = ecFirstLazarus + 323;
ecToggleRegisters = ecFirstLazarus + 324;
ecToggleAssembler = ecFirstLazarus + 325;
// sourcenotebook commands
ecNextEditor = ecFirstLazarus + 330;
ecPrevEditor = ecFirstLazarus + 331;
ecMoveEditorLeft = ecFirstLazarus + 332;
ecMoveEditorRight = ecFirstLazarus + 333;
ecToggleBreakPoint = ecFirstLazarus + 334;
ecRemoveBreakPoint = ecFirstLazarus + 335;
ecMoveEditorLeftmost = ecFirstLazarus + 336;
ecMoveEditorRightmost = ecFirstLazarus + 337;
ecGotoEditor1 = ecFirstLazarus + 350;
ecGotoEditor2 = ecGotoEditor1 + 1;
ecGotoEditor3 = ecGotoEditor2 + 1;
ecGotoEditor4 = ecGotoEditor3 + 1;
ecGotoEditor5 = ecGotoEditor4 + 1;
ecGotoEditor6 = ecGotoEditor5 + 1;
ecGotoEditor7 = ecGotoEditor6 + 1;
ecGotoEditor8 = ecGotoEditor7 + 1;
ecGotoEditor9 = ecGotoEditor8 + 1;
ecGotoEditor0 = ecGotoEditor9 + 1;
// marker
ecSetFreeBookmark = ecFirstLazarus + 381;
ecPrevBookmark = ecFirstLazarus + 382;
ecNextBookmark = ecFirstLazarus + 383;
// compile menu
ecBuild = ecFirstLazarus + 400;
ecBuildAll = ecFirstLazarus + 401;
ecQuickCompile = ecFirstLazarus + 402;
ecAbortBuild = ecFirstLazarus + 403;
ecRun = ecFirstLazarus + 404;
ecPause = ecFirstLazarus + 405;
ecStepInto = ecFirstLazarus + 406;
ecStepOver = ecFirstLazarus + 407;
ecRunToCursor = ecFirstLazarus + 408;
ecStopProgram = ecFirstLazarus + 409;
ecResetDebugger = ecFirstLazarus + 410;
ecBuildLazarus = ecFirstLazarus + 411;
ecBuildFile = ecFirstLazarus + 412;
ecRunFile = ecFirstLazarus + 413;
ecConfigBuildFile = ecFirstLazarus + 414;
ecInspect = ecFirstLazarus + 415;
ecEvaluate = ecFirstLazarus + 416;
ecAddWatch = ecFirstLazarus + 417;
ecShowExecutionPoint = ecFirstLazarus + 418;
ecStepOut = ecFirstLazarus + 419;
// project menu
ecNewProject = ecFirstLazarus + 500;
ecNewProjectFromFile = ecFirstLazarus + 501;
ecOpenProject = ecFirstLazarus + 502;
ecCloseProject = ecFirstLazarus + 503;
ecSaveProject = ecFirstLazarus + 504;
ecSaveProjectAs = ecFirstLazarus + 505;
ecPublishProject = ecFirstLazarus + 506;
ecProjectInspector = ecFirstLazarus + 507;
ecAddCurUnitToProj = ecFirstLazarus + 508;
ecRemoveFromProj = ecFirstLazarus + 509;
ecViewProjectSource = ecFirstLazarus + 510;
ecProjectOptions = ecFirstLazarus + 512;
// components menu
ecOpenPackage = ecFirstLazarus + 600;
ecOpenPackageFile = ecFirstLazarus + 601;
ecOpenPackageOfCurUnit = ecFirstLazarus + 602;
ecAddCurUnitToPkg = ecFirstLazarus + 603;
ecPackageGraph = ecFirstLazarus + 604;
ecEditInstallPkgs = ecFirstLazarus + 605;
ecConfigCustomComps = ecFirstLazarus + 606;
ecNewPackage = ecFirstLazarus + 607;
// custom tools menu
ecExtToolFirst = ecFirstLazarus + 700;
ecExtToolLast = ecFirstLazarus + 799;
// option commmands
ecRunParameters = ecFirstLazarus + 800;
ecReserved0 = ecFirstLazarus + 801; // reserved
ecExtToolSettings = ecFirstLazarus + 802;
ecConfigBuildLazarus = ecFirstLazarus + 803;
ecEnvironmentOptions = ecFirstLazarus + 804;
ecReserved1 = ecFirstLazarus + 805; // reserved
ecEditCodeTemplates = ecFirstLazarus + 806;
ecReserved2 = ecFirstLazarus + 807; // reserved
ecCodeToolsDefinesEd = ecFirstLazarus + 808;
ecRescanFPCSrcDir = ecFirstLazarus + 809;
// help menu
ecAboutLazarus = ecFirstLazarus + 900;
ecOnlineHelp = ecFirstLazarus + 901;
ecReserved3 = ecFirstLazarus + 902; // reserved
ecContextHelp = ecFirstLazarus + 903;
ecEditContextHelp = ecFirstLazarus + 904;
ecReportingBug = ecFirstLazarus + 905;
// designer
ecDesignerCopy = ecFirstLazarus + 1000;
ecDesignerCut = ecFirstLazarus + 1001;
ecDesignerPaste = ecFirstLazarus + 1002;
ecDesignerSelectParent = ecFirstLazarus + 1003;
ecDesignerMoveToFront = ecFirstLazarus + 1004;
ecDesignerMoveToBack = ecFirstLazarus + 1005;
ecDesignerForwardOne = ecFirstLazarus + 1006;
ecDesignerBackOne = ecFirstLazarus + 1007;
// custom commands
ecLazarusLast = ecFirstLazarus + 2000;
type
TIDECommand = class;
TIDECommandCategory = class;
TNotifyProcedure = procedure(Sender: TObject);
{ TIDECommandScope
A TIDECommandScope defines a set of IDE windows that will share the same
IDE commands. An IDE command can be valid in several scopes at the same
time. }
{ TIDECommandScope }
TIDECommandScope = class(TPersistent)
private
FName: string;
FIDEWindowClasses: TFPList;// list of TCustomFormClass
FCategories: TFPList;
function GetCategories(Index: integer): TIDECommandCategory;
function GetIDEWindowClasses(Index: integer): TCustomFormClass;
public
constructor Create(const TheName: string);
destructor Destroy; override;
procedure AddWindowClass(AWindowClass: TCustomFormClass);
procedure RemoveWindowClass(AWindowClass: TCustomFormClass);
function IDEWindowClassCount: integer;
function CategoryCount: integer;
function HasIDEWindowClass(AWindowClass: TCustomFormClass): boolean;
function Intersects(AScope: TIDECommandScope): boolean;
procedure WriteDebugReport;
public
property Name: string read FName;
property IDEWindowClasses[Index: integer]: TCustomFormClass read GetIDEWindowClasses;
property Categories[Index: integer]: TIDECommandCategory read GetCategories;
end;
{ TIDECommandScopes }
TIDECommandScopes = class(TPersistent)
private
FItems: TFPList;
function GetItems(Index: integer): TIDECommandScope;
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure Add(NewItem: TIDECommandScope);
function IndexOf(AnItem: TIDECommandScope): Integer;
function IndexByName(const AName: string): Integer;
function FindByName(const AName: string): TIDECommandScope;
function CreateUniqueName(const AName: string): string;
function Count: integer;
public
property Items[Index: integer]: TIDECommandScope read GetItems;
end;
{ TIDEShortCut }
TIDEShortCut = record
Key1: word;
Shift1: TShiftState;
Key2: word;
Shift2: TShiftState;
end;
PIDEShortCut = ^TIDEShortCut;
{ TIDECommandCategory
TIDECommandCategory is used to divide the commands in handy packets }
TIDECommandCategory = class(TList)
private
procedure SetDescription(const AValue: string);
protected
FDescription: string;
FName: string;
FParent: TIDECommandCategory;
FScope: TIDECommandScope;
procedure SetScope(const AValue: TIDECommandScope);
public
destructor Destroy; override;
function ScopeIntersects(AScope: TIDECommandScope): boolean;
procedure WriteScopeDebugReport;
public
property Name: string read FName;
property Description: string read FDescription write SetDescription;
property Parent: TIDECommandCategory read FParent;
procedure Delete(Index: Integer); virtual;
property Scope: TIDECommandScope read FScope write SetScope;
end;
{ TIDECommand }
{ class for storing the keys of a single command
(shortcut-command relationship) }
TIDECommand = class
private
FCategory: TIDECommandCategory;
FCommand: word;
FLocalizedName: string;
FName: String;
FOnChange: TNotifyEvent;
FOnExecute: TNotifyEvent;
FOnExecuteProc: TNotifyProcedure;
FShortcutA: TIDEShortCut;
FShortcutB: TIDEShortCut;
protected
function GetLocalizedName: string; virtual;
procedure SetLocalizedName(const AValue: string); virtual;
procedure SetCategory(const AValue: TIDECommandCategory); virtual;
procedure SetShortcutA(const AValue: TIDEShortCut); virtual;
procedure SetShortcutB(const AValue: TIDEShortCut); virtual;
procedure Change;
public
function AsShortCut: TShortCut; virtual;
constructor Create(TheCategory: TIDECommandCategory; const TheName,
TheLocalizedName: String;
TheCommand: word; const TheShortcutA, TheShortcutB: TIDEShortCut;
const ExecuteMethod: TNotifyEvent;
const ExecuteProc: TNotifyProcedure);
constructor Create(ACommand: TIDECommand; ACategory: TIDECommandCategory);
destructor Destroy; override;
procedure Assign(ACommand: TIDECommand);
function IsEqual(ACommand: TIDECommand): boolean;
public
DefaultShortcutA: TIDEShortCut;
DefaultShortcutB: TIDEShortCut;
procedure ClearShortcutA;
procedure ClearShortcutB;
function GetCategoryAndName: string;
function Execute(Sender: TObject): boolean;
public
property Name: String read FName;
property Command: word read FCommand;// see the ecXXX constants above
property LocalizedName: string read GetLocalizedName write SetLocalizedName;
property Category: TIDECommandCategory read FCategory write SetCategory;
property ShortcutA: TIDEShortCut read FShortcutA write SetShortcutA;
property ShortcutB: TIDEShortCut read FShortcutB write SetShortcutB;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnExecute: TNotifyEvent read FOnExecute write FOnExecute;
property OnExecuteProc: TNotifyProcedure read FOnExecuteProc write FOnExecuteProc;
end;
{ TIDECommands }
TIDECommands = class
protected
function GetCategory(Index: integer): TIDECommandCategory; virtual; abstract;
public
function FindIDECommand(ACommand: word): TIDECommand; virtual; abstract;
function CreateCategory(Parent: TIDECommandCategory;
const Name, Description: string;
Scope: TIDECommandScope = nil): TIDECommandCategory; virtual; abstract;
function CreateCommand(Category: TIDECommandCategory;
const Name, Description: string;
const TheShortcutA, TheShortcutB: TIDEShortCut;
const OnExecuteMethod: TNotifyEvent = nil;
const OnExecuteProc: TNotifyProcedure = nil
): TIDECommand; virtual; abstract;
function FindCategoryByName(const CategoryName: string): TIDECommandCategory; virtual; abstract;
function FindCommandByName(const CommandName: string): TIDECommand; virtual; abstract;
function CategoryCount: integer; virtual; abstract;
public
property Categories[Index: integer]: TIDECommandCategory read GetCategory;
end;
const
CleanIDEShortCut: TIDEShortCut =
(Key1: VK_UNKNOWN; Shift1: []; Key2: VK_UNKNOWN; Shift2: []);
function IDEShortCut(Key1: word; Shift1: TShiftState;
Key2: word = VK_UNKNOWN; Shift2: TShiftState = []): TIDEShortCut;
type
TExecuteIDEShortCut =
procedure(Sender: TObject; var Key: word; Shift: TShiftState;
IDEWindowClass: TCustomFormClass) of object;
TExecuteIDECommand = function(Sender: TObject; Command: word): boolean of object;
var
OnExecuteIDEShortCut: TExecuteIDEShortCut;
OnExecuteIDECommand: TExecuteIDECommand;
procedure ExecuteIDEShortCut(Sender: TObject; var Key: word; Shift: TShiftState;
IDEWindowClass: TCustomFormClass);
procedure ExecuteIDEShortCut(Sender: TObject; var Key: word; Shift: TShiftState);
function ExecuteIDECommand(Sender: TObject; Command: word): boolean;
function IDEShortCutToMenuShortCut(const IDEShortCut: TIDEShortCut): TShortCut;
var
// will be set by the IDE
IDECommandList: TIDECommands;
IDECommandScopes: TIDECommandScopes = nil;
var
IDECmdScopeSrcEdit: TIDECommandScope;
IDECmdScopeSrcEditOnly: TIDECommandScope;
IDECmdScopeSrcEditOnlyTmplEdit: TIDECommandScope;
IDECmdScopeSrcEditOnlyTmplEditOff: TIDECommandScope;
IDECmdScopeSrcEditOnlySyncroEditSel: TIDECommandScope;
IDECmdScopeSrcEditOnlySyncroEdit: TIDECommandScope;
IDECmdScopeSrcEditOnlySyncroEditOff: TIDECommandScope;
IDECmdScopeDesignerOnly: TIDECommandScope;
IDECmdScopeObjectInspectorOnly: TIDECommandScope;
const
CommandCategoryToolMenuName = 'ToolMenu';
CommandCategoryCustomName = 'Custom';
// register a new IDE command category (i.e. set of commands)
function RegisterIDECommandCategory(Parent: TIDECommandCategory;
const Name, Description: string): TIDECommandCategory;
// register a new IDE command (i.e. a shortcut, IDE function)
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string;
const OnExecuteMethod: TNotifyEvent = nil;
const OnExecuteProc: TNotifyProcedure = nil): TIDECommand;
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string; Key1: word; Shift1: TShiftState;
const OnExecuteMethod: TNotifyEvent = nil;
const OnExecuteProc: TNotifyProcedure = nil): TIDECommand;
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string; const ShortCut1: TIDEShortCut;
const OnExecuteMethod: TNotifyEvent = nil;
const OnExecuteProc: TNotifyProcedure = nil): TIDECommand;
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string;
const ShortCut1, ShortCut2: TIDEShortCut;
const OnExecuteMethod: TNotifyEvent = nil;
const OnExecuteProc: TNotifyProcedure = nil): TIDECommand;
// register a new IDE command scope (i.e. a set of windows)
function RegisterIDECommandScope(const Name: string): TIDECommandScope;
procedure CreateStandardIDECommandScopes;
function CompareIDEShortCuts(Data1, Data2: Pointer): integer;
function CompareIDEShortCutKey1s(Data1, Data2: Pointer): integer;
function IdentToIDECommand(const Ident: string; var Cmd: longint): boolean;
function IDECommandToIdent(Cmd: longint; var Ident: string): boolean;
implementation
function IDEShortCut(Key1: word; Shift1: TShiftState;
Key2: word; Shift2: TShiftState): TIDEShortCut;
begin
Result.Key1:=Key1;
Result.Shift1:=Shift1;
Result.Key2:=Key2;
Result.Shift2:=Shift2;
end;
procedure ExecuteIDEShortCut(Sender: TObject; var Key: word; Shift: TShiftState;
IDEWindowClass: TCustomFormClass);
begin
if (OnExecuteIDECommand<>nil) and (Key<>VK_UNKNOWN) then
OnExecuteIDEShortCut(Sender,Key,Shift,IDEWindowClass);
end;
procedure ExecuteIDEShortCut(Sender: TObject; var Key: word;
Shift: TShiftState);
begin
OnExecuteIDEShortCut(Sender,Key,Shift,nil);
end;
function ExecuteIDECommand(Sender: TObject; Command: word): boolean;
begin
if (OnExecuteIDECommand<>nil) and (Command<>0) then
Result:=OnExecuteIDECommand(Sender,Command)
else
Result:=false;
end;
function IDEShortCutToMenuShortCut(const IDEShortCut: TIDEShortCut): TShortCut;
begin
if IDEShortCut.Key2=VK_UNKNOWN then
Result:=ShortCut(IDEShortCut.Key1,IDEShortCut.Shift1)
else
Result:=ShortCut(VK_UNKNOWN,[]);
end;
procedure CreateStandardIDECommandScopes;
begin
IDECommandScopes:=TIDECommandScopes.Create;
IDECmdScopeSrcEdit:=RegisterIDECommandScope('SourceEditor');
IDECmdScopeSrcEditOnly:=RegisterIDECommandScope('SourceEditorOnly');
IDECmdScopeSrcEditOnlyTmplEdit:=RegisterIDECommandScope('SourceEditorOnlyTemplateEdit');
IDECmdScopeSrcEditOnlyTmplEditOff:=RegisterIDECommandScope('SourceEditorOnlyTemplateEditOff');
IDECmdScopeSrcEditOnlySyncroEditSel:=RegisterIDECommandScope('SourceEditorOnlySyncroEditSel');
IDECmdScopeSrcEditOnlySyncroEdit:=RegisterIDECommandScope('SourceEditorOnlySyncroEdit');
IDECmdScopeSrcEditOnlySyncroEditOff:=RegisterIDECommandScope('SourceEditorOnlySyncroEdit');
IDECmdScopeDesignerOnly:=RegisterIDECommandScope('DesignerOnly');
IDECmdScopeObjectInspectorOnly:=RegisterIDECommandScope('ObjectInspectorOnly');
end;
type
// in fpc 2.3.1 TShiftState is declared with {$packset 1}
{$IF sizeof(TShiftState)=2}
TShiftStateInt = word;
{$ELSE}
TShiftStateInt = integer;
{$ENDIF}
function CompareIDEShortCuts(Data1, Data2: Pointer): integer;
var
ShortCut1: PIDEShortCut absolute Data1;
ShortCut2: PIDEShortCut absolute Data2;
begin
if ShortCut1^.Key1>ShortCut2^.Key1 then
Result:=1
else if ShortCut1^.Key1<ShortCut2^.Key1 then
Result:=-1
else if TShiftStateInt(ShortCut1^.Shift1)>TShiftStateInt(ShortCut2^.Shift1) then
Result:=1
else if TShiftStateInt(ShortCut1^.Shift1)<TShiftStateInt(ShortCut2^.Shift1) then
Result:=-1
else if ShortCut1^.Key2>ShortCut2^.Key2 then
Result:=1
else if ShortCut1^.Key2<ShortCut2^.Key2 then
Result:=-1
else if TShiftStateInt(ShortCut1^.Shift2)>TShiftStateInt(ShortCut2^.Shift2) then
Result:=1
else if TShiftStateInt(ShortCut1^.Shift2)<TShiftStateInt(ShortCut2^.Shift2) then
Result:=-1
else
Result:=0;
end;
function CompareIDEShortCutKey1s(Data1, Data2: Pointer): integer;
var
ShortCut1: PIDEShortCut;
ShortCut2: PIDEShortCut;
begin
ShortCut1:=PIDEShortCut(Data1);
ShortCut2:=PIDEShortCut(Data2);
if ShortCut1^.Key1>ShortCut2^.Key1 then
Result:=1
else if ShortCut1^.Key1<ShortCut2^.Key1 then
Result:=-1
else if TShiftStateInt(ShortCut1^.Shift1)>TShiftStateInt(ShortCut2^.Shift1) then
Result:=1
else if TShiftStateInt(ShortCut1^.Shift1)<TShiftStateInt(ShortCut2^.Shift1) then
Result:=-1
else
Result:=0;
end;
function RegisterIDECommandCategory(Parent: TIDECommandCategory;
const Name, Description: string): TIDECommandCategory;
begin
Result:=IDECommandList.CreateCategory(Parent,Name,Description);
end;
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string;
const OnExecuteMethod: TNotifyEvent = nil;
const OnExecuteProc: TNotifyProcedure = nil): TIDECommand;
begin
Result:=RegisterIDECommand(Category,Name,Description,IDEShortCut(VK_UNKNOWN,[]),
OnExecuteMethod,OnExecuteProc);
end;
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string;
Key1: word; Shift1: TShiftState;
const OnExecuteMethod: TNotifyEvent;
const OnExecuteProc: TNotifyProcedure): TIDECommand;
begin
Result:=RegisterIDECommand(Category,Name,Description,IDEShortCut(Key1,Shift1),
OnExecuteMethod,OnExecuteProc);
end;
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string; const ShortCut1: TIDEShortCut;
const OnExecuteMethod: TNotifyEvent;
const OnExecuteProc: TNotifyProcedure): TIDECommand;
begin
Result:=RegisterIDECommand(Category,Name,Description,
ShortCut1,IDEShortCut(VK_UNKNOWN,[]),
OnExecuteMethod,OnExecuteProc);
end;
function RegisterIDECommand(Category: TIDECommandCategory;
const Name, Description: string;
const ShortCut1, ShortCut2: TIDEShortCut;
const OnExecuteMethod: TNotifyEvent;
const OnExecuteProc: TNotifyProcedure): TIDECommand;
begin
Result:=IDECommandList.CreateCommand(Category,Name,Description,
ShortCut1,ShortCut2,OnExecuteMethod,
OnExecuteProc);
end;
function RegisterIDECommandScope(const Name: string): TIDECommandScope;
begin
Result:=TIDECommandScope.Create(Name);
IDECommandScopes.Add(Result);
end;
{ TIDECommand }
procedure TIDECommand.SetShortcutA(const AValue: TIDEShortCut);
begin
if CompareIDEShortCuts(@FShortcutA,@AValue)=0 then exit;
FShortcutA:=AValue;
//DebugLn('TIDECommand.SetShortcutA ',dbgs(Assigned(OnChange)),' ',Name);
Change;
end;
procedure TIDECommand.SetShortcutB(const AValue: TIDEShortCut);
begin
if CompareIDEShortCuts(@FShortcutB,@AValue)=0 then exit;
FShortcutB:=AValue;
//DebugLn('TIDECommand.SetShortcutB ',dbgs(Assigned(OnChange)),' ',Name);
Change;
end;
procedure TIDECommand.Change;
begin
if Assigned(OnChange) then OnChange(Self);
end;
function TIDECommand.GetLocalizedName: string;
begin
if FLocalizedName<>'' then
Result:=FLocalizedName
else
Result:=Name;
end;
procedure TIDECommand.SetLocalizedName(const AValue: string);
begin
if FLocalizedName=AValue then exit;
FLocalizedName:=AValue;
//DebugLn('TIDECommand.SetLocalizedName ',dbgs(Assigned(OnChange)),' ',Name);
Change;
end;
procedure TIDECommand.SetCategory(const AValue: TIDECommandCategory);
begin
if FCategory=AValue then exit;
// unbind
if Category<>nil then
Category.Remove(Self);
// bind
fCategory:=AValue;
if Category<>nil then
Category.Add(Self);
//DebugLn('TIDECommand.SetCategory ',dbgs(Assigned(OnChange)),' ',Name);
Change;
end;
function TIDECommand.AsShortCut: TShortCut;
var
CurKey: TIDEShortCut;
begin
if (ShortcutA.Key1<>VK_UNKNOWN) and (ShortcutA.Key2=VK_UNKNOWN) then
CurKey:=ShortcutA
else if (ShortcutB.Key1<>VK_UNKNOWN) and (ShortcutB.Key2=VK_UNKNOWN) then
CurKey:=ShortcutB
else
CurKey:=CleanIDEShortCut;
Result:=CurKey.Key1;
if ssCtrl in CurKey.Shift1 then
Result:=Result+scCtrl;
if ssShift in CurKey.Shift1 then
Result:=Result+scShift;
if ssAlt in CurKey.Shift1 then
Result:=Result+scAlt;
end;
constructor TIDECommand.Create(TheCategory: TIDECommandCategory;
const TheName, TheLocalizedName: String; TheCommand: word;
const TheShortcutA, TheShortcutB: TIDEShortCut;
const ExecuteMethod: TNotifyEvent;
const ExecuteProc: TNotifyProcedure);
begin
fCommand:=TheCommand;
fName:=TheName;
FLocalizedName:=TheLocalizedName;
fShortcutA:=TheShortcutA;
fShortcutB:=TheShortcutB;
DefaultShortcutA:=ShortcutA;
DefaultShortcutB:=ShortcutB;
Category:=TheCategory;
FOnExecute:=ExecuteMethod;
FOnExecuteProc:=ExecuteProc;
//DebugLn('TIDECommand.Create Name=',Name,' ',ShortCutToText(AsShortCut),' ',dbgs(Pointer(Self)));
end;
constructor TIDECommand.Create(ACommand: TIDECommand;
ACategory: TIDECommandCategory);
begin
fCommand:=ACommand.Command;
fName:=ACommand.Name;
FLocalizedName:=ACommand.LocalizedName;
fShortcutA:=ACommand.ShortcutA;
fShortcutB:=ACommand.ShortcutB;
DefaultShortcutA:=ACommand.ShortcutA;
DefaultShortcutB:=ACommand.ShortcutB;
Category:=ACategory;
end;
destructor TIDECommand.Destroy;
begin
inherited Destroy;
end;
procedure TIDECommand.Assign(ACommand: TIDECommand);
begin
if IsEqual(ACommand) then exit;
//DebugLn('TIDECommand.Assign ',dbgs(Assigned(OnChange)),' ',Name,' ');
FShortcutA:=ACommand.FShortcutA;
FShortcutB:=ACommand.FShortcutB;
Change;
end;
function TIDECommand.IsEqual(ACommand: TIDECommand): boolean;
begin
Result:=(CompareIDEShortCuts(@FShortcutA,@ACommand.FShortcutA)=0)
and (CompareIDEShortCuts(@FShortcutB,@ACommand.FShortcutB)=0);
end;
procedure TIDECommand.ClearShortcutA;
begin
ShortcutA:=CleanIDEShortCut;
end;
procedure TIDECommand.ClearShortcutB;
begin
ShortcutB:=CleanIDEShortCut;
end;
function TIDECommand.GetCategoryAndName: string;
begin
Result:='"'+GetLocalizedName+'"';
if Category<>nil then
Result:=Result+' in "'+Category.Description+'"';
end;
function TIDECommand.Execute(Sender: TObject): boolean;
begin
Result:=false;
if Assigned(OnExecute) then begin
Result:=true;
OnExecute(Sender);
end;
if Assigned(OnExecuteProc) then begin
Result:=true;
OnExecuteProc(Sender);
end;
end;
{ TIDECommandScopes }
function TIDECommandScopes.GetItems(Index: integer): TIDECommandScope;
begin
Result:=TIDECommandScope(FItems[Index]);
end;
constructor TIDECommandScopes.Create;
begin
FItems:=TFPList.Create;
end;
destructor TIDECommandScopes.Destroy;
begin
Clear;
FItems.Free;
inherited Destroy;
end;
procedure TIDECommandScopes.Clear;
var
i: Integer;
begin
for i:=0 to FItems.Count-1 do Items[i].Free;
FItems.Clear;
end;
procedure TIDECommandScopes.Add(NewItem: TIDECommandScope);
begin
NewItem.fName:=CreateUniqueName(NewItem.Name);
FItems.Add(NewItem);
end;
function TIDECommandScopes.IndexOf(AnItem: TIDECommandScope): Integer;
begin
Result:=FItems.IndexOf(AnItem);
end;
function TIDECommandScopes.IndexByName(const AName: string): Integer;
begin
Result:=Count-1;
while (Result>=0) and (CompareText(AName,Items[Result].Name)<>0) do
dec(Result);
end;
function TIDECommandScopes.FindByName(const AName: string): TIDECommandScope;
var
i: LongInt;
begin
i:=IndexByName(AName);
if i>=0 then
Result:=Items[i]
else
Result:=nil;
end;
function TIDECommandScopes.CreateUniqueName(const AName: string): string;
begin
Result:=AName;
if IndexByName(Result)<0 then exit;
Result:=CreateFirstIdentifier(Result);
while IndexByName(Result)>=0 do
Result:=CreateNextIdentifier(Result);
end;
function TIDECommandScopes.Count: integer;
begin
Result:=FItems.Count;
end;
{ TIDECommandCategory }
procedure TIDECommandCategory.SetDescription(const AValue: string);
begin
if FDescription=AValue then exit;
FDescription:=AValue;
end;
procedure TIDECommandCategory.SetScope(const AValue: TIDECommandScope);
begin
if FScope=AValue then exit;
if FScope<>nil then
FScope.FCategories.Remove(Self);
FScope:=AValue;
if FScope<>nil then
FScope.FCategories.Add(Self);
end;
destructor TIDECommandCategory.Destroy;
begin
Scope:=nil;
inherited Destroy;
end;
function TIDECommandCategory.ScopeIntersects(AScope: TIDECommandScope
): boolean;
begin
if (Scope=nil) or (AScope=nil) then
Result:=true
else
Result:=Scope.Intersects(AScope);
end;
procedure TIDECommandCategory.WriteScopeDebugReport;
begin
debugln('TIDECommandCategory.WriteScopeDebugReport ',Name,'=',Description);
if Scope<>nil then
Scope.WriteDebugReport
else
debugln(' Scope=nil');
end;
procedure TIDECommandCategory.Delete(Index: Integer);
begin
inherited Delete(Index);
end;
{ TIDECommandScope }
function TIDECommandScope.GetCategories(Index: integer): TIDECommandCategory;
begin
Result:=TIDECommandCategory(FCategories[Index]);
end;
function TIDECommandScope.GetIDEWindowClasses(Index: integer): TCustomFormClass;
begin
Result:=TCustomFormClass(FIDEWindowClasses[Index]);
end;
constructor TIDECommandScope.Create(const TheName: string);
begin
FName:=TheName;
FIDEWindowClasses:=TFPList.Create;
FCategories:=TFPList.Create;
end;
destructor TIDECommandScope.Destroy;
var
i: Integer;
begin
for i:=FCategories.Count-1 downto 0 do
Categories[i].Scope:=nil;
FreeAndNil(FIDEWindowClasses);
FreeAndNil(FCategories);
inherited Destroy;
end;
procedure TIDECommandScope.AddWindowClass(AWindowClass: TCustomFormClass);
begin
if FIDEWindowClasses.IndexOf(AWindowClass)>=0 then
RaiseGDBException('TIDECommandScope.AddWindowClass');
FIDEWindowClasses.Add(AWindowClass);
end;
procedure TIDECommandScope.RemoveWindowClass(AWindowClass: TCustomFormClass);
begin
FIDEWindowClasses.Remove(AWindowClass);
end;
function TIDECommandScope.IDEWindowClassCount: integer;
begin
Result:=FIDEWindowClasses.Count;
end;
function TIDECommandScope.CategoryCount: integer;
begin
Result:=FCategories.Count;
end;
function TIDECommandScope.HasIDEWindowClass(AWindowClass: TCustomFormClass
): boolean;
var
i: Integer;
begin
if AWindowClass<>nil then begin
for i:=0 to FIDEWindowClasses.Count-1 do begin
if (FIDEWindowClasses[i]=nil)
or AWindowClass.InheritsFrom(TCustomFormClass(FIDEWindowClasses[i])) then
exit(true);
end;
end else begin
if FIDEWindowClasses.IndexOf(nil)>=0 then
exit(true);
end;
Result:=false;
end;
function TIDECommandScope.Intersects(AScope: TIDECommandScope): boolean;
var
i: Integer;
CurClass: TCustomFormClass;
begin
if AScope=nil then
Result:=true
else begin
for i:=0 to FIDEWindowClasses.Count-1 do begin
CurClass:=TCustomFormClass(FIDEWindowClasses[i]);
if (CurClass=nil)
or (AScope.FIDEWindowClasses.IndexOf(FIDEWindowClasses[i])>=0) then
exit(true);
end;
Result:=false;
end;
end;
procedure TIDECommandScope.WriteDebugReport;
var
i: Integer;
begin
debugln('TIDECommandScope.WriteDebugReport ',Name);
for i:=0 to FIDEWindowClasses.Count-1 do begin
if FIDEWindowClasses[i]=nil then
debugln(' ',dbgs(i),'/',dbgs(FIDEWindowClasses.Count),' nil')
else
debugln(' ',dbgs(i),'/',dbgs(FIDEWindowClasses.Count),' ',TClass(FIDEWindowClasses[i]).ClassName);
end;
end;
function IdentToIDECommand(const Ident: string; var Cmd: longint): boolean;
var
IDECommand: TIDECommand;
begin
if IDECommandList=nil then exit(false);
IDECommand := IDECommandList.FindCommandByName(Ident);
if IDECommand=nil then exit(false);
Result:=true;
Cmd := IDECommand.Command;
end;
function IDECommandToIdent(Cmd: longint; var Ident: string): boolean;
var
IDECommand: TIDECommand;
begin
if IDECommandList=nil then exit(false);
IDECommand := IDECommandList.FindIDECommand(Cmd);
if IDECommand=nil then exit(false);
Result:=true;
Ident:=IDECommand.Name;
end;
end.