1  //!-- UTF8
     2  /*
     3  ----------------------------------------------
     4  EventSource Class
     5  
     6  	@description : 
     7  		Habilite une classe enfant à gérer
     8  		une liste de diffusion (_listeners)
     9  		d'événements souscrits par abonnements
    10  	
    11  	PUBLIC METHODS
    12  		toString
    13  		broadcastMessage
    14  		addListener
    15  		removeListener
    16  		deleteListeners
    17  		countListeners
    18  	
    19  	PUBLIC STATIC METHODS
    20  		initialize
    21  	
    22  	PRIVATE STATIC METHODS
    23  		$broadcastMessage
    24  		
    25  	@author Jens Halm copyright http://www.spicefactory.org/
    26  	@author erixtekila copyleft http://www.v-i-a.net 
    27  ----------------------------------------------
    28  	version history :
    29  	1.0 : 24/04/03
    30  		- Réécrit à partir du code de Bokel
    31  		Replacement for ASBroadcaster
    32  		http://chattyfig.figleaf.com/flashcoders-wiki/index.php?AsBroadcaster
    33  		pour éviter une future(?) suppression.
    34  		- Mise en place de l'héritage de certaines méthodes
    35  		pour que certaines classes puissent qui l'étendre.
    36  		- Ai conservé la méthode statique initialize
    37  		pour dériver les méthodes de la classe sans héritage
    38  		ala mix-in… Attention au typage.
    39  	2.0 : 02/01/05
    40  		- Portage en actionscript 2.
    41  		- Passage de $broadcaster en non static
    42  ----------------------------------------------
    43  */
    44  
    45  /**
    46   *	Habilite une classe enfant à gérer
    47   *	une liste de diffusion (_listeners)
    48   *	d'événements souscrits par abonnements
    49   *
    50   *	@author Jens Halm copyright http://www.spicefactory.org/
    51   *	@author erixtekila copyleft http://www.v-i-a.net 
    52   *	@version 2.0
    53   */
    54  class org.omus.util.EventSource
    55  {
    56  	//--------------------
    57  	// PROPRIETES
    58  	//--------------------
    59  	/**
    60  	*	Liste des abonnés.
    61  	*/
    62  	private var _listeners:Array;
    63  	
    64  	//--------------------
    65  	// CONSTRUCTEUR
    66  	//--------------------
    67  	/**
    68  	*	Initialise une liste d'observateurs.
    69  	*/
    70  	public function EventSource()
    71  	{
    72  		// initialise la liste des abonnés dans l'objet source
    73  		// Utiliser super(); dans la sous classe
    74  		_listeners = [];
    75  		
    76  		// Enumeration
    77  		_global.ASSetPropFlags(this, ["$broadcastMessage"], 131);
    78  		
    79  		// trace(this+ " installé.");
    80  	}
    81  	
    82  	//--------------------
    83  	// METHODES PUBLIQUES
    84  	//--------------------
    85  	/**
    86  	 *	Utilisé dans un contexte littéral
    87  	 *
    88  	 *	@return	Une chaine définissant l'objet.
    89  	 */
    90  	public function toString ():String
    91  	{
    92  		return "[objet EventSource]";
    93  	}
    94  	
    95  	/**
    96  	 *	Envoie les événements à tous les objets observateurs.
    97  	 *
    98  	 *	@param event	Le nom de l'événement.
    99  	 *	@param args		Une suite d'arguments (autant que souhaité : overload)
   100  	 */
   101  	public function broadcastMessage ():Void{}
   102  	
   103  	
   104  	/** 
   105  	 *	Active une méthode particulière de l'interface de l'abonné : l'événement.
   106  	 */
   107  	private function $broadcastMessage ():Void
   108  	{
   109  		// Nouvelle référence au _listener array
   110  		var a = _listeners.concat();
   111  		// Liste des arguments sans le 1er élément (nom de l'événement)
   112  		var e = arguments.shift();
   113  		for(var i:String in a)
   114  		{
   115  			a[i][e].apply(a[i], arguments);
   116  		}
   117  	}
   118  	
   119  	/**
   120  	 *	Ajoute un nouvel observateur.
   121  	 *
   122  	 *	@param obj		Référence à l'objet abonné.
   123  	 *	@return Un booléen indiquant la réussite de l'opération.
   124  	 */
   125  	public function addListener (obj:Object):Boolean
   126  	{
   127  		var a = _listeners;
   128  		var i = a.length;
   129  		// technique qui positionne l'objet dans un indice négatif
   130  		// pour observer sa position par comparaison sans modifier 
   131  		// le tableau.
   132  		a[-1] = obj;
   133  		// Descends pour trouver l'index de i
   134  		while (a[--i] != obj){/*** Ne sert qu'à décrémenter i ***/}
   135  		delete a[-1];
   136  		// si i<0, l'objet n'était pas présent dans la liste des listeners
   137  		if (i < 0)
   138  		{
   139  			a.unshift(obj);
   140  			// référence masquée vers static
   141  			broadcastMessage = $broadcastMessage;
   142  			return true;
   143  		}
   144  		return false;
   145  	}
   146  	
   147  	/**
   148  	 *	Supprime un observateur.
   149  	 *
   150  	 *	@param obj		référence à l'objet abonné
   151  	 *	@return Un booléen indiquant la réussite de l'opération.		
   152  	 */
   153  	public function removeListener (obj:Object):Boolean
   154  	{
   155  		var a = _listeners;
   156  		var i = a.length;
   157  		// cf addListener
   158  		a[-1] = obj;
   159  		while (a[--i] != obj){/*** Ne sert qu'à décrémenter i ***/}
   160  		delete a[-1];
   161  		//
   162  		if(i>=0)
   163  		{
   164  			a.splice(i, 1);
   165  			if (a.length == 0) 
   166  			{
   167  				// évite le bug de ne pouvoir supprimer un listener 
   168  				// à partir de l'objet source lui-même.
   169  				broadcastMessage = null;
   170  			}
   171  			return true;
   172  		}
   173  		return false;
   174  	}
   175  	
   176  	/**
   177  	 *	Supprime tous les observateurs.
   178  	 */
   179  	public function removeAllListeners ():Void
   180  	{
   181  		_listeners = [];
   182  		broadcastMessage = undefined;
   183  	}
   184  	
   185  	/**
   186  	 *	Retourne le nombre d'observateurs.
   187  	 *
   188  	 *	@return Le nombre d'observateurs enregistrés.
   189  	 */
   190  	public function countListeners ():Number
   191  	{
   192  		return _listeners.length;
   193  	}
   194  	
   195  	//--------------------
   196  	// METHODES STATIQUES
   197  	//--------------------
   198  	/**
   199  	 *	Mix-in de méthodes de broadcasting dans un objet soumis en argument.
   200  	 *	Permet d'utiliser le broadcasting sans héritage de EventSource.
   201  	 *	Mais penser à implémenter l'interface Observable dans ce cas pour le compile time type checking.
   202  	 *
   203  	 *	@param obj		La nouvelle source d'événement.
   204  	 *	@deprecated		Préférer la composition à cette technique. 
   205  	 *					D'autant que l'interface Observable peut servir pour le type checking.
   206  	 */
   207  	public static function initialize (obj:Object):Void
   208  	{
   209  		obj.broadcastMessage = undefined;
   210  		for(var i:String in org.omus.util.EventSource.prototype){
   211  			obj[i] = org.omus.util.EventSource.prototype[i];
   212  		}
   213  		obj._listeners = [];
   214  		// Protection contre l'énumération et la suppression ; pas l'overwrite
   215  		// décommenter si nécessaire
   216  		// _global.ASSetPropFlags(obj, ["broadcastMessage, addListener, removeListener, _listeners"], 131);
   217  	}
   218  }
   219