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
- Root items
- 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;
@ -27,7 +32,7 @@ unit MenuIntf;
interface
uses
Classes, SysUtils, Menus, ImgList, Graphics, IDECommands;
Classes, SysUtils, Menus, ImgList, Graphics, TextTools, IDECommands;
type
TAddMenuItemProc =
@ -36,6 +41,7 @@ type
TIDEMenuSection = class;
{ TIDEMenuItem
A menu item in one of the IDE's menus.
This is only the base class for TIDEMenuSection and TIDEMenuCommand }
@ -87,6 +93,7 @@ type
end;
TIDEMenuItemClass = class of TIDEMenuItem;
{ TIDEMenuSection
An TIDEMenuItem with childs, either in a sub menu or separated with
separators. }
@ -116,6 +123,10 @@ type
function IndexOf(AnItem: TIDEMenuItem): Integer;
function NeedTopSeparator: 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
property ChildsAsSubMenu: boolean read FChildsAsSubMenu
write SetChildsAsSubMenu default true;
@ -127,11 +138,11 @@ type
end;
TIDEMenuSectionClass = class of TIDEMenuSection;
{ TIDEMenuCommand
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)
private
FAutoCheck: boolean;
@ -165,26 +176,89 @@ type
end;
TIDEMenuCommandClass = class of TIDEMenuCommand;
{ TIDEMenuRoots }
{ TIDEMenuRoots
These are the top level menu items of the IDE. }
TIDEMenuRoots = class(TPersistent)
private
FItems: TFPList;
function GetItems(Index: integer): TIDEMenuItem;
FItems: TFPList;// list of TIDEMenuSection
function GetItems(Index: integer): TIDEMenuSection;
public
constructor Create;
destructor Destroy; override;
procedure RegisterMenuRoot(Section: TIDEMenuItem);
procedure UnregisterMenuRoot(Section: TIDEMenuItem);
procedure RegisterMenuRoot(Section: TIDEMenuSection);
procedure UnregisterMenuRoot(Section: TIDEMenuSection);
function Count: Integer;
procedure Clear;
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
property Items[Index: integer]: TIDEMenuItem read GetItems; default;
property Items[Index: integer]: TIDEMenuSection read GetItems; default;
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
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 }
procedure TIDEMenuItem.SetEnabled(const AValue: Boolean);
@ -308,7 +382,10 @@ end;
function TIDEMenuItem.Size: Integer;
begin
Result:=1;
if Visible then
Result:=1
else
Result:=0;
end;
{ TIDEMenuSection }
@ -358,6 +435,7 @@ end;
procedure TIDEMenuSection.Insert(Index: Integer; AnItem: TIDEMenuItem);
begin
AnItem.fName:=CreateUniqueName(AnItem.Name);
FItems.Insert(Index,AnItem);
AnItem.FSection:=Self;
CreateChildMenuItem(Index);
@ -368,21 +446,42 @@ var
Item: TIDEMenuItem;
SubSection: TIDEMenuSection;
i: Integer;
ContainerMenuItem: TMenuItem;
MenuIndex: Integer;
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];
// create the child TMenuItem
Item.CreateMenuItem;
MenuItem.Insert(Index+GetChildsStartIndex,Item.MenuItem);
MenuItem.Insert(MenuIndex,Item.MenuItem);
// create the subsections
if Item is TIDEMenuSection then begin
SubSection:=TIDEMenuSection(Item);
for i:=0 to SubSection.Count-1 do
SubSection.CreateChildMenuItem(i);
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;
function TIDEMenuSection.GetChildsStartIndex: Integer;
@ -396,30 +495,22 @@ begin
inc(Result,Section[SiblingIndex].Size);
inc(SiblingIndex);
end;
if not Section.ChildsAsSubMenu then
inc(Result,Section.GetChildsStartIndex);
end;
function TIDEMenuSection.Size: Integer;
var
SelfIndex: LongInt;
NextSibling: TIDEMenuItem;
begin
Result:=1;
if (Section<>nil) and (not ChildsAsSubMenu) then begin
// childs are not in a submenu but directly added to parents menuitem
Result:=Count;
SelfIndex:=Section.IndexOf(Self);
if (SelfIndex>0) then begin
// a top separator is needed
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;
if Visible then begin
Result:=1;
if (Section<>nil) and (not ChildsAsSubMenu) then begin
// childs are not in a submenu but directly added to parents menuitem
Result:=Count;
if NeedTopSeparator then inc(Result);
if NeedBottomSeparator then inc(Result);
end;
end else begin
Result:=0;
end;
end;
@ -454,6 +545,44 @@ begin
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;
begin
Result:=TIDEMenuItem(FItems[Index]);
@ -548,7 +677,7 @@ end;
{ TIDEMenuRoots }
function TIDEMenuRoots.GetItems(Index: integer): TIDEMenuItem;
function TIDEMenuRoots.GetItems(Index: integer): TIDEMenuSection;
begin
Result:=TIDEMenuSection(FItems[Index]);
end;
@ -564,12 +693,13 @@ begin
inherited Destroy;
end;
procedure TIDEMenuRoots.RegisterMenuRoot(Section: TIDEMenuItem);
procedure TIDEMenuRoots.RegisterMenuRoot(Section: TIDEMenuSection);
begin
Section.FName:=CreateUniqueName(Section.Name);
FItems.Add(Section);
end;
procedure TIDEMenuRoots.UnregisterMenuRoot(Section: TIDEMenuItem);
procedure TIDEMenuRoots.UnregisterMenuRoot(Section: TIDEMenuSection);
begin
FItems.Remove(Section);
end;
@ -589,12 +719,73 @@ end;
procedure TIDEMenuRoots.Delete(Index: Integer);
var
OldItem: TIDEMenuItem;
OldItem: TIDEMenuSection;
begin
OldItem:=Items[Index];
UnregisterMenuRoot(OldItem);
OldItem.Free;
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.

View File

@ -82,6 +82,14 @@ function RESplit(const TheText, SeparatorRegExpr: string;
procedure RESplit(const TheText, SeparatorRegExpr: string; Pieces: TStrings;
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.
@ -149,5 +157,36 @@ begin
RESplit(TheText,SeparatorRegExpr,Result,ModifierStr);
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.