| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.managers.dragClasses |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import flash.display.InteractiveObject; |
| import flash.events.Event; |
| import flash.events.IEventDispatcher; |
| import flash.events.KeyboardEvent; |
| import flash.events.MouseEvent; |
| import flash.geom.Point; |
| import flash.system.ApplicationDomain; |
| import flash.utils.getQualifiedClassName; |
| |
| import mx.core.DragSource; |
| import mx.core.IFlexModule; |
| import mx.core.IUIComponent; |
| import mx.core.UIComponent; |
| import mx.core.mx_internal; |
| import mx.effects.EffectInstance; |
| import mx.effects.Move; |
| import mx.effects.Zoom; |
| import mx.events.DragEvent; |
| import mx.events.EffectEvent; |
| import mx.events.InterDragManagerEvent; |
| import mx.events.InterManagerRequest; |
| import mx.events.SandboxMouseEvent; |
| import mx.managers.CursorManager; |
| import mx.managers.DragManager; |
| import mx.managers.ISystemManager; |
| import mx.managers.SystemManager; |
| import mx.modules.ModuleManager; |
| import mx.styles.CSSStyleDeclaration; |
| import mx.styles.IStyleManager2; |
| import mx.styles.StyleManager; |
| |
| use namespace mx_internal; |
| |
| [ExcludeClass] |
| |
| /** |
| * @private |
| * A helper class for DragManager that displays the drag image |
| */ |
| public class DragProxy extends UIComponent |
| { |
| include "../../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function DragProxy(dragInitiator:IUIComponent, |
| dragSource:DragSource) |
| { |
| super(); |
| |
| this.dragInitiator = dragInitiator; |
| this.dragSource = dragSource; |
| |
| var sm:ISystemManager = dragInitiator.systemManager. |
| topLevelSystemManager as ISystemManager; |
| |
| var ed:IEventDispatcher = sandboxRoot = sm.getSandboxRoot(); |
| |
| ed.addEventListener(MouseEvent.MOUSE_MOVE, |
| mouseMoveHandler, true); |
| |
| ed.addEventListener(MouseEvent.MOUSE_UP, |
| mouseUpHandler, true); |
| |
| ed.addEventListener(KeyboardEvent.KEY_DOWN, |
| keyDownHandler); |
| |
| ed.addEventListener(KeyboardEvent.KEY_UP, |
| keyUpHandler); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function initialize():void |
| { |
| super.initialize(); |
| |
| // in case we go offscreen |
| dragInitiator.systemManager.getSandboxRoot().addEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, |
| mouseLeaveHandler); |
| |
| // Make sure someone has focus, otherwise we |
| // won't get keyboard events. |
| if (!getFocus()) |
| setFocus(); |
| } |
| |
| /** |
| * @private |
| */ |
| override public function get styleManager():IStyleManager2 |
| { |
| // If the dragInitiator has a styleManager, use that one. |
| // In a situation where a main application that loads a module with drag initiator, |
| // the main application may not link in the DragManager and appropriate styles. |
| // We want to use the styles of the module of the dragInitiator. See SDK-24324. |
| if (this.dragInitiator is IFlexModule) |
| return StyleManager.getStyleManager(IFlexModule(dragInitiator).moduleFactory); |
| |
| return super.styleManager; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Class of current cursor being displayed. |
| */ |
| private var cursorClass:Class = null; |
| |
| /** |
| * @private |
| * ID of current cursor. |
| */ |
| private var cursorID:int = CursorManager.NO_CURSOR; |
| |
| /** |
| * @private |
| * Last keyboard event received |
| */ |
| private var lastKeyEvent:KeyboardEvent; |
| |
| /** |
| * @private |
| * Last Mouse event received |
| */ |
| private var lastMouseEvent:MouseEvent; |
| |
| /** |
| * @private |
| * Root of sandbox |
| */ |
| private var sandboxRoot:IEventDispatcher; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| public var dragInitiator:IUIComponent; |
| |
| /** |
| * @private |
| */ |
| public var dragSource:DragSource; |
| |
| /** |
| * @private |
| */ |
| public var xOffset:Number; |
| |
| /** |
| * @private |
| */ |
| public var yOffset:Number; |
| |
| /** |
| * @private |
| */ |
| public var startX:Number; |
| |
| /** |
| * @private |
| */ |
| public var startY:Number; |
| |
| /** |
| * @private |
| */ |
| public var target:DisplayObject = null; |
| |
| /** |
| * @private |
| * Current drag action - NONE, COPY, MOVE or LINK |
| */ |
| public var action:String; |
| |
| /** |
| * @private |
| * whether move is allowed or not |
| */ |
| public var allowMove:Boolean = true; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| public function showFeedback():void |
| { |
| var newCursorClass:Class = cursorClass; |
| var styleSheet:CSSStyleDeclaration = |
| styleManager.getMergedStyleDeclaration("mx.managers.DragManager"); |
| |
| if (action == DragManager.COPY) |
| newCursorClass = styleSheet.getStyle("copyCursor"); |
| else if (action == DragManager.LINK) |
| newCursorClass = styleSheet.getStyle("linkCursor"); |
| else if (action == DragManager.NONE) |
| newCursorClass = styleSheet.getStyle("rejectCursor"); |
| else |
| newCursorClass = styleSheet.getStyle("moveCursor"); |
| |
| if (newCursorClass != cursorClass) |
| { |
| cursorClass = newCursorClass; |
| if (cursorID != CursorManager.NO_CURSOR) |
| cursorManager.removeCursor(cursorID); |
| cursorID = cursorManager.setCursor(cursorClass, 2, 0, 0); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| public function checkKeyEvent(event:KeyboardEvent):void |
| { |
| if (target) |
| { |
| // Ignore repeat events. We only send the dragOver |
| // event when the key state changes. |
| if (lastKeyEvent |
| && (event.type == lastKeyEvent.type) |
| && (event.keyCode == lastKeyEvent.keyCode)) |
| { |
| return; |
| } |
| |
| lastKeyEvent = event; |
| |
| // Dispatch a "dragOver" event. |
| var dragEvent:DragEvent = new DragEvent(DragEvent.DRAG_OVER); |
| dragEvent.dragInitiator = dragInitiator; |
| dragEvent.dragSource = dragSource; |
| dragEvent.action = action; |
| dragEvent.ctrlKey = event.ctrlKey; |
| dragEvent.altKey = event.altKey; |
| dragEvent.shiftKey = event.shiftKey; |
| var pt:Point = new Point(); |
| pt.x = lastMouseEvent.localX; |
| pt.y = lastMouseEvent.localY; |
| pt = DisplayObject(lastMouseEvent.target).localToGlobal(pt); |
| pt = DisplayObject(target).globalToLocal(pt); |
| dragEvent.localX = pt.x; |
| dragEvent.localY = pt.y; |
| |
| _dispatchDragEvent(target, dragEvent); |
| |
| showFeedback(); |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override protected function keyDownHandler(event:KeyboardEvent):void |
| { |
| // On every key down call the mouseMove because the drag |
| // feedback may change |
| checkKeyEvent(event); |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function keyUpHandler(event:KeyboardEvent):void |
| { |
| checkKeyEvent(event); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| |
| /** |
| * @private |
| */ |
| public function stage_mouseMoveHandler(event:MouseEvent):void |
| { |
| if (event.target != stage) |
| return; |
| |
| mouseMoveHandler(event); |
| } |
| |
| /** |
| * @private |
| */ |
| private function dispatchDragEvent(type:String, mouseEvent:MouseEvent, eventTarget:Object):void |
| { |
| var dragEvent:DragEvent = new DragEvent(type); |
| var pt:Point = new Point(); |
| |
| dragEvent.dragInitiator = dragInitiator; |
| dragEvent.dragSource = dragSource; |
| dragEvent.action = action; |
| dragEvent.ctrlKey = mouseEvent.ctrlKey; |
| dragEvent.altKey = mouseEvent.altKey; |
| dragEvent.shiftKey = mouseEvent.shiftKey; |
| pt.x = lastMouseEvent.localX; |
| pt.y = lastMouseEvent.localY; |
| pt = DisplayObject(lastMouseEvent.target).localToGlobal(pt); |
| pt = DisplayObject(eventTarget).globalToLocal(pt); |
| dragEvent.localX = pt.x; |
| dragEvent.localY = pt.y; |
| _dispatchDragEvent(DisplayObject(eventTarget), dragEvent); |
| } |
| |
| /** |
| * @private |
| */ |
| private function _dispatchDragEvent(target:DisplayObject, event:DragEvent):void |
| { |
| // in trusted mode, the target could be in another application domain |
| // in untrusted mode, the mouse events shouldn't work so we shouldn't be here |
| |
| // same domain |
| if (isSameOrChildApplicationDomain(target)) |
| target.dispatchEvent(event); |
| else |
| { |
| // wake up all the other DragManagers |
| var me:InterManagerRequest = new InterManagerRequest(InterManagerRequest.INIT_MANAGER_REQUEST); |
| me.name = "mx.managers::IDragManager"; |
| sandboxRoot.dispatchEvent(me); |
| // bounce this message off the sandbox root and hope |
| // another DragManager picks it up |
| var mde:InterDragManagerEvent = new InterDragManagerEvent(InterDragManagerEvent.DISPATCH_DRAG_EVENT, false, false, |
| event.localX, |
| event.localY, |
| event.relatedObject, |
| event.ctrlKey, |
| event.altKey, |
| event.shiftKey, |
| event.buttonDown, |
| event.delta, |
| target, |
| event.type, |
| event.dragInitiator, |
| event.dragSource, |
| event.action, |
| event.draggedItem |
| ); |
| sandboxRoot.dispatchEvent(mde); |
| } |
| } |
| |
| private function isSameOrChildApplicationDomain(target:Object):Boolean |
| { |
| var swfRoot:DisplayObject = SystemManager.getSWFRoot(target); |
| if (swfRoot) |
| return true; |
| |
| if (ModuleManager.getAssociatedFactory(target)) |
| return true; |
| |
| var me:InterManagerRequest = new InterManagerRequest(InterManagerRequest.SYSTEM_MANAGER_REQUEST); |
| me.name = "hasSWFBridges"; |
| sandboxRoot.dispatchEvent(me); |
| |
| // if no bridges, it might be a private/internal class so return true and hope we're right |
| if (!me.value) return true; |
| |
| return false; |
| } |
| |
| /** |
| * @private |
| */ |
| public function mouseMoveHandler(event:MouseEvent):void |
| { |
| var dragEvent:DragEvent; |
| var dropTarget:DisplayObject; |
| var i:int; |
| |
| lastMouseEvent = event; |
| |
| var pt:Point = new Point(); |
| var point:Point = new Point(event.localX, event.localY); |
| var stagePoint:Point = DisplayObject(event.target).localToGlobal(point); |
| point = DisplayObject(sandboxRoot).globalToLocal(stagePoint); |
| var mouseX:Number = point.x; |
| var mouseY:Number = point.y; |
| x = mouseX - xOffset; |
| y = mouseY - yOffset; |
| |
| // The first time through we only want to position the proxy. |
| if (!event) |
| { |
| return; |
| } |
| |
| |
| // trace("===>DragProxy:mouseMove"); |
| var targetList:Array; /* of DisplayObject */ |
| targetList = []; |
| DragProxy.getObjectsUnderPoint(DisplayObject(sandboxRoot), stagePoint, targetList); |
| |
| var newTarget:DisplayObject = null; |
| // trace(" ", targetList.length, "objects under point"); |
| |
| // targetList is in depth order, and we want the top of the list. However, we |
| // do not want the target to be a decendent of us. |
| var targetIndex:int = targetList.length - 1; |
| while (targetIndex >= 0) |
| { |
| newTarget = targetList[targetIndex]; |
| if (newTarget != this && !contains(newTarget)) |
| break; |
| targetIndex--; |
| } |
| // trace(" skipped", targetList.length - targetIndex - 1); |
| |
| // If we already have a target, send it a dragOver event |
| // if we're still over it. |
| // If we're not over it, send it a dragExit event. |
| if (target) |
| { |
| var foundIt:Boolean = false; |
| var oldTarget:DisplayObject = target; |
| |
| dropTarget = newTarget; |
| |
| while (dropTarget) |
| { |
| if (dropTarget == target) |
| { |
| // trace(" dispatch DRAG_OVER on", dropTarget); |
| // Dispatch a "dragOver" event |
| dispatchDragEvent(DragEvent.DRAG_OVER, event, dropTarget); |
| foundIt = true; |
| break; |
| } |
| else |
| { |
| // trace(" dispatch DRAG_ENTER on", dropTarget); |
| // Dispatch a "dragEnter" event and see if a new object |
| // steals the target. |
| dispatchDragEvent(DragEvent.DRAG_ENTER, event, dropTarget); |
| |
| // If the potential target accepted the drag, our target |
| // now points to the dropTarget. Bail out here, but make |
| // sure we send a dragExit event to the oldTarget. |
| if (target == dropTarget) |
| { |
| foundIt = false; |
| break; |
| } |
| } |
| dropTarget = dropTarget.parent; |
| } |
| |
| if (!foundIt) |
| { |
| // trace(" dispatch DRAG_EXIT on", oldTarget); |
| // Dispatch a "dragExit" event on the old target. |
| dispatchDragEvent(DragEvent.DRAG_EXIT, event, oldTarget); |
| |
| if (target == oldTarget) |
| target = null; |
| } |
| } |
| |
| // If we don't have an existing target, go look for one. |
| if (!target) |
| { |
| action = DragManager.MOVE; |
| |
| // Dispatch a "dragEnter" event. |
| dropTarget = newTarget; |
| while (dropTarget) |
| { |
| if (dropTarget != this) |
| { |
| // trace(" dispatch DRAG_ENTER on", dropTarget); |
| dispatchDragEvent(DragEvent.DRAG_ENTER, event, dropTarget); |
| if (target) |
| break; |
| } |
| dropTarget = dropTarget.parent; |
| } |
| |
| if (!target) |
| action = DragManager.NONE; |
| } |
| // trace("<===DragProxy:mouseMove"); |
| |
| |
| showFeedback(); |
| } |
| |
| /** |
| * @private |
| */ |
| public function mouseLeaveHandler(event:Event):void |
| { |
| mouseUpHandler(lastMouseEvent); |
| } |
| |
| /** |
| * @private |
| */ |
| public function mouseUpHandler(event:MouseEvent):void |
| { |
| var dragEvent:DragEvent; |
| |
| var sm:ISystemManager = dragInitiator.systemManager. |
| topLevelSystemManager as ISystemManager; |
| |
| var ed:IEventDispatcher = sandboxRoot; |
| |
| ed.removeEventListener(MouseEvent.MOUSE_MOVE, |
| mouseMoveHandler, true); |
| |
| ed.removeEventListener(MouseEvent.MOUSE_UP, |
| mouseUpHandler, true); |
| |
| ed.removeEventListener(KeyboardEvent.KEY_DOWN, |
| keyDownHandler); |
| |
| // in case we go offscreen |
| ed.removeEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, |
| mouseLeaveHandler); |
| |
| ed.removeEventListener(KeyboardEvent.KEY_UP, |
| keyUpHandler); |
| var delegate:Object = automationDelegate; |
| if (target && action != DragManager.NONE) |
| { |
| // Dispatch a "dragDrop" event. |
| dragEvent = new DragEvent(DragEvent.DRAG_DROP); |
| dragEvent.dragInitiator = dragInitiator; |
| dragEvent.dragSource = dragSource; |
| dragEvent.action = action; |
| dragEvent.ctrlKey = event.ctrlKey; |
| dragEvent.altKey = event.altKey; |
| dragEvent.shiftKey = event.shiftKey; |
| var pt:Point = new Point(); |
| pt.x = lastMouseEvent.localX; |
| pt.y = lastMouseEvent.localY; |
| pt = DisplayObject(lastMouseEvent.target).localToGlobal(pt); |
| pt = DisplayObject(target).globalToLocal(pt); |
| dragEvent.localX = pt.x; |
| dragEvent.localY = pt.y; |
| if (delegate) |
| delegate.recordAutomatableDragDrop(target, dragEvent); |
| _dispatchDragEvent(target, dragEvent); |
| } |
| else |
| { |
| action = DragManager.NONE; |
| } |
| |
| // Do the drop effect. |
| // If the drop was accepted, zoom the proxy image into |
| // the current mouse location. |
| // If the drop was rejected, move the proxy image |
| // back to its original location. |
| if (action == DragManager.NONE) |
| { |
| // Tween back to original position |
| var m1:Move = new Move(this); |
| m1.addEventListener(EffectEvent.EFFECT_END, effectEndHandler); |
| m1.xFrom = x; |
| m1.yFrom = y; |
| m1.xTo = startX; |
| m1.yTo = startY; |
| m1.duration = 200; |
| m1.play(); |
| } |
| else |
| { |
| // Zoom into mouse location to show drag was accepted. |
| var e:Zoom = new Zoom(this); |
| e.zoomWidthFrom = e.zoomHeightFrom = 1.0; |
| e.zoomWidthTo = e.zoomHeightTo = 0; |
| e.duration = 200; |
| e.play(); |
| |
| var m:Move = new Move(this); |
| m.addEventListener(EffectEvent.EFFECT_END, effectEndHandler); |
| m.xFrom = x; |
| m.yFrom = y; |
| m.xTo = parent.mouseX; |
| m.yTo = parent.mouseY; |
| m.duration = 200; |
| m.play(); |
| } |
| |
| // Dispatch a "dragComplete" event. |
| dragEvent = new DragEvent(DragEvent.DRAG_COMPLETE); |
| dragEvent.dragInitiator = dragInitiator; |
| dragEvent.dragSource = dragSource; |
| dragEvent.relatedObject = InteractiveObject(target); |
| dragEvent.action = action; |
| dragEvent.ctrlKey = event.ctrlKey; |
| dragEvent.altKey = event.altKey; |
| dragEvent.shiftKey = event.shiftKey; |
| dragInitiator.dispatchEvent(dragEvent); |
| |
| if (delegate && action == DragManager.NONE) |
| delegate.recordAutomatableDragCancel(dragInitiator, dragEvent); |
| // Hide the drag cursor |
| cursorManager.removeCursor(cursorID); |
| cursorID = CursorManager.NO_CURSOR; |
| |
| this.lastMouseEvent = null; |
| } |
| |
| /** |
| * @private |
| */ |
| private function effectEndHandler(event:EffectEvent):void |
| { |
| DragManager.endDrag(); |
| } |
| |
| /** |
| * Player doesn't handle this correctly so we have to do it ourselves |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| private static function getObjectsUnderPoint(obj:DisplayObject, pt:Point, arr:Array):void |
| { |
| if (!obj.visible) |
| return; |
| |
| if ((obj is UIComponent) && !UIComponent(obj).$visible) |
| return; |
| |
| if (obj.hitTestPoint(pt.x, pt.y, true)) |
| { |
| if (obj is InteractiveObject && InteractiveObject(obj).mouseEnabled) |
| arr.push(obj); |
| if (obj is DisplayObjectContainer) |
| { |
| var doc:DisplayObjectContainer = obj as DisplayObjectContainer; |
| if (doc.mouseChildren) |
| { |
| // we use this test so we can test in other application domains |
| if ("rawChildren" in doc) |
| { |
| var rc:Object = doc["rawChildren"]; |
| n = rc.numChildren; |
| for (i = 0; i < n; i++) |
| { |
| try |
| { |
| getObjectsUnderPoint(rc.getChildAt(i), pt, arr); |
| } |
| catch (e:Error) |
| { |
| //another sandbox? |
| } |
| } |
| } |
| else |
| { |
| if (doc.numChildren) |
| { |
| var n:int = doc.numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| try |
| { |
| var child:DisplayObject = doc.getChildAt(i); |
| getObjectsUnderPoint(child, pt, arr); |
| } |
| catch (e:Error) |
| { |
| //another sandbox? |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| } |
| |
| } |