incubator-flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cframp...@apache.org
Subject svn commit: r1370028 [35/43] - in /incubator/flex/whiteboard/cframpton/adobe.next: ./ frameworks/ frameworks/projects/advancedgrids/src/mx/collections/ frameworks/projects/advancedgrids/src/mx/controls/ frameworks/projects/airframework/src/mx/managers/...
Date Mon, 06 Aug 2012 21:26:02 GMT
Modified: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/DataGridEditor.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/DataGridEditor.as?rev=1370028&r1=1370027&r2=1370028&view=diff
==============================================================================
--- incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/DataGridEditor.as (original)
+++ incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/DataGridEditor.as Mon Aug  6 21:25:54 2012
@@ -50,6 +50,7 @@ import mx.styles.ISimpleStyleClient;
 
 import spark.components.DataGrid;
 import spark.components.Grid;
+import spark.components.gridClasses.GridItemEditorActivationMouseEvent;
 import spark.events.GridEvent;
 import spark.events.GridItemEditorEvent;
 
@@ -833,9 +834,11 @@ public class DataGridEditor
      *  by calling the item editor's save() method.  If the cancel parameter is true,
      *  then the editor's cancel() method is called instead.
      * 
-     *  @param cancel If false the data in the editor is saved. 
-     *  Otherwise the data in the editor is discarded.
-     *
+     *  @param cancel if true then the data in the editor is discarded, 
+     *  otherwise it's saved.
+     * 
+     *  @return true if the data in the editor was saved, false otherwise.
+     * 
      *  @see spark.components.IGridItemEditor
      *  
      *  @langversion 3.0
@@ -861,13 +864,20 @@ public class DataGridEditor
      * 
      *  Close the item editor without saving the data.
      */
-    mx_internal function cancelEdit():void
+    mx_internal function cancelEdit():Boolean
     {
         if (itemEditorInstance)
         {
-            // send the cancel event and tear down the editor.
-            dispatchCancelEvent();
-            destroyItemEditor();
+            if (itemEditorInstance.cancel())
+            {
+                // send the cancel event and tear down the editor.
+                dispatchCancelEvent();
+                destroyItemEditor();
+            }
+            else
+            {
+                return false;
+            }
         }
         else if (editedItemRenderer)
         {
@@ -875,6 +885,8 @@ public class DataGridEditor
             destroyItemEditor();
         }
 
+        return true;                   
+
     }
 
     
@@ -922,16 +934,19 @@ public class DataGridEditor
         var itemPosition:Object = editedItemPosition;
         if (!saveItemEditorSession())
         {
-            // the save was cancelled so dispatch a cancel event.
-            dispatchCancelEvent();
+            // The save was cancelled so check if the editor can be cancelled.
+            // If it can then dispatch a cancel event.
+            if (itemEditorInstance.cancel())
+                dispatchCancelEvent();
+            
             inEndEdit = false;
             return false;
         }
         
         var dataGridEvent:GridItemEditorEvent =
-            new GridItemEditorEvent(GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_SAVE, false, true);
+            new GridItemEditorEvent(GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_SAVE);
         
-        // SAVE_GRID_ITEM_EDITOR_SESSION events are cancelable
+        // GRID_ITEM_EDITOR_SESSION_SAVE events are NOT cancelable
         dataGridEvent.columnIndex = itemPosition.columnIndex;
         dataGridEvent.column = dataGrid.columns.getItemAt(itemPosition.columnIndex) as GridColumn;
         dataGridEvent.rowIndex = itemPosition.rowIndex;
@@ -1199,6 +1214,29 @@ public class DataGridEditor
 
     }
     
+    /**
+     *  @private
+     * 
+     *  Get the effective mouse event that activates an editor.
+     *  If the column has a setting, then use it. Otherwise use the setting on
+     *  the data grid.
+     */ 
+    private function getEditorActivationMouseEvent(columnIndex:int):String
+    {
+        var editorActivationMouseEvent:String = null;
+        
+        if (columnIndex >= 0 && columnIndex < dataGrid.columns.length)
+        {
+            var column:GridColumn = grid.columns.getItemAt(columnIndex) as GridColumn; 
+            editorActivationMouseEvent = column.editorActivationMouseEvent;    
+        }
+        
+        if (!editorActivationMouseEvent)
+            editorActivationMouseEvent = dataGrid.editorActivationMouseEvent;
+        
+        return editorActivationMouseEvent;
+    }
+    
     //--------------------------------------------------------------------------
     //
     //  Event handlers
@@ -1313,12 +1351,22 @@ public class DataGridEditor
             return;
         }
         
