scaffold.libs_as.org.osflash.signals.natives.NativeSignal.as Maven / Gradle / Ivy
package org.osflash.signals.natives
{
import org.osflash.signals.ISlot;
import org.osflash.signals.Slot;
import org.osflash.signals.SlotList;
import flash.errors.IllegalOperationError;
import flash.events.Event;
import flash.events.IEventDispatcher;
/**
* Allows the eventClass to be set in MXML, e.g.
* {MouseEvent}
*/
[DefaultProperty("eventClass")]
/**
* The NativeSignal class provides a strongly-typed facade for an IEventDispatcher.
* A NativeSignal is essentially a mini-dispatcher locked to a specific event type and class.
* It can become part of an interface.
*/ public class NativeSignal implements INativeDispatcher
{
protected var slots : SlotList;
protected var _target : IEventDispatcher;
/** @inheritDoc */
public function get target() : IEventDispatcher
{
return _target;
}
public function set target( value : IEventDispatcher ) : void
{
if( value == _target ) return;
if( _target ) removeAll();
_target = value;
}
protected var _eventType : String;
/** @inheritDoc */
public function get eventType() : String
{
return _eventType;
}
public function set eventType( value : String ) : void
{
_eventType = value;
}
protected var _eventClass : Class;
/** @inheritDoc */
public function get eventClass() : Class
{
return _eventClass;
}
public function set eventClass( value : Class ) : void
{
_eventClass = value || Event;
_valueClasses = [ _eventClass ];
}
protected var _valueClasses : Array;
/** @inheritDoc */
[ArrayElementType("Class")]
public function get valueClasses() : Array
{
return _valueClasses;
}
public function set valueClasses( value : Array ) : void
{
eventClass = value && value.length > 0 ? value[ 0 ] : null;
}
/** @inheritDoc */
public function get numListeners() : uint
{
return slots.length;
}
/**
* Creates a NativeSignal instance to dispatch events on behalf of a target object.
* @param target The object on whose behalf the signal is dispatching events.
* @param eventType The type of Event permitted to be dispatched from this signal. Corresponds to Event.type.
* @param eventClass An optional class reference that enables an event type check in dispatch(). Defaults to flash.events.Event if omitted.
*/
public function NativeSignal( target : IEventDispatcher = null, eventType : String = "", eventClass : Class = null )
{
slots = SlotList.NIL;
this.target = target;
this.eventType = eventType;
this.eventClass = eventClass;
}
/**
* @inheritDoc
* @throws flash.errors.IllegalOperationError IllegalOperationError
: You cannot addOnce() then add() the same listener without removing the relationship first.
* @throws ArgumentError ArgumentError
: Given listener is null
.
* @throws ArgumentError ArgumentError
: Target object cannot be null
.
*/
public function add( listener : Function ) : ISlot
{
return addWithPriority( listener );
}
/**
* @inheritDoc
* @throws flash.errors.IllegalOperationError IllegalOperationError
: You cannot addOnce() then add() the same listener without removing the relationship first.
* @throws ArgumentError ArgumentError
: Given listener is null
.
* @throws ArgumentError ArgumentError
: Target object cannot be null
.
*/
public function addWithPriority( listener : Function, priority : int = 0 ) : ISlot
{
return registerListenerWithPriority( listener, false, priority );
}
/**
* @inheritDoc
* @throws flash.errors.IllegalOperationError IllegalOperationError
: You cannot addOnce() then add() the same listener without removing the relationship first.
* @throws ArgumentError ArgumentError
: Given listener is null
.
* @throws ArgumentError ArgumentError
: Target object cannot be null
.
*/
public function addOnce( listener : Function ) : ISlot
{
return addOnceWithPriority( listener );
}
/**
* @inheritDoc
* @throws flash.errors.IllegalOperationError IllegalOperationError
: You cannot addOnce() then add() the same listener without removing the relationship first.
* @throws ArgumentError ArgumentError
: Given listener is null
.
* @throws ArgumentError ArgumentError
: Target object cannot be null
.
*/
public function addOnceWithPriority( listener : Function, priority : int = 0 ) : ISlot
{
return registerListenerWithPriority( listener, true, priority );
}
/** @inheritDoc */
public function remove( listener : Function ) : ISlot
{
const slot : ISlot = slots.find( listener );
if( !slot ) return null;
_target.removeEventListener( _eventType, slot.execute1 );
slots = slots.filterNot( listener );
return slot;
}
/** @inheritDoc */
public function removeAll() : void
{
var slotsToProcess : SlotList = slots;
while( slotsToProcess.nonEmpty )
{
target.removeEventListener( _eventType, slotsToProcess.head.execute1 );
slotsToProcess = slotsToProcess.tail;
}
slots = SlotList.NIL;
}
/**
* @inheritDoc
* @throws ArgumentError ArgumentError
: Event object expected.
* @throws ArgumentError ArgumentError
: No more than one Event object expected.
* @throws ArgumentError ArgumentError
: Target object cannot be null
.
* @throws ArgumentError ArgumentError
: Event object cannot be null
.
* @throws ArgumentError ArgumentError
: Event object [event] is not an instance of [eventClass].
* @throws ArgumentError ArgumentError
: Event object has incorrect type. Expected [eventType] but was [event.type].
*/
public function dispatch( ...valueObjects ) : void
{
// TODO: check if ...valueObjects can ever be null.
if( null == valueObjects ) throw new ArgumentError( 'Event object expected.' );
if( valueObjects.length != 1 ) throw new ArgumentError( 'No more than one Event object expected.' );
dispatchEvent( valueObjects[ 0 ] as Event );
}
protected function registerListenerWithPriority( listener : Function, once : Boolean = false, priority : int = 0 ) : ISlot
{
if( !target ) throw new ArgumentError( 'Target object cannot be null.' );
if( registrationPossible( listener, once ) )
{
const slot : ISlot = new Slot( listener, this, once, priority );
// Not necessary to insertWithPriority() because the target takes care of ordering.
slots = slots.prepend( slot );
_target.addEventListener( _eventType, slot.execute1, false, priority );
return slot;
}
return slots.find( listener );
}
protected function registrationPossible( listener : Function, once : Boolean ) : Boolean
{
if( !slots.nonEmpty ) return true;
const existingSlot : ISlot = slots.find( listener );
if( existingSlot )
{
if( existingSlot.once != once )
{
// If the listener was previously added, definitely don't add it again.
// But throw an exception if their once value differs.
throw new IllegalOperationError( 'You cannot addOnce() then add() the same listener without removing the relationship first.' );
}
// Listener was already added.
return false;
}
// This listener has not been added before.
return true;
}
/**
* Unlike other signals, NativeSignal does not dispatch null
* because it causes an exception in EventDispatcher.
* @inheritDoc
* @throws ArgumentError ArgumentError
: Target object cannot be null
.
* @throws ArgumentError ArgumentError
: Event object cannot be null
.
* @throws ArgumentError ArgumentError
: Event object [event] is not an instance of [eventClass].
* @throws ArgumentError ArgumentError
: Event object has incorrect type. Expected [eventType] but was [event.type].
*/
public function dispatchEvent( event : Event ) : Boolean
{
if( !target ) throw new ArgumentError( 'Target object cannot be null.' );
if( !event ) throw new ArgumentError( 'Event object cannot be null.' );
if( !(event is eventClass) )
throw new ArgumentError( 'Event object ' + event + ' is not an instance of ' + eventClass + '.' );
if( event.type != eventType )
throw new ArgumentError( 'Event object has incorrect type. Expected <' + eventType + '> but was <' + event.type + '>.' );
return target.dispatchEvent( event );
}
}
}