implemented menuintf registering menu items

git-svn-id: trunk@7450 -
This commit is contained in:
mattias 2005-07-30 01:44:06 +00:00
parent 7e8d0cc9c9
commit b4bd7945db
2 changed files with 267 additions and 37 deletions

View File

@ -19,6 +19,11 @@
- implement creating Top and Bottom separator - implement creating Top and Bottom separator
- Root items - Root items
- OnPopup - OnPopup
- Create MainBar menu with the menu interface
- Create Source Editor Popupmenu with the menu interface
- Create CodeExplorer Popupmenu with the menu interface
- Create Project Inspector Popupmenu with the menu interface
- Create Messages Popupmenu with the menu interface
} }
unit MenuIntf; unit MenuIntf;
@ -27,7 +32,7 @@ unit MenuIntf;
interface interface
uses uses
Classes, SysUtils, Menus, ImgList, Graphics, IDECommands; Classes, SysUtils, Menus, ImgList, Graphics, TextTools, IDECommands;
type type
TAddMenuItemProc = TAddMenuItemProc =
@ -36,6 +41,7 @@ type
TIDEMenuSection = class; TIDEMenuSection = class;
{ TIDEMenuItem { TIDEMenuItem
A menu item in one of the IDE's menus. A menu item in one of the IDE's menus.
This is only the base class for TIDEMenuSection and TIDEMenuCommand } This is only the base class for TIDEMenuSection and TIDEMenuCommand }
@ -87,6 +93,7 @@ type
end; end;
TIDEMenuItemClass = class of TIDEMenuItem; TIDEMenuItemClass = class of TIDEMenuItem;
{ TIDEMenuSection { TIDEMenuSection
An TIDEMenuItem with childs, either in a sub menu or separated with An TIDEMenuItem with childs, either in a sub menu or separated with
separators. } separators. }
@ -116,6 +123,10 @@ type
function IndexOf(AnItem: TIDEMenuItem): Integer; function IndexOf(AnItem: TIDEMenuItem): Integer;
function NeedTopSeparator: Boolean; function NeedTopSeparator: Boolean;
function NeedBottomSeparator: Boolean; function NeedBottomSeparator: Boolean;
function GetContainerMenuItem: TMenuItem;
function IndexByName(const AName: string): Integer;
function FindByName(const AName: string): TIDEMenuItem;
function CreateUniqueName(const AName: string): string;
public public
property ChildsAsSubMenu: boolean read FChildsAsSubMenu property ChildsAsSubMenu: boolean read FChildsAsSubMenu
write SetChildsAsSubMenu default true; write SetChildsAsSubMenu default true;
@ -127,11 +138,11 @@ type
end; end;
TIDEMenuSectionClass = class of TIDEMenuSection; TIDEMenuSectionClass = class of TIDEMenuSection;
{ TIDEMenuCommand { TIDEMenuCommand
A leaf menu item. No childs. A leaf menu item. No childs.
An IDE command can be assigned, which defines the shortcut. Hint: The shortcut is defined via the Command property.
} }
TIDEMenuCommand = class(TIDEMenuItem) TIDEMenuCommand = class(TIDEMenuItem)
private private
FAutoCheck: boolean; FAutoCheck: boolean;
@ -165,26 +176,89 @@ type
end; end;
TIDEMenuCommandClass = class of TIDEMenuCommand; TIDEMenuCommandClass = class of TIDEMenuCommand;
{ TIDEMenuRoots }
{ TIDEMenuRoots
These are the top level menu items of the IDE. }
TIDEMenuRoots = class(TPersistent) TIDEMenuRoots = class(TPersistent)
private private
FItems: TFPList; FItems: TFPList;// list of TIDEMenuSection
function GetItems(Index: integer): TIDEMenuItem; function GetItems(Index: integer): TIDEMenuSection;
public public
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
procedure RegisterMenuRoot(Section: TIDEMenuItem); procedure RegisterMenuRoot(Section: TIDEMenuSection);
procedure UnregisterMenuRoot(Section: TIDEMenuItem); procedure UnregisterMenuRoot(Section: TIDEMenuSection);
function Count: Integer; function Count: Integer;
procedure Clear; procedure Clear;
procedure Delete(Index: Integer); procedure Delete(Index: Integer);
function IndexByName(const Name: string): Integer;
function FindByName(const Name: string): TIDEMenuSection;
function CreateUniqueName(const Name: string): string;
function FindByPath(const Path: string;
ErrorOnNotFound: boolean): TIDEMenuItem;
public public
property Items[Index: integer]: TIDEMenuItem read GetItems; default; property Items[Index: integer]: TIDEMenuSection read GetItems; default;
end; end;
var
IDEMenuRoots: TIDEMenuRoots = nil;// created by the IDE
function RegisterIDEMenuRoot(const Name: string; MenuItem: TMenuItem
): TIDEMenuSection;
function RegisterIDEMenuSection(const Path, Name: string): TIDEMenuSection;
function RegisterIDESubMenu(const Path, Name, Caption: string;
const OnClick: TNotifyEvent): TIDEMenuSection;
function RegisterIDEMenuItem(const Path, Name, Caption: string;
const OnClick: TNotifyEvent;
const Command: TIDECommandKeys): TIDEMenuCommand;
implementation implementation
function RegisterIDEMenuRoot(const Name: string; MenuItem: TMenuItem
): TIDEMenuSection;
begin
Result:=TIDEMenuSection.Create(Name);
IDEMenuRoots.RegisterMenuRoot(Result);
Result.MenuItem:=MenuItem;
end;
function RegisterIDEMenuSection(const Path, Name: string): TIDEMenuSection;
var
Parent: TIDEMenuSection;
begin
Parent:=IDEMenuRoots.FindByPath(Path,true) as TIDEMenuSection;
Result:=TIDEMenuSection.Create(Name);
Result.ChildsAsSubMenu:=false;
Parent.AddLast(Result);
end;
function RegisterIDESubMenu(const Path, Name, Caption: string;
const OnClick: TNotifyEvent): TIDEMenuSection;
var
Parent: TIDEMenuSection;
begin
Parent:=IDEMenuRoots.FindByPath(Path,true) as TIDEMenuSection;
Result:=TIDEMenuSection.Create(Name);
Result.ChildsAsSubMenu:=true;
Result.Caption:=Caption;
Result.OnClick:=OnClick;
Parent.AddLast(Result);
end;
function RegisterIDEMenuItem(const Path, Name, Caption: string;
const OnClick: TNotifyEvent; const Command: TIDECommandKeys): TIDEMenuCommand;
var
Parent: TIDEMenuSection;
begin
Parent:=IDEMenuRoots.FindByPath(Path,true) as TIDEMenuSection;
Result:=TIDEMenuCommand.Create(Name);
Result.Caption:=Caption;
Result.OnClick:=OnClick;
Result.Command:=Command;
Parent.AddLast(Result);
end;
{ TIDEMenuItem } { TIDEMenuItem }
procedure TIDEMenuItem.SetEnabled(const AValue: Boolean); procedure TIDEMenuItem.SetEnabled(const AValue: Boolean);
@ -308,7 +382,10 @@ end;
function TIDEMenuItem.Size: Integer; function TIDEMenuItem.Size: Integer;
begin begin
Result:=1; if Visible then
Result:=1
else
Result:=0;
end; end;
{ TIDEMenuSection } { TIDEMenuSection }
@ -358,6 +435,7 @@ end;
procedure TIDEMenuSection.Insert(Index: Integer; AnItem: TIDEMenuItem); procedure TIDEMenuSection.Insert(Index: Integer; AnItem: TIDEMenuItem);
begin begin
AnItem.fName:=CreateUniqueName(AnItem.Name);
FItems.Insert(Index,AnItem); FItems.Insert(Index,AnItem);
AnItem.FSection:=Self; AnItem.FSection:=Self;
CreateChildMenuItem(Index); CreateChildMenuItem(Index);
@ -368,21 +446,42 @@ var
Item: TIDEMenuItem; Item: TIDEMenuItem;
SubSection: TIDEMenuSection; SubSection: TIDEMenuSection;
i: Integer; i: Integer;
ContainerMenuItem: TMenuItem;
MenuIndex: Integer;
begin begin
if MenuItem=nil then exit; ContainerMenuItem:=GetContainerMenuItem;
if (ContainerMenuItem=nil) then exit;
MenuIndex:=GetChildsStartIndex+Index;
if NeedTopSeparator then begin
if (TopSeparator=nil) then begin
// create TopSeparator
FTopSeparator:=MenuItemClass.Create(nil);
FTopSeparator.Caption:='-';
MenuItem.Insert(GetChildsStartIndex,FTopSeparator);
end;
inc(MenuIndex);
end;
Item:=Items[Index]; Item:=Items[Index];
// create the child TMenuItem // create the child TMenuItem
Item.CreateMenuItem; Item.CreateMenuItem;
MenuItem.Insert(Index+GetChildsStartIndex,Item.MenuItem); MenuItem.Insert(MenuIndex,Item.MenuItem);
// create the subsections // create the subsections
if Item is TIDEMenuSection then begin if Item is TIDEMenuSection then begin
SubSection:=TIDEMenuSection(Item); SubSection:=TIDEMenuSection(Item);
for i:=0 to SubSection.Count-1 do for i:=0 to SubSection.Count-1 do
SubSection.CreateChildMenuItem(i); SubSection.CreateChildMenuItem(i);
end; end;
if (Index=Count-1) and NeedBottomSeparator and (BottomSeparator=nil) then
begin
// create bottom separator
FBottomSeparator:=MenuItemClass.Create(nil);
FBottomSeparator.Caption:='-';
MenuItem.Insert(MenuIndex+1,FBottomSeparator);
end;
end; end;
function TIDEMenuSection.GetChildsStartIndex: Integer; function TIDEMenuSection.GetChildsStartIndex: Integer;
@ -396,30 +495,22 @@ begin
inc(Result,Section[SiblingIndex].Size); inc(Result,Section[SiblingIndex].Size);
inc(SiblingIndex); inc(SiblingIndex);
end; end;
if not Section.ChildsAsSubMenu then
inc(Result,Section.GetChildsStartIndex);
end; end;
function TIDEMenuSection.Size: Integer; function TIDEMenuSection.Size: Integer;
var
SelfIndex: LongInt;
NextSibling: TIDEMenuItem;
begin begin
Result:=1; if Visible then begin
if (Section<>nil) and (not ChildsAsSubMenu) then begin Result:=1;
// childs are not in a submenu but directly added to parents menuitem if (Section<>nil) and (not ChildsAsSubMenu) then begin
Result:=Count; // childs are not in a submenu but directly added to parents menuitem
SelfIndex:=Section.IndexOf(Self); Result:=Count;
if (SelfIndex>0) then begin if NeedTopSeparator then inc(Result);
// a top separator is needed if NeedBottomSeparator then inc(Result);
inc(Result);
end;
if (SelfIndex<Section.Count-1) then begin
NextSibling:=Section[SelfIndex-1];
if (not (NextSibling is TIDEMenuSection))
or (not TIDEMenuSection(NextSibling).ChildsAsSubMenu) then begin
// a bottom separator is needed
inc(Result);
end;
end; end;
end else begin
Result:=0;
end; end;
end; end;
@ -454,6 +545,44 @@ begin
end; end;
end; end;
function TIDEMenuSection.GetContainerMenuItem: TMenuItem;
var
IDEMenuItem: TIDEMenuSection;
begin
IDEMenuItem:=Self;
while (IDEMenuItem<>nil) and (not IDEMenuItem.ChildsAsSubMenu) do
IDEMenuItem:=IDEMenuItem.Section;
if (IDEMenuItem<>nil) then
Result:=IDEMenuItem.MenuItem;
end;
function TIDEMenuSection.IndexByName(const AName: string): Integer;
begin
Result:=Count-1;
while (Result>=0) and (CompareText(AName,Items[Result].Name)<>0) do
dec(Result);
end;
function TIDEMenuSection.FindByName(const AName: string): TIDEMenuItem;
var
i: LongInt;
begin
i:=IndexByName(AName);
if i>=0 then
Result:=Items[i]
else
Result:=nil;
end;
function TIDEMenuSection.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 TIDEMenuSection.GetItems(Index: Integer): TIDEMenuItem; function TIDEMenuSection.GetItems(Index: Integer): TIDEMenuItem;
begin begin
Result:=TIDEMenuItem(FItems[Index]); Result:=TIDEMenuItem(FItems[Index]);
@ -548,7 +677,7 @@ end;
{ TIDEMenuRoots } { TIDEMenuRoots }
function TIDEMenuRoots.GetItems(Index: integer): TIDEMenuItem; function TIDEMenuRoots.GetItems(Index: integer): TIDEMenuSection;
begin begin
Result:=TIDEMenuSection(FItems[Index]); Result:=TIDEMenuSection(FItems[Index]);
end; end;
@ -564,12 +693,13 @@ begin
inherited Destroy; inherited Destroy;
end; end;
procedure TIDEMenuRoots.RegisterMenuRoot(Section: TIDEMenuItem); procedure TIDEMenuRoots.RegisterMenuRoot(Section: TIDEMenuSection);
begin begin
Section.FName:=CreateUniqueName(Section.Name);
FItems.Add(Section); FItems.Add(Section);
end; end;
procedure TIDEMenuRoots.UnregisterMenuRoot(Section: TIDEMenuItem); procedure TIDEMenuRoots.UnregisterMenuRoot(Section: TIDEMenuSection);
begin begin
FItems.Remove(Section); FItems.Remove(Section);
end; end;
@ -589,12 +719,73 @@ end;
procedure TIDEMenuRoots.Delete(Index: Integer); procedure TIDEMenuRoots.Delete(Index: Integer);
var var
OldItem: TIDEMenuItem; OldItem: TIDEMenuSection;
begin begin
OldItem:=Items[Index]; OldItem:=Items[Index];
UnregisterMenuRoot(OldItem); UnregisterMenuRoot(OldItem);
OldItem.Free; OldItem.Free;
end; end;
function TIDEMenuRoots.IndexByName(const Name: string): Integer;
begin
Result:=Count-1;
while (Result>=0) and (CompareText(Name,Items[Result].Name)<>0) do
dec(Result);
end;
function TIDEMenuRoots.FindByName(const Name: string): TIDEMenuSection;
var
i: LongInt;
begin
i:=IndexByName(Name);
if i>=0 then
Result:=Items[i]
else
Result:=nil;
end;
function TIDEMenuRoots.CreateUniqueName(const Name: string): string;
begin
Result:=Name;
if IndexByName(Result)=0 then exit;
Result:=CreateFirstIdentifier(Result);
while IndexByName(Result)>=0 do
Result:=CreateNextIdentifier(Result);
end;
function TIDEMenuRoots.FindByPath(const Path: string;
ErrorOnNotFound: boolean): TIDEMenuItem;
var
StartPos: Integer;
EndPos: LongInt;
Name: String;
begin
Result:=nil;
StartPos:=1;
while StartPos<=length(Path) do begin
EndPos:=StartPos;
while (EndPos<=length(Path)) and (Path[EndPos]<>'/') do inc(EndPos);
if EndPos>StartPos then begin
Name:=copy(Path,StartPos,EndPos-StartPos);
if Result=nil then
// search root
Result:=FindByName(Name)
else if Result is TIDEMenuSection then
// search child
Result:=TIDEMenuSection(Result).FindByName(Name)
else
// path too long -> we are already at a leaf
Result:=nil;
if Result=nil then break;
end;
StartPos:=EndPos+1;
end;
if Result=nil then begin
if ErrorOnNotFound then begin
raise Exception.Create('IDE Menu path not found: '+Path);
end;
end;
end;
end. end.

