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

import flash.geom.Point;
import flash.geom.Rectangle;

import mx.core.IFactory;
import mx.core.IVisualElement;
import mx.core.mx_internal;

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