TreeView recursion

Hi All,

I am using a Treeview class to display the directory structure of all mounted volumes on a Mac, to include all subfolders/files. However, I can only get as far and getting the first sub-level of the volume to display. I understand that I have to use recursion to get this done, but I just can’t figure this one out. Below is the code I have to get the first sub-level, but I have commented out my attempt to do the recursion to get the rest of the levels to show, because it doesn’t work. Any help would be greatly appreciated!

[code]dim mItemCount, thisItem as Integer
dim currentItem as FolderItem
dim child, grandchild As String

mItemCount = folder.count //counts the item in the folder

for thisItem = 1 to mItemCount
child = “C”+str(thisItem)
currentItem = folder.Item(thisItem) // get the next item in the folder

If currentItem.Visible Then
Listbox1.Add(parent, child, currentItem.Name, True ) // recursive call
'if currentItem.Directory Then
'For i As Integer = 1 To currentItem.Count
'grandchild = “GC”+str(i)
'add_recursive(Listbox1, grandchild, currentItem)
'end if
end if

You need to have different methods for getting all files and displaying them in the listbox. And I love recursion, too.

Here is my method for getting all files in a folder (I don’t know why the name is for getting mails). The code is using the MBS plugin because this is way faster:

[code]Private Sub GetListOfMails(StartFolderitem as FolderItem)

if StartFolderitem = nil then return

dim theFileList as new FileListMBS(StartFolderitem)
dim FileCount as Integer = theFileList.Count - 1
for currentFile as Integer = 0 to FileCount

if theFileList.Visible(currentFile) then
  if theFileList.Directory(currentFile) then
    ListOfMails.Append theFileList.TrueItem(currentFile)
    GetListOfMails theFileList.TrueItem(currentFile) '<--- recursion here
    ListOfMails.Append theFileList.TrueItem(currentFile)
  end if
end if


End Sub[/code]

I was asking just yesterday how to put this into a thread because this can take seconds for a large folder.

However: adding this to a Xojo listbox will be slow. Consider a different approach with getting and displaying only the data when a folder is opened. But try this as second step.

Beatrix: Sorry, but this is not working for me. I have a feeling that because I am trying to do this recursion using a Treeview class for the Hierarchical listbox, normal methods aren’t going to work. I don’t know what to do. I did not think that doing a Hierarchical Listbox for a Volume browser would be so difficult, yeeesh! I need to get some sleep and try to work on this more tomorrow.

Maybe dont try to fill the entire treeview in one go.

start by creating a simple method that adds rows and folders to a node in the tree, based on a passed folderitem

List the folders and files from the start point, and add the equivalent folderitems to the new rows, in the rowtags

on the first pass you ‘consider’ the 'root folder (whichever it is) and work through the children.
here there are 4


AddFolder 2017Docs (rowtag = the 2017Docs folder) expanded = false AddFolder 2018Docs (rowtag = the 2018Docs folder) expanded = false Addrow Somefile.txt (rowtag = somefile) Addrow Somefile2.txt (rowtag = somefile)

Now, if someone expands the 2017Docs folder, you get the rowtag, and work through the Child records of THAT, using 2017Docs as the ‘base’ folder this time, instead of ‘work documents’
Adding folders and files to the 2017Docs row in the treeview

Arguably, if you want to do the whole lot, you can loop through the treeview rows
If any are not expanded, expand them.
and repeat until no unexpanded rows are found

while somethingexpanded for x as integer = 0 to thetree.listcount-1 if <this row is not expanded> //expand it somethingexpanded = true end if next wend

what was wrong with the code I gave you to work with a few days ago…

NOTE : IT HAS NOT BEEN TESTED… so it is for illustration purposes only

Public Sub LoadVolumes(tv as treeview)
  Dim v As FolderItem 
  Dim i As Integer 
  Dim parent As String
  Dim trunk As String
  tv.AutoUpdate=False // delay tree update
  // add the base of the tree (the trunk)
  tv.Add("",trunk, "Devices")
  // step thru each mounted volume
  For i=0 To VolumeCount-1
    add_recursive(tv,parent,v) //<-- add all the files of this volume
  Next i
  tv.AutoUpdate=True // now redraw the whole tree
End Sub
Private Sub add_recursive(tv as treeview,parent as string, folder as folderitem)
  Dim g As Integer
  Dim f As FolderItem
  Dim child As String
  For g = 1 To folder.Count
    If f.Visible Then
      tv.Add(parent, child , f.Name, True) // This adds a new folder to the list
      If f.Directory = True Then add_recursive(tv,child,f) // <- recursive call to add the children of this "Child" (ie. "grandchildren" of "parent")
    End If
  Next g
End Sub

in the OPEN event of the treeview


a) Try to understand what the code I posted is trying to do.
b) If you use the MBS plugin have a look at the example “Disk Browser”. This does exactly what you want to do.
c) Instead of saying “the code doesn’t work” show us what you tried.

Jeff: The While somethingexpanded doesn’t work because the calls to the listbox work with a Treeview class, which doesn’t have the standard listbox calls.

Dave: I will pm you.

Beatrix: I have purchased a Treeview class that presents an amazing UI, which is what I need for the people I am creating this application for. I did show an example of the code that I tried at the beginning of the thread. I have tried multiple iterations of the commented out code without success.

For the record… the Treeview he refers to is one that I wrote… and the untested solution above was offered with the syntax of that treeview in mind.

And Roger… IF you are in fact trying to read the ENTIRE file contents of your system in one go, it will
a) take a LONG time
b) most likely fail due to memory constraints

neither are a flaw in TreeView… but rather the fact the data exceeds ability (by a number of magnitudes)

Yup. I was fooled by Listbox1.Add

Dave’s Treeview control is pretty good, but you will fall foul of performance or memory issues
I question whether it makes sense fully recursing all the folders on all the volumes you find.
Just my trash folder currently holds 16000 items.

The memory isn’t really a problem. I’m testing at the moment with a folder that contains 200k files. Unfortunately, getting the folderitems is rather slow.

@Roger Martin: your code doesn’t contain even a hint of recursion or iteration. Even if you don’t use the MBS plugin the example shows how to do a file browser. I’m sure there are others around.

Haven’t we already done this

Wayne: we went through this process for a basic hierarchical listbox. I have moved on to using a special Treeview class and working on implementing that now.

Still wondering why the code I posted has not been considered… or if it has what seems to be “not right”, especailly since it was tailored for the exact treeview you are using.

Again… memory/performance are going to be a problem no matter what if you are trying to read the directory entry for every file in your system…

Dave: I tried the exact code you posted. I have even tried multiple iterations of the code. The problem seems to be that the recursion halts after going down one level and does not recurse all the directories, sub-directories on any mounted volume. If you pm me and provide me your email address, I will send you the test project I have been working on so you can see what is happening and maybe that will shed some light on this issue.

Turn on ‘break on exceptions’

Does an error occur causing the recursion to just abort?

The code actually works… the problem it is attempting to recurse both Alias and Bundles
Alias is easy to reject, but I can’t find Cocoa code to id a Bundle (all I have is deprecated Carbon methods)

EDIT… the error Roger is experiencing is due to an anomoly in the Treeview code itself… an internal recursion is getting “lost”
EDIT #2 : TreeView anomoly located… new code will be sent to Roger later today

Does checking folderitem.permissions for ‘bit 1 set’ (executable) help?
I know there are other kinds/uses of a bundle, but maybe thats a start?