Reading structured data into a TreeView

I am building an application that reads IMAP mail folders using curl and then puts them into a hierarchical tree structure using a TreeView control (Einhugur).
I can download the data fine and get a string array that looks a bit like this:

INBOX
INBOX.secoros
INBOX.secoros.Designers
INBOX.old-messages
INBOX.jisc
INBOX.jisc.JISC mail
INBOX.jisc.JISC mail.keep
[etc]

The dots represent the hierarchy. I’m struggling a bit with how to translate this data into entities that I can use with the addNode or insertNode methods for TreeView.
It feels like there should be an elegant (and probably existing) solution to taking structured data like this and adding it to a TreeeView, but I can’t find anything that might guide me. I have been thinking of making an array out of a line using string.split or nthfield, but I can’t get much further than that.
Does anyone here know of examples of how to do this? Any pointers will be much appreciated.

I’ve got an old solution to read hierarchical data from the original Realbasic book.

I used to have that book but not any more (never thought I’d need it again…). Can you share that solution?

I only found half the original code. I’ll try to make an example tomorrow.

Create a window.
Add listbox1 (ordinary Xojo one will do… you may want to modify this for the Treeview control)
Set it to allow expandable rows

Add a property lines() as string to the window

In the Open event or somewhere, I populate the array of lines for demo purposes.

Window Open event:


//array lines() is a window variable

lines.append "INBOX"
lines.append "INBOX.secoros"
lines.append "INBOX.secoros.Designers"
lines.append "INBOX.old-messages"
lines.append "INBOX.jisc"
lines.append "INBOX.jisc.JISC mail"
lines.append "INBOX.jisc.JISC mail.keep"


//fill listbox with level 1 items:

var flds() as string
for x as integer = 0 to lines.lastindex
  flds = lines(x).Split(".")
  if flds.LastIndex = 0 then
    listbox1.AddExpandableRow flds(0)
    listbox1.rowtagat(listbox1.LastAddedRowIndex) = flds(0)
    
  end if
  
next

In the listbox ExpandRow event:

//get info for this row, from the rowtag
var strParent as string = me.rowtagat(row)
var parflds() as string
parflds = strParent.split(".")

var flds() as string
var isChild as boolean

for x as integer = 0 to lines.LastIndex  //read all the lines
  flds = lines(x).Split(".")  //chop them up
  
  if flds.LastIndex = parflds.lastindex +1 then 
    //correct depth eg 3 flds needs 2 fld parent
    
    isChild = true
    for y as integer= 0 to parflds.lastindex
      if parflds(y) <> flds(y) then isChild = false
    next
    
    if ischild then
      me.AddExpandableRowAt(row+1,flds(flds.lastindex), flds.lastindex )
      me.rowtagat(me.LastAddedRowIndex) = string.FromArray(flds,".")
    end if
  end if
next

Result:

Thank you Jeff, that works nicely. It also illuminates for me why I have a problem with the TreeView control; there is no obvious equivalent of the row tag that your code uses to keep track of the parent. Maybe I will try to make TreeView work in the same way that your code does, by populating the TreeView node at the time of opening it; I’d been trying to build the entire tree structure in one go.

Ian.

An update on this question.

I have slightly adapted Jeff’s solution and managed to get something that works nicely for me. The slight issue that the solution above presents is that it only loads the top-most member of the tree to begin with, and then as you click on each level of the tree it opens up to show its immediate children. In other words, you have to manually work through the listbox to see all of the tree. My kludge was to force the tree to open up to all levels so my entire tree structure now shows.

The code, which is far from efficient, is below. I have added an auto-complete search function to help me find my IMAP mail folders (since I have hundreds of them) and can supply the code if anyone’s interested.

buildTreeList method

// put a temporary expandable row into the listbox
lstTree.AddExpandableRow "INBOX"
// go through the lines array
for x as integer = 0 to lines.Count
  // make the current row expanded
  lstTree.RowExpandedAt(x) = true
next
// remove the first row
lstTree.RemoveRowAt(0)
// update the label
lblTreeList.text = "Total number of folders in " + txtIMAPServer.text + ": " + lstTree.RowCount.ToText

// enable the search box and button
if lstTree.RowCount > 0 then
  txtSearch.Enabled = true
  btnSearch.Enabled = true
else
  txtSearch.Enabled = False
  btnSearch.Enabled = false
end If

lstTree.RowExpanded event handler
code supplied by Jeff Tullin - thanks

var strParent as string = me.rowTagAt(row)
var parflds() as string
parflds = strParent.split(".")

var flds() as string
var isChild as boolean

for x as integer = 0 to lines.LastIndex  //read all the lines
  flds = lines(x).Split(".")  //chop them up
  if flds.LastIndex = parflds.lastindex +1 then 
    isChild = true
    for y as integer= 0 to parflds.lastindex
      if parflds(y) <> flds(y) then isChild = false
    next
    
    if isChild then
      me.AddExpandableRowAt(row+1,flds(flds.lastindex), flds.lastindex )
      me.rowTagAt(me.LastAddedRowIndex) = string.FromArray(flds,".")
    end if
  end if
next