Flex 2 :: Tree :: Walking the Tree method
October 16th, 2006Hi,
I thought I would post this method to show some of you that the dataDescriptor rocks. One thing you will notice in the method below is there is an if() check on the model at every turn. With experience comes wisdom and I have found this is essential in creating methods that test the sands of time.
Also note, the method is 'actually' two methods. The first half of the method will back step on the item's parent. The nice thing about this is, if you do pass startAtParent as true, the first part of the method only gets executed once in the recursion algorithm. It's main purpose is to get the item's parent and siblings, loop through them and then branch down the chain.
This is handy if you want to know the item's sibling branches. If you do not need the sibling branches, pass startAtParent as false and you bypass the first part of the method and go straight to the item.
If the item is a leaf, it will just trace the leaf item. If the item is a branch, it will then recurse through the whole composite structure of the item passed.
I hope this helps people, and you can discover some of the fascinating aspects about recursion and dataDescriptors. OOP is all about abstraction and decoupling through dataDescriptors. Adobe has found a wonderful balance in all the composite controls they have made thus far.
Look for the comments where you could break into your own method branch.
* This method will traverse a Tree's model independent of it's
* type.
*
* <p>Note :: This method may look long and arduous but, rest assured
* it has all the checks to perform like a champ. Also, you 'could'
* refactor part of this method but, for the sake of explanation, I
* kept it all in one place.</p>
*
* <p>Remember, I had coupled the model to this method by tracing
* @label, obviously you do not need to do this. The intention of
* this example is to show you that the dataDescriptor seperates
* the models type and is awesome. It enables you to create a tight
* method like this without type checks on the model.</p>
*
* @param tree The Tree instance that will be examined by the method.
* @param item An item found in the dataProvider of the Tree passed in.
* @param startAtParent A boolean that determines if the method upon
* initialization will back up one leve3l to the item passed in and
* start it's recursion at the item's parent node.
*/
public function walkTree(tree:Tree, item:Object, startAtParent:Boolean = false):void
{
// get the Tree's data descriptor
var descriptor:ITreeDataDescriptor = tree.dataDescriptor;
var cursor:IViewCursor;
var parentItem:Object;
var childItem:Object;
var childItems:Object;
// if the item is null, stop
if (item == null)
return;
// do we back up one level to the item's parent
if (startAtParent)
{
// get the parent
parentItem = tree.getParentItem(item);
// is the parent real
if (parentItem)
{
trace("|-- Parent Node ", parentItem[tree.labelField]);
// if the parent is a branch
if (descriptor.isBranch(parentItem))
{
// if the branch has children to run through
if (descriptor.hasChildren(parentItem))
{
// get the children of the branch
// this part of the algorithm contains the item
// passed
childItems = descriptor.getChildren(parentItem);
}
}
// if the branch has valid child items
if (childItems)
{
// create our back step cursor
cursor = childItems.createCursor();
// loop through the items parent's children (item)
while (!cursor.afterLast)
{
// get the current child item
childItem = cursor.current;
var label:String = childItem[tree.labelField];
var branch:Boolean = descriptor.isBranch(childItem);
// good place for a custom method()
trace("Sibling Nodes :: ", label, "Is Branch :: ", branch);
// if the child item is a branch
if (descriptor.isBranch(childItem))
// traverse the childs branch all the way down
// before returning
walkTree(tree, childItem);
// do it again!
cursor.moveNext();
}
}
}
}
else // we don't want the parent OR this is the second iteration
{
// if we are a branch
if (descriptor.isBranch(item))
{
// if the branch has children to run through
if (descriptor.hasChildren(item))
{
// get the children of the branch
childItems = descriptor.getChildren(item);
}
// if the child items exist
if (childItems)
{
// create our cursor pointer
cursor = childItems.createCursor();
// loop through all of the children
// if one of these children are a branch we will recurse
while (!cursor.afterLast)
{
// get the current child item
childItem = cursor.current;
var label:String = childItem[tree.labelField];
var branch:Boolean = descriptor.isBranch(childItem);
// good place for a custom method()
trace("-- Sub Node :: ", label, "Is Branch :: ", branch);
// if the child item is a branch
if (descriptor.isBranch(childItem))
// traverse the childs branch all the way down
// before returning
walkTree(tree, childItem);
// check the next child
cursor.moveNext();
}
}
}
}
}
Peace, Mike







