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. LSourceMarkerTrackingImpl.mesa code which ensures that the records of parent viewers & positions within them attached to voice viewers are kept consistent as the parent viewers are edited Ades, May 1, 1986 1:24:50 pm PDT n.b. no consideration given in this code to the existence of split viewers first section deals with what happens when you delete a text viewer which is pointed to by voice viewer(s) this is a list of all the viewers in which source markers have been created and which therefore have a destroyProc set up to sever parent links. When the destroyProc is called the viewer will be deleted from this list; however when all relevant source markers have been deleted from the viewer we do not bother to delete it from the list called everytime a source marker is created within a text viewer remainder of the code deals with tracking pointers correctly as the text they point to is edited called before the primary selection is deleted, if in a text viewer N.B. that the selection may span more than one node we now have a list of all the voice viewers whose parent links point at the viewer containing the primary selection: we need to go through all the nodes in the selection severing the links which point within the selection and altering those which lie in the last node of the selection, beyond the end of the selection Κ3˜™™œIcode™ K™—™JK™——šΟk ˜ Kšœœ˜Kšœ œ˜Kšœ œ˜!Kšœ œ˜+Kšœ œ˜#Kšœœ ˜Kšœ œH˜ZKšœ œ ˜Kšœ œ(˜:šœ˜K™——Kš ΟnœœœœœLœ˜’K˜K˜K™lK˜šœœœ˜%Kšœ˜K˜+—K˜šœœœ˜3K™Ρ—K˜šžœœœ#˜>K™@Jšœœœ˜Jšœœœ5œœœœœœœœ˜€J˜Jšœ˜šœ“œ˜šJšœœ!˜<—J˜—J˜J˜šžœ˜/Jšœ œ.˜AJšœœœ-˜CJš œ œœ*œ$œΟcC˜΅J˜Jšœ"œ œœ1˜Jšœ œ2œ.˜vJ˜Jšœ˜—Jšœ˜J˜šœF˜FšœYœœ˜oJšœ˜"šœœ˜Jšœœ6œ˜i—J˜—Jš˜—J˜J˜J˜J™`J˜J˜šž œœœ˜J™CJ™3J˜Jšœ+˜+Jšœ œœ œ˜5J˜šž œœ$œ˜<š œœœ1œœ˜OJšœ&œ œ ˜XJš˜šœœ˜Jšœœ6œ˜l—J˜—Jš˜—J˜J˜JšœC˜CJšœYœœœœœ œœ˜ΌJšœ œœœ˜J™Jšœ½™½J˜Jšœ˜Kšœ/˜3Kš˜šœ˜Kšœa˜aš˜Kšœ2˜2Kšœ˜šœ*˜*Kš˜—K˜KšœV˜Z—Kš˜—K˜K˜šœœ˜9š œœœ1œœ˜OJšœ*œ+˜ZJšœ]˜a—Jš˜—K˜—˜J˜J™J™J™—Jšœ˜—…—.­