| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package spark.components.gridClasses |
| { |
| import flash.events.Event; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| import flash.utils.describeType; |
| |
| import mx.collections.ICollectionView; |
| import mx.collections.ISort; |
| import mx.core.IIMESupport; |
| import mx.core.IInvalidating; |
| import mx.core.IVisualElement; |
| import mx.core.IVisualElementContainer; |
| import mx.core.mx_internal; |
| import mx.validators.IValidatorListener; |
| |
| import spark.components.DataGrid; |
| import spark.components.Group; |
| import spark.components.gridClasses.GridColumn; |
| |
| |
| use namespace mx_internal; |
| |
| /** |
| * The GridItemEditor class defines the base class for custom item editors |
| * for the Spark grid controls, such as DataGrid and Grid. |
| * Item editors lets you edit the value of the cell of the grid, and then |
| * save that value back to the data provider of the control. |
| * |
| * <p>Item editors are associated with each column of a grid. |
| * Set the item editor for a column by using |
| * the <code>GridColumn.itemEditor property</code>.</p> |
| * |
| * @mxml <p>The <code><s:GridItemEditor></code> tag inherits all of the tag |
| * attributes of its superclass and adds the following tag attributes:</p> |
| * |
| * <pre> |
| * <s:GridItemEditor |
| * <strong>Properties</strong> |
| * column="null" |
| * data="null" |
| * imeMode="null" |
| * itemRenderer="null" |
| * rowIndex="0" |
| * value="null" |
| * /> |
| * </pre> |
| * |
| * @see spark.components.DataGrid |
| * @see spark.components.Grid |
| * @see spark.components.gridClasses.GridColumn |
| * @see spark.components.gridClasses.GridColumn#itemEditor |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public class GridItemEditor extends Group implements IGridItemEditor |
| { |
| include "../../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| public function GridItemEditor() |
| { |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // column |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _column:GridColumn; |
| |
| /** |
| * @inheritDoc |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get column():GridColumn |
| { |
| return _column; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set column(value:GridColumn):void |
| { |
| _column = value; |
| } |
| |
| //---------------------------------- |
| // columnIndex |
| //---------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get columnIndex():int |
| { |
| return column.columnIndex;; |
| } |
| |
| //---------------------------------- |
| // data |
| //---------------------------------- |
| |
| private var _data:Object = null; |
| |
| /** |
| * @inheritDoc |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get data():Object |
| { |
| return _data; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set data(value:Object):void |
| { |
| _data = value; |
| |
| if (_data && column.dataField) |
| { |
| // If complex field reference need to dig the data value out of the correct object. |
| var dataFieldPath:Array = column.dataFieldPath; |
| this.value = column.dataFieldPath.length == 1 ? |
| _data[column.dataField] : |
| column.itemToString(_data, dataFieldPath, null, null); |
| } |
| } |
| |
| //---------------------------------- |
| // dataGrid |
| //---------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dataGrid():DataGrid |
| { |
| return DataGrid(owner); |
| } |
| |
| //---------------------------------- |
| // enableIME |
| //---------------------------------- |
| |
| /** |
| * A flag that indicates whether the IME should |
| * be enabled when the component receives focus. |
| * |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get enableIME():Boolean |
| { |
| return true; |
| } |
| |
| //---------------------------------- |
| // imeMode |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _imeMode:String = null; |
| |
| [Inspectable(environment="none")] |
| |
| /** |
| * Specifies the IME (Input Method Editor) mode. |
| * The IME enables users to enter text in Chinese, Japanese, and Korean. |
| * Flex sets the specified IME mode when the control gets the focus, |
| * and sets it back to the previous value when the control loses the focus. |
| * |
| * <p>The flash.system.IMEConversionMode class defines constants for the |
| * valid values for this property. |
| * You can also specify <code>null</code> to specify no IME.</p> |
| * |
| * @see flash.system.IMEConversionMode |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get imeMode():String |
| { |
| return _imeMode; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set imeMode(value:String):void |
| { |
| _imeMode = value; |
| |
| // set the ime mode in child controls |
| var n:int = numElements; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:IIMESupport = getElementAt(i) as IIMESupport; |
| if (child) |
| { |
| child.imeMode = value; |
| } |
| } |
| |
| } |
| |
| //---------------------------------- |
| // itemRenderer |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _itemRenderer:IGridItemRenderer; |
| |
| /** |
| * The item renderer associated with the edited cell. |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get itemRenderer():IGridItemRenderer |
| { |
| return _itemRenderer; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set itemRenderer(value:IGridItemRenderer):void |
| { |
| _itemRenderer = value; |
| } |
| |
| //---------------------------------- |
| // rowIndex |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _rowIndex:int; |
| |
| /** |
| * @inheritDoc |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get rowIndex():int |
| { |
| return _rowIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set rowIndex(value:int):void |
| { |
| _rowIndex = value; |
| } |
| |
| //---------------------------------- |
| // value |
| //---------------------------------- |
| |
| private var _value:Object; |
| |
| [Bindable("valueChanged")] |
| |
| /** |
| * By default, this property is initialized by the setter method of |
| * the <code>data</code> property. |
| * The default value of this property is the cell data from the |
| * data provider of the grid control. |
| * The item editor can use this property to initialize |
| * any visual elements in the item editor. |
| * |
| * <p>By default, the <code>save()</code> method write the value of |
| * this property back to the data provider of the grid control |
| * when the editor closes on a save. </p> |
| * |
| * <p>Many custom item renderers override the getter and setter methods |
| * of this property. |
| * Override the setter method to initialize the editor based on the cell value. |
| * Override the getter method to return a new cell value to |
| * the <code>save()</code> method. </p> |
| * |
| * @default null |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get value():Object |
| { |
| return _value; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set value(newValue:Object):void |
| { |
| if (newValue != value) |
| { |
| _value = newValue |
| |
| if (hasEventListener("valueChanged")) |
| { |
| dispatchEvent(new Event("valueChanged")); |
| } |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function discard():void |
| { |
| // Clean up |
| clearErrorStringFromContainer(this); |
| removeEventListener(MouseEvent.MOUSE_UP, mouseUpDownMoveHandler); |
| removeEventListener(MouseEvent.MOUSE_DOWN, mouseUpDownMoveHandler); |
| removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function prepare():void |
| { |
| // Stop the item renderer from seeing mouse clicks on the editor. |
| addEventListener(MouseEvent.MOUSE_UP, mouseUpDownMoveHandler); |
| addEventListener(MouseEvent.MOUSE_DOWN, mouseUpDownMoveHandler); |
| |
| // Stop hover highlighting on rows underneath the editor. |
| addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function save():Boolean |
| { |
| if (!validate()) |
| return false; |
| |
| // set focus to DataGrid to force internal components to commit changes to |
| // their data properties. |
| dataGrid.setFocus(); |
| |
| var newData:Object = value; |
| var property:String; |
| var data:Object = data; |
| var typeInfo:String = ""; |
| |
| // If a complex field reference need to get the object where the property |
| // will be updated. It is a complex field reference if dataFieldPath.length > 1. |
| var dataFieldPath:Array = column.dataFieldPath; |
| for (var i:int = 0; i < dataFieldPath.length - 1; i++) |
| data = data[dataFieldPath[i]]; |
| |
| property = dataFieldPath[i]; |
| |
| for each(var variable:XML in describeType(data).variable) |
| { |
| if (property == variable.@name.toString()) |
| { |
| typeInfo = variable.@type.toString(); |
| break; |
| } |
| } |
| |
| if (typeInfo == "String") |
| { |
| if (!(newData is String)) |
| newData = newData.toString(); |
| } |
| else if (typeInfo == "uint") |
| { |
| if (!(newData is uint)) |
| newData = uint(newData); |
| } |
| else if (typeInfo == "int") |
| { |
| if (!(newData is int)) |
| newData = int(newData); |
| } |
| else if (typeInfo == "Number") |
| { |
| if (!(newData is Number)) |
| newData = Number(newData); |
| } |
| else if (typeInfo == "Boolean") |
| { |
| if (!(newData is Boolean)) |
| { |
| var strNewData:String = newData.toString(); |
| if (strNewData) |
| { |
| newData = (strNewData.toLowerCase() == "true") ? true : false; |
| } |
| } |
| } |
| |
| if (property && data[property] !== newData) |
| { |
| // If the data is sorted, turn off the sort for the edited data. |
| var sort:ISort = null; |
| if (dataGrid.dataProvider is ICollectionView) |
| { |
| var dataProvider:ICollectionView = ICollectionView(dataGrid.dataProvider); |
| if (dataProvider.sort) |
| { |
| sort = dataProvider.sort; |
| dataProvider.sort = null; |
| } |
| } |
| |
| var oldData:Object = data[property]; |
| data[property] = newData; |
| |
| // If a complex field reference then the data and property local vars were modified and |
| // no longer point to the top-level data object and the complete path to the property |
| // so use the original values. |
| dataGrid.dataProvider.itemUpdated(this.data, column.dataField, oldData, newData); |
| |
| // Restore the sort. The data will not be sorted due to this change. |
| if (sort) |
| ICollectionView(dataGrid.dataProvider).sort = sort; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function cancel():Boolean |
| { |
| return true; |
| } |
| |
| /** |
| * Tests if the value in the editor is valid and may be saved. |
| * |
| * @return <code>true</code> if the value in the editor is valid. |
| * Otherwise return <code>false</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 10 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function validate():Boolean |
| { |
| return validateContainer(this); |
| } |
| |
| /** |
| * @private |
| * |
| * Verify the container's children are valid. |
| * @param container container to verify, may not be null. |
| * @return true if the container and its children are valid, false otherwise. |
| */ |
| private function validateContainer(container:IVisualElementContainer):Boolean |
| { |
| if (container is IValidatorListener && IValidatorListener(container).errorString) |
| return false; |
| |
| // loop thru the children, looking for errors. |
| var n:int = container.numElements; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:IVisualElement = container.getElementAt(i); |
| if (child is IValidatorListener && IValidatorListener(child).errorString) |
| { |
| return false; |
| } |
| |
| if (child is IVisualElementContainer && |
| !validateContainer(IVisualElementContainer(child))) |
| { |
| return false; |
| } |
| |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @private |
| * |
| * Clear the error strings left by any validators. This will ensure any |
| * tooltips left by a validator are torn down. |
| * |
| * @param container container to verify, may not be null. |
| */ |
| private function clearErrorStringFromContainer(container:IVisualElementContainer):void |
| { |
| if (container is IValidatorListener && IValidatorListener(container).errorString) |
| { |
| clearErrorString(IValidatorListener(container)); |
| } |
| |
| // loop thru the children, looking for errors to clear. |
| var n:int = container.numElements; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:IVisualElement = container.getElementAt(i); |
| if (child is IValidatorListener && IValidatorListener(child).errorString) |
| { |
| clearErrorString(IValidatorListener(child)); |
| } |
| |
| if (child is IVisualElementContainer) |
| { |
| clearErrorStringFromContainer(IVisualElementContainer(child)); |
| } |
| } |
| |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * |
| * Clear the error string left by a validator. This will ensure any |
| * tooltips left by a validator are torn down. |
| * |
| * @param validatorListener listener to clear error message in. |
| */ |
| private function clearErrorString(validatorListener:IValidatorListener):void |
| { |
| validatorListener.errorString = ""; |
| if (validatorListener is IInvalidating) |
| { |
| IInvalidating(validatorListener).validateNow(); |
| } |
| } |
| |
| /** |
| * @private |
| * Stop the item renderer from getting the click. |
| */ |
| private function mouseUpDownMoveHandler(event:MouseEvent):void |
| { |
| if (event.cancelable) |
| event.preventDefault(); |
| } |
| |
| /** |
| * @private |
| * Stop the data grid from seeing the mouse move events. |
| */ |
| private function mouseMoveHandler(event:MouseEvent):void |
| { |
| // Redispatch the event to the dataGrid's parent and stop |
| // the event from propagating past the editor. |
| // The stopPropagation() keeps the grid from showing hover from mouse |
| // moves within the editor. |
| // Dispatching the mouse move event to the data grid's parent |
| // keeps the data grid from seeing the event and allows the |
| // RichEditableText control to see the event (it listens to the stage). |
| var pt:Point = dataGrid.parent.globalToLocal(new Point(event.stageX, event.stageY)); |
| event.localX = pt.x; |
| event.localY = pt.y; |
| dataGrid.parent.dispatchEvent(event); |
| event.stopPropagation(); |
| } |
| } |
| } |