Transferred from the Adobe Open Source Subversion Repository

Revision: 12850
Author:   jimurphy@adobe.com
Date:     2009-12-11T14:57:14.623098Z

Log Message:
-----------
add 6 new DMV projects to the SDK:
automation
automation_air
automation_dmv
automation_flashflexkit
automation_spark
datavisualization

These projects are setup to build in an ant main call.  There are currently several warnings in the datavisualization project that will be cleaned up.  No checkintests exist for these projects as of yet.

I also modified the exisitng projects build files for easier management of the localization targets, bundle and fat-swc. If the projects that I updated:airframework,airspark,framework,playerglobal,rpc,and spark.  All the new projects have been implemented this same way.

QE notes: DMV folks should run through their tests
Doc notes: probably
Bugs: nope
Reviewer:
Tests run: ran the following targets: compile,checkintests,other.locales and doc
Is noteworthy for integration: no

Modified Paths:
--------------
1404 paths were modified

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1248428 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/advancedgrids/src/mx/collections/HierarchicalCollectionViewCursor.as
+++ frameworks/projects/advancedgrids/src/mx/collections/HierarchicalCollectionViewCursor.as
@@ -0,0 +1,1312 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  ADOBE SYSTEMS INCORPORATED
+//  Copyright 2009 Adobe Systems Incorporated
+//  All Rights Reserved.
+//
+//  NOTICE: Adobe permits you to use, modify, and distribute this file
+//  in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package mx.collections
+{
+
+import flash.events.EventDispatcher;
+import flash.utils.Dictionary;
+
+import mx.collections.errors.ChildItemPendingError;
+import mx.collections.errors.ItemPendingError;
+import mx.core.mx_internal;
+import mx.events.CollectionEvent;
+import mx.events.CollectionEventKind;
+import mx.events.FlexEvent;
+import mx.utils.UIDUtil;
+
+use namespace mx_internal;
+
+/**
+ *  The HierarchicalCollectionViewCursor class defines a
+ *  cursor for a hierarchical view of a standard collection.
+ *  The collection that this cursor walks across need not be hierarchical - it may be flat.
+ *  This class delegates to the IHierarchicalData for information regarding the tree
+ *  structure of the data it walks across.
+ *
+ *  @see HierarchicalCollectionView
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class HierarchicalCollectionViewCursor extends EventDispatcher
+                                    implements IHierarchicalCollectionViewCursor
+{
+    include "../core/Version.as";
+
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Constructor.
+     *
+     *  @param collection The HierarchicalCollectionView instance referenced by this cursor.
+     *
+     *  @param model The source data collection.
+     *
+     *  @param hierarchicalData The data used to create the HierarchicalCollectionView instance.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function HierarchicalCollectionViewCursor(
+                            collection:HierarchicalCollectionView,
+                            model:ICollectionView,
+                            hierarchicalData:IHierarchicalData)
+    {
+        super();
+
+        //fields
+        this.collection = collection;
+        this.hierarchicalData = hierarchicalData;
+        this.model = model;
+
+        //events
+        collection.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler, false, 0, true);
+
+        //init
+        modelCursor = model.createCursor();
+
+        //check to see if the model has more than one top level items
+        if (model.length > 1)
+            more = true;
+        else
+            more = false;
+
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    // Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    private var hierarchicalData:IHierarchicalData;
+
+    /**
+     *  @private
+     */
+    private var currentChildBookmark:CursorBookmark = CursorBookmark.FIRST;
+
+    /**
+     *  @private
+     *  Its effective offset into the "array".
+     */
+    private var currentIndex:int = 0;
+
+    /**
+     *  @private
+     *  The depth of the current node.
+     */
+    private var _currentDepth:int = 1;
+
+    /**
+     *  @private
+     *  The current set of childNodes we are walking.
+     */
+    private var childNodes:ICollectionView;
+
+    /**
+     *  @private
+     *  The current set of parentNodes that we have walked from
+     */
+    private var parentNodes:Array = [];
+
+    /**
+     *  @private
+     *  A stack of the currentChildBookmark in all parents of the currentNode.
+     */
+    private var childIndexStack:Array = [];
+
+    /**
+     *  @private
+     *  The collection that stores the user data
+     */
+    private var model:ICollectionView;
+
+    /**
+     *  @private
+     *  The collection wrapper of the model
+     */
+    private var collection:HierarchicalCollectionView;
+
+    /**
+     *  @private
+     *  Flag indicating model has more data
+     */
+    private var more:Boolean;
+
+    /**
+     *  @private
+     *  Cursor from the model
+     */
+    private var modelCursor:IViewCursor;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    // index
+    //----------------------------------
+    /**
+     * @private
+     */
+    public function get index():int
+    {
+        return currentIndex;
+    }
+
+    //----------------------------------
+    //  bookmark
+    //----------------------------------
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get bookmark():CursorBookmark
+    {
+        return new CursorBookmark(currentIndex.toString());
+    }
+
+    //----------------------------------
+    //  current
+    //----------------------------------
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get current():Object
+    {
+        if (childIndexStack.length == 0)
+        {
+            return modelCursor.current;
+        }
+        else
+        {
+            var childCursor:IViewCursor = childNodes.createCursor();
+            try
+            {
+
+                childCursor.seek(currentChildBookmark);
+                return childCursor.current;
+            }
+            catch (e:ItemPendingError)
+            {
+                return null;
+            }
+        }
+
+        return null;
+    }
+
+
+    //---------------------------------
+    // currentDepth
+    //---------------------------------
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get currentDepth():int
+    {
+        return _currentDepth;
+    }
+
+
+    //----------------------------------
+    //  beforeFirst
+    //----------------------------------
+    /**
+     *  @copy mx.collections.IViewCursor#beforeFirst
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get beforeFirst():Boolean
+    {
+        return (currentIndex <= collection.length && current == null);
+    }
+
+    //----------------------------------
+    //  afterLast
+    //----------------------------------
+    /**
+     *  @copy mx.collections.IViewCursor#afterLast
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get afterLast():Boolean
+    {
+        return (currentIndex >= collection.length && current == null);
+    }
+
+    //----------------------------------
+    //  view
+    //----------------------------------
+    /**
+     *  @copy mx.collections.IViewCursor#view
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get view():ICollectionView
+    {
+        return model;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function findAny(values:Object):Boolean
+    {
+        seek(CursorBookmark.FIRST);
+
+        var done:Boolean = false;
+        while (!done)
+        {
+            var o:Object = hierarchicalData.getData(current);
+
+            var matches:Boolean = true;
+            for (var p:String in values)
+            {
+                if (o[p] != values[p])
+                {
+                    matches = false;
+                    break;
+                }
+            }
+
+            if (matches)
+                return true;
+
+            done = !moveNext();
+        }
+
+        return false;
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function findFirst(values:Object):Boolean
+    {
+        return findAny(values);
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function findLast(values:Object):Boolean
+    {
+        seek(CursorBookmark.LAST);
+
+        var done:Boolean = false;
+        while (!done)
+        {
+            var o:Object = current;
+
+            var matches:Boolean = true;
+            for (var p:String in values)
+            {
+                if (o[p] != values[p])
+                {
+                    matches = false;
+                    break;
+                }
+            }
+
+            if (matches)
+                return true;
+
+            done = !movePrevious();
+        }
+
+        return false;
+    }
+
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function moveNext():Boolean
+    {
+        var currentNode:Object = current;
+        //if there is no currentNode then we cant move forward and must be off the ends
+        if (currentNode == null)
+            return false;
+
+        var childCursor:IViewCursor;
+        var uid:String = UIDUtil.getUID(currentNode);
+
+        // If current node is a branch and is open, the first child is our next item so return it
+        if (collection.openNodes[uid] &&
+            hierarchicalData.canHaveChildren(currentNode) &&
+            hierarchicalData.hasChildren(currentNode))
+        {
+                var previousChildNodes:ICollectionView = childNodes;
+                childNodes = collection.getChildren(currentNode);
+                if (childNodes.length > 0)
+                {
+                    childIndexStack.push(currentChildBookmark);
+                    parentNodes.push(currentNode);
+                    currentChildBookmark = CursorBookmark.FIRST;
+                    childCursor = childNodes.createCursor();
+                    try
+                    {
+                        currentNode = childCursor.current;
+						// update parent map
+						updateParentMap(currentNode);
+                    }
+                    catch (e:ItemPendingError)
+                    {
+                        currentNode = null;
+                        throw new ChildItemPendingError(e.message);
+                    }
+                    currentIndex++;
+                    _currentDepth++;
+                    return true;
+                }
+                else
+                {
+                    childNodes = previousChildNodes;
+                }
+        }
+
+        // Otherwise until we find the next child (could be on any level)
+        while (true)
+        {
+            // If we hit the end of this list, pop up a level.
+            if(childNodes != null)
+            {
+                childCursor = childNodes.createCursor();
+                try
+                {
+                    childCursor.seek(currentChildBookmark);
+                    childCursor.moveNext();
+                }
+                catch(e:ItemPendingError)
+                {
+                    childCursor.seek(CursorBookmark.FIRST);
+                }
+             }
+
+             var grandParent:Object;
+
+            if (childNodes != null &&
+                childNodes.length > 0 &&
+                (childCursor.bookmark == CursorBookmark.LAST || childCursor.afterLast))
+            {
+                //check for the end of the tree here.
+                if (childIndexStack.length < 1 && !more)
+                {
+                    currentNode = null;
+                    currentIndex++;
+                    _currentDepth = 1;
+                    return false;
+                }
+                else
+                {
+                    //pop up to parent
+                    currentNode = parentNodes.pop();
+                    //get parents siblings
+                    grandParent = parentNodes[parentNodes.length-1];
+                    //we could probably assume that a non-null grandparent has descendants
+                    //but the analogy only goes so far...
+                    if (grandParent != null &&
+                        hierarchicalData.canHaveChildren(grandParent) &&
+                        hierarchicalData.hasChildren(grandParent))
+                    {
+                        childNodes = collection.getChildren(grandParent);
+                    }
+                    else
+                    {
+                        childNodes = null;
+                    }
+                    //get new current nodes index
+                    currentChildBookmark = childIndexStack.pop();
+                    //pop the level up one
+                    _currentDepth--;
+                }
+            }
+            else
+            {
+                //if no childnodes then we're probably at the top level
+                if (childIndexStack.length == 0)
+                {
+                    //check for more top level siblings
+                    //and if we're here the depth should be 1
+                    _currentDepth = 1;
+                    more = modelCursor.moveNext();
+                    if (more)
+                    {
+                        currentNode = modelCursor.current;
+                        break;
+                    }
+                    else
+                    {
+                        //at the end of the tree
+                        _currentDepth = 1;
+                        currentIndex++;  //this should push us to afterLast
+                        currentNode = null;
+                        return false;
+                    }
+                }
+                else
+                {
+                    //get the next child node
+                    try
+                    {
+                        childCursor = childNodes.createCursor();
+                        childCursor.seek(currentChildBookmark);
+
+                        childCursor.moveNext();
+                        currentChildBookmark = childCursor.bookmark;
+
+                        currentNode = childCursor.current;
+                        break;
+                    }
+                    catch(e:ItemPendingError)
+                    {
+                        //pop up to parent
+                        currentNode = parentNodes.pop();
+                        //get parents siblings
+                        grandParent = parentNodes[parentNodes.length-1];
+                        //we could probably assume that a non-null grandparent has descendants
+                        //but the analogy only goes so far...
+                        if (grandParent != null &&
+                            hierarchicalData.canHaveChildren(grandParent) &&
+                            hierarchicalData.hasChildren(grandParent))
+                        {
+                            childNodes = collection.getChildren(grandParent);
+                        }
+                        else
+                        {
+                            childNodes = null;
+                        }
+                        //get new current nodes index
+                        currentChildBookmark = childIndexStack.pop();
+                        //pop the level up one
+                        _currentDepth--;
+
+                        if (childIndexStack.length == 0)
+                        {
+                            //check for more top level siblings
+                            //and if we're here the depth should be 1
+                            _currentDepth = 1;
+                            more = modelCursor.moveNext();
+                            if (more)
+                            {
+                                currentNode = modelCursor.current;
+                                throw new ChildItemPendingError(e.message);
+                            }
+                            else
+                            {
+                                //at the end of the tree
+                                _currentDepth = 1;
+                                currentIndex++;  //this should push us to afterLast
+                                currentNode = null;
+                                return false;
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+		updateParentMap(currentNode);
+
+        currentIndex++;
+        return true;
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function movePrevious():Boolean
+    {
+        var currentNode:Object = current;
+        // If there are no items, there's no current node, so return false.
+        if (currentNode == null)
+            return false;
+
+        var childCursor:IViewCursor;
+
+        //if not at top level
+        if (parentNodes && parentNodes.length > 0)
+        {
+            if (currentChildBookmark == CursorBookmark.FIRST)
+            {
+                //at the first node in this branch so move to parent
+                currentNode = parentNodes.pop();
+                currentChildBookmark = childIndexStack.pop();
+                var grandParent:Object = parentNodes[parentNodes.length-1];
+                //we could probably assume that a non-null grandparent has descendants
+                //but the analogy only goes so far...
+                if (grandParent != null &&
+                    hierarchicalData.canHaveChildren(grandParent) &&
+                    hierarchicalData.hasChildren(grandParent))
+                {
+                    childNodes = collection.getChildren(grandParent);
+                }
+                else
+                {
+                    childNodes = null;
+                }
+                _currentDepth--;
+                currentIndex--;
+                return true;
+            }
+            else
+            {
+                // get previous child sibling
+                try
+                {
+                    childCursor = childNodes.createCursor();
+
+                    childCursor.seek(currentChildBookmark);
+                    childCursor.movePrevious();
+                    currentChildBookmark = childCursor.bookmark;
+                    currentNode = childCursor.current;
+
+                    try
+                    {
+                        // this is needed because the cursor bookmark for
+                        // the zero position and CursorBookmark.FIRST is not
+                        // same. this condition is encountered while doing
+                        // a movePrevious()
+                        childCursor.movePrevious();
+                        if (childCursor.bookmark == CursorBookmark.FIRST)
+                            currentChildBookmark = CursorBookmark.FIRST;
+                    }
+                    catch (e:ItemPendingError)
+                    {
+                    }
+                }
+                catch(e:ItemPendingError)
+                {
+                    //lets try to recover
+                    return false;
+                }
+            }
+        }
+        //handle top level siblings
+        else
+        {
+            more = modelCursor.movePrevious();
+            if (more)
+            {
+                //move back one node and then loop through children
+                currentNode = modelCursor.current;
+            }
+            //if past the begining of the tree return false
+            else
+            {
+                //currentIndex--;  //should be before first
+                currentIndex = -1;
+                currentNode = null;
+                return false;
+            }
+        }
+        while (true)
+        {
+            // If there are children, walk backwards on the children
+            // and consider youself after your children.
+            if (collection.openNodes[UIDUtil.getUID(currentNode)] &&
+                hierarchicalData.canHaveChildren(currentNode) &&
+                hierarchicalData.hasChildren(currentNode))
+            {
+                var previousChildNodes:ICollectionView = childNodes;
+                childNodes = collection.getChildren(currentNode);
+                if (childNodes.length > 0)
+                {
+                    childIndexStack.push(currentChildBookmark);
+                    parentNodes.push(currentNode);
+                    // if the child collection has only one item then set the
+                    // bookmark to first
+                    if (childNodes.length == 1)
+                        currentChildBookmark = CursorBookmark.FIRST;
+                    else
+                        currentChildBookmark = CursorBookmark.LAST;
+
+                    childCursor = childNodes.createCursor();
+                    try
+                    {
+                        childCursor.seek(currentChildBookmark);
+                        currentNode = childCursor.current;
+                    }
+                    catch (e:ItemPendingError)
+                    {
+                        try
+                        {
+                            childCursor.seek(CursorBookmark.FIRST);
+                            while (!childCursor.afterLast)
+                            {
+                                currentNode = childCursor.current;
+                                childCursor.moveNext();
+                            }
+                        }
+                        catch(e1:ItemPendingError)
+                        {
+                        }
+
+                        throw new ChildItemPendingError(e.message);
+                    }
+                    _currentDepth++;
+                }
+                else
+                {
+                    childNodes = previousChildNodes;
+                    break;
+                }
+            }
+            else
+            {
+                //No more open branches so we'll bail
+                break;
+            }
+        }
+
+		updateParentMap(currentNode);
+
+        currentIndex--;
+        return true;
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function seek(bookmark:CursorBookmark, offset:int=0,
+                         prefetch:int = 0):void
+    {
+        var value:int;
+
+        if (bookmark == CursorBookmark.FIRST)
+        {
+            value = 0;
+        }
+        else if (bookmark == CursorBookmark.CURRENT)
+        {
+            value = currentIndex;
+        }
+        else if (bookmark == CursorBookmark.LAST)
+        {
+            value = collection.length - 1;
+        }
+        else
+        {
+            value = int(bookmark.value);
+        }
+
+        value = Math.max(Math.min(value + offset, collection.length), 0);
+        var dc:int = Math.abs(currentIndex - value);
+        var de:int = Math.abs(collection.length - value);
+        var movedown:Boolean = true;
+        // if we're closer to the current than the beginning
+        if (dc < value)
+        {
+            // if we're closer to the end than the current position
+            if (de < dc)
+            {
+                moveToLast();
+
+                if (de == 0)
+                {
+                    // if de = 0; we need to be "off the end"
+                    moveNext();
+                    value = 0;
+                }
+                else
+                {
+                    value = de - 1;
+                }
+                movedown = false;
+            }
+            else
+            {
+                movedown = currentIndex < value;
+                value = dc;
+                // if current is off the end, reset
+                if (currentIndex == collection.length)
+                {
+                    value--;
+                    moveToLast();
+                }
+            }
+        }
+        else // we're closer to the beginning than the current
+        {
+            // if we're closer to the end than the beginning
+            if (de < value)
+            {
+                moveToLast();
+                if (de == 0)
+                {
+                    // if de = 0; we need to be "off the end"
+                    moveNext();
+                    value = 0;
+                }
+                else
+                {
+                    value = de - 1;
+                }
+                movedown = false;
+            }
+            else
+            {
+                moveToFirst();
+            }
+        }
+
+        if (movedown)
+        {
+            while (value && value > 0)
+            {
+                moveNext();
+                value--;
+            }
+        }
+        else
+        {
+            while (value && value > 0)
+            {
+                movePrevious();
+                value--;
+            }
+        }
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function insert(item:Object):void
+    {
+        var parent:Object = collection.getParentItem(current);
+        collection.addChildAt(parent, item, currentIndex);
+    }
+
+    /**
+     *  @inheritDoc
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function remove():Object
+    {
+        var obj:Object = current;
+        var parent:Object = collection.getParentItem(current);
+        collection.removeChild(parent, current);
+        return obj;
+    }
+
+    /**
+     *  @private
+     *  Determines if a node is visible on the screen
+     */
+    private function isItemVisible(node:Object):Boolean
+    {
+        var parentNode:Object = collection.getParentItem(node);
+        while (parentNode != null)
+        {
+            if (collection.openNodes[UIDUtil.getUID(parentNode)] == null)
+                return false;
+
+            parentNode = collection.getParentItem(parentNode);
+        }
+        return true;
+    }
+
+	/**
+	 * @private
+	 * Update the parent map.
+	 */
+	private function updateParentMap(currentNode:Object):void
+	{
+		if (currentNode != null)
+		{
+			var uid:String = UIDUtil.getUID(currentNode);
+			if (!collection.parentMap.hasOwnProperty(uid))
+				collection.parentMap[uid] = parentNodes[parentNodes.length - 1];
+		}
+	}
+
+    /**
+     *  @private
+     *  Creates a stack of parent nodes by walking upwards
+     */
+    private function getParentStack(node:Object):Array
+    {
+        var nodeParents:Array = [];
+
+        // Make a list of parents of the node.
+        var obj:Object = collection.getParentItem(node);
+        while (obj != null)
+        {
+            nodeParents.unshift(obj);
+            obj = collection.getParentItem(obj);
+        }
+        return nodeParents;
+    }
+
+    /**
+     *  @private
+     *  When something happens to the tree, find out if it happened
+     *  to children that occur before the current child in the tree walk.
+     */
+    private function isNodeBefore(node:Object, currentNode:Object):Boolean
+    {
+        if (currentNode == null)
+            return false;
+
+        var i:int;
+        var tmpChildNodes:ICollectionView;
+        var sameParent:Object;
+
+        var nodeParents:Array = getParentStack(node);
+        var curParents:Array = getParentStack(currentNode);
+
+        var cursor:IViewCursor;
+        var child:Object;
+
+        // Starting from the root, compare parents
+        // (assumes the root must be the same).
+        while (nodeParents.length != 0 && curParents.length != 0)
+        {
+            var nodeParent:Object = nodeParents.shift();
+            var curParent:Object = curParents.shift();
+
+            // If not the same parentm then which ever one is first
+            // in the child list is before the other.
+            if (nodeParent != curParent)
+            {
+                // The last parent must be common.
+                sameParent = collection.getParentItem(nodeParent);
+
+                // Get the child list.
+                if (sameParent != null &&
+                    hierarchicalData.canHaveChildren(sameParent) &&
+                    hierarchicalData.hasChildren(sameParent))
+                {
+                    tmpChildNodes = collection.getChildren(sameParent);
+                }
+                else
+                {
+                    tmpChildNodes = model;
+                }
+                // Walk it until you hit one or the other.
+                {
+                    cursor = tmpChildNodes.createCursor();
+                    try
+                    {
+                        cursor.seek(CursorBookmark.FIRST, i);
+                        child = cursor.current;
+                    }
+                    catch (e:ItemPendingError)
+                    {
+                        // item pending - this may never happen
+                        return false;
+                    }
+
+                    if (child == curParent)
+                        return false;
+
+                    if (child == nodeParent)
+                        return true;
+                }
+            }
+        }
+
+        if (nodeParents.length)
+            node = nodeParents.shift();
+        if (curParents.length)
+            currentNode = curParents.shift();
+
+        // If we get here, they have the same parentage or one or both
+        // had a root parent. Who's first?
+        tmpChildNodes = model;
+        cursor = tmpChildNodes.createCursor();
+        while (!cursor.afterLast)
+        {
+            child = cursor.current;
+
+            if (child == currentNode)
+                return false;
+
+            if (child == node)
+                return true;
+
+            try
+            {
+                cursor.moveNext();
+            }
+            catch (e:ItemPendingError)
+            {
+                // item pending
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *  @private
+     */
+    private function moveToFirst():void
+    {
+        childNodes = null;
+
+        //first move to the begining of the top level collection
+        // let it throw an IPE, the classes using this cursor will handle it
+        modelCursor.seek(CursorBookmark.FIRST, 0);
+
+        if (model.length > 1)
+            more = true;
+        else
+            more = false;
+        currentChildBookmark = CursorBookmark.FIRST;
+        parentNodes = [];
+        childIndexStack = [];
+        currentIndex = 0;
+        _currentDepth = 1;
+    }
+
+    /**
+     *  @private
+     */
+    public function moveToLast():void
+    {
+        childNodes = null;
+        childIndexStack = [];
+        _currentDepth = 1;
+        parentNodes = [];
+        var emptyBranch:Boolean = false;
+
+        //first move to the end of the top level collection
+        // let it throw an IPE, the classes using this cursor will handle it
+        modelCursor.seek(CursorBookmark.LAST, 0);
+
+        //if its a branch and open then get children for the last item
+        var currentNode:Object = modelCursor.current;
+        //if current node is open get its children
+        while (collection.openNodes[UIDUtil.getUID(currentNode)] &&
+               hierarchicalData.canHaveChildren(currentNode) &&
+               hierarchicalData.hasChildren(currentNode))
+        {
+            var previousChildNodes:ICollectionView = childNodes;
+            childNodes = collection.getChildren(currentNode);
+            if (childNodes != null && childNodes.length > 0)
+            {
+                var childCursor:IViewCursor = childNodes.createCursor();
+                try
+                {
+                    childCursor.seek(CursorBookmark.LAST);
+                }
+                catch (e:ItemPendingError)
+                {
+                    // just break because if the last child item is pending
+                    // return its parent
+                    break;
+                }
+                parentNodes.push(currentNode);
+                childIndexStack.push(currentChildBookmark);
+                currentNode = childCursor.current;
+                currentChildBookmark = CursorBookmark.LAST;
+                try
+                {
+                    // this is needed because the cursor bookmark for
+                    // the zero position and CursorBookmark.FIRST is not
+                    // same. this condition is encountered while doing
+                    // a movePrevious()
+                    childCursor.movePrevious();
+                    if (childCursor.bookmark == CursorBookmark.FIRST)
+                        currentChildBookmark = CursorBookmark.FIRST;
+                }
+                catch (e:ItemPendingError)
+                {
+                }
+                _currentDepth++;
+            }
+            else
+            {
+                childNodes = previousChildNodes;
+                break;
+            }
+        }
+        currentIndex = collection.length - 1;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Event handlers
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    public function collectionChangeHandler(event:CollectionEvent):void
+    {
+        var i:int;
+        var n:int;
+        var node:Object;
+        var nodeParent:Object
+        var parent:Object;
+        var parentStack:Array;
+        var parentTable:Dictionary;
+        var isBefore:Boolean = false;
+
+        // get the parent of the current item
+        parentStack = getParentStack(current);
+        // hash it by parent to map to depth
+        parentTable = new Dictionary();
+        n = parentStack.length;
+        // don't insert the immediate parent
+        for (i = 0; i < n - 1; i++)
+        {
+            // 0 is null parent (the model)
+            parentTable[parentStack[i]] = i + 1;
+        }
+        // remember the current parent
+        parent = parentStack[parentStack.length - 1];
+
+        var tmpChildnodes:ICollectionView;
+        var childCursor:IViewCursor;
+
+        if (event.kind == CollectionEventKind.ADD)
+        {
+            n = event.items.length;
+            if (event.location <= currentIndex)
+            {
+                currentIndex += n;
+                isBefore = true;
+            }
+
+            for (i = 0; i < n; i++)
+            {
+                node = event.items[i];
+                if (isBefore)
+                {
+                    // if the added node is before the current
+                    // and they share parent's then we have to
+                    // adjust the currentChildIndex or
+                    // the stack of child indexes.
+                    nodeParent = collection.getParentItem(node);
+                    tmpChildnodes = collection.getChildren(nodeParent);
+                    if (nodeParent == parent)
+                    {
+                        if (tmpChildnodes != null)
+                        {
+                            childCursor = tmpChildnodes.createCursor();
+                            try
+                            {
+                                childCursor.seek(currentChildBookmark);
+                                childCursor.moveNext();
+                                currentChildBookmark = childCursor.bookmark;
+                            }
+                            catch (e:ItemPendingError)
+                            {
+
+                            }
+                        }
+                    }
+                    else if (parentTable[nodeParent] != null)
+                    {
+                        if (tmpChildnodes != null)
+                        {
+                            childCursor = tmpChildnodes.createCursor();
+                            try
+                            {
+                                childCursor.seek(currentChildBookmark);
+                                childCursor.moveNext();
+                                currentChildBookmark = childCursor.bookmark;
+                            }
+                            catch (e:ItemPendingError)
+                            {
+                            }
+                            childIndexStack[parentTable[nodeParent]] = currentChildBookmark;
+                        }
+                    }
+                }
+            }
+
+        }
+        else if (event.kind == CollectionEventKind.REMOVE)
+        {
+            n = event.items.length;
+            if (event.location <= currentIndex)
+            {
+                if (event.location + n >= currentIndex)
+                {
+                    // the current node was removed
+                    // the list classes expect that we
+                    // leave the cursor on whatever falls
+                    // into that slot
+                    var newIndex:int = event.location;
+                    moveToFirst();
+                    seek(CursorBookmark.FIRST, newIndex);
+                    for (i = 0; i < n; i++)
+                    {
+                        node = event.items[i];
+                        delete collection.parentMap[UIDUtil.getUID(node)];
+                    }
+                    return;
+                }
+
+                currentIndex -= n;
+                isBefore = true;
+            }
+
+            for (i = 0; i < n; i++)
+            {
+                node = event.items[i];
+                if (isBefore)
+                {
+                    // if the removed node is before the current
+                    // and they share parent's then we have to
+                    // adjust the currentChildIndex or
+                    // the stack of child indexes.
+                    nodeParent = collection.getParentItem(node);
+                    tmpChildnodes = collection.getChildren(nodeParent);
+                    if (nodeParent == parent)
+                    {
+                        if (tmpChildnodes != null)
+                        {
+                            childCursor = tmpChildnodes.createCursor();
+                            try
+                            {
+                                childCursor.seek(currentChildBookmark);
+                                childCursor.movePrevious();
+                                currentChildBookmark = childCursor.bookmark;
+                            }
+                            catch (e:ItemPendingError)
+                            {
+
+                            }
+                        }
+                    }
+                    else if (parentTable[nodeParent] != null)
+                    {
+                        if (tmpChildnodes != null)
+                        {
+                            childCursor = tmpChildnodes.createCursor();
+                            try
+                            {
+                                childCursor.seek(currentChildBookmark);
+                                childCursor.movePrevious();
+                                currentChildBookmark = childCursor.bookmark;
+                            }
+                            catch (e:ItemPendingError)
+                            {
+                            }
+                            childIndexStack[parentTable[nodeParent]] = currentChildBookmark;
+                        }
+                    }
+                }
+                delete collection.parentMap[UIDUtil.getUID(node)];
+            }
+
+        }
+        else if (event.kind == CollectionEventKind.RESET)
+        {
+            // update the source collection and the cursor
+            model = collection.treeData;
+            modelCursor = model.createCursor();
+            // dispatch CURSOR_UPDATE event
+            collection.dispatchEvent(new FlexEvent(FlexEvent.CURSOR_UPDATE));
+        }
+		else if (event.kind == CollectionEventKind.REFRESH)
+		{
+			// find the correct index of the item
+			if (!(beforeFirst || afterLast))
+			{
+				findFirst(current);
+			}
+		}
+    }
+}
+
+}


Transferred from the Adobe Open Source Subversion Repository

Revision: 23246
Author:   cframpto@adobe.com
Date:     2011-12-20T17:40:08.069454Z

Log Message:
-----------
Rollback 23243.  If comment followed header it was stripped as well.

Modified Paths:
--------------
2361 paths were modified

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1290692 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/advancedgrids/src/mx/styles/metadata/FocusStyles.as
+++ frameworks/projects/advancedgrids/src/mx/styles/metadata/FocusStyles.as
@@ -1,4 +1,24 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  ADOBE SYSTEMS INCORPORATED
+//  Copyright 2009 Adobe Systems Incorporated
+//  All Rights Reserved.
+//
+//  NOTICE: Adobe permits you to use, modify, and distribute this file
+//  in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////

+/**
+ *  Specifies the alpha transparency value of the focus skin.
+ *
+ *  @default 0.4
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
 [Style(name="focusAlpha", type="Number", inherit="no")]

 /**


Transferred from the Adobe Open Source Subversion Repository

Revision: 23243
Author:   cframpto@adobe.com
Date:     2011-12-20T00:59:57.384047Z

Log Message:
-----------
In frameworks, remove Adobe headers from all files except xml/mxml file types.  There are also a few .txt files that are license files that I didn't touch yet.

Modified Paths:
--------------
2361 paths were modified

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1265176 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/mobiletheme/src/spark/skins/mobile/ButtonBarSkin.as
+++ frameworks/projects/mobiletheme/src/spark/skins/mobile/ButtonBarSkin.as
@@ -1,13 +1,3 @@
-////////////////////////////////////////////////////////////////////////////////
-//
-//  ADOBE SYSTEMS INCORPORATED
-//  Copyright 2010 Adobe Systems Incorporated
-//  All Rights Reserved.
-//
-//  NOTICE: Adobe permits you to use, modify, and distribute this file
-//  in accordance with the terms of the license agreement accompanying it.
-//
-////////////////////////////////////////////////////////////////////////////////

 package spark.skins.mobile
 {


Transferred from the Adobe Open Source Subversion Repository

Revision: 17978
Author:   hmuller@adobe.com
Date:     2010-09-30T23:20:34.653070Z

Log Message:
-----------
Restored support for ColumnHeaderBar event dispatching and added support for interactive column resizing.

Fixed support for DataGrid,Grid requestedColumnCount.

Renamed protected grid event handler methods, added an underscore: grid_RollOverHandler, grid_RollOutHandler, grid_MouseUpHandler, grid_MouseDownHandler.

Added SEPARATOR_DOUBLE_CLICK GridEvent type.

Remove unused private Grid/isEventTargetExcludeded() method.

QE notes:
Doc notes:
Bugs: SDK-28005, SDK-26364
Reviewer: Kevin
Tests run: checkin, mustella cyclone
Is noteworthy for integration: no

Modified Paths:
--------------
<path kind="file" action="M">/private/flex/sdk/branches/hero_private/frameworks/projects/spark/src/spark/components/Grid.as</path>
<path kind="file" action="M">/private/flex/sdk/branches/hero_private/frameworks/projects/spark/src/spark/events/GridEvent.as</path>
<path kind="file" action="M">/private/flex/sdk/branches/hero_private/frameworks/projects/spark/src/spark/components/ColumnHeaderBar.as</path>
<path kind="file" action="M">/private/flex/sdk/branches/hero_private/frameworks/projects/spark/src/spark/components/supportClasses/GridColumn.as</path>
<path kind="file" action="M">/private/flex/sdk/branches/hero_private/frameworks/projects/spark/src/spark/components/DataGrid.as</path>
<path kind="file" action="M">/private/flex/sdk/branches/hero_private/frameworks/projects/spark/defaults.css</path>
<path kind="file" action="M">/private/flex/sdk/branches/hero_private/frameworks/projects/spark/src/spark/components/supportClasses/ColumnHeaderBarLayout.as</path>

git-svn-id: 7146a936b37d36e51ea0d66f8acbe0b8281bc7b7@1279054 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/spark/src/spark/components/GridColumnHeaderGroup.as
+++ frameworks/projects/spark/src/spark/components/GridColumnHeaderGroup.as
@@ -17,6 +17,7 @@
 import flash.geom.Point;
 import flash.geom.Rectangle;

+import mx.collections.IList;
 import mx.core.IFactory;
 import mx.core.IVisualElement;
 import mx.core.mx_internal;
@@ -34,6 +35,187 @@
 use namespace mx_internal;

 //--------------------------------------
+//  Events
+//--------------------------------------
+
+/**
+ *  Dispatched when the mouse button is pressed over a column header.
+ *
+ *  @eventType spark.events.GridEvent.GRID_MOUSE_DOWN
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridMouseDown", type="spark.events.GridEvent")]
+
+
+/**
+ *  Dispatched after a GRID_MOUSE_DOWN event if the mouse moves before the button is released.
+ *
+ *  @eventType spark.events.GridEvent.GRID_MOUSE_DRAG
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridMouseDrag", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched after a GRID_MOUSE_DOWN event when the mouse button is released, even
+ *  if the mouse is no longer within the ColumnHeaderBar.
+ *
+ *  @eventType spark.events.GridEvent.GRID_MOUSE_UP
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridMouseUp", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse enters a column header.
+ *
+ *  @eventType spark.events.GridEvent.GRID_ROLL_OVER
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridRollOver", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse leaves a column header.
+ *
+ *  @eventType spark.events.GridEvent.GRID_ROLL_OUT
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridRollOut", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse is clicked over a column header.
+ *
+ *  @eventType spark.events.GridEvent.GRID_CLICK
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridClick", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse is double-clicked over a column header.
+ *
+ *  @eventType spark.events.GridEvent.GRID_DOUBLE_CLICK
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridDoubleClick", type="spark.events.GridEvent")]
+
+
+/**
+ *  Dispatched when the mouse button is pressed over a column header.
+ *
+ *  @eventType spark.events.GridEvent.GRID_MOUSE_DOWN
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="gridMouseDown", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched after a SEPARATOR_MOUSE_DOWN event if the mouse moves before
+ *  the button is released.
+ *
+ *  @eventType spark.events.GridEvent.SEPARATOR_MOUSE_DRAG
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="separatorMouseDrag", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched after a SEPARATOR_MOUSE_DOWN event when the mouse button is
+ *  released, even if the mouse is no longer within the separator affordance.
+ *
+ *  @eventType spark.events.GridEvent.SEPARATOR_MOUSE_UP
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="separatorMouseUp", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse enters the area defined by a column
+ *  separator and separatorMouseWidth.
+ *
+ *  @eventType spark.events.GridEvent.SEPARATOR_ROLL_OVER
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="separatorRollOver", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse leaves the area defined by a column
+ *  separator and separatorMouseWidth.
+ *
+ *  @eventType spark.events.GridEvent.SEPARATOR_ROLL_OUT
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="separatorRollOut", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse is clicked over a column header separator.
+ *
+ *  @eventType spark.events.GridEvent.SEPARATOR_CLICK
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="separatorClick", type="spark.events.GridEvent")]
+
+/**
+ *  Dispatched when the mouse is double-clicked over a column
+ *  header separator.
+ *
+ *  @eventType spark.events.GridEvent.SEPARATOR_DOUBLE_CLICK
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 10
+ *  @playerversion AIR 2.0
+ *  @productversion Flex 4.5
+ */
+[Event(name="separatorDoubleClick", type="spark.events.GridEvent")]
+
+
+//--------------------------------------
 //  Styles
 //--------------------------------------

@@ -121,6 +303,15 @@
         overlayGroup = new Group();
         overlayGroup.layout = new LayoutBase(); // no layout
         overlay.addDisplayObject(overlayGroup);
+
+        // Event handler that dispatch GridEvents
+
+        MouseEventUtil.addDownDragUpListeners(this,
+            chb_mouseDownDragUpHandler,
+            chb_mouseDownDragUpHandler,
+            chb_mouseDownDragUpHandler);
+        addEventListener(MouseEvent.MOUSE_MOVE, chb_mouseMoveHandler);
+        addEventListener(MouseEvent.ROLL_OUT, chb_mouseRollOutHandler);
     }

     //--------------------------------------------------------------------------
@@ -249,12 +440,80 @@
         dispatchChangeEvent("overlayGroupChanged");
     }

+    //----------------------------------
+    //  separatorMouseWidth
+    //----------------------------------
+
+    [Bindable("separatorMouseWidthChanged")]
+
+    private var _separatorMouseWidth:Number = 5;
+
+    /**
+     *  Horizontal space on either side of a column separator that's considered to be
+     *  part of the separator for the sake of mouse event dispatching.
+     *
+     *
Separators are often just one pixel wide which makes interacting with them difficult.
+     *  This value is used by getSeparatorIndexAt() to give separators a wider
+     *  berth, so that separator events are dispatched when the mouse is closer than
+     *  separatorMouseWidth to the horizontal midpoint of a separator.

+     *
+     *  @default 5
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 1.5
+     *  @productversion Flex 4.5
+     */
+    public function get separatorMouseWidth():Number
+    {
+        return _separatorMouseWidth;
+    }
+
+    /**
+     *  @private
+     */
+    public function set separatorMouseWidth(value:Number):void
+    {
+        if (_separatorMouseWidth == value)
+            return;
+
+        _separatorMouseWidth = value;
+        invalidateDisplayList();
+        dispatchChangeEvent("separatorMouseWidthChanged");
+    }
+
     //--------------------------------------------------------------------------
     //
     //  Methods
     //
     //--------------------------------------------------------------------------
-
+
+    /**
+     *  @copy spark.components.supportClasses.ColumnHeaderBarLayout#getColumnIndexAt()
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    public function getHeaderIndexAt(x:Number, y:Number):int
+    {
+        return ColumnHeaderBarLayout(layout).getHeaderIndexAt(x, y);
+    }
+
+    /**
+     *  @copy spark.components.supportClasses.ColumnHeaderBarLayout#getSeparatorIndexAt()
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    public function getSeparatorIndexAt(x:Number, y:Number):int
+    {
+        return ColumnHeaderBarLayout(layout).getSeparatorIndexAt(x, y);
+    }
+
     /**
      *  @copy spark.components.supportClasses.ColumnHeaderBarLayout#getHeaderRendererAt()
      *
@@ -268,5 +527,278 @@
         return ColumnHeaderBarLayout(layout).getHeaderRendererAt(columnIndex);
     }

+    /**
+     *  @copy spark.components.supportClasses.ColumnHeaderBarLayout#getHeaderBounds()
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    public function getHeaderBounds(columnIndex:int):Rectangle
+    {
+        return ColumnHeaderBarLayout(layout).getHeaderBounds(columnIndex);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  GridEvent dispatching
+    //
+    //--------------------------------------------------------------------------
+
+    // The down,roll pairs of variables below define column indices.  Only one
+    // member of each pair will be not equal to -1 at a time.
+
+    private var rollColumnIndex:int = -1;      // column mouse has rolled into
+    private var rollSeparatorIndex:int = -1;   // separator mouse has rolled into
+    private var downColumnIndex:int = -1;      // column button press occurred on
+    private var downSeparatorIndex:int = -1;   // separator button press occurred on
+
+    /**
+     *  This method is called when a MOUSE_DOWN event occurs within the column header bar and
+     *  for all subsequent MOUSE_MOVE events until the button is released (even if the
+     *  mouse leaves the column header bar).  The last event in such a "down drag up" gesture is
+     *  always a MOUSE_UP.  By default this method dispatches GRID_MOUSE_DOWN,
+     *  GRID_MOUSE_DRAG, or a GRID_MOUSE_UP event in response to the the corresponding
+     *  mouse event on a column header or SEPARATOR_MOUSE_DOWN, SEPARATOR_MOUSE_DRAG,
+     *  or a SEPARATOR_MOUSE_UP event in response to the the corresponding
+     *  mouse event on a column header separator.
+     *
+     *  The GridEvent's columnIndex, column itemRenderer properties correspond to the
+     *  column header or separator under the mouse.
+     *
+     *  @param event A MOUSE_DOWN, MOUSE_MOVE, or MOUSE_UP MouseEvent from a
+     *  down/move/up gesture initiated within the column header bar.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    protected function chb_mouseDownDragUpHandler(event:MouseEvent):void
+    {
+        const eventStageXY:Point = new Point(event.stageX, event.stageY);
+        const eventHeaderBarXY:Point = globalToLocal(eventStageXY);
+        const eventSeparatorIndex:int = getSeparatorIndexAt(eventHeaderBarXY.x, 0);
+        const eventColumnIndex:int =
+            (eventSeparatorIndex == -1) ? getHeaderIndexAt(eventHeaderBarXY.x, 0) : -1;
+
+        var gridEventType:String;
+        switch(event.type)
+        {
+            case MouseEvent.MOUSE_MOVE:
+                gridEventType = (downSeparatorIndex != -1) ? GridEvent.SEPARATOR_MOUSE_DRAG : GridEvent.GRID_MOUSE_DRAG;
+                break;
+
+            case MouseEvent.MOUSE_UP:
+                gridEventType = (downSeparatorIndex != -1) ? GridEvent.SEPARATOR_MOUSE_UP : GridEvent.GRID_MOUSE_UP;
+                break;
+
+            case MouseEvent.MOUSE_DOWN:
+                if (eventSeparatorIndex != -1)
+                {
+                    gridEventType = GridEvent.SEPARATOR_MOUSE_DOWN;
+                    downSeparatorIndex = eventSeparatorIndex;
+                    downColumnIndex = -1;
+                }
+                else
+                {
+                    gridEventType = GridEvent.GRID_MOUSE_DOWN;
+                    downSeparatorIndex = -1;
+                    downColumnIndex = eventSeparatorIndex;
+                }
+                break;
+        }
+
+        const columnIndex:int = (eventSeparatorIndex != -1) ? eventSeparatorIndex : eventColumnIndex;
+        dispatchGridEvent(event, gridEventType, eventHeaderBarXY, columnIndex);
+    }
+
+    /**
+     *  This method is called whenever a MOUSE_MOVE event occurs and the
+     *  button is not pressed.   Despite the fact that the area considered to be
+     *  occupied by the separators overlaps the headers (see mouseSeparatorWidth)
+     *  the mouse is considered to be in either a header or a separator, but not both.
+     *
+     *  This method dispatches a GRID_ROLL_OVER event when the mouse enters a header,
+     *  a SEPARATOR_ROLL_OVER when the mouse enters a separator, and GRID_ROLL_OUT
+     *  and SEPARATOR_ROLL_OUT when the mouse leaves a header or separator respectively.
+     *
+     *  Listeners are guaranteed to receive a GRID_ROLL_OUT event for every
+     *  GRID_ROLL_OVER event and to receive a SEPARATOR_ROLL_OUT event for
+     *  every SEPARATOR_ROLL_OVER event.
+     *
+     *  @param event A MOUSE_MOVE MouseEvent within the column header bar
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    protected function chb_mouseMoveHandler(event:MouseEvent):void
+    {
+        const eventStageXY:Point = new Point(event.stageX, event.stageY);
+        const eventHeaderBarXY:Point = globalToLocal(eventStageXY);
+        const eventSeparatorIndex:int = getSeparatorIndexAt(eventHeaderBarXY.x, 0);
+        const eventColumnIndex:int =
+            (eventSeparatorIndex == -1) ? getHeaderIndexAt(eventHeaderBarXY.x, 0) : -1;
+
+        if (eventSeparatorIndex != rollSeparatorIndex)
+        {
+            if (rollSeparatorIndex != -1)
+                dispatchGridEvent(event, GridEvent.SEPARATOR_ROLL_OUT, eventHeaderBarXY, rollSeparatorIndex);
+            if (eventSeparatorIndex != -1)
+                dispatchGridEvent(event, GridEvent.SEPARATOR_ROLL_OVER, eventHeaderBarXY, eventSeparatorIndex);
+        }
+
+        if (eventColumnIndex != rollColumnIndex)
+        {
+            if (rollColumnIndex != -1)
+                dispatchGridEvent(event, GridEvent.GRID_ROLL_OUT, eventHeaderBarXY, rollColumnIndex);
+            if (eventColumnIndex != -1)
+                dispatchGridEvent(event, GridEvent.GRID_ROLL_OVER, eventHeaderBarXY, eventColumnIndex);
+        }
+
+        rollColumnIndex = eventColumnIndex;
+        rollSeparatorIndex = eventSeparatorIndex;
+    }
+
+    /**
+     *  Called when the mouse moves out of the ColumnHeaderbar.
+     *  By default it dispatches either a GRID_ROLL_OUT or a
+     *  SEPARATOR_ROLL_OUT event.
+     *
+     *  @param event A ROLL_OUT MouseEvent from the column header bar.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    protected function chb_mouseRollOutHandler(event:MouseEvent):void
+    {
+        const eventStageXY:Point = new Point(event.stageX, event.stageY);
+        const eventHeaderBarXY:Point = globalToLocal(eventStageXY);
+
+        if (rollSeparatorIndex != -1)
+            dispatchGridEvent(event, GridEvent.SEPARATOR_ROLL_OUT, eventHeaderBarXY, rollSeparatorIndex);
+        else if (rollColumnIndex != -1)
+            dispatchGridEvent(event, GridEvent.GRID_ROLL_OUT, eventHeaderBarXY, rollColumnIndex);
+
+        rollColumnIndex = -1;
+        rollSeparatorIndex = -1;
+    }
+
+    /**
+     *  This method is called whenever a CLICK MouseEvent occurs on the
+     *  column header bar if both the corresponding down and up events occur
+     *  within the same column header cell. By default it dispatches a
+     *  GRID_CLICK event.
+     *
+     *  @param event A CLICK MouseEvent from the column header bar.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    protected function chb_clickHandler(event:MouseEvent):void
+    {
+        const eventStageXY:Point = new Point(event.stageX, event.stageY);
+        const eventHeaderBarXY:Point = globalToLocal(eventStageXY);
+        const eventSeparatorIndex:int = getSeparatorIndexAt(eventHeaderBarXY.x, 0);
+        const eventColumnIndex:int =
+            (eventSeparatorIndex == -1) ? getHeaderIndexAt(eventHeaderBarXY.x, 0) : -1;
+
+        if ((eventSeparatorIndex != -1) && (downSeparatorIndex == eventSeparatorIndex))
+            dispatchGridEvent(event, GridEvent.SEPARATOR_CLICK, eventHeaderBarXY, eventSeparatorIndex);
+        else if ((eventColumnIndex != -1) && (downColumnIndex == eventColumnIndex))
+            dispatchGridEvent(event, GridEvent.GRID_CLICK, eventHeaderBarXY, eventColumnIndex);
+    }
+
+    /**
+     *  This method is called whenever a DOUBLE_CLICK MouseEvent occurs
+     *  if the corresponding sequence of down and up events occur within
+     *  the same column header cell.  It dispatches a GRID_DOUBLE_CLICK event.
+     *
+     *  @param event A DOUBLE_CLICK MouseEvent from the column header bar.
+     *
+     *  @see flash.display.InteractiveObject#doubleClickEnabled
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    protected function chb_doubleClickHandler(event:MouseEvent):void
+    {
+        const eventStageXY:Point = new Point(event.stageX, event.stageY);
+        const eventHeaderBarXY:Point = globalToLocal(eventStageXY);
+        const eventSeparatorIndex:int = getSeparatorIndexAt(eventHeaderBarXY.x, 0);
+        const eventColumnIndex:int =
+            (eventSeparatorIndex == -1) ? getHeaderIndexAt(eventHeaderBarXY.x, 0) : -1;
+
+        if ((eventSeparatorIndex != -1) && (downSeparatorIndex == eventSeparatorIndex))
+            dispatchGridEvent(event, GridEvent.SEPARATOR_DOUBLE_CLICK, eventHeaderBarXY, eventSeparatorIndex);
+        else if ((eventColumnIndex != -1) && (downColumnIndex == eventColumnIndex))
+            dispatchGridEvent(event, GridEvent.GRID_DOUBLE_CLICK, eventHeaderBarXY, eventColumnIndex);
+    }
+
+    /**
+     *  @private
+     */
+    private function dispatchGridEvent(mouseEvent:MouseEvent, type:String, headerBarXY:Point, columnIndex:int):void
+    {
+        const column:GridColumn = getColumnAt(columnIndex);
+        const item:Object = null;
+        const itemRenderer:IVisualElement = getHeaderRendererAt(columnIndex);
+        const bubbles:Boolean = mouseEvent.bubbles;
+        const cancelable:Boolean = mouseEvent.cancelable;
+        const relatedObject:InteractiveObject = mouseEvent.relatedObject;
+        const ctrlKey:Boolean = mouseEvent.ctrlKey;
+        const altKey:Boolean = mouseEvent.altKey;
+        const shiftKey:Boolean = mouseEvent.shiftKey;
+        const buttonDown:Boolean = mouseEvent.buttonDown;
+        const delta:int = mouseEvent.delta;
+
+        const event:GridEvent = new GridEvent(
+            type, bubbles, cancelable,
+            headerBarXY.x, headerBarXY.y, -1, columnIndex, column, item, itemRenderer,
+            relatedObject, ctrlKey, altKey, shiftKey, buttonDown, delta);
+        dispatchEvent(event);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Private methods, properties
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    private function get dataGrid():DataGrid
+    {
+        return owner as DataGrid;
+    }
+
+    /**
+     *  @private
+     */
+    private function get grid():Grid
+    {
+        return dataGrid ? dataGrid.grid : null;
+    }
+
+    private function getColumnAt(columnIndex:int):GridColumn
+    {
+        const grid:Grid = grid;
+        if (!grid || !grid.columns)
+            return null;
+
+        const columns:IList = grid.columns;
+        return ((columnIndex >= 0) && (columnIndex < columns.length)) ? columns.getItemAt(columnIndex) as GridColumn : null;
+    }
+
 }
 }