////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.collections
{
import flash.events.EventDispatcher;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
/**
* Hierarchical data is data already in a structure of parent and child data items.
* The HierarchicalData class provides a default implementation for
* accessing and manipulating data for use in controls such as the AdvancedDataGrid control.
* To configure the AdvancedDataGrid control to display hierarchical data,
* you pass to the dataProvider
property an instance of the HierarchicalData class.
*
* This implementation handles E4X, XML, and Object nodes in similar but different
* ways. See each method description for details on how the method
* accesses values in nodes of various types.
*
* @see mx.controls.AdvancedDataGrid
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class HierarchicalData extends EventDispatcher implements IHierarchicalData
{
include "../core/Version.as";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @param value The data used to populate the HierarchicalData instance.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function HierarchicalData(value:Object = null)
{
super();
source = value;
}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// childrenField
//--------------------------------------------------------------------------
/**
* @private
* The field name to be used to detect children field.
*/
private var _childrenField:String = "children";
/**
* Indicates the field name to be used to detect children objects in
* a data item.
* By default, all subnodes are considered as children for
* XML data, and the children
property is used for the Object data type.
*
* This is helpful in adapting to a data format that uses custom data fields
* to represent children.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get childrenField():String
{
return _childrenField;
}
/**
* @private
*/
public function set childrenField(value:String):void
{
_childrenField = value;
}
//--------------------------------------------------------------------------
// source
//--------------------------------------------------------------------------
/**
* @private
* The source collection.
*/
private var _source:Object;
/**
* The source collection.
* The collection should implement the IList interface
* to facilitate operation like the addition and removal of items.
*
* @see mx.collections.IList
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get source():Object
{
return _source;
}
/**
* @private
*/
public function set source(value:Object):void
{
_source = value;
var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
event.kind = CollectionEventKind.RESET;
dispatchEvent(event);
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function canHaveChildren(node:Object):Boolean
{
if (node == null)
return false;
var branch:Boolean = false;
if (node is XML)
{
var childList:XMLList = childrenField == "children" ? node.children() : node.child(childrenField).children();
//accessing non-required e4x attributes is quirky
//but we know we'll at least get an XMLList
var branchFlag:XMLList = node.@isBranch;
//check to see if a flag has been set
if (branchFlag.length() == 1)
{
//check flag and return (this flag overrides termination status)
if (branchFlag[0] == "true")
branch = true;
}
//since no flags, we'll check to see if there are children
else if (childList.length() != 0)
{
branch = true;
}
}
else if (node is Object)
{
try
{
if (node[childrenField] != undefined)
{
branch = true;
}
}
catch (e:Error)
{
}
}
return branch;
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function getChildren(node:Object):Object
{
if (node == null)
return null;
var children:*;
//first get the children based on the type of node.
if (node is XML)
{
children = childrenField == "children" ? node.* : node.child(childrenField).*;
}
else if (node is Object)
{
//we'll try the default children property
try
{
children = node[childrenField];
}
catch (e:Error)
{
}
}
//no children exist for this node
if(children === undefined)
return null;
return children;
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function hasChildren(node:Object):Boolean
{
if (node == null)
return false;
//This default impl can't optimize this call to getChildren
//since we can't make any assumptions by type. Custom impl's
//can probably avoid this call and reduce the number of calls to
//getChildren if need be.
var children:Object = getChildren(node);
try
{
if(children is XMLList || children is XML)
{
if (children.length() > 0)
return true;
}
if (children.length > 0)
return true;
}
catch (e:Error)
{
}
return false;
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function getData(node:Object):Object
{
return Object(node);
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function getRoot():Object
{
return source;
}
}
}