<> <> <> <> <> <> <> <> <> <> <<>> DIRECTORY Atom USING [GetPName], Buttons USING [ButtonProc, Create], FS USING [Error], Commander USING [CommandProc, Handle, Register], EditSpan USING [CannotDoEdit, ChangeNesting, Delete, InsertTextNode], InputFocus USING [GetInputFocus], IO USING [EndOfStream, GetTokenRope, PutFR, PutRope, RIS, STREAM], MessageWindow USING [Append, Blink], NodeProps USING [GetProp, GetSpecs, MapProps, MapPropsAction, PutProp, true], Process USING [CheckForAbort], PutGet USING [FromFile, ToFile], Rope USING [Cat, Equal, Find, IsEmpty, ROPE], TextEdit USING [AppendRope], TextNode USING [FirstChild, Forward, Level, MakeNodeSpan, Ref, RefTextNode], TiogaOps USING [CancelSelection, Jump, Lock, Unlock, ViewerDoc], ViewerClasses USING [Viewer]; AnnotateProperties: CEDAR PROGRAM IMPORTS Atom, Buttons, FS, Commander, EditSpan, InputFocus, IO, MessageWindow, NodeProps, Process, PutGet, Rope, TextEdit, TextNode, TiogaOps = { commentAtom: ATOM ~ $Comment; propertyAnnotationAtom: ATOM ~ $PropertyAnnotation; trueRope: Rope.ROPE ~ "TRUE"; DoAnnotations: Commander.CommandProc = { <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL]>> execOut: IO.STREAM = cmd.out; filename: Rope.ROPE; commandLineStream: IO.STREAM = IO.RIS[cmd.commandLine]; annotate: BOOL _ cmd.procData.clientData = $Annotate; rootNode: TextNode.Ref; DO -- process each file in command line filename _ IO.GetTokenRope[commandLineStream ! IO.EndOfStream => {filename _ NIL; CONTINUE}].token; IF filename.IsEmpty THEN EXIT; IF filename.Find["."] = -1 THEN -- add .mesa extension filename _ filename.Cat[".mesa"]; { ENABLE FS.Error => { execOut.PutRope[filename]; execOut.PutRope[" not found.\n"]; result _ $Warning; msg _ "Some files not found"; LOOP }; Process.CheckForAbort[]; rootNode _ PutGet.FromFile[filename]; Process.CheckForAbort[]; }; TRUSTED { TiogaOps.Lock[LOOPHOLE[rootNode]]; }; IF annotate THEN AddAnnotationNodes[rootNode] ELSE PruneAnnotationNodes[rootNode]; [] _ PutGet.ToFile[filename, rootNode]; TRUSTED { TiogaOps.Unlock[LOOPHOLE[rootNode]]; }; ENDLOOP; }; AddAnnotationNodes: PROC [rootNode: TextNode.Ref] = { annotationNode: TextNode.RefTextNode; CreateRootAnnotationNode: PROC = { annotationNode _ EditSpan.InsertTextNode[rootNode, rootNode, child]; [] _ TextEdit.AppendRope[rootNode, annotationNode, "<>"]; NodeProps.PutProp[annotationNode, propertyAnnotationAtom, trueRope]; NodeProps.PutProp[annotationNode, commentAtom, NodeProps.true]; }; CreateAnnotationNode: PROC [thisNode: TextNode.Ref, level: INTEGER] = { annotationNode _ EditSpan.InsertTextNode[root~rootNode, old~thisNode, where~before]; IF TextNode.Level[annotationNode] > TextNode.Level[thisNode] THEN [] _ EditSpan.ChangeNesting[ root~rootNode, span~TextNode.MakeNodeSpan[annotationNode, annotationNode], change~TextNode.Level[thisNode]-TextNode.Level[annotationNode]]; [] _ TextEdit.AppendRope[ rootNode, annotationNode, IO.PutFR["<>"]; NodeProps.PutProp[annotationNode, propertyAnnotationAtom, trueRope]; NodeProps.PutProp[annotationNode, commentAtom, NodeProps.true]; }; AnnotateProps: NodeProps.MapPropsAction = { nodeRope: Rope.ROPE _ Rope.Cat[", ", Atom.GetPName[name], ": ", NodeProps.GetSpecs[name, value]]; [] _ TextEdit.AppendRope[rootNode, annotationNode, nodeRope]; RETURN[FALSE]}; next: TextNode.Ref; level, levelDelta: INTEGER _ 1; IF AnAnnotationNode[TextNode.FirstChild[rootNode]] THEN RETURN; CreateRootAnnotationNode[]; [next, levelDelta] _ TextNode.Forward[TextNode.FirstChild[rootNode]]; WHILE next#NIL DO level _ level+levelDelta; CreateAnnotationNode[next, level]; [next, levelDelta] _ TextNode.Forward[next]; ENDLOOP; }; PruneAnnotationNodes: PROC [rootNode: TextNode.Ref] = { next, prev: TextNode.Ref; [next, ] _ TextNode.Forward[rootNode]; WHILE next#NIL DO IF AnAnnotationNode[next] THEN { prev _ next; [next, ] _ TextNode.Forward[next]; EditSpan.Delete[ root: rootNode, del: TextNode.MakeNodeSpan[prev, prev], saveForPaste: FALSE ! EditSpan.CannotDoEdit => CONTINUE]} ELSE [next, ] _ TextNode.Forward[next]; ENDLOOP; }; AnAnnotationNode: PROC [node: TextNode.Ref] RETURNS[BOOL] = { propValue: REF; IF node#NIL THEN IF (propValue _ NodeProps.GetProp[node, propertyAnnotationAtom])#NIL THEN IF Rope.Equal[trueRope, NodeProps.GetSpecs[propertyAnnotationAtom, propValue]] THEN RETURN[TRUE]; RETURN[FALSE]; }; TiogaPropsButton: Buttons.ButtonProc ~ { viewer: ViewerClasses.Viewer ~ InputFocus.GetInputFocus[].owner; rootNode: TextNode.Ref; IF viewer = NIL THEN { MessageWindow.Append[message: "Please select a viewer first.", clearFirst: TRUE]; MessageWindow.Blink[]; RETURN; }; IF viewer.class.flavor # $Text THEN { MessageWindow.Append[message: "Selected viewer is not a Tioga viewer.", clearFirst: TRUE]; MessageWindow.Blink[]; RETURN; }; TiogaOps.CancelSelection[primary]; TRUSTED { rootNode _ LOOPHOLE[TiogaOps.ViewerDoc[viewer]] }; TRUSTED { TiogaOps.Lock[LOOPHOLE[rootNode]]; }; IF mouseButton = red THEN AddAnnotationNodes[rootNode] ELSE PruneAnnotationNodes[rootNode]; TRUSTED { TiogaOps.Unlock[LOOPHOLE[rootNode]]; }; TRUSTED { TiogaOps.Jump[viewer, [LOOPHOLE[rootNode], 0]]; }; }; Commander.Register[ "AnnotateProperties", DoAnnotations, "Annotate a Tioga document by inserting nodes identifying properties and styles of each node", $Annotate]; Commander.Register[ "PruneAnnotations", DoAnnotations, "Prune the nodes created by the AnnotateProperties command", $Prune]; [] _ Buttons.Create[ info: [name: "TiogaProps"], proc: TiogaPropsButton, documentation: "Annotate a Tioga viewer; right-click to remove annotations"]; }. <> <> <<>> <> <> <<>>