IdeIntf, Designer: Improve deleting components from OI's tree. Make a special case for PairSplitterSide. Issue #38235.

git-svn-id: trunk@64254 -
This commit is contained in:
juha 2020-12-20 14:46:02 +00:00
parent da1542668b
commit deba76613b
6 changed files with 119 additions and 91 deletions

View File

@ -47,16 +47,13 @@ type
FPropertyEditorHook: TPropertyEditorHook;
FRootNode: TTreeNode;
FDrawWholeTree: Boolean;
// A Component (Persistent) to be moved or deleted based on FZOrderDelete value.
FPersToChange: TPersistent;
FZOrderDelete: TZOrderDelete;
// Events
FOnComponentGetImageIndex: TCTVGetImageIndexEvent;
FOnModified: TNotifyEvent;
function AddOrGetPersNode(AParentNode: TTreeNode; APers: TPersistent;
ACapt: String): TTreeNode;
procedure AddChildren(AComponent: TComponent);
procedure ChangeNode(ANode: TTreeNode);
function FindAndChange(APers: TPersistent; ZOrderDel: TZOrderDelete): Boolean;
function GetSelection: TPersistentSelectionList;
procedure SetPropertyEditorHook(AValue: TPropertyEditorHook);
procedure SetSelection(NewSelection: TPersistentSelectionList);
@ -212,15 +209,18 @@ var
TVNode: TTreeNode;
TheRoot: TPersistent;
begin
if (APers is TComponent)
and (csDestroying in TComponent(APers).ComponentState) then Exit;
if (APers is TComponent) then
Assert(not (csDestroying in TComponent(APers).ComponentState), 'TComponentWalker: Comp is Destroying.');
TheRoot := GetLookupRootForComponent(APers);
{$IFDEF VerboseComponentTVWalker}
DebugLn(['TComponentWalker.AddOwnedPersistent'+
' PropName=',APropName,' Persistent=',DbgSName(APers),
' its root=',DbgSName(TheRoot),' FLookupRoot=',DbgSName(FLookupRoot)]);
{$ENDIF}
if TheRoot <> FLookupRoot then Exit;
if TheRoot <> FLookupRoot then begin
DebugLn(['TComponentWalker.AddOwnedPersistent: TheRoot "', TheRoot, '" <> FLookupRoot "', FLookupRoot, '"']);
Exit;
end;
TVNode := FCompTV.AddOrGetPersNode(AParentNode, APers, CreateNodeCaption(APers, APropName));
if APers is TCollection then
AddCollection(TCollection(APers), TVNode);
@ -261,8 +261,14 @@ var
OldNode: TTreeNode;
Root: TComponent;
begin
if csDestroying in AComponent.ComponentState then exit;
if GetLookupRootForComponent(AComponent) <> FLookupRoot then Exit;
if csDestroying in AComponent.ComponentState then begin
DebugLn(['TComponentWalker.Walk: ', AComponent, ' is Destroying.']);
Exit;
end;
if GetLookupRootForComponent(AComponent) <> FLookupRoot then begin
DebugLn(['TComponentWalker.Walk: "', AComponent, '" LookupRoot <> FLookupRoot "', FLookupRoot, '"']);
Exit;
end;
OldNode := FNode;
FNode := FCompTV.AddOrGetPersNode(FNode, AComponent, ComponentCaption(AComponent));
GetOwnedPersistents(AComponent, FNode);
@ -631,37 +637,6 @@ begin
inherited Destroy;
end;
procedure TComponentTreeView.ChangeNode(ANode: TTreeNode);
// A node matching FPersToChange was found. Change its ZOrder or delete it.
var
Neighbor: TTreeNode;
begin
case FZOrderDelete of
zoToFront: begin // Front means the last sibling.
Neighbor := ANode.GetLastSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsertBehind);
end;
zoToBack: begin // Back means the first sibling.
Neighbor := ANode.GetFirstSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsert);
end;
zoForward: begin // Towards the end.
Neighbor := ANode.GetNextSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsertBehind);
end;
zoBackward: begin // Towards the beginning.
Neighbor := ANode.GetPrevSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsert);
end;
zoDelete: ANode.Delete; // Delete the node
end;
FPersToChange := nil; // No need to search again in the next round.
end;
function TComponentTreeView.AddOrGetPersNode(AParentNode: TTreeNode;
APers: TPersistent; ACapt: String): TTreeNode;
var
@ -671,15 +646,6 @@ begin
begin
if AParentNode = nil then
Exit(Items.GetFirstNode); // Return existing root node.
// Search for a node to change.
if Assigned(FPersToChange) then
begin
xNode := AParentNode.GetFirstChild;
while (xNode<>nil) and (TObject(xNode.Data)<>FPersToChange) do
xNode := xNode.GetNextSibling;
if Assigned(xNode) then
ChangeNode(xNode);
end;
// Search for an existing valid node.
xNode := AParentNode.GetFirstChild;
while (xNode<>nil) and (TObject(xNode.Data)<>APers) do
@ -741,19 +707,76 @@ begin
EndUpdate;
end;
function TComponentTreeView.FindAndChange(APers: TPersistent;
ZOrderDel: TZOrderDelete): Boolean;
// APers is Component to be moved or deleted based on ZOrderDel value.
procedure ChangeNode(ANode: TTreeNode);
// Change ZOrder of the given node or delete it.
var
Neighbor: TTreeNode;
begin
case ZOrderDel of
zoToFront: begin // Front means the last sibling.
Neighbor := ANode.GetLastSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsertBehind);
end;
zoToBack: begin // Back means the first sibling.
Neighbor := ANode.GetFirstSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsert);
end;
zoForward: begin // Towards the end.
Neighbor := ANode.GetNextSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsertBehind);
end;
zoBackward: begin // Towards the beginning.
Neighbor := ANode.GetPrevSibling;
if Assigned(Neighbor) then
ANode.MoveTo(Neighbor, naInsert);
end;
zoDelete: ANode.Delete; // Delete the node
end;
end;
function IterateTree(ANode: TTreeNode): Boolean;
begin
if TObject(ANode.Data)=APers then
begin
ChangeNode(ANode);
Exit(True); // Found and changed.
end;
ANode := ANode.GetFirstChild;
while ANode<>nil do
begin
Result := IterateTree(ANode); // Recursive call.
if Result then Exit; // Found in a child item. Don't search more.
ANode := ANode.GetNextSibling;
end;
Result := False;
end;
begin
// Search for a node to change.
Assert(Assigned(APers), 'TComponentTreeView.FindAndChangeItem: APers=Nil.');
Assert(Items.GetFirstNode.GetNextSibling=Nil,
'TComponentTreeView.FindAndChange: Top node has siblings.');
Result := IterateTree(Items.GetFirstNode);
end;
procedure TComponentTreeView.ChangeCompZOrder(APersistent: TPersistent;
AZOrder: TZOrderDelete);
begin
FPersToChange := APersistent;
FZOrderDelete := AZOrder;
BuildComponentNodes(False);
if not FindAndChange(APersistent, AZOrder) then
DebugLn(['TComponentTreeView.ChangeCompZOrder failed.']);
end;
procedure TComponentTreeView.DeleteComponentNode(APersistent: TPersistent);
begin
FPersToChange := APersistent;
FZOrderDelete := zoDelete;
BuildComponentNodes(False);
if not FindAndChange(APersistent, zoDelete) then
DebugLn(['TComponentTreeView.DeleteComponentNode failed.']);
end;
procedure TComponentTreeView.UpdateCompNode(ANode: TTreeNode);

View File

@ -4623,8 +4623,12 @@ end;
procedure TObjectInspectorDlg.DeleteCompFromList(APersistent: TPersistent);
begin
if FShowComponentTree then
ComponentTree.DeleteComponentNode(APersistent)
if FShowComponentTree then begin
if APersistent=nil then
ComponentTree.BuildComponentNodes(True)
else
ComponentTree.DeleteComponentNode(APersistent);
end
else
FillPersistentComboBox;
end;
@ -4652,7 +4656,6 @@ var
OldText: AnsiString;
NewList: TStringList;
begin
DebugLn('TObjectInspectorDlg.FillPersistentComboBox: Updating ComboBox with components');
Assert(not FUpdatingAvailComboBox,
'TObjectInspectorDlg.FillPersistentComboBox: Updating Avail ComboBox');
//if FUpdatingAvailComboBox then exit;

View File

@ -2989,6 +2989,7 @@ end;
procedure TDesigner.DoDeletePersistent(APersistent: TPersistent; FreeIt: boolean);
var
Hook: TPropertyEditorHook;
Special: Boolean;
begin
if APersistent=nil then exit;
Include(FFlags, dfDuringDeletePers);
@ -3012,17 +3013,22 @@ begin
end;
// call component deleting handlers
Hook:=GetPropertyEditorHook;
if Hook<>nil then
if Assigned(Hook) then
Hook.PersistentDeleting(APersistent);
Special:=(APersistent is TWinControl) and TWinControl(APersistent).IsSpecialSubControl;
// delete component
if APersistent is TComponent then
TheFormEditor.DeleteComponent(TComponent(APersistent),FreeIt)
else if FreeIt then
APersistent.Free;
// call ComponentDeleted handler
if Assigned(FOnPersistentDeleted) then
FOnPersistentDeleted(Self,APersistent);
if Hook<>nil then
if Assigned(FOnPersistentDeleted) then begin
if Special then // Special treatment is now needed only for TPairSplitterSide.
FOnPersistentDeleted(Self,nil) // Will rebuild whole OI Tree.
else
FOnPersistentDeleted(Self,APersistent);
end;
if Assigned(Hook) then
Hook.PersistentDeleted;
finally
// unmark component

View File

@ -1946,7 +1946,9 @@ type
wcfUpdateShowing,
wcfHandleVisible,
wcfAdjustedLogicalClientRectValid,
wcfKillIntfSetBounds
wcfKillIntfSetBounds,
wcfDesignerDeleting, // Only used for PairSplitter which should be redesigned
wcfSpecialSubControl // Only set by PairSplitterSide
);
TWinControlFlags = set of TWinControlFlag;
@ -2032,7 +2034,6 @@ type
FShowing: Boolean;
FDockSite: Boolean;
FUseDockManager: Boolean;
FDesignerDeleting: Boolean;
procedure AlignControl(AControl: TControl);
function DoubleBufferedIsStored: Boolean;
function GetBrush: TBrush;
@ -2042,9 +2043,11 @@ type
function GetDockClients(Index: Integer): TControl;
function GetHandle: HWND;
function GetIsResizing: boolean;
function GetIsSpecialSubControl: Boolean;
function GetTabOrder: TTabOrder;
function GetVisibleDockClientCount: Integer;
procedure SetChildSizing(const AValue: TControlChildSizing);
procedure SetDesignerDeleting(AValue: Boolean);
procedure SetDockSite(const NewDockSite: Boolean);
procedure SetDoubleBuffered(Value: Boolean);
procedure SetHandle(NewHandle: HWND);
@ -2274,7 +2277,8 @@ type
property Showing: Boolean read FShowing; // handle visible
property UseDockManager: Boolean read FUseDockManager
write SetUseDockManager default False;
property DesignerDeleting: Boolean read FDesignerDeleting write FDesignerDeleting;
property DesignerDeleting: Boolean write SetDesignerDeleting;
property IsSpecialSubControl: Boolean read GetIsSpecialSubControl;
property VisibleDockClientCount: Integer read GetVisibleDockClientCount;
public
// size, position, bounds

View File

@ -6470,17 +6470,11 @@ begin
Result := Control = Self;
end;
{------------------------------------------------------------------------------
TWinControl GetBorderStyle
------------------------------------------------------------------------------}
function TWinControl.GetBorderStyle: TBorderStyle;
begin
Result := TBorderStyle(FBorderStyle);
end;
{------------------------------------------------------------------------------
TWinControl GetBrush
------------------------------------------------------------------------------}
function TWinControl.GetBrush: TBrush;
begin
if not BrushCreated then
@ -6488,17 +6482,11 @@ begin
Result := FBrush;
end;
{------------------------------------------------------------------------------
TWinControl GetControl
------------------------------------------------------------------------------}
function TWinControl.GetControl(const Index: Integer): TControl;
begin
Result := TControl(FControls[Index]);
end;
{------------------------------------------------------------------------------
TWinControl GetControlCount
------------------------------------------------------------------------------}
function TWinControl.GetControlCount: Integer;
begin
if FControls <> nil then
@ -6523,9 +6511,6 @@ begin
Result := nil;
end;
{------------------------------------------------------------------------------
TWinControl GetHandle
------------------------------------------------------------------------------}
function TWinControl.GetHandle: HWND;
begin
//if not HandleAllocated then DebugLn('TWinControl.GetHandle Creating handle on the fly: ',DbgSName(Self));
@ -8004,9 +7989,11 @@ begin
Result:=BoundsLockCount>0;
end;
{------------------------------------------------------------------------------
function TWinControl.GetTabOrder: TTabOrder;
------------------------------------------------------------------------------}
function TWinControl.GetIsSpecialSubControl: Boolean;
begin
Result := wcfSpecialSubControl in FWinControlFlags;
end;
function TWinControl.GetTabOrder: TTabOrder;
begin
if FParent <> nil then
@ -8015,9 +8002,6 @@ begin
Result := FTabOrder;
end;
{------------------------------------------------------------------------------
function TWinControl.GetVisibleDockClientCount: Integer;
------------------------------------------------------------------------------}
function TWinControl.GetVisibleDockClientCount: Integer;
var
i: integer;
@ -8028,15 +8012,20 @@ begin
if TControl(FDockClients[I]).Visible then inc(Result);
end;
{------------------------------------------------------------------------------
procedure TWinControl.SetChildSizing(const AValue: TControlChildSizing);
------------------------------------------------------------------------------}
procedure TWinControl.SetChildSizing(const AValue: TControlChildSizing);
begin
if (FChildSizing=AValue) then exit;
FChildSizing.Assign(AValue);
end;
procedure TWinControl.SetDesignerDeleting(AValue: Boolean);
begin
if AValue then
Include(FWinControlFlags, wcfDesignerDeleting)
else
Exclude(FWinControlFlags, wcfDesignerDeleting);
end;
{------------------------------------------------------------------------------
procedure TWinControl.SetDockSite(const NewDockSite: Boolean);

View File

@ -191,7 +191,8 @@ begin
ASplitter := Splitter;
if ASplitter <> nil then begin
ASplitter.RemoveSide(Self);
DeletingSplitter := (csDestroying in ASplitter.ComponentState) or DesignerDeleting;
DeletingSplitter := (csDestroying in ASplitter.ComponentState)
or (wcfDesignerDeleting in FWinControlFlags);
end
else
DeletingSplitter := False;
@ -238,6 +239,8 @@ begin
inherited Create(TheOwner);
FCompStyle := csPairSplitterSide;
ControlStyle := ControlStyle + [csAcceptsControls];
// A flag custom made for TPairSplitterSide.
Include(FWinControlFlags, wcfSpecialSubControl);
end;
destructor TPairSplitterSide.Destroy;
@ -334,7 +337,7 @@ begin
end;
// if the user deletes a side at designtime, autocreate a new one
if (ComponentState * [csDesigning,csDestroying] = [csDesigning])
and not DesignerDeleting then
and not (wcfDesignerDeleting in FWinControlFlags) then
CreateSides;
end;