2
*****************************************************************************
4
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
5
* for details about the copyright. *
7
* This program is distributed in the hope that it will be useful, *
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
11
*****************************************************************************
13
Author: Alexander Klenin
16
unit TASubcomponentsEditor;
23
Classes, ComCtrls, ComponentEditors, Forms, Menus, PropEdits, StdCtrls;
27
{ TSubComponentListEditor }
29
TSubComponentListEditor = class(TComponentEditor)
31
function MakeEditorForm: TForm; virtual; abstract;
33
procedure ExecuteVerb(Index: Integer); override;
34
function GetVerbCount: Integer; override;
37
{ TComponentListPropertyEditor }
39
TComponentListPropertyEditor = class(TPropertyEditor)
41
function GetChildrenCount: Integer; virtual; abstract;
42
function MakeEditorForm: TForm; virtual; abstract;
44
procedure Edit; override;
45
function GetAttributes: TPropertyAttributes; override;
46
function GetValue: AnsiString; override;
49
{ TComponentListEditorForm }
51
TComponentListEditorForm = class(TForm)
52
ChildrenListBox: TListBox;
53
menuAddItem: TPopupMenu;
56
tbDelete: TToolButton;
57
tbMoveDown: TToolButton;
58
tbMoveUp: TToolButton;
59
procedure ChildrenListBoxClick(Sender: TObject);
60
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
61
procedure FormCreate(Sender: TObject);
62
procedure FormDestroy(Sender: TObject);
63
procedure miAddClick(Sender: TObject);
64
procedure tbDeleteClick(Sender: TObject);
65
procedure tbMoveDownClick(Sender: TObject);
66
procedure tbMoveUpClick(Sender: TObject);
68
FComponentEditor: TSubComponentListEditor;
69
FDesigner: TComponentEditorDesigner;
71
FPropertyEditor: TComponentListPropertyEditor;
72
function FindChild(ACandidate: TPersistent; out AIndex: Integer): Boolean;
73
procedure MoveSelection(AStart, ADir: Integer);
74
procedure OnComponentRenamed(AComponent: TComponent);
75
procedure OnGetSelection(const ASelection: TPersistentSelectionList);
76
procedure OnPersistentAdded(APersistent: TPersistent; ASelect: Boolean);
77
procedure OnPersistentDeleting(APersistent: TPersistent);
78
procedure OnSetSelection(const ASelection: TPersistentSelectionList);
79
procedure RefreshList;
80
procedure SelectionChanged(AOrderChanged: Boolean = false);
82
procedure AddSubcomponent(AParent, AChild: TComponent); virtual; abstract;
83
procedure AddSubcomponentClass(const ACaption: String; ATag: Integer);
84
procedure BuildCaption; virtual; abstract;
85
function ChildClass: TComponentClass; virtual; abstract;
86
procedure EnumerateSubcomponentClasses; virtual; abstract;
87
function GetChildrenList: TFPList; virtual; abstract;
88
function MakeSubcomponent(
89
AOwner: TComponent; ATag: Integer): TComponent; virtual; abstract;
90
property Parent: TComponent read FParent;
93
AOwner, AParent: TComponent; AComponentEditor: TSubComponentListEditor;
94
APropertyEditor: TComponentListPropertyEditor); reintroduce;
95
destructor Destroy; override;
101
IDEImagesIntf, Math, SysUtils, TAChartUtils;
105
{ TComponentListPropertyEditor }
107
procedure TComponentListPropertyEditor.Edit;
109
propValue: TPersistent;
112
propValue := GetComponent(0);
113
if propValue = nil then
114
raise Exception.Create('TComponentListPropertyEditor.Component=nil');
115
editorForm := FindEditorForm(propValue) as TForm;
116
if editorForm = nil then begin
117
editorForm := MakeEditorForm;
118
RegisterEditorForm(editorForm, propValue);
120
editorForm.EnsureVisible;
123
function TComponentListPropertyEditor.GetAttributes: TPropertyAttributes;
125
Result := [paDialog, paReadOnly];
128
function TComponentListPropertyEditor.GetValue: ansistring;
132
c := GetChildrenCount;
136
Result := IntToStr(c) + ' items';
139
{ TSubComponentListEditor }
141
procedure TSubComponentListEditor.ExecuteVerb(Index: Integer);
143
propValue: TPersistent;
146
if Index <> 0 then exit;
147
propValue := GetComponent;
148
if propValue = nil then
149
raise Exception.Create('TSubComponentListEditor.Component=nil');
150
editorForm := FindEditorForm(propValue) as TForm;
151
if editorForm = nil then begin
152
editorForm := MakeEditorForm;
153
RegisterEditorForm(editorForm, propValue);
155
editorForm.ShowOnTop;
158
function TSubComponentListEditor.GetVerbCount: Integer;
163
{ TComponentListEditorForm }
165
procedure TComponentListEditorForm.AddSubcomponentClass(
166
const ACaption: String; ATag: Integer);
170
if ACaption = '' then exit; // Empty names denote deprecated components.
171
mi := TMenuItem.Create(Self);
172
mi.OnClick := @miAddClick;
173
mi.Caption := ACaption;
175
menuAddItem.Items.Add(mi);
178
procedure TComponentListEditorForm.ChildrenListBoxClick(Sender: TObject);
183
constructor TComponentListEditorForm.Create(
184
AOwner, AParent: TComponent; AComponentEditor: TSubComponentListEditor;
185
APropertyEditor: TComponentListPropertyEditor);
187
inherited Create(AOwner);
189
FComponentEditor := AComponentEditor;
190
FPropertyEditor := APropertyEditor;
191
if FComponentEditor <> nil then
192
FDesigner := FComponentEditor.Designer
194
FDesigner := FindRootDesigner(FParent) as TComponentEditorDesigner;
196
EnumerateSubcomponentClasses;
200
GlobalDesignHook.AddHandlerComponentRenamed(@OnComponentRenamed);
201
GlobalDesignHook.AddHandlerPersistentDeleting(@OnPersistentDeleting);
202
GlobalDesignHook.AddHandlerGetSelection(@OnGetSelection);
203
GlobalDesignHook.AddHandlerSetSelection(@OnSetSelection);
204
GlobalDesignHook.AddHandlerPersistentAdded(@OnPersistentAdded);
209
destructor TComponentListEditorForm.Destroy;
211
UnregisterEditorForm(Self);
215
function TComponentListEditorForm.FindChild(
216
ACandidate: TPersistent; out AIndex: Integer): Boolean;
218
if ACandidate is ChildClass then
219
AIndex := ChildrenListBox.Items.IndexOfObject(ACandidate)
222
Result := AIndex >= 0;
225
procedure TComponentListEditorForm.FormClose(
226
Sender: TObject; var CloseAction: TCloseAction);
228
CloseAction := caFree;
231
procedure TComponentListEditorForm.FormCreate(Sender: TObject);
233
tbCommands.Images := IDEImages.Images_16;
234
tbAdd.ImageIndex := IDEImages.LoadImage(16, 'laz_add');
235
tbDelete.ImageIndex := IDEImages.LoadImage(16, 'laz_delete');
236
tbMoveDown.ImageIndex := IDEImages.LoadImage(16, 'arrow_down');
237
tbMoveUp.ImageIndex := IDEImages.LoadImage(16, 'arrow_up');
240
procedure TComponentListEditorForm.FormDestroy(Sender: TObject);
243
(FComponentEditor <> nil) and (FParent <> nil) and
244
(not (csDestroying in FParent.ComponentState)) and
245
(ChildrenListBox.SelCount > 0)
247
GlobalDesignHook.SelectOnlyThis(FParent);
248
if Assigned(GlobalDesignHook) then
249
GlobalDesignHook.RemoveAllHandlersForObject(Self);
252
procedure TComponentListEditorForm.miAddClick(Sender: TObject);
257
s := MakeSubcomponent(FParent.Owner, (Sender as TMenuItem).Tag);
259
n := Copy(s.ClassName, 2, Length(s.ClassName) - 1);
260
s.Name := FDesigner.CreateUniqueComponentName(FParent.Name + n);
261
AddSubcomponent(FParent, s);
262
FDesigner.PropertyEditorHook.PersistentAdded(s, true);
271
procedure TComponentListEditorForm.MoveSelection(AStart, ADir: Integer);
275
if not ChildrenListBox.SelCount = 0 then exit;
277
with ChildrenListBox do
278
while InRange(i, 0, Count - 1) and InRange(i + ADir, 0, Count - 1) do begin
279
if Selected[i] and not Selected[i + ADir] then begin
280
with TIndexedComponent(Items.Objects[i]) do
281
Index := Index + ADir;
282
Items.Move(i, i + ADir);
283
Selected[i + ADir] := true;
284
Selected[i] := false;
289
SelectionChanged(true);
292
procedure TComponentListEditorForm.OnComponentRenamed(AComponent: TComponent);
296
if AComponent = nil then exit;
297
if FindChild(AComponent, i) then
298
ChildrenListBox.Items[i] := AComponent.Name
299
else if AComponent = FParent then
303
procedure TComponentListEditorForm.OnGetSelection(
304
const ASelection: TPersistentSelectionList);
308
if ASelection = nil then exit;
310
with ChildrenListBox do
311
for i := 0 to Items.Count - 1 do
313
ASelection.Add(TPersistent(Items.Objects[i]));
316
procedure TComponentListEditorForm.OnPersistentAdded(
317
APersistent: TPersistent; ASelect: Boolean);
321
if (APersistent = nil) or not (APersistent is ChildClass) then exit;
322
s := APersistent as TComponent;
323
if s.GetParentComponent <> FParent then exit;
324
with ChildrenListBox do
325
Selected[Items.AddObject(s.Name, s)] := ASelect;
328
procedure TComponentListEditorForm.OnPersistentDeleting(
329
APersistent: TPersistent);
331
i, wasSelected: Integer;
333
if not FindChild(APersistent, i) then exit;
334
with ChildrenListBox do begin
335
wasSelected := ItemIndex;
337
ItemIndex := Min(wasSelected, Count - 1);
341
procedure TComponentListEditorForm.OnSetSelection(
342
const ASelection: TPersistentSelectionList);
346
if ASelection = nil then exit;
347
ChildrenListBox.ClearSelection;
348
for i := 0 to ASelection.Count - 1 do
349
if FindChild(ASelection.Items[i], j) then
350
ChildrenListBox.Selected[j] := true;
353
procedure TComponentListEditorForm.RefreshList;
358
ci := ChildrenListBox.Items;
362
with GetChildrenList do
363
for i := 0 to Count - 1 do
364
ci.AddObject(TComponent(Items[i]).Name, TObject(Items[i]));
370
procedure TComponentListEditorForm.SelectionChanged(AOrderChanged: Boolean);
372
sel: TPersistentSelectionList;
374
GlobalDesignHook.RemoveHandlerSetSelection(@OnSetSelection);
376
sel := TPersistentSelectionList.Create;
377
sel.ForceUpdate := AOrderChanged;
380
FDesigner.PropertyEditorHook.SetSelection(sel);
385
GlobalDesignHook.AddHandlerSetSelection(@OnSetSelection);
389
procedure TComponentListEditorForm.tbDeleteClick(Sender: TObject);
391
if ChildrenListBox.SelCount = 0 then exit;
392
FDesigner.DeleteSelection;
396
procedure TComponentListEditorForm.tbMoveDownClick(Sender: TObject);
398
MoveSelection(ChildrenListBox.Count - 1, 1);
401
procedure TComponentListEditorForm.tbMoveUpClick(Sender: TObject);
403
MoveSelection(0, -1);