mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-25 21:07:24 +01:00
IdeIntf: Remember the expanded/collapsed state in OI's ComponentTree when changing designer form. Issue #33464.
git-svn-id: trunk@64313 -
This commit is contained in:
parent
b4fc035018
commit
33cb0bd3a6
@ -24,9 +24,9 @@ unit ComponentTreeView;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Classes, SysUtils, TypInfo,
|
Classes, SysUtils, TypInfo, Laz_AVL_Tree,
|
||||||
// LazUtils
|
// LazUtils
|
||||||
LazUtilities, LazLoggerBase, LazTracer,
|
LazUtilities, LazLoggerBase, LazTracer, AvgLvlTree,
|
||||||
// LCL
|
// LCL
|
||||||
Dialogs, Forms, Controls, ComCtrls,
|
Dialogs, Forms, Controls, ComCtrls,
|
||||||
// IdeIntf
|
// IdeIntf
|
||||||
@ -45,17 +45,23 @@ type
|
|||||||
private
|
private
|
||||||
FComponentList: TBackupComponentList;
|
FComponentList: TBackupComponentList;
|
||||||
FPropertyEditorHook: TPropertyEditorHook;
|
FPropertyEditorHook: TPropertyEditorHook;
|
||||||
FRootNode: TTreeNode;
|
// Map of Root component -> TAVLTree of collapsed components.
|
||||||
|
FRoot2CollapasedMap: TPointerToPointerTree;
|
||||||
|
FCollapsedComps: TAVLTree; // The current list of collapsed components.
|
||||||
FDrawWholeTree: Boolean;
|
FDrawWholeTree: Boolean;
|
||||||
// Events
|
// Events
|
||||||
FOnComponentGetImageIndex: TCTVGetImageIndexEvent;
|
FOnComponentGetImageIndex: TCTVGetImageIndexEvent;
|
||||||
FOnModified: TNotifyEvent;
|
FOnModified: TNotifyEvent;
|
||||||
function AddOrGetPersNode(AParentNode: TTreeNode; APers: TPersistent;
|
function AddOrGetPersNode(AParentNode: TTreeNode; APers: TPersistent;
|
||||||
ACapt: String): TTreeNode;
|
ACapt: String): TTreeNode;
|
||||||
procedure AddChildren(AComponent: TComponent);
|
procedure AddChildren(AComponent: TComponent; ARootNode: TTreeNode);
|
||||||
function FindAndChange(APers: TPersistent; ZOrderDel: TZOrderDelete): Boolean;
|
function FindAndChange(APers: TPersistent; ZOrderDel: TZOrderDelete): Boolean;
|
||||||
|
function GetRootObject: TPersistent;
|
||||||
function GetSelection: TPersistentSelectionList;
|
function GetSelection: TPersistentSelectionList;
|
||||||
|
procedure NodeCollapsed(Sender: TObject; Node: TTreeNode);
|
||||||
|
procedure NodeExpanded(Sender: TObject; Node: TTreeNode);
|
||||||
procedure RebuildCollection(ANode: TTreeNode);
|
procedure RebuildCollection(ANode: TTreeNode);
|
||||||
|
procedure RestoreExpand(ANode: TTreeNode);
|
||||||
procedure SetPropertyEditorHook(AValue: TPropertyEditorHook);
|
procedure SetPropertyEditorHook(AValue: TPropertyEditorHook);
|
||||||
procedure SetSelection(NewSelection: TPersistentSelectionList);
|
procedure SetSelection(NewSelection: TPersistentSelectionList);
|
||||||
procedure UpdateCompNode(ANode: TTreeNode);
|
procedure UpdateCompNode(ANode: TTreeNode);
|
||||||
@ -608,7 +614,6 @@ procedure TComponentTreeView.SetPropertyEditorHook(AValue: TPropertyEditorHook);
|
|||||||
begin
|
begin
|
||||||
if FPropertyEditorHook=AValue then exit;
|
if FPropertyEditorHook=AValue then exit;
|
||||||
FPropertyEditorHook:=AValue;
|
FPropertyEditorHook:=AValue;
|
||||||
BuildComponentNodes(True);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TComponentTreeView.GetSelection: TPersistentSelectionList;
|
function TComponentTreeView.GetSelection: TPersistentSelectionList;
|
||||||
@ -621,6 +626,7 @@ begin
|
|||||||
inherited Create(TheOwner);
|
inherited Create(TheOwner);
|
||||||
DragMode := dmAutomatic;
|
DragMode := dmAutomatic;
|
||||||
FComponentList:=TBackupComponentList.Create;
|
FComponentList:=TBackupComponentList.Create;
|
||||||
|
FRoot2CollapasedMap:=TPointerToPointerTree.Create;
|
||||||
Options := Options + [tvoAllowMultiselect, tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly];
|
Options := Options + [tvoAllowMultiselect, tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly];
|
||||||
MultiSelectStyle := MultiSelectStyle + [msShiftSelect];
|
MultiSelectStyle := MultiSelectStyle + [msShiftSelect];
|
||||||
ImgIndexForm := IDEImages.GetImageIndex('oi_form');
|
ImgIndexForm := IDEImages.GetImageIndex('oi_form');
|
||||||
@ -633,11 +639,30 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TComponentTreeView.Destroy;
|
destructor TComponentTreeView.Destroy;
|
||||||
|
var
|
||||||
|
Enumer: TPointerToPointerEnumerator;
|
||||||
begin
|
begin
|
||||||
|
Enumer := FRoot2CollapasedMap.GetEnumerator;
|
||||||
|
while Enumer.MoveNext do
|
||||||
|
FreeAndNil(TObject(Enumer.Current^.Value)); // Free the CollapsedComp TAVLTrees.
|
||||||
|
FreeThenNil(FRoot2CollapasedMap);
|
||||||
FreeThenNil(FComponentList);
|
FreeThenNil(FComponentList);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TComponentTreeView.NodeCollapsed(Sender: TObject; Node: TTreeNode);
|
||||||
|
begin
|
||||||
|
Assert(Assigned(FCollapsedComps), 'TComponentTreeView.NodeCollapsed: FCollapsedComps=Nil.');
|
||||||
|
FCollapsedComps.Add(Node.Data);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TComponentTreeView.NodeExpanded(Sender: TObject; Node: TTreeNode);
|
||||||
|
begin
|
||||||
|
Assert(Assigned(FCollapsedComps), 'TComponentTreeView.NodeExpanded: FCollapsedComps=Nil.');
|
||||||
|
if not FCollapsedComps.Remove(Node.Data) then
|
||||||
|
DebugLn(['TComponentTreeView.NodeExpanded: Removing node ', TPersistent(Node.Data), ' failed.']);
|
||||||
|
end;
|
||||||
|
|
||||||
function TComponentTreeView.AddOrGetPersNode(AParentNode: TTreeNode;
|
function TComponentTreeView.AddOrGetPersNode(AParentNode: TTreeNode;
|
||||||
APers: TPersistent; ACapt: String): TTreeNode;
|
APers: TPersistent; ACapt: String): TTreeNode;
|
||||||
var
|
var
|
||||||
@ -664,13 +689,13 @@ begin
|
|||||||
Result.MultiSelected := Selection.IndexOf(APers) >= 0;
|
Result.MultiSelected := Selection.IndexOf(APers) >= 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TComponentTreeView.AddChildren(AComponent: TComponent);
|
procedure TComponentTreeView.AddChildren(AComponent: TComponent; ARootNode: TTreeNode);
|
||||||
var
|
var
|
||||||
Walker: TComponentWalker;
|
Walker: TComponentWalker;
|
||||||
begin
|
begin
|
||||||
if csDestroying in AComponent.ComponentState then exit;
|
if csDestroying in AComponent.ComponentState then exit;
|
||||||
Walker := TComponentWalker.Create(Self, AComponent);
|
Walker := TComponentWalker.Create(Self, AComponent);
|
||||||
Walker.FNode := FRootNode;
|
Walker.FNode := ARootNode;
|
||||||
try // add inline components children
|
try // add inline components children
|
||||||
TComponentAccessor(AComponent).GetChildren(@Walker.Walk, AComponent);
|
TComponentAccessor(AComponent).GetChildren(@Walker.Walk, AComponent);
|
||||||
finally
|
finally
|
||||||
@ -678,34 +703,65 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TComponentTreeView.GetRootObject: TPersistent;
|
||||||
|
// Get root object / component
|
||||||
|
begin
|
||||||
|
if PropertyEditorHook = nil then Exit(nil);
|
||||||
|
Result := PropertyEditorHook.LookupRoot;
|
||||||
|
if (Result is TComponent) and (csDestroying in TComponent(Result).ComponentState) then
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TComponentTreeView.BuildComponentNodes(AWholeTree: Boolean);
|
procedure TComponentTreeView.BuildComponentNodes(AWholeTree: Boolean);
|
||||||
// Add all components to the tree.
|
// Add all components to the tree.
|
||||||
// AWholeTree=True means clearing and refilling all,
|
// AWholeTree=True means clearing and refilling all,
|
||||||
// False means existing tree is used and only missing components are added.
|
// False means existing tree is used and only missing components are added.
|
||||||
var
|
var
|
||||||
RootObject: TPersistent;
|
RootObject: TPersistent;
|
||||||
RootComponent: TComponent absolute RootObject;
|
RootNode: TTreeNode;
|
||||||
begin
|
begin
|
||||||
|
OnCollapsed:=nil; // Don't handle these events while the tree builds.
|
||||||
|
OnExpanded:=nil;
|
||||||
BeginUpdate;
|
BeginUpdate;
|
||||||
FDrawWholeTree := AWholeTree;
|
RootObject := GetRootObject;
|
||||||
if AWholeTree then
|
if AWholeTree then
|
||||||
Items.Clear;
|
Items.Clear;
|
||||||
RootObject := nil;
|
|
||||||
if PropertyEditorHook<>nil then
|
|
||||||
RootObject := PropertyEditorHook.LookupRoot;
|
|
||||||
if (RootObject is TComponent) and (csDestroying in RootComponent.ComponentState) then
|
|
||||||
RootObject:=nil;
|
|
||||||
if RootObject <> nil then
|
if RootObject <> nil then
|
||||||
begin // first add the lookup root
|
begin
|
||||||
FRootNode := AddOrGetPersNode(nil, RootObject, CreateNodeCaption(RootObject,''));
|
//DebugLn(['TComponentTreeView.BuildComponentNodes: RootObj=', RootObject, ', AWholeTree=', AWholeTree]);
|
||||||
|
FDrawWholeTree := AWholeTree;
|
||||||
|
// first add the lookup root
|
||||||
|
RootNode := AddOrGetPersNode(nil, RootObject, CreateNodeCaption(RootObject,''));
|
||||||
// add components in creation order and TControl.Parent relationship
|
// add components in creation order and TControl.Parent relationship
|
||||||
if RootObject is TComponent then
|
if RootObject is TComponent then
|
||||||
AddChildren(RootComponent);
|
AddChildren(TComponent(RootObject), RootNode);
|
||||||
if AWholeTree then // Don't expand existing tree as a user
|
if AWholeTree then
|
||||||
FRootNode.Expand(true); // may want to have some nodes collapsed.
|
begin
|
||||||
|
// Get the right list of collapsed nodes based on LookupRoot
|
||||||
|
FCollapsedComps := TAVLTree(FRoot2CollapasedMap[RootObject]);
|
||||||
|
if FCollapsedComps = nil then
|
||||||
|
begin
|
||||||
|
FCollapsedComps := TAVLTree.Create;
|
||||||
|
FRoot2CollapasedMap[RootObject] := FCollapsedComps;
|
||||||
|
end;
|
||||||
|
RestoreExpand(RootNode); // then restore the Expanded/Collapsed state.
|
||||||
|
end;
|
||||||
|
MakeSelectionVisible;
|
||||||
end;
|
end;
|
||||||
MakeSelectionVisible;
|
|
||||||
EndUpdate;
|
EndUpdate;
|
||||||
|
OnCollapsed:=@NodeCollapsed;
|
||||||
|
OnExpanded:=@NodeExpanded;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TComponentTreeView.RestoreExpand(ANode: TTreeNode);
|
||||||
|
// Restore Expanded/Collapsed state based on user's choice from last time.
|
||||||
|
begin
|
||||||
|
ANode.Expanded := FCollapsedComps.Find(ANode.Data) = Nil; // Nil means a user
|
||||||
|
ANode := ANode.GetFirstChild; // did not collapse the node last time.
|
||||||
|
while ANode<>nil do begin
|
||||||
|
RestoreExpand(ANode); // Recursive call.
|
||||||
|
ANode := ANode.GetNextSibling;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TComponentTreeView.RebuildCollection(ANode: TTreeNode);
|
procedure TComponentTreeView.RebuildCollection(ANode: TTreeNode);
|
||||||
@ -716,7 +772,7 @@ begin
|
|||||||
begin
|
begin
|
||||||
if TObject(ANode.Data) is TOwnedCollection then
|
if TObject(ANode.Data) is TOwnedCollection then
|
||||||
begin
|
begin
|
||||||
DebugLn(['IterateTree: Rebuilding Collection node ', TOwnedCollection(ANode.Data)]);
|
DebugLn(['TComponentTreeView.RebuildCollection: Node ', TOwnedCollection(ANode.Data)]);
|
||||||
ANode.DeleteChildren;
|
ANode.DeleteChildren;
|
||||||
BuildComponentNodes(False);
|
BuildComponentNodes(False);
|
||||||
ANode.Expand(False);
|
ANode.Expand(False);
|
||||||
|
|||||||
@ -4519,16 +4519,13 @@ begin
|
|||||||
if FPropertyEditorHook.LookupRoot is TComponent then
|
if FPropertyEditorHook.LookupRoot is TComponent then
|
||||||
FSelection.Add(TComponent(FPropertyEditorHook.LookupRoot));
|
FSelection.Add(TComponent(FPropertyEditorHook.LookupRoot));
|
||||||
end;
|
end;
|
||||||
end else begin
|
end
|
||||||
// the OI gets the selection from the propertyeditorhook
|
else
|
||||||
Selection := OldSelection;
|
Selection := OldSelection; // OI gets the selection from propertyeditorhook
|
||||||
end;
|
|
||||||
finally
|
finally
|
||||||
OldSelection.Free;
|
OldSelection.Free;
|
||||||
end;
|
end;
|
||||||
FillComponentList(True);
|
|
||||||
ComponentTree.PropertyEditorHook:=FPropertyEditorHook;
|
ComponentTree.PropertyEditorHook:=FPropertyEditorHook;
|
||||||
RefreshSelection;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user