| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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 |
| { |
| import flash.display.InteractiveObject; |
| import flash.events.Event; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| import flash.geom.Rectangle; |
| import flash.utils.getTimer; |
| |
| import mx.collections.ArrayList; |
| import mx.collections.IList; |
| import mx.core.IFactory; |
| import mx.core.IVisualElement; |
| import mx.core.UIComponent; |
| import mx.core.UIComponentGlobals; |
| import mx.core.mx_internal; |
| import mx.events.CollectionEvent; |
| import mx.events.CollectionEventKind; |
| import mx.events.FlexEvent; |
| import mx.events.PropertyChangeEvent; |
| import mx.graphics.SolidColorStroke; |
| import mx.utils.ObjectUtil; |
| |
| import spark.collections.SubListView; |
| import spark.components.gridClasses.CellPosition; |
| import spark.components.gridClasses.GridDoubleClickMode; |
| import spark.components.gridClasses.GridColumn; |
| import spark.components.gridClasses.GridDimensions; |
| import spark.components.gridClasses.GridDimensionsView; |
| import spark.components.gridClasses.GridLayout; |
| import spark.components.gridClasses.GridSelection; |
| import spark.components.gridClasses.GridSelectionMode; |
| import spark.components.gridClasses.GridView; |
| import spark.components.gridClasses.GridViewLayout; |
| import spark.components.gridClasses.IDataGridElement; |
| import spark.components.gridClasses.IGridItemRenderer; |
| import spark.components.supportClasses.GroupBase; |
| import spark.components.supportClasses.IDataProviderEnhance; |
| import spark.components.supportClasses.RegExPatterns; |
| import spark.events.GridCaretEvent; |
| import spark.events.GridEvent; |
| import spark.layouts.VerticalLayout; |
| import spark.layouts.supportClasses.LayoutBase; |
| import spark.primitives.Line; |
| import spark.primitives.Rect; |
| import spark.utils.MouseEventUtil; |
| |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Events |
| //-------------------------------------- |
| |
| /** |
| * Dispatched when the mouse button is pressed over a Grid cell. |
| * |
| * @eventType spark.events.GridEvent.GRID_MOUSE_DOWN |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridMouseDown", type="spark.events.GridEvent")] |
| |
| /** |
| * Dispatched after a <code>gridMouseDown</code> event |
| * if the mouse moves before the button is released. |
| * |
| * @eventType spark.events.GridEvent.GRID_MOUSE_DRAG |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridMouseDrag", type="spark.events.GridEvent")] |
| |
| /** |
| * Dispatched when the mouse button is released over a Grid cell. |
| * During a drag operation, it is also dispatched after a |
| * <code>gridMouseDown</code> event |
| * when the mouse button is released, even if the mouse is no longer |
| * in the Grid. |
| * |
| * @eventType spark.events.GridEvent.GRID_MOUSE_UP |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridMouseUp", type="spark.events.GridEvent")] |
| |
| /** |
| * Dispatched when the mouse enters a grid cell. |
| * |
| * @eventType spark.events.GridEvent.GRID_ROLL_OVER |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridRollOver", type="spark.events.GridEvent")] |
| |
| /** |
| * Dispatched when the mouse leaves a grid cell. |
| * |
| * @eventType spark.events.GridEvent.GRID_ROLL_OUT |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridRollOut", type="spark.events.GridEvent")] |
| |
| /** |
| * Dispatched when the mouse is clicked over a cell |
| * |
| * @eventType spark.events.GridEvent.GRID_CLICK |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridClick", type="spark.events.GridEvent")] |
| |
| /** |
| * Dispatched when the mouse is double-clicked over a cell |
| * |
| * @eventType spark.events.GridEvent.GRID_DOUBLE_CLICK |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridDoubleClick", type="spark.events.GridEvent")] |
| |
| /** |
| * Dispatched after the caret changes. |
| * |
| * @eventType spark.events.GridCaretEvent.CARET_CHANGE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="caretChange", type="spark.events.GridCaretEvent")] |
| |
| /** |
| * The Grid control displays a list of data items called |
| * its <i>data provider</i> in a scrollable table or "grid", one item per row. |
| * Each of the grid's columns, defined by a GridColumn object, |
| * displays a value based on the item for the corresponding row. |
| * The grid's data provider is mutable, meaning its items can be added or |
| * removed, or changed. |
| * Similarly, the list of columns is mutable. |
| * |
| * <p>The Grid component is intended to be used as a DataGrid skin part, or |
| * as an element of other custom composite components. |
| * Therefore, it is not skinnable, it does not include a scroller or scrollbars, |
| * and it does not provide default mouse or keyboard event handling.</p> |
| * |
| * <p>Each visible Grid <i>cell</i> is displayed by a GridItemRenderer |
| * instance created by using the <code>itemRenderer</code> property. |
| * specify an item renderer for each column. |
| * Before it is displayed, each item renderer instance is configured |
| * with the value of the data provider item for that row. |
| * Item renderers are created as needed and then, to keep creation |
| * overhead to a minimum, pooled and recycled.</p> |
| * |
| * <p>The Grid control supports a doubleClick event, according the <code>doubleClickMode</code> |
| * property.</p> |
| * |
| * <p>The Grid control supports selection, according the <code>selectionMode</code> |
| * property. The set of selected row or cell indices can be modified or |
| * queried programatically using the selection methods, such as |
| * <code>setSelectedIndex</code> or <code>selectionContainsIndex()</code>.</p> |
| * |
| * <p>The Grid control displays hover, caret, and selection indicators based |
| * on the <code>selectionMode</code> property and the corresponding |
| * row index and column index properties, such as |
| * <code>hoverRowIndex</code> and <code>columnRowIndex</code>. |
| * An indicator can be any visual element. |
| * Indicators that implement IGridVisualElement can configure themselves |
| * according to the row and column in which they are used.</p> |
| * |
| * <p>The Grid control supports smooth scrolling. |
| * Their vertical and horizontal scroll positions define the pixel origin |
| * of the visible part of the grid and the grid's layout only displays |
| * as many cell item renderers as are needed to fill the available space.</p> |
| * |
| * <p>The Grid control supports variable height rows that automatically compute |
| * their height based on the item renderers' contents. |
| * This support is called grid <i>virtualization</i> |
| * because the mapping from (pixel) scroll positions to row and column indices |
| * is typically based on incomplete information about the preferred sizes |
| * for grid cells. |
| * The Grid caches the computed heights of rows that have been |
| * scrolled into view and estimates the rest based on a single |
| * <code>typicalItem</code>.</p> |
| * |
| * <p>Transitions in DataGrid item renderers aren't supported. The GridItemRenderer class |
| * has disabled its <code>transitions</code> property so setting it will have no effect.</p> |
| * |
| * @mxml <p>The <code><s:Grid></code> tag inherits all of the tag |
| * attributes of its superclass and adds the following tag attributes:</p> |
| * |
| * <pre> |
| * <s:Grid |
| * <strong>Properties</strong> |
| * /> |
| * </pre> |
| * |
| * @see DataGrid |
| * @see spark.components.gridClasses.GridColumn |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public class Grid extends Group implements IDataGridElement, IDataProviderEnhance |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * A list of functions to be called at commitProperties() time, after the dataProvider |
| * has been set. This list is used to defer making grid selection updates per the |
| * set methods for the selectedIndex, selectedIndices, selectedItem, selectedItems, |
| * selectedCell and selectedCells properties. |
| */ |
| private const deferredOperations:Vector.<Function> = new Vector.<Function>(); |
| |
| /** |
| * @private |
| * Cache the dataItem that goes with the caretRowIndex so we can find the |
| * rowIndex of the caret after a collection refresh event. |
| */ |
| private var caretSelectedItem:Object = null; |
| private var updateCaretForDataProviderChanged:Boolean = false; |
| private var updateCaretForDataProviderChangeLastEvent:CollectionEvent; |
| |
| /** |
| * @private |
| * True while updateDisplayList is running. Use to disable invalidateSize(), |
| * invalidateDisplayList() here and in the GridLayer class. |
| */ |
| mx_internal var inUpdateDisplayList:Boolean = false; |
| |
| /** |
| * @private |
| * True while doing a drag operation with the mouse. |
| */ |
| private var dragInProgress:Boolean = false; |
| |
| /** |
| * @private |
| * True if the columns were generated rather than explicitly set. |
| */ |
| private var generatedColumns:Boolean = false; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function Grid() |
| { |
| super(); |
| |
| layout = new GridLayout(); |
| |
| MouseEventUtil.addDownDragUpListeners(this, |
| grid_mouseDownDragUpHandler, |
| grid_mouseDownDragUpHandler, |
| grid_mouseDownDragUpHandler); |
| |
| addEventListener(MouseEvent.MOUSE_UP, grid_mouseUpHandler); |
| addEventListener(MouseEvent.MOUSE_MOVE, grid_mouseMoveHandler); |
| addEventListener(MouseEvent.ROLL_OUT, grid_mouseRollOutHandler); |
| } |
| |
| /** |
| * @private |
| * Return the GridView which contains the specified cell. If rowIndex == -1, |
| * then return the topmost GridView that contains the specified column and |
| * if columnIndex == -1 then return the leftmost GridView that contains the specified row. |
| */ |
| private function getGridViewAt(rowIndex:int, columnIndex:int):GridView |
| { |
| if ((rowIndex < 0) && (columnIndex < 0)) |
| return null; |
| |
| const gridLayout:GridLayout = layout as GridLayout; |
| |
| if ((rowIndex >= lockedRowCount) || (rowIndex == -1)) |
| { |
| if ((columnIndex >= lockedColumnCount) || (columnIndex == -1)) |
| return gridLayout.centerGridView; |
| |
| return gridLayout.leftGridView; |
| } |
| |
| return (columnIndex < lockedColumnCount) ? gridLayout.topLeftGridView : gridLayout.topGridView; |
| } |
| |
| |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function dispatchChangeEvent(type:String):void |
| { |
| if (hasEventListener(type)) |
| dispatchEvent(new Event(type)); |
| } |
| |
| /** |
| * @private |
| */ |
| private function dispatchFlexEvent(type:String):void |
| { |
| if (hasEventListener(type)) |
| dispatchEvent(new FlexEvent(type)); |
| } |
| |
| //---------------------------------- |
| // anchorColumnIndex |
| //---------------------------------- |
| |
| private var _anchorColumnIndex:int = 0; |
| |
| /** |
| * @private |
| * True if either anchorColumnIndex or anchorRowIndex changes. |
| */ |
| private var anchorChanged:Boolean = false; |
| |
| [Bindable("anchorColumnIndexChanged")] |
| |
| /** |
| * The column index of the <i>anchor</i> for the next shift selection. |
| * The anchor is the item most recently selected. |
| * It defines the anchor item when selecting multiple items in the grid. |
| * When you select multiple items, the set of items extends from |
| * the anchor to the caret item. |
| * |
| * <p>Grid event handlers should use this property to record the |
| * location of the most recent unshifted mouse down or keyboard |
| * event that defines one end of the next potential shift |
| * selection. |
| * The caret index defines the other end.</p> |
| * |
| * @default 0 |
| * |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#caretColumnIndex |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get anchorColumnIndex():int |
| { |
| return _anchorColumnIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set anchorColumnIndex(value:int):void |
| { |
| if (_anchorColumnIndex == value || |
| selectionMode == GridSelectionMode.SINGLE_ROW || |
| selectionMode == GridSelectionMode.MULTIPLE_ROWS) |
| { |
| return; |
| } |
| |
| _anchorColumnIndex = value; |
| |
| anchorChanged = true; |
| invalidateProperties(); |
| |
| dispatchChangeEvent("anchorColumnIndexChanged"); |
| } |
| |
| //---------------------------------- |
| // anchorRowIndex |
| //---------------------------------- |
| |
| private var _anchorRowIndex:int = 0; |
| |
| [Bindable("anchorRowIndexChanged")] |
| |
| /** |
| * The row index of the <i>anchor</i> for the next shift selection. |
| * The anchor is the item most recently selected. |
| * It defines the anchor item when selecting multiple items in the grid. |
| * When you select multiple items, the set of items extends from |
| * the anchor to the caret item. |
| * |
| * <p>Grid event handlers should use this property to record the |
| * location of the most recent unshifted mouse down or keyboard |
| * event that defines one end of the next potential shift |
| * selection. |
| * The caret index defines the other end.</p> |
| * |
| * @default 0 |
| * |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#caretColumnIndex |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get anchorRowIndex():int |
| { |
| return _anchorRowIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set anchorRowIndex(value:int):void |
| { |
| if (_anchorRowIndex == value) |
| return; |
| |
| _anchorRowIndex = value; |
| |
| anchorChanged = true; |
| invalidateProperties(); |
| |
| dispatchChangeEvent("anchorRowIndexChanged"); |
| } |
| |
| //---------------------------------- |
| // caretIndicator |
| //---------------------------------- |
| |
| private var _caretIndicator:IFactory = null; |
| |
| [Bindable("caretIndicatorChanged")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, |
| * a single visual element displayed for the caret row, |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, the |
| * visual element displayed for the caret cell. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get caretIndicator():IFactory |
| { |
| return _caretIndicator; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set caretIndicator(value:IFactory):void |
| { |
| if (_caretIndicator == value) |
| return; |
| |
| _caretIndicator = value; |
| invalidateDisplayListFor("caretIndicator"); |
| dispatchChangeEvent("caretIndicatorChanged"); |
| } |
| |
| //---------------------------------- |
| // caretColumnIndex |
| //---------------------------------- |
| |
| private var _caretColumnIndex:int = -1; |
| private var _oldCaretColumnIndex:int = -1; |
| private var caretChanged:Boolean = false; |
| |
| [Bindable("caretColumnIndexChanged")] |
| |
| /** |
| * If <code>showCaretIndicator</code> is <code>true</code>, |
| * the column index of the <code>caretIndicator</code>. |
| |
| * <p>If <code>selectionMode</code> is |
| * <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code> then the indicator |
| * occupies the entire row and <code>caretColumnIndex</code> is ignored. |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, then the |
| * <code>caretIndicator</code> occupies the specified cell.</p> |
| * |
| * <p>Setting <code>caretColumnIndex</code> to -1 means that the column |
| * index is undefined and a cell caret is not shown.</p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get caretColumnIndex():int |
| { |
| return _caretColumnIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set caretColumnIndex(value:int):void |
| { |
| if (_caretColumnIndex == value || value < -1) |
| return; |
| |
| _caretColumnIndex = value; |
| |
| caretChanged = true; |
| invalidateProperties(); |
| |
| // Unconditionally invalidate because renderers may depend on |
| // caretColumnIndex even when the caretIndicator doesn't exist. |
| invalidateDisplayListFor("caretIndicator"); |
| dispatchChangeEvent("caretColumnIndexChanged"); |
| } |
| |
| //---------------------------------- |
| // caretRowIndex |
| //---------------------------------- |
| |
| private var _caretRowIndex:int = -1; |
| private var _oldCaretRowIndex:int = -1; |
| |
| [Bindable("caretRowIndexChanged")] |
| |
| /** |
| * If <code>showCaretIndicator</code> is <code>true</code>, |
| * the row index of the <code>caretIndicator</code>. |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code> then the indicator |
| * occupies the entire row and the <code>caretColumnIndex</code> |
| * property is ignored. |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, then the <code>caretIndicator</code> |
| * occupies the specified cell. |
| * |
| * <p>Setting <code>caretRowIndex</code> to -1 means that the row index |
| * is undefined and the caret will not be shown.</p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get caretRowIndex():int |
| { |
| return _caretRowIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set caretRowIndex(value:int):void |
| { |
| if (_caretRowIndex == value || value < -1) |
| return; |
| |
| _caretRowIndex = value; |
| |
| caretChanged = true; |
| invalidateProperties(); |
| |
| // Unconditionally invalidate because renderers may depend on |
| // caretRowIndex even when the caretIndicator doesn't exist. |
| invalidateDisplayListFor("caretIndicator"); |
| dispatchChangeEvent("caretRowIndexChanged"); |
| } |
| |
| //---------------------------------- |
| // clipAndEnableScrolling (private override) |
| //---------------------------------- |
| |
| private var _clipAndEnableScrolling:Boolean = false; |
| |
| /** |
| * @private |
| */ |
| override public function get clipAndEnableScrolling():Boolean |
| { |
| return _clipAndEnableScrolling; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set clipAndEnableScrolling(value:Boolean):void |
| { |
| if (value == _clipAndEnableScrolling) |
| return; |
| |
| _clipAndEnableScrolling = value; |
| |
| const gridLayout:GridLayout = layout as GridLayout; |
| const topGridView:GridView = gridLayout.topGridView; |
| const leftGridView:GridView = gridLayout.leftGridView; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| |
| if (topGridView) topGridView.clipAndEnableScrolling = value; |
| if (leftGridView) leftGridView.clipAndEnableScrolling = value; |
| if (centerGridView) centerGridView.clipAndEnableScrolling = value; |
| } |
| |
| |
| //---------------------------------- |
| // contentHeight (private get override) |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get contentHeight():Number |
| { |
| return Math.ceil(gridDimensions.getContentHeight()); |
| } |
| |
| //---------------------------------- |
| // contentWidth (private get override) |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get contentWidth():Number |
| { |
| return Math.ceil(gridDimensions.getContentWidth()); |
| } |
| |
| //---------------------------------- |
| // horizontalScrollPosition (private override) |
| //---------------------------------- |
| |
| private var _horizontalScrollPosition:Number = 0; |
| |
| [Bindable] |
| [Inspectable(minValue="0.0")] |
| |
| /** |
| * @copy spark.core.IViewport#horizontalScrollPosition |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| override public function get horizontalScrollPosition():Number |
| { |
| return _horizontalScrollPosition; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set horizontalScrollPosition(value:Number):void |
| { |
| if (_horizontalScrollPosition == value) |
| return; |
| |
| const gridLayout:GridLayout = layout as GridLayout; |
| const topGridView:GridView = gridLayout.topGridView; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| |
| if (centerGridView) |
| { |
| const gridViewLayout:GridViewLayout = centerGridView.gridViewLayout; |
| const gridMaxHSP:Number = contentWidth - width; |
| const centerContentWidth:Number = Math.ceil(gridViewLayout.gridDimensionsView.getContentWidth()); |
| const centerMaxHSP:Number = centerContentWidth - centerGridView.width; |
| const hsp:Number = (gridMaxHSP > 0) ? (centerMaxHSP / gridMaxHSP) * value : 0; |
| |
| centerGridView.horizontalScrollPosition = hsp; |
| |
| if (topGridView) |
| topGridView.horizontalScrollPosition = hsp; |
| } |
| |
| _horizontalScrollPosition = value; |
| } |
| |
| |
| //---------------------------------- |
| // isFirstRow |
| //---------------------------------- |
| |
| /** |
| * Returns if the selectedIndex is equal to the first row. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function get isFirstRow():Boolean |
| { |
| if (dataProvider && dataProvider.length > 0) |
| { |
| if (selectedIndex == 0) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| //---------------------------------- |
| // isLastRow |
| //---------------------------------- |
| |
| /** |
| * Returns if the selectedIndex is equal to the last row. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function get isLastRow():Boolean |
| { |
| if (dataProvider && dataProvider.length > 0) |
| { |
| if (selectedIndex == dataProvider.length - 1) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| //---------------------------------- |
| // verticalScrollPosition (private override) |
| //---------------------------------- |
| |
| private var _verticalScrollPosition:Number = 0; |
| |
| [Bindable] |
| [Inspectable(minValue="0.0")] |
| |
| /** |
| * @copy spark.core.IViewport#verticalScrollPosition |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| override public function get verticalScrollPosition():Number |
| { |
| return _verticalScrollPosition; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set verticalScrollPosition(value:Number):void |
| { |
| if (_verticalScrollPosition == value) |
| return; |
| |
| const gridLayout:GridLayout = layout as GridLayout; |
| const leftGridView:GridView = gridLayout.leftGridView; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| |
| if (centerGridView) |
| { |
| const gridViewLayout:GridViewLayout = centerGridView.gridViewLayout; |
| const gridMaxVSP:Number = contentHeight - height; |
| const centerContentHeight:Number = Math.ceil(gridViewLayout.gridDimensionsView.getContentHeight()); |
| const centerMaxVSP:Number = centerContentHeight - centerGridView.height; |
| const vsp:Number = (gridMaxVSP > 0) ? (centerMaxVSP / gridMaxVSP) * value : 0; |
| |
| centerGridView.verticalScrollPosition = vsp; |
| |
| if (leftGridView) |
| leftGridView.verticalScrollPosition = vsp; |
| } |
| |
| _verticalScrollPosition = value; |
| } |
| |
| //---------------------------------- |
| // hoverIndicator |
| //---------------------------------- |
| |
| private var _hoverIndicator:IFactory = null; |
| |
| [Bindable("hoverIndicatorChanged")] |
| |
| /** |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>. |
| * a single visual element displayed for the row under the mouse. |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, |
| * the visual element for the cell. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get hoverIndicator():IFactory |
| { |
| return _hoverIndicator; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set hoverIndicator(value:IFactory):void |
| { |
| if (_hoverIndicator == value) |
| return; |
| |
| _hoverIndicator = value; |
| invalidateDisplayListFor("hoverIndicator"); |
| dispatchChangeEvent("hoverIndicatorChanged"); |
| } |
| |
| //---------------------------------- |
| // hoverColumnIndex |
| //---------------------------------- |
| |
| private var _hoverColumnIndex:int = -1; |
| |
| [Bindable("hoverColumnIndexChanged")] |
| |
| /** |
| * If <code>showHoverIndicator</code> is <code>true</code>, |
| * Specifies column index of the <code>hoverIndicator</code>. |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, then the indicator |
| * occupies the entire row and <code>hoverColumnIndex</code> is ignored. |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code> then the <code>hoverIndicator</code> |
| * occupies the specified cell. |
| * |
| * <p>Setting <code>hoverColumnIndex</code> to -1 (the default) means |
| * that the column index is undefined and a cell hover indicator is not displayed.</p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get hoverColumnIndex():int |
| { |
| return _hoverColumnIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set hoverColumnIndex(value:int):void |
| { |
| if (_hoverColumnIndex == value) |
| return; |
| |
| _hoverColumnIndex = value; |
| |
| // Unconditionally invalidate because renderers may depend on |
| // hoverColumnIndex even when the hoverIndicator doesn't exist. |
| invalidateDisplayListFor("hoverIndicator"); |
| dispatchChangeEvent("hoverColumnIndexChanged"); |
| } |
| |
| //---------------------------------- |
| // hoverRowIndex |
| //---------------------------------- |
| |
| private var _hoverRowIndex:int = -1; |
| |
| [Bindable("hoverRowIndexChanged")] |
| |
| /** |
| * If <code>showHoverIndicator</code> is <code>true</code>, |
| * specifies the column index of the <code>hoverIndicator</code>. |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, then the indicator |
| * occupies the entire row and <code>hoverColumnIndex</code> is ignored. |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code> then the <code>hoverIndicator</code> |
| * occupies the specified cell. |
| * |
| * <p>Setting <code>hoverRowIndex</code> to -1,the default, means that |
| * the row index is undefined and a hover indicator is not displayed.</p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get hoverRowIndex():int |
| { |
| return _hoverRowIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set hoverRowIndex(value:int):void |
| { |
| if (_hoverRowIndex == value) |
| return; |
| |
| _hoverRowIndex = value; |
| |
| // Unconditionally invalidate because renderers may depend on |
| // hoverRowIndex even when the hoverIndicator doesn't exist. |
| invalidateDisplayListFor("hoverIndicator"); |
| dispatchChangeEvent("hoverRowIndexChanged"); |
| } |
| |
| //---------------------------------- |
| // columns |
| //---------------------------------- |
| |
| private var _columns:IList = null; |
| private var columnsChanged:Boolean = false; |
| |
| [Bindable("columnsChanged")] |
| [Inspectable(category="General")] |
| |
| /** |
| * The list of GridColumn objectss displayed by this grid. |
| * Each column selects different data provider item properties |
| * to display. |
| * |
| * <p>GridColumn objects can only appear in the <code>columns</code> |
| * for a single Grid control.</p> |
| * |
| * @default null |
| * |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get columns():IList |
| { |
| return _columns; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set columns(value:IList):void |
| { |
| if (_columns == value) |
| return; |
| |
| // Remove the old column listener, and set each column's grid=null, columnIndex=-1. |
| |
| const oldColumns:IList = _columns; |
| if (oldColumns) |
| { |
| oldColumns.removeEventListener(CollectionEvent.COLLECTION_CHANGE, columns_collectionChangeHandler); |
| for (var index:int = 0; index < oldColumns.length; index++) |
| { |
| var oldColumn:GridColumn = GridColumn(oldColumns.getItemAt(index)); |
| oldColumn.setGrid(null); |
| oldColumn.setColumnIndex(-1); |
| } |
| } |
| |
| _columns = value; |
| |
| // Add the new columns listener, and set their grid,columnIndex properties. |
| // The listener is a local method, so creating a weak reference to it (last |
| // addEventListener parameter) is safe, since the listener's lifetime is the |
| // same as this object. |
| |
| const newColumns:IList = _columns; |
| if (newColumns) |
| { |
| newColumns.addEventListener(CollectionEvent.COLLECTION_CHANGE, columns_collectionChangeHandler, false, 0, true); |
| for (index = 0; index < newColumns.length; index++) |
| { |
| var newColumn:GridColumn = GridColumn(newColumns.getItemAt(index)); |
| newColumn.setGrid(this); |
| newColumn.setColumnIndex(index); |
| } |
| } |
| |
| columnsChanged = true; |
| generatedColumns = false; |
| invalidateProperties(); |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| dispatchChangeEvent("columnsChanged"); |
| } |
| |
| /** |
| * @private |
| */ |
| private function getColumnsLength():uint |
| { |
| const columns:IList = columns; |
| return (columns) ? columns.length : 0; |
| } |
| |
| /** |
| * @private |
| * This method is similar to mx.controls.DataGrid/ls(). |
| */ |
| private function generateColumns():IList |
| { |
| var item:Object = typicalItem; |
| if (!item && dataProvider && (dataProvider.length > 0)) |
| item = dataProvider.getItemAt(0); |
| |
| var itemColumns:IList = null; |
| if (item) |
| { |
| itemColumns = new ArrayList(); |
| const classInfo:Object = ObjectUtil.getClassInfo(item, ["uid", "mx_internal_uid"]); |
| if (classInfo) |
| { |
| for each (var property:QName in classInfo.properties) |
| { |
| var column:GridColumn = new GridColumn(); |
| column.dataField = property.localName; |
| itemColumns.addItem(column); |
| } |
| } |
| } |
| |
| return itemColumns; |
| } |
| |
| //---------------------------------- |
| // dataProvider |
| //---------------------------------- |
| |
| private var _dataProvider:IList = null; |
| private var dataProviderChanged:Boolean; |
| |
| [Bindable("dataProviderChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * A list of data items that correspond to the rows in the grid. |
| * Each grid column is associated with a property of the |
| * data items to display that property in the grid <i>cells</i>. |
| * |
| * @default null |
| * |
| * @see spark.components.Grid#columns |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataProvider():IList |
| { |
| return _dataProvider; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataProvider(value:IList):void |
| { |
| if (_dataProvider == value) |
| return; |
| |
| const oldDataProvider:IList = dataProvider; |
| if (oldDataProvider) |
| oldDataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE, dataProvider_collectionChangeHandler); |
| |
| _dataProvider = value; |
| |
| // The listener is a local method, so creating a weak reference to it (last addEventListener |
| // parameter) is safe, since the listener's lifetime is the same as this object. |
| |
| const newDataProvider:IList = dataProvider; |
| if (newDataProvider) |
| newDataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE, dataProvider_collectionChangeHandler, false, 0, true); |
| |
| dataProviderChanged = true; |
| invalidateProperties(); |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| dispatchChangeEvent("dataProviderChanged"); |
| } |
| |
| //---------------------------------- |
| // dataTipField |
| //---------------------------------- |
| |
| private var _dataTipField:String = null; |
| |
| [Bindable("dataTipFieldChanged")] |
| [Inspectable(category="Data", defaultValue="null")] |
| |
| /** |
| * @copy spark.components.gridClasses.GridColumn#dataTipField |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataTipField():String |
| { |
| return _dataTipField; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataTipField(value:String):void |
| { |
| if (_dataTipField == value) |
| return; |
| |
| _dataTipField = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("dataTipFieldChanged"); |
| } |
| |
| //---------------------------------- |
| // dataTipFunction |
| //---------------------------------- |
| |
| private var _dataTipFunction:Function = null; |
| |
| [Bindable("dataTipFunctionChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * @copy spark.components.gridClasses.GridColumn#dataTipFunction |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataTipFunction():Function |
| { |
| return _dataTipFunction; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataTipFunction(value:Function):void |
| { |
| if (_dataTipFunction == value) |
| return; |
| |
| _dataTipFunction = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("dataTipFunctionChanged"); |
| } |
| |
| |
| //---------------------------------- |
| // doubleClickMode |
| //---------------------------------- |
| private var _doubleClickMode:String = GridDoubleClickMode.ROW; |
| |
| [Bindable("doubleClickModeChanged")] |
| [Inspectable(category="General", enumeration="cell,grid,row", defaultValue="row")] |
| |
| /** |
| * The doubleClick mode of the control. Possible values are: |
| * <code>GridDoubleClickMode.CELL</code>, |
| * <code>GridDoubleClickMode.GRID</code>, |
| * <code>GridDoubleClickMode.ROW</code>, |
| * |
| * <p>Changing the doubleClickMode changes the double click |
| * criteria for firing the doubleClick event</p> |
| * |
| * @default GridDoubleClickMode.ROW |
| * |
| * @see spark.components.gridClasses.GridDoubleClickMode |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function get doubleClickMode():String |
| { |
| return _doubleClickMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set doubleClickMode(newValue:String):void |
| { |
| if (newValue == _doubleClickMode) |
| { |
| return; |
| } |
| |
| switch(newValue) |
| { |
| case GridDoubleClickMode.CELL: |
| case GridDoubleClickMode.GRID: |
| case GridDoubleClickMode.ROW: |
| { |
| _doubleClickMode = newValue; |
| |
| dispatchChangeEvent("doubleClickModeChanged"); |
| |
| break; |
| } |
| } |
| } |
| |
| |
| //---------------------------------- |
| // gridDimensions (mx_internal) |
| //---------------------------------- |
| |
| private var _gridDimensions:GridDimensions = null; |
| |
| mx_internal function get gridDimensions():GridDimensions |
| { |
| if (!_gridDimensions) |
| _gridDimensions = new GridDimensions(); |
| |
| return _gridDimensions; |
| } |
| |
| //---------------------------------- |
| // itemRenderer |
| //---------------------------------- |
| |
| private var _itemRenderer:IFactory = null; |
| private var itemRendererChanged:Boolean = false; |
| |
| [Bindable("itemRendererChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * The item renderer that's used for columns that do not specify one. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get itemRenderer():IFactory |
| { |
| return _itemRenderer; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set itemRenderer(value:IFactory):void |
| { |
| if (_itemRenderer == value) |
| return; |
| |
| _itemRenderer = value; |
| |
| itemRendererChanged = true; |
| invalidateProperties(); |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| dispatchChangeEvent("itemRendererChanged"); |
| } |
| |
| //---------------------------------- |
| // columnSeparator |
| //---------------------------------- |
| |
| private var _columnSeparator:IFactory = null; |
| |
| [Bindable("columnSeparatorChanged")] |
| |
| /** |
| * A visual element displayed between each column. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get columnSeparator():IFactory |
| { |
| return _columnSeparator; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set columnSeparator(value:IFactory):void |
| { |
| if (_columnSeparator == value) |
| return; |
| |
| _columnSeparator = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("columnSeparatorChanged"); |
| } |
| |
| //---------------------------------- |
| // gridSelection (mx_internal) |
| //---------------------------------- |
| |
| private var _gridSelection:GridSelection; |
| |
| /** |
| * @private |
| */ |
| mx_internal function get gridSelection():GridSelection |
| { |
| if (!_gridSelection) |
| _gridSelection = createGridSelection(); |
| |
| return _gridSelection; |
| } |
| |
| /** |
| * @private |
| * If this Grid is serving as a DataGrid skin part, then this property is created |
| * by DataGrid/partAdded() and then set here. It is only set once, unless that |
| * "grid" part is removed, at which point it's set to null. |
| */ |
| mx_internal function set gridSelection(value:GridSelection):void |
| { |
| _gridSelection = value; |
| } |
| |
| //---------------------------------- |
| // dataGrid |
| //---------------------------------- |
| |
| private var _dataGrid:DataGrid = null; |
| |
| [Bindable("dataGridChanged")] |
| |
| /** |
| * The DataGrid control for which this Grid is used as the grid skin part. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataGrid():DataGrid |
| { |
| return _dataGrid; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataGrid(value:DataGrid):void |
| { |
| if (_dataGrid == value) |
| return; |
| |
| _dataGrid = value; |
| dispatchChangeEvent("dataGridChanged"); |
| } |
| |
| //---------------------------------- |
| // lockedColumnCount |
| //---------------------------------- |
| |
| private var _lockedColumnCount:int = 0; |
| |
| [Bindable("lockedColumnCountChanged")] |
| [Inspectable(category="General", defaultValue="0", minValue="0")] |
| |
| /** |
| * The first lockedColumnCount columns are "locked", i.e. they do not scroll horizontally. |
| * If lockedColumnCount is zero (the default) then changes to the horizontalScrollPosition |
| * affect all columns. |
| * |
| * <p>The locked columns are displayed in the topGridView and, if lockedRowCount is also |
| * greater than zero, the topLeftGridView. The locked columns are separated from the remaining |
| * columns by a lockedColumnSeparator.</p> |
| * |
| * @default 0 |
| * |
| * @see spark.components.gridClasses.GridColumn#topGridView |
| * @see spark.components.gridClasses.GridColumn#topLeftGridView |
| * @see spark.components.gridClasses.GridColumn#lockedColumnSeparator |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public function get lockedColumnCount():int |
| { |
| return _lockedColumnCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedColumnCount(value:int):void |
| { |
| if (_lockedColumnCount == value) |
| return; |
| |
| invalidateProperties(); |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| _lockedColumnCount = value; |
| dispatchChangeEvent("lockedColumnCountChanged"); |
| } |
| |
| //---------------------------------- |
| // lockedColumnsSeparator |
| //---------------------------------- |
| |
| private var _lockedColumnsSeparator:IFactory = null; |
| |
| [Bindable("lockedColumnsSeparatorChanged")] |
| |
| /** |
| * A visual element displayed between the locked and unlocked columns. The factory value of this |
| * property is used to create the lockedColumnsSeparatorElement. |
| * |
| * @see spark.components.Grid#lockedRowsSeparatorElement |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| * |
| * @default null |
| */ |
| public function get lockedColumnsSeparator():IFactory |
| { |
| return _lockedColumnsSeparator; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedColumnsSeparator(value:IFactory):void |
| { |
| if (_lockedColumnsSeparator == value) |
| return; |
| |
| _lockedColumnsSeparator = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("lockedColumnsSeparatorChanged"); |
| } |
| |
| //---------------------------------- |
| // lockedRowCount |
| //---------------------------------- |
| |
| private var _lockedRowCount:int = 0; |
| |
| [Bindable("lockedRowCountChanged")] |
| [Inspectable(category="General", defaultValue="0", minValue="0")] |
| |
| /** |
| * The first lockedRowCount rows are "locked", i.e. they do not scroll vertically. |
| * If lockedRowCount is zero (the default) then changes to the verticalScrollPosition |
| * affect all rows. |
| * |
| * <p>The locked rows are displayed in the leftGridView and, if lockedColumnCount is also |
| * greater than zero, the topLeftGridView. The locked rows are separated from the remaining |
| * rows by a lockedRowSeparator.</p> |
| * |
| * @default 0 |
| * |
| * @see spark.components.gridClasses.GridColumn#leftGridView |
| * @see spark.components.gridClasses.GridColumn#topLeftGridView |
| * @see spark.components.gridClasses.GridColumn#lockedRowSeparator |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public function get lockedRowCount():int |
| { |
| return _lockedRowCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedRowCount(value:int):void |
| { |
| if (_lockedRowCount == value) |
| return; |
| |
| invalidateProperties(); |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| _lockedRowCount = value; |
| dispatchChangeEvent("lockedRowCountChanged"); |
| } |
| |
| //---------------------------------- |
| // lockedRowsSeparator |
| //---------------------------------- |
| |
| private var _lockedRowsSeparator:IFactory = null; |
| |
| [Bindable("lockedRowsSeparatorChanged")] |
| |
| /** |
| * A visual element displayed between the locked and unlocked rows. The factory value of this |
| * property is used to create the lockedRowsSeparatorElement. |
| * |
| * @default null |
| * |
| * @see spark.components.Grid#lockedRowsSeparatorElement |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public function get lockedRowsSeparator():IFactory |
| { |
| return _lockedRowsSeparator; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedRowsSeparator(value:IFactory):void |
| { |
| if (_lockedRowsSeparator == value) |
| return; |
| |
| _lockedRowsSeparator = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("lockedRowsSeparatorChanged"); |
| } |
| |
| //---------------------------------- |
| // preserveSelection (delegates to gridSelection.preserveSelection) |
| //---------------------------------- |
| |
| [Inspectable(category="General", defaultValue="true")] |
| |
| /** |
| * If <code>true</code>, the selection is preserved when the data provider |
| * refreshes its collection. |
| * Because this refresh requires each item in the selection to be saved, |
| * this action is not desirable if the selection is large. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get preserveSelection():Boolean |
| { |
| return gridSelection.preserveSelection; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set preserveSelection(value:Boolean):void |
| { |
| gridSelection.preserveSelection = value; |
| } |
| |
| //---------------------------------- |
| // requestedMaxRowCount |
| //---------------------------------- |
| |
| private var _requestedMaxRowCount:int = 10; |
| |
| [Inspectable(category="General", defaultValue="10", minValue="-1")] |
| |
| /** |
| * The measured height of the grid is large enough to display |
| * no more than <code>requestedMaxRowCount</code> rows. |
| * |
| * <p>This property has no effect if any of the following are true; |
| * <ul> |
| * <li><code>requestedRowCount</code> is set.</li> |
| * <li>The actual size of the grid has been explicitly set.</li> |
| * </ul> |
| * </p> |
| * |
| * @default 10 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedMaxRowCount():int |
| { |
| return _requestedMaxRowCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedMaxRowCount(value:int):void |
| { |
| if (_requestedMaxRowCount == value) |
| return; |
| |
| _requestedMaxRowCount = value; |
| invalidateSize(); |
| } |
| |
| //---------------------------------- |
| // requestedMinRowCount |
| //---------------------------------- |
| |
| private var _requestedMinRowCount:int = -1; |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * The measured height of this grid is large enough to display |
| * at least <code>requestedMinRowCount</code> rows. |
| * |
| * <p>This property has no effect if any of the following are true; |
| * <ul> |
| * <li><code>requestedRowCount</code> is set.</li> |
| * <li>The actual size of the grid has been explicitly set.</li> |
| * </ul> |
| * </p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedMinRowCount():int |
| { |
| return _requestedMinRowCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedMinRowCount(value:int):void |
| { |
| if (_requestedMinRowCount == value) |
| return; |
| |
| _requestedMinRowCount = value; |
| invalidateSize(); |
| } |
| |
| //---------------------------------- |
| // requestedRowCount |
| //---------------------------------- |
| |
| private var _requestedRowCount:int = -1; |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * The measured height of this grid is large enough to display |
| * the first <code>requestedRowCount</code> rows. |
| * |
| * <p>If <code>requestedRowCount</code> is -1, then the measured |
| * size will be big enough for all of the layout elements.</p> |
| * |
| * <p>If the actual size of the grid has been explicitly set, |
| * then this property has no effect.</p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4 |
| */ |
| public function get requestedRowCount():int |
| { |
| return _requestedRowCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedRowCount(value:int):void |
| { |
| if (_requestedRowCount == value) |
| return; |
| |
| _requestedRowCount = value; |
| invalidateSize(); |
| } |
| |
| //---------------------------------- |
| // requestedMinColumnCount |
| //---------------------------------- |
| |
| private var _requestedMinColumnCount:int = -1; |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * The measured width of this grid is large enough to display |
| * at least <code>requestedMinColumnCount</code> columns. |
| * |
| * <p>This property has no effect if any of the following are true; |
| * <ul> |
| * <li><code>requestedColumnCount</code> is set.</li> |
| * <li>The actual size of the grid has been explicitly set.</li> |
| * <li>The grid is inside a Scroller component.</li> |
| * </ul> |
| * </p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedMinColumnCount():int |
| { |
| return _requestedMinColumnCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedMinColumnCount(value:int):void |
| { |
| if (_requestedMinColumnCount == value) |
| return; |
| |
| _requestedMinColumnCount = value; |
| invalidateSize(); |
| } |
| |
| //---------------------------------- |
| // requestedColumnCount |
| //---------------------------------- |
| |
| private var _requestedColumnCount:int = -1; |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * The measured width of this grid is large enough to display |
| * the first <code>requestedColumnCount</code> columns. |
| * If <code>requestedColumnCount</code> is -1, then the measured |
| * width is big enough for all of the columns. |
| * |
| * <p>If the actual size of the grid has been explicitly set, |
| * then this property has no effect.</p> |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedColumnCount():int |
| { |
| return _requestedColumnCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedColumnCount(value:int):void |
| { |
| if (_requestedColumnCount == value) |
| return; |
| |
| _requestedColumnCount = value; |
| invalidateSize(); |
| } |
| |
| //---------------------------------- |
| // requireSelection |
| //---------------------------------- |
| |
| [Inspectable(category="General", defaultValue="false")] |
| |
| /** |
| * If <code>true</code> and the <code>selectionMode</code> property is not |
| * <code>GridSelectionMode.NONE</code>, an item must always be selected |
| * in the grid. |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requireSelection():Boolean |
| { |
| return gridSelection.requireSelection; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requireSelection(value:Boolean):void |
| { |
| gridSelection.requireSelection = value; |
| |
| if (value) |
| invalidateDisplayListFor("selectionIndicator"); |
| } |
| |
| //---------------------------------- |
| // resizableColumns |
| //---------------------------------- |
| |
| private var _resizableColumns:Boolean = true; |
| |
| [Bindable("resizableColumnsChanged")] |
| [Inspectable(category="General", defaultValue="true")] |
| |
| /** |
| * Indicates whether the user can change the size of the columns. |
| * If <code>true</code>, the user can stretch or shrink the columns of |
| * the DataGrid control by dragging the grid lines between the header cells. |
| * If <code>true</code>, individual columns must also have their |
| * <code>resizable</code> properties set to <code>false</code> to |
| * prevent the user from resizing a particular column. |
| * |
| * @default true |
| * |
| * @see spark.components.gridClasses.GridColumn |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get resizableColumns():Boolean |
| { |
| return _resizableColumns; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set resizableColumns(value:Boolean):void |
| { |
| if (value == resizableColumns) |
| return; |
| |
| _resizableColumns = value; |
| dispatchChangeEvent("resizableColumnsChanged"); |
| } |
| |
| //---------------------------------- |
| // rowBackground |
| //---------------------------------- |
| |
| private var _rowBackground:IFactory = null; |
| |
| [Bindable("rowBackgroundChanged")] |
| |
| /** |
| * A visual element that's displays the background for each row. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get rowBackground():IFactory |
| { |
| return _rowBackground; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set rowBackground(value:IFactory):void |
| { |
| if (_rowBackground == value) |
| return; |
| |
| _rowBackground = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("rowBackgroundChanged"); |
| } |
| |
| //---------------------------------- |
| // rowHeight |
| //---------------------------------- |
| |
| private var _rowHeight:Number = NaN; |
| private var rowHeightChanged:Boolean; |
| |
| [Bindable("rowHeightChanged")] |
| [Inspectable(category="General", minValue="0.0")] |
| |
| /** |
| * If <code>variableRowHeight</code> is <code>false</code>, then |
| * this property specifies the actual height of each row, in pixels. |
| * |
| * <p>If <code>variableRowHeight</code> is <code>true</code>, |
| * the value of this property is used as the estimated |
| * height for rows that haven't been scrolled into view yet, rather |
| * than the preferred height of renderers configured with the <code>typicalItem</code>. |
| * Similarly, when the Grid pads its display with empty rows, this property |
| * specifies the empty rows' height.</p> |
| * |
| * <p>If <code>variableRowHeight</code> is <code>false</code>, |
| * the default value of this property is the maximum preferred height |
| * of the per-column renderers created for the <code>typicalItem</code>.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get rowHeight():Number |
| { |
| return _rowHeight; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set rowHeight(value:Number):void |
| { |
| if (_rowHeight == value) |
| return; |
| |
| _rowHeight = value; |
| rowHeightChanged = true; |
| invalidateProperties(); |
| |
| dispatchChangeEvent("rowHeightChanged"); |
| } |
| |
| /** |
| * @private |
| */ |
| private function setFixedRowHeight(value:Number):void |
| { |
| if (_rowHeight == value) |
| return; |
| |
| _rowHeight = value; |
| dispatchChangeEvent("rowHeightChanged"); |
| } |
| |
| //---------------------------------- |
| // rowSeparator |
| //---------------------------------- |
| |
| private var _rowSeparator:IFactory = null; |
| |
| [Bindable("rowSeparatorChanged")] |
| |
| /** |
| * A visual element that's displayed in between each row. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get rowSeparator():IFactory |
| { |
| return _rowSeparator; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set rowSeparator(value:IFactory):void |
| { |
| if (_rowSeparator == value) |
| return; |
| |
| _rowSeparator = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("rowSeparatorChanged"); |
| } |
| |
| //---------------------------------- |
| // selectedCell |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELL</code> |
| * or <code>GridSelectionMode.MULTIPLE_CELLS</code>, returns the first |
| * selected cell starting at row 0 column 0 and progressing through each |
| * column in a row before moving to the next row. |
| * |
| * <p>When the user changes the selection by interacting with the |
| * control, the control dispatches the <code>selectionChange</code> |
| * event. When the user changes the selection programmatically, the |
| * control dispatches the <code>valueCommit</code> event.</p> |
| * |
| * <p> This property is intended to be used to initialize or bind to the |
| * selection in MXML markup. The <code>setSelectedCell()</code> method |
| * should be used for programatic selection updates, for example |
| * when writing a keyboard or mouse event handler. </p> |
| * |
| * @default null |
| * |
| * @return CellPosition of the first selected cell or null if there is |
| * no cell selection. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedCell():CellPosition |
| { |
| var selectedCells:Vector.<CellPosition> = gridSelection.allCells(); |
| return selectedCells.length ? selectedCells[0] : null; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedCell(value:CellPosition):void |
| { |
| const rowIndex:int = (value) ? value.rowIndex : -1; |
| const columnIndex:int = (value) ? value.columnIndex : -1; |
| |
| // Defer the selection change if we haven't been initialized |
| |
| if (!initialized) |
| { |
| // Append a deferred operation function that selects the specified cell |
| |
| var f:Function = function():void |
| { |
| if ((rowIndex != -1) && (columnIndex != -1)) |
| setSelectedCell(rowIndex, columnIndex); |
| else |
| clearSelection(); |
| } |
| |
| deferredOperations.push(f); // function f() to be called by commitProperties() |
| invalidateProperties(); |
| } |
| else |
| { |
| if ((rowIndex != -1) && (columnIndex != -1)) |
| setSelectedCell(rowIndex, columnIndex); |
| else |
| clearSelection(); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedCells |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELL</code> |
| * or <code>GridSelectionMode.MULTIPLE_CELLS</code>, returns a Vector |
| * of CellPosition objects representing the positions of the selected |
| * cells in the grid. |
| * |
| * <p>When the user changes the selection by interacting with the |
| * control, the control dispatches the <code>selectionChange</code> |
| * event. When the user changes the selection programmatically, the |
| * control dispatches the <code>valueCommit</code> event.</p> |
| * |
| * <p> This property is intended to be used to initialize or bind to the |
| * selection in MXML markup. The <code>setSelectedCell()</code> method |
| * should be used for programatic selection updates, for example when |
| * writing a keyboard or mouse event handler. </p> |
| * |
| * <p>The default value is an empty <code>Vector.<CellPosition></code></p> |
| * |
| * @return Vector of CellPosition objects where each element represents |
| * a selected cell. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedCells():Vector.<CellPosition> |
| { |
| return gridSelection.allCells(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedCells(value:Vector.<CellPosition>):void |
| { |
| // Defensively deep-copy the incoming value; tolerate value=null |
| |
| var valueCopy:Vector.<CellPosition> = new Vector.<CellPosition>(0); |
| if (value) |
| { |
| for each (var cell:CellPosition in value) |
| valueCopy.push(new CellPosition(cell.rowIndex, cell.columnIndex)); |
| } |
| |
| // Defer the selection change if we haven't been initialized |
| |
| if (!initialized) |
| { |
| // Append a deferred operation function that selects the specified cells |
| |
| var f:Function = function():void |
| { |
| doSetSelectedCells(valueCopy); |
| } |
| deferredOperations.push(f); // function f() to be called by commitProperties() |
| invalidateProperties(); |
| } |
| else |
| { |
| doSetSelectedCells(valueCopy); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedIndex |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General", defaultValue="-1")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> |
| * or <code>GridSelectionMode.MULTIPLE_ROWS</code>, returns the |
| * rowIndex of the first selected row. |
| * |
| * <p>When the user changes the selection by interacting with the |
| * control, the control dispatches the <code>selectionChange</code> |
| * event. When the user changes the selection programmatically, the |
| * control dispatches the <code>valueCommit</code> event.</p> |
| * |
| * <p> This property is intended to be used to initialize or bind to the |
| * selection in MXML markup. The <code>setSelectedCell()</code> method should be used |
| * for programatic selection updates, for example when writing a keyboard |
| * or mouse event handler. </p> |
| * |
| * @default -1 |
| * |
| * @return rowIndex of first selected row or -1 if there are no |
| * selected rows. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedIndex():int |
| { |
| var selectedRows:Vector.<int> = gridSelection.allRows(); |
| return (selectedRows.length > 0) ? selectedRows[0] : -1; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedIndex(value:int):void |
| { |
| // Defer the selection change if we haven't been initialized |
| |
| if (!initialized) |
| { |
| // Append a deferred operation function that selects the specified index |
| |
| var f:Function = function():void |
| { |
| if (value != -1) |
| setSelectedIndex(value); |
| else |
| clearSelection(); |
| } |
| deferredOperations.push(f); // function f() to be called by commitProperties() |
| invalidateProperties(); |
| } |
| else |
| { |
| if (value != -1) |
| setSelectedIndex(value); |
| else |
| clearSelection(); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedIndices |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> |
| * or <code>GridSelectionMode.MULTIPLE_ROWS</code>, returns a Vector of |
| * the selected rows indices. For all other selection modes, this |
| * method has no effect. |
| * |
| * <p>When the user changes the selection by interacting with the |
| * control, the control dispatches the <code>selectionChange</code> |
| * event. When the user changes the selection programmatically, the |
| * control dispatches the <code>valueCommit</code> event.</p> |
| * |
| * <p> This property is intended to be used to initialize or bind to the |
| * selection in MXML markup. The setSelectedCell() method should be used |
| * for programatic selection updates, for example when writing a keyboard |
| * or mouse event handler. </p> > |
| * |
| * <p>The default value is an empty <code>Vector.<int></code></p> |
| * |
| * @return Vector of ints where each element is the index in |
| * data provider of the selected row. |
| * |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedIndices():Vector.<int> |
| { |
| return gridSelection.allRows(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedIndices(value:Vector.<int>):void |
| { |
| // Defensively copy the incoming value; tolerate value=null |
| |
| const valueCopy:Vector.<int> = (value) ? value.concat() : new Vector.<int>(0); |
| |
| // Defer the selection change if we haven't been initialized |
| |
| if (!initialized) |
| { |
| // Append a deferred operation function that selects the specified indices |
| |
| var f:Function = function():void |
| { |
| doSetSelectedIndices(valueCopy); |
| } |
| deferredOperations.push(f); // function f() to be called by commitProperties() |
| invalidateProperties(); |
| } |
| else |
| { |
| doSetSelectedIndices(valueCopy); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedItem |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General", defaultValue="null")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> |
| * or <code>GridSelectionMode.MULTIPLE_ROWS</code>, returns the |
| * item in the the data provider that is currently selected or |
| * <code>undefined</code> if no rows are selected. |
| * |
| * <p>When the user changes the selection by interacting with the |
| * control, the control dispatches the <code>selectionChange</code> |
| * event. When the user changes the selection programmatically, the |
| * control dispatches the <code>valueCommit</code> event.</p> |
| * |
| * <p> This property is intended to be used to initialize or bind to the |
| * selection in MXML markup. The <code>setSelectedCell()</code> method should be used |
| * for programatic selection updates, for example when writing a keyboard |
| * or mouse event handler. </p> |
| * |
| * @default null |
| * |
| * @return Vector of data provider items. |
| * |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedItem():Object |
| { |
| var rowIndex:int = selectedIndex; |
| if (rowIndex == -1) |
| return undefined; |
| |
| return getDataProviderItem(rowIndex); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedItem(value:Object):void |
| { |
| // Defer the selection change if we haven't been initialized |
| |
| if (!initialized) |
| { |
| // Append a deferred operation function that selects the specified item |
| |
| var f:Function = function():void |
| { |
| if (!dataProvider) |
| return; |
| |
| const rowIndex:int = dataProvider.getItemIndex(value); |
| if (rowIndex == -1) |
| clearSelection(); |
| else |
| setSelectedIndex(rowIndex); |
| } |
| deferredOperations.push(f); // function f() to be called by commitProperties() |
| invalidateProperties(); |
| } |
| else |
| { |
| if (!dataProvider) |
| return; |
| |
| const rowIndex:int = dataProvider.getItemIndex(value); |
| if (rowIndex == -1) |
| clearSelection(); |
| else |
| setSelectedIndex(rowIndex); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedItems |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> |
| * or <code>GridSelectionMode.MULTIPLE_ROWS</code>, returns a Vector of |
| * the dataProvider items that are currently selected. |
| * |
| * <p>When the user changes the selection by interacting with the |
| * control, the control dispatches the <code>selectionChange</code> |
| * event. When the user changes the selection programmatically, the |
| * control dispatches the <code>valueCommit</code> event.</p> |
| * |
| * <p> This property is intended to be used to initialize or bind to the |
| * selection in MXML markup. The setSelectedCell() method should be used |
| * for programatic selection updates, for example when writing a keyboard |
| * or mouse event handler. </p> |
| * |
| * <p>The default value is an empty <code>Vector.<Object></code></p> |
| * |
| * @return Vector of data provider items. |
| * |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedItems():Vector.<Object> |
| { |
| var rowIndices:Vector.<int> = selectedIndices; |
| if (rowIndices.length == 0) |
| return undefined; |
| |
| var items:Vector.<Object> = new Vector.<Object>(); |
| |
| for each (var rowIndex:int in rowIndices) |
| items.push(dataProvider.getItemAt(rowIndex)); |
| |
| return items; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedItems(value:Vector.<Object>):void |
| { |
| // Defensively copy the incoming value; tolerate value=null |
| |
| const valueCopy:Vector.<Object> = (value) ? value.concat() : new Vector.<Object>(0); |
| |
| // Defer the selection change if we haven't been initialized |
| |
| if (!initialized) |
| { |
| // Append a deferred operation function that selects the specified items |
| |
| var f:Function = function():void |
| { |
| doSetSelectedItems(valueCopy); |
| } |
| deferredOperations.push(f); // function f() to be called by commitProperties() |
| invalidateProperties(); |
| } |
| else |
| { |
| doSetSelectedItems(valueCopy); |
| } |
| } |
| |
| //---------------------------------- |
| // selectionIndicator |
| //---------------------------------- |
| |
| private var _selectionIndicator:IFactory = null; |
| |
| [Bindable("selectionIndicatorChanged")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, |
| * a visual element that's displayed for each selected row, |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, |
| * a visual element displayed for each selected cell. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectionIndicator():IFactory |
| { |
| return _selectionIndicator; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectionIndicator(value:IFactory):void |
| { |
| if (_selectionIndicator == value) |
| return; |
| |
| _selectionIndicator = value; |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchChangeEvent("selectionIndicatorChanged"); |
| } |
| |
| //---------------------------------- |
| // selectionLength (delegates to gridSelection.selectionLength) |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> |
| * or <code>GridSelectionMode.MULTIPLE_ROWS</code>, |
| * returns the number of selected rows. |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELLS</code> |
| * or <code>GridSelectionMode.MULTIPLE_CELLS</code>, |
| * returns the number of selected cells. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectionLength():int |
| { |
| return gridSelection.selectionLength; |
| } |
| |
| //---------------------------------- |
| // selectionMode (delegates to gridSelection.selectionMode) |
| //---------------------------------- |
| |
| [Bindable("selectionModeChanged")] |
| [Inspectable(category="General", enumeration="none,singleRow,multipleRows,singleCell,multipleCells", defaultValue="singleRow")] |
| |
| /** |
| * The selection mode of the control. Possible values are: |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, |
| * <code>GridSelectionMode.NONE</code>, |
| * <code>GridSelectionMode.SINGLE_CELL</code>, and |
| * <code>GridSelectionMode.SINGLE_ROW</code>. |
| * |
| * <p>Changing the selectionMode causes the current selection to be |
| * cleared and the caretRowIndex and caretColumnIndex to be set to -1.</p> |
| * |
| * @default GridSelectionMode.SINGLE_ROW |
| * |
| * @see spark.components.gridClasses.GridSelectionMode |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectionMode():String |
| { |
| return gridSelection.selectionMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectionMode(value:String):void |
| { |
| if (selectionMode == value) |
| return; |
| |
| gridSelection.selectionMode = value; |
| if (selectionMode != value) // value wasn't a valid GridSelectionMode constant |
| return; |
| |
| initializeAnchorPosition(); |
| if (!requireSelection) |
| initializeCaretPosition(); |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| |
| dispatchChangeEvent("selectionModeChanged"); |
| } |
| |
| //---------------------------------- |
| // showCaret |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _showCaret:Boolean = false; |
| |
| [Bindable("showCaretChanged")] |
| |
| /** |
| * Determines if the caret is visible. |
| * TBD: when is this property automatically set? |
| */ |
| public function get showCaret():Boolean |
| { |
| return _showCaret; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showCaret(value:Boolean):void |
| { |
| if (_showCaret == value) |
| return; |
| |
| _showCaret = value; |
| invalidateDisplayListFor("caretIndicator"); |
| dispatchChangeEvent("showCaretChanged"); |
| } |
| |
| //---------------------------------- |
| // showDataTips |
| //---------------------------------- |
| |
| private var _showDataTips:Boolean = false; |
| |
| [Bindable("showDataTipsChanged")] |
| [Inspectable(category="Data", defaultValue="false")] |
| |
| /** |
| * If <code>true</code> then a dataTip is displayed for all visible cells. |
| * If <code>false</code>, the default, |
| * then a dataTip is only displayed if the column's |
| * <code>showDataTips</code> property is <code>true</code>. |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get showDataTips():Boolean |
| { |
| return _showDataTips; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showDataTips(value:Boolean):void |
| { |
| if (_showDataTips == value) |
| return; |
| |
| _showDataTips = value; |
| invalidateDisplayList(); |
| dispatchChangeEvent("showDataTipsChanged"); |
| } |
| |
| //---------------------------------- |
| // typicalItem |
| //---------------------------------- |
| |
| private var _typicalItem:Object = null; |
| private var typicalItemChanged:Boolean = false; |
| |
| [Bindable("typicalItemChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * The grid's layout ensures that columns whose width is not specified are wide |
| * enough to display an item renderer for this default data provider item. |
| * If a typical item is not specified, then the first data provider item is used. |
| * |
| * <p>Restriction: if the <code>typicalItem</code> is an IVisualItem, it must not |
| * also be a member of the data provider.</p> |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get typicalItem():Object |
| { |
| return _typicalItem; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set typicalItem(value:Object):void |
| { |
| if (_typicalItem == value) |
| return; |
| |
| _typicalItem = value; |
| invalidateTypicalItemRenderer(); |
| dispatchChangeEvent("typicalItemChanged"); |
| } |
| |
| /** |
| * Clears cached column width data that had been based on the |
| * <code>typicalItem</code> property, and requests a new layout pass. |
| * Call this method if some aspect of the <code>typicalItem</code> |
| * has changed that should be reflected by the Grid's layout. |
| * |
| * <p>This method is called automatically if the <code>typicalItem</code> |
| * is changed directly. That means if the property is set to a new value |
| * that is not "==" to current value.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.5 |
| */ |
| public function invalidateTypicalItemRenderer():void |
| { |
| typicalItemChanged = true; |
| invalidateProperties(); |
| invalidateSize(); |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // variableRowHeight |
| //---------------------------------- |
| |
| private var _variableRowHeight:Boolean = false; |
| private var variableRowHeightChanged:Boolean = false; |
| |
| [Bindable("variableRowHeightChanged")] |
| [Inspectable(category="General", defaultValue="false")] |
| |
| /** |
| * If <code>true</code>, each row's height is the maximum of |
| * preferred heights of the cells displayed so far. |
| * |
| * <p>If <code>false</code>, the height of each row is just |
| * the value of the <code>rowHeight</code> property. |
| * If <code>rowHeight</code> isn't specified, then the height of |
| * each row is defined by the <code>typicalItem</code> property.</p> |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get variableRowHeight():Boolean |
| { |
| return _variableRowHeight; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set variableRowHeight(value:Boolean):void |
| { |
| if (value == variableRowHeight) |
| return; |
| |
| _variableRowHeight = value; |
| variableRowHeightChanged = true; |
| invalidateProperties(); |
| |
| dispatchChangeEvent("variableRowHeightChanged"); |
| } |
| |
| //---------------------------------- |
| // gridView |
| //---------------------------------- |
| |
| private var _gridView:IFactory = null; |
| |
| [Bindable("gridViewChanged")] |
| |
| /** |
| * Used to initialize this grid's gridViews: centerGridView, leftGridView, topGridView, topLeftGridView. |
| * GridViews are created as needed, depending on the values of lockedRowCount and lockedColumnCount. |
| * |
| * @default null. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public function get gridView():IFactory |
| { |
| return _gridView; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set gridView(value:IFactory):void |
| { |
| if (value == _gridView) |
| return; |
| |
| _gridView = value; |
| invalidateProperties(); |
| |
| // TBD clear everything |
| |
| dispatchChangeEvent("gridViewChanged"); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // GridSelection Cover Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, selects all rows and |
| * removes the caret or if <code>selectionMode</code> is |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code> selects all cells |
| * and removes the caret. For all other selection modes, this method |
| * has no effect. |
| * |
| * <p>If items are added to the <code>dataProvider</code> or |
| * <code>columns</code> are added after this method is called, the |
| * new rows or cells in the new column will be selected.</p> |
| * |
| * <p>This implicit "selectAll" mode ends when any of the following occur: |
| * <ul> |
| * <li>selection is cleared using <code>clearSelection</code></li> |
| * <li>selection reset using one of <code>setSelectedCell</code>, |
| * <code>setSelectedCells</code>, <code>setSelectedIndex</code>, |
| * <code>selectIndices</code></li> |
| * <li><code>dataProvider</code> is refreshed and <code>preserveSelection</code> is false</li> |
| * <li><code>dataProvider</code> is reset</li> |
| * <li><code>columns</code> is refreshed, |
| * <code>preserveSelection</code> is <code>false</code> and |
| * <code>selectionMode</code> is |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code></li> |
| * <li><code>columns</code> is reset and <code>selectionMode</code> is |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code></li> |
| * </ul></p> |
| * |
| * @return <code>true</code> if the selection changed. |
| * |
| * @see spark.components.Grid#clearSelection |
| * @see spark.components.Grid#selectIndices |
| * @see spark.components.Grid#setSelectedCell |
| * @see spark.components.Grid#setSelectedCells |
| * @see spark.components.Grid#setSelectedIndex |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectAll():Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.selectAll(); |
| if (selectionChanged) |
| { |
| initializeCaretPosition(); |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * Removes all of the selected rows and cells, if <code>selectionMode</code> |
| * is not <code>GridSelectionMode.NONE</code>. Removes the caret and |
| * sets the anchor to the initial item. |
| * |
| * @return <code>true</code> if the selection changed. |
| * <code>false</code> if there was nothing previously selected. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function clearSelection():Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.removeAll(); |
| if (selectionChanged) |
| { |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| // Remove caret and reset the anchor. |
| initializeCaretPosition(); |
| initializeAnchorPosition(); |
| |
| return selectionChanged; |
| } |
| |
| //---------------------------------- |
| // selection for rows |
| //---------------------------------- |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_ROW</code> |
| * or <code>GridSelectionMode.MULTIPLE_ROWS</code>, returns <code>true</code> |
| * if the row at <code>index</code> is in the current selection. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the selected cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the row. |
| * |
| * @return <code>true</code> if the selection contains the row. |
| * |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectionContainsIndex(rowIndex:int):Boolean |
| { |
| return gridSelection.containsRow(rowIndex); |
| } |
| |
| /** |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, returns <code>true</code> |
| * if the rows in <code>indices</code> are in the current selection. |
| * |
| * @param rowIndices Vector of 0-based row indices to include in selection. |
| * |
| * @return <code>true</code> if the current selection contains these rows. |
| * |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectionContainsIndices(rowIndices:Vector.<int>):Boolean |
| { |
| return gridSelection.containsRows(rowIndices); |
| } |
| |
| /** |
| * If <code>selectionMode</code> |
| * is <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, sets the selection and |
| * the caret position to this row. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the selected cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @return <code>true</code> if if no errors. |
| * <code>false</code> if <code>index</code> is invalid, or |
| * the <code>selectionMode</code> is invalid. |
| * |
| * @see spark.components.Grid#caretColumnIndex |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function setSelectedIndex(rowIndex:int):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.setRow(rowIndex); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex; |
| caretColumnIndex = -1; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * If <code>selectionMode</code> |
| * is <code>GridSelectionMode.MULTIPLE_ROWS</code>, adds this row to |
| * the selection and sets the caret position to this row. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the selected cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @return <code>true</code> if no errors. |
| * <code>false</code> if <code>index</code> is invalid or |
| * the <code>selectionMode</code> is invalid. |
| * |
| * @see spark.components.Grid#caretColumnIndex |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function addSelectedIndex(rowIndex:int):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.addRow(rowIndex); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex; |
| caretColumnIndex = -1; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * If <code>selectionMode</code> |
| * is <code>GridSelectionMode.SINGLE_ROW</code> or |
| * <code>GridSelectionMode.MULTIPLE_ROWS</code>, removes this row |
| * from the selection and sets the caret position to this row. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the selected cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @return <code>true</code> if no errors. |
| * <code>false</code> if <code>index</code> is invalid or |
| * the <code>selectionMode</code> is invalid. |
| * |
| * @see spark.components.Grid#caretColumnIndex |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function removeSelectedIndex(rowIndex:int):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.removeRow(rowIndex); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex; |
| caretColumnIndex = -1; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.MULTIPLE_ROWS</code>, |
| * sets the selection to the specfied rows and the caret position to |
| * <code>endRowIndex</code>. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>Each index represents an item in the data provider |
| * to include in the selection.</p> |
| * |
| * @param rowIndex 0-based row index of the first row in the selection. |
| * |
| * @param rowCount Number of rows in the selection. |
| * |
| * @return <code>true</code> if no errors. |
| * <code>false</code> if any of the indices are invalid, |
| * if <code>startRowIndex</code> is not less than or equal to |
| * <code>endRowIndex</code>, or the <code>selectionMode</code> is invalid. |
| * |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectIndices(rowIndex:int, rowCount:int):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.setRows(rowIndex, rowCount); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex + rowCount - 1; |
| caretColumnIndex = -1; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| //---------------------------------- |
| // selection for cells |
| //---------------------------------- |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.SINGLE_CELL</code> |
| * or <code>GridSelectionMode.MULTIPLE_CELLS</code>, returns <code>true</code> |
| * if the cell is in the current selection. |
| * |
| * <p>The <code>rowIndex</code> must be between 0 and the |
| * length of the data provider. The <code>columnIndex</code> |
| * must be between 0 and the length of <code>columns</code>. </p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @param columnIndex The 0-based column index of the cell. |
| * |
| * @return <code>true</code> if the current selection contains the cell. |
| * |
| * @see spark.components.Grid#columns |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectionContainsCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| return gridSelection.containsCell(rowIndex, columnIndex); |
| } |
| |
| /** |
| * If <code>selectionMode</code> is |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, returns <code>true</code> |
| * if the cells in the cell region are in the current selection. |
| * |
| * <p>The <code>rowIndex</code> must be between 0 and the |
| * length of the data provider. The <code>columnIndex</code> |
| * must be between 0 and the length of <code>columns</code>. </p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @param columnIndex The 0-based column index of the cell. |
| * |
| * @param rowCount Number of rows, starting at <code>rowIndex</code> to |
| * include in the cell region. |
| * |
| * @param columnCount Number of columns, starting at |
| * <code>columnIndex</code> to include in the cell region. |
| * |
| * @return <code>true</code> if the current selection contains all |
| * the cells in the cell region. |
| * |
| * @see spark.components.Grid#columns |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectionContainsCellRegion(rowIndex:int, columnIndex:int, |
| rowCount:int, columnCount:int):Boolean |
| { |
| return gridSelection.containsCellRegion(rowIndex, columnIndex, |
| rowCount, columnCount); |
| } |
| |
| /** |
| * If <code>selectionMode</code> |
| * is <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, sets the selection |
| * and the caret position to this cell. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the selected cell. The <code>columnIndex</code> |
| * is the index in <code>columns</code> of the column containing the |
| * selected cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @param columnIndex The 0-based column index of the cell. |
| * |
| * @return <code>true</code> if no errors. |
| * <code>false</code> if <code>rowIndex</code> |
| * or <code>columnIndex</code> is invalid or the <code>selectionMode</code> |
| * is invalid. |
| * |
| * @see spark.components.Grid#caretColumnIndex |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#columns |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function setSelectedCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.setCell(rowIndex, columnIndex); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex; |
| caretColumnIndex = columnIndex; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * If <code>selectionMode</code> |
| * is <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, adds the cell to |
| * the selection and sets the caret position to the cell. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the selected cell. The <code>columnIndex</code> |
| * is the index in <code>columns</code> of the column containing the |
| * selected cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @param columnIndex The 0-based column index of the cell. |
| * |
| * @return <code>true</code> if no errors. |
| * <code>false</code> if <code>rowIndex</code> |
| * or <code>columnIndex</code> is invalid, or the <code>selectionMode</code> |
| * is invalid. |
| * |
| * @see spark.components.Grid#caretColumnIndex |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#columns |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function addSelectedCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.addCell(rowIndex, columnIndex); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex; |
| caretColumnIndex = columnIndex; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * If <code>selectionMode</code> |
| * is <code>GridSelectionMode.SINGLE_CELL</code> or |
| * <code>GridSelectionMode.MULTIPLE_CELLS</code>, removes the cell |
| * from the selection and sets the caret position to the cell. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the selected cell. The <code>columnIndex</code> |
| * is the index in <code>columns</code> of the column containing the |
| * selected cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the cell. |
| * |
| * @param columnIndex The 0-based column index of the cell. |
| * |
| * @return <code>true</code> if no errors. |
| * <code>false</code> if <code>rowIndex</code> |
| * or <code>columnIndex</code> is invalid or the <code>selectionMode</code> |
| * is invalid. |
| * |
| * @see spark.components.Grid#caretColumnIndex |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#columns |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function removeSelectedCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.removeCell(rowIndex, columnIndex); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex; |
| caretColumnIndex = columnIndex; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * If <code>selectionMode</code> is <code>GridSelectionMode.MULTIPLE_CELLS</code>, |
| * sets the selection to all the cells in the cell region and the |
| * caret position to the last cell in the cell region. |
| * For all other selection modes, this method has no effect. |
| * |
| * <p>The <code>rowIndex</code> is the index in the data provider |
| * of the item containing the origin of the cell region. |
| * The <code>columnIndex</code> |
| * is the index in <code>columns</code> of the column containing the |
| * origin of the cell region.</p> |
| * |
| * <p>This method has no effect if the cell region is not wholly |
| * contained within the grid.</p> |
| * |
| * @param rowIndex The 0-based row index of the origin of the cell region. |
| * |
| * @param columnIndex The 0-based column index of the origin of the cell |
| * region. |
| * |
| * @param rowCount Number of rows, starting at <code>rowIndex</code> to |
| * include in the cell region. |
| * |
| * @param columnCount Number of columns, starting at |
| * <code>columnIndex</code> to include in the cell region. |
| * |
| * @return <code>true</code> if no errors. |
| * <code>false</code> if the cell region is invalid or |
| * the <code>selectionMode</code> is invalid. |
| * |
| * @see spark.components.Grid#caretColumnIndex |
| * @see spark.components.Grid#caretRowIndex |
| * @see spark.components.Grid#columns |
| * @see spark.components.Grid#dataProvider |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectCellRegion(rowIndex:int, columnIndex:int, |
| rowCount:uint, columnCount:uint):Boolean |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| const selectionChanged:Boolean = gridSelection.setCellRegion( |
| rowIndex, columnIndex, |
| rowCount, columnCount); |
| if (selectionChanged) |
| { |
| caretRowIndex = rowIndex + rowCount - 1; |
| caretColumnIndex = columnIndex + columnCount - 1; |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Selection API Helper Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * For performance reasons, make sure validateClient, anchor and caret updates, |
| * and selectionIndicator and VALUE_COMMIT updates are only done once. |
| */ |
| private function doSetSelectedCells(valueCopy:Vector.<CellPosition>):void |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| gridSelection.removeAll(); |
| for each (var cell:CellPosition in valueCopy) |
| { |
| gridSelection.addCell(cell.rowIndex, cell.columnIndex); |
| } |
| |
| doFinalizeSetSelection(cell ? cell.rowIndex : -1, |
| cell ? cell.columnIndex : -1); |
| } |
| |
| /** |
| * For performance reasons, make sure validateClient, anchor and caret updates, |
| * and selectionIndicator and VALUE_COMMIT updates are only done once. |
| */ |
| private function doSetSelectedIndices(valueCopy:Vector.<int>):void |
| { |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| var newRowIndex:int = -1; |
| gridSelection.removeAll(); |
| for each (newRowIndex in valueCopy) |
| { |
| gridSelection.addRow(newRowIndex); |
| } |
| |
| doFinalizeSetSelection(newRowIndex, -1); |
| } |
| |
| /** |
| * For performance reasons, make sure validateClient, anchor and caret updates, |
| * and selectionIndicator and VALUE_COMMIT updates are only done once. |
| */ |
| private function doSetSelectedItems(valueCopy:Vector.<Object>):void |
| { |
| if (!dataProvider) |
| return; |
| |
| // Need to apply pending dataProvider and column changes so selection |
| // isn't reset after it is set here. |
| if (invalidatePropertiesFlag) |
| UIComponentGlobals.layoutManager.validateClient(this, false); |
| |
| var newRowIndex:int = -1; |
| gridSelection.removeAll(); |
| for each (var item:Object in valueCopy) |
| { |
| newRowIndex = dataProvider.getItemIndex(item); |
| gridSelection.addRow(newRowIndex); |
| } |
| |
| doFinalizeSetSelection(newRowIndex, -1); |
| } |
| |
| /** |
| * Finished selection operations so update the anchor, caret, selection indicators and |
| * trigger the selection bindings. |
| */ |
| private function doFinalizeSetSelection(rowIndex:int, columnIndex:int):void |
| { |
| initializeAnchorPosition(); |
| caretRowIndex = rowIndex |
| caretColumnIndex = columnIndex |
| |
| invalidateDisplayListFor("selectionIndicator"); |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // GridViewLayout Cover Methods, Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Update the scroll position so that the virtual Grid element at the specified |
| * index is visible. Note that getScrollPositionDeltaToElement() is only |
| * approximate when variableRowHeight=true, so calling this method once will |
| * not necessarily scroll far enough to expose the specified element. |
| * |
| * @returns True if either the horizontalScrollPosition or verticalScrollPosition changed. |
| */ |
| private function scrollToIndex(view:GridView, elementIndex:int, scrollHorizontally:Boolean, scrollVertically:Boolean):Boolean |
| { |
| var spDelta:Point = view.gridViewLayout.getScrollPositionDeltaToElement(elementIndex); |
| |
| // The cell is completely visible or the specified index is no longer valid so punt. |
| |
| if (!spDelta) |
| return false; |
| |
| // If the required scroll is locked then punt |
| |
| if ((spDelta.y != 0) && view.gridViewLayout.verticalScrollingLocked) |
| return false; |
| |
| if ((spDelta.x != 0) && view.gridViewLayout.horizontalScrollingLocked) |
| return false; |
| |
| // Update the scroll positions |
| |
| var scrollChanged:Boolean = false; |
| |
| if (scrollHorizontally) |
| { |
| horizontalScrollPosition += spDelta.x; |
| scrollChanged = spDelta.x != 0; |
| } |
| |
| if (scrollVertically) |
| { |
| verticalScrollPosition += spDelta.y; |
| scrollChanged = scrollChanged || spDelta.y != 0; |
| } |
| |
| return scrollChanged; |
| } |
| |
| /** |
| * If necessary, set the <code>verticalScrollPosition</code> and |
| * <code>horizontalScrollPosition</code> properties so that the |
| * specified cell is completely visible. |
| * If <code>rowIndex</code> is -1 and <code>columnIndex</code> is specified, |
| * then just adjust the <code>horizontalScrollPosition</code> |
| * so that the specified column is visible. |
| * If <code>columnIndex</code> is -1 and <code>rowIndex</code> |
| * is specified, then just adjust the <code>verticalScrollPosition</code> |
| * so that the specified row is visible. |
| * |
| * @param rowIndex The 0-based row index of the item renderer's cell, or -1 to specify a column. |
| * |
| * @param columnIndex The 0-based column index of the item renderer's cell, or -1 to specify a row. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function ensureCellIsVisible(rowIndex:int = -1, columnIndex:int = -1):void |
| { |
| const columns:IList = this.columns; |
| |
| // Check that each index is within range. |
| if (!columns || columnIndex < -1 || columnIndex >= columns.length || |
| !dataProvider || rowIndex < -1 || rowIndex >= dataProvider.length || |
| (columnIndex == -1 && rowIndex == -1)) |
| return; |
| |
| // Check to see if any columns are visible or specified column is visible. |
| if ((columnIndex == -1 && getNextVisibleColumnIndex(-1) == -1) || |
| (columnIndex != -1 && !(GridColumn(columns.getItemAt(columnIndex)).visible))) |
| return; |
| |
| const scrollHorizontally:Boolean = columnIndex != -1; |
| const scrollVertically:Boolean = rowIndex != -1; |
| |
| // If the row, column, or cell is locked, then there's nothing to do. |
| |
| if ((columnIndex < lockedColumnCount) && (rowIndex < lockedRowCount)) |
| return; |
| |
| if (!scrollVertically && (columnIndex < lockedColumnCount)) |
| return; |
| |
| if (!scrollHorizontally && (rowIndex < lockedRowCount)) |
| return; |
| |
| // If called after the layout cache is cleared, need to rebuild the cache |
| // before accessing visible rows/columns and attempting to scroll. |
| if (getVisibleRowIndices().length == 0 || getVisibleColumnIndices().length == 0) |
| validateNow(); |
| |
| // When not scrolling horizontally, columnIndex can just be 0. |
| if (!scrollHorizontally) |
| columnIndex = 0; |
| |
| // Find the GridView the specified cell is contained by and punt if it's not visible |
| |
| const cellGridView:GridView = getGridViewAt(rowIndex, columnIndex); |
| if (!cellGridView || |
| (cellGridView.getLayoutBoundsX() >= getLayoutBoundsWidth()) || |
| (cellGridView.getLayoutBoundsY() >= getLayoutBoundsHeight())) |
| return; |
| |
| // If the row index isn't specified, use the first one that's visible. |
| if (!scrollVertically) |
| { |
| const visibleRowIndices:Vector.<int> = cellGridView.gridViewLayout.getVisibleRowIndices(); |
| rowIndex = (visibleRowIndices.length > 0) ? visibleRowIndices[0] : 0; |
| } |
| |
| // A cell's index as defined by LayoutBase it's just its position |
| // in the row-major linear ordering of the grid's cells. |
| |
| const gridViewLayout:GridViewLayout = cellGridView.gridViewLayout; |
| const cellViewRowIndex:int = rowIndex - gridViewLayout.viewRowIndex; |
| const cellViewColumnIndex:int = columnIndex - gridViewLayout.viewColumnIndex; |
| const cellElementIndex:int = (cellViewRowIndex * gridViewLayout.columnsView.length) + cellViewColumnIndex; |
| |
| var scrollChanged:Boolean = false; |
| var firstScroll:Boolean = true; |
| |
| // Iterate until we've scrolled elementIndex at least partially into view. |
| do |
| { |
| scrollChanged = scrollToIndex(cellGridView, cellElementIndex, scrollHorizontally, scrollVertically); |
| |
| // Fixed row heights, and we're only scrolling vertically. |
| if (!variableRowHeight && !scrollHorizontally) |
| return; |
| |
| // Bail. This could indicate there is a bug but it avoids an infinite loop. |
| // scrollToIndex() then validateNow() then scrollToIndex() again and |
| // no changes in scroll position. |
| if (!firstScroll && !scrollChanged) |
| return; |
| |
| validateNow(); |
| |
| firstScroll = false; |
| } |
| while (!isCellVisible(scrollVertically ? rowIndex : -1, scrollHorizontally ? columnIndex : -1)); |
| |
| // At this point we've only ensured that the requested cell is at least |
| // partially visible. Ensure that it's completely visible. |
| |
| scrollToIndex(cellGridView, cellElementIndex, scrollHorizontally, scrollVertically); |
| } |
| |
| /** |
| * Return the data provider indices and padding indices of the |
| * currently visible rows. |
| * Indices which are greater than or equal to the |
| * <code>dataProvider</code> length represent padding rows. |
| * Note that the item renderers for the first and last rows |
| * may only be partially visible. |
| * The returned vector's contents are in the order they're displayed. |
| * |
| * @return A vector of the visible row indices. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getVisibleRowIndices():Vector.<int> |
| { |
| const gridLayout:GridLayout = layout as GridLayout; |
| const topGridView:GridView = gridLayout.topGridView; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| |
| if (!centerGridView) |
| return new Vector.<int>(0); |
| |
| const centerRowIndices:Vector.<int> = centerGridView.gridViewLayout.getVisibleRowIndices(); |
| if (!topGridView) |
| return centerRowIndices; |
| |
| const topRowIndices:Vector.<int> = topGridView.gridViewLayout.getVisibleRowIndices(); |
| return topRowIndices.concat(centerRowIndices); |
| } |
| |
| /** |
| * Return the indices of the currently visible columns. Note that the |
| * item renderers for the first and last columns may only be partially visible. |
| * The returned vector's contents are in the order they're displayed. |
| * |
| * <p>The following example function uses this method to compute a vector of |
| * visible GridColumn objects.</p> |
| * <pre> |
| * function getVisibleColumns():Vector.<GridColumn> |
| * { |
| * var visibleColumns = new Vector.<GridColumn>; |
| * for each (var columnIndex:int in grid.getVisibleColumnIndices()) |
| * visibleColumns.push(grid.columns.getItemAt(columnIndex)); |
| * return visibleColumns; |
| * } |
| * </pre> |
| * |
| * @return A vector of the visible column indices. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getVisibleColumnIndices():Vector.<int> |
| { |
| const gridLayout:GridLayout = layout as GridLayout; |
| const leftGridView:GridView = gridLayout.leftGridView; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| |
| const centerColumnIndices:Vector.<int> = centerGridView.gridViewLayout.getVisibleColumnIndices(); |
| if (!leftGridView) |
| return centerColumnIndices; |
| |
| const leftColumnIndices:Vector.<int> = leftGridView.gridViewLayout.getVisibleColumnIndices(); |
| return leftColumnIndices.concat(centerColumnIndices); |
| } |
| |
| /** |
| * Returns the current pixel bounds of the specified cell, or null if no such cell exists. |
| * Cell bounds are reported in grid coordinates. |
| * |
| * <p>If all of the columns for the the specfied row and all of the rows preceeding |
| * it have not yet been scrolled into view, the returned bounds may only be an approximation, |
| * based on all of the columns' <code>typicalItem</code>s.</p> |
| * |
| * @param rowIndex The 0-based index of the row. |
| * |
| * @param columnIndex The 0-based index of the column. |
| * |
| * @return A <code>Rectangle</code> that represents the cell's pixel bounds, or null. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getCellBounds(rowIndex:int, columnIndex:int):Rectangle |
| { |
| return gridDimensions.getCellBounds(rowIndex, columnIndex); |
| } |
| |
| /** |
| * Returns the current pixel bounds of the specified row, or null if no such row exists. |
| * Row bounds are reported in grid coordinates. |
| * |
| * <p>If all of the columns for the the specfied row and all of the rows preceeding |
| * it have not yet been scrolled into view, the returned bounds may only be an approximation, |
| * based on all of the columns' <code>typicalItem</code>s.</p> |
| * |
| * @param rowIndex The 0-based index of the row. |
| * |
| * @return A <code>Rectangle</code> that represents the row's pixel bounds, or null. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getRowBounds(rowIndex:int):Rectangle |
| { |
| return gridDimensions.getRowBounds(rowIndex); |
| } |
| |
| /** |
| * Returns the current pixel bounds of the specified column, or null if no such column exists. |
| * Column bounds are reported in grid coordinates. |
| * |
| * <p>If all of the cells in the specified column have not yet been scrolled into view, the |
| * returned bounds may only be an approximation, based on the column's <code>typicalItem</code>.</p> |
| * |
| * @param columnIndex The 0-based index of the column. |
| * |
| * @return A <code>Rectangle</code> that represents the column's pixel bounds, or null. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getColumnBounds(columnIndex:int):Rectangle |
| { |
| return gridDimensions.getColumnBounds(columnIndex); |
| } |
| |
| /** |
| * Returns the row index corresponding to the specified grid coordinates, |
| * or -1 if the coordinates are out of bounds. |
| * |
| * <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 x coordinate. |
| * |
| * @param y The y coordinate. |
| * |
| * @return The index of the row corresponding to the specified coordinates. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getRowIndexAt(x:Number, y:Number):int |
| { |
| return gridDimensions.getRowIndexAt(x, y); |
| } |
| |
| /** |
| * Returns the column index corresponding to the specified grid coordinates, |
| * or -1 if the coordinates are out of bounds. |
| * |
| * <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 grid. |
| * |
| * @param y The pixel's y coordinate relative to the grid. |
| * |
| * @return The index of the column, or -1 if the coordinates are out of bounds. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getColumnIndexAt(x:Number, y:Number):int |
| { |
| return gridDimensions.getColumnIndexAt(x, y); |
| } |
| |
| /** |
| * Return the width of the specified column. If the cell's entire bounds |
| * aren't needed, this method is more efficient than <code>getColumnBounds().width</code>. |
| * |
| * <p>If the specified column's width property isn't defined, then the returned value |
| * may only be an approximation. The actual column width is only computed after the column |
| * has been scrolled into view.</p> |
| * |
| * @param columnIndex The 0-based index of the column. |
| * @return The width of the specified column. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getColumnWidth(columnIndex:int):Number |
| { |
| const column:GridColumn = getGridColumn(columnIndex); |
| return (column && !isNaN(column.width)) ? column.width : gridDimensions.getColumnWidth(columnIndex); |
| } |
| |
| /** |
| * Return the row and column indices of the cell that overlaps the pixel at the |
| * specified grid coordinate. |
| * If no such cell exists, null is returned. |
| * |
| * <p>The example function below uses this method to compute the value of the |
| * <code>dataField</code> for a grid cell.</p> |
| * <pre> |
| * function getCellData(x:Number, y:Number):Object |
| * { |
| * var cell:CellPosition = getCellAt(x, y); |
| * if (!cell) |
| * return null; |
| * var GridColumn:column = grid.columns.getItemAt(cell.columnIndex); |
| * return grid.dataProvider.getItemAt(cell.rowIndex)[column.dataField]; |
| * } |
| * </pre> |
| * |
| * @param x The pixel's x coordinate relative to the grid. |
| * |
| * @param y The pixel's y coordinate relative to the grid. |
| * |
| * @return The cell position, or null. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getCellAt(x:Number, y:Number):CellPosition |
| { |
| const rowIndex:int = gridDimensions.getRowIndexAt(x, y); |
| const columnIndex:int = gridDimensions.getColumnIndexAt(x, y); |
| if ((rowIndex == -1) || (columnIndex == -1)) |
| return null; |
| return new CellPosition(rowIndex, columnIndex); |
| } |
| |
| /** |
| * Returns a vector of CellPosition objects whose |
| * <code>rowIndex</code> and <code>columnIndex</code> properties specify the |
| * row and column indices of the cells that overlap the specified grid region. |
| * If no such cells exist, an empty vector is returned. |
| * |
| * @param x The x coordinate of the pixel at the origin of the region, relative to the grid. |
| * |
| * @param x The x coordinate of the pixel at the origin of the region, relative to the grid. |
| * |
| * @param w The width of the region, in pixels. |
| * |
| * @param h The height of the region, in pixels. |
| * |
| * @return A vector of objects like <code>Vector.<Object>([{rowIndex:0, columnIndex:0}, ...])</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getCellsAt(x:Number, y:Number, w:Number, h:Number):Vector.<CellPosition> |
| { |
| var cells:Vector.<CellPosition> = new Vector.<CellPosition>; |
| |
| if (w <= 0 || h <= 0) |
| return cells; |
| |
| // Get the row/column indexes of the corners of the region. |
| var topLeft:CellPosition = getCellAt(x, y); |
| var bottomRight:CellPosition = getCellAt(x + w, y + h); |
| if (!topLeft || !bottomRight) |
| return cells; |
| |
| for (var rowIndex:int = topLeft.rowIndex; |
| rowIndex <= bottomRight.rowIndex; rowIndex++) |
| { |
| for (var columnIndex:int = topLeft.columnIndex; |
| columnIndex <= bottomRight.columnIndex; columnIndex++) |
| { |
| cells.push(new CellPosition(rowIndex, columnIndex)); |
| } |
| } |
| |
| return cells; |
| } |
| |
| /** |
| * Return the X coordinate of the specified cell's origin. If the cell's entire bounds |
| * aren't needed, this method is more efficient than <code>getCellBounds().x</code>. |
| * |
| * <p>If all of the columns for the the specfied row and all of the rows preceeding |
| * it have not yet been scrolled into view, the returned value may only be an approximation, |
| * based on all of the columns' <code>typicalItem</code>s.</p> |
| * |
| * @param rowIndex The 0-based index of the row. |
| * @param columnIndex The 0-based index of the column. |
| * @return The x coordindate of the specified cell's origin. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getCellX(rowIndex:int, columnIndex:int):Number |
| { |
| return gridDimensions.getCellX(rowIndex, columnIndex); |
| } |
| |
| /** |
| * Return the Y coordinate of the specified cell's origin. If the cell's entire bounds |
| * aren't needed, this method is more efficient than <code>getCellBounds().y</code>. |
| * |
| * <p>If all of the columns for the the specfied row and all of the rows preceeding |
| * it have not yet been scrolled into view, the returned value may only be an approximation, |
| * based on all of the columns' <code>typicalItem</code>s.</p> |
| * |
| * @param rowIndex The 0-based index of the row. |
| * @param columnIndex The 0-based index of the column. |
| * @return The y coordindate of the specified cell's origin. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getCellY(rowIndex:int, columnIndex:int):Number |
| { |
| return gridDimensions.getCellY(rowIndex, columnIndex); |
| } |
| |
| /** |
| * If the requested item renderer is visible, returns a reference to |
| * the item renderer currently displayed at the specified cell. |
| * Note that once the returned item renderer is no longer visible it may be |
| * recycled and its properties reset. |
| * |
| * <p>If the requested item renderer is not visible. then |
| * each time this method is called, a new item renderer is created. |
| * The new item renderer is not visible</p> |
| * |
| * <p>If the specified column does not have an explicit width, then the width |
| * of this cell is based on the <code>typicalItem</code>. |
| * If a <code>typicalItem</code> was not specified or has not been measured yet, |
| * then the item renderer's width defaults to <code>150</code>.</p> |
| * |
| * <p>If the grid property <code>variableRowHeight</code> is |
| * <code>true</code> (the default) and an overall row height hasn't been |
| * cached for the specified row, then the item renderer's height is based |
| * on the <code>typicalItem</code>. |
| * If the <code>typicalItem</code> was not |
| * specified or has not been measured yet, then the item renderer's height |
| * defaults to its preferred height.</p> |
| * |
| * @param rowIndex The 0-based row index of the item renderer's cell. |
| * |
| * @param columnIndex The 0-based column index of the item renderer's cell. |
| * |
| * @return The item renderer or null if the cell location is invalid. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function getItemRendererAt(rowIndex:int, columnIndex:int):IGridItemRenderer |
| { |
| const view:GridView = getGridViewAt(rowIndex, columnIndex); |
| if (!view) |
| return null; |
| |
| return view.gridViewLayout.getItemRendererAt(rowIndex, columnIndex); |
| } |
| |
| /** |
| * Returns <code>true</code> if the specified cell is at least partially visible. |
| * If <code>columnIndex == -1</code>, then return |
| * <code>true</code> if the specified row is at least partially visible. |
| * If <code>rowIndex == -1</code>, then return <code>true</code> |
| * if the specified column is at least partially visible. |
| * If both <code>columnIndex</code> and <code>rowIndex</code> are -1, |
| * then return <code>false</code>. |
| * |
| * @param rowIndex The 0-based row index of the item renderer's cell. |
| * |
| * @param columnIndex The 0-based column index of the item renderer's cell. |
| * |
| * @return True if the specified cell (or row if columnIndex == -1) is at least partially visible |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function isCellVisible(rowIndex:int = -1, columnIndex:int = -1):Boolean |
| { |
| const view:GridView = getGridViewAt(rowIndex, columnIndex); |
| return view && view.gridViewLayout.isCellVisible(rowIndex, columnIndex); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Tracking Grid invalidateDisplayList() "reasons", invalid cells |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Low cost "list" of invalidateDisplayList() reasons. |
| */ |
| private var invalidateDisplayListReasonsMask:uint = 0; |
| |
| /** |
| * @private |
| * This flag makes it possible to defer clearing the invalidateDisplayListReasonsMask |
| * until after the Grid's subtree has been redisplayed. It's set by updateDisplayList() |
| * and not cleared until the next invalidateDisplayListFor() call, on the assumption |
| * that the Grid subtree's updateDisplayList() methods will not reset any Grid properties |
| * (that call invalidateDisplayListFor()). |
| */ |
| private var clearInvalidateDisplayListReasons:Boolean = false; |
| |
| /** |
| * @private |
| * Table that maps from reason names to bit fields. |
| */ |
| private static const invalidateDisplayListReasonBits:Object = { |
| verticalScrollPosition: uint(1 << 0), |
| horizontalScrollPosition: uint(1 << 1), |
| bothScrollPositions: (uint(1 << 0) | uint(1 << 1)), |
| hoverIndicator: uint(1 << 2), |
| caretIndicator: uint(1 << 3), |
| selectionIndicator: uint(1 << 4), |
| editorIndicator: uint(1 << 5), |
| none: uint(~0) |
| }; |
| |
| /** |
| * @private |
| * Set the bit that corresponds to reason. Only used by invalidateDisplayListFor(). |
| */ |
| private function setInvalidateDisplayListReason(reason:String):void |
| { |
| if (clearInvalidateDisplayListReasons) |
| { |
| invalidateDisplayListReasonsMask = 0; |
| clearInvalidateDisplayListReasons = false; |
| } |
| |
| invalidateDisplayListReasonsMask |= invalidateDisplayListReasonBits[reason]; |
| } |
| |
| /** |
| * @private |
| * Return true if invalidateDisplayListFor() was called with the specified reason |
| * since the last updateDisplayList() pass. |
| */ |
| mx_internal function isInvalidateDisplayListReason(reason:String):Boolean |
| { |
| const bit:uint = invalidateDisplayListReasonBits[reason]; |
| return (invalidateDisplayListReasonsMask & bit) == bit; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Method Overrides |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function getHorizontalScrollPositionDelta(navigationUnit:uint):Number |
| { |
| const gridLayout:GridLayout = layout as GridLayout; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| return (centerGridView) ? centerGridView.getHorizontalScrollPositionDelta(navigationUnit) : 0; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function getVerticalScrollPositionDelta(navigationUnit:uint):Number |
| { |
| const gridLayout:GridLayout = layout as GridLayout; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| return (centerGridView) ? centerGridView.getVerticalScrollPositionDelta(navigationUnit) : 0; |
| } |
| |
| |
| /** |
| * @private |
| * During virtual layout updateDisplayList() eagerly validates lazily |
| * created (or recycled) IRs. We don't want changes to those IRs to |
| * invalidate the size of the grid. |
| * |
| * This method also dispatches an invalidateSize event that's used |
| * by the DataGrid to invalidate IDataGridElements. |
| */ |
| override public function invalidateSize():void |
| { |
| if (!inUpdateDisplayList) |
| { |
| super.invalidateSize(); |
| |
| for each (var view:GridView in allGridViews) |
| { |
| if (!view) |
| continue; |
| view.invalidateSize(); |
| } |
| |
| dispatchChangeEvent("invalidateSize"); |
| } |
| } |
| |
| /** |
| * @private |
| * During virtual layout updateDisplayList() eagerly validates lazily |
| * created (or recycled) IRs. Calls to invalidateDisplayList() eventually |
| * short-circuit but doing so early saves a few percent. |
| * |
| * This method also dispatches an invalidateDisplayList event that's used |
| * by the DataGrid to invalidate IDataGridElements. |
| */ |
| override public function invalidateDisplayList():void |
| { |
| if (!inUpdateDisplayList) |
| { |
| setInvalidateDisplayListReason("none"); |
| super.invalidateDisplayList(); |
| |
| for each (var view:GridView in allGridViews) |
| { |
| if (!view) |
| continue; |
| view.invalidateDisplayList(); |
| } |
| |
| dispatchChangeEvent("invalidateDisplayList"); |
| } |
| } |
| |
| private function get allGridViews():Array |
| { |
| const gridLayout:GridLayout = layout as GridLayout; |
| return gridLayout ? [gridLayout.topLeftGridView, gridLayout.topGridView, gridLayout.leftGridView, gridLayout.centerGridView] : []; |
| } |
| |
| private function createGridView():GridView |
| { |
| const elt:GridView = gridView.newInstance() as GridView; |
| addElement(elt); |
| return elt; |
| } |
| |
| private function configureGridView(gv:GridView, viewRowIndex:int, viewColumnIndex:int, viewRowCount:int, viewColumnCount:int):void |
| { |
| const gridViewLayout:GridViewLayout = gv.gridViewLayout; |
| gridViewLayout.grid = this; |
| gridViewLayout.viewRowIndex = viewRowIndex; |
| gridViewLayout.viewColumnIndex = viewColumnIndex; |
| gridViewLayout.viewRowCount = viewRowCount; |
| gridViewLayout.viewColumnCount = viewColumnCount; |
| } |
| |
| /** |
| * Create and/or configure this Grid's GridViews. We're assuming that the |
| * Grid's viewFactory, columns and dataProvider are specified. |
| * |
| * If GridVeiws are added or removed, a "gridViewsChanged" event is dispatched. |
| */ |
| private function configureGridViews():void |
| { |
| const columnCount:int = columns.length; |
| const rowCount:int = (dataProvider) ? dataProvider.length : 0; |
| |
| lockedColumnCount = Math.min(lockedColumnCount, columnCount); |
| lockedRowCount = Math.min(lockedRowCount, rowCount); |
| |
| const centerRowCount:int = Math.max(0, rowCount - lockedRowCount); |
| const centerColumnCount:int = Math.max(0, columnCount - lockedColumnCount); |
| |
| const gridLayout:GridLayout = layout as GridLayout; |
| var topLeftGridView:GridView = gridLayout.topLeftGridView; |
| var topGridView:GridView = gridLayout.topGridView; |
| var leftGridView:GridView = gridLayout.leftGridView; |
| var centerGridView:GridView = gridLayout.centerGridView; |
| var lockedRowsSeparatorElement:IVisualElement = gridLayout.lockedRowsSeparatorElement; |
| var lockedColumnsSeparatorElement:IVisualElement = gridLayout.lockedColumnsSeparatorElement; |
| |
| var gridViewsChanged:Boolean = false; |
| |
| // Unconditionally create and configure the "center" GridView |
| |
| if (centerGridView == null) |
| { |
| gridLayout.centerGridView = centerGridView = createGridView(); |
| gridViewsChanged = true; |
| } |
| |
| configureGridView(centerGridView, lockedRowCount, lockedColumnCount, -1, -1); |
| |
| centerGridView.gridViewLayout.requestedRowCount = requestedRowCount - lockedRowCount; |
| centerGridView.gridViewLayout.requestedColumnCount = requestedColumnCount - lockedColumnCount; |
| |
| // Remove or create/configure the topLeftGridView |
| |
| if ((lockedRowCount > 0) && (lockedColumnCount > 0)) |
| { |
| if (!topLeftGridView) |
| { |
| gridLayout.topLeftGridView = topLeftGridView = createGridView(); |
| topLeftGridView.gridViewLayout.verticalScrollingLocked = true; |
| topLeftGridView.gridViewLayout.horizontalScrollingLocked = true; |
| gridViewsChanged = true; |
| } |
| |
| } |
| else if (topLeftGridView) |
| { |
| removeElement(topLeftGridView); |
| gridLayout.topLeftGridView = topLeftGridView = null; |
| gridViewsChanged = true; |
| } |
| |
| if (topLeftGridView) |
| configureGridView(topLeftGridView, 0, 0, lockedRowCount, lockedColumnCount); |
| |
| // Remove or create/configure the topGridView |
| |
| if (lockedRowCount > 0) |
| { |
| if (!topGridView) |
| { |
| gridLayout.topGridView = topGridView = createGridView(); |
| topGridView.gridViewLayout.verticalScrollingLocked = true; |
| gridViewsChanged = true; |
| } |
| |
| if (lockedRowsSeparator && !lockedRowsSeparatorElement) |
| { |
| gridLayout.lockedRowsSeparatorElement = lockedRowsSeparatorElement = lockedRowsSeparator.newInstance() as IVisualElement; |
| addElement(lockedRowsSeparatorElement); |
| } |
| } |
| else |
| { |
| if (topGridView) |
| { |
| removeElement(topGridView); |
| gridLayout.topGridView = topGridView = null; |
| gridViewsChanged = true; |
| } |
| |
| if (lockedRowsSeparatorElement) |
| { |
| removeElement(lockedRowsSeparatorElement); |
| gridLayout.lockedRowsSeparatorElement = lockedRowsSeparatorElement = null; |
| } |
| } |
| |
| if (topGridView) |
| configureGridView(topGridView, 0, lockedColumnCount, lockedRowCount, centerColumnCount); |
| |
| // Remove or create/configure the leftGridView |
| |
| if (lockedColumnCount > 0) |
| { |
| if (!leftGridView) |
| { |
| gridLayout.leftGridView = leftGridView = createGridView(); |
| leftGridView.gridViewLayout.horizontalScrollingLocked = true; |
| gridViewsChanged = true; |
| } |
| |
| if (lockedColumnsSeparator && !lockedColumnsSeparatorElement) |
| { |
| gridLayout.lockedColumnsSeparatorElement = lockedColumnsSeparatorElement = lockedColumnsSeparator.newInstance() as IVisualElement; |
| addElement(lockedColumnsSeparatorElement); |
| } |
| } |
| else |
| { |
| if (leftGridView) |
| { |
| removeElement(leftGridView); |
| gridLayout.leftGridView = leftGridView = null; |
| gridViewsChanged = true; |
| } |
| |
| if (lockedColumnsSeparatorElement) |
| { |
| removeElement(lockedColumnsSeparatorElement); |
| gridLayout.lockedColumnsSeparatorElement = lockedColumnsSeparatorElement = null; |
| } |
| } |
| |
| if (leftGridView) |
| configureGridView(leftGridView, lockedRowCount, 0, centerRowCount, lockedColumnCount); |
| |
| if (gridViewsChanged) |
| dispatchChangeEvent("gridViewsChanged"); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function commitProperties():void |
| { |
| // rowHeight and variableRowHeight can be set in either order |
| if (variableRowHeightChanged || rowHeightChanged) |
| { |
| if (rowHeightChanged) |
| gridDimensions.defaultRowHeight = _rowHeight; |
| gridDimensions.variableRowHeight = variableRowHeight; |
| |
| if ((!variableRowHeight && rowHeightChanged) || variableRowHeightChanged) |
| { |
| clearGridLayoutCache(false); |
| invalidateSize(); |
| invalidateDisplayList(); |
| } |
| |
| rowHeightChanged = false; |
| variableRowHeightChanged = false; |
| } |
| |
| // item renderer changed or typical item changed |
| if (itemRendererChanged || typicalItemChanged) |
| { |
| clearGridLayoutCache(true); |
| itemRendererChanged = false; |
| } |
| |
| // Try to generate columns if there aren't any or there are generated |
| // ones which need to be regenerated because the typicalItem or |
| // dataProvider changed. |
| if (!columns || (generatedColumns && |
| (typicalItemChanged || (!typicalItem && dataProviderChanged)))) |
| { |
| const oldColumns:IList = columns; |
| columns = generateColumns(); |
| generatedColumns = (columns != null); |
| columnsChanged = columns != oldColumns; |
| } |
| typicalItemChanged = false; |
| |
| // If the dataProvider or columns change, reset the selection and |
| // the grid dimensions. This has to be done here rather than in the |
| // setters because the gridSelection and gridDimensions might not |
| // be set yet, depending on the order they are initialized when the |
| // grid skin part is added to the data grid. |
| |
| if (dataProviderChanged || columnsChanged) |
| { |
| |
| // Remove the current selection and, if requireSelection, make |
| // sure the selection is reset to row 0 or cell 0,0. |
| if (gridSelection) |
| { |
| var savedRequireSelection:Boolean = gridSelection.requireSelection; |
| gridSelection.requireSelection = false; |
| gridSelection.removeAll(); |
| gridSelection.requireSelection = savedRequireSelection; |
| } |
| |
| // make sure we have the right number of columns. |
| if (columnsChanged) |
| gridDimensions.columnCount = _columns ? _columns.length : 0; |
| |
| // Keep typical item size cache only when the typical item is still valid |
| // and the columns haven't changed. |
| if (typicalItem != null && !columnsChanged) |
| clearGridLayoutCache(false); |
| else |
| clearGridLayoutCache(true); |
| |
| if (!caretChanged) |
| initializeCaretPosition(); |
| |
| if (!anchorChanged) |
| initializeAnchorPosition(); |
| |
| dataProviderChanged = false; |
| columnsChanged = false; |
| } |
| |
| anchorChanged = false; |
| |
| // Create or reconfigure the Grid's GridViews |
| |
| if (gridView && columns) |
| configureGridViews(); |
| |
| // Deferred selection operations |
| |
| if (dataProvider) |
| { |
| for each (var deferredOperation:Function in deferredOperations) |
| deferredOperation(); |
| deferredOperations.length = 0; |
| } |
| |
| // Only want one event if both caretRowIndex and caretColumnIndex changed |
| |
| if (caretChanged) |
| { |
| // Validate values now. Need to let caret be set in the same |
| // update as the dp and/or columns. -1 is a valid value. |
| if (_dataProvider && caretRowIndex >= _dataProvider.length) |
| _caretRowIndex = _dataProvider.length - 1; |
| if (_columns && caretColumnIndex >= _columns.length) |
| _caretColumnIndex = getPreviousVisibleColumnIndex(_columns.length - 1); |
| |
| caretSelectedItem = |
| _dataProvider && _caretRowIndex >= 0 ? |
| _dataProvider.getItemAt(_caretRowIndex) : null; |
| |
| dispatchCaretChangeEvent(); |
| |
| // Last reported values. |
| _oldCaretRowIndex = _caretRowIndex; |
| _oldCaretColumnIndex = _caretColumnIndex; |
| |
| caretChanged = false; |
| } |
| |
| if (updateCaretForDataProviderChanged) |
| { |
| updateCaretForDataProviderChanged = false; |
| updateCaretForDataProviderChange(updateCaretForDataProviderChangeLastEvent); |
| updateCaretForDataProviderChangeLastEvent = null; |
| } |
| } |
| |
| |
| /** |
| * @private |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void |
| { |
| inUpdateDisplayList = true; |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| inUpdateDisplayList = false; |
| |
| clearInvalidateDisplayListReasons = true; |
| |
| if (!variableRowHeight) |
| setFixedRowHeight(gridDimensions.getRowHeight(0)); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * This version of invlaidateDisplayList() stores the "reason" for the invalidate |
| * request so that GridLayout/updateDisplayList() can do its job more efficiently. |
| * GridLayout tests the accumulated invalidateDisplayList reasons with |
| * isInvalidateDisplayListReason() and they're automatically cleared by |
| * updateDisplayList() here. |
| * |
| * Note that if invalidateDisplayList() is called directly, all possible |
| * invalidateDispayList reasons are implicitly specified, in other words if |
| * no reason is specified then they all are (see invalidateDisplayListReasonBits.none). |
| * That way, callers need not be aware of this internal API. |
| * |
| * Also: most reason="selectionIndicator" calls also change the caret index which |
| * in turn adds reason="caretIndicator" to the invalidateDisplayList reasons, if the |
| * caret index actually changed. |
| */ |
| mx_internal function invalidateDisplayListFor(reason:String):void |
| { |
| if (!inUpdateDisplayList) |
| { |
| setInvalidateDisplayListReason(reason); |
| super.invalidateDisplayList(); |
| |
| // Minor optimization: if the reason for this invalidation is a |
| // scroll, don't invalidate GridViews that can't change. |
| |
| const vspReason:Boolean = reason == "verticalScrollPosition"; |
| const hspReason:Boolean = reason == "horizontalScrollPosition"; |
| const bothReason:Boolean = reason == "bothScrollPositions"; |
| |
| const gridLayout:GridLayout = layout as GridLayout; |
| const topLeftGridView:GridView = gridLayout.topLeftGridView; |
| const topGridView:GridView = gridLayout.topGridView; |
| const leftGridView:GridView = gridLayout.leftGridView; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| |
| if (topLeftGridView && !vspReason && !hspReason && !bothReason) |
| topLeftGridView.invalidateDisplayList(); |
| |
| if (topGridView && !vspReason) |
| topGridView.invalidateDisplayList(); |
| |
| if (leftGridView && !hspReason) |
| leftGridView.invalidateDisplayList(); |
| |
| if (centerGridView) |
| centerGridView.invalidateDisplayList(); |
| |
| dispatchChangeEvent("invalidateDisplayList"); |
| } |
| } |
| |
| /** |
| * If the specified cell is visible, it is redisplayed. |
| * If <code>variableRowHeight=true</code>, |
| * then doing so may cause the height of the corresponding row to change. |
| * |
| * <p>If columnIndex is -1, then the entire row is invalidated. |
| * Similarly if <code>rowIndex is -1</code>, then the entire column is invalidated.</p> |
| * |
| * <p>This method should be called when there is a change to any aspect of |
| * the data provider item at <code>rowIndex</code> that might have some |
| * impact on the way the specified cell is displayed. |
| * Calling this method is similar to calling the |
| * <code>dataProvider.itemUpdated()</code> method, which advises the Grid that all rows |
| * displaying the specified item should be redisplayed. |
| * Using this method can be relatively efficient, since it narrows |
| * the scope of the change to a single cell.</p> |
| * |
| * @param rowIndex The 0-based row index of the cell that changed, or -1. |
| * |
| * @param columnIndex The 0-based column index of the cell that changed or -1. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function invalidateCell(rowIndex:int, columnIndex:int):void |
| { |
| if ((rowIndex == -1) && (columnIndex == -1)) |
| { |
| invalidateDisplayList(); |
| return; |
| } |
| |
| const view:GridView = getGridViewAt(rowIndex, columnIndex); |
| if (!dataProvider || !view) |
| return; |
| |
| const gridLayout:GridViewLayout = view.gridViewLayout; |
| const dataProviderLength:int = dataProvider.length; |
| if (!gridLayout || (rowIndex >= dataProvider.length)) |
| return; |
| |
| if (!isCellVisible(rowIndex, columnIndex)) |
| return; |
| |
| if (invalidateDisplayListFlag || invalidateSizeFlag) |
| return; |
| |
| if ((rowIndex >= 0) && (columnIndex >= 0)) |
| { |
| gridLayout.invalidateCell(rowIndex, columnIndex); |
| } |
| else if (rowIndex >= 0) // invalidate a row |
| { |
| const visibleColumnIndices:Vector.<int> = getVisibleColumnIndices(); |
| for each (var visibleColumnIndex:int in visibleColumnIndices) |
| { |
| gridLayout.invalidateCell(rowIndex, visibleColumnIndex); |
| |
| // If invalidating the cell caused the entire grid to be invalid, punt |
| if (invalidateDisplayListFlag || invalidateSizeFlag) |
| break; |
| } |
| } |
| else if (columnIndex >= 0) // invalidate a column |
| { |
| const visibleRowIndices:Vector.<int> = getVisibleRowIndices(); |
| for each (var visibleRowIndex:int in visibleRowIndices) |
| { |
| // If there are any padding rows, skip them. |
| if (visibleRowIndex >= dataProviderLength) |
| break; |
| |
| gridLayout.invalidateCell(visibleRowIndex, columnIndex); |
| |
| // If invalidating the cell caused the entire grid to be invalid, punt |
| if (invalidateDisplayListFlag || invalidateSizeFlag) |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Creates a grid selection object to use to manage selection. Override this method if you have a custom grid |
| * selection that you want to use in place of the default and this grid is not a skin part for DataGrid. |
| * This method is not used when this grid is a skin part for DataGrid. |
| * |
| * @see spark.components.DataGrid.createGridSelection |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| mx_internal function createGridSelection():GridSelection |
| { |
| return new GridSelection(); |
| } |
| |
| |
| /** |
| * This will search through a dataprovider checking the given field and for the given value and return the index for the match. |
| * It can start the find from a given startingIndex; |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function findRowIndex(field:String, value:String, startingIndex:int = 0, patternType:String = RegExPatterns.EXACT):int |
| { |
| var pattern:RegExp; |
| var currentObject:Object = null; |
| var dataProviderTotal:int = 0; |
| var loopingIndex:int = startingIndex; |
| |
| |
| pattern = RegExPatterns.createRegExp(value, patternType); |
| |
| |
| if (dataProvider && dataProvider.length > 0) |
| { |
| dataProviderTotal = dataProvider.length; |
| |
| if (startingIndex >= dataProviderTotal) |
| { |
| return -1; |
| } |
| |
| |
| for (loopingIndex; loopingIndex < dataProviderTotal; loopingIndex++) |
| { |
| currentObject = dataProvider.getItemAt(loopingIndex); |
| |
| if (currentObject.hasOwnProperty(field) == true && currentObject[field].search(pattern) != -1) |
| { |
| return loopingIndex; |
| } |
| } |
| |
| } |
| |
| return -1; |
| } |
| |
| |
| /** |
| * This will search through a dataprovider checking the given field and for the given values and return an array of indices that matched. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function findRowIndices(field:String, values:Array, patternType:String = RegExPatterns.EXACT):Array |
| { |
| var currentObject:Object = null; |
| var regexList:Array = []; |
| var matchedIndices:Array = []; |
| var dataProviderTotal:uint = 0; |
| var valuesTotal:uint = 0; |
| var loopingDataProviderIndex:uint = 0; |
| var loopingValuesIndex:uint = 0; |
| |
| |
| if (dataProvider != null && dataProvider.length > 0 && values != null && values.length > 0) |
| { |
| dataProviderTotal = dataProvider.length; |
| valuesTotal = values.length; |
| |
| |
| //Set the regex patterns in an array once. |
| for (loopingValuesIndex = 0; loopingValuesIndex < valuesTotal; loopingValuesIndex++) |
| { |
| regexList.push(RegExPatterns.createRegExp(values[loopingValuesIndex], patternType)); |
| } |
| |
| |
| //Loop through dataprovider |
| for (loopingDataProviderIndex; loopingDataProviderIndex < dataProviderTotal; loopingDataProviderIndex++) |
| { |
| currentObject = dataProvider.getItemAt(loopingDataProviderIndex); |
| |
| if (currentObject.hasOwnProperty(field) == false) |
| { |
| continue; |
| } |
| |
| //Loop through regex patterns from the values array. |
| for (loopingValuesIndex = 0; loopingValuesIndex < valuesTotal; loopingValuesIndex++) |
| { |
| if (currentObject[field].search(regexList[loopingValuesIndex]) != -1) |
| { |
| matchedIndices.push(loopingDataProviderIndex); |
| |
| break; |
| } |
| } |
| } |
| |
| } |
| |
| |
| return matchedIndices; |
| } |
| |
| |
| /** |
| * This will search through a dataprovider checking the given field and will set the selectedIndex to a matching value. |
| * It can start the search from the startingIndex; |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| * |
| */ |
| public function moveIndexFindRow(field:String, value:String, startingIndex:int = 0, patternType:String = RegExPatterns.EXACT):Boolean |
| { |
| var indexFound:int = -1; |
| |
| indexFound = findRowIndex(field, value, startingIndex, patternType); |
| |
| if (indexFound != -1) |
| { |
| selectedIndex = indexFound; |
| |
| return true; |
| } |
| |
| return false; |
| } |
| |
| |
| /** |
| * Changes the selectedIndex to the first row of the dataProvider. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexFirstRow():void |
| { |
| if (dataProvider && dataProvider.length > 0) |
| { |
| selectedIndex = 0; |
| } |
| } |
| |
| |
| /** |
| * Changes the selectedIndex to the last row of the dataProvider. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexLastRow():void |
| { |
| if (dataProvider && dataProvider.length > 0) |
| { |
| selectedIndex = dataProvider.length - 1; |
| } |
| } |
| |
| |
| /** |
| * Changes the selectedIndex to the next row of the dataProvider. If there isn't a current selectedIndex, it silently returns. |
| * If the selectedIndex is on the first row, it does not wrap around. However the <code>isFirstRow</code> property returns true. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexNextRow():void |
| { |
| if (dataProvider && dataProvider.length > 0 && selectedIndex >= 0) |
| { |
| if (isLastRow == false) |
| { |
| selectedIndex += 1; |
| } |
| } |
| } |
| |
| |
| /** |
| * Changes the selectedIndex to the previous row of the dataProvider. If there isn't a current selectedIndex, it silently returns. |
| * If the selectedIndex is on the last row, it does not wrap around. However the <code>isLastRow</code> property returns true. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexPreviousRow():void |
| { |
| if (dataProvider && dataProvider.length > 0 && selectedIndex >= 0) |
| { |
| if (isFirstRow == false) |
| { |
| selectedIndex -= 1; |
| } |
| } |
| } |
| |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Internal Grid Access |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function getGridColumn(columnIndex:int):GridColumn |
| { |
| const columns:IList = columns; |
| if ((columns == null) || (columnIndex < 0) || (columnIndex >= columns.length)) |
| return null; |
| |
| return columns.getItemAt(columnIndex) as GridColumn; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function getDataProviderItem(rowIndex:int):Object |
| { |
| const dataProvider:IList = dataProvider; |
| if ((dataProvider == null) || (rowIndex >= dataProvider.length)) |
| return null; |
| |
| return dataProvider.getItemAt(rowIndex); |
| } |
| |
| /** |
| * @private |
| */ |
| private function getVisibleItemRenderer(rowIndex:int, columnIndex:int):IGridItemRenderer |
| { |
| const view:GridView = getGridViewAt(rowIndex, columnIndex); |
| if (!view) |
| return null; |
| |
| const gridViewLayout:GridViewLayout = view.gridViewLayout; |
| const viewRowIndex:int = rowIndex - gridViewLayout.viewRowIndex; |
| const viewColumnIndex:int = columnIndex - gridViewLayout.viewColumnIndex; |
| return gridViewLayout.getVisibleItemRenderer(viewRowIndex, viewColumnIndex); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // GridEvents |
| // |
| //-------------------------------------------------------------------------- |
| |
| private var rollRowIndex:int = -1; |
| private var rollColumnIndex:int = -1; |
| private var mouseDownRowIndex:int = -1; |
| private var mouseDownColumnIndex:int = -1; |
| private var lastClickedColumnIndex:int = -1; |
| private var lastClickedRowIndex:int = -1; |
| private var lastClickTime:Number; |
| |
| // default max time between clicks for a double click is 480ms. |
| mx_internal var DOUBLE_CLICK_TIME:Number = 480; |
| |
| /** |
| * @private |
| * Return the GridView whose bounds contain the MouseEvent, or null. Note that the |
| * comparison is based strictly on the event's location and the GridViews' bounds. |
| * The event's target can be anything. |
| */ |
| private function mouseEventGridView(event:MouseEvent):GridView |
| { |
| const gridLayout:GridLayout = layout as GridLayout; |
| |
| const centerGridView:GridView = gridLayout.centerGridView; |
| if (centerGridView && centerGridView.containsMouseEvent(event)) |
| return centerGridView; |
| |
| const leftGridView:GridView = gridLayout.leftGridView; |
| if (leftGridView && leftGridView.containsMouseEvent(event)) |
| return leftGridView; |
| |
| const topGridView:GridView = gridLayout.topGridView; |
| if (topGridView && topGridView.containsMouseEvent(event)) |
| return topGridView; |
| |
| const topLeftGridView:GridView = gridLayout.topLeftGridView; |
| if (topLeftGridView && topLeftGridView.containsMouseEvent(event)) |
| return topLeftGridView; |
| |
| return null; |
| } |
| |
| /** |
| * @private |
| * Return the Grid-relative row,column (gridCP) and X,Y location (gridXY) of the MouseEvent. |
| */ |
| private function eventToGridLocations(event:MouseEvent, gridCP:CellPosition, gridXY:Point):void |
| { |
| const stageXY:Point = new Point(event.stageX, event.stageY); |
| const localXY:Point = globalToLocal(stageXY); |
| gridXY.x = localXY.x; // event may not have targeted the Grid |
| gridXY.y = localXY.y; |
| |
| const view:GridView = mouseEventGridView(event); |
| if (view) |
| { |
| const viewXY:Point = view.globalToLocal(stageXY); |
| const gridViewLayout:GridViewLayout = view.gridViewLayout; |
| const gdv:GridDimensionsView = gridViewLayout.gridDimensionsView; |
| |
| |
| gridCP.rowIndex = gdv.getRowIndexAt(viewXY.x, viewXY.y) + gridViewLayout.viewRowIndex; |
| gridCP.columnIndex = gdv.getColumnIndexAt(viewXY.x, viewXY.y) + gridViewLayout.viewColumnIndex; |
| |
| gridXY.x = viewXY.x + gdv.viewOriginX; |
| gridXY.y = viewXY.y + gdv.viewOriginY; |
| } |
| else |
| { |
| gridCP.rowIndex = -1; |
| gridCP.columnIndex = -1; |
| } |
| } |
| |
| /** |
| * @private |
| * This method is called when a MOUSE_DOWN event occurs within the grid and |
| * for all subsequent MOUSE_MOVE events until the button is released (even if the |
| * mouse leaves the grid). 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. The GridEvent's rowIndex, columnIndex, column, item, and itemRenderer |
| * properties correspond to the grid cell under the mouse. |
| * |
| * @param event A MOUSE_DOWN, MOUSE_MOVE, or MOUSE_UP MouseEvent from a down/move/up gesture initiated within the grid. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function grid_mouseDownDragUpHandler(event:MouseEvent):void |
| { |
| const eventGridCP:CellPosition = new CellPosition(); |
| const eventGridXY:Point = new Point(); |
| eventToGridLocations(event, eventGridCP, eventGridXY); |
| |
| const eventRowIndex:int = eventGridCP.rowIndex; |
| const eventColumnIndex:int = eventGridCP.columnIndex; |
| |
| var gridEventType:String; |
| switch(event.type) |
| { |
| case MouseEvent.MOUSE_MOVE: |
| { |
| gridEventType = GridEvent.GRID_MOUSE_DRAG; |
| break; |
| } |
| case MouseEvent.MOUSE_UP: |
| { |
| gridEventType = GridEvent.GRID_MOUSE_UP; |
| break; |
| } |
| case MouseEvent.MOUSE_DOWN: |
| { |
| gridEventType = GridEvent.GRID_MOUSE_DOWN; |
| mouseDownRowIndex = eventRowIndex; |
| mouseDownColumnIndex = eventColumnIndex; |
| dragInProgress = true; |
| break; |
| } |
| } |
| |
| dispatchGridEvent(event, gridEventType, eventGridXY, eventRowIndex, eventColumnIndex); |
| if (gridEventType == GridEvent.GRID_MOUSE_UP) |
| dispatchGridClickEvents(event, eventGridXY, eventRowIndex, eventColumnIndex); |
| } |
| |
| /** |
| * @private |
| * This method is called whenever a MOUSE_MOVE event occurs within the grid |
| * without the button pressed. By default it dispatches a GRID_ROLL_OVER for the |
| * first MOUSE_MOVE GridEvent whose location is within a grid cell, and a |
| * GRID_ROLL_OUT GridEvent when the mouse leaves a cell. Listeners are guaranteed |
| * to receive a GRID_ROLL_OUT event for every GRID_ROLL_OVER event. |
| * |
| * @param event A MOUSE_MOVE MouseEvent within the grid, without the button pressed. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function grid_mouseMoveHandler(event:MouseEvent):void |
| { |
| const eventGridCP:CellPosition = new CellPosition(); |
| const eventGridXY:Point = new Point(); |
| eventToGridLocations(event, eventGridCP, eventGridXY); |
| |
| const eventRowIndex:int = eventGridCP.rowIndex; |
| const eventColumnIndex:int = eventGridCP.columnIndex; |
| |
| if ((eventRowIndex != rollRowIndex) || (eventColumnIndex != rollColumnIndex)) |
| { |
| if ((rollRowIndex != -1) || (rollColumnIndex != -1)) |
| dispatchGridEvent(event, GridEvent.GRID_ROLL_OUT, eventGridXY, rollRowIndex, rollColumnIndex); |
| if ((eventRowIndex != -1) && (eventColumnIndex != -1)) |
| dispatchGridEvent(event, GridEvent.GRID_ROLL_OVER, eventGridXY, eventRowIndex, eventColumnIndex); |
| rollRowIndex = eventRowIndex; |
| rollColumnIndex = eventColumnIndex; |
| } |
| } |
| |
| /** |
| * @private |
| * This method is called whenever a ROLL_OUT occurs on the grid. |
| * By default it dispatches a GRID_ROLL_OUT event. |
| * |
| * @param event A ROLL_OUT MouseEvent from the grid. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function grid_mouseRollOutHandler(event:MouseEvent):void |
| { |
| if ((rollRowIndex != -1) || (rollColumnIndex != -1)) |
| { |
| const eventStageXY:Point = new Point(event.stageX, event.stageY); |
| const eventGridXY:Point = globalToLocal(eventStageXY); |
| |
| dispatchGridEvent(event, GridEvent.GRID_ROLL_OUT, eventGridXY, rollRowIndex, rollColumnIndex); |
| rollRowIndex = -1; |
| rollColumnIndex = -1; |
| } |
| } |
| |
| /** |
| * @private |
| * This method is called whenever a GRID_MOUSE_UP occurs on the grid. |
| * By default it dispatches a GRID_MOUSE_UP event. |
| * |
| * @param event A GRID_MOUSE_UP MouseEvent from the grid. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function grid_mouseUpHandler(event:MouseEvent):void |
| { |
| if (dragInProgress) |
| { |
| // drag handler has already dispatched a mouse up event, don't do so again here |
| dragInProgress = false; |
| return; |
| } |
| |
| const eventGridCP:CellPosition = new CellPosition(); |
| const eventGridXY:Point = new Point(); |
| eventToGridLocations(event, eventGridCP, eventGridXY); |
| |
| const eventRowIndex:int = eventGridCP.rowIndex; |
| const eventColumnIndex:int = eventGridCP.columnIndex; |
| |
| dispatchGridEvent(event, GridEvent.GRID_MOUSE_UP, eventGridXY, eventRowIndex, eventColumnIndex); |
| dispatchGridClickEvents(event, eventGridXY, eventRowIndex, eventColumnIndex); |
| } |
| |
| /** |
| * @private |
| * This method is called after we dispatch a GRID_MOUSE_UP. |
| * It determines whether to dispatch a GRID_CLICK or GRID_DOUBLE_CLICK |
| * event following a GRID_MOUSE_UP. |
| * |
| * A GRID_CLICK event is dispatched when the mouse up event happens in |
| * the same cell as the mouse down event. |
| * |
| * A GRID_DOUBLE_CLICK event is dispatched in place of the GRID_CLICK |
| * event when the last click event happened within DOUBLE_CLICK_TIME. |
| */ |
| private function dispatchGridClickEvents(mouseEvent:MouseEvent, gridXY:Point, rowIndex:int, columnIndex:int):void |
| { |
| const dispatchGridClick:Boolean = ((rowIndex == mouseDownRowIndex) && (columnIndex == mouseDownColumnIndex)); |
| const newClickTime:Number = getTimer(); |
| var isDoubleClick:Boolean = false; |
| |
| // In the case that we dispatched a click last time, check if we |
| // should dispatch a double click this time. The type of check will be based on the double click mode. |
| if (doubleClickEnabled && dispatchGridClick && !isNaN(lastClickTime) && |
| (newClickTime - lastClickTime <= DOUBLE_CLICK_TIME)) |
| { |
| switch(_doubleClickMode) |
| { |
| case GridDoubleClickMode.CELL: |
| { |
| if (rowIndex != -1 && columnIndex != -1 && rowIndex == lastClickedRowIndex && columnIndex == lastClickedColumnIndex) |
| { |
| isDoubleClick = true; |
| } |
| |
| break; |
| } |
| |
| case GridDoubleClickMode.GRID: |
| { |
| isDoubleClick = true; |
| |
| break; |
| } |
| |
| case GridDoubleClickMode.ROW: |
| { |
| if (rowIndex != -1 && rowIndex == lastClickedRowIndex) |
| { |
| isDoubleClick = true; |
| } |
| |
| break; |
| } |
| } |
| |
| if (isDoubleClick == true) |
| { |
| dispatchGridEvent(mouseEvent, GridEvent.GRID_DOUBLE_CLICK, gridXY, rowIndex, columnIndex); |
| lastClickTime = NaN; |
| lastClickedColumnIndex = -1; |
| lastClickedRowIndex = -1; |
| isDoubleClick = false; |
| |
| return; |
| } |
| } |
| |
| // Otherwise, just dispatch the click event. |
| if (dispatchGridClick) |
| { |
| dispatchGridEvent(mouseEvent, GridEvent.GRID_CLICK, gridXY, rowIndex, columnIndex); |
| lastClickTime = newClickTime; |
| lastClickedColumnIndex = columnIndex; |
| lastClickedRowIndex = rowIndex; |
| isDoubleClick = false; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function dispatchGridEvent(mouseEvent:MouseEvent, type:String, gridXY:Point, rowIndex:int, columnIndex:int):void |
| { |
| const column:GridColumn = columnIndex >= 0 ? getGridColumn(columnIndex) : null; |
| const item:Object = rowIndex >= 0 ? getDataProviderItem(rowIndex) : null; |
| const itemRenderer:IGridItemRenderer = getVisibleItemRenderer(rowIndex, 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, |
| gridXY.x, gridXY.y, |
| relatedObject, ctrlKey, altKey, shiftKey, buttonDown, delta, |
| rowIndex, columnIndex, column, item, itemRenderer); |
| dispatchEvent(event); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // IList listeners: columns, dataProvider |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Update caretRowIndex if necessary. This method should only be called when |
| * caretRowIndex is valid, i.e. != -1. |
| */ |
| private function updateCaretForDataProviderChange(event:CollectionEvent):void |
| { |
| const oldCaretRowIndex:int = caretRowIndex; |
| const location:int = event.location; |
| const itemsLength:int = event.items ? event.items.length : 0; |
| var newCaretRowIndex:int; |
| |
| switch (event.kind) |
| { |
| case CollectionEventKind.ADD: |
| if (oldCaretRowIndex >= location) |
| caretRowIndex += event.items.length; |
| break; |
| |
| case CollectionEventKind.REMOVE: |
| if (oldCaretRowIndex >= location) |
| { |
| // ToDo(cframpto): If the caret is on an item that is deleted, rather than |
| // removing the caret, which is what we do now, it is preferable |
| // to have the caret "stick" to the same position. There is some complexity |
| // to picking a row/cell based on what’s currently visible or partially |
| // visible – after – the delete operation. |
| if (oldCaretRowIndex < (location + itemsLength)) |
| caretRowIndex = -1; |
| else |
| caretRowIndex -= itemsLength; |
| } |
| |
| break; |
| |
| case CollectionEventKind.MOVE: |
| { |
| const oldLocation:int = event.oldLocation; |
| if ((oldCaretRowIndex >= oldLocation) && (oldCaretRowIndex < (oldLocation + itemsLength))) |
| caretRowIndex += location - oldLocation; |
| } |
| break; |
| |
| case CollectionEventKind.REPLACE: |
| case CollectionEventKind.UPDATE: |
| break; |
| |
| case CollectionEventKind.REFRESH: |
| { |
| newCaretRowIndex = |
| caretSelectedItem ? |
| _dataProvider.getItemIndex(caretSelectedItem) : -1; |
| |
| // Caret sticks to item if possible and ensure it is totally |
| // visible by scrolling vertically if necessary. |
| if (newCaretRowIndex != -1) |
| { |
| caretRowIndex = newCaretRowIndex; |
| ensureCellIsVisible(caretRowIndex, -1); |
| } |
| else |
| { |
| // No caret. Maintain the existing scroll position if |
| // within the current data. |
| |
| var oldVsp:int = verticalScrollPosition; |
| |
| validateNow(); |
| |
| // If variable row heights the height is |
| // approximate so the scroll position may not be |
| // in exactly the same place. |
| |
| const cHeight:Number = Math.ceil(gridDimensions.getContentHeight()); |
| const maximum:int = Math.max(cHeight - height, 0); |
| verticalScrollPosition = (oldVsp > maximum) ? maximum : oldVsp; |
| } |
| break; |
| } |
| |
| case CollectionEventKind.RESET: |
| { |
| newCaretRowIndex = |
| caretSelectedItem ? |
| _dataProvider.getItemIndex(caretSelectedItem) : -1; |
| |
| // Caret sticks to item if possible and ensure it is totally |
| // visible by scrolling vertically if necessary. |
| if (newCaretRowIndex != -1) |
| { |
| caretRowIndex = newCaretRowIndex; |
| ensureCellIsVisible(caretRowIndex, -1); |
| } |
| |
| // No caret item so reset caret and vsp. |
| else |
| { |
| caretRowIndex = _dataProvider.length > 0 ? 0 : -1; |
| // we need to call validateSize() to force computing maxTypicalCellHeight or verticalScrollPosition will fail |
| GridLayout(layout).centerGridView.validateSize(); |
| verticalScrollPosition = 0; |
| } |
| |
| break; |
| } |
| } |
| |
| } |
| |
| /** |
| * @private |
| * Update caretColumnIndex if necessary. This method should only be |
| * called when caretColumnIndex is valid, i.e. != -1. |
| */ |
| private function updateCaretForColumnsChange(event:CollectionEvent):void |
| { |
| const oldCaretColumnIndex:int = caretColumnIndex; |
| const location:int = event.location; |
| const itemsLength:int = event.items ? event.items.length : 0; |
| |
| switch (event.kind) |
| { |
| case CollectionEventKind.ADD: |
| if (oldCaretColumnIndex >= location) |
| caretColumnIndex += itemsLength; |
| break; |
| |
| case CollectionEventKind.REMOVE: |
| if (oldCaretColumnIndex >= location) |
| { |
| if (oldCaretColumnIndex < (location + itemsLength)) |
| caretColumnIndex = _columns.length > 0 ? 0 : -1; |
| else |
| caretColumnIndex -= itemsLength; |
| } |
| break; |
| |
| case CollectionEventKind.MOVE: |
| const oldLocation:int = event.oldLocation; |
| if ((oldCaretColumnIndex >= oldLocation) && (oldCaretColumnIndex < (oldLocation + itemsLength))) |
| caretColumnIndex += location - oldLocation; |
| break; |
| |
| case CollectionEventKind.REPLACE: |
| break; |
| |
| case CollectionEventKind.UPDATE: |
| // column may have changed visiblity which matters if cell |
| // selection mode. |
| var pe:PropertyChangeEvent; |
| |
| if (selectionMode == GridSelectionMode.SINGLE_CELL || |
| selectionMode == GridSelectionMode.MULTIPLE_CELLS) |
| { |
| for (var i:int = 0; i < itemsLength; i++) |
| { |
| pe = event.items[i] as PropertyChangeEvent; |
| if (pe && pe.property == "visible") |
| { |
| const column:GridColumn = pe.source as GridColumn; |
| if (!column || column.visible) |
| continue; |
| |
| if (column.columnIndex == caretColumnIndex) |
| initializeCaretPosition(true); // column only |
| if (column.columnIndex == anchorColumnIndex) |
| initializeAnchorPosition(true); // column only |
| } |
| } |
| } |
| break; |
| |
| case CollectionEventKind.REFRESH: |
| case CollectionEventKind.RESET: |
| initializeCaretPosition(true); // column only |
| horizontalScrollPosition = 0; |
| break; |
| } |
| } |
| |
| /** |
| * @private |
| * Update hoverRowIndex if necessary. This method should only be called when |
| * hoverRowIndex is valid, i.e. != -1. |
| */ |
| private function updateHoverForDataProviderChange(event:CollectionEvent):void |
| { |
| const oldHoverRowIndex:int = hoverRowIndex; |
| const location:int = event.location; |
| |
| switch (event.kind) |
| { |
| case CollectionEventKind.ADD: |
| case CollectionEventKind.REMOVE: |
| case CollectionEventKind.REPLACE: |
| case CollectionEventKind.UPDATE: |
| case CollectionEventKind.MOVE: |
| if (oldHoverRowIndex >= location) |
| hoverRowIndex = gridDimensions.getRowIndexAt(mouseX, mouseY); |
| break; |
| |
| case CollectionEventKind.REFRESH: |
| case CollectionEventKind.RESET: |
| hoverRowIndex = gridDimensions.getRowIndexAt(mouseX, mouseY); |
| break; |
| } |
| } |
| |
| /** |
| * @private |
| * Update hoverColumnIndex if necessary. This method should only be called when |
| * hoverColumnIndex is valid, i.e. != -1. |
| */ |
| private function updateHoverForColumnsChange(event:CollectionEvent):void |
| { |
| switch (event.kind) |
| { |
| case CollectionEventKind.ADD: |
| case CollectionEventKind.REMOVE: |
| case CollectionEventKind.REPLACE: |
| case CollectionEventKind.UPDATE: |
| case CollectionEventKind.MOVE: |
| if (hoverColumnIndex >= event.location) |
| hoverColumnIndex = gridDimensions.getColumnIndexAt(mouseX, mouseY); |
| break; |
| |
| case CollectionEventKind.REFRESH: |
| case CollectionEventKind.RESET: |
| hoverColumnIndex = gridDimensions.getColumnIndexAt(mouseX, mouseY); |
| break; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function dataProvider_collectionChangeHandler(event:CollectionEvent):void |
| { |
| var selectionChanged:Boolean = false; |
| |
| |
| // If no columns exist, we should try to generate them. |
| if (!columns && dataProvider.length > 0) |
| { |
| columns = generateColumns(); |
| generatedColumns = (columns != null); |
| this.gridDimensions.columnCount = generatedColumns ? columns.length : 0; |
| } |
| |
| const gridDimensions:GridDimensions = this.gridDimensions; |
| if (gridDimensions) |
| { |
| gridDimensions.dataProviderCollectionChanged(event); |
| gridDimensions.rowCount = dataProvider.length; |
| } |
| |
| for each (var view:GridView in allGridViews) |
| { |
| if (!view) |
| continue; |
| view.gridViewLayout.dataProviderCollectionChanged(event); |
| } |
| |
| if (gridSelection) |
| selectionChanged = gridSelection.dataProviderCollectionChanged(event); |
| |
| if (gridDimensions && hoverRowIndex != -1) |
| updateHoverForDataProviderChange(event); |
| |
| // The data has changed so need to do this here so the grid dimensions |
| // will be accurate if setting the caret requires scrolling. |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| if (caretRowIndex != -1) { |
| if (event.kind == CollectionEventKind.RESET){ |
| // defer for reset events |
| updateCaretForDataProviderChanged = true; |
| updateCaretForDataProviderChangeLastEvent = event; |
| invalidateProperties(); |
| } |
| else { |
| updateCaretForDataProviderChange(event); |
| } |
| } |
| |
| |
| // Trigger bindings to selectedIndex/selectedCell/selectedItem and the plurals of those. |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| /** |
| * @private |
| */ |
| private function columns_collectionChangeHandler(event:CollectionEvent):void |
| { |
| var column:GridColumn; |
| var columnIndex:int = event.location; |
| var i:int; |
| var selectionChanged:Boolean = false; |
| |
| switch (event.kind) |
| { |
| case CollectionEventKind.ADD: |
| { |
| // Note: multiple columns may be added. |
| while (columnIndex < columns.length) |
| { |
| column = GridColumn(columns.getItemAt(columnIndex)); |
| column.setGrid(this); |
| column.setColumnIndex(columnIndex); |
| columnIndex++; |
| } |
| break; |
| } |
| |
| case CollectionEventKind.MOVE: |
| { |
| // All columns between the old and new locations need to |
| // have their index updated. |
| columnIndex = Math.min(event.oldLocation, event.location); |
| var maxIndex:int = Math.max(event.oldLocation, event.location); |
| while (columnIndex <= maxIndex) |
| { |
| column = GridColumn(columns.getItemAt(columnIndex)); |
| column.setColumnIndex(columnIndex); |
| columnIndex++; |
| } |
| break; |
| } |
| |
| case CollectionEventKind.REPLACE: |
| { |
| var items:Array = event.items; |
| var length:int = items.length; |
| for (i = 0; i < length; i++) |
| { |
| if (items[i].oldValue is GridColumn) |
| { |
| column = GridColumn(items[i].oldValue); |
| column.setGrid(null); |
| column.setColumnIndex(-1); |
| } |
| if (items[i].newValue is GridColumn) |
| { |
| column = GridColumn(items[i].newValue); |
| column.setGrid(this); |
| column.setColumnIndex(columnIndex); |
| } |
| } |
| break; |
| } |
| |
| case CollectionEventKind.UPDATE: |
| { |
| break; |
| } |
| |
| case CollectionEventKind.REFRESH: |
| { |
| for (columnIndex = 0; columnIndex < columns.length; columnIndex++) |
| { |
| column = GridColumn(columns.getItemAt(columnIndex)); |
| column.setColumnIndex(columnIndex); |
| } |
| break; |
| } |
| |
| case CollectionEventKind.REMOVE: |
| { |
| // Note: multiple columns may be removed. |
| var count:int = event.items.length; |
| |
| for (i = 0; i < count; i++) |
| { |
| column = GridColumn(event.items[i]); |
| column.setGrid(null); |
| column.setColumnIndex(-1); |
| } |
| |
| // Renumber the columns which follow the removed columns. |
| while (columnIndex < columns.length) |
| { |
| column = GridColumn(columns.getItemAt(columnIndex)); |
| column.setColumnIndex(columnIndex); |
| columnIndex++; |
| } |
| |
| break; |
| } |
| |
| case CollectionEventKind.RESET: |
| { |
| for (columnIndex = 0; columnIndex < columns.length; columnIndex++) |
| { |
| column = GridColumn(columns.getItemAt(columnIndex)); |
| column.setGrid(this); |
| column.setColumnIndex(columnIndex); |
| } |
| break; |
| } |
| } |
| |
| if (gridDimensions) |
| gridDimensions.columnsCollectionChanged(event); |
| |
| for each (var view:GridView in allGridViews) |
| { |
| if (!view) |
| continue; |
| view.gridViewLayout.columnsCollectionChanged(event); |
| } |
| |
| |
| if (gridSelection) |
| selectionChanged = gridSelection.columnsCollectionChanged(event); |
| |
| if (caretColumnIndex != -1) |
| updateCaretForColumnsChange(event); |
| |
| if (gridDimensions && hoverColumnIndex != -1) |
| updateHoverForColumnsChange(event); |
| |
| invalidateSize(); |
| invalidateDisplayList(); |
| |
| // Trigger bindings to selectedCell/selectedItem and the plurals of those. |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Clears the layout's renderers and cached sizes. Also clears |
| * the typical item's size if clearTypicalSizes is true. |
| */ |
| mx_internal function clearGridLayoutCache(clearTypicalSizes:Boolean):void |
| { |
| for each (var view:GridView in allGridViews) |
| { |
| if (!view) |
| continue; |
| view.gridViewLayout.clearVirtualLayoutCache(); |
| } |
| |
| const gridDimensions:GridDimensions = this.gridDimensions; |
| if (gridDimensions) |
| { |
| if (clearTypicalSizes) |
| { |
| gridDimensions.clearTypicalCellWidthsAndHeights(); |
| gridDimensions.clearColumns(0, gridDimensions.columnCount); |
| } |
| |
| gridDimensions.clearHeights(); |
| |
| // Reset row count because dataProvider length may have changed. |
| gridDimensions.rowCount = _dataProvider ? _dataProvider.length : 0; |
| } |
| |
| // Reset content size so scroller's viewport can be resized. There |
| // is loop-prevention logic in the scroller which may not allow the |
| // width/height to be reduced if there are automatic scrollbars. |
| // See ScrollerLayout/measure(). |
| setContentSize(0, 0); |
| } |
| |
| /** |
| * @private |
| * Returns the index of the next GridColumn.visible==true column |
| * after index. |
| * Returns -1 if there are no more visible columns. |
| * To find the first GridColumn.visible==true column index, use |
| * getNextVisibleColumnIndex(-1). |
| */ |
| mx_internal function getNextVisibleColumnIndex(index:int=-1):int |
| { |
| if (index < -1) |
| return -1; |
| |
| const columns:IList = this.columns; |
| const columnsLength:int = (columns) ? columns.length : 0; |
| |
| for (var i:int = index + 1; i < columnsLength; i++) |
| { |
| var column:GridColumn = columns.getItemAt(i) as GridColumn; |
| if (column && column.visible) |
| return i; |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * @private |
| * Returns the index of the previous GridColumn.visible==true column |
| * before index. |
| * Returns -1 if there are no more visible columns. |
| * To find the last GridColumn.visible==true column index, use |
| * getPreviousVisibleColumnIndex(columns.length). |
| */ |
| mx_internal function getPreviousVisibleColumnIndex(index:int):int |
| { |
| const columns:IList = this.columns; |
| if (!columns || index > columns.length) |
| return -1; |
| |
| for (var i:int = index - 1; i >= 0; i--) |
| { |
| var column:GridColumn = columns.getItemAt(i) as GridColumn; |
| if (column && column.visible) |
| return i; |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * @private |
| */ |
| private function initializeAnchorPosition(columnOnly:Boolean=false):void |
| { |
| if (!columnOnly) |
| anchorRowIndex = _dataProvider && _dataProvider.length > 0 ? 0 : -1; |
| |
| // First visible column, or -1, if there are no columns or none are visible. |
| anchorColumnIndex = getNextVisibleColumnIndex(); |
| } |
| |
| /** |
| * @private |
| */ |
| private function initializeCaretPosition(columnOnly:Boolean=false):void |
| { |
| if (!columnOnly) |
| caretRowIndex = _dataProvider && _dataProvider.length > 0 ? 0 : -1; |
| |
| // First visible column, or -1, if there are no columns or none are visible. |
| caretColumnIndex = getNextVisibleColumnIndex(); |
| } |
| |
| /** |
| * @private |
| * The caret change has already been comitted. Dispatch the "caretChange" |
| * event. |
| */ |
| private function dispatchCaretChangeEvent():void |
| { |
| if (hasEventListener(GridCaretEvent.CARET_CHANGE)) |
| { |
| const caretChangeEvent:GridCaretEvent = |
| new GridCaretEvent(GridCaretEvent.CARET_CHANGE); |
| caretChangeEvent.oldRowIndex = _oldCaretRowIndex; |
| caretChangeEvent.oldColumnIndex = _oldCaretColumnIndex; |
| caretChangeEvent.newRowIndex = _caretRowIndex; |
| caretChangeEvent.newColumnIndex = _caretColumnIndex; |
| dispatchEvent(caretChangeEvent); |
| } |
| } |
| } |
| } |