/* * 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 DnnTrigger \typ{DnnTrigger}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{DnnBaseReaction}). 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. ?*/ DnnTrigger :: DnnTrigger () : FirstSubscribers (), LastSubscribers (), Subscribers (), Grabs (), Criteria () { } /*?nodoc?*/ DnnTrigger :: ~DnnTrigger () { /* Force reactions to unsubscribe. We should take care of conditions when destructor is called during iteration */ CcuListIterOf 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 DnnTrigger :: Subscribe (DnnBaseReaction& 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 DnnTrigger :: Unsubscribe (DnnBaseReaction& a) { FirstSubscribers.Remove (&a); Subscribers.Remove (&a); LastSubscribers.Remove (&a); Grabs.Remove (&a); } /*?nextdoc?*/ void DnnTrigger :: Grab (DnnBaseReaction& a) { Grabs.Prepend (&a); } /*? Add (resp. Remove) a reaction onto (resp. from) the stack of reactions that preempt events caused by this trigger. ?*/ void DnnTrigger :: Release (DnnBaseReaction& a) { Grabs.Remove (&a); } #if 0 void DnnTrigger :: Circulate (DnnBaseReaction& r, REL_POS pos, DnnBaseReaction* ref) { if (Subscribers.Remove (&r)) { /* find the predecessor of ref */ CcuListIterOf 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 DnnTrigger :: Dispatch (DnnEvent& ev) { DnnBaseReaction* r = Grabs.First (); if (r) { r->Manage (ev); } else { /* calls to Manage may result in changes in Subscribers; let's make a safe copy */ CcuListOf first_subscribers = FirstSubscribers; CcuListOf subscribers = Subscribers; CcuListOf last_subscribers = LastSubscribers; CcuListIterOf 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 DnnTrigger :: Check (DnnEvent& ev) { CcuListIterOf c = Criteria; while (++c) if (!(*c)->Test (ev)) return false; #ifdef CRITERIA_IN_REACTIONS CcuListIterOf 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 }