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@1248487 13f79535-47bb-0310-9956-ffa450edef68

--- frameworks/projects/advancedgrids/src/mx/controls/AdvancedDataGrid.as
+++ frameworks/projects/advancedgrids/src/mx/controls/AdvancedDataGrid.as
@@ -0,0 +1,9126 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.controls
+{
+
+import flash.display.DisplayObject;
+import flash.display.Graphics;
+import flash.display.Shape;
+import flash.display.Sprite;
+import flash.events.Event;
+import flash.events.KeyboardEvent;
+import flash.events.MouseEvent;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import flash.ui.Keyboard;
+import flash.utils.Dictionary;
+import flash.utils.describeType;
+import flash.utils.getDefinitionByName;
+import flash.utils.getQualifiedClassName;
+
+import mx.collections.ArrayCollection;
+import mx.collections.CursorBookmark;
+import mx.collections.HierarchicalCollectionView;
+import mx.collections.HierarchicalCollectionViewCursor;
+import mx.collections.HierarchicalData;
+import mx.collections.ICollectionView;
+import mx.collections.IGroupingCollection;
+import mx.collections.IGroupingCollection2;
+import mx.collections.IHierarchicalCollectionView;
+import mx.collections.IHierarchicalData;
+import mx.collections.IViewCursor;
+import mx.collections.ItemResponder;
+import mx.collections.Sort;
+import mx.collections.SortField;
+import mx.collections.SummaryObject;
+import mx.collections.errors.ItemPendingError;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridBaseSelectionData;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridBaseSelectionPending;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridColumnGroup;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridGroupItemRenderer;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridHeaderInfo;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridListData;
+import mx.controls.advancedDataGridClasses.AdvancedDataGridRendererDescription;
+import mx.controls.advancedDataGridClasses.IAdvancedDataGridRendererProvider;
+import mx.controls.advancedDataGridClasses.SortInfo;
+import mx.controls.listClasses.BaseListData;
+import mx.controls.listClasses.IDropInListItemRenderer;
+import mx.controls.listClasses.IListItemRenderer;
+import mx.controls.listClasses.ListBaseSeekPending;
+import mx.controls.listClasses.ListRowInfo;
+import mx.core.ClassFactory;
+import mx.core.EdgeMetrics;
+import mx.core.EventPriority;
+import mx.core.FlexShape;
+import mx.core.FlexSprite;
+import mx.core.IDataRenderer;
+import mx.core.IFactory;
+import mx.core.IFlexDisplayObject;
+import mx.core.IInvalidating;
+import mx.core.IUITextField;
+import mx.core.ScrollPolicy;
+import mx.core.SpriteAsset;
+import mx.core.UIComponent;
+import mx.core.UIComponentGlobals;
+import mx.core.mx_internal;
+import mx.effects.Tween;
+import mx.events.AdvancedDataGridEvent;
+import mx.events.AdvancedDataGridEventReason;
+import mx.events.CollectionEvent;
+import mx.events.CollectionEventKind;
+import mx.events.DragEvent;
+import mx.events.FlexEvent;
+import mx.events.IndexChangedEvent;
+import mx.events.ListEvent;
+import mx.events.ListEventReason;
+import mx.events.ScrollEvent;
+import mx.events.ScrollEventDetail;
+import mx.events.ScrollEventDirection;
+import mx.events.TweenEvent;
+import mx.managers.DragManager;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.styles.ISimpleStyleClient;
+import mx.styles.IStyleClient;
+import mx.utils.UIDUtil;
+
+use namespace mx_internal;
+
+//--------------------------------------
+//  Events
+//--------------------------------------
+
+/**
+*  Dispatched when a branch of the navigation tree is closed or collapsed.
+*
+*  @eventType mx.events.AdvancedDataGridEvent.ITEM_CLOSE
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Event(name="itemClose", type="mx.events.AdvancedDataGridEvent")]
+
+/**
+*  Dispatched when a branch of the navigation tree is opened or expanded.
+*
+*  @eventType mx.events.AdvancedDataGridEvent.ITEM_OPEN
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Event(name="itemOpen", type="mx.events.AdvancedDataGridEvent")]
+
+/**
+*  Dispatched when a tree branch open or close operation is initiated.
+*
+*  @eventType mx.events.AdvancedDataGridEvent.ITEM_OPENING
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Event(name="itemOpening", type="mx.events.AdvancedDataGridEvent")]
+
+/**
+*  Dispatched when the user drags a column outside of its column group.
+*  TheAdvancedDataGrid control does not provide a default event handler for this event.
+*
+*  @eventType mx.events.AdvancedDataGridEvent.HEADER_DRAG_OUTSIDE
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Event(name="headerDragOutside", type="mx.events.AdvancedDataGridEvent")]
+
+/**
+*  Dispatched when the user drops a column outside of its column group.
+*  TheAdvancedDataGrid control doesn't provide a default handler for this event.
+*
+*  @eventType mx.events.AdvancedDataGridEvent.HEADER_DROP_OUTSIDE
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Event(name="headerDropOutside", type="mx.events.AdvancedDataGridEvent")]
+
+//--------------------------------------
+//  Styles
+//--------------------------------------
+
+include "../styles/metadata/PaddingStyles.as";
+
+/**
+*  Colors for rows in an alternating pattern.
+*  Value can be an Array of two of more colors.
+*  For the AdvancedDataGrid controls,
+*  all items in a row have the same background color,
+*  and each row's background color is determined from the Array of colors.
+*  Used only if the backgroundColor property is not specified.
+*
+*  @default undefined
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="alternatingItemColors", type="Array", arrayType="uint", format="Color", inherit="yes")]
+
+/**
+*  Array of colors used for the rows of each level of the navigation tree
+*  of the AdvancedDataGrid control, in descending order.
+*
+*  @default undefined
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="depthColors", type="Array", arrayType="uint", format="Color", inherit="yes")]
+
+/**
+*  The default icon for a leaf node of the navigation tree.
+*
+*  The default value is TreeNodeIcon in the assets.swf file.
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="defaultLeafIcon", type="Class", format="EmbeddedFile", inherit="no")]
+
+/**
+*  The icon that is displayed next to an open branch node of the navigation tree.
+*
+*  The default value is TreeDisclosureOpen in the assets.swf file.
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="disclosureOpenIcon", type="Class", format="EmbeddedFile", inherit="no")]
+
+/**
+*  The icon that is displayed next to a closed branch node of the navigation tree.
+*
+*  The default value is TreeDisclosureClosed in the assets.swf file.
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="disclosureClosedIcon", type="Class", format="EmbeddedFile", inherit="no")]
+
+/**
+*  Specifies the folder open icon for a branch node of the navigation tree.
+*
+*  The default value is TreeFolderOpen in the assets.swf file.
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="folderOpenIcon", type="Class", format="EmbeddedFile", inherit="no")]
+
+/**
+*  Specifies the folder closed icon for a branch node of the navigation tree.
+*
+*  The default value is TreeFolderClosed in the assets.swf file.
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="folderClosedIcon", type="Class", format="EmbeddedFile", inherit="no")]
+
+/**
+*  The indentation for each node of the navigation tree, in pixels.
+*
+*  @default 17
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="indentation", type="Number", inherit="no")]
+
+/**
+*  Length of an open or close transition for the navigation tree, in milliseconds.
+*
+*  @default 250
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="openDuration", type="Number", format="Time", inherit="no")]
+
+/**
+*  Easing function to control component tweening.
+*
+*
The default value is undefined.

+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="openEasingFunction", type="Function", inherit="no")]
+
+/**
+*  The skin that defines the appearance of the separators between the text
+*  and icon parts of a header in a AdvancedDataGrid control.
+*
+*  @default undefined
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="headerSortSeparatorSkin", type="Class", inherit="no")]
+
+/**
+*  The class to use as the skin that defines the appearance of the
+*  separators between column headers of different depth in a AdvancedDataGrid control.
+*
+*  @default undefined
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="headerHorizontalSeparatorSkin", type="Class", inherit="no")]
+
+/**
+*  The disabled color of a list item.
+*
+*  @default 0xDDDDDD
+*
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="selectionDisabledColor", type="uint", format="Color", inherit="yes")]
+
+/**
+*  Reference to an easingFunction function used for controlling programmatic tweening.
+*
+*
The default value is undefined.

+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="selectionEasingFunction", type="Function", inherit="no")]
+
+/**
+*  Color of the text when the user rolls over a row.
+*
+*  @default 0x2B333C
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="textRollOverColor", type="uint", format="Color", inherit="yes")]
+
+/**
+*  Color of the text when the user selects a row.
+*
+*  @default 0x2B333C
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="textSelectedColor", type="uint", format="Color", inherit="yes")]
+
+/**
+*  The font family used by the AdvancedDataGridSortItemRenderer class
+*  to render the sort icon in the column header.
+*
+*  @default Verdana
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="sortFontFamily", type="String", inherit="yes")]
+
+/**
+*  The font size used by the AdvancedDataGridSortItemRenderer class
+*  to render the sort icon in the column header.
+*
+*  @default 10
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="sortFontSize", type="Number", format="Length", inherit="yes")]
+
+/**
+*  The font style used by the AdvancedDataGridSortItemRenderer class
+*  to render the sort icon in the column header.
+*
+*  @default normal
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="sortFontStyle", type="String", enumeration="normal,italic", inherit="yes")]
+
+/**
+*  The font weight used by the AdvancedDataGridSortItemRenderer class
+*  to render the sort icon in the column header.
+*
+*  @default normal
+*
+*  @langversion 3.0
+*  @playerversion Flash 9
+*  @playerversion AIR 1.1
+*  @productversion Flex 3
+*/
+[Style(name="sortFontWeight", type="String", enumeration="normal,bold", inherit="yes")]
+
+/*************************************************************************
+*
+* End of Tree Events, Styles and Metadata
+*
+*************************************************************************/
+
+[AccessibilityClass(implementation="mx.accessibility.AdvancedDataGridAccImpl")]
+
+[ResourceBundle("datamanagement")]
+/**
+*  The AdvancedDataGrid control expands on the functionality of the standard DataGrid control
+*  to add data visualization features to your Adobe Flex application.
+*  These features provide greater control of data display, data aggregation, and data formatting.
+*
+ *  The AdvancedDataGrid control is like a List control except that it can show
+ *  more than one column of data,
+ *  making it suited for showing objects with multiple properties.
+ *

+ *  The AdvancedDataGrid control provides the following features:
+ *

+ *
Columns of different widths or identical fixed widths.

+ *
Columns that the user can resize at run time.

+ *
Columns that the user can reorder at run time.

+ *
Optional customizable column headers.

+ *
Ability to use a custom item renderer for any column to display data
+ *  other than text.

+ *
Support for sorting the data by clicking on a column.

+ *

+ *

+ *  The AdvancedDataGrid control is intended for viewing data, and not as a
+ *  layout tool like an HTML table.
+ *  The mx.containers package provides those layout tools.
+ *
+ *  @mxml
+ *

+ *  The <mx:AdvancedDataGrid> tag inherits all of the tag attributes
+ *  of its superclass, except for labelField, iconField,
+ *  and iconFunction, and adds the following tag attributes:
+ *

+ *

+ *  <mx:AdvancedDataGrid
+ *    Properties
+ *    displayDisclosureIcon="true|false"
+ *    displayItemsExpanded="false|true"
+ *    groupedColumns="[]"
+ *    groupIconFunction="null"
+ *    groupItemRenderer="AdvancedDataGridGroupItemRenderer"
+ *    groupLabelFunction="null"
+ *    groupRowHeight="-1"
+ *    itemIcons="undefined"
+ *    lockedColumnCount="0"
+ *    lockedRowCount="0"
+ *    rendererProviders="[]"
+ *    selectedCells="null"
+ *    treeColumn="null"
+ *
+ *    Styles
+ *    alternatingItemColors="undefined"
+ *    defaultLeafIcon="TreeNodeIcon"
+ *    depthColors="undefined"
+ *    disclosureClosedIcon="TreeDisclosureClosed"
+ *    disclosureOpenIcon="TreeDisclosureOpen"
+ *    folderClosedIcon="TreeFolderClosed"
+ *    folderOpenIcon="TreeFolderOpen"
+ *    headerHorizontalSeparatorSkin="undefined"
+ *    indentation="17"
+ *    openDuration="250"
+ *    openEasingFunction="undefined"
+ *    paddingLeft="2"
+ *    paddingRight="0"
+ *    selectionDisabledColor="#DDDDDD"
+ *    selectionEasingFunction="undefined"
+ *    sortFontFamily="Verdana"
+ *    sortFontSize="10"
+ *    sortFontStyle="normal"
+ *    sortFontWeight="normal"
+ *    textRollOverColor="#2B333C"
+ *    textSelectedColor="#2B333C"
+ *
+ *    Events
+ *    headerDragOutside="No default"
+ *    headerDropOutside="No default"
+ *    itemClose="No default"
+ *    itemOpen="No default"
+ *    itemOpening="No default"
+ *  />
+ *
+ *  The following AdvancedDataGrid code sample specifies the column order:
+ *  <mx:AdvancedDataGrid>
+ *    <mx:dataProvider>
+ *        <mx:Object Artist="Pavement" Price="11.99"
+ *          Album="Slanted and Enchanted"/>
+ *        <mx:Object Artist="Pavement"
+ *          Album="Brighten the Corners" Price="11.99"/>
+ *    </mx:dataProvider>
+ *    <mx:columns>
+ *        <mx:AdvancedDataGridColumn dataField="Album"/>
+ *        <mx:AdvancedDataGridColumn dataField="Price"/>
+ *    </mx:columns>
+ *  </mx:AdvancedDataGrid>
+ *

+ *

+ *
+ *  @see mx.controls.advancedDataGridClasses.AdvancedDataGridItemRenderer
+ *  @see mx.controls.advancedDataGridClasses.AdvancedDataGridColumn
+ *  @see mx.controls.advancedDataGridClasses.AdvancedDataGridDragProxy
+ *  @see mx.events.AdvancedDataGridEvent
+ *  @see mx.controls.DataGrid
+ *
+ *  @includeExample examples/AdvancedDataGridExample.mxml
+ *
+ *  @langversion 3.0
+ *  @playerversion Flash 9
+ *  @playerversion AIR 1.1
+ *  @productversion Flex 3
+ */
+public class AdvancedDataGrid extends AdvancedDataGridBaseEx
+{
+    include "../core/Version.as";
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class mixins
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Placeholder for mixin by AdvancedDataGridAccImpl.
+     */
+    mx_internal static var createAccessibilityImplementation:Function;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Class constants
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * Indicates mouse is over the text part of the header.
+     * Used as a return value by mouseEventToHeaderPart.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const HEADER_TEXT_PART:String = "headerTextPart";
+
+    /**
+     * Indicates that the mouse is over the header part of the header.
+     * Used as a return value by
+     * the AdvancedDataGridHeaderRenderer.mouseEventToHeaderPart method.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public static const HEADER_ICON_PART:String = "headerIconPart";
+
+    /**
+     *  @private
+     */
+    private static var resourceManager:IResourceManager =
+                                ResourceManager.getInstance();
+
+    //--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  Constructor.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function AdvancedDataGrid()
+    {
+        super();
+        rendererDescriptionMap = new Dictionary(true);
+
+        groupItemRenderer = new ClassFactory(AdvancedDataGridGroupItemRenderer);
+
+        // Added Listener from Tree
+        addEventListener(AdvancedDataGridEvent.ITEM_OPENING, expandItemHandler,
+                         false, EventPriority.DEFAULT_HANDLER);
+
+        addEventListener(FlexEvent.UPDATE_COMPLETE, updateCompleteHandler);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Maps items to AdvancedDataGridDescription
+     */
+    private var rendererDescriptionMap:Dictionary;
+
+    /**
+     *  @private
+     */
+    private var isMeasuringHeader:Boolean;
+
+    /**
+     *  @private
+     *  Keep track of styles of the individual item renderers when custom
+     *  row/column formatting i.e. grid and column styleFunctions are applied.
+     */
+    private var oldStyles:Dictionary;
+
+    // Cell Selection variables
+    /**
+     *  @private
+     *  The first AdvancedDataGridBaseSelectionData in a link list of
+     *  AdvancedDataGridBaseSelectionData. This represents the item that was
+     *  most recently selected.  AdvancedDataGridBaseSelectionData instances are
+     *  linked together and keep track of the order the user selects an item.
+     *  This order is reflected in selectedCells.
+     */
+    mx_internal var firstCellSelectionData:AdvancedDataGridBaseSelectionData;
+
+    /**
+     *  A hash table of AdvancedDataGridBaseSelectionData objects that track
+     *  which items are currently selected.  The table is indexed by the UID of
+     *  the items and then the column number.
+     *
+     *  @see mx.controls.advancedDataGridClasses.AdvancedDataGridBaseSelectionData
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    mx_internal var cellSelectionData:Object = {};
+
+	/**
+	 *  Map of selections keyes by x,y and referred to by modified isCellAlreadySelected()
+	 *  and addToSelectedCells()
+	 *
+	 *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 4
+	 */
+	mx_internal var cellSelections:Object = {};
+
+    /**
+     *  A hash table of selection indicators.  This table allows the component
+     *  to quickly find and remove the indicators when the set of selected
+     *  items is cleared.  The table is indexed by the item's UID and column number.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    mx_internal var cellSelectionIndicators:Object = {};
+
+    /**
+     *  A hash table of data provider item renderers currently in view. The
+     *  table is indexed by the data provider item's UID and column number and is
+     *  used to quickly get the renderer used to display a particular item.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    // Parallel data structure to visibleData in listItems.
+    protected var visibleCellRenderers:Object = {};
+
+    /**
+     *  The column of the selected cell.
+     *
+     *  Used in conjunction with selectedIndex property to determine
+     *  the column and row indices of the selected cell.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var selectedColumnIndex:int = -1;
+
+    /**
+     *  The column index of the item that is currently rolled over or under the cursor.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var highlightColumnIndex:int = -1;
+
+    /**
+     *  The column name of the item under the caret.
+     *
+     *  Used in conjunction with the caretIndex property to determine
+     *  the column/row indices of the cell where the caret is located.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var caretColumnIndex:int = -1;
+
+    /**
+     *  The column index of the current anchor.
+     *
+     *  Use this property in conjunction with the ListBase.anchorIndex property
+     *  to determine the column and row
+     *  indices of the cell where the anchor is located.
+     *
+     *  @see mx.controls.listClasses.ListBase#anchorIndex
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var anchorColumnIndex:int = -1;
+
+    /**
+     *  A hash table of selection tweens.  This allows the component to
+     *  quickly find and clean up any tweens in progress if the set
+     *  of selected items is cleared.  The table is indexed by the item's UID
+     *  and column number.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var cellSelectionTweens:Object = {};
+
+    /**
+     *  Flag to indicate that selectedCells has changed
+     *
+     *  @private
+     */
+    private var selectedCellsChanged:Boolean = false;
+
+    /**
+     *  Temporary storage for selectedCells
+     *
+     *  @private
+     */
+    private var _temporary_selectedCells:Array = null;
+
+    /**
+     * Storage of sortInfos, used for the multi column sorting UI.
+     *
+     *  @private
+     */
+    private var visualSortInfo:Dictionary = new Dictionary();
+
+    /**
+     * Flag to check if design view data is set, so that openNodes can also be changed.
+     *
+     *  @private
+     */
+    private var designViewDataFlag:Boolean = false;
+
+    /**
+     *  @private
+     */
+    private var lastColumnWidth:Number = NaN;
+
+    /**
+     *  @private
+     */
+    protected var movingSelectionLayer:Sprite;
+
+    /**
+     *  @private
+     */
+    private var headerSelected:Boolean = true;
+
+    /**
+     *  @private
+     */
+    private var _lockedColumnCountVal:int;
+
+    /**
+     *  @private
+     */
+    private var lockedColumnCountChanged:Boolean = false;
+
+    /**
+     *  @private
+     */
+    private var headerItemsList:Array;
+
+    /**
+     *  @private
+     */
+    private var headerDraggedOutside:Boolean = false;
+
+    /**
+     *  @private
+     */
+    private var dropInfo:AdvancedDataGridEvent;
+
+    /**
+     *  @private
+     */
+    private var lastHeaderInfos:Array;
+
+    /**
+     *  @private
+     */
+    private var horizontalSeparators:Array;
+
+    /**
+     *  @private
+     */
+    private var horizontalLockedSeparators:Array;
+
+    /**
+     *  @private
+     */
+    private var numSeparators:int = 0;
+
+    private var groupedColumnsChanged:Boolean=false;
+
+    private var columnsChanged:Boolean = false;
+
+    private var designViewDataFlatType:String = "flat";
+    private var designViewDataTreeType:String = "tree";
+    private var designViewDataTypeChanged:Boolean = false;
+
+    mx_internal var columnsToInfo:Dictionary = new Dictionary();
+
+    /**
+     *  @private
+     *  Needed for Accessibility to know if column grouping is present or not.
+     */
+    mx_internal var columnGrouping:Boolean = false;
+
+    /**
+     *  @private
+     *  Item is currently in the process of opening
+     */
+    private var opening:Boolean;
+
+    /**
+     *  The tween object that animates rows
+     *
+     *  Users can add event listeners to this Object to get
+     *  notified when the tween starts, updates and ends.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected var tween:Object;
+
+    /**
+     *  @private
+     */
+    private var maskList:Array;
+
+    /**
+     *  @private
+     */
+    private var _userMaxHorizontalScrollPosition:Number = 0;
+
+    /**
+     *  @private
+     */
+    private var eventAfterTween:Object;
+
+    /**
+     *  Storage for the Group item renderer in case of item opening/closing events
+     *  @private
+     */
+    private var eventItemRenderer:IListItemRenderer;
+
+    /**
+     *  @private
+     */
+    private var oldLength:int = -1;
+
+    /**
+     *  @private
+     */
+    private var expandedItem:Object;
+
+    /**
+     *  @private
+     */
+    private var bSelectedItemRemoved:Boolean = false;
+
+    /**
+     *  @private
+     *  Storage for the groupLabelField property.
+     */
+    private var groupLabelField:String;
+
+    /**
+     *  @private
+     */
+    private var lastUserInteraction:Event;
+
+    /**
+     *  @private
+     *  automation delegate access
+     */
+    mx_internal var _dropData:Object;
+
+    /**
+     *  @private
+     */
+    mx_internal var isOpening:Boolean = false;
+
+    /**
+     *  @private
+     *  used by opening tween
+     *  rowIndex is the row below the row that was picked
+     *  and is the first one that will actually change
+     */
+    private var rowIndex:int;
+
+    /**
+     *  @private
+     *  Number of rows that are or will be tweened
+     */
+    private var rowsTweened:int;
+
+    /**
+     *  @private
+     */
+    private var rowList:Array;
+
+    /**
+     *  @private
+     *  variable to hold the IHierarchicalCollectionView instance provided by the user.
+     */
+    private var hierarchicalCollectionInstance:IHierarchicalCollectionView;
+
+    /**
+     *  @private
+     */
+    mx_internal var collectionLength:int;
+
+    /**
+     *  @private
+     */
+    private var dataProviderChanged:Boolean = false;
+
+    /**
+     *  @private
+     *  Storage variable for the original dataProvider
+     */
+    mx_internal var _rootModel:IHierarchicalData;
+
+    /**
+     *  @private
+     *  Storage variable for changes to displayItemsExpanded.
+     */
+    private var displayItemsExpandedChanged:Boolean = false;
+
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  dataProvider
+    //----------------------------------
+
+    [Bindable("collectionChange")]
+    [Inspectable(category="Data", defaultValue="null")]
+
+    /**
+     *  @private
+     */
+    override public function get dataProvider():Object
+    {
+        if(super.dataProvider)
+            return super.dataProvider;
+
+        return null;
+    }
+
+    /**
+     *
+     *  @private
+     */
+    override public function set dataProvider(value:Object):void
+    {
+        if (itemEditorInstance)
+            endEdit(AdvancedDataGridEventReason.OTHER);
+
+        if (isCellSelectionMode())
+        {
+            clearCellSelectionData();
+        }
+
+        if (_rootModel)
+            _rootModel.removeEventListener(
+                CollectionEvent.COLLECTION_CHANGE,
+                collectionChangeHandler);
+        if (value is IHierarchicalData)
+        {
+            _rootModel = value as IHierarchicalData;
+        }
+        else if (value is IHierarchicalCollectionView)
+        {
+            // if the dataProvider is IHierarchicalCollectionView,
+            // set it to super.dataProvider in commitProperties()
+            _rootModel = IHierarchicalCollectionView(value).source;
+            hierarchicalCollectionInstance = IHierarchicalCollectionView(value);
+        }
+        else
+        {
+            _rootModel = null;
+            hierarchicalCollectionInstance = null;
+            super.dataProvider = value;
+        }
+
+        if (_rootModel)
+           _rootModel.addEventListener(
+           CollectionEvent.COLLECTION_CHANGE,
+           collectionChangeHandler);
+
+        //flag for processing in commitProps
+        dataProviderChanged = true;
+        invalidateProperties();
+    }
+
+    //----------------------------------
+    //  lockedRowCount
+    //----------------------------------
+
+    /**
+     *  The index of the first row in the control that scrolls.
+     *  Rows above this one remain fixed in view.
+     *
+     *  @default 0
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override public function get lockedRowCount():int
+    {
+        // if dataProvider is hierarchical, return 0
+        // because lockedRowCount has no effect in a hierarchical display
+        if (_rootModel is IHierarchicalData)
+            return 0;
+
+        return super.lockedRowCount;
+    }
+
+    //----------------------------------
+    //  lockedColumnCount
+    //----------------------------------
+
+    /**
+     *  The index of the first column in the control that scrolls.
+     *  Columns to the left of this one remain fixed in view.
+     *
+     *
When using column groups, a column group is considered to be a single column.
+     *  For example, if you set this property to 2, and the left-most two column groups
+     *  contain two and three children, respectively, then you have effectively locked the
+     *  first five columns of the control.

+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override public function set lockedColumnCount(value:int):void
+    {
+        _lockedColumnCountVal = value;
+        lockedColumnCountChanged = true;
+
+        invalidateProperties();
+    }
+
+    //----------------------------------
+    //  columns
+    //----------------------------------
+
+    /**
+     *  @private
+     */
+    private var _columnsValue:Array;
+
+	[Inspectable(category="General", arrayType="mx.controls.advancedDataGridClasses.AdvancedDataGridColumn")]
+    /**
+     *  @private
+     */
+    override public function set columns(value:Array):void
+    {
+        _columnsValue = value;
+        columnsChanged = true;
+        generatedColumns = false;
+
+        invalidateProperties();
+    }
+
+    //----------------------------------
+    //  verticalScrollPosition
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Sets verticalScrollPosition and draw vertical lines again
+     *  if rendererProviders are used.
+     */
+    override public function set verticalScrollPosition(value:Number):void
+    {
+        var oldAnchorColumnIndex:int   = anchorColumnIndex;
+        var oldCaretColumnIndex:int    = caretColumnIndex;
+        var oldSelectedColumnIndex:int = selectedColumnIndex;
+
+        super.verticalScrollPosition = value;
+
+        anchorColumnIndex   = oldAnchorColumnIndex;
+        caretColumnIndex    = oldCaretColumnIndex;
+        selectedColumnIndex = oldSelectedColumnIndex;
+
+        // draw the vertically lines afresh if Custom Row Renderers are used
+        // i.e., update the vertical lines if items are spanning columns
+        if (rendererProviders.length != 0)
+          drawVerticalSeparators();
+
+        // draw the horizontal lines afresh if groupRowHeight is not -1
+        // and its not equal to rowHeight
+        if (!variableRowHeight && groupRowHeight != -1 && groupRowHeight != rowHeight)
+            drawHorizontalSeparators();
+
+        // Display cells set in selectionMode which are not yet visible
+        if (cellsWaitingToBeDisplayed)
+            processCellsWaitingToBeDisplayed();
+    }
+
+    //----------------------------------
+    //  horizontalScrollPosition
+    //----------------------------------
+
+    /**
+     *  @private
+     */
+    override public function set horizontalScrollPosition(value:Number):void
+    {
+        var oldAnchorColumnIndex:int   = anchorColumnIndex;
+        var oldCaretColumnIndex:int    = caretColumnIndex;
+        var oldSelectedColumnIndex:int = selectedColumnIndex;
+
+        super.horizontalScrollPosition = value;
+
+        anchorColumnIndex   = oldAnchorColumnIndex;
+        caretColumnIndex    = oldCaretColumnIndex;
+        selectedColumnIndex = oldSelectedColumnIndex;
+
+        // Display cells set in selectionMode which are not yet visible
+        if (cellsWaitingToBeDisplayed)
+            processCellsWaitingToBeDisplayed();
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    // groupedColumns
+    //----------------------------------
+
+    /**
+     *  @private
+     */
+    private var _groupedColumns:Array;
+
+    /**
+     *  An Array that defines the hierarchy of AdvancedDataGridColumn instances when performing column grouping.
+     *  If you specify both the columns and groupedColumns properties,
+     *  the control uses the groupedColumns property and ignores
+     *  the columns property.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get groupedColumns():Array
+    {
+        return _groupedColumns;
+    }
+
+    public function set groupedColumns(value:Array):void
+    {
+        //Validate
+        if(validateGroupedColumns(value))
+        {
+            if(_groupedColumns)
+            {
+                var n:int = _groupedColumns.length;
+                for ( var i:int = 0; i < n; i++)
+                {
+                    if(_groupedColumns[i] is AdvancedDataGridColumnGroup)
+                        columnGroupRendererChanged(AdvancedDataGridColumnGroup(_groupedColumns[i]));
+                }
+            }
+
+            _groupedColumns = value;
+            groupedColumnsChanged = true;
+            invalidateProperties();
+        }
+    }
+
+    //
+    // Cell Selection properties
+    //
+    //----------------------------------
+    // selectedCells
+    //----------------------------------
+
+    /**
+     *  @private
+     */
+    protected var _selectedCells:Array = [];
+
+    [Inspectable(category="Data", arrayType="Object")]
+    /**
+     *  Contains an Array of cell locations as row and column indices.
+     *  Changing the value of the selectionMode property
+     *  sets this property to null.
+     *
+     *
Note that these row and column indices are absolute values,
+     *  irrespective of the display. This is explained by a typical
+     *  selectedCells property setting as follows:

+     *
+     *

+     *  selectedCells = [ { rowIndex : r1, columnIndex : c1 },
+     *                    { rowIndex : r2, columnIndex : c2 },
+     *                    ... ]

+     *
+     *
Then, dataProvider[r1], columns[c1], dataProvider[r2], columns[c2],
+     *  etc. will always be valid.

+     *
+     *
If you want to programmatically change the set of selected cells, you
+     *  must get this Array, make modifications to the cells and order of
+     *  cells in the Array, and then assign the new array to the selectedCells
+     *  property. This is because the AdvancedDataGrid control returns a new
+     *  copy of the Array of selectedCells and therefore does not notice the
+     *  changes.

+     *
+     *
The value of the selectionMode property determines the data in
+     *  the rowIndex and columnIndex properties, as the following table describes:

+     *
+     *

+     *

+     *      selectionMode
+     *      Value of rowIndex and columnIndex properties
+     *

+     *

+     *      none
+     *      No selection allowed in the control, and selectedCells is null.
+     *

+     *

+     *      singleRow
+     *      Click any cell in the row to select the row. After the selection,
+     *       selectedCells contains a single Object:
+     *
[{rowIndex:selectedRowIndex, columnIndex: -1}]

+     *

+     *

+     *      multipleRows
+     *      Click any cell in the row to select the row.
+     *       While holding down the Control key, click any cell in another row
+     *       to select the row for discontiguous selection.
+     *       While holding down the Shift key, click any cell in another row to select multiple, contiguous rows.
+     *       After the selection, selectedCells contains one Object for each selected row:
+     *
[   {rowIndex: selectedRowIndex1, columnIndex: -1},
+     *           {rowIndex: selectedRowIndex2, columnIndex: -1},
+     *           ...
+     *           {rowIndex: selectedRowIndexN, columnIndex: -1}
+     *       ]

+     *

+     *

+     *      singleCell
+     *      Click any cell to select the cell.
+     *       After the selection, selectedCells contains a single Object:
+     *
[{rowIndex: selectedRowIndex, columnIndex:selectedColIndex}]

+     *

+     *

+     *      multipleCells
+     *      Click any cell to select the cell.
+     *       While holding down the Control key, click any cell to select the cell multiple discontiguous selection.
+     *       While holding down the Shift key, click any cell to select multiple, contiguous cells.
+     *       After the selection, selectedCells contains one Object for each selected cell:
+     *
[   {rowIndex: selectedRowIndex1, columnIndex: selectedColIndex1},
+     *           {rowIndex: selectedRowIndex2, columnIndex: selectedColIndex2},
+     *           ...
+     *           {rowIndex: selectedRowIndexN, columnIndex: selectedColIndexN}
+     *      ]

+     *

+     *

+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get selectedCells():Array
+    {
+        if (_selectedCells)
+            return _selectedCells.slice(); // make a copy
+        else
+            return null;
+    }
+
+    /**
+     *  @private
+     */
+    public function set selectedCells(value:Array):void
+    {
+        // clear selectedCells
+        clearSelectedCells();
+
+        _temporary_selectedCells = value;
+		syncCellSelections(value);
+        clearPendingCells();
+        selectedCellsChanged = true;
+        invalidateProperties();
+        invalidateDisplayList();
+    }
+
+    //--------------------------------------------------------------------------
+    // Flex Builder design view functionality
+    //--------------------------------------------------------------------------
+
+    //----------------------------------
+    // designViewDataType
+    //----------------------------------
+
+    private var _designViewDataType:String = designViewDataTreeType;
+
+    [Inspectable(enumeration="flat,tree", defaultValue="tree")]
+    /**
+     *  Flag from Flex Builder on what kind of data is needed to display
+     *  in Design View.
+     *
+     *  Unfortunately, this can't be mx_internal because we need to set it
+     *  from the AdvancedDataGridInserter.java class
+     *
+     *  @private
+     */
+    public function get designViewDataType():String
+    {
+        return _designViewDataType;
+    }
+
+    /**
+     *  @private
+     */
+    public function set designViewDataType(value:String):void
+    {
+        _designViewDataType = value;
+        designViewDataTypeChanged = true;
+    }
+
+    //----------------------------------
+    // dataType
+    //----------------------------------
+
+    /**
+     *  What kind of data is being displayed? "tree" or "flat"?
+     *
+     *  @private
+     */
+    mx_internal function get dataType():String
+    {
+        if (dataProvider)
+            return (dataProvider is IHierarchicalCollectionView)
+                        ? designViewDataTreeType : designViewDataFlatType;
+        else
+            return designViewDataTreeType;
+    }
+
+    //----------------------------------
+    //  groupIconFunction
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for groupIconFunction property.
+     */
+    private var _groupIconFunction:Function;
+
+    [Bindable("groupIconFunctionChanged")]
+    [Inspectable(category="Data")]
+
+    /**
+     *  A user-supplied callback function to run on each group item
+     *  to determine its branch icon in the navigation tree.
+     *  You can specify icons by using the itemIcons or setItemIcon properties
+     *  if you have predetermined icons for data items.
+     *  Use this callback function to determine the icon dynamically after examining the data.
+     *
+     *
The groupIconFunction takes the item in the data provider
+     *  and its depth and returns a Class defining the icon, or null property
+     *  to use the default icon.
+     *  The callback function must have the following signature:

+     *
+     *

+     *    groupIconFunction(item:Object,depth:int):Class

+     *
+     *  @default null
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get groupIconFunction():Function
+    {
+        return _groupIconFunction;
+    }
+
+    /**
+     *  @private
+     */
+    public function set groupIconFunction(value:Function):void
+    {
+        _groupIconFunction = value;
+
+        itemsSizeChanged = true;
+        invalidateDisplayList();
+
+        dispatchEvent(new Event("groupIconFunctionChanged"));
+    }
+
+    //----------------------------------
+    //  groupItemRenderer
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the groupItemRenderer property.
+     */
+    private var _groupItemRenderer:IFactory;
+
+    [Inspectable(category="Data")]
+
+    /**
+     *  Specifies the item renderer used to display the branch nodes
+     *  in the navigation tree that correspond to groups.
+     *  By default, it is an instance of the AdvancedDataGridGroupItemRenderer class.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get groupItemRenderer():IFactory
+    {
+        return _groupItemRenderer;
+    }
+
+    /**
+     *  @private
+     */
+    public function set groupItemRenderer(value:IFactory):void
+    {
+        _groupItemRenderer = value;
+
+        invalidateSize();
+        invalidateDisplayList();
+
+        itemsSizeChanged = true;
+        rendererChanged = true;
+
+        dispatchEvent(new Event("itemRendererChanged"));
+    }
+
+    //----------------------------------
+    //  groupLabelFunction
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for groupLabelFunction property.
+     */
+    private var _groupLabelFunction:Function;
+
+    [Bindable("groupLabelFunctionChanged")]
+    [Inspectable(category="Data")]
+
+    /**
+     *  A callback function to run on each item to determine its label
+     *  in the navigation tree.
+     *  By default, the control looks for a property named label
+     *  on each data provider item and displays it.
+     *  However, some data sets do not have a label property,
+     *  or have another property that can be used for displaying.
+     *  An example is a data set that has lastName and firstName fields
+     *  but you want to display full names.
+     *
+     *
You can supply a groupLabelFunction that finds the
+     *  appropriate fields and returns a displayable string. The
+     *  groupLabelFunction is also good for handling formatting and
+     *  localization.

+     *
+     *
The method signature for the AdvancedDataGrid
+     *  and AdvancedDataGridColumn classes is:

+     *

+     *  myGroupLabelFunction(item:Object, column:AdvancedDataGridColumn):String

+     *
+     *
Where item contains the AdvancedDataGrid item object, and
+     *  column specifies the AdvancedDataGrid column.
+     *  The function returns a String containing the label.

+     *
+     *  @default null
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get groupLabelFunction():Function
+    {
+        return _groupLabelFunction;
+    }
+
+    /**
+     *  @private
+     */
+    public function set groupLabelFunction(value:Function):void
+    {
+        _groupLabelFunction = value;
+
+        itemsSizeChanged = true;
+        invalidateDisplayList();
+
+        dispatchEvent(new Event("groupLabelFunctionChanged"));
+    }
+
+    //----------------------------------
+    //  groupRowHeight
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for groupNodeHeight property.
+     */
+    private var _groupRowHeight:Number = -1;
+
+    [Inspectable(category="Data")]
+
+    /**
+     *  The height of the grouped row, in pixels.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get groupRowHeight():Number
+    {
+        return _groupRowHeight;
+    }
+
+    /**
+     *  @private
+     */
+    public function set groupRowHeight(value:Number):void
+    {
+        _groupRowHeight = value;
+
+        invalidateSize();
+        invalidateDisplayList();
+
+        itemsSizeChanged = true;
+
+    }
+
+    //----------------------------------
+    //  rendererProviders
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for rendererProvider property.
+     */
+    private var _rendererProviders:Array = []; /* of AdvancedDataGridRendererProvider */
+
+    /**
+     *  Array of AdvancedDataGridRendererProvider instances.
+     *  You can use several renderer providers to specify custom item renderers
+     *  used for particular data, at a particular depth of the navigation tree,
+     *  or with column spanning or row spanning.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get rendererProviders():Array
+    {
+        return _rendererProviders;
+    }
+
+    /**
+     *  @private
+     */
+    public function set rendererProviders(value:Array):void
+    {
+        _rendererProviders = value;
+
+        invalidateSize();
+        invalidateDisplayList();
+
+        itemsSizeChanged = true;
+        rendererChanged = true;
+    }
+
+    //----------------------------------
+    //  itemIcons
+    //----------------------------------
+
+    [Inspectable(category="Data")]
+    /**
+     *  An object that specifies the icons for the items.
+     *  Each entry in the object has a field name that is the item UID
+     *  and a value that is an object with the following format:
+     *

+     *  {iconID: Class, iconID2: Class}
+     *

+     *  The iconID field value is the class of the icon for
+     *  a closed or leaf item and the iconID2 is the class
+     *  of the icon for an open item.
+     *
+     *
This property is intended to allow initialization of item icons.
+     *  Changes to this array after initialization are not detected
+     *  automatically.
+     *  Use the setItemIcon() method to change icons dynamically.

+     *
+     *  @see #setItemIcon()
+     *  @default undefined
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public var itemIcons:Object;
+
+    //----------------------------------
+    //  firstVisibleItem
+    //----------------------------------
+
+    [Bindable("firstVisibleItemChanged")]
+
+    /**
+     *  The data provider element that corresponds to the
+     *  item that is currently displayed in the top row of the AdvancedDataGrid control.
+     *  For example, based on how the branches have been opened, closed, and scrolled,
+     *  the top row might be the ninth item in the list of
+     *  currently viewable items, which represents
+     *  some great-grandchild of the root node.
+     *  Setting this property is analogous to setting the verticalScrollPosition of the List control.
+     *
+     *
If the item is not currently viewable (for example, because it
+     *  is under a nonexpanded item), setting this property has no effect.

+     *
+     *
The default value is the first item in the AdvancedDataGrid control.

+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get firstVisibleItem():Object
+    {
+        return listItems[0][0].data;
+    }
+
+    /**
+     *  @private
+     */
+    public function set firstVisibleItem(value:Object):void
+    {
+        var pos:int = getItemIndex(value);
+        if (pos < 0)
+            return;
+
+        verticalScrollPosition = Math.min(maxVerticalScrollPosition, pos);
+
+        dispatchEvent(new Event("firstVisibleItemChanged"));
+    }
+
+    //----------------------------------
+    //  hierarchicalCollectionView
+    //----------------------------------
+
+    /**
+     *  @private
+     */
+    private var _hierarchicalCollectionView:IHierarchicalCollectionView =
+            new HierarchicalCollectionView();
+
+    [Inspectable(category="Data")]
+
+    /**
+     *  The IHierarchicalCollectionView instance used by the control.
+     *
+     *
The default value is an internal instance of the
+     *  HierarchicalCollectionView class.

+     *
+     *  @see mx.collections.IHierarchicalCollectionView
+     *
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function set hierarchicalCollectionView(value:IHierarchicalCollectionView):void
+    {
+        _hierarchicalCollectionView = value;
+
+        // set the dataProvider using the new IHierarchicalCollectionView
+        dataProviderChanged = true;
+        invalidateProperties();
+    }
+
+    /**
+     * @private
+     */
+    public function get hierarchicalCollectionView():IHierarchicalCollectionView
+    {
+        return IHierarchicalCollectionView(_hierarchicalCollectionView);
+    }
+
+    //----------------------------------
+    //  displayDisclosureIcon
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Indicates that disclosure icons will be shown or not.
+     */
+    private var _displayDisclosureIcon:Boolean = true;
+
+    [Inspectable(category="General")]
+    /**
+     *  Controls the creation and visibility of disclosure icons
+     *  in the navigation tree.
+     *  If false, disclosure icons are not displayed.
+     *
+     *  @default true
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get displayDisclosureIcon():Boolean
+    {
+        return _displayDisclosureIcon;
+    }
+
+    public function set displayDisclosureIcon(value:Boolean):void
+    {
+        if (value != _displayDisclosureIcon)
+        {
+            _displayDisclosureIcon = value;
+
+            itemsSizeChanged = true;
+            invalidateDisplayList();
+        }
+    }
+
+    //----------------------------------
+    //  displayItemsExpanded
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Indicates that items will be shown expanded or not.
+     */
+    private var _displayItemsExpanded:Boolean = false;
+
+    [Inspectable(category="General", enumeration="true,false", defaultValue="false")]
+    /**
+     *  If true, expand the navigation tree to show all items.
+     *  If a new branch is added, it will be shown expanded.
+     *
+     *  @default false
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get displayItemsExpanded():Boolean
+    {
+        return _displayItemsExpanded;
+    }
+
+    public function set displayItemsExpanded(value:Boolean):void
+    {
+        if (value != _displayItemsExpanded)
+        {
+            _displayItemsExpanded = value;
+
+            if (_displayItemsExpanded)
+            {
+                displayItemsExpandedChanged = true;
+                invalidateProperties();
+            }
+        }
+    }
+
+    //----------------------------------
+    //  treeColumn
+    //----------------------------------
+
+    /**
+     *  @private
+     *  Storage for the treeColumn property.
+     */
+    private var _treeColumn:AdvancedDataGridColumn = null;
+
+    [Inspectable(category="General")]
+    /**
+     *  The column in which the tree is displayed.
+     *  Set this property to the value of the id property of an
+     *  AdvancedDataGridColumn instance, as the following example shows:
+     *
+     *

+     *    <mx:AdvancedDataGrid
+     *       width="100%" height="100%"
+     *       treeColumn="{rep}">
+     *       <mx:dataProvider>
+     *          <mx:HierarchicalData source="{dpHierarchy}"
+     *              childrenField="categories"/>
+     *       </mx:dataProvider>
+     *       <mx:columns>
+     *          <mx:AdvancedDataGridColumn dataField="Region"/>
+     *          <mx:AdvancedDataGridColumn id="rep"
+     *              dataField="Territory_Rep"
+     *              headerText="Territory Rep"/>
+     *          <mx:AdvancedDataGridColumn dataField="Actual"/>
+     *          <mx:AdvancedDataGridColumn dataField="Estimate"/>
+     *       </mx:columns>
+     *    </mx:AdvancedDataGrid>

+     *
+     *  @default null
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function get treeColumn():AdvancedDataGridColumn
+    {
+        if (_treeColumn)
+            return _treeColumn;
+
+        return null;
+    }
+
+    /**
+     *  @private
+     */
+    public function set treeColumn(value:AdvancedDataGridColumn):void
+    {
+        if (value != _treeColumn)
+        {
+            _treeColumn = value;
+
+            purgeItemRenderers();
+            freeItemRenderersTable = new Dictionary(false);
+            itemsSizeChanged = true;
+            invalidateDisplayList();
+        }
+    }
+
+    //----------------------------------
+    //  treeColumnIndex
+    //----------------------------------
+
+    /**
+     *  The tree column number.
+     *
+     *  @default 0
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function get treeColumnIndex():int
+    {
+        if (_treeColumn)
+            return _treeColumn.colNum;
+
+        return 0;
+    }
+
+    //----------------------------------
+    //  movingColumnIndex
+    //----------------------------------
+
+    private var _movingColumnIndex:int;
+
+    /**
+     *  For Automation
+     *  returns the index of the moving column, in the orderedHeadersList array.
+     *  Essentialy the order in which column comes if traversed in a DFS manner
+     *  @private
+     */
+    mx_internal function get movingColumnIndex():int
+    {
+        return _movingColumnIndex;
+
+    }
+    /**
+     *  Given the index, finds the corresponding column and set it as movingColumn
+     *  @private
+     */
+    mx_internal function set movingColumnIndex(index:int):void
+    {
+        _movingColumnIndex = index;
+        if (index >= 0 && orderedHeadersList
+           && index < orderedHeadersList.length && orderedHeadersList[index])
+            movingColumn = orderedHeadersList[index].column;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     */
+    override protected function initializeAccessibility():void
+    {
+        if (AdvancedDataGrid.createAccessibilityImplementation != null)
+            AdvancedDataGrid.createAccessibilityImplementation(this);
+    }
+
+    /**
+    *  @private
+    */
+    override protected function makeRowsAndColumns(left:Number, top:Number,
+                                                   right:Number, bottom:Number,
+                                                   firstCol:int, firstRow:int,
+                                                   byCount:Boolean = false, rowsNeeded:uint = 0):Point
+    {
+        if (!visibleColumns || visibleColumns.length == 0)
+            visibleCellRenderers = {};
+
+        return super.makeRowsAndColumns(left, top, right, bottom, firstCol,
+                                        firstRow, byCount, rowsNeeded);
+    }
+
+   /**
+    *  @inheritDoc
+    *
+    *  @langversion 3.0
+    *  @playerversion Flash 9
+    *  @playerversion AIR 1.1
+    *  @productversion Flex 3
+    */
+    override protected function finishKeySelection():void
+    {
+        if (isCellSelectionMode())
+            finishCellKeySelection();
+        else
+            super.finishKeySelection();
+    }
+
+    /**
+     *  Updates the set of selected items given that the item renderer provided
+     *  was clicked by the mouse and the keyboard modifiers are in the given
+     *  state. This method also updates the display of the item renderers based
+     *  on their updated selected state.
+     *
+     *  @param item The item renderer that was clicked.
+     *
+     *  @param shiftKey true if the Shift key was held down when
+     *  the mouse was clicked.
+     *
+     *  @param ctrlKey true if the Control key was held down when
+     *  the mouse was clicked.
+     *
+     *  @param transition true if the graphics for the selected
+     *  state should be faded in using an effect.
+     *
+     *  @return true if the set of selected items changed.
+     *  Clicking an already selected item doesn't always change the set
+     *  of selected items.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override protected function selectItem(item:IListItemRenderer,
+                                           shiftKey:Boolean, ctrlKey:Boolean,
+                                           transition:Boolean = true):Boolean
+    {
+
+        if (isCellSelectionMode() && !selectedHeaderInfo)
+            return selectCellItem(item, shiftKey, ctrlKey, transition);
+
+        return super.selectItem(item, shiftKey, ctrlKey, transition);
+    }
+
+   /**
+    *  @private
+    */
+    override protected function drawVisibleItem(uid:String,
+                                                selected:Boolean = false,
+                                                highlighted:Boolean = false,
+                                                caret:Boolean = false,
+                                                transition:Boolean = false):void
+    {
+        if (isCellSelectionMode())
+        {
+            if (visibleCellRenderers[uid])
+            {
+                var n:int = _columns.length;
+                for (var i:int = 0; i < n; i++)
+                {
+                    var bSelectCell:Boolean = cellSelectionData
+                        && cellSelectionData[uid]
+                        && cellSelectionData[uid][i.toString()];
+
+                    var bHighlightCell:Boolean = highlightUID == uid
+                        && highlightColumnIndex == i;
+
+                    var bCaretCell:Boolean = caretUID == uid
+                        && caretColumnIndex == i;
+
+                    drawCellItem(visibleCellRenderers[uid][i.toString()],
+                                 bSelectCell,
+                                 bHighlightCell,
+                                 bCaretCell);
+                }
+            }
+        }
+
+        super.drawVisibleItem(uid, selected, highlighted, caret, transition);
+    }
+
+   /**
+    *  @private
+    */
+    override protected function setVisibleDataItem(uid:String, item:IListItemRenderer):void
+    {
+        if (isCellSelectionMode())
+        {
+            if (uid)
+            {
+                if (!visibleCellRenderers[uid])
+                    visibleCellRenderers[uid]  = {};
+                visibleCellRenderers[uid]
+                    [indexToColNum(currentColNum).toString()] = item;
+            }
+        }
+
+        super.setVisibleDataItem(uid, item);
+    }
+
+    /**
+     *  @private
+     *
+     */
+    override protected function addRendererToContentArea(item:IListItemRenderer, column:AdvancedDataGridColumn):void
+    {
+        //Creating a header
+        if(columnGrouping && item.data is AdvancedDataGridColumn)
+        {
+            var headerInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(item.data as AdvancedDataGridColumn);
+
+            if(headerInfo && (headerInfo.columnSpan + headerInfo.actualColNum) <= lockedColumnCount)
+                listContent.addChild(DisplayObject(item));
+            else
+                listSubContent.addChild(DisplayObject(item));
+        }
+        else
+        {
+            super.addRendererToContentArea(item, column);
+        }
+    }
+
+    /**
+     *  @private
+     *
+     */
+    override protected function mouseEventToItemRenderer(event:MouseEvent):IListItemRenderer
+    {
+        if(!columnGrouping)
+        {
+            return super.mouseEventToItemRenderer(event);
+        }
+        else
+        {
+            var r:IListItemRenderer;
+
+            if (event.target == highlightIndicator || event.target == listContent)
+            {
+                var pt:Point = new Point(event.stageX, event.stageY);
+                pt = listContent.globalToLocal(pt);
+
+                var ww:Number = 0;
+
+                // For headerItems
+                r = findHeaderRenderer(pt);
+            }
+
+            if (!r)
+                r = super.mouseEventToItemRenderer(event);
+
+            // To handle case when mouse is at the border of the header item
+            // renderer. Ignoring prevents flickering of the highlight of the
+            // header because of infinite loop of mouseOver and mouseOut events.
+            if (event.target == listContent && isHeaderItemRenderer(r))
+                return null;
+
+            return r == itemEditorInstance ? null : r;
+
+        }
+    }
+
+    /**
+     *  @private
+     *
+     */
+    override protected function hasHeaderItemsCreated(index:int=-1):Boolean
+    {
+        if(!columnGrouping)
+            return super.hasHeaderItemsCreated(index);
+
+        if(index == -1)
+            return (visibleHeaderInfos && visibleHeaderInfos[0].headerItem);
+
+        var headerInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(getOptimumColumns()[index]);
+        return (headerInfo && headerInfo.headerItem);
+    }
+
+    /**
+     *  @private
+     *
+     */
+    override protected function purgeHeaderRenderers():void
+    {
+        if(!columnGrouping)
+        {
+            super.purgeHeaderRenderers();
+        }
+        else
+        {
+            if(headerItemsList && headerItemsList.length)
+            {
+                while (headerItemsList.length)
+                {
+                    var item:IListItemRenderer = headerItemsList.pop();
+                    addHeaderToFreeItemRenderers(item, item.data as AdvancedDataGridColumn);
+                }
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function createHeaders(left:Number, top:Number):void
+    {
+        if(!columnGrouping)
+        {
+            var creatingHeaders:Boolean = false;
+            if(horizontalScrollPolicy != ScrollPolicy.OFF && getOptimumColumns()!= visibleColumns)
+            {
+                if(!headerItems[0] || !headerItems[0][0] || (top < headerItems[0][0].y + headerItems[0][0].height))
+                    creatingHeaders = true;
+            }
+
+            super.createHeaders(left, top);
+
+            if (creatingHeaders)
+            {
+                creatingHeaders = false;
+
+                var residualWidth:Number = getLastColumnResidualWidth();
+
+                var lastColIndex:int = displayableColumns.length - 1;
+                var lastCol:AdvancedDataGridColumn = displayableColumns[lastColIndex];
+                var w:Number = (isNaN(lastCol.explicitWidth) ? lastCol.preferredWidth : lastCol.explicitWidth);
+
+                var item:IListItemRenderer = headerItems[0][lastColIndex];
+                if (item)
+                {
+                    item.explicitWidth = w + residualWidth;
+                    UIComponentGlobals.layoutManager.validateClient(item, true);
+                    item.setActualSize(w + residualWidth, item.height);
+                }
+            }
+
+        }
+        else
+        {
+            if(visibleHeaderInfos && (!visibleHeaderInfos[0].headerItem || (top < visibleHeaderInfos[0].headerItem.y + visibleHeaderInfos[0].headerItem.height)))
+            {
+                //Creating new header items..need to purge old ones.
+                purgeHeaderRenderers();
+                headerItemsList = [];
+                lastColumnWidth = NaN;
+
+                //Just create the headerItems!! no measuring, Nothing
+                createHeaderItems(visibleHeaderInfos);
+                headerRowInfo = [];
+
+                //Calculate the heights of each header rows
+                measureHeaderHeights(visibleHeaderInfos,0);
+
+                //Set heights of all headerItems
+                var visibleHeaderInfo:AdvancedDataGridHeaderInfo;
+                var padding:int = cachedPaddingTop + cachedPaddingBottom;
+                var currentItemHeight:Number=0;
+
+                var n:int = orderedHeadersList.length;
+                for (var i:int = 0; i < n; i++)
+                {
+                    visibleHeaderInfo = orderedHeadersList[i];
+                    if(visibleHeaderInfo.visible)
+                    {
+
+                        currentItemHeight = headerRowInfo[visibleHeaderInfo.depth].height - padding;
+
+                        if(visibleHeaderInfo.visibleChildren)
+                            currentItemHeight -= headerRowInfo[visibleHeaderInfo.depth+1].height;
+
+                        if(horizontalScrollPolicy != ScrollPolicy.OFF && !isNaN(lastColumnWidth)
+                           && visibleHeaderInfo.column == displayableColumns[displayableColumns.length-1])
+                            visibleHeaderInfo.headerItem.setActualSize(lastColumnWidth, currentItemHeight);
+                        else
+                            visibleHeaderInfo.headerItem.setActualSize(visibleHeaderInfo.column.width, currentItemHeight);
+
+                        visibleHeaderInfo.headerItem.visible = headerVisible;
+                    }
+                }
+
+                lastColumnWidth = NaN;
+
+                //Done with measuring, we know the dimensions for each header now. Just layout them at their proper place
+                layoutHeaders(visibleHeaderInfos, left, top,0);
+
+                currentItemTop = headerVisible ? headerRowInfo[0].height : 0;
+                _headerHeight = !_explicitHeaderHeight ?  headerRowInfo[0].height : _headerHeight;
+            }
+        }
+    }
+
+    /**
+     *  Returns the item renderer for a specific item in a column.
+     *
+     *  @param c The AdvancedDataGridColumn instance for the column.
+     *
+     *  @param itemData The item in the column.
+     *
+     *  @return The IListItemRenderer defining the item renderer.
+     *
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override mx_internal function getRenderer(c:AdvancedDataGridColumn, itemData:Object, forDragProxy:Boolean = false):IListItemRenderer
+    {
+        var renderer:IListItemRenderer;
+        var factory:IFactory;
+
+        var adgDescription:AdvancedDataGridRendererDescription;
+
+        if (rendererProviders.length != 0)
+            adgDescription = getRendererDescription(itemData,c,forDragProxy);
+
+        if (adgDescription && adgDescription.renderer)
+        {
+            if (freeItemRenderersTable[c]
+                    && freeItemRenderersTable[c][adgDescription.renderer]
+                    && freeItemRenderersTable[c][adgDescription.renderer].length)
+            {
+                renderer = freeItemRenderersTable[c][adgDescription.renderer].pop();
+            }
+           else
+            {
+                renderer = adgDescription.renderer.newInstance();
+                itemRendererToFactoryMap[renderer] = adgDescription.renderer;
+            }
+            rendererDescriptionMap[renderer] = adgDescription;
+
+            return renderer;
+        }
+
+        return super.getRenderer(c, itemData, forDragProxy);
+    }
+
+    /**
+     *  @private
+     *  This grid just returns the column size,
+     *  but could handle column spanning.
+     */
+    override mx_internal function getWidthOfItem(item:IListItemRenderer,
+                                                 col:AdvancedDataGridColumn, visibleColumnIndex:int):Number
+    {
+        var ww:Number = 0;
+        var adgDescription:AdvancedDataGridRendererDescription = rendererDescriptionMap[item] as AdvancedDataGridRendererDescription;
+        if (adgDescription && adgDescription.renderer)
+        {
+            var i:int;
+            var end:int;
+            // set the width of the item according to the number of columns it is spaning
+            if (adgDescription.columnSpan == 0)
+            {
+                end = _columns.length;
+                if (visibleColumnIndex < lockedColumnCount)
+                    end = lockedColumnCount;
+
+                var tmpWidth:Number = 0;
+                for (i = visibleColumnIndex; i < end ;i++)
+                {
+                    tmpWidth += AdvancedDataGridColumn(_columns[i]).width;
+                }
+                ww = tmpWidth;
+            }
+            else
+            {
+                ww = 0;
+                end = visibleColumnIndex+adgDescription.columnSpan;
+                if (visibleColumnIndex < lockedColumnCount && end > lockedColumnCount)
+                    end = lockedColumnCount;
+                if (end > displayableColumns.length)
+                    end = displayableColumns.length;
+
+                var optimumColumns:Array = getOptimumColumns();
+                for (i = visibleColumnIndex; i < end ; i++)
+                {
+                    ww += super.getWidthOfItem(item,optimumColumns[i], visibleColumnIndex);
+                }
+            }
+
+            var lastColIndex:int = displayableColumns.length - 1;
+            if(horizontalScrollPolicy != ScrollPolicy.OFF
+               && lastColIndex >= visibleColumnIndex && lastColIndex < end)
+            {
+                // Find the extra width we need to add..
+                var residualWidth:Number = getLastColumnResidualWidth();
+                var lastCol:AdvancedDataGridColumn = displayableColumns[lastColIndex];
+                // subtract the width which got added above in the loop
+                ww -= lastCol.width;
+                // Add the corrected width
+                ww += (isNaN(lastCol.explicitWidth) ?
+                       lastCol.preferredWidth :
+                       lastCol.explicitWidth) + getLastColumnResidualWidth();
+            }
+            return ww ;
+        }
+        else if(horizontalScrollPolicy != ScrollPolicy.OFF
+                && col == displayableColumns[displayableColumns.length-1])
+        {
+            return (isNaN(col.explicitWidth) ? col.preferredWidth : col.explicitWidth) + getLastColumnResidualWidth();
+        }
+        else
+        {
+            return super.getWidthOfItem(item, col, visibleColumnIndex);
+        }
+    }
+
+    /**
+     *  @private
+     *  Creates the header seperators taking into
+     *  account the different depths of the two headers
+     *  on the two sides of the seperator
+     */
+    override protected function createHeaderSeparators(n:int, separators:Array, headerLines:UIComponent):void
+    {
+        if(!columnGrouping)
+        {
+            super.createHeaderSeparators(n, separators, headerLines);
+        }
+        else
+        {
+            var separatorAffordance:Number = 3;
+
+            var optimumColumns:Array = getOptimumColumns();
+
+            var offset:int = (lockedColumnCount > 0 && separators != lockedSeparators) ? lockedColumnCount - 1 : 0;
+            for (var i:int = 0; i < n; i++)
+            {
+                var headerItemIndex:int = i + offset;
+                var sep:UIComponent = getSeparator(i, separators, headerLines);
+                var sepSkin:IFlexDisplayObject = IFlexDisplayObject(sep.getChildAt(0));
+
+                var leftHeaderInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(optimumColumns[headerItemIndex]);
+
+                var leftHeaderItem:IListItemRenderer = leftHeaderInfo.headerItem;
+                if(!leftHeaderInfo || !leftHeaderInfo.visible || !(leftHeaderItem ))
+                {
+                    sep.visible = false;
+                    continue;
+                }
+
+                sep.visible = true;
+                var posX:Number;
+                posX = leftHeaderItem.x +
+                    optimumColumns[headerItemIndex].width - Math.round(sep.measuredWidth / 2 + 0.5);
+
+                if (i > 0)
+                {
+                    posX = Math.max(posX,
+                                    separators[i - 1].x + Math.round(sep.measuredWidth / 2 + 0.5));
+                }
+                sep.x = posX;
+
+                //Column on the other side of the seperator
+                var rightHeaderInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(optimumColumns[headerItemIndex+1]);
+
+                var lineHeight:Number;
+                //Based on what is on left and right of the seperator
+                //We need to find out the height of the separator
+                var leftParent:AdvancedDataGridHeaderInfo = leftHeaderInfo;
+                var rightParent:AdvancedDataGridHeaderInfo = rightHeaderInfo;
+                var padding:int = cachedPaddingBottom+cachedPaddingTop;
+                while(leftParent!=rightParent && leftParent.parent!=null && rightParent.parent!=null)
+                {
+                    if(leftParent.depth > rightParent.depth)
+                    {
+                        leftParent = leftParent.parent;
+                    }
+                    else if(leftParent.depth < rightParent.depth)
+                    {
+                        rightParent = rightParent.parent;
+                    }
+                    else
+                    {
+                        leftParent = leftParent.parent;
+                        rightParent = rightParent.parent;
+                    }
+                }
+
+                sep.y = 0;
+                lineHeight = leftHeaderItem.y + leftHeaderItem.height + padding;
+                //Two columns have the same ancestor, may not be parent!!
+                if(leftParent == rightParent && leftParent)
+                {
+                    sep.y = leftParent.headerItem.y + leftParent.headerItem.height + cachedPaddingBottom;
+                    lineHeight = leftHeaderItem.y + leftHeaderItem.height - leftParent.headerItem.y - leftParent.headerItem.height;
+                }
+
+                sepSkin.setActualSize(sepSkin.measuredWidth,lineHeight);
+
+                // Draw invisible background for separator affordance
+                sep.graphics.clear();
+                sep.graphics.beginFill(0xFFFFFF, 0);
+                sep.graphics.drawRect(-separatorAffordance, 0, sepSkin.measuredWidth + separatorAffordance , lineHeight);
+                sep.graphics.endFill();
+            }
+        }
+    }
+
+    /**
+     *  Setup Renderers
+     *  Make renderer and populate listItems with them.
+     *  @private
+     */
+    override protected function setupRenderer(itemData:Object,uid:String,insertItems:Boolean = false):void
+    {
+        var savedColNum:int = currentColNum;
+
+        super.setupRenderer(itemData, uid, insertItems);
+
+        if (rendererProviders.length == 0)
+            return;
+
+        var itemCount:int = listItems[currentRowNum].length;
+        // count of the items which will be invisible due to the previous item's column span
+        var count:int = 0;
+        var optimumColumns:Array = getOptimumColumns();
+        for(var i:int = 0; i < itemCount; ++i)
+        {
+            var item:IListItemRenderer = listItems[currentRowNum][i];
+            var adgDescription:AdvancedDataGridRendererDescription = rendererDescriptionMap[item];
+            if (adgDescription && adgDescription.renderer)
+            {
+                // set count to the max of the column span of the previous renderer and the present renderer
+                if (adgDescription.columnSpan == 0)
+                    count = Math.max(count-1, optimumColumns.length - i);
+                else
+                    count = Math.max(count-1, adgDescription.columnSpan - 1);
+            }
+            else if (count > 0)
+            {
+                // make the item invisible if there is already an item that is spaning onto it
+                item.visible = false;
+                count--;
+            }
+        }
+    }
+
+    /**
+     * @private
+     */
+    override protected function updateDisplayOfItemRenderer(r:IListItemRenderer):void
+    {
+        applyUserStylesForItemRenderer(r);
+        super.updateDisplayOfItemRenderer(r);
+    }
+
+    /**
+     *  Draws a vertical line between columns.
+     *  This implementation draws a line
+     *  directly into the given Sprite.  The Sprite has been cleared
+     *  before lines are drawn into it.
+     *
+     *  @param s A Sprite that contains a DisplayObject
+     *  that contains the graphics for that row.
+     *
+     *  @param columnIndex The column's index in the set of displayed columns.
+     *  The left most visible column has a column index of 0.
+     *
+     *  @param color The color for the indicator.
+     *
+     *  @param x The x position for the background
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override protected function drawVerticalLine(s:Sprite, colIndex:int, color:uint, x:Number):void
+    {
+        //draw our vertical lines
+        var g:Graphics = s.graphics;
+        if (lockedColumnCount > 0 && colIndex == lockedColumnCount - 1)
+            g.lineStyle(1, 0, 100);
+        else
+            g.lineStyle(1, color, 100);
+
+        var tempY:Number = 0;
+        if(headerVisible)
+        {
+            tempY = headerRowInfo[0].height;
+        }
+
+        // check if custom renderers are used
+        if (rendererProviders.length != 0)
+        {
+            var item:IListItemRenderer;
+            var n:int = listItems.length;
+            for (var i:int = 0; i < n; i++)
+            {
+                // if listItem has any item, update tempY
+                if (listItems[i].length != 0)
+                {
+                    item = listItems[i][colIndex] as IListItemRenderer;
+                    tempY = rowInfo[i].y + rowInfo[i].height;
+                    // check for item and its width
+                    if (item.visible)
+                    {
+                        if ((item.x +item.width) <= x)
+                        {
+                            g.moveTo(x, rowInfo[i].y);
+                            g.lineTo(x, tempY);
+                        }
+                    }
+                    else
+                    {
+                        // check for the item renderers in the previous columns in the same row
+                        for (var j:int= colIndex - 1; j >= 0; j--)
+                        {
+                            item = listItems[i][j] as IListItemRenderer;
+                            if (item.visible)
+                            {
+                                if ((item.x +item.width) <= x)
+                                {
+                                    g.moveTo(x, rowInfo[i].y);
+                                    g.lineTo(x, tempY);
+                                    break;
+                                }
+                                else
+                                {
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // draw line from tempY to listContent's height
+        g.moveTo(x, tempY);
+        g.lineTo(x, listContent.height);
+    }
+
+    /**
+     *  Get the appropriate renderer factory for a column,
+     *  using the default renderer if none specified
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override mx_internal function columnItemRendererFactory(c:AdvancedDataGridColumn, forHeader:Boolean, itemData:Object):IFactory
+    {
+        var factory:IFactory;
+        if (!forHeader)
+        {
+            if (_rootModel is  IHierarchicalData && c.colNum == treeColumnIndex)
+            {
+                if (!isBranch(itemData) && c.itemRenderer)
+                {
+                    factory = c.itemRenderer;
+                }
+                else if (groupItemRenderer)
+                {
+                    factory = groupItemRenderer;
+                }
+            }
+        }
+        if (!factory)
+        {
+            factory = super.columnItemRendererFactory(c, forHeader, itemData);
+        }
+
+        return factory;
+    }
+
+    /**
+     *  @private
+     */
+    override protected function getNumColumns():int
+    {
+        if(columnGrouping)
+        {
+            var optimumColumns:Array = getOptimumColumns();
+            if(!optimumColumns)
+                return 0;
+            return optimumColumns.length;
+        }
+        else
+        {
+            return super.getNumColumns();
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function getPossibleDropPositions(c:AdvancedDataGridColumn):Array
+    {
+        if(columnGrouping && c!=null)
+        {
+            var headerInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(c);
+            if(headerInfo && headerInfo.parent && headerInfo.parent.visibleChildren && headerInfo.parent.visibleChildren.length > 0)
+                return headerInfo.parent.visibleChildren;
+            else
+                return visibleHeaderInfos;
+        }
+        else
+        {
+            return super.getPossibleDropPositions(c);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override mx_internal function getHeaderInfo(col:AdvancedDataGridColumn):AdvancedDataGridHeaderInfo
+    {
+        if(columnGrouping)
+            return columnsToInfo[itemToUID(col)];
+        else
+            return super.getHeaderInfo(col);
+    }
+
+    /**
+     *  @private
+     */
+    override mx_internal function getHeaderInfoAt(colIndex:int):AdvancedDataGridHeaderInfo
+    {
+        if(columnGrouping)
+            return columnsToInfo[itemToUID(columns[colIndex])];
+        else
+            return super.getHeaderInfoAt(colIndex);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function createChildren():void
+    {
+        super.createChildren();
+
+        // This invisible layer, which is a child of listSubContent
+        // catches mouse events for all items
+        // and is where we put selection highlighting by default.
+        if (!movingSelectionLayer)
+        {
+            movingSelectionLayer = new FlexSprite();
+            movingSelectionLayer.name = "movingSelectionLayer";
+            movingSelectionLayer.mouseEnabled = false;
+            listSubContent.addChild(movingSelectionLayer);
+
+            // trace("movingSelectionLayer parent set to " + movingSelectionLayer.parent);
+
+            var g:Graphics = movingSelectionLayer.graphics;
+            g.beginFill(0, 0); // 0 alpha means transparent
+            g.drawRect(0, 0, 10, 10);
+            g.endFill();
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function commitProperties():void
+    {
+        if (dataProviderChanged)
+        {
+            var tmpCollection:Object;
+            //reset flags
+
+            dataProviderChanged = false;
+
+            if (hierarchicalCollectionInstance)
+            {
+                super.dataProvider = hierarchicalCollectionInstance;
+            }
+            // at this point _rootModel may be null so we dont need to continue
+            else if (_rootModel is IHierarchicalData)
+            {
+                //wrap userdata in a HierarchicalCollection and pass that collection to the List
+                hierarchicalCollectionView.source = _rootModel;
+                super.dataProvider = hierarchicalCollectionView;
+            }
+        }
+
+        // if the data is grouped, get the groupLabelField.
+        if (_rootModel is IGroupingCollection && IGroupingCollection(_rootModel).grouping)
+            groupLabelField = IGroupingCollection(_rootModel).grouping.label;
+
+		if (_rootModel is IGroupingCollection2 && IGroupingCollection2(_rootModel).grouping)
+			groupLabelField = IGroupingCollection2(_rootModel).grouping.label;
+
+        if (groupedColumnsChanged || columnsChanged)
+        {
+            anchorColumnIndex    = -1;
+            highlightColumnIndex = -1;
+            selectedColumnIndex  = -1;
+        }
+
+        // This code should always come after the hierarchicalData code above
+        // because if no columns array has been defined, columns are generated
+        // based on the dataProvider. Thus setting of columns by dataProvider
+        // falls in the same cycle of commitProperties and if moved above will
+        // not get picked unless a second call to commitProperties come
+        if(groupedColumnsChanged)
+        {
+            columnGrouping = true;
+            columnsChanged = false;
+
+            removeOldHeaders();
+
+            columnsToInfo = new Dictionary();
+            headerInfos = initializeHeaderInfo(_groupedColumns);
+
+            headerInfoInitialized = true;
+
+            // In case a new set of groupedColumns have been specified
+            // its possible the effective value of lockedColumnCount
+            // changes
+            if(lockedColumnCount > 0)
+                lockedColumnCountChanged = true;
+
+            super.columns = getLeafColumns(_groupedColumns.slice(0));
+        }
+        else if(columnsChanged)
+        {
+            columnGrouping = false;
+            columnsChanged = false;
+
+            removeOldHeaders();
+
+            super.columns = _columnsValue;
+        }
+
+        if (displayItemsExpandedChanged)
+        {
+            displayItemsExpandedChanged = false;
+            // if displayItemsExpanded is set to true, then expand all the items.
+            if (displayItemsExpanded)
+                expandAll();
+        }
+
+        super.commitProperties();
+
+        // lockedColumnCount set code should always come after groupedColumns set code
+        // and super.commitProperties because in case of column grouping the actual value
+        // of lockedColumnCount is dependent on groupedColumns and visibleHeaderInfos
+        // So if both are set in the same cycle then lockedColumnCount may miss the
+        // actual value
+        if(lockedColumnCountChanged)
+        {
+            if(columnGrouping)
+                super.lockedColumnCount = getAdjustedLockedCount(_lockedColumnCountVal);
+            else
+                super.lockedColumnCount = _lockedColumnCountVal;
+        }
+
+        if(groupedColumnsChanged)
+        {
+            groupedColumnsChanged = false;
+            headerInfoInitialized = false;
+        }
+
+        if (selectedCellsChanged)
+        {
+            setSelectedCells(_temporary_selectedCells);
+            selectedCellsChanged = false;
+            _temporary_selectedCells = null;
+        }
+
+        // If column becomes hidden, invalidate anchor, highlight and selected indices.
+        {
+            if (anchorColumnIndex != -1 && columns[anchorColumnIndex].visible == false)
+                anchorColumnIndex = -1;
+            if (highlightColumnIndex != -1 && columns[highlightColumnIndex].visible == false)
+                highlightColumnIndex = -1;
+            if (selectedColumnIndex != -1 && columns[selectedColumnIndex].visible == false)
+                selectedColumnIndex = -1;
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+        // Kill any animation before resizing;
+        // tween is null if there is no Tween underway.
+        if (tween)
+            tween.endTween();
+
+        // Display cells set in selectionMode which are not yet visible
+        if (cellsWaitingToBeDisplayed)
+            processCellsWaitingToBeDisplayed();
+
+        super.updateDisplayList(unscaledWidth, unscaledHeight);
+
+        if (headerVisible && columnGrouping)
+            drawHeaderHorizontalSeparators();
+        else
+            clearHeaderHorizontalSeparators();
+
+        //update collection length
+        if (collection)
+            collectionLength = collection.length;
+
+        // Keyboard access to header
+        if (columnGrouping && selectedHeaderInfo)
+        {
+            selectColumnGroupHeader(selectedHeaderInfo);
+        }
+        else if(!columnGrouping && headerIndex != -1)
+        {
+            selectedHeaderInfo = getHeaderInfo(columns[headerIndex]);
+            selectColumnHeader(headerIndex);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override public function calculateDropIndex(event:DragEvent = null):int
+    {
+        if (event)
+        {
+            if (_rootModel is IHierarchicalData)
+            {
+                if (event)
+                    updateDropData(event);
+
+                return _dropData.rowIndex;
+            }
+        }
+
+        return super.calculateDropIndex(event);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function drawRowBackgrounds():void
+    {
+        var colors:Array;
+        colors = getStyle("depthColors");
+
+        if (!(_rootModel is IHierarchicalData) || !colors)
+        {
+            super.drawRowBackgrounds();
+            return;
+        }
+
+        var rowBGs:Sprite = Sprite(listContent.getChildByName("rowBGs"));
+        if (!rowBGs)
+        {
+            rowBGs = new FlexSprite();
+            rowBGs.mouseEnabled = false;
+            rowBGs.name = "rowBGs";
+            listContent.addChildAt(rowBGs, 0);
+        }
+
+        var color:*;
+        var depthColors:Boolean = false;
+		var n:int = listItems.length;
+
+        if (colors)
+            depthColors = true;
+        else
+            colors = getStyle("alternatingItemColors");
+
+        color = getStyle("backgroundColor");
+		if (color === undefined)
+			color = 0xFFFFFF;
+        if (!colors || colors.length == 0)
+		{
+			while (rowBGs.numChildren > n)
+			{
+				rowBGs.removeChildAt(rowBGs.numChildren - 1);
+			}
+			return;
+		}
+
+        styleManager.getColorNames(colors);
+
+        var curRow:int = 0;
+
+        var i:int = 0;
+        var actualRow:int = verticalScrollPosition;
+
+        while (curRow < n)
+        {
+            if (depthColors)
+            {
+                try {
+                    if (listItems[curRow][0])
+                    {
+                        var d:int = getItemDepth(listItems[curRow][0].data, curRow);
+                        drawRowBackground(rowBGs, i++, rowInfo[curRow].y, rowInfo[curRow].height, colors[d - 1], curRow);
+                    }
+                    else
+                    {
+                        drawRowBackground(rowBGs, i++, rowInfo[curRow].y, rowInfo[curRow].height, uint(color), curRow);
+                    }
+                }
+                catch (e:Error)
+                {
+                    //trace("[Tree] caught exception in drawRowBackground");
+                }
+            }
+            else
+            {
+                drawRowBackground(rowBGs, i++, rowInfo[curRow].y, rowInfo[curRow].height, colors[actualRow % colors.length], actualRow);
+            }
+            curRow++;
+            actualRow++;
+        }
+
+        while (rowBGs.numChildren > i)
+        {
+            rowBGs.removeChildAt(rowBGs.numChildren - 1);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function isDraggingAllowed(draggedColumn:AdvancedDataGridColumn):Boolean
+    {
+        if (!draggedColumn.draggable)
+            return false;
+
+        if(columnGrouping)
+        {
+            var parentInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(draggedColumn).parent;
+
+            //Parent doesn't allow its children to be draggable
+            if(parentInfo && (parentInfo.column as AdvancedDataGridColumnGroup).childrenDragEnabled == false)
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     *  @private
+     */
+    override protected function columnDraggingMouseUpHandler(event:Event):void
+    {
+        if(!columnGrouping)
+        {
+            super.columnDraggingMouseUpHandler(event);
+            return;
+        }
+
+        if (!movingColumn)
+            return;
+
+        var headerInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(movingColumn);
+
+        var origIndex:int = headerInfo.index;//movingColumn.colNum;
+        var dropPositions:Array = getPossibleDropPositions(movingColumn);
+        var n:int = dropPositions.length;
+
+        if (dropColumnIndex >= 0)
+        {
+            if (dropColumnIndex >= n)
+                dropColumnIndex = n - 1;
+            else if (origIndex < dropColumnIndex)
+                dropColumnIndex--;
+
+            //dropColumnIndex is actually the index into the group w.r.t to the displayableColumns,
+            //We need to get the corresponding actual index
+            dropColumnIndex = dropPositions[dropColumnIndex].index;
+        }
+
+        // Shift columns.
+        shiftColumns(origIndex, dropColumnIndex, event);
+        unsetColumnDragParameters();
+
+    }
+
+    /**
+     *  @private
+     */
+    override protected function dragEnterHandler(event:DragEvent):void
+    {
+        // Drag-and-drop not supported for cells
+        if (isCellSelectionMode())
+            return;
+
+        if (!(_rootModel is IHierarchicalData) &&
+			(event.dragSource.hasFormat("items") || event.dragSource.hasFormat("orderedItems")))
+        {
+            super.dragEnterHandler(event);
+            return;
+        }
+
+        if (event.isDefaultPrevented())
+            return;
+
+		lastDragEvent = event;
+
+        if ((!_rootModel || _rootModel is IHierarchicalData) && event.dragSource.hasFormat("treeDataGridItems"))
+        {
+            DragManager.acceptDragDrop(this);
+            DragManager.showFeedback(event.ctrlKey ?
+                                     DragManager.COPY :
+                                     DragManager.MOVE);
+            showDropFeedback(event);
+            return;
+        }
+        hideDropFeedback(event);
+        DragManager.showFeedback(DragManager.NONE);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function dragOverHandler(event:DragEvent):void
+    {
+        // Drag-and-drop not supported for cells
+        if (isCellSelectionMode())
+            return;
+
+        if (!(_rootModel is IHierarchicalData) &&
+			(event.dragSource.hasFormat("items") || event.dragSource.hasFormat("orderedItems")))
+        {
+            super.dragOverHandler(event);
+            return;
+        }
+
+        if (event.isDefaultPrevented())
+            return;
+
+		lastDragEvent = event;
+
+        if ((!_rootModel || _rootModel is IHierarchicalData) && event.dragSource.hasFormat("treeDataGridItems"))
+        {
+            DragManager.showFeedback(event.ctrlKey ?
+                                     DragManager.COPY :
+                                     DragManager.MOVE);
+            showDropFeedback(event);
+            return;
+        }
+        hideDropFeedback(event);
+        DragManager.showFeedback(DragManager.NONE);
+    }
+
+    /**
+     *  Handler for the DragEvent.DRAG_DROP event.
+     *  This method  hides
+     *  the drop feedback by calling the hideDropFeedback() method.
+     *
+     *  By default, only the DragManager.MOVE drag action is supported.
+     *  To support the DragManager.COPY
+     *  drag action, you must write an event handler for the
+     *  DragEvent.DRAG_DROP event that
+     *  implements the copy of the AdvancedDataGrid data based on its structure.
+     *
+     *  @param event The DragEvent object.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override protected function dragDropHandler(event:DragEvent):void
+    {
+        // Drag-and-drop not supported for cells
+        if (isCellSelectionMode())
+            return;
+
+        if (!(_rootModel is IHierarchicalData) &&
+			(event.dragSource.hasFormat("items") || event.dragSource.hasFormat("orderedItems")))
+        {
+            super.dragDropHandler(event);
+            return;
+        }
+
+        if (event.isDefaultPrevented())
+            return;
+
+        hideDropFeedback(event);
+
+        if ((!_rootModel || _rootModel is IHierarchicalData) && event.dragSource.hasFormat("treeDataGridItems"))
+        {
+            //we only support MOVE by default
+            if (event.action == DragManager.MOVE && dragMoveEnabled)
+            {
+                var items:Array = event.dragSource.dataForFormat("treeDataGridItems") as Array;
+                //Are we dropping on ourselves?
+                if (event.dragInitiator == this)
+                {
+                    // If we're dropping onto ourselves or a child of a descendant then dont actually drop
+
+                    calculateDropIndex(event);
+
+                    // If we did start this drag op then we need to remove first
+                    var index:int;
+                    var parent:*;
+                    var parentItem:*;
+                    //get ancestors of the drop target item
+                    var dropParentStack:Array = getParentStack(_dropData.parent);
+                    dropParentStack.unshift(_dropData.parent); //optimize stack method
+                    var n:int = items.length;
+                    for (var i:int = 0; i < n; i++)
+                    {
+                        parent = getParentItem(items[i]);
+                        index = getChildIndexInParent(parent, items[i]);
+                        //check ancestors of the dropTarget if the item matches, we're invalid
+                        for each (parentItem in dropParentStack)
+                        {
+                            //we dont want to drop into one of our own sets of children
+                            if (items[i] == parentItem)
+                                return;
+                        }
+                        //we remove before we add due to the behavior
+                        //of structures with parent pointers like e4x
+                        removeChildItem(parent, items[i], index);
+                        //is the removed item before the drop location?
+                        if (parent == _dropData.parent && index < _dropData.index)
+                        {
+                            addChildItem(_dropData.parent, items[i], (_dropData.index - i - 1));
+                        }
+                        else
+                        {
+                            addChildItem(_dropData.parent, items[i], _dropData.index);
+                        }
+                    }
+                }
+            }
+        }
+		lastDragEvent = null;
+    }
+
+    /**
+     *  Handler for the DragEvent.DRAG_COMPLETE event.
+     *
+     *  By default, only the DragManager.MOVE drag action is supported.
+     *  To support the DragManager.COPY
+     *  drag action, you must write an event handler for the
+     *  DragEvent.DRAG_DROP event that
+     *  implements the copy of the AdvancedDataGrid data based on its structure.
+     *
+     *  @param event The DragEvent object.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override protected function dragCompleteHandler(event:DragEvent):void
+    {
+        // Drag-and-drop not supported for cells
+        if (isCellSelectionMode())
+            return;
+
+        if (!(_rootModel is IHierarchicalData) &&
+			(event.dragSource.hasFormat("items") || event.dragSource.hasFormat("orderedItems")))
+        {
+            super.dragCompleteHandler(event);
+            return;
+        }
+
+        isPressed = false;
+
+        if (event.isDefaultPrevented())
+            return;
+
+		resetDragScrolling();
+
+        if ((!_rootModel || _rootModel is IHierarchicalData) && event.dragSource.hasFormat("treeDataGridItems"))
+        {
+            var items:Array;
+            //we only support MOVE by default
+            if (event.action == DragManager.MOVE && dragMoveEnabled)
+            {
+                if (event.relatedObject != this)
+                {
+                    //if we dropped on another component
+                    //then we need to remove from ourself first
+                    items = event.dragSource.dataForFormat("treeDataGridItems") as Array;
+                    var parent:*;
+                    var index:int;
+                    //do the remove
+                    var n:int = items.length;
+                    for (var i:int=0; i < n; i++)
+                    {
+                        parent = getParentItem(items[i]);
+                        index = getChildIndexInParent(parent, items[i]);
+                        removeChildItem(parent, items[i], index);
+                    }
+                    addItemsToTarget(event, items);
+                }
+                clearSelected(false);
+            }
+            else if (event.action == DragManager.COPY)
+            {
+                if (event.relatedObject != this)
+                {
+                    items = event.dragSource.dataForFormat("treeDataGridItems") as Array;
+                    addItemsToTarget(event, items);
+                }
+                clearSelected(false);
+            }
+
+        }
+		lastDragEvent = null;
+    }
+
+    /**
+     *  @private
+     *  Initialized the headerInfos structure w.r.t to the groupedColumns
+     *  configuration
+     */
+    override protected function initializeHeaderInfo(groupedColumns:Array):Array
+    {
+        if(!columnGrouping)
+            return super.initializeHeaderInfo(groupedColumns);
+        else
+            return initializeGroupedHeaderInfo(groupedColumns, null,0,null);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function createDisplayableColumns():void
+    {
+        if(!columnGrouping)
+        {
+            super.createDisplayableColumns();
+        }
+        else
+        {
+            var i:int;
+            var n:int;
+
+            displayableColumns = [];
+            n = _columns.length;
+            for (i = 0; i < n; i++)
+            {
+                if(getHeaderInfo(_columns[i]).visible)
+                    displayableColumns.push(_columns[i]);
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function updateVisibleHeaders():Array
+    {
+        if(!columnGrouping)
+            return super.updateVisibleHeaders();
+        else
+            return updateVisibleHeaderInfos(headerInfos).infos;
+    }
+
+    /**
+     *  @private
+     */
+    override protected function updateHeaderSearchList():void
+    {
+        orderedHeadersList = [];
+        updateHeadersList(visibleHeaderInfos);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function calculateHeaderHeight():Number
+    {
+        if (!columnGrouping)
+            return super.calculateHeaderHeight();
+
+        // first measure the header
+        isMeasuringHeader = true;
+        createHeaders(0, 0);
+        isMeasuringHeader = false;
+
+        return headerHeight;
+    }
+
+    /**
+     *  @private
+     *  Position indicator bar that shows where an item will be placed in the list.
+     */
+    override public function showDropFeedback(event:DragEvent):void
+    {
+        if (!(_rootModel is IHierarchicalData))
+        {
+            super.showDropFeedback(event);
+            return;
+        }
+
+        super.showDropFeedback(event);
+        // Adjust for indent
+        var vm:EdgeMetrics = viewMetrics;
+        var offset:int = 0;
+        updateDropData(event);
+        var indent:int = 0;
+        var depth:int;
+        if (_dropData.parent)
+        {
+            offset = getItemIndex(iterator.current);
+            depth = getItemDepth(_dropData.parent, Math.abs(offset - getItemIndex(_dropData.parent)));
+            indent = (depth + 1) * getStyle("indentation");
+        }
+        else
+        {
+            indent = getStyle("indentation");
+        }
+        if (indent < 0)
+            indent = 0;
+        //position drop indicator
+        dropIndicator.width = listContent.width - indent;
+        dropIndicator.x = indent + vm.left + 2;
+        if (_dropData.emptyFolder)
+        {
+            dropIndicator.y += _dropData.rowHeight / 2;
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function addDragData(ds:Object):void    // actually a DragSource
+    {
+        if (_rootModel is IHierarchicalData)
+            ds.addHandler(collapseSelectedItems, "treeDataGridItems");
+        else
+            super.addDragData(ds);
+    }
+
+    /**
+     *  @private
+     *  Set the itemEditor instance position according to the indentation of the item it is representing.
+     */
+    override protected function layoutItemEditor():void
+    {
+        if (_rootModel is IHierarchicalData)
+        {
+            var indent:int = rowMap[editedItemRenderer.name].indent;
+            itemEditorInstance.move(itemEditorInstance.x + indent, itemEditorInstance.y);
+            itemEditorInstance.setActualSize(itemEditorInstance.width - indent, itemEditorInstance.height);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function selectColumnHeader(columnNumber:int):void
+    {
+        if(!columnGrouping || selectedHeaderInfo == null)
+            super.selectColumnHeader(columnNumber);
+        else
+            selectColumnGroupHeader(selectedHeaderInfo);
+    }
+
+    /**
+     *  @private
+     */
+    override public function createItemEditor(colIndex:int, rowIndex:int):void
+    {
+        // TODO - Check for the item renderer instead of the column number
+        if (_rootModel is IHierarchicalData && colIndex == treeColumnIndex)
+        {
+            var col:AdvancedDataGridColumn = displayableColumns[colIndex];
+            if (col.editorXOffset == 0 || col.editorWidthOffset == 0)
+            {
+                col.editorXOffset = 12;
+                col.editorWidthOffset = -12;
+            }
+        }
+        super.createItemEditor(colIndex, rowIndex);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function adjustAfterRemove(items:Array, location:int, emitEvent:Boolean):Boolean
+    {
+        var requiresValueCommit:Boolean = emitEvent;
+
+        if (isCellSelectionMode())
+        {
+            var n:int = items.length;
+            for (var i:int = 0; i < n; i++)
+            {
+                var uid:String = UIDUtil.getUID(items[i]);
+
+                if (cellSelectionData[uid])
+                {
+                    for (var p:String in cellSelectionData[uid])
+                    {
+                        removeCellIndicators(uid, int(p));
+                        removeCellSelectionData(uid, int(p));
+                        requiresValueCommit = true;
+                    }
+                }
+            }
+        }
+        else // if (isRowSelectionMode())
+        {
+            var indicesLength:int = selectedItems.length;
+            var length:int = items.length;
+
+            if (_selectedIndex > location)
+            {
+                _selectedIndex -= length;
+                requiresValueCommit = true;
+            }
+
+            if (bSelectedItemRemoved && indicesLength < 1)
+            {
+                _selectedIndex = getItemIndex(expandedItem);
+                requiresValueCommit = true;
+                bSelectionChanged = true;
+                bSelectedIndexChanged = true;
+                invalidateDisplayList();
+            }
+        }
+
+        return requiresValueCommit;
+    }
+
+    /**
+     *  @private
+     */
+    override protected function makeListData(data:Object, uid:String,
+                                             rowNum:int, columnNum:int, column:AdvancedDataGridColumn):BaseListData
+    {
+        var label:String ;
+        var advancedDataGridListData:AdvancedDataGridListData;
+        if(data is AdvancedDataGridColumnGroup)
+        {
+            return new AdvancedDataGridListData((column.headerText != null) ? column.headerText : "",
+                                                data.dataField, -1, uid, this, rowNum);
+        }
+        else if (!(data is AdvancedDataGridColumn))
+        {
+            if (groupItemRenderer && isBranch(data) && column.colNum == treeColumnIndex)
+            {
+                // Checking for a groupLabelFunction or a groupLabelField property to be present
+                if (groupLabelFunction != null)
+                    label = groupLabelFunction(data, column);
+                else if (groupLabelField != null && data.hasOwnProperty(groupLabelField))
+                    label = data[groupLabelField];
+
+                if (label)
+                    advancedDataGridListData = new AdvancedDataGridListData(label, column.dataField,
+                                                                            columnNum, uid, this, rowNum);
+            }
+        }
+
+        if (!advancedDataGridListData)
+            advancedDataGridListData =
+                super.makeListData(data, uid, rowNum,columnNum,column) as AdvancedDataGridListData;
+
+        if (iterator && iterator is HierarchicalCollectionViewCursor && columnNum == treeColumnIndex
+                        && !(data is AdvancedDataGridColumn))
+            initListData(data, advancedDataGridListData);
+        else
+            //item needs to be set, otherwise it will flicker the display when a node is expanded or collapsed
+            advancedDataGridListData.item = data;
+
+        return advancedDataGridListData;
+    }
+
+    /**
+     *  @private
+     */
+    override public function itemToIcon(item:Object):Class
+    {
+        if (item == null)
+        {
+            return null;
+        }
+
+        var icon:*;
+        var open:Boolean = isItemOpen(item);
+        var branch:Boolean = isBranch(item);
+        var uid:String = itemToUID(item);
+
+        //first lets check the component
+        var iconClass:Class =
+            itemIcons && itemIcons[uid] ?
+            itemIcons[uid][open ? "iconID2" : "iconID"] :
+            null;
+
+        if (iconClass)
+        {
+            return iconClass;
+        }
+        else if (iconFunction != null)
+        {
+            return iconFunction(item);
+        }
+        else if (branch)
+        {
+            return getStyle(open ? "folderOpenIcon" : "folderClosedIcon");
+        }
+        else
+            //let's check the item itself
+        {
+            if (item is XML)
+            {
+                try
+                {
+                    if (item[iconField].length() != 0)
+                        icon = String(item[iconField]);
+                }
+                catch(e:Error)
+                {
+                }
+            }
+            else if (item is Object)
+            {
+                try
+                {
+                    if (iconField && item[iconField])
+                        icon = item[iconField];
+                    else if (item.icon)
+                        icon = item.icon;
+                }
+                catch (e:Error)
+                {
+                }
+            }
+        }
+
+        //set default leaf icon if nothing else was found
+        if (icon == null)
+            icon = getStyle("defaultLeafIcon");
+
+        //convert to the correct type and class
+        if (icon is Class)
+        {
+            return icon;
+        }
+        else if (icon is String)
+        {
+            iconClass = Class(systemManager.getDefinitionByName(String(icon)));
+            if (iconClass)
+                return iconClass;
+
+            return document[icon];
+        }
+        else
+        {
+            return Class(icon);
+        }
+
+    }
+
+    /**
+     *   Checks to see if item is visible in the list
+     *  @private
+     */
+    override public function isItemVisible(item:Object):Boolean
+    {
+        //first check visible data
+        if (visibleData[itemToUID(item)])
+            return true;
+
+        //then check parent items
+        var parentItem:Object = getParentItem(item);
+        if (parentItem)
+        {
+            var uid:String = itemToUID(parentItem);
+            if (visibleData[uid] && IHierarchicalCollectionView(collection).openNodes[uid])
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *  @private
+     */
+    override protected function isDataEditable(data:Object):Boolean
+    {
+        if (_rootModel && (_rootModel is IGroupingCollection || _rootModel is IGroupingCollection2))
+        {
+            // group header
+            if (_rootModel.hasChildren(data))
+                return editable.indexOf("group") != -1;
+
+            // summary data
+            if (data is SummaryObject)
+                return editable.indexOf("summary") != -1;
+        }
+
+        // any item renderer
+        return editable.indexOf("item") != -1;
+    }
+
+    /**
+     *  @private
+     *
+     *  see ListBase.as
+     */
+    override mx_internal function addClipMask(layoutChanged:Boolean):void
+    {
+        var vm:EdgeMetrics = viewMetrics;
+        var bHScrollBar:Boolean
+        if (horizontalScrollBar && horizontalScrollBar.visible)
+            vm.bottom -= horizontalScrollBar.minHeight;
+
+        if (verticalScrollBar && verticalScrollBar.visible)
+            vm.right -= verticalScrollBar.minWidth;
+
+        if(verticalScrollBar && verticalScrollBar.visible && horizontalScrollBar && horizontalScrollBar.visible)
+            vm.right += verticalScrollBar.minWidth;
+
+        listContent.scrollRect = new Rectangle(
+            0, 0,
+            unscaledWidth - vm.left - vm.right,
+            listContent.height);
+    }
+
+    override mx_internal function shiftColumns(oldIndex:int, newIndex:int,
+                                               trigger:Event = null):void
+    {
+        if (newIndex >= 0 && oldIndex != newIndex)
+        {
+            if(!columnGrouping)
+            {
+                super.shiftColumns(oldIndex, newIndex, trigger);
+            }
+            else
+            {
+                var headerInfo:AdvancedDataGridHeaderInfo =  getHeaderInfo(movingColumn);
+                //needed for automation, which uses movingColumnIndex
+                updateMovingColumnIndex();
+                var groupInfos:Array = headerInfo.parent ? headerInfo.parent.children : headerInfos;
+                var groupColumns:Array = headerInfo.parent == null ? groupedColumns : (headerInfo.parent.column as AdvancedDataGridColumnGroup).children;
+
+                var k:int;
+                var queue:Array = [];
+                var pointer:int = 0;
+                var i:int;
+                var increment:int;
+                if (newIndex >= 0 && oldIndex != newIndex)
+                {
+                    var incr:int = oldIndex < newIndex ? 1 : -1;
+                    for (i = oldIndex; i != newIndex; i += incr)
+                    {
+                        var j:int = i + incr;
+                        var c:AdvancedDataGridColumn = groupColumns[i];
+                        groupColumns[i] = groupColumns[j];
+                        groupColumns[j] = c;
+
+                        groupInfos[i].actualColNum +=  groupInfos[j].columnSpan * incr;
+                        groupInfos[j].actualColNum -=  groupInfos[i].columnSpan * incr;
+
+                        //If the columns being dragged or shifted is a Column Group then actualColNum
+                        //need to be modified for all the descendants of the column group.
+                        if (groupInfos[i].children && groupInfos[i].children.length > 0)
+                        {
+                            increment = groupInfos[j].columnSpan * incr;
+                            for( k = 0; k < groupInfos[i].children.length; k++)
+                            {
+                                queue.push(groupInfos[i].children[k]);
+                            }
+                            while (queue[pointer])
+                            {
+                                headerInfo = queue[pointer++];
+                                headerInfo.actualColNum +=  increment;
+                                if(headerInfo && headerInfo.children)
+                                {
+                                    for( k = 0; k < headerInfo.children.length; k++)
+                                    {
+                                        queue.push(headerInfo.children[k]);
+                                    }
+                                }
+                            }
+                        }
+                        if (groupInfos[j].children && groupInfos[j].children.length > 0)
+                        {
+                            queue = [];
+                            pointer = 0;
+                            increment = groupInfos[i].columnSpan * incr;
+                            for( k = 0; k < groupInfos[j].children.length; k++)
+                            {
+                                queue.push(groupInfos[j].children[k]);
+                            }
+                            while (queue[pointer])
+                            {
+                                headerInfo = queue[pointer++]
+                                    headerInfo.actualColNum -=  increment;
+                                if(headerInfo && headerInfo.children)
+                                    for( k = 0; k < headerInfo.children.length; k++)
+                                        queue.push(headerInfo.children[k]);
+                            }
+                        }
+
+                        var cInfo:AdvancedDataGridHeaderInfo = groupInfos[i];
+                        groupInfos[i] = groupInfos[j];
+                        groupInfos[j] = cInfo;
+                        groupInfos[i].index -=incr;
+                        groupInfos[j].index += incr;
+
+                    }
+
+                    var newColumns:Array = getLeafColumns(groupedColumns);
+                    _columns = [];
+                    var n:int = newColumns.length;
+                    for (i = 0; i < n; i++)
+                    {
+                        _columns[i] = newColumns[i];
+                        _columns[i].colNum = i;
+
+                    }
+                    visibleHeaderInfos = updateVisibleHeaders();
+                    updateHeaderSearchList();
+
+                    createDisplayableColumns();
+                    //In case of column grouping a shifting of columns may lead to
+                    //change in the effective layout owing to a bigger or
+                    //smaller group shifted in from locked area to unlocked area
+                    //or vice versa
+                    var newLockedColCount:int =  getAdjustedLockedCount(_lockedColumnCountVal);
+                    if (lockedColumnCount != newLockedColCount)
+                    {
+                        lockedColumnCountChanged = true;
+                        super.lockedColumnCount = newLockedColCount;
+                    }
+                    columnsInvalid = true;
+                    itemsSizeChanged = true;
+                    invalidateDisplayList();
+                    var icEvent:IndexChangedEvent =
+                        new IndexChangedEvent(IndexChangedEvent.HEADER_SHIFT);
+                    icEvent.oldIndex = oldIndex;
+                    icEvent.newIndex = newIndex;
+                    icEvent.triggerEvent = trigger;
+                    dispatchEvent(icEvent);
+                }
+            }
+            if (isCellSelectionMode())
+                clearSelectedCells();
+        }
+    }
+
+    /**
+     *  @private
+     *  Fetch sort information for the given column.
+     */
+    override public function getFieldSortInfo(column:AdvancedDataGridColumn):SortInfo
+    {
+        if (!sortExpertMode && visualSortInfo[column.colNum])
+            return visualSortInfo[column.colNum];
+
+         var headerInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(column);
+
+         if (columnGrouping && column && collection && collection.sort
+             && headerInfo.internalLabelFunction != null)
+         {
+
+            var n:int = collection.sort.fields.length;
+            for (var i:int = 0; i < n; i++)
+            {
+                var uid:String = itemToUID(column);
+                if( uid &&  collection.sort.fields[i].name == uid)
+                    return new SortInfo(i + 1, collection.sort.fields[i].descending);
+            }
+        }
+        else
+        {
+            return super.getFieldSortInfo(column);
+        }
+
+        return null;
+    }
+
+    /**
+     *  @private
+     */
+    override protected function unselectColumnHeader(columnNumber:int,
+                                                     completely:Boolean=false):void
+    {
+        var s:Sprite = Sprite( selectionLayer.getChildByName("headerKeyboardSelection") );
+
+        //If not found, then see if there is a child in the movingSelectionLayer
+        if(!s)
+            s = Sprite(movingSelectionLayer.getChildByName("headerKeyboardSelection"));
+
+        if (s)
+            s.parent.removeChild(s);
+
+        selectedHeaderInfo = null;
+
+        if (completely)
+        {
+            caretIndex = 0;
+            isPressed = false;
+
+            if (isCellSelectionMode())
+            {
+                caretColumnIndex = columnNumber;
+                selectItem(listItems[caretIndex][absoluteToVisibleColumnIndex(columnNumber)],
+                           false, false);
+            }
+            else
+            {
+                selectItem(listItems[caretIndex][0], false, false);
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override public function styleChanged(styleProp:String):void
+    {
+        super.styleChanged(styleProp);
+
+        if (styleProp == "sortFontFamily"
+            || styleProp == "sortFontSize"
+            || styleProp == "sortFontStyle"
+            || styleProp == "sortFontWeight")
+        {
+            itemsSizeChanged = true;
+            rendererChanged = true;
+            invalidateProperties();
+            invalidateDisplayList();
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function removeIndicators(uid:String):void
+    {
+        if (isCellSelectionMode())
+        {
+            for (var p:String in cellSelectionIndicators[uid])
+            {
+                removeCellIndicators(uid, int(p));
+            }
+
+            for (p in visibleCellRenderers[uid])
+            {
+                delete visibleCellRenderers[uid][p];
+            }
+
+            delete visibleCellRenderers[uid];
+        }
+
+        super.removeIndicators(uid);
+    }
+
+    /**
+     *  Moves the cell and row selection indicators up or down by the given offset
+     *  as the control scrolls its display.
+     *  This assumes all the selection indicators in this row are at
+     *  the same y position.
+     *
+     *  @param uid The UID of the row.
+     *
+     *  @param The scroll offset.
+     *
+     *  @param absolute true if offset contains the new scroll position,
+     *  and false if it contains a value relative to the current scroll position.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override protected function moveIndicators(uid:String, offset:int, absolute:Boolean):void
+    {
+        if (!uid)
+            return;
+
+        if (!absolute && offset == 0)
+            return;
+
+         if (isCellSelectionMode())
+         {
+            if (cellSelectionIndicators[uid])
+            {
+                for (var p:String in cellSelectionIndicators[uid])
+                {
+                    if (absolute)
+                        cellSelectionIndicators[uid][p].y = offset;
+                    else
+                        cellSelectionIndicators[uid][p].y += offset;
+                }
+            }
+        }
+        else
+        {
+            // Functionality in AdvancedListBase, so we can't assume that it
+            // checks for isRowSelectionMode as in ADGBase, otherwise usually
+            // we would call the super version directly, and not in an 'else'
+            // clause.
+            super.moveIndicators(uid, offset, absolute);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override mx_internal function clearHighlight(item:IListItemRenderer):void
+    {
+        if (isCellSelectionMode())
+        {
+            var uid:String = itemToUID(item.data);
+            var c:AdvancedDataGridColumn = columnMap[item.name];
+            if (c)
+            {
+                var columnIndex:int = c.colNum;
+
+                drawCellItem(item,
+                             cellSelectionData[uid]
+                             && cellSelectionData[uid][columnIndex],
+                             false,
+                             caretUID == uid
+                             && caretColumnIndex == columnIndex);
+            }
+        }
+
+        super.clearHighlight(item);
+    }
+
+    /**
+     * @private
+     */
+    override protected function selectData(uid:String, data:Object,
+                            index:int, selectedBookmark:CursorBookmark):void
+    {
+        if (isCellSelectionMode())
+        {
+            var columnIndex:int = selectedColumnIndex;
+            if (!cellSelectionData[uid] || !cellSelectionData[uid][columnIndex])
+            {
+                if (cellSelectionIndicators[uid] && cellSelectionIndicators[uid][columnIndex])
+                {
+                    selectCellItem(cellSelectionData[uid][columnIndex], false, false);
+                }
+                else
+                {
+                    clearSelectedCells();
+                    addCellSelectionData(uid, columnIndex,
+                             new AdvancedDataGridBaseSelectionData(data,
+                                                       index, columnIndex, false) );
+                    selectedColumnIndex = caretColumnIndex = anchorColumnIndex = columnIndex;
+                    _selectedIndex      = caretIndex       = anchorIndex       = index;
+                    caretBookmark       = anchorBookmark   = selectedBookmark;
+                }
+            }
+        }
+        else
+        {
+            super.selectData(uid, data, index, selectedBookmark);
+        }
+    }
+
+    /**
+     * @private
+     * Clear all the selected data.
+     */
+    override protected function clearAllSelection():void
+    {
+        if (isCellSelectionMode())
+        {
+            clearSelectedCells();
+            clearCellIndicators();
+        }
+
+        super.clearAllSelection();
+    }
+
+    /**
+     *  @private
+     */
+    override protected function itemRendererToIndices(item:IListItemRenderer):Point
+    {
+        // We do not support this method for headers as headerItems are separate from the
+        // listItems. On the other hand, DataGrid supports this fine since headers are
+        // listItems[0].
+        if (isHeaderItemRenderer(item))
+            return null;
+
+        var pt:Point = super.itemRendererToIndices(item);
+
+        // When optimumColumns is displayableColumns, then pt.x already points
+        // to the correct column number, so we don't need to add
+        // horizontalScrollPosition, so undo what the 'super' version does.
+        if (pt && getOptimumColumns() != visibleColumns && pt.x >= lockedColumnCount)
+            pt.x -= horizontalScrollPosition;
+        return pt;
+    }
+
+    /**
+     *  @private
+     */
+    override protected function getOptimumColumns():Array
+    {
+        if (rendererProviders.length > 0 && horizontalScrollPolicy != ScrollPolicy.OFF || columnGrouping)
+            return displayableColumns;
+
+        return super.getOptimumColumns();
+    }
+
+    /**
+     *  @private
+     */
+    override protected function getRowHeight(itemData:Object = null):Number
+    {
+        if (groupRowHeight > 0 && dataProvider is IHierarchicalCollectionView && _rootModel.hasChildren(itemData))
+            return groupRowHeight;
+        else
+            return super.getRowHeight();
+    }
+
+    /**
+     *  @private
+     */
+    override mx_internal function getMeasuringRenderer(c:AdvancedDataGridColumn, forHeader:Boolean, data:Object):IListItemRenderer
+    {
+        if (!forHeader)
+        {
+            var adgDescription:AdvancedDataGridRendererDescription;
+
+            if (rendererProviders.length != 0)
+            {
+                adgDescription = getRendererDescription(data,c,false);
+
+                if (adgDescription && adgDescription.renderer)
+                {
+                    var factory:IFactory = adgDescription.renderer;
+                    var item:IListItemRenderer = measuringObjects[factory];
+
+                    if (!item)
+                    {
+                        item = adgDescription.renderer.newInstance();
+                        item.visible = false;
+                        item.styleName = c;
+                        listContent.addChild(DisplayObject(item));
+                        measuringObjects[factory] = item;
+                    }
+
+                    return item;
+                }
+            }
+        }
+
+        return super.getMeasuringRenderer(c, forHeader, data);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Returns true if the specified item is a branch item. The AdvancedDataGrid
+     *  control delegates to the IDataDescriptor to determine if an item is a branch.
+     *  @param item Item to inspect.
+     *  @return True if a branch, false if not.
+     *
+     */
+    protected function isBranch(item:Object):Boolean
+    {
+        if (_rootModel && item != null)
+            return _rootModel.canHaveChildren(item);
+        return false;
+    }
+
+    /**
+     *  @private
+     *  wraps calls to the descriptor
+     *  mx_internal for automation delegate access
+     */
+    mx_internal function getChildren(item:Object, view:Object):ICollectionView
+    {
+        //get the collection of children
+        var children:ICollectionView = IHierarchicalCollectionView(collection).getChildren(item);
+        return children;
+    }
+
+    /**
+     *  Determines the number of parents from root to the specified item.
+     *  Method starts with the Cursor.current item and will seek forward
+     *  to a specific offset, returning the cursor to its original position.
+     *
+     *  @private
+     */
+    mx_internal function getItemDepth(item:Object, offset:int):int
+    {
+        //first test for a match (most cases)
+        if (!collection)
+            return 0;
+
+        if (!iterator)
+            iterator = collection.createCursor();
+
+        return getDepth(item);
+    }
+
+    /**
+     *  @private
+     *  Utility method to get the depth of the item.
+     */
+    protected function getDepth(item:Object):int  //private
+    {
+        // if data is hierarchical, calculate its depth
+        if (_rootModel is IHierarchicalData && collection is IHierarchicalCollectionView)
+            return IHierarchicalCollectionView(dataProvider).getNodeDepth(item);
+
+        return -1;
+    }
+
+    /**
+     *  Sets the associated icon in the navigation tree for the item.
+     *  Calling this method overrides the
+     *  iconField and iconFunction properties for
+     *  this item if it is a leaf item. Branch items don't use the
+     *  iconField and iconFunction properties.
+     *  They use the folderOpenIcon and folderClosedIcon properties.
+     *
+     *  @param item An Object defining the item in the navigation tree.
+     *  This Object contains the data provider element for the item.
+     *
+     *  @param iconID The closed (or leaf) icon.
+     *
+     *  @param iconID2 The open icon.
+     *
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function setItemIcon(item:Object, iconID:Class, iconID2:Class):void
+    {
+        if (!itemIcons)
+            itemIcons = {};
+
+        if (!iconID2)
+            iconID2 = iconID;
+
+        itemIcons[itemToUID(item)] = { iconID: iconID, iconID2: iconID2 };
+
+        itemsSizeChanged = true;
+        invalidateDisplayList();
+    }
+
+    /**
+     *  @private
+     *  Gets the number of visible items from a starting item.
+     */
+    private function getVisibleChildrenCount(item:Object):int
+    {
+        var count:int = 0;
+
+        if (item == null)
+            return count;
+
+        var uid:String = itemToUID(item);
+        var children:Object;
+        if (IHierarchicalCollectionView(collection).openNodes[uid] &&
+            _rootModel.canHaveChildren(item) &&
+            _rootModel.hasChildren(item))
+        {
+            children = getChildren(item, iterator.view);
+        }
+        if (children != null)
+        {
+            var n:int = children.length;
+            for (var i:int = 0; i < n; i++)
+            {
+                count++;
+
+                uid = itemToUID(children[i]);
+                if (IHierarchicalCollectionView(collection).openNodes[uid])
+                    count += getVisibleChildrenCount(children[i]);
+            }
+        }
+        return count;
+    }
+
+    /**
+     *  Returns true if the specified branch node is open.
+     *
+     *  @param item Branch node to inspect.
+     *  This Object contains the data provider element for the branch node.
+     *
+     *  @return true if open, and false if not.
+     *
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function isItemOpen(item:Object):Boolean
+    {
+        var uid:String = itemToUID(item);
+        return IHierarchicalCollectionView(collection).openNodes[uid] != null;
+    }
+
+    /**
+     *  @private
+     */
+    private function makeMask():DisplayObject
+    {
+        var tmpMask:Shape = new FlexShape();
+        tmpMask.name = "mask";
+
+        var g:Graphics = tmpMask.graphics;
+        g.beginFill(0xFFFFFF);
+        g.moveTo(0,0);
+        g.lineTo(0,10);
+        g.lineTo(10,10);
+        g.lineTo(10,0);
+        g.lineTo(0,0);
+        g.endFill();
+
+        listContent.addChild(tmpMask);
+        return tmpMask;
+    }
+
+    /**
+     *  Opens or closes a branch node of the navigation tree.
+     *  When a branch item opens, it restores the open and closed states
+     *  of its child branches if they were already opened.
+     *
+     *
If you set the dataProvider property and then immediately call
+     *  the expandItem() method, you may not see the correct behavior.
+     *  You should either wait for the component to validate
+     *  or call validateNow().

+     *
+     *  @param item An Object defining the branch node. This Object contains the
+     *  data provider element for the branch node.
+     *
+     *  @param open Specify true to open the branch node,
+     *  and false to close it.
+     *
+     *  @param animate Specify true to animate the transition. (Note:
+     *  If a branch has over 20 children, to improve performance
+     *  it does not animate the first time it opens.)
+     *
+     *  @param dispatchEvent Specifies whether the control dispatches an open event
+     *  after the open animation is complete (true), or not (false).
+     *
+     *  @param cause The event, if any, that initiated the item action.
+     *
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function expandItem(item:Object, open:Boolean,
+                               animate:Boolean = false,
+                               dispatchEvent:Boolean = false,
+                               cause:Event = null):void
+    {
+        //if the iterator is null, that indicates we have not been
+        //validated yet, so we will not continue.
+        if (iterator == null)
+            return;
+
+        if (cause)
+            lastUserInteraction = cause;
+
+        expandedItem = item;
+
+        listContent.allowItemSizeChangeNotification = false;
+        listSubContent.allowItemSizeChangeNotification = false;
+
+        var i:int;
+        var n:int;
+        var bSelected:Boolean = false;
+        var bHighlight:Boolean = false;
+        var bCaret:Boolean = false;
+        var newRowIndex:int;
+        var rowData:BaseListData;
+
+        var tmpMask:DisplayObject;
+
+        var uid:String = itemToUID(item);
+        // if this can't be opened, or shouldn't be, don't!
+        if (!isBranch(item) || (isItemOpen(item)==open) || isOpening)
+            return;
+
+        if (itemEditorInstance)
+            endEdit(ListEventReason.OTHER);
+
+        //we'll use the last recorded length not necessarily the current one
+        oldLength = collectionLength;
+
+        var bookmark:CursorBookmark = iterator.bookmark;
+
+        // sent to update the length in the collection
+        var event:CollectionEvent = new CollectionEvent(
+            CollectionEvent.COLLECTION_CHANGE,
+            false,
+            true,
+            CollectionEventKind.mx_internal::EXPAND);
+        event.items = [item];
+
+        // update the list of openNodes
+        if (open)
+        {
+            IHierarchicalCollectionView(collection).openNode(item);
+            rowsTweened = Math.abs(oldLength - collection.length);
+        }
+        else
+        {
+            IHierarchicalCollectionView(collection).closeNode(item);
+            //how many rows to move?
+            rowsTweened = Math.abs(oldLength - collection.length);
+        }
+
+        // will it affect the displayList?
+        if (isItemVisible(item))
+        {
+            // is the item on screen?
+            if (visibleData[uid])
+            {
+                //find the rowindex of the row after the open thats opening/closing
+                n = listItems.length;
+                for (rowIndex = 0; rowIndex < n; rowIndex++)
+                {
+                    if (rowInfo[rowIndex].uid == uid)
+                    {
+                        rowIndex++;
+                        // rowIndex is set to the row after the one opening/closing
+                        // because that is the first row to change
+                        break;
+                    }
+                }
+            }
+        }
+        //if we're opening or closing a node that is not visible,
+        //we still need to dispatch the correct collectionChange events
+        //so that scroll position and selection properties update correctly.
+        else
+        {
+            var eventArr:Array = open ?
+                buildUpCollectionEvents(true) : buildUpCollectionEvents(false);
+            n = eventArr.length;
+            for (i = 0; i < n; i++)
+            {
+                collection.dispatchEvent(eventArr[i]);
+            }
+
+            // This item is not visible but we need to dispatch the appropiate event
+            if (dispatchEvent)
+            {
+                dispatchAdvancedDataGridEvent(open ? AdvancedDataGridEvent.ITEM_OPEN : AdvancedDataGridEvent.ITEM_CLOSE,
+                                              item,
+                                              visibleData[itemToUID(item)],
+                                              lastUserInteraction);
+                lastUserInteraction = null;
+            }
+
+            return;
+        }
+
+        var rC:int = listItems.length;
+        var tmpRowInfo:Object;
+        var col:int = treeColumnIndex;
+        // we will cap this with as many rows as can be displayed later
+        var rowsToMove:int = rowsTweened;
+        var dur:Number = getStyle("openDuration");
+        if (animate && rowIndex < rC && rowsToMove > 0 && rowsToMove < 20 && dur!=0)
+        {
+            // Kill any previous animation. tween is undefined if there is no Tween underway.
+            if (tween)
+                tween.endTween();
+
+
+            var renderer:IListItemRenderer = listItems[rowIndex - 1][col];
+            if (renderer is IDropInListItemRenderer)
+            {
+                // this is done to refresh the items with their disclosure/folder icons state updated with the new one
+                // If this is removed then the disclosure/folder icons will change their state after the
+                // tween is over.
+                var di:IDropInListItemRenderer = IDropInListItemRenderer(renderer);
+                var advancedDataGridListData:AdvancedDataGridListData = AdvancedDataGridListData(di.listData);
+                advancedDataGridListData = AdvancedDataGridListData(
+                        makeListData(advancedDataGridListData.item, advancedDataGridListData.uid,
+                        advancedDataGridListData.rowIndex,col,visibleColumns[col]));
+
+                di.listData = advancedDataGridListData;
+                renderer.data = renderer.data;  // this forces eval of new listData
+            }
+
+            // animate the opening
+            opening = open;
+            isOpening = true;
+
+            maskList = [];
+            rowList = [];
+
+            // ignoring padding left
+            //var paddingLeft:Number = getStyle("paddingLeft");
+            var paddingLeft:Number = 0;
+            var xx:Number = paddingLeft;
+            var ww:Number = 0;
+            var yy:Number = 0;
+            var hh:Number = 0;
+
+            // don't tween anymore than the amount of space we have
+            var delta:int = rowIndex;
+            var maxDist:Number = 0;
+            var c:AdvancedDataGridColumn;
+            var optimumColumns:Array = getOptimumColumns();
+            if (open)
+            {
+                newRowIndex = rowIndex;
+                // don't tween anymore than the amount of space we have
+                maxDist = listContent.height - rowInfo[rowIndex].y;
+                iterator.seek(CursorBookmark.CURRENT, delta);
+                var data:Object;
+
+                // create the rows now so we know how much to move
+                for (i = 0; i < rowsToMove && yy < maxDist; i++)
+                {
+                    data = iterator.current;
+                    xx = paddingLeft;
+
+                    currentRowNum = rowIndex + i;
+                    hh = 0;
+                    currentColNum = 0;
+                    uid = itemToUID(data);
+
+                    // create renderers
+                    setupRenderer(data,uid,true);
+
+                    bSelected = (selectedData[uid] != null)
+                                || (cellSelectionData[uid] &&
+                                cellSelectionData[uid][currentColNum.toString()]);
+                    bHighlight = highlightUID == uid;
+                    bCaret = caretUID == uid;
+
+                    // layout renderers created above
+                    currentItemTop = yy;
+                    hh = layoutRow(true,xx,hh);
+
+                    tmpRowInfo = new ListRowInfo(yy, hh, uid, data);
+                    yy += hh;
+                    rowInfo.splice(rowIndex + i, 0, tmpRowInfo);
+
+                    iterator.moveNext();
+                }
+                rowsTweened = i;
+                // position the new rows;
+                var referenceRowInfo:ListRowInfo = rowInfo[rowIndex + rowsTweened];
+                for (i = 0; i < rowsTweened; i++)
+                {
+                    xx = paddingLeft;
+                    rowInfo[rowIndex + i].y -= yy - referenceRowInfo.y;
+                    for (col = 0; col < optimumColumns.length; ++col)
+                    {
+                        renderer = listItems[rowIndex + i][col];
+                        renderer.move(renderer.x, renderer.y - (yy - referenceRowInfo.y));
+                        tmpMask = makeMask();
+                        if (col < lockedColumnCount)
+                            tmpMask.x = xx;
+                        else
+                            tmpMask.x = getAdjustedXPos(xx);
+                        tmpMask.y = referenceRowInfo.y;
+                        tmpMask.width = renderer.width;
+                        tmpMask.height = yy;
+                        listItems[rowIndex + i][col].mask = tmpMask;
+                        xx += optimumColumns[col].width;
+                    }
+                }
+            }
+            else // closing up rows
+            {
+                var more:Boolean = true;
+                var valid:Boolean = true;
+                var startY:Number = yy = rowInfo[listItems.length - 1].y + rowInfo[listItems.length - 1].height;
+
+                // figure out how much space was consumed by the rows that are going away
+                for (i = rowIndex; i < rowIndex + rowsToMove && i < rC; i++)
+                {
+                    maxDist += rowInfo[i].height;
+                    xx = paddingLeft;
+                    var tempArray:Array = [];
+                    for (col = 0; col < optimumColumns.length; ++col)
+                    {
+                        // retain a reference to the rows going away
+                        tempArray.push({item: listItems[i][col]});
+                        tmpMask = makeMask();
+                        if (col < lockedColumnCount)
+                            tmpMask.x = xx;
+                        else
+                            tmpMask.x = getAdjustedXPos(xx);
+                        tmpMask.y = listItems[rowIndex][col].y;
+                        // changed rowIndex to i because we want to create the mask for the entire renderer's width
+                        //tmpMask.width = listItems[rowIndex][col].width;
+                        tmpMask.width = listItems[i][col].width;
+                        tmpMask.height = maxDist;
+                        listItems[i][col].mask = tmpMask;
+                        xx += optimumColumns[col].width;
+                    }
+                    if (tempArray.length != 0)
+                        rowList.push(tempArray);
+                }
+                rowsToMove = i - rowIndex;
+                // remove the rows going away
+                rowInfo.splice(rowIndex, rowsToMove);
+                listItems.splice(rowIndex, rowsToMove);
+
+                iterator.seek(CursorBookmark.CURRENT, listItems.length);
+                more = (iterator != null && !iterator.afterLast && iteratorValid);
+
+                maxDist += yy;
+                // create the rows now so we know how much to move
+                for (i = 0; i < rowsToMove && yy < maxDist; i++)
+                {
+                    //reset item specific values
+                    uid = null;
+                    data = null;
+                    renderer = null;
+
+                    valid = more;
+                    data = more ? iterator.current : null;
+
+                    xx = paddingLeft;
+
+                    if(valid)
+                    {
+                        currentRowNum = rC - rowsToMove + i;
+                        currentColNum = 0;
+                        uid = itemToUID(data);
+                        setupRenderer(data,uid,true);
+
+                        bSelected = selectedData[uid] != null;
+                        bHighlight = highlightUID == uid;
+                        bCaret = caretUID == uid;
+
+                        currentItemTop = yy;
+                        hh = layoutRow(true,xx,hh);
+                    }
+                    else
+                    {
+                        // if we've run out of data, we dont make renderers
+                        // and we inherit the previous row's height or rowHeight
+                        // if it is the first row.
+                        // EXCEPT when variable row height is on since the row
+                        // above us might be bigger then we are.  So we'll get
+                        // this row out of the rowList and check it.
+
+                        /* if (!variableRowHeight)
+                           {
+                           hh = rowIndex + i > 0 ? rowInfo[rowIndex + i - 1].height : rowHeight;
+                           }
+                           else
+                           {
+                           if (rowList[i])
+                           {
+                           hh = Math.ceil(rowList[i].item.getExplicitOrMeasuredHeight() +
+                           cachedPaddingTop + cachedPaddingBottom);
+                           }
+                           else
+                           {
+                           //default
+                           hh = rowHeight;
+                           }
+                           } */
+                        hh = rowHeight;
+                    }
+                    tmpRowInfo = new ListRowInfo(yy, hh, uid, data);
+                    rowInfo.push(tmpRowInfo);
+                    yy += hh;
+
+                    if (more)
+                        more = iterator.moveNext();
+                }
+
+                //make indicator masks for rows
+                var maskY:Number = rowList[0][0].item.y - getStyle("paddingTop");
+                var maskX:Number = rowList[0][0].item.x - getStyle("paddingLeft");
+                for (i = 0; i < rowList.length; i++)
+                {
+                    var lastColumn:int = rowList[i].length -1;
+                    var indicator:Object = selectionIndicators[itemToUID(rowList[i][lastColumn].item.data)];
+                    if (indicator)
+                    {
+                        tmpMask = makeMask();
+                        tmpMask.x = maskX;
+                        tmpMask.y = maskY;
+                        tmpMask.width = rowList[i][lastColumn].item.x +
+                            rowList[i][lastColumn].item.width +
+                            getStyle("paddingLeft") +
+                            getStyle("paddingRight");
+                        tmpMask.height = rowList[i][lastColumn].item.y +
+                            rowList[i][lastColumn].item.height +
+                            getStyle("paddingTop") +
+                            getStyle("paddingBottom") -
+                            maskY;
+                        selectionIndicators[itemToUID(rowList[i][lastColumn].item.data)].mask = tmpMask;
+                    }
+                }
+
+                //make indicator masks for cells
+                var cellMaskY:Number = rowList[0][0].item.y - getStyle("paddingTop");
+                var cellMaskX:Number = rowList[0][0].item.x - getStyle("paddingLeft");
+                for (var cellRow:int = 0; cellRow < rowList.length; cellRow++)
+                    for (var cellColumn:int = 0; cellColumn < rowList[cellRow].length; cellColumn++)
+                    {
+                        var cellLastColumn:int = rowList[cellRow].length -1;
+                        var cellUID:String = itemToUID(rowList[cellRow][cellColumn].item.data);
+
+                        if (cellUID in cellSelectionIndicators)
+                        {
+                            var cellIndicator:Object = cellSelectionIndicators[cellUID]
+                                                                              [cellColumn];
+                            if (cellIndicator)
+                            {
+                                tmpMask = makeMask();
+                                tmpMask.x = maskX;
+                                tmpMask.y = maskY;
+                                tmpMask.width = rowList[cellRow][cellLastColumn].item.x +
+                                    rowList[cellRow][cellLastColumn].item.width +
+                                    getStyle("paddingLeft") +
+                                    getStyle("paddingRight");
+                                tmpMask.height = rowList[cellRow][cellLastColumn].item.y +
+                                    rowList[cellRow][cellLastColumn].item.height +
+                                    getStyle("paddingTop") +
+                                    getStyle("paddingBottom") -
+                                    maskY;
+                                cellIndicator.mask = tmpMask;
+                            }
+                        }
+                    }
+            }
+            // restore the iterator
+            iterator.seek(bookmark, 0);
+
+            rC = rowList.length;
+            for (i = 0; i < rC; i++)
+            {
+                for (col = 0; col < rowList[i].length; col++)
+                {
+                    rowList[i][col].itemOldY = rowList[i][col].item.y;
+                }
+            }
+            rC = listItems.length;
+            for (i = rowIndex; i < rC; i++)
+            {
+                if (listItems[i].length)
+                {
+                    rowInfo[i].itemOldY = listItems[i][0].y;
+                }
+                rowInfo[i].oldY = rowInfo[i].y;
+            }
+            // slow down the tween if there's lots of rows to tween
+            dur = dur * Math.max(rowsToMove / 5, 1);
+
+            if (dispatchEvent)
+                eventAfterTween = item;
+
+            tween = new Tween(this, 0, (open) ? yy : startY - yy, dur, 5);
+            var oE:Function = getStyle("openEasingFunction") as Function;
+            if (oE != null)
+                tween.easingFunction = oE;
+
+            // Block all layout, responses from web service, and other background
+            // processing until the tween finishes executing.
+            UIComponent.suspendBackgroundProcessing();
+            // force drawing in case there's new rows
+            UIComponentGlobals.layoutManager.validateNow();
+        }
+        else
+        {
+            // not to be animated
+            if (dispatchEvent)
+            {
+                // in case when eventItemRenderer is null,
+                // instead of taking item renderer from visibleData, we should take it from listItems for
+                // the correct value.
+                var itemRenderer:IListItemRenderer = eventItemRenderer ? eventItemRenderer : visibleData[itemToUID(item)];
+                dispatchAdvancedDataGridEvent(open ? AdvancedDataGridEvent.ITEM_OPEN : AdvancedDataGridEvent.ITEM_CLOSE,
+                                              item,
+                                              itemRenderer,
+                                              lastUserInteraction);
+                lastUserInteraction = null;
+                eventItemRenderer = null;
+            }
+            itemsSizeChanged = true;
+            invalidateDisplayList();
+        }
+
+        // If we're wordwrapping, no need to adjust maxHorizontalScrollPosition.
+        // Also check if _userMaxHorizontalScrollPosition is greater than 0.
+        if (!wordWrap && initialized)
+        {
+            super.maxHorizontalScrollPosition =
+                _userMaxHorizontalScrollPosition > 0 ?
+                _userMaxHorizontalScrollPosition + getIndent() :
+                super.maxHorizontalScrollPosition;
+        }
+        //restore ItemSizeChangeNotification flag
+        listContent.allowItemSizeChangeNotification = variableRowHeight;
+        listSubContent.allowItemSizeChangeNotification = variableRowHeight;
+    }
+
+    /**
+     *  @private
+     */
+    mx_internal function onTweenUpdate(value:Object):void
+    {
+        var renderer:IFlexDisplayObject;
+        var n:int;
+        var m:int;
+        var i:int;
+        var j:int;
+        var deltaY:Number;
+        var lastY:Number;
+        var columnIndexString:String;
+        var cellSelectionUID:String;
+
+        n = listItems.length;
+        var s:Sprite;
+        for (i = rowIndex; i < n; i++)
+        {
+            //move items that are staying
+            if (listItems[i].length)
+            {
+                m = listItems[i].length;
+                for (j = 0; j < m; ++j)
+                {
+                    renderer = IFlexDisplayObject(listItems[i][j]);
+                    lastY = renderer.y;
+                    renderer.move(renderer.x, rowInfo[i].itemOldY + value);
+                    deltaY = renderer.y - lastY;
+                }
+            }
+            //move selection graphics of the items that are staying visible
+            rowInfo[i].y += deltaY;
+
+            s = selectionIndicators[rowInfo[i].uid];
+            if (s)
+                s.y += deltaY;
+
+            // Cell movement
+            if (isCellSelectionMode())
+            {
+                cellSelectionUID = rowInfo[i].uid;
+                if (cellSelectionIndicators[cellSelectionUID])
+                {
+                    for (columnIndexString in cellSelectionIndicators[cellSelectionUID])
+                    {
+                        cellSelectionIndicators[cellSelectionUID][columnIndexString].y += deltaY;
+                    }
+                }
+            }
+        }
+
+        //move the items that are going away.
+        n = rowList.length;
+        for (i = 0; i < n; i++)
+        {
+            var doOnce:Boolean = true ;
+            m = rowList[i].length;
+            for (j = 0; j < m; j++)
+            {
+                s = null;
+                renderer = IFlexDisplayObject(rowList[i][j].item);
+
+                // Row movement
+                if (rowMap[renderer.name] != null)
+                {
+                    s = selectionIndicators[BaseListData(rowMap[renderer.name]).uid];
+                }
+
+                lastY = renderer.y;
+                renderer.move(renderer.x, rowList[i][j].itemOldY + value);
+                deltaY = renderer.y - lastY;
+
+                //move selection graphic for items that are going away
+                if (doOnce && s)
+                {
+                    s.y += deltaY;
+                    doOnce = false;
+                }
+            }
+
+            // Cell movement
+            if (isCellSelectionMode())
+            {
+                cellSelectionUID = BaseListData(rowMap[renderer.name]).uid;
+                if (cellSelectionIndicators[cellSelectionUID])
+                {
+                    for (columnIndexString in cellSelectionIndicators[cellSelectionUID])
+                    {
+                        cellSelectionIndicators[cellSelectionUID][columnIndexString].y += deltaY;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    mx_internal function onTweenEnd(value:Object):void
+    {
+        UIComponent.resumeBackgroundProcessing();
+
+        onTweenUpdate(value);
+
+        var i:int;
+        var j:int;
+        var n:int;
+        var m:int;
+        var renderer:*;
+        var dilir:IDropInListItemRenderer;
+        var rC:int = listItems.length;
+        var itemUID:*;
+        var indicator:Object;
+        var cellColumnString:String;
+        isOpening = false;
+
+        //dispatch collectionChange ADD or REMOVE events that correlate
+        //to the nodes that were expanded or collapsed
+        if (collection)
+        {
+            var eventArr:Array = opening ?
+                buildUpCollectionEvents(true) : buildUpCollectionEvents(false);
+            n = eventArr.length;
+            for (i = 0; i < n; i++)
+            {
+                collection.dispatchEvent(eventArr[i]);
+            }
+        }
+
+        if (opening)
+        {
+            var firstDeletedRow:int = -1;
+            for (i = rowIndex; i < rC; i++)
+            {
+                if (listItems[i].length)
+                {
+                    for (j =0; j < listItems[i].length; ++j)
+                    {
+                        renderer = listItems[i][j];
+                        var mask:DisplayObject = renderer.mask;
+                        if (mask)
+                        {
+                            listContent.removeChild(mask);
+                            renderer.mask = null;
+                        }
+                        rowMap[renderer.name].rowIndex = i;
+                        if (renderer is IDropInListItemRenderer)
+                        {
+                            dilir = IDropInListItemRenderer(renderer);
+                            if (dilir.listData)
+                            {
+                                dilir.listData.rowIndex = i;
+                                dilir.listData = dilir.listData; // call the setter
+                            }
+                        }
+                        if (renderer.y > listContent.height)
+                        {
+                            addToFreeItemRenderers(renderer);
+                            itemUID = itemToUID(renderer.data);
+
+                            // row mask
+                            if (selectionIndicators[itemUID])
+                            {
+                                //remove indicators mask
+                                indicator = selectionIndicators[itemUID];
+                                if (indicator)
+                                {
+                                    mask = indicator.mask;
+                                    if (mask)
+                                    {
+                                        listContent.removeChild(mask);
+                                        indicator.mask = null;
+                                    }
+                                }
+                                removeIndicators(itemUID);
+                            }
+
+                            // cell mask
+                            if (isCellSelectionMode())
+                            {
+                                if (cellSelectionIndicators[itemUID])
+                                {
+                                    for (cellColumnString in cellSelectionIndicators[itemUID])
+                                    {
+                                        //remove indicators mask
+                                        indicator =
+                                            cellSelectionIndicators[itemUID][cellColumnString];
+                                        if (indicator)
+                                        {
+                                            mask = indicator.mask;
+                                            if (mask)
+                                            {
+                                                listContent.removeChild(mask);
+                                                indicator.mask = null;
+                                            }
+                                        }
+                                    }
+                                    removeCellIndicators(itemUID, int(cellColumnString));
+                                }
+                            }
+
+                            delete rowMap[renderer.name];
+                            if (firstDeletedRow < 0)
+                                firstDeletedRow = i;
+                        }
+                    }
+                }
+                else
+                {
+                    if (rowInfo[i].y >= listContent.height)
+                    {
+                        if (firstDeletedRow < 0)
+                            firstDeletedRow = i;
+                    }
+                }
+            }
+            if (firstDeletedRow >= 0)
+            {
+                rowInfo.splice(firstDeletedRow);
+                listItems.splice(firstDeletedRow);
+            }
+        }
+        else //closing
+        {
+            n = rowList.length;
+            for (i = 0; i < n; i++)
+            {
+                m = rowList[i].length;
+                for (j = 0; j < m; j++)
+                {
+                    mask = rowList[i][j].item.mask;
+                    if (mask)
+                    {
+                        listContent.removeChild(mask);
+                        rowList[i][j].item.mask = null;
+                    }
+                    addToFreeItemRenderers(rowList[i][j].item);
+                    //kill graphic and graphic mask if necessary
+                    itemUID = itemToUID(rowList[i][j].item.data);
+
+                    // row mask
+                    if (selectionIndicators[itemUID])
+                    {
+                        //remove indicators mask
+                        indicator = selectionIndicators[itemUID];
+                        if (indicator)
+                        {
+                            mask = indicator.mask;
+                            if (mask)
+                            {
+                                listContent.removeChild(mask);
+                                indicator.mask = null;
+                            }
+                        }
+                        removeIndicators(itemUID);
+                    }
+
+                    // cell mask
+                    if (isCellSelectionMode())
+                    {
+                        if (cellSelectionIndicators[itemUID])
+                        {
+                            for (cellColumnString in cellSelectionIndicators[itemUID])
+                            {
+                                //remove indicators mask
+                                indicator = cellSelectionIndicators[itemUID][cellColumnString];
+                                if (indicator)
+                                {
+                                    mask = indicator.mask;
+                                    if (mask)
+                                    {
+                                        listContent.removeChild(mask);
+                                        indicator.mask = null;
+                                    }
+                                }
+                                removeCellIndicators(itemUID, int(cellColumnString));
+                            }
+                        }
+                    }
+
+                    delete rowMap[rowList[i][j].item.name];
+                }
+            }
+            for (i = rowIndex; i < rC; i++)
+            {
+                if (listItems[i].length)
+                {
+                    m = listItems[i].length;
+                    for (j =0; j < m; ++j)
+                    {
+                        renderer = listItems[i][j];
+                        rowMap[renderer.name].rowIndex = i;
+                        if (renderer is IDropInListItemRenderer)
+                        {
+                            dilir = IDropInListItemRenderer(renderer);
+                            if (dilir.listData)
+                            {
+                                dilir.listData.rowIndex = i;
+                                dilir.listData = dilir.listData; // call the setter
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //should we dispatch an AdvancedDataGrid event?
+        if (eventAfterTween)
+        {
+            // in case when eventItemRenderer is null,
+            // instead of taking item renderer from visibleData, we should take it from listItems for
+            // the correct value.
+            var itemRenderer:IListItemRenderer = eventItemRenderer ? eventItemRenderer : visibleData[itemToUID(eventAfterTween)];
+            dispatchAdvancedDataGridEvent((isItemOpen(eventAfterTween)
+                                           ? AdvancedDataGridEvent.ITEM_OPEN
+                                           : AdvancedDataGridEvent.ITEM_CLOSE),
+                                          eventAfterTween,
+                                          itemRenderer,
+                                          lastUserInteraction);
+            lastUserInteraction = null;
+            eventAfterTween = false;
+            itemRenderer = null;
+        }
+        //invalidate
+        itemsSizeChanged = true;
+        invalidateDisplayList();
+        // Get rid of the tween, so this onTweenEnd doesn't get called more than once.
+        tween = null;
+        // check for scrollbars
+        configureScrollBars();
+    }
+
+    /**
+     *  @private
+     *
+     *  Helper function that builds up the collectionChange ADD or
+     *  REMOVE events that correlate to the nodes that were expanded
+     *  or collapsed.
+     */
+    private function buildUpCollectionEvents(open:Boolean):Array
+    {
+        var ce:CollectionEvent;
+        var item:Object;
+        var parentArray:Array;
+        var rowsAdded:Array = [];
+        var rowsRemoved:Array = [];
+        var retVal:Array = [];
+
+        var itemIndex:int = getItemIndex(expandedItem);
+
+        if (open)
+        {
+            var children:ICollectionView = getChildren(expandedItem, iterator.view);
+            if (!children)
+                return [];
+            var cursor:IViewCursor = children.createCursor();
+            var push:Boolean = true;
+            while (!cursor.afterLast)
+            {
+                rowsAdded.push(item);
+                try
+                {
+                    cursor.moveNext();
+                }
+                catch (e:ItemPendingError)
+                {
+                    // should not come here
+                    break;
+                }
+            }
+        }
+        else
+        {
+            var stack:Array = [];
+            var i:int;
+            stack = getOpenChildrenStack(expandedItem, stack);
+            var n:int = stack.length;
+            while (i < n)
+            {
+                var m:int = selectedItems.length;
+                for (var j:int = 0; j < m; j++)
+                {
+                    if (selectedItems[j] == stack[i])
+                    {
+                        bSelectedItemRemoved = true;
+                    }
+                }
+                rowsRemoved.push(stack[i]);
+                i++;
+            }
+        }
+        if (rowsAdded.length > 0)
+        {
+            ce = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+            ce.kind = CollectionEventKind.ADD;
+            ce.location = itemIndex + 1;
+            ce.items = rowsAdded;
+            retVal.push(ce);
+        }
+        if (rowsRemoved.length > 0)
+        {
+            ce = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
+            ce.kind = CollectionEventKind.REMOVE;
+            ce.location = itemIndex;
+            ce.items = rowsRemoved;
+            retVal.push(ce);
+        }
+        return retVal;
+    }
+
+    /**
+     *  @private
+     *  Go through the open items and figure out which is deepest.
+     */
+    private function getIndent():Number
+    {
+        var depth:Number = 0;
+        for (var p:String in IHierarchicalCollectionView(collection).openNodes)
+        {
+            // add one since its children are actually indented
+            depth = Math.max(getItemDepth(IHierarchicalCollectionView(collection).openNodes[p], 0), depth);
+        }
+        return depth * getStyle("indentation");
+    }
+
+    /**
+     *  @private
+     */
+    private function getItemIndex(item:Object):int
+    {
+        var cursor:IViewCursor = collection.createCursor();
+        var i:int = 0;
+        do
+        {
+            if (cursor.current === item)
+                break;
+            i++;
+        }
+        while (cursor.moveNext());
+        return i;
+    }
+
+    /**
+     *  @private
+     */
+    private function getIndexItem(index:int):Object
+    {
+        var cursor:IViewCursor = collection.createCursor();
+        var i:int = index;
+        while (cursor.moveNext())
+        {
+            if (i == 0)
+                return cursor.current;
+            i--;
+        }
+        return null;
+    }
+
+    /**
+     *  Opens or closes all the nodes of the navigation tree below the specified item.
+     *
+     *
If you set the dataProvider property and then immediately call
+     *  the expandChildrenOf() method, you may not see the correct behavior.
+     *  You should either wait for the component to validate,
+     *  or call the validateNow() method before calling expandChildrenOf().

+     *
+     *  @param item An Object defining the branch node. This Object contains the
+     *  data provider element for the branch node.
+     *
+     *  @param open Specify true to open the items,
+     *  and false to close them.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function expandChildrenOf(item:Object, open:Boolean):void
+    {
+        //if the iterator is null, that indicates we have not been
+        //validated yet, so we will not continue.
+        if (iterator == null)
+            return;
+
+        // if it is not a branch item there's nothing to do
+        if (isBranch(item))
+        {
+            dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPENING,
+                                          item,   //item
+                                          null,   //renderer
+                                          null,   //trigger
+                                          open,   //opening
+                                          false,  //animate
+                                          true);  //dispatch
+
+            var i:int = 0;
+            var childItems:Object
+            if (item != null &&
+                _rootModel.canHaveChildren(item) &&
+                _rootModel.hasChildren(item))
+            {
+                childItems = getChildren(item, iterator.view);
+            }
+            if (childItems)
+            {
+                var cursor:IViewCursor = childItems.createCursor();
+                while (!cursor.afterLast)
+                {
+                    if (isBranch(cursor.current))
+                        expandChildrenOf(cursor.current, open);
+                    cursor.moveNext();
+                }
+            }
+        }
+    }
+
+    /**
+     *  Returns the parent of a child item. This method returns a value
+     *  only if the item was or is currently visible. Top-level items have a
+     *  parent with the value null.
+     *
+     *  @param item An Object defining the child item. This Object contains the
+     *  data provider element for the child.
+     *
+     *  @return The parent of the item.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function getParentItem(item:Object):*
+    {
+        if (item == null)
+            return null;
+        if (item && collection)
+            return IHierarchicalCollectionView(collection).getParentItem(item);
+        return null;
+    }
+
+    /**
+     *  @private
+     *  Returns the stack of parents from a child item.
+     */
+    private function getParentStack(item:Object):Array
+    {
+        var stack:Array = [];
+        if (item == null)
+            return stack;
+
+        var parent:* = getParentItem(item);
+        while (parent)
+        {
+            stack.push(parent);
+            parent = getParentItem(parent);
+        }
+        return stack;
+    }
+
+    /**
+     *  @private
+     *  Returns a stack of all open descendants of an item.
+     */
+    private function getOpenChildrenStack(item:Object, stack:Array):Array
+    {
+        var curr:Object;
+        if (item == null)
+            return stack;
+
+        var children:ICollectionView = getChildren(item, iterator.view);
+
+        if (!children)
+            return [];
+
+        var cursor:IViewCursor = children.createCursor();
+        while (!cursor.afterLast)
+        {
+            curr = cursor.current;
+            stack.push(curr);
+            if (isBranch(curr) && isItemOpen(curr))
+            {
+                getOpenChildrenStack(curr, stack);
+            }
+            try
+            {
+                cursor.moveNext();
+            }
+            catch(e:ItemPendingError)
+            {
+                break;
+            }
+        }
+        return stack;
+    }
+
+    /**
+     *  @private
+     *  Finds the index distance between a parent and child
+     */
+    private function getChildIndexInParent(parent:Object, child:Object):int
+    {
+        var index:int = 0;
+        if (!parent)
+        {
+            var cursor:IViewCursor = ICollectionView(iterator.view).createCursor();
+            while (!cursor.afterLast)
+            {
+                if (child === cursor.current)
+                    break;
+                index++;
+                cursor.moveNext();
+            }
+        }
+        else
+        {
+            if (parent != null &&
+                _rootModel.canHaveChildren(parent) &&
+                _rootModel.hasChildren(parent))
+            {
+                var children:ICollectionView = getChildren(parent, iterator.view);
+                if (children.contains(child))
+                {
+                    var n:int = children.length;
+                    for (; index < n; index++)
+                    {
+                        if (child === children[index])
+                            break;
+                    }
+                }
+                else
+                {
+                    //throw new Error("Parent item does not contain specified child: " + itemToUID(child));
+                }
+            }
+        }
+        return index;
+    }
+
+    /**
+     *  @private
+     *  Collapses those items in the selected items array that have
+     *  parent nodes already selected.
+     */
+    private function collapseSelectedItems():Array
+    {
+        var collection:ArrayCollection = new ArrayCollection(selectedItems);
+
+        for (var i:int = 0; i < selectedItems.length; i++)
+        {
+            var item:Object = selectedItems[i];
+            var stack:Array = getParentStack(item);
+            for (var j:int = 0; j < stack.length; j++)
+            {
+                if (collection.contains(stack[j]))
+                {
+                    //item's parent is included in the selected item set
+                    var index:int = collection.getItemIndex(item);
+                    var removed:Object = collection.removeItemAt(index);
+                    break;
+                }
+            }
+        }
+        return collection.source;
+    }
+
+    /**
+     *  Initializes an AdvancedDataGridListData object that is used by the AdvancedDataGrid item renderer.
+     *
+     *  @param item The item to be rendered.
+     *  This Object contains the data provider element for the item.
+     *
+     *  @param adgListData The AdvancedDataGridListDataItem to use in rendering the item.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function initListData(item:Object, adgListData:AdvancedDataGridListData):void
+    {
+        if (item == null)
+            return;
+
+        var open:Boolean = isItemOpen(item);
+        var branch:Boolean = isBranch(item);
+        var uid:String = itemToUID(item);
+
+        // this is hidden by non-branches but kept so we know how wide it is so things align
+        if (displayDisclosureIcon)
+            adgListData.disclosureIcon = getStyle(open ? "disclosureOpenIcon" :
+                                                  "disclosureClosedIcon");
+        adgListData.open = open;
+        adgListData.hasChildren = _rootModel.hasChildren(item);
+        // set the depth as 1 if the item is pending
+        if (itemPending)
+            adgListData.depth = 1;
+        else
+            adgListData.depth = getItemDepth(item, adgListData.rowIndex);
+
+        adgListData.indent = (adgListData.depth - 1) * getStyle("indentation");
+        adgListData.item = item;
+        if (groupIconFunction != null && isBranch(item))
+        {
+            if (groupIconFunction(item, adgListData.depth) != null)
+                adgListData.icon = groupIconFunction(item, adgListData.depth);
+            else
+                adgListData.icon = itemToIcon(item);
+        }
+        else
+            adgListData.icon = itemToIcon(item);
+    }
+
+    /**
+     *  @private
+     *  Delegates to the Descriptor to add a child to a parent
+     */
+    mx_internal function addChildItem(parent:Object, child:Object, index:Number):Boolean
+    {
+        return IHierarchicalCollectionView(dataProvider).addChildAt(parent, child, index);
+    }
+
+    /**
+     *  @private
+     *  Delegates to the Descriptor to remove a child from a parent
+     */
+    mx_internal function removeChildItem(parent:Object, child:Object, index:Number):Boolean
+    {
+        return IHierarchicalCollectionView(dataProvider).removeChildAt(parent, index);
+    }
+
+    /**
+     *  @private
+     */
+    mx_internal function dispatchAdvancedDataGridEvent(type:String,
+                                                       item:Object,
+                                                       renderer:IListItemRenderer,
+                                                       trigger:Event = null,
+                                                       opening:Boolean = true,
+                                                       animate:Boolean = true,
+                                                       dispatch:Boolean = true):void
+    {
+        var event:AdvancedDataGridEvent;
+
+        // Create expanding event.
+        if (type == AdvancedDataGridEvent.ITEM_OPENING)
+        {
+            event = new AdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPENING,
+                                              false, true);
+            event.opening = opening;
+            event.animate = animate;
+            event.dispatchEvent = dispatch;
+        }
+
+        // Create all other events.
+        if (!event)
+            event = new AdvancedDataGridEvent(type);
+
+        // Common values.
+        event.item = item;
+        event.itemRenderer = renderer;
+        event.triggerEvent = trigger;
+
+        // Send it off.
+        dispatchEvent(event);
+    }
+
+    /**
+     *  Generate sample data based on number of columns and their dataFields,
+     *  so that the designer can see how the data will look like.
+     *
+     *  @private
+     */
+    private function setDesignViewData():void
+    {
+        designViewDataFlag = true;
+
+        var sampleDataProvider:Array = [];
+        // The sample data is going to be just integers in ascending order.
+        var counter:int = 1;
+        // Number of rows to display.
+        const numberOfRows:int = 10;
+
+        if (!columns || columns.length == 0)
+            return;
+
+        var i:int;
+        var sampleDataRow:Object;
+        var j:int;
+        var m:int;
+        var col:AdvancedDataGridColumn;
+
+        if (designViewDataType == designViewDataFlatType)
+        {
+            for (i = 0; i < numberOfRows; i++)
+            {
+                sampleDataRow = {};
+
+                m = columns.length;
+                for (j = 0; j < m; j++)
+                {
+                    col = columns[j];
+                    if (col.dataField != null)
+                    {
+                        sampleDataRow[col.dataField] = counter;
+                    }
+                    counter++;
+                }
+
+                sampleDataProvider.push(sampleDataRow);
+            }
+
+            dataProvider = sampleDataProvider;
+        }
+        else if (designViewDataType == designViewDataTreeType)
+        {
+            var branchName:String = columns[0].dataField || "";
+            var branchCounter:int = 1;
+
+            for (i = 0; i < numberOfRows; i++)
+            {
+                var childrenString:String = "children";
+                sampleDataRow = {};
+                sampleDataRow[childrenString] = [{}];
+                sampleDataRow[branchName] = resourceManager.getString("datamanagement", "Branch", [branchCounter]);
+
+                m = columns.length;
+                for (j = 0; j < m; j++)
+                {
+                    col = columns[j];
+                    if (col.dataField != null)
+                    {
+                        sampleDataRow[childrenString][0][col.dataField] = counter;
+                    }
+                    counter++;
+                }
+
+                sampleDataProvider.push(sampleDataRow);
+                branchCounter++;
+            }
+
+            dataProvider = new HierarchicalData(sampleDataProvider);
+        }
+    }
+
+    /**
+     * Set sort in design view to showcase multi column sorting.
+     *
+     *  @private
+     */
+    private function setDesignViewSort():void
+    {
+        if (collection == null)
+            return;
+
+        var sort:Sort = new Sort();
+        sort.fields = [];
+        var oddDescending:Boolean = false;
+
+        var n:int = columns.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            sort.fields.push(
+                    new SortField(columns[i].dataField,
+                                  false,
+                                  oddDescending,
+                                  false)
+                    );
+
+            oddDescending = !oddDescending;
+        }
+
+        if (collection)
+            collection.sort = sort;
+    }
+
+    /**
+     *  @private
+     */
+    public function setDesignView():void
+    {
+        designViewDataType = dataType;
+        designViewDataTypeChanged = true;
+        invalidateProperties();
+    }
+
+    /**
+     *  Process cells (set in selectedCells) which are not yet displayed
+     *  in case we have scrolled to the view where it can be displayed.
+     *
+     *  @private
+     */
+    protected function processCellsWaitingToBeDisplayed():void
+    {
+        var pendingCellsDisplayed:Array = [];
+        var n:int = pendingCellSelection.length;
+        var i:int;
+        for (i = 0; i < n; i++)
+        {
+            var visibleCoords:Object = absoluteToVisibleIndices(
+                                            pendingCellSelection[i].rowIndex,
+                                            pendingCellSelection[i].columnIndex);
+            var visibleRowIndex:int = visibleCoords.rowIndex;
+            var visibleColIndex:int = visibleCoords.columnIndex;
+
+            var listItem:IListItemRenderer;
+            if (listItems[visibleRowIndex] && listItems[visibleRowIndex][visibleColIndex])
+            {
+                listItem = listItems[visibleRowIndex][visibleColIndex];
+                selectCellItem(listItem, false, true);
+                pendingCellsDisplayed.push(i);
+            }
+        }
+
+        // Make sure we remove in reverse order, from things at the end to
+        // the start so that we remove correctly. For example, if we have to
+        // remove the first and third entries, then we have to make sure we
+        // remove third and then first to maintain correctness.
+        pendingCellsDisplayed.sort(Array.NUMERIC | Array.DESCENDING);
+        n = pendingCellsDisplayed.length;
+        for (i = 0; i < n; i++)
+        {
+            pendingCellSelection.removeItemAt(pendingCellsDisplayed[i]);
+        }
+
+        if (pendingCellSelection.length == 0)
+            cellsWaitingToBeDisplayed = false;
+    }
+
+    /**
+     *  Expands all the nodes of the navigation tree in the control.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function expandAll():void
+    {
+        if (dataProvider is IHierarchicalCollectionView && iterator)
+        {
+            // move to the first item
+            iterator.seek(CursorBookmark.FIRST);
+            while(!iterator.afterLast)
+            {
+                var item:Object = iterator.current;
+                // open the item if its a branch item and its not already open
+                if (isBranch(item) && !isItemOpen(item))
+                {
+                    IHierarchicalCollectionView(collection).openNode(item); // open node
+
+                    // dispatch ITEM_OPEN event
+                    var itemRenderer:IListItemRenderer = visibleData[itemToUID(item)];
+                    dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPEN,
+                                                  item,
+                                                  itemRenderer,
+                                                  null);
+                }
+                iterator.moveNext();
+            }
+            itemsSizeChanged = true;
+            invalidateDisplayList();
+            // seek to the correct position
+            iterator.seek(CursorBookmark.FIRST, verticalScrollPosition);
+        }
+    }
+
+    /**
+     *  Collapses all the nodes of the navigation tree.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    public function collapseAll():void
+    {
+        if (dataProvider is IHierarchicalCollectionView && iterator)
+        {
+            // clear the selected items
+            clearSelected();
+
+            //dispatch events
+            for each (var item:* in IHierarchicalCollectionView(collection).openNodes)
+            {
+                dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_CLOSE,
+                                              item,
+                                              visibleData[itemToUID(item)]);
+            }
+
+            var oldValue:int = verticalScrollPosition;
+            verticalScrollPosition = 0;
+
+            IHierarchicalCollectionView(collection).openNodes = {};
+
+            // set the verticalScrollPosition to a valid value and seek to that position
+            verticalScrollPosition =
+                    oldValue >= collection.length ? collection.length - 1 : oldValue;
+
+            iterator.seek(CursorBookmark.FIRST, verticalScrollPosition);
+        }
+    }
+
+    /**
+     *  @private
+     *
+     *  Get the renderer and column span for custom renderer
+     *
+     */
+    mx_internal function getRendererDescription(itemData:Object,c:AdvancedDataGridColumn, forDragProxy:Boolean = false):AdvancedDataGridRendererDescription
+    {
+        var adgDescription:AdvancedDataGridRendererDescription = new AdvancedDataGridRendererDescription();
+        var index:int = 0;
+        var depth:int = 0;
+        if (rendererProviders.length !=0)
+        {
+            if (forDragProxy)
+                index = getItemIndex(itemData);
+
+            depth = getItemDepth(itemData,index);
+        }
+
+        var n:int = rendererProviders.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            IAdvancedDataGridRendererProvider(rendererProviders[i]).describeRendererForItem(itemData,depth,c,adgDescription);
+            if (adgDescription.renderer)
+                return adgDescription;
+        }
+        return adgDescription;
+    }
+
+    /**
+     *  @private
+     *
+     */
+    private function findHeaderRenderer(pt:Point):IListItemRenderer
+    {
+        var headerItem:IListItemRenderer;
+        var xMatched:Boolean=false;
+        var array:Array = visibleHeaderInfos;
+        var x:Number;
+
+        while(!xMatched)
+        {
+            var n:int = array ? array.length : 0;
+            for(var i:int=0; i < n; i++)
+            {
+                headerItem = array[i]["headerItem"];
+                x = headerItem.x;
+
+                if(array[i].actualColNum >= lockedColumnCount)
+                    x = getAdjustedXPos(headerItem.x);
+
+                if(pt.x >= x && pt.x < (x + headerItem.getExplicitOrMeasuredWidth()))
+                {
+                    xMatched = true;
+
+                    if(pt.y >headerItem.y - cachedPaddingTop &&
+                       pt.y <= headerItem.y + headerItem.height + cachedPaddingBottom)
+                        return headerItem;
+                    else if(array[i].visibleChildren && array[i].visibleChildren.length > 0)
+                        array = array[i].visibleChildren;
+                    else
+                        return null;
+                    break;
+                }
+
+            }
+            if(!xMatched)//There is no point of keep looping over if x is not within range
+                return null;
+            xMatched = false;
+        }
+        return null;
+    }
+
+    /**
+     *  @private
+     */
+    private function getLastColumnResidualWidth():Number
+    {
+        var n:int = displayableColumns.length-1;
+        var displayWidth:int = unscaledWidth - viewMetrics.right - viewMetrics.left;
+        var totalWidth:Number = 0;
+        var i:int;
+        var numLockCols:int = Math.max(0, lockedColumnCount);
+
+        //Find the scrollable width i.e displayWidth - { sum of width of locked columns}
+        if (numLockCols > 0 && numLockCols < visibleColumns.length)
+        {
+            for (i = 0; i < numLockCols; i++)
+            {
+                displayWidth -= displayableColumns[i].width;
+            }
+        }
+
+        // Starting from the right most column in the displayableColumns array
+        // find out how many columns we will be able to
+        // accumulate and how much width they will take
+        // when horizontal scroll bar is at the rightmost end
+        if (n>=0)
+        {
+            totalWidth = (isNaN(displayableColumns[n].explicitWidth) ? displayableColumns[n].preferredWidth : displayableColumns[n].explicitWidth);
+        }
+
+        for (i = n-1; i >= numLockCols; i--)
+        {
+            if (totalWidth + displayableColumns[i].width <= displayWidth)
+                totalWidth += displayableColumns[i].width;
+            else
+                break;
+        }
+
+        // The residual width is the width which should be added to
+        // the last column apriori, so that in future when we have horizontally
+        // scrolled to the right most position we don't need to create larger
+        // items for that column
+        return displayWidth - totalWidth;
+    }
+
+    /**
+     *  @private
+     */
+    private function createHeaderItems(subHeaderInfos:Array):Number
+    {
+        var i:int;
+        var c:AdvancedDataGridColumn;
+        var rowData:AdvancedDataGridListData;
+        var item:IListItemRenderer;
+        var childrenWidth:Number;
+        var w:Number = 0;
+
+        var n:int = subHeaderInfos.length;
+        for (i = 0; i < n; i++)
+        {
+            if(subHeaderInfos[i].visibleChildren)
+                childrenWidth = createHeaderItems(subHeaderInfos[i].visibleChildren);
+
+            c = subHeaderInfos[i].column;
+
+            //When we have reached the last column little extra work
+            //to see the future i.e when display will be scrolled horizontally
+            // at extreme right position
+            if (horizontalScrollPolicy != ScrollPolicy.OFF
+               && c == displayableColumns[displayableColumns.length-1])
+                lastColumnWidth = (isNaN(c.explicitWidth) ? c.preferredWidth : c.explicitWidth) + getLastColumnResidualWidth();
+
+            item = getHeaderRenderer(c);
+            // passing rowNum as -1 for headers
+            rowData = AdvancedDataGridListData(makeListData(c, uid, -1, c.colNum, c));
+            rowMap[item.name] = rowData;
+            if (item is IDropInListItemRenderer)
+                IDropInListItemRenderer(item).listData = rowData;
+            item.data = c;
+            item.styleName = c;
+            if (!isMeasuringHeader)
+                addRendererToContentArea(item, c);
+
+            headerItemsList.push(item);
+
+            subHeaderInfos[i].headerItem = item;
+
+            // set prefW so we can compute prefH
+            if (subHeaderInfos[i].visibleChildren)
+            {
+                item.explicitWidth = childrenWidth;
+                c.width = childrenWidth;
+            }
+            else if (!isNaN(lastColumnWidth)&& c == displayableColumns[displayableColumns.length-1])
+            {
+                item.explicitWidth = lastColumnWidth;
+            }
+            else
+            {
+                item.explicitWidth = c.width;
+            }
+
+            UIComponentGlobals.layoutManager.validateClient(item, true);
+
+            // but size it regardless of what prefW is
+            if (!isNaN(lastColumnWidth) && c == displayableColumns[displayableColumns.length-1])
+                w += lastColumnWidth;
+            else
+                w += c.width;
+        }
+        return w;
+    }
+
+    /**
+     *  @private
+     */
+    private function measureHeaderHeights(subHeaderInfos:Array, depth:uint):Number
+    {
+        var i:int;
+        var maxRowHeight:Number=0;
+        var padding:int = cachedPaddingTop + cachedPaddingBottom;
+
+        var n:int = subHeaderInfos.length;
+        for ( i = 0; i < n; i++)
+        {
+            var currentGroupHeight:Number = _explicitHeaderHeight ?
+                _headerHeight : subHeaderInfos[i].headerItem.getExplicitOrMeasuredHeight()+padding;
+
+            if (subHeaderInfos[i].visibleChildren)
+                currentGroupHeight += measureHeaderHeights(subHeaderInfos[i].visibleChildren, depth+1);
+            maxRowHeight = Math.max(maxRowHeight, currentGroupHeight);
+        }
+        if (!headerRowInfo[depth])
+            headerRowInfo[depth] = new ListRowInfo(0,0, uid);
+
+        headerRowInfo[depth].height = Math.max(headerRowInfo[depth].height, maxRowHeight);
+        return headerRowInfo[depth].height;
+    }
+
+    /**
+     *  @private
+     */
+    private function layoutHeaders(subHeaderInfos:Array, rowX:Number, rowY:Number, depth:int):void
+    {
+        var i:int;
+        var w:Number = rowX;
+        var padding:int = cachedPaddingTop + cachedPaddingBottom;
+        headerRowInfo[depth].y = rowY;
+
+        var n:int = subHeaderInfos.length;
+        for (i = 0; i < n; i++)
+        {
+            subHeaderInfos[i].headerItem.move(w, rowY+cachedPaddingTop);
+
+            var currentItemHeight:Number = subHeaderInfos[i].headerItem.height;
+
+            if (subHeaderInfos[i].visibleChildren)
+                layoutHeaders(subHeaderInfos[i].visibleChildren, w, rowY + currentItemHeight + padding, depth+1);
+
+            w += subHeaderInfos[i].headerItem.getExplicitOrMeasuredWidth();
+        }
+    }
+
+    /**
+     *  Applies styles from the AdvancedDatagrid control to an item renderer.
+     *  The item renderer should implement the IStyleClient and IDataRenderer interfaces,
+     *  and be a subclass of the DisplayObject class.
+     *
+     *  @param givenItemRenderer The item renderer.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function applyUserStylesForItemRenderer(givenItemRenderer:IListItemRenderer):void
+    {
+        if (!givenItemRenderer)
+            return;
+
+        if (!
+            (
+                // It should support all the following interfaces/inheritances
+                givenItemRenderer is IStyleClient
+                && givenItemRenderer is IDataRenderer
+                && givenItemRenderer is DisplayObject
+                )
+            )
+        {
+            return;
+        }
+
+        var itemRenderer:IStyleClient = givenItemRenderer as IStyleClient;
+
+        var column:AdvancedDataGridColumn = columnMap[DisplayObject(itemRenderer).name];
+
+        // 0. Make sure we have a dictionary
+        if (!oldStyles)
+        {
+            oldStyles = new Dictionary(true); // use weakKeys
+        }
+
+        // 1. Reset to the default i.e. "old" styles
+        var styleName:String;
+        if (oldStyles[itemRenderer])
+        {
+            for (styleName in oldStyles[itemRenderer])
+            {
+                itemRenderer.setStyle(styleName, oldStyles[itemRenderer][styleName]);
+            }
+            delete oldStyles[itemRenderer];
+        }
+
+        // 2. Call the grid's styleFunction
+        var newStyles:Object;
+        if (styleFunction != null)
+        {
+            newStyles = styleFunction(IDataRenderer(itemRenderer).data, column);
+            if (newStyles)
+            {
+                for (styleName in newStyles)
+                {
+                    if (!oldStyles[itemRenderer])
+                    {
+                        oldStyles[itemRenderer] = {};
+                    }
+
+                    oldStyles[itemRenderer][styleName] = itemRenderer.getStyle(styleName);
+                    itemRenderer.setStyle(styleName, newStyles[styleName]);
+                }
+            }
+        }
+
+        // 3. Call the column's styleFunction
+        if (column && column.styleFunction != null)
+        {
+            newStyles = column.styleFunction(IDataRenderer(itemRenderer).data, column);
+            if (newStyles)
+            {
+                for (styleName in newStyles)
+                {
+                    // Don't store the "old" value for this styleName if grid.styleFunction has
+                    // already stored it
+                    if (!oldStyles[itemRenderer])
+                    {
+                        oldStyles[itemRenderer] = {};
+                    }
+                    if (!oldStyles[itemRenderer][styleName])
+                    {
+                        oldStyles[itemRenderer][styleName] = itemRenderer.getStyle(styleName);
+                    }
+                    itemRenderer.setStyle(styleName, newStyles[styleName]);
+                }
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    private function removeOldHeaders():void
+    {
+        var item:IListItemRenderer;
+        if (columnGrouping)
+        {
+            //In case column grouping was not there previously then there will be items in headerItems
+            // We need to remove them
+            if (headerItems && headerItems.length)
+            {
+                while (headerItems.length)
+                {
+                    var headerRow:Array = headerItems.pop();
+                    while (headerRow.length)
+                    {
+                        item = IListItemRenderer(headerRow.pop());
+                        item.parent.removeChild(DisplayObject(item));
+                    }
+                }
+            }
+        }
+        else
+        {
+            //In case column grouping was there previously then there will be items in headerItemsList
+            // We need to remove them
+            if (headerItemsList && headerItemsList.length)
+            {
+                while (headerItemsList.length)
+                {
+                    item = headerItemsList.pop();
+                    item.parent.removeChild(DisplayObject(item));
+                }
+            }
+            //there may be items in freeItemRenderersTable also. We need to remove them as well
+            if (_groupedColumns)
+            {
+                var n:int = _groupedColumns.length;
+                for ( var i:int = 0; i < n; i++)
+                {
+                    if (_groupedColumns[i] is AdvancedDataGridColumnGroup)
+                        columnGroupRendererChanged(AdvancedDataGridColumnGroup(_groupedColumns[i]));
+                }
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    private function columnGroupRendererChanged(c:AdvancedDataGridColumnGroup):void
+    {
+        var n:int = c.children ? c.children.length : 0;
+        if (n > 0)
+        {
+            columnRendererChanged(c);
+            for( var i:int = 0; i < n; i++)
+            {
+                if (c.children[i] is AdvancedDataGridColumnGroup)
+                    columnGroupRendererChanged(c.children[i]);
+            }
+        }
+
+    }
+
+    /**
+     *  @private
+     */
+    private function addItemsToTarget(event:DragEvent, items:Array):void
+    {
+        // add items only if the target component is AdvancedDataGrid
+        /* if (!(event.relatedObject is AdvancedDataGrid))
+            return; */
+
+        var className:String  = getQualifiedClassName(event.relatedObject);
+        var classType:Class = getDefinitionByName(className) as Class;
+        var o:Object = new classType();
+        if (!(o is AdvancedDataGrid))
+            return;
+
+        //then do the add on the target control
+        var targetADG:Object = event.relatedObject;
+        if (!targetADG.collection)
+        {
+            // Empty tree. Use the first item to create a dataprovider
+            var item:Object = items.shift();
+            targetADG.dataProvider = new HierarchicalData(item);
+            targetADG.validateNow();
+        }
+        else if (targetADG.collection.length == 0)
+        {
+            //Empty dataProvider. Add the first item in.
+            var obj:Object = items.shift();
+            targetADG.addChildItem(targetADG._dropData.parent,
+                                   obj, targetADG._dropData.index);
+        }
+
+        var n:int = items.length;
+        for (var i:int = n - 1; i >= 0; i--)
+        {
+            targetADG.addChildItem(targetADG._dropData.parent,
+                                   items[i],
+                                   targetADG._dropData.index);
+        }
+    }
+
+    /**
+     *  @private
+     *
+     *  validate the groupedColumns and verify that same column object is not
+     *  used twice
+     */
+    private function validateGroupedColumns(groupedColumns:Array):Boolean
+    {
+        var dict:Dictionary = new Dictionary();
+        var queue:Array = [];
+        var valid:Boolean = true;
+
+        var n:int = groupedColumns.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            queue.push(groupedColumns[i]);
+        }
+
+        while (queue.length > 0 && valid)
+        {
+            var c:AdvancedDataGridColumn = queue.shift();;
+            var uid:String = itemToUID(c);
+            if (dict[uid]!=null)
+            {
+                valid = false;
+                throw new Error(resourceManager.getString(
+                                    "datamanagement", "repeatColumnsNotAllowed"));
+            }
+            else
+            {
+                dict[uid] = c;
+                if (c is AdvancedDataGridColumnGroup)
+                {
+                    var cGroup:AdvancedDataGridColumnGroup = AdvancedDataGridColumnGroup(c);
+                    if (cGroup.children)
+                    {
+                        n = cGroup.children.length;
+                        for (i = 0; i < n; i++)
+                        {
+                            queue.push(cGroup.children[i]);
+                        }
+                    }
+                }
+            }
+        }
+
+        return valid;
+    }
+
+    /**
+     *  @private
+     */
+    private function getLeafColumns(groupedColumns:Array):Array
+    {
+        var i:int=0;
+        while (i < groupedColumns.length)
+        {
+            if (groupedColumns[i] is AdvancedDataGridColumnGroup && groupedColumns[i].children && groupedColumns[i].children.length >0)
+            {
+                var prefix:Array = groupedColumns.slice(0,i);
+                var postfix:Array = groupedColumns.slice(i+1);
+                prefix = prefix.concat(getLeafColumns(groupedColumns[i].children));
+                groupedColumns = prefix.concat(postfix);
+                i = prefix.length;
+            }
+            else
+            {
+                i++;
+            }
+        }
+        return groupedColumns;
+    }
+
+    /**
+     *  @private
+     */
+    private function initializeGroupedHeaderInfo(groupedColumns:Array, parent:AdvancedDataGridHeaderInfo, depth:int, parentInternalLabelFunction:Function=null):Array
+    {
+        var headerInfos:Array = [];
+
+        var n:int = groupedColumns.length;
+        for (var i:int = 0; i < n; i++ )
+        {
+            var headerInfo:AdvancedDataGridHeaderInfo = new AdvancedDataGridHeaderInfo(groupedColumns[i],
+                                                                                parent, i, depth) ;
+            var uid:String = itemToUID(groupedColumns[i]);
+            columnsToInfo[uid] = headerInfo;
+            groupedColumns[i].owner = this;
+
+            //Parent has a dataField/labelFunction already, child can extract data via this internalLabelFunction only
+            headerInfo.internalLabelFunction = parentInternalLabelFunction;
+
+            //In case this header was selected through keyboard navigation
+            if (selectedHeaderInfo && selectedHeaderInfo.column == groupedColumns[i])
+                selectedHeaderInfo = headerInfo;
+
+            if (groupedColumns[i] is AdvancedDataGridColumnGroup && groupedColumns[i].children && groupedColumns[i].children.length > 0)
+            {
+                //If this column has a dataField/labelFunction, children columns will get data through an internalLabelFunction
+                if (groupedColumns[i].dataField || groupedColumns[i].labelFunction || parentInternalLabelFunction != null)
+                {
+                    var childInternalLabelFunction:Function;
+
+                    if (parentInternalLabelFunction == null)
+                        childInternalLabelFunction = (function(data:Object, c:AdvancedDataGridColumn):*
+                        {
+                            var parentInfo:AdvancedDataGridHeaderInfo  = getHeaderInfo(c).parent;
+                            var parentColumn:AdvancedDataGridColumnGroup = parentInfo.column as AdvancedDataGridColumnGroup;
+
+                            return parentColumn.itemToData(data);
+                        });
+                    else
+                        childInternalLabelFunction = (
+                            function(data:Object, c:AdvancedDataGridColumn):*
+                        {
+                            var parentInfo:AdvancedDataGridHeaderInfo  = getHeaderInfo(c).parent;
+                            var parentColumn:AdvancedDataGridColumnGroup = parentInfo.column as AdvancedDataGridColumnGroup;
+
+                            var dataFromParent:* = parentInfo.internalLabelFunction(data, parentInfo.column);
+
+                            return parentColumn.itemToData(dataFromParent);
+                        });
+                }
+                headerInfo.children = initializeGroupedHeaderInfo(groupedColumns[i].children, headerInfo, depth+1, childInternalLabelFunction);
+            }
+
+            headerInfos.push(headerInfo);
+        }
+        return headerInfos;
+    }
+
+    /**
+     *  @private
+     */
+    protected function updateVisibleHeaderInfos(headerInfos:Array = null, parentVisible:Boolean = true, actualColNum:int = 0):Object
+    {
+        var n:int = headerInfos ? headerInfos.length : 0;
+        var i:int;
+        var k:int = 0;
+        var visibleHeaderInfos:Array;
+        var totalColumnSpan:int = 0;
+
+        for (i = 0; i < n; i++)
+        {
+            var headerInfo:AdvancedDataGridHeaderInfo = headerInfos[i];
+
+            //If parent is not visible we don't want any of the child to be visible
+            if(!parentVisible)
+                headerInfo.visible = false;
+            else
+                headerInfo.visible = headerInfo.column.visible;
+
+            if(headerInfos[i].visible == false)
+            {
+                headerInfo.visibleIndex = NaN;
+                headerInfo.actualColNum = NaN;
+                headerInfo.columnSpan = 0;
+                //Need to tell set visible = false to all the children
+                updateVisibleHeaderInfos(headerInfo.children, false);
+            }
+            else
+            {
+                if (headerInfos[i].children && headerInfos[i].children.length > 0)
+                {
+                    var children:Object = updateVisibleHeaderInfos(headerInfos[i].children, true, actualColNum);
+
+                    headerInfo.visibleChildren = children.infos;
+
+                    //If there aren't any visibleChildren then we don't want parent either
+                    if (headerInfo.visibleChildren == null)
+                    {
+                        headerInfo.visible = false;
+                        headerInfo.actualColNum = NaN;
+                        headerInfo.columnSpan = 0;
+                    }
+                    else
+                    {
+                        if (!visibleHeaderInfos)
+                            visibleHeaderInfos = [];
+
+                        visibleHeaderInfos.push(headerInfo);
+                        headerInfo.visibleIndex = k++;
+                        headerInfo.actualColNum = actualColNum;
+                        headerInfo.columnSpan = children.colSpan;
+                    }
+                }
+                else
+                {
+                    //No children and..it is visible we want this!!
+                    if (!visibleHeaderInfos)
+                        visibleHeaderInfos = [];
+
+                    headerInfo.visibleIndex = k++;
+                    visibleHeaderInfos.push(headerInfo);
+                    headerInfo.actualColNum = actualColNum;
+                    headerInfo.columnSpan = 1;
+                }
+            }
+
+            totalColumnSpan += headerInfo.columnSpan;
+            actualColNum += headerInfo.columnSpan;
+        }
+        return {infos:visibleHeaderInfos, colSpan:totalColumnSpan};
+    }
+
+    /**
+     *  @private
+     */
+    private function updateHeadersList(headerInfos:Array):void
+    {
+        var n:int = headerInfos ? headerInfos.length : 0;
+        var totalColumnSpan:int = 0;
+
+        for( var i:int = 0; i < n; i++)
+        {
+            var headerInfo:AdvancedDataGridHeaderInfo = headerInfos[i];
+            orderedHeadersList.push(headerInfo);
+
+            if(headerInfo.visibleChildren && headerInfo.visibleChildren.length > 0)
+                updateHeadersList(headerInfo.visibleChildren);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    private function updateDropData(event:DragEvent):void
+    {
+        var rowCount:int = rowInfo.length;
+        var rowNum:int = 0;
+        // we need to take care of headerHeight
+        var yy:int = rowInfo[rowNum].height + (headerVisible ? headerHeight :0);
+        var pt:Point = globalToLocal(new Point(event.stageX, event.stageY));
+        while (rowInfo[rowNum] && pt.y >= yy)
+        {
+            if (rowNum != rowInfo.length-1)
+            {
+                rowNum++;
+                yy += rowInfo[rowNum].height;
+            }
+            else
+            {
+                // now we're past all rows.  adding a pixel or two should be enough.
+                // at this point yOffset doesn't really matter b/c we're past all elements
+                // but might as well try to keep it somewhat correct
+                yy += rowInfo[rowNum].height;
+                rowNum++;
+            }
+        }
+        var lastRowY:Number = rowNum < rowInfo.length ? rowInfo[rowNum].y : (rowInfo[rowNum-1].y + rowInfo[rowNum-1].height);
+        var yOffset:Number = pt.y - lastRowY;
+        var rowHeight:Number = rowNum < rowInfo.length ? rowInfo[rowNum].height : rowInfo[rowNum-1].height;  //rowInfo[rowNum].height;
+        rowNum += verticalScrollPosition;
+
+        var parent:Object;
+        var index:int;
+        var emptyFolder:Boolean = false;
+        var numItems:int = collection ? collection.length : 0;
+
+        var topItem:Object = (rowNum > _verticalScrollPosition && rowNum <= numItems) ?
+                             listItems[rowNum - _verticalScrollPosition - 1][0].data : null;
+        var bottomItem:Object = (rowNum - verticalScrollPosition < rowInfo.length && rowNum < numItems) ?
+                                listItems[rowNum - _verticalScrollPosition][0].data  : null;
+
+        var topParent:Object = collection ? getParentItem(topItem) : null;
+        var bottomParent:Object = collection ? getParentItem(bottomItem) : null;
+
+        // check their relationship
+        if (yOffset > rowHeight * .5 &&
+            isItemOpen(bottomItem) &&
+            _rootModel.canHaveChildren(bottomItem) &&
+            !_rootModel.hasChildren(bottomItem))
+        {
+            // we'll get here if we're dropping into an empty folder.
+            // we have to be in the lower 50% of the row, otherwise
+            // we're "between" rows.
+            parent = bottomItem;
+            index = 0;
+            emptyFolder = true;
+        }
+        else if (!topItem && !rowNum == rowCount)
+        {
+            parent = collection ? getParentItem(bottomItem) : null;
+            index =  bottomItem ? getChildIndexInParent(parent, bottomItem) : 0;
+            rowNum = 0;
+        }
+        else if (bottomItem && bottomParent == topItem)
+        {
+            // we're dropping in the first item of a folder, that's an easy one
+            parent = topItem;
+            index = 0;
+        }
+        else if (topItem && bottomItem && topParent == bottomParent)
+        {
+            parent = collection ? getParentItem(topItem) : null;
+            index = iterator ? getChildIndexInParent(parent, bottomItem) : 0;
+        }
+        else
+        {
+            //we're dropping at the end of a folder.  Pay attention to the position.
+            if (topItem && (yOffset < (rowHeight * .5)))
+            {
+                // ok, we're on the top half of the bottomItem.
+                parent = topParent;
+                index = getChildIndexInParent(parent, topItem) + 1; // insert after
+            }
+            else if (!bottomItem)
+            {
+                parent = null;
+                if ((rowNum - verticalScrollPosition) == 0)
+                    index = 0;
+                else if (collection)
+                    index = collection.length;
+                else index = 0;
+            }
+            else
+            {
+                parent = bottomParent;
+                index = getChildIndexInParent(parent, bottomItem);
+            }
+        }
+        _dropData = { parent: parent, index: index, localX: event.localX, localY: event.localY,
+                      emptyFolder: emptyFolder, rowHeight: rowHeight, rowIndex: rowNum };
+    }
+
+    /**
+     *  @private
+     */
+    protected function selectColumnGroupHeader(headerInfo:AdvancedDataGridHeaderInfo):void
+    {
+        var r:IListItemRenderer = headerInfo.headerItem;
+
+        var parentLayer:Sprite;
+        var otherLayer:Sprite;
+
+        var s:Sprite;
+
+        if (headerInfo.actualColNum < lockedColumnCount)
+        {
+            parentLayer = selectionLayer;
+            otherLayer = movingSelectionLayer;
+        }
+        else
+        {
+            parentLayer = movingSelectionLayer;
+            otherLayer = selectionLayer;
+        }
+
+        s = Sprite(parentLayer.getChildByName("headerKeyboardSelection"));
+        if (!s)
+            s = Sprite(otherLayer.getChildByName("headerKeyboardSelection"));
+
+        if (! s)
+        {
+            s = new FlexSprite();
+            s.name = "headerKeyboardSelection";
+        }
+
+        if (s.parent != parentLayer)
+            parentLayer.addChild(s);
+
+        var g:Graphics = s.graphics;
+        g.clear();
+        g.beginFill( (isPressed || isKeyPressed) ? getStyle("selectionColor") : getStyle("rollOverColor") );
+        g.drawRect(0, 0, r.width, r.height+cachedPaddingTop+cachedPaddingBottom - 0.5);
+        g.endFill();
+
+        s.x = r.x;
+        s.y = r.y - cachedPaddingTop;
+
+        // Make sure other selection is removed
+        caretIndex = -1;
+        isPressed = false;
+        selectItem(headerInfo.headerItem, false, false);
+
+    }
+
+    /**
+     *  @private
+     */
+    private function scrollColumnGroupIfNeeded(h1:AdvancedDataGridHeaderInfo, h2:AdvancedDataGridHeaderInfo):void
+    {
+        if (!isColumnFullyVisible(displayableColumns[h2.actualColNum].colNum))
+            scrollToViewColumn(displayableColumns[h2.actualColNum].colNum, displayableColumns[h1.actualColNum].colNum);
+    }
+
+    /**
+     *  @private
+     */
+    protected function clearHeaderHorizontalSeparators():void
+    {
+        if (!horizontalSeparators)
+            return;
+
+        var lines:Sprite = Sprite(listSubContent.getChildByName("lines"));
+        var headerHorizontalLines:Sprite = Sprite(lines.getChildByName("headerHorizontalLines"));
+        while (headerHorizontalLines.numChildren)
+        {
+            headerHorizontalLines.removeChildAt(headerHorizontalLines.numChildren - 1);
+            horizontalSeparators.pop();
+        }
+
+        var lockedContent:Sprite = getLockedContent();
+        var lockedHeaderHorizontalLines:Sprite = Sprite(lockedContent.getChildByName("lockedHeaderheaderHorizontalLines"));
+        if (lockedHeaderHorizontalLines)
+        {
+            while (lockedHeaderHorizontalLines.numChildren)
+            {
+                lockedHeaderHorizontalLines.removeChildAt(lockedHeaderHorizontalLines.numChildren - 1);
+                horizontalLockedSeparators.pop();
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    protected function drawHeaderHorizontalSeparators():void
+    {
+        if (!horizontalSeparators)
+        {
+            horizontalSeparators = [];
+            horizontalLockedSeparators = [];
+        }
+        var childIndex:int;
+        var lines:Sprite = Sprite(listSubContent.getChildByName("lines"));
+        var headerHorizontalLines:UIComponent = UIComponent(lines.getChildByName("headerHorizontalLines"));
+
+        if (!headerHorizontalLines)
+        {
+            headerHorizontalLines = new UIComponent();
+            headerHorizontalLines.name = "headerHorizontalLines";
+            lines.addChild(headerHorizontalLines);
+
+        }
+        if (lines.numChildren > 1)
+        {
+            var vHeaderLines:UIComponent = UIComponent(lines.getChildByName("header"));
+            //Push the horizontal header lines behind vertical lines
+            // Otherwise they look little dirty
+            if (vHeaderLines)
+            {
+                childIndex = lines.getChildIndex(vHeaderLines);
+                if (childIndex+1 < lines.numChildren)
+                    lines.setChildIndex(headerHorizontalLines, childIndex+1);
+            }
+        }
+
+        numSeparators = 0;
+        var unlockedHeaderInfos:Array;
+        var lockedHeaderInfos:Array
+
+        if(visibleHeaderInfos)
+        {
+            if(!isNaN(_lockedColumnCountVal) && _lockedColumnCountVal > 0)
+            {
+                lockedHeaderInfos = visibleHeaderInfos.slice(0, _lockedColumnCountVal);
+                unlockedHeaderInfos = visibleHeaderInfos.slice(_lockedColumnCountVal);
+            }
+            else
+            {
+                unlockedHeaderInfos = visibleHeaderInfos;
+            }
+
+            //Draw horizontal header separators in the unlocked area
+            createHeaderHorizontalSeparators(unlockedHeaderInfos, horizontalSeparators, headerHorizontalLines);
+        }
+        //Remove extra separators created from the unlocked area
+        while (headerHorizontalLines.numChildren > numSeparators)
+        {
+            headerHorizontalLines.removeChildAt(headerHorizontalLines.numChildren - 1);
+            horizontalSeparators.pop();
+        }
+
+        var lockedHeaderHorizontalLines:UIComponent ;
+
+        numSeparators = 0;
+        if (lockedColumnCount > 0)
+        {
+            var lockedContent:Sprite = getLockedContent();
+            lockedHeaderHorizontalLines = UIComponent(lockedContent.getChildByName("lockedHeaderHorizontalLines"));
+
+            if (!lockedHeaderHorizontalLines)
+            {
+                lockedHeaderHorizontalLines = new UIComponent();
+                lockedHeaderHorizontalLines.name = "lockedHeaderHorizontalLines";
+                lockedContent.addChild(lockedHeaderHorizontalLines);
+            }
+
+            if (lockedContent.numChildren > 1)
+            {
+                var lockedHeaderLines:UIComponent = UIComponent(lockedContent.getChildByName("lockedHeaderLines"));
+
+                //Push the horizontal header lines behind vertical lines
+                // Otherwise they look little dirty
+                if (lockedHeaderLines)
+                {
+                    childIndex = lockedContent.getChildIndex(lockedHeaderLines);
+                        if (childIndex+1 < lines.numChildren)
+                          lockedContent.setChildIndex(lockedHeaderHorizontalLines, childIndex+1);
+                }
+            }
+            createHeaderHorizontalSeparators(lockedHeaderInfos, horizontalLockedSeparators, lockedHeaderHorizontalLines);
+        }
+
+        //Remove extra horizontal separators from the locked area
+        if (lockedHeaderHorizontalLines)
+            while (lockedHeaderHorizontalLines.numChildren > numSeparators)
+            {
+                lockedHeaderHorizontalLines.removeChildAt(lockedHeaderHorizontalLines.numChildren - 1);
+                horizontalLockedSeparators.pop();
+            }
+    }
+
+    /**
+     *  @private
+     */
+    private function getLockedContent():Sprite
+    {
+        var locked:Sprite = Sprite(listContent.getChildByName("lockedContent"));
+        if (!locked)
+        {
+            locked = new UIComponent();
+            locked.name = "lockedContent";
+            locked.cacheAsBitmap = true;
+            locked.mouseEnabled = false;
+            listContent.addChild(locked);
+        }
+        listContent.setChildIndex(locked, listContent.numChildren - 1);
+
+        return locked;
+    }
+
+    /**
+     *  @private
+     */
+    protected function createHeaderHorizontalSeparators(subHeaderInfos:Array, seperators:Array, headerLines:UIComponent):void
+    {
+        var n:int = subHeaderInfos.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            if(subHeaderInfos[i].visible && subHeaderInfos[i].visibleChildren && subHeaderInfos[i].visibleChildren.length > 0)
+            {
+                var sep:UIComponent = getHorizontalSeparator(numSeparators, seperators, headerLines);
+                var sepSkin:IFlexDisplayObject = IFlexDisplayObject(sep.getChildAt(0));
+
+                if (!subHeaderInfos[i].headerItem)
+                    sep.visible = false;
+
+                numSeparators++;
+
+                sep.visible = true;
+                var w:Number = subHeaderInfos[i].column.width;
+                sepSkin.setActualSize(w, 2);
+
+                sep.x = subHeaderInfos[i].headerItem.x;
+                var depth:int = subHeaderInfos[i].depth;
+                sep.y = headerRowInfo[depth].y + (headerRowInfo[depth].height - headerRowInfo[depth+1].height) -  2;
+                createHeaderHorizontalSeparators(subHeaderInfos[i].children, seperators, headerLines);
+            }
+        }
+
+    }
+
+    /**
+     *  @private
+     */
+    protected function getHorizontalSeparator(i:int, seperators:Array, headerLines:UIComponent):UIComponent
+    {
+        var sep:UIComponent;
+        var sepSkin:IFlexDisplayObject;
+
+        var headerSeparatorClass:Class =
+            getStyle("headerHorizontalSeparatorSkin");
+
+        if (i < headerLines.numChildren)
+        {
+            sep = UIComponent(headerLines.getChildAt(i));
+            sepSkin = IFlexDisplayObject(sep.getChildAt(0));
+        }
+        else
+        {
+            sep = new UIComponent();
+            headerLines.addChild(sep);
+        }
+
+        if (sepSkin)
+        {
+            if (sepSkin is headerSeparatorClass)
+            {
+                sepSkin = IFlexDisplayObject(sep.getChildAt(0));
+            }
+            else
+            {
+                //Remove the skin, because headerHorizontalSeparatorSkin style has
+                //changed now and this skin is of no use
+                sep.removeChildAt(0);
+                sepSkin = null;
+            }
+        }
+
+        if (!sepSkin)
+        {
+            sepSkin = new headerSeparatorClass();
+            if (sepSkin is ISimpleStyleClient)
+                ISimpleStyleClient(sepSkin).styleName = this;
+            sep.addChild(DisplayObject(sepSkin));
+        }
+
+        seperators.push(sep);
+        return sep;
+    }
+
+    /**
+     *  @private
+     */
+    private function updateMovingColumnIndex():void
+    {
+        movingColumnIndex = -1;
+        if(movingColumn)
+        {
+            var n:int = orderedHeadersList ? orderedHeadersList.length : 0;
+            for ( var i:int = 0; i < n; i++)
+            {
+                if(orderedHeadersList[i].column == movingColumn)
+                 {
+                     movingColumnIndex = i;
+                     break;
+                 }
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    protected function finishCellKeySelection():void
+    {
+        var uid:String;
+        var rowCount:int   = listItems.length;
+        var partialRow:int = (rowInfo[rowCount-1].y + rowInfo[rowCount-1].height >
+                              listContent.height) ? 1 : 0;
+
+        var listItem:IListItemRenderer;
+        var bSelChanged:Boolean = false;
+
+        var columnIndex:int = caretColumnIndex;
+
+        // Move selection
+        if (bSelectItem && caretIndex - verticalScrollPosition >= 0)
+        {
+            if (caretIndex - verticalScrollPosition > listItems.length-1)
+                caretIndex = listItems.length - 1 + verticalScrollPosition;
+
+            var visibleCoords:Object = absoluteToVisibleIndices(caretIndex, caretColumnIndex);
+            var visibleRowIndex:int = visibleCoords.rowIndex;
+            var visibleColIndex:int = visibleCoords.columnIndex;
+            if (visibleRowIndex >= 0 && visibleColIndex >= 0)
+                listItem = listItems[visibleRowIndex][visibleColIndex];
+
+            // if column spanning is used and the item is invisible,
+            // then find the item which is spanning across this column
+            while (listItem && !listItem.visible)
+            {
+                if (listItems[visibleRowIndex] && listItems[visibleRowIndex][visibleColIndex - 1])
+                {
+                    listItem = listItems[visibleRowIndex][visibleColIndex];
+                    visibleColIndex--;
+                    columnIndex--;
+                }
+                else
+                {
+                    break;
+                }
+            }
+
+            if (listItem)
+            {
+                uid = itemToUID(listItem.data);
+                if (visibleCellRenderers[uid])
+                    listItem = visibleCellRenderers[uid][columnIndex.toString()];
+
+                if (bShiftKey)
+                {
+                    selectCellItem(listItem, bShiftKey, bCtrlKey);
+                    bSelChanged = true;
+                }
+                else if (bCtrlKey)
+                {
+                    if (lastKey == Keyboard.SPACE)
+                    {
+                        selectCellItem(listItem, bShiftKey, bCtrlKey, true);
+                    }
+                    else
+                    {
+                        drawCellItem(listItem,
+                                     cellSelectionData[uid]
+                                     && cellSelectionData[uid][columnIndex.toString()] != null,
+                                     uid == highlightUID && caretColumnIndex == highlightColumnIndex,
+                                     true);
+                        bSelChanged = true;
+                    }
+                }
+                else
+                {
+                    var oldCaretIndex:int   = caretIndex;
+
+                    clearSelectedCells();
+
+                    caretIndex     = oldCaretIndex;
+                    anchorIndex    = caretIndex;
+                    _selectedIndex = caretIndex;
+
+                    selectedColumnIndex = caretColumnIndex;
+                    anchorColumnIndex   = caretColumnIndex;
+
+                    selectCellItem(listItem, bShiftKey, bCtrlKey, false);
+                    bSelChanged = true;
+                }
+            }
+        }
+
+        // Move caret
+        if (!bSelectItem && caretColumnIndex - horizontalScrollPosition >= 0)
+        {
+            if (caretColumnIndex - horizontalScrollPosition > _columns.length - 1)
+                caretColumnIndex = _columns.length - 1 + horizontalScrollPosition;
+
+            if (caretIndex - verticalScrollPosition >= 0)
+            {
+                var caretCoords:Object = absoluteToVisibleIndices(caretIndex, caretColumnIndex);
+                listItem = listItems[caretCoords.rowIndex][caretCoords.columnIndex];
+            }
+
+            if (listItem)
+            {
+                uid = itemToUID(listItem.data);
+                if (visibleCellRenderers[uid])
+                    listItem = visibleCellRenderers[uid][columnIndex.toString()];
+
+                if (bShiftKey)
+                {
+                    selectCellItem(listItem, bShiftKey, bCtrlKey);
+                    bSelChanged = true;
+                }
+                else if (bCtrlKey)
+                {
+                    drawCellItem(listItem,
+                                 cellSelectionData[uid]
+                                 && cellSelectionData[uid][columnIndex.toString()] != null,
+                                 uid == highlightUID && caretColumnIndex == highlightColumnIndex,
+                                 true);
+                }
+                else
+                {
+                    oldCaretIndex  = caretIndex;
+
+                    clearSelectedCells();
+
+                    caretIndex     = oldCaretIndex;
+                    anchorIndex    = caretIndex;
+                    _selectedIndex = caretIndex;
+
+                    selectCellItem(listItem, bShiftKey, bCtrlKey, false);
+                    bSelChanged = true;
+                }
+            }
+        }
+
+        if (bSelChanged)
+        {
+            var evt:ListEvent = new ListEvent(ListEvent.CHANGE);
+            evt.itemRenderer = listItem;
+
+            var pt:Point = itemRendererToIndices(listItem);
+            if (pt)
+            {
+                evt.rowIndex = pt.y;
+                evt.columnIndex = displayToAbsoluteColumnIndex(pt.x);
+            }
+            dispatchEvent(evt);
+        }
+    }
+
+    /**
+     *  Updates the list of selected cells, assuming that the specified item renderer was
+     *  clicked by the mouse, and the keyboard modifiers are in the specified state.
+     *
+     *
This method also updates the display of the item renderers based on their updated
+     *  selected state.

+     *
+     *  @param item The item renderer for the cell.
+     *
+     *  @param shiftKey true to specify that the Shift key is pressed,
+     *  and false if not.
+     *
+     *  @param ctrlKey true to specify that the Control key is pressed,
+     *  and false if not.
+     *
+     *  @param transition Specify true to animate the transition.
+     *
+     *  @return Returns true if the operation succeeded.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function selectCellItem(item:IListItemRenderer,
+                                      shiftKey:Boolean,
+                                      ctrlKey:Boolean,
+                                      transition:Boolean = true):Boolean
+    {
+        if (!selectable || !item || !itemRendererToIndices(item))
+            return false;
+
+        if (isHeaderItemRenderer(item))
+            return false;
+
+        // We'll start by assuming that the selection has not changed.
+        var selectionChange:Boolean    = false;
+        var placeHolder:CursorBookmark = iterator.bookmark;
+
+        var pt:Point                   = itemRendererToIndices(item);
+        if (pt.x < 0)
+            return false;
+        var index:int                  = pt.y;
+        var columnIndex:int            = displayToAbsoluteColumnIndex(pt.x);
+
+        var uid:String                 = itemToUID(item.data);
+        var data:Object                = item.data;
+
+        if (selectionMode == SINGLE_CELL
+            || (selectionMode == MULTIPLE_CELLS && !ctrlKey && !shiftKey))
+        {
+            // We want to know if 0, 1 or more items are selected
+            var numSelected:int = 0;
+            if (selectionMode == MULTIPLE_CELLS)
+            {
+                var curSelectionData:AdvancedDataGridBaseSelectionData
+                    = firstCellSelectionData;
+                if (curSelectionData != null)
+                {
+                    numSelected++;
+                    if (curSelectionData.nextSelectionData)
+                        numSelected++;
+                }
+            }
+
+            // allow unselecting via ctrl-click
+            if (ctrlKey && cellSelectionData[uid] && cellSelectionData[uid][columnIndex])
+            {
+                selectionChange = true;
+
+                var oldCaretIndex:int       = caretIndex;
+                var oldCaretColumnIndex:int = caretColumnIndex;
+
+                clearSelectedCells();
+
+                caretIndex       = oldCaretIndex;
+                caretColumnIndex = oldCaretColumnIndex;
+            }
+            // Plain old click, ignore if same item is selected unless number of
+            // selected items is going to change
+            else if ((_selectedIndex != index || selectedColumnIndex != columnIndex)
+                || (selectionMode == MULTIPLE_CELLS && numSelected != 1)
+                || (selectionMode == SINGLE_CELL))
+            {
+                selectionChange = true;
+
+                clearSelectedCells();
+
+                // Add new cell to cellSelectionData
+                addCellSelectionData(uid, columnIndex,
+                                     new AdvancedDataGridBaseSelectionData(item.data,
+                                                                           index, columnIndex, false) );
+
+                // Insert new cell's location at head position
+                // of outside-facing selectedCells
+                addToSelectedCells(index, columnIndex);
+
+                // Draw the cell as selected, check if it is already highlighted
+                drawCellItem(item, true,
+                             uid == highlightUID && columnIndex == highlightColumnIndex,
+                             true, transition);
+
+                // Update index, cell
+                selectedColumnIndex = columnIndex;
+                _selectedIndex      = pt.y;
+                iterator.seek(CursorBookmark.CURRENT, _selectedIndex - verticalScrollPosition);
+
+                // Update caret and anchor
+                anchorColumnIndex = caretColumnIndex = selectedColumnIndex;
+                anchorIndex       = caretIndex       = _selectedIndex;
+                anchorBookmark    = caretBookmark    = iterator.bookmark;
+
+                // Reset iterator to top of visible rows
+                iterator.seek(placeHolder, 0);
+            }
+        }
+        else if (shiftKey && selectionMode == MULTIPLE_CELLS)
+        {
+            if (anchorBookmark)
+            {
+                var oldAnchorBookmark:CursorBookmark = anchorBookmark;
+                var oldAnchorIndex:int               = anchorIndex;
+                var oldAnchorColumnIndex:int         = anchorColumnIndex;
+
+                clearSelectedCells();
+
+                caretIndex        = index;
+                caretColumnIndex  = columnIndex;
+                caretBookmark     = iterator.bookmark;
+
+                anchorIndex       = oldAnchorIndex;
+                anchorBookmark    = oldAnchorBookmark;
+                anchorColumnIndex = oldAnchorColumnIndex;
+
+                try
+                {
+                    iterator.seek(anchorBookmark, 0);
+                }
+                catch (e:ItemPendingError)
+                {
+                    e.addResponder(new ItemResponder(
+                                       cellSelectionPendingResultHandler,
+                                       cellSelectionPendingFailureHandler,
+                                       new AdvancedDataGridBaseSelectionPending(
+                                           index,
+                                           anchorIndex,
+                                           columnIndex,
+                                           anchorColumnIndex,
+                                           item.data,
+                                           transition,
+                                           placeHolder,
+                                           CursorBookmark.CURRENT,
+                                           0) ) );
+                    iteratorValid = false;
+                }
+
+                shiftCellSelectionLoop(index, anchorIndex, columnIndex, anchorColumnIndex,
+                                       item.data, transition, placeHolder);
+
+                selectionChange = true;
+            }
+        }
+        else if (ctrlKey && selectionMode == MULTIPLE_CELLS)
+        {
+            if (cellSelectionData[uid] && cellSelectionData[uid][columnIndex.toString()])
+            {
+                removeCellSelectionData(uid, columnIndex);
+                drawCellItem(visibleCellRenderers[uid][columnIndex.toString()], // item
+                             false, // selected
+                             uid == highlightUID && columnIndex == highlightColumnIndex, // highlighted
+                             true, // caret
+                             transition); // transition
+                removeFromSelectedCells(index, columnIndex);
+            }
+            else
+            {
+                addCellSelectionData(uid, columnIndex,
+                                     new AdvancedDataGridBaseSelectionData(
+                                         item.data,
+                                         index,
+                                         columnIndex,
+                                         false) );
+
+                drawCellItem(visibleCellRenderers[uid][columnIndex.toString()], // item
+                             true, // selected
+                             uid == highlightUID && columnIndex == highlightColumnIndex, // highlighted
+                             true, // caret
+                             transition); // transition
+
+                addToSelectedCells(index, columnIndex);
+
+                _selectedIndex      = index;
+                selectedColumnIndex = columnIndex;
+                // Setting this causes unexpected behavior in the UI because
+                // it does a call of updateDisplayList on its own, and we can't
+                // set it directly since it's a private variable in ListBase
+                // selectedItem       = item.data;
+            }
+
+            iterator.seek(CursorBookmark.CURRENT, index - verticalScrollPosition);
+
+            caretIndex       = index;
+            caretColumnIndex = columnIndex;
+            caretBookmark    = iterator.bookmark;
+
+            anchorIndex       = index;
+            anchorColumnIndex = columnIndex;
+            anchorBookmark    = iterator.bookmark;
+
+            iterator.seek(placeHolder, 0);
+
+            selectionChange = true;
+        }
+
+        return selectionChange;
+    }
+
+    /**
+     *  @private
+     *  Handle shift-selection of cells.
+     *
+     */
+    private function shiftCellSelectionLoop(stopIndex:int,
+                                            anchorIndex:int,
+                                            stopColumnIndex:int,
+                                            anchorColumnIndex:int,
+                                            stopData:Object,
+                                            transition:Boolean,
+                                            placeHolder:CursorBookmark):void
+    {
+        var incr:Boolean       = (anchorIndex < stopIndex);
+        var columnIncr:Boolean = (anchorColumnIndex < stopColumnIndex);
+        var data:Object;
+        var uid:String;
+        var index:int = anchorIndex;
+
+        try
+        {
+            // loop for rows
+            do
+            {
+                data = iterator.current;
+                uid  = itemToUID(data);
+                var columnIndex:int = anchorColumnIndex;
+
+                // loop for columns
+                while (true)
+                {
+					addCellSelectionData(uid,
+						columnIndex,
+						new AdvancedDataGridBaseSelectionData(
+							data,
+							index,
+							columnIndex,
+							false)
+					);
+					addToSelectedCells(index, columnIndex);
+
+                    if (visibleCellRenderers[uid]
+                        && visibleCellRenderers[uid][columnIndex.toString()]
+                        && visibleCellRenderers[uid][columnIndex.toString()].visible)
+                        // Checking visibility to handle column spanning
+                    {
+                        drawCellItem(visibleCellRenderers[uid][columnIndex.toString()],
+                                     true,
+                                     uid == highlightUID && columnIndex == highlightColumnIndex,
+                                     false,
+                                     transition);
+                    }
+
+                    if (columnIndex != stopColumnIndex && columnIndex != -1)
+                    {
+                        if (columnIncr)
+                            columnIndex = viewDisplayableColumnAtOffset(columnIndex, +1, -1, false);
+                        else
+                            columnIndex = viewDisplayableColumnAtOffset(columnIndex, -1, -1, false);
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+
+                if (data == stopData)
+                {
+                    if (visibleCellRenderers[uid]
+                        && visibleCellRenderers[uid][columnIndex.toString()])
+                    {
+                        drawCellItem(visibleCellRenderers[uid][columnIndex.toString()],
+                                     true,
+                                     uid == highlightUID && columnIndex == highlightColumnIndex,
+                                     true,
+                                     transition);
+                    }
+
+                    break;
+                }
+
+                if (incr)
+                    index++;
+                else
+                    index--;
+            }
+            while (incr ? iterator.moveNext() : iterator.movePrevious());
+        }
+        catch (e:ItemPendingError)
+        {
+            e.addResponder(new ItemResponder(
+                               cellSelectionPendingResultHandler,
+                               cellSelectionPendingFailureHandler,
+                               new AdvancedDataGridBaseSelectionPending(
+                                   index,
+                                   anchorIndex,
+                                   columnIndex,
+                                   anchorColumnIndex,
+                                   data,
+                                   transition,
+                                   placeHolder,
+                                   CursorBookmark.CURRENT,
+                                   0) ) );
+
+            iteratorValid = false;
+        }
+
+        try
+        {
+            iterator.seek(placeHolder, 0);
+            iteratorValid = true;
+        }
+        catch (e2:ItemPendingError)
+        {
+            lastSeekPending = new ListBaseSeekPending(placeHolder, 0);
+
+            e2.addResponder(new ItemResponder(
+                                seekPendingResultHandler,
+                                seekPendingFailureHandler,
+                                lastSeekPending));
+        }
+    }
+
+    /**
+     *  @private
+     */
+    private function cellSelectionPendingResultHandler(data:Object,
+                                                       info:AdvancedDataGridBaseSelectionPending):void
+    {
+        iterator.seek(info.bookmark, info.offset);
+        shiftCellSelectionLoop(info.index, info.anchorIndex, info.columnIndex,
+                               info.anchorColumnIndex, info.stopData,
+                               info.transition, info.placeHolder);
+    }
+
+    /**
+     *  @private
+     */
+    private function cellSelectionPendingFailureHandler(data:Object,
+                                                        info:AdvancedDataGridBaseSelectionPending):void
+    {
+    }
+
+    /**
+     *  @private
+     *  Check if a cell is already present in selecedCells.
+     */
+    private function isCellAlreadySelected(rowIndex:int, columnIndex:int):Boolean
+    {
+        if (!_selectedCells || !_selectedCells.length)
+            return false;
+
+		return cellSelections[[rowIndex, columnIndex]] != null;
+    }
+
+    /**
+     *  Helper function to add a row/column location to the selectedCells array
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    mx_internal function addToSelectedCells(rowIndex:int, columnIndex:int):void
+    {
+		if (isCellAlreadySelected(rowIndex, columnIndex))
+			return;
+
+        var newCell:Object = {   rowIndex    : rowIndex,
+                                 columnIndex : columnIndex };
+
+        var newSelectedCells:Array = _selectedCells;
+        if (!newSelectedCells)
+            newSelectedCells = [];
+        newSelectedCells.unshift(newCell);
+        _selectedCells = newSelectedCells;
+		cellSelections[[rowIndex,columnIndex]] = newCell;
+    }
+
+    /**
+     *  Helper function to remove a row/column location to the selectedCells array
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    mx_internal function removeFromSelectedCells(rowIndex:int, columnIndex:int):void
+    {
+        var cellToRemove:int = -1;
+
+        if (_selectedCells)
+        {
+            var n:int = _selectedCells.length;
+            for (var i:int = 0; i < n; i++)
+            {
+                // Skip the cell that we want to remove
+                if (_selectedCells[i].rowIndex == rowIndex
+                    && _selectedCells[i].columnIndex == columnIndex)
+                {
+                    cellToRemove = i;
+                    break;
+                }
+            }
+
+            if (cellToRemove != -1)
+                _selectedCells.splice(cellToRemove, 1);
+        }
+    }
+
+    /**
+     *  Adds cell selection information to the control, as if you used the mouse to select the cell.
+     *
+     *  @param uid The UID of the selected cell.
+     *
+     *  @param columnIndex The column index of the selected cell.
+     *
+     *  @param selectionData An AdvancedDataGridBaseSelectionData instance defining the
+     *  information about the selected cell.
+     *
+     *  @see mx.controls.advancedDataGridClasses.AdvancedDataGridBaseSelectionData
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function addCellSelectionData(uid:String,
+                                            columnIndex:int,
+                                            selectionData:AdvancedDataGridBaseSelectionData):void
+    {
+        if (firstCellSelectionData != null)
+            firstCellSelectionData.prevSelectionData = selectionData;
+
+        selectionData.nextSelectionData = firstCellSelectionData;
+        firstCellSelectionData          = selectionData;
+
+        if (!cellSelectionData[uid])
+            cellSelectionData[uid] = {};
+
+        cellSelectionData[uid][columnIndex.toString()] = selectionData;
+    }
+
+    /**
+     *  Removes cell selection information from the control.
+     *
+     *  @param uid The UID of the selected cell.
+     *
+     *  @param columnIndex The column index of the selected cell.
+     *
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function removeCellSelectionData(uid:String, columnIndex:int):void
+    {
+        if (!cellSelectionData[uid])
+            return;
+
+        var curSelectionData:AdvancedDataGridBaseSelectionData
+            = cellSelectionData[uid][columnIndex.toString()];
+
+        if (firstCellSelectionData == curSelectionData)
+            firstCellSelectionData = curSelectionData.nextSelectionData;
+
+        if (curSelectionData.prevSelectionData != null)
+            curSelectionData.prevSelectionData.nextSelectionData
+                = curSelectionData.nextSelectionData;
+
+        if (curSelectionData.nextSelectionData != null)
+            curSelectionData.nextSelectionData.prevSelectionData
+                = curSelectionData.prevSelectionData;
+
+        delete cellSelectionData[uid][columnIndex.toString()];
+
+        // Remove uid if there are no columns for that uid in cellSelectionData
+        if (!atLeastOneProperty(cellSelectionData[uid]))
+            delete cellSelectionData[uid];
+    }
+
+    /**
+     *  Returns true if the Object has at least one property,
+     *  which means that the dictionary has at least one key.
+     *
+     *  @param o The Object to inspect.
+     *
+     *  @return true if the Object has at least one property.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function atLeastOneProperty(o:Object):Boolean
+    {
+        for (var p:String in o) // substitute for an "object.length" property
+            return true;
+
+        for each (var variable:XML in describeType(data).variable)
+            return true;
+
+        return false;
+    }
+
+    /**
+     *  Clears the selectedCells property.
+     *
+     *  @param transition Specify true to animate the transition.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function clearSelectedCells(transition:Boolean = false):void
+    {
+        for (var p:String in visibleCellRenderers)
+        {
+            for (var q:String in cellSelectionData[p])
+            {
+				var item:IListItemRenderer;
+				var visibleRenderer:Object = visibleCellRenderers[p];
+				if (visibleRenderer)
+					item = visibleRenderer[q];
+                if (item)
+                    drawCellItem(item, false,
+                                 p == highlightUID
+                                 && highlightColumnIndex == int(q),
+                                 false,
+                                 transition);
+            }
+        }
+
+        _selectedCells = [];
+		cellSelections = {};
+
+        clearCellSelectionData();
+
+        _selectedIndex = -1;
+        selectedItem   = null;
+
+        caretIndex  = -1;
+        anchorIndex = -1;
+
+        caretBookmark  = null;
+        anchorBookmark = null;
+    }
+
+    /**
+     *  @private
+     *  Remove entries in pendingCellSelection.
+     */
+    protected function clearPendingCells():void
+    {
+        cellsWaitingToBeDisplayed = false;
+        pendingCellSelection.removeAll();
+    }
+
+    /**
+     *  Clears information on cell selection.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function clearCellSelectionData():void
+    {
+        cellSelectionData = {};
+        firstCellSelectionData = null;
+    }
+
+    /**
+     *  @private
+     */
+    protected function addIndicatorToSelectionLayer(o:Sprite, columnIndex:int):void
+    {
+        if (columnIndex < lockedColumnCount)
+        {
+            if (o.parent != selectionLayer)
+                selectionLayer.addChild(DisplayObject(o));
+            else
+                o.parent.setChildIndex(DisplayObject(o),
+                                       o.parent.numChildren - 1);
+        }
+        else
+        {
+            if (o.parent != movingSelectionLayer)
+                movingSelectionLayer.addChild(DisplayObject(o));
+            else
+                o.parent.setChildIndex(DisplayObject(o),
+                                       o.parent.numChildren - 1);
+        }
+    }
+
+    /**
+     *  @private
+     *  Draw a cell item renderer based on whether it is/is not selected,
+     *  highlighted and the caret is positioned on the cell.
+     *
+     */
+    protected function drawCellItem(item:IListItemRenderer,
+                                    selected:Boolean    = false,
+                                    highlighted:Boolean = false,
+                                    caret:Boolean       = false,
+                                    transition:Boolean  = false):void
+    {
+        if (!item || isHeaderItemRenderer(item))
+            return;
+
+        var pt:Point = itemRendererToIndices(item);
+        if (!pt)
+            return;
+
+        var index:int       = pt.y;
+        var columnIndex:int = displayToAbsoluteColumnIndex(pt.x);
+
+        var rowData:BaseListData = rowMap[item.name];
+
+        var o:Sprite;
+        var g:Graphics;
+
+        var itemXPos:Number = item.x;
+//         if (columnIndex > lockedColumnCount)
+//             itemXPos = getAdjustedXPos(itemXPos);
+
+        if (highlighted
+            && (!highlightItemRenderer
+                || (highlightUID != rowData.uid && columnIndex != highlightColumnIndex)))
+        {
+            if (!highlightIndicator)
+            {
+                o = new SpriteAsset();
+                highlightIndicator = o;
+            }
+
+            o = highlightIndicator;
+
+            addIndicatorToSelectionLayer(o, pt.x);
+
+            drawHighlightIndicator(
+                o,                                  // sprite
+                itemXPos,                             // x
+                rowInfo[rowData.rowIndex].y,        // y
+                item.width,                         // width
+                rowInfo[rowData.rowIndex].height,   // height
+                getStyle("rollOverColor"),          // color
+                item);                              // IListItemRenderer
+
+            highlightItemRenderer = item;
+            highlightUID          = rowData.uid;
+            highlightColumnIndex  = columnIndex;
+        }
+        else if (!highlighted
+                 && highlightItemRenderer
+                 && (rowData && highlightUID == rowData.uid && highlightColumnIndex == columnIndex))
+        {
+            if (highlightIndicator)
+                Sprite(highlightIndicator).graphics.clear();
+            lastHighlightItemRenderer = highlightItemRenderer;
+            highlightItemRenderer     = null;
+            highlightUID              = null;
+            highlightColumnIndex      = -1;
+        }
+
+        if (selected)
+        {
+            if (!cellSelectionIndicators[rowData.uid])
+                cellSelectionIndicators[rowData.uid] = {};
+
+            var newIndicator:Boolean = false;
+
+            if (!cellSelectionIndicators[rowData.uid][columnIndex.toString()])
+            {
+                o = new SpriteAsset();
+                o.mouseEnabled = false;
+                cellSelectionIndicators[rowData.uid][columnIndex.toString()] = o;
+                newIndicator = true;
+            }
+            o = cellSelectionIndicators[rowData.uid][columnIndex.toString()];
+            addIndicatorToSelectionLayer(o, pt.x);
+
+                drawSelectionIndicator(
+                    o,                                      // sprite
+                    itemXPos,                               // x
+                    rowInfo[rowData.rowIndex].y,            // y
+                    item.width,                             // width
+                    rowInfo[rowData.rowIndex].height,       // height
+                    enabled ?                               // color
+                    getStyle("selectionColor") :
+                    getStyle("selectionDisabledColor"),
+                    item);                                  // IListItemRenderer
+
+            if (newIndicator)
+                if (transition)
+                    applyCellSelectionEffect(o, rowData.uid, columnIndex, item);
+        }
+        else if (!selected)
+        {
+			if (rowData)
+			{
+				var rowIndicators:Object = cellSelectionIndicators[rowData.uid];
+				var columnIndicator:Sprite;
+				if (rowIndicators && (columnIndicator = rowIndicators[columnIndex.toString()]))
+				{
+					o = columnIndicator;
+					if (o.parent)
+						o.parent.removeChild(o);
+
+					delete rowIndicators[columnIndex.toString()];
+					if (!atLeastOneProperty(rowIndicators))
+						delete cellSelectionIndicators[rowData.uid];
+				}
+			}
+        }
+
+        if (caret)
+        {
+            // Only draw the caret if there has been keyboard navigation.
+            if (showCaret)
+            {
+                if (!caretIndicator)
+                {
+                    o = new SpriteAsset();
+                    o.mouseEnabled = false;
+                    caretIndicator = o;
+                }
+                o = caretIndicator;
+
+                addIndicatorToSelectionLayer(o, pt.x);
+
+                drawCaretIndicator(
+                    o,                                  // sprite
+                    itemXPos,                           // x
+                    rowInfo[rowData.rowIndex].y,        // y
+                    item.width,                         // width
+                    rowInfo[rowData.rowIndex].height,   // height
+                    getStyle("selectionColor"),         // color
+                    item);                              // IListItemRenderer
+
+                caretItemRenderer = item;
+                caretUID          = rowData.uid;
+                caretColumnIndex  = columnIndex;
+            }
+        }
+        else if (!caret && caretItemRenderer
+                 && caretUID == rowData.uid
+                 && caretColumnIndex == columnIndex)
+        {
+            if (caretIndicator)
+                Sprite(caretIndicator).graphics.clear();
+
+            caretItemRenderer = null;
+            caretUID          = null;
+        }
+
+        if (item is IFlexDisplayObject)
+        {
+            if (item is IInvalidating)
+            {
+                IInvalidating(item).invalidateDisplayList();
+                IInvalidating(item).validateNow();
+            }
+        }
+        else if (item is IUITextField)
+        {
+            IUITextField(item).validateNow();
+        }
+
+        var rowIndex:int = rowMap[item.name].rowIndex;
+        var optimumColumns:Array = getOptimumColumns();
+        var n:int = optimumColumns.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            var r:IListItemRenderer = listItems[rowIndex][i];
+            updateDisplayOfItemRenderer(r);
+        }
+    }
+
+    /**
+     *  Sets up the effect for applying the selection indicator.
+     *  The default is a basic alpha tween.
+     *
+     *  @param indicator A Sprite that contains the graphics depicting selection.
+     *
+     *  @param uid The UID of the item being selected which can be used to index
+     *  into a table and track more than one selection effect.
+     *
+     *  @param columnIndex The column index of the selected cell.
+     *
+     *  @param itemRenderer The item renderer that is being shown as selected.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function applyCellSelectionEffect(indicator:Sprite,
+                                                uid:String,
+                                                columnIndex:int,
+                                                itemRenderer:IListItemRenderer):void
+    {
+        var selectionDuration:Number = getStyle("selectionDuration");
+
+        if (selectionDuration != 0)
+        {
+            indicator.alpha = 0;
+
+            if (!cellSelectionTweens[uid])
+                cellSelectionTweens[uid] = {};
+
+            cellSelectionTweens[uid][columnIndex.toString()] =
+                new Tween(indicator, 0, 1, selectionDuration, 5);
+
+            cellSelectionTweens[uid][columnIndex.toString()].addEventListener(
+                TweenEvent.TWEEN_UPDATE,
+                selectionTween_updateHandler);
+
+            cellSelectionTweens[uid][columnIndex.toString()].addEventListener(
+                TweenEvent.TWEEN_END,
+                selectionTween_endHandler);
+
+            cellSelectionTweens[uid][columnIndex.toString()].setTweenHandlers(
+                onSelectionTweenUpdate,
+                onSelectionTweenUpdate);
+
+            var selectionEasingFunction:Function =
+                getStyle("selectionEasingFunction") as Function;
+            if (selectionEasingFunction != null)
+                cellSelectionTweens[uid][columnIndex.toString()].easingFunction
+                    = selectionEasingFunction;
+        }
+    }
+
+    /**
+     *  @private
+     */
+    protected function removeCellIndicators(uid:String, columnIndex:int):void
+    {
+        if (cellSelectionTweens[uid] && cellSelectionTweens[uid][columnIndex.toString()])
+        {
+            cellSelectionTweens[uid][columnIndex.toString()].removeEventListener(
+                TweenEvent.TWEEN_UPDATE, selectionTween_updateHandler);
+
+            cellSelectionTweens[uid][columnIndex.toString()].removeEventListener(
+                TweenEvent.TWEEN_END, selectionTween_endHandler);
+
+            if (cellSelectionIndicators[uid][columnIndex.toString()].alpha < 1)
+                Tween.removeTween(cellSelectionTweens[uid][columnIndex.toString()]);
+
+            delete cellSelectionTweens[uid][columnIndex.toString()];
+            if (!atLeastOneProperty(cellSelectionTweens[uid]))
+                delete cellSelectionTweens[uid];
+        }
+
+        // toss associated graphics if needed
+
+        if (cellSelectionIndicators[uid] && cellSelectionIndicators[uid][columnIndex.toString()])
+        {
+            cellSelectionIndicators[uid][columnIndex.toString()].parent.removeChild(cellSelectionIndicators[uid][columnIndex.toString()]);
+            delete cellSelectionIndicators[uid][columnIndex.toString()];
+            if (!atLeastOneProperty(cellSelectionIndicators[uid]))
+                delete cellSelectionIndicators[uid];
+        }
+
+        if (uid == highlightUID && columnIndex == highlightColumnIndex)
+        {
+            lastHighlightItemRenderer = highlightItemRenderer;
+            highlightItemRenderer = null;
+            highlightUID = null;
+            if (highlightIndicator)
+                Sprite(highlightIndicator).graphics.clear();
+        }
+
+        if (uid == caretUID && columnIndex == caretColumnIndex)
+        {
+            caretItemRenderer = null;
+            caretUID = null;
+            if (caretIndicator)
+                Sprite(caretIndicator).graphics.clear();
+        }
+    }
+
+    /**
+     *  @inheritDoc mx.controls.listClasses.ListBase#clearIndicators()
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    override protected function clearIndicators():void
+    {
+        if (isCellSelectionMode())
+            clearCellIndicators();
+
+        super.clearIndicators();
+    }
+
+    /**
+     *  @private
+     */
+    protected function clearCellIndicators():void
+    {
+        for (var p:String in cellSelectionIndicators)
+        {
+            for (var q:String in cellSelectionIndicators[p])
+            {
+                removeCellIndicators(p, int(q));
+            }
+        }
+
+        cellSelectionTweens     = {};
+        cellSelectionIndicators = {};
+        visibleCellRenderers    = {};
+    }
+
+    /**
+     * @private
+     * Set selectedCells and update display accordingly.
+     */
+    mx_internal function setSelectedCells(value:Array):void
+    {
+        var isFirstCell:Boolean = true;
+        var n:int = value.length;
+        for (var i:int = 0; i < n; i++)
+        {
+			var cell:Object = value[i];
+            if (isCellAlreadySelected(cell.rowIndex, cell.columnIndex))
+                continue;
+
+            var visibleCoords:Object = absoluteToVisibleIndices(value[i].rowIndex,
+                                            value[i].columnIndex);
+            var visibleRowIndex:int = visibleCoords.rowIndex;
+            var visibleColIndex:int = visibleCoords.columnIndex;
+
+            var listItem:IListItemRenderer;
+            if (listItems[visibleRowIndex] && listItems[visibleRowIndex][visibleColIndex])
+            {
+                listItem = listItems[visibleRowIndex][visibleColIndex];
+            }
+            else
+            {
+                addToSelectedCells(value[i].rowIndex, value[i].columnIndex);
+                pendingCellSelection.addItem(value[i]);
+                cellsWaitingToBeDisplayed = true;
+                continue;
+            }
+
+            if (isFirstCell)
+            {
+                // Replaces selectedCells with only this cell location
+                selectCellItem(listItem, false, false);
+                isFirstCell = false;
+            }
+            else
+            {
+                // Add to selectedCells
+                selectCellItem(listItem, false, true); // ctrl-key => multiple selection
+            }
+        }
+    }
+
+    /**
+     *  @private
+     *  Update the selectedCells array based on the changes in non-cell
+     *  selection modes.
+     */
+    protected function updateSelectedCells():void
+    {
+        switch(selectionMode)
+        {
+            case NONE:
+            {
+                if (_selectedCells)
+                    _selectedCells = null;
+                break;
+            }
+
+            case SINGLE_ROW:
+            {
+                // When in row selection mode, selectedCells is updated
+                // along with selectedItems, selectedIndices as well
+                _selectedCells = [
+                {
+                    rowIndex : selectedIndex,
+                    columnIndex : -1
+                }
+                    ];
+                break;
+            }
+
+            case MULTIPLE_ROWS:
+            {
+                // When in row selection mode, selectedCells is updated
+                // along with selectedItems, selectedIndices as well
+                _selectedCells = selectedIndices.map(rowToCell);
+                break;
+            }
+        }
+		syncCellSelections(_selectedCells);
+    }
+
+	/**
+	 *  @private
+	 */
+	private function syncCellSelections(cells:Array):void
+	{
+		if (!cells)
+		{
+			cellSelections = null;
+		}
+		else
+		{
+			cellSelections = {};
+			for each (var cell:Object in cells)
+			{
+				cellSelections[[cell.rowIndex, cell.columnIndex]] = cell;
+			}
+		}
+	}
+
+    /**
+     *  @private
+     */
+    private function rowToCell(item:*, index:int, array:Array):Object
+    {
+        return {
+            rowIndex : item,
+                columnIndex : -1
+                };
+    }
+
+     /**
+     *  @private
+     */
+   private function getAdjustedLockedCount(index:int):int
+    {
+        if(visibleHeaderInfos)
+        {
+            index = Math.min(index, visibleHeaderInfos.length);
+            if(visibleHeaderInfos[ index - 1])
+                return visibleHeaderInfos[index-1].actualColNum + visibleHeaderInfos[index-1].columnSpan;
+       }
+        return 0;
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Overridden event handlers
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Catches any events from the model. Optimized for editing one item.
+     *  Creates columns when there are none. Inherited from list.
+     *  @param eventObj
+     */
+    override protected function collectionChangeHandler(event:Event):void
+    {
+        if (event is CollectionEvent)
+        {
+            var ceEvent:CollectionEvent = CollectionEvent(event)
+                if (ceEvent.kind == CollectionEventKind.RESET)
+                {
+                    // if the data is grouped, update the groupLabelField.
+                    if (_rootModel is IGroupingCollection && IGroupingCollection(_rootModel).grouping)
+                        groupLabelField = IGroupingCollection(_rootModel).grouping.label;
+
+					if (_rootModel is IGroupingCollection2 && IGroupingCollection2(_rootModel).grouping)
+						groupLabelField = IGroupingCollection2(_rootModel).grouping.label;
+
+                    // if collection is reset, then expand the items if displayItemsExpanded is true
+                    if (displayItemsExpanded)
+                        expandAll();
+                }
+                if (ceEvent.kind == CollectionEventKind.REFRESH)
+                {
+                    // if collection is reset, then expand the items if displayItemsExpanded is true
+                    if (displayItemsExpanded)
+                        expandAll();
+                }
+        }
+
+        super.collectionChangeHandler(event);
+
+        if (event is CollectionEvent)
+        {
+            var ce:CollectionEvent = CollectionEvent(event);
+            if (ce.kind == CollectionEventKind.ADD)
+            {
+                if (displayItemsExpanded)
+                {
+                    // when children are added, display them expanded
+                    var n:int = ce.items.length;
+                    for (var i:int = 0; i < n; i++)
+                    {
+                        expandChildrenOf(ce.items[i],true);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function headerNavigationHandler(event:KeyboardEvent):void
+    {
+       if (!columnGrouping || headerIndex == -1 || selectedHeaderInfo == null)
+       {
+          super.headerNavigationHandler(event);
+       }
+       else
+       {
+          if (headerIndex == -1 || selectedHeaderInfo == null)
+             return;
+
+          var newSelectedHeaderInfo:AdvancedDataGridHeaderInfo;
+          var siblings:Array;
+          if (event.keyCode == Keyboard.UP)
+          {
+             if (selectedHeaderInfo.parent != null)
+             {
+                newSelectedHeaderInfo = selectedHeaderInfo.parent;
+                unselectColumnHeader(headerIndex);
+
+                selectedHeaderInfo = newSelectedHeaderInfo;
+                headerIndex = newSelectedHeaderInfo.index;
+                selectColumnGroupHeader(newSelectedHeaderInfo);
+             }
+
+          }
+          else if (event.keyCode == Keyboard.DOWN)
+          {
+             //Check if we are a leaf-header
+             if (selectedHeaderInfo.visibleChildren == null || selectedHeaderInfo.visibleChildren.length == 0)
+             {
+                unselectColumnHeader(selectedHeaderInfo.column.colNum, true);
+                headerIndex = -1;
+             }
+             else
+             {
+                 newSelectedHeaderInfo = selectedHeaderInfo.visibleChildren[0];
+                 unselectColumnHeader(headerIndex);
+
+                 selectedHeaderInfo = newSelectedHeaderInfo;
+                 headerIndex = 0;
+                 selectColumnGroupHeader(newSelectedHeaderInfo);
+             }
+          }
+          else if (event.keyCode == Keyboard.LEFT)
+          {
+             siblings = (selectedHeaderInfo.parent !=null)? selectedHeaderInfo.parent.visibleChildren : visibleHeaderInfos;
+             if (selectedHeaderInfo.visibleIndex > 0)
+             {
+                 newSelectedHeaderInfo = siblings[selectedHeaderInfo.visibleIndex-1];
+                 scrollColumnGroupIfNeeded(selectedHeaderInfo, newSelectedHeaderInfo);
+
+                 unselectColumnHeader(headerIndex);
+                 selectedHeaderInfo = newSelectedHeaderInfo;
+                 headerIndex = newSelectedHeaderInfo.visibleIndex;
+                 selectColumnGroupHeader(newSelectedHeaderInfo);
+             }
+          }
+          else if (event.keyCode == Keyboard.RIGHT)
+          {
+             siblings = (selectedHeaderInfo.parent !=null)? selectedHeaderInfo.parent.visibleChildren : visibleHeaderInfos;
+             if (selectedHeaderInfo.visibleIndex < siblings.length - 1)
+             {
+                newSelectedHeaderInfo = siblings[selectedHeaderInfo.visibleIndex+1];
+                scrollColumnGroupIfNeeded(selectedHeaderInfo, newSelectedHeaderInfo);
+
+                unselectColumnHeader(headerIndex);
+
+                selectedHeaderInfo = newSelectedHeaderInfo;
+                headerIndex = newSelectedHeaderInfo.visibleIndex;
+                selectColumnGroupHeader(newSelectedHeaderInfo);
+             }
+          }
+          else if (event.keyCode == Keyboard.SPACE)
+          {
+              if (sortableColumns &&
+                  selectedHeaderInfo.column.colNum != -1 && !isNaN(selectedHeaderInfo.column.colNum)
+                  && columns[selectedHeaderInfo.column.colNum].sortable)
+              {
+                  isKeyPressed = true;
+                  selectColumnHeader(selectedHeaderInfo.column.colNum);
+
+                  var advancedDataGridEvent:AdvancedDataGridEvent =
+                      new AdvancedDataGridEvent(AdvancedDataGridEvent.SORT, false, true);
+
+                  advancedDataGridEvent.multiColumnSort      = event.ctrlKey;
+                  advancedDataGridEvent.removeColumnFromSort = event.shiftKey;
+                  advancedDataGridEvent.columnIndex     = selectedHeaderInfo.column.colNum;//headerIndex;
+                  advancedDataGridEvent.dataField       = selectedHeaderInfo.column.dataField;
+
+                  dispatchEvent(advancedDataGridEvent);
+              }
+          }
+          // horizontal scrolling when focus is on header
+          else if ( event.shiftKey
+                  && (event.keyCode == Keyboard.PAGE_UP
+                     || event.keyCode == Keyboard.PAGE_DOWN) )
+          {
+             moveSelectionHorizontally(event.keyCode, event.shiftKey, event.ctrlKey);
+          }
+
+          // don't we allow vertical scrolling when focus is on the header?
+          // if the focus is on header and we hit page-down/page-up no action would be taken
+          // is this fine?
+
+          event.stopPropagation();
+       }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function keyDownHandler(event:KeyboardEvent):void
+    {
+        // If tab pressed in editor, it'll skip here and go to the keyFocusChangeHandler.
+        if (itemEditorInstance || event.target != event.currentTarget)
+            return;
+
+        if (isOpening)
+        {
+            event.stopImmediatePropagation();
+            return;
+        }
+
+        if (_rootModel is IHierarchicalData) // tree model/view
+        {
+            // If tree navigation couldn't handle the event, continue looking for a handler.
+            if (treeNavigationHandler(event))
+                return;
+        }
+
+        if (isCellSelectionMode() && headerIndex == -1 && event.keyCode != Keyboard.ESCAPE)
+            cellNavigationHandler(event);
+        else
+            super.keyDownHandler(event);
+
+        if (isRowSelectionMode())
+            updateSelectedCells();
+    }
+
+    /**
+     *  @private
+     */
+    override protected function keyUpHandler(event:KeyboardEvent):void
+    {
+        if (isKeyPressed && columnGrouping)
+        {
+            isKeyPressed = false;
+            if (selectedHeaderInfo != null)
+                selectColumnHeader(selectedHeaderInfo.column.colNum);
+        }
+        else
+        {
+            super.keyUpHandler(event);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function editorKeyDownHandler(event:KeyboardEvent):void
+    {
+        if (event.keyCode == Keyboard.F2)
+        {
+            // Save data and close editor
+            endEdit(AdvancedDataGridEventReason.OTHER);
+            setFocus();
+            invalidateDisplayList();
+        }
+
+        super.editorKeyDownHandler(event);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function mouseOutHandler(event:MouseEvent):void
+    {
+        // To handle case when mouse is at the border of the header item
+        // renderer. Ignoring prevents flickering of the highlight of the
+        // header because of infinite loop of mouseOver and mouseOut events.
+        if (event.target == listContent.getChildByName("headerBG"))
+            return;
+
+        if (tween)
+            return;
+
+        // mouse-out should remove the "proposed" numeric sort icon
+        if (!sortExpertMode)
+        {
+            var item:IListItemRenderer = mouseEventToItemRenderer(event);
+            if (item && item is IDropInListItemRenderer
+                    && isHeaderItemRenderer(item))
+            {
+                var colNum:int = IDropInListItemRenderer(item).listData.columnIndex;
+                delete visualSortInfo[colNum];
+                delete visualSortInfo["HEADERPART" + colNum];
+                invalidateRenderer(item);
+            }
+        }
+
+        super.mouseOutHandler(event);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function mouseOverHandler(event:MouseEvent):void
+    {
+        if (tween)
+            return;
+
+        if (movingColumn)
+            return;
+
+        if (!enabled || !selectable)
+            return;
+
+        var item:IListItemRenderer = mouseEventToItemRenderer(event);
+
+        if (!sortExpertMode)
+        {
+            // Mouseover should display a "proposed" numeric sort icon
+            var dropInItem:IDropInListItemRenderer;
+            if (item)
+                dropInItem = item as IDropInListItemRenderer;
+            else
+                // we're no longer hovering over any headers, so remove the proposed sorts
+                visualSortInfo = new Dictionary();
+
+            var colNum:int;
+            if (dropInItem && dropInItem.listData)
+                colNum = dropInItem.listData.columnIndex;
+            if (dropInItem
+                    && isHeaderItemRenderer(item)
+                    && sortableColumns
+                    && colNum != -1
+                    && columns[colNum].sortable
+                    && Object(item).hasOwnProperty("mouseEventToHeaderPart") )
+            {
+                var headerPart:String = Object(item).mouseEventToHeaderPart(event);
+
+                if (!visualSortInfo[colNum] || visualSortInfo["HEADERPART" + colNum] != headerPart)
+                {
+                    if (headerPart == HEADER_TEXT_PART)
+                    {
+                        visualSortInfo[colNum] = new SortInfo(1, false, SortInfo.PROPOSEDSORT);
+                        invalidateRenderer(item);
+                        visualSortInfo["HEADERPART" + colNum] = headerPart;
+                    }
+                    else if (headerPart == HEADER_ICON_PART)
+                    {
+                        var sequenceNumber:int;
+                        var descending:Boolean;
+                        var sortInfo:SortInfo = getFieldSortInfo(columns[colNum]);
+                        if (sortInfo)
+                        {
+                            sequenceNumber = sortInfo.sequenceNumber;
+                            // we want to show the proposed sort
+                            // which will always be opposite of the present sort
+                            descending     = !sortInfo.descending;
+                        }
+                        else if (collection && collection.sort && collection.sort.fields
+                                && collection.sort.fields.length)
+                        {
+                            sequenceNumber = collection.sort.fields.length + 1;
+                            descending     = false;
+                        }
+                        else
+                        {
+                            sequenceNumber = 1;
+                            descending = false;
+                        }
+
+                        visualSortInfo[colNum] = new SortInfo(sequenceNumber, descending,
+                                                                SortInfo.PROPOSEDSORT);
+                        invalidateRenderer(item);
+                        visualSortInfo["HEADERPART" + colNum] = headerPart;
+                    }
+                }
+            }
+        }
+
+        if (item && !isHeaderItemRenderer(item) && isCellSelectionMode())
+        {
+            // Copied from ListBase.mouseOverHandler()
+            var evt:ListEvent;
+
+            var pt:Point = itemRendererToIndices(item);
+            if (!pt)
+                return;
+            isPressed = event.buttonDown;
+            var columnIndex:int = displayToAbsoluteColumnIndex(pt.x);
+
+            if (!isPressed || allowDragSelection)
+            {
+                if (getStyle("useRollOver") && (item.data != null))
+                {
+                    if (allowDragSelection)
+                        bSelectOnRelease = true;
+
+                    var uid:String = itemToUID(item.data);
+
+                    if (visibleCellRenderers[uid])
+                        drawCellItem(visibleCellRenderers[uid][columnIndex.toString()],
+                                     cellSelectionData[uid] &&
+                                     cellSelectionData[uid][columnIndex.toString()],
+                                     true,
+                                     uid == caretUID && columnIndex == caretColumnIndex);
+
+                    if (pt) // during tweens, we may get null
+                    {
+                        evt = new ListEvent(ListEvent.ITEM_ROLL_OVER);
+                        evt.columnIndex = pt.x;
+                        evt.rowIndex = pt.y;
+                        evt.itemRenderer = item;
+                        dispatchEvent(evt);
+                    }
+                }
+            }
+            else
+            {
+                if (DragManager.isDragging)
+                    return;
+
+                if ((/* dragScrollingInterval != 0 && */ allowDragSelection) || menuSelectionMode)
+                {
+                    if (selectCellItem(item, event.shiftKey, event.ctrlKey))
+                    {
+                        evt = new ListEvent(ListEvent.CHANGE);
+                        evt.itemRenderer = item;
+                        if (pt)
+                        {
+                            evt.columnIndex = pt.x;
+                            evt.rowIndex = pt.y;
+                        }
+                        dispatchEvent(evt);
+                    }
+                }
+            }
+        }
+        else
+        {
+            super.mouseOverHandler(event);
+        }
+    }
+
+    /**
+     *  @private
+     */
+    override protected function sortHandler(event:AdvancedDataGridEvent):void
+    {
+        if (event.isDefaultPrevented())
+            return;
+
+        if (!sortableColumns
+            || isNaN(event.columnIndex)
+            || event.columnIndex == -1
+            || !columns[event.columnIndex].sortable)
+            return;
+
+        if(columnGrouping)
+        {
+            var columnNumber:int  = event.columnIndex;
+            //In case it is a column number, skip, we can't sort a column group
+            if(isNaN(columnNumber) ||  columnNumber == -1)
+                return;
+
+            var headerInfo:AdvancedDataGridHeaderInfo = getHeaderInfo(columns[columnNumber]);
+            //If this is a leaf column and doesn't get data directly from the data row, but through internalLabelFunction
+            if(headerInfo.internalLabelFunction != null)
+                event.dataField = null;
+        }
+
+        // If navigating header via keyboard, and you mouse click on some
+        // other header to sort it, then move the keyboard navigation focus
+        // to that column header.
+        if (columnGrouping && selectedHeaderInfo != null)
+            selectedHeaderInfo = getHeaderInfo(columns[event.columnIndex]);
+
+        super.sortHandler(event);
+
+        if (isRowSelectionMode())
+            updateSelectedCells();
+    }
+
+    /**
+     *  @private
+     */
+    override protected function headerReleaseHandler(event:AdvancedDataGridEvent):void
+    {
+        if (event.isDefaultPrevented())
+            return;
+
+        if (itemEditorInstance)
+            endEdit(AdvancedDataGridEventReason.OTHER);
+
+        if (sortExpertMode)
+        {
+            super.headerReleaseHandler(event);
+            return;
+        }
+
+        var adgEvent:AdvancedDataGridEvent =
+            new AdvancedDataGridEvent(AdvancedDataGridEvent.SORT, false, true);
+
+        adgEvent.columnIndex     = event.columnIndex;
+        adgEvent.dataField       = event.dataField;
+        adgEvent.triggerEvent    = event.triggerEvent;
+        adgEvent.multiColumnSort = false;
+
+        if (!collection || !collection.sort || !collection.sort.fields
+            || !collection.sort.fields.length) // first sort
+        {
+            dispatchEvent(adgEvent);
+            return;
+        }
+
+        if (event.headerPart == HEADER_TEXT_PART)
+        {
+            dispatchEvent(adgEvent);
+        }
+        else if (event.headerPart == HEADER_ICON_PART)
+        {
+            adgEvent.multiColumnSort = true;
+            dispatchEvent(adgEvent);
+        }
+    }
+
+    /**
+     *  @private
+     *  Blocks mouse events on items that are tweening away and are invalid for input
+     */
+    override protected function mouseClickHandler(event:MouseEvent):void
+    {
+        if (!tween)
+            super.mouseClickHandler(event);
+    }
+
+    /**
+     *  @private
+     *  Blocks mouse events on items that are tweening away and are invalid for input
+     */
+    override protected function mouseDoubleClickHandler(event:MouseEvent):void
+    {
+        if (!tween)
+            super.mouseDoubleClickHandler(event);
+    }
+
+    /**
+     *  @private
+     */
+    override protected function mouseDownHandler(event:MouseEvent):void
+    {
+        if (!tween)
+        {
+            super.mouseDownHandler(event);
+            updateSelectedCells();
+        }
+    }
+
+    /**
+     *  @private
+     *  Blocks mouse events on items that are tweening away and are invalid for input
+     */
+    override protected function mouseUpHandler(event:MouseEvent):void
+    {
+        if (!tween)
+            super.mouseUpHandler(event);
+    }
+
+    /**
+     *  @private
+     *  Blocks mouse wheel handling while tween is running
+     */
+    override protected function mouseWheelHandler(event:MouseEvent):void
+    {
+        if (!tween)
+            super.mouseWheelHandler(event);
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Event handlers
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     * @private
+     */
+    mx_internal function expandItemHandler(event:AdvancedDataGridEvent):void
+    {
+        if (event.isDefaultPrevented())
+            return;
+
+        if (event.type == AdvancedDataGridEvent.ITEM_OPENING)
+        {
+            // store the item renderer
+            // it is needed while dispatching ITEM_OPEN/ ITEM_CLOSE event
+            eventItemRenderer = event.itemRenderer;
+            expandItem(event.item, event.opening, event.animate, event.dispatchEvent, event.triggerEvent);
+        }
+    }
+
+    /**
+     * @private
+     */
+    private function updateCompleteHandler(event:FlexEvent):void
+    {
+        // Are we running inside Flex Builder design view? Then set hard-coded data.
+        if (UIComponentGlobals.designTime)
+        {
+            if (!dataProvider ||
+                    ((dataProvider is ArrayCollection && !ArrayCollection(dataProvider).length) ||
+                    (dataProvider is IHierarchicalCollectionView && !IHierarchicalCollectionView(dataProvider).length)))
+            {
+                setDesignViewData();
+            }
+
+            if (designViewDataType == designViewDataTreeType
+                    && dataProvider
+                    && dataProvider is IHierarchicalCollectionView
+                    && (designViewDataFlag
+                        || !atLeastOneProperty(IHierarchicalCollectionView(collection).openNodes))
+                    )
+                    // set if openNodes is empty
+            {
+                // Open the first branch so that the designer can see
+                // how leaf nodes look like as well
+                IHierarchicalCollectionView(collection).openNodes
+                    = IHierarchicalCollectionView(dataProvider).createCursor().current;
+                invalidateProperties();
+                invalidateDisplayList();
+                designViewDataFlag = false;
+            }
+
+            if (designViewDataTypeChanged)
+            {
+                designViewDataTypeChanged = false; // Make sure we do this to avoid infinite loop
+                setDesignViewSort();
+            }
+        }
+    }
+
+    /**
+     *  Handler for keyboard navigation for the navigation tree.
+     *
+     *  @param event The keyboard event.
+     *
+     *  @return true if the keyboard navigation is handled correctly.
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 9
+     *  @playerversion AIR 1.1
+     *  @productversion Flex 3
+     */
+    protected function treeNavigationHandler(event:KeyboardEvent):Boolean
+    {
+        var evt:ListEvent;
+        var pt:Point;
+
+        // In cell selection mode, caretColumnIndex is valid.
+        // In row selection mode, caretColumnIndex is -1, so we should use 0 since the
+        // branch node item renderer is in the zeroeth column always.
+        var visibleCoords:Object = absoluteToVisibleIndices(caretIndex,
+                                        caretColumnIndex != -1 ? caretColumnIndex : 0);
+        var visibleRowIndex:int = visibleCoords.rowIndex;
+        var visibleColIndex:int = visibleCoords.columnIndex;
+        var item:Object;
+        if (listItems[visibleRowIndex] && listItems[visibleRowIndex][visibleColIndex])
+            item = listItems[visibleRowIndex][visibleColIndex].data;
+        if (!item)
+            return false;
+
+        var treeItemRenderer:IListItemRenderer;
+
+        // get the item renderer to be passed in the ITEM_OPENING events
+        if (listItems[visibleRowIndex])
+            treeItemRenderer = listItems[visibleRowIndex][treeColumnIndex];
+
+        if (event.ctrlKey && event.shiftKey && event.keyCode == Keyboard.SPACE)
+        {
+            // if user has moved the caret cursor from the selected item
+            // move the cursor back to selected item
+            if (caretIndex != selectedIndex)
+            {
+                // erase the caret
+                var renderer:IListItemRenderer = indexToItemRenderer(caretIndex);
+                if (renderer)
+                    drawItem(renderer);
+                caretIndex = selectedIndex;
+            }
+
+            // Spacebar toggles the current open/closed status. No effect for leaf items.
+            if (isBranch(item))
+            {
+                var o:Boolean = !isItemOpen(item);
+                dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPENING,
+                                              item,   //item
+                                              treeItemRenderer,   //renderer
+                                              event,  //trigger
+                                              o,      //opening
+                                              true,   //animate
+                                              true);  //dispatch
+            }
+            event.stopImmediatePropagation();
+        }
+        else if (event.ctrlKey && event.shiftKey && event.keyCode == Keyboard.LEFT)
+        {
+            // Left Arrow closes an open item. Otherwise selects the parent item.
+            if (isItemOpen(item))
+            {
+                dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPENING,
+                                              item,   //item
+                                              treeItemRenderer,   //renderer
+                                              event,  //trigger
+                                              false,  //opening
+                                              true,   //animate
+                                              true)   //dispatch
+                    }
+            else
+            {
+                selectedItem = getParentItem(item);
+                evt = new ListEvent(ListEvent.CHANGE);
+                evt.itemRenderer = indexToItemRenderer(selectedIndex);
+                pt = itemRendererToIndices(evt.itemRenderer);
+                if (pt)
+                {
+                    evt.rowIndex = pt.y;
+                    evt.columnIndex = pt.x;
+                }
+                dispatchEvent(evt);
+                var dI:int = getItemIndex(selectedItem);
+                if (dI != caretIndex)
+                {
+                    caretIndex = selectedIndex;
+                }
+                if (dI < _verticalScrollPosition)
+                {
+                    verticalScrollPosition = dI;
+                }
+
+            }
+            event.stopImmediatePropagation();
+        }
+        else if (event.ctrlKey && event.shiftKey && event.keyCode == Keyboard.RIGHT)
+        {
+            // Right Arrow has no effect on leaf items. Closed branch items are opened.
+            //Opened branch items select the first child.
+            if (isBranch(item))
+            {
+                if (isItemOpen(item))
+                {
+                    if (item)
+                    {
+                        var children:ICollectionView = getChildren(item, iterator.view);
+                        if (children)
+                        {
+                            var cursor:IViewCursor  = children.createCursor();
+                            selectedItem = cursor.current;
+                        }
+                    }
+                    else
+                    {
+                        selectedItem = null;
+                    }
+                    if (caretIndex != selectedIndex)
+                        caretIndex = getItemIndex(selectedItem);
+                    evt = new ListEvent(ListEvent.CHANGE);
+                    evt.itemRenderer = indexToItemRenderer(selectedIndex);
+                    pt = itemRendererToIndices(evt.itemRenderer);
+                    if (pt)
+                    {
+                        evt.rowIndex = pt.y;
+                        evt.columnIndex = pt.x;
+                    }
+                    dispatchEvent(evt);
+                }
+                else
+                {
+                    dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPENING,
+                                                  item,   //item
+                                                  treeItemRenderer,   //renderer
+                                                  event,  //trigger
+                                                  true,   //opening
+                                                  true,   //animate
+                                                  true);  //dispatch
+                }
+
+            }
+            event.stopImmediatePropagation();
+        }
+        else if (event.keyCode == Keyboard.NUMPAD_MULTIPLY)
+        {
+            expandChildrenOf(item, !isItemOpen(item));
+        }
+        else if (event.keyCode == Keyboard.NUMPAD_ADD)
+        {
+            if (isBranch(item))
+            {
+                if (!isItemOpen(item))
+                {
+                    dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPENING,
+                                                  item,   //item
+                                                  treeItemRenderer,   //renderer
+                                                  event,  //trigger
+                                                  true,   //opening
+                                                  true,   //animate
+                                                  true);   //dispatch
+                }
+            }
+        }
+        else if (event.keyCode == Keyboard.NUMPAD_SUBTRACT)
+        {
+            if (isItemOpen(item))
+            {
+                dispatchAdvancedDataGridEvent(AdvancedDataGridEvent.ITEM_OPENING,
+                                              item, //item
+                                              treeItemRenderer,   //renderer
+                                              event,  //trigger
+                                              false,  //opening
+                                              true,   //animate
+                                              true);   //dispatch
+            }
+        }
+        else
+        {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     *  @private
+     *  Handle keyboard navigation in cell selection mode
+     *  i.e. selectionMode == SINGLE_CELL || selectionMode == MULTIPLE_CELLS
+     */
+    protected function cellNavigationHandler(event:KeyboardEvent):void
+    {
+        // Can't use a straight-forward Object/Dictionary
+        // because they don't allow integer keys.
+        const validKeys:Array = [
+            Keyboard.UP,
+            Keyboard.DOWN,
+            Keyboard.LEFT,
+            Keyboard.RIGHT,
+            Keyboard.SPACE,
+            Keyboard.HOME,
+            Keyboard.END,
+            Keyboard.PAGE_UP,
+            Keyboard.PAGE_DOWN,
+            Keyboard.F2
+            ];
+
+        var isValidKey:Boolean = false;
+        var n:int = validKeys.length;
+        for (var i:int = 0; i < n; i++)
+        {
+            if (event.keyCode == validKeys[i])
+            {
+                isValidKey = true;
+                break;
+            }
+        }
+
+        if (!isValidKey)
+        {
+            // Handles single-character type-ahead lookup for data in the rows.
+            if (findKey(event.keyCode))
+                event.stopPropagation();
+
+            return;
+        }
+
+        var bUpdateHorizontalScrollPosition:Boolean = false;
+        var bUpdateVerticalScrollPosition:Boolean   = false;
+        var newVerticalScrollPosition:Number;
+        var newHorizontalScrollPosition:Number;
+        var maxPosition:int;
+
+        var rowCount:int = listItems.length;
+        if (rowCount == 0)
+            return;
+
+        var partialRow:int = 0;
+        if (rowInfo[rowCount - 1].y +
+            rowInfo[rowCount - 1].height > listContent.height)
+        {
+            partialRow++;
+        }
+
+        showCaret   = true;
+        bSelectItem = false;
+
+        var newCaretColumnIndex:int;
+
+        switch (event.keyCode)
+        {
+            case Keyboard.UP:
+            {
+                if (caretIndex == 0 && selectedIndex == 0 && headerVisible
+                    && !event.ctrlKey && !event.shiftKey) // move to header
+                {
+                    var oldCaretColumnIndex:int = caretColumnIndex;
+                    clearSelectedCells();
+                    moveFocusToHeader(oldCaretColumnIndex);
+                }
+                else if (caretIndex > 0)
+                {
+                    // if the first column of the column span is hidden from view,
+                    // then we move to the first visible column
+                    if (visibleColumns.length > 0 && visibleColumns[0].colNum > caretColumnIndex)
+                        caretColumnIndex = visibleColumns[0].colNum;
+                    caretIndex--;
+                    bUpdateVerticalScrollPosition = true;
+                    bSelectItem = true;
+                }
+                break;
+            }
+
+            case Keyboard.DOWN:
+            {
+                if (caretIndex < collection.length - 1)
+                {
+                    caretIndex++;
+                    // When focus is on ADG and down arrow is pressed, focus
+                    // should go to the first visible cell
+                    if (caretIndex == 0)
+                        caretColumnIndex = 0;
+                     // if the first column of the column span is hidden from view,
+                    // then we move to the first visible column
+                    else if (visibleColumns.length > 0 && visibleColumns[0].colNum > caretColumnIndex)
+                        caretColumnIndex = visibleColumns[0].colNum;
+
+                    bUpdateVerticalScrollPosition = true;
+                    bSelectItem = true;
+                }
+                else if ( (caretIndex == collection.length - 1) && partialRow )
+                {
+                    if (verticalScrollPosition < maxVerticalScrollPosition)
+                        newVerticalScrollPosition = verticalScrollPosition + 1;
+                }
+                break;
+            }
+
+            case Keyboard.LEFT:
+            {
+                newCaretColumnIndex =
+                    viewDisplayableColumnAtOffset(caretColumnIndex, -1, caretIndex);
+                if (newCaretColumnIndex != -1)
+                {
+                    caretColumnIndex = newCaretColumnIndex;
+                    bSelectItem = true;
+                }
+                break;
+            }
+
+            case Keyboard.RIGHT:
+            {
+                newCaretColumnIndex =
+                    viewDisplayableColumnAtOffset(caretColumnIndex, +1, caretIndex);
+                if (newCaretColumnIndex != -1)
+                {
+                    caretColumnIndex = newCaretColumnIndex;
+                    bSelectItem = true;
+                }
+                break;
+            }
+
+            case Keyboard.SPACE:
+            {
+                // ctrl-space selects (and unselects) item
+                bSelectItem = event.ctrlKey;
+                break;
+            }
+
+            case Keyboard.HOME:
+            case Keyboard.END:
+            case Keyboard.PAGE_UP:
+            case Keyboard.PAGE_DOWN:
+            {
+                moveSelectionVertically(event.keyCode, event.shiftKey, event.ctrlKey);
+                break;
+            }
+
+            case Keyboard.F2:
+            {
+                if (caretColumnIndex != -1)
+                {
+                    var newData:Object = rowNumberToData(caretIndex);
+                    if (newData && isDataEditable(newData) && displayableColumns[caretColumnIndex].editable)
+                    {
+                        // Open editor
+                        var advancedDataGridEvent:AdvancedDataGridEvent
+                                = new AdvancedDataGridEvent(
+                                        AdvancedDataGridEvent.ITEM_EDIT_BEGINNING,
+                                                        false, true);
+                        // ITEM_EDIT events are cancelable
+                        advancedDataGridEvent.columnIndex = caretColumnIndex;
+                        advancedDataGridEvent.dataField = columns[caretColumnIndex].dataField;
+                        advancedDataGridEvent.rowIndex = caretIndex;
+
+                        var visibleCoords:Object
+                            = absoluteToVisibleIndices(caretIndex, caretColumnIndex);
+                        var visibleRowIndex:int = visibleCoords.rowIndex;
+                        var visibleColIndex:int = visibleCoords.columnIndex;
+                        advancedDataGridEvent.itemRenderer
+                            = listItems[visibleRowIndex][visibleColIndex];
+                        dispatchEvent(advancedDataGridEvent);
+                    }
+                }
+                break;
+            }
+        }
+
+        event.stopPropagation();
+
+        if (bUpdateVerticalScrollPosition)
+        {
+            if (caretIndex < lockedRowCount)
+            {
+                newVerticalScrollPosition = 0;
+            }
+            else if (caretIndex < verticalScrollPosition + lockedRowCount)
+            {
+                newVerticalScrollPosition = caretIndex - lockedRowCount;
+            }
+            else if (caretIndex >= verticalScrollPosition + rowCount - partialRow)
+            {
+                newVerticalScrollPosition = Math.min(maxVerticalScrollPosition,
+                                                     caretIndex - rowCount + partialRow + 1);
+            }
+
+            if (!isNaN(newVerticalScrollPosition))
+            {
+                if (verticalScrollPosition != newVerticalScrollPosition)
+                {
+                    var se:ScrollEvent     = new ScrollEvent(ScrollEvent.SCROLL);
+                    se.detail              = ScrollEventDetail.THUMB_POSITION;
+                    se.direction           = ScrollEventDirection.VERTICAL;
+                    se.delta               = newVerticalScrollPosition - verticalScrollPosition;
+                    se.position            = newVerticalScrollPosition;
+                    verticalScrollPosition = newVerticalScrollPosition;
+                    dispatchEvent(se);
+                }
+
+                // bail if we page faulted
+                if (!iteratorValid)
+                {
+                    keySelectionPending = true;
+                    return;
+                }
+            }
+        }
+
+        bShiftKey = event.shiftKey;
+        bCtrlKey  = event.ctrlKey;
+        lastKey   = event.keyCode;
+
+        finishCellKeySelection();
+    }
+}
+
+}