mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 10:41:47 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1403 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			1403 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| { Copyright (C) 2004
 | |
| 
 | |
|  *****************************************************************************
 | |
|   See the file COPYING.modifiedLGPL.txt, included in this distribution,
 | |
|   for details about the license.
 | |
|  *****************************************************************************
 | |
| 
 | |
| 
 | |
|   implementing ActionList Editor
 | |
| 
 | |
|   authors:
 | |
|      Radek Cervinka, radek.cervinka@centrum.cz
 | |
|      Mattias Gaertner
 | |
|      Pawel Piwowar, alfapawel@tlen.pl
 | |
| 
 | |
|   TODO:- multiselect for the actions and categories
 | |
|        - drag & drop for the actions and categories
 | |
|        - standard icon for "Standard Action"
 | |
| }
 | |
| unit ActionsEditor;
 | |
| 
 | |
| {$mode objfpc}{$H+}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   Classes, SysUtils, LCLProc, Forms, Controls, Dialogs,
 | |
|   ActnList, ExtCtrls, Buttons, StdCtrls, ObjInspStrConsts,
 | |
|   ComponentEditors, PropEdits, PropEditUtils, DBActns, StdActns, LCLIntf,
 | |
|   LCLType, Graphics, Menus, ComCtrls, contnrs, IDEWindowIntf;
 | |
| 
 | |
| type
 | |
|   TActStdPropItem = class;
 | |
|   TActStdProp = class;
 | |
|   TResultActProc = procedure (const Category: string; ActionClass: TBasicActionClass;
 | |
|                   ActionProperty: TActStdPropItem; LastItem: Boolean) of object;
 | |
| 
 | |
|   TRecActStdProp = packed record
 | |
|     Caption: String;
 | |
|     ShortCut: TShortCut;
 | |
|     Hint: String;
 | |
|   end;
 | |
| 
 | |
|   { TActStdPropItem }
 | |
| 
 | |
|   TActStdPropItem = class
 | |
|   private
 | |
|     FActProperties: TRecActStdProp;
 | |
|     FClassName: String;
 | |
|     procedure SetActClassName(const AValue: String);
 | |
|     procedure SetActProperties(const AValue: TRecActStdProp);
 | |
|   public
 | |
|     property ActClassName: String read FClassName write SetActClassName;
 | |
|     property ActionProperty: TRecActStdProp read FActProperties write FActProperties;
 | |
|   end;
 | |
| 
 | |
|   { TActStdProp }
 | |
| 
 | |
|   TActStdProp = class
 | |
|   private
 | |
|     fPropList: TObjectList;
 | |
|   public
 | |
|     constructor Create;
 | |
|     destructor Destroy; override;
 | |
|     function IndexOfClass(ActClassName: String): TActStdPropItem;
 | |
|     procedure Add(ActClassType: TClass; HeadLine, ShortCut, Hint: String);
 | |
|   end;
 | |
| 
 | |
| 
 | |
|   TActionListComponentEditor = class;
 | |
|   
 | |
|   { TActionListEditor }
 | |
| 
 | |
|   TActionListEditor = class(TForm)
 | |
|     ActDelete: TAction;
 | |
|     ActPanelToolBar: TAction;
 | |
|     ActPanelDescr: TAction;
 | |
|     ActMoveUp: TAction;
 | |
|     ActMoveDown: TAction;
 | |
|     ActNewStd: TAction;
 | |
|     ActionListSelf: TActionList;
 | |
|     ActNew: TAction;
 | |
|     ImageList1: TImageList;
 | |
|     lblCategory: TLabel;
 | |
|     lblName: TLabel;
 | |
|     lstCategory: TListBox;
 | |
|     lstActionName: TListBox;
 | |
|     MenuItem1: TMenuItem;
 | |
|     MenuItem2: TMenuItem;
 | |
|     mItemActListPanelDescr: TMenuItem;
 | |
|     mItemToolBarNewStdAction: TMenuItem;
 | |
|     mItemToolBarNewAction: TMenuItem;
 | |
|     mItemActListNewAction: TMenuItem;
 | |
|     mItemActListNewStdAction: TMenuItem;
 | |
|     mItemActListMoveUpAction: TMenuItem;
 | |
|     mItemActListMoveDownAction: TMenuItem;
 | |
|     MenuItem6: TMenuItem;
 | |
|     mItemActListDelAction: TMenuItem;
 | |
|     MenuItem8: TMenuItem;
 | |
|     PanelDescr: TPanel;
 | |
|     PopMenuActions: TPopupMenu;
 | |
|     PopMenuToolBarActions: TPopupMenu;
 | |
|     Splitter: TSplitter;
 | |
|     ToolBar1: TToolBar;
 | |
|     btnAdd: TToolButton;
 | |
|     btnAddMore: TToolButton;
 | |
|     btnDelete: TToolButton;
 | |
|     ToolButton4: TToolButton;
 | |
|     btnUp: TToolButton;
 | |
|     btnDown: TToolButton;
 | |
|     procedure ActDeleteExecute(Sender: TObject);
 | |
|     procedure ActDeleteUpdate(Sender: TObject);
 | |
|     procedure ActMoveDownExecute(Sender: TObject);
 | |
|     procedure ActMoveDownUpdate(Sender: TObject);
 | |
|     procedure ActMoveUpUpdate(Sender: TObject);
 | |
|     procedure ActNewExecute(Sender: TObject);
 | |
|     procedure ActNewStdExecute(Sender: TObject);
 | |
|     procedure ActPanelDescrExecute(Sender: TObject);
 | |
|     procedure ActPanelToolBarExecute(Sender: TObject);
 | |
|     procedure ActionListEditorClose(Sender: TObject;
 | |
|       var CloseAction: TCloseAction);
 | |
|     procedure ActionListEditorKeyDown(Sender: TObject; var Key: Word;
 | |
|       {%H-}Shift: TShiftState);
 | |
|     procedure ActionListEditorKeyPress(Sender: TObject; var Key: char);
 | |
|     procedure FormCreate(Sender: TObject);
 | |
|     procedure lstActionNameDrawItem(Control: TWinControl; Index: Integer;
 | |
|       ARect: TRect; State: TOwnerDrawState);
 | |
|     procedure SplitterCanResize(Sender: TObject; var {%H-}NewSize: Integer;
 | |
|       var {%H-}Accept: Boolean);
 | |
|     procedure lstActionNameKeyDown(Sender: TObject; var Key: Word;
 | |
|       Shift: TShiftState);
 | |
|     procedure lstActionNameMouseDown(Sender: TOBject; Button: TMouseButton;
 | |
|       {%H-}Shift: TShiftState; {%H-}X, Y: Integer);
 | |
|     procedure lstCategoryClick(Sender: TObject);
 | |
|     procedure lstActionNameClick(Sender: TObject);
 | |
|     procedure lstActionNameDblClick(Sender: TObject);
 | |
|   protected
 | |
|     procedure OnComponentRenamed(AComponent: TComponent);
 | |
|     procedure OnComponentSelection(const NewSelection: TPersistentSelectionList);
 | |
|     procedure OnComponentDelete(APersistent: TPersistent);
 | |
|     procedure OnRefreshPropertyValues;
 | |
|     function GetSelectedAction: TContainedAction;
 | |
|     procedure Notification(AComponent: TComponent; Operation: TOperation);
 | |
|       override;
 | |
|   private
 | |
|     FActionList: TActionList;
 | |
|     FDesigner: TComponentEditorDesigner;
 | |
