using System; using System.Collections.Generic; using System.Linq; namespace DMX2 { /// /// Event data : Objet passé aux cibles d'evenements /// public struct EventData { public string id; public byte value; } /// /// Interface pour les fournisseurs d'evenements /// public interface IEventProvider { /// /// Renvoie le nom du sous menu associé au fournisseur d'evenements. /// /// /// Le nom du menu. /// string MenuName{ get; } /// Demande au fournisseur de signaler l'evenement spécifié /// L'id de l'evenement. /// true si le fournisseur reconnais l'id bool Bind (string eventId); /// Signale au fournisseur que l'evenement n'est plus attendu /// L'id de l'evenement. void Unbind (string eventId); /// Demande la construction du sous-menu evenement au fournisseur /// Le sous menu /// Un objet qui sera devra etre stocké dans Data[EventManager.StateKey] /// La delegate qui devra etre associée aux ButtonClickedEvent Gtk.Menu GetProviderSubMenu( EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler ); /// Appelé par le Timer de la conduite /// Fonction a appeler pour chaque evenement. void ProcessEvents(EventManagerCallback callback); } /// /// Interface pour les recepteurs d'evenements. /// public interface IEventTarget { /// Fonction appelée lors d'un evenement /// Vrai si l'evenement est traité /// Evenement bool FireEvent(EventData data); /// Indique a la cible qu'on lui associe un evenement /// l'id de l'evenement void Bind(string id); /// Indique a la cible qu'on lui des associe un evenement /// l'id de l'evenement void Unbind(string id); } /// /// Callback sur evenement. /// public delegate void EventManagerCallback(EventData data); /// /// Callback appele sur clic sur un bouton de menu de choix d'evenement /// public delegate void EventManagerMenuCallBack(object state, string eventId); /// /// Cible generique d'evenement. /// public class actionEventTarget : IEventTarget { public delegate bool EventAction (EventData data); EventAction action; public actionEventTarget(EventAction _action) { action=_action; } #region IEventTarget implementation bool IEventTarget.FireEvent (EventData data) { return action(data); } void IEventTarget.Bind (string id){} // Rien a faire ici void IEventTarget.Unbind (string id){} #endregion } public class EventManager { Dictionary bindings = new Dictionary(); List providers = new List(); class eventBinding { List targets=new List(); public void AddTarget(IEventTarget target) { if(!targets.Contains(target)) targets.Add(target); } public void RemoveTarget(IEventTarget target) { targets.Remove(target); } public ICollection Targets { get { return targets; } } } public EventManager () { } public void RegisterProvider (IEventProvider prov) { providers.Add (prov); } #region Menus // Cles pour association d'etat au elements de menu static public object StateKey = new object(); static public object EventIdKey = new object(); // Objet associe aux menus afin de pourvoir retransmettre les infos au createur du menu public class EventMenuData { public EventManagerMenuCallBack CallBack; public object state; } /// Appelé par l'interface. L'objet 'state' sera retransmis tel quel lors de l'appel au callback public Gtk.Menu GetMenu (object state, EventManagerMenuCallBack callback) { Gtk.Menu menu = new Gtk.Menu (); EventMenuData evd = new EventMenuData(); evd.CallBack = callback; evd.state = state; Gtk.ButtonPressEventHandler handler = new Gtk.ButtonPressEventHandler (HandleButtonPressEvent); foreach (IEventProvider prov in providers) { Gtk.MenuItem provitem = new Gtk.MenuItem(prov.MenuName); provitem.Submenu = prov.GetProviderSubMenu(evd, handler); if(provitem.Submenu!=null) menu.Add(provitem); } // Creation de l'element 'Aucun' retournant un ID vide, pour permettre la desassociation Gtk.MenuItem itemNone = new Gtk.MenuItem("Aucun"); itemNone.Data[StateKey] = evd; itemNone.Data[EventIdKey] = ""; itemNone.ButtonPressEvent += handler; menu.Add(itemNone); return menu; } /// Traitement du clic sur les menus generes au dessus void HandleButtonPressEvent (object o, Gtk.ButtonPressEventArgs args) { Gtk.MenuItem item = o as Gtk.MenuItem; EventMenuData evd = item.Data[EventManager.StateKey] as EventMenuData; // On récupere l'objet d'etat et la fonction a rappeler string id = item.Data[EventManager.EventIdKey] as string; // ainsi que l'id evenement evd.CallBack(evd.state,id); // Appel de la fonction } #endregion /// Appelé par le Timer de la conduite ... appel le traitement pour l'ensemble des fournisseurs public void ProcessEvents () { foreach (IEventProvider prov in providers) { prov.ProcessEvents(new EventManagerCallback(EventCallBack)); } } public void UnregisterProvider (IEventProvider prov) { providers.Remove(prov); } /// Enregistrement d'une association id => cible public bool Bind (string eventId, IEventTarget target) { if(!bindings.ContainsKey(eventId)) bindings.Add (eventId,new eventBinding()); bindings[eventId].AddTarget(target); target.Bind(eventId); foreach (IEventProvider prov in providers) { if(prov.Bind(eventId)) return true; } return false; } /// Desenregistrement de toutes les associations d'une cible public void Unbind (IEventTarget target) { var q = from bind in bindings where bind.Value.Targets.Contains(target) select bind.Key; foreach(string id in q.ToArray()) Unbind(id,target); } /// Desenregistrement d'une association id => cible public void Unbind (string eventId, IEventTarget target) { if (!bindings.ContainsKey (eventId)) return; bindings [eventId].RemoveTarget (target); if (bindings [eventId].Targets.Count == 0) { bindings.Remove(eventId); foreach (IEventProvider prov in providers) { prov.Unbind(eventId); } } target.Unbind(eventId); } /// Fonction appelee sur evenement public void EventCallBack (EventData data) { Console.WriteLine("Event {0} => {1}",data.id,data.value); if (bindings.ContainsKey (data.id)) { foreach (IEventTarget target in bindings[data.id].Targets) { target.FireEvent(data); } } } public bool SaveBindings (System.Xml.XmlElement xmlParent, IEventTarget target) { bool ret=false; System.Xml.XmlElement xmlB; var q = from bind in bindings where bind.Value.Targets.Contains(target) select bind.Key; foreach (string id in q) { ret=true; xmlParent.AppendChild(xmlB = xmlParent.OwnerDocument.CreateElement("EventBinding")); xmlB.SetAttribute("id",id); } return ret; } public static string[] LoadBindings (System.Xml.XmlElement xmlParent) { var all=xmlParent.GetElementsByTagName("EventBinding"); string[] ret = new string[all.Count]; int index=0; foreach (var xb in all) { ret[index++] = (xb as System.Xml.XmlElement).GetAttribute("id"); } return ret; } } }