blob: 234c67a658302844f9825b866c9c54f75e1edd9a [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package spark.components.gridClasses
{
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.InteractiveObject;
import flash.events.Event;
import flash.events.FocusEvent;
import flash.events.IEventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.ui.Keyboard;
import flash.utils.Timer;
import mx.core.ClassFactory;
import mx.core.EventPriority;
import mx.core.IFactory;
import mx.core.IIMESupport;
import mx.core.IInvalidating;
import mx.core.IUIComponent;
import mx.core.IVisualElement;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.events.SandboxMouseEvent;
import mx.managers.FocusManager;
import mx.managers.IFocusManager;
import mx.managers.IFocusManagerComponent;
import mx.styles.ISimpleStyleClient;
import spark.components.DataGrid;
import spark.components.Grid;
import spark.components.gridClasses.GridItemEditorActivationMouseEvent;
import spark.events.GridEvent;
import spark.events.GridItemEditorEvent;
use namespace mx_internal;
/**
* The DataGridEditor contains all the logic and event handling needed to
* manage the life cycle of an item editor.
* A DataGridEditor is owned by a
* specified DataGrid. The owning DataGrid is responsible for calling
* initialize() to enable editing and uninitialize() when editing is no
* longer needed.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public class DataGridEditor
{
include "../../core/Version.as";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor
*
* @param dataGrid The owner of this editor.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function DataGridEditor(dataGrid:DataGrid)
{
_dataGrid = dataGrid;
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
* Timer used to cancel edits if a double click occurs.
*/
private var doubleClickTimer:Timer;
/**
* @private
* True if we have received double click event since the last click.
*/
private var gotDoubleClickEvent:Boolean;
/**
* @private
* True if we have received a FlexEvent.ENTER.
*/
private var gotFlexEnterEvent:Boolean;
/**
* @private
*/
private var lastEvent:Event;
/**
* @private
* Position of the last item renderer that was clicked.
*/
private var lastItemClickedPosition:Object;
/**
* @private
* Used to make sure the mouse up is on the same item
* renderer as the mouse down.
*/
private var lastItemDown:IVisualElement;
/**
* @private
* the last editedItemPosition and the last
* position where editing was attempted if editing
* was cancelled.
*/
private var lastEditedItemPosition:*;
/**
* @private
* Determines if the hasFocusableChildren flags are restored when
* an editor is destroyed. This is set to false when we know we will
* be starting up another editor immeditiately. By not restoring
* the tab children flag we will be saving FocusManager from removing
* and then adding all the focusable children of the data grid.
*/
private var restoreFocusableChildren:Boolean = true;
/**
* @private
* Used to restore the value of DataGrid's hasFocusableChildren.
*/
private var saveDataGridHasFocusableChildren:Boolean;
/**
* @private
* Used to restore the value of scroller's hasFocusableChildren.
*/
private var saveScrollerHasFocusableChildren:Boolean;
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
/**
* @private
*/
private var _dataGrid:DataGrid;
/**
* Reference to the <code>DataGrid</code> that created the editor.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function get dataGrid():DataGrid
{
return _dataGrid;
}
/**
* Convenience property to get the <code>Grid</code> associated with the parent <code>DataGrid</code>.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function get grid():Grid
{
return _dataGrid.grid;
}
//----------------------------------
// editedItemPosition
//----------------------------------
/**
* @private
*/
private var _editedItemPosition:Object;
/**
* The column and row index of the item renderer for the
* data provider item being edited, if any.
*
* <p>This Object has two fields, <code>columnIndex</code> and
* <code>rowIndex</code>,
* the zero-based column and row indexes of the item.
* For example: {columnIndex:2, rowIndex:3}</p>
*
* <p>Setting this property scrolls the item into view and
* dispatches the <code>itemEditBegin</code> event to
* open an item editor on the specified item renderer.</p>
*
* @default null
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get editedItemPosition():Object
{
if (_editedItemPosition)
return {rowIndex: _editedItemPosition.rowIndex,
columnIndex: _editedItemPosition.columnIndex};
else
return _editedItemPosition;
}
/**
* Sets the edited item position based on the grids <code>rowIndex</code> and <code>columnIndex</code>.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function set editedItemPosition(value:Object):void
{
if (!value)
{
setEditedItemPosition(null);
return;
}
var newValue:Object = {rowIndex: value.rowIndex,
columnIndex: value.columnIndex};
setEditedItemPosition(newValue);
}
/**
* @private
*/
private function setEditedItemPosition(coord:Object):void
{
if (!grid.enabled || !dataGrid.editable)
return;
if (!grid.dataProvider || grid.dataProvider.length == 0)
return;
// just give focus back to the itemEditorInstance
if (itemEditorInstance && coord &&
itemEditorInstance is IFocusManagerComponent &&
_editedItemPosition.rowIndex == coord.rowIndex &&
_editedItemPosition.columnIndex == coord.columnIndex)
{
IFocusManagerComponent(itemEditorInstance).setFocus();
return;
}
// dispose of any existing editor, saving away its data first
if (itemEditorInstance)
{
if (!dataGrid.endItemEditorSession())
return;
}
// store the value
_editedItemPosition = coord;
// allow setting of undefined to dispose item editor instance
if (!coord)
return;
var rowIndex:int = coord.rowIndex;
var columnIndex:int = coord.columnIndex;
dataGrid.ensureCellIsVisible(rowIndex, columnIndex);
createItemEditor(rowIndex, columnIndex);
if (itemEditorInstance is IInvalidating)
IInvalidating(itemEditorInstance).validateNow();
var column:GridColumn = dataGrid.columns.getItemAt(columnIndex) as GridColumn;
if (itemEditorInstance is IIMESupport)
IIMESupport(itemEditorInstance).imeMode =
(column.imeMode == null) ? dataGrid.imeMode : column.imeMode;
var fm:IFocusManager = grid.focusManager;
if (itemEditorInstance is IFocusManagerComponent)
{
// Temporarily remove the FOCUS_OUT handler: if we give the editor the focus and
// it immediately vectors it to a non-editor descendant, like to the mobile soft
// keyboard, we don't want to end the editor session.
itemEditorInstance.removeEventListener(FocusEvent.FOCUS_OUT, editor_focusOutHandler);
fm.setFocus(IFocusManagerComponent(itemEditorInstance));
itemEditorInstance.addEventListener(FocusEvent.FOCUS_OUT, editor_focusOutHandler);
}
lastEditedItemPosition = _editedItemPosition;
// Notify event that a new editor is starting.
// Don't dispatch life cycle events for item renderers.
var dataGridEvent:GridItemEditorEvent = null;
if (column.rendererIsEditable == false)
dataGridEvent = new GridItemEditorEvent(GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_START);
if (dataGridEvent)
{
dataGridEvent.columnIndex = editedItemPosition.columnIndex;
dataGridEvent.column = column;
dataGridEvent.rowIndex = editedItemPosition.rowIndex;
dataGrid.dispatchEvent(dataGridEvent);
}
}
/**
* @private
* true if we're in the endEdit call. Used to handle
* some timing issues with collection updates
*/
private var inEndEdit:Boolean = false;
/**
* 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 after the event listener for
* the <code>itemEditBegin</code> event executes. Therefore, you typically
* only access the <code>itemEditorInstance</code> property from within
* the event listener for the <code>itemEditEnd</code> event.</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>You do not set this property in MXML.</p>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public var itemEditorInstance:IGridItemEditor;
/**
* @private
*/
private var _editedItemRenderer:IVisualElement;
/**
* A reference to the item renderer
* in the DataGrid control whose item is currently being edited.
*
* <p>From within an event listener for the <code>itemEditBegin</code>
* and <code>itemEditEnd</code> events,
* you can access the current value of the item being edited
* using the <code>editedItemRenderer.data</code> property.</p>
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get editedItemRenderer():IVisualElement
{
return _editedItemRenderer;
}
//----------------------------------
// 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 9
* @playerversion AIR 1.1
* @productversion Flex 4.5
*/
public function get editorColumnIndex():int
{
if (editedItemPosition)
return editedItemPosition.columnIndex;
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 9
* @playerversion AIR 1.1
* @productversion Flex 4.5
*/
public function get editorRowIndex():int
{
if (editedItemPosition)
return editedItemPosition.rowIndex;
return -1;
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Called by the <code>DataGrid</code> after construction to initialize the editor. No
* item editors can be created until after this method is called.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function initialize():void
{
// add listeners to enable cell editing
var grid:Grid = dataGrid.grid;
dataGrid.addEventListener(KeyboardEvent.KEY_DOWN, dataGrid_keyboardDownHandler);
// Make sure we get first shot at mouse events before selection is changed. We use
// this is test if you are clicking on a selected row or not.
grid.addEventListener(GridEvent.GRID_MOUSE_DOWN, grid_gridMouseDownHandler, false, 1000);
grid.addEventListener(GridEvent.GRID_MOUSE_UP, grid_gridMouseUpHandler, false, 1000);
grid.addEventListener(GridEvent.GRID_DOUBLE_CLICK, grid_gridDoubleClickHandler);
grid.addEventListener(MouseEvent.MOUSE_WHEEL, grid_gridMouseWheelHandler, false, 0);
}
/**
* The method is called to disable item editing on the <code>DataGrid</code>.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function uninitialize():void
{
// remove listeners to disable cell editing
grid.removeEventListener(KeyboardEvent.KEY_DOWN, dataGrid_keyboardDownHandler);
grid.removeEventListener(GridEvent.GRID_MOUSE_DOWN, grid_gridMouseDownHandler);
grid.removeEventListener(GridEvent.GRID_MOUSE_UP, grid_gridMouseUpHandler);
grid.removeEventListener(GridEvent.GRID_DOUBLE_CLICK, grid_gridDoubleClickHandler);
grid.removeEventListener(MouseEvent.MOUSE_WHEEL, grid_gridMouseWheelHandler);
}
/**
* @private
*
* This method closes an item editor currently open on an item renderer.
* You typically only call this method from within the event listener
* for the <code>itemEditEnd</code> event, after
* you have already called the <code>preventDefault()</code> method to
* prevent the default event listener from executing.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
mx_internal function destroyItemEditor():void
{
// trace("destroyItemEditor");
if (grid.root)
grid.systemManager.removeEventListener(Event.DEACTIVATE, deactivateHandler);
grid.systemManager.getSandboxRoot().
removeEventListener(MouseEvent.MOUSE_DOWN, sandBoxRoot_mouseDownHandler, true);
grid.systemManager.getSandboxRoot().
removeEventListener(SandboxMouseEvent.MOUSE_DOWN_SOMEWHERE, sandBoxRoot_mouseDownHandler);
grid.systemManager.removeEventListener(Event.RESIZE, editorAncestorResizeHandler);
dataGrid.removeEventListener(Event.RESIZE, editorAncestorResizeHandler);
if (itemEditorInstance || editedItemRenderer)
{
if (itemEditorInstance)
itemEditorInstance.discard();
var o:IVisualElement = (itemEditorInstance ?
itemEditorInstance : editedItemRenderer);
o.removeEventListener(KeyboardEvent.KEY_DOWN, editor_keyDownHandler);
o.removeEventListener(FocusEvent.FOCUS_OUT, editor_focusOutHandler);
o.removeEventListener(Event.REMOVED_FROM_STAGE, editor_removedFromStageHandler);
o.removeEventListener(FocusEvent.KEY_FOCUS_CHANGE, editor_keyFocusChangeHandler);
addRemoveFlexEventEnterListener(DisplayObject(o), false);
if (grid.focusManager)
grid.focusManager.defaultButtonEnabled = true;
// setfocus back to us so something on stage has focus
dataGrid.setFocus();
// defer focus can cause focusOutHandler to destroy the editor
// and make itemEditorInstance null
if (itemEditorInstance)
grid.removeElement(itemEditorInstance);
else
grid.invalidateDisplayList(); // force the editorIndicator to be redrawn
if (restoreFocusableChildren)
{
restoreFocusableChildrenFlags();
}
itemEditorInstance = null;
_editedItemRenderer = null;
_editedItemPosition = null;
}
}
/**
* @private
*
* Creates the item editor for the item renderer at the
* <code>editedItemPosition</code> using the editor
* specified by the <code>itemEditor</code> property.
*
* <p>This method sets the editor instance as the
* <code>itemEditorInstance</code> property.</p>
*
* @param rowIndex The row index in the data provider of the item to be edited.
* @param columnIndex The column index in the data provider of the item to be edited.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
mx_internal function createItemEditor(rowIndex:int, columnIndex:int):void
{
// check for bad values
if (columnIndex >= grid.columns.length)
return;
var col:GridColumn = grid.columns.getItemAt(columnIndex) as GridColumn;
var item:IGridItemRenderer = grid.getItemRendererAt(rowIndex, columnIndex);
var cellBounds:Rectangle = grid.getCellBounds(rowIndex,columnIndex);
var localCellOrigin:Point = cellBounds.topLeft;
_editedItemRenderer = item;
// Need to turn on focusable children flag so focus manager will
// allow focus into the data grid's children.
if (restoreFocusableChildren)
saveDataGridHasFocusableChildren = dataGrid.hasFocusableChildren;
dataGrid.hasFocusableChildren = true;
if (dataGrid.scroller)
{
//Correct the item edit positioning based on the scroll position.
localCellOrigin.x -= grid.horizontalScrollPosition;
localCellOrigin.y -= grid.verticalScrollPosition;
if (restoreFocusableChildren)
saveScrollerHasFocusableChildren = dataGrid.scroller.hasFocusableChildren;
dataGrid.scroller.hasFocusableChildren = true;
}
restoreFocusableChildren = true;
if (!col.rendererIsEditable)
{
// First use the column's itemEditor.
// If that is unspecified try the dataGrid's itemEditor.
// If that is unspecified then use the default itemEditor
// set on the column.
var itemEditor:IFactory = col.itemEditor;
if (!itemEditor)
itemEditor = dataGrid.itemEditor;
if (!itemEditor)
itemEditor = GridColumn.defaultItemEditorFactory;
if (itemEditor == GridColumn.defaultItemEditorFactory)
{
// if it is the default factory, see if someone
// overrode it with this style
var c:Class = dataGrid.getStyle("defaultDataGridItemEditor");
if (c)
{
itemEditor = col.itemEditor = new ClassFactory(c);
}
}
itemEditorInstance = itemEditor.newInstance();
itemEditorInstance.owner = dataGrid;
itemEditorInstance.rowIndex = rowIndex;
itemEditorInstance.column = col;
itemEditorInstance.hasFocusableChildren = true;
if (itemEditorInstance is ISimpleStyleClient)
ISimpleStyleClient(itemEditorInstance).styleName = item;
// Add the editor to the grid before setting the data so that
// the editor's children will be created.
grid.addElement(itemEditorInstance);
itemEditorInstance.data = item.data;
// The editor will overlay the cell, covering the first pixel of the
// cell separators. This is done so that a cell editor with borders
// will overlay the cell separators. It prevents the cell separators
// from adding borders to the editor for the common case when the cell
// separators are only 1 pixel wide.
itemEditorInstance.width = cellBounds.width + 1;
itemEditorInstance.height = cellBounds.height + 1;
itemEditorInstance.setLayoutBoundsPosition(localCellOrigin.x, localCellOrigin.y);
if (itemEditorInstance is IInvalidating)
IInvalidating(itemEditorInstance).validateNow();
// Allow the user code to make any final adjustments and make the editor visible.
itemEditorInstance.prepare();
itemEditorInstance.visible = true;
}
else
{
setFocusInItemRenderer(item);
}
if (itemEditorInstance || editedItemRenderer)
{
var editor:IEventDispatcher = itemEditorInstance ? itemEditorInstance : editedItemRenderer;
editor.addEventListener(FocusEvent.FOCUS_OUT, editor_focusOutHandler);
editor.addEventListener(Event.REMOVED_FROM_STAGE, editor_removedFromStageHandler);
// listen for keyStrokes on the itemEditorInstance (which lets the grid supervise for ESC/ENTER)
editor.addEventListener(KeyboardEvent.KEY_DOWN, editor_keyDownHandler);
editor.addEventListener(FocusEvent.KEY_FOCUS_CHANGE, editor_keyFocusChangeHandler, false, 1000);
addRemoveFlexEventEnterListener(DisplayObject(editor), true);
}
if (grid.focusManager)
grid.focusManager.defaultButtonEnabled = false;
// Invalidate the grid so the editor indicator will be shown.
grid.invalidateDisplayList();
if (grid.root)
grid.systemManager.addEventListener(Event.DEACTIVATE, deactivateHandler, false, 0, true);
// we disappear on any mouse down outside the editor
grid.systemManager.getSandboxRoot().
addEventListener(MouseEvent.MOUSE_DOWN, sandBoxRoot_mouseDownHandler, true, 0, true);
grid.systemManager.getSandboxRoot().
addEventListener(SandboxMouseEvent.MOUSE_DOWN_SOMEWHERE, sandBoxRoot_mouseDownHandler, false, 0, true);
// we disappear if stage or our grid is resized
grid.systemManager.addEventListener(Event.RESIZE, editorAncestorResizeHandler);
grid.addEventListener(Event.RESIZE, editorAncestorResizeHandler);
}
/**
* @private
*/
private function setFocusInItemRenderer(item:IGridItemRenderer):void
{
// if the item renderer is editable then set focus
// to the first item that should get focus.
if (grid.focusManager && grid.focusManager is FocusManager)
{
var fm:FocusManager = grid.focusManager as FocusManager;
var o:DisplayObject = item as DisplayObject;
var firstComponent:DisplayObject = null;
var found:Boolean = false;
// find the first component to take focus inside the renderer.
do
{
fm.fauxFocus = o;
o = fm.getNextFocusManagerComponent(false) as DisplayObject;
if (o == item ||
item is DisplayObjectContainer &&
DisplayObjectContainer(item).contains(o))
{
found = true;
break;
}
// prevent infinite loop
if (!firstComponent)
firstComponent = o;
else if (firstComponent == o)
break;
} while (o && dataGrid.contains(o));
// if we are moving backward then put focus on the last
// item in the renderer instead of the first.
if (found && wasLastEventMovingBackward())
{
// put focus on last item in cell editor instead of first.
var lastItem:DisplayObject = o;
do
{
fm.fauxFocus = o;
lastItem = o;
o = fm.getNextFocusManagerComponent(false) as DisplayObject;
} while (o && DisplayObjectContainer(item).contains(o));
o = lastItem;
}
fm.fauxFocus = null;
if (found)
{
fm.setFocus(IFocusManagerComponent(o));
// Since we may have gotton here with the F2 key show the focus
// indicator to make it obvious which control has focus.
fm.showFocus();
}
}
}
/**
* @private
*/
private function wasLastEventMovingBackward():Boolean
{
if (lastEvent)
{
// Last event was a key focus change moving backward.
if (lastEvent.type == FocusEvent.KEY_FOCUS_CHANGE &&
FocusEvent(lastEvent).shiftKey)
{
return true;
}
// Last event was Shift+TAB
if (lastEvent.type == KeyboardEvent.KEY_DOWN &&
KeyboardEvent(lastEvent).keyCode == Keyboard.TAB &&
KeyboardEvent(lastEvent).shiftKey)
{
return true;
}
}
return false;
}
/**
* Start editing a cell for a specified row and column index.
*
* Dispatches a <code>GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_STARTING
* </code> event.
*
* @param rowIndex The zero-based row index of the cell to edit.
*
* @param columnIndex The zero-based column index of the cell to edit.
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.5
* @productversion Flex 4.5
*/
public function startItemEditorSession(rowIndex:int, columnIndex:int):Boolean
{
// validate row and column index
if (!isValidCellPosition(rowIndex, columnIndex))
return false;
dataGrid.addEventListener(GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_STARTING,
dataGrid_gridItemEditorSessionStartingHandler,
false, EventPriority.DEFAULT_HANDLER);
var column:GridColumn = grid.columns.getItemAt(columnIndex) as GridColumn;
if (!column || !column.visible)
return false;
// The START_GRID_ITEM_EDITOR_SESSION event is cancelable
var dataGridEvent:GridItemEditorEvent = new GridItemEditorEvent(
GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_STARTING,
false, true);
dataGridEvent.rowIndex = Math.min(rowIndex, grid.dataProvider.length - 1);
dataGridEvent.columnIndex = Math.min(columnIndex, grid.columns.length - 1);
dataGridEvent.column = column;
// Don't send a life cycle event if the cell contains an item renderer.
var editorStarted:Boolean = false;
if (column.rendererIsEditable == true)
{
dataGrid_gridItemEditorSessionStartingHandler(dataGridEvent); // start editor session without the option to cancel
editorStarted = true;
}
else
{
editorStarted = dataGrid.dispatchEvent(dataGridEvent);
}
if (editorStarted)
{
lastEditedItemPosition = { columnIndex: columnIndex, rowIndex: rowIndex };
dataGrid.grid.caretRowIndex = rowIndex;
dataGrid.grid.caretColumnIndex = columnIndex;
}
restoreFocusableChildren = true;
dataGrid.removeEventListener(GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_STARTING,
dataGrid_gridItemEditorSessionStartingHandler);
return editorStarted;
}
/**
* Closes the currently active editor and optionally saves the editor's value
* by calling the item editor's save() method. If the cancel parameter is true,
* then the editor's cancel() method is called instead.
*
* @param cancel if true then the data in the editor is discarded,
* otherwise it's saved.
*
* @return true if the data in the editor was saved, false otherwise.
*
* @see spark.components.IGridItemEditor
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 2.0
* @productversion Flex 4.5
*/
public function endItemEditorSession(cancel:Boolean = false):Boolean
{
if (cancel)
{
cancelEdit();
return false;
}
else
{
return endEdit();
}
}
/**
* @private
*
* Close the item editor without saving the data.
*/
mx_internal function cancelEdit():Boolean
{
if (itemEditorInstance)
{
if (itemEditorInstance.cancel())
{
// send the cancel event and tear down the editor.
dispatchCancelEvent();
destroyItemEditor();
}
else
{
return false;
}
}
else if (editedItemRenderer)
{
// cancel focus in an item editor by setting focus back to the grid.
destroyItemEditor();
}
return true;
}
/**
* @private
*
* Notify event that the editor session is cancelled.
* This event cannot be cancelled.
*/
private function dispatchCancelEvent():void
{
var dataGridEvent:GridItemEditorEvent =
new GridItemEditorEvent(GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_CANCEL);
dataGridEvent.columnIndex = editedItemPosition.columnIndex;
dataGridEvent.column = itemEditorInstance.column;
dataGridEvent.rowIndex = dataGrid.dataProvider ? dataGrid.dataProvider.getItemIndex(itemEditorInstance.data) : -1;
dataGrid.dispatchEvent(dataGridEvent);
}
/**
* @private
*
* When the user finished editing an item, this method is called to close
* the editor and save the data.
*
*/
private function endEdit():Boolean
{
// Focus is inside an item renderer
if (!itemEditorInstance && editedItemRenderer)
{
inEndEdit = true;
destroyItemEditor();
inEndEdit = false;
return true;
}
// this happens if the renderer is removed asynchronously ususally with FDS
if (!itemEditorInstance)
return false;
inEndEdit = true;
var itemPosition:Object = editedItemPosition;
var editedItem:Object = itemEditorInstance.data;
if (!saveItemEditorSession())
{
// The save was cancelled so check if the editor can be cancelled.
// If it can then dispatch a cancel event.
if (itemEditorInstance.cancel())
dispatchCancelEvent();
inEndEdit = false;
return false;
}
var dataGridEvent:GridItemEditorEvent =
new GridItemEditorEvent(GridItemEditorEvent.GRID_ITEM_EDITOR_SESSION_SAVE);
// GRID_ITEM_EDITOR_SESSION_SAVE events are NOT cancelable
dataGridEvent.columnIndex = itemPosition.columnIndex;
dataGridEvent.column = dataGrid.columns.getItemAt(itemPosition.columnIndex) as GridColumn;
dataGridEvent.rowIndex = dataGrid.dataProvider ? dataGrid.dataProvider.getItemIndex(editedItem) : -1;
dataGrid.dispatchEvent(dataGridEvent);
inEndEdit = false;
return true;
}
/**
* @private
* Save the editor session. The developer can still cancel out so the
* data may not be saved.
*
* @return true if the data is saved, false otherwise.
*/
private function saveItemEditorSession():Boolean
{
var dataSaved:Boolean = false;
if (itemEditorInstance)
{
dataSaved = itemEditorInstance.save();
if (dataSaved)
destroyItemEditor();
}
return dataSaved;
}
/**
* @private
* Start an editor session in the next editable cell.
*
* @param rowIndex zero-based row index to start search from, inclusive.
* @param columnIndex zero-based column index to start search from, not inclusive.
* @param backward - if true move backward column by column and then row by row.
* If false, then move forward column by column, row by row.
*
* @return true if an editor was opened, false otherwise.
*
*/
private function openEditorInNextEditableCell(rowIndex:int, columnIndex:int, backward:Boolean):Boolean
{
var nextCell:Point = new Point(rowIndex, columnIndex);
var openedEditor:Boolean = false;
do
{
nextCell = getNextEditableCell(nextCell.x, nextCell.y, backward);
if (nextCell)
openedEditor = dataGrid.startItemEditorSession(nextCell.x, nextCell.y);
} while (nextCell && !openedEditor);
return openedEditor;
}
/**
* @private
* Find the next editable cell.
*
* @param rowIndex zero-based row index to start search from, inclusive.
* @param columnIndex zero-based column index to start search from, not inclusive.
* @param backward - if true move backward column by column and then row by row.
* If false, then move forward column by column, row by row.
*
* @return If an editable cell was found then return a Point with the x property
* containing the rowIndex and the y property containing the column index. If no
* editable cell was found then null is returned.
*/
private function getNextEditableCell(rowIndex:int, columnIndex:int, backward:Boolean):Point
{
// what is the next cell?
// increment is -1 if we are moving backward and 1 if moving
// forward.
const increment:int = backward ? -1 : 1;
//var rowIndex:int = rowIndex;
//var columnIndex:int = columnIndex;
do {
var nextColumn:int = columnIndex + increment;
if (nextColumn >= 0 && nextColumn < dataGrid.columns.length)
{
columnIndex += increment;
}
else
{
// move to next row.
columnIndex = backward ? dataGrid.grid.columns.length - 1: 0;
var nextRow:int = rowIndex + increment;
if (nextRow >= 0 && nextRow < dataGrid.dataProvider.length)
rowIndex += increment;
else
return null;
}
} while (!canEditColumn(columnIndex));
return new Point(rowIndex, columnIndex);
}
/**
* @private
*
* @param columnIndex
*
* @return true if the column can be edited, false otherwise.
*/
private function canEditColumn(columnIndex:int):Boolean
{
var column:GridColumn = grid.columns.getItemAt(columnIndex) as GridColumn;
return (dataGrid.editable &&
column.editable &&
column.visible);
}
/**
* @private
*
* Test if the cell was selected at the last selection snapshot.
*/
private function wasCellPreviouslySelected(rowIndex:int, columnIndex:int):Boolean
{
if (dataGrid.isRowSelectionMode())
return dataGrid.selectionContainsIndex(rowIndex);
else if (dataGrid.isCellSelectionMode())
return dataGrid.selectionContainsCell(rowIndex, columnIndex);
return false;
}
/**
* @private
*
* Determine if a cell position is valid.
*
* @return true if valid, false otherwise.
*/
private function isValidCellPosition(rowIndex:int, cellIndex:int):Boolean
{
if (rowIndex >= 0 && rowIndex < dataGrid.dataProvider.length &&
cellIndex >= 0 && cellIndex < dataGrid.columns.length)
{
return true;
}
return false;
}
/**
* @private
*
* Add a FlexEvent.ENTER listener to all child IVisualElements.
*
* @param element add listener to element and its children.
* @param addListener if true add a listener, otherwise remove a listener.
*/
private function addRemoveFlexEventEnterListener(element:DisplayObject, addListener:Boolean):void
{
if (addListener)
element.addEventListener(FlexEvent.ENTER, editor_enterHandler);
else
element.removeEventListener(FlexEvent.ENTER, editor_enterHandler);
if (element is DisplayObjectContainer)
{
var container:DisplayObjectContainer = DisplayObjectContainer(element);
var n:int = container.numChildren;
for (var i:int = 0; i < n; i++)
{
var child:DisplayObject = container.getChildAt(i);
if (child is DisplayObjectContainer)
{
addRemoveFlexEventEnterListener(child, addListener);
}
else
{
if (addListener)
child.addEventListener(FlexEvent.ENTER, editor_enterHandler);
else
child.removeEventListener(FlexEvent.ENTER, editor_enterHandler);
}
}
}
}
/**
* @private
* Check if a mouse click occured within the editor.
*
* @param event A MouseEvent or a SandboxMouseEvent
*
* @return true if the target is within the editor, false otherwise.
*/
private function editorOwnsClick(event:Event):Boolean
{
if (event is MouseEvent)
{
var target:IUIComponent = getIUIComponent(DisplayObject(event.target));
if (target)
return editorOwns(target);
}
return false;
}
/**
* @private
* Check if a child is contained within the editor using the owns() method.
* The editor can be either editedItemRenderer or itemEditorInstance.
*
* @param child child to test.
* @return true if the child is owned by the editor.
*/
private function editorOwns(child:IUIComponent):Boolean
{
return (itemEditorInstance &&
(itemEditorInstance == child ||
IUIComponent(itemEditorInstance).owns(DisplayObject(child))) ||
(editedItemRenderer &&
(editedItemRenderer == child ||
IUIComponent(editedItemRenderer).owns(DisplayObject(child)))));
}
/**
* @private
* The IUIComponent related to a given object. If the object is not a IUIComponent
* then work up the display list until we find a IUIComponent.
* @param displayObject The object to get a IUIComponet from.
* @return returns the displayObject if it is a display object or its
* closest parent that is a display object.
*/
private function getIUIComponent(displayObject:DisplayObject):IUIComponent
{
if (displayObject is IUIComponent)
return IUIComponent(displayObject);
var current:DisplayObject = displayObject.parent;
while (current)
{
if (current is IUIComponent)
return IUIComponent(current);
current = current.parent;
}
return null;
}
/**
* @private
*
* Restore the focusable children flags.
*/
private function restoreFocusableChildrenFlags():void
{
dataGrid.hasFocusableChildren = saveDataGridHasFocusableChildren;
if (dataGrid.scroller)
dataGrid.scroller.hasFocusableChildren = saveScrollerHasFocusableChildren;
}
/**
* @private
*
* Get the effective mouse event that activates an editor.
* If the column has a setting, then use it. Otherwise use the setting on
* the data grid.
*/
private function getEditorActivationMouseEvent(columnIndex:int):String
{
var editorActivationMouseEvent:String = null;
if (columnIndex >= 0 && columnIndex < dataGrid.columns.length)
{
var column:GridColumn = grid.columns.getItemAt(columnIndex) as GridColumn;
editorActivationMouseEvent = column.editorActivationMouseEvent;
}
if (!editorActivationMouseEvent)
editorActivationMouseEvent = dataGrid.editorActivationMouseEvent;
return editorActivationMouseEvent;
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* @private
*
* Default handler for the startItemEditorSession event.
*
*/
private function dataGrid_gridItemEditorSessionStartingHandler(event:GridItemEditorEvent):void
{
// trace("itemEditorItemEditBeginningHandler");
if (!event.isDefaultPrevented())
{
setEditedItemPosition({columnIndex: event.column.columnIndex, rowIndex: event.rowIndex});
}
else if (!itemEditorInstance)
{
_editedItemPosition = null;
// return focus to the grid w/o selecting an item
dataGrid.setFocus();
}
}
/**
* @private
*
* Handle the F2 key to start editing a cell.
*/
private function dataGrid_keyboardDownHandler(event:KeyboardEvent):void
{
if (!dataGrid.editable || dataGrid.selectionMode == GridSelectionMode.NONE)
return;
if (event.isDefaultPrevented())
return;
lastEvent = event;
if (event.keyCode == dataGrid.editKey)
{
// ignore F2 if we are already editing a cell or the column is not
// editable
if (itemEditorInstance)
return;
// Edit the last column edited. If no last column then try to
// edit the first column.
var nextCell:Point = null;
if (dataGrid.isRowSelectionMode())
{
var lastColumn:int = lastEditedItemPosition ? lastEditedItemPosition.columnIndex : 0;
openEditorInNextEditableCell(dataGrid.grid.caretRowIndex,
lastColumn - 1,
false);
return;
}
else if (canEditColumn(grid.caretColumnIndex))
{
dataGrid.startItemEditorSession(grid.caretRowIndex, grid.caretColumnIndex);
}
}
}
/**
* @private
*
*/
private function grid_gridMouseDownHandler(event:GridEvent):void
{
//trace("grid_gridMouseDownHandler");
gotDoubleClickEvent = false;
// check if the mouse was clicked outside of the editor. If it was
// then end the editing session.
if (!dataGrid.editable || editorOwnsClick(event))
return;
if (!isValidCellPosition(event.rowIndex, event.columnIndex))
return;
lastEvent = event;
const rowIndex:int = event.rowIndex;
const columnIndex:int = event.columnIndex;
//trace("grid_gridMouseDownHandler: (rowIndex, columnIndex) = (" + rowIndex + "," + columnIndex + ")");
// item editor handling
var r:IGridItemRenderer = event.itemRenderer;
lastItemDown = null;
// if selection is being modified with shift or ctrl keys then
// don't start up an editor session.
if (event.shiftKey || event.ctrlKey)
return;
// if an editor is already up, close it without starting a new editor.
if (itemEditorInstance)
{
// if the user clicks outside the cell but we can't save the data,
// say, because the data was invalid, then cancel the save.
if (!dataGrid.endItemEditorSession())
{
dataGrid.endItemEditorSession(true);
}
return;
}
var editorActivationMouseEvent:String = getEditorActivationMouseEvent(columnIndex);
if (editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK &&
editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK_ON_SELECTED_CELL)
{
return; // not allowed to start editor on a single click
}
// Don't open and editor if the click was not on a previously selected
// cell, unless that cell is an item renderer. We don't want to stop
// the item renderer from getting focus so start an edit session.
const column:GridColumn = dataGrid.columns.getItemAt(columnIndex) as GridColumn;
if (r &&
(column.rendererIsEditable ||
(wasCellPreviouslySelected(rowIndex, columnIndex) &&
editorActivationMouseEvent == GridItemEditorActivationMouseEvent.SINGLE_CLICK_ON_SELECTED_CELL) ||
editorActivationMouseEvent == GridItemEditorActivationMouseEvent.SINGLE_CLICK))
{
//trace("cell was previously selected: (" + rowIndex + "," + columnIndex + ")");
lastItemDown = r;
}
}
/**
* @private
*
* If clicked on a the same cell as mouse down then start editing the cell.
*/
private function grid_gridMouseUpHandler(event:GridEvent):void
{
//trace("grid_gridMouseUpHandler");
if (!dataGrid.editable)
return;
if (!isValidCellPosition(event.rowIndex, event.columnIndex))
return;
lastEvent = event;
const eventRowIndex:int = event.rowIndex;
const eventColumnIndex:int = event.columnIndex;
// Only start an edit if the row is the only selected row.
// Only start editing when one row is selected.
if (dataGrid.selectionLength != 1)
return;
const rowIndex:int = eventRowIndex;
var columnIndex:int = eventColumnIndex;
var editorActivationMouseEvent:String = getEditorActivationMouseEvent(columnIndex);
if (editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK &&
editorActivationMouseEvent != GridItemEditorActivationMouseEvent.SINGLE_CLICK_ON_SELECTED_CELL)
{
return; // not allowed to start editor on a single click
}
var r:IVisualElement = event.itemRenderer;
//trace("grid_gridMouseUpHandler: itemRenderer = " + event.itemRenderer);
if (r && r != editedItemRenderer &&
lastItemDown && lastItemDown == r)
{
if (columnIndex >= 0)
{
if (grid.columns.getItemAt(columnIndex).editable)
{
// Check if clicking again on the same item
if (doubleClickTimer)
{
if (rowIndex == lastItemClickedPosition.rowIndex &&
columnIndex == lastItemClickedPosition.columnIndex)
{
// Clicked on the same item again and we
// already have a timer. Wait on the existing timer.
lastItemDown == null;
return;
}
else
{
// Clicked on a different item. Stop the timer and start a new one
doubleClickTimer.stop();
doubleClickTimer = null;
}
}
lastItemClickedPosition = { columnIndex: columnIndex, rowIndex: rowIndex};
// If double click is not enabled or we want a double click to open an
// editor, then open the editor directly now. Otherwise start a timer
// and wait to see if a double click comes in that will cancel the edit.
if (dataGrid.editOnDoubleClick ||
InteractiveObject(lastItemDown).doubleClickEnabled == false)
{
// we don't need to wait on the time since editing double click is ok.
dataGrid.startItemEditorSession(rowIndex, columnIndex);
}
else
{
doubleClickTimer = new Timer(dataGrid.doubleClickTime, 1);
doubleClickTimer.addEventListener(TimerEvent.TIMER, doubleClickTimerHandler);
doubleClickTimer.start();
}
}
}
}
lastItemDown = null;
}
/**
* Grid MouseWheel event handler. Used to end the itemeditor when scrolling on the grid.
* Default action is to save the edited contents.
*
* @langversion 3.0
* @playerversion Flash 11.8
* @playerversion AIR 3.8
* @productversion Flex 4.11
*/
protected function grid_gridMouseWheelHandler(event:MouseEvent):void
{
endEdit();
}
/**
* @private
*
* If clicked on a the same cell as mouse down then start editing the cell.
*/
private function grid_gridDoubleClickHandler(event:GridEvent):void
{
//trace("grid_gridDoubleClickHandler: got double click");
if (!dataGrid.editable)
return;
if (!isValidCellPosition(event.rowIndex, event.columnIndex))
return;
lastEvent = event;
gotDoubleClickEvent = true;
// If double-click editing is enabled then start up and editor session.
var editorActivationMouseEvent:String = getEditorActivationMouseEvent(event.columnIndex);
if (editorActivationMouseEvent == GridItemEditorActivationMouseEvent.DOUBLE_CLICK)
dataGrid.startItemEditorSession(event.rowIndex, event.columnIndex);
}
/**
* @private
*
* Timer for double click events.
*/
private function doubleClickTimerHandler(event:TimerEvent):void
{
//trace("doubleClickTimerHandler");
doubleClickTimer.removeEventListener(TimerEvent.TIMER, doubleClickTimerHandler);
doubleClickTimer = null;
if (!gotDoubleClickEvent)
{
dataGrid.startItemEditorSession(lastItemClickedPosition.rowIndex, lastItemClickedPosition.columnIndex);
}
gotDoubleClickEvent = false;
}
/**
* @private
*/
private function deactivateHandler(event:Event):void
{
// If stage losing activation, set focus to DG close the editor and set
// focus back to the dataGrid.
if (itemEditorInstance || editedItemRenderer)
{
// If we can't save the data, say, because the data was invalid,
// then cancel the save.
if (!dataGrid.endItemEditorSession())
{
dataGrid.endItemEditorSession(true);
}
dataGrid.setFocus();
}
}
/**
* @private
* Closes the itemEditorInstance if the focus is outside of the data grid.
*/
private function editor_removedFromStageHandler(event:Event):void
{
if (itemEditorInstance || editedItemRenderer)
{
// If we can't save the data, say, because the data was invalid,
// then cancel the save.
if (!dataGrid.endItemEditorSession())
{
dataGrid.endItemEditorSession(true);
}
}
}
/**
* @private
* Closes the itemEditorInstance if the focus is outside of the data grid.
*/
private function editor_focusOutHandler(event:FocusEvent):void
{
//trace("editor_focusOutHandler " + event.relatedObject);
// If the focus goes to a component that is owned by the editor,
// then don't end the editor session.
if (event.relatedObject)
{
var component:IUIComponent = getIUIComponent(event.relatedObject);
if (component && editorOwns(component))
return;
}
// ignore textfields losing focus on mousedowns
if (!event.relatedObject)
return;
if (itemEditorInstance || editedItemRenderer)
{
// If we can't save the data, say, because the data was invalid,
// then cancel the save.
if (!dataGrid.endItemEditorSession())
{
dataGrid.endItemEditorSession(true);
}
}
}
/**
* @private
* Special case for TextArea control. See editor_keyDownHandler.
* ColorPicker also dispatches the "enter" event so keep the
* parameter of type Event, not FlexEvent.
*/
private function editor_enterHandler(event:Event):void
{
//trace("FlexEvent" );
if (event is FlexEvent)
gotFlexEnterEvent = true;
}
/**
* @private
*
* Handle keys on the editor to stop the editing session.
*/
private function editor_keyDownHandler(event:KeyboardEvent):void
{
//trace("keyboard event = " + event);
if (event.isDefaultPrevented())
{
// Special case the ENTER key since TextArea cancels the ENTER when it
// doesn't use it but instead it dispatches an FlexEvent.ENTER.
// The problem is the ENTER event does not have the control and
// shift key flags we need.
if (!(event.charCode == Keyboard.ENTER && gotFlexEnterEvent))
{
gotFlexEnterEvent = false;
return;
}
}
gotFlexEnterEvent = false;
// ESC just kills the editor, no new data
if (event.keyCode == Keyboard.ESCAPE)
{
cancelEdit();
}
else if (event.ctrlKey && event.charCode == 46)
{ // Check for Ctrl-.
cancelEdit();
}
else if (event.charCode == Keyboard.ENTER && event.keyCode != 229)
{
if (!_editedItemPosition)
return;
// If the ctrl or ctrl and shift keys are down then set a flag to
// avoid changing the focusable children flag becaue
// need to be redone when starting up the editor again.
if (event.ctrlKey || (event.ctrlKey && event.shiftKey))
restoreFocusableChildren = false;
// Enter closes the editor.
// The 229 keyCode is for IME compatability. When entering an IME expression,
// the enter key is down, but the keyCode is 229 instead of the enter key code.
// Thanks to Yukari for this little trick...
if (dataGrid.endItemEditorSession())
{
if (grid.focusManager)
grid.focusManager.defaultButtonEnabled = false;
if (event.ctrlKey || (event.ctrlKey && event.shiftKey))
{
var lastRow:int = lastEditedItemPosition ? lastEditedItemPosition.rowIndex : 0;
var lastColumn:int = lastEditedItemPosition ? lastEditedItemPosition.columnIndex : 0;
if (event.shiftKey)
lastRow -= 1;
else
lastRow += 1;
// If we have a valid next row, then start another editor.
if (lastRow >= 0 && lastRow < dataGrid.dataProvider.length)
{
if (!openEditorInNextEditableCell(lastRow, lastColumn - 1, false))
{
// We didn't start an editor so restore the data grid's
// focusable chidlren flags.
restoreFocusableChildren = true;
restoreFocusableChildrenFlags();
}
}
}
}
}
// Prevent the DataGrid from processing any keystrokes that were
// received by the editor. We don't cancel the keystokes here
// because on AIR that cancels text input into the text field.
// We need to let the copy/cut/past combinations pass through
// because they need to reach the NativeApplication in order to
// be correctly processed by the item editors.
// Note on Mac OS ctrlKey covers ctrl and command keys
if (!event.ctrlKey)
{
event.stopPropagation();
}
}
/**
* @private
* handle focus changes generated from keyboard keys.
*/
private function editor_keyFocusChangeHandler(event:FocusEvent):void
{
// if we tabbed out of the edit then prevent the tab and
// save the edit. Next start up a new edit session in the
// next cell.
//trace("editor_editor_keyFocusChangeHandler");
lastEvent = event;
if (itemEditorInstance || editedItemRenderer)
{
if (event.isDefaultPrevented())
return;
var nextObject:IFocusManagerComponent = grid.focusManager.getNextFocusManagerComponent(event.shiftKey);
if (nextObject == itemEditorInstance ||
(itemEditorInstance && !DisplayObjectContainer(itemEditorInstance).contains(DisplayObject(nextObject))) ||
(!itemEditorInstance &&
(nextObject == editedItemRenderer ||
(editedItemRenderer && !DisplayObjectContainer(editedItemRenderer).contains(DisplayObject(nextObject))))))
{
event.preventDefault();
restoreFocusableChildren = false;
dataGrid.endItemEditorSession();
if (!openEditorInNextEditableCell(lastEditedItemPosition.rowIndex,
lastEditedItemPosition.columnIndex,
event.shiftKey))
{
// We didn't start an editor so restore the data grid's
// focusable chidlren flags.
restoreFocusableChildren = true;
restoreFocusableChildrenFlags();
}
}
}
}
/**
* @private
*/
private function editorAncestorResizeHandler(event:Event):void
{
// If we can't save the data, say, because the data was invalid,
// then cancel the save.
if (!dataGrid.endItemEditorSession())
{
dataGrid.endItemEditorSession(true);
}
}
/**
* @private
*/
private function sandBoxRoot_mouseDownHandler(event:Event):void
{
if (editorOwnsClick(event))
{
return;
}
// If clicked on the scroll bars then keep the editor up
if (dataGrid.scroller &&
dataGrid.scroller.contains(DisplayObject(event.target)) &&
!grid.contains(DisplayObject(event.target)))
{
return;
}
// If we can't save the data, say, because the data was invalid,
// then cancel the save.
if (!dataGrid.endItemEditorSession())
{
dataGrid.endItemEditorSession(true);
}
// If the item editor was destroyed then set focus back to the grid
// so grid logic will deal if focus doesn't end up somewhere else.
if (!itemEditorInstance)
dataGrid.setFocus();
}
}
}