| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.DisplayObject; |
| import flash.display.Graphics; |
| import flash.events.Event; |
| import flash.events.FocusEvent; |
| import flash.events.KeyboardEvent; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| import flash.geom.Rectangle; |
| import flash.ui.Keyboard; |
| |
| import mx.collections.ArrayCollection; |
| import mx.collections.ComplexFieldChangeWatcher; |
| import mx.collections.ICollectionView; |
| import mx.collections.IComplexSortField; |
| import mx.collections.IList; |
| import mx.collections.ISort; |
| import mx.collections.ISortField; |
| import mx.collections.ListCollectionView; |
| import mx.core.DragSource; |
| import mx.core.EventPriority; |
| import mx.core.IFactory; |
| import mx.core.IFlexDisplayObject; |
| import mx.core.IIMESupport; |
| import mx.core.IUID; |
| import mx.core.IVisualElement; |
| import mx.core.InteractionMode; |
| import mx.core.LayoutDirection; |
| import mx.core.ScrollPolicy; |
| import mx.core.UIComponent; |
| import mx.core.mx_internal; |
| import mx.events.DragEvent; |
| import mx.events.FlexEvent; |
| import mx.events.SandboxMouseEvent; |
| import mx.events.TouchInteractionEvent; |
| import mx.managers.CursorManager; |
| import mx.managers.CursorManagerPriority; |
| import mx.managers.DragManager; |
| import mx.managers.IFocusManagerComponent; |
| import mx.styles.IAdvancedStyleClient; |
| import mx.utils.ObjectUtil; |
| import mx.utils.UIDUtil; |
| |
| import spark.collections.Sort; |
| import spark.components.gridClasses.CellPosition; |
| import spark.components.gridClasses.CellRegion; |
| import spark.components.gridClasses.DataGridEditor; |
| import spark.components.gridClasses.GridColumn; |
| import spark.components.gridClasses.GridItemEditorActivationMouseEvent; |
| 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.IGridItemEditor; |
| import spark.components.supportClasses.IDataProviderEnhance; |
| import spark.components.supportClasses.RegExPatterns; |
| import spark.components.supportClasses.SkinnableContainerBase; |
| import spark.core.NavigationUnit; |
| import spark.events.GridCaretEvent; |
| import spark.events.GridEvent; |
| import spark.events.GridSelectionEvent; |
| import spark.events.GridSelectionEventKind; |
| import spark.events.GridSortEvent; |
| import spark.layouts.supportClasses.DropLocation; |
| |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| /** |
| * Used to initialize the DataGrid's <code>rowBackground</code> skin part. |
| * If the <code>alternatingRowColors</code> style is specified, |
| * then use the <code>alternatingRowColorsBackground</code> skin part |
| * as the value of the <code>rowBackground</code> skin part. |
| * The alternating colors for the grid rows are defined by |
| * successive entries in the Array value of this style. |
| * |
| * <p>If you want to change how this style is rendered, |
| * replace the <code>alternatingRowColorsBackground</code> skin part |
| * in the DataGridSkin class. |
| * If you want to specify the background for each row, then |
| * initialize the <code>rowBackground</code> skin part directly.</p> |
| * |
| * @default undefined |
| * |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="alternatingRowColors", type="Array", arrayType="uint", format="Color", inherit="no", theme="spark")] |
| |
| /** |
| * The alpha value of the border for this component. |
| * Valid values are 0.0 to 1.0. |
| * |
| * @default 1.0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="borderAlpha", type="Number", inherit="no", theme="spark", minValue="0.0", maxValue="1.0")] |
| |
| /** |
| * The color of the border for this component. |
| * |
| * @default #696969 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="borderColor", type="uint", format="Color", inherit="no", theme="spark")] |
| |
| /** |
| * Controls the visibility of the border for this component. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="borderVisible", type="Boolean", inherit="no", theme="spark")] |
| |
| /** |
| * Color of the caret indicator when navigating the Grid. |
| * |
| * @default 0x0167FF |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.0 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="caretColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * The alpha of the content background for this component. |
| * Valid values are 0.0 to 1.0. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="contentBackgroundAlpha", type="Number", inherit="yes", theme="spark", minValue="0.0", maxValue="1.0")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:contentBackgroundColor |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="contentBackgroundColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:rollOverColor |
| * |
| * @default 0xCEDBEF |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.0 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="rollOverColor", type="uint", format="Color", inherit="yes", theme="spark")] |
| |
| /** |
| * @copy spark.components.List#style:selectionColor |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.0 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="selectionColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * The class to use as the skin for the cursor that indicates that a column |
| * can be resized. |
| * The default value is the <code>cursorStretch</code> symbol from the Assets.swf file. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="stretchCursor", type="Class", inherit="no")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:symbolColor |
| * |
| * @default 0x000000 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.0 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="symbolColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| include "../styles/metadata/BasicInheritingTextStyles.as" |
| |
| /** |
| * The class to use as the item editor, if one is not |
| * specified by a column. |
| * This style property lets you set |
| * an item editor for a group of DataGrid controls instead of having to |
| * set each one individually. |
| * The <code>DataGridColumn.itemEditor</code> property supercedes this value. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="defaultDataGridItemEditor", type="Class", inherit="no")] |
| |
| /** |
| * Indicates the conditions for which the horizontal scroll bar is displayed. |
| * |
| * <ul> |
| * <li> |
| * <code>ScrollPolicy.ON</code> ("on") - The scroll bar is always displayed. |
| * </li> |
| * <li> |
| * <code>ScrollPolicy.OFF</code> ("off") - The scroll bar is never displayed. |
| * The viewport can still be scrolled programmatically, by setting its |
| * <code>horizontalScrollPosition</code> property. |
| * </li> |
| * <li> |
| * <code>ScrollPolicy.AUTO</code> ("auto") - The scroll bar is displayed when |
| * the viewport's <code>contentWidth</code> is larger than its width. |
| * </li> |
| * </ul> |
| * |
| * <p> |
| * The scroll policy affects the measured size of the scroller skin part. |
| * This style is a reference to the scroller skin part's |
| * <code>horizontalScrollPolicy</code> style. |
| * It is not an inheriting style |
| * Therefor, for example, it will not affect item renderers. </p> |
| * |
| * @default ScrollPolicy.AUTO |
| * |
| * @see mx.core.ScrollPolicy |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="horizontalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")] |
| |
| /** |
| * Indicates under what conditions the vertical scroll bar is displayed. |
| * |
| * <ul> |
| * <li> |
| * <code>ScrollPolicy.ON</code> ("on") - The scroll bar is always displayed. |
| * </li> |
| * <li> |
| * <code>ScrollPolicy.OFF</code> ("off") - The scroll bar is never displayed. |
| * The viewport can still be scrolled programmatically, by setting its |
| * <code>verticalScrollPosition</code> property. |
| * </li> |
| * <li> |
| * <code>ScrollPolicy.AUTO</code> ("auto") - The scroll bar is displayed when |
| * the viewport's <code>contentHeight</code> is larger than its height. |
| * </li> |
| * </ul> |
| * |
| * <p> |
| * The scroll policy affects the measured size of the scroller skin part. |
| * This style is a reference to the scroller skin part's |
| * <code>verticalScrollPolicy</code> style. |
| * It is not an inheriting style |
| * Therefor, for example, it will not affect item renderers. </p> |
| * |
| * @default ScrollPolicy.AUTO |
| * |
| * @see mx.core.ScrollPolicy |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="verticalScrollPolicy", type="String", inherit="no", enumeration="off,on,auto")] |
| |
| //-------------------------------------- |
| // Events |
| //-------------------------------------- |
| |
| /** |
| * Dispatched by the <code>grid</code> skin part when the caret position, size, or |
| * visibility has changed due to user interaction or being programmatically set. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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")] |
| |
| /** |
| * Dispatched by the <code>grid</code> skin part when the mouse button |
| * is pressed over a grid cell. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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 by the <code>grid</code> skin part after a <code>gridMouseDown</code> event |
| * if the mouse moves before the button is released. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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 by the <code>grid</code> skin part after a <code>gridMouseDown</code> event |
| * when the mouse button is released, even if the mouse is no longer within the grid. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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 by the <code>grid</code> skin part when the mouse enters a grid cell. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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 by the <code>grid</code> skin part when the mouse leaves a grid cell. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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 by the <code>grid</code> skin part when the mouse is clicked over a cell. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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 by the <code>grid</code> skin part when the mouse is double-clicked over a cell. |
| * |
| * <p>To handle this event, assign an event handler to the <code>grid</code> skin part |
| * of the DataGrid control.</p> |
| * |
| * @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 when the selection is going to change. |
| * Calling the <code>preventDefault()</code> method |
| * on the event prevents the selection from changing. |
| * |
| * <p>This event is dispatched when the user interacts with the control. |
| * When you change the selection programmatically, |
| * the component does not dispatch the <code>selectionChanging</code> event. </p> |
| * |
| * @eventType spark.events.GridSelectionEvent.SELECTION_CHANGING |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="selectionChanging", type="spark.events.GridSelectionEvent")] |
| |
| /** |
| * Dispatched when the selection has changed. |
| * |
| * <p>This event is dispatched when the user interacts with the control. |
| * When you change the selection programmatically, |
| * the component does not dispatch the <code>selectionChange</code> event. |
| * In either case it dispatches the <code>valueCommit</code> event as well.</p> |
| * |
| * @eventType spark.events.GridSelectionEvent.SELECTION_CHANGE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="selectionChange", type="spark.events.GridSelectionEvent")] |
| |
| /** |
| * Dispatched before the sort has been applied to the data provider's collection. |
| * Typically this is when the user releases the mouse button on a column header |
| * to request the control to sort the grid contents based on the contents of the column. |
| * Only dispatched if the column is sortable and the data provider supports sorting. |
| * |
| * <p>The DataGrid control has a default handler for this event that implements |
| * a single-column sort and updates the <code>visibleSortIndices</code> in the grid's |
| * <code>columnHeaderGroup</code> with the <code>columnIndices</code>.</p> |
| * |
| * <p>Multiple-column sort can be implemented by calling the <code>preventDefault()</code> method |
| * to prevent the single column sort and setting the <code>columnIndices</code> and |
| * <code>newSortFields</code> parameters of the event to change the default behavior. |
| * <code>newSortFields</code> should be set to the desired sort fields. |
| * <code>columnIndices</code> should be set to the indices of the columns that should |
| * have a visible sort indicator in the column header bar.</p> |
| * |
| * <p>This event is dispatched when the user interacts with the control. |
| * When you sort the data provider's collection programmatically, |
| * the component does not dispatch the <code>sortChanging</code> event. </p> |
| * |
| * @eventType spark.events.GridSortEvent.SORT_CHANGING |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="sortChanging", type="spark.events.GridSortEvent")] |
| |
| /** |
| * Dispatched after the sort has been applied to the data provider's collection. |
| * Typically this is after the user releases the mouse button on a column header and |
| * the sort has been applied to the data provider's collection. |
| * |
| * <p>This event is dispatched when the user interacts with the control. |
| * When you sort the data provider's collection programmatically, |
| * the component does not dispatch the <code>sortChanging</code> event.</p> |
| * |
| * @eventType spark.events.GridSortEvent.SORT_CHANGE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="sortChange", type="spark.events.GridSortEvent")] |
| |
| //-------------------------------------- |
| // Edit Events |
| //-------------------------------------- |
| |
| /** |
| * Dispatched when a new item editor session has been requested. A listener can |
| * dynamically determine if a cell is editable and cancel the edit (by calling |
| * the <code>preventDefault()</code> method) if it is not. |
| * A listener may also dynamically change the editor used by assigning a |
| * different item editor to a column. |
| * |
| * <p>If this event is canceled the item editor will not be created.</p> |
| * |
| * @eventType spark.events.GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_STARTING |
| * |
| * @see spark.components.DataGrid.itemEditorInstance |
| * @see flash.events.Event |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridItemEditorSessionStarting", type="spark.events.GridItemEditorEvent")] |
| |
| /** |
| * Dispatched immediately after an item editor has been opened. |
| * |
| * @eventType spark.events.GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_START |
| * |
| * @see spark.components.DataGrid.itemEditorInstance |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridItemEditorSessionStart", type="spark.events.GridItemEditorEvent")] |
| |
| /** |
| * Dispatched after the data in item editor has been saved into the data provider |
| * and the editor has been closed. |
| * |
| * @eventType spark.events.GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_SAVE |
| * |
| * @see spark.components.DataGrid.itemEditorInstance |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridItemEditorSessionSave", type="spark.events.GridItemEditorEvent")] |
| |
| /** |
| * Dispatched after the item editor has been closed without saving its data. |
| * |
| * @eventType spark.events.GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_CANCEL |
| * |
| * @see spark.components.DataGrid.itemEditorInstance |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="gridItemEditorSessionCancel", type="spark.events.GridItemEditorEvent")] |
| |
| //-------------------------------------- |
| // Other metadata |
| //-------------------------------------- |
| |
| [AccessibilityClass(implementation="spark.accessibility.DataGridAccImpl")] |
| |
| [DefaultProperty("dataProvider")] |
| |
| [DefaultTriggerEvent("selectionChange")] |
| |
| [DiscouragedForProfile("mobileDevice")] |
| |
| [IconFile("DataGrid.png")] |
| |
| /** |
| * The DataGrid displays a row of column headings above a scrollable grid. |
| * The grid is arranged as a collection of individual cells arranged |
| * in rows and columns. |
| * The DataGrid control is designed to support smooth scrolling through |
| * large numbers of rows and columns. |
| * |
| * <p>The Spark DataGrid control is implemented as a skinnable wrapper |
| * around the Spark Grid control. |
| * The Grid control defines the columns of the data grid, and much of |
| * the functionality of the DataGrid control itself.</p> |
| * |
| * <p>The DataGrid skin is responsible for laying out the grid, column header, and scroller. |
| * The skin also configures the graphic elements used to render visual elements |
| * used as indicators, separators, and backgrounds. |
| * The DataGrid skin also defines a default item renderer, |
| * used to display the contents of each cell. |
| * Please see the documentation for the renderer class for the list of supported styles.</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:DataGrid></code> tag inherits all of the tag |
| * attributes of its superclass and adds the following tag attributes:</p> |
| * |
| * <pre> |
| * <s:DataGrid |
| * <strong>Properties</strong> |
| * columns="null" |
| * dataProvider="null" |
| * dataTipField="null" |
| * dataTipFunction="null" |
| * doubleClickMode="row" |
| * editable="false" |
| * editorColumnIndex="-1" |
| * editorRowIndex="-1" |
| * imeMode="null" |
| * itemEditor="null" |
| * itemRenderer="<i>DefaultGridItemRenderer</i>" |
| * preserveSelection="true" |
| * requestedColumnCount="-1" |
| * requestedMaxRowCount="-1" |
| * requestedMinColumnCount="-1" |
| * requestedMinRowCount="-1" |
| * requestedRowCount="-1" |
| * requireSelection="false" |
| * resizeableColumns="true" |
| * rowHeight="<i>Calculated default</i>" |
| * selectedCell="null" |
| * selectedCells="<i>empty Vector.<CellPosition></i>" |
| * selectedIndex="null" |
| * selectedIndices="<i>empty Vector.<CellPosition></i>" |
| * selectedItem="null" |
| * selectedItems="<i>empty Vector.<Object></i>" |
| * selectionMode="singleRow" |
| * showDataTips="false" |
| * sortableColumns="true" |
| * typicalItem="null" |
| * variableRowHeight="false" |
| * |
| * <strong>Styles</strong> |
| * alignmentBaseline="useDominantBaseline" |
| * baselineShift="0.0" |
| * cffHinting="horizontalStem" |
| * color="0" |
| * defaultGridItemEditor="null" |
| * digitCase="default" |
| * digitWidth="default" |
| * direction="ltr" |
| * dominantBaseline="auto" |
| * fontFamily="Arial" |
| * fontLookup="device" |
| * fontSize="12" |
| * fontStyle="normal" |
| * fontWeight="normal" |
| * justificationRule="auto" |
| * justificationStyle="auto" |
| * kerning="auto" |
| * ligatureLevel="common" |
| * lineHeight="120%" |
| * lineThrough="false" |
| * locale="en" |
| * renderingMode="cff" |
| * stretchCursor="<i>cursorStretch symbol from Assets.swf</i>" |
| * textAlign="start" |
| * textAlignLast="start" |
| * textAlpha="1" |
| * textDecoration="none" |
| * textJustify="interWord" |
| * trackingLeft="0" |
| * trackingRight="0" |
| * typographicCase="default" |
| * verticalScrollPolicy="auto" |
| * |
| * <strong>Styles for the Spark Theme</strong> |
| * alternatingRowColors="undefined" |
| * borderAlpha="1.0" |
| * borderColor="0x696969" |
| * borderVisible="true" |
| * caretColor="0x0167FF" |
| * contentBackgroundAlpha="1.0" |
| * contentBackgroundColor="0xFFFFFF" |
| * rollOverColor="0xCEDBEF" |
| * selectionColor="0xA8C6EE" |
| * symbolColor="0x000000" |
| * |
| * <strong>Styles for the Mobile Theme</strong> |
| * leading="0" |
| * letterSpacing="0" |
| * selectionColor="0xE0E0E0" |
| * symbolColor="0x000000" |
| * |
| * <strong>Events</strong> |
| * caretChange="<i>No default</i>" |
| * gridClick="<i>No default</i>" |
| * gridDoubleClick="<i>No default</i>" |
| * gridItemEditorSessionCancel="<i>No default</i>" |
| * gridItemEditorSessionSave="<i>No default</i>" |
| * gridItemEditorSessionStart="<i>No default</i>" |
| * gridItemEditorSessionStarting="<i>No default</i>" |
| * gridMouseDown="<i>No default</i>" |
| * gridMouseDrag="<i>No default</i>" |
| * gridMouseUp="<i>No default</i>" |
| * gridMouseRollOut="<i>No default</i>" |
| * gridMouseRollOver="<i>No default</i>" |
| * selectionChange="<i>No default</i>" |
| * selectionChanging="<i>No default</i>" |
| * sortChange="<i>No default</i>" |
| * sortChanging="<i>No default</i>" |
| * /> |
| * </pre> |
| * |
| * @see spark.components.Grid |
| * @see spark.components.gridClasses.GridColumn |
| * @see spark.skins.spark.DataGridSkin |
| * @see spark.skins.spark.DefaultGridItemRenderer |
| * |
| * @includeExample examples/DataGridSimpleExample.mxml |
| * @includeExample examples/DataGridMasterDetailExample.mxml |
| * @includeExample examples/DataGridTypicalItemExample.mxml |
| * @includeExample examples/DataGridRowHeightExample.mxml |
| * @includeExample examples/DataGridSelectionExample.mxml |
| * @includeExample examples/DataGridInvalidateCellExample.mxml |
| * @includeExample examples/DataGridLockedRowsAndColumnsExample.mxml |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public class DataGrid extends SkinnableContainerBase |
| implements IDataProviderEnhance, IFocusManagerComponent, IIMESupport |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class mixins |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Placeholder for mixin by DataGridAccImpl. |
| */ |
| mx_internal static var createAccessibilityImplementation:Function; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function DataGrid() |
| { |
| super(); |
| |
| addEventListener(Event.SELECT_ALL, selectAllHandler); |
| addEventListener(FocusEvent.KEY_FOCUS_CHANGE, keyFocusChangeHandler, false, EventPriority.DEFAULT_HANDLER); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * True, when the hover indicator should be updated on a ROLL_OVER event. |
| * If the mouse button is depressed while outside of the grid, the hover |
| * indicator is not enabled again until MOUSE_UP or ROLL_OUT. |
| */ |
| private var updateHoverOnRollOver:Boolean = true; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Drag and Drop Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * The point where the mouse down event was received. |
| * Used to track whether a drag operation should be initiated when the user |
| * drags further than a certain threshold. |
| */ |
| private var mouseDownPoint:Point; |
| |
| /** |
| * @private |
| * The index of the element the mouse down event was received for. Used to |
| * track which is the "focus item" for a drag and drop operation. |
| */ |
| private var mouseDownRowIndex:int = -1; |
| |
| /** |
| * @private |
| * The index of the element the mouse down event was received for. Used to |
| * track which is the "focus item" for a drag and drop operation. |
| */ |
| private var mouseDownColumnIndex:int = -1; |
| |
| /** |
| * @private |
| * The displayObject where the mouse down event was received. |
| * In touch interactionMode, used to track whether this item is |
| * the one that is moused up on so we can possibly select it. |
| */ |
| private var mouseDownObject:DisplayObject; |
| |
| /** |
| * @private |
| * When dragging is enabled with multiple selection, the selection is not |
| * comitted immediately on mouse down, but we wait to see whether the user |
| * intended to start a drag gesture instead. In that case we postpone |
| * comitting the selection until mouse up. |
| */ |
| private var pendingSelectionOnMouseUp:Boolean = false; |
| |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Skin Parts |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * IFactory valued skin parts that require special handling, see findSkinParts(). |
| */ |
| private static const factorySkinPartNames:Array = [ |
| "alternatingRowColorsBackground", |
| "caretIndicator", |
| "columnSeparator", |
| "headerColumnSeparator", |
| "hoverIndicator", |
| "lockedRowsSeparator", |
| "lockedColumnsSeparator", |
| "rowBackground", |
| "rowSeparator", |
| "selectionIndicator"]; |
| |
| //---------------------------------- |
| // alternatingRowColorsBackground |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render the <code>alternatingRowColors</code> style. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var alternatingRowColorsBackground:IFactory; |
| |
| //---------------------------------- |
| // caretIndicator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render the grid's caret indicator. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var caretIndicator:IFactory; |
| |
| //---------------------------------- |
| // columnHeaderGroup |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false")] |
| |
| /** |
| * A reference to the GridColumnHeaderGroup object that displays the column headers. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var columnHeaderGroup:GridColumnHeaderGroup; |
| |
| //---------------------------------- |
| // columnSeparator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render the vertical separator between columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var columnSeparator:IFactory; |
| |
| //---------------------------------- |
| // dropIndicator |
| //---------------------------------- |
| |
| [SkinPart(required="false", type="flash.display.DisplayObject")] |
| |
| /** |
| * The IVisualElement class that defines the appearance of the drop indicator. |
| * The drop indicator is resized and positioned by the layout to indicate |
| * in between which grid rows the drop will insert the drag source item. |
| * |
| * <p>This is a dynamic skin part: it's created as needed and then destroyed.</p> |
| * |
| * <p>The DataGrid will set the dropIndicator's height to its |
| * preferred height bracketed by its minHeight and maxHeight values. |
| * Its width will be unconditionally set to the grid's visible width.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public var dropIndicator:IFactory; |
| |
| //---------------------------------- |
| // editorIndicator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render a background behind |
| * item renderers that are being edited. |
| * Item renderers may only be edited |
| * when the data grid and the column are both editable and the |
| * column sets <code>rendererIsEditable</code> to <code>true</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var editorIndicator:IFactory; |
| |
| //---------------------------------- |
| // grid |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false")] |
| |
| /** |
| * A reference to the Grid control that displays row and columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var grid:Grid; |
| |
| //---------------------------------- |
| // hoverIndicator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to provide hover feedback. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var hoverIndicator:IFactory; |
| |
| //---------------------------------- |
| // lockedColumnsSeparator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render the vertical separator between locked and unlocked columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public var lockedColumnsSeparator:IFactory; |
| |
| //---------------------------------- |
| // lockedRowsSeparator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render the horizontal separator between locked and unlocked rows. |
| */ |
| public var lockedRowsSeparator:IFactory; |
| |
| //---------------------------------- |
| // rowBackground |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render the background of each row. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var rowBackground:IFactory; |
| |
| //---------------------------------- |
| // rowSeparator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render the horizontal separator between header rows. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var rowSeparator:IFactory; |
| |
| //---------------------------------- |
| // scroller |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false")] |
| |
| /** |
| * A reference to the Scroller control in the skin class |
| * that adds scroll bars to the DataGrid control. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var scroller:Scroller; |
| |
| //---------------------------------- |
| // selectionIndicator |
| //---------------------------------- |
| |
| [Bindable] |
| [SkinPart(required="false", type="mx.core.IVisualElement")] |
| |
| /** |
| * The IVisualElement class used to render selected rows or cells. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public var selectionIndicator:IFactory; |
| |
| /** |
| * @private |
| * If the alternatingRowColors style is set AND the alternatingRowColorsBackground |
| * skin part has been added AND the grid skin part has been added, then set |
| * grid.rowBackground = alternatingRowColorsBackground here. Otherwise just |
| * set it to the value of the rowBackground skin part (property). |
| */ |
| private function initializeGridRowBackground():void |
| { |
| if (!grid) |
| return; |
| |
| if ((getStyle("alternatingRowColors") as Array) && alternatingRowColorsBackground) |
| grid.rowBackground = alternatingRowColorsBackground; |
| else |
| grid.rowBackground = rowBackground; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Skin Part Property Internals |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * A list of functions to be applied to the grid skin part at partAdded() time. |
| * 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 deferredGridOperations:Vector.<Function> = new Vector.<Function>(); |
| |
| /** |
| * @private |
| * Defines one bit for each skin part property that's covered by DataGrid. Currently |
| * there are only grid properties. |
| */ |
| private static const partPropertyBits:Object = { |
| columns: uint(1 << 0), |
| dataProvider: uint(1 << 1), |
| itemRenderer: uint(1 << 2), |
| requestedRowCount: uint(1 << 3), |
| requestedColumnCount: uint(1 << 4), |
| requestedMaxRowCount: uint(1 << 5), |
| requestedMinRowCount: uint(1 << 6), |
| requestedMinColumnCount: uint(1 << 7), |
| rowHeight: uint(1 << 8), |
| showDataTips: uint(1 << 9), |
| typicalItem: uint(1 << 10), |
| variableRowHeight: uint(1 << 11), |
| dataTipField: uint(1 << 12), |
| dataTipFunction: uint(1 << 13), |
| resizableColumns: uint(1 << 14), |
| lockedColumnCount: uint(1 << 15), |
| lockedRowCount: uint(1 << 16) |
| }; |
| |
| /** |
| * @private |
| * If the grid skin part hasn't been added, this var is an object whose properties |
| * temporarily record the values of DataGrid properties that just "cover" grid skin |
| * part properties. |
| * |
| * If the grid skin part has been added (is non-null), then this var has |
| * a single is a uint bitmask property called propertyBits that's used |
| * used to track which grid properties have been explicitly set. |
| * |
| * See getPartProperty(), setPartProperty(). |
| */ |
| private var gridProperties:Object = {}; |
| |
| /** |
| * @private |
| * The default values of the grid skin part properties covered by DataGrid. |
| */ |
| private static const gridPropertyDefaults:Object = { |
| columns: null, |
| dataProvider: null, |
| itemRenderer: null, |
| resizableColumns: true, |
| requestedRowCount: int(-1), |
| requestedMaxRowCount: int(10), |
| requestedMinRowCount: int(-1), |
| requestedColumnCount: int(-1), |
| requestedMinColumnCount: int(-1), |
| rowHeight: NaN, |
| showDataTips: false, |
| typicalItem: null, |
| variableRowHeight: false, |
| dataTipField: null, |
| dataTipFunction: null, |
| lockedColumnCount: int(0), |
| lockedRowCount: int(0) |
| }; |
| |
| /** |
| * @private |
| * A utility method for looking up a skin part property that accounts for the possibility that |
| * the skin part is null. It's intended to be used in the definition of properties that just |
| * "cover" skin part properties. |
| * |
| * If part is non-null, then return part[propertyName]. Otherwise return the value |
| * of properties[propertyName], or defaults[propertyName] if the specified property's |
| * value is undefined. |
| */ |
| private static function getPartProperty(part:Object, properties:Object, propertyName:String, defaults:Object):* |
| { |
| if (part) |
| return part[propertyName]; |
| |
| const value:* = properties[propertyName]; |
| return (value === undefined) ? defaults[propertyName] : value; |
| } |
| |
| /** |
| * @private |
| * A utility method for setting a skin part property that accounts for the possibility that |
| * the skin part is null. It's intended to be used in the definition of properties that just |
| * "cover" skin part properties. |
| * |
| * Return true if the property's value was changed. |
| * |
| * If part is non-null, then set part[propertyName], otherwise set properties[propertyName]. |
| * |
| * If part is non-null then we set the bit for this property on the properties.propertyBits, to record |
| * the fact that the DataGrid cover property was explicitly set. |
| * |
| * In either case we treat setting a property to its default value specially: the effect |
| * is as if the property was never set at all. |
| */ |
| private static function setPartProperty(part:Object, properties:Object, propertyName:String, value:*, defaults:Object):Boolean |
| { |
| if (getPartProperty(part, properties, propertyName, defaults) === value) |
| return false; |
| |
| const defaultValue:* = defaults[propertyName]; |
| |
| if (part) |
| { |
| part[propertyName] = value; |
| if (value === defaultValue) |
| properties.propertyBits &= ~partPropertyBits[propertyName]; |
| else |
| properties.propertyBits |= partPropertyBits[propertyName]; |
| } |
| else |
| { |
| if (value === defaultValue) |
| delete properties[propertyName]; |
| else |
| properties[propertyName] = value; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @private |
| * Return the specified grid property. |
| */ |
| private function getGridProperty(propertyName:String):* |
| { |
| return getPartProperty(grid, gridProperties, propertyName, gridPropertyDefaults); |
| } |
| |
| /** |
| * @private |
| * Set the specified grid property and return true if the property actually changed. |
| */ |
| private function setGridProperty(propertyName:String, value:*):Boolean |
| { |
| return setPartProperty(grid, gridProperties, propertyName, value, gridPropertyDefaults); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Maximum time in milliseconds between a click and a double click. |
| */ |
| mx_internal var doubleClickTime:Number = 620; |
| |
| /** |
| * @private |
| * Key used to start editting a cell. |
| */ |
| mx_internal var editKey:uint = Keyboard.F2; |
| |
| /** |
| * @private |
| * A cell editor is initiated by a single click on a selected cell. |
| * If this variable is true then also open an editor when a cell is |
| * double clicked, otherwise cancel the edit. |
| */ |
| mx_internal var editOnDoubleClick:Boolean = false; |
| |
| /** |
| * @private |
| * Provides all the logic to start and end item |
| * editor sessions. |
| * |
| * Create your own editor by overriding the <code>createEditor()</code> |
| * method. |
| */ |
| mx_internal var editor:DataGridEditor; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // 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)); |
| } |
| |
| //---------------------------------- |
| // columns (delegates to grid.columns) |
| //---------------------------------- |
| |
| [Bindable("columnsChanged")] |
| [Inspectable(category="General")] |
| |
| /** |
| * @copy spark.components.Grid#columns |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get columns():IList |
| { |
| return getGridProperty("columns"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set columns(value:IList):void |
| { |
| if (setGridProperty("columns", value)) |
| { |
| if (columnHeaderGroup) |
| { |
| columnHeaderGroup.layout.clearVirtualLayoutCache(); |
| columnHeaderGroup.invalidateSize(); |
| columnHeaderGroup.invalidateDisplayList(); |
| } |
| |
| dispatchChangeEvent("columnsChanged"); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function getColumnAt(columnIndex:int):GridColumn |
| { |
| const grid:Grid = grid; |
| if (!grid || !grid.columns) |
| return null; |
| |
| const columns:IList = grid.columns; |
| return ((columnIndex >= 0) && (columnIndex < columns.length)) ? columns.getItemAt(columnIndex) as GridColumn : null; |
| } |
| |
| //---------------------------------- |
| // columnsLength |
| //---------------------------------- |
| |
| /** |
| * Returns the value of <code>columns.length</code> if the columns IList |
| * was specified, otherwise 0. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5* |
| */ |
| public function get columnsLength():int |
| { |
| const columns:IList = columns; |
| return (columns) ? columns.length : 0; |
| } |
| |
| //---------------------------------- |
| // dataProvider (delegates to grid.dataProvider) |
| //---------------------------------- |
| |
| [Bindable("dataProviderChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * @copy spark.components.Grid#dataProvider |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataProvider():IList |
| { |
| return getGridProperty("dataProvider"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataProvider(value:IList):void |
| { |
| if (setGridProperty("dataProvider", value)) |
| dispatchChangeEvent("dataProviderChanged"); |
| } |
| |
| //---------------------------------- |
| // dataProviderLength |
| //---------------------------------- |
| |
| /** |
| * Returns the value of <code>dataProvider.length</code> if the dataProvider IList |
| * was specified, otherwise 0. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataProviderLength():int |
| { |
| const dataProvider:IList = dataProvider; |
| return (dataProvider) ? dataProvider.length : 0; |
| } |
| |
| //---------------------------------- |
| // dataTipField (delegates to grid.dataTipField) |
| //---------------------------------- |
| |
| [Bindable("dataTipFieldChanged")] |
| [Inspectable(category="Data", defaultValue="null")] |
| |
| /** |
| * @copy spark.components.Grid#dataTipField |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataTipField():String |
| { |
| return getGridProperty("dataTipField"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataTipField(value:String):void |
| { |
| if (setGridProperty("dataTipField", value)) |
| dispatchChangeEvent("dataTipFieldChanged"); |
| } |
| |
| //---------------------------------- |
| // dataTipFunction (delegates to grid.dataTipFunction) |
| //---------------------------------- |
| |
| [Bindable("dataTipFunctionChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * @copy spark.components.Grid#dataTipFunction |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataTipFunction():Function |
| { |
| return getGridProperty("dataTipFunction"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dataTipFunction(value:Function):void |
| { |
| if (setGridProperty("dataTipFunction", value)) |
| dispatchChangeEvent("dataTipFunctionChanged"); |
| } |
| |
| |
| //---------------------------------- |
| // doubleClickMode |
| //---------------------------------- |
| |
| [Bindable("doubleClickModeChanged")] |
| [Inspectable(category="General", enumeration="cell,grid,row", defaultValue="row")] |
| |
| /** |
| * @copy spark.components.Grid#doubleClickMode |
| * |
| * @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 grid.doubleClickMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set doubleClickMode(newValue:String):void |
| { |
| if (setGridProperty("doubleClickMode", newValue)) |
| { |
| dispatchChangeEvent("doubleClickModeChanged"); |
| } |
| } |
| |
| |
| //---------------------------------- |
| // draggableColumns |
| //---------------------------------- |
| |
| private var _draggableColumns:Boolean = false; |
| |
| [Inspectable(category="General", defaultValue="false")] |
| [Bindable("draggableColumnsChanged")] |
| |
| /** |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 1 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public function get draggableColumns():Boolean |
| { |
| return _draggableColumns; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set draggableColumns(value:Boolean):void |
| { |
| if (value == _draggableColumns) |
| return; |
| |
| _draggableColumns = value; |
| dispatchChangeEvent("draggableColumnsChanged"); |
| } |
| |
| //---------------------------------- |
| // editable |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the editable property. |
| */ |
| private var _editable:Boolean = false; |
| |
| [Inspectable(category="General", defaultValue="false")] |
| |
| /** |
| * A flag which enables editing the data items in the DataGrid. |
| * If <code>true</code> and <code>selectionMode</code> is not equal to "none", clicking on |
| * a cell opens an item editor. |
| * |
| * <p>You can disable editing for individual columns of the DataGrid control using the |
| * GridColumn <code>editable</code> property. |
| * By default, all visible columns are editable.</p> |
| * |
| * <p>You can enable or disable editing per cell (rather than per column) |
| * by handling the <code>startItemEditorSession</code> event. |
| * In the event handler, add the necessary logic to determine |
| * if the cell should be editable.</p> |
| * |
| * @default false |
| * |
| * @see #selectionMode |
| * @see spark.components.gridClasses.GridColumn#editable |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get editable():Boolean |
| { |
| return _editable; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set editable(value:Boolean):void |
| { |
| _editable = value; |
| } |
| |
| //---------------------------------- |
| // editorActivationMouseEvent |
| //---------------------------------- |
| |
| private var _editorActivationMouseEvent:String = GridItemEditorActivationMouseEvent.SINGLE_CLICK_ON_SELECTED_CELL; |
| |
| [Bindable("editorActivationMouseEventChanged")] |
| [Inspectable(category="General", enumeration="doubleClick,none,singleClick,singleClickOnSelectedCell", defaultValue="singleClickOnSelectedCell")] |
| |
| /** |
| * The type of mouse event that starts an editor session. Must be one of |
| * values in <code>GridItemEditorMouseEvent</code>. This value |
| * provides a default value for each column of a DataGrid. A different |
| * value can be specified on a grid column to override the default. |
| * |
| * @default "singleClickOnSelectedCell" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function get editorActivationMouseEvent():String |
| { |
| return _editorActivationMouseEvent; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set editorActivationMouseEvent(value:String):void |
| { |
| if (_editorActivationMouseEvent == value) |
| return; |
| |
| _editorActivationMouseEvent = value; |
| dispatchChangeEvent("editorActivationMouseEventChanged"); |
| } |
| |
| //---------------------------------- |
| // editorColumnIndex |
| //---------------------------------- |
| |
| /** |
| * The zero-based column index of the cell that is being edited. |
| * The value is -1 if no cell is being edited. |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get editorColumnIndex():int |
| { |
| if (editor) |
| return editor.editorColumnIndex; |
| |
| return -1; |
| } |
| |
| //---------------------------------- |
| // editorRowIndex |
| //---------------------------------- |
| |
| /** |
| * The zero-based row index of the cell that is being edited. |
| * The value is -1 if no cell is being edited. |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get editorRowIndex():int |
| { |
| if (editor) |
| return editor.editorRowIndex; |
| |
| return -1; |
| } |
| |
| //---------------------------------- |
| // enableIME |
| //---------------------------------- |
| |
| /** |
| * A flag that indicates whether the IME should |
| * be enabled when the component receives focus. |
| * |
| * If the item editor is open, it sets this property |
| * accordingly. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get enableIME():Boolean |
| { |
| return false; |
| } |
| |
| |
| //---------------------------------- |
| // isFirstRow |
| //---------------------------------- |
| |
| /** |
| * @copy spark.components.Grid#isFirstRow |
| * If a <code>grid</code> is not assigned, will always return false; |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function get isFirstRow():Boolean |
| { |
| if (grid) |
| { |
| return grid.isFirstRow; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| //---------------------------------- |
| // isLastRow |
| //---------------------------------- |
| |
| /** |
| * @copy spark.components.Grid#isLastRow |
| * If a <code>grid</code> is not assigned, will always return false; |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function get isLastRow():Boolean |
| { |
| if (grid) |
| { |
| return grid.isLastRow; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| //---------------------------------- |
| // multiColumnSortingEnabled |
| //---------------------------------- |
| |
| private var _multiColumnSortingEnabled:Boolean = false; |
| |
| [Bindable("multiColumnSortingEnabledChanged")] |
| [Inspectable(category="General", defaultValue="false")] |
| |
| /** |
| * If this property is true and sorting has been enabled, then users can interactively |
| * specify multi-column sorts by control-clicking in column headers (Command+Click on OSX). |
| * Sorting is enabled for a column if the DataGrid <code>sortable</code> property is true |
| * and the column's <code>sortable</code> property is true. Sorting is enabled for |
| * all columns by default, multi-column sorting is not. |
| * |
| * @default false |
| * |
| * @see #sortableColumns |
| * @see spark.components.gridClasses.GridColumn#sortable |
| |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get multiColumnSortingEnabled():Boolean |
| { |
| return _multiColumnSortingEnabled; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set multiColumnSortingEnabled(value:Boolean):void |
| { |
| if (_multiColumnSortingEnabled == value) |
| return; |
| |
| _multiColumnSortingEnabled = value; |
| dispatchChangeEvent("multiColumnSortingEnabledChanged"); |
| } |
| |
| //---------------------------------- |
| // gridSelection (private) |
| //---------------------------------- |
| |
| private var _gridSelection:GridSelection = null; |
| |
| /** |
| * @private |
| * This object becomes the grid's gridSelection property after the grid skin part has been |
| * added. It should only be referenced by this class when the grid skin part is null. |
| */ |
| protected function get gridSelection():GridSelection |
| { |
| if (!_gridSelection) |
| _gridSelection = createGridSelection(); |
| return _gridSelection; |
| } |
| |
| //---------------------------------- |
| // imeMode |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _imeMode:String = null; |
| |
| [Inspectable(environment="none")] |
| |
| /** |
| * The default value for the GridColumn <code>imeMode</code> property, |
| * which specifies the IME (Input Method Editor) mode. |
| * The IME enables users to enter text in Chinese, Japanese, and Korean. |
| * Flex sets the specified IME mode when the control gets focus, |
| * and sets it back to the previous value when the control loses focus. |
| * |
| * <p>The flash.system.IMEConversionMode class defines constants for the |
| * valid values for this property. |
| * You can also specify <code>null</code> to specify no IME.</p> |
| * |
| * @see flash.system.IMEConversionMode |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get imeMode():String |
| { |
| return _imeMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set imeMode(value:String):void |
| { |
| _imeMode = value; |
| } |
| |
| //---------------------------------- |
| // internalFocusOwner |
| //---------------------------------- |
| |
| private static const GRID_FOCUS_OWNER:int = 0; |
| private static const HEADER_FOCUS_OWNER:int = 1; |
| private static const NO_FOCUS_OWNER:int = -1; |
| |
| private var _internalFocusOwner:int = -1; |
| |
| [Bindable("internalFocusOwnerChanged")] |
| |
| /** |
| * Tracks the internal focus owner when the DataGrid has the focus: one of GRID_FOCUS_OWNER, |
| * HEADER_FOCUS_OWNER, or NO_FOCUS_OWNER. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| private function get internalFocusOwner():int |
| { |
| return _internalFocusOwner; |
| } |
| |
| /** |
| * @private |
| */ |
| private function set internalFocusOwner(value:int):void |
| { |
| if (_internalFocusOwner == value) |
| return; |
| |
| _internalFocusOwner = value; |
| |
| if (columnHeaderGroup) |
| columnHeaderGroup.highlightSelectedColumn = (value == HEADER_FOCUS_OWNER); |
| |
| if (grid) |
| grid.showCaret = (value == GRID_FOCUS_OWNER); |
| |
| dispatchChangeEvent("internalFocusOwnerChanged"); |
| } |
| |
| //---------------------------------- |
| // itemEditor |
| //---------------------------------- |
| |
| private var _itemEditor:IFactory = null; |
| |
| [Bindable("itemEditorChanged")] |
| |
| /** |
| * The default value for the GridColumn <code>itemEditor</code> property, |
| * which specifies the IGridItemEditor class used to create item editor instances. |
| * |
| * @default null. |
| * |
| * @see #dataField |
| * @see spark.components.gridClasses.IGridItemEditor |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get itemEditor():IFactory |
| { |
| return _itemEditor; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set itemEditor(value:IFactory):void |
| { |
| if (_itemEditor == value) |
| return; |
| |
| _itemEditor = value; |
| |
| dispatchChangeEvent("itemEditorChanged"); |
| } |
| |
| /** |
| * A reference to the currently active instance of the item editor, |
| * if it exists. |
| * |
| * <p>To access the item editor instance and the new item value when an |
| * item is being edited, you use the <code>itemEditorInstance</code> |
| * property. The <code>itemEditorInstance</code> property |
| * is not valid until the <code>itemEditorSessionStart</code> event is |
| * dispatched.</p> |
| * |
| * <p>The <code>DataGridColumn.itemEditor</code> property defines the |
| * class of the item editor and, therefore, the data type of the item |
| * editor instance.</p> |
| * |
| * <p>Do not set this property in MXML.</p> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get itemEditorInstance():IGridItemEditor |
| { |
| if (editor) |
| return editor.itemEditorInstance; |
| |
| return null; |
| } |
| |
| //---------------------------------- |
| // itemRenderer (delegates to grid.itemRenderer) |
| //---------------------------------- |
| |
| [Bindable("itemRendererChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * @copy spark.components.Grid#itemRenderer |
| * |
| * @default DefaultGridItemRenderer |
| * |
| * @see spark.components.gridClasses.GridItemRenderer |
| * @see spark.skins.spark.DefaultGridItemRenderer |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get itemRenderer():IFactory |
| { |
| return getGridProperty("itemRenderer"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set itemRenderer(value:IFactory):void |
| { |
| if (setGridProperty("itemRenderer", value)) |
| dispatchChangeEvent("itemRendererChanged"); |
| } |
| |
| //---------------------------------- |
| // lockedColumnCount (delegates to grid.lockedColumnCount) |
| //---------------------------------- |
| |
| [Bindable("lockedColumnCountChanged")] |
| [Inspectable(category="General", defaultValue="0", minValue="0")] |
| |
| /** |
| * @copy spark.components.Grid#lockedColumnCount |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public function get lockedColumnCount():int |
| { |
| return getGridProperty("lockedColumnCount"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedColumnCount(value:int):void |
| { |
| if (setGridProperty("lockedColumnCount", value)) |
| dispatchChangeEvent("lockedColumnCountChanged"); |
| } |
| |
| //---------------------------------- |
| // lockedRowCount (delegates to grid.lockedRowCount) |
| //---------------------------------- |
| |
| [Bindable("lockedRowCountChanged")] |
| [Inspectable(category="General", defaultValue="0", minValue="0")] |
| |
| /** |
| * @copy spark.components.Grid#lockedRowCount |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 5.0 |
| */ |
| public function get lockedRowCount():int |
| { |
| return getGridProperty("lockedRowCount"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedRowCount(value:int):void |
| { |
| if (setGridProperty("lockedRowCount", value)) |
| dispatchChangeEvent("lockedRowCountChanged"); |
| } |
| |
| //---------------------------------- |
| // preserveSelection (delegates to grid.preserveSelection) |
| //---------------------------------- |
| |
| [Inspectable(category="General", defaultValue="true")] |
| |
| /** |
| * @copy spark.components.Grid#preserveSelection |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get preserveSelection():Boolean |
| { |
| if (grid) |
| return grid.preserveSelection; |
| else |
| return gridSelection.preserveSelection; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set preserveSelection(value:Boolean):void |
| { |
| if (grid) |
| grid.preserveSelection = value; |
| else |
| gridSelection.preserveSelection = value; |
| } |
| |
| //---------------------------------- |
| // requireSelection (delegates to grid.requireSelection) |
| //---------------------------------- |
| |
| [Inspectable(category="General", defaultValue="false")] |
| |
| /** |
| * @copy spark.components.Grid#requireSelection |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requireSelection():Boolean |
| { |
| if (grid) |
| return grid.requireSelection; |
| else |
| return gridSelection.requireSelection; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requireSelection(value:Boolean):void |
| { |
| if (grid) |
| grid.requireSelection = value; |
| else |
| gridSelection.requireSelection = value; |
| } |
| |
| //---------------------------------- |
| // requestedRowCount (delegates to grid.requestedRowCount) |
| //---------------------------------- |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * @copy spark.components.Grid#requestedRowCount |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedRowCount():int |
| { |
| return getGridProperty("requestedRowCount"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedRowCount(value:int):void |
| { |
| setGridProperty("requestedRowCount", value); |
| } |
| |
| //---------------------------------- |
| // requestedColumnCount (delegates to grid.requestedColumnCount) |
| //---------------------------------- |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * @copy spark.components.Grid#requestedColumnCount |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedColumnCount():int |
| { |
| return getGridProperty("requestedColumnCount"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedColumnCount(value:int):void |
| { |
| setGridProperty("requestedColumnCount", value); |
| } |
| |
| //---------------------------------- |
| // requestedMaxRowCount (delegates to grid.requestedMaxRowCount) |
| //---------------------------------- |
| |
| [Inspectable(category="General", defaultValue="10", minValue="-1")] |
| |
| /** |
| * @copy spark.components.Grid#requestedMaxRowCount |
| * |
| * @default 10 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedMaxRowCount():int |
| { |
| return getGridProperty("requestedMaxRowCount"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedMaxRowCount(value:int):void |
| { |
| setGridProperty("requestedMaxRowCount", value); |
| } |
| |
| //---------------------------------- |
| // requestedMinRowCount (delegates to grid.requestedMinRowCount) |
| //---------------------------------- |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * @copy spark.components.Grid#requestedMinRowCount |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedMinRowCount():int |
| { |
| return getGridProperty("requestedMinRowCount"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedMinRowCount(value:int):void |
| { |
| setGridProperty("requestedMinRowCount", value); |
| } |
| |
| //---------------------------------- |
| // requestedMinColumnCount (delegates to grid.requestedMinColumnCount) |
| //---------------------------------- |
| |
| [Inspectable(category="General", minValue="-1")] |
| |
| /** |
| * @copy spark.components.Grid#requestedMinColumnCount |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get requestedMinColumnCount():int |
| { |
| return getGridProperty("requestedMinColumnCount"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set requestedMinColumnCount(value:int):void |
| { |
| setGridProperty("requestedMinColumnCount", value); |
| } |
| |
| //---------------------------------- |
| // resizableColumns (delegates to grid.resizableColumns) |
| //---------------------------------- |
| |
| [Bindable("resizableColumnsChanged")] |
| [Inspectable(category="General", defaultValue="true")] |
| |
| /** |
| * @copy spark.components.Grid#resizableColumns |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get resizableColumns():Boolean |
| { |
| return getGridProperty("resizableColumns"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set resizableColumns(value:Boolean):void |
| { |
| if (setGridProperty("resizableColumns", value)) |
| dispatchChangeEvent("resizableColumnsChanged"); |
| } |
| |
| //---------------------------------- |
| // rowHeight (delegates to grid.rowHeight) |
| //---------------------------------- |
| |
| [Bindable("rowHeightChanged")] |
| [Inspectable(category="General", minValue="0.0")] |
| |
| /** |
| * @copy spark.components.Grid#rowHeight |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get rowHeight():Number |
| { |
| return getGridProperty("rowHeight"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set rowHeight(value:Number):void |
| { |
| if (setGridProperty("rowHeight", value)) |
| dispatchChangeEvent("rowHeightChanged"); |
| } |
| |
| //---------------------------------- |
| // selectionMode (delegates to grid.selectionMode) |
| //---------------------------------- |
| |
| [Bindable("selectionModeChanged")] |
| [Inspectable(category="General", enumeration="none,singleRow,multipleRows,singleCell,multipleCells", defaultValue="singleRow")] |
| |
| /** |
| * @copy spark.components.Grid#selectionMode |
| * |
| * @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 |
| { |
| if (grid) |
| return grid.selectionMode; |
| else |
| return gridSelection.selectionMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectionMode(value:String):void |
| { |
| if (selectionMode == value) |
| return; |
| |
| if (grid) |
| grid.selectionMode = value; |
| else |
| gridSelection.selectionMode = value; |
| |
| // Show the caret if we have focus and not in grid selection mode of "none". |
| if (grid) |
| grid.showCaret = (value != GridSelectionMode.NONE) && (this == getFocus()) && (internalFocusOwner == GRID_FOCUS_OWNER); |
| |
| dispatchChangeEvent("selectionModeChanged"); |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function isRowSelectionMode():Boolean |
| { |
| const mode:String = selectionMode; |
| return mode == GridSelectionMode.SINGLE_ROW || mode == GridSelectionMode.MULTIPLE_ROWS; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function isCellSelectionMode():Boolean |
| { |
| const mode:String = selectionMode; |
| return mode == GridSelectionMode.SINGLE_CELL || mode == GridSelectionMode.MULTIPLE_CELLS; |
| } |
| |
| //---------------------------------- |
| // showDataTips |
| //---------------------------------- |
| |
| [Bindable("showDataTipsChanged")] |
| [Inspectable(category="Data", defaultValue="false")] |
| |
| /** |
| * @copy spark.components.Grid#showDataTips |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get showDataTips():Boolean |
| { |
| return getGridProperty("showDataTips"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showDataTips(value:Boolean):void |
| { |
| if (setGridProperty("showDataTips", value)) |
| dispatchChangeEvent("showDataTipsChanged"); |
| } |
| |
| //---------------------------------- |
| // sortableColumns |
| //---------------------------------- |
| |
| private var _sortableColumns:Boolean = true; |
| |
| [Bindable("sortableColumnsChanged")] |
| [Inspectable(category="General", defaultValue="true")] |
| |
| /** |
| * Specifies whether the user can interactively sort columns. |
| * If <code>true</code>, the user can sort the data provider by the |
| * data field of a column by clicking on the column's header. |
| * If <code>true</code>, an individual column can set its |
| * <code>sortable</code> property to <code>false</code> to |
| * prevent the user from sorting by that column. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get sortableColumns():Boolean |
| { |
| return _sortableColumns; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set sortableColumns(value:Boolean):void |
| { |
| if (_sortableColumns == value) |
| return; |
| |
| _sortableColumns = value; |
| dispatchChangeEvent("sortableColumnsChanged"); |
| } |
| |
| //---------------------------------- |
| // typicalItem (delegates to grid.typicalItem) |
| //---------------------------------- |
| |
| [Bindable("typicalItemChanged")] |
| [Inspectable(category="Data")] |
| |
| /** |
| * @copy spark.components.Grid#typicalItem |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get typicalItem():Object |
| { |
| return getGridProperty("typicalItem"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set typicalItem(value:Object):void |
| { |
| if (setGridProperty("typicalItem", value)) |
| dispatchChangeEvent("typicalItemChanged"); |
| } |
| |
| /** |
| * @copy spark.components.Grid#invalidateTypicalItem() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4.5 |
| */ |
| public function invalidateTypicalItem():void |
| { |
| if (grid) |
| grid.invalidateTypicalItemRenderer(); |
| } |
| |
| //---------------------------------- |
| // variableRowHeight (delegates to grid.variableRowHeight) |
| //---------------------------------- |
| |
| [Bindable("variableRowHeightChanged")] |
| [Inspectable(category="General", defaultValue="false")] |
| |
| /** |
| * @copy spark.components.Grid#variableRowHeight |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get variableRowHeight():Boolean |
| { |
| return getGridProperty("variableRowHeight"); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set variableRowHeight(value:Boolean):void |
| { |
| if (setGridProperty("variableRowHeight", value)) |
| dispatchChangeEvent("variableRowHeightChanged"); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Drag and Drop Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // dragEnabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the dragEnabled property. |
| */ |
| private var _dragEnabled:Boolean = false; |
| |
| [Inspectable(defaultValue="false")] |
| |
| /** |
| * A flag that indicates whether you can drag items out of |
| * this control and drop them on other controls. |
| * If <code>true</code>, dragging is enabled for the control. |
| * If the <code>dropEnabled</code> property is also <code>true</code>, |
| * you can drag items and drop them within this control |
| * to reorder the items. |
| * |
| * <p>Drag and drop is not supported on mobile devices where |
| * <code>interactionMode</code> is set to <code>touch</code>.</p> |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function get dragEnabled():Boolean |
| { |
| return _dragEnabled; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dragEnabled(value:Boolean):void |
| { |
| if (value == _dragEnabled) |
| return; |
| _dragEnabled = value; |
| |
| if (_dragEnabled) |
| { |
| addEventListener(DragEvent.DRAG_START, dragStartHandler, false, EventPriority.DEFAULT_HANDLER); |
| addEventListener(DragEvent.DRAG_COMPLETE, dragCompleteHandler, false, EventPriority.DEFAULT_HANDLER); |
| } |
| else |
| { |
| removeEventListener(DragEvent.DRAG_START, dragStartHandler, false); |
| removeEventListener(DragEvent.DRAG_COMPLETE, dragCompleteHandler, false); |
| } |
| } |
| |
| //---------------------------------- |
| // dragMoveEnabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the dragMoveEnabled property. |
| */ |
| private var _dragMoveEnabled:Boolean = false; |
| |
| [Inspectable(defaultValue="false")] |
| |
| /** |
| * A flag that indicates whether items can be moved instead |
| * of just copied from the control as part of a drag-and-drop |
| * operation. |
| * If <code>true</code>, and the <code>dragEnabled</code> property |
| * is <code>true</code>, items can be moved. |
| * Often the data provider cannot or should not have items removed |
| * from it, so a MOVE operation should not be allowed during |
| * drag-and-drop. |
| * |
| * <p>Drag and drop is not supported on mobile devices where |
| * <code>interactionMode</code> is set to <code>touch</code>.</p> |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function get dragMoveEnabled():Boolean |
| { |
| return _dragMoveEnabled; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dragMoveEnabled(value:Boolean):void |
| { |
| _dragMoveEnabled = value; |
| } |
| |
| //---------------------------------- |
| // dropEnabled |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the <code>dropEnabled</code> property. |
| */ |
| private var _dropEnabled:Boolean = false; |
| |
| [Inspectable(defaultValue="false")] |
| |
| /** |
| * A flag that indicates whether dragged items can be dropped onto the |
| * control. |
| * |
| * <p>If you set this property to <code>true</code>, |
| * the control accepts all data formats, and assumes that |
| * the dragged data matches the format of the data in the data provider. |
| * If you want to explicitly check the data format of the data |
| * being dragged, you must handle one or more of the drag events, |
| * such as <code>dragEnter</code> and <code>dragOver</code>, |
| * and call the DragEvent's <code>preventDefault()</code> method |
| * to customize the way the list class accepts dropped data.</p> |
| * |
| * <p>When you set <code>dropEnabled</code> to <code>true</code>, |
| * Flex automatically calls the <code>showDropFeedback()</code> |
| * and <code>hideDropFeedback()</code> methods to display the drop |
| * indicator.</p> |
| * |
| * <p>Drag and drop is not supported on mobile devices where |
| * <code>interactionMode</code> is set to <code>touch</code>.</p> |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function get dropEnabled():Boolean |
| { |
| return _dropEnabled; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dropEnabled(value:Boolean):void |
| { |
| if (value == _dropEnabled) |
| return; |
| _dropEnabled = value; |
| |
| if (_dropEnabled) |
| { |
| addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler, false, EventPriority.DEFAULT_HANDLER); |
| addEventListener(DragEvent.DRAG_EXIT, dragExitHandler, false, EventPriority.DEFAULT_HANDLER); |
| addEventListener(DragEvent.DRAG_OVER, dragOverHandler, false, EventPriority.DEFAULT_HANDLER); |
| addEventListener(DragEvent.DRAG_DROP, dragDropHandler, false, EventPriority.DEFAULT_HANDLER); |
| } |
| else |
| { |
| removeEventListener(DragEvent.DRAG_ENTER, dragEnterHandler, false); |
| removeEventListener(DragEvent.DRAG_EXIT, dragExitHandler, false); |
| removeEventListener(DragEvent.DRAG_OVER, dragOverHandler, false); |
| removeEventListener(DragEvent.DRAG_DROP, dragDropHandler, false); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * This component holds the focus and accessibilityImplementation (DataGridAccImpl) |
| * for the DataGrid to enable accessibility when the focus shifts to DataGrid descendants, |
| * notably item editors. |
| * |
| * DataGridAccImpl/createAccessibilityImplementation() initializes the focusOwner's |
| * accessibilityImplementation, rather than the DataGrid's, so that the MSAA |
| * representation of descendant components will not be "obscured" by DataGridAccImpl. |
| * |
| * @see #createChildren(), #setFocus(), #isOurFocus(). |
| */ |
| mx_internal var focusOwner:UIComponent; |
| |
| /** |
| * @private |
| * The accessibility implementation depends on the focusOwner's bounds, as in |
| * DisplayObject.getBounds(), which is defined by the bounds of what has been drawn, |
| * not the focusOwner's width and height properties. |
| */ |
| private var focusOwnerWidth:Number = 1; |
| private var focusOwnerHeight:Number = 1; |
| |
| /** |
| * @private |
| * Create the focusOwner - a component that holds the keyboard focus for the DataGrid |
| * for the sake of the accessibility implementation. |
| * |
| * This component fails to add its DataGridAccImpl accessibilityImplementation to |
| * the MSAA if it doesn't render, so we draw one alpha=0.0 pixel here and make it |
| * $visible=true. |
| */ |
| override protected function createChildren():void |
| { |
| super.createChildren(); |
| |
| focusOwner = new UIComponent(); |
| const g:Graphics = focusOwner.graphics; |
| g.clear(); |
| g.lineStyle(0, 0x000000, 0); |
| g.drawRect(0, 0, focusOwnerWidth, focusOwnerHeight); |
| $addChild(focusOwner); |
| focusOwner.tabEnabled = true; |
| focusOwner.tabIndex = tabIndex; |
| focusOwner.$visible = true; |
| } |
| |
| /** |
| * @private |
| * Ensure that IDataGridElements are laid out after the grid skin part. |
| * At the moment, DataGrid has only one IDataGridElement, columnHeaderGroup. |
| * |
| * The DataGrid columnHeaderGroup's layout role is unusual, since it depends on |
| * the layout of the grid skin part. |
| * Â The columnHeaderGroup's column widths, scroll position, and list of visible columns |
| * are defined by the grid. |
| * Â That means that the grid needs to compute its layout first. |
| * |
| * The Flex LayoutManager orders the per-element work in each of its phases according |
| * to the element's nestLevel. The measure() (validateSize) phase is "bottom up" |
| * with respect to the nestLevel, which means that the deepest nodes in the tree with the |
| * highest nestLevel are measured first. |
| * Similarly the updateDisplayList() (validateDisplayList) phase is "top down" where the nodes |
| * with the lowest nestLevel are validated first. |
| * To guarantee that the columnHeaderGroup skin part is laid out after the grid skin part, |
| * we need to ensure that its nestLevel is greater than the grid's nestLevel. |
| * |
| * As the DataGrid's skin defines the grid and columnHeaderGroup skin parts, there is no |
| * way for the DataGrid component to constrain their relative locations in the visual element |
| * hierarchy. |
| * However, all ILayoutManagerClients have a nestLevel property, which specifies the element's |
| * depth relative to its SystemManager root. |
| * Thus, we can overcome the limitation by initializing the columnHeaderGroup's nestLevel |
| * to be grid.nestLevel+1, which ensures that the columnHeaderGroup will be validated after |
| * the grid. |
| */ |
| override public function set nestLevel(value:int):void |
| { |
| super.nestLevel = value; |
| |
| if (grid) |
| initializeDataGridElement(columnHeaderGroup); |
| } |
| |
| /** |
| * @private |
| * Ensure that the DataGrid appears in the correct tab order, despite the fact that its |
| * focusOwner gets the focus. |
| */ |
| override public function set tabIndex(index:int):void |
| { |
| super.tabIndex = index; |
| if (focusOwner) |
| focusOwner.tabIndex = index; |
| } |
| |
| /** |
| * @private |
| * Sync the focusOwner's copy of this value because the we can't cover this case in |
| * DataGridAccImpl/get_accDescription(childID). Currently get_accDescription() is never |
| * called with childID=0. |
| */ |
| override public function set accessibilityDescription(value:String):void |
| { |
| super.accessibilityDescription = value; |
| if (focusOwner) |
| focusOwner.accessibilityDescription = value; |
| } |
| |
| /** |
| * @private |
| * Sync the focusOwner's copy of this value because the we can't cover this case in |
| * DataGridAccImpl/get_accShortcut(childID). Currently get_accShortcut() is never |
| * called with childID=0. |
| */ |
| override public function set accessibilityShortcut(value:String):void |
| { |
| super.accessibilityShortcut = value; |
| if (focusOwner) |
| focusOwner.accessibilityShortcut = value; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function initializeAccessibility():void |
| { |
| if (DataGrid.createAccessibilityImplementation != null) |
| DataGrid.createAccessibilityImplementation(this); |
| } |
| |
| /** |
| * @private |
| * Override to set proper width and height on focusOwner object that |
| * the DataGridAccImpl uses to compute the location of the DataGrid. |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void |
| { |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| if (focusOwner && ((focusOwnerWidth != unscaledWidth) || (focusOwnerHeight != unscaledHeight))) |
| { |
| focusOwnerWidth = unscaledWidth; |
| focusOwnerHeight = unscaledHeight; |
| const g:Graphics = focusOwner.graphics; |
| g.clear(); |
| g.lineStyle(0, 0x000000, 0); |
| g.drawRect(0, 0, focusOwnerWidth, focusOwnerHeight); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override public function setFocus():void |
| { |
| if (grid) |
| focusOwner.setFocus(); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function isOurFocus(target:DisplayObject):Boolean |
| { |
| return (target == focusOwner) || super.isOurFocus(target); |
| } |
| |
| /** |
| * @private |
| */ |
| override public function styleChanged(styleName:String):void |
| { |
| super.styleChanged(styleName); |
| |
| const allStyles:Boolean = (styleName == null || styleName == "styleName"); |
| |
| if (grid) |
| { |
| if (allStyles || styleManager.isSizeInvalidatingStyle(styleName)) |
| { |
| if (grid) |
| { |
| grid.invalidateSize(); |
| grid.clearGridLayoutCache(true); |
| } |
| if (columnHeaderGroup) |
| { |
| columnHeaderGroup.layout.clearVirtualLayoutCache(); |
| columnHeaderGroup.invalidateSize(); |
| } |
| } |
| |
| if (allStyles || (styleName == "alternatingRowColors")) |
| { |
| initializeGridRowBackground(); |
| if (grid && grid.layout) |
| grid.layout.clearVirtualLayoutCache(); |
| } |
| |
| if (grid) |
| grid.invalidateDisplayList(); |
| |
| if (columnHeaderGroup) |
| columnHeaderGroup.invalidateDisplayList(); |
| } |
| |
| if (scroller) |
| { |
| // The scrollPolicy styles are initialized in framework/defaults.css |
| // so there's no way to determine if been explicitly set here. To avoid |
| // preempting explicitly set scroller scrollPolicy styles with the default |
| // "auto" value, we only forward the style if it's not "auto". |
| |
| const vsp:String = getStyle("verticalScrollPolicy"); |
| if (styleName == "verticalScrollPolicy") |
| scroller.setStyle("verticalScrollPolicy", vsp); |
| else if (allStyles && vsp && (vsp !== ScrollPolicy.AUTO)) |
| scroller.setStyle("verticalScrollPolicy", vsp); |
| |
| const hsp:String = getStyle("horizontalScrollPolicy"); |
| if (styleName == "horizontalScrollPolicy") |
| scroller.setStyle("horizontalScrollPolicy", hsp); |
| else if (allStyles && hsp && (hsp !== ScrollPolicy.AUTO)) |
| scroller.setStyle("horizontalScrollPolicy", hsp); |
| } |
| } |
| |
| /** |
| * @private |
| * Used to prevent keyboard events that have been redispatched to the Scroller from being |
| * redispatched a second time when they bubble back up. |
| */ |
| private var scrollerEvent:KeyboardEvent = null; |
| |
| /** |
| * @private |
| * Build in basic keyboard navigation support in Grid. The focus is on |
| * the DataGrid which means the Scroller doesn't see the Keyboard events |
| * unless the event is dispatched to it. |
| */ |
| override protected function keyDownHandler(event:KeyboardEvent):void |
| { |
| if (!grid || event.isDefaultPrevented()) |
| return; |
| |
| // We've seen this event already and dispatched it to the Scroller |
| if (event == scrollerEvent) |
| { |
| scrollerEvent = null; |
| event.preventDefault(); |
| return; |
| } |
| |
| // If the key wasn't targeted to us, then ignore it. |
| if (!isOurFocus(DisplayObject(event.target))) |
| return; |
| |
| // Ctrl-A only comes thru on Mac. On Windows it is a SELECT_ALL |
| // event. |
| if (event.keyCode == Keyboard.A && event.ctrlKey) |
| { |
| selectAllFromKeyboard(); |
| event.preventDefault(); |
| return; |
| } |
| |
| // Row selection requires valid row caret, cell selection |
| // requires both a valid row and a valid column caret. |
| |
| if (selectionMode == GridSelectionMode.NONE || |
| grid.caretRowIndex < 0 || |
| grid.caretRowIndex >= dataProviderLength || |
| (isCellSelectionMode() && |
| (grid.caretColumnIndex < 0 || grid.caretColumnIndex >= columnsLength))) |
| { |
| // We're not going to handle this event, so give the scroller a chance. |
| if (scroller && (scrollerEvent != event)) |
| { |
| scrollerEvent = event.clone() as KeyboardEvent; |
| scroller.dispatchEvent(scrollerEvent); |
| } |
| return; |
| } |
| |
| switch (internalFocusOwner) |
| { |
| case GRID_FOCUS_OWNER: handleGridKeyEvent(event); break; |
| case HEADER_FOCUS_OWNER: handleHeaderKeyEvent(event); break; |
| } |
| } |
| |
| /** |
| * @private |
| * Handle KeyboardEvents when the internalFocusOwner is the grid. |
| */ |
| private function handleGridKeyEvent(event:KeyboardEvent):void |
| { |
| var op:String; |
| |
| if (event.keyCode == Keyboard.SPACE) |
| { |
| if (event.ctrlKey) |
| { |
| // Updates the selection. The caret remains the same and the |
| // anchor is updated. |
| if (toggleSelection(grid.caretRowIndex, grid.caretColumnIndex)) |
| { |
| grid.anchorRowIndex = grid.caretRowIndex; |
| grid.anchorColumnIndex = grid.caretColumnIndex; |
| event.preventDefault(); |
| } |
| } |
| else if (event.shiftKey) |
| { |
| // Extend the selection. The caret remains the same. |
| if (extendSelection(grid.caretRowIndex, grid.caretColumnIndex)) |
| event.preventDefault(); |
| } |
| else |
| { |
| if (grid.caretRowIndex != -1) |
| { |
| if (isRowSelectionMode()) |
| { |
| op = selectionMode == GridSelectionMode.SINGLE_ROW ? |
| GridSelectionEventKind.SET_ROW : |
| GridSelectionEventKind.ADD_ROW; |
| |
| // Add the row and leave the caret position unchanged. |
| if (!commitInteractiveSelection( |
| op, grid.caretRowIndex, grid.caretColumnIndex)) |
| { |
| return; |
| } |
| event.preventDefault(); |
| } |
| else if (isCellSelectionMode() && grid.caretColumnIndex != -1) |
| { |
| op = selectionMode == GridSelectionMode.SINGLE_CELL ? |
| GridSelectionEventKind.SET_CELL : |
| GridSelectionEventKind.ADD_CELL; |
| |
| // Add the cell and leave the caret position unchanged. |
| if (!commitInteractiveSelection( |
| op, grid.caretRowIndex, grid.caretColumnIndex)) |
| { |
| return; |
| } |
| event.preventDefault(); |
| } |
| } |
| } |
| return; |
| } |
| |
| // Was some other navigation key hit? |
| adjustSelectionUponNavigation(event); |
| } |
| |
| /** |
| * @private |
| * Handle KeyboardEvents when the internalFocusOwner is the header. |
| */ |
| private function handleHeaderKeyEvent(event:KeyboardEvent):void |
| { |
| if (!columnHeaderGroup) |
| return; |
| |
| const selectedIndex:int = columnHeaderGroup.selectedColumnIndex; |
| |
| if (selectedIndex == -1) |
| return; |
| |
| if ((event.keyCode == Keyboard.SPACE) || (event.keyCode == Keyboard.ENTER)) |
| { |
| const column:GridColumn = getColumnAt(selectedIndex); |
| const isMultiColumnSort:Boolean = event.ctrlKey; |
| interactiveSortByColumns(column, isMultiColumnSort); |
| if (!isMultiColumnSort && grid) |
| internalFocusOwner = GRID_FOCUS_OWNER; |
| return; |
| } |
| |
| if (!NavigationUnit.isNavigationUnit(event.keyCode)) |
| return; |
| |
| // swap Keyboard.LEFT and Keyboard.RIGHT for RTL layout |
| const navigationUnit:uint = mapKeycodeForLayoutDirection(event); |
| |
| const firstVisibleColumnIndex:int = grid.getNextVisibleColumnIndex(-1); |
| const lastVisibleColumnIndex:int = grid.getPreviousVisibleColumnIndex(columns.length); |
| var newSelectedIndex:int = selectedIndex; |
| |
| switch (navigationUnit) |
| { |
| case NavigationUnit.HOME: |
| { |
| newSelectedIndex = firstVisibleColumnIndex; |
| break; |
| } |
| |
| case NavigationUnit.END: |
| { |
| newSelectedIndex = lastVisibleColumnIndex; |
| break; |
| } |
| |
| case NavigationUnit.LEFT: |
| { |
| if (event.ctrlKey && !event.shiftKey) |
| { |
| moveColumnPosition(selectedIndex, -1); |
| } |
| else if (event.ctrlKey && event.shiftKey) |
| { |
| changeColumnWidth(selectedIndex, -3); |
| } |
| else |
| { |
| if (selectedIndex <= firstVisibleColumnIndex) |
| newSelectedIndex = firstVisibleColumnIndex; |
| else |
| newSelectedIndex = grid.getPreviousVisibleColumnIndex(selectedIndex); |
| } |
| break; |
| } |
| |
| case NavigationUnit.RIGHT: |
| { |
| if (event.ctrlKey && !event.shiftKey) |
| { |
| moveColumnPosition(selectedIndex, +1); |
| } |
| else if (event.ctrlKey && event.shiftKey) |
| { |
| changeColumnWidth(selectedIndex, +3); |
| } |
| else |
| { |
| if (selectedIndex >= lastVisibleColumnIndex) |
| newSelectedIndex = lastVisibleColumnIndex; |
| else |
| newSelectedIndex = grid.getNextVisibleColumnIndex(selectedIndex); |
| } |
| break; |
| } |
| } |
| |
| if (newSelectedIndex != selectedIndex) |
| { |
| columnHeaderGroup.selectedColumnIndex = newSelectedIndex; |
| ensureCellIsVisible(-1, newSelectedIndex); |
| } |
| } |
| |
| /** |
| * @private |
| * Change the specified column's position by delta, where delta is either +1 or -1. |
| */ |
| private function moveColumnPosition(columnIndex:int, delta:int):void |
| { |
| const column:GridColumn = getColumnAt(columnIndex); |
| if (!column) |
| return; |
| |
| var newColumnIndex:int = -1; |
| if (delta == +1) |
| newColumnIndex = grid.getNextVisibleColumnIndex(columnIndex); |
| else if (delta == -1) |
| newColumnIndex = grid.getPreviousVisibleColumnIndex(columnIndex); |
| |
| if (newColumnIndex != -1) |
| { |
| columns.removeItemAt(columnIndex); |
| columns.addItemAt(column, newColumnIndex); |
| columnHeaderGroup.selectedColumnIndex = newColumnIndex; |
| grid.ensureCellIsVisible(-1, newColumnIndex); |
| } |
| } |
| |
| /** |
| * @private |
| * Change the specified column's width by delta. |
| */ |
| private function changeColumnWidth(columnIndex:int, delta:Number):void |
| { |
| const column:GridColumn = getColumnAt(columnIndex); |
| if (!column) |
| return; |
| |
| var columnWidth:Number = column.width; |
| if (isNaN(columnWidth)) |
| columnWidth = grid.getColumnWidth(columnIndex); |
| |
| columnWidth = Math.max(1, columnWidth + delta); |
| if (!isNaN(column.maxWidth)) |
| columnWidth = Math.min(columnWidth, column.maxWidth); |
| if (!isNaN(column.minWidth)) |
| columnWidth = Math.max(columnWidth, column.minWidth); |
| column.width = columnWidth; |
| } |
| |
| /** |
| * @private |
| * If the focusManager is trying to tab forwards from the DataGrid and the internalFocusOwner is |
| * currently the grid, then switch the internal focus to the header and cancel the focusManager's |
| * event. Similarly, if the focusManager is trying to tab backwards (shift-tab) and the internal |
| * focus is currently on the header, then set the internal focus to the grid and cancel the event. |
| */ |
| protected function keyFocusChangeHandler(event:FocusEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| // In an edit session. Don't let the TAB switch the internal focus. |
| if (editor && editor.editorRowIndex != -1 && editor.editorColumnIndex != -1) |
| return; |
| |
| if ((internalFocusOwner == GRID_FOCUS_OWNER) && !event.shiftKey && columnHeaderGroup) |
| { |
| internalFocusOwner = HEADER_FOCUS_OWNER; |
| event.preventDefault(); |
| } |
| else if ((internalFocusOwner == HEADER_FOCUS_OWNER) && event.shiftKey && grid) |
| { |
| internalFocusOwner = GRID_FOCUS_OWNER; |
| event.preventDefault(); |
| } |
| else |
| { |
| internalFocusOwner = (internalFocusOwner == GRID_FOCUS_OWNER) ? HEADER_FOCUS_OWNER : GRID_FOCUS_OWNER; |
| // If there's another focusable component, we will lose the focus here |
| } |
| } |
| |
| /** |
| * @private |
| * New event in FP10 dispatched when the user activates the platform |
| * specific accelerator key combination for a select all operation. |
| * On Windows this is ctrl-A and on Mac this is cmd-A. |
| */ |
| protected function selectAllHandler(event:Event):void |
| { |
| // If the select all was not targeted to the DataGrid, then ignore it. |
| if (!grid || event.isDefaultPrevented() || |
| !isOurFocus(DisplayObject(event.target))) |
| { |
| return; |
| } |
| |
| selectAllFromKeyboard(); |
| } |
| |
| /** |
| * @private |
| */ |
| private function selectAllFromKeyboard():void |
| { |
| // If there is a caret, leave it in its current position. |
| if (selectionMode == GridSelectionMode.MULTIPLE_CELLS || |
| selectionMode == GridSelectionMode.MULTIPLE_ROWS) |
| { |
| if (commitInteractiveSelection( |
| GridSelectionEventKind.SELECT_ALL, |
| 0, 0, dataProvider.length, columns.length)) |
| { |
| grid.anchorRowIndex = 0; |
| grid.anchorColumnIndex = 0; |
| } |
| } |
| } |
| |
| /** |
| * @private |
| * Call partAdded() for IFactory type skin parts. By default, partAdded() is not |
| * called for IFactory type skin part variables, because they're assumed to be |
| * "dynamic" skin parts, to be created with createDynamicPartInstance(). That's |
| * not the case with the IFactory valued parts listed in factorySkinPartNames. |
| */ |
| override protected function findSkinParts():void |
| { |
| super.findSkinParts(); |
| |
| for each (var partName:String in factorySkinPartNames) |
| { |
| if ((partName in skin) && skin[partName]) |
| partAdded(partName, skin[partName]); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private function initializeDataGridElement(elt:IDataGridElement):void |
| { |
| if (!elt) |
| return; |
| |
| elt.dataGrid = this; |
| if (elt.nestLevel <= grid.nestLevel) |
| { |
| elt.validateNow(); |
| elt.nestLevel = grid.nestLevel + 1; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function partAdded(partName:String, instance:Object):void |
| { |
| super.partAdded(partName, instance); |
| |
| if (instance == grid) |
| { |
| // Basic Initialization |
| |
| gridSelection.grid = grid; |
| grid.gridSelection = gridSelection; |
| grid.dataGrid = this; |
| |
| // Grid cover Properties |
| |
| const modifiedGridProperties:Object = gridProperties; // explicitly set properties |
| gridProperties = {propertyBits:0}; |
| |
| for (var propertyName:String in modifiedGridProperties) |
| { |
| if (propertyName == "propertyBits") |
| continue; |
| setGridProperty(propertyName, modifiedGridProperties[propertyName]); |
| } |
| |
| // IFactory valued skin parts => Grid visual element properties |
| |
| initializeGridRowBackground(); // sets grid.rowBackground if alternatingRowColors set |
| grid.columnSeparator = columnSeparator; |
| grid.rowSeparator = rowSeparator; |
| grid.hoverIndicator = hoverIndicator; |
| grid.caretIndicator = caretIndicator; |
| grid.selectionIndicator = selectionIndicator; |
| grid.lockedColumnsSeparator = lockedColumnsSeparator; |
| grid.lockedRowsSeparator = lockedRowsSeparator; |
| |
| // Event Handlers |
| |
| grid.addEventListener(GridEvent.GRID_MOUSE_DOWN, grid_mouseDownHandler, false, EventPriority.DEFAULT_HANDLER); |
| grid.addEventListener(GridEvent.GRID_MOUSE_UP, grid_mouseUpHandler, false, EventPriority.DEFAULT_HANDLER); |
| grid.addEventListener(GridEvent.GRID_ROLL_OVER, grid_rollOverHandler, false, EventPriority.DEFAULT_HANDLER); |
| grid.addEventListener(GridEvent.GRID_ROLL_OUT, grid_rollOutHandler, false, EventPriority.DEFAULT_HANDLER); |
| grid.addEventListener(GridCaretEvent.CARET_CHANGE, grid_caretChangeHandler); |
| grid.addEventListener(FlexEvent.VALUE_COMMIT, grid_valueCommitHandler); |
| grid.addEventListener("invalidateSize", grid_invalidateSizeHandler); |
| grid.addEventListener("invalidateDisplayList", grid_invalidateDisplayListHandler); |
| grid.addEventListener("gridViewsChanged", grid_gridViewsChangedHandler); |
| |
| // Deferred operations (grid selection updates) |
| |
| for each (var deferredGridOperation:Function in deferredGridOperations) |
| deferredGridOperation(grid); |
| deferredGridOperations.length = 0; |
| |
| // IDataGridElements: columnHeaderGroup... |
| |
| initializeDataGridElement(columnHeaderGroup); |
| |
| // Create the data grid editor |
| |
| editor = createEditor(); |
| editor.initialize(); |
| } |
| |
| if (instance == alternatingRowColorsBackground) |
| initializeGridRowBackground(); |
| |
| if (grid) |
| { |
| if (instance == columnSeparator) |
| grid.columnSeparator = columnSeparator; |
| |
| if (instance == rowSeparator) |
| grid.rowSeparator = rowSeparator; |
| |
| if (instance == lockedColumnsSeparator) |
| grid.lockedColumnsSeparator = lockedColumnsSeparator; |
| |
| if (instance == lockedRowsSeparator) |
| grid.lockedRowsSeparator = lockedRowsSeparator; |
| |
| if (instance == hoverIndicator) |
| grid.hoverIndicator = hoverIndicator; |
| |
| if (instance == caretIndicator) |
| { |
| grid.caretIndicator = caretIndicator; |
| |
| // Add a focus listener so we can turn the caret on and off |
| // when we get and lose focus. |
| addEventListener(FocusEvent.FOCUS_IN, dataGrid_focusHandler); |
| addEventListener(FocusEvent.FOCUS_OUT, dataGrid_focusHandler); |
| if (grid) |
| grid.showCaret = false; |
| } |
| |
| if (instance == rowBackground) |
| grid.rowBackground = rowBackground; |
| |
| if (instance == selectionIndicator) |
| grid.selectionIndicator = selectionIndicator; |
| |
| } |
| |
| if (instance == columnHeaderGroup) |
| { |
| if (grid) |
| initializeDataGridElement(columnHeaderGroup); |
| |
| columnHeaderGroup.addEventListener(GridEvent.GRID_CLICK, columnHeaderGroup_clickHandler); |
| columnHeaderGroup.addEventListener(GridEvent.GRID_ROLL_OVER, columnHeaderGroup_rollOverHandler); |
| columnHeaderGroup.addEventListener(GridEvent.GRID_ROLL_OUT, columnHeaderGroup_rollOutHandler); |
| columnHeaderGroup.addEventListener(GridEvent.SEPARATOR_ROLL_OVER, separator_rollOverHandler); |
| columnHeaderGroup.addEventListener(GridEvent.SEPARATOR_ROLL_OUT, separator_rollOutHandler); |
| columnHeaderGroup.addEventListener(GridEvent.SEPARATOR_MOUSE_DOWN, separator_mouseDownHandler); |
| columnHeaderGroup.addEventListener(GridEvent.SEPARATOR_MOUSE_DRAG, separator_mouseDragHandler); |
| columnHeaderGroup.addEventListener(GridEvent.SEPARATOR_MOUSE_UP, separator_mouseUpHandler); |
| } |
| |
| if (instance == scroller) |
| { |
| // The scrollPolicy styles are initialized in framework/defaults.css |
| // so there's no way to determine if been explicitly set here. To avoid |
| // preempting explicitly set scroller scrollPolicy styles with the default |
| // "auto" value, we only forward the style if it's not "auto". |
| |
| const vsp:String = getStyle("verticalScrollPolicy"); |
| if (vsp && (vsp !== ScrollPolicy.AUTO)) |
| scroller.setStyle("verticalScrollPolicy", vsp); |
| |
| const hsp:String = getStyle("horizontalScrollPolicy"); |
| if (hsp && (hsp !== ScrollPolicy.AUTO)) |
| scroller.setStyle("horizontalScrollPolicy", hsp); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function partRemoved(partName:String, instance:Object):void |
| { |
| super.partRemoved(partName, instance); |
| |
| if (instance == grid) |
| { |
| // Basic Initialization |
| |
| gridSelection.grid = null; |
| grid.gridSelection = null; |
| grid.dataGrid = null; |
| |
| // Event Handlers |
| grid.removeEventListener("gridViewsChanged", grid_gridViewsChangedHandler); |
| grid.removeEventListener("invalidateSize", grid_invalidateSizeHandler); |
| grid.removeEventListener("invalidateDisplayList", grid_invalidateDisplayListHandler); |
| grid.removeEventListener(GridEvent.GRID_MOUSE_DOWN, grid_mouseDownHandler); |
| grid.removeEventListener(GridEvent.GRID_MOUSE_UP, grid_mouseUpHandler); |
| grid.removeEventListener(GridEvent.GRID_ROLL_OVER, grid_rollOverHandler); |
| grid.removeEventListener(GridEvent.GRID_ROLL_OUT, grid_rollOutHandler); |
| grid.removeEventListener(GridCaretEvent.CARET_CHANGE, grid_caretChangeHandler); |
| grid.removeEventListener(FlexEvent.VALUE_COMMIT, grid_valueCommitHandler); |
| |
| // Cover Properties |
| |
| const gridPropertyBits:uint = gridProperties.propertyBits; |
| gridProperties = {}; |
| |
| for (var propertyName:String in gridPropertyDefaults) |
| { |
| var propertyBit:uint = partPropertyBits[propertyName]; |
| if ((propertyBit & gridPropertyBits) == propertyBit) |
| gridProperties[propertyName] = getGridProperty(propertyName); |
| } |
| |
| // Visual Elements |
| |
| grid.rowBackground = null; |
| grid.columnSeparator = null; |
| grid.rowSeparator = null; |
| grid.hoverIndicator = null; |
| grid.caretIndicator = null; |
| grid.selectionIndicator = null; |
| |
| // IDataGridElements: grid, columnHeaderGroup |
| |
| if (columnHeaderGroup) |
| columnHeaderGroup.dataGrid = null; |
| |
| // Data grid editor |
| if (editor) |
| { |
| editor.uninitialize(); |
| editor = null; |
| } |
| |
| if (internalFocusOwner == GRID_FOCUS_OWNER) |
| internalFocusOwner = NO_FOCUS_OWNER; |
| } |
| |
| if (grid) |
| { |
| if (instance == columnSeparator) |
| grid.columnSeparator = null; |
| |
| if (instance == rowSeparator) |
| grid.rowSeparator = null; |
| |
| if (instance == lockedColumnsSeparator) |
| grid.lockedColumnsSeparator = null; |
| |
| if (instance == lockedRowsSeparator) |
| grid.lockedRowsSeparator = null; |
| |
| if (instance == hoverIndicator) |
| grid.hoverIndicator = null; |
| |
| if (instance == caretIndicator) |
| { |
| grid.caretIndicator = null; |
| |
| removeEventListener(FocusEvent.FOCUS_IN, dataGrid_focusHandler); |
| removeEventListener(FocusEvent.FOCUS_OUT, dataGrid_focusHandler); |
| } |
| |
| if (instance == selectionIndicator) |
| grid.selectionIndicator = null; |
| |
| if (instance == rowBackground) |
| grid.rowBackground = null; |
| } |
| |
| if (instance == columnHeaderGroup) |
| { |
| columnHeaderGroup.dataGrid = null; |
| columnHeaderGroup.removeEventListener(GridEvent.GRID_CLICK, columnHeaderGroup_clickHandler); |
| columnHeaderGroup.removeEventListener(GridEvent.GRID_ROLL_OVER, columnHeaderGroup_rollOverHandler); |
| columnHeaderGroup.removeEventListener(GridEvent.GRID_ROLL_OUT, columnHeaderGroup_rollOutHandler); |
| columnHeaderGroup.removeEventListener(GridEvent.SEPARATOR_ROLL_OVER, separator_rollOverHandler); |
| columnHeaderGroup.removeEventListener(GridEvent.SEPARATOR_ROLL_OUT, separator_rollOutHandler); |
| columnHeaderGroup.removeEventListener(GridEvent.SEPARATOR_MOUSE_DOWN, separator_mouseDownHandler); |
| columnHeaderGroup.removeEventListener(GridEvent.SEPARATOR_MOUSE_DRAG, separator_mouseDragHandler); |
| columnHeaderGroup.removeEventListener(GridEvent.SEPARATOR_MOUSE_UP, separator_mouseUpHandler); |
| |
| if (internalFocusOwner == HEADER_FOCUS_OWNER) |
| internalFocusOwner = NO_FOCUS_OWNER; |
| } |
| } |
| |
| //---------------------------------- |
| // selectedCell |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| |
| /** |
| * @copy spark.components.Grid#selectedCell |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedCell():CellPosition |
| { |
| if (grid) |
| return grid.selectedCell; |
| |
| return selectedCells.length ? selectedCells[0] : null; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedCell(value:CellPosition):void |
| { |
| if (grid) |
| grid.selectedCell = value; |
| else |
| { |
| const valueCopy:CellPosition = (value) ? new CellPosition(value.rowIndex, value.columnIndex) : null; |
| |
| var f:Function = function(g:Grid):void |
| { |
| g.selectedCell = valueCopy; |
| } |
| deferredGridOperations.push(f); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedCells |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| |
| /** |
| * @copy spark.components.Grid#selectedCells |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedCells():Vector.<CellPosition> |
| { |
| return grid ? grid.selectedCells : gridSelection.allCells(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedCells(value:Vector.<CellPosition>):void |
| { |
| if (grid) |
| grid.selectedCells = value; |
| else |
| { |
| const valueCopy:Vector.<CellPosition> = (value) ? value.concat() : null; |
| var f:Function = function(g:Grid):void |
| { |
| g.selectedCells = valueCopy; |
| } |
| deferredGridOperations.push(f); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedIndex |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General", defaultValue="-1")] |
| |
| /** |
| * @copy spark.components.Grid#selectedIndex |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedIndex():int |
| { |
| if (grid) |
| return grid.selectedIndex; |
| |
| return (selectedIndices.length > 0) ? selectedIndices[0] : -1; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedIndex(value:int):void |
| { |
| if (grid) |
| grid.selectedIndex = value; |
| else |
| { |
| var f:Function = function(g:Grid):void |
| { |
| g.selectedIndex = value; |
| }; |
| deferredGridOperations.push(f); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedIndices |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General")] |
| |
| /** |
| * @copy spark.components.Grid#selectedIndices |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedIndices():Vector.<int> |
| { |
| return grid ? grid.selectedIndices : gridSelection.allRows(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedIndices(value:Vector.<int>):void |
| { |
| if (grid) |
| grid.selectedIndices = value; |
| else |
| { |
| const valueCopy:Vector.<int> = (value) ? value.concat() : null; |
| var f:Function = function(g:Grid):void |
| { |
| g.selectedIndices = valueCopy; |
| } |
| deferredGridOperations.push(f); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedItem |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General", defaultValue="null")] |
| |
| /** |
| * @copy spark.components.Grid#selectedItem |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedItem():Object |
| { |
| if (grid) |
| return grid.selectedItem; |
| |
| return (dataProvider && (selectedIndex > 0)) ? |
| dataProvider.getItemAt(selectedIndex) : undefined; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedItem(value:Object):void |
| { |
| if (grid) |
| grid.selectedItem = value; |
| else |
| { |
| var f:Function = function(g:Grid):void |
| { |
| g.selectedItem = value; |
| } |
| deferredGridOperations.push(f); |
| } |
| } |
| |
| //---------------------------------- |
| // selectedItems |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| [Inspectable(category="General")] |
| |
| /** |
| * @copy spark.components.Grid#selectedItems |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectedItems():Vector.<Object> |
| { |
| if (grid) |
| return grid.selectedItems; |
| |
| var items:Vector.<Object> = new Vector.<Object>(); |
| |
| for (var i:int = 0; i < selectedIndices.length; i++) |
| items.push(selectedIndices[i]); |
| |
| return items; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selectedItems(value:Vector.<Object>):void |
| { |
| if (grid) |
| grid.selectedItems = value; |
| else |
| { |
| const valueCopy:Vector.<Object> = value.concat(); |
| var f:Function = function(g:Grid):void |
| { |
| g.selectedItems = valueCopy; |
| } |
| deferredGridOperations.push(f); |
| } |
| } |
| |
| //---------------------------------- |
| // selectionLength |
| //---------------------------------- |
| |
| [Bindable("selectionChange")] |
| [Bindable("valueCommit")] |
| |
| /** |
| * @copy spark.components.Grid#selectionLength |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selectionLength():int |
| { |
| return grid ? grid.selectionLength : gridSelection.selectionLength; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Public Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @copy spark.components.Grid#findRowIndex() |
| * |
| * @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 |
| { |
| if (grid) |
| { |
| return grid.findRowIndex(field, value, startingIndex, patternType); |
| } |
| else |
| { |
| return -1; |
| } |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#findRowIndices() |
| * |
| * @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 |
| { |
| if (grid) |
| { |
| return grid.findRowIndices(field, values, patternType); |
| } |
| else |
| { |
| return []; |
| } |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#invalidateCell() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function invalidateCell(rowIndex:int, columnIndex:int):void |
| { |
| if (grid) |
| grid.invalidateCell(rowIndex, columnIndex); |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#moveIndexFindRow() |
| * |
| * @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 |
| { |
| if (grid) |
| { |
| return grid.moveIndexFindRow(field, value, startingIndex, patternType); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#moveIndexFirstRow() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexFirstRow():void |
| { |
| if (grid) |
| { |
| grid.moveIndexFirstRow(); |
| } |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#moveIndexLastRow() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexLastRow():void |
| { |
| if (grid) |
| { |
| grid.moveIndexLastRow(); |
| } |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#moveIndexNextRow() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexNextRow():void |
| { |
| if (grid) |
| { |
| grid.moveIndexNextRow(); |
| } |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#moveIndexPreviousRow() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11.1 |
| * @playerversion AIR 3.4 |
| * @productversion Flex 4.10 |
| */ |
| public function moveIndexPreviousRow():void |
| { |
| if (grid) |
| { |
| grid.moveIndexPreviousRow(); |
| } |
| } |
| |
| |
| /** |
| * @copy spark.components.Grid#selectAll() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectAll():Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.selectAll(); |
| } |
| else |
| { |
| selectionChanged = gridSelection.selectAll(); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * @copy spark.components.Grid#clearSelection() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function clearSelection():Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.clearSelection(); |
| } |
| else |
| { |
| selectionChanged = gridSelection.removeAll(); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| //---------------------------------- |
| // selection for rows |
| //---------------------------------- |
| |
| /** |
| * @copy spark.components.Grid#selectionContainsIndex() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectionContainsIndex(rowIndex:int):Boolean |
| { |
| if (grid) |
| return grid.selectionContainsIndex(rowIndex); |
| else |
| return gridSelection.containsRow(rowIndex); |
| } |
| |
| /** |
| * @copy spark.components.Grid#selectionContainsIndices() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectionContainsIndices(rowIndices:Vector.<int>):Boolean |
| { |
| if (grid) |
| return grid.selectionContainsIndices(rowIndices); |
| else |
| return gridSelection.containsRows(rowIndices); |
| } |
| |
| /** |
| * @copy spark.components.Grid#setSelectedIndex() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function setSelectedIndex(rowIndex:int):Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.setSelectedIndex(rowIndex); |
| } |
| else |
| { |
| selectionChanged = gridSelection.setRow(rowIndex); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * @copy spark.components.Grid#addSelectedIndex() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function addSelectedIndex(rowIndex:int):Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.addSelectedIndex(rowIndex); |
| } |
| else |
| { |
| selectionChanged = gridSelection.addRow(rowIndex); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * @copy spark.components.Grid#removeSelectedIndex() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function removeSelectedIndex(rowIndex:int):Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.removeSelectedIndex(rowIndex); |
| } |
| else |
| { |
| selectionChanged = gridSelection.removeRow(rowIndex); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * @copy spark.components.Grid#selectIndices() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectIndices(rowIndex:int, rowCount:int):Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.selectIndices(rowIndex, rowCount); |
| } |
| else |
| { |
| selectionChanged = gridSelection.setRows(rowIndex, rowCount); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| //---------------------------------- |
| // selection for cells |
| //---------------------------------- |
| |
| /** |
| * @copy spark.components.Grid#selectionContainsCell() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function selectionContainsCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| if (grid) |
| return grid.selectionContainsCell(rowIndex, columnIndex); |
| else |
| return gridSelection.containsCell(rowIndex, columnIndex); |
| } |
| |
| /** |
| * @copy spark.components.Grid#selectionContainsCellRegion() |
| * |
| * @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 |
| { |
| if (grid) |
| { |
| return grid.selectionContainsCellRegion( |
| rowIndex, columnIndex, rowCount, columnCount); |
| } |
| else |
| { |
| return gridSelection.containsCellRegion( |
| rowIndex, columnIndex, rowCount, columnCount); |
| } |
| } |
| |
| /** |
| * @copy spark.components.Grid#setSelectedCell() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function setSelectedCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.setSelectedCell(rowIndex, columnIndex); |
| } |
| else |
| { |
| selectionChanged = gridSelection.setCell(rowIndex, columnIndex); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * @copy spark.components.Grid#addSelectedCell() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function addSelectedCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.addSelectedCell(rowIndex, columnIndex); |
| } |
| else |
| { |
| selectionChanged = gridSelection.addCell(rowIndex, columnIndex); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * @copy spark.components.Grid#removeSelectedCell() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function removeSelectedCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.removeSelectedCell(rowIndex, columnIndex); |
| } |
| else |
| { |
| selectionChanged = gridSelection.removeCell(rowIndex, columnIndex); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * @copy spark.components.Grid#selectCellRegion() |
| * |
| * @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 |
| { |
| var selectionChanged:Boolean; |
| |
| if (grid) |
| { |
| selectionChanged = grid.selectCellRegion( |
| rowIndex, columnIndex, rowCount, columnCount); |
| } |
| else |
| { |
| selectionChanged = gridSelection.setCellRegion( |
| rowIndex, columnIndex, rowCount, columnCount); |
| if (selectionChanged) |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| } |
| |
| return selectionChanged; |
| } |
| |
| /** |
| * In response to user input (mouse or keyboard) which changes the |
| * selection, this method dispatches the <code>selectionChanging</code> event. |
| * If the event is not canceled, it then commits the selection change, and then |
| * dispatches the <code>selectionChange</code> event. |
| * The caret location is not updated. |
| * To detect if the caret has changed, use the <code>caretChanged</code> event. |
| * |
| * @param selectionEventKind A constant defined by the GridSelectionEventKind class |
| * that specifies the selection that is being committed. If not null, this is used to |
| * generate the <code>selectionChanging</code> event. |
| * |
| * @param rowIndex If <code>selectionEventKind</code> is for a row or a |
| * cell, the 0-based <code>rowIndex</code> of the selection in the |
| * data provider. |
| * If <code>selectionEventKind</code> is |
| * for multiple cells, the 0-based <code>rowIndex</code> of the origin of the |
| * cell region. The default is -1 to indicate this |
| * parameter is not being used. |
| * |
| * @param columnIndex If <code>selectionEventKind</code> is for a single row or |
| * a single cell, the 0-based <code>columnIndex</code> of the selection. |
| * If <code>selectionEventKind</code> is for multiple |
| * cells, the 0-based <code>columnIndex</code> of the origin of the |
| * cell region. The default is -1 to indicate this |
| * parameter is not being used. |
| * |
| * @param rowCount If <code>selectionEventKind</code> is for a cell region, |
| * the number of rows in the cell region. The default is -1 to indicate |
| * this parameter is not being used. |
| * |
| * @param columnCount If <code>selectionEventKind</code> is for a cell region, |
| * the number of columns in the cell region. The default is -1 to |
| * indicate this parameter is not being used. |
| * |
| * @return <code>true</code> if the selection was committed or did not change, or |
| * <code>false</code> if the selection was canceled or could not be committed due to |
| * an error, such as index out of range or the <code>selectionEventKind</code> is not |
| * compatible with the <code>selectionMode</code>. |
| * |
| * @see spark.events.GridSelectionEvent#SELECTION_CHANGE |
| * @see spark.events.GridSelectionEvent#SELECTION_CHANGING |
| * @see spark.events.GridSelectionEventKind |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function commitInteractiveSelection( |
| selectionEventKind:String, |
| rowIndex:int, |
| columnIndex:int, |
| rowCount:int = 1, |
| columnCount:int = 1):Boolean |
| |
| { |
| if (!grid) |
| return false; |
| |
| // Assumes selectionEventKind is valid for given selectionMode. Assumes |
| // indices are within range. |
| |
| var selectionChange:CellRegion = |
| new CellRegion(rowIndex, columnIndex, rowCount, columnCount); |
| |
| // Step 1: determine if the selection will change if the operation. |
| // is committed. |
| if (!doesChangeCurrentSelection(selectionEventKind, selectionChange)) |
| return true; |
| |
| // Step 2: dispatch the "changing" event. If preventDefault() is called |
| // on this event, the selection change will be cancelled. |
| if (hasEventListener(GridSelectionEvent.SELECTION_CHANGING)) |
| { |
| const changingEvent:GridSelectionEvent = |
| new GridSelectionEvent(GridSelectionEvent.SELECTION_CHANGING, |
| false, true, |
| selectionEventKind, selectionChange); |
| |
| // The event was cancelled so don't change the selection. |
| if (!dispatchEvent(changingEvent)) |
| return false; |
| } |
| |
| // Step 3: commit the selection change. Call the gridSelection |
| // methods directly so that the caret position is not altered and |
| // a VALUE_COMMIT event is not dispatched. |
| |
| var changed:Boolean; |
| switch (selectionEventKind) |
| { |
| case GridSelectionEventKind.SET_ROW: |
| { |
| changed = grid.gridSelection.setRow(rowIndex); |
| break; |
| } |
| case GridSelectionEventKind.ADD_ROW: |
| { |
| changed = grid.gridSelection.addRow(rowIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.REMOVE_ROW: |
| { |
| changed = grid.gridSelection.removeRow(rowIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.SET_ROWS: |
| { |
| changed = grid.gridSelection.setRows(rowIndex, rowCount); |
| break; |
| } |
| |
| case GridSelectionEventKind.SET_CELL: |
| { |
| changed = grid.gridSelection.setCell(rowIndex, columnIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.ADD_CELL: |
| { |
| changed = grid.gridSelection.addCell(rowIndex, columnIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.REMOVE_CELL: |
| { |
| changed = grid.gridSelection.removeCell(rowIndex, columnIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.SET_CELL_REGION: |
| { |
| changed = grid.gridSelection.setCellRegion( |
| rowIndex, columnIndex, |
| rowCount, columnCount); |
| break; |
| } |
| |
| case GridSelectionEventKind.SELECT_ALL: |
| { |
| changed = grid.gridSelection.selectAll(); |
| break; |
| } |
| } |
| |
| // Selection change failed for some unforseen reason. |
| if (!changed) |
| return false; |
| |
| grid.invalidateDisplayListFor("selectionIndicator"); |
| |
| // Step 4: dispatch the "change" event. |
| if (hasEventListener(GridSelectionEvent.SELECTION_CHANGE)) |
| { |
| const changeEvent:GridSelectionEvent = |
| new GridSelectionEvent(GridSelectionEvent.SELECTION_CHANGE, |
| false, true, |
| selectionEventKind, selectionChange); |
| dispatchEvent(changeEvent); |
| // TBD: to trigger bindings on grid selectedCell/Index/Item properties |
| if (grid.hasEventListener(GridSelectionEvent.SELECTION_CHANGE)) |
| grid.dispatchEvent(changeEvent); |
| } |
| |
| // Step 5: dispatch the "valueCommit" event. |
| dispatchFlexEvent(FlexEvent.VALUE_COMMIT); |
| |
| return true; |
| } |
| |
| /** |
| * Updates the grid's caret position. |
| * If the caret position changes, the <code>grid</code> skin part dispatches a |
| * <code>caretChange</code> event. |
| * |
| * @param newCaretRowIndex The 0-based rowIndex of the new caret position. |
| * |
| * @param newCaretColumnIndex The 0-based columnIndex of the new caret |
| * position. If the selectionMode is row-based, this is -1. |
| * |
| * @see spark.events.GridCaretEvent#CARET_CHANGE |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function commitCaretPosition(newCaretRowIndex:int, |
| newCaretColumnIndex:int):void |
| { |
| grid.caretRowIndex = newCaretRowIndex; |
| grid.caretColumnIndex = newCaretColumnIndex; |
| } |
| |
| /** |
| * 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. |
| * |
| * @see spark.components.Grid.createGridSelection |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| mx_internal function createGridSelection():GridSelection |
| { |
| return new GridSelection(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Selection Utility Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| protected function selectionContainsOnlyIndex(index:int):Boolean |
| { |
| if (grid) |
| return grid.selectionContainsIndex(index) && grid.selectionLength == 1; |
| else |
| return gridSelection.containsRow(index) && gridSelection.selectionLength == 1; |
| } |
| |
| /** |
| * @private |
| * Return true, if the current selection, only contains the rows in |
| * the selection change. |
| */ |
| protected function selectionContainsOnlyIndices(selectionChange:CellRegion):Boolean |
| { |
| var selectionLength:int = |
| grid ? grid.selectionLength : gridSelection.selectionLength; |
| |
| if (selectionChange.rowCount != selectionLength) |
| return false; |
| |
| const bottom:int = |
| selectionChange.rowIndex + selectionChange.rowCount; |
| |
| for (var rowIndex:int = selectionChange.rowIndex; |
| rowIndex < bottom; |
| rowIndex++) |
| { |
| if (grid) |
| { |
| if (!grid.selectionContainsIndex(rowIndex)) |
| return false; |
| } |
| else |
| { |
| if (!gridSelection.containsRow(rowIndex)) |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @private |
| */ |
| private function selectionContainsOnlyCell(rowIndex:int, columnIndex:int):Boolean |
| { |
| if (grid) |
| return grid.selectionContainsCell(rowIndex, columnIndex) && grid.selectionLength == 1; |
| else |
| return gridSelection.containsCell(rowIndex, columnIndex) && gridSelection.selectionLength == 1; |
| } |
| |
| /** |
| * @private |
| */ |
| private function selectionContainsOnlyCellRegion(rowIndex:int, |
| columnIndex:int, |
| rowCount:int, |
| columnCount:int):Boolean |
| { |
| if (grid) |
| { |
| return grid.selectionContainsCellRegion( |
| rowIndex, columnIndex, rowCount, columnCount) && |
| grid.selectionLength == rowCount * columnCount; |
| } |
| else |
| { |
| return gridSelection.containsCellRegion( |
| rowIndex, columnIndex, rowCount, columnCount) && |
| gridSelection.selectionLength == rowCount * columnCount; |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Item Editor Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Returns true if a datagrid cell is editable. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| * |
| */ |
| protected function isCellEditable(rowIndex:int, columnIndex:int):Boolean |
| { |
| try |
| { |
| var dataItem:Object = dataProvider.getItemAt(rowIndex); |
| var column:GridColumn = GridColumn(columns.getItemAt(columnIndex)); |
| var dataField:String = column.dataField; |
| } |
| catch (e:RangeError) |
| { |
| return false; |
| } |
| |
| |
| return isDataEditable(dataItem, dataField); |
| } |
| |
| /** |
| * Override to make a datagrid cell editable based on the data item. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| * |
| */ |
| protected function isDataEditable(dataItem:Object, dataField:String):Boolean |
| { |
| return (dataItem != null); |
| } |
| |
| /** |
| * Starts an editor session on a selected cell in the grid. This method |
| * by-passes checks of the editable property on the DataGrid and GridColumn |
| * that prevent the user interface from starting an editor session. |
| * |
| * A <code>startItemEditorSession</code> event is dispatched before |
| * an item editor is created. This allows a listener dynamically change |
| * the item editor for a specified cell. |
| * |
| * The event can also be cancelled by calling the |
| * <code>preventDefault()</code> method, to prevent the |
| * editor session from being created. |
| * |
| * @param rowIndex The zero-based row index of the cell to edit. |
| * |
| * @param columnIndex The zero-based column index of the cell to edit. |
| * |
| * @return <code>true</code> if the editor session was started. |
| * Returns <code>false</code> if the editor session was cancelled or was |
| * otherwise unable to be started. Note that an editor session cannot be |
| * started in a column that is not visible. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| * |
| */ |
| public function startItemEditorSession(rowIndex:int, columnIndex:int):Boolean |
| { |
| if (editor && isCellEditable(rowIndex,columnIndex)) |
| return editor.startItemEditorSession(rowIndex, columnIndex); |
| |
| return false; |
| } |
| |
| /** |
| * Closes the currently active editor and optionally saves the editor's value |
| * by calling the item editor's <code>save()</code> method. |
| * If the <code>cancel</code> parameter is <code>true</code>, |
| * then the editor's <code>cancel()</code> method is called instead. |
| * |
| * @param cancel If <code>false</code>, the data in the editor is saved. |
| * Otherwise the data in the editor is discarded. |
| * |
| * @return <code>true</code> if the editor session was saved, |
| * and <code>false</code> if the save was cancelled. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function endItemEditorSession(cancel:Boolean = false):Boolean |
| { |
| if (editor) |
| return editor.endItemEditorSession(cancel); |
| |
| return false; |
| } |
| |
| /** |
| * Create the data grid editor. Overriding this function will |
| * allow the complete replacement of the data grid editor. |
| */ |
| mx_internal function createEditor():DataGridEditor |
| { |
| return new DataGridEditor(this); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Sorting Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| private function ensureComplexFieldsMonitoring(sortFields:Array):void |
| { |
| if(!(dataProvider is ListCollectionView)) |
| return; |
| |
| for (var i:int = 0; i < sortFields.length; i++) |
| { |
| var sortField:ISortField = sortFields[i]; |
| if(sortField is IComplexSortField) |
| break; |
| } |
| |
| if(i < sortFields.length) |
| { |
| if(!ListCollectionView(dataProvider).complexFieldWatcher) |
| ListCollectionView(dataProvider).complexFieldWatcher = new ComplexFieldChangeWatcher(); |
| } |
| else |
| ListCollectionView(dataProvider).complexFieldWatcher = null; |
| } |
| |
| /** |
| * Sort the DataGrid by one or more columns, and refresh the display. |
| * |
| * <p>If the <code>dataProvider</code> is an ICollectionView, then it's <code>sort</code> property is |
| * set to a value based on each column's <code>dataField</code>, <code>sortCompareFunction</code>, |
| * and <code>sortDescending</code> flag. |
| * Then, the data provider's <code>refresh()</code> method is called. </p> |
| * |
| * <p>If the <code>dataProvider</code> is not an ICollectionView, then this method has no effect.</p> |
| * |
| * <p>If isInteractive is true then a <code>GridSortEvent.SORT_CHANGING</code> is dispatched before the |
| * sort is applied. Listeners can change modify the event to change the sort or cancel |
| * the event to cancel the sort. If isInteractive is true and the sort is not cancelled, then a |
| * <code>GridSortEvent.SORT_CHANGE</code> event is dispatched after the dataProvider's sort has been |
| * updated.</p> |
| * |
| * <p>If the sort has not be cancelled, the columnHeaderGroup's <code>visibleSortIndicatorIndices</code> is updated.</p> |
| * |
| * @param columnIndices The indices of the columns by which to sort the <code>dataProvider</code>. |
| * |
| * @param isInteractive If true, <code>GridSortEvent.SORT_CHANGING</code> and |
| * <code>GridSortEvent.SORT_CHANGE</code> events are dispatched. |
| * |
| * @return <code>true</code> if the <code>dataProvider</code> was sorted with the provided |
| * column indicies. |
| * |
| * @see spark.components.DataGrid#dataProvider |
| * @see spark.components.gridClasses.GridColumn#sortCompareFunction |
| * @see spark.components.gridClasses.GridColumn#sortDescending |
| * @see spark.components.gridClasses.GridColumn#sortField |
| * @see spark.components.GridColumnHeaderGroup#visibleSortIndicatorIndices |
| * @see spark.events.GridSortEvent |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function sortByColumns(columnIndices:Vector.<int>, isInteractive:Boolean=false):Boolean |
| { |
| const dataProvider:ICollectionView = this.dataProvider as ICollectionView; |
| if (!dataProvider) |
| return false; |
| |
| var sort:ISort = dataProvider.sort; |
| if (sort) |
| sort.compareFunction = null; |
| else |
| sort = new Sort(); |
| |
| var sortFields:Array = createSortFields(columnIndices, sort.fields); |
| if (!sortFields || (sortFields.length == 0)) |
| return false; |
| |
| var oldSortFields:Array = (dataProvider.sort) ? dataProvider.sort.fields : null; |
| |
| // Dispatch the "changing" event. If preventDefault() is called |
| // on this event, the sort operation will be cancelled. If columnIndices or |
| // sortFields are changed, the new values will be used. |
| if (isInteractive) |
| { |
| // This is a shallow copy which means only the pointers to the ISortField objects |
| // are copied to the new Array, not the ISortField objects themselves. |
| if (oldSortFields) |
| oldSortFields = oldSortFields.concat(); |
| |
| if (hasEventListener(GridSortEvent.SORT_CHANGING)) |
| { |
| const changingEvent:GridSortEvent = |
| new GridSortEvent(GridSortEvent.SORT_CHANGING, |
| false, true, |
| columnIndices, |
| oldSortFields, /* intended to be read-only but no way to enforce this */ |
| sortFields); |
| |
| // The event was cancelled so don't sort. |
| if (!dispatchEvent(changingEvent)) |
| return false; |
| |
| // Update the sort columns since they might have changed. |
| columnIndices = changingEvent.columnIndices; |
| if (!columnIndices) |
| return false; |
| |
| // Update the new sort fields since they might have changed. |
| sortFields = changingEvent.newSortFields; |
| if (!sortFields) |
| return false; |
| } |
| } |
| |
| // Remove each old SortField that's not a member of the new sortFields Array |
| // as a "styleClient" of this DataGrid. |
| |
| if (oldSortFields) |
| { |
| for each (var oldSortField:ISortField in oldSortFields) |
| { |
| var oldASC:IAdvancedStyleClient = oldSortField as IAdvancedStyleClient; |
| if (!oldASC || (oldASC.styleParent != this) || (sortFields.indexOf(oldASC) != -1)) |
| continue; |
| removeStyleClient(oldASC); |
| } |
| } |
| |
| // Add new SortFields as "styleClients" of this DataGrid so that they |
| // inherit this DataGrid's locale style. |
| |
| for each (var newSortField:ISortField in sortFields) |
| { |
| var newASC:IAdvancedStyleClient = newSortField as IAdvancedStyleClient; |
| if (!newASC || (newASC.styleParent == this)) |
| continue; |
| addStyleClient(newASC); |
| } |
| |
| ensureComplexFieldsMonitoring(sortFields); |
| |
| sort.fields = sortFields; |
| |
| dataProvider.sort = sort; |
| dataProvider.refresh(); |
| |
| if (isInteractive) |
| { |
| // Dispatch the "change" event. |
| if (hasEventListener(GridSortEvent.SORT_CHANGE)) |
| { |
| const changeEvent:GridSortEvent = |
| new GridSortEvent(GridSortEvent.SORT_CHANGE, |
| false, true, |
| columnIndices, |
| oldSortFields, sortFields); |
| dispatchEvent(changeEvent); |
| } |
| |
| // Update the visible sort indicators. |
| if (columnHeaderGroup) |
| columnHeaderGroup.visibleSortIndicatorIndices = columnIndices; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @private |
| * Return an array of ISortFields, one per column. If a matching sort field is found in |
| * previousFields then it's used, otherwise a new sort field is created. Each sort field's |
| * sortDescending property is set to match its column's sortDescending property. |
| */ |
| private function createSortFields(columnIndices:Vector.<int>, previousFields:Array):Array |
| { |
| const fields:Array = []; // return value |
| |
| for each (var columnIndex:int in columnIndices) |
| { |
| var col:GridColumn = this.getColumnAt(columnIndex); |
| |
| if (!col || (!col.dataField && (col.labelFunction == null) && (col.sortCompareFunction == null))) |
| return null; |
| |
| var sortField:ISortField = findSortField(col.dataField, previousFields); |
| |
| if (!sortField) |
| { |
| //Constructs a new sortField from the columns own sortField property. |
| sortField = col.sortField; |
| } |
| else |
| { |
| sortField.descending = col.sortDescending; |
| } |
| |
| fields.push(sortField); |
| } |
| |
| return fields; |
| } |
| |
| /** |
| * @private |
| * Finds a SortField using the provided dataField and returns it. |
| * |
| * @param dataField The dataField of the column. |
| * @param fields The array of SortFields to search through. |
| */ |
| private static function findSortField(dataField:String, fields:Array):ISortField |
| { |
| if (dataField == null) |
| return null; |
| |
| for each (var field:ISortField in fields) |
| { |
| if (field.name == dataField) |
| return field; |
| } |
| |
| return null; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Private Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * @return True if there is an anchor position set. |
| */ |
| private function isAnchorSet():Boolean |
| { |
| if (!grid) |
| return false; |
| |
| if (isRowSelectionMode()) |
| return grid.anchorRowIndex != -1; |
| else |
| return grid.anchorRowIndex != -1 && grid.anchorRowIndex != -1; |
| } |
| |
| /** |
| * @private |
| * Toggle the selection and set the caret to rowIndex/columnIndex. |
| * |
| * @return True if the selection has changed. |
| */ |
| private function toggleSelection(rowIndex:int, columnIndex:int):Boolean |
| { |
| var kind:String; |
| |
| if (isRowSelectionMode()) |
| { |
| if (grid.selectionContainsIndex(rowIndex)) |
| kind = GridSelectionEventKind.REMOVE_ROW; |
| else if (selectionMode == GridSelectionMode.MULTIPLE_ROWS) |
| kind = GridSelectionEventKind.ADD_ROW; |
| else |
| kind = GridSelectionEventKind.SET_ROW; |
| |
| } |
| else if (isCellSelectionMode()) |
| { |
| if (grid.selectionContainsCell(rowIndex, columnIndex)) |
| kind = GridSelectionEventKind.REMOVE_CELL; |
| else if (selectionMode == GridSelectionMode.MULTIPLE_CELLS) |
| kind = GridSelectionEventKind.ADD_CELL; |
| else |
| kind = GridSelectionEventKind.SET_CELL; |
| } |
| |
| var success:Boolean = |
| commitInteractiveSelection(kind, rowIndex, columnIndex); |
| |
| // Update the caret if the selection was not cancelled. |
| if (success) |
| commitCaretPosition(rowIndex, columnIndex); |
| |
| return success; |
| } |
| |
| /** |
| * @private |
| * Extends the selection from the anchor position to the given 'caret' |
| * position and updates the caret position. |
| */ |
| private function extendSelection(caretRowIndex:int, |
| caretColumnIndex:int):Boolean |
| { |
| if (!isAnchorSet()) |
| return false; |
| |
| const startRowIndex:int = Math.min(grid.anchorRowIndex, caretRowIndex); |
| const endRowIndex:int = Math.max(grid.anchorRowIndex, caretRowIndex); |
| var success:Boolean; |
| |
| if (selectionMode == GridSelectionMode.MULTIPLE_ROWS) |
| { |
| success = commitInteractiveSelection( |
| GridSelectionEventKind.SET_ROWS, |
| startRowIndex, -1, |
| endRowIndex - startRowIndex + 1, 0); |
| } |
| else if (selectionMode == GridSelectionMode.SINGLE_ROW) |
| { |
| // Can't extend the selection so move it to the caret position. |
| success = commitInteractiveSelection( |
| GridSelectionEventKind.SET_ROW, caretRowIndex, -1, 1, 0); |
| } |
| else if (selectionMode == GridSelectionMode.MULTIPLE_CELLS) |
| { |
| const rowCount:int = endRowIndex - startRowIndex + 1; |
| const startColumnIndex:int = |
| Math.min(grid.anchorColumnIndex, caretColumnIndex); |
| const endColumnIndex:int = |
| Math.max(grid.anchorColumnIndex, caretColumnIndex); |
| const columnCount:int = endColumnIndex - startColumnIndex + 1; |
| |
| success = commitInteractiveSelection( |
| GridSelectionEventKind.SET_CELL_REGION, |
| startRowIndex, startColumnIndex, |
| rowCount, columnCount); |
| } |
| else if (selectionMode == GridSelectionMode.SINGLE_CELL) |
| { |
| // Can't extend the selection so move it to the caret position. |
| success = commitInteractiveSelection( |
| GridSelectionEventKind.SET_CELL, |
| caretRowIndex, caretColumnIndex, 1, 1); |
| } |
| |
| // Update the caret. |
| if (success) |
| commitCaretPosition(caretRowIndex, caretColumnIndex); |
| |
| return success; |
| } |
| |
| /** |
| * @private |
| * Sets the selection and updates the caret and anchor positions. |
| */ |
| private function setSelectionAnchorCaret(rowIndex:int, columnIndex:int):Boolean |
| { |
| // click sets the selection and updates the caret and anchor |
| // positions. |
| var success:Boolean; |
| if (isRowSelectionMode()) |
| { |
| // Select the row. |
| success = commitInteractiveSelection( |
| GridSelectionEventKind.SET_ROW, |
| rowIndex, columnIndex); |
| } |
| else if (isCellSelectionMode()) |
| { |
| // Select the cell. |
| success = commitInteractiveSelection( |
| GridSelectionEventKind.SET_CELL, |
| rowIndex, columnIndex); |
| } |
| |
| // Update the caret and anchor positions unless cancelled. |
| if (success) |
| { |
| commitCaretPosition(rowIndex, columnIndex); |
| grid.anchorRowIndex = rowIndex; |
| grid.anchorColumnIndex = columnIndex; |
| } |
| |
| return success; |
| } |
| |
| /** |
| * @private |
| * Returns the new caret position based on the current caret position and |
| * the navigationUnit as a Point, where x is the columnIndex and y is the |
| * rowIndex. Assures there is a valid caretPosition. |
| */ |
| private function setCaretToNavigationDestination(navigationUnit:uint):CellPosition |
| { |
| var caretRowIndex:int = grid.caretRowIndex; |
| var caretColumnIndex:int = grid.caretColumnIndex; |
| |
| const rowCount:int = dataProviderLength; |
| const columnCount:int = columnsLength; |
| |
| const gridLayout:GridLayout = grid.layout as GridLayout; |
| const centerGridView:GridView = gridLayout.centerGridView; |
| const topGridView:GridView = gridLayout.topGridView; |
| var caretGridView:GridView; |
| |
| switch (navigationUnit) |
| { |
| case NavigationUnit.LEFT: |
| { |
| if (isCellSelectionMode()) |
| { |
| if (grid.caretColumnIndex > 0) |
| caretColumnIndex = grid.getPreviousVisibleColumnIndex(caretColumnIndex); |
| } |
| break; |
| } |
| |
| case NavigationUnit.RIGHT: |
| { |
| if (isCellSelectionMode()) |
| { |
| if (grid.caretColumnIndex + 1 < columnCount) |
| caretColumnIndex = grid.getNextVisibleColumnIndex(caretColumnIndex); |
| } |
| break; |
| } |
| |
| case NavigationUnit.UP: |
| { |
| if (grid.caretRowIndex > 0) |
| caretRowIndex--; |
| break; |
| } |
| |
| case NavigationUnit.DOWN: |
| { |
| if (grid.caretRowIndex + 1 < rowCount) |
| caretRowIndex++; |
| break; |
| } |
| |
| case NavigationUnit.PAGE_UP: |
| { |
| // If the caret is below the first visible row, then just move the caret up to |
| // the first visible row. Otherwise scroll up far enough to put the caret row |
| // at the top of the view. |
| |
| caretGridView = ((lockedRowCount > 0) && (caretRowIndex <= lockedRowCount)) ? topGridView : centerGridView; |
| const firstVisibleRowIndex:int = caretGridView.gridViewLayout.getFirstFullyVisibleRowIndex(); |
| |
| if (caretRowIndex > firstVisibleRowIndex) |
| { |
| caretRowIndex = firstVisibleRowIndex; |
| } |
| else if (caretRowIndex >= lockedRowCount) |
| { |
| // Attempt to synchronously scroll caretRowIndex to bottom of the view |
| // and then reset the caretRowIndex to whatever row actually ends up at the top. |
| |
| const caretRowBounds:Rectangle = grid.getRowBounds(caretRowIndex); |
| const visibleBounds:Rectangle = centerGridView.gridViewLayout.getVisibleBounds(); |
| const pageUpDelta:Number = visibleBounds.bottom - caretRowBounds.bottom; |
| grid.verticalScrollPosition -= pageUpDelta; |
| validateNow(); |
| |
| caretRowIndex = centerGridView.gridViewLayout.getFirstFullyVisibleRowIndex(); |
| } |
| |
| break; |
| } |
| |
| case NavigationUnit.PAGE_DOWN: |
| { |
| // If the caret is on the last locked row, move to the first unlocked row. Otherwise: |
| // If the caret is above the last visible row, then just move the caret to the last visible row. |
| // Otherwise scroll down far enough to position the caret row at the top of the grid view and |
| // then reset the caret to the new last fully visible row. |
| |
| caretGridView = ((lockedRowCount > 0) && (caretRowIndex < (lockedRowCount - 1))) ? topGridView : centerGridView; |
| const lastVisibleRowIndex:int = caretGridView.gridViewLayout.getLastFullyVisibleRowIndex(); |
| |
| if ((lockedRowCount > 0) && (rowCount > lockedRowCount) && (caretRowIndex == (lockedRowCount - 1))) |
| { |
| caretRowIndex = lockedRowCount; |
| } |
| else if (caretRowIndex < lastVisibleRowIndex) |
| { |
| caretRowIndex = lastVisibleRowIndex; |
| } |
| else if (caretRowIndex >= lockedRowCount) |
| { |
| // Attempt to synchronously scroll caretRowIndex to the top of the view |
| // and then reset the caretRowIndex to whatever row actually ends up at the bottom. |
| |
| grid.verticalScrollPosition = grid.getRowBounds(caretRowIndex).y; |
| validateNow(); |
| |
| caretRowIndex = centerGridView.gridViewLayout.getLastFullyVisibleRowIndex(); |
| } |
| |
| break; |
| } |
| |
| case NavigationUnit.HOME: |
| { |
| caretRowIndex = 0; |
| caretColumnIndex = isCellSelectionMode() ? grid.getNextVisibleColumnIndex(-1) : -1; |
| break; |
| } |
| |
| case NavigationUnit.END: |
| { |
| caretRowIndex = rowCount - 1; |
| caretColumnIndex = isCellSelectionMode() ? grid.getPreviousVisibleColumnIndex(columnCount) : -1; |
| |
| // The heights of any rows that have not been rendered yet are |
| // estimated. Force them to draw so the heights are accurate. |
| // TBD: is there a better way to do this? |
| grid.verticalScrollPosition = grid.contentHeight; |
| validateNow(); |
| if (grid.contentHeight != grid.verticalScrollPosition) |
| { |
| grid.verticalScrollPosition = grid.contentHeight; |
| validateNow(); |
| } |
| break; |
| } |
| |
| default: |
| { |
| return null; |
| } |
| } |
| |
| return new CellPosition(caretRowIndex, caretColumnIndex); |
| } |
| |
| /** |
| * @copy spark.components.Grid#ensureCellIsVisible() |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function ensureCellIsVisible(rowIndex:int, columnIndex:int = -1):void |
| { |
| if (grid) |
| grid.ensureCellIsVisible(rowIndex, columnIndex); |
| } |
| |
| /** |
| * @private |
| * |
| * Adjusts the caret and the selection based on what keystroke is used |
| * in combination with a ctrl/cmd key or a shift key. Returns false |
| * if the selection was not changed. |
| */ |
| protected function adjustSelectionUponNavigation(event:KeyboardEvent):Boolean |
| { |
| // Some unrecognized key stroke was entered, return. |
| if (!NavigationUnit.isNavigationUnit(event.keyCode)) |
| return false; |
| |
| // If rtl layout, need to swap Keyboard.LEFT and Keyboard.RIGHT. |
| var navigationUnit:uint = mapKeycodeForLayoutDirection(event); |
| |
| const newPosition:CellPosition = setCaretToNavigationDestination(navigationUnit); |
| if (!newPosition) |
| return false; |
| |
| // Cancel so another component doesn't handle this event. |
| event.preventDefault(); |
| |
| var selectionChanged:Boolean = false; |
| |
| if (event.shiftKey) |
| { |
| // The shift key-nav key combination extends the selection and |
| // updates the caret. |
| selectionChanged = |
| extendSelection(newPosition.rowIndex, newPosition.columnIndex); |
| } |
| else if (event.ctrlKey) |
| { |
| // If its a ctrl/cmd key-nav key combination, there is nothing |
| // more to do then set the caret. |
| commitCaretPosition(newPosition.rowIndex, newPosition.columnIndex); |
| } |
| else |
| { |
| // Select the current row/cell. |
| setSelectionAnchorCaret(newPosition.rowIndex, newPosition.columnIndex); |
| } |
| |
| // Ensure this position is visible. |
| ensureCellIsVisible(newPosition.rowIndex, newPosition.columnIndex); |
| |
| return true; |
| } |
| |
| /** |
| * @private |
| * |
| * Returns true if committing the given selection operation would change |
| * the current selection. |
| */ |
| private function doesChangeCurrentSelection( |
| selectionEventKind:String, |
| selectionChange:CellRegion):Boolean |
| { |
| var changesSelection:Boolean; |
| |
| const rowIndex:int = selectionChange.rowIndex; |
| const columnIndex:int = selectionChange.columnIndex; |
| const rowCount:int = selectionChange.rowCount; |
| const columnCount:int = selectionChange.columnCount; |
| |
| switch (selectionEventKind) |
| { |
| case GridSelectionEventKind.SET_ROW: |
| { |
| changesSelection = |
| !selectionContainsOnlyIndex(rowIndex); |
| break; |
| } |
| case GridSelectionEventKind.ADD_ROW: |
| |
| { |
| changesSelection = |
| !grid.selectionContainsIndex(rowIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.REMOVE_ROW: |
| { |
| changesSelection = requireSelection ? |
| !selectionContainsOnlyIndex(rowIndex) : |
| grid.selectionContainsIndex(rowIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.SET_ROWS: |
| { |
| changesSelection = |
| !selectionContainsOnlyIndices(selectionChange); |
| break; |
| } |
| |
| case GridSelectionEventKind.SET_CELL: |
| { |
| changesSelection = |
| !selectionContainsOnlyCell(rowIndex, columnIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.ADD_CELL: |
| { |
| changesSelection = |
| !grid.selectionContainsCell(rowIndex, columnIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.REMOVE_CELL: |
| { |
| changesSelection = requireSelection ? |
| !selectionContainsOnlyCell(rowIndex, columnIndex) : |
| grid.selectionContainsCell(rowIndex, columnIndex); |
| break; |
| } |
| |
| case GridSelectionEventKind.SET_CELL_REGION: |
| { |
| changesSelection = |
| !selectionContainsOnlyCellRegion( |
| rowIndex, columnIndex, rowCount, columnCount); |
| break; |
| } |
| |
| case GridSelectionEventKind.SELECT_ALL: |
| { |
| changesSelection = true; |
| break; |
| } |
| } |
| |
| return changesSelection; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Grid event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Updating the hover is disabled if the mouse button was depressed |
| * while not over the grid. The common case for this is while |
| * scrolling. While the scroll thumb is depressed don't want the |
| * hover updated if the mouse drifts into the grid. |
| */ |
| protected function grid_rollOverHandler(event:GridEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| // The related object is the object that was previously under |
| // the pointer. |
| if (event.buttonDown && event.relatedObject != grid) |
| updateHoverOnRollOver = false; |
| |
| grid.hoverRowIndex = updateHoverOnRollOver ? event.rowIndex : -1; |
| grid.hoverColumnIndex = updateHoverOnRollOver ? event.columnIndex : -1; |
| |
| event.updateAfterEvent(); |
| } |
| |
| /** |
| * @private |
| * If the mouse button is depressed while outside of the grid, the hover |
| * indicator is not enabled again until GRID_MOUSE_UP or GRID_ROLL_OUT. |
| */ |
| protected function grid_rollOutHandler(event:GridEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| grid.hoverRowIndex = -1; |
| grid.hoverColumnIndex = -1; |
| |
| updateHoverOnRollOver = true; |
| event.updateAfterEvent(); |
| } |
| |
| /** |
| * @private |
| * If the mouse button is depressed while outside of the grid, the hover |
| * indicator is not enabled again until GRID_MOUSE_UP or GRID_ROLL_OUT. |
| */ |
| protected function grid_mouseUpHandler(event:GridEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| if (!updateHoverOnRollOver) |
| { |
| grid.hoverRowIndex = event.rowIndex; |
| grid.hoverColumnIndex = event.columnIndex; |
| updateHoverOnRollOver = true; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| protected function grid_mouseDownHandler(event:GridEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| const isCellSelection:Boolean = isCellSelectionMode(); |
| |
| const rowIndex:int = event.rowIndex; |
| const columnIndex:int = isCellSelection ? event.columnIndex : -1; |
| |
| // Clicked on empty place in grid. Don't change selection or caret |
| // position. |
| if (rowIndex == -1 || isCellSelection && columnIndex == -1) |
| return; |
| |
| |
| if (event.ctrlKey) |
| { |
| // ctrl-click toggles the selection and updates caret and anchor. |
| if (!toggleSelection(rowIndex, columnIndex)) |
| return; |
| |
| grid.anchorRowIndex = rowIndex; |
| grid.anchorColumnIndex = columnIndex; |
| } |
| else |
| { |
| if (event.shiftKey) |
| { |
| // shift-click extends the selection and updates the caret. |
| if (grid.selectionMode == GridSelectionMode.MULTIPLE_ROWS || grid.selectionMode == GridSelectionMode.MULTIPLE_CELLS) |
| { |
| if (!extendSelection(rowIndex, columnIndex)) |
| return; |
| } |
| } |
| else |
| { |
| // click sets the selection and updates the caret and anchor positions. |
| setSelectionAnchorCaret(rowIndex, columnIndex); |
| } |
| } |
| |
| |
| if (dragEnabled && isRowSelectionMode() && selectionContainsIndex(rowIndex)) |
| { |
| pendingSelectionOnMouseUp = true; |
| } |
| |
| // If selection is pending on mouse up then we have just moused down on |
| // an item, part of an already commited selection. |
| // However if we moused down on an item that's not currently selected, |
| // we must commit the selection before trying to start dragging since |
| // listeners may prevent the item from being selected. |
| if (!pendingSelectionOnMouseUp) |
| validateProperties(); |
| |
| mouseDownPoint = event.target.localToGlobal(new Point(event.localX, event.localY)); |
| mouseDownObject = event.target as DisplayObject; |
| mouseDownRowIndex = rowIndex; |
| mouseDownColumnIndex = columnIndex; |
| |
| var listenForDrag:Boolean = (dragEnabled && |
| getStyle("interactionMode") == InteractionMode.MOUSE && selectedIndices && |
| this.selectedIndices.indexOf(rowIndex) != -1); |
| // Handle any drag gestures that may have been started |
| if (listenForDrag) |
| { |
| // Listen for GRID_MOUSE_DRAG. |
| // The user may have cliked on the item renderer close |
| // to the edge of the list, and we still want to start a drag |
| // operation if they move out of the list. |
| grid.addEventListener(GridEvent.GRID_MOUSE_DRAG, grid_mouseDragHandler); |
| } |
| |
| if (pendingSelectionOnMouseUp || listenForDrag) |
| { |
| // FIXME (dloverin): When dragging a proxy in an untrusted |
| // child application the cursor does not follow drag proxy. |
| |
| // FIXME (dloverin): The listener on the sandbox root can be removed when: |
| // 1. MouseEventUtil.addDownDragUpListeners() dispatches |
| // a MOUSE_UP_SOMEWHERE. |
| // 2. Grid.grid_mouseDownDragUpHandler() changes its parameter from |
| // a MouseEvent to an event so a MOUSE_UP_SOMEWHERE event does |
| // not cause an RTE. Grid can then handle the MOUSE_UP_SOMEWHERE |
| // event by dispatching a MOUSE_UP or aGRID_MOUSE_UP_SOMEWHERE |
| // event. |
| systemManager.getSandboxRoot().addEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, sandbox_mouseUpHandler, false, 0, true); |
| } |
| |
| } |
| |
| /** |
| * @private |
| * Redispatch the grid's "caretChange" event. |
| */ |
| protected function grid_caretChangeHandler(event:GridCaretEvent):void |
| { |
| if (hasEventListener(GridCaretEvent.CARET_CHANGE)) |
| dispatchEvent(event); |
| } |
| |
| /** |
| * @private |
| * Redispatch the grid's "valueCommit" event. |
| */ |
| protected function grid_valueCommitHandler(event:FlexEvent):void |
| { |
| if (hasEventListener(FlexEvent.VALUE_COMMIT)) |
| dispatchEvent(event); |
| } |
| |
| /** |
| * @private |
| */ |
| private function grid_invalidateDisplayListHandler(event:Event):void |
| { |
| // invalidate all IDataGridElements |
| if (columnHeaderGroup && grid.isInvalidateDisplayListReason("horizontalScrollPosition")) |
| columnHeaderGroup.invalidateDisplayList(); |
| } |
| |
| /** |
| * @private |
| */ |
| private function grid_invalidateSizeHandler(event:Event):void |
| { |
| // invalidate all IDataGridElements |
| if (columnHeaderGroup) |
| columnHeaderGroup.invalidateSize(); |
| } |
| |
| /** |
| * @private |
| */ |
| private function grid_gridViewsChangedHandler(event:Event):void |
| { |
| if (columnHeaderGroup) |
| columnHeaderGroup.configureGridColumnHeaderViews(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Header event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| private var stretchCursorID:int = CursorManager.NO_CURSOR; |
| private var resizeColumn:GridColumn = null; |
| private var resizeAnchorX:Number = NaN; |
| private var resizeColumnWidth:Number = NaN; |
| private var nextColumn:GridColumn = null; // RTL layout only |
| private var nextColumnWidth:Number = NaN; // RTL layout only |
| |
| /** |
| * @private |
| * Flip the specified column's sortDescending flag and and sort the dataProvider. If |
| * isMultiColumnSort is true, add the column to the set of columns being sorted (that's |
| * columnHeaderGroup.visibleSortIndicatorIndices) otherwise just sort per the specified column. |
| * |
| * If the sort was possible and was not cancelled (see sortByColumns()) then set the |
| * columnHeaderGroup's selectedColumnIndex and return true, otherwise return false. |
| */ |
| private function interactiveSortByColumns(column:GridColumn, isMultiColumnSort:Boolean):Boolean |
| { |
| if (!enabled || !sortableColumns || !column || !column.sortable || !columnHeaderGroup) |
| return false; |
| |
| const columnIndex:int = column.columnIndex; |
| const currentSortColumnIndices:Vector.<int> = columnHeaderGroup.visibleSortIndicatorIndices; |
| const reverseSort:Boolean = currentSortColumnIndices.indexOf(columnIndex) != -1; |
| var sortColumnIndices:Vector.<int>; |
| |
| if (isMultiColumnSort && multiColumnSortingEnabled) |
| { |
| sortColumnIndices = currentSortColumnIndices; |
| if (!reverseSort) |
| sortColumnIndices.push(columnIndex); |
| } |
| else |
| { |
| sortColumnIndices = new <int>[columnIndex]; |
| } |
| |
| if (reverseSort) |
| column.sortDescending = !column.sortDescending; |
| |
| if (!sortByColumns(sortColumnIndices, true) && reverseSort) |
| { |
| column.sortDescending = !column.sortDescending; // sort was cancelled |
| return false; |
| } |
| |
| columnHeaderGroup.selectedColumnIndex = column.columnIndex; |
| |
| return true; |
| } |
| |
| /** |
| * @private |
| */ |
| protected function columnHeaderGroup_clickHandler(event:GridEvent):void |
| { |
| interactiveSortByColumns(event.column, event.ctrlKey); |
| } |
| |
| /** |
| * @private |
| */ |
| protected function columnHeaderGroup_rollOverHandler(event:GridEvent):void |
| { |
| if (resizeColumn || !enabled) |
| return; |
| |
| columnHeaderGroup.hoverColumnIndex = event.columnIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| protected function columnHeaderGroup_rollOutHandler(event:GridEvent):void |
| { |
| if (!enabled) |
| return; |
| |
| columnHeaderGroup.hoverColumnIndex = -1; |
| } |
| |
| /** |
| * @private |
| */ |
| protected function separator_mouseDownHandler(event:GridEvent):void |
| { |
| const column:GridColumn = event.column; |
| if (!enabled || !grid.resizableColumns || !column || !column.resizable) |
| return; |
| |
| resizeColumn = event.column; |
| resizeAnchorX = event.localX; |
| resizeColumnWidth = grid.getColumnWidth(resizeColumn.columnIndex); |
| |
| // If we're laying out RTL then dragging to the left - which increases |
| // a column's width - and the Grid's width is unconstrained, then only |
| // allow the column's width to grow to the extent that the adjacent |
| // (next) column can shrink. |
| |
| if (isNaN(explicitWidth) && (layoutDirection == LayoutDirection.RTL)) |
| { |
| const nextColumnIndex:int = grid.getNextVisibleColumnIndex(resizeColumn.columnIndex); |
| nextColumn = getColumnAt(nextColumnIndex); |
| nextColumnWidth = Math.ceil(grid.getColumnWidth(nextColumnIndex)); |
| } |
| else |
| { |
| nextColumn = null; |
| nextColumnWidth = NaN; |
| } |
| |
| // Give all of the columns to the left of this one an explicit so that resizing |
| // this column doesn't change their width and, consequently, this column's location. |
| |
| const resizeColumnIndex:int = resizeColumn.columnIndex; |
| for (var columnIndex:int = 0; columnIndex < resizeColumnIndex; columnIndex++) |
| { |
| var gc:GridColumn = getColumnAt(columnIndex); |
| if (gc.visible && isNaN(gc.width)) |
| gc.width = grid.getColumnWidth(columnIndex); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| protected function separator_mouseDragHandler(event:GridEvent):void |
| { |
| if (!resizeColumn) |
| return; |
| |
| const widthDelta:Number = event.localX - resizeAnchorX; |
| const minWidth:Number = isNaN(resizeColumn.minWidth) ? 0 : resizeColumn.minWidth; |
| const maxWidth:Number = resizeColumn.maxWidth; |
| var newWidth:Number = Math.ceil(resizeColumnWidth + widthDelta); |
| |
| // Layout is RTL (see sparator_mouseDownHandler). Make sure that the |
| // next column's width can shrink as much as the resizeColumn is growing, |
| // or vice versa. |
| |
| if (nextColumn) |
| { |
| const nextMinWidth:Number = isNaN(nextColumn.minWidth) ? 0 : nextColumn.minWidth; |
| |
| if (Math.ceil(nextColumnWidth - widthDelta) <= nextMinWidth) |
| return; |
| if (Math.ceil(resizeColumnWidth + widthDelta) <= minWidth) |
| return; |
| |
| nextColumn.width = nextColumnWidth - widthDelta; |
| } |
| |
| newWidth = Math.max(newWidth, minWidth); |
| if (!isNaN(maxWidth)) |
| newWidth = Math.min(newWidth, maxWidth); |
| |
| resizeColumn.width = newWidth; |
| validateNow(); // smooth out the drag |
| event.updateAfterEvent(); |
| } |
| |
| /** |
| * @private |
| */ |
| protected function separator_mouseUpHandler(event:GridEvent):void |
| { |
| if (!resizeColumn) |
| return; |
| |
| resizeColumn = null; |
| cursorManager.removeCursor(stretchCursorID); |
| } |
| |
| /** |
| * @private |
| */ |
| protected function separator_rollOverHandler(event:GridEvent):void |
| { |
| const column:GridColumn = event.column; |
| if (resizeColumn || !enabled || !grid.resizableColumns || !column || !column.resizable) |
| return; |
| |
| var stretchCursorClass:Class = getStyle("stretchCursor") as Class; |
| if (stretchCursorClass) |
| stretchCursorID = cursorManager.setCursor(stretchCursorClass, CursorManagerPriority.HIGH, 0, 0); |
| } |
| |
| /** |
| * @private |
| */ |
| protected function separator_rollOutHandler(event:GridEvent):void |
| { |
| if (!enabled || resizeColumn) |
| return; |
| |
| cursorManager.removeCursor(stretchCursorID); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // DataGrid event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * The UIComponent's focusInHandler and focusOutHandler draw the |
| * focus. This handler exists only when there is a caretIndicator part. |
| */ |
| protected function dataGrid_focusHandler(event:FocusEvent):void |
| { |
| if (!grid) |
| return; |
| |
| const isFocusIn:Boolean = event.type == FocusEvent.FOCUS_IN; |
| const isFocusOut:Boolean = event.type == FocusEvent.FOCUS_OUT; |
| |
| if (isOurFocus(DisplayObject(event.target))) |
| grid.showCaret = isFocusIn && (selectionMode != GridSelectionMode.NONE); |
| |
| if (isFocusIn) |
| internalFocusOwner = GRID_FOCUS_OWNER; |
| else if (isFocusOut) |
| internalFocusOwner = NO_FOCUS_OWNER; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Drag methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * The default handler for the <code>dragStart</code> event. |
| * |
| * @param event The DragEvent object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function dragStartHandler(event:DragEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| var dragSource:DragSource = new DragSource(); |
| addDragData(dragSource); |
| DragManager.doDrag(this, |
| dragSource, |
| event, |
| createDragIndicator(), |
| 0 /*xOffset*/, |
| 0 /*yOffset*/, |
| 0.5 /*imageAlpha*/, |
| dragMoveEnabled); |
| } |
| |
| /** |
| * @private |
| * Used to sort the selected indices during drag and drop operations. |
| */ |
| private function compareValues(a:int, b:int):int |
| { |
| return a - b; |
| } |
| |
| /** |
| * @private |
| * Handles <code>DragEvent.DRAG_COMPLETE</code> events. This method |
| * removes the items from the data provider. |
| * |
| * @param event The DragEvent object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function dragCompleteHandler(event:DragEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| // Remove the dragged items only if they were drag moved to |
| // a different list. If the items were drag moved to this |
| // list, the reordering was already handles in the |
| // DragEvent.DRAG_DROP listener. |
| if (!dragMoveEnabled || |
| event.action != DragManager.MOVE || |
| event.relatedObject == this) |
| return; |
| |
| // Clear the selection, but remember which items were moved |
| var movedIndices:Vector.<int> = selectedIndices; |
| selectedIndices = new Vector.<int>(); |
| validateProperties(); // To commit the selection |
| |
| // Remove the moved items |
| movedIndices.sort(compareValues); |
| var count:int = movedIndices.length; |
| for (var i:int = count - 1; i >= 0; i--) |
| { |
| dataProvider.removeItemAt(movedIndices[i]); |
| } |
| } |
| |
| /** |
| * Creates an instance of a class that is used to display the visuals |
| * of the dragged items during a drag and drop operation. |
| * The default <code>DragEvent.DRAG_START</code> handler passes the |
| * instance to the <code>DragManager.doDrag()</code> method. |
| * |
| * @return The IFlexDisplayObject representing the drag indicator. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function createDragIndicator():IFlexDisplayObject |
| { |
| var dragIndicator:IFlexDisplayObject; |
| var dragIndicatorClass:Class = Class(getStyle("dragIndicatorClass")); |
| if (dragIndicatorClass) |
| { |
| dragIndicator = new dragIndicatorClass(); |
| if (dragIndicator is IVisualElement) |
| IVisualElement(dragIndicator).owner = this; |
| } |
| |
| return dragIndicator; |
| } |
| |
| /** |
| * Adds the selected items to the DragSource object as part of |
| * a drag-and-drop operation. |
| * Override this method to add other data to the drag source. |
| * |
| * @param ds The DragSource object to which to add the data. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function addDragData(dragSource:DragSource):void |
| { |
| dragSource.addHandler(copySelectedItemsForDragDrop, "itemsByIndex"); |
| |
| // Calculate the index of the focus item within the vector |
| // of ordered items returned for the "itemsByIndex" format. |
| var caretIndex:int = 0; |
| var draggedIndices:Vector.<int> = selectedIndices; |
| var count:int = draggedIndices.length; |
| for (var i:int = 0; i < count; i++) |
| { |
| if (mouseDownRowIndex > draggedIndices[i]) |
| caretIndex++; |
| } |
| dragSource.addData(caretIndex, "caretIndex"); |
| } |
| |
| /** |
| * @private |
| */ |
| private function copySelectedItemsForDragDrop():Vector.<Object> |
| { |
| // Copy the vector so that we don't modify the original |
| // since selectedIndices returns a reference. |
| var draggedIndices:Vector.<int> = selectedIndices.slice(0, selectedIndices.length); |
| var result:Vector.<Object> = new Vector.<Object>(draggedIndices.length); |
| |
| // Sort in the order of the data source |
| draggedIndices.sort(compareValues); |
| |
| // Copy the items |
| var count:int = draggedIndices.length; |
| for (var i:int = 0; i < count; i++) |
| result[i] = dataProvider.getItemAt(draggedIndices[i]); |
| return result; |
| } |
| |
| /** |
| * @private |
| * Handles <code>MouseEvent.MOUSE_MOVE</code> events from any mouse |
| * targets contained in the list including the renderers. This method |
| * watches for a gesture that constitutes the beginning of a |
| * drag drop and send a <code>DragEvent.DRAG_START</code> event. |
| * It also checks to see if the mouse is over a non-target area of a |
| * renderer so that Flex can try to make it look like that renderer was |
| * the target. |
| * |
| * @param event The MouseEvent object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function grid_mouseDragHandler(event:MouseEvent):void |
| { |
| if (!mouseDownPoint || !dragEnabled) |
| return; |
| |
| var pt:Point = new Point(event.localX, event.localY); |
| pt = DisplayObject(event.target).localToGlobal(pt); |
| |
| const DRAG_THRESHOLD:int = 5; |
| |
| if (Math.abs(mouseDownPoint.x - pt.x) > DRAG_THRESHOLD || |
| Math.abs(mouseDownPoint.y - pt.y) > DRAG_THRESHOLD) |
| { |
| var dragEvent:DragEvent = new DragEvent(DragEvent.DRAG_START); |
| dragEvent.dragInitiator = this; |
| |
| var localMouseDownPoint:Point = this.globalToLocal(mouseDownPoint); |
| |
| dragEvent.localX = localMouseDownPoint.x; |
| dragEvent.localY = localMouseDownPoint.y; |
| dragEvent.buttonDown = true; |
| |
| // We're starting a drag operation, remove the handlers |
| // that are monitoring the mouse move, we don't need them anymore: |
| dispatchEvent(dragEvent); |
| |
| var gridEvent:GridEvent = new GridEvent(GridEvent.GRID_MOUSE_UP, false, false, event.localX, event.localY, |
| event.relatedObject, event.ctrlKey, event.altKey, event.shiftKey, event.buttonDown, event.delta); |
| |
| // Finally, remove the mouse handlers |
| removeMouseHandlersForDragStart(gridEvent); |
| } |
| } |
| |
| private function removeMouseHandlersForDragStart(event:GridEvent):void |
| { |
| // If dragging failed, but we had a pending selection, commit it here |
| if (pendingSelectionOnMouseUp && !DragManager.isDragging) |
| { |
| const rowIndex:int = mouseDownRowIndex; |
| const columnIndex:int = mouseDownColumnIndex; |
| |
| if (event.ctrlKey) |
| { |
| // ctrl-click toggles the selection and updates caret and anchor. |
| if (!toggleSelection(rowIndex, columnIndex)) |
| return; |
| |
| grid.anchorRowIndex = rowIndex; |
| grid.anchorColumnIndex = columnIndex; |
| } |
| else if (event.shiftKey) |
| { |
| // shift-click extends the selection and updates the caret. |
| if (grid.selectionMode == GridSelectionMode.MULTIPLE_ROWS || |
| grid.selectionMode == GridSelectionMode.MULTIPLE_CELLS) |
| { |
| if (!extendSelection(rowIndex, columnIndex)) |
| return; |
| } |
| } |
| else |
| { |
| // click sets the selection and updates the caret and anchor |
| // positions. |
| setSelectionAnchorCaret(rowIndex, columnIndex); |
| } |
| } |
| |
| // Always clean up the flag, even if currently dragging. |
| pendingSelectionOnMouseUp = false; |
| |
| mouseDownPoint = null; |
| mouseDownObject = null; |
| mouseDownRowIndex = -1; |
| mouseDownColumnIndex = -1; |
| |
| grid.removeEventListener(GridEvent.GRID_MOUSE_DRAG, grid_mouseDragHandler); |
| systemManager.getSandboxRoot().removeEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, sandbox_mouseUpHandler, false); |
| } |
| |
| /** |
| * @private |
| * Handles <code>SandboxMouseEvent.MOUSE_UP_SOMEWHERE</code> events. |
| * |
| * @param event The SandboxMouseEvent object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| protected function sandbox_mouseUpHandler(event:SandboxMouseEvent):void |
| { |
| var sandboxMouseEvent:SandboxMouseEvent = SandboxMouseEvent(event); |
| var gridEvent:GridEvent = new GridEvent(GridEvent.GRID_MOUSE_UP, false, false, NaN, NaN, null, |
| sandboxMouseEvent.ctrlKey, sandboxMouseEvent.altKey, sandboxMouseEvent.shiftKey, |
| sandboxMouseEvent.buttonDown, 0); |
| |
| removeMouseHandlersForDragStart(gridEvent); |
| } |
| |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Drop methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Used in drag n drop methods for drop location / drop indicators. |
| */ |
| private var _gridViewLayout:GridViewLayout = null; |
| |
| |
| /** |
| * Creates and instance of the dropIndicator class that is used to |
| * display the visuals of the drop location during a drag and drop |
| * operation. The instance is set in the layout's |
| * <code>dropIndicator</code> property. |
| * |
| * <p>If you override the <code>dragEnter</code> event handler, |
| * and call <code>preventDefault()</code> so that the default handler does not execute, |
| * call <code>createDropIndicator()</code> to create the drop indicator.</p> |
| * |
| * @return Returns the dropIndicator that was set in the layout. |
| * |
| * @see #destroyDropIndicator |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function createDropIndicator():DisplayObject |
| { |
| // Do we have a drop indicator already? |
| if (_gridViewLayout.dropIndicator) |
| return _gridViewLayout.dropIndicator; |
| |
| |
| var dropIndicatorInstance:DisplayObject; |
| |
| if (dropIndicator) |
| { |
| dropIndicatorInstance = DisplayObject(createDynamicPartInstance("dropIndicator")); |
| } |
| else |
| { |
| var dropIndicatorClass:Class = Class(getStyle("dropIndicatorSkin")); |
| if (dropIndicatorClass) |
| dropIndicatorInstance = new dropIndicatorClass(); |
| } |
| |
| if (dropIndicatorInstance is IVisualElement) |
| IVisualElement(dropIndicatorInstance).owner = this; |
| |
| // Set it in the layout |
| _gridViewLayout.dropIndicator = dropIndicatorInstance; |
| |
| return dropIndicatorInstance; |
| } |
| |
| /** |
| * Releases the <code>dropIndicator</code> instance that is currently set in the layout. |
| * |
| * <p>If you override the <code>dragExit</code> event handler, |
| * and call <code>preventDefault()</code> so that the default handler does not execute, |
| * call <code>destroyDropIndicator()</code> to delete the drop indicator.</p> |
| * |
| * @return Returns the dropIndicator that was removed. |
| * |
| * @see #createDropIndicator |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| public function destroyDropIndicator():DisplayObject |
| { |
| var dropIndicatorInstance:DisplayObject = _gridViewLayout.dropIndicator; |
| |
| if (!dropIndicatorInstance) |
| return null; |
| |
| // Release the reference from the layout |
| _gridViewLayout.dropIndicator = null; |
| |
| // Release it if it's a dynamic skin part |
| var count:int = numDynamicParts("dropIndicator"); |
| |
| for (var i:int = 0; i < count; i++) |
| { |
| if (dropIndicatorInstance == getDynamicPartAt("dropIndicator", i)) |
| { |
| // This was a dynamic part, remove it now: |
| removeDynamicPartInstance("dropIndicator", dropIndicatorInstance); |
| break; |
| } |
| } |
| |
| return dropIndicatorInstance; |
| } |
| |
| /** |
| * @private |
| * Handles <code>DragEvent.DRAG_ENTER</code> events. This method |
| * determines if the DragSource object contains valid elements and uses |
| * the <code>DragManager.showDropFeedback()</code> method to set up the |
| * UI feedback as well as the layout's <code>showDropIndicator()</code> |
| * method to display the drop indicator and initiate drag scrolling. |
| * |
| * @param event The DragEvent object. |
| * |
| * @see spark.layouts.LayoutBase#showDropIndicator |
| * @see spark.layouts.LayoutBase#hideDropIndicator |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function dragEnterHandler(event:DragEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| |
| if (!_gridViewLayout) |
| { |
| //Store a current gridview layout. |
| _gridViewLayout = (grid.layout as GridLayout).centerGridView.layout as GridViewLayout; |
| } |
| |
| |
| var dropLocation:DropLocation = _gridViewLayout.calculateDropLocation(event); |
| |
| if (dropLocation) |
| { |
| DragManager.acceptDragDrop(this); |
| |
| // Create the dropIndicator instance. The layout will take care of |
| // parenting, sizing, positioning and validating the dropIndicator. |
| createDropIndicator(); |
| |
| // Show focus |
| drawFocusAnyway = true; |
| drawFocus(true); |
| |
| // Notify manager we can drop |
| DragManager.showFeedback(event.ctrlKey ? DragManager.COPY : DragManager.MOVE); |
| |
| // Show drop indicator |
| _gridViewLayout.showDropIndicator(dropLocation); |
| } |
| else |
| { |
| DragManager.showFeedback(DragManager.NONE); |
| } |
| } |
| |
| /** |
| * @private |
| * Handles <code>DragEvent.DRAG_OVER</code> events. This method |
| * determines if the DragSource object contains valid elements and uses |
| * the <code>showDropFeedback()</code> method to set up the UI feedback |
| * as well as the layout's <code>showDropIndicator()</code> method |
| * to display the drop indicator and initiate drag scrolling. |
| * |
| * @param event The DragEvent object. |
| * |
| * @see spark.layouts.LayoutBase#showDropIndicator |
| * @see spark.layouts.LayoutBase#hideDropIndicator |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function dragOverHandler(event:DragEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| |
| var dropLocation:DropLocation = _gridViewLayout.calculateDropLocation(event); |
| |
| if (dropLocation) |
| { |
| // Show focus |
| drawFocusAnyway = true; |
| drawFocus(true); |
| |
| // Notify manager we can drop |
| DragManager.showFeedback(event.ctrlKey ? DragManager.COPY : DragManager.MOVE); |
| |
| // Show drop indicator |
| _gridViewLayout.showDropIndicator(dropLocation); |
| } |
| else |
| { |
| // Hide if previously showing |
| _gridViewLayout.hideDropIndicator(); |
| |
| // Hide focus |
| drawFocus(false); |
| drawFocusAnyway = false; |
| |
| // Notify manager we can't drop |
| DragManager.showFeedback(DragManager.NONE); |
| } |
| } |
| |
| /** |
| * @private |
| * Handles <code>DragEvent.DRAG_EXIT</code> events. This method hides |
| * the UI feedback by calling the <code>hideDropFeedback()</code> method |
| * and also hides the drop indicator by calling the layout's |
| * <code>hideDropIndicator()</code> method. |
| * |
| * @param event The DragEvent object. |
| * |
| * @see spark.layouts.LayoutBase#showDropIndicator |
| * @see spark.layouts.LayoutBase#hideDropIndicator |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function dragExitHandler(event:DragEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| // Hide if previously showing |
| _gridViewLayout.hideDropIndicator(); |
| |
| // Hide focus |
| drawFocus(false); |
| drawFocusAnyway = false; |
| |
| // Destroy the dropIndicator instance |
| destroyDropIndicator(); |
| } |
| |
| /** |
| * @private |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| private function touchInteractionStartHandler(event:TouchInteractionEvent):void |
| { |
| // cancel actual selection |
| mouseDownRowIndex = -1; |
| mouseDownColumnIndex = -1; |
| mouseDownObject = null; |
| mouseDownPoint = null; |
| pendingSelectionOnMouseUp = false; |
| } |
| |
| /** |
| * @private |
| * Handles <code>DragEvent.DRAG_DROP events</code>. This method hides |
| * the drop feedback by calling the <code>hideDropFeedback()</code> method. |
| * |
| * <p>If the action is a <code>COPY</code>, |
| * then this method makes a deep copy of the object |
| * by calling the <code>ObjectUtil.copy()</code> method, |
| * and replaces the copy's <code>uid</code> property (if present) |
| * with a new value by calling the <code>UIDUtil.createUID()</code> method.</p> |
| * |
| * @param event The DragEvent object. |
| * |
| * @see mx.utils.ObjectUtil |
| * @see mx.utils.UIDUtil |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function dragDropHandler(event:DragEvent):void |
| { |
| if (event.isDefaultPrevented()) |
| return; |
| |
| |
| // Hide the drop indicator |
| _gridViewLayout.hideDropIndicator(); |
| destroyDropIndicator(); |
| |
| // Hide focus |
| drawFocus(false); |
| drawFocusAnyway = false; |
| |
| // Get the dropLocation |
| var dropLocation:DropLocation = _gridViewLayout.calculateDropLocation(event); |
| |
| if (!dropLocation) |
| return; |
| |
| // Find the dropIndex |
| var dropIndex:int = dropLocation.dropIndex; |
| |
| // Make sure the manager has the appropriate action |
| DragManager.showFeedback(event.ctrlKey ? DragManager.COPY : DragManager.MOVE); |
| |
| var dragSource:DragSource = event.dragSource; |
| var items:Vector.<Object> = dragSource.dataForFormat("itemsByIndex") as Vector.<Object>; |
| |
| var caretIndex:int = -1; |
| if (dragSource.hasFormat("caretIndex")) |
| caretIndex = event.dragSource.dataForFormat("caretIndex") as int; |
| |
| // Clear the selection first to avoid extra work while adding and removing items. |
| // We will set a new selection further below in the method. |
| var indices:Vector.<int> = selectedIndices; |
| clearSelection(); |
| validateProperties(); // To commit the selection |
| |
| // If we are reordering the list, remove the items now, |
| // adjusting the dropIndex in the mean time. |
| // If the items are drag moved to this list from a different list, |
| // the drag initiator will remove the items when it receives the |
| // DragEvent.DRAG_COMPLETE event. |
| if (dragMoveEnabled && |
| event.action == DragManager.MOVE && |
| event.dragInitiator == this) |
| { |
| // Remove the previously selected items |
| indices.sort(compareValues); |
| for (var i:int = indices.length - 1; i >= 0; i--) |
| { |
| if (indices[i] < dropIndex) |
| dropIndex--; |
| dataProvider.removeItemAt(indices[i]); |
| } |
| } |
| |
| // Drop the items at the dropIndex |
| var newSelection:Vector.<int> = new Vector.<int>(); |
| |
| // Update the selection with the index of the caret item |
| if (caretIndex != -1) |
| newSelection.push(dropIndex + caretIndex); |
| |
| // Create dataProvider if needed |
| if (!dataProvider) |
| dataProvider = new ArrayCollection(); |
| |
| var copyItems:Boolean = (event.action == DragManager.COPY); |
| for (i = 0; i < items.length; i++) |
| { |
| // Get the item, clone if needed |
| var item:Object = items[i]; |
| if (copyItems) |
| item = copyItemWithUID(item); |
| |
| // Copy the data |
| dataProvider.addItemAt(item, dropIndex + i); |
| |
| // Update the selection |
| if (i != caretIndex) |
| newSelection.push(dropIndex + i); |
| } |
| |
| // Set the selection |
| selectedIndices = newSelection; |
| |
| // Scroll the caret index in view |
| if (caretIndex != -1) |
| ensureCellIsVisible(dropIndex + items.length); |
| } |
| |
| /** |
| * Makes a deep copy of the object by calling the |
| * <code>ObjectUtil.copy()</code> method, and replaces |
| * the copy's <code>uid</code> property (if present) with a |
| * new value by calling the <code>UIDUtil.createUID()</code> method. |
| * |
| * <p>This method is used for a drag and drop copy.</p> |
| * |
| * @param item The item to copy. |
| * |
| * @return The copy of the object. |
| * |
| * @see mx.utils.ObjectUtil |
| * @see mx.utils.UIDUtil |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 11 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 5.0 |
| */ |
| protected function copyItemWithUID(item:Object):Object |
| { |
| var copyObj:Object = ObjectUtil.copy(item); |
| |
| if (copyObj is IUID) |
| { |
| IUID(copyObj).uid = UIDUtil.createUID(); |
| } |
| else if (copyObj is Object && "mx_internal_uid" in copyObj) |
| { |
| copyObj.mx_internal_uid = UIDUtil.createUID(); |
| } |
| |
| return copyObj; |
| } |
| } |
| } |