+        var editorActivationMouseEvent:String = getEditorActivationMouseEvent(columnIndex);
+        if (editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK && 
+            editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK_ON_SELECTED_CELL)
+        {
+            return;     // not allowed to start editor on a single click
+        }
+        
         // Don't open and editor if the click was not on a previously selected 
         // cell, unless that cell is an item renderer. We don't want to stop 
         // the item renderer from getting focus so start an edit session.
         const column:GridColumn = dataGrid.columns.getItemAt(columnIndex) as GridColumn;
         if (r && 
-            (column.rendererIsEditable || wasCellPreviouslySelected(rowIndex, columnIndex)))
+            (column.rendererIsEditable || 
+             (wasCellPreviouslySelected(rowIndex, columnIndex) && 
+                 editorActivationMouseEvent == GridItemEditorActivationMouseEvent.SINGLE_CLICK_ON_SELECTED_CELL) ||
+             editorActivationMouseEvent == GridItemEditorActivationMouseEvent.SINGLE_CLICK))
         {
             //trace("cell was previously selected: (" + rowIndex + "," + columnIndex + ")");  
             lastItemDown = r;
@@ -1354,6 +1402,13 @@ public class DataGridEditor
         const rowIndex:int = eventRowIndex;
         var columnIndex:int = eventColumnIndex;
         
+        var editorActivationMouseEvent:String = getEditorActivationMouseEvent(columnIndex);
+        if (editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK && 
+            editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK_ON_SELECTED_CELL)
+        {
+            return;     // not allowed to start editor on a single click
+        }
+        
         var r:IVisualElement = event.itemRenderer;
         //trace("grid_gridMouseUpHandler: itemRenderer = " + event.itemRenderer);  
         if (r && r != editedItemRenderer && 
@@ -1424,6 +1479,12 @@ public class DataGridEditor
         lastEvent = event;
         
         gotDoubleClickEvent = true;
+        
+        // If double-click editing is enabled then start up and editor session.
+        var editorActivationMouseEvent:String = getEditorActivationMouseEvent(event.columnIndex);
+        if (editorActivationMouseEvent == GridItemEditorActivationMouseEvent.DOUBLE_CLICK)
+            dataGrid.startItemEditorSession(event.rowIndex, event.columnIndex);
+            
     }
     
     /**
@@ -1674,9 +1735,10 @@ public class DataGridEditor
             dataGrid.endItemEditorSession(true);
         }
         
-        // set focus back to the grid so grid logic will deal if focus doesn't
-        // end up somewhere else
-        dataGrid.setFocus();
+        // If the item editor was destroyed then set focus back to the grid 
+        // so grid logic will deal if focus doesn't end up somewhere else. 
+        if (!itemEditorInstance)
+            dataGrid.setFocus();
     }
    
 }

Modified: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridColumn.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridColumn.as?rev=1370028&r1=1370027&r2=1370028&view=diff
==============================================================================
--- incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridColumn.as (original)
+++ incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridColumn.as Mon Aug  6 21:25:54 2012
@@ -553,6 +553,8 @@ public class GridColumn extends EventDis
      *  pressing the F2 key.
      *
      *  @default true
+     * 
+     *  @see spark.components.DataGrid#editable
      *  
      *  @langversion 3.0
      *  @playerversion Flash 10
@@ -577,6 +579,48 @@ public class GridColumn extends EventDis
     }
     
     //----------------------------------
+    //  editorActivationMouseEvent
+    //----------------------------------
+    
+    private var _editorActivationMouseEvent:String = null;
+    
+    [Bindable("editorActivationMouseEventChanged")]
+    [Inspectable(category="General", enumeration="doubleClick,none,singleClick,singleClickOnSelectedCell", defaultValue="singleClickOnSelectedCell")]
+
+    /**
+     *  The type of mouse event that starts an editor session. Must be one of
+     *  values in <code>GridItemEditorMouseEvent</code>. Each grid
+     *  column may use a different value for cell activation. If no
+     *  value is specified the DataGrid's <code>editorActivationMouseEvent
+     *  </code> will be used.
+     *       
+     *  @default null
+     * 
+     *  @see spark.components.DataGrid
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 11
+     *  @playerversion AIR 3.0
+     *  @productversion Flex 5.0
+     */
+    public function get editorActivationMouseEvent():String
+    {
+        return _editorActivationMouseEvent;
+    }
+    
+    /**
+     *  @private
+     */
+    public function set editorActivationMouseEvent(value:String):void
+    {
+        if (_editorActivationMouseEvent == value)
+            return;
+        
+        _editorActivationMouseEvent = value;
+        dispatchChangeEvent("editorActivationMouseEventChanged");
+    }
+    
+    //----------------------------------
     //  formatter
     //----------------------------------
     

Modified: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as?rev=1370028&r1=1370027&r2=1370028&view=diff
==============================================================================
--- incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as (original)
+++ incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensions.as Mon Aug  6 21:25:54 2012
@@ -31,9 +31,11 @@ import mx.events.PropertyChangeEvent;
 /**
  *  A sparse data structure that represents the widths and heights of a grid.
  *  
- *  Provides efficient support for finding the cumulative y distance to the
+ *  <p>Provides efficient support for finding the cumulative y distance to the
  *  start of a particular cell as well as finding the index of a particular
  *  cell at a certain y value.
+ *  GridDimensions optimizes these operations by bookmarking the most recently
+ *  visited rows.</p>
  * 
  *  @langversion 3.0
  *  @playerversion Flash 10
@@ -156,9 +158,12 @@ public class GridDimensions 
     private var rowList:GridRowList = new GridRowList();
     private var _columnWidths:Vector.<Number> = new Vector.<Number>();
 
-    //cache for cumulative y values.
+    // Bookmark recently visited rows by caching the node representing the row
+    // and the y-value corresponding to the start of the node.
+    // startY/recentNode is the bookmark used by getRowIndexAt()
     private var startY:Number = 0;
     private var recentNode:GridRowNode = null;
+    // startY2/recentNode2 is bookmark used by getCellY()
     private var startY2:Number = 0;
     private var recentNode2:GridRowNode = null;
     
@@ -302,10 +307,8 @@ public class GridDimensions 
             return;
         
         _rowGap = value;
-        
-        // reset recent node.
-        recentNode = null;
-        recentNode2 = null;
+
+        clearCachedNodes();
     }
     
     //----------------------------------
@@ -338,10 +341,8 @@ public class GridDimensions 
             return;
         
         _columnGap = value;
-        
-        // reset recent node.
-        recentNode = null;
-        recentNode2 = null;
+
+        clearCachedNodes();
     }
     
     //----------------------------------
@@ -382,15 +383,15 @@ public class GridDimensions 
         _defaultRowHeight = bound(value, _minRowHeight, _maxRowHeight);
         useMaxTypicalCellHeight = isNaN(_defaultRowHeight);
         
-        // reset recent node.
-        recentNode = null;
-        recentNode2 = null;
+        clearCachedNodes();
     }
     
     //----------------------------------
     //  defaultColumnWidth
     //----------------------------------
     
+    private var _defaultColumnWidth:Number = 150;
+    
     /**
      *  The default width of a column.
      *  If this changes, update the ASDoc for GridLayout/getItemRendererAt().
@@ -400,12 +401,28 @@ public class GridDimensions 
      *  @playerversion AIR 2.0
      *  @productversion Flex 4.5
      */
-    public var defaultColumnWidth:Number = 150;
+    public function get defaultColumnWidth():Number
+    {
+        return _defaultColumnWidth;
+    }
+    
+    /**
+     *  @private
+     */
+    public function set defaultColumnWidth(value:Number):void
+    {
+        if (value == _defaultColumnWidth)
+            return;
+        
+        _defaultColumnWidth = value;
+    }    
     
     //----------------------------------
     //  variableRowHeight
     //----------------------------------
     
+    private var _variableRowHeight:Boolean = false;  // default value must match Grid property default value
+    
     /**
      *  If variableRowHeight is false, calling getRowHeight
      *  will return the value of defaultRowHeight.
@@ -415,7 +432,21 @@ public class GridDimensions 
      *  @playerversion AIR 2.0
      *  @productversion Flex 4.5
      */
-    public var variableRowHeight:Boolean = false;  // default value must match Grid property default value
+    public function get variableRowHeight():Boolean
+    {
+        return _variableRowHeight;
+    }
+    
+    /**
+     *  @private
+     */
+    public function set variableRowHeight(value:Boolean):void
+    {
+        if (value == _variableRowHeight)
+            return;
+        
+        _variableRowHeight = value;
+    }       
     
     //----------------------------------
     //  minRowHeight
@@ -490,6 +521,20 @@ public class GridDimensions 
     //--------------------------------------------------------------------------
 
     /**
+     *  Clears bookmarked nodes.
+     *  Each bookmarked node is associated with a cumulative y-value representing
+     *  the total height of the grid up to the start of the row.
+     *  These values are cleared as well.
+     */
+    private function clearCachedNodes():void
+    {
+        recentNode = null;
+        startY = 0;
+        recentNode2 = null;
+        startY2 = 0;
+    }
+    
+    /**
      *  Returns the height of the row at the given index. If variableRowHeight
      *  is true, then the height in precendence order is: the height set by setRowHeight,
      *  the natural height of the row (determined by the maximum of its cell heights),
@@ -551,6 +596,8 @@ public class GridDimensions 
             if (node)
                 node.fixedHeight = bound(height, minRowHeight, maxRowHeight);
         }
+        
+        clearCachedNodes();
     }
 
     /**
@@ -762,11 +809,11 @@ public class GridDimensions 
             
             // subtract previous node's height and its gap.
             indDiff = node.rowIndex - prevNode.rowIndex - 1;
-            currentY = currentY - indDiff * (defaultRowHeight + rowGap) - (prevNode.maxCellHeight + rowGap);
+            currentY = currentY - indDiff * (defaultRowHeight + rowGap) - (getRowHeight(prevNode.rowIndex) + rowGap);
             nodeY = currentY;
             node = prevNode;
         }
-
+        
         this.recentNode2 = node;
         this.startY2 = nodeY;
         
@@ -797,13 +844,14 @@ public class GridDimensions 
         {
             if (node.rowIndex == row)
                 break;
-            
-            currentY += node.maxCellHeight;
+
+            // add next row's height and rowGap
+            currentY += getRowHeight(node.rowIndex);
             if (node.rowIndex < _rowCount - 1)
                 currentY += rowGap;
             
             nextNode = node.next;
-
+            
             if (!nextNode || (row > node.rowIndex && row < nextNode.rowIndex))
             {
                 // at the beginning or somewhere between nodes
@@ -813,7 +861,7 @@ public class GridDimensions 
                 break;
             }
             
-            // add next node's maxCellHeight and rowGap
+            // add estimated heights of rows in between measured rows.
             indDiff = nextNode.rowIndex - node.rowIndex - 1;
             currentY = currentY + indDiff * (defaultRowHeight + rowGap);
             nodeY = currentY; 
@@ -966,7 +1014,7 @@ public class GridDimensions 
      */
     private function isYInRow(y:Number, startY:Number, node:GridRowNode):Boolean
     {
-        var end:Number = startY + node.maxCellHeight;
+        var end:Number = startY + getRowHeight(node.rowIndex);
         
         // don't add gap for last row.
         if (node.rowIndex != rowCount - 1)
@@ -1031,7 +1079,7 @@ public class GridDimensions 
             }
 
             // subtract previous node's height and its gap.
-            currentY = prevY - prevNode.maxCellHeight - rowGap;
+            currentY = prevY - getRowHeight(prevNode.rowIndex) - rowGap;
             node = node.prev;
             index = node.rowIndex;
         }
@@ -1070,7 +1118,7 @@ public class GridDimensions 
                 break;
             
             // currentY increments to end of the current node.
-            currentY += node.maxCellHeight;
+            currentY += getRowHeight(node.rowIndex);
             if (node.rowIndex != rowCount - 1)
                 currentY += rowGap;
             
@@ -1152,7 +1200,7 @@ public class GridDimensions 
             
             cur -= temp + columnGap;
 
-            if (cur <= 0)
+            if (cur < 0)
                 return i;
         }
         
@@ -1169,28 +1217,27 @@ public class GridDimensions 
      *  @playerversion AIR 2.0
      *  @productversion Flex 4.5
      */
