Home > database >  How do I populate a Treeview via FTP
How do I populate a Treeview via FTP

Time:10-19

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 enter image description here

What I did see Using a Ttreeview in Delphi

enter image description here

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?

CodePudding user response:

Untested:

  • I made the TIdFTP variable a parameter, since TTreeView was also one and it should be done consistently, not archaic.
  • Using for loops instead of repeat until.
  • Eliminating IncludeFiles when it wasn't used anyway.
  • Eliminating weird logic to always get the new TreeNode's parent.
  • Not locking the TreeView anymore - do this once before calling this method and unlock it after calling - otherwise you do that dozens of times in vain.
  • Basic logic is as I wrote in the comments:
    1. Store all folder strings into your own list and avoid recursion at this point.
    2. Fix the path to be concatenated once, not with every iteration of a loop.
    3. Go through that list to do the recursion - at this point the state of FTP is irrelevant and you won't mess up listings at different levels.
    4. Of course, release the created instance of the StringList.
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.

  • Related