
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9581 8e941d3f-bd1b-0410-a28a-d453659cc2b4
506 lines
14 KiB
ObjectPascal
506 lines
14 KiB
ObjectPascal
{
|
|
Plugin component and property editor. Adapted from TAChart.
|
|
}
|
|
unit mvPluginEditors;
|
|
|
|
{$MODE ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, Math, Classes, LazLoggerBase,
|
|
PropEdits, ComponentEditors, IDEImagesIntf,
|
|
Forms, Menus, StdCtrls, ComCtrls;
|
|
|
|
type
|
|
|
|
{ TMvSubComponentListEditor }
|
|
|
|
TMvSubComponentListEditor = class(TComponentEditor)
|
|
protected
|
|
function MakeEditorForm: TForm; virtual; abstract;
|
|
public
|
|
procedure ExecuteVerb(Index: Integer); override;
|
|
function GetVerbCount: Integer; override;
|
|
end;
|
|
|
|
{ TMvComponentListPropertyEditor }
|
|
|
|
TMvComponentListPropertyEditor = class(TPropertyEditor)
|
|
protected
|
|
function GetChildrenCount: Integer; virtual; abstract;
|
|
function MakeEditorForm: TForm; virtual; abstract;
|
|
public
|
|
procedure Edit; override;
|
|
function GetAttributes: TPropertyAttributes; override;
|
|
function GetValue: AnsiString; override;
|
|
end;
|
|
|
|
{ TMvComponentListEditorForm }
|
|
|
|
TMvComponentListEditorForm = class(TForm)
|
|
ChildrenListBox: TListBox;
|
|
menuAddItem: TPopupMenu;
|
|
tbAdd: TToolButton;
|
|
tbCommands: TToolBar;
|
|
tbDelete: TToolButton;
|
|
tbMoveDown: TToolButton;
|
|
tbMoveUp: TToolButton;
|
|
procedure ChildrenListBoxClick(Sender: TObject);
|
|
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure miAddClick(Sender: TObject);
|
|
procedure tbDeleteClick(Sender: TObject);
|
|
procedure tbMoveDownClick(Sender: TObject);
|
|
procedure tbMoveUpClick(Sender: TObject);
|
|
private
|
|
FComponentEditor: TMvSubComponentListEditor;
|
|
FDesigner: TComponentEditorDesigner;
|
|
FParent: TComponent;
|
|
FPropertyEditor: TMvComponentListPropertyEditor;
|
|
function FindChild(ACandidate: TPersistent; out AIndex: Integer): Boolean;
|
|
procedure MoveSelection(AStart, ADir: Integer);
|
|
procedure OnComponentRenamed(AComponent: TComponent);
|
|
procedure OnGetSelection(const ASelection: TPersistentSelectionList);
|
|
procedure OnPersistentAdded(APersistent: TPersistent; ASelect: Boolean);
|
|
procedure OnPersistentDeleting(APersistent: TPersistent);
|
|
procedure OnSetSelection(const ASelection: TPersistentSelectionList);
|
|
procedure RefreshList;
|
|
procedure SelectionChanged(AOrderChanged: Boolean = false);
|
|
protected
|
|
procedure AddSubcomponent(AParent, AChild: TComponent); virtual; abstract;
|
|
procedure AddSubcomponentClass(const ACaption: String; ATag: Integer);
|
|
procedure BuildCaption; virtual; abstract;
|
|
function ChildClass: TComponentClass; virtual; abstract;
|
|
procedure EnumerateSubcomponentClasses; virtual; abstract;
|
|
function GetChildrenList: TFPList; virtual; abstract;
|
|
function MakeSubcomponent(
|
|
AOwner: TComponent; ATag: Integer): TComponent; virtual; abstract;
|
|
property Parent: TComponent read FParent;
|
|
public
|
|
constructor Create(
|
|
AOwner, AParent: TComponent; AComponentEditor: TMvSubComponentListEditor;
|
|
APropertyEditor: TMvComponentListPropertyEditor); reintroduce;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
type
|
|
{ TMvPluginManagerComponentEditor }
|
|
|
|
TMvPluginManagerComponentEditor = class(TMvSubComponentListEditor)
|
|
protected
|
|
function MakeEditorForm: TForm; override;
|
|
public
|
|
function GetVerb(Index: Integer): string; override;
|
|
end;
|
|
|
|
{ TMvPluginListPropertyEditor }
|
|
|
|
TMvPluginListPropertyEditor = class(TMvComponentListPropertyEditor)
|
|
protected
|
|
function GetChildrenCount: Integer; override;
|
|
function MakeEditorForm: TForm; override;
|
|
end;
|
|
|
|
{ TMvPluginManagerEditorForm }
|
|
|
|
TMvPluginManagerEditorForm = class(TMvComponentListEditorForm)
|
|
protected
|
|
procedure AddSubcomponent(AParent, AChild: TComponent); override;
|
|
procedure BuildCaption; override;
|
|
function ChildClass: TComponentClass; override;
|
|
procedure EnumerateSubcomponentClasses; override;
|
|
function GetChildrenList: TFPList; override;
|
|
function MakeSubcomponent(
|
|
AOwner: TComponent; ATag: Integer): TComponent; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses
|
|
mvPluginCommon;
|
|
|
|
{ TMvComponentListPropertyEditor }
|
|
|
|
procedure TMvComponentListPropertyEditor.Edit;
|
|
var
|
|
propValue: TPersistent;
|
|
editorForm: TForm;
|
|
begin
|
|
propValue := GetComponent(0);
|
|
if propValue = nil then
|
|
raise Exception.Create('TComponentListPropertyEditor.Component=nil');
|
|
editorForm := FindEditorForm(propValue) as TForm;
|
|
if editorForm = nil then begin
|
|
editorForm := MakeEditorForm;
|
|
RegisterEditorForm(editorForm, propValue);
|
|
end;
|
|
editorForm.EnsureVisible;
|
|
end;
|
|
|
|
function TMvComponentListPropertyEditor.GetAttributes: TPropertyAttributes;
|
|
begin
|
|
Result := [paDialog, paReadOnly];
|
|
end;
|
|
|
|
function TMvComponentListPropertyEditor.GetValue: AnsiString;
|
|
var
|
|
c: Integer;
|
|
begin
|
|
c := GetChildrenCount;
|
|
if c = 1 then
|
|
Result := '1 item'
|
|
else
|
|
Result := IntToStr(c) + ' items';
|
|
end;
|
|
|
|
|
|
{ TMvSubComponentListEditor }
|
|
|
|
procedure TMvSubComponentListEditor.ExecuteVerb(Index: Integer);
|
|
var
|
|
propValue: TPersistent;
|
|
editorForm: TForm;
|
|
begin
|
|
if Index <> 0 then exit;
|
|
propValue := GetComponent;
|
|
if propValue = nil then
|
|
raise Exception.Create('TSubComponentListEditor.Component=nil');
|
|
editorForm := FindEditorForm(propValue) as TForm;
|
|
if editorForm = nil then begin
|
|
editorForm := MakeEditorForm;
|
|
RegisterEditorForm(editorForm, propValue);
|
|
end;
|
|
editorForm.ShowOnTop;
|
|
end;
|
|
|
|
function TMvSubComponentListEditor.GetVerbCount: Integer;
|
|
begin
|
|
Result := 1;
|
|
end;
|
|
|
|
|
|
{ TMvComponentListEditorForm }
|
|
|
|
constructor TMvComponentListEditorForm.Create(
|
|
AOwner, AParent: TComponent; AComponentEditor: TMvSubComponentListEditor;
|
|
APropertyEditor: TMvComponentListPropertyEditor);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FParent := AParent;
|
|
FComponentEditor := AComponentEditor;
|
|
FPropertyEditor := APropertyEditor;
|
|
if FComponentEditor <> nil then
|
|
FDesigner := FComponentEditor.Designer
|
|
else
|
|
FDesigner := FindRootDesigner(FParent) as TComponentEditorDesigner;
|
|
BuildCaption;
|
|
EnumerateSubcomponentClasses;
|
|
RefreshList;
|
|
if Assigned(GlobalDesignHook) then
|
|
begin
|
|
GlobalDesignHook.AddHandlerComponentRenamed(@OnComponentRenamed);
|
|
GlobalDesignHook.AddHandlerPersistentDeleting(@OnPersistentDeleting);
|
|
GlobalDesignHook.AddHandlerGetSelection(@OnGetSelection);
|
|
GlobalDesignHook.AddHandlerSetSelection(@OnSetSelection);
|
|
GlobalDesignHook.AddHandlerPersistentAdded(@OnPersistentAdded);
|
|
end;
|
|
SelectionChanged;
|
|
end;
|
|
|
|
destructor TMvComponentListEditorForm.Destroy;
|
|
begin
|
|
UnregisterEditorForm(Self);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.AddSubcomponentClass(
|
|
const ACaption: String; ATag: Integer);
|
|
var
|
|
mi: TMenuItem;
|
|
begin
|
|
if ACaption = '' then exit; // Empty names denote deprecated components.
|
|
mi := TMenuItem.Create(Self);
|
|
mi.OnClick := @miAddClick;
|
|
mi.Caption := ACaption;
|
|
mi.Tag := ATag;
|
|
menuAddItem.Items.Add(mi);
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.ChildrenListBoxClick(Sender: TObject);
|
|
begin
|
|
SelectionChanged;
|
|
end;
|
|
|
|
function TMvComponentListEditorForm.FindChild(
|
|
ACandidate: TPersistent; out AIndex: Integer): Boolean;
|
|
begin
|
|
if ACandidate is ChildClass then
|
|
AIndex := ChildrenListBox.Items.IndexOfObject(ACandidate)
|
|
else
|
|
AIndex := -1;
|
|
Result := AIndex >= 0;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.FormClose(
|
|
Sender: TObject; var CloseAction: TCloseAction);
|
|
begin
|
|
CloseAction := caFree;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.FormCreate(Sender: TObject);
|
|
begin
|
|
tbCommands.Images := IDEImages.Images_16;
|
|
tbAdd.ImageIndex := IDEImages.LoadImage('laz_add');
|
|
tbDelete.ImageIndex := IDEImages.LoadImage('laz_delete');
|
|
tbMoveDown.ImageIndex := IDEImages.LoadImage('arrow_down');
|
|
tbMoveUp.ImageIndex := IDEImages.LoadImage('arrow_up');
|
|
tbAdd.Caption := 'Add';
|
|
tbDelete.Caption := 'Delete';
|
|
tbMoveUp.Caption := 'Up';
|
|
tbMoveDown.Caption := 'Down';
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.FormDestroy(Sender: TObject);
|
|
begin
|
|
if GlobalDesignHook = Nil then
|
|
Exit;
|
|
if Assigned(FComponentEditor) and Assigned(FParent) and
|
|
not (csDestroying in FParent.ComponentState) and
|
|
(ChildrenListBox.SelCount > 0)
|
|
then
|
|
GlobalDesignHook.SelectOnlyThis(FParent);
|
|
GlobalDesignHook.RemoveAllHandlersForObject(Self);
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.miAddClick(Sender: TObject);
|
|
var
|
|
s: TComponent;
|
|
n: String;
|
|
begin
|
|
s := MakeSubcomponent(FParent.Owner, (Sender as TMenuItem).Tag);
|
|
try
|
|
n := Copy(s.ClassName, 2, Length(s.ClassName) - 1);
|
|
s.Name := FDesigner.CreateUniqueComponentName(FParent.Name + n);
|
|
AddSubcomponent(FParent, s);
|
|
FDesigner.PropertyEditorHook.PersistentAdded(s, true);
|
|
FDesigner.Modified;
|
|
RefreshList;
|
|
except
|
|
s.Free;
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.MoveSelection(AStart, ADir: Integer);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if not ChildrenListBox.SelCount = 0 then exit;
|
|
i := AStart - ADir;
|
|
with ChildrenListBox do
|
|
while InRange(i, 0, Count - 1) and InRange(i + ADir, 0, Count - 1) do begin
|
|
if Selected[i] and not Selected[i + ADir] then begin
|
|
with TMvIndexedComponent(Items.Objects[i]) do
|
|
Index := Index + ADir;
|
|
Items.Move(i, i + ADir);
|
|
Selected[i + ADir] := true;
|
|
Selected[i] := false;
|
|
end;
|
|
i -= ADir;
|
|
end;
|
|
FDesigner.Modified;
|
|
SelectionChanged(true);
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.OnComponentRenamed(AComponent: TComponent);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if AComponent = nil then exit;
|
|
if FindChild(AComponent, i) then
|
|
ChildrenListBox.Items[i] := AComponent.Name
|
|
else if AComponent = FParent then
|
|
BuildCaption;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.OnGetSelection(
|
|
const ASelection: TPersistentSelectionList);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if ASelection = nil then exit;
|
|
ASelection.Clear;
|
|
with ChildrenListBox do
|
|
for i := 0 to Items.Count - 1 do
|
|
if Selected[i] then
|
|
ASelection.Add(TPersistent(Items.Objects[i]));
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.OnPersistentAdded(
|
|
APersistent: TPersistent; ASelect: Boolean);
|
|
var
|
|
s: TComponent;
|
|
begin
|
|
if (APersistent = nil) or not (APersistent is ChildClass) then exit;
|
|
s := APersistent as TComponent;
|
|
if s.GetParentComponent <> FParent then exit;
|
|
with ChildrenListBox do
|
|
Selected[Items.AddObject(s.Name, s)] := ASelect;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.OnPersistentDeleting(
|
|
APersistent: TPersistent);
|
|
var
|
|
i, wasSelected: Integer;
|
|
begin
|
|
if not FindChild(APersistent, i) then exit;
|
|
with ChildrenListBox do begin
|
|
wasSelected := ItemIndex;
|
|
Items.Delete(i);
|
|
ItemIndex := Min(wasSelected, Count - 1);
|
|
end;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.OnSetSelection(
|
|
const ASelection: TPersistentSelectionList);
|
|
var
|
|
i, j: Integer;
|
|
begin
|
|
if ASelection = nil then exit;
|
|
ChildrenListBox.ClearSelection;
|
|
for i := 0 to ASelection.Count - 1 do
|
|
if FindChild(ASelection.Items[i], j) then
|
|
ChildrenListBox.Selected[j] := true;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.RefreshList;
|
|
var
|
|
ci: TStrings;
|
|
i: Integer;
|
|
begin
|
|
ci := ChildrenListBox.Items;
|
|
try
|
|
ci.BeginUpdate;
|
|
ci.Clear;
|
|
with GetChildrenList do
|
|
for i := 0 to Count - 1 do
|
|
ci.AddObject(TComponent(Items[i]).Name, TObject(Items[i]));
|
|
finally
|
|
ci.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.SelectionChanged(AOrderChanged: Boolean);
|
|
var
|
|
sel: TPersistentSelectionList;
|
|
begin
|
|
if GlobalDesignHook=nil then exit;
|
|
GlobalDesignHook.RemoveHandlerSetSelection(@OnSetSelection);
|
|
try
|
|
sel := TPersistentSelectionList.Create;
|
|
sel.ForceUpdate := AOrderChanged;
|
|
try
|
|
OnGetSelection(sel);
|
|
FDesigner.PropertyEditorHook.SetSelection(sel);
|
|
finally
|
|
sel.Free;
|
|
end;
|
|
finally
|
|
GlobalDesignHook.AddHandlerSetSelection(@OnSetSelection);
|
|
end;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.tbDeleteClick(Sender: TObject);
|
|
begin
|
|
if ChildrenListBox.SelCount = 0 then exit;
|
|
FDesigner.DeleteSelection;
|
|
SelectionChanged;
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.tbMoveDownClick(Sender: TObject);
|
|
begin
|
|
MoveSelection(ChildrenListBox.Count - 1, 1);
|
|
end;
|
|
|
|
procedure TMvComponentListEditorForm.tbMoveUpClick(Sender: TObject);
|
|
begin
|
|
MoveSelection(0, -1);
|
|
end;
|
|
|
|
{==============================================================================}
|
|
|
|
|
|
{ TMvPluginManagerComponentEditor }
|
|
|
|
function TMvPluginManagerComponentEditor.GetVerb(Index: Integer): string;
|
|
begin
|
|
if Index = 0 then
|
|
Result := 'Edit plugin'
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TMvPluginManagerComponentEditor.MakeEditorForm: TForm;
|
|
begin
|
|
Result := TMvPluginManagerEditorForm.Create(Application, GetComponent, Self, nil);
|
|
end;
|
|
|
|
|
|
{ TMvPluginListPropertyEditor }
|
|
|
|
function TMvPluginListPropertyEditor.GetChildrenCount: Integer;
|
|
begin
|
|
Result := (GetObjectValue as TMvPluginList).Count;
|
|
end;
|
|
|
|
function TMvPluginListPropertyEditor.MakeEditorForm: TForm;
|
|
begin
|
|
with TMvPluginManagerEditorForm do
|
|
Result := Create(Application, GetComponent(0) as TComponent, nil, Self);
|
|
end;
|
|
|
|
|
|
{ TMvPluginManagerEditorForm }
|
|
|
|
procedure TMvPluginManagerEditorForm.AddSubcomponent(AParent, AChild: TComponent);
|
|
begin
|
|
(AChild as TMvCustomPlugin).PluginManager := (AParent as TMvPluginManager);
|
|
end;
|
|
|
|
procedure TMvPluginManagerEditorForm.BuildCaption;
|
|
begin
|
|
Caption := 'Edit plugin - ' + Parent.Name;
|
|
end;
|
|
|
|
function TMvPluginManagerEditorForm.ChildClass: TComponentClass;
|
|
begin
|
|
Result := TMvCustomPlugin;
|
|
end;
|
|
|
|
procedure TMvPluginManagerEditorForm.EnumerateSubcomponentClasses;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to PluginClassRegistry.Count - 1 do
|
|
AddSubcomponentClass(PluginClassRegistry.GetCaption(i), i);
|
|
end;
|
|
|
|
function TMvPluginManagerEditorForm.GetChildrenList: TFPList;
|
|
begin
|
|
Result := (Parent as TMvPluginManager).PluginList;
|
|
end;
|
|
|
|
function TMvPluginManagerEditorForm.MakeSubcomponent(AOwner: TComponent;
|
|
ATag: Integer): TComponent;
|
|
begin
|
|
Result := TMvCustomPluginClass(PluginClassRegistry.GetClass(ATag)).Create(AOwner);
|
|
end;
|
|
|
|
|
|
end.
|
|
|