View File

@ -82,6 +82,14 @@ function RESplit(const TheText, SeparatorRegExpr: string;
procedure RESplit(const TheText, SeparatorRegExpr: string; Pieces: TStrings; procedure RESplit(const TheText, SeparatorRegExpr: string; Pieces: TStrings;
const ModifierStr: string = ''); const ModifierStr: string = '');
// identifier
function CreateFirstIdentifier(const Identifier: string): string;
function CreateNextIdentifier(const Identifier: string): string;
// xml paths
function GetPathElement(const Path: string; StartPos: integer;
Stopper: char): string;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Internal stuff. // Internal stuff.
@ -149,5 +157,36 @@ begin
RESplit(TheText,SeparatorRegExpr,Result,ModifierStr); RESplit(TheText,SeparatorRegExpr,Result,ModifierStr);
end; end;
function CreateFirstIdentifier(const Identifier: string): string;
// example: Ident59 becomes Ident1
var
p: Integer;
begin
p:=length(Identifier);
while (p>=1) and (Identifier[p] in ['0'..'9']) do dec(p);
Result:=copy(Identifier,1,p)+'1';
end;
function CreateNextIdentifier(const Identifier: string): string;
// example: Ident59 becomes Ident60
var
p: Integer;
begin
p:=length(Identifier);
while (p>=1) and (Identifier[p] in ['0'..'9']) do dec(p);
Result:=copy(Identifier,1,p)
+IntToStr(1+StrToIntDef(copy(Identifier,p+1,length(Identifier)-p),0));
end;
function GetPathElement(const Path: string; StartPos: integer;
Stopper: char): string;
var
p: LongInt;
begin
p:=StartPos;
while (p<=length(Path)) and (Path[p]<>Stopper) do inc(p);
Result:=copy(Path,StartPos,p-StartPos);
end;
end. end.