13.7 Notifications Interface

ORIGIN 'astlevel';
INCLUDE 'observer';
LIB_ITEM 'mpsastlevel';
BODY 'private/notificationsbody';
(* This fragment implements a signalling system to be used by different
 * software components, each manipulating fragments through the same
 * mps instance.
 *
 * The system consists of the concept of a 'handle', which the software
 * component can use to both signal, that it has made some changes to
 * a fragment, and to subscribe to information on what other software
 * components are doing to the fragments.
 *
 * A handle therefore has a dual set of operations:
 *    'signal's and 'event's
 * A 'signal' operation is named 'signalXXX', and the corresponding
 * event is called 'onXXX', where 'XXX' is the name of the change
 * being reported.
 *
 * It is the responsability of the software component making the change
 * to signal this change.  This is done by invoking the corresponding
 * 'signalXXX' operation.  If a software component want to monitor
 * particular changes, it must obtain a handle with proper further
 * binding of the corresonding 'eventXXX' (more on this later).
 *
 * A few of these signals are automatically invoked by 'mps'.
 * In these cases, this is explicitly specified in the operation below.
 *
 * A software component obtains a handle by:
 *
 *    mps.getHandle
 *      (# handleType::
 *           (# onGroupOpen::
 *                (# do fg.fullname->puttext; ' opened'->putline #);
 *              onGroupClose
 *                (# do fg.fullname->puttext; ' closed'->putline #);
 *              ...etc...
 *           #)
 *      #);
 *
 * This handle monitors opening and closing of all fragment groups.
 *
 * If you want a handle, that only monitors a particular fragment
 * group, you can do this by:
 *
 *    mps.getHandle
 *      (# handleType::
 *           (# ignore:: (# (fg[]<>myFG[])->value #);
 *              ... som ovenfor ...
 *          #)
 *      #);
 *
 * You can get hold of this newly created handle by:
 *
 *    mps.getHandle(# ...som ovenfor... #)->h[];
 *
 * in which case it becomes possible later to decide to cancel this
 * handle by:
 *
 *    h[]->mps.ignoreHandle;
 *
 * If you later want to reactivate this handle, you can always do:
 *
 *    h[]->mps.activateHandle;
 *
 * If you have made changes to a fragment group, e.g. replaced an ast,
 * you can signal this to the other components by:
 *
 *    (fg[], ff[], oldAst[], newAst[])->mps.signalAstReplaced
 *
 * If you wish to control which handlers, signals are send to, you can
 * use the 'where' clause of 'signal'.  E.g. if you with to send a
 * signal to all handlers, except 'h[]', you can do this by:
 *
 *    (fg[], ff[], oldAst[], newAst[])->mps.signalAstReplaced
 *      (# where:: (# do (current[]<>h[])->value #) #)
 *)
(* This fragment implements a signalling system to be used by different
 * software components, each manipulating fragments through the same
 * mps instance.
 *
 * The system consists of the concept of a 'handle', which the software
 * component can use to both signal, that it has made some changes to
 * a fragment, and to subscribe to information on what other software
 * components are doing to the fragments.
 *
 * A handle therefore has a dual set of operations:
 *    'signal's and 'event's
 * A 'signal' operation is named 'signalXXX', and the corresponding
 * event is called 'onXXX', where 'XXX' is the name of the change
 * being reported.
 *
 * It is the responsability of the software component making the change
 * to signal this change.  This is done by invoking the corresponding
 * 'signalXXX' operation.  If a software component want to monitor
 * particular changes, it must obtain a handle with proper further
 * binding of the corresonding 'eventXXX' (more on this later).
 *
 * A few of these signals are automatically invoked by 'mps'.
 * In these cases, this is explicitly specified in the operation below.
 *
 * A software component obtains a handle by:
 *
 *    mps.getHandle
 *      (# handleType::
 *           (# onGroupOpen::
 *                (# do fg.fullname->puttext; ' opened'->putline #);
 *              onGroupClose
 *                (# do fg.fullname->puttext; ' closed'->putline #);
 *              ...etc...
 *           #)
 *      #);
 *
 * This handle monitors opening and closing of all fragment groups.
 *
 * If you want a handle, that only monitors a particular fragment
 * group, you can do this by:
 *
 *    mps.getHandle
 *      (# handleType::
 *           (# ignore:: (# (fg[]<>myFG[])->value #);
 *              ... som ovenfor ...
 *          #)
 *      #);
 *
 * You can get hold of this newly created handle by:
 *
 *    mps.getHandle(# ...som ovenfor... #)->h[];
 *
 * in which case it becomes possible later to decide to cancel this
 * handle by:
 *
 *    h[]->mps.ignoreHandle;
 *
 * If you later want to reactivate this handle, you can always do:
 *
 *    h[]->mps.activateHandle;
 *
 * If you have made changes to a fragment group, e.g. replaced an ast,
 * you can signal this to the other components by:
 *
 *    (fg[], ff[], oldAst[], newAst[])->mps.signalAstReplaced
 *
 * If you wish to control which handlers, signals are send to, you can
 * use the 'where' clause of 'signal'.  E.g. if you with to send a
 * signal to all handlers, except 'h[]', you can do this by:
 *
 *    (fg[], ff[], oldAst[], newAst[])->mps.signalAstReplaced
 *      (# where:: (# do (current[]<>h[])->value #) #)
 *)
-- astinterfacelib: Attributes --
getHandle: (* called to get a new handle on this MPS *)
  (# handleType:< handle; h: ^handleType
  ...
  exit h[]
  #);
ignoreHandle:
(* called to return a handle (i.e. now wanting to be monitoring
 * this MPS through this handle 'h' any longer
 *) (# h: ^handle enter h[] ... #);
activateHandle:
(* called to activate a handle (i.e. now wanting to be monitoring
 * this MPS through this handle 'h' again
 *) (# h: ^handle enter h[] ... #);
handle:
(* this defines the events of a handle *)
  (#
     ignore:< booleanValue
     (* if this returns TRUE, this(handle) will be ignored *)
       (#
          fg: ^astInterface.fragmentGroup;
          ff: ^astInterface.fragmentForm;
          node: ^astInterface.ast
       enter (fg[],ff[],node[])
       do INNER
       #);
     event: (* abstract superpattern *) (# do INNER #);
     fragmentGroupEvent: event (* abstract superpattern *)
       (# fg: ^astInterface.fragmentGroup;  enter fg[] do INNER ;  #);
     fragmentFormEvent: fragmentGroupEvent (* abstract superpattern *)
       (# ff: ^astInterface.fragmentForm;  enter ff[] do INNER ;  #);
     astEvent: fragmentFormEvent (* abstract superpattern *)
       (# node: ^astInterface.ast enter node[] do INNER #);
     onGroupOpen:< fragmentGroupEvent
     (* invoked by MPS when fg[] have been opened by someone *)
       (# do INNER #);
     onGroupLock:< fragmentGroupEvent (* invoked by MPS when fg[] is locked *)
       (# do INNER #);
     onGroupUnlock:< fragmentGroupEvent
     (* invoked by MPS when fg[] is unlocked *) (# do INNER #);
     onGroupPack:< fragmentGroupEvent
     (* invoked by MPS when fg[] is saved to disk *) (# do INNER #);
     onGroupUnpack:< fragmentGroupEvent
     (* invoked by MPS when fg[] is unpacked from disk *)
       (# do INNER #);
     onBeforeGroupClose:< fragmentGroupEvent
     (* invoked by MPS before fg[] is closed
      *    okToClose=false   => fg will not be closed.
      *)
       (# okToClose: @boolean
       do true->okToClose; INNER
       exit okToClose
       #);
     onGroupClose:< fragmentGroupEvent
     (* invoked by MPS when fg[] have been closed *) (# do INNER #);
     onTrace:< event (* invoked by MPS if tracing is activated *)
       (# msg: ^text enter msg[] do INNER #)
  #);
signal:
  (#
     where:< booleanValue (#  do true->value; INNER #);
     start:< object (* executed before the signal is posted to all handlers *) ;
     current: ^handle;
     fg: ^astInterface.fragmentGroup;
     ff: ^astInterface.fragmentForm;
     node: ^astInterface.ast;
     
  ...
  #);
fragmentGroupSignal: signal
(* abstract superpattern *) (#  enter fg[] do INNER #);
fragmentFormSignal: signal (* abstract superpattern *)
  (#  enter ff[] do INNER #);
astSignal: signal (* abstract superpattern *)
  (#  enter node[] do INNER #);
signalGroupOpen: fragmentGroupSignal (#  do fg[]->current.onGroupOpen #);
signalGroupLock: fragmentGroupSignal (#  do fg[]->current.onGroupLock #);
signalGroupUnlock: fragmentGroupSignal
  (#  do fg[]->current.onGroupUnlock #);
signalGroupPack: fragmentGroupSignal (#  do fg[]->current.onGroupPack #);
signalGroupUnpack: fragmentGroupSignal
  (#  do fg[]->current.onGroupUnpack #);
signalBeforeGroupClose: fragmentGroupSignal
  (# okToClose: @boolean; start::<  (#  do true->okToClose; INNER #); 
  do (okToClose and (fg[]->current.onBeforeGroupClose))->okToClose
  exit okToClose
  #);
signalGroupClose: fragmentGroupSignal (#  do fg[]->current.onGroupClose #);
signalTrace: signal
  (#
     traceNo: @integer;
     msg: ^text;
     start::< 
       (# 
       do 'Trace: '->msg[]; traceNo->msg.putInt; ' '->msg.put; INNER
       #)
  enter traceNo
  do msg[]->current.onTrace
  #);
astFocus:
  (# node: ^astInterface.ast; length,subCommentInx1,subCommentInx2: @integer
  enter (node[],length,subCommentInx1,subCommentInx2)
  exit (node[],length,subCommentInx1,subCommentInx2)
  #);
astList: (# elm: [50] ^astInterface.ast #);
astReplacedElement: (# oldAst,newAst: ^astInterface.ast #);
astReplacedList: containerList
  (#
     element:: astReplacedElement;
     appendElement:
       (# oldAst,newAst: ^astInterface.ast; e: ^astReplacedElement; 
       enter (oldAst[],newAst[])
       do
          &astReplacedElement[]->e[];
          oldAst[]->e.oldAst[];
          newAst[]->e.newAst[];
          e[]->append
       #)
  #);
  

-- fragmentGroupLib: Attributes --
attachObserver: (* called to attach a new observer on this fragmentgroup *)
  (# theObserver: ^fragmentGroupObserver; 
  enter theObserver[]
  ...
  #);
detachObserver:
(* called to detach an observer (i.e. now wanting to be monitoring
 * this fragmentGroup through this observer 'o' any longer
 *)
  (# theObserver: ^fragmentGroupObserver; 
  enter theObserver[]
  ...
  #);
notify:
  (#
     where:<
      booleanValue (#  do true->value; INNER #);
     before:< object
     (* executed before the notification is posted to all observers *) ;
     after:< object
     (* executed after the notification is posted to all observers *) ;
     current: ^fragmentGroupObserver;
     ff: ^astInterface.fragmentForm;
     
  ...
  #);
notifyAs:
  (#
     where:< booleanValue
       (# 
       do true->value; INNER
       #);
     before:< object
     (* executed before the notification is posted to all observers *) ;
     after:< object
     (* executed after the notification is posted to all observers *) ;
     current: ^type;
     type:< fragmentGroupObserver;
     ff: ^astInterface.fragmentForm;
     
  ...
  #);
fragmentFormNotify: notify
  (#  enter ff[] do INNER #);
notifyNameChanged:
 fragmentFormNotify
  (# oldName,newName: ^text; 
  enter (oldName[],newName[])
  do (ff[],oldName[],newName[])->current.onNameChanged
  #);
notifyFragmentInserted: fragmentFormNotify
  (#  do ff[]->current.onFragmentInserted #);
notifyFragmentDeleted: fragmentFormNotify
  (#  do ff[]->current.onFragmentDeleted #);
notifyPropertiesChanged: notify
  (# oldProp,newProp: ^propertyList; 
  enter (oldProp[],newProp[])
  do (oldProp[],newProp[])->current.onPropertiesChanged
  #);
notifyGroupSaved: notify (#  do current.onGroupSaved #);
notifyGroupNotSaved: notify (#  do current.onGroupNotSaved #);
notifyGroupAutosaved: notify (#  do current.onGroupAutosaved #);
notifyGroupChecked: notify
  (# semanticErrors: @boolean
  enter semanticErrors
  do semanticErrors->current.onGroupChecked
  #);
notifyGroupLocked: notify (#  do current.onGroupLocked #);
notifyGroupUnlocked: notify (#  do current.onGroupUnlocked #);
notifyBeforeGroupClose: notify
  (# okToClose: @boolean; before::<  (#  do true->okToClose; INNER #); 
  do (okToClose and current.onBeforeGroupClose)->okToClose
  exit okToClose
  #);
notifyGroupClosed: notify (#  do current.onGroupClosed #);
  

-- fragmentFormLib: Attributes --
attachObserver: (* called to attach a new observer on this fragmentform *)
  (# theObserver: ^fragmentFormObserver; 
  enter theObserver[]
  ...
  #);
detachObserver:
(* called to detach an observer (i.e. now wanting to be monitoring
 * this fragmentForm through this observer 'o' any longer
 *)
  (# theObserver: ^fragmentFormObserver
  enter theObserver[]
  ...
  #);
notify:
  (#
     where:<
      booleanValue (#  do true->value; INNER #);
     before:< object
     (* executed before the notification is posted to all observers *) ;
     after:< object
     (* executed after the notification is posted to all observers *) ;
     current: ^fragmentFormObserver;
     node: ^astInterface.ast;
     
  ...
  #);
notifyAs:
  (#
     where:< booleanValue
       (# 
       do true->value; INNER
       #);
     before:< object
     (* executed before the notification is posted to all observers *) ;
     after:< object
     (* executed after the notification is posted to all observers *) ;
     current: ^type;
     type:< fragmentFormObserver;
     node: ^astInterface.ast;
     
  ...
  #);
listNotify: notify
(* abstract superpattern *) (#  enter node[] do INNER #);
notifyAstReplaced: notify
  (# oldAst,newAst: ^astInterface.ast; 
  enter (oldAst[],newAst[])
  do (oldAst[],newAst[])->current.onAstReplaced
  #);
notifyAstReplacedSequence: notify
  (# theSequence: ^astReplacedList
  enter (node[],theSequence[])
  do (node[],theSequence[])->current.onAstReplacedSequence
  #);
notifyListElementInserted: listNotify
  (# position: @integer
  enter position
  do (node[],position)->current.onListElementInserted
  #);
notifyListElementsDeleted: listNotify
  (# oldElements: ^astList; position,length: @integer
  enter (position,length,oldElements[])
  do (node[],position,length,oldElements[])->current.onListElementsDeleted
  #);
notifyListElementsReplaced: listNotify
  (# oldElements: ^astList; position,length,newLength: @integer
  enter (position,length,oldElements[],newLength)
  do
     (node[],position,length,oldElements[],newLength)
       ->current.onListElementsReplaced
  #);
locked: booleanValue (# ... #);
lock: (# ... #);
unLock: (# ... #);
readOnly: booleanValue (# ... #);
setReadOnly: (# ... #);
unsetReadOnly: (# ... #);
touched: booleanValue (# ... #);
touch: (# ... #);
detouch: (# ... #);
  

-- lib: Attributes --
fragmentGroupObserver: observer
  (#
     group: ^astInterface.fragmentGroup;
     no: @integer;
     ignore:< booleanValue
     (* if this returns TRUE, this(fragmentGroupObserver) will be ignored *)
       (# do INNER #);
     fragmentFormEvent:
       (# ff: ^astInterface.fragmentForm enter ff[] do INNER #);
     fragmentGroupEvent: (# do INNER #);
     onNameChanged:< fragmentFormEvent
     (* invoked if ff[] have been given a new name *)
       (# oldName,newName: ^text; 
       enter (oldName[],newName[])
       do INNER ; 
       #);
     onFragmentInserted:< fragmentFormEvent
     (* invoked when ff[] is inserted in fg[] *) (# do INNER #);
     onFragmentDeleted:< fragmentFormEvent
     (* invoked when ff[] is deleted from fg[] *) (# do INNER #);
     onPropertiesChanged:< fragmentGroupEvent
     (* invoked when the properties of fg[] have changed *)
       (# oldProp,newProp: ^propertyList; 
       enter (oldProp[],newProp[])
       do INNER
       #);
     onGroupSaved:< fragmentGroupEvent (* invoked when fg[] have been saved *)
       (# do INNER #);
     onGroupNotSaved:< fragmentGroupEvent 
     (* invoked when quitting without saving the fg[], 
      * either because no changes have been made to the fg 
      * or becauset he user has decided not to save the changes
      *)
       (# do INNER #);
     onGroupAutoSaved:< fragmentGroupEvent
     (* invoked when fg[] have been auto-saved *) (# do INNER #);
     onGroupChecked:< fragmentGroupEvent
     (* invoked when fg[] have been checked by the checker *)
       (# semanticErrors: @boolean enter semanticErrors do INNER #);
     onGroupLocked:< fragmentGroupEvent (* invoked by MPS when fg[] is locked *)
     (# do INNER #);
     onGroupUnlocked:< fragmentGroupEvent
     (* invoked by MPS when fg[] is unlocked *) (# do INNER #);
     onBeforeGroupClose:< fragmentGroupEvent
     (* invoked by MPS before fg[] is closed
      *    okToClose=false   => fg will not be closed.
      *)
       (# okToClose: @boolean
       do true->okToClose; INNER
       exit okToClose
       #);
     onGroupClosed:< fragmentGroupEvent
     (* invoked by MPS when fg[] have been closed *) (# do INNER #)
  #);
fragmentFormObserver: observer
  (#
     frag: ^astinterface.fragmentForm;
     no: @integer;
     astEvent: (* abstract superpattern *)
       (#  do before; INNER ; after #);
     listEvent: astEvent
       (# node: ^astInterface.list enter node[] do INNER #);
     before:< object (* executed before INNER in all astEvents   *) ;
     after:< object (* executed after INNER in all astEvents *) ;
     onAstReplaced:< astEvent (* invoked when an ast has been replaced *)
       (# oldAst,newAst: ^astInterface.ast; 
       enter (oldAst[],newAst[])
       do INNER
       #);
     onAstReplacedSequence:< astEvent
     (* invoked when a sequence of astReplaced events have occured in node[]  *)
       (# node: ^astInterface.ast; theSequence: ^astInterface.astReplacedList
       enter (node[],theSequence[])
       do INNER
       #);
     onListElementInserted:< listEvent
     (* invoked when a new list element have been inserted in node[] *)
       (# position: @integer;  enter position do INNER #);
     onListElementsDeleted:< listEvent
     (* invoked when a list of elements have been deleted from node[] *)
       (# oldElements: ^astInterface.astList; position,length: @integer
       enter (position,length,oldElements[])
       do INNER
       #);
     onListElementsReplaced:< listEvent
     (* invoked when a list of elements have been replaced in node[] *)
       (#
          oldElements: ^astInterface.astList;
          position,length,newLength: @integer
       enter (position,length,oldElements[],newLength)
       do INNER
       #)
  #)


13.7 Notifications Interface
© 1991-2002 Mjølner Informatics
[Modified: Wednesday January 3rd 2001 at 12:15]