/* * DNN - Data News Network * * by Stephane Chatty * * Copyright 1993-1995 * Centre d'Etudes de la Navigation Aerienne (CENA) * * Event triggers. * * $Id$ * $CurLog$ */ #include "Trigger.h" #include "Reaction.h" #include "Criterion.h" /*?class IvlTrigger \typ{IvlTrigger}s are the core of event detection and emission. The presence of a trigger (generally in a sensor) determines whether a certain situation, or the reception of an event from the underlying window system, should provoke the emission of an event. Each trigger holds a list of reactions (of type \typ{IvlBaseReaction}). These reactions will receive all the events whose creation and emission was caused by the presence of the trigger. ?*/ /*? Create a trigger with an empty list of associated reaction. ?*/ IvlTrigger :: IvlTrigger () : FirstSubscribers (), LastSubscribers (), Subscribers (), Grabs (), Criteria () { } /*?nodoc?*/ IvlTrigger :: ~IvlTrigger () { /* Force reactions to unsubscribe. We should take care of conditions when destructor is called during iteration */ IvlListIterOf ri = FirstSubscribers; while (++ri) (*ri)->Forget (*this); ri = Subscribers; while (++ri) (*ri)->Forget (*this); ri = LastSubscribers; while (++ri) (*ri)->Forget (*this); ri = Grabs; while (++ri) (*ri)->Forget (*this); } /*?nextdoc?*/ void IvlTrigger :: Subscribe (IvlBaseReaction& a, REL_PRIORITY p) { switch (p) { case isFirstPriority: FirstSubscribers.Append (&a); break; case isNormalPriority: Subscribers.Append (&a); break; case isLastPriority: LastSubscribers.Prepend (&a); break; } } /*? Add (resp. Remove) a reaction to (resp. from) the list of reactions that should receive events caused by this trigger. ?*/ void IvlTrigger :: Unsubscribe (IvlBaseReaction& a) { FirstSubscribers.Remove (&a); Subscribers.Remove (&a); LastSubscribers.Remove (&a); Grabs.Remove (&a); } /*?nextdoc?*/ void IvlTrigger :: Grab (IvlBaseReaction& a) { Grabs.Prepend (&a); } /*? Add (resp. Remove) a reaction onto (resp. from) the stack of reactions that preempt events caused by this trigger. ?*/ void IvlTrigger :: Release (IvlBaseReaction& a) { Grabs.Remove (&a); } #if 0 void IvlTrigger :: Circulate (IvlBaseReaction& r, REL_POS pos, IvlBaseReaction* ref) { if (Subscribers.Remove (&r)) { /* find the predecessor of ref */ IvlListIterOf lc = Subscribers; while (++lc && (*lc != ref)) ; /* NOW, lc is on ref, or at the end if ref == 0 */ if (pos == isBefore) Subscribers.InsertBefore (lc, &r); else Subscribers.InsertAfter (lc, &r); } } #endif /*? Have a trigger dispatch the event \var{ev} to its associated reactions. ?*/ void IvlTrigger :: Dispatch (IvlEvent& ev) { IvlBaseReaction* r = Grabs.First (); if (r) { r->Manage (ev); } else { /* calls to Manage may result in changes in Subscribers; let's make a safe copy */ IvlListOf first_subscribers = FirstSubscribers; IvlListOf subscribers = Subscribers; IvlListOf last_subscribers = LastSubscribers; IvlListIterOf s = first_subscribers; while (++s) #ifdef CRITERIA_IN_REACTIONS if ((*s)->Check (ev)) #endif (*s)->Manage (ev); s = subscribers; while (++s) #ifdef CRITERIA_IN_REACTIONS if ((*s)->Check (ev)) #endif (*s)->Manage (ev); s = last_subscribers; while (++s) #ifdef CRITERIA_IN_REACTIONS if ((*s)->Check (ev)) #endif (*s)->Manage (ev); } } bool IvlTrigger :: Check (IvlEvent& ev) { IvlListIterOf c = Criteria; while (++c) if (!(*c)->Test (ev)) return false; #ifdef CRITERIA_IN_REACTIONS IvlListIterOf ri = FirstSubscribers; while (++ri) if ((*ri)->Check (ev)) return true; ri = Subscribers; while (++ri) if ((*ri)->Check (ev)) return true; ri = LastSubscribers; while (++ri) if ((*ri)->Check (ev)) return true; return false; #else return true; #endif }