package components { import flash.events.Event; import mx.binding.utils.ChangeWatcher; import mx.collections.XMLListCollection; import mx.controls.Tree; import mx.events.CollectionEvent; /** * An Tree component with some additional functionality */ public class ExtendedTree extends Tree { /** * Initially expand the tree till a specific depth */ [Bindable] public var initialExpand:int = 0; public override function set dataProvider(provider:Object) : void { super.dataProvider = provider; // initialExpand is only implemented for XMLListCollection if(initialExpand > 0 && provider is XMLListCollection) { initiateExpand(); } } public override function initialize() : void { super.initialize(); ChangeWatcher.watch(this, "initialExpand", function() : void { if(initialExpand > 0 && dataProvider is XMLListCollection) { initiateExpand(); } }); } private function initiateExpand() : void { var collection:XMLListCollection = XMLListCollection(dataProvider); if(collection.length == 0) { // Collection not filled yet. Postpone tree expansion. collection.addEventListener(CollectionEvent.COLLECTION_CHANGE, doExpand); } // Expand immediately after all other events handlers are called . callLater(doExpand); } /** * Expand the tree. */ private function doExpand(event:Object = null) : void { openItems = createOpenItems(initialExpand - 1, XMLListCollection(dataProvider).source); if(event != null) { // doExpand has been called on collection change XMLListCollection(dataProvider).removeEventListener(CollectionEvent.COLLECTION_CHANGE, doExpand); } } /** * Creates an Array containing all items that has to be expanded. */ private function createOpenItems(level:int, list:XMLList, array:Array = null) : Array { if(array == null) { array = new Array(); } for each(var item:XML in list) { array.push(item); if(level > 0) { createOpenItems(level - 1, item.children(), array); } } return array; } /** * Workaround: empty arrays in Tree.listItems causes problems */ public override function expandItem(item:Object, open:Boolean, animate:Boolean = false, dispatchEvent:Boolean = false, cause:Event = null) : void { var count:int = 0; for each(var obj:Object in listItems) { if((obj as Array).length == 0) { break; } count++; } var empty:int = listItems.length - count; listItems.splice(count, empty); super.expandItem(item, open, animate, dispatchEvent, cause); for(var i:int = 0; i < empty; i++) { listItems.push(new Array()); } } } }