//////////////////////////////////////////////////////////////////////////////// // // 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.automation.delegates.components.supportClasses { import flash.display.DisplayObject; import flash.events.Event; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.ui.Keyboard; import flash.utils.getTimer; import mx.automation.Automation; import mx.automation.AutomationIDPart; import mx.automation.IAutomationClass; import mx.automation.IAutomationObject; import mx.automation.IAutomationObjectHelper; import mx.automation.IAutomationTabularData; import mx.automation.delegates.DragManagerAutomationImpl; import mx.automation.events.AutomationDragEvent; import mx.core.IVisualElement; import mx.core.mx_internal; import mx.managers.DragManager; import mx.utils.StringUtil; import spark.automation.events.SparkListItemSelectEvent; import spark.automation.tabularData.SparkListBaseTabularData; import spark.components.IItemRenderer; import spark.components.supportClasses.ListBase; import spark.events.RendererExistenceEvent; import spark.layouts.HorizontalLayout; import spark.layouts.VerticalLayout; use namespace mx_internal; [Mixin] /** * * Defines methods and properties required to perform instrumentation for the * ListBase class. * * @see spark.components.supportClasses.ListBase * * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public class SparkListBaseAutomationImpl extends SparkSkinnableContainerBaseAutomationImpl { include "../../../../core/Version.as"; //-------------------------------------------------------------------------- // // Class methods // //-------------------------------------------------------------------------- /** * Registers the delegate class for a component class with automation manager. * * @param root The SystemManger of the application. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public static function init(root:DisplayObject):void { Automation.registerDelegateClass(spark.components.supportClasses.ListBase, SparkListBaseAutomationImpl); } //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * @param obj ListBase object to be automated. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function SparkListBaseAutomationImpl(obj:spark.components.supportClasses.ListBase) { super(obj); obj.addEventListener(Event.ADDED, childAddedHandler, false, 0, true); } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private * storage for the owner component */ protected function get sparkListBase():spark.components.supportClasses.ListBase { return uiComponent as spark.components.supportClasses.ListBase; } /** * @private */ protected var preventDragDropRecording:Boolean = true; /** * @private */ protected var shiftKeyDown:Boolean = false; /** * @private */ protected var ctrlKeyDown:Boolean = false; //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @private */ protected function recordListItemSelectEvent(item:IItemRenderer, trigger:Event, cacheable:Boolean=true):void { var selected:Boolean = false; if(sparkListBase.selectedItem == item.data) selected = true; var selectionType:String = SparkListItemSelectEvent.SELECT; var keyEvent:KeyboardEvent = trigger as KeyboardEvent; var mouseEvent:MouseEvent = trigger as MouseEvent; var indexSelection:Boolean = false; if (!Automation.automationManager || !Automation.automationManager.automationEnvironment || !Automation.automationManager.recording) return ; var automationClass:IAutomationClass = Automation.automationManager.automationEnvironment.getAutomationClassByInstance(sparkListBase); if (automationClass) { var propertyNameMap:Object = automationClass.propertyNameMap; if (propertyNameMap["enableIndexBasedSelection"]) { var message:String = "TBD - We should find the item renderer and convert it to index"; Automation.automationDebugTracer.traceMessage("SparkListBaseAutomationImpl","recordListItemSelectEvent()",message); selectionType = SparkListItemSelectEvent.SELECT_INDEX; indexSelection = true; } } var event:SparkListItemSelectEvent = new SparkListItemSelectEvent(selectionType); if (indexSelection) fillItemRendererIndex(item, event); else event.itemRenderer = item; event.triggerEvent = trigger; if (keyEvent) { event.ctrlKey = keyEvent.ctrlKey; event.shiftKey = keyEvent.shiftKey; event.altKey = keyEvent.altKey; } else if (mouseEvent) { event.ctrlKey = mouseEvent.ctrlKey; event.shiftKey = mouseEvent.shiftKey; event.altKey = mouseEvent.altKey; } recordAutomatableEvent(event, cacheable); } //-------------------------------------------------------------------------- // // Overridden methods // //-------------------------------------------------------------------------- /** * @private */ override protected function componentInitialized():void { // Sometimes List doesn't get initialized by the time constructor of // this delegate is called. // For ex: In TitleWindow - http://bugs.adobe.com/jira/browse/FLEXENT-1128 // So instead of calling these code directly from the constructor, we call it // on component initialization. addMouseClickHandlerToExistingRenderers(); if(sparkListBase.dataGroup) { sparkListBase.dataGroup.addEventListener( RendererExistenceEvent.RENDERER_ADD, dataGroup_rendererAddHandler, false, 0, true); sparkListBase.dataGroup.addEventListener( RendererExistenceEvent.RENDERER_REMOVE, dataGroup_rendererRemoveHandler, false, 0 , true); } super.componentInitialized(); } //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- /** * @private */ mx_internal var itemAutomationNameFunction:Function = getItemAutomationValue; /** * @private */ public function getItemAutomationValue(item:IAutomationObject):String { // check for atleast one non-null item var values:Array = item.automationValue; if (values) { var n:int = values.length; for (var i:int = 0; i < n; i++) { if (values[i]) return values.join(" | "); // found one non null item, so return } } return null; } /** * @private */ public function getItemAutomationName(item:IAutomationObject):String { return item.automationName; } /** * @private */ public function getItemAutomationIndex(item:IAutomationObject):String { return String("index:" + sparkListBase.dataGroup.getChildIndex(item as DisplayObject)); } //-------------------------------------------------------------------------- // // Overridden properties // //-------------------------------------------------------------------------- //---------------------------------- // automationValue //---------------------------------- /** * @private */ override public function get automationValue():Array { var result:Array = []; return result; } /** * @private */ override public function createAutomationIDPart(child:IAutomationObject):Object { var help:IAutomationObjectHelper = Automation.automationObjectHelper; return (help ? help.helpCreateIDPart(uiAutomationObject, child, itemAutomationNameFunction, getItemAutomationIndex) : null); } /** * @private */ override public function createAutomationIDPartWithRequiredProperties(child:IAutomationObject, properties:Array):Object { var help:IAutomationObjectHelper = Automation.automationObjectHelper; return (help ? help.helpCreateIDPartWithRequiredProperties(uiAutomationObject, child, properties,itemAutomationNameFunction, getItemAutomationIndex) : null); } /** * @private */ override public function resolveAutomationIDPart(part:Object):Array { var help:IAutomationObjectHelper = Automation.automationObjectHelper; return help ? help.helpResolveIDPart(uiAutomationObject, part) : null; } /** * private */ protected function getVisibleRowsRenderers():Array { var visibleRows:Array = new Array(); var count:int = sparkListBase.dataGroup?sparkListBase.dataGroup.numElements:0; var startIndex:int = 0; if(sparkListBase.useVirtualLayout == false) { if(sparkListBase.layout is VerticalLayout) { startIndex = ((sparkListBase.layout)as VerticalLayout).firstIndexInView; count = ((sparkListBase.layout)as VerticalLayout).lastIndexInView+1; } else if (sparkListBase.layout is HorizontalLayout) { startIndex = ((sparkListBase.layout)as HorizontalLayout).firstIndexInView; count = ((sparkListBase.layout)as HorizontalLayout).lastIndexInView+1; } } for (var i:int = startIndex; i 0) { result--; if (col != 0) col--; else if (row != 0) { row--; col = listItems[0].length - 1; } } return result; } /** * @private */ override public function getAutomationChildAt(index:int):IAutomationObject { var listItems:Array = getVisibleRowsRenderers(); var numCols:int = listItems? listItems[0].length:0; var row:uint = uint(numCols == 0 ? 0 : index / numCols); var col:uint = uint(numCols == 0 ? index : index % numCols); var item:IAutomationObject = listItems[row][col]; return item; } /** * @private */ override public function getAutomationChildren():Array { var childrenList:Array = new Array(); var listItems:Array = getVisibleRowsRenderers(); // we get this as the 2 dim array of row and columns // we need to make this as single element array //while (!listItems[row][col] var rowcount:int = listItems?listItems.length:0; if (rowcount != 0) { var coulumcount:int = 0; if ((listItems[0]) is Array) coulumcount = (listItems[0] as Array).length; for (var i:int = 0; i < rowcount ; i++) { for(var j:int = 0; j < coulumcount ; j++) { var item:IItemRenderer = listItems[i][j]; if(item) childrenList.push(item as IAutomationObject); } } } childrenList = addScrollers(childrenList); return childrenList; } /** * private */ protected function addScrollers(chilArray:Array):Array { var count:int = sparkListBase.numChildren; for (var i:int=0; i= completeTime; }); var lise:SparkListItemSelectEvent = SparkListItemSelectEvent(event); if (event.type == SparkListItemSelectEvent.SELECT_INDEX) { lise.itemRenderer = sparkListBase.dataGroup.getElementAt(lise.itemIndex) as IItemRenderer; } else { if (!lise.itemRenderer) findItemRenderer(lise); } // keyboard and mouse are currently treated the same if (lise.triggerEvent is MouseEvent) { return replayMouseClickOnItem(lise.itemRenderer, lise.ctrlKey, lise.shiftKey, lise.altKey); } else if (lise.triggerEvent is KeyboardEvent) { return help.replayKeyDownKeyUp(lise.itemRenderer, Keyboard.SPACE, lise.ctrlKey, lise.shiftKey, lise.altKey); } else { throw new Error(); } } case AutomationDragEvent.DRAG_START: case AutomationDragEvent.DRAG_DROP: case AutomationDragEvent.DRAG_COMPLETE: { return DragManagerAutomationImpl.replayAutomatableEvent(uiAutomationObject, event); } // fall thru if not dragging while scroll occurs default: { return super.replayAutomatableEvent(event); } } } /** * @private * Plays back MouseEvent.CLICK on the item renderer. */ protected function replayMouseClickOnItem(item:IItemRenderer, ctrlKey:Boolean = false, shiftKey:Boolean = false, altKey:Boolean = false):Boolean { var me:MouseEvent = new MouseEvent(MouseEvent.CLICK); me.ctrlKey = ctrlKey; me.altKey = altKey; me.shiftKey = shiftKey; var help:IAutomationObjectHelper = Automation.automationObjectHelper; return help.replayClick(item, me); } //-------------------------------------------------------------------------- // // Event handlers // //-------------------------------------------------------------------------- /** * @private */ public function childAddedHandler(event:Event):void { } /** * @private */ protected function dataGroup_rendererAddHandler(event:RendererExistenceEvent):void { var renderer:IVisualElement = event.renderer; if (renderer) renderer.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler,false,-100,true); if(renderer is IAutomationObject) IAutomationObject(renderer).showInAutomationHierarchy = true; } /** * @private */ protected function dataGroup_rendererRemoveHandler(event:RendererExistenceEvent):void { var renderer:Object = event.renderer; if (renderer) renderer.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); } protected function addMouseClickHandlerToExistingRenderers():void { var count:int = sparkListBase.dataGroup? sparkListBase.dataGroup.numElements:0; for (var i:int = 0; i