|     procedure ResultStdActProc(const Category: string; ActionClass: TBasicActionClass;
 | |
|                             ActionProperty: TActStdPropItem; LastItem: Boolean);
 | |
|   public
 | |
|     constructor Create(AOwner: TComponent); override;
 | |
|     destructor Destroy; override;
 | |
|     procedure SetActionList(AActionList: TActionList);
 | |
|     procedure FillCategories;
 | |
|     procedure FillActionByCategory(iIndex: Integer);
 | |
|     property Designer:TComponentEditorDesigner read FDesigner write FDesigner;
 | |
|   end; 
 | |
| 
 | |
|   { TActionListComponentEditor }
 | |
| 
 | |
|   TActionListComponentEditor = class(TComponentEditor)
 | |
|   private
 | |
|     FActionList: TActionList;
 | |
|     FDesigner: TComponentEditorDesigner;
 | |
|   protected
 | |
|   public
 | |
|     constructor Create(AComponent: TComponent;
 | |
|                        ADesigner: TComponentEditorDesigner); override;
 | |
|     destructor Destroy; override;
 | |
|     procedure Edit; override;
 | |
|     property ActionList: TActionList read FActionList write FActionList;
 | |
|     function GetVerbCount: Integer; override;
 | |
|     function GetVerb({%H-}Index: Integer): string; override;
 | |
|     procedure ExecuteVerb({%H-}Index: Integer); override;
 | |
|   end;
 | |
| 
 | |
|   { Action Registration }
 | |
| 
 | |
|   TRegisteredAction = class
 | |
|   private
 | |
|     FActionClass: TBasicActionClass;
 | |
|     FGroupId: Integer;
 | |
|   public
 | |
|     constructor Create(TheActionClass: TBasicActionClass; TheGroupID: integer);
 | |
|     property ActionClass: TBasicActionClass read FActionClass;
 | |
|     property GroupId: Integer read FGroupId;
 | |
|   end;
 | |
|   PRegisteredAction = ^TRegisteredAction;
 | |
|   
 | |
|   TRegisteredActionCategory = class
 | |
|   private
 | |
|     FCount: integer;
 | |
|     FName: string;
 | |
|     FItems: PRegisteredAction;
 | |
|     FResource: TComponentClass;
 | |
|     function GetItems(Index: integer): TRegisteredAction;
 | |
|   public
 | |
|     constructor Create(const CategoryName: string; AResource: TComponentClass);
 | |
|     procedure Add(const AClasses: array of TBasicActionClass);
 | |
|     destructor Destroy; override;
 | |
|     function IndexOfClass(AClass: TBasicActionClass): Integer;
 | |
|     procedure EnumActions(Proc: TEnumActionProc; Info: Pointer);
 | |
|     property Count: integer read FCount;
 | |
|     property Name: string read FName;
 | |
|     property Items[Index: integer]: TRegisteredAction read GetItems;
 | |
|     property Resource: TComponentClass read FResource;
 | |
|   end;
 | |
| 
 | |
|   TRegisteredActionCategories = class
 | |
|   private
 | |
|     FItems: TList;
 | |
|     function GetItems(Index: Integer): TRegisteredActionCategory;
 | |
|   public
 | |
|     procedure Add(const CategoryName: String;
 | |
|                   const AClasses: array of TBasicActionClass;
 | |
|                   AResource: TComponentClass);
 | |
|     destructor Destroy; override;
 | |
|     function IndexOfCategory(const CategoryName: String): integer;
 | |
|     procedure EnumActions(Proc: TEnumActionProc; Info: Pointer);
 | |
|     function FindResource(AClass: TBasicActionClass): TComponentClass;
 | |
|     function Count: Integer;
 | |
|     property Items[Index: Integer]: TRegisteredActionCategory read GetItems;
 | |
|   end;
 | |
| 
 | |
|   TNotifyActionListChange = procedure;
 | |
|   TCreateDlgStdActions = procedure(AOwner: TComponent; ResultActProc: TResultActProc;
 | |
|                                    out Form: TForm);
 | |
| 
 | |
|   { TActionCategoryProperty }
 | |
| 
 | |
|   TActionCategoryProperty = class(TStringPropertyEditor)
 | |
|   public
 | |
|     function  GetAttributes: TPropertyAttributes; override;
 | |
|     procedure GetValues(Proc: TGetStrProc); override;
 | |
|   end;
 | |
| 
 | |
| var
 | |
|   RegisteredActions: TRegisteredActionCategories = nil;
 | |
|   NotifyActionListChange: TNotifyActionListChange = nil;
 | |
|   CreateDlgStdActions: TCreateDlgStdActions = nil;
 | |
| 
 | |
| procedure RegisterActions(const ACategory: string;
 | |
|                           const AClasses: array of TBasicActionClass;
 | |
|                           AResource: TComponentClass);
 | |
| procedure UnRegisterActions(const {%H-}Classes: array of TBasicActionClass);
 | |
| procedure EnumActions(Proc: TEnumActionProc; Info: Pointer);
 | |
| function CreateAction(TheOwner: TComponent;
 | |
|                       ActionClass: TBasicActionClass): TBasicAction;
 | |
| 
 | |
| 
 | |
| implementation
 | |
| 
 | |
| var
 | |
|   EditorForms : TList = nil;
 | |
|   
 | |
| procedure InitFormsList;
 | |
| begin
 | |
|   EditorForms:=TList.Create;
 | |
| end;
 | |
| 
 | |
| procedure ReleaseFormsList;
 | |
| begin
 | |
|   EditorForms.Free;
 | |
|   EditorForms:=nil;
 | |
| end;
 | |
| 
 | |
| procedure AddActionEditor(Editor: TActionListEditor);
 | |
| begin
 | |
|   if Assigned(EditorForms) and (EditorForms.IndexOf(Editor)<0) then 
 | |
|     EditorForms.Add(Editor);
 | |
| end;
 | |
| 
 | |
| procedure ReleaseActionEditor(Editor: TActionListEditor);
 | |
| var
 | |
|   i : Integer;
 | |
| begin
 | |
|   if not Assigned(EditorForms) then Exit;
 | |
|   i:=EditorForms.IndexOf(Editor);
 | |
|   if i>=0 then EditorForms.Delete(i);
 | |
| end;
 | |
|   
 | |
| function FindActionEditor(AList: TActionList): TActionListEditor;
 | |
| var
 | |
|   i : Integer;
 | |
| begin
 | |
|   if AList<>nil then
 | |
|     for i:=0 to EditorForms.Count-1 do begin
 | |
|       if TActionListEditor(EditorForms[i]).FActionList=AList then begin
 | |
|         Result:=TActionListEditor(EditorForms[i]);
 | |
|         Exit;
 | |
|       end;
 | |
|     end;
 | |
|   Result:=nil
 | |
| end;
 | |
| 
 | |
| 
 | |
| {$R *.lfm}
 | |
| 
 | |
| procedure RegisterActions(const ACategory: string;
 | |
|   const AClasses: array of TBasicActionClass; AResource: TComponentClass);
 | |
| begin
 | |
|   RegisteredActions.Add(ACategory,AClasses,AResource);
 | |
| end;
 | |
| 
 | |
| procedure UnRegisterActions(const Classes: array of TBasicActionClass);
 | |
| begin
 | |
| 
 | |
| end;
 | |
| 
 | |
| procedure EnumActions(Proc: TEnumActionProc; Info: Pointer);
 | |
| begin
 | |
|   RegisteredActions.EnumActions(Proc,Info);
 | |
| end;
 | |
| 
 | |
