<> <> <> <> <> <> DIRECTORY Tioga, TiogaPrivate; EditNotifyImpl: CEDAR MONITOR LOCKS data USING data: EditNotifyData EXPORTS TiogaPrivate = BEGIN OPEN Tioga, TiogaPrivate; <> EditNotifyData: TYPE ~ REF EditNotifyDataRep; EditNotifyDataRep: PUBLIC TYPE ~ MONITORED RECORD [ beforeProcs: NotifyArray, afterProcs: NotifyArray, unlocked: CONDITION, lockCount: INTEGER _ 0 ]; NotifyList: TYPE = REF NotifyListBody; NotifyListBody: TYPE = RECORD [ next: NotifyList, action: EditNotifyProc, changeSet: ChangeSet ]; NotifyArray: TYPE = ARRAY Priority OF NotifyList; Lock: ENTRY PROC [data: EditNotifyData] = { data.lockCount _ data.lockCount+1; }; Unlock: ENTRY PROC [data: EditNotifyData] = { data.lockCount _ data.lockCount-1; IF data.lockCount <= 0 THEN { data.lockCount _ 0; BROADCAST data.unlocked }; }; InternalRemove: PROC [data: EditNotifyData, proc: EditNotifyProc, time: When] = { FOR p: Priority IN Priority DO prev: NotifyList _ NIL; list: NotifyList _ IF time=before THEN data.beforeProcs[p] ELSE data.afterProcs[p]; IF list=NIL THEN LOOP; UNTIL list=NIL DO IF list.action = proc THEN EXIT; prev _ list; list _ list.next; REPEAT FINISHED => LOOP; -- proc not found on this list ENDLOOP; IF prev#NIL THEN prev.next _ list.next ELSE IF time=before THEN data.beforeProcs[p] _ list.next ELSE data.afterProcs[p] _ list.next; ENDLOOP; }; EntryAdd: ENTRY PROC [data: EditNotifyData, proc: EditNotifyProc, time: When, priority: Priority, changeSet: ChangeSet] = { ENABLE UNWIND => NULL; WHILE data.lockCount > 0 DO WAIT data.unlocked; ENDLOOP; InternalRemove[data, proc, time]; IF time=before THEN data.beforeProcs[priority] _ NEW[NotifyListBody _ [data.beforeProcs[priority], proc, changeSet]] ELSE data.afterProcs[priority] _ NEW[NotifyListBody _ [data.afterProcs[priority], proc, changeSet]]; }; EntryRemove: ENTRY PROC [data: EditNotifyData, proc: EditNotifyProc, time: When] = { <> ENABLE UNWIND => NULL; WHILE data.lockCount > 0 DO WAIT data.unlocked; ENDLOOP; InternalRemove[data, proc, time]; }; AddEditNotifyProc: PUBLIC PROC [world: World, proc: EditNotifyProc, time: When _ after, priority: Priority _ normal, changeSet: ChangeSet _ defaultChangeSet] ~ { data: EditNotifyData ~ world.editNotify; EntryAdd[data, proc, time, priority, changeSet]; }; RemoveEditNotifyProc: PUBLIC PROC [world: World, proc: EditNotifyProc, time: When _ after] ~ { data: EditNotifyData ~ world.editNotify; EntryRemove[data, proc, time]; }; GetList: PROC [data: EditNotifyData, p: Priority, time: When] RETURNS [NotifyList] = { RETURN [IF time=before THEN data.beforeProcs[p] ELSE data.afterProcs[p]] }; EditNotify: PUBLIC PROC [world: World, change: REF READONLY Change, time: When] = { <> data: EditNotifyData ~ world.editNotify; IF change#NIL THEN { ENABLE UNWIND => Unlock[data]; kind: ChangeType ~ change.kind; Lock[data]; FOR p: Priority IN Priority DO FOR lst: NotifyList _ GetList[data, p, time], lst.next UNTIL lst=NIL DO IF lst.changeSet[kind] THEN lst.action[change]; ENDLOOP; ENDLOOP; Unlock[data]; }; }; <> CreateEvent: PUBLIC PROC RETURNS [Event] = { RETURN [NEW[EventBody _ [subevents: NIL]]]; }; NoteEvent: PUBLIC PROC [world: World, undoProc: UndoProc, undoRef: REF Change] = { event: Event ~ IF world=NIL THEN NIL ELSE world.currentEvent; IF event = NIL THEN RETURN; event.subevents _ NEW[SubEventBody _ [next: event.subevents, undoProc: undoProc, undoRef: undoRef]]; }; UndoEvent: PUBLIC PROC [world: World, undoEvent: Event] = { <> <> sub: SubEvent; IF undoEvent=NIL THEN RETURN; sub _ undoEvent.subevents; undoEvent.subevents _ NIL; UNTIL sub=NIL DO sub.undoProc[world, sub.undoRef]; sub _ sub.next; ENDLOOP; }; ResetEvent: PUBLIC PROC [event: Event] = { IF event # NIL THEN event.subevents _ NIL; }; EmptyEvent: PUBLIC PROC [event: Event] RETURNS [BOOL] = { RETURN [event=NIL OR event.subevents=NIL]; }; END.