<> <> <> <<>> <> <<>> DIRECTORY IO USING [PutFR, int], TextEdit USING [Size], TiogaButtons USING [TextNodeRef], TiogaOps USING [GetSelection, StepForward], TiogaOpsDefs USING [Location, Ref], ViewerClasses USING [Viewer], ViewerEvents USING [EventRegistration, EventProc, RegisterEventProc, UnRegisterEventProc], VoiceInText USING [DebugRope], VoiceViewers USING [VoiceViewerInfo, voiceViewerInfoList], SourceMarkerTracking; <<>> SourceMarkerTrackingImpl: CEDAR PROGRAM IMPORTS IO, TextEdit, TiogaButtons, TiogaOps, ViewerEvents, VoiceInText, VoiceViewers EXPORTS SourceMarkerTracking = BEGIN <> ViewerAndDestroyProc: TYPE = RECORD [ viewer: ViewerClasses.Viewer, destroyProc: ViewerEvents.EventRegistration ]; registeredViewerList: LIST OF ViewerAndDestroyProc; <> RegisterViewer: PUBLIC PROC [viewer: ViewerClasses.Viewer] = { <> alreadyInList: BOOLEAN _ FALSE; FOR l: LIST OF ViewerAndDestroyProc _ registeredViewerList, l.rest WHILE l # NIL AND ~alreadyInList DO IF l.first.viewer = viewer THEN alreadyInList _ TRUE ENDLOOP; IF ~alreadyInList THEN { newEntry: ViewerAndDestroyProc _ [viewer, ViewerEvents.RegisterEventProc[ proc: DestroyViewerEvent, event: destroy, filter: viewer, before: TRUE]]; registeredViewerList _ CONS [newEntry, registeredViewerList] } }; DestroyViewerEvent: ViewerEvents.EventProc = { firstEntry: BOOLEAN _ viewer = registeredViewerList.first.viewer; previousEntry: LIST OF ViewerAndDestroyProc _ registeredViewerList; IF ~firstEntry THEN WHILE previousEntry.rest.first.viewer # viewer DO previousEntry _ previousEntry.rest ENDLOOP; -- if this runs off the end then something has gone seriously wrong ViewerEvents.UnRegisterEventProc[(IF firstEntry THEN registeredViewerList ELSE previousEntry.rest).first.destroyProc, destroy]; IF firstEntry THEN registeredViewerList _ registeredViewerList.rest ELSE previousEntry.rest _ previousEntry.rest.rest; RemoveParentPointersTo[viewer]; }; RemoveParentPointersTo: PUBLIC PROC [viewer: ViewerClasses.Viewer] = { FOR info: VoiceViewers.VoiceViewerInfo _ VoiceViewers.voiceViewerInfoList, info.nextInfoRec WHILE info # NIL DO IF info.parentViewer = viewer THEN { info.parentViewer _ NIL; VoiceInText.DebugRope[IO.PutFR["detaching parent link for voice viewer %d\n", IO.int[info.viewerNumber]]] } ENDLOOP }; <> TrackDeletes: PUBLIC PROC = { <> <> viewer: ViewerClasses.Viewer; start, end, current: TiogaOpsDefs.Location; infoList: LIST OF VoiceViewers.VoiceViewerInfo _ NIL; SeverLinks: PROC [node: TiogaOpsDefs.Ref, from, to: INT] = { FOR l: LIST OF VoiceViewers.VoiceViewerInfo _ infoList, l.rest WHILE l # NIL DO IF l.first.positionInParent.node = node AND l.first.positionInParent.where IN [from..to] THEN { l.first.parentViewer _ NIL; VoiceInText.DebugRope[IO.PutFR["detaching parent link for voice viewer %d\n", IO.int[l.first.viewerNumber]]] } ENDLOOP }; [viewer: viewer, start: start, end: end] _ TiogaOps.GetSelection[]; FOR info: VoiceViewers.VoiceViewerInfo _ VoiceViewers.voiceViewerInfoList, info.nextInfoRec WHILE info # NIL DO IF info.parentViewer = viewer THEN infoList _ CONS [info, infoList] ENDLOOP; IF infoList = NIL THEN RETURN; <<>> <> IF start.node = end.node THEN SeverLinks[start.node, start.where, end.where] ELSE { current _ start; SeverLinks[current.node, current.where, TextEdit.Size[TiogaButtons.TextNodeRef[current.node]]-1]; DO current.node _ TiogaOps.StepForward[current.node]; IF current.node = end.node THEN { SeverLinks[current.node, 0, end.where]; EXIT } ELSE SeverLinks[current.node, 0, TextEdit.Size[TiogaButtons.TextNodeRef[current.node]]-1] ENDLOOP }; { positionAdjustment: INT _ end.where - start.where + 1; FOR l: LIST OF VoiceViewers.VoiceViewerInfo _ infoList, l.rest WHILE l # NIL DO IF l.first.positionInParent.node = end.node AND l.first.positionInParent.where > end.where THEN l.first.positionInParent _ [start.node, l.first.positionInParent.where - positionAdjustment] ENDLOOP } }; <<>> <<>> <<>> END.