| function CreateAction(TheOwner: TComponent;
 | |
|   ActionClass: TBasicActionClass): TBasicAction;
 | |
| var
 | |
|   ResourceClass: TComponentClass;
 | |
|   ResInstance: TComponent;
 | |
|   i: Integer;
 | |
|   Component: TComponent;
 | |
|   Action: TBasicAction;
 | |
|   Src: TCustomAction;
 | |
|   Dest: TCustomAction;
 | |
| begin
 | |
|   Result := ActionClass.Create(TheOwner);
 | |
|   // find a Resource component registered for this ActionClass
 | |
|   ResourceClass := RegisteredActions.FindResource(ActionClass);
 | |
|   if ResourceClass = nil then Exit;
 | |
|   ResInstance := ResourceClass.Create(nil);
 | |
|   try
 | |
|     // find an action owned by the Resource component
 | |
|     Action:=nil;
 | |
|     for i:= 0 to ResInstance.ComponentCount-1 do begin
 | |
|       Component := ResInstance.Components[i];
 | |
|       if (CompareText(Component.ClassName, ActionClass.ClassName)=0)
 | |
|          and (Component is TBasicAction) then begin
 | |
|         Action := TBasicAction(Component);
 | |
|         Break;
 | |
|       end;
 | |
|     end;
 | |
|     if Action = nil then Exit;
 | |
| 
 | |
|     // copy TCustomAction properties
 | |
|     if (Action is TCustomAction) and (Result is TCustomAction) then begin
 | |
|       Src := TCustomAction(Action);
 | |
|       Dest := TCustomAction(Result);
 | |
|       Dest.AutoCheck := Src.AutoCheck;
 | |
|       Dest.Caption:=Src.Caption;
 | |
|       Dest.Category := Src.Category;
 | |
|       Dest.Checked:=Src.Checked;
 | |
|       Dest.Enabled:=Src.Enabled;
 | |
|       Dest.HelpContext:=Src.HelpContext;
 | |
|       Dest.HelpKeyword := Src.HelpKeyword;
 | |
|       Dest.HelpType := Src.HelpType;
 | |
|       Dest.Hint:=Src.Hint;
 | |
|       Dest.ImageIndex:=Src.ImageIndex;
 | |
|       Dest.SecondaryShortCuts := Src.SecondaryShortCuts;
 | |
|       Dest.ShortCut:=Src.ShortCut;
 | |
|       Dest.Visible:=Src.Visible;
 | |
| //      Src.AssignTo(Dest);
 | |
|       if (Dest is TContainedAction) and (Dest.ImageIndex>=0)
 | |
|       and (Src is TContainedAction) then begin
 | |
|         // ToDo: copy image
 | |
| 
 | |
|       end;
 | |
|     end;
 | |
|   finally
 | |
|     ResInstance.Free;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| { TActionListEditor }
 | |
| 
 | |
| procedure TActionListEditor.OnComponentRenamed(AComponent: TComponent);
 | |
| begin
 | |
|   if Visible and Assigned(FActionList)
 | |
|   and (AComponent is TAction) and (TAction(AComponent).ActionList = FActionList)
 | |
|   and Assigned(FActionList.ActionByName(AComponent.Name)) then
 | |
|     lstActionName.Items[lstActionName.ItemIndex] := AComponent.Name;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.OnComponentSelection(
 | |
|   const NewSelection: TPersistentSelectionList);
 | |
| var
 | |
|   CurSelect: TContainedAction;
 | |
|   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
 | |
|   // TODO: multiselect
 | |
|   if Self.Visible
 | |
|      and Assigned(NewSelection)
 | |
|      and (NewSelection.Count > 0)
 | |
|      and (NewSelection.Items[0] is TContainedAction)
 | |
|      and (TContainedAction(NewSelection.Items[0]).ActionList = FActionList) then
 | |
|     begin
 | |
|       if GetSelectedAction = NewSelection.Items[0]
 | |
|       then Exit;
 | |
|       CurSelect := TContainedAction(NewSelection.Items[0]);
 | |
|       CurSelect.Category := Trim(CurSelect.Category);
 | |
|       tmpCategory := CurSelect.Category;
 | |
|       if (tmpCategory <> '')
 | |
|          and (lstCategory.Items.IndexOf(tmpCategory) < 0)
 | |
|       then FillCategories;
 | |
|       if tmpCategory = ''
 | |
|       then tmpCategory := cActionListEditorUnknownCategory;
 | |
|       if (lstCategory.Items[lstCategory.ItemIndex] <> tmpCategory)
 | |
|          or ((lstCategory.Items[lstCategory.ItemIndex] = tmpCategory)
 | |
|               and (lstActionName.Items.IndexOf(CurSelect.Name) < 0)) then begin
 | |
|         if CurSelect.Category = ''
 | |
|         then lstCategory.ItemIndex := lstCategory.Items.IndexOf(tmpCategory)
 | |
|         else lstCategory.ItemIndex := CategoryIndexOf(CurSelect.Category);
 | |
|         lstCategory.Click;
 | |
|       end;
 | |
|       lstActionName.ItemIndex := lstActionName.Items.IndexOf(CurSelect.Name);
 | |
|       lstActionName.Click;
 | |
|     end
 | |
|   else lstActionName.ItemIndex := -1;
 | |
| end;
 | |
| 
 | |
| 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
 | |
|   ASelections: TPersistentSelectionList;
 | |
|   curSelect: TContainedAction;
 | |
|   oldSelCategory, tmpCategory: String;
 | |
|   tmpIndex: Integer;
 | |
|   tmpValidCategory, tmpIsActCategory: Boolean;
 | |
| begin
 | |
|   if Self.Visible and Assigned(GlobalDesignHook) then begin
 | |
|     ASelections:= TPersistentSelectionList.Create;
 | |
|     GlobalDesignHook.GetSelection(ASelections);
 | |
|     try
 | |
|       if (ASelections.Count > 0)
 | |
|          and (ASelections.Items[0] is TContainedAction)
 | |
|          and (TContainedAction(ASelections.Items[0]).ActionList = FActionList)
 | |
|       then begin
 | |
|         curSelect := TContainedAction(ASelections.Items[0]);
 | |
|         CurSelect.Category := Trim(CurSelect.Category);
 | |
|         oldSelCategory := lstCategory.Items[lstCategory.ItemIndex];
 | |
|         tmpCategory := CurSelect.Category;
 | |
|         
 | |
|         tmpValidCategory := ValidCategory;
 | |
|         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);
 | |
|         if (lstCategory.Items.Count > 1)
 | |
|            and ( ((not tmpIsActCategory) and (not tmpValidCategory))
 | |
|                  or ((lstCategory.Items.IndexOf(oldSelCategory) >=0) and (not tmpIsActCategory))
 | |
|                  or ((lstCategory.Items.IndexOf(oldSelCategory) = -1) and (tmpIndex >= 0))
 | |
|                  or ((lstCategory.Items.IndexOf(oldSelCategory) >= 0) and (tmpIndex >= 0)) )
 | |
|            and (oldSelCategory <> cActionListEditorAllCategory) then begin
 | |
|           lstCategory.ItemIndex := tmpIndex;
 | |
|           lstCategory.Click;
 | |
|         end;
 | |
|         tmpIndex := lstActionName.items.IndexOf(CurSelect.Name);
 | |
|         if lstActionName.ItemIndex <> tmpIndex then begin
 | |
|           lstActionName.ItemIndex := tmpIndex;
 | |
|           lstActionName.Click;
 | |
|         end;
 | |
|       end;
 | |
