Scenario
I'm trying to duplicate the standard way to fill a Treeview with directories/folders from a folder structure, starting at the root, but using IdFTP to get the structure from a remote server instead of my local hard drive. I'd like the result to look similar to clients like Filezilla.
I used this reasonably standard code from the Swiss Delphi Centre (which works to display my hard drive's structure) and then modified it to use IdFTP.ChangeDir(Directory) and IdFTP.List instead of FindFirst() and FindNext().
Problem
I seem to have got myself in a muddle as it is not correctly 'unwinding' the recursion so that once it traverses down the /cpanel/cashes/config directories on the remote server it doesn't return and traverse all the other directories hanging off the root but exits the procedure without displaying anything else. Also it doesn't seem to show all the top level folders but this could be simply due to the order that IdFTP.List returns them in
Can anyone tell me what I have done wrong here?
If you can also tell me how I should get the root (/) shown as well that would be very helpful
(I've commented out displaying non directories as I only want folders at this stage)
What I expected to see Copied from Filezilla
What I did see Using a Ttreeview in Delphi
My Code
procedure TForm2.Button1Click(Sender: TObject);
var StartingDir : string;
begin
TreeView1.Items.BeginUpdate;
try
StartingDir := '/';
Screen.Cursor := crHourGlass;
TreeView1.Items.Clear;
FTPconnect; //procedure to connect to remote server
GetDirectories(TreeView1, StartingDir, nil, True);
FTPDisconnect; //procedure to disconnect from remote server
finally
TreeView1.Items.EndUpdate;
Screen.Cursor := crDefault;
end;
end;
procedure TForm2.GetDirectories(Tree: TTreeView; Directory: string; Item: TTreeNode; IncludeFiles: Boolean);
var
ItemTemp: TTreeNode;
DirItemType : TIdDirItemType ;
Filename , NewStartingDirectory: string;
i : Integer;
begin
Tree.Items.BeginUpdate;
IdFTP.ChangeDir(Directory);
IdFTP.List; //get directory of remote folder
i:=0;
repeat
DirItemType := IdFTP.DirectoryListing[I].ItemType;
Filename := IdFTP.DirectoryListing[I].FileName;
If (DirItemType = ditDirectory) and (Filename <> '.') and (Filename <> '..')then
begin
if DirItemType = ditDirectory then
Item := Tree.Items.AddChild(Item, Filename);
ItemTemp := Item.Parent;
if Directory = '/' then
NewStartingDirectory := Directory + Filename
else
NewStartingDirectory := Directory + '/' +Filename;
GetDirectories(Tree, NewStartingDirectory, Item, IncludeFiles);
Item := ItemTemp;
end
else
if IncludeFiles then
begin //this bit commented out as we only want to see directories
// if (Filename <> '.') and (Filename <> '..') then
// Tree.Items.AddChild(Item, Filename);
end;
inc(i);
until i = IdFTP.DirectoryListing.Count;
Tree.Items.EndUpdate;
end;
Swiss Delhpi Centre's code (for comparison)
procedure TForm1.Button1Click(Sender: TObject);
var
Node: TTreeNode;
Path: string;
Dir: string;
begin
Dir := 'c:\temp';
Screen.Cursor := crHourGlass;
TreeView1.Items.BeginUpdate;
try
TreeView1.Items.Clear;
GetDirectories(TreeView1, Dir, nil, True);
finally
Screen.Cursor := crDefault;
TreeView1.Items.EndUpdate;
end;
end;
procedure TForm1.GetDirectories(Tree: TTreeView; Directory: string; Item: TTreeNode; IncludeFiles: Boolean);
var
SearchRec: TSearchRec;
ItemTemp: TTreeNode;
begin
Tree.Items.BeginUpdate;
if Directory[Length(Directory)] <> '\' then Directory := Directory + '\';
if FindFirst(Directory + '*.*', faDirectory, SearchRec) = 0 then
begin
repeat
if (SearchRec.Attr and faDirectory = faDirectory) and (SearchRec.Name[1] <> '.') then
begin
if (SearchRec.Attr and faDirectory > 0) then
Item := Tree.Items.AddChild(Item, SearchRec.Name);
ItemTemp := Item.Parent;
GetDirectories(Tree, Directory + SearchRec.Name, Item, IncludeFiles);
Item := ItemTemp;
end
else if IncludeFiles then
if SearchRec.Name[1] <> '.' then
Tree.Items.AddChild(Item, SearchRec.Name);
until FindNext(SearchRec) <> 0;
FindClose(SearchRec);
end;
Tree.Items.EndUpdate;
end;
I've looked on SO here - too complicated and wrong language and here - similar to the Swiss Delphi Centre and here - wrong language and not sure what its doing.
if it's better to use a TlistView, can you please show me the equivalent code to use that instead?
Untested:
TIdFTP
variable a parameter, since TTreeView
was also one and it should be done consistently, not archaic.for
loops instead of repeat until
.IncludeFiles
when it wasn't used anyway.FTP
is irrelevant and you won't mess up listings at different levels.procedure TForm2.GetFolders
( Ftp: TIdFTP // The source, from which we read the content
; Tree: TTreeView // The destination, which we want to fill
; ParentNode: TTreeNode // Node under which all new child nodes should be created
; Path: String // Starting directory
);
var
NewNode: TTreeNode; // New child in the tree
Filename: String; // Check against unwanted folder entries
i: Integer; // Looping over both lists
sl: TStringList; // Collect folders only
begin
FTP.ChangeDir( Path );
FTP.List; // Entire remote listing
sl:= TStringList.Create; // Collect all entries we're interested in
try
for i:= 0 to FTP.DirectoryListing.Count- 1 do begin // For each entry
Filename:= FTP.DirectoryListing[i].FileName;
if (FTP.DirectoryListing[i].ItemType= ditDirectory) // Only folders
and (Filename<> '.')
and (Filename<> '..') then begin
sl.Add( Filename ); // Only the name, not the full path
end;
end;
// Do this only once
if Path<> '/' then Path:= '/'+ Path+ '/';
for i:= 0 to sl.Count- 1 do begin // All collected folders
NewNode:= Tree.Items.AddChild( ParentNode, sl[i] ); // Populate tree
GetFolders( Ftp, Tree, NewNode, Path+ sl[i] ); // Recursion of folder name + current path
end;
finally
sl.Free;
end;
end;
Untested, but should compile.