package org.libspark.events { import flash.events.Event; import flash.events.EventDispatcher; import flash.events.EventPhase; import flash.events.IEventDispatcher; import org.libspark.common.Any; import org.libspark.common.store.IReadableStore; import org.libspark.common.store.IWritableStore; public class HierarchicalEventDispatcher extends Any implements IHierarchicalEventDispatcher { public function HierarchicalEventDispatcher(target:IHierarchicalEventDispatcher = null) { setTarget(target); resetInternalDispatchers(); } private var _parent:IHierarchicalEventDispatcher; private var _target:IHierarchicalEventDispatcher; private var _internalDispatcher:IEventDispatcher; private var _internalCaptureDispatcher:IEventDispatcher; protected function resetInternalDispatchers():void { internalDispatcher = new EventDispatcher(actualTarget); internalCaptureDispatcher = new EventDispatcher(actualTarget); } protected function get internalDispatcher():IEventDispatcher { return _internalDispatcher; } protected function set internalDispatcher(value:IEventDispatcher):void { _internalDispatcher = value; } protected function get internalCaptureDispatcher():IEventDispatcher { return _internalCaptureDispatcher; } protected function set internalCaptureDispatcher(value:IEventDispatcher):void { _internalCaptureDispatcher = value; } public function get parentDispatcher():IHierarchicalEventDispatcher { return _parent; } public function set parentDispatcher(value:IHierarchicalEventDispatcher):void { _parent = value; } public function get target():IHierarchicalEventDispatcher { return _target; } protected function setTarget(value:IHierarchicalEventDispatcher):void { _target = value; } protected function get actualTarget():IHierarchicalEventDispatcher { return target || this; } public function dispatchCaptureEvent(event:Event):void { internalCaptureDispatcher.dispatchEvent(event); } public function dispatchBubblingEvent(event:Event):void { internalDispatcher.dispatchEvent(event); } public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void { if (useCapture) { internalCaptureDispatcher.addEventListener(type, listener, false, priority, useWeakReference); } else { internalDispatcher.addEventListener(type, listener, false, priority, useWeakReference); } } public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void { if (useCapture) { internalCaptureDispatcher.removeEventListener(type, listener, false); } else { internalDispatcher.removeEventListener(type, listener, false); } } protected function get dispatchRoute():Array { var result:Array = []; var dispatcher:IHierarchicalEventDispatcher = parentDispatcher; while (dispatcher != null) { result.unshift(dispatcher); dispatcher = dispatcher.parentDispatcher; } return result; } public function dispatchEvent(event:Event):Boolean { var e:HierarchicalEvent = event as HierarchicalEvent; if (e == null) { throw new ArgumentError("Parameter 'event' must be not null and an instance of HierarchicalEvent."); } e.setTarget(actualTarget); e.stopImmediatePropagationCalled = false; e.stopPropagationCalled = false; var route:Array = dispatchRoute; var l:int = route.length; var i:int; var dispatcher:IHierarchicalEventDispatcher; var stoped:Boolean = false; // Capture e.setEventPhase(EventPhase.CAPTURING_PHASE); for (i = 0; i < l; ++i) { dispatcher = route[i] as IHierarchicalEventDispatcher; dispatcher.dispatchCaptureEvent(e); stoped = e.stopImmediatePropagationCalled || e.stopPropagationCalled; if (stoped) { break; } } // Target if (!stoped) { e.setEventPhase(EventPhase.AT_TARGET); internalDispatcher.dispatchEvent(e); stoped = e.stopImmediatePropagationCalled || e.stopPropagationCalled; } // Bubbling if (!stoped && e.bubbles) { for (i = l - 1; i >= 0; --i) { dispatcher = route[i] as IHierarchicalEventDispatcher; dispatcher.dispatchBubblingEvent(e); stoped = e.stopImmediatePropagationCalled || e.stopPropagationCalled; if (stoped) { break; } } } return e.isDefaultPrevented(); } public function hasEventListener(type:String):Boolean { return internalDispatcher.hasEventListener(type) || internalCaptureDispatcher.hasEventListener(type); } public function willTrigger(type:String):Boolean { if (hasEventListener(type)) { return true; } var route:Array = dispatchRoute; var l:int = route.length; var i:int; var dispatcher:IHierarchicalEventDispatcher; for (i = l - 1; i >= 0; --i) { dispatcher = route[i] as IHierarchicalEventDispatcher; if (dispatcher.hasEventListener(type)) { return true; } } return false; } override public function store(to:IWritableStore):void { to.writeStorable('parentDispatcher', parentDispatcher); to.writeStorable('target', target); } override public function restore(from:IReadableStore):void { parentDispatcher = from.readStorable('parentDispatcher', null) as IHierarchicalEventDispatcher; setTarget(from.readStorable('target', null) as IHierarchicalEventDispatcher); resetInternalDispatchers(); } } }