|     finally
 | |
|       ASelections.Free;
 | |
|     end;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TActionListEditor.GetSelectedAction: TContainedAction;
 | |
| begin
 | |
|   if (lstActionName.ItemIndex >= 0)
 | |
|   and (FActionList<>nil) then
 | |
|     Result := FActionList.ActionByName(lstActionName.Items[lstActionName.ItemIndex])
 | |
|   else
 | |
|     Result := nil;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.Notification(AComponent: TComponent;
 | |
|   Operation: TOperation);
 | |
| begin
 | |
|   inherited Notification(AComponent, Operation);
 | |
|   if Operation=opRemove then begin
 | |
|     if AComponent=FActionList then begin
 | |
|       FActionList:=nil;
 | |
|       FillCategories;
 | |
|       FillActionByCategory(-1);
 | |
|       Close;
 | |
|     end;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ResultStdActProc(const Category: string;
 | |
|   ActionClass: TBasicActionClass; ActionProperty: TActStdPropItem;
 | |
|   LastItem: Boolean);
 | |
| var
 | |
|   NewAction: TContainedAction;
 | |
| begin
 | |
|   if FActionList=nil then exit;
 | |
|   NewAction := ActionClass.Create(FActionList.Owner) as TContainedAction;
 | |
| //  NewAction := CreateAction(FActionList.Owner, ActionClass) as TContainedAction;
 | |
|   if Category <> cActionListEditorUnknownCategory
 | |
|   then NewAction.Category := Category
 | |
|   else NewAction.Category := '';
 | |
|   NewAction.Name := FDesigner.CreateUniqueComponentName(NewAction.ClassName);
 | |
|   
 | |
|   if Assigned(ActionProperty) then begin
 | |
|     TCustomAction(NewAction).Caption := ActionProperty.ActionProperty.Caption;
 | |
|     TCustomAction(NewAction).ShortCut := ActionProperty.ActionProperty.ShortCut;
 | |
|     TCustomAction(NewAction).Hint := ActionProperty.ActionProperty.Hint;
 | |
|   end;
 | |
| 
 | |
|   NewAction.ActionList := FActionList;
 | |
|   FDesigner.PropertyEditorHook.PersistentAdded(NewAction,True);
 | |
| 
 | |
|   FDesigner.Modified;
 | |
|   if LastItem
 | |
|   then FDesigner.SelectOnlyThisComponent(FActionList.ActionByName(NewAction.Name));
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.SplitterCanResize(Sender: TObject;
 | |
|   var NewSize: Integer; var Accept: Boolean);
 | |
| begin
 | |
|   lblName.Left := lstActionName.Left + 3;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.lstActionNameKeyDown(Sender: TObject;
 | |
|   var Key: Word; Shift: TShiftState);
 | |
| begin
 | |
|   if (ssCtrl in Shift) then begin
 | |
|      case key of
 | |
|        VK_UP: if ActMoveUp.Enabled then begin
 | |
|            ActMoveUp.OnExecute(ActMoveUp);
 | |
|            Key := 0;
 | |
|          end;
 | |
|          
 | |
|        VK_DOWN: if ActMoveDown.Enabled then begin
 | |
|            ActMoveDown.OnExecute(ActMoveDown);
 | |
|            Key := 0;
 | |
|          end;
 | |
