package mx.managers.dragClasses { import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.display.InteractiveObject; import flash.events.IEventDispatcher; import flash.events.Event; 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.IUIComponent; import mx.core.mx_internal; import mx.core.UIComponent; 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.SandboxMouseEvent; import mx.events.InterManagerRequest; import mx.managers.CursorManager; import mx.managers.DragManager; import mx.managers.ISystemManager; import mx.managers.SystemManager; import mx.styles.CSSStyleDeclaration; import mx.styles.StyleManager; use namespace mx_internal; [ExcludeClass] /** * @private * A helper class for DragManager that displays the drag image * * THIS IS A MONKEY-PATCH HACK * * This file has been Monkey-Patched to override the animation * that occurs when you drop a draggable item. * * At runtime this class will override the Flex SDK version of * DragProxy, it is identical to the 3.5.0 version of this class * apart from the fact that it ovverides the drop animation * */ public class DragProxy extends UIComponent { //include "../../core/Version.as"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. */ 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(); } //-------------------------------------------------------------------------- // // 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.getStyleDeclaration("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; 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 */ var tlr:IEventDispatcher = systemManager.getTopLevelRoot(); /* having trouble with getObjectsUnderPoint. Some things seem to get in list like cursors that shouldn't. We roll our own for sandboxed apps and it works better for now. if (tlr) targetList = DisplayObjectContainer(tlr). getObjectsUnderPoint(stagePoint); else { */ 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 = 0; e.play(); var m:Move = new Move(this); m.addEventListener(EffectEvent.EFFECT_END, effectEndHandler); m.xFrom = x; m.yFrom = this.y; m.xTo = parent.mouseX; m.yTo = parent.mouseY; m.duration = 0; 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 */ 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? } } } } } } } } } }