-    public function getContentWidth(columnCountOverride:int = -1):Number
+    public function getContentWidth(columnCountOverride:int = -1, startColumnIndex:int = 0):Number
     {
-		const nCols:int = (columnCountOverride == -1) ? _columnCount : columnCountOverride;
+        const nCols:int = (columnCountOverride == -1) ? columnCount - startColumnIndex : columnCountOverride;
         var contentWidth:Number = 0;
-        var width:Number;
         var measuredColCount:int = 0;
         
-        for (var i:int = 0; (i < _columnCount) && (measuredColCount < nCols); i++)
+        for (var columnIndex:int = startColumnIndex; (columnIndex < columnCount) && (measuredColCount < nCols); columnIndex++)
         {
-            if (i >= _columnWidths.length)
+            if (columnIndex >= _columnWidths.length)
             {
                 contentWidth += defaultColumnWidth;
                 measuredColCount++;
                 continue;
             }
             
-            width = _columnWidths[i];
+            var width:Number = _columnWidths[columnIndex];
             
             // fall back on typical width
             if (isNaN(width))
             {
-                width = typicalCellWidths[i];
+                width = typicalCellWidths[columnIndex];
                 // column.visible==false, skip this column.
                 if (width == 0)
                     continue;
@@ -1204,15 +1251,15 @@ public class GridDimensions 
             measuredColCount++;
         }
         
-        if (nCols > 1)
-            contentWidth += (nCols - 1) * columnGap;
+        if (measuredColCount > 1)
+            contentWidth += (measuredColCount - 1) * columnGap;
         
         return contentWidth;
     }
     
     /**
      *  Returns the total layout height of the content including gaps.  If 
-	 *  rowHeightOverride is specified, then the overall height of as many rows
+	 *  rowCountOverride is specified, then the overall height of as many rows
 	 *  is returned.
      * 
      *  @langversion 3.0
@@ -1220,9 +1267,10 @@ public class GridDimensions 
      *  @playerversion AIR 2.0
      *  @productversion Flex 4.5
      */
-    public function getContentHeight(rowCountOverride:int = -1):Number
+    public function getContentHeight(rowCountOverride:int = -1, startRowIndex:int = 0):Number
     {
-		const nRows:int = (rowCountOverride == -1) ? rowCount : rowCountOverride;
+        const nRows:int = (rowCountOverride == -1) ? rowCount - startRowIndex : rowCountOverride;        
+        const maxRow:int = (rowCountOverride == -1) ? rowCount : startRowIndex + rowCountOverride;
 		var contentHeight:Number = 0;
         
         if (nRows > 1)
@@ -1231,12 +1279,14 @@ public class GridDimensions 
         if (!variableRowHeight || rowList.length == 0)
             return contentHeight + nRows * defaultRowHeight;
         
-        var node:GridRowNode = rowList.first;
+        var node:GridRowNode = (startRowIndex == 0) ? rowList.first : rowList.findNearestLTE(startRowIndex);
         var numRows:int = 0;
         
-        while (node && node.rowIndex < nRows)
+        while (node && node.rowIndex < maxRow)  
         {
-            contentHeight += node.maxCellHeight;
+            if (node.rowIndex < startRowIndex)
+                continue;
+            contentHeight += getRowHeight(node.rowIndex);
             numRows++;
             node = node.next;
         }
@@ -1256,16 +1306,16 @@ public class GridDimensions 
      *  @playerversion AIR 2.0
      *  @productversion Flex 4.5
      */
-    public function getTypicalContentWidth(columnCountOverride:int = -1):Number
+    public function getTypicalContentWidth(columnCountOverride:int = -1, startColumnIndex:int = 0):Number
     {
-        const nCols:int = (columnCountOverride == -1) ? _columnCount : columnCountOverride;
+        const nCols:int = (columnCountOverride == -1) ? columnCount - startColumnIndex : columnCountOverride;
         var contentWidth:Number = 0;
         var measuredColCount:int = 0;
         
-        for (var columnIndex:int = 0; (columnIndex < _columnCount) && (measuredColCount < nCols); columnIndex++)
+        for (var columnIndex:int = startColumnIndex; (columnIndex < columnCount) && (measuredColCount < nCols); columnIndex++)
         {
             // column.visible==false columns will have a typicalCellWidth of 0, so skip them.
-            var width:Number = columnIndex < _columnCount ? typicalCellWidths[columnIndex] : NaN;
+            var width:Number = columnIndex < columnCount ? typicalCellWidths[columnIndex] : NaN;
             if (width == 0)
                 continue;
             
@@ -1276,7 +1326,7 @@ public class GridDimensions 
             measuredColCount++;
         }
         
-        if (nCols > 1)
+        if (measuredColCount > 1)
             contentWidth += (measuredColCount - 1) * columnGap;
 
         return contentWidth;
@@ -1292,9 +1342,9 @@ public class GridDimensions 
      *  @playerversion AIR 2.0
      *  @productversion Flex 4.5
      */
-    public function getTypicalContentHeight(rowCountOverride:int = -1):Number
+    public function getTypicalContentHeight(rowCountOverride:int = -1, startRowIndex:int = 0):Number
     {
-        const nRows:int = (rowCountOverride == -1) ? rowCount : rowCountOverride;
+        const nRows:int = (rowCountOverride == -1) ? rowCount - startRowIndex : rowCountOverride;          
         var contentHeight:Number = 0;
         
         if (nRows > 1)
@@ -1487,9 +1537,8 @@ public class GridDimensions 
         typicalCellWidths.splice(startColumn, count);
         typicalCellHeights.splice(startColumn, count);
         
-        // cache is invalid because node values might have changed
-        recentNode = null;
-        recentNode2 = null;
+        // bookmarks are invalid because row heights may have changed.
+        clearCachedNodes();
     }
     
     /**
@@ -1520,9 +1569,8 @@ public class GridDimensions 
             rowList.removeNode(oldNode);
         }
         
-        // cache is invalid now.
-        recentNode = null;
-        recentNode2 = null;
+        // bookmarks are invalid because row heights may have changed.
+        clearCachedNodes();
     }
     
     /**
@@ -1545,9 +1593,8 @@ public class GridDimensions 
         clearVector(typicalCellHeights, NaN, startColumn, count);
         clearVector(_columnWidths, NaN, startColumn, count);
         
-        // cache is invalid because node values might have changed
-        recentNode = null;
-        recentNode2 = null;   
+        // bookmarks are invalid because row heights may have changed.
+        clearCachedNodes(); 
     }
         
     /**
@@ -1605,10 +1652,7 @@ public class GridDimensions 
     public function clearHeights():void
     {
         rowList.removeAll();
-        recentNode = null;
-        recentNode2 = null;
-        startY = 0;
-        startY2 = 0;
+        clearCachedNodes();
     }
     
     /**
@@ -1656,9 +1700,8 @@ public class GridDimensions 
         
         this.rowCount += count;
         
-        // cache is invalid now.
-        recentNode = null;
-        recentNode2 = null;
+        // bookmarks are invalid because row heights may have changed.
+        clearCachedNodes();
     }
     
     /**
@@ -1695,9 +1738,8 @@ public class GridDimensions 
         
         _rowCount -= count;
         
-        // cache is invalid now.
-        recentNode = null;
-        recentNode2 = null;
+        // bookmarks are invalid because row heights may have changed.
+        clearCachedNodes();
         return vec;
     }
     

Added: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as?rev=1370028&view=auto
==============================================================================
--- incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as (added)
+++ incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as Mon Aug  6 21:25:54 2012
@@ -0,0 +1,283 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.components.gridClasses
+{
+import flash.geom.Rectangle;
+
+[ExcludeClass]
+
+/**
+ *  A "view" of a rectangular region within a GridDimensions object.   The origin of the region
+ *  is specified by viewRowIndex,viewColumnIndex and the size of the region by viewRowCount and
+ *  viewColumnCount.
+ * 
+ *  Unless otherwise specified, all of the methods defined here have GridDimensionsView-relative 
+ *  parameters and similarly return values relative to the GridView's viewRow,ColumnIndex origin.
+ *  
+ *  All of the methods and properties defined here just delegate to GridDimensions 
+ *  methods with the same names and semantics.
+ * 
+ *  This class is internal to the Grid implementation.
+ *  
+ *  @langversion 3.0
+ *  @playerversion Flash 11
+ *  @playerversion AIR 3
+ *  @productversion Flex 5.0
+ */
+public class GridDimensionsView
+{
+    public var gridDimensions:GridDimensions = null;
+    public var viewRowIndex:int = 0;
+    public var viewColumnIndex:int = 0;
+    public var viewRowCount:int = -1;
+    public var viewColumnCount:int = -1;
+    
+    public function GridDimensionsView(gridDimensions:GridDimensions = null, 
+                                       viewRowIndex:int = 0, viewColumnIndex:int = 0, viewRowCount:int = -1, viewColumnCount:int = -1)
+    {
+        super();
+        this.gridDimensions = gridDimensions;
+        this.viewRowIndex = viewRowIndex;
+        this.viewColumnIndex = viewColumnIndex;
+        this.viewRowCount = viewRowCount;
+        this.viewColumnCount = viewColumnCount;
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------	
+    
+    public function get rowCount():int
+    {
+        const nRows:int = gridDimensions.rowCount;
+        return (viewRowCount == -1) ? nRows - viewRowIndex : viewRowCount;
+    }
+    
+    public function get columnCount():int
+    {
+        const nColumns:int = gridDimensions.columnCount;
+        return (viewColumnCount == -1) ? nColumns - viewColumnIndex : viewColumnCount;
+    }
+    
+    public function get rowGap():Number
+    {
+        return gridDimensions.rowGap;
+    }
+    
+    public function get columnGap():Number
+    {
+        return gridDimensions.columnGap;
+    } 
+    
+    public function get defaultRowHeight():Number
+    {
+        return gridDimensions.defaultRowHeight;
+    }
+    
+    public function get defaultColumnWidth():Number
+    {
+        return gridDimensions.defaultColumnWidth;
+    }
+    
+    public function get variableRowHeight():Boolean
+    {
+        return gridDimensions.variableRowHeight;
+    }
+    
+    public function get minRowHeight():Number
+    {
+        return gridDimensions.minRowHeight;
+    }
+    
+    public function get maxRowHeight():Number
+    {
+        return gridDimensions.maxRowHeight;
+    } 
+    
+    /** 
+     *  Return the Grid X coordinate of the GridDimensionView's viewRow,ColumnIndex origin.
+     */
+    public function get viewOriginX():Number
+    {
+        return gridDimensions.getCellX(viewRowIndex, viewColumnIndex);       
+    }
+    
+    /** 
+     *  Return the Grid Y coordinate of the GridDimensionView's viewRow,ColumnIndex origin.
+     */    
+    public function get viewOriginY():Number
+    {
+        return gridDimensions.getCellY(viewRowIndex, viewColumnIndex);         
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+    
+    public function getRowHeight(row:int):Number
+    {
+        return gridDimensions.getRowHeight(row + viewRowIndex);
+    }
+    
+    public function setRowHeight(row:int, height:Number):void
+    {
+        gridDimensions.setRowHeight(row + viewRowIndex, height);
+    }
+    
+    public function getColumnWidth(col:int):Number
+    {    
+        return gridDimensions.getColumnWidth(col + viewColumnIndex);
+    }
+    
+    public function setColumnWidth(col:int, width:Number):void
+    {
+        gridDimensions.setColumnWidth(col + viewColumnIndex, width);
+    }
+    
+    public function getCellHeight(row:int, col:int):Number
+    {
+        return gridDimensions.getCellHeight(row + viewRowIndex, col + viewColumnIndex);
+    }
+    
+    public function setCellHeight(row:int, col:int, height:Number):void
+    {
+        gridDimensions.setCellHeight(row + viewRowIndex, col + viewColumnIndex, height);
+    }
+    
+    public function getCellBounds(row:int, col:int):Rectangle
+    {
+        const bounds:Rectangle = gridDimensions.getCellBounds(row + viewRowIndex, col + viewColumnIndex);
+        if (!bounds)
+            return null;
+        
+        bounds.x -= viewOriginX;
+        bounds.y -= viewOriginY;
+        return bounds;
+    }
+    
+    public function getCellX(row:int, col:int):Number
+    {
+        return gridDimensions.getCellX(row + viewRowIndex, col + viewColumnIndex) - viewOriginX;
+    }
+    
+    public function getCellY(row:int, col:int):Number
+    {
+        return gridDimensions.getCellY(row + viewRowIndex, col + viewColumnIndex) - viewOriginY;
+    }
+    
+    public function getRowBounds(row:int):Rectangle
+    {
+        const bounds:Rectangle = gridDimensions.getRowBounds(row + viewRowIndex);
+        if (!bounds)
+            return null;
+        
+        bounds.x -= viewOriginX;
+        bounds.y -= viewOriginY;
+        return bounds;
+    }
+    
+    public function getPadRowBounds(row:int):Rectangle
+    {
+        const bounds:Rectangle = gridDimensions.getPadRowBounds(row + viewRowIndex);
+        if (!bounds)
+            return null;
+        
+        bounds.x -= viewOriginX;
+        bounds.y -= viewOriginY;
+        return bounds;
+    }
+    
+    public function getColumnBounds(col:int):Rectangle
+    {
+        const bounds:Rectangle = gridDimensions.getColumnBounds(col + viewColumnIndex);
+        if (!bounds)
+            return null;
+        
+        bounds.x -= viewOriginX;
+        bounds.y -= viewOriginY;
+        return bounds;
+    }
+    
+    public function getRowIndexAt(viewX:Number, viewY:Number):int
+    {
+        return gridDimensions.getRowIndexAt(viewX + viewOriginX, viewY + viewOriginY) - viewRowIndex;
+    }
+    
+    public function getColumnIndexAt(viewX:Number, viewY:Number):int
+    {
+        return gridDimensions.getColumnIndexAt(viewX + viewOriginX, viewY + viewOriginY) - viewColumnIndex;
+    }
+    
+    public function getContentWidth(columnCountOverride:int = -1, startColumnIndex:int = 0):Number
+    {
+        const nColumns:int = (columnCount== -1) ? viewColumnCount : columnCountOverride;        
+        return gridDimensions.getContentWidth(nColumns, viewColumnIndex + startColumnIndex);
+    }
+    
+    public function getContentHeight(rowCountOverride:int = -1, startRowIndex:int = 0):Number
+    {
+        const nRows:int = (rowCount== -1) ? viewRowCount : rowCountOverride;
+        return gridDimensions.getContentHeight(nRows, viewRowIndex + startRowIndex);
+    }
+    
+    public function getTypicalContentWidth(columnCountOverride:int = -1, startColumnIndex:int = 0):Number
+    {
+        const nColumns:int = (columnCount== -1) ? viewColumnCount : columnCountOverride;        
+        return gridDimensions.getTypicalContentWidth(nColumns, viewColumnIndex + startColumnIndex);
+    }
+    
+    public function getTypicalContentHeight(rowCountOverride:int = -1, startRowIndex:int = 0):Number
+    {
+        const nRows:int = (rowCount== -1) ? viewRowCount : rowCountOverride;        
+        return gridDimensions.getTypicalContentHeight(nRows, viewRowIndex + startRowIndex);
+    }
+    
+    public function getTypicalCellWidth(columnIndex:int):Number
+    {
+        return gridDimensions.getTypicalCellWidth(columnIndex + viewColumnIndex);
+    }
+    
+    public function setTypicalCellWidth(columnIndex:int, value:Number):void
+    {
+        gridDimensions.setTypicalCellWidth(columnIndex + viewColumnIndex, value);
+    }
+    
+    public function getTypicalCellHeight(columnIndex:int):Number
+    {
+        return gridDimensions.getTypicalCellHeight(columnIndex + viewColumnIndex);
+    }
+    
+    public function setTypicalCellHeight(columnIndex:int, value:Number):void
+    {
+        gridDimensions.setTypicalCellHeight(columnIndex + viewColumnIndex, value);
+    }
+    
+    public function toString():String
+    {
+        return "GridDimensionsView " + 
+            viewRowIndex + "," + viewColumnIndex + " " + viewRowCount + "X" + viewColumnCount + " " + 
+            gridDimensions.toString();
+    }
+}
+}
\ No newline at end of file

Propchange: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridDimensionsView.as
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderLayout.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderLayout.as?rev=1370028&view=auto
==============================================================================
--- incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderLayout.as (added)
+++ incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderLayout.as Mon Aug  6 21:25:54 2012
@@ -0,0 +1,219 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.components.gridClasses
+{
+import flash.events.Event;
+
+import spark.components.Grid;
+import spark.components.GridColumnHeaderGroup;
+import spark.components.Group;
+import spark.layouts.supportClasses.LayoutBase;
+
+//[ExcludeClass]  TBD
+
+/**
+ *  @private
+ *  The internal layout class used by GridColumnHeaderGroup.   Responsible for the 
+ *  the layout the left and center column header views.   There is no gap between the
+ *  two views however there are gaps between the overall left and right header view edges
+ *  defined by leftPadding and rightPadding.
+ * 
+ *  This class is private to the DataGrid implementation.  It's only used by the 
+ *  DataGrid's columnHeaderGroup skin part.
+ * 
+ *  This layout class is unusual because its updateDisplayList method depends on 
+ *  the results of laying out the DataGrid grid's columns, i.e. it depends on the 
+ *  the results of the Grid's layout.  The DataGrid forces the grid's nestLevel to 
+ *  be less than the nestLevel of its columnHeaderGroup to ensure that the grid
+ *  subtree is laid out first.
+ * 
+ *  This layout's measuredWidth is essentially zero because the DataGrid's grid
+ *  dictates the overall measured width.  The columnHeaderGroup only contributes
+ *  to the DataGrid's measured height.
+ */
+public class GridHeaderLayout extends LayoutBase
+{
+	public function GridHeaderLayout()
+	{
+		super();
+	}
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    //--------------------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    private function dispatchChangeEvent(type:String):void
+    {
+        if (hasEventListener(type))
+            dispatchEvent(new Event(type));
+    }
+    
+    //----------------------------------
+    //  centerGridColumnHeaderView
+    //----------------------------------
+    
+    private var _centerGridColumnHeaderView:Group = null; 
+    
+    [Bindable("centerGridColumnHeaderViewChanged")]
+    
+    /**
+     *  Contains the column headers for the Grid's centerGridView, the unlocked columns. 
+     * 
+     *  @default null
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 5.0
+     */
+    public function get centerGridColumnHeaderView():Group
+    {
+        return _centerGridColumnHeaderView;
+    }
+    
+    /**
+     *  @private
+     */
+    public function set centerGridColumnHeaderView(value:Group):void
+    {
+        if (_centerGridColumnHeaderView == value)
+            return;
+        
+        _centerGridColumnHeaderView = value;
+        dispatchChangeEvent("centerGridColumnHeaderViewChanged");
+    }
+
+    //----------------------------------
+    //  leftGridColumnHeaderView
+    //----------------------------------
+    
+    private var _leftGridColumnHeaderView:Group = null; 
+    
+    [Bindable("leftGridColumnHeaderViewChanged")]
+    
+    /**
+     *  Contains the column headers for the Grid's leftGridView lockedColumnCount columns. 
+     * 
+     *  @default null
+     *
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 5.0
+     */
+    public function get leftGridColumnHeaderView():Group
+    {
+        return _leftGridColumnHeaderView;
+    }
+    
+    /**
+     *  @private
+     */
+    public function set leftGridColumnHeaderView(value:Group):void
+    {
+        if (_leftGridColumnHeaderView == value)
+            return;
+        
+        _leftGridColumnHeaderView = value;
+        dispatchChangeEvent("leftGridColumnHeaderViewChanged");
+    }
+
+    //--------------------------------------------------------------------------
+    //
+    //  Methods
+    //
+    //--------------------------------------------------------------------------
+    
+	/**
+	 *  @private
+	 */
+	override public function measure():void
+	{
+		const gridColumnHeaderGroup:GridColumnHeaderGroup = target as GridColumnHeaderGroup;
+		if (!gridColumnHeaderGroup)
+			return;
+		
+		const paddingLeft:Number = gridColumnHeaderGroup.getStyle("paddingLeft");
+		const paddingRight:Number = gridColumnHeaderGroup.getStyle("paddingRight");
+		const paddingTop:Number = gridColumnHeaderGroup.getStyle("paddingTop");
+		const paddingBottom:Number = gridColumnHeaderGroup.getStyle("paddingBottom");
+		
+		const measuredWidth:Number = Math.max(0, target.getMinBoundsWidth()) + paddingLeft + paddingRight;
+        const centerView:Group = centerGridColumnHeaderView;        
+        const centerHeight:Number = (centerView) ? centerView.getPreferredBoundsHeight() : 0;
+		const measuredHeight:Number = centerHeight + paddingTop + paddingBottom;
+		
+		target.measuredWidth = Math.ceil(measuredWidth); 
+		target.measuredHeight = Math.ceil(measuredHeight);
+		target.measuredMinWidth = Math.ceil(measuredWidth);    
+		target.measuredMinHeight = Math.ceil(measuredHeight);
+	}
+	
+	/**
+	 *  @private
+	 */
+	override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+	{
+		const gridColumnHeaderGroup:GridColumnHeaderGroup = target as GridColumnHeaderGroup;
+		if (!gridColumnHeaderGroup || !centerGridColumnHeaderView)
+			return;
+		
+        // Note that paddingLeft guarantees that the centerGridColumnHeaderView lines up 
+        // with the Grid's centerGridView.
+        
+		const paddingLeft:Number = gridColumnHeaderGroup.getStyle("paddingLeft");
+		const paddingRight:Number = gridColumnHeaderGroup.getStyle("paddingRight");
+		const paddingTop:Number = gridColumnHeaderGroup.getStyle("paddingTop");
+		const paddingBottom:Number = gridColumnHeaderGroup.getStyle("paddingBottom");		
+		
+		const grid:Grid = gridColumnHeaderGroup.dataGrid.grid;
+		const gridLayout:GridLayout = gridColumnHeaderGroup.dataGrid.grid.layout as GridLayout;
+		const lockedColumnCount:int = gridColumnHeaderGroup.dataGrid.lockedColumnCount;
+		
+		const centerView:Group = centerGridColumnHeaderView;
+		const leftView:Group = leftGridColumnHeaderView;
+		const headerHeight:Number = Math.max(0, unscaledHeight - (paddingTop + paddingBottom));
+		
+		var centerGridViewX:Number = gridLayout.centerGridView.getLayoutBoundsX();
+		if (lockedColumnCount > 0)
+		{
+			leftView.setLayoutBoundsSize(centerGridViewX - paddingLeft, headerHeight);
+			leftView.setLayoutBoundsPosition(paddingLeft, paddingTop);
+		}
+        else 
+        {
+            centerGridViewX += paddingLeft; 
+        }
+        
+		centerView.setLayoutBoundsSize(unscaledWidth - centerGridViewX, headerHeight);
+		centerView.setLayoutBoundsPosition(centerGridViewX, paddingTop);
+        
+        // The DataGrid invalidates this layout when the GridLayout's centerGridView is scrolled
+        // horizontally.  It assumes that the header's centerView has the same contentWidth as
+        // the centerGridView so it's not necessary to set the content size here.
+	}
+	
+}
+}
\ No newline at end of file

Propchange: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderLayout.as
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderLayout.as
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as?rev=1370028&view=auto
==============================================================================
--- incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as (added)
+++ incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as Mon Aug  6 21:25:54 2012
@@ -0,0 +1,1038 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.components.gridClasses
+{
+import flash.geom.Rectangle;
+import flash.utils.Dictionary;
+
+import mx.collections.IList;
+import mx.core.IFactory;
+import mx.core.IVisualElement;
+import mx.core.mx_internal;
+import mx.events.CollectionEvent;
+import mx.events.CollectionEventKind;
+
+import spark.components.DataGrid;
+import spark.components.Grid;
+import spark.components.GridColumnHeaderGroup;
+import spark.components.Group;
+import spark.components.supportClasses.GroupBase;
+import spark.layouts.supportClasses.LayoutBase;
+
+use namespace mx_internal;
+
+[ExcludeClass]
+
+/**
+ *  @private
+ *  Virtual horizontal layout for each column header view Group.  This is not a general 
+ *  purpose layout class, it's only intended for column header view Groups.
+ * 
+ *  This layout tracks the layout of the corresponding GridView. 
+ *  
+ */
+public class GridHeaderViewLayout extends LayoutBase
+{
+    /**
+     *  Constructor. 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 4.5
+     */    
+    public function GridHeaderViewLayout()
+    {
+        super();
+    }
+    
+    //--------------------------------------------------------------------------
+    //
+    //  Internal variables
+    //
+    //--------------------------------------------------------------------------
+
+    /**
+     *  @private
+     *  Layers for header renderers and separators.
+     */
+    private var rendererLayer:Group;
+    private var overlayLayer:Group;
+    
+    /**
+     *  @private
+     *  Cached header renderer heights maintained by the measure() method, 
+     *  and the current content height.
+     */
+    private const rendererHeights:Array = new Array();
+    private var maxRendererHeight:Number = 0;
+    
+    /**
+     *  @private
+     *  Bounds of all currently visible header renderers.
+     */
+    private const visibleRenderersBounds:Rectangle = new Rectangle();
+    
+    /**
+     *  @private
+     *  Currently visible header renderers.
+     */
+    private const visibleHeaderRenderers:Vector.<IGridItemRenderer> = new Vector.<IGridItemRenderer>();
+    
+    /**
+     *  @private
+     *  Currently visible header separators.
+     */
+    private const visibleHeaderSeparators:Vector.<IVisualElement> = new Vector.<IVisualElement>();
+    
+    /**
+     *  @private
+     *  The elements available for reuse aka the "free list".   Maps from an IFactory 
+     *  to a list of the elements that have been allocated by that factory and then freed.   
+     *  The list is represented by a Vector.<IVisualElement>.
+     */
+    private var freeElementMap:Dictionary = new Dictionary(); 
+    
+    /**
+     *  @private
+     *  Records the IFactory used to allocate a Element so that freeVisualElement()
+     *  can find it again.
+     */
+    private var elementToFactoryMap:Dictionary = new Dictionary();
+	
+	//---------------------------------------------------------------
+	//
+	//  Properties
+	//
+	//---------------------------------------------------------------
+
+	//----------------------------------
+	//  columns
+	//----------------------------------
+	
+	private var _columnsView:IList;
+	
+	/**
+	 *  @private
+	 *  Returns a cached reference to gridView.columns. A local reference is kept so
+	 *  that we can remove the colllection change handler if the columns list changes.
+	 */
+	private function get columnsView():IList
+	{
+		const gridView:GridView = this.gridView;
+		const newColumns:IList = (gridView) ? gridView.gridViewLayout.columnsView : null;
+		
+		if (newColumns != _columnsView)
+		{
+			if (_columnsView)
+				_columnsView.removeEventListener(CollectionEvent.COLLECTION_CHANGE, columns_collectionChangeHandler);
+			
+			_columnsView = newColumns;
+			
+			if (_columnsView)
+				_columnsView.addEventListener(CollectionEvent.COLLECTION_CHANGE, columns_collectionChangeHandler);
+		}
+		
+		return _columnsView;
+	}
+	
+	//----------------------------------
+	//  grid (private read-only)
+	//----------------------------------
+	
+	/**
+	 *  @private
+	 */
+	private function get grid():Grid
+	{
+		const view:GridView = this.gridView;
+		return (view) ? view.parent as Grid : null;
+	}
+	
+	//----------------------------------
+	//  gridColumnHeaderGroup
+	//----------------------------------
+	
+	private var _gridColumnHeaderGroup:GridColumnHeaderGroup = null;
+	
+	/**
+	 *  The GridColumnHeaderGroup whose columns this header view is associated with.
+	 * 
+	 *  This property is set by GridColumnHeaderGroup.
+	 */
+	public function get gridColumnHeaderGroup():GridColumnHeaderGroup
+	{
+		return _gridColumnHeaderGroup
+	}
+	
+	/**
+	 *  @private
+	 */
+	public function set gridColumnHeaderGroup(value:GridColumnHeaderGroup):void
+	{
+		if (value == _gridColumnHeaderGroup)
+			return;
+		
+		_gridColumnHeaderGroup = value;
+	}	
+	
+	//----------------------------------
+	//  gridView
+	//----------------------------------
+	
+	private var _gridView:GridView = null;
+	
+	/**
+	 *  The GridView whose columns this header view is associated with.
+	 * 
+	 *  This property is set by GridColumnHeaderGroup.
+	 */
+	public function get gridView():GridView
+	{
+		return _gridView
+	}
+	
+	/**
+	 *  @private
+	 */
+	public function set gridView(value:GridView):void
+	{
+		if (value == _gridView)
+			return;
+		
+		_gridView = value;
+	}
+	
+    //---------------------------------------------------------------
+    //
+    //  Overridden methods
+    //
+    //---------------------------------------------------------------
+    
+    /**
+     *  @private
+     */
+    override public function set target(value:GroupBase):void
+    {
+        super.target = value;
+        
+        const group:Group = value as Group;
+		if (!group)
+			return;
+		
+		rendererLayer = new Group();
+		rendererLayer.layout = new LayoutBase();
+		group.addElement(rendererLayer);
+		
+		overlayLayer = new Group();
+		overlayLayer.layout = new LayoutBase();
+		group.addElement(overlayLayer);
+    }
+    
+    /**
+     *  @private
+     */
+    override public function get useVirtualLayout():Boolean
+    {
+        return true;
+    }
+    
+    /**
+     *  @private
+     */
+    override public function set useVirtualLayout(value:Boolean):void
+    {
+    }
+    
+    /**
+     *  @private
+     *  Clear everything.
+     */
+    override public function clearVirtualLayoutCache():void
+    {		
+		freeRenderers(visibleHeaderRenderers);
+        visibleHeaderRenderers.length = 0;
+		
+		freeVisualElements(visibleHeaderSeparators);
+        visibleHeaderSeparators.length = 0;
+		
+        rendererHeights.length = 0;
+        visibleRenderersBounds.setEmpty();
+        elementToFactoryMap = new Dictionary();
+        freeElementMap = new Dictionary();
+
+		if (gridColumnHeaderGroup)
+			gridColumnHeaderGroup.visibleSortIndicatorIndices = null;
+    }     
+    
+    /**
+     *  @private
+     */
+    override protected function scrollPositionChanged():void
+    {
+		const target:GroupBase = this.target;
+        if (!target)
+            return;
+        
+        super.scrollPositionChanged();  // sets target's scrollRect
+        
+        // Only invalidate if we're clipping and scrollR extends outside visibleRenderersBounds
+        const scrollR:Rectangle = target.scrollRect;
+		if (scrollR && !visibleRenderersBounds.containsRect(scrollR))
+            target.invalidateDisplayList();
+    }    
+    
+    /**
+     *  @private
+     */
+    override public function measure():void
+    {
+		const target:GroupBase = this.target;
+		if (!target)
+			return;
+		
+		updateRendererHeights();
+		
+		const measuredWidth:Number = Math.max(0, target.minWidth);
+		const measuredHeight:Number = Math.max(maxRendererHeight, target.minHeight);
+		
+        target.measuredWidth = Math.ceil(measuredWidth);
+        target.measuredHeight = Math.ceil(measuredHeight);
+    }
+
+    /**
+     *  @private
+     */
+    override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+    {
+		const target:GroupBase = this.target;
+        const gridColumnHeaderGroup:GridColumnHeaderGroup = this.gridColumnHeaderGroup;
+        const gridView:GridView = this.gridView;
+        
+        if (!target || !gridColumnHeaderGroup || !gridView)
+            return;
+
+		// TBD explain about Grid relative column indices...
+		
+		const visibleColumnIndices:Vector.<int> = gridView.gridViewLayout.getVisibleColumnIndices();  
+		const visibleColumnCount:int = visibleColumnIndices.length;
+		const firstVisibleColumnIndex:int = (visibleColumnCount > 0) ? visibleColumnIndices[0] : -1;
+		const lastVisibleColumnIndex:int = (visibleColumnCount > 0) ? visibleColumnIndices[visibleColumnCount - 1] : -1;
+		
+        const oldRenderers:Array = [];
+        const rendererLayer:Group = this.rendererLayer;
+        const overlayLayer:Group = this.overlayLayer;
+        const columnSeparatorFactory:IFactory = gridColumnHeaderGroup.columnSeparator;
+        
+        var renderer:IGridItemRenderer;
+        var separator:IVisualElement;
+        var column:GridColumn;
+        var columnIndex:int = -1;
+        
+        // Add all of the renderers whose column is still visible to oldRenderers and free the rest
+        
+        for each (renderer in visibleHeaderRenderers)
+        {
+            column = renderer.column;
+            columnIndex = (column) ? column.columnIndex : -1; 
+            
+            if ((visibleColumnIndices.indexOf(columnIndex) != -1) && (oldRenderers[columnIndex] == null))
+                oldRenderers[columnIndex] = renderer;
+            else
+                freeRenderer(renderer);
+        }
+        visibleHeaderRenderers.length = 0;
+        
+        // Add all of the separators to the free-list, since laying them out is cheap.
+        
+		freeVisualElements(visibleHeaderSeparators);
+		visibleHeaderSeparators.length = 0;
+        
+        // Layout the header renderers and update the CHB's content size
+        // The loop below is written in terms of Grid - not GridView - column indices,
+        // and terminates when we reach GridColumnCount.
+        
+        const gridColumns:IList = grid.columns;  // TBD what if grid.columns is null?
+        const gridViewLayout:GridViewLayout = gridView.layout as GridViewLayout;
+        const gridColumnCount:int = gridViewLayout.viewColumnIndex + gridViewLayout.columnsView.length; 
+        
+		const rendererY:Number = 0;
+		const rendererHeight:Number = unscaledHeight;
+        const maxRendererX:Number = target.horizontalScrollPosition + unscaledWidth;
+        
+        var visibleLeft:Number = 0;
+        var visibleRight:Number = 0;
+        
+        // This isn't quite as simple as: 
+        //     for each (var columnIndex:int in visibleColumnIndices)
+        // since the GridColumnHeaderGroup may be wider than the grid because it
+        // spans the vertical scrollbar.  If it does, we may need to display 
+        // additional column headers (usually one).  
+        
+        for (var index:int = 0; /* termination conditions below */; index++)
+        {
+            if (index < visibleColumnIndices.length)
+                columnIndex = visibleColumnIndices[index];
+            else
+                columnIndex = grid.getNextVisibleColumnIndex(columnIndex);
+           
+            if (columnIndex < 0 || columnIndex >= gridColumnCount)
+                break;
+
+            column = gridColumns.getItemAt(columnIndex) as GridColumn;
+
+            // reuse or create a new renderer
+            
+            renderer = oldRenderers[columnIndex];
+            delete oldRenderers[columnIndex];
+            if (!renderer)
+            {
+                var factory:IFactory = column.headerRenderer;
+                if (!factory)
+                    factory = gridColumnHeaderGroup.headerRenderer;
+                renderer = allocateVisualElement(factory) as IGridItemRenderer;
+            }
+            visibleHeaderRenderers.push(renderer);
+            
+            // initialize the renderer
+            
+            initializeItemRenderer(renderer, columnIndex, column, true);
+            if (renderer.parent != rendererLayer)
+                rendererLayer.addElement(renderer);
+            
+            // layout the renderer
+            
+            var isLastColumn:Boolean = columnIndex == lastVisibleColumnIndex;
+            var headerViewColumnIndex:int = columnIndex - gridViewLayout.viewColumnIndex;
+			var rendererX:Number = gridViewLayout.gridDimensionsView.getCellX(0, headerViewColumnIndex);
+            var rendererWidth:Number = grid.getColumnWidth(columnIndex);
+            
+			if (isLastColumn)
+                rendererWidth = horizontalScrollPosition + unscaledWidth - rendererX - 1; // TODO: this is a temporary hack
+			
+            renderer.setLayoutBoundsSize(rendererWidth, rendererHeight);
+            renderer.setLayoutBoundsPosition(rendererX, rendererY);
+            
+            if (index == 0)
+                visibleLeft = rendererX;
+            visibleRight = rendererX + rendererWidth;
+            
+            renderer.prepare(!createdVisualElement);
+            
+            if (isLastColumn || ((rendererX + rendererWidth) >= maxRendererX))
+                break;
+            
+            // allocate and layout a column separator
+            
+            if (columnSeparatorFactory && !isLastColumn)
+            {
+                separator = allocateVisualElement(columnSeparatorFactory);
+                visibleHeaderSeparators.push(separator);
+                separator.visible = true;
+                if (separator.parent != overlayLayer)
+                    overlayLayer.addElement(separator);
+                
+                var separatorWidth:Number = separator.getPreferredBoundsWidth();
+                var separatorX:Number = rendererX + rendererWidth;
+                separator.setLayoutBoundsSize(separatorWidth, rendererHeight);
+                separator.setLayoutBoundsPosition(separatorX, rendererY);
+            }
+        }
+
+        target.setContentSize(grid.contentWidth, rendererHeight);
+
+		visibleRenderersBounds.left = visibleLeft;
+		visibleRenderersBounds.right = visibleRight = 0;
+		visibleRenderersBounds.top = rendererY;
+        visibleRenderersBounds.height = rendererHeight;
+		
+        // We may have created new renderers or changed their visibility.  Force
+        // validation to avoid a display list flash.
+
+        target.validateNow();
+        
+        // Update the renderer heights cache.
+        // Invalidates the target's size if the maxRendererHeight has changed.
+        
+        updateRendererHeights(true);
+    }
+    
+    //---------------------------------------------------------------
+    //
+    //  Public methods
+    //
+    //--------------------------------------------------------------- 
+    
+    /**
+     *  Returns the column index corresponding to the specified coordinates,
+     *  or -1 if the coordinates are out of bounds. The coordinates are 
+     *  resolved with respect to the column header view layout target.
+     * 
+     *  <p>If all of the columns or rows for the grid have not yet been scrolled
+     *  into view, the returned index may only be an approximation, 
+     *  based on all of the columns' <code>typicalItem</code>s.</p>
+     *  
+     *  @param x The pixel's x coordinate relative to the target column header view
+     *  @param y The pixel's y coordinate relative to the target column header view
+     *  @return the index of the column or -1 if the coordinates are out of bounds. 
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    public function getHeaderIndexAt(x:Number, y:Number):int
+    {
+        return gridView.gridViewLayout.gridDimensionsView.getColumnIndexAt(x, y);
+        
+        // TODO: restore the special case handling below
+        /*
+        const gridColumnHeaderGroup:GridColumnHeaderGroup = this.gridColumnHeaderGroup;
+        const grid:Grid = this.grid;
+        const columnsView:IList = this.columnsView;
+        
+        if (!gridColumnHeaderGroup || !grid || !columnsView)
+            return -1; 
+        
+        const paddingLeft:Number = gridColumnHeaderGroup.getStyle("paddingLeft");
+        const paddedX:Number = x + paddingLeft;
+        var columnIndex:int = grid.getColumnIndexAt(paddedX, 0);
+        
+        // Special case for the stretched renderer above the vertical scrollbar
+        // TODO (klin): Rethink this case if we change how the last header looks.
+        if (columnIndex < 0)
+        {
+            const contentWidth:Number = gridColumnHeaderGroup.contentWidth;
+            const totalWidth:Number = horizontalScrollPosition + gridColumnHeaderGroup.width - gridColumnHeaderGroup.getStyle("paddingRight");
+            if (paddedX >= contentWidth && paddedX < totalWidth)
+                columnIndex = grid.getPreviousVisibleColumnIndex(columnsView.length)
+        }
+        
+        return columnIndex;
+        */
+    }
+    
+    /**
+     *  Returns the column separator index corresponding to the specified 
+     *  coordinates, or -1 if the coordinates don't overlap a separator. The 
+     *  coordinates are resolved with respect to the GridColumnHeaderGroup layout target.
+     * 
+     *  <p>A separator is considered to "overlap" the specified location if the
+     *  x coordinate is within <code>separatorMouseWidth</code> of separator's
+     *  horizontal midpoint.</p>
+     *  
+     *  <p>The separator index is the same as the index of the column on the left
+     *  (assuming that this component's layoutDirection is "rtl").  That means 
+     *  that all column headers are flanked by two separators, except for the first
+     *  visible column, which just has a separator on the right, and the last visible
+     *  column, which just has a separator on the left.</p>
+     * 
+     *  <p>If all of the columns or rows for the grid have not yet been scrolled
+     *  into view, the returned index may only be an approximation, 
+     *  based on all of the columns' <code>typicalItem</code>s.</p>
+     *  
+     *  @param x The pixel's x coordinate relative to the columnHeaderGroup
+     *  @param y The pixel's y coordinate relative to the columnHeaderGroup
+     *  @return the index of the column or -1 if the coordinates don't overlap a separator.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    public function getSeparatorIndexAt(x:Number, y:Number):int
+    {
+        const gdv:GridDimensionsView = gridView.gridViewLayout.gridDimensionsView;
+        const columnIndex:int = gdv.getColumnIndexAt(x, y); 
+        if (columnIndex == -1)
+            return -1;        
+        
+        const isFirstColumn:Boolean = columnIndex == gridView.getNextVisibleColumnIndex(-1);
+        const isLastColumn:Boolean = false; //columnIndex == gridView.getPreviousVisibleColumnIndex(gridView.viewColumnCount);
+        
+        const columnLeft:Number = gdv.getCellX(0, columnIndex);
+        const columnRight:Number = columnLeft + gdv.getColumnWidth(columnIndex);
+        const smw:Number = gridColumnHeaderGroup.getStyle("separatorAffordance");
+        
+        if (!isFirstColumn && (x > (columnLeft - smw)) && (x < (columnLeft + smw)))
+            return grid.getPreviousVisibleColumnIndex(columnIndex);
+        
+        if (!isLastColumn && (x > (columnRight - smw)) && (x < columnRight + smw))
+            return columnIndex;
+        
+        return -1;
+    }
+    
+    /**
+     *  Returns the current pixel bounds of the specified header (renderer), or null if 
+     *  no such column exists.  Header bounds are reported in GridColumnHeaderGroup coordinates.
+     * 
+     *  <p>If all of the visible columns preceeding the specified column have not 
+     *  yet been scrolled into view, the returned bounds may only be an approximation, 
+     *  based on all of the Grid's <code>typicalItem</code>s.</p>
+     * 
+     *  @param columnIndex The 0-based index of the column. 
+     *  @return A <code>Rectangle</code> that represents the column header's pixel bounds, or null.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */ 
+    public function getHeaderBounds(columnIndex:int):Rectangle
+    {
+        const gridColumnHeaderGroup:GridColumnHeaderGroup = this.gridColumnHeaderGroup;
+        const grid:Grid = this.grid;
+        
+        if (!gridColumnHeaderGroup || !grid)
+            return null;
+        
+        const columns:IList = columns;
+        const columnsLength:int = (columns) ? columns.length : 0;
+        
+        if (columnIndex >= columnsLength)
+            return null;
+        
+        const column:GridColumn = columns.getItemAt(columnIndex) as GridColumn;
+        if (!column.visible)
+            return null;
+        
+        const paddingLeft:Number = gridColumnHeaderGroup.getStyle("paddingLeft");
+        const paddingRight:Number = gridColumnHeaderGroup.getStyle("paddingRight");
+        const paddingTop:Number = gridColumnHeaderGroup.getStyle("paddingTop");
+        const paddingBottom:Number = gridColumnHeaderGroup.getStyle("paddingBottom");
+        
+        var isLastColumn:Boolean = columnIndex == grid.getPreviousVisibleColumnIndex(columnsLength);
+        var rendererX:Number = grid.getCellX(0, columnIndex) + paddingLeft;
+        const rendererY:Number = paddingTop;
+        var rendererWidth:Number = grid.getColumnWidth(columnIndex); 
+        const rendererHeight:Number = gridColumnHeaderGroup.height - paddingTop - paddingBottom;        
+        
+        if (isLastColumn)
+            rendererWidth = horizontalScrollPosition + gridColumnHeaderGroup.width - rendererX - paddingRight;
+        
+        return new Rectangle(rendererX, rendererY, rendererWidth, rendererHeight);
+    }
+
+    /**
+     *  If the requested header renderer is visible, returns a reference to 
+     *  the header renderer currently displayed for the specified column. 
+     *  Note that once the returned header renderer is no longer visible it 
+     *  may be recycled and its properties reset.  
+     * 
+     *  <p>If the requested header renderer is not visible then, 
+     *  each time this method is called, a new header renderer is created.  The
+     *  new item renderer is not visible</p>
+     * 
+     *  <p>The width of the returned renderer is the same as for item renderers
+     *  returned by DataGrid/getItemRendererAt().</p>
+     *  
+     *  @param columnIndex The 0-based column index of the header renderer's column
+     *  @return The item renderer or null if the column index is invalid.
+     * 
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.0
+     *  @productversion Flex 4.5
+     */
+    public function getHeaderRendererAt(columnIndex:int):IGridItemRenderer
+    {
+        const gridColumnHeaderGroup:GridColumnHeaderGroup = this.gridColumnHeaderGroup;
+        const grid:Grid = this.grid;
+        
+        if (!gridColumnHeaderGroup || !grid || (columnIndex < 0))
+            return null;
+        
+        // If columnIndex refers to a visible header renderer, return it
+        
+        const rendererLayer:Group = rendererLayer;
+        const visibleColumnIndices:Vector.<int> = grid.getVisibleColumnIndices();
+        const eltIndex:int = visibleColumnIndices.indexOf(columnIndex);
+        if (eltIndex != -1)
+        {
+            const rendererLayerNumElements:int = rendererLayer.numElements;
+            for (var index:int = 0; index < rendererLayerNumElements; index++)
+            {
+                var elt:IGridItemRenderer = rendererLayer.getElementAt(index) as IGridItemRenderer;
+                if (elt && elt.visible && elt.column && (elt.column.columnIndex == columnIndex))
+                    return elt;
+            }
+            return null;
+        }
+            
+        // create a new renderer
+
+        const columns:IList = columns;
+        if (!columns || (columns.length <= columnIndex))
+            return null;
+        const column:GridColumn = columns.getItemAt(columnIndex) as GridColumn;
+        if (!column.visible)
+            return null;
+        
+        var factory:IFactory = column.headerRenderer;
+        if (!factory)
+            factory = gridColumnHeaderGroup.headerRenderer;
+        const renderer:IGridItemRenderer = allocateVisualElement(factory) as IGridItemRenderer;
+        
+        rendererLayer.addElement(renderer);
+
+        // initialize the renderer
+        
+        initializeItemRenderer(renderer, columnIndex, column, renderer.visible);
+        
+        // layout the renderer
+
+        const paddingLeft:Number = gridColumnHeaderGroup.getStyle("paddingLeft");
+        const paddingRight:Number = gridColumnHeaderGroup.getStyle("paddingRight");
+        const paddingTop:Number = gridColumnHeaderGroup.getStyle("paddingTop");
+        const paddingBottom:Number = gridColumnHeaderGroup.getStyle("paddingBottom");
+        
+        const isLastColumn:Boolean = columnIndex == grid.getPreviousVisibleColumnIndex(columns.length);
+        const rendererX:Number = grid.getCellX(0, columnIndex) + paddingLeft;
+        const rendererY:Number = paddingTop;
+        const rendererHeight:Number = gridColumnHeaderGroup.height - paddingTop - paddingBottom;
+        var rendererWidth:Number = grid.getColumnWidth(columnIndex); 
+        
+        if (isLastColumn)
+            rendererWidth = horizontalScrollPosition + gridColumnHeaderGroup.width - rendererX - paddingRight;
+        
+        renderer.setLayoutBoundsSize(rendererWidth, rendererHeight);
+        renderer.setLayoutBoundsPosition(rendererX, rendererY);
+        
+        rendererLayer.removeElement(renderer);
+        renderer.visible = false;
+        
+        return renderer;
+    }
+    
+    //---------------------------------------------------------------
+    //
+    //  Internal methods, properties
+    //
+    //---------------------------------------------------------------    
+    
+    /**
+     *  @private
+     */
+    private function initializeItemRenderer(renderer:IGridItemRenderer,
+                                            columnIndex:int,
+                                            column:GridColumn,
+                                            visible:Boolean=true):void
+    {
+        renderer.visible = visible;
+        renderer.column = column;
+        renderer.label = column.headerText;
+        
+        const columnHeaderGroup:GridColumnHeaderGroup = this.gridColumnHeaderGroup;
+
+        const dataGrid:DataGrid = columnHeaderGroup.dataGrid;
+        if (dataGrid)
+            renderer.owner = dataGrid;
+        
+        renderer.hovered = columnIndex == columnHeaderGroup.hoverColumnIndex;
+        renderer.selected = columnIndex == columnHeaderGroup.selectedColumnIndex;
+        renderer.down = columnIndex == columnHeaderGroup.downColumnIndex;
+    }
+    
+    /**
+     *  @private
+     *  Let the allocateGridElement() caller know if the returned element was 
+     *  created or recycled.
+     */
+    private var createdVisualElement:Boolean = false;
+    
+    /**
+     *  @private
+     */
+    private function createVisualElement(factory:IFactory):IVisualElement
+    {
+        createdVisualElement = true;
+        const newElement:IVisualElement = factory.newInstance() as IVisualElement;
+        elementToFactoryMap[newElement] = factory;
+        return newElement;
+    }
+    
+    /**
+     *  @private
+     *  If the freeElementMap "free list" contains an instance of this factory, then 
+     *  remove if from the free list and return it, otherwise create a new instance
+     *  using createVisualElement().
+     */
+    private function allocateVisualElement(factory:IFactory):IVisualElement
+    {
+        createdVisualElement = false;
+        const freeElements:Vector.<IVisualElement> = freeElementMap[factory] as Vector.<IVisualElement>;
+        if (freeElements)
+        {
+            const freeElement:IVisualElement = freeElements.pop();
+            if (freeElements.length == 0)
+                delete freeElementMap[factory];
+            if (freeElement)
+                return freeElement;
+        }
+        
+        return createVisualElement(factory);
+    }
+    
+    /**
+     *  @private
+     *  Move the specified element to the free list after hiding it. Note that we 
+     *  do not actually remove the element from its parent.
+     */
+    private function freeVisualElement(element:IVisualElement):void
+    {
+        const factory:IFactory = elementToFactoryMap[element];
+
+        var freeElements:Vector.<IVisualElement> = freeElementMap[factory];
+        if (!freeElements)
+        {
+            freeElements = new Vector.<IVisualElement>();
+            freeElementMap[factory] = freeElements;
+        }
+        freeElements.push(element);
+        
+        element.visible = false;
+    }
+	
+	private function freeVisualElements(elements:Vector.<IVisualElement>):void
+	{
+		for each (var elt:IVisualElement in elements)
+		    freeVisualElement(elt);
+			
+		elements.length = 0;
+	}
+	
+	private function freeRenderer(renderer:IGridItemRenderer):void
+	{
+		freeVisualElement(renderer as IVisualElement);
+		renderer.discard(true);	
+	}
+	
+	private function freeRenderers(renderers:Vector.<IGridItemRenderer>):void
+	{
+		for each (var renderer:IGridItemRenderer in renderers)
+			freeRenderer(renderer);
+			
+		renderers.length = 0;
+	}		
+    
+    /**
+     *  @private
+     *  Updates the renderer heights cache and the current max renderer height.
+     *  Invalidates the target's size if the max renderer height has changed.
+     * 
+     *  <p>If the max live renderer height is the same as the max cached height, then
+     *  just update the cache.
+     *  If the max live renderer height is greater than the max cached height, then
+     *  update the cache, cache the new height, and invalidate the target's size if
+     *  necessary.
+     *  If the max live renderer height is less than the max cached height, then
+     *  update the cache, check to see if the cached max height has lowered, and
+     *  invalidate the target's size if necessary.
+     */
+    private function updateRendererHeights(inUpdateDisplayList:Boolean = false):void
+    {
+        const columns:IList = this.columnsView;
+        rendererHeights.length = (columns) ? columns.length : 0;
+        
+        var newHeight:Number = 0;
+        
+        // update cached renderer heights with live renderer heights.
+        for each (var renderer:IGridItemRenderer in visibleHeaderRenderers)
+        {
+            var preferredHeight:Number = renderer.getPreferredBoundsHeight();
+            rendererHeights[renderer.column.columnIndex] = preferredHeight;
+            if (preferredHeight > newHeight)
+                newHeight = preferredHeight;
+        }
+        
+        // Do nothing if the heights are the same.
+        if (newHeight == maxRendererHeight)
+            return;
+        
+        if (newHeight < maxRendererHeight)
+        {
+            // If the live renderers' max height is less than the current
+            // max height, check if this also lowers the maxRendererHeight.
+			for each (var rendererHeight:Number in rendererHeights)
+			{
+                if (!isNaN(rendererHeight) && rendererHeight > newHeight)
+                    newHeight = rendererHeight;
+            }
+        }
+        
+        maxRendererHeight = newHeight;
+        
+        if (inUpdateDisplayList) // TBD: should be target.invalidateSize()?
+            gridColumnHeaderGroup.invalidateSize();
+    }
+    
+
+    /**
+     *  @private
+     *  Handles changes to the columns IList that might affect the visible sort
+     *  indicators.
+     */
+    private function columns_collectionChangeHandler(event:CollectionEvent):void
+    {
+        // TODO (klin): The cache could be adjusted here too.
+        switch (event.kind)
+        {
+            case CollectionEventKind.ADD: 
+            {
+                columns_collectionChangeAdd(event);
+                break;
+            }
+            
+            case CollectionEventKind.REMOVE:
+            {
+                columns_collectionChangeRemove(event);
+                break;
+            }
+                
+            case CollectionEventKind.MOVE:
+            {
+                columns_collectionChangeMove(event);
+                break;
+            }
+                
+            case CollectionEventKind.REPLACE:
+            case CollectionEventKind.UPDATE:
+            {
+                // Do nothing.
+                break;
+            }
+                
+            case CollectionEventKind.REFRESH:
+            case CollectionEventKind.RESET:
+            {
+                clearVirtualLayoutCache();
+                break;
+            }                
+        }
+    }
+    
+    /**
+     *  @private
+     *  Adjusts the visibleSortIndicatorIndices to the correct columns
+     *  after columns are added.
+     */
+    private function columns_collectionChangeAdd(event:CollectionEvent):void
+    {   
+        const itemsLength:int = event.items.length;
+        if (itemsLength <= 0)
+            return;
+        
+        const chg:GridColumnHeaderGroup = gridColumnHeaderGroup;
+        const indices:Vector.<int> = chg.visibleSortIndicatorIndices;
+        const indicesLength:int = indices.length;
+        const startIndex:int = event.location;
+        
+        for (var i:int = 0; i < indicesLength; i++)
+        {
+            if (indices[i] >= startIndex)
+                indices[i] += itemsLength;
+        }
+        chg.visibleSortIndicatorIndices = indices;
+    }
+    
+    /**
+     *  @private
+     *  Adjusts the visibleSortIndicatorIndices to the correct columns
+     *  after columns are removed.
+	 * 
+	 *  TBD: Remove the rendererHeights cache entries for the corresponding columns.
+     */
+    private function columns_collectionChangeRemove(event:CollectionEvent):void
+    {
+        const itemsLength:int = event.items.length;
+        if (itemsLength <= 0)
+            return;
+        
+        const chg:GridColumnHeaderGroup = gridColumnHeaderGroup;
+        const indices:Vector.<int> = chg.visibleSortIndicatorIndices;
+        const indicesLength:int = indices.length;
+        const startIndex:int = event.location;
+        const lastIndex:int = startIndex + itemsLength;
+        const newIndices:Vector.<int> = new Vector.<int>();
+        var index:int;
+        
+        for each (index in indices)
+        {
+            if (index < startIndex)
+                newIndices.push(index);
+            else if (index >= lastIndex)
+                newIndices.push(index - lastIndex);
+        }
+        chg.visibleSortIndicatorIndices = newIndices;
+    }
+    
+    /**
+     *  @private
+     *  Adjusts the visibleSortIndicatorIndices to the correct columns
+     *  after columns are moved.
+     */
+    private function columns_collectionChangeMove(event:CollectionEvent):void
+    {
+        const itemsLength:int = event.items.length;
+        if (itemsLength <= 0)
+            return;
+        
+        const gridColumnHeaderGroup:GridColumnHeaderGroup = this.gridColumnHeaderGroup;
+        const indices:Vector.<int> = gridColumnHeaderGroup.visibleSortIndicatorIndices;
+        const indicesLength:int = indices.length;
+        const oldStart:int = event.oldLocation;
+        const oldEnd:int = event.oldLocation + itemsLength;
+        const newStart:int = event.location;
+        const newEnd:int = event.location + itemsLength;
+        var index:int;
+        
+        for (var i:int = 0; i < indicesLength; i++)
+        {
+            index = indices[i];
+            
+            if (index >= oldStart && index < oldEnd)
+            {
+                // Moved items move up to new position
+                indices[i] = newStart + (index - oldStart);
+                continue;
+            }
+            
+            // Two cases:
+            //      1) New position is greater than old position, so we
+            //         decrement their position by the number of moved items.
+            //      2) New position is less than old position, so we
+            //         increment their position by the number of moved items.
+            if (newStart > oldStart)
+            {
+                if (index >= oldEnd && index < newEnd)
+                    indices[i] -= itemsLength;
+            }
+            else if (newStart < oldStart)
+            {
+                if (index >= newStart && index < oldStart)
+                    indices[i] += itemsLength;
+            }
+        }
+		
+        gridColumnHeaderGroup.visibleSortIndicatorIndices = indices;
+    }
+}
+}
\ No newline at end of file

Propchange: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridHeaderViewLayout.as
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridItemEditor.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridItemEditor.as?rev=1370028&r1=1370027&r2=1370028&view=diff
==============================================================================
--- incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridItemEditor.as (original)
+++ incubator/flex/whiteboard/cframpton/adobe.next/frameworks/projects/spark/src/spark/components/gridClasses/GridItemEditor.as Mon Aug  6 21:25:54 2012
@@ -39,6 +39,7 @@ import spark.components.gridClasses.Grid
 import spark.components.DataGrid;
 import spark.components.Group;
 
+
 use namespace mx_internal;
 
 /**
@@ -529,6 +530,19 @@ public class GridItemEditor extends Grou
     }
     
     /**
+     *  @inheritDoc 
+     *  
+     *  @langversion 3.0
+     *  @playerversion Flash 10
+     *  @playerversion AIR 2.5
+     *  @productversion Flex 4.5
+     */
+    public function cancel():Boolean
+    {
+        return true;
+    }
+    
+    /**
      *  Tests if the value in the editor is valid and may be saved.
      * 
      *  @return <code>true</code> if the value in the editor is valid. 



Mime
View raw message