|       end;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.lstActionNameMouseDown(Sender: TOBject;
 | |
|   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
 | |
| var
 | |
|   oldIndex, index: Integer;
 | |
| begin
 | |
|   if Button = mbRight then begin
 | |
|     oldIndex := TListBox(Sender).ItemIndex;
 | |
|     index := TListBox(Sender).GetIndexAtY(Y);
 | |
|     if (index >= 0) and (oldIndex <> index) then begin
 | |
|       TListBox(Sender).ItemIndex := index;
 | |
|       TListBox(Sender).Click;
 | |
|     end;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActDeleteUpdate(Sender: TObject);
 | |
| begin
 | |
|   TAction(Sender).Enabled := lstActionName.SelCount > 0;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActMoveDownExecute(Sender: TObject);
 | |
| var
 | |
|   fact0,fAct1: TContainedAction;
 | |
|   lboxIndex: Integer;
 | |
|   direction: Integer;
 | |
| begin
 | |
|   if FActionList=nil then exit;
 | |
|   if TComponent(Sender).Name = 'ActMoveUp'
 | |
|   then direction := -1
 | |
|   else direction := 1;
 | |
| 
 | |
|   lboxIndex := lstActionName.ItemIndex;
 | |
|   
 | |
|   fact0 := FActionList.ActionByName(lstActionName.Items[lboxIndex]);
 | |
|   fact1 := FActionList.ActionByName(lstActionName.Items[lboxIndex+direction]);
 | |
|   fact1.Index := fact0.Index;
 | |
| 
 | |
|   lstActionName.Items.Move(lboxIndex, lboxIndex+direction);
 | |
|   lstActionName.ItemIndex := lboxIndex+direction;
 | |
|   FDesigner.Modified;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActMoveDownUpdate(Sender: TObject);
 | |
| begin
 | |
|   TAction(Sender).Enabled := (lstActionName.Items.Count > 1)
 | |
|                          and (lstActionName.ItemIndex >= 0)
 | |
|                          and (lstActionName.ItemIndex < lstActionName.Items.Count-1);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActMoveUpUpdate(Sender: TObject);
 | |
| begin
 | |
|   TAction(Sender).Enabled := (lstActionName.Items.Count > 1)
 | |
|                          and (lstActionName.ItemIndex > 0);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActNewExecute(Sender: TObject);
 | |
| var
 | |
|   NewAction: TContainedAction;
 | |
| begin
 | |
|   if FActionList=nil then exit;
 | |
|   NewAction := TAction.Create(FActionList.Owner);
 | |
|   NewAction.Name := FDesigner.CreateUniqueComponentName(NewAction.ClassName);
 | |
| 
 | |
|   if lstCategory.ItemIndex > 1 // ignore first two items (virtual categories)
 | |
|   then NewAction.Category := lstCategory.Items[lstCategory.ItemIndex]
 | |
|   else NewAction.Category := '';
 | |
| 
 | |
|   NewAction.ActionList := FActionList;
 | |
| 
 | |
|   FDesigner.PropertyEditorHook.PersistentAdded(NewAction,True);
 | |
|   FDesigner.Modified;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActNewStdExecute(Sender: TObject);
 | |
| var
 | |
|   Form: TForm;
 | |
| begin
 | |
|   CreateDlgStdActions(Self, @ResultStdActProc, Form);
 | |
|   Form.ShowModal;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActPanelDescrExecute(Sender: TObject);
 | |
| begin
 | |
|   PanelDescr.Visible := TAction(Sender).Checked;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActPanelToolBarExecute(Sender: TObject);
 | |
| begin
 | |
|   ToolBar1.Visible := TAction(Sender).Checked;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActionListEditorClose(Sender: TObject;
 | |
|   var CloseAction: TCloseAction);
 | |
| begin
 | |
|   CloseAction := caFree;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActionListEditorKeyDown(Sender: TObject;
 | |
|   var Key: Word; Shift: TShiftState);
 | |
| var
 | |
|   MousePoint: TPoint;
 | |
| begin
 | |
|   MousePoint := Self.ClientToScreen(Point(0,0));
 | |
|   if Key = VK_APPS
 | |
|   then PopMenuActions.PopUp(MousePoint.X, MousePoint.Y);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActionListEditorKeyPress(Sender: TObject;
 | |
|   var Key: char);
 | |
| begin
 | |
|   if Ord(Key) = VK_ESCAPE then Self.Close;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.FormCreate(Sender: TObject);
 | |
| begin
 | |
|   //imageindex 0 exists
 | |
|   ImageList1.AddResourceName(HInstance, 'laz_add'); //imageindex 1
 | |
|   ImageList1.AddResourceName(HInstance, 'laz_delete'); //imageindex 2
 | |
|   ImageList1.AddResourceName(HInstance, 'arrow_up'); //imadeindex 3
 | |
|   ImageList1.AddResourceName(HInstance, 'arrow_down'); //imageindex 4
 | |
|   btnAddMore.ImageIndex := 0;
 | |
|   // These must be set in code because OI does not work with non-existent values.
 | |
|   btnAdd.ImageIndex := 1;
 | |
|   btnDelete.ImageIndex := 2;
 | |
|   btnUp.ImageIndex := 3;
 | |
|   btnDown.ImageIndex := 4;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.lstActionNameDrawItem(Control: TWinControl;
 | |
|   Index: Integer; ARect: TRect; State: TOwnerDrawState);
 | |
| var
 | |
|   ACanvas: TCanvas;
 | |
|   R: TRect;
 | |
|   dh, dth: Integer;
 | |
|   AAction: TCustomAction;
 | |
|   S: String;
 | |
| begin
 | |
|   if FActionList=nil then exit;;
 | |
|   ACanvas := TListBox(Control).Canvas;
 | |
|   if odSelected in State then
 | |
|   begin
 | |
|     ACanvas.Brush.Color := clHighlight;
 | |
|     ACanvas.Font.Color := clHighlightText;
 | |
|   end
 | |
|   else begin
 | |
|     ACanvas.Brush.Color := clWindow;
 | |
|     ACanvas.Font.Color := clWindowText;
 | |
|   end;
 | |
|   S := TListBox(Control).Items[Index];
 | |
|   R := ARect;
 | |
|   dh := R.Bottom - R.Top;
 | |
|   ACanvas.FillRect(R);
 | |
|   inc(R.Left, 2);
 | |
|   if (TListBox(Control).Items.Objects[Index] is TCustomAction)
 | |
|   and (FActionList.Images <> nil) then begin
 | |
|     AAction := TListBox(Control).Items.Objects[Index] as TCustomAction;
 | |
|     R.Right := R.Left + dh;
 | |
|     if AAction.ImageIndex <> -1 then
 | |
|     begin
 | |
|       dth := FActionList.Images.Height;
 | |
|       if dth > dh then
 | |
|         FActionList.Images.StretchDraw(ACanvas, AAction.ImageIndex, Rect(R.Left, R.Top + 1, R.Left + dh - 2, R.Bottom - 1))
 | |
|       else
 | |
|         FActionList.Images.Draw(ACanvas, R.Left, R.Top + (dh -dth) div 2, AAction.ImageIndex);
 | |
|     end;
 | |
|     Inc(R.Left, dh + 2);
 | |
|   end;
 | |
|   dth := Canvas.TextHeight(S);
 | |
|   ACanvas.TextOut(R.Left, R.Top + (dh - dth) div 2, S);
 | |
|   if odFocused in State then
 | |
|     ACanvas.DrawFocusRect(ARect);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.OnComponentDelete(APersistent: TPersistent);
 | |
| var
 | |
|   i: Integer;
 | |
| begin
 | |
|   if not (APersistent is TContainedAction) then Exit;
 | |
|   i := lstActionName.Items.IndexOfObject(APersistent);
 | |
|   if i >= 0 then
 | |
|     lstActionName.Items.Delete(i);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.ActDeleteExecute(Sender: TObject);
 | |
|   function IsCategory(Category: String): Boolean;
 | |
|   var
 | |
|     i: Integer;
 | |
|   begin
 | |
|     Result := False;
 | |
|     for i:= FActionList.ActionCount-1 downto 0 do begin
 | |
|       if FActionList.Actions[i].Category = Category then begin
 | |
|         Result := True;
 | |
|         Break;
 | |
|       end;
 | |
|     end;
 | |
|   end;
 | |
| var
 | |
|   iNameIndex: Integer;
 | |
|   OldName: String;
 | |
|   OldAction: TContainedAction;
 | |
|   OldIndex: LongInt;
 | |
| begin
 | |
|   if FActionList=nil then exit;
 | |
|   iNameIndex := lstActionName.ItemIndex;
 | |
|   if iNameIndex < 0 then Exit;
 | |
|   OldName := lstActionName.Items[iNameIndex];
 | |
|   lstActionName.Items.Delete(iNameIndex);
 | |
| 
 | |
|   OldAction := FActionList.ActionByName(OldName);
 | |
|   OldName := OldAction.Category;
 | |
| 
 | |
|   // be gone
 | |
|   if Assigned(OldAction) then
 | |
|   begin
 | |
|     try
 | |
|       FDesigner.PropertyEditorHook.DeletePersistent(TPersistent(OldAction));
 | |
|       OldAction:=nil;
 | |
|     except
 | |
|       on E: Exception do begin
 | |
|         MessageDlg(oisErrorDeletingAction,
 | |
|           Format(oisErrorWhileDeletingAction, [LineEnding, E.Message]), mtError,
 | |
|           [mbOk], 0);
 | |
|       end;
 | |
|     end;
 | |
|   end;
 | |
| 
 | |
|   if lstActionName.Items.Count = 0 then // last act in category > rebuild
 | |
|     FillCategories
 | |
|   else
 | |
|   begin
 | |
|     if iNameIndex >= lstActionName.Items.Count
 | |
|     then lstActionName.ItemIndex := lstActionName.Items.Count -1
 | |
|     else lstActionName.ItemIndex := iNameIndex;
 | |
| 
 | |
|     FDesigner.SelectOnlyThisComponent(
 | |
|        FActionList.ActionByName(lstActionName.Items[lstActionName.ItemIndex]));
 | |
|   end;
 | |
| 
 | |
|   If not IsCategory(OldName) then begin
 | |
|     OldIndex:=lstCategory.Items.IndexOf(OldName);
 | |
|     if OldIndex>=0 then
 | |
|       lstCategory.Items.Delete(OldIndex);
 | |
|   end;
 | |
|   if lstActionName.ItemIndex < 0
 | |
|   then FDesigner.SelectOnlyThisComponent(FActionList);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.lstCategoryClick(Sender: TObject);
 | |
| begin
 | |
|   if lstCategory.ItemIndex >= 0
 | |
|   then FillActionByCategory(lstCategory.ItemIndex);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.lstActionNameClick(Sender: TObject);
 | |
| var
 | |
|   CurAction: TContainedAction;
 | |
| begin
 | |
|   // TODO: multiselect
 | |
|   if lstActionName.ItemIndex < 0 then Exit;
 | |
|   CurAction := GetSelectedAction;
 | |
|   if CurAction = nil then Exit;
 | |
| 
 | |
|   FDesigner.SelectOnlyThisComponent(CurAction);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.lstActionNameDblClick(Sender: TObject);
 | |
| var
 | |
|   CurAction: TContainedAction;
 | |
| begin
 | |
|   if lstActionName.GetIndexAtY(lstActionName.ScreenToClient(Mouse.CursorPos).Y) < 0
 | |
|   then Exit;
 | |
|   CurAction := GetSelectedAction;
 | |
|   if CurAction = nil then Exit;
 | |
|   // Add OnExecute for this action
 | |
|   CreateComponentEvent(CurAction,'OnExecute');
 | |
| end;
 | |
| 
 | |
| constructor TActionListEditor.Create(AOwner: TComponent);
 | |
| begin
 | |
|   inherited Create(AOwner);
 | |
|   Caption := oisActionListEditor;
 | |
|   lblCategory.Caption := oisCategory;
 | |
|   lblName.Caption := oisAction;
 | |
|   Splitter.MinSize := lblCategory.Left + lblCategory.Width;
 | |
|   ActNew.Hint := cActionListEditorNewAction;
 | |
|   ActNewStd.Hint := cActionListEditorNewStdAction;
 | |
|   ActDelete.Hint := cActionListEditorDeleteActionHint;
 | |
|   ActMoveUp.Hint := cActionListEditorMoveUpAction;
 | |
|   ActMoveDown.Hint := cActionListEditorMoveDownAction;
 | |
|   ActPanelDescr.Caption := cActionListEditorPanelDescrriptions;
 | |
|   ActPanelToolBar.Caption := cActionListEditorPanelToolBar;
 | |
|   btnAddMore.Hint := cActionListEditorNewAction;
 | |
|   mItemToolBarNewAction.Caption := cActionListEditorNewAction;
 | |
|   mItemToolBarNewStdAction.Caption := cActionListEditorNewStdAction;
 | |
|   mItemActListNewAction.Caption := cActionListEditorNewAction;
 | |
|   mItemActListNewStdAction.Caption := cActionListEditorNewStdAction;
 | |
|   mItemActListMoveDownAction.Caption := cActionListEditorMoveDownAction;
 | |
|   mItemActListMoveUpAction.Caption := cActionListEditorMoveUpAction;
 | |
|   mItemActListDelAction.Caption := cActionListEditorDeleteAction;
 | |
| 
 | |
|   if Assigned(GlobalDesignHook) then
 | |
|   begin
 | |
|     GlobalDesignHook.AddHandlerComponentRenamed(@OnComponentRenamed);
 | |
|     GlobalDesignHook.AddHandlerSetSelection(@OnComponentSelection);
 | |
|     GlobalDesignHook.AddHandlerRefreshPropertyValues(@OnRefreshPropertyValues);
 | |
|     GlobalDesignHook.AddHandlerPersistentDeleting(@OnComponentDelete);
 | |
|   end;
 | |
| 
 | |
|   AddActionEditor(Self);
 | |
| end;
 | |
| 
 | |
| destructor TActionListEditor.Destroy;
 | |
| begin
 | |
|   if Assigned(GlobalDesignHook) then
 | |
|     GlobalDesignHook.RemoveAllHandlersForObject(Self);
 | |
| 
 | |
|   ReleaseActionEditor(Self);
 | |
|   
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.SetActionList(AActionList: TActionList);
 | |
| begin
 | |
|   if FActionList = AActionList then exit;
 | |
|   if FActionList<>nil then RemoveFreeNotification(FActionList);
 | |
|   FActionList := AActionList;
 | |
|   if FActionList<>nil then FreeNotification(FActionList);
 | |
|   FillCategories;
 | |
|   FillActionByCategory(-1);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.FillCategories;
 | |
| var
 | |
|   i: Integer;
 | |
|   sCategory: String;
 | |
|   xIndex: Integer;
 | |
|   sOldCategory: String;
 | |
|   countCategory: Integer;
 | |
| begin
 | |
|   // try remember old category
 | |
|   sOldCategory := '';
 | |
|   if (lstCategory.Items.Count>0) and (lstCategory.ItemIndex>-1)
 | |
|   then sOldCategory := lstCategory.Items[lstCategory.ItemIndex];
 | |
| 
 | |
|   lstCategory.Items.BeginUpdate;
 | |
|   try
 | |
|     countCategory := lstCategory.Items.Count;
 | |
|     lstCategory.Clear;
 | |
| 
 | |
|     if FActionList<>nil then
 | |
|       for i := 0 to FActionList.ActionCount-1 do begin
 | |
|         sCategory := FActionList.Actions[i].Category;
 | |
|         if sCategory = ''
 | |
|         then Continue;
 | |
|         xIndex := lstCategory.Items.IndexOf(sCategory);
 | |
|         if xIndex < 0
 | |
|         then lstCategory.Items.Add(sCategory);
 | |
|       end;
 | |
|     if lstCategory.Items.Count > 0
 | |
|     then lstCategory.Sorted := True;
 | |
|     lstCategory.Sorted := False;
 | |
|     
 | |
|     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
 | |
|       begin
 | |
|         lstCategory.Items.Insert(1, cActionListEditorUnknownCategory);
 | |
|         if xIndex > 0 then Inc(xIndex);
 | |
|       end
 | |
|     else lstCategory.Items.Add(cActionListEditorUnknownCategory);
 | |
|   finally
 | |
|     lstCategory.Items.EndUpdate;
 | |
|   end;
 | |
|   if xIndex < 0 then begin
 | |
|     if Assigned(GetSelectedAction)
 | |
|        and (GetSelectedAction.Category = '')
 | |
|     then xIndex := lstCategory.Items.IndexOf(cActionListEditorUnknownCategory)
 | |
|     else xIndex := 0;
 | |
|   end;
 | |
|   lstCategory.ItemIndex := xIndex;
 | |
| 
 | |
|   if ( ((lstCategory.ItemIndex <> lstCategory.items.IndexOf(cActionListEditorAllCategory))
 | |
|          or (lstActionName.Items.Count = 0))
 | |
|       or (countCategory <> lstCategory.Items.Count) )
 | |
|   then FillActionByCategory(xIndex);
 | |
| end;
 | |
| 
 | |
| procedure TActionListEditor.FillActionByCategory(iIndex:Integer);
 | |
| var
 | |
|   i: Integer;
 | |
|   sCategory: String;
 | |
|   IndexedActionName: String;
 | |
| begin
 | |
|   if FActionList=nil then
 | |
|   begin
 | |
|     lstActionName.Items.Clear;
 | |
|     exit;
 | |
|   end;
 | |
|   lstActionName.Items.BeginUpdate;
 | |
|   try
 | |
|     if iIndex < 0 then iIndex := 0;  // the first possition
 | |
|     if lstActionName.ItemIndex > -1
 | |
|     then IndexedActionName := lstActionName.Items[lstActionName.ItemIndex];
 | |
| 
 | |
|     lstActionName.Clear;
 | |
|     // handle all
 | |
|     if (iIndex = lstCategory.Items.IndexOf(cActionListEditorAllCategory)) then begin
 | |
|       for i := 0 to FActionList.ActionCount-1 do
 | |
|         lstActionName.Items.AddObject(FActionList.Actions[i].Name, FActionList.Actions[i]);
 | |
|       Exit;
 | |
|     end;
 | |
| 
 | |
|     // handle unknown
 | |
|     if iIndex = lstCategory.Items.IndexOf(cActionListEditorUnknownCategory) then begin
 | |
|       for i := 0 to FActionList.ActionCount-1 do begin
 | |
|         if Trim(FActionList.Actions[i].Category) = '' then
 | |
|           lstActionName.Items.AddObject(FActionList.Actions[i].Name, FActionList.Actions[i]);
 | |
|       end;
 | |
|       Exit; //throught finally
 | |
|     end;
 | |
| 
 | |
|     // else sort to categories
 | |
|     sCategory := 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
 | |
|     lstActionName.Items.EndUpdate;
 | |
|     if (IndexedActionName <> '')
 | |
|        and (lstActionName.Items.IndexOf(IndexedActionName) > -1)
 | |
|     then lstActionName.ItemIndex := lstActionName.Items.IndexOf(IndexedActionName)
 | |
|     else if lstActionName.ItemIndex = -1
 | |
|     then FDesigner.SelectOnlyThisComponent(FActionList);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| 
 | |
| { TActionListComponentEditor }
 | |
| 
 | |
| constructor TActionListComponentEditor.Create(AComponent: TComponent;
 | |
|   ADesigner: TComponentEditorDesigner);
 | |
| begin
 | |
|   inherited Create(AComponent, ADesigner);
 | |
|   FDesigner := ADesigner;
 | |
| end;
 | |
| 
 | |
| destructor TActionListComponentEditor.Destroy;
 | |
| begin
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| procedure TActionListComponentEditor.Edit;
 | |
| var
 | |
|   AActionList: TActionList;
 | |
|   AEditor: TActionListEditor;
 | |
| begin
 | |
|   AActionList := GetComponent as TActionList;
 | |
|   if AActionList = nil
 | |
|   then raise Exception.Create('TActionListComponentEditor.Edit AActionList=nil');
 | |
|   AEditor:=FindActionEditor(AActionList);
 | |
|   if not Assigned(AEditor) then begin
 | |
|     AEditor:=TActionListEditor.Create(Application);
 | |
|     with AEditor do begin
 | |
|       lstActionName.ItemIndex := -1;
 | |
|       Designer := Self.FDesigner;
 | |
|       SetActionList(AActionList);
 | |
|     end;
 | |
|   end;
 | |
|   SetPopupModeParentForPropertyEditor(AEditor);
 | |
|   AEditor.ShowOnTop;
 | |
| end;
 | |
| 
 | |
| function TActionListComponentEditor.GetVerbCount: Integer;
 | |
| begin
 | |
|   Result := 1;
 | |
| end;
 | |
| 
 | |
| function TActionListComponentEditor.GetVerb(Index: Integer): string;
 | |
| begin
 | |
|   Result := oisActionListComponentEditor;
 | |
| end;
 | |
| 
 | |
| procedure TActionListComponentEditor.ExecuteVerb(Index: Integer);
 | |
| begin
 | |
|   Edit;
 | |
| end;
 | |
| 
 | |
| 
 | |
| { TRegisteredAction }
 | |
| 
 | |
| constructor TRegisteredAction.Create(TheActionClass: TBasicActionClass;
 | |
|   TheGroupID: integer);
 | |
| begin
 | |
|   FActionClass := TheActionClass;
 | |
|   FGroupId := TheGroupID;
 | |
| end;
 | |
| 
 | |
| 
 | |
| { TRegisteredActionCategory }
 | |
| 
 | |
| function TRegisteredActionCategory.GetItems(Index: integer): TRegisteredAction;
 | |
| begin
 | |
|   Result := FItems[Index];
 | |
| end;
 | |
| 
 | |
| constructor TRegisteredActionCategory.Create(const CategoryName: string;
 | |
|   AResource: TComponentClass);
 | |
| begin
 | |
|   FName := CategoryName;
 | |
|   FResource := AResource;
 | |
| end;
 | |
| 
 | |
| procedure TRegisteredActionCategory.Add(
 | |
|   const AClasses: array of TBasicActionClass);
 | |
| var
 | |
|   i: integer;
 | |
|   CurCount: Integer;
 | |
|   IsDouble: Boolean;
 | |
|   j: Integer;
 | |
|   AClass: TBasicActionClass;
 | |
|   l: Integer;
 | |
| begin
 | |
|   l := High(AClasses)-Low(AClasses)+1;
 | |
|   if l = 0 then exit;
 | |
|   CurCount := FCount;
 | |
|   Inc(FCount,l);
 | |
|   // add all classes (ignoring doubles)
 | |
|   ReAllocMem(FItems,SizeOf(TBasicActionClass)*FCount);
 | |
|   for i:=Low(AClasses) to High(AClasses) do begin
 | |
|     AClass:=AClasses[i];
 | |
|     // check if already exists
 | |
|     IsDouble:=false;
 | |
|     for j:=0 to CurCount-1 do begin
 | |
|       if FItems[j].ActionClass = AClass then begin
 | |
|         IsDouble := True;
 | |
|         Break;
 | |
|       end;
 | |
|     end;
 | |
|     // add
 | |
|     if not IsDouble then begin
 | |
|       // TODO use current designer group instead of -1
 | |
|       FItems[CurCount] := TRegisteredAction.Create(AClass,-1);
 | |
|       Inc(CurCount);
 | |
|       RegisterNoIcon([AClass]);
 | |
|       Classes.RegisterClass(AClass);
 | |
|     end;
 | |
|   end;
 | |
|   // resize FItems
 | |
|   if CurCount < FCount then begin
 | |
|     FCount := CurCount;
 | |
|     ReAllocMem(FItems,SizeOf(TBasicActionClass)*FCount);
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| destructor TRegisteredActionCategory.Destroy;
 | |
| var
 | |
|   i: Integer;
 | |
| begin
 | |
|   for i:= Count-1 downto 0 do Items[i].Free;
 | |
|   ReAllocMem(FItems,0);
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| function TRegisteredActionCategory.IndexOfClass(AClass: TBasicActionClass
 | |
|   ): integer;
 | |
| begin
 | |
|   Result:=Count-1;
 | |
|   while (Result>=0) and (FItems[Result].ActionClass<>AClass) do Dec(Result);
 | |
| end;
 | |
| 
 | |
| procedure TRegisteredActionCategory.EnumActions(Proc: TEnumActionProc;
 | |
|   Info: Pointer);
 | |
| var
 | |
|   i: Integer;
 | |
| begin
 | |
|   for i := 0 to Count-1 do
 | |
|     Proc(Name,FItems[i].ActionClass,Info);
 | |
| end;
 | |
| 
 | |
| 
 | |
| { TRegisteredActionCategories }
 | |
| 
 | |
| function TRegisteredActionCategories.GetItems(Index: integer
 | |
|   ): TRegisteredActionCategory;
 | |
| begin
 | |
|   Result:=TRegisteredActionCategory(FItems[Index]);
 | |
| end;
 | |
| 
 | |
| procedure TRegisteredActionCategories.Add(const CategoryName: string;
 | |
|   const AClasses: array of TBasicActionClass; AResource: TComponentClass);
 | |
| var
 | |
|   i: LongInt;
 | |
|   Category: TRegisteredActionCategory;
 | |
| begin
 | |
|   i := IndexOfCategory(CategoryName);
 | |
|   if i >= 0 then begin
 | |
|     Category := Items[i];
 | |
|     if Category.Resource<>AResource then
 | |
|       raise Exception.Create('TRegisteredActionCategories.Add Resource<>OldResource');
 | |
|   end else begin
 | |
|     Category := TRegisteredActionCategory.Create(CategoryName,AResource);
 | |
|     if FItems = nil then FItems := TList.Create;
 | |
|     FItems.Add(Category);
 | |
|   end;
 | |
|   Category.Add(AClasses);
 | |
|   if Assigned(NotifyActionListChange) then
 | |
|     NotifyActionListChange;
 | |
| end;
 | |
| 
 | |
| destructor TRegisteredActionCategories.Destroy;
 | |
| var
 | |
|   i: Integer;
 | |
| begin
 | |
|   for i:= Count-1 downto 0 do Items[i].Free;
 | |
|   FItems.Free;
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| function TRegisteredActionCategories.IndexOfCategory(const CategoryName: string
 | |
|   ): integer;
 | |
| begin
 | |
|   Result := Count-1;
 | |
|   while (Result>=0) and (CompareText(Items[Result].Name,CategoryName)<>0) do
 | |
|     Dec(Result);
 | |
| end;
 | |
| 
 | |
| procedure TRegisteredActionCategories.EnumActions(Proc: TEnumActionProc;
 | |
|   Info: Pointer);
 | |
| var
 | |
|   i: Integer;
 | |
| begin
 | |
|   for i:=0 to Count-1 do
 | |
|     Items[i].EnumActions(Proc,Info);
 | |
| end;
 | |
| 
 | |
| function TRegisteredActionCategories.FindResource(AClass: TBasicActionClass
 | |
|   ): TComponentClass;
 | |
| var
 | |
|   Category: TRegisteredActionCategory;
 | |
|   i: Integer;
 | |
| begin
 | |
|   Result := nil;
 | |
|   for i := 0 to Count-1 do begin
 | |
|     Category := Items[i];
 | |
|     if Category.IndexOfClass(AClass) >= 0 then begin
 | |
|       Result := Category.Resource;
 | |
|       Break;
 | |
|     end;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| function TRegisteredActionCategories.Count: integer;
 | |
| begin
 | |
|   if FItems = nil
 | |
|   then Result := 0
 | |
|   else Result := FItems.Count;
 | |
| end;
 | |
| 
 | |
| { TActStdProp }
 | |
| 
 | |
| procedure TActStdProp.Add(ActClassType: TClass; HeadLine, ShortCut, Hint: String);
 | |
| var
 | |
|   ActItem: TActStdPropItem;
 | |
|   ActionProperty: TRecActStdProp;
 | |
| begin
 | |
|   if Assigned(IndexOfClass(ActClassType.ClassName)) then Exit;
 | |
|   ActItem := TActStdPropItem.Create;
 | |
|   ActItem.ActClassName := ActClassType.ClassName;
 | |
|   ActionProperty.Caption := HeadLine;
 | |
|   ActionProperty.ShortCut := TextToShortCut(ShortCut);
 | |
|   ActionProperty.Hint := Hint;
 | |
|   ActItem.ActionProperty := ActionProperty;
 | |
|   fPropList.Add(ActItem);
 | |
| end;
 | |
| 
 | |
| constructor TActStdProp.Create;
 | |
| begin
 | |
|   fPropList := TObjectList.Create;
 | |
| end;
 | |
| 
 | |
| destructor TActStdProp.Destroy;
 | |
| begin
 | |
|   fPropList.Free;
 | |
|   inherited Destroy;
 | |
| end;
 | |
| 
 | |
| function TActStdProp.IndexOfClass(ActClassName: String): TActStdPropItem;
 | |
| var
 | |
|   i: Integer;
 | |
| begin
 | |
|   Result := nil;
 | |
|   for i:= 0 to fPropList.Count-1 do begin
 | |
|     if TActStdPropItem(fPropList[i]).ActClassName = ActClassName then begin
 | |
|       Result := TActStdPropItem(fPropList[i]);
 | |
|       Break;
 | |
|     end;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| { TActStdPropItem }
 | |
| 
 | |
| procedure TActStdPropItem.SetActClassName(const AValue: String);
 | |
| begin
 | |
|   if FClassName = AValue then Exit;
 | |
|   FClassName := AValue;
 | |
| end;
 | |
| 
 | |
| procedure TActStdPropItem.SetActProperties(const AValue: TRecActStdProp);
 | |
| begin
 | |
|   FActProperties := AValue;
 | |
| end;
 | |
| 
 | |
| procedure RegisterStandardActions;
 | |
| begin
 | |
|   // TODO
 | |
|   //  - default images for actions
 | |
| 
 | |
|   RegisterActions(cActionListEditorUnknownCategory, [TAction], nil);
 | |
|   // register edit actions
 | |
|   RegisterActions(cActionListEditorEditCategory, [TEditCut, TEditCopy, TEditPaste, TEditSelectAll,
 | |
|    TEditUndo, TEditDelete], nil);
 | |
|   // register search/replace actions
 | |
|   RegisterActions(cActionListEditorSearchCategory, [TSearchFind, TSearchReplace, TSearchFindFirst, 
 | |
|    TSearchFindNext], nil);
 | |
|   // register help actions
 | |
|   RegisterActions(cActionListEditorHelpCategory, [THelpAction, THelpContents, THelpTopicSearch,
 | |
|     THelpOnHelp, THelpContextAction], nil);
 | |
|   // register dialog actions
 | |
|   RegisterActions(cActionListEditorDialogCategory, [TColorSelect, TFontEdit], nil);
 | |
|   // register file actions
 | |
|   RegisterActions(cActionListEditorFileCategory, [TFileOpen, TFileOpenWith, TFileSaveAs, TFileExit], nil);
 | |
|   // register database actions
 | |
|   RegisterActions(cActionListEditorDatabaseCategory, [TDataSetFirst, TDataSetLast, TDataSetNext,
 | |
|     TDataSetPrior, TDataSetRefresh, TDataSetCancel, TDataSetDelete, TDataSetEdit,
 | |
|     TDataSetInsert, TDataSetPost], nil);
 | |
| end;
 | |
| 
 | |
| { TActionCategoryProperty }
 | |
| 
 | |
| function TActionCategoryProperty.GetAttributes: TPropertyAttributes;
 | |
| begin
 | |
|   Result:=inherited GetAttributes + [paValueList, paSortList];
 | |
| end;
 | |
| 
 | |
| procedure TActionCategoryProperty.GetValues(Proc: TGetStrProc);
 | |
| var
 | |
|   I: Integer;
 | |
|   Values: TStringList;
 | |
|   Act:TContainedAction;
 | |
|   ActLst:TCustomActionList;
 | |
|   S:string;
 | |
| begin
 | |
|   ActLst:=nil;
 | |
|   Act:=GetComponent(0) as TContainedAction;
 | |
|   if Assigned(Act) then
 | |
|     ActLst:=Act.ActionList;
 | |
|   if not Assigned(ActLst) then exit;
 | |
|   Values := TStringList.Create;
 | |
|   try
 | |
|     for i:=0 to ActLst.ActionCount-1 do
 | |
|     begin
 | |
|       S:=ActLst.Actions[i].Category;
 | |
|       if Values.IndexOf(S)<0 then
 | |
|         Values.Add(S);
 | |
|     end;
 | |
|     for i := 0 to Values.Count - 1 do
 | |
|       Proc(Values[I]);
 | |
|   finally
 | |
|     Values.Free;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| initialization
 | |
|   NotifyActionListChange := nil;
 | |
| 
 | |
|   RegisteredActions := TRegisteredActionCategories.Create;
 | |
|   RegisterActionsProc := @RegisterActions;
 | |
|   UnRegisterActionsProc := @UnregisterActions;
 | |
|   EnumRegisteredActionsProc := @EnumActions;
 | |
|   CreateActionProc := @CreateAction;
 | |
|   
 | |
|   RegisterComponentEditor(TActionList,TActionListComponentEditor);
 | |
|   RegisterStandardActions;
 | |
|   RegisterPropertyEditor(TypeInfo(string), TContainedAction, 'Category', TActionCategoryProperty);
 | |
|   InitFormsList;
 | |
| 
 | |
| finalization
 | |
|   ReleaseFormsList;
 | |
|   RegisteredActions.Free;
 | |
|   RegisteredActions := nil;
 | |
| end.
 | |
| 
 | 
