EditNotifyImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
written by Bill Paxton, March 1981
last edit by Bill Paxton, October 18, 1982 10:42 am
Michael Plass, March 29, 1985 2:31:39 pm PST
Doug Wyatt, September 22, 1986 4:54:02 pm PDT
EditNotify
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] = {
remove proc from list of notification procedures
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] = {
call notification procedures
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];
};
};
UndoEvent
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] = {
calls undoProc[undoRef] for each subevent
in reverse order that subevents originally happened
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];
};