Expand All TreeView nodes?

BlitzMax Forums/MaxGUI Module/Expand All TreeView nodes?

DavidDC(Posted 2007) [#1]
How do I do it?

The code below doesn't work and I'm wondering what I'm doing wrong?

		
If TreeView
  Local root_node:TGadget=TreeViewRoot(TreeView) 
  For Local node:TGadget=EachIn root_node.kids
     If node.CountKids() > 0 Then ExpandTreeViewNode node
  Next
End If


Any ideas appreciated! Thanks

David


SebHoll(Posted 2007) [#2]
A simple recursive function should do the trick. How about something like this:

Function ExpandAllTreeViewNodes( pTreeView:TGadget, pRecurseNode:TGadget = Null )
	
	If Not pTreeView Then Return
	
	If pRecurseNode Then
		
		ExpandTreeViewNode( pRecurseNode )
		PollSystem()
		
		For Local tmpChildNode:TGadget = EachIn pRecurseNode.kids
			
			ExpandAllTreeViewNodes( pTreeView, tmpChildNode )
		
		Next
	
	Else
		
		ExpandAllTreeViewNodes( pTreeView, TreeViewRoot(pTreeView) )
	
	EndIf
	
EndFunction
It should iterate through all nodes and child-nodes and expand them each in turn. Don't worry about the second parameter when calling it, simply pass the treeview you want to completely expand.

For example (modified CreateTreeView.bmx source from the BMax docs):




DavidDC(Posted 2007) [#3]
Seb,

Thanks very much for a thorough answer. I really appreciate it.

I'm running your example on OS X 10.4.10 Intel iMac, however, and the treeview stays collapsed (as does my initial attempt's code).

Perhaps this is an OS X issue? Did you try it on your mac?

David


SebHoll(Posted 2007) [#4]
I'm running your example on OS X 10.4.10 Intel iMac, however, and the treeview stays collapsed (as does my initial attempt's code).

That's strange... It seems to work fine on Windows. You could try calling RedrawGadget( treeview ) after calling ExpandAllTreeViewNodes(). I'm away from home at the moment, so I didn't have my Mac to try it on.


DavidDC(Posted 2007) [#5]
Unfortunately the result is the same with RedrawGadget( treeview ) included as suggested above. All nodes remain collapsed.


Dreamora(Posted 2007) [#6]
Did you check if there is some OSX design enforcement on that topic?

many of the OSX ui things have enforced behaviors to guarantee consistency.


DavidDC(Posted 2007) [#7]
Dreamora, I'm not sure of the logic of such a restriction or how it is enforced when single calls to ExpandTreeViewNode(node) work just fine in the example above?

For eg, although the above doesn't work, if I place (OS X)

ExpandTreeViewNode(help)
ExpandTreeViewNode(projects)

Just under (or instead of)

ExpandAllTreeViewNodes( treeview ) 'Let's expand all the nodes we just created

Then help and projects (but not project 2) expand as expected.


SebHoll(Posted 2007) [#8]
Try the (now modified) function I posted above. It's a shot in the dark, but it might work :-P Notice the addition of PollSystem() after ExpandTreeViewNode(). I remember having a few problems with Cocoa not updating under certain circumstances but PollSystem() fixed them.

If that doesn't work, could you post what happens to the treeview if you add DebugStop before calling ExpandAllTreeViewNodes() and step through the function line-by-line.


DavidDC(Posted 2007) [#9]
Modified function has no effect Seb. Strangely, I can't see the line I'm on (no highlighting - this is in the plain MaxIDE) when I try a DebugStop on this (even though the debugger works fine if I switch straight to the project I'm working on).

But by inserting a print statement after every line in the recursive function I can say with certainty that the code never enters the for-loop.

For Local tmpChildNode:TGadget = EachIn pRecurseNode.kids

' We never get in here

Next

This is despite pRecurseNode.CountKids() returning the right amount immediately before this same loop

A puzzle!


SebHoll(Posted 2007) [#10]
What is output if you call pRecurseNode.kids.Count() just before the For...Next loop? From what you've said, it seems as though Cocoa MaxGUI isn't storing child nodes in the parent's kid list (which is strange).

NB: pRecurseNode.CountKids() uses an external Cocoa fuinction to count how many children there are and therefore doesn't rely on pRecurseNode.kids.Count().


DavidDC(Posted 2007) [#11]
OK let's get a bit more serious.

1. The debugger is working this morning!
2. Modified code:

Function ExpandAllTreeViewNodes( pTreeView:TGadget, pRecurseNode:TGadget = Null )
	
	If Not pTreeView Then Return
	
	If pRecurseNode Then
		Print "Recurse Node is OK, about to expand " +GadgetText(pRecurseNode)

		ExpandTreeViewNode( pRecurseNode )
		PollSystem()

		Print "Pre For Loop node " +GadgetText(pRecurseNode) +" has kids: " +pRecurseNode.Countkids() +" alt kids count: " +pRecurseNode.kids.Count()
		
		If pRecurseNode.kids = Null Print "kids are null!"

		For Local tmpChildNode:TGadget = EachIn pRecurseNode.kids
			Print "Inside For Loop: num kids " +pRecurseNode.Countkids()
			ExpandAllTreeViewNodes( pTreeView, tmpChildNode )
		
		Next
	Else
		Print GadgetText(pTreeView) + " Recursing to a root node"
		ExpandAllTreeViewNodes( pTreeView, TreeViewRoot(pTreeView) )
	
	EndIf
	
EndFunction


Produces the following output. Note GadgetText doesn't seem to work on the nodes?

Building test_expand_treeview
Compiling:test_expand_treeview.bmx
Linking:test_expand_treeview.debug
Executing:test_expand_treeview.debug
Recursing to a root node
Recurse Node is OK, about to expand
Pre For Loop node has kids: 2 alt kids count: 0
WindowActivate: data=0, mods=0, x=0, y=0, extra=""
AppResume: data=0, mods=0, x=0, y=0, extra=""
WindowClose: data=0, mods=0, x=0, y=0, extra=""

Process complete


SebHoll(Posted 2007) [#12]
It seems like nodes aren't being added the parent node's child list when using the Cocoa MaxGUI driver. Therefore, we can't iterate through them and expand them.

I don't think there is much you can do about this - you could try posting a bug report in the MaxGUI Bug Reports forum, but I wouldn't hold your breath!


DavidDC(Posted 2007) [#13]
Thanks Seb.

Assuming I can work around this problem, I'm still faced with the need to clear and repopulate a treeview in OSX.

Given that I can't traverse the child nodes, how to I clear a treeview in OSX without actually freeing the gadget?

[later edit]

One messy and inefficient answer: You can create a TList and add a node to the list every time one is added to the treeview. Then:

	Method FreeListNodes()
	
		If Not TreeView Or Not List Return 
		
		Local b_node_removed:Int = True
	
		'	While at least one node has been removed last pass
		While b_node_removed
			
			b_node_removed = False
			
			'	Step through all nodes in the list
			For Local node:TGadget = EachIn List
	
				'	If the node has no children, it is safe to remove
				If node.CountKids() = 0 
				
					List.Remove(node)
					FreeTreeViewNode(node)
					b_node_removed = True
					
				EndIf
	
			Next
	
		Wend
		
		'	This should be redundant	
		List.Clear()
			
	End Method




SebHoll(Posted 2007) [#14]
I've used these function from the code archives and they work fine on Win32, but you may again have some problems on OS X.


DavidDC(Posted 2007) [#15]
No, that code appears to be broken as well.

For example, using the above example

Print TreeViewNodeIndex(AddTreeViewNode("node sits under projects",projects))

Prints 0 using Jake's code. Actually it calls an exception as Jake fails to test for NULL links before calling link.Value().

I think the node child List is broken in MacOS treeviews generally. Be nice if someone else out there would confirm this before I submit a bug report though.