IdeIntf: Sanitize and simplify ActionListEditor code. Don't use for-loop variable after loop. Fix potential bugs.

git-svn-id: trunk@53094 -
This commit is contained in:
juha 2016-10-11 20:04:52 +00:00
parent 78830476ff
commit 41ea2e0f9e
2 changed files with 171 additions and 206 deletions

View File

@ -147,6 +147,10 @@ type
private private
FActionList: TActionList; FActionList: TActionList;
FDesigner: TComponentEditorDesigner; FDesigner: TComponentEditorDesigner;
procedure AddCategoryActions(aCategory: String);
function CategoryIndexOf(Category: String): Integer;
function IsValidCategory(Category: String): Boolean;
function ValidCategoriesInAllActions: Boolean;
procedure ResultStdActProc(const Category: string; ActionClass: TBasicActionClass; procedure ResultStdActProc(const Category: string; ActionClass: TBasicActionClass;
ActionProperty: TActStdPropItem; LastItem: Boolean); ActionProperty: TActStdPropItem; LastItem: Boolean);
procedure FillCategories; procedure FillCategories;
@ -252,6 +256,8 @@ function CreateAction(TheOwner: TComponent;
implementation implementation
{$R *.lfm}
var var
EditorForms : TList = nil; EditorForms : TList = nil;
@ -287,17 +293,12 @@ var
begin begin
if AList<>nil then if AList<>nil then
for i:=0 to EditorForms.Count-1 do begin for i:=0 to EditorForms.Count-1 do begin
if TActionListEditor(EditorForms[i]).FActionList=AList then begin if TActionListEditor(EditorForms[i]).FActionList=AList then
Result:=TActionListEditor(EditorForms[i]); Exit(TActionListEditor(EditorForms[i]));
Exit;
end;
end; end;
Result:=nil Result:=nil
end; end;
{$R *.lfm}
procedure RegisterActions(const ACategory: string; procedure RegisterActions(const ACategory: string;
const AClasses: array of TBasicActionClass; AResource: TComponentClass); const AClasses: array of TBasicActionClass; AResource: TComponentClass);
begin begin
@ -364,7 +365,6 @@ begin
if (Dest is TContainedAction) and (Dest.ImageIndex>=0) if (Dest is TContainedAction) and (Dest.ImageIndex>=0)
and (Src is TContainedAction) then begin and (Src is TContainedAction) then begin
// ToDo: copy image // ToDo: copy image
end; end;
end; end;
finally finally
@ -374,6 +374,31 @@ end;
{ TActionListEditor } { TActionListEditor }
function TActionListEditor.CategoryIndexOf(Category: String): Integer;
begin
Assert((Category <> cActionListEditorUnknownCategory)
and (Category <> cActionListEditorAllCategory), 'TActionListEditor.CategoryIndexOf: unexpected value.');
Result := lstCategory.Items.IndexOf(Category);
end;
function TActionListEditor.IsValidCategory(Category: String): Boolean;
begin
Assert((Category <> cActionListEditorUnknownCategory)
and (Category <> cActionListEditorAllCategory), 'TActionListEditor.IsValidCategory: unexpected value.');
Result := (lstCategory.Items.IndexOf(Category) >= 0);
end;
function TActionListEditor.ValidCategoriesInAllActions: Boolean;
var
i: Integer;
begin
Result := True;
if FActionList = nil then Exit;
for i := FActionList.ActionCount-1 downto 0 do
if not IsValidCategory(TContainedAction(FActionList.Actions[i]).Category) then
Exit(False);
end;
procedure TActionListEditor.OnComponentRenamed(AComponent: TComponent); procedure TActionListEditor.OnComponentRenamed(AComponent: TComponent);
begin begin
if Visible and Assigned(FActionList) if Visible and Assigned(FActionList)
@ -385,23 +410,8 @@ end;
procedure TActionListEditor.OnComponentSelection( procedure TActionListEditor.OnComponentSelection(
const NewSelection: TPersistentSelectionList); const NewSelection: TPersistentSelectionList);
var var
CurSelect: TContainedAction; CurAct: TContainedAction;
tmpCategory: String; tmpCategory: String;
function CategoryIndexOf(Name: String): Integer;
var
i: Integer;
begin
for i:= lstCategory.Items.Count-1 downto 0 do begin
if lstCategory.Items[i] = Name
then Break;
end;
Result := i;
if (i = lstCategory.Items.IndexOf(cActionListEditorUnknownCategory))
and (i = lstCategory.Items.IndexOf(cActionListEditorAllCategory))
then Result := 0;
end;
begin begin
// TODO: multiselect // TODO: multiselect
if Self.Visible if Self.Visible
@ -410,131 +420,89 @@ begin
and (NewSelection.Items[0] is TContainedAction) and (NewSelection.Items[0] is TContainedAction)
and (TContainedAction(NewSelection.Items[0]).ActionList = FActionList) then and (TContainedAction(NewSelection.Items[0]).ActionList = FActionList) then
begin begin
if GetSelectedAction = NewSelection.Items[0] if GetSelectedAction = NewSelection.Items[0] then Exit;
then Exit; CurAct := TContainedAction(NewSelection.Items[0]);
CurSelect := TContainedAction(NewSelection.Items[0]); Assert(curAct.Category = Trim(curAct.Category),
CurSelect.Category := Trim(CurSelect.Category); 'TActionListEditor.OnComponentSelection: Category must be trimmed.');
tmpCategory := CurSelect.Category; tmpCategory := CurAct.Category;
if (tmpCategory <> '') if (tmpCategory <> '') and (lstCategory.Items.IndexOf(tmpCategory) < 0) then
and (lstCategory.Items.IndexOf(tmpCategory) < 0) FillCategories;
then FillCategories; if tmpCategory = '' then
if tmpCategory = '' tmpCategory := cActionListEditorUnknownCategory;
then tmpCategory := cActionListEditorUnknownCategory;
if (lstCategory.Items[lstCategory.ItemIndex] <> tmpCategory) if (lstCategory.Items[lstCategory.ItemIndex] <> tmpCategory)
or (lstActionName.Items.IndexOf(CurSelect.Name) < 0) then or (lstActionName.Items.IndexOf(CurAct.Name) < 0) then
begin begin
if CurSelect.Category = '' lstCategory.ItemIndex := lstCategory.Items.IndexOf(tmpCategory);
then lstCategory.ItemIndex := lstCategory.Items.IndexOf(tmpCategory)
else lstCategory.ItemIndex := CategoryIndexOf(CurSelect.Category);
lstCategory.Click; lstCategory.Click;
end; end;
lstActionName.ItemIndex := lstActionName.Items.IndexOf(CurSelect.Name); lstActionName.ItemIndex := lstActionName.Items.IndexOf(CurAct.Name);
lstActionName.Click; lstActionName.Click;
end end
else lstActionName.ItemIndex := -1; else lstActionName.ItemIndex := -1;
end; end;
procedure TActionListEditor.OnRefreshPropertyValues; procedure TActionListEditor.OnRefreshPropertyValues;
function ValidCategory: Boolean;
// spr. czy wszystkie kategorie w ListBox'sie istniej¹ w TActionList
// inaczej: czy istnieje kategoria elementu wywoluj¹cego zdarzenie
var
i, j: Integer;
bool: Boolean;
begin
Result := True;
for i:= lstCategory.Items.Count-1 downto 0 do begin
if (lstCategory.Items[i] = cActionListEditorUnknownCategory)
and (i = lstCategory.Items.IndexOf(cActionListEditorAllCategory))
then Break;
bool := False;
if FActionList<>nil then
for j:= FActionList.ActionCount-1 downto 0 do begin
if TContainedAction(FActionList.Actions[j]).Category = lstCategory.Items[i] then begin
bool := True;
Break;
end;
end;
if not bool then begin
Result := False;
Break;
end;
end; // for i
end;
function IsCategory(Category: String): Boolean;
var
i: Integer;
begin
Result := False;
for i:= lstCategory.Items.Count-1 downto 0 do begin
if lstCategory.Items[i] = Category then begin
Result := True;
Break;
end;
end;
if (i >= 0)
and ((i = lstCategory.Items.IndexOf(cActionListEditorUnknownCategory))
or (i = lstCategory.Items.IndexOf(cActionListEditorAllCategory)))
then Result := False;
end;
var var
ASelections: TPersistentSelectionList; ASelections: TPersistentSelectionList;
curSelect: TContainedAction; curSel: TPersistent;
curAct: TContainedAction;
oldSelCategory, tmpCategory: String; oldSelCategory, tmpCategory: String;
tmpIndex: Integer; tmpIndex, OldIndex: Integer;
tmpValidCategory, tmpIsActCategory: Boolean; tmpValidAllCategories, tmpIsActCategory: Boolean;
begin begin
if Self.Visible and Assigned(GlobalDesignHook) then begin if not Visible then Exit;
ASelections:= TPersistentSelectionList.Create; if GlobalDesignHook = nil then Exit;
GlobalDesignHook.GetSelection(ASelections); ASelections := TPersistentSelectionList.Create;
try GlobalDesignHook.GetSelection(ASelections);
if (ASelections.Count > 0) try
and (ASelections.Items[0] is TContainedAction) if ASelections.Count = 0 then Exit;
and (TContainedAction(ASelections.Items[0]).ActionList = FActionList) curSel := ASelections.Items[0];
then begin if not (curSel is TContainedAction) then Exit;
curSelect := TContainedAction(ASelections.Items[0]); curAct := TContainedAction(curSel);
CurSelect.Category := Trim(CurSelect.Category); if curAct.ActionList <> FActionList then Exit;
oldSelCategory := lstCategory.Items[lstCategory.ItemIndex]; Assert(curAct.Category = Trim(curAct.Category),
tmpCategory := CurSelect.Category; 'TActionListEditor.OnRefreshPropertyValues: Category must be trimmed.');
oldSelCategory := lstCategory.Items[lstCategory.ItemIndex];
tmpValidCategory := ValidCategory; tmpCategory := curAct.Category;
tmpIsActCategory := IsCategory(CurSelect.Category);
if tmpCategory = '' then tmpCategory := cActionListEditorUnknownCategory;
if ((curSelect.Category <> '') and not tmpIsActCategory)
or not tmpValidCategory
or ((tmpCategory <> lstCategory.Items[lstCategory.Items.IndexOf(tmpCategory)])
and ((lstCategory.Items.IndexOf(cActionListEditorAllCategory) >= 0)
and (tmpCategory <> lstCategory.Items[lstCategory.Items.IndexOf(cActionListEditorAllCategory)]))
and (tmpCategory <> lstCategory.Items[lstCategory.Items.IndexOf(cActionListEditorUnknownCategory)]))
then FillCategories;
tmpIndex := lstCategory.Items.IndexOf(tmpCategory); tmpValidAllCategories := ValidCategoriesInAllActions;
if (lstCategory.Items.Count > 1) tmpIsActCategory := IsValidCategory(curAct.Category);
and ( ((not tmpIsActCategory) and (not tmpValidCategory))
or ((lstCategory.Items.IndexOf(oldSelCategory) >=0) and (not tmpIsActCategory)) if tmpCategory = '' then
or ((lstCategory.Items.IndexOf(oldSelCategory) = -1) and (tmpIndex >= 0)) tmpCategory := cActionListEditorUnknownCategory;
or ((lstCategory.Items.IndexOf(oldSelCategory) >= 0) and (tmpIndex >= 0)) ) tmpIndex := lstCategory.Items.IndexOf(tmpCategory);
and (oldSelCategory <> cActionListEditorAllCategory) then begin if ( (curAct.Category <> '') and not tmpIsActCategory )
lstCategory.ItemIndex := tmpIndex; or not tmpValidAllCategories
lstCategory.Click; or ( (tmpCategory <> lstCategory.Items[tmpIndex])
end; and (tmpCategory <> cActionListEditorUnknownCategory) )
tmpIndex := lstActionName.items.IndexOf(CurSelect.Name); then
if lstActionName.ItemIndex <> tmpIndex then begin FillCategories;
lstActionName.ItemIndex := tmpIndex;
lstActionName.Click; tmpIndex := lstCategory.Items.IndexOf(tmpCategory);
end; OldIndex := lstCategory.Items.IndexOf(oldSelCategory);
end; if (lstCategory.Items.Count > 1)
finally and ( ( not (tmpIsActCategory or tmpValidAllCategories) )
ASelections.Free; or ( (OldIndex >=0) and (not tmpIsActCategory) )
or ( tmpIndex >= 0 ) )
and (oldSelCategory <> cActionListEditorAllCategory) then
begin
lstCategory.ItemIndex := tmpIndex;
lstCategory.Click;
end; end;
tmpIndex := lstActionName.items.IndexOf(curAct.Name);
if lstActionName.ItemIndex <> tmpIndex then
begin
lstActionName.ItemIndex := tmpIndex;
lstActionName.Click;
end;
finally
ASelections.Free;
end; end;
end; end;
function TActionListEditor.GetSelectedAction: TContainedAction; function TActionListEditor.GetSelectedAction: TContainedAction;
begin begin
if (lstActionName.ItemIndex >= 0) if (lstActionName.ItemIndex >= 0) and (FActionList <> nil) then
and (FActionList<>nil) then
Result := FActionList.ActionByName(lstActionName.Items[lstActionName.ItemIndex]) Result := FActionList.ActionByName(lstActionName.Items[lstActionName.ItemIndex])
else else
Result := nil; Result := nil;
@ -578,8 +546,8 @@ begin
FDesigner.PropertyEditorHook.PersistentAdded(NewAction,True); FDesigner.PropertyEditorHook.PersistentAdded(NewAction,True);
FDesigner.Modified; FDesigner.Modified;
if LastItem if LastItem then
then FDesigner.SelectOnlyThisComponent(FActionList.ActionByName(NewAction.Name)); FDesigner.SelectOnlyThisComponent(FActionList.ActionByName(NewAction.Name));
end; end;
procedure TActionListEditor.SplitterCanResize(Sender: TObject; procedure TActionListEditor.SplitterCanResize(Sender: TObject;
@ -676,8 +644,8 @@ begin
NewAction.ActionList := FActionList; NewAction.ActionList := FActionList;
// Selection updates correctly when we first clear the selection in Designer // Selection updates correctly when we first clear the selection in Designer
// and in Object Inspector, then add a new item. // and in Object Inspector, then add a new item. Otherwise there is
// Otherwise there is a loop of back-and-forth updates and the new item does not show. // a loop of back-and-forth selection updates and the new item does not show.
FDesigner.ClearSelection; FDesigner.ClearSelection;
FDesigner.PropertyEditorHook.PersistentAdded(NewAction,True); FDesigner.PropertyEditorHook.PersistentAdded(NewAction,True);
FDesigner.Modified; FDesigner.Modified;
@ -794,18 +762,17 @@ begin
end; end;
procedure TActionListEditor.ActDeleteExecute(Sender: TObject); procedure TActionListEditor.ActDeleteExecute(Sender: TObject);
function IsCategory(Category: String): Boolean;
function ActionListHasCategory(Category: String): Boolean;
var var
i: Integer; i: Integer;
begin begin
Result := False; Result := False;
for i:= FActionList.ActionCount-1 downto 0 do begin for i:= FActionList.ActionCount-1 downto 0 do
if FActionList.Actions[i].Category = Category then begin if FActionList.Actions[i].Category = Category then
Result := True; Exit(True);
Break;
end;
end;
end; end;
var var
iNameIndex: Integer; iNameIndex: Integer;
OldName: String; OldName: String;
@ -848,7 +815,7 @@ begin
FActionList.ActionByName(lstActionName.Items[lstActionName.ItemIndex])); FActionList.ActionByName(lstActionName.Items[lstActionName.ItemIndex]));
end; end;
If not IsCategory(OldName) then begin If not ActionListHasCategory(OldName) then begin
OldIndex:=lstCategory.Items.IndexOf(OldName); OldIndex:=lstCategory.Items.IndexOf(OldName);
if OldIndex>=0 then if OldIndex>=0 then
lstCategory.Items.Delete(OldIndex); lstCategory.Items.Delete(OldIndex);
@ -951,8 +918,8 @@ var
begin begin
// try remember old category // try remember old category
sOldCategory := ''; sOldCategory := '';
if (lstCategory.Items.Count>0) and (lstCategory.ItemIndex>-1) if lstCategory.ItemIndex > -1 then
then sOldCategory := lstCategory.Items[lstCategory.ItemIndex]; sOldCategory := lstCategory.Items[lstCategory.ItemIndex];
lstCategory.Items.BeginUpdate; lstCategory.Items.BeginUpdate;
try try
@ -960,51 +927,63 @@ begin
lstCategory.Clear; lstCategory.Clear;
if FActionList<>nil then if FActionList<>nil then
for i := 0 to FActionList.ActionCount-1 do begin for i := 0 to FActionList.ActionCount-1 do
begin
sCategory := FActionList.Actions[i].Category; sCategory := FActionList.Actions[i].Category;
if sCategory = '' if sCategory = '' then Continue;
then Continue;
xIndex := lstCategory.Items.IndexOf(sCategory); xIndex := lstCategory.Items.IndexOf(sCategory);
if xIndex < 0 if xIndex < 0 then
then lstCategory.Items.Add(sCategory); lstCategory.Items.Add(sCategory);
end; end;
if lstCategory.Items.Count > 0 if lstCategory.Items.Count > 0 then
then lstCategory.Sorted := True; lstCategory.Sorted := True;
lstCategory.Sorted := False; lstCategory.Sorted := False;
xIndex := lstCategory.Items.IndexOf(sOldCategory); xIndex := lstCategory.Items.IndexOf(sOldCategory);
if lstCategory.Items.Count > 0 then begin
lstCategory.Items.Insert(0, cActionListEditorAllCategory);
if xIndex > 0 then Inc(xIndex);
end;
if lstCategory.Items.Count > 0 then if lstCategory.Items.Count > 0 then
begin begin
lstCategory.Items.Insert(1, cActionListEditorUnknownCategory); lstCategory.Items.Insert(0, cActionListEditorAllCategory);
if xIndex > 0 then Inc(xIndex); lstCategory.Items.Insert(1, cActionListEditorUnknownCategory);
end if xIndex > 0 then
else lstCategory.Items.Add(cActionListEditorUnknownCategory); Inc(xIndex, 2);
end
else
lstCategory.Items.Add(cActionListEditorUnknownCategory);
finally finally
lstCategory.Items.EndUpdate; lstCategory.Items.EndUpdate;
end; end;
if xIndex < 0 then begin if xIndex < 0 then begin
if Assigned(GetSelectedAction) if Assigned(GetSelectedAction) and (GetSelectedAction.Category = '') then
and (GetSelectedAction.Category = '') xIndex := lstCategory.Items.IndexOf(cActionListEditorUnknownCategory)
then xIndex := lstCategory.Items.IndexOf(cActionListEditorUnknownCategory) else
else xIndex := 0; xIndex := 0;
end; end;
lstCategory.ItemIndex := xIndex; lstCategory.ItemIndex := xIndex;
if ( ((lstCategory.ItemIndex <> lstCategory.items.IndexOf(cActionListEditorAllCategory)) if (lstCategory.ItemIndex <> lstCategory.items.IndexOf(cActionListEditorAllCategory))
or (lstActionName.Items.Count = 0)) or (lstActionName.Items.Count = 0)
or (countCategory <> lstCategory.Items.Count) ) or (countCategory <> lstCategory.Items.Count) then
then FillActionByCategory(xIndex); FillActionByCategory(xIndex);
end; end;
procedure TActionListEditor.FillActionByCategory(iIndex:Integer); procedure TActionListEditor.AddCategoryActions(aCategory: String);
var
i: Integer;
Act: TContainedAction;
begin
for i := 0 to FActionList.ActionCount-1 do
begin
Act := FActionList.Actions[i];
if Act.Category = aCategory then
lstActionName.Items.AddObject(Act.Name, Act);
end;
end;
procedure TActionListEditor.FillActionByCategory(iIndex: Integer);
var var
i: Integer; i: Integer;
sCategory: String;
IndexedActionName: String; IndexedActionName: String;
begin begin
if FActionList=nil then if FActionList=nil then
@ -1014,9 +993,10 @@ begin
end; end;
lstActionName.Items.BeginUpdate; lstActionName.Items.BeginUpdate;
try try
if iIndex < 0 then iIndex := 0; // the first possition if iIndex < 0 then
if lstActionName.ItemIndex > -1 iIndex := 0; // the first position
then IndexedActionName := lstActionName.Items[lstActionName.ItemIndex]; if lstActionName.ItemIndex > -1 then
IndexedActionName := lstActionName.Items[lstActionName.ItemIndex];
lstActionName.Clear; lstActionName.Clear;
// handle all // handle all
@ -1028,27 +1008,22 @@ begin
// handle unknown // handle unknown
if iIndex = lstCategory.Items.IndexOf(cActionListEditorUnknownCategory) then begin if iIndex = lstCategory.Items.IndexOf(cActionListEditorUnknownCategory) then begin
for i := 0 to FActionList.ActionCount-1 do begin AddCategoryActions('');
if Trim(FActionList.Actions[i].Category) = '' then
lstActionName.Items.AddObject(FActionList.Actions[i].Name, FActionList.Actions[i]);
end;
Exit; //throught finally Exit; //throught finally
end; end;
// else sort to categories // else sort to categories
sCategory := lstCategory.Items[iIndex]; AddCategoryActions(lstCategory.Items[iIndex]);
for i := 0 to FActionList.ActionCount-1 do
begin
if FActionList.Actions[i].Category = sCategory
then lstActionName.Items.AddObject(FActionList.Actions[i].Name, FActionList.Actions[i]);
end;
finally finally
lstActionName.Items.EndUpdate; lstActionName.Items.EndUpdate;
if (IndexedActionName <> '') i := -1;
and (lstActionName.Items.IndexOf(IndexedActionName) > -1) if IndexedActionName <> '' then
then lstActionName.ItemIndex := lstActionName.Items.IndexOf(IndexedActionName) i := lstActionName.Items.IndexOf(IndexedActionName);
else if lstActionName.ItemIndex = -1 if i > -1 then
then FDesigner.SelectOnlyThisComponent(FActionList); lstActionName.ItemIndex := i
else if lstActionName.ItemIndex = -1 then
FDesigner.SelectOnlyThisComponent(FActionList);
end; end;
end; end;
@ -1128,8 +1103,7 @@ begin
FResource := AResource; FResource := AResource;
end; end;
procedure TRegisteredActionCategory.Add( procedure TRegisteredActionCategory.Add(const AClasses: array of TBasicActionClass);
const AClasses: array of TBasicActionClass);
var var
i: integer; i: integer;
CurCount: Integer; CurCount: Integer;
@ -1179,15 +1153,13 @@ begin
inherited Destroy; inherited Destroy;
end; end;
function TRegisteredActionCategory.IndexOfClass(AClass: TBasicActionClass function TRegisteredActionCategory.IndexOfClass(AClass: TBasicActionClass): integer;
): integer;
begin begin
Result:=Count-1; Result:=Count-1;
while (Result>=0) and (FItems[Result].ActionClass<>AClass) do Dec(Result); while (Result>=0) and (FItems[Result].ActionClass<>AClass) do Dec(Result);
end; end;
procedure TRegisteredActionCategory.EnumActions(Proc: TEnumActionProc; procedure TRegisteredActionCategory.EnumActions(Proc: TEnumActionProc; Info: Pointer);
Info: Pointer);
var var
i: Integer; i: Integer;
begin begin
@ -1198,8 +1170,7 @@ end;
{ TRegisteredActionCategories } { TRegisteredActionCategories }
function TRegisteredActionCategories.GetItems(Index: integer function TRegisteredActionCategories.GetItems(Index: integer): TRegisteredActionCategory;
): TRegisteredActionCategory;
begin begin
Result:=TRegisteredActionCategory(FItems[Index]); Result:=TRegisteredActionCategory(FItems[Index]);
end; end;
@ -1260,10 +1231,8 @@ begin
Result := nil; Result := nil;
for i := 0 to Count-1 do begin for i := 0 to Count-1 do begin
Category := Items[i]; Category := Items[i];
if Category.IndexOfClass(AClass) >= 0 then begin if Category.IndexOfClass(AClass) >= 0 then
Result := Category.Resource; Exit(Category.Resource);
Break;
end;
end; end;
end; end;
@ -1307,12 +1276,9 @@ var
i: Integer; i: Integer;
begin begin
Result := nil; Result := nil;
for i:= 0 to fPropList.Count-1 do begin for i:= 0 to fPropList.Count-1 do
if TActStdPropItem(fPropList[i]).ActClassName = ActClassName then begin if TActStdPropItem(fPropList[i]).ActClassName = ActClassName then
Result := TActStdPropItem(fPropList[i]); Exit(TActStdPropItem(fPropList[i]));
Break;
end;
end;
end; end;
{ TActStdPropItem } { TActStdPropItem }

View File

@ -49,8 +49,7 @@ type
property ActionList: TCustomActionList read FActionList write SetActionList; property ActionList: TCustomActionList read FActionList write SetActionList;
property Index: Integer read GetIndex write SetIndex stored False; property Index: Integer read GetIndex write SetIndex stored False;
published published
property Category: string property Category: string read FCategory write SetCategory;
read FCategory write SetCategory;
end; end;
TContainedActionClass = class of TContainedAction; TContainedActionClass = class of TContainedAction;