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.
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
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.
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