| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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 { |
| |
| import flash.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import flash.display.InteractiveObject; |
| import flash.text.TextField; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| |
| import mx.core.mx_internal; |
| use namespace mx_internal; |
| |
| /** |
| * The test step that fakes a mouse event |
| * MXML attributes: |
| * target |
| * type |
| * ctrlKey (optional) |
| * delta (optional) |
| * localX |
| * localY |
| * relatedObject (optional) |
| * shiftKey (optional) |
| * stageX |
| * stageY |
| * waitTarget (optional) |
| * waitEvent (optional) |
| * timeout (optional); |
| */ |
| public class DispatchMouseEvent extends TestStep |
| { |
| private static var mouseX:QName = new QName(mx_internal, "_mouseX"); |
| private static var mouseY:QName = new QName(mx_internal, "_mouseY"); |
| |
| /** |
| * @private |
| */ |
| override public function execute(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):Boolean |
| { |
| if (waitEvent && waitTarget == null) |
| waitTarget = target; |
| return super.execute(root, context, testCase, testResult); |
| } |
| |
| /** |
| * Set the target's property to the specified value |
| */ |
| override protected function doStep():void |
| { |
| UnitTester.blockFocusEvents = false; |
| |
| var actualTarget:Object = context.stringToObject(target); |
| if (!actualTarget) |
| { |
| testResult.doFail("Target " + target + " not found"); |
| UnitTester.blockFocusEvents = false; |
| return; |
| } |
| |
| var event:MouseEvent = new MouseEvent(type, true); // all mouse events bubble |
| event.ctrlKey = ctrlKey; |
| event.shiftKey = shiftKey; |
| event.buttonDown = buttonDown || type == "mouseDown"; |
| event.delta = delta; |
| if (relatedObject && relatedObject.length > 0) |
| { |
| event.relatedObject = InteractiveObject(context.stringToObject(relatedObject)); |
| if (!event.relatedObject) |
| { |
| testResult.doFail("RelatedObject " + relatedObject + " not found"); |
| UnitTester.blockFocusEvents = false; |
| return; |
| } |
| } |
| |
| var stagePt:Point; |
| if (!isNaN(localX) && !isNaN(localY)) |
| { |
| stagePt = actualTarget.localToGlobal(new Point(localX, localY)); |
| } |
| else if (!isNaN(stageX) && !isNaN(stageY)) |
| { |
| stagePt = new Point(stageX, stageY); |
| } |
| else |
| { |
| stagePt = actualTarget.localToGlobal(new Point(0, 0)); |
| } |
| try { |
| root[mouseX] = stagePt.x; |
| root[mouseY] = stagePt.y; |
| UnitTester.setMouseXY(stagePt); |
| if (root["topLevelSystemManager"] != root) |
| { |
| root["topLevelSystemManager"][mouseX] = stagePt.x; |
| root["topLevelSystemManager"][mouseY] = stagePt.y; |
| } |
| } catch (e:Error) {}; // some scenarios don't support this |
| |
| if (actualTarget is DisplayObjectContainer) |
| { |
| var targets:Array = actualTarget.stage.getObjectsUnderPoint(stagePt); |
| var arr:Array = UnitTester.getObjectsUnderPoint(DisplayObject(actualTarget), stagePt); |
| targets = targets.concat(arr); |
| |
| for (var i:int = targets.length - 1; i >= 0; i--) |
| { |
| if (targets[i] is InteractiveObject) |
| { |
| if (targets[i] is TextField && !targets[i].selectable) |
| { |
| actualTarget = targets[i].parent; |
| break; |
| } |
| |
| if (isMouseTarget(InteractiveObject(targets[i]))) |
| { |
| actualTarget = targets[i]; |
| break; |
| } |
| } |
| /* else |
| { |
| try |
| { |
| actualTarget = targets[i].parent; |
| while (actualTarget) |
| { |
| if (actualTarget is InteractiveObject) |
| { |
| if (isMouseTarget(InteractiveObject(actualTarget))) |
| { |
| break; |
| } |
| } |
| actualTarget = actualTarget.parent; |
| } |
| if (actualTarget && actualTarget != root) |
| break; |
| } |
| catch (e:Error) |
| { |
| if (actualTarget) |
| break; |
| } |
| } |
| */ } |
| } |
| |
| var localPt:Point = actualTarget.globalToLocal(stagePt); |
| event.localX = localPt.x; |
| event.localY = localPt.y; |
| |
| if (actualTarget is TextField) |
| { |
| if (type == "mouseDown") |
| { |
| var charIndex:int = actualTarget.getCharIndexAtPoint(event.localX, event.localY); |
| actualTarget.setSelection(charIndex + 1, charIndex + 1); |
| } |
| } |
| |
| try |
| { |
| actualTarget.dispatchEvent(event); |
| } |
| catch (e2:Error) |
| { |
| TestOutput.logResult("Exception thrown in DispatchMouseClickEvent."); |
| testResult.doFail (e2.getStackTrace()); |
| } |
| |
| UnitTester.blockFocusEvents = true; |
| } |
| |
| /** |
| * The object that receives the mouse event |
| */ |
| public var target:String; |
| |
| /** |
| * The type of the event to send (mouseUp, mouseDown, etc). |
| */ |
| public var type:String; |
| |
| /** |
| * The buttonDown property on the MouseEvent (optional) |
| */ |
| public var buttonDown:Boolean; |
| |
| /** |
| * The ctrlKey property on the MouseEvent (optional) |
| */ |
| public var ctrlKey:Boolean; |
| |
| /** |
| * The delta property on the MouseEvent (optional) |
| */ |
| public var delta:int; |
| |
| /** |
| * The localX property on the MouseEvent (optional) |
| * Either set stageX/stageY or localX/localY, but not both. |
| */ |
| public var localX:Number; |
| |
| /** |
| * The localY property on the MouseEvent (optional) |
| * Either set stageX/stageY or localX/localY, but not both. |
| */ |
| public var localY:Number; |
| |
| /** |
| * The stageX property on the MouseEvent (optional) |
| * Either set stageX/stageY or localX/localY, but not both. |
| */ |
| public var stageX:Number; |
| |
| /** |
| * The stageY property on the MouseEvent (optional) |
| * Either set stageX/stageY or localX/localY, but not both. |
| */ |
| public var stageY:Number; |
| |
| /** |
| * The shiftKey property on the MouseEvent (optional) |
| */ |
| public var shiftKey:Boolean; |
| |
| /** |
| * The relatedObject property on the MouseEvent (optional) |
| */ |
| public var relatedObject:String; |
| |
| |
| private function isMouseTarget(target:InteractiveObject):Boolean |
| { |
| if (!target.mouseEnabled) |
| return false; |
| |
| // Examine parent chain for "mouseChildren" set to false: |
| try |
| { |
| var parent:DisplayObjectContainer = target.parent; |
| while (parent) |
| { |
| if (!parent.mouseChildren) |
| return false; |
| parent = parent.parent; |
| } |
| } |
| catch (e1:Error) |
| { |
| } |
| |
| return true; |
| } |
| |
| /** |
| * customize string representation |
| */ |
| override public function toString():String |
| { |
| var s:String = "DispatchMouseEvent: target = "; |
| s += target; |
| if (type) |
| s += ", type = " + type; |
| if (!isNaN(localX)) |
| s += ", localX = " + localX.toString(); |
| if (!isNaN(localY)) |
| s += ", localY = " + localY.toString(); |
| if (!isNaN(stageX)) |
| s += ", stageX = " + stageX.toString(); |
| if (!isNaN(stageY)) |
| s += ", stageY = " + stageY.toString(); |
| if (shiftKey) |
| s += ", shiftKey = " + shiftKey.toString(); |
| if (ctrlKey) |
| s += ", ctrlKey = " + ctrlKey.toString(); |
| if (relatedObject) |
| s += ", relatedObject = " + relatedObject.toString(); |
| if (delta) |
| s += ", delta = " + delta.toString(); |
| return s; |
| } |
| } |
| |
| } |