| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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 mx.controls.dataGridClasses |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.display.Graphics; |
| import flash.display.Shape; |
| import flash.display.Sprite; |
| import flash.events.Event; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| import flash.ui.Keyboard; |
| import flash.utils.Dictionary; |
| import flash.utils.setInterval; |
| |
| import mx.collections.CursorBookmark; |
| import mx.collections.IViewCursor; |
| import mx.collections.ItemResponder; |
| import mx.collections.errors.ItemPendingError; |
| import mx.controls.listClasses.BaseListData; |
| import mx.controls.listClasses.IDropInListItemRenderer; |
| import mx.controls.listClasses.IListItemRenderer; |
| import mx.controls.listClasses.ListBase; |
| import mx.controls.listClasses.ListBaseContentHolder; |
| import mx.controls.listClasses.ListBaseSeekPending; |
| import mx.controls.listClasses.ListRowInfo; |
| import mx.core.EdgeMetrics; |
| import mx.core.IFactory; |
| import mx.core.IFlexDisplayObject; |
| import mx.core.IFlexModuleFactory; |
| import mx.core.IFontContextComponent; |
| import mx.core.IInvalidating; |
| import mx.core.ILayoutDirectionElement; |
| import mx.core.IUIComponent; |
| import mx.core.IUITextField; |
| import mx.core.SpriteAsset; |
| import mx.core.UIComponentGlobals; |
| import mx.core.mx_internal; |
| import mx.events.DragEvent; |
| import mx.events.ListEvent; |
| import mx.events.ScrollEvent; |
| import mx.events.ScrollEventDetail; |
| import mx.events.ScrollEventDirection; |
| import mx.events.TweenEvent; |
| import mx.skins.halo.ListDropIndicator; |
| |
| use namespace mx_internal; |
| |
| /** |
| * The DataGridBase class is the base class for controls |
| * that display lists of items in multiple columns. |
| * It is not used directly in applications. |
| * |
| * @mxml |
| * |
| * <p>The DataGridBase class inherits all the properties of its parent classes |
| * and adds the following properties:</p> |
| * |
| * <pre> |
| * <mx:<i>tagname</i> |
| * headerHeight="depends on styles and header renderer" |
| * showHeaders="true|false" |
| * /> |
| * </pre> |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class DataGridBase extends ListBase implements IFontContextComponent |
| { |
| include "../../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function DataGridBase() |
| { |
| super(); |
| |
| listType = "vertical"; |
| |
| defaultRowCount = 7; // default number of rows is 7 |
| columnMap = {}; |
| freeItemRenderersTable = new Dictionary(false); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * A map of item renderes to columns. |
| * Like <code>ListBase.rowMap</code>, this property contains |
| * a hash map of item renderers and the columns they belong to. |
| * Item renderers are indexed by their DisplayObject name. |
| * |
| * @see mx.controls.listClasses.ListBase#rowMap |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var columnMap:Object; |
| |
| /** |
| * A per-column table of unused item renderers. |
| * Most list classes recycle item renderers that they have already created |
| * as they scroll off screen. |
| * The recycled renderers are stored here. |
| * The table is a Dictionary where the entries are Arrays indexed |
| * by the actual DataGridColumn (not the column's dataField or other |
| * properties), and each array is a stack of currently unused renderers. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var freeItemRenderersTable:Dictionary; |
| |
| /** |
| * The set of visible columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal var visibleColumns:Array; |
| |
| /** |
| * The set of visible locked columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal var visibleLockedColumns:Array; |
| |
| /** |
| * The header sub-component. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var header:DataGridHeaderBase; |
| |
| /** |
| * The class to use as the DGHeader. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal var headerClass:Class = DataGridHeader; |
| |
| /** |
| * The header mask. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var headerMask:Shape; |
| |
| /** |
| * The header sub-component for locked columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var lockedColumnHeader:DataGridHeaderBase; |
| |
| private var lockedColumnHeaderMask:Shape; |
| |
| /** |
| * The sub-component that contains locked rows. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var lockedRowContent:DataGridLockedRowContentHolder; |
| |
| private var lockedRowMask:Shape; |
| |
| /** |
| * The sub-component that contains locked rows for locked columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var lockedColumnAndRowContent:DataGridLockedRowContentHolder; |
| |
| private var lockedColumnAndRowMask:Shape; |
| |
| /** |
| * The sub-component that contains locked columns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var lockedColumnContent:ListBaseContentHolder; |
| |
| private var lockedColumnMask:Shape; |
| |
| /** |
| * @private |
| * automation |
| */ |
| mx_internal function get dataGridHeader():DataGridHeaderBase |
| { |
| return header; |
| } |
| |
| /** |
| * @private |
| * automation |
| */ |
| mx_internal function get dataGridLockedColumnHeader():DataGridHeaderBase |
| { |
| return lockedColumnHeader; |
| } |
| |
| /** |
| * @private |
| * automation |
| */ |
| mx_internal function get dataGridLockedColumnAndRows():ListBaseContentHolder |
| { |
| return lockedColumnAndRowContent; |
| } |
| |
| /** |
| * @private |
| * automation |
| */ |
| mx_internal function get dataGridLockedRows():ListBaseContentHolder |
| { |
| return lockedRowContent; |
| } |
| |
| /** |
| * @private |
| * automation |
| */ |
| mx_internal function get dataGridLockedColumns():ListBaseContentHolder |
| { |
| return lockedColumnContent; |
| } |
| |
| /** |
| * Flag specifying that the set of visible columns and/or their sizes needs to |
| * be recomputed. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal var columnsInvalid:Boolean = true; |
| |
| /** |
| * Flag specifying that the font context of the renderers need to |
| * be recomputed. |
| */ |
| mx_internal var fontContextChanged:Boolean = true; |
| |
| /** |
| * @private |
| * must be overridden by subclasses |
| */ |
| mx_internal function columnRendererChanged(c:DataGridColumn):void |
| { |
| } |
| |
| /** |
| * @private |
| * must be overridden by subclasses |
| */ |
| mx_internal function resizeColumn(col:int, w:Number):void |
| { |
| } |
| |
| // these three keep track of the key selection that caused |
| // the page fault |
| private var bShiftKey:Boolean = false; |
| private var bCtrlKey:Boolean = false; |
| private var lastKey:uint = 0; |
| private var bSelectItem:Boolean = false; |
| |
| private var inSelectItem:Boolean = false; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // columns |
| //---------------------------------- |
| |
| /** |
| * @private |
| * must be overridden by subclasses |
| */ |
| public function get columns():Array |
| { |
| return null; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set columns(value:Array):void |
| { |
| } |
| |
| //---------------------------------- |
| // fontContext |
| //---------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get fontContext():IFlexModuleFactory |
| { |
| return moduleFactory; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set fontContext(moduleFactory:IFlexModuleFactory):void |
| { |
| this.moduleFactory = moduleFactory; |
| } |
| |
| //---------------------------------- |
| // headerHeight |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the headerHeight property. |
| */ |
| mx_internal var _headerHeight:Number = 22; |
| |
| /** |
| * @private |
| */ |
| mx_internal var _explicitHeaderHeight:Boolean; |
| |
| [Bindable("resize")] |
| [Inspectable(category="General", defaultValue="22")] |
| |
| /** |
| * The height of the header cell of the column, in pixels. |
| * If set explicitly, that height will be used for all of |
| * the headers. If not set explicitly, |
| * the height will based on style settings and the header |
| * renderer. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get headerHeight():Number |
| { |
| return _headerHeight; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set headerHeight(value:Number):void |
| { |
| _headerHeight = value; |
| _explicitHeaderHeight = true; |
| itemsSizeChanged = true; |
| |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // lockedColumnCount |
| //---------------------------------- |
| |
| private var lockedColumnCountChanged:Boolean = false; |
| |
| /** |
| * @private |
| * Storage for the lockedColumnCount property. |
| */ |
| mx_internal var _lockedColumnCount:int = 0; |
| |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The index of the first column in the control that scrolls. |
| * Columns with indexes that are lower than this value remain fixed |
| * in view. Not supported by all list classes. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get lockedColumnCount():int |
| { |
| return _lockedColumnCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedColumnCount(value:int):void |
| { |
| _lockedColumnCount = value; |
| lockedColumnCountChanged = true; |
| itemsSizeChanged = true; |
| |
| columnsInvalid = true; |
| |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // lockedRowCount |
| //---------------------------------- |
| |
| private var lockedRowCountChanged:Boolean = false; |
| |
| /** |
| * @private |
| * Storage for the lockedRowCount property. |
| */ |
| mx_internal var _lockedRowCount:int = 0; |
| |
| [Inspectable(defaultValue="0")] |
| |
| /** |
| * The index of the first row in the control that scrolls. |
| * Rows above this one remain fixed in view. |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get lockedRowCount():int |
| { |
| return _lockedRowCount; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set lockedRowCount(value:int):void |
| { |
| _lockedRowCount = value; |
| lockedRowCountChanged = true; |
| itemsSizeChanged = true; |
| |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // showHeaders |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the showHeaders property. |
| */ |
| private var _showHeaders:Boolean = true; |
| |
| [Bindable("showHeadersChanged")] |
| [Inspectable(category="General", defaultValue="true")] |
| |
| /** |
| * A flag that indicates whether the control should show |
| * column headers. |
| * If <code>true</code>, the control shows column headers. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function get showHeaders():Boolean |
| { |
| return _showHeaders; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showHeaders(value:Boolean):void |
| { |
| if (value == _showHeaders) |
| return; |
| |
| _showHeaders = value; |
| itemsSizeChanged = true; |
| |
| invalidateDisplayList(); |
| |
| dispatchEvent(new Event("showHeadersChanged")); |
| } |
| |
| /** |
| * @private |
| * headers are not renderered if showHeaders = false |
| * or headerheight = 0, so this test is whether row0 is |
| * a header or not. |
| */ |
| mx_internal function get headerVisible():Boolean |
| { |
| return showHeaders && (headerHeight > 0); |
| } |
| |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Sizes and positions the column headers, columns, and items based on the |
| * size of the DataGrid. |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| if (header) |
| { |
| header.visibleColumns = visibleColumns; |
| header.headerItemsChanged = true; |
| header.invalidateSize(); |
| header.validateNow(); |
| } |
| |
| if (lockedColumnCountChanged) |
| { |
| lockedColumnCountChanged = false; |
| |
| if (lockedColumnCount > 0) |
| { |
| if (!lockedColumnContent) |
| { |
| lockedColumnHeader = new headerClass(); |
| lockedColumnHeader.styleName = this; |
| addChild(lockedColumnHeader); |
| lockedColumnAndRowContent = new DataGridLockedRowContentHolder(this); |
| lockedColumnAndRowContent.styleName = this; |
| addChild(lockedColumnAndRowContent) |
| lockedColumnContent = new ListBaseContentHolder(this); |
| lockedColumnContent.styleName = this; |
| addChild(lockedColumnContent); |
| } |
| |
| lockedColumnHeader.visible = true; |
| lockedColumnAndRowContent.visible = (lockedRowCount > 0); |
| lockedColumnContent.visible = true; |
| } |
| else |
| { |
| if (lockedColumnContent) |
| { |
| lockedColumnHeader.visible = false; |
| lockedColumnAndRowContent.visible = false; |
| lockedColumnContent.visible = false; |
| } |
| } |
| } |
| |
| if (lockedRowCountChanged && iterator) |
| { |
| lockedRowCountChanged = false; |
| |
| if (lockedRowCount > 0) |
| { |
| if (!lockedRowContent) |
| { |
| lockedRowContent = new DataGridLockedRowContentHolder(this); |
| lockedRowContent.styleName = this; |
| addChild(lockedRowContent); |
| } |
| lockedRowContent.visible = true; |
| } |
| else |
| { |
| if (lockedRowContent) |
| lockedRowContent.visible = false; |
| } |
| |
| if (lockedColumnAndRowContent) |
| lockedColumnAndRowContent.visible = (lockedRowCount > 0 && lockedColumnCount > 0); |
| |
| seekPositionSafely(lockedRowCount + verticalScrollPosition); |
| } |
| |
| // ensure lockedColumnAndRowContent above other content |
| var ci:int; |
| var lcri:int; |
| if (lockedRowContent && lockedColumnAndRowContent) |
| { |
| lcri = getChildIndex(lockedColumnAndRowContent); |
| ci = getChildIndex(lockedRowContent); |
| if (lcri < ci) |
| setChildIndex(lockedRowContent, lcri); |
| } |
| if (lockedColumnContent && lockedColumnAndRowContent) |
| { |
| lcri = getChildIndex(lockedColumnAndRowContent); |
| ci = getChildIndex(lockedColumnContent); |
| if (lcri < ci) |
| setChildIndex(lockedColumnContent, lcri); |
| } |
| if (headerVisible && lockedColumnHeader) |
| { |
| lockedColumnHeader.visibleColumns = visibleLockedColumns; |
| lockedColumnHeader.headerItemsChanged = true; |
| lockedColumnHeader.invalidateSize(); |
| lockedColumnHeader.validateNow(); |
| } |
| |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function makeRowsAndColumns(left:Number, top:Number, |
| right:Number, bottom:Number, |
| firstCol:int, firstRow:int, |
| byCount:Boolean = false, rowsNeeded:uint = 0):Point |
| { |
| // trace(this, "makeRowsAndColumns " + left + " " + top + " " + right + " " + bottom + " " + firstCol + " " + firstRow); |
| return makeRows(listContent, left, top, right, bottom, firstCol, firstRow, byCount, rowsNeeded); |
| } |
| |
| /** |
| * @private |
| */ |
| protected function makeRows(contentHolder:ListBaseContentHolder, |
| left:Number, top:Number, |
| right:Number, bottom:Number, |
| firstCol:int, firstRow:int, |
| byCount:Boolean = false, rowsNeeded:uint = 0, |
| alwaysCleanup:Boolean = false):Point |
| { |
| var xx:Number; |
| var yy:Number; |
| var hh:Number; |
| |
| var bSelected:Boolean = false; |
| var bHighlight:Boolean = false; |
| var bCaret:Boolean = false; |
| |
| var i:int; |
| var j:int; |
| var n:int; |
| |
| var colNum:int = 0; |
| var rowNum:int = 0; |
| var rowsMade:int = 0; |
| |
| var item:IListItemRenderer; |
| var listItems:Array = contentHolder.listItems; |
| var iterator:IViewCursor = contentHolder.iterator; |
| var visibleData:Object = contentHolder.visibleData; |
| var rowInfo:Object = contentHolder.rowInfo; |
| |
| // bail if we have no columns |
| if ((!visibleColumns || visibleColumns.length == 0) && lockedColumnCount == 0) |
| { |
| while (listItems.length) |
| { |
| rowNum = listItems.length - 1; |
| while (listItems[rowNum].length) |
| { |
| // remove extra columns |
| item = listItems[rowNum].pop(); |
| addToFreeItemRenderers(item); |
| } |
| listItems.pop(); |
| } |
| contentHolder.visibleData = {}; |
| return new Point(0,0); |
| } |
| |
| invalidateSizeFlag = true; |
| |
| var data:Object; |
| var uid:String; |
| var more:Boolean = true; |
| var valid:Boolean = true; |
| |
| yy = top; |
| rowNum = firstRow; |
| more = (iterator != null && !iterator.afterLast && iteratorValid); |
| while ((!byCount && yy < bottom) || (byCount && rowsNeeded > 0)) |
| { |
| if (byCount) |
| rowsNeeded--; |
| |
| valid = more; |
| data = more ? iterator.current : null; |
| if (iterator && more) |
| { |
| try |
| { |
| more = iterator.moveNext(); |
| } |
| catch(e:ItemPendingError) |
| { |
| //AJH commented out to fix one bug. We'll see if it causes others |
| //lastSeekPending = new ListBaseSeekPending(CursorBookmark.CURRENT, 0) |
| //e.addResponder(new ItemResponder(seekPendingResultHandler, seekPendingFailureHandler, |
| // lastSeekPending)); |
| more = false; |
| iteratorValid = false; |
| } |
| } |
| |
| hh = 0; |
| uid = null; |
| |
| prepareRowArray(contentHolder, rowNum); |
| |
| if (valid) |
| { |
| uid = itemToUID(data); |
| hh = makeRow(contentHolder, rowNum, left, right, yy, data, uid); |
| } |
| else |
| { |
| hh = rowNum > 1 ? rowInfo[rowNum - 1].height : rowHeight; |
| } |
| if (valid && variableRowHeight) |
| { |
| hh = Math.ceil(calculateRowHeight(data, hh, true)); |
| } |
| if (valid) |
| adjustRow(contentHolder, rowNum, yy, hh); |
| else |
| clearRow(contentHolder, rowNum); |
| |
| bSelected = isItemSelectable(data) && isItemSelected(uid); |
| bHighlight = highlightUID == uid; |
| bCaret = caretUID == uid; |
| setRowInfo(contentHolder, rowNum, yy, hh, uid); |
| // trace("rowNum = " + rowNum); |
| if (valid) |
| drawVisibleItem(uid, bSelected, bHighlight, bCaret); |
| if (hh == 0) // hh can be zero if we had zero width |
| hh = rowHeight; |
| yy += hh; |
| rowNum++; |
| rowsMade++; |
| } |
| // byCount means we're making rows and wont get all the way to the bottom |
| // so we skip this cleanup pass |
| if (!byCount || alwaysCleanup) |
| { |
| // trace("MakeRowsAndColumns rowNum = " + rowNum); |
| // delete extra rows |
| while (rowNum < listItems.length) |
| { |
| removeExtraRow(contentHolder); |
| } |
| } |
| // trace("MakeRowsAndColumns listItems.length = " + listItems.length); |
| |
| invalidateSizeFlag = false; |
| |
| return new Point(colNum, rowsMade); |
| } |
| |
| /** |
| * Ensures that there is a slot in the row arrays for the given row number. |
| * |
| * @param contentHolder The set of rows (locked rows, regular rows). |
| * |
| * @param rowNum The row number. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function prepareRowArray(contentHolder:ListBaseContentHolder, rowNum:int):void |
| { |
| var listItems:Array = contentHolder.listItems; |
| var columnContent:ListBaseContentHolder; |
| |
| if (lockedColumnCount > 0) |
| { |
| if (contentHolder == lockedRowContent) |
| columnContent = lockedColumnAndRowContent; |
| else |
| columnContent = lockedColumnContent; |
| } |
| else |
| columnContent = null; |
| |
| |
| if (!listItems[rowNum]) |
| listItems[rowNum] = []; |
| if (columnContent) |
| if (!columnContent.listItems[rowNum]) |
| columnContent.listItems[rowNum] = []; |
| } |
| |
| /** |
| * Creates the renderers for the given rowNum, dataObject and uid. |
| * |
| * @param contentHolder The set of rows (locked rows, regular rows). |
| * @param rowNum The row number. |
| * @param left The offset from the left side for the first column. |
| * @param right The offset from the right side for the last column. |
| * @param yy The y position of the row. |
| * @param data The data for the row. |
| * @param uid The uid for the data. |
| * |
| * @return Height of the row. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function makeRow(contentHolder:ListBaseContentHolder, rowNum:int, left:Number, right:Number, yy:Number, data:Object, uid:String):Number |
| { |
| var listItems:Array = contentHolder.listItems; |
| var columnContent:ListBaseContentHolder; |
| var item:IListItemRenderer; |
| var extraItem:IListItemRenderer; |
| var c:DataGridColumn; |
| var itemSize:Point; |
| |
| if (lockedColumnCount > 0) |
| { |
| if (contentHolder == lockedRowContent) |
| columnContent = lockedColumnAndRowContent; |
| else |
| columnContent = lockedColumnContent; |
| } |
| else |
| columnContent = null; |
| |
| var colNum:int = 0; |
| var xx:Number = left; |
| var hh:Number = 0; |
| |
| while (colNum < visibleLockedColumns.length) |
| { |
| c = visibleLockedColumns[colNum]; |
| item = setupColumnItemRenderer(c, columnContent, rowNum, colNum, data, uid); |
| itemSize = layoutColumnItemRenderer(c, item, xx, yy); |
| xx += itemSize.x; |
| colNum++; |
| hh = Math.ceil(Math.max(hh, variableRowHeight ? itemSize.y + cachedPaddingTop + cachedPaddingBottom : rowHeight)); |
| } |
| if (visibleLockedColumns.length) |
| { |
| while (columnContent.listItems[rowNum].length > colNum) |
| { |
| // remove extra columns |
| extraItem = columnContent.listItems[rowNum].pop(); |
| addToFreeItemRenderers(extraItem); |
| } |
| } |
| colNum = 0; |
| xx = left; |
| while (xx < right && colNum < visibleColumns.length) |
| { |
| c = visibleColumns[colNum]; |
| item = setupColumnItemRenderer(c, contentHolder, rowNum, colNum, data, uid); |
| itemSize = layoutColumnItemRenderer(c, item, xx, yy); |
| xx += itemSize.x; |
| colNum++; |
| hh = Math.ceil(Math.max(hh, variableRowHeight ? itemSize.y + cachedPaddingTop + cachedPaddingBottom : rowHeight)); |
| } |
| while (listItems[rowNum].length > colNum) |
| { |
| // remove extra columns |
| extraItem = listItems[rowNum].pop(); |
| addToFreeItemRenderers(extraItem); |
| } |
| |
| return hh; |
| } |
| |
| /** |
| * Removes renderers from a row that should be empty for the given rowNum. |
| * |
| * @param contentHolder The set of rows (locked rows, regular rows). |
| * @param rowNum The row number. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function clearRow(contentHolder:ListBaseContentHolder, rowNum:int):void |
| { |
| var listItems:Array = contentHolder.listItems; |
| var columnContent:ListBaseContentHolder; |
| var extraItem:IListItemRenderer; |
| |
| if (lockedColumnCount > 0) |
| { |
| if (contentHolder == lockedRowContent) |
| columnContent = lockedColumnAndRowContent; |
| else |
| columnContent = lockedColumnContent; |
| } |
| else |
| columnContent = null; |
| |
| while (listItems[rowNum].length) |
| { |
| // remove extra columns |
| extraItem = listItems[rowNum].pop(); |
| addToFreeItemRenderers(extraItem); |
| } |
| if (columnContent) |
| { |
| while (columnContent.listItems[rowNum].length) |
| { |
| // remove extra columns |
| extraItem = columnContent.listItems[rowNum].pop(); |
| addToFreeItemRenderers(extraItem); |
| } |
| } |
| |
| } |
| |
| /** |
| * Adjusts the size and positions of the renderers for the given rowNum, row position and height. |
| * |
| * @param contentHolder The set of rows (locked rows, regular rows). |
| * @param rowNum The row number. |
| * @param yy The y position of the row. |
| * @param hh The height of the row. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function adjustRow(contentHolder:ListBaseContentHolder, rowNum:int, yy:Number, hh:Number):void |
| { |
| var listItems:Array = contentHolder.listItems; |
| var columnContent:ListBaseContentHolder; |
| var i:int; |
| var j:int; |
| var n:int; |
| var colNum:int; |
| var item:IListItemRenderer; |
| |
| if (lockedColumnCount > 0) |
| { |
| if (contentHolder == lockedRowContent) |
| columnContent = lockedColumnAndRowContent; |
| else |
| columnContent = lockedColumnContent; |
| } |
| else |
| columnContent = null; |
| |
| if (listItems[rowNum]) |
| { |
| if (columnContent) |
| { |
| n = columnContent.listItems[rowNum].length; |
| for (j = 0; j < n; j++) |
| columnContent.listItems[rowNum][j].setActualSize( |
| columnContent.listItems[rowNum][j].width, |
| hh - cachedPaddingTop - cachedPaddingBottom); |
| } |
| n = listItems[rowNum].length; |
| for (j = 0; j < n; j++) |
| listItems[rowNum][j].setActualSize( |
| listItems[rowNum][j].width, |
| hh - cachedPaddingTop - cachedPaddingBottom); |
| } |
| if (cachedVerticalAlign != "top") |
| { |
| if (cachedVerticalAlign == "bottom") |
| { |
| colNum = listItems[rowNum].length; |
| for (j = 0; j < colNum; j++) |
| { |
| item = listItems[rowNum][j]; |
| item.move(item.x, yy + hh - cachedPaddingBottom - item.getExplicitOrMeasuredHeight()); |
| } |
| if (columnContent) |
| { |
| n = columnContent.listItems[rowNum].length |
| for (j = 0; j < n; j++) |
| { |
| item = columnContent.listItems[rowNum][j]; |
| item.move(item.x, yy + hh - cachedPaddingBottom - item.getExplicitOrMeasuredHeight()); |
| } |
| } |
| } |
| else |
| { |
| colNum = listItems[rowNum].length; |
| for (j = 0; j < colNum; j++) |
| { |
| item = listItems[rowNum][j]; |
| item.move(item.x, yy + cachedPaddingTop + (hh - cachedPaddingBottom - cachedPaddingTop - item.getExplicitOrMeasuredHeight()) / 2); |
| } |
| if (columnContent) |
| { |
| n = columnContent.listItems[rowNum].length |
| for (j = 0; j < n; j++) |
| { |
| item = columnContent.listItems[rowNum][j]; |
| item.move(item.x, yy + cachedPaddingTop + (hh - cachedPaddingBottom - cachedPaddingTop - item.getExplicitOrMeasuredHeight()) / 2); |
| } |
| } |
| } |
| |
| } |
| } |
| |
| /** |
| * Sets the rowInfo for the given rowNum, row position and height. |
| * |
| * @param contentHolder The set of rows (locked rows, regular rows). |
| * @param rowNum The row number. |
| * @param yy The y position of the row. |
| * @param hh The height of the row. |
| * @param uid The UID for the data. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function setRowInfo(contentHolder:ListBaseContentHolder, rowNum:int, yy:Number, hh:Number, uid:String):void |
| { |
| var listItems:Array = contentHolder.listItems; |
| var rowInfo:Object = contentHolder.rowInfo; |
| var columnContent:ListBaseContentHolder; |
| if (lockedColumnCount > 0) |
| { |
| if (contentHolder == lockedRowContent) |
| columnContent = lockedColumnAndRowContent; |
| else |
| columnContent = lockedColumnContent; |
| } |
| else |
| columnContent = null; |
| |
| rowInfo[rowNum] = new ListRowInfo(yy, hh, uid); |
| if (columnContent) |
| columnContent.rowInfo[rowNum] = rowInfo[rowNum]; |
| } |
| |
| /** |
| * Removes extra row from the end of the contentHolder. |
| * |
| * @param contentHolder The set of rows (locked rows, regular rows). |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function removeExtraRow(contentHolder:ListBaseContentHolder):void |
| { |
| var item:IListItemRenderer; |
| var listItems:Array = contentHolder.listItems; |
| var rowInfo:Object = contentHolder.rowInfo; |
| var columnContent:ListBaseContentHolder; |
| if (contentHolder == lockedRowContent) |
| columnContent = lockedColumnAndRowContent; |
| else |
| columnContent = lockedColumnContent; |
| |
| var rr:Array = listItems.pop(); |
| rowInfo.pop(); |
| while (rr.length) |
| { |
| item = rr.pop(); |
| addToFreeItemRenderers(item); |
| } |
| if (columnContent) |
| { |
| columnContent.rowInfo.pop(); |
| rr = columnContent.listItems.pop(); |
| while (rr && rr.length) |
| { |
| item = rr.pop(); |
| addToFreeItemRenderers(item); |
| } |
| } |
| } |
| |
| /** |
| * Sets up an item renderer for a column and put it in the listItems array |
| * at the requested position. |
| * |
| * @param c The DataGridColumn for the renderer. |
| * @param contentHolder The set of rows (locked rows, regular rows). |
| * @param rowNum The row number. |
| * @param colNum The column number. |
| * @param data The data for the row. |
| * @param uid The uid for the data. |
| * |
| * @return The renderer for this column and row. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function setupColumnItemRenderer(c:DataGridColumn, contentHolder:ListBaseContentHolder, |
| rowNum:int, colNum:int, data:Object, uid:String):IListItemRenderer |
| { |
| var listItems:Array = contentHolder.listItems; |
| var item:IListItemRenderer; |
| var rowData:DataGridListData; |
| |
| item = listItems[rowNum][colNum]; |
| if (!item || itemToUID(item.data) != uid |
| || columnMap[item.name] != c) |
| { |
| item = createColumnItemRenderer(c, false, data); |
| if (item == null) |
| return null; |
| if (item.parent != contentHolder) |
| contentHolder.addChild(DisplayObject(item)); |
| |
| // a space is used if no data so text widgets get some default size |
| columnMap[item.name] = c; |
| if (listItems[rowNum][colNum]) |
| addToFreeItemRenderers(listItems[rowNum][colNum]); |
| listItems[rowNum][colNum] = item; |
| } |
| |
| //[Matt] moved from inside the block above to outside because |
| //the item definitely exists at this point, and always needs |
| //its data refreshed |
| rowData = DataGridListData(makeListData(data, uid, rowNum, c.colNum, c)); |
| rowMap[item.name] = rowData; |
| if (item is IDropInListItemRenderer) |
| IDropInListItemRenderer(item).listData = data ? rowData : null; |
| item.data = data; |
| item.visible = true; |
| if (uid && colNum == 0) |
| contentHolder.visibleData[uid] = item; |
| return item; |
| } |
| |
| /** |
| * Sizes and temporarily positions an itemRenderer for a column, returning its size as a Point. |
| * The final position might be adjusted later due to alignment settings. |
| * |
| * @param c The DataGridColumn for the renderer. |
| * @param item The renderer. |
| * @param xx The x position. |
| * @param yy The y position. |
| * |
| * @return Size of the renderer as a Point. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function layoutColumnItemRenderer(c:DataGridColumn, item:IListItemRenderer, xx:Number, yy:Number):Point |
| { |
| var ww:Number = 0; |
| var rh:Number = 0; |
| if (item) |
| { |
| item.explicitWidth = ww = getWidthOfItem(item, c); |
| UIComponentGlobals.layoutManager.validateClient(item, true); |
| rh = item.getExplicitOrMeasuredHeight(); |
| item.setActualSize(ww, variableRowHeight |
| ? item.getExplicitOrMeasuredHeight() |
| : rowHeight - cachedPaddingTop - cachedPaddingBottom); |
| item.move(xx, yy + cachedPaddingTop); |
| } |
| return new Point(ww, rh); |
| } |
| |
| /** |
| * Draws an item if it is visible. |
| * |
| * @param uid The uid used to find the renderer. |
| * @param selected <code>true</code> if the renderer should be drawn in |
| * its selected state. |
| * @param highlighted <code>true</code> if the renderer should be drawn in |
| * its highlighted state. |
| * @param caret <code>true</code> if the renderer should be drawn as if |
| * it is the selection caret. |
| * @param transition <code>true</code> if the selection state should fade in |
| * via an effect. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function drawVisibleItem(uid:String, |
| selected:Boolean = false, |
| highlighted:Boolean = false, |
| caret:Boolean = false, |
| transition:Boolean = false):void |
| { |
| if (visibleData[uid]) |
| drawItem(visibleData[uid], selected, highlighted, caret, transition); |
| if (lockedRowCount && lockedRowContent && lockedRowContent.visibleData[uid]) |
| drawItem(lockedRowContent.visibleData[uid], selected, highlighted, caret, transition); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function drawItem(item:IListItemRenderer, |
| selected:Boolean = false, |
| highlighted:Boolean = false, |
| caret:Boolean = false, |
| transition:Boolean = false):void |
| { |
| if (!item) |
| return; |
| |
| super.drawItem(item, selected, highlighted, caret, transition); |
| |
| var rowIndex:int = rowMap[item.name].rowIndex; |
| |
| var i:int; |
| var r:IListItemRenderer; |
| |
| for (i = 0; i < visibleColumns.length; i++) |
| { |
| r = (item.parent as ListBaseContentHolder).listItems[rowIndex][i]; |
| updateRendererDisplayList(r); |
| } |
| |
| if (lockedColumnCount) |
| { |
| var columnContents:ListBaseContentHolder; |
| if ((item.parent == listContent) || (item.parent == lockedColumnContent)) |
| columnContents = lockedColumnContent; |
| else |
| columnContents = lockedColumnAndRowContent; |
| |
| for (i = 0; i < visibleLockedColumns.length; i++) |
| { |
| r = columnContents.listItems[rowIndex][i]; |
| updateRendererDisplayList(r); |
| } |
| } |
| } |
| |
| /** |
| * Redraws the renderer synchronously. |
| * |
| * @param r The renderer; |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function updateRendererDisplayList(r:IListItemRenderer):void |
| { |
| if (r is IInvalidating) |
| { |
| var ui:IInvalidating = IInvalidating(r); |
| ui.invalidateDisplayList(); |
| ui.validateNow(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function addToFreeItemRenderers(item:IListItemRenderer):void |
| { |
| // trace("putting " + item + " on free list"); |
| DisplayObject(item).visible = false; |
| |
| delete rowMap[item.name]; |
| var factory:IFactory = factoryMap[item]; |
| |
| // Only delete from visibleData if we are freeing the renderer for |
| // the first visible column |
| var UID:String = itemToUID(item.data); |
| var visibleData:Object = ListBaseContentHolder(item.parent).visibleData; |
| if (visibleData[UID] == item) |
| delete visibleData[UID]; |
| |
| if (columnMap[item.name]) |
| { |
| var c:DataGridColumn = columnMap[item.name]; |
| if (factory == c.itemRenderer) |
| { |
| if (freeItemRenderersTable[c] == undefined) |
| freeItemRenderersTable[c] = []; |
| freeItemRenderersTable[c].push(item); |
| } |
| if (!c.freeItemRenderersByFactory) |
| c.freeItemRenderersByFactory = new Dictionary(true); |
| if (c.freeItemRenderersByFactory[factory] == undefined) |
| c.freeItemRenderersByFactory[factory] = new Dictionary(true); |
| c.freeItemRenderersByFactory[factory][item] = 1; |
| |
| delete columnMap[item.name]; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function purgeItemRenderers():void |
| { |
| var listItems:Array; |
| var row:Array; |
| var item:IListItemRenderer; |
| |
| if (lockedRowContent) |
| { |
| listItems = lockedRowContent.listItems; |
| while (listItems.length) |
| { |
| row = listItems.pop(); |
| while (row.length) |
| { |
| item = IListItemRenderer(row.pop()); |
| if (item) |
| { |
| lockedRowContent.removeChild(DisplayObject(item)); |
| delete lockedRowContent.visibleData[itemToUID(item.data)]; |
| } |
| } |
| } |
| } |
| if (lockedColumnContent) |
| { |
| listItems = lockedColumnContent.listItems; |
| while (listItems.length) |
| { |
| row = listItems.pop(); |
| while (row.length) |
| { |
| item = IListItemRenderer(row.pop()); |
| if (item) |
| { |
| lockedColumnContent.removeChild(DisplayObject(item)); |
| delete lockedColumnContent.visibleData[itemToUID(item.data)]; |
| } |
| } |
| } |
| } |
| if (lockedColumnAndRowContent) |
| { |
| listItems = lockedColumnAndRowContent.listItems; |
| while (listItems.length) |
| { |
| row = listItems.pop(); |
| while (row.length) |
| { |
| item = IListItemRenderer(row.pop()); |
| if (item) |
| { |
| lockedColumnAndRowContent.removeChild(DisplayObject(item)); |
| delete lockedColumnAndRowContent.visibleData[itemToUID(item.data)]; |
| } |
| } |
| } |
| } |
| |
| super.purgeItemRenderers(); |
| } |
| |
| /** |
| * @private |
| */ |
| override public function indicesToIndex(rowIndex:int, colIndex:int):int |
| { |
| if (inSelectItem) |
| return 0; |
| |
| return rowIndex; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Creates a new DataGridListData instance and populates the fields based on |
| * the input data provider item. |
| * |
| * @param data The data provider item used to populate the ListData. |
| * @param uid The UID for the item. |
| * @param rowNum The index of the item in the data provider. |
| * @param columnNum The columnIndex associated with this item. |
| * @param column The column associated with this item. |
| * |
| * @return A newly constructed ListData object. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function makeListData(data:Object, uid:String, |
| rowNum:int, columnNum:int, column:DataGridColumn):BaseListData |
| { |
| if (data is DataGridColumn) |
| { |
| return new DataGridListData((column.headerText != null) ? column.headerText : column.dataField, |
| column.dataField, columnNum, uid, this, rowNum); |
| } |
| else |
| { |
| return new DataGridListData(column.itemToLabel(data), column.dataField, |
| columnNum, uid, this, rowNum); |
| } |
| } |
| |
| /** |
| * @private |
| * This grid just returns the column size, |
| * but could handle column spanning. |
| */ |
| mx_internal function getWidthOfItem(item:IListItemRenderer, |
| col:DataGridColumn):Number |
| { |
| return col.width; |
| } |
| |
| /** |
| * Calculates the row height of columns in a row. |
| * If <code>skipVisible</code> is <code>true></code>, |
| * the DataGridBase already knows the height of |
| * the renderers for the column that do fit in the display area |
| * so this method only needs to calculate for the item renderers |
| * that would exist if other columns in that row were in the |
| * display area. This is needed so that if the user scrolls |
| * horizontally, the height of the row does not adjust as different |
| * columns appear and disappear. |
| * |
| * @param data The data provider item for the row. |
| * |
| * @param hh The current height of the row. |
| * |
| * @param skipVisible If <code>true</code>, there is no need to measure item |
| * renderers in visible columns. |
| * |
| * @return The row height, in pixels. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected function calculateRowHeight(data:Object, hh:Number, skipVisible:Boolean = false):Number |
| { |
| return NaN; |
| } |
| |
| /** |
| * Returns the item renderer for a column cell or for a column header. |
| * This method returns the default item renderer if no custom render is assigned |
| * to the column. |
| * |
| * <p>This method is public so that is can be accessed by the DataGridHeader class, |
| * and is primarily used in subclasses of the DataGrid control.</p> |
| * |
| * @param c The DataGridColumn instance of the item renderer. |
| * |
| * @param forHeader <code>true</code> to return the header item renderer, |
| * and <code>false</code> to return the item render for the column cells. |
| * |
| * @param data If <code>forHeader</code> is <code>false</code>, |
| * the <code>data</code> Object for the item renderer. |
| * If <code>forHeader</code> is <code>true</code>, |
| * the DataGridColumn instance. |
| * |
| * @return The item renderer. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function createColumnItemRenderer(c:DataGridColumn, forHeader:Boolean, data:Object):IListItemRenderer |
| { |
| var factory:IFactory; |
| |
| // get the factory for the data |
| factory = c.getItemRendererFactory(forHeader, data); |
| if (!factory) |
| { |
| if (data == null) |
| factory = nullItemRenderer; |
| if (!factory) |
| factory = itemRenderer; |
| } |
| |
| var renderer:IListItemRenderer; |
| |
| // if it is the default column factory, see if |
| // the freeItemRenderersTable has a free one |
| if (factory == c.itemRenderer) |
| { |
| if (freeItemRenderersTable[c] && freeItemRenderersTable[c].length) |
| { |
| renderer = freeItemRenderersTable[c].pop(); |
| delete c.freeItemRenderersByFactory[factory][renderer]; |
| } |
| } |
| else if (c.freeItemRenderersByFactory) |
| { |
| // other re-usable renderers are in the FactoryMap |
| var d:Dictionary = c.freeItemRenderersByFactory[factory]; |
| if (d) |
| { |
| for (var p:* in d) |
| { |
| renderer = IListItemRenderer(p); |
| delete d[p]; |
| break; |
| } |
| } |
| } |
| |
| if (!renderer ) |
| { |
| renderer = factory.newInstance(); |
| if (renderer) |
| { |
| renderer.styleName = c; |
| factoryMap[renderer] = factory; |
| } |
| } |
| |
| |
| if (renderer) |
| renderer.owner = this; |
| return renderer; |
| } |
| |
| /** |
| * Gets the headerWordWrap for a column, using the default wordWrap if none is specified. |
| * |
| * @param c The column to get the headerWordWrap for. |
| * |
| * @return <code>true</code> if the value of the column's <code>headerWordWrap</code> property is <code>true</code>, or |
| * <code>false</code> if the value is <code>false</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal function columnHeaderWordWrap(c:DataGridColumn):Boolean |
| { |
| if (c.headerWordWrap == true) |
| return true; |
| if (c.headerWordWrap == false) |
| return false; |
| |
| return wordWrap; |
| } |
| |
| /** |
| * Gets the wordWrap for a column, using the default wordWrap if none is specified. |
| * |
| * @param c The column to get the wordWrap for. |
| * |
| * @return <code>true</code> if the value of the column's <code>wordWrap</code> property is <code>true</code>, or |
| * <code>false</code> if the value is <code>false</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal function columnWordWrap(c:DataGridColumn):Boolean |
| { |
| if (c.wordWrap == true) |
| return true; |
| if (c.wordWrap == false) |
| return false; |
| |
| return wordWrap; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function clearIndicators():void |
| { |
| super.clearIndicators(); |
| if (lockedColumnCount && lockedColumnContent) |
| { |
| while (lockedColumnContent.selectionLayer.numChildren > 0) |
| { |
| lockedColumnContent.selectionLayer.removeChildAt(0); |
| } |
| } |
| if (lockedRowCount && lockedRowContent) |
| { |
| while (lockedRowContent.selectionLayer.numChildren > 0) |
| { |
| lockedRowContent.selectionLayer.removeChildAt(0); |
| } |
| if (lockedColumnCount && lockedColumnAndRowContent) |
| { |
| while (lockedColumnAndRowContent.selectionLayer.numChildren > 0) |
| { |
| lockedColumnAndRowContent.selectionLayer.removeChildAt(0); |
| } |
| } |
| } |
| if (header) |
| header.clearSelectionLayer(); |
| if (lockedColumnHeader) |
| lockedColumnHeader.clearSelectionLayer(); |
| |
| } |
| |
| /** |
| * The DisplayObject that contains the graphics that indicates |
| * which renderer is highlighted for lockedColumns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var columnHighlightIndicator:Sprite; |
| |
| /** |
| * The DisplayObject that contains the graphics that indicates |
| * which renderer is the caret for lockedColumns. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| protected var columnCaretIndicator:Sprite; |
| |
| /** |
| * @private |
| */ |
| override protected function drawHighlightIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void |
| { |
| super.drawHighlightIndicator(indicator, x, y, unscaledWidth - viewMetrics.left - viewMetrics.right, height, color, itemRenderer); |
| if (lockedColumnCount) |
| { |
| var columnContents:ListBaseContentHolder; |
| if (itemRenderer.parent == listContent) |
| columnContents = lockedColumnContent; |
| else |
| columnContents = lockedColumnAndRowContent; |
| var selectionLayer:Sprite = columnContents.selectionLayer; |
| |
| if (!columnHighlightIndicator) |
| { |
| columnHighlightIndicator = new SpriteAsset(); |
| columnContents.selectionLayer.addChild(DisplayObject(columnHighlightIndicator)); |
| } |
| else |
| { |
| if (columnHighlightIndicator.parent != selectionLayer) |
| selectionLayer.addChild(columnHighlightIndicator); |
| else |
| selectionLayer.setChildIndex(DisplayObject(columnHighlightIndicator), |
| selectionLayer.numChildren - 1); |
| } |
| |
| // Let the columnHighlightIndicator inherit the layoutDirection |
| if (columnHighlightIndicator is ILayoutDirectionElement) |
| ILayoutDirectionElement(columnHighlightIndicator).layoutDirection = null; |
| |
| super.drawHighlightIndicator(columnHighlightIndicator, x, y, columnContents.width, height, color, itemRenderer); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function clearHighlightIndicator(indicator:Sprite, itemRenderer:IListItemRenderer):void |
| { |
| super.clearHighlightIndicator(indicator, itemRenderer); |
| if (lockedColumnCount) |
| { |
| if (columnHighlightIndicator) |
| Sprite(columnHighlightIndicator).graphics.clear(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function drawCaretIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void |
| { |
| super.drawCaretIndicator(indicator, x, y, unscaledWidth - viewMetrics.left - viewMetrics.right, height, color, itemRenderer); |
| if (lockedColumnCount) |
| { |
| var columnContents:ListBaseContentHolder; |
| if (itemRenderer.parent == listContent) |
| columnContents = lockedColumnContent; |
| else |
| columnContents = lockedColumnAndRowContent; |
| var selectionLayer:Sprite = columnContents.selectionLayer; |
| |
| if (!columnCaretIndicator) |
| { |
| columnCaretIndicator = new SpriteAsset(); |
| columnContents.selectionLayer.addChild(DisplayObject(columnCaretIndicator)); |
| } |
| else |
| { |
| if (columnCaretIndicator.parent != selectionLayer) |
| selectionLayer.addChild(columnCaretIndicator); |
| else |
| selectionLayer.setChildIndex(DisplayObject(columnCaretIndicator), |
| selectionLayer.numChildren - 1); |
| } |
| |
| // Let the columnCaretIndicator inherit the layoutDirection |
| if (columnCaretIndicator is ILayoutDirectionElement) |
| ILayoutDirectionElement(columnCaretIndicator).layoutDirection = null; |
| |
| super.drawCaretIndicator(columnCaretIndicator, x, y, columnContents.width, height, color, itemRenderer); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function clearCaretIndicator(indicator:Sprite, itemRenderer:IListItemRenderer):void |
| { |
| super.clearCaretIndicator(indicator, itemRenderer); |
| if (lockedColumnCount) |
| { |
| if (columnCaretIndicator) |
| Sprite(columnCaretIndicator).graphics.clear(); |
| } |
| } |
| |
| private var indicatorDictionary:Dictionary = new Dictionary(true); |
| |
| /** |
| * @private |
| */ |
| override protected function drawSelectionIndicator(indicator:Sprite, x:Number, y:Number, width:Number, height:Number, color:uint, itemRenderer:IListItemRenderer):void |
| { |
| super.drawSelectionIndicator(indicator, x, y, unscaledWidth - viewMetrics.left - viewMetrics.right, height, color, itemRenderer); |
| if (lockedColumnCount) |
| { |
| var columnContents:ListBaseContentHolder; |
| if (itemRenderer.parent == listContent) |
| columnContents = lockedColumnContent; |
| else |
| columnContents = lockedColumnAndRowContent; |
| var selectionLayer:Sprite = columnContents.selectionLayer; |
| |
| var columnIndicator:Sprite = indicatorDictionary[indicator] as Sprite; |
| if (!columnIndicator) |
| { |
| columnIndicator = new SpriteAsset(); |
| columnIndicator.mouseEnabled = false; |
| selectionLayer.addChild(DisplayObject(columnIndicator)); |
| indicator.parent.addEventListener(Event.REMOVED, selectionRemovedListener); |
| indicatorDictionary[indicator] = columnIndicator; |
| } |
| |
| // Let the columnIndicator inherit the layoutDirection |
| if (columnIndicator is ILayoutDirectionElement) |
| ILayoutDirectionElement(columnIndicator).layoutDirection = null; |
| |
| super.drawSelectionIndicator(columnIndicator, x, y, columnContents.width, height, color, itemRenderer); |
| } |
| } |
| |
| private function selectionRemovedListener(event:Event):void |
| { |
| if (!lockedColumnCount) |
| return; |
| |
| var columnIndicator:Sprite = indicatorDictionary[event.target] as Sprite; |
| if (columnIndicator) |
| { |
| columnIndicator.parent.removeChild(columnIndicator); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override mx_internal function mouseEventToItemRendererOrEditor(event:MouseEvent):IListItemRenderer |
| { |
| var isHighlight:Boolean = false; |
| |
| var target:DisplayObject = DisplayObject(event.target); |
| var currentContent:ListBaseContentHolder; |
| var visibleColumns:Array = this.visibleColumns; |
| |
| if (event.target == listContent) |
| currentContent = listContent; |
| else if (event.target == lockedColumnContent) |
| { |
| currentContent = lockedColumnContent; |
| visibleColumns = visibleLockedColumns; |
| } |
| else if (event.target == lockedRowContent) |
| currentContent = lockedRowContent; |
| else if (event.target == lockedColumnAndRowContent) |
| { |
| currentContent = lockedColumnAndRowContent; |
| visibleColumns = visibleLockedColumns; |
| } |
| else if (event.target == highlightIndicator) |
| { |
| currentContent = highlightIndicator.parent.parent as ListBaseContentHolder; |
| visibleColumns = this.visibleColumns; |
| if (currentContent == lockedColumnContent || currentContent == lockedColumnAndRowContent) |
| visibleColumns = visibleLockedColumns; |
| isHighlight = true; |
| } |
| else if (event.target == columnHighlightIndicator) |
| { |
| currentContent = columnHighlightIndicator.parent.parent as ListBaseContentHolder; |
| visibleColumns = this.visibleColumns; |
| if (currentContent == lockedColumnContent || currentContent == lockedColumnAndRowContent) |
| visibleColumns = visibleLockedColumns; |
| isHighlight = true; |
| } |
| |
| |
| if (isHighlight || target == currentContent) |
| { |
| var listItems:Array = currentContent.listItems; |
| var rowInfo:Array = currentContent.rowInfo; |
| |
| var pt:Point = new Point(event.stageX, event.stageY); |
| pt = currentContent.globalToLocal(pt); |
| |
| var yy:Number = 0; |
| |
| var n:int = listItems.length; |
| for (var i:int = 0; i < n; i++) |
| { |
| if (listItems[i].length) |
| { |
| if (pt.y < yy + rowInfo[i].height) |
| { |
| var xx:Number = 0; |
| var m:int = visibleColumns.length; |
| for (var j:int = 0; j < m; j++) |
| { |
| if (pt.x < xx + visibleColumns[j].width) |
| return listItems[i][j]; |
| xx += visibleColumns[j].width; |
| } |
| } |
| } |
| yy += rowInfo[i].height; |
| } |
| } |
| |
| while (target && target != this) |
| { |
| if (target is IListItemRenderer && target.parent && |
| target.parent.parent == this && target.parent is ListBaseContentHolder) |
| { |
| if (target.visible) |
| return IListItemRenderer(target); |
| break; |
| } |
| |
| if (target is IUIComponent) |
| target = IUIComponent(target).owner; |
| else |
| target = target.parent; |
| } |
| return null; |
| } |
| |
| /** |
| * Determines the column under the mouse for dropping a column, if any. |
| * This method only checks horizontal position, and assumes the y value is within headers. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| mx_internal function getAllVisibleColumns():Array |
| { |
| var temp:Array = []; |
| if (lockedColumnCount) |
| temp = temp.concat(visibleLockedColumns); |
| temp = temp.concat(visibleColumns); |
| return temp; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function UIDToItemRenderer(uid:String):IListItemRenderer |
| { |
| var r:IListItemRenderer = visibleData[uid]; |
| if (!r) |
| { |
| if (lockedRowContent) |
| r = lockedRowContent.visibleData[uid]; |
| } |
| if (!r) |
| { |
| if (lockedColumnContent) |
| r = lockedColumnContent.visibleData[uid]; |
| } |
| if (!r) |
| { |
| if (lockedColumnAndRowContent) |
| r = lockedColumnAndRowContent.visibleData[uid]; |
| } |
| return r; |
| } |
| |
| /** |
| * @private |
| * By default, there's a single large clip mask applied to the entire |
| * listContent area of the List. When the List contains a mixture of |
| * device text and vector graphics (e.g.: there are custom item renderers), |
| * that clip mask imposes a rendering overhead. |
| * |
| * When graphical (non-text) item renderers are used, we optimize by only |
| * applying a clip mask to the list items in the last row ... and then |
| * only when it's needed. |
| * |
| * This optimization breaks down when there's a horizontal scrollbar. |
| * Rather than attempting to apply clip masks to every item along the left |
| * and right edges, we give up and use the default clip mask that covers |
| * the entire List. |
| * |
| * For Lists and DataGrids containing custom item renderers, this |
| * optimization yields a 25% improvement in scrolling speed. |
| */ |
| override mx_internal function addClipMask(layoutChanged:Boolean):void |
| { |
| var g:Graphics; |
| |
| // If something about the List has changed, check to see if we need |
| // to clip items in the last row. |
| if (layoutChanged) |
| { |
| if ((horizontalScrollBar && horizontalScrollBar.visible) || hasOnlyTextRenderers() || |
| listContent.bottomOffset != 0 || |
| listContent.topOffset != 0 || |
| listContent.leftOffset != 0 || |
| listContent.rightOffset != 0) |
| { |
| // As described above, we just use the default clip mask |
| // when there's a horizontal scrollbar or the item renders |
| // are all UITextFields. |
| listContent.mask = maskShape; |
| selectionLayer.mask = null; |
| if (!headerMask) |
| { |
| headerMask = new Shape(); |
| addChild(headerMask); |
| g = headerMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| headerMask.visible = false; |
| } |
| header.mask = headerMask; |
| header.selectionLayer.mask = null; |
| headerMask.width = maskShape.width; |
| headerMask.height = maskShape.height; |
| headerMask.x = maskShape.x; |
| headerMask.y = maskShape.y; |
| |
| // If we have a vScroll only, we want the scrollbar to be below |
| // the header. |
| if (verticalScrollBar != null && verticalScrollBar.visible && |
| (horizontalScrollBar == null || !horizontalScrollBar.visible) && |
| headerVisible) |
| { |
| headerMask.width += verticalScrollBar.getExplicitOrMeasuredWidth(); |
| } |
| |
| if (lockedRowContent) |
| { |
| if (!lockedRowMask) |
| { |
| lockedRowMask = new Shape(); |
| addChild(lockedRowMask); |
| g = lockedRowMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedRowMask.visible = false; |
| } |
| lockedRowContent.mask = lockedRowMask; |
| lockedRowContent.selectionLayer.mask = null; |
| lockedRowMask.width = maskShape.width; |
| lockedRowMask.height = maskShape.height; |
| lockedRowMask.x = maskShape.x; |
| lockedRowMask.y = maskShape.y; |
| } |
| if (lockedColumnContent) |
| { |
| if (!lockedColumnMask) |
| { |
| lockedColumnMask = new Shape(); |
| addChild(lockedColumnMask); |
| g = lockedColumnMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedColumnMask.visible = false; |
| } |
| lockedColumnContent.mask = lockedColumnMask; |
| lockedColumnContent.selectionLayer.mask = null; |
| lockedColumnMask.width = maskShape.width; |
| lockedColumnMask.height = maskShape.height; |
| lockedColumnMask.x = maskShape.x; |
| lockedColumnMask.y = maskShape.y; |
| } |
| if (lockedColumnAndRowContent) |
| { |
| if (!lockedColumnAndRowMask) |
| { |
| lockedColumnAndRowMask = new Shape(); |
| addChild(lockedColumnAndRowMask); |
| g = lockedColumnAndRowMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedColumnAndRowMask.visible = false; |
| } |
| lockedColumnAndRowContent.mask = lockedColumnAndRowMask; |
| lockedColumnAndRowContent.selectionLayer.mask = null; |
| lockedColumnAndRowMask.width = maskShape.width; |
| lockedColumnAndRowMask.height = maskShape.height; |
| lockedColumnAndRowMask.x = maskShape.x; |
| lockedColumnAndRowMask.y = maskShape.y; |
| } |
| if (lockedColumnHeader) |
| { |
| if (!lockedColumnHeaderMask) |
| { |
| lockedColumnHeaderMask = new Shape(); |
| addChild(lockedColumnHeaderMask); |
| g = lockedColumnHeaderMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedColumnHeaderMask.visible = false; |
| } |
| lockedColumnHeader.mask = lockedColumnHeaderMask; |
| lockedColumnHeader.selectionLayer.mask = null; |
| lockedColumnHeaderMask.width = maskShape.width; |
| lockedColumnHeaderMask.height = maskShape.height; |
| lockedColumnHeaderMask.x = maskShape.x; |
| lockedColumnHeaderMask.y = maskShape.y; |
| } |
| } |
| else |
| { |
| // When we're not applying the default clip mask to the whole |
| // listContent, we still want to apply it to the selectionLayer |
| // (so that the selection rectangle and the mouseOver rectangle |
| // are properly clipped) |
| listContent.mask = null; |
| selectionLayer.mask = maskShape; |
| if (!headerMask) |
| { |
| headerMask = new Shape(); |
| addChild(headerMask); |
| g = headerMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| headerMask.visible = false; |
| } |
| header.mask = null; |
| header.selectionLayer.mask = headerMask; |
| headerMask.width = maskShape.width; |
| headerMask.height = maskShape.height; |
| headerMask.x = maskShape.x; |
| headerMask.y = maskShape.y; |
| // If we have a vScroll only, we want the scrollbar to be below |
| // the header. |
| if (verticalScrollBar != null && verticalScrollBar.visible && |
| (horizontalScrollBar == null || !horizontalScrollBar.visible) && |
| headerVisible) |
| { |
| headerMask.width += verticalScrollBar.getExplicitOrMeasuredWidth(); |
| } |
| |
| |
| if (lockedRowContent) |
| { |
| if (!lockedRowMask) |
| { |
| lockedRowMask = new Shape(); |
| addChild(lockedRowMask); |
| g = lockedRowMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedRowMask.visible = false; |
| } |
| lockedRowContent.mask = null; |
| lockedRowContent.selectionLayer.mask = lockedRowMask; |
| lockedRowMask.width = maskShape.width; |
| lockedRowMask.height = maskShape.height; |
| lockedRowMask.x = maskShape.x; |
| lockedRowMask.y = maskShape.y; |
| } |
| if (lockedColumnContent) |
| { |
| if (!lockedColumnMask) |
| { |
| lockedColumnMask = new Shape(); |
| addChild(lockedColumnMask); |
| g = lockedColumnMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedColumnMask.visible = false; |
| } |
| lockedColumnContent.mask = null; |
| lockedColumnContent.selectionLayer.mask = lockedColumnMask; |
| lockedColumnMask.width = maskShape.width; |
| lockedColumnMask.height = maskShape.height; |
| lockedColumnMask.x = maskShape.x; |
| lockedColumnMask.y = maskShape.y; |
| } |
| if (lockedColumnAndRowContent) |
| { |
| if (!lockedColumnAndRowMask) |
| { |
| lockedColumnAndRowMask = new Shape(); |
| addChild(lockedColumnAndRowMask); |
| g = lockedColumnAndRowMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedColumnAndRowMask.visible = false; |
| } |
| lockedColumnAndRowContent.mask = null; |
| lockedColumnAndRowContent.selectionLayer.mask = lockedColumnAndRowMask; |
| lockedColumnAndRowMask.width = maskShape.width; |
| lockedColumnAndRowMask.height = maskShape.height; |
| lockedColumnAndRowMask.x = maskShape.x; |
| lockedColumnAndRowMask.y = maskShape.y; |
| } |
| if (lockedColumnHeader) |
| { |
| if (!lockedColumnHeaderMask) |
| { |
| lockedColumnHeaderMask = new Shape(); |
| addChild(lockedColumnHeaderMask); |
| g = lockedColumnHeaderMask.graphics; |
| g.beginFill(0xFFFFFF); |
| g.drawRect(0, 0, 10, 10); |
| g.endFill(); |
| lockedColumnHeaderMask.visible = false; |
| } |
| lockedColumnHeader.mask = null; |
| lockedColumnHeader.selectionLayer.mask = lockedColumnHeaderMask; |
| lockedColumnHeaderMask.width = maskShape.width; |
| lockedColumnHeaderMask.height = maskShape.height; |
| lockedColumnHeaderMask.x = maskShape.x; |
| lockedColumnHeaderMask.y = maskShape.y; |
| } |
| } |
| } |
| |
| // If we've decided to clip the entire listContent, then stop here. |
| // There's no need to clip individual items |
| if (listContent.mask) |
| return; |
| |
| // If the last row fits inside listContent, then stop here. There's |
| // no need to do any clipping. |
| var lastRowIndex:int = listItems.length - 1; |
| var lastRowInfo:ListRowInfo = rowInfo[lastRowIndex]; |
| var lastRowItems:Array = listItems[lastRowIndex]; |
| if (lastRowInfo.y + lastRowInfo.height <= listContent.height) |
| return; |
| |
| // For each list item in the last row, either apply a clip mask or |
| // set the row's height to not exceed the height of listContent |
| var numColumns:int = lastRowItems.length; |
| var rowY:Number = lastRowInfo.y; |
| var rowWidth:Number = listContent.width; |
| var rowHeight:Number = listContent.height - lastRowInfo.y; |
| for (var i:int = 0; i < numColumns; i++) |
| { |
| var item:DisplayObject = lastRowItems[i]; |
| var yOffset:Number = item.y - rowY; |
| if (item is IUITextField && !IUITextField(item).embedFonts) |
| item.height = Math.max(rowHeight - yOffset, 0); |
| else |
| item.mask = createItemMask(0, rowY + yOffset, rowWidth, Math.max(rowHeight - yOffset, 0)); |
| } |
| if (lockedColumnContent) |
| { |
| lastRowIndex = lockedColumnContent.listItems.length - 1; |
| lastRowItems = lockedColumnContent.listItems[lastRowIndex]; |
| numColumns = lastRowItems.length; |
| rowWidth = lockedColumnContent.width; |
| for (i = 0; i < numColumns; i++) |
| { |
| item = lastRowItems[i]; |
| yOffset = item.y - rowY; |
| if (item is IUITextField && !IUITextField(item).embedFonts) |
| item.height = Math.max(rowHeight - yOffset, 0); |
| else |
| item.mask = createItemMask(0, rowY + yOffset, rowWidth, Math.max(rowHeight - yOffset, 0), lockedColumnContent); |
| } |
| |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override mx_internal function removeClipMask():void |
| { |
| super.removeClipMask(); |
| |
| if (!lockedColumnContent) |
| return; |
| |
| // If there are no rows, do nothing. |
| var lastRowIndex:int = listItems.length - 1; |
| if (lastRowIndex < 0) |
| return; |
| |
| // Undo the effects of the last "for" loop in addClipMask |
| var rowHeight:Number = rowInfo[lastRowIndex].height; |
| var lastRowInfo:ListRowInfo = rowInfo[lastRowIndex]; |
| var lastRowItems:Array = lockedColumnContent.listItems[lastRowIndex]; |
| if (lastRowItems) |
| { |
| var numColumns:int = lastRowItems.length; |
| for (var i:int = 0; i < numColumns; i++) |
| { |
| var item:DisplayObject = lastRowItems[i]; |
| if (item is IUITextField && !IUITextField(item).embedFonts) |
| { |
| if (item.height != rowHeight - (item.y - lastRowInfo.y)) |
| item.height = rowHeight - (item.y - lastRowInfo.y); |
| } |
| else if (item && item.mask) |
| { |
| itemMaskFreeList.push(item.mask); |
| item.mask = null; |
| } |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal function get gridColumnMap():Object |
| { |
| return columnMap; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function itemRendererToIndex(itemRenderer:IListItemRenderer):int |
| { |
| if (itemRenderer.name in rowMap) |
| { |
| var index:int = rowMap[itemRenderer.name].rowIndex; |
| |
| if (itemRenderer.parent is DataGridLockedRowContentHolder) |
| return index; |
| |
| // not clear why the commented out logic isn't correct... |
| // maybe rowIndex isn't being set correctly? |
| // return index + verticalScrollPosition + offscreenExtraRowsTop; |
| return index + lockedRowCount + verticalScrollPosition - offscreenExtraRowsTop; |
| } |
| return int.MIN_VALUE; |
| } |
| |
| /** |
| * @private |
| */ |
| override mx_internal function selectionTween_updateHandler(event:TweenEvent):void |
| { |
| super.selectionTween_updateHandler(event); |
| if (lockedColumnCount) |
| { |
| var s:Sprite = Sprite(event.target.listener); |
| s = indicatorDictionary[s] as Sprite; |
| s.alpha = Number(event.value); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function destroyRow(i:int, numCols:int):void |
| { |
| super.destroyRow(i, numCols); |
| if (lockedColumnCount) |
| { |
| var listItems:Array = lockedColumnContent.listItems; |
| numCols = listItems[i].length; |
| var rowInfo:Array = lockedColumnContent.rowInfo; |
| var visibleData:Object = lockedColumnContent.visibleData; |
| |
| var r:IListItemRenderer; |
| var uid:String = rowInfo[i].uid; |
| |
| removeIndicators(uid); |
| for (var j:int = 0; j < numCols; j++) |
| { |
| r = listItems[i][j]; |
| if (r.data) |
| delete visibleData[uid]; |
| addToFreeItemRenderers(r); |
| // we don't seem to be doing this consistently throughout the code? |
| // listContent.removeChild(DisplayObject(r)); |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function moveRowVertically(i:int, numCols:int, moveBlockDistance:Number):void |
| { |
| super.moveRowVertically(i, numCols, moveBlockDistance); |
| if (lockedColumnCount) |
| { |
| var listItems:Array = lockedColumnContent.listItems; |
| numCols = listItems[i].length; |
| var rowInfo:Array = lockedColumnContent.rowInfo; |
| var r:IListItemRenderer; |
| |
| for (var j:int = 0; j < numCols; j++) |
| { |
| r = listItems[i][j]; |
| r.move(r.x, r.y + moveBlockDistance); |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function shiftRow(oldIndex:int, newIndex:int, numCols:int, shiftItems:Boolean):void |
| { |
| super.shiftRow(oldIndex, newIndex, numCols, shiftItems); |
| if (lockedColumnCount) |
| { |
| var listItems:Array = lockedColumnContent.listItems; |
| numCols = listItems[oldIndex].length; |
| |
| var r:IListItemRenderer; |
| for (var j:int = 0; j < numCols; j++) |
| { |
| r = listItems[oldIndex][j]; |
| if (shiftItems) |
| { |
| listItems[newIndex][j] = r; |
| rowMap[r.name].rowIndex = newIndex; |
| |
| } |
| // this is sort of a hack to accomodate the fact that |
| // scrolling down does a splice which throws off these values. |
| // probably better to call shiftRow with different parameters? |
| else |
| rowMap[r.name].rowIndex = oldIndex; |
| } |
| if (shiftItems) |
| lockedColumnContent.rowInfo[newIndex] = lockedColumnContent.rowInfo[oldIndex]; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function moveIndicatorsVertically(uid:String, moveBlockDistance:Number):void |
| { |
| super.moveIndicatorsVertically(uid, moveBlockDistance); |
| if (lockedColumnCount) |
| { |
| if (uid) |
| { |
| if (selectionIndicators[uid]) |
| Sprite(indicatorDictionary[selectionIndicators[uid]]).y += moveBlockDistance; |
| if (highlightUID == uid) |
| columnHighlightIndicator.y += moveBlockDistance; |
| if (caretUID == uid) |
| columnCaretIndicator.y += moveBlockDistance; |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function truncateRowArrays(numRows:int):void |
| { |
| super.truncateRowArrays(numRows); |
| if (lockedColumnCount) |
| { |
| lockedColumnContent.listItems.splice(numRows); |
| lockedColumnContent.rowInfo.splice(numRows); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function addToRowArrays():void |
| { |
| super.addToRowArrays(); |
| |
| if (lockedColumnCount) |
| { |
| lockedColumnContent.listItems.splice(0, 0, null); |
| lockedColumnContent.rowInfo.splice(0, 0, null); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function restoreRowArrays(modDeltaPos:int):void |
| { |
| super.restoreRowArrays(modDeltaPos); |
| if (lockedColumnCount) |
| { |
| lockedColumnContent.listItems.splice(0, modDeltaPos); |
| lockedColumnContent.rowInfo.splice(0, modDeltaPos); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function removeFromRowArrays(i:int):void |
| { |
| super.removeFromRowArrays(i); |
| if (lockedColumnCount) |
| { |
| lockedColumnContent.listItems.splice(i, 1); |
| lockedColumnContent.rowInfo.splice(i, 1); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function clearVisibleData():void |
| { |
| if (lockedColumnContent) |
| lockedColumnContent.visibleData = {}; |
| if (lockedRowContent) |
| lockedRowContent.visibleData = {}; |
| if (lockedColumnAndRowContent) |
| lockedColumnAndRowContent.visibleData = {}; |
| |
| super.clearVisibleData(); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function set allowItemSizeChangeNotification(value:Boolean):void |
| { |
| if (lockedColumnContent) |
| lockedColumnContent.allowItemSizeChangeNotification = value; |
| if (lockedRowContent) |
| lockedRowContent.allowItemSizeChangeNotification = value; |
| if (lockedColumnAndRowContent) |
| lockedColumnAndRowContent.allowItemSizeChangeNotification = value; |
| |
| super.allowItemSizeChangeNotification = value; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function indexToRow(index:int):int |
| { |
| if (index < lockedRowCount) |
| return -1; |
| return index - lockedRowCount; |
| } |
| |
| /** |
| * Moves the selection in a vertical direction in response |
| * to the user selecting items with the up arrow or down arrow |
| * keys and modifiers such as the Shift and Ctrl keys. This method |
| * might change the <code>horizontalScrollPosition</code>, |
| * <code>verticalScrollPosition</code>, and <code>caretIndex</code> |
| * properties, and call the <code>finishKeySelection()</code>method |
| * to update the selection. |
| * |
| * @param code The key that was pressed (for example, <code>Keyboard.DOWN</code>). |
| * |
| * @param shiftKey <code>true</code> if the Shift key was held down when |
| * the keyboard key was pressed. |
| * |
| * @param ctrlKey <code>true</code> if the Ctrl key was held down when |
| * the keyboard key was pressed |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override protected function moveSelectionVertically(code:uint, shiftKey:Boolean, |
| ctrlKey:Boolean):void |
| { |
| var newVerticalScrollPosition:Number; |
| var listItem:IListItemRenderer; |
| var uid:String; |
| var len:int; |
| var bSelChanged:Boolean = false; |
| |
| showCaret = true; |
| |
| var rowCount:int = listItems.length; |
| var onscreenRowCount:int = listItems.length - offscreenExtraRowsTop - offscreenExtraRowsBottom; |
| var partialRow:int = (rowInfo[rowCount - offscreenExtraRowsBottom - 1].y + |
| rowInfo[rowCount - offscreenExtraRowsBottom - 1].height > |
| listContent.heightExcludingOffsets - listContent.topOffset) ? 1 : 0; |
| var bUpdateVerticalScrollPosition:Boolean = false; |
| bSelectItem = false; |
| |
| switch (code) |
| { |
| case Keyboard.UP: |
| { |
| if (caretIndex > 0) |
| { |
| caretIndex--; |
| bSelectItem = true; |
| if (caretIndex >= lockedRowCount) |
| bUpdateVerticalScrollPosition = true; |
| } |
| break; |
| } |
| |
| case Keyboard.DOWN: |
| { |
| if (caretIndex >= lockedRowCount - 1) |
| { |
| if (caretIndex < collection.length - 1) |
| { |
| caretIndex++; |
| bUpdateVerticalScrollPosition = true; |
| bSelectItem = true; |
| } |
| else if ((caretIndex == collection.length - 1) && partialRow) |
| { |
| if (verticalScrollPosition < maxVerticalScrollPosition) |
| newVerticalScrollPosition = verticalScrollPosition + 1; |
| } |
| } |
| else if (caretIndex < collection.length - 1) |
| { |
| caretIndex++; |
| bSelectItem = true; |
| } |
| break; |
| } |
| |
| case Keyboard.PAGE_UP: |
| { |
| if (caretIndex > lockedRowCount) |
| { |
| // if the caret is on-screen, but not at the top row |
| // just move the caret to the top row |
| if (caretIndex > verticalScrollPosition + lockedRowCount && |
| caretIndex < verticalScrollPosition + lockedRowCount + onscreenRowCount) |
| { |
| caretIndex = verticalScrollPosition + lockedRowCount; |
| } |
| else |
| { |
| // paging up is really hard because we don't know how many |
| // rows to move because of variable row height. We would have |
| // to double-buffer a previous screen in order to get this exact |
| // so we just guess for now based on current rowCount |
| caretIndex = Math.max(caretIndex - Math.max(onscreenRowCount - partialRow, 1), lockedRowCount); |
| newVerticalScrollPosition = Math.max(caretIndex, lockedRowCount) - lockedRowCount; |
| } |
| bSelectItem = true; |
| } |
| else |
| { |
| caretIndex = 0; |
| bSelectItem = true; |
| } |
| break; |
| } |
| |
| case Keyboard.PAGE_DOWN: |
| { |
| // if the caret is on-screen, but not at the bottom row |
| // just move the caret to the bottom row (not partial row) |
| if (caretIndex >= verticalScrollPosition + lockedRowCount && |
| caretIndex < verticalScrollPosition + lockedRowCount + onscreenRowCount - partialRow - 1) |
| { |
| } |
| else |
| { |
| // With edge case involving very large rows |
| // make sure we move forward. |
| if ((caretIndex - lockedRowCount == verticalScrollPosition) && |
| (onscreenRowCount - partialRow <= 1)) |
| caretIndex++; |
| newVerticalScrollPosition = Math.min(Math.max(caretIndex - lockedRowCount, 0), maxVerticalScrollPosition); |
| } |
| bSelectItem = true; |
| break; |
| } |
| |
| case Keyboard.HOME: |
| { |
| if (caretIndex > 0) |
| { |
| caretIndex = 0; |
| bSelectItem = true; |
| newVerticalScrollPosition = 0; |
| } |
| break; |
| } |
| |
| case Keyboard.END: |
| { |
| if (lockedRowCount >= collection.length) |
| { |
| caretIndex = collection.length - 1; |
| bSelectItem = true; |
| } |
| else |
| { |
| if (caretIndex < collection.length - 1) |
| { |
| caretIndex = collection.length - 1; |
| bSelectItem = true; |
| newVerticalScrollPosition = maxVerticalScrollPosition; |
| } |
| } |
| break; |
| } |
| case Keyboard.SPACE: |
| { |
| bUpdateVerticalScrollPosition = true; |
| bSelectItem = true; |
| break; |
| } |
| } |
| |
| if (bUpdateVerticalScrollPosition) |
| { |
| if (caretIndex >= verticalScrollPosition + lockedRowCount + onscreenRowCount - partialRow) |
| { |
| if (onscreenRowCount - partialRow == 0) |
| newVerticalScrollPosition = Math.min(maxVerticalScrollPosition, Math.max(caretIndex - lockedRowCount, 0)); |
| else |
| newVerticalScrollPosition = Math.min(maxVerticalScrollPosition, caretIndex - lockedRowCount - onscreenRowCount + partialRow + 1); |
| } |
| else if (caretIndex < verticalScrollPosition + lockedRowCount) |
| newVerticalScrollPosition = Math.max(caretIndex - lockedRowCount, 0); |
| } |
| |
| if (!isNaN(newVerticalScrollPosition)) |
| { |
| if (verticalScrollPosition != newVerticalScrollPosition) |
| { |
| var se:ScrollEvent = new ScrollEvent(ScrollEvent.SCROLL); |
| se.detail = ScrollEventDetail.THUMB_POSITION; |
| se.direction = ScrollEventDirection.VERTICAL; |
| se.delta = newVerticalScrollPosition - verticalScrollPosition; |
| se.position = newVerticalScrollPosition; |
| verticalScrollPosition = newVerticalScrollPosition; |
| dispatchEvent(se); |
| } |
| |
| // bail if we page faulted |
| if (!iteratorValid) |
| { |
| keySelectionPending = true; |
| return; |
| } |
| } |
| |
| bShiftKey = shiftKey; |
| bCtrlKey = ctrlKey; |
| |
| lastKey = code; |
| |
| finishKeySelection(); |
| } |
| |
| /** |
| * Sets selected items based on the <code>caretIndex</code> and |
| * <code>anchorIndex</code> properties. |
| * This method is called by the keyboard selection handlers |
| * and by the <code>updateDisplayList()</code> method in case the |
| * keyboard selection handler received a page fault while scrolling to get more items. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override protected function finishKeySelection():void |
| { |
| var uid:String; |
| var rowCount:int = listItems.length; |
| var onscreenRowCount:int = listItems.length - offscreenExtraRowsTop - offscreenExtraRowsBottom; |
| var partialRow:int = (rowInfo[rowCount - offscreenExtraRowsBottom - 1].y + |
| rowInfo[rowCount - offscreenExtraRowsBottom - 1].height > |
| listContent.heightExcludingOffsets - listContent.topOffset) ? 1 : 0; |
| |
| if (lastKey == Keyboard.PAGE_DOWN) |
| { |
| // set caret to last full row of new screen |
| // partial rows take what you can get |
| if (onscreenRowCount - partialRow == 0) |
| { |
| caretIndex = Math.min(verticalScrollPosition + lockedRowCount + onscreenRowCount - partialRow, |
| collection.length - 1); |
| } |
| else |
| { |
| caretIndex = Math.min(verticalScrollPosition + lockedRowCount + onscreenRowCount - partialRow - 1, |
| collection.length - 1); |
| } |
| } |
| |
| var listItem:IListItemRenderer; |
| var bSelChanged:Boolean = false; |
| |
| if (bSelectItem && ((caretIndex - verticalScrollPosition >= 0) || (caretIndex < lockedRowCount))) |
| { |
| if (caretIndex - lockedRowCount - verticalScrollPosition > Math.max(onscreenRowCount - partialRow - 1,0)) |
| { |
| // If we've tried to jump to the end of the list but find that |
| // maxVerticalScrollPosition was off...try again. |
| if ((lastKey == Keyboard.END) && (maxVerticalScrollPosition > verticalScrollPosition)) |
| { |
| caretIndex = caretIndex - 1; |
| moveSelectionVertically(lastKey,bShiftKey,bCtrlKey); |
| return; |
| } |
| caretIndex = lockedRowCount + onscreenRowCount - partialRow - 1 + verticalScrollPosition; |
| } |
| |
| if (caretIndex < lockedRowCount) |
| listItem = lockedRowContent.listItems[caretIndex][0]; |
| else |
| listItem = listItems[caretIndex - lockedRowCount - verticalScrollPosition + offscreenExtraRowsTop][0]; |
| |
| if (listItem) |
| { |
| uid = itemToUID(listItem.data); |
| |
| listItem = UIDToItemRenderer(uid); |
| if (!bCtrlKey || lastKey == Keyboard.SPACE) |
| { |
| selectItem(listItem, bShiftKey, bCtrlKey); |
| bSelChanged = true; |
| } |
| if (bCtrlKey) |
| { |
| drawItem(listItem, selectedData[uid] != null, uid == highlightUID, true); |
| } |
| } |
| } |
| |
| if (bSelChanged) |
| { |
| var pt:Point = itemRendererToIndices(listItem); |
| var evt:ListEvent = new ListEvent(ListEvent.CHANGE); |
| if (pt) |
| { |
| evt.columnIndex = pt.x; |
| evt.rowIndex = pt.y; |
| } |
| evt.itemRenderer = listItem; |
| dispatchEvent(evt); |
| } |
| } |
| |
| /** |
| * Returns a Point object that defines the <code>columnIndex</code> and <code>rowIndex</code> properties of an |
| * item renderer. Because item renderers are only created for items |
| * within the set of viewable rows, you cannot use this method to get the indices for items |
| * that are not visible. Also, item renderers |
| * are recycled so the indices that you get for an item might change |
| * if that item renderer is reused to display a different item. |
| * Usually, this method is called during mouse and keyboard handling |
| * when the set of data displayed by the item renderers has not yet changed. |
| * |
| * @param item An item renderer. |
| * |
| * @return A Point object. The <code>x</code> property is the <code>columnIndex</code> |
| * and the <code>y</code> property is the <code>rowIndex</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override protected function itemRendererToIndices(item:IListItemRenderer):Point |
| { |
| if (!item || !(item.name in rowMap)) |
| return null; |
| |
| var content:ListBaseContentHolder = item.parent as ListBaseContentHolder; |
| |
| var found:Boolean = false; |
| var index:int = rowMap[item.name].rowIndex; |
| var len:int = content.listItems[index].length; |
| for (var i:int = 0; i < len; i++) |
| { |
| if (content.listItems[index][i] == item) |
| { |
| found = true; |
| break; |
| } |
| } |
| if (!found) |
| return null; |
| |
| if (lockedRowContent == content) |
| return new Point(i + horizontalScrollPosition + lockedColumnCount, |
| index + offscreenExtraRowsTop); |
| |
| if (lockedColumnAndRowContent == content) |
| return new Point(i, index + offscreenExtraRowsTop); |
| |
| if (lockedColumnContent == content) |
| return new Point(i, |
| index + verticalScrollPosition + lockedRowCount + offscreenExtraRowsTop); |
| |
| return new Point(i + horizontalScrollPosition + lockedColumnCount, |
| index + verticalScrollPosition + lockedRowCount + offscreenExtraRowsTop); |
| } |
| |
| /** |
| * @private |
| * the inselectItem is a flag that converts relative seeks to absolute |
| */ |
| override protected function selectItem(item:IListItemRenderer, |
| shiftKey:Boolean, ctrlKey:Boolean, |
| transition:Boolean = true):Boolean |
| { |
| var bookmark:CursorBookmark = iterator.bookmark; |
| |
| if (lockedRowCount) |
| { |
| inSelectItem = true; |
| iterator.seek(CursorBookmark.FIRST, 0); |
| } |
| |
| var retval:Boolean = super.selectItem(item, shiftKey, ctrlKey, transition); |
| |
| if (lockedRowCount) |
| { |
| iterator.seek(bookmark, 0); |
| inSelectItem = false; |
| } |
| |
| return retval; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function showDropFeedback(event:DragEvent):void |
| { |
| if (!dropIndicator) |
| { |
| var dropIndicatorClass:Class = getStyle("dropIndicatorSkin"); |
| if (!dropIndicatorClass) |
| dropIndicatorClass = ListDropIndicator; |
| dropIndicator = IFlexDisplayObject(new dropIndicatorClass()); |
| |
| var vm:EdgeMetrics = viewMetrics; |
| |
| drawFocus(true); |
| |
| dropIndicator.x = 2; |
| dropIndicator.setActualSize(listContent.width - 4, 4); |
| dropIndicator.visible = true; |
| listContent.addChild(DisplayObject(dropIndicator)); |
| |
| if (collection) |
| dragScrollingInterval = setInterval(dragScroll, 15); |
| } |
| |
| var rowNum:Number = calculateDropIndex(event); |
| if (lockedRowCount && rowNum < lockedRowCount) |
| { |
| if (dropIndicator.parent != lockedRowContent) |
| lockedRowContent.addChild(DisplayObject(dropIndicator)); |
| dropIndicator.y = lockedRowContent.listItems[rowNum][0].y - 1 |
| |
| } |
| else |
| { |
| var rowCount:int = listItems.length; |
| var partialRow:int = (rowCount > 0 && rowInfo[rowCount - offscreenExtraRowsBottom - 1].y + |
| rowInfo[rowCount - offscreenExtraRowsBottom - 1].height > |
| listContent.heightExcludingOffsets - listContent.topOffset) ? 1 : 0; |
| |
| rowNum -= verticalScrollPosition + lockedRowCount; |
| |
| if (rowNum >= rowCount) |
| { |
| if (partialRow) |
| rowNum = rowCount - 1; |
| else |
| rowNum = rowCount; |
| } |
| |
| if (rowNum < 0) |
| rowNum = 0; |
| |
| if (dropIndicator.parent != listContent) |
| listContent.addChild(DisplayObject(dropIndicator)); |
| dropIndicator.y = calculateDropIndicatorY(rowCount, rowNum + offscreenExtraRowsTop); |
| } |
| } |
| |
| /** |
| * @private |
| * If there are locked rows but there weren't enough collection items, the iterator |
| * is not in the right place and needs fixing. |
| */ |
| override protected function adjustAfterAdd(items:Array, location:int):Boolean |
| { |
| var retval:Boolean = super.adjustAfterAdd(items, location); |
| if (lockedRowCount) |
| { |
| if (verticalScrollPosition > 0 && verticalScrollPosition >= location && location <= lockedRowCount) |
| { |
| if (verticalScrollPosition + lockedRowCount >= collection.length) |
| { |
| // don't let adjustment take us beyond end of iterator |
| super.verticalScrollPosition = verticalScrollPosition - items.length; |
| } |
| } |
| if (collection.length - items.length <= lockedRowCount && collection.length >= lockedRowCount |
| || location <= lockedRowCount |
| || location == lockedRowCount + verticalScrollPosition) |
| { |
| try |
| { |
| iterator.seek(CursorBookmark.FIRST, lockedRowCount + verticalScrollPosition); |
| if (!iteratorValid) |
| { |
| iteratorValid = true; |
| lastSeekPending = null; |
| } |
| } |
| catch(e:ItemPendingError) |
| { |
| lastSeekPending = new ListBaseSeekPending(CursorBookmark.FIRST, lockedRowCount + verticalScrollPosition) |
| e.addResponder(new ItemResponder(seekPendingResultHandler, seekPendingFailureHandler, |
| lastSeekPending)); |
| // trace("IPE in UpdateDisplayList"); |
| iteratorValid = false; |
| // don't do anything, we'll repaint when the data arrives |
| } |
| } |
| } |
| return retval; |
| } |
| |
| /** |
| * @private |
| * If there are locked rows but there weren't enough collection items, the iterator |
| * is not in the right place and needs fixing. |
| */ |
| override protected function adjustAfterRemove(items:Array, location:int, requiresValueCommit:Boolean):Boolean |
| { |
| var adjustIterator:Boolean = false; |
| |
| if (lockedRowCount && listItems.length && listItems[0].length) |
| { |
| if (location <= lockedRowCount + verticalScrollPosition) |
| adjustIterator = true; |
| else |
| { |
| // special case when we have less than a screen full of stuff |
| var firstUID:String = rowMap[listItems[0][0].name].uid; |
| |
| for (var i:int = 0; i < items.length; i++) |
| { |
| var uid:String = itemToUID(items[i]); |
| |
| if (uid == firstUID && verticalScrollPosition == 0) |
| { |
| adjustIterator = true; |
| break; |
| } |
| } |
| } |
| } |
| |
| var retval:Boolean = super.adjustAfterRemove(items, location, requiresValueCommit); |
| |
| if (lockedRowCount) |
| { |
| if (verticalScrollPosition > 0 && location > lockedRowCount |
| && verticalScrollPosition <= lockedRowCount && verticalScrollPosition == maxVerticalScrollPosition ) |
| { |
| super.verticalScrollPosition = verticalScrollPosition - items.length; |
| adjustIterator = true; |
| } |
| if (adjustIterator) |
| { |
| try |
| { |
| iterator.seek(CursorBookmark.FIRST, lockedRowCount + verticalScrollPosition); |
| if (!iteratorValid) |
| { |
|