ideintf: ComponentTreeView: a generic way to create subtrees from child components (patch from Alexander S. Klenin, issue #0013217)

git-svn-id: trunk@18782 -
This commit is contained in:
paul 2009-02-20 18:18:37 +00:00
parent 0265fae03f
commit cf81a4cbf8

View File

@ -28,7 +28,7 @@ unit ComponentTreeView;
interface interface
uses uses
Classes, SysUtils, LCLProc, AvgLvlTree, Controls, ComCtrls, PropEdits, Menus, Classes, SysUtils, LCLProc, AvgLvlTree, Controls, ComCtrls, PropEdits,
ExtCtrls, LResources; ExtCtrls, LResources;
type type
@ -72,6 +72,23 @@ type
Added: boolean; Added: boolean;
end; end;
{ TComponentWalker }
TComponentWalker = class
FTreeView: TComponentTreeView;
FCandidates: TAvgLvlTree;
FRootComponent: TComponent;
FNode: TTreeNode;
public
constructor Create(
ATreeView: TComponentTreeView; ACandidates: TAvgLvlTree;
ARootComponent: TComponent; ANode: TTreeNode);
procedure Walk(AComponent: TComponent);
end;
TComponentAccessor = class(TComponent);
function CompareComponentCandidates( function CompareComponentCandidates(
Candidate1, Candidate2: TComponentCandidate): integer; Candidate1, Candidate2: TComponentCandidate): integer;
begin begin
@ -84,6 +101,42 @@ begin
Result := ComparePointers(APersistent, Candidate.APersistent); Result := ComparePointers(APersistent, Candidate.APersistent);
end; end;
{ TComponentWalker }
constructor TComponentWalker.Create(ATreeView: TComponentTreeView;
ACandidates: TAvgLvlTree; ARootComponent: TComponent; ANode: TTreeNode);
begin
FTreeView := ATreeView;
FCandidates := ACandidates;
FRootComponent := ARootComponent;
FNode := ANode;
end;
procedure TComponentWalker.Walk(AComponent: TComponent);
var
oldNode: TTreeNode;
candidate: TComponentCandidate;
avlNode: TAvgLvlTreeNode;
begin
if GetLookupRootForComponent(AComponent) <> FRootComponent then exit;
avlNode := FCandidates.FindKey(
AComponent, TListSortCompare(@ComparePersistentWithComponentCandidate));
if avlNode = nil then exit;
candidate := TComponentCandidate(avlNode.Data);
if candidate.Added then exit;
candidate.Added := true;
oldNode := FNode;
FNode := FTreeView.Items.AddChild(FNode, FTreeView.CreateNodeCaption(AComponent));
FNode.Data := AComponent;
FNode.ImageIndex := FTreeView.GetImageFor(AComponent);
FNode.SelectedIndex := FNode.ImageIndex;
FNode.MultiSelected := FTreeView.Selection.IndexOf(AComponent) >= 0;
TComponentAccessor(AComponent).GetChildren(@Walk, FRootComponent);
FNode := oldNode;
FNode.Expanded := true;
end;
{ TComponentTreeView } { TComponentTreeView }
procedure TComponentTreeView.SetSelection( procedure TComponentTreeView.SetSelection(
@ -275,60 +328,16 @@ var
Candidates: TAvgLvlTree; Candidates: TAvgLvlTree;
RootComponent: TComponent; RootComponent: TComponent;
procedure AddChildControls(AControl: TWinControl; ANode: TTreeNode); procedure AddChildren(AComponent: TComponent; ANode: TTreeNode);
var var
i: Integer; walker: TComponentWalker;
CurControl: TControl;
NewNode: TTreeNode;
Candidate: TComponentCandidate;
AVLNode: TAvgLvlTreeNode;
begin begin
if AControl=nil then exit; walker := TComponentWalker.Create(Self, Candidates, RootComponent, ANode);
for i:=0 to AControl.ControlCount-1 do begin try
CurControl:=AControl.Controls[i]; TComponentAccessor(AComponent).GetChildren(@walker.Walk, RootComponent);
if GetLookupRootForComponent(CurControl)<>RootComponent then continue; finally
AVLNode:=Candidates.FindKey(CurControl, walker.Free;
TListSortCompare(@ComparePersistentWithComponentCandidate));
if AVLNode=nil then continue;
Candidate:=TComponentCandidate(AVLNode.Data);
if Candidate.Added then continue;
Candidate.Added:=true;
NewNode:=Items.AddChild(ANode,CreateNodeCaption(CurControl));
NewNode.Data:=CurControl;
NewNode.ImageIndex:=GetImageFor(CurControl);
NewNode.SelectedIndex:=NewNode.ImageIndex;
NewNode.MultiSelected:=Selection.IndexOf(CurControl)>=0;
if CurControl is TWinControl then
AddChildControls(TWinControl(CurControl),NewNode);
end; end;
ANode.Expanded:=true;
end;
procedure AddMenuItemChilds(AMenuItem: TMenuItem; ANode: TTreeNode);
var
i: Integer;
CurMenuItem: TMenuItem;
NewNode: TTreeNode;
Candidate: TComponentCandidate;
AVLNode: TAvgLvlTreeNode;
begin
if AMenuItem=nil then exit;
for i:=0 to AMenuItem.Count-1 do begin
CurMenuItem:=AMenuItem.Items[i];
if CurMenuItem.Owner<>RootComponent then continue;
AVLNode:=Candidates.FindKey(CurMenuItem,
TListSortCompare(@ComparePersistentWithComponentCandidate));
Candidate:=TComponentCandidate(AVLNode.Data);
if Candidate.Added then continue;
Candidate.Added:=true;
NewNode:=Items.AddChild(ANode,CreateNodeCaption(CurMenuItem));
NewNode.Data:=CurMenuItem;
NewNode.ImageIndex:=1;
NewNode.SelectedIndex:=NewNode.ImageIndex;
NewNode.MultiSelected:=Selection.IndexOf(CurMenuItem)>=0;
AddMenuItemChilds(CurMenuItem,NewNode);
end;
ANode.Expanded:=true;
end; end;
procedure AddCandidates(OwnerComponent: TComponent); procedure AddCandidates(OwnerComponent: TComponent);
@ -360,9 +369,7 @@ var
i: Integer; i: Integer;
AComponent: TComponent; AComponent: TComponent;
RootNode: TTreeNode; RootNode: TTreeNode;
AControl: TControl;
AVLNode: TAvgLvlTreeNode; AVLNode: TAvgLvlTreeNode;
AMenu: TMenu;
Candidate: TComponentCandidate; Candidate: TComponentCandidate;
begin begin
BeginUpdate; BeginUpdate;
@ -397,31 +404,18 @@ begin
AVLNode:=Candidates.FindKey(AComponent, AVLNode:=Candidates.FindKey(AComponent,
TListSortCompare(@ComparePersistentWithComponentCandidate)); TListSortCompare(@ComparePersistentWithComponentCandidate));
Candidate:=TComponentCandidate(AVLNode.Data); Candidate:=TComponentCandidate(AVLNode.Data);
if Candidate.Added then if Candidate.Added or
AComponent.HasParent and
(AComponent.GetParentComponent <> nil) and
(AComponent.GetParentComponent <> RootComponent) then
continue; continue;
if AComponent is TControl then begin
AControl:=TControl(AComponent);
if (AControl.Parent<>nil) and (AControl.Parent<>RootComponent) then
// grand child controls will be added recursively, not here
continue;
end
else if (AComponent is TMenuItem) then begin
AMenu:=TMenuItem(AComponent).GetParentMenu;
if (AMenu<>nil) and (AMenu.Owner=RootComponent) then
// child menuitems will be added recursively, not here
continue;
end;
Candidate.Added:=true; Candidate.Added:=true;
NewNode:=Items.AddChild(RootNode,CreateNodeCaption(AComponent)); NewNode:=Items.AddChild(RootNode,CreateNodeCaption(AComponent));
NewNode.Data:=AComponent; NewNode.Data:=AComponent;
NewNode.ImageIndex:=GetImageFor(AComponent); NewNode.ImageIndex:=GetImageFor(AComponent);
NewNode.SelectedIndex:=NewNode.ImageIndex; NewNode.SelectedIndex:=NewNode.ImageIndex;
NewNode.MultiSelected:=Selection.IndexOf(AComponent)>=0; NewNode.MultiSelected:=Selection.IndexOf(AComponent)>=0;
if AComponent is TWinControl then AddChildren(AComponent, NewNode);
AddChildControls(TWinControl(AComponent),NewNode)
else if (AComponent is TMenu) then begin
AddMenuItemChilds(TMenu(AComponent).Items,NewNode);
end;
end; end;
end; end;
finally finally