implemented selections in component tree

git-svn-id: trunk@4513 -
This commit is contained in:
mattias 2003-08-22 18:10:39 +00:00
parent 2ba9e24665
commit f9aa787cd3
7 changed files with 303 additions and 33 deletions

View File

@ -14,14 +14,18 @@
Abstract:
TComponentTreeView is a component to show the child components of a
TComponent. TControls can be shown in a hierachic view.
TComponent. TControls are shown in a hierachic view.
It supports
- multi selecting components
- editing the creation order
- editing the TControl.Parent hierachy
For example of the usage, see the object inspector.
For an usage example, see the object inspector.
ToDo:
- pass selection to form editor
- icons
- pass keys to form editor
- drag&drop: change parent and position
}
unit ComponentTreeView;
@ -37,17 +41,20 @@ type
TComponentTreeView = class(TCustomTreeView)
private
FComponentList: TComponentSelectionList;
FComponentList: TBackupComponentList;
FPropertyEditorHook: TPropertyEditorHook;
function GetSelections: TComponentSelectionList;
procedure SetPropertyEditorHook(const AValue: TPropertyEditorHook);
procedure SetSelections(const NewSelections: TComponentSelectionList);
protected
procedure DoSelectionChanged; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure RebuildComponentNodes; virtual;
function CreateNodeCaption(AComponent: TComponent): string; virtual;
public
property Selections: TComponentSelectionList read FComponentList
property Selections: TComponentSelectionList read GetSelections
write SetSelections;
property PropertyEditorHook: TPropertyEditorHook
read FPropertyEditorHook write SetPropertyEditorHook;
@ -60,10 +67,51 @@ implementation
procedure TComponentTreeView.SetSelections(
const NewSelections: TComponentSelectionList);
begin
FComponentList.Assign(NewSelections);
if (PropertyEditorHook=nil) then begin
if (FComponentList.LookupRoot=nil) then
exit;
FComponentList.Clear;
end else begin
if FComponentList.IsEqual(PropertyEditorHook.LookupRoot,NewSelections) then
exit;
end;
FComponentList.LookupRoot:=PropertyEditorHook.LookupRoot;
FComponentList.Selection.Assign(NewSelections);
RebuildComponentNodes;
end;
procedure TComponentTreeView.DoSelectionChanged;
var
ANode: TTreeNode;
AComponent: TComponent;
NewSelection: TComponentSelectionList;
begin
NewSelection:=TComponentSelectionList.Create;
try
if (PropertyEditorHook<>nil)
and (PropertyEditorHook.LookupRoot<>nil)
and (not (csDestroying in ComponentState)) then begin
ANode:=GetFirstMultiSelected;
while ANode<>nil do begin
AComponent:=TComponent(ANode.Data);
if AComponent=nil then
RaiseGDBException('TComponentTreeView.DoSelectionChanged ANode.Data=nil');
if ((AComponent.Owner=nil)
and (AComponent=PropertyEditorHook.LookupRoot))
or (AComponent.Owner=PropertyEditorHook.LookupRoot)
then
NewSelection.Add(AComponent);
ANode:=ANode.GetNextMultiSelected;
end;
end;
if NewSelection.IsEqual(FComponentList.Selection) then exit;
FComponentList.Selection.Assign(NewSelection);
finally
NewSelection.Free;
end;
inherited DoSelectionChanged;
end;
procedure TComponentTreeView.SetPropertyEditorHook(
const AValue: TPropertyEditorHook);
begin
@ -72,10 +120,15 @@ begin
RebuildComponentNodes;
end;
function TComponentTreeView.GetSelections: TComponentSelectionList;
begin
Result:=FComponentList.Selection;
end;
constructor TComponentTreeView.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FComponentList:=TComponentSelectionList.Create;
FComponentList:=TBackupComponentList.Create;
Options:=Options+[tvoAllowMultiselect,tvoAutoItemHeight,tvoKeepCollapsedNodes];
end;
@ -86,6 +139,26 @@ begin
end;
procedure TComponentTreeView.RebuildComponentNodes;
procedure AddChildControls(AControl: TWinControl; ANode: TTreeNode);
var
i: Integer;
CurControl: TControl;
NewNode: TTreeNode;
begin
if AControl=nil then exit;
for i:=0 to AControl.ControlCount-1 do begin
CurControl:=AControl.Controls[i];
if CurControl.Owner<>AControl.Owner then continue;
NewNode:=Items.AddChild(ANode,CreateNodeCaption(CurControl));
NewNode.Data:=CurControl;
NewNode.ImageIndex:=-1;
NewNode.MultiSelected:=Selections.IndexOf(CurControl)>=0;
if CurControl is TWinControl then
AddChildControls(TWinControl(CurControl),NewNode);
end;
end;
var
OldExpanded: TTreeNodeExpandedState;
NewNode: TTreeNode;
@ -93,6 +166,7 @@ var
i: Integer;
AComponent: TComponent;
RootNode: TTreeNode;
AControl: TControl;
begin
BeginUpdate;
// save old expanded state and clear
@ -103,15 +177,25 @@ begin
if RootComponent<>nil then begin
// first add the lookup root
RootNode:=Items.Add(nil,CreateNodeCaption(RootComponent));
RootNode.Data:=RootComponent;
RootNode.ImageIndex:=-1;
RootNode.Selected:=Selections.IndexOf(RootComponent)>=0;
RootNode.MultiSelected:=Selections.IndexOf(RootComponent)>=0;
// add components in creation order
// add components in creation order and TControl.Parent relationship
for i:=0 to RootComponent.ComponentCount-1 do begin
AComponent:=RootComponent.Components[i];
if AComponent is TControl then begin
AControl:=TControl(AComponent);
if (AControl.Parent<>nil) and (AControl.Parent<>RootComponent) then
// child controls will be added recursively, not here
continue;
end;
NewNode:=Items.AddChild(RootNode,CreateNodeCaption(AComponent));
NewNode.Data:=AComponent;
NewNode.ImageIndex:=-1;
NewNode.Selected:=Selections.IndexOf(AComponent)>=0;
NewNode.MultiSelected:=Selections.IndexOf(AComponent)>=0;
if AComponent is TWinControl then
AddChildControls(TWinControl(AComponent),NewNode);
end;
RootNode.Expand(true);

View File

@ -38,7 +38,7 @@ interface
uses
Classes, LCLLinux, LCLType, Controls, Forms, GraphType, Graphics, SysUtils,
EnvironmentOpts, DesignerProcs, Menus;
Menus, EnvironmentOpts, PropEdits, DesignerProcs;
type
TControlSelection = class;
@ -348,11 +348,12 @@ type
function IndexOf(AComponent:TComponent):integer;
function Add(AComponent: TComponent):integer;
function AssignComponent(AComponent:TComponent): boolean;
procedure Remove(AComponent: TComponent);
procedure Delete(Index:integer);
procedure Clear;
procedure Assign(AControlSelection:TControlSelection);
function AssignComponent(AComponent:TComponent): boolean;
procedure Assign(AControlSelection: TControlSelection);
procedure AssignSelection(ASelection: TComponentSelectionList);
function IsSelected(AComponent: TComponent): Boolean;
function IsOnlySelected(AComponent: TComponent): Boolean;
procedure SaveBounds;
@ -1818,6 +1819,25 @@ begin
DoChange;
end;
procedure TControlSelection.AssignSelection(ASelection: TComponentSelectionList
);
var i:integer;
begin
if (cssNotSavingBounds in FStates) then exit;
Include(FStates,cssNotSavingBounds);
BeginUpdate;
Clear;
FControls.Capacity:=ASelection.Count;
for i:=0 to ASelection.Count-1 do
Add(ASelection[i]);
SetCustomForm;
UpdateBounds;
Exclude(FStates,cssNotSavingBounds);
SaveBounds;
EndUpdate;
DoChange;
end;
function TControlSelection.IsSelected(AComponent: TComponent): Boolean;
begin
Result:=(IndexOf(AComponent)>=0);

View File

@ -22,6 +22,11 @@
ToDo:
- backgroundcolor=clNone
- pair splitter
- default values for property editors
- set to default value
- Define Init values
- Set to init value
}
unit ObjectInspector;
@ -303,8 +308,6 @@ type
TOnAddAvailableComponent = procedure(AComponent:TComponent;
var Allowed:boolean) of object;
TOnSelectComponentInOI = procedure(AComponent:TComponent) of object;
TOIFlag = (
oifRebuildPropListsNeeded
);
@ -324,6 +327,7 @@ type
ShowOptionsPopupMenuItem: TMenuItem;
ComponentTree: TComponentTreeView;
procedure AvailComboBoxCloseUp(Sender: TObject);
procedure ComponentTreeSelectionChanged(Sender: TObject);
procedure OnBackgroundColPopupMenuItemClick(Sender :TObject);
procedure OnShowHintPopupMenuItemClick(Sender :TObject);
procedure OnShowOptionsPopupMenuItemClick(Sender :TObject);
@ -337,7 +341,7 @@ type
FOnShowOptions: TNotifyEvent;
FPropertyEditorHook:TPropertyEditorHook;
FOnAddAvailableComponent:TOnAddAvailableComponent;
FOnSelectComponentInOI:TOnSelectComponentInOI;
FOnSelectComponentsInOI:TNotifyEvent;
FOnModified: TNotifyEvent;
FShowComponentTree: boolean;
FUpdateLock: integer;
@ -372,8 +376,8 @@ type
read FComponentList write SetSelections;
property OnAddAvailComponent: TOnAddAvailableComponent
read FOnAddAvailableComponent write FOnAddAvailableComponent;
property OnSelectComponentInOI: TOnSelectComponentInOI
read FOnSelectComponentInOI write FOnSelectComponentInOI;
property OnSelectComponentsInOI: TNotifyEvent
read FOnSelectComponentsInOI write FOnSelectComponentsInOI;
property PropertyEditorHook: TPropertyEditorHook
read FPropertyEditorHook write SetPropertyEditorHook;
property OnModified: TNotifyEvent read FOnModified write FOnModified;
@ -2201,13 +2205,14 @@ begin
Visible:=not FShowComponentTree;
end;
// Component Tree
// Component Tree at top (filled with available components)
ComponentTree:=TComponentTreeView.Create(Self);
with ComponentTree do begin
Name:='ComponentTree';
Height:=ComponentTreeHeight;
Parent:=Self;
Align:=alTop;
OnSelectionChanged:=@ComponentTreeSelectionChanged;
Visible:=FShowComponentTree;
end;
@ -2453,8 +2458,8 @@ var NewComponent,Root:TComponent;
FComponentList.Clear;
FComponentList.Add(c);
RefreshSelections;
if Assigned(FOnSelectComponentInOI) then
FOnSelectComponentInOI(c);
if Assigned(FOnSelectComponentsInOI) then
FOnSelectComponentsInOI(Self);
end;
// AvailComboBoxChange
@ -2477,6 +2482,15 @@ begin
end;
end;
procedure TObjectInspector.ComponentTreeSelectionChanged(Sender: TObject);
begin
if (PropertyEditorHook=nil) or (PropertyEditorHook.LookupRoot=nil) then exit;
FComponentList.Assign(ComponentTree.Selections);
RefreshSelections;
if Assigned(FOnSelectComponentsInOI) then
FOnSelectComponentsInOI(Self);
end;
procedure TObjectInspector.OnBackgroundColPopupMenuItemClick(Sender :TObject);
var ColorDialog:TColorDialog;
begin

View File

@ -882,6 +882,30 @@ type
procedure Assign(SourceSelectionList: TComponentSelectionList);
property Items[Index: integer]: TComponent read GetItems write SetItems; default;
end;
TBackupComponentList = class
private
FComponentList: TList;
FLookupRoot: TComponent;
FSelection: TComponentSelectionList;
function GetComponents(Index: integer): TComponent;
procedure SetComponents(Index: integer; const AValue: TComponent);
procedure SetLookupRoot(const AValue: TComponent);
procedure SetSelection(const AValue: TComponentSelectionList);
protected
public
constructor Create;
destructor Destroy; override;
function IndexOf(AComponent: TComponent): integer;
procedure Clear;
function ComponentCount: integer;
function IsEqual(ALookupRoot: TComponent;
ASelection: TComponentSelectionList): boolean;
public
property LookupRoot: TComponent read FLookupRoot write SetLookupRoot;
property Components[Index: integer]: TComponent read GetComponents write SetComponents;
property Selection: TComponentSelectionList read FSelection write SetSelection;
end;
//==============================================================================
{
@ -5015,6 +5039,82 @@ begin
end;
{ TBackupComponentList }
function TBackupComponentList.GetComponents(Index: integer): TComponent;
begin
Result:=TComponent(FComponentList[Index]);
end;
procedure TBackupComponentList.SetComponents(Index: integer;
const AValue: TComponent);
begin
FComponentList[Index]:=AValue;
end;
procedure TBackupComponentList.SetLookupRoot(const AValue: TComponent);
var
i: Integer;
begin
FLookupRoot:=AValue;
FComponentList.Clear;
if FLookupRoot<>nil then
for i:=0 to FLookupRoot.ComponentCount-1 do
FComponentList.Add(FLookupRoot.Components[i]);
FSelection.Clear;
end;
procedure TBackupComponentList.SetSelection(
const AValue: TComponentSelectionList);
begin
if FSelection=AValue then exit;
FSelection.Assign(AValue);
end;
constructor TBackupComponentList.Create;
begin
FSelection:=TComponentSelectionList.Create;
FComponentList:=TList.Create;
end;
destructor TBackupComponentList.Destroy;
begin
FreeAndNil(FSelection);
FreeAndNil(FComponentList);
inherited Destroy;
end;
function TBackupComponentList.IndexOf(AComponent: TComponent): integer;
begin
Result:=FComponentList.IndexOf(AComponent);
end;
procedure TBackupComponentList.Clear;
begin
LookupRoot:=nil;
end;
function TBackupComponentList.ComponentCount: integer;
begin
Result:=FComponentList.Count;
end;
function TBackupComponentList.IsEqual(ALookupRoot: TComponent;
ASelection: TComponentSelectionList): boolean;
var
i: Integer;
begin
Result:=false;
if ALookupRoot<>LookupRoot then exit;
if not FSelection.IsEqual(ASelection) then exit;
if ALookupRoot<>nil then begin
if ComponentCount<>ALookupRoot.ComponentCount then exit;
for i:=0 to FComponentList.Count-1 do
if TComponent(FComponentList[i])<>ALookupRoot.Components[i] then exit;
end;
Result:=true;
end;
initialization
InitPropEdits;

View File

@ -271,7 +271,7 @@ type
procedure OnSrcNotebookViewJumpHistory(Sender : TObject);
// ObjectInspector + PropertyEditorHook events
procedure OIOnSelectComponent(AComponent:TComponent);
procedure OIOnSelectComponents(Sender: TObject);
procedure OIOnShowOptions(AComponent:TComponent);
procedure OnPropHookGetMethods(TypeData:PTypeData; Proc:TGetStringProc);
function OnPropHookMethodExists(const AMethodName:ShortString;
@ -930,11 +930,9 @@ begin
Application.CreateForm(TLazFindReplaceDialog, FindReplaceDlg);
end;
procedure TMainIDE.OIOnSelectComponent(AComponent:TComponent);
procedure TMainIDE.OIOnSelectComponents(Sender: TObject);
begin
TheControlSelection.AssignComponent(AComponent);
if AComponent.Owner is TControl then
TControl(AComponent.Owner).Invalidate;
TheControlSelection.AssignSelection(ObjectInspector1.Selections);
end;
procedure TMainIDE.OIOnShowOptions(AComponent: TComponent);
@ -1147,7 +1145,7 @@ procedure TMainIDE.SetupObjectInspector;
begin
ObjectInspector1 := TObjectInspector.Create(Self);
ObjectInspector1.OnSelectComponentInOI:=@OIOnSelectComponent;
ObjectInspector1.OnSelectComponentsInOI:=@OIOnSelectComponents;
ObjectInspector1.OnShowOptions:=@OIOnShowOptions;
GlobalDesignHook:=TPropertyEditorHook.Create;
@ -9750,6 +9748,9 @@ end.
{ =============================================================================
$Log$
Revision 1.643 2003/08/22 18:10:39 mattias
implemented selections in component tree
Revision 1.642 2003/08/20 15:06:57 mattias
implemented Build+Run File

View File

@ -1519,7 +1519,8 @@ type
tvsWaitForDragging,
tvsDblClicked,
tvsTripleClicked,
tvsQuadClicked
tvsQuadClicked,
tvsSelectionChanged
);
TTreeViewStates = set of TTreeViewState;
@ -1602,6 +1603,8 @@ type
FScrolledTop: integer; // vertical scrolled pixels (hidden pixels at top)
FSelectedColor: TColor;
FSelectedNode: TTreeNode;
fSelectionChangeEventLock: integer;
fSeparatorColor: TColor;
FSortType: TSortType;
FStateChangeLink: TChangeLink;
FStateImages: TCustomImageList;
@ -1610,7 +1613,6 @@ type
FTreeLineColor: TColor;
FTreeNodes: TTreeNodes;
FUpdateCount: integer;
fSeparatorColor: TColor;
//FWideText: WideString;
procedure CanvasChanged(Sender: TObject);
//procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
@ -1688,6 +1690,7 @@ type
procedure WMSize(var Msg: TLMSize); message LM_SIZE;
//procedure WMContextMenu(var Message: TLMContextMenu); message LM_CONTEXTMENU;
//procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE;
procedure InternalSelectionChanged;
protected
FChangeTimer: TTimer;
//procedure Edit(const Item: TTVItem); dynamic;
@ -1744,6 +1747,7 @@ type
procedure UpdateDefaultItemHeight; virtual;
procedure WndProc(var Message: TLMessage); override;
procedure UpdateInsertMark(X,Y: integer); virtual;
procedure DoSelectionChanged; virtual;
protected
property AutoExpand: Boolean read GetAutoExpand write SetAutoExpand default False;
property BorderStyle: TBorderStyle
@ -1814,6 +1818,9 @@ type
procedure SaveToFile(const FileName: string);
procedure SaveToStream(Stream: TStream);
procedure WriteDebugReport(const Prefix: string; AllNodes: boolean);
procedure LockSelectionChangeEvent;
procedure UnlockSelectionChangeEvent;
function GetFirstMultiSelected: TTreeNode;
public
property BackgroundColor: TColor
read FBackgroundColor write SetBackgroundColor;
@ -2030,6 +2037,9 @@ end.
{ =============================================================================
$Log$
Revision 1.84 2003/08/22 18:10:39 mattias
implemented selections in component tree
Revision 1.83 2003/08/22 07:58:38 mattias
started componenttree

View File

@ -950,6 +950,7 @@ begin
Exclude(FStates,nsMultiSelected);
if TreeNodes<>nil then UnbindFromMultiSelected;
end;
if TreeView<>nil then TreeView.InternalSelectionChanged;
Update;
end;
@ -1290,6 +1291,7 @@ var
begin
if (TreeView<>nil) and (not (tvoAllowMultiselect in TreeView.Options)) then
exit;
if (TreeView<>nil) then TreeView.LockSelectionChangeEvent;
FirstNode:=GetPrevSibling;
while (FirstNode<>nil) and (not FirstNode.MultiSelected) do
FirstNode:=FirstNode.GetPrevSibling;
@ -1304,6 +1306,7 @@ begin
if ANode=LastNode then break;
ANode:=ANode.GetNextSibling;
end;
if (TreeView<>nil) then TreeView.UnlockSelectionChangeEvent;
end;
procedure TTreeNode.MakeVisible;
@ -1742,12 +1745,14 @@ procedure TTreeNodes.ClearMultiSelection;
var
ANode, OldNode: TTreeNode;
begin
if Owner<>nil then Owner.LockSelectionChangeEvent;
ANode:=FFirstMultiSelected;
while ANode<>nil do begin
OldNode:=ANode;
ANode:=ANode.GetNextMultiSelected;
OldNode.MultiSelected:=false;
end;
if Owner<>nil then Owner.UnlockSelectionChangeEvent;
end;
function TTreeNodes.IsMultiSelection: boolean;
@ -2776,13 +2781,13 @@ end;}
procedure TCustomTreeView.BeginUpdate;
begin
inc(FUpdateCount);
LockSelectionChangeEvent;
end;
procedure TCustomTreeView.EndUpdate;
begin
// if FUpdateCount<=0 then
// writeln('TCustomTreeView.EndUpdate UpdateCount=',FUpdateCount);
if FUpdateCount<=0 then exit;
UnlockSelectionChangeEvent;
if FUpdateCount<=0 then RaiseGDBException('TCustomTreeView.EndUpdate');
dec(FUpdateCount);
if FUpdateCount=0 then begin
// ToDo: only refresh if something changed
@ -3618,8 +3623,7 @@ begin
Value.Selected := True;
Value.MakeVisible;
end;
if Assigned(OnSelectionChanged) then OnSelectionChanged(Self);
Invalidate;
InternalSelectionChanged;
end;
function TCustomTreeView.GetShowButtons: boolean;
@ -4026,6 +4030,11 @@ begin
SetInsertMark(nil,tvimNone);
end;
procedure TCustomTreeView.DoSelectionChanged;
begin
if Assigned(OnSelectionChanged) then OnSelectionChanged(Self);
end;
function TCustomTreeView.IsInsertMarkVisible: boolean;
begin
Result:=(FInsertMarkType<>tvimNone) and (FInsertMarkNode<>nil)
@ -4628,8 +4637,10 @@ begin
CursorNode.MultiSelected:=not CursorNode.MultiSelected;
end else begin
if (Selected<>CursorNode) or Items.IsMultiSelection then begin
LockSelectionChangeEvent;
Items.ClearMultiSelection;
CursorNode.MultiSelected:=true;
UnlockSelectionChangeEvent;
end;
end;
end;
@ -4936,6 +4947,16 @@ begin
inherited;
end;
procedure TCustomTreeView.InternalSelectionChanged;
begin
if fSelectionChangeEventLock>0 then begin
Include(fStates,tvsSelectionChanged);
end else begin
Exclude(fStates,tvsSelectionChanged);
DoSelectionChanged;
end;
end;
{ CustomDraw support }
procedure TCustomTreeView.CanvasChanged(Sender: TObject);
@ -5054,6 +5075,26 @@ begin
end;
end;
procedure TCustomTreeView.LockSelectionChangeEvent;
begin
inc(fSelectionChangeEventLock);
end;
procedure TCustomTreeView.UnlockSelectionChangeEvent;
begin
dec(fSelectionChangeEventLock);
if fSelectionChangeEventLock<0 then
RaiseGDBException('TCustomTreeView.UnlockSelectionChangeEvent');
if (fSelectionChangeEventLock=0)
and (tvsSelectionChanged in fStates) then
InternalSelectionChanged;
end;
function TCustomTreeView.GetFirstMultiSelected: TTreeNode;
begin
Result:=Items.FFirstMultiSelected;
end;
procedure TCustomTreeView.SetSeparatorColor(const AValue: TColor);
begin
if fSeparatorColor=AValue then exit;