mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-09 06:38:15 +02:00
LCL/ShellCtrls: Add method UpdateView to TShellTreeView and TShellListView which updates these controls and keeps the selection and the expanded nodes. Based on patch by tcrass (https://forum.lazarus.freepascal.org/index.php/topic,65100.msg495622.html).
This commit is contained in:
parent
2113ad4fef
commit
8fa26c3c71
@ -110,6 +110,7 @@ type
|
|||||||
function CanExpand(Node: TTreeNode): Boolean; override;
|
function CanExpand(Node: TTreeNode): Boolean; override;
|
||||||
procedure Collapse(Node: TTreeNode); override;
|
procedure Collapse(Node: TTreeNode); override;
|
||||||
function DrawBuiltInIcon(ANode: TTreeNode; ARect: TRect): TSize; override;
|
function DrawBuiltInIcon(ANode: TTreeNode; ARect: TRect): TSize; override;
|
||||||
|
function Exists(APath: String): Boolean;
|
||||||
function GetBuiltinIconSize: TSize; override;
|
function GetBuiltinIconSize: TSize; override;
|
||||||
function NodeHasChildren(Node: TTreeNode): Boolean; override;
|
function NodeHasChildren(Node: TTreeNode): Boolean; override;
|
||||||
property ExpandCollapseMode: TExpandCollapseMode read FExpandCollapseMode write FExpandCollapseMode default ecmRefreshedExpanding;
|
property ExpandCollapseMode: TExpandCollapseMode read FExpandCollapseMode write FExpandCollapseMode default ecmRefreshedExpanding;
|
||||||
@ -125,6 +126,7 @@ type
|
|||||||
function GetPathFromNode(ANode: TTreeNode): string;
|
function GetPathFromNode(ANode: TTreeNode): string;
|
||||||
procedure PopulateWithBaseFiles;
|
procedure PopulateWithBaseFiles;
|
||||||
procedure Refresh(ANode: TTreeNode); overload;
|
procedure Refresh(ANode: TTreeNode); overload;
|
||||||
|
procedure UpdateView;
|
||||||
property UseBuiltinIcons: Boolean read FUseBuiltinIcons write SetUseBuiltinIcons default true;
|
property UseBuiltinIcons: Boolean read FUseBuiltinIcons write SetUseBuiltinIcons default true;
|
||||||
|
|
||||||
{ Properties }
|
{ Properties }
|
||||||
@ -257,6 +259,7 @@ type
|
|||||||
FRoot: string;
|
FRoot: string;
|
||||||
FShellTreeView: TCustomShellTreeView;
|
FShellTreeView: TCustomShellTreeView;
|
||||||
FUseBuiltInIcons: Boolean;
|
FUseBuiltInIcons: Boolean;
|
||||||
|
FLockUpdate: Integer;
|
||||||
FOnAddItem: TAddItemEvent;
|
FOnAddItem: TAddItemEvent;
|
||||||
FOnFileAdded: TCSLVFileAddedEvent;
|
FOnFileAdded: TCSLVFileAddedEvent;
|
||||||
{ Setters and getters }
|
{ Setters and getters }
|
||||||
@ -282,6 +285,7 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
{ Methods specific to Lazarus }
|
{ Methods specific to Lazarus }
|
||||||
function GetPathFromItem(ANode: TListItem): string;
|
function GetPathFromItem(ANode: TListItem): string;
|
||||||
|
procedure UpdateView;
|
||||||
{ Properties }
|
{ Properties }
|
||||||
property AutoSizeColumns: Boolean read FAutoSizeColumns write SetAutoSizeColumns default true;
|
property AutoSizeColumns: Boolean read FAutoSizeColumns write SetAutoSizeColumns default true;
|
||||||
property Mask: string read FMask write SetMask; // Can be used to conect to other controls
|
property Mask: string read FMask write SetMask; // Can be used to conect to other controls
|
||||||
@ -1231,11 +1235,113 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomShellTreeView.UpdateView;
|
||||||
|
|
||||||
|
procedure RecordNodeState(const ANode: TTreeNode; const AExpandedPaths: TStringList);
|
||||||
|
var
|
||||||
|
currentNode: TTreeNode;
|
||||||
|
firstChild: TTreeNode;
|
||||||
|
begin
|
||||||
|
currentNode := ANode;
|
||||||
|
while currentNode <> nil do
|
||||||
|
begin
|
||||||
|
if currentNode.Expanded then
|
||||||
|
begin
|
||||||
|
AExpandedPaths.Add(GetPathFromNode(currentNode));
|
||||||
|
firstChild := currentNode.GetFirstChild();
|
||||||
|
if firstChild <> nil then
|
||||||
|
RecordNodeState(firstChild, AExpandedPaths);
|
||||||
|
end;
|
||||||
|
currentNode := currentNode.GetNextSibling();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure RestoreNodeState(const ANode: TTreeNode; const ARefresh: boolean;
|
||||||
|
const AExpandedPaths: TStringList);
|
||||||
|
var
|
||||||
|
currentNode: TTreeNode;
|
||||||
|
firstChild: TTreeNode;
|
||||||
|
begin
|
||||||
|
currentNode := ANode;
|
||||||
|
while currentNode <> nil do
|
||||||
|
begin
|
||||||
|
if AExpandedPaths.IndexOf(GetPathFromNode(currentNode)) >= 0 then
|
||||||
|
begin
|
||||||
|
currentNode.Expanded := True;
|
||||||
|
if ARefresh then
|
||||||
|
Refresh(currentNode);
|
||||||
|
firstChild := currentNode.GetFirstChild();
|
||||||
|
if firstChild <> nil then
|
||||||
|
RestoreNodeState(firstChild, ARefresh, AExpandedPaths);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
currentNode.Expanded := False;
|
||||||
|
currentNode := currentNode.GetNextSibling();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
node: TTreeNode;
|
||||||
|
topNodePath: String;
|
||||||
|
selectedPath: String;
|
||||||
|
selectedWasExpanded: Boolean = false;
|
||||||
|
expandedPaths: TStringList;
|
||||||
|
begin
|
||||||
|
expandedPaths := TStringList.Create;
|
||||||
|
Items.BeginUpdate;
|
||||||
|
try
|
||||||
|
topNodePath := ChompPathDelim(GetPathFromNode(TopItem));
|
||||||
|
selectedPath := GetPathFromNode(Selected);
|
||||||
|
if Assigned(Selected) then
|
||||||
|
selectedWasExpanded := Selected.Expanded;
|
||||||
|
|
||||||
|
node := Items.GetFirstNode;
|
||||||
|
RecordNodeState(node, expandedPaths);
|
||||||
|
RestoreNodeState(node, true, expandedPaths);
|
||||||
|
|
||||||
|
if Exists(selectedPath) then
|
||||||
|
begin
|
||||||
|
Path := selectedPath;
|
||||||
|
// Setting the path expands the selected node --> apply the stored state.
|
||||||
|
Selected.Expanded := selectedWasExpanded;
|
||||||
|
// Avoid selected node to scroll away.
|
||||||
|
TopItem := Items.FindNodeWithTextPath(topNodePath);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Force synchronization of associated ShellListView
|
||||||
|
if Assigned(FShellListView) then
|
||||||
|
FShellListView.UpdateView;
|
||||||
|
finally
|
||||||
|
Items.EndUpdate;
|
||||||
|
expandedPaths.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TCustomShellTreeView.GetPath: string;
|
function TCustomShellTreeView.GetPath: string;
|
||||||
begin
|
begin
|
||||||
Result := GetPathFromNode(Selected);
|
Result := GetPathFromNode(Selected);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TCustomShellTreeView.Exists(APath: String): Boolean;
|
||||||
|
// APath should be fully qualified
|
||||||
|
var
|
||||||
|
Attr: LongInt;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
Attr := FileGetAttrUtf8(APath);
|
||||||
|
{$ifdef debug_shellctrls}
|
||||||
|
debugln(['TCustomShellTreeView.SetPath.Exists: Attr = ', Attr]);
|
||||||
|
{$endif}
|
||||||
|
if (Attr = -1) then Exit;
|
||||||
|
if not (otNonFolders in FObjectTypes) then
|
||||||
|
Result := ((Attr and faDirectory) > 0)
|
||||||
|
else
|
||||||
|
Result := True;
|
||||||
|
{$ifdef debug_shellctrls}
|
||||||
|
debugln(['TCustomShellTreeView.SetPath.Exists: Result = ',Result]);
|
||||||
|
{$endif}
|
||||||
|
end;
|
||||||
|
|
||||||
{
|
{
|
||||||
SetPath: Path can be
|
SetPath: Path can be
|
||||||
- Absolute like '/usr/lib'
|
- Absolute like '/usr/lib'
|
||||||
@ -1265,28 +1371,6 @@ var
|
|||||||
else Result := ANode.Text;
|
else Result := ANode.Text;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function Exists(Fn: String): Boolean;
|
|
||||||
//Fn should be fully qualified
|
|
||||||
var
|
|
||||||
Attr: LongInt;
|
|
||||||
Dirs: TStringList;
|
|
||||||
i: Integer;
|
|
||||||
begin
|
|
||||||
Result := False;
|
|
||||||
Attr := FileGetAttrUtf8(Fn);
|
|
||||||
{$ifdef debug_shellctrls}
|
|
||||||
debugln(['TCustomShellTreeView.SetPath.Exists: Attr = ', Attr]);
|
|
||||||
{$endif}
|
|
||||||
if (Attr = -1) then Exit;
|
|
||||||
if not (otNonFolders in FObjectTypes) then
|
|
||||||
Result := ((Attr and faDirectory) > 0)
|
|
||||||
else
|
|
||||||
Result := True;
|
|
||||||
{$ifdef debug_shellctrls}
|
|
||||||
debugln(['TCustomShellTreeView.SetPath.Exists: Result = ',Result]);
|
|
||||||
{$endif}
|
|
||||||
end;
|
|
||||||
|
|
||||||
function PathIsDriveRoot({%H-}Path: String): Boolean; {$if not (defined(windows) and not defined(wince))}inline;{$endif}
|
function PathIsDriveRoot({%H-}Path: String): Boolean; {$if not (defined(windows) and not defined(wince))}inline;{$endif}
|
||||||
//WinNT filesystem reports faHidden on all physical drive-roots (e.g. C:\)
|
//WinNT filesystem reports faHidden on all physical drive-roots (e.g. C:\)
|
||||||
begin
|
begin
|
||||||
@ -1808,6 +1892,28 @@ begin
|
|||||||
Result := IncludeTrailingPathDelimiter(FRoot) + ANode.Caption;
|
Result := IncludeTrailingPathDelimiter(FRoot) + ANode.Caption;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomShellListView.UpdateView;
|
||||||
|
var
|
||||||
|
selectedItem: String = '';
|
||||||
|
begin
|
||||||
|
if (FLockUpdate = 0) then
|
||||||
|
begin
|
||||||
|
if Assigned(Selected) then
|
||||||
|
selectedItem := Selected.Caption;
|
||||||
|
Clear;
|
||||||
|
PopulateWithRoot;
|
||||||
|
if selectedItem <> '' then
|
||||||
|
Selected := FindCaption(0, selectedItem, false, true, false);
|
||||||
|
|
||||||
|
inc(FLockUpdate);
|
||||||
|
try
|
||||||
|
ShellTreeView.UpdateView;
|
||||||
|
finally
|
||||||
|
dec(FLockUpdate);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
class procedure TCustomShellListView.WSRegisterClass;
|
class procedure TCustomShellListView.WSRegisterClass;
|
||||||
begin
|
begin
|
||||||
inherited WSRegisterClass;
|
inherited WSRegisterClass;
|
||||||
|
Loading…
Reference in New Issue
Block a user