DIRECTORY Ascii USING [SP], Basics USING [bitsPerWord], BasicTime USING [Now, nullGMT, Period], Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], Commander USING [CommandProc, Register], Containers USING [ChildXBound, ChildYBound, Container, Create], DFOperations USING [ ChoiceInteraction, ChoiceResponse, Choices, DFInfoInteraction, FileInteraction, InfoInteraction, InteractionProc, YesNoInteraction, YesNoResponse], DFOperationsQueue USING [Abort, Create, Empty, NotifierProc, OpTerminationInteraction], DFToolInternal USING [ AcquireLog, DFTool, DFToolRecord, GetToolParameters, offScreenY, OpDefiner, Operation, OperationRecord, OpSpecificAction, OuterContainerWidth, Parameters, PrompterSeq, ReactToProfile, ReleaseLog], DFUtilities USING [DateToRope], Graphics USING [SetCP], GraphicsOps USING [BitmapRef, BitmapRep, DrawBitmap], IO USING [card, PutChar, PutF, PutFR, PutRope, rope, STREAM, time], Labels USING [Create], List USING [Assoc, PutAssoc], Loader USING [BCDBuildTime], Process USING [MsecToTicks, SetTimeout], ProcessProps USING [AddPropList, GetPropList], Rope USING [Cat, Concat, Equal, Length, ROPE], Rules USING [Create, Rule], TypeScript USING [Create], UserProfile USING [CallWhenProfileChanges], VFonts USING [StringWidth], ViewerClasses USING [PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerIO USING [CreateViewerStreams], ViewerOps USING [ ComputeColumn, CreateViewer, DestroyViewer, MoveViewer, OpenIcon, PaintViewer, RegisterViewerClass, SetOpenHeight, ViewerColumn], ViewerTools USING [ GetContents, GetSelectedViewer, InhibitUserEdits, MakeNewTextViewer, SelPosRec, SetContents, SetSelection]; DFInterfaceImpl: CEDAR MONITOR LOCKS tool.LOCK USING tool: DFTool IMPORTS BasicTime, Buttons, Commander, Containers, DFOperationsQueue, DFToolInternal, DFUtilities, Graphics, GraphicsOps, IO, Labels, List, Loader, Process, ProcessProps, Rope, Rules, TypeScript, UserProfile, VFonts, ViewerIO, ViewerOps, ViewerTools EXPORTS DFToolInternal = BEGIN OPEN Ops: DFOperations, OpsQ: DFOperationsQueue, Tool: DFToolInternal, Utils: DFUtilities; ROPE: TYPE = Rope.ROPE; DFTool: TYPE = Tool.DFTool; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- PromptArray: TYPE = ARRAY [0..promptH) OF WORD; promptW: NAT = 13; promptH: NAT = 10; prompt: GraphicsOps.BitmapRef = NEW[GraphicsOps.BitmapRep _ [ base: NEW [PromptArray _ [ 001600B, 000700B, 00340B, 000160B, 177770B, 177770B, 000160B, 000340B, 000700B, 001600B]], raster: (promptW + Basics.bitsPerWord - 1)/Basics.bitsPerWord, width: promptW, height: promptH ]]; dfPrompter: ViewerClasses.ViewerClass = NEW[ViewerClasses.ViewerClassRec _ [paint: PaintPrompter]]; idleMessage: ROPE = "\NIdle."; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- maxOps: NAT = 10; minFeedbackLines: NAT = 5; interactionQuestionLines: NAT = 3; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- DFToolCommand: Commander.CommandProc = {NewDFTool[iconic: TRUE]}; NewDFTool: PROC [iconic: BOOL] = { parameters: Tool.Parameters = Tool.GetToolParameters[]; tool: DFTool = NEW[Tool.DFToolRecord _ [parameters: parameters]]; firstOp: Tool.Operation _ NIL; AddSeparatingRule: PROC = { rule: Rules.Rule = Rules.Create[info: [ wx: 0, wy: tool.height, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: 1, parent: tool.outer ]]; Containers.ChildXBound[tool.outer, rule]; -- constrain rule to be width of parent tool.height _ tool.height + parameters.entryVSpace; -- spacing after rule }; BuildActions: PROC = { prev, rule: ViewerClasses.Viewer; heightForLabel: INT = tool.height; IF ~parameters.compactLayout THEN tool.height _ heightForLabel + parameters.entryHeight + parameters.entryVSpace; prev _ Buttons.Create[ info: [name: "Do It", wx: parameters.entryHSpace, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: TRUE ], proc: DoIt, fork: FALSE, clientData: tool, guarded: FALSE, font: parameters.font ]; prev _ Buttons.Create[ info: [name: "Help", wx: prev.wx + prev.ww + parameters.entryHSpace, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: TRUE ], proc: DoHelp, fork: FALSE, clientData: tool, guarded: FALSE, font: parameters.font ]; prev _ Buttons.Create[ info: [name: "Command Line", wx: prev.wx + prev.ww + parameters.entryHSpace, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: TRUE ], proc: DoCommandLine, fork: FALSE, clientData: tool, guarded: FALSE, font: parameters.font ]; prev _ Buttons.Create[ info: [name: "Stop!", wx: prev.wx + prev.ww + 2*parameters.entryHSpace, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: TRUE ], proc: AbortOperation, clientData: tool, guarded: FALSE, font: parameters.boldFont ]; IF ~parameters.compactLayout THEN { actionLabel: ROPE = "Action for Selected Operation"; [] _ Labels.Create[ info: [name: actionLabel, wx: (prev.wx + prev.ww + parameters.entryHSpace - VFonts.StringWidth[actionLabel])/2, wy: heightForLabel, wh: parameters.entryHeight, parent: tool.outer, border: FALSE ], font: parameters.boldFont ]; }; rule _ Rules.Create[info: [ wx: prev.wx + prev.ww + parameters.entryHSpace, wy: 0, ww: 1, wh: tool.height + parameters.entryHeight + parameters.entryVSpace, parent: tool.outer ]]; prev _ Buttons.Create[ info: [name: "New Tool", wx: rule.wx + rule.ww + 2*parameters.entryHSpace, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: TRUE ], proc: MakeDFTool, clientData: tool, guarded: FALSE, font: parameters.font ]; IF ~parameters.compactLayout THEN { miscLabel: ROPE = "Miscellaneous"; [] _ Labels.Create[ info: [name: miscLabel, wx: rule.wx + (Tool.OuterContainerWidth[tool] - rule.wx - VFonts.StringWidth[miscLabel])/2, wy: heightForLabel, wh: parameters.entryHeight, parent: tool.outer, border: FALSE ], font: parameters.boldFont ]; }; tool.height _ tool.height + parameters.entryHeight + parameters.entryVSpace; }; BuildOperations: PROC RETURNS [firstOp: Tool.Operation _ NIL] = { wDir: ROPE _ NARROW[List.Assoc[key: $WorkingDirectory, aList: ProcessProps.GetPropList[]]]; prev: ViewerClasses.Viewer; prevX: INT _ parameters.entryHSpace; IF wDir.Length[] = 0 THEN wDir _ "///"; tool.opsQueue _ OpsQ.Create[idleNotifier: IdleNotifier, clientData: tool]; tool.inner _ Containers.Create[info: [ wx: 0, wy: 0, -- to be recomputed by MoveViewer later ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: 9999, -- arbitrary; Containers.ChildYBound overrides parent: tool.outer, border: FALSE, scrollable: FALSE ]]; Containers.ChildXBound[container: tool.outer, child: tool.inner]; Containers.ChildYBound[container: tool.outer, child: tool.inner]; IF ~parameters.compactLayout THEN { operationsLabel: ROPE = "Operations (select one)"; [] _ Labels.Create[ info: [name: operationsLabel, wx: (Tool.OuterContainerWidth[tool] - VFonts.StringWidth[operationsLabel])/2, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: FALSE ], font: parameters.boldFont ]; tool.height _ tool.height + parameters.entryHeight + parameters.entryVSpace; }; FOR i: NAT IN [0..parameters.opTable.nOps) DO opDefiner: REF Tool.OpDefiner = parameters.opTable.ops[i]; IF opDefiner.userClass <= tool.parameters.userClass THEN { op: Tool.Operation = NEW[Tool.OperationRecord _ [tool: tool, definer: opDefiner]]; op.button _ Buttons.Create[ info: [name: opDefiner.opAlias, wx: prevX, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: TRUE ], proc: SelectOperation, fork: FALSE, clientData: op, font: parameters.font ]; IF op.button.wx + op.button.ww > Tool.OuterContainerWidth[tool] THEN ViewerOps.MoveViewer[ viewer: op.button, x: (prevX _ parameters.entryHSpace), y: (tool.height _ tool.height + parameters.entryHeight + parameters.entryVSpace), w: op.button.ww, h: op.button.wh, paint: FALSE ]; opDefiner.proc[$createOptions, op]; prevX _ parameters.entryHSpace + op.button.wx + op.button.ww; IF firstOp = NIL THEN firstOp _ op; }; ENDLOOP; tool.height _ tool.height + parameters.entryHeight + parameters.entryVSpace; prev _ Buttons.Create[ info: [name: "DF file(s):", wx: parameters.entryHSpace, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: FALSE ], proc: SelectDFNames, fork: FALSE, clientData: tool, font: parameters.font ]; tool.dfNames _ ViewerTools.MakeNewTextViewer[info: [ wx: prev.wx + prev.ww + parameters.entryHSpace, wy: tool.height, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: parameters.entryHeight, data: IF tool.parameters.dfNamePrefixes = NIL THEN NIL ELSE tool.parameters.dfNamePrefixes.first, parent: tool.outer, scrollable: TRUE, border: FALSE ]]; Containers.ChildXBound[container: tool.outer, child: tool.dfNames]; tool.height _ tool.height + parameters.entryHeight + parameters.entryVSpace; prev _ Buttons.Create[ info: [name: "Working Directory:", wx: parameters.entryHSpace, wy: tool.height, wh: parameters.entryHeight, parent: tool.outer, border: FALSE ], proc: SelectWorkingDirectory, fork: FALSE, clientData: tool, font: parameters.font ]; tool.wDir _ ViewerTools.MakeNewTextViewer[info: [ wx: prev.wx + prev.ww + parameters.entryHSpace, wy: tool.height, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: parameters.entryHeight, data: wDir, parent: tool.outer, scrollable: TRUE, border: FALSE ]]; Containers.ChildXBound[container: tool.outer, child: tool.dfNames]; tool.height _ tool.height + parameters.entryHeight + parameters.entryVSpace; AddSeparatingRule[]; ViewerOps.MoveViewer[ viewer: tool.inner, x: tool.inner.wx, y: tool.height, w: tool.inner.ww, h: tool.inner.wh, paint: FALSE ]; }; BuildInteraction: PROC = { h, ih: INT _ 0; v: ViewerClasses.Viewer; tool.bottom _ Containers.Create[info: [ wx: 0, wy: 0, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: 9999, -- arbitrary; Containers.ChildYBound overrides parent: tool.inner, border: FALSE, scrollable: FALSE ]]; Containers.ChildXBound[container: tool.inner, child: tool.bottom]; Containers.ChildYBound[container: tool.inner, child: tool.bottom]; v _ Rules.Create[info: [ wy: h, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: 1, parent: tool.bottom ]]; Containers.ChildXBound[tool.bottom, v]; -- constrain rule to be width of parent h _ h + parameters.entryVSpace; IF ~parameters.compactLayout THEN { interactionLabel: ROPE = "Confirmation Area"; [] _ Labels.Create[ info: [name: interactionLabel, wx: (Tool.OuterContainerWidth[tool] - VFonts.StringWidth[interactionLabel])/2, wy: h, wh: parameters.entryHeight, parent: tool.bottom, border: FALSE ], font: parameters.boldFont ]; h _ h + parameters.entryHeight + parameters.entryVSpace; }; tool.interaction _ Containers.Create[info: [ wx: 0, wy: h, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: 0, -- will be established by MoveViewer, later parent: tool.bottom, border: FALSE, scrollable: FALSE ]]; Containers.ChildXBound[container: tool.bottom, child: tool.interaction]; tool.question _ ViewerTools.MakeNewTextViewer[info: [ wx: 0, wy: ih, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: interactionQuestionLines*parameters.entryHeight, data: idleMessage, parent: tool.interaction, scrollable: TRUE, border: FALSE ]]; Containers.ChildXBound[container: tool.interaction, child: tool.question]; ViewerTools.InhibitUserEdits[tool.question]; ih _ ih + interactionQuestionLines*parameters.entryHeight + parameters.entryVSpace; v _ Buttons.Create[ info: [name: "Auto-Confirm", wx: parameters.entryHSpace, wy: ih, wh: parameters.entryHeight, parent: tool.interaction, border: TRUE ], proc: AutoConfirmButton, fork: FALSE, -- for atomic update/test of tool.autoConfirm clientData: tool, font: parameters.font ]; v _ tool.prompter _ ViewerOps.CreateViewer[ flavor: $DFPrompter, info: [ wx: v.wx + v.ww + parameters.entryHSpace, wy: ih + (IF parameters.entryHeight > promptH THEN (parameters.entryHeight - promptH)/2 ELSE 0), ww: promptW+Tool.PrompterSeq.LAST, wh: promptH, data: tool, parent: tool.interaction, scrollable: FALSE, border: FALSE ] ]; TRUSTED{Process.SetTimeout[@tool.responseMade, Process.MsecToTicks[90]]}; tool.choicesX _ v.wx + v.ww + parameters.entryHSpace; tool.choicesY _ ih + (IF parameters.entryHeight < promptH THEN (promptH - parameters.entryHeight)/2 ELSE 0); ih _ ih + MAX[parameters.entryHeight, promptH]; ViewerOps.MoveViewer[ viewer: tool.interaction, x: tool.interaction.wx, y: tool.interaction.wy, w: tool.interaction.ww, h: ih, paint: FALSE ]; h _ h + ih + parameters.entryVSpace; v _ Rules.Create[info: [ wy: h, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: 1, parent: tool.bottom ]]; Containers.ChildXBound[tool.bottom, v]; -- constrain rule to be width of parent h _ h + parameters.entryVSpace; IF ~parameters.compactLayout THEN { feedbackLabel: ROPE = "Session Log"; [] _ Labels.Create[ info: [name: feedbackLabel, wx: (Tool.OuterContainerWidth[tool] - VFonts.StringWidth[feedbackLabel])/2, wy: h, wh: parameters.entryHeight, parent: tool.bottom, border: FALSE ], font: parameters.boldFont ]; h _ h + parameters.entryHeight + parameters.entryVSpace; }; v _ TypeScript.Create[info: [ wx: 0, wy: h, ww: 9999, -- arbitrary; Containers.ChildXBound overrides wh: 9999, -- arbitrary; Containers.ChildYBound overrides parent: tool.bottom, border: FALSE ]]; ViewerTools.InhibitUserEdits[v]; Containers.ChildXBound[container: tool.bottom, child: v]; Containers.ChildYBound[container: tool.bottom, child: v]; tool.bottomMinHeight _ h _ h + minFeedbackLines*parameters.entryHeight + parameters.entryVSpace; tool.feedback _ ViewerIO.CreateViewerStreams[name: NIL, viewer: v].out; tool.height _ tool.height + h; }; tool.outer _ Containers.Create[ info: [name: "DF Tool", iconic: TRUE, column: right, scrollable: FALSE], paint: iconic -- if ~iconic, we keep the icon from appearing at all ]; tool.height _ parameters.entryVSpace; BuildActions[]; AddSeparatingRule[]; firstOp _ BuildOperations[]; BuildInteraction[]; ViewerOps.SetOpenHeight[tool.outer, tool.height]; IF firstOp ~= NIL THEN SelectOperation[parent: firstOp.button, clientData: firstOp]; IF ~iconic THEN ViewerOps.OpenIcon[icon: tool.outer, bottom: FALSE]; tool.feedback.PutF["DFTool of %t\N", IO.time[Loader.BCDBuildTime[]]]; tool.feedback.PutF["Session began at %t\N", IO.time[BasicTime.Now[]]]; }; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ResponseData: TYPE = RECORD [tool: DFTool, index: NAT]; OpsInteraction: PUBLIC Ops.InteractionProc = { tool: DFTool = NARROW[clientData]; buttonList: LIST OF Buttons.Button _ NIL; MakeChoiceButtons: PROC [tool: DFTool, choices: REF Ops.Choices] = { x: INT _ tool.choicesX; last: LIST OF Buttons.Button _ NIL; FOR i: NAT IN [0..choices.length) DO button: Buttons.Button _ Buttons.Create[ info: [name: choices[i], wx: x, wy: tool.choicesY, wh: tool.parameters.entryHeight, parent: tool.interaction, border: TRUE ], proc: ResponseButtonHit, clientData: NEW[ResponseData _ [tool: tool, index: i]], font: tool.parameters.font, paint: FALSE ]; buttonL: LIST OF Buttons.Button = CONS[button, NIL]; x _ button.wx + button.ww + tool.parameters.entryHSpace; IF last = NIL THEN buttonList _ buttonL ELSE last.rest _ buttonL; last _ buttonL; ENDLOOP; }; DestroyChoiceButtons: PROC [tool: DFTool] = { FOR l: LIST OF Buttons.Button _ buttonList, l.rest UNTIL l = NIL DO ViewerOps.DestroyViewer[viewer: l.first, paint: FALSE]; ENDLOOP; }; IF ~tool.abortRequested THEN { WITH interaction SELECT FROM info: REF Ops.InfoInteraction => { THROUGH [0..2*tool.recursionDepth) DO tool.feedback.PutChar[Ascii.SP]; ENDLOOP; tool.feedback.PutF["%g%g\N", IO.rope[ SELECT info.class FROM warning => "Warning: ", error => "Error: ", abort => "Abort: ", ENDCASE => NIL ], IO.rope[info.message] ]; }; info: REF Ops.DFInfoInteraction => { GetMessage: PROC RETURNS [ROPE] = { RETURN[ IF info.message = NIL THEN info.dfFile ELSE IO.PutFR["%g (%g)", IO.rope[info.dfFile], IO.rope[info.message]] ] }; SELECT info.action FROM $start => { IF (tool.recursionDepth _ tool.recursionDepth.SUCC) = 0 THEN PostProgressMessage[tool, Rope.Cat["\NWorking on ", info.dfFile, " . . ."]]; THROUGH [0..2*tool.recursionDepth) DO tool.feedback.PutChar[Ascii.SP]; ENDLOOP; tool.feedback.PutF["%g: %g\N", IO.rope[tool.selectedOp.definer.opAlias], IO.rope[GetMessage[]] ]; }; $end => { THROUGH [0..2*tool.recursionDepth) DO tool.feedback.PutChar[Ascii.SP]; ENDLOOP; tool.feedback.PutF["End: %g\N", IO.rope[GetMessage[]]]; tool.recursionDepth _ tool.recursionDepth.PRED; }; $abort => { tool.feedback.PutF["Aborted: %g\N", IO.rope[GetMessage[]]]; tool.recursionDepth _ -1; }; ENDCASE; }; done: REF OpsQ.OpTerminationInteraction => { trouble: BOOL = done.errors + done.warnings ~= 0; tool.feedback.PutF["%d files %g%g\N", IO.card[done.filesActedUpon], IO.rope[ SELECT done.op FROM bringOver => "retrieved", sModel => "stored", verify => "checked", ENDCASE => NIL ], IO.rope[ IF trouble THEN IO.PutFR[" (with %d errors, %d warnings)", IO.card[done.errors], IO.card[done.warnings]] ELSE ", no errors" ] ]; IF trouble THEN tool.unusualEnd _ CONS[done, tool.unusualEnd]; }; file: REF Ops.FileInteraction => { THROUGH [0..2*tool.recursionDepth) DO tool.feedback.PutChar[Ascii.SP]; ENDLOOP; tool.feedback.PutF["%g %g %g {%g}%g\N", IO.rope[file.localFile], IO.rope[ SELECT file.action FROM $fetch => "<--", $store => "-->", $check => "<-->", ENDCASE => NIL], IO.rope[file.remoteFile], IO.rope[Utils.DateToRope[[$explicit, file.date]]], IO.rope[ IF file.dateFormat = $explicit THEN NIL ELSE IO.PutFR[" ('%g')", SELECT file.dateFormat FROM $greaterThan => [character['>]], $notEqual => [rope["~="]], ENDCASE => [null[]] ] ] ]; }; yn: REF Ops.YesNoInteraction => { oldContents: ROPE = ViewerTools.GetContents[tool.question]; choices: REF Ops.Choices _ NIL; yes: BOOL; IF tool.autoConfirm THEN RETURN; choices _ NEW[Ops.Choices[2]]; choices[0] _ "Yes"; choices[1] _ "No"; ViewerTools.SetContents[viewer: tool.question, contents: yn.message, paint: FALSE]; MakeChoiceButtons[tool, choices]; ViewerOps.PaintViewer[tool.interaction, $all]; yes _ WaitForResponse[tool] = 0; DestroyChoiceButtons[tool]; ViewerTools.SetContents[viewer: tool.question, contents: oldContents, paint: FALSE]; ViewerOps.PaintViewer[tool.interaction, $all]; IF tool.autoConfirm THEN RETURN; RETURN[response: NEW[Ops.YesNoResponse _ [yes]]] }; choice: REF Ops.ChoiceInteraction => { oldContents: ROPE = ViewerTools.GetContents[tool.question]; x: INT _ tool.choicesX; last: LIST OF Buttons.Button _ NIL; value: NAT; IF tool.autoConfirm THEN RETURN; ViewerTools.SetContents[viewer: tool.question, contents: choice.message, paint: FALSE]; MakeChoiceButtons[tool, choice.choices]; ViewerOps.PaintViewer[tool.interaction, $all]; value _ WaitForResponse[tool]; DestroyChoiceButtons[tool]; ViewerTools.SetContents[viewer: tool.question, contents: oldContents, paint: FALSE]; ViewerOps.PaintViewer[tool.interaction, $all]; IF tool.autoConfirm THEN RETURN; RETURN[response: NEW[Ops.ChoiceResponse _ [value]]] }; ENDCASE; }; IF tool.abortRequested THEN { abort _ TRUE; abortMessageForLog _ "(user generated)"; tool.abortRequested _ FALSE; }; }; ResponseButtonHit: Buttons.ButtonProc = { responseData: REF ResponseData = NARROW[clientData]; tool: DFTool = responseData.tool; ResponseSeen[tool, responseData.index]; }; AutoConfirmButton: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; IF (tool.autoConfirm _ ~tool.autoConfirm) THEN { Buttons.SetDisplayStyle[NARROW[parent], $WhiteOnBlack]; ResponseSeen[tool]; } ELSE Buttons.SetDisplayStyle[NARROW[parent], $BlackOnWhite]; }; ResponseSeen: ENTRY PROC [tool: DFTool, value: NAT _ NAT.LAST] = { tool.responseValue _ value; tool.responseSeen _ TRUE; BROADCAST tool.responseMade; -- wakes up both prompter and main operation }; WaitForResponse: PROC [tool: DFTool] RETURNS [value: NAT] = { p: PROCESS; WaitForResponseEntry: ENTRY PROC [tool: DFTool] = { tool.responseSeen _ FALSE; p _ FORK PrompterProcess[tool]; UNTIL tool.responseSeen DO WAIT tool.responseMade; ENDLOOP; value _ tool.responseValue; }; WaitForResponseEntry[tool]; TRUSTED{JOIN p}; }; PrompterProcess: PROC [tool: DFTool] = { Done: ENTRY PROC [tool: DFTool] RETURNS [BOOL] = { WAIT tool.responseMade; RETURN[tool.responseSeen] }; UNTIL Done[tool] DO ViewerOps.PaintViewer[tool.prompter, all]; ENDLOOP; ViewerOps.PaintViewer[tool.prompter, all]; -- clears prompter entirely }; PaintPrompter: ViewerClasses.PaintProc = { tool: DFTool = NARROW[self.data]; IF ~tool.responseSeen THEN { -- strictly speaking, should be inside the monitor Graphics.SetCP[context, tool.prompterSeq, 0]; GraphicsOps.DrawBitmap[ self: context, bitmap: prompt, w: promptW, h: promptH, xorigin: 0, yorigin: promptH ]; tool.prompterSeq _ (tool.prompterSeq + 2) MOD Tool.PrompterSeq.LAST.SUCC; }; }; PostProgressMessage: PROC [tool: DFTool, r: ROPE] = { ViewerTools.SetContents[tool.question, r]; }; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- DoIt: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; op: Tool.Operation = tool.selectedOp; DoItEntry: ENTRY PROC [tool: DFTool] = { IF tool.startTime = BasicTime.nullGMT THEN { herald: ROPE; tool.startTime _ BasicTime.Now[]; herald _ IO.PutFR["\N%g at %t\N", IO.rope[op.definer.opAlias], IO.time[tool.startTime]]; tool.log _ Tool.AcquireLog[]; PostProgressMessage[tool, IO.PutFR["\NRunning at %t . . .", IO.time[tool.startTime]]]; tool.feedback.PutRope[herald]; IF tool.log ~= NIL THEN tool.log.PutRope[herald]; tool.unusualEnd _ NIL; }; op.definer.proc[$doOp, op]; }; IF op ~= NIL THEN DoItEntry[tool] ELSE tool.feedback.PutRope["\NPlease select an operation first.\N"]; }; IdleNotifier: OpsQ.NotifierProc = { IdleNotifierEntry: ENTRY PROC [tool: DFTool] = { IF tool.opsQueue.Empty[] THEN { msg: ROPE _ NIL; tool.feedback.PutF["Time: %r\N", IO.card[BasicTime.Period[from: tool.startTime, to: BasicTime.Now[]]] ]; Tool.ReleaseLog[tool.log]; IF tool.unusualEnd ~= NIL THEN { msg _ msg.Concat["The following terminated unusually:"]; FOR list: LIST OF REF OpsQ.OpTerminationInteraction _ tool.unusualEnd, list.rest UNTIL list = NIL DO done: REF OpsQ.OpTerminationInteraction = list.first; msg _ msg.Concat[ IO.PutFR["\N %g: %d errors, %d warnings", IO.rope[done.dfFile], IO.card[done.errors], IO.card[done.warnings]] ]; ENDLOOP; tool.unusualEnd _ NIL; }; PostProgressMessage[tool, msg.Concat[idleMessage]]; tool.recursionDepth _ -1; tool.abortRequested _ FALSE; tool.log _ NIL; tool.startTime _ BasicTime.nullGMT; -- indicate tool is idle }; }; IdleNotifierEntry[NARROW[clientData]] }; DoHelp: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; IF tool.selectedOp ~= NIL THEN tool.selectedOp.definer.proc[$doHelp, tool.selectedOp] ELSE tool.feedback.PutRope["\NPlease select an operation first.\N"]; }; DoCommandLine: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; IF tool.selectedOp ~= NIL THEN tool.selectedOp.definer.proc[$makeCommandLine, tool.selectedOp] ELSE tool.feedback.PutRope["\NPlease select an operation first.\N"]; }; AbortOperation: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; tool.abortRequested _ TRUE; IF mouseButton = blue THEN tool.opsQueue.Abort[]; ResponseSeen[tool]; -- wake up waiting operation, if any. }; MakeDFTool: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; MakeDFToolInner: PROC = {NewDFTool[iconic: FALSE]}; ProcessProps.AddPropList[ List.PutAssoc[ key: $WorkingDirectory, val: ViewerTools.GetContents[tool.wDir], aList: NIL ], MakeDFToolInner]; }; SelectOperation: Buttons.ButtonProc = { op: Tool.Operation = NARROW[clientData]; tool: DFTool = op.tool; SelectOperationEntry: ENTRY PROC [tool: DFTool] = { ENABLE UNWIND => NULL; selected: Tool.Operation = tool.selectedOp; IF selected = op THEN RETURN; IF selected ~= NIL THEN { ViewerOps.MoveViewer[ viewer: selected.optionsContainer, x: 0, y: Tool.offScreenY, w: selected.optionsContainer.ww, h: selected.optionsContainer.wh, paint: FALSE ]; Buttons.SetDisplayStyle[selected.button, $BlackOnWhite]; }; tool.selectedOp _ op; Buttons.SetDisplayStyle[op.button, $WhiteOnBlack]; ViewerOps.MoveViewer[ viewer: tool.bottom, x: 0, y: op.optionsContainer.wh, w: tool.bottom.ww, h: tool.bottomMinHeight, paint: FALSE ]; tool.height _ tool.inner.wy + op.optionsContainer.wh + tool.bottomMinHeight; ViewerOps.SetOpenHeight[tool.outer, tool.height]; ViewerOps.ComputeColumn[ViewerOps.ViewerColumn[tool.outer]]; ViewerOps.MoveViewer[ viewer: op.optionsContainer, x: 0, y: 0, w: op.optionsContainer.ww, h: op.optionsContainer.wh ]; }; SelectOperationEntry[tool]; }; SelectDFNames: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; selection: REF ViewerTools.SelPosRec _ NIL; SELECT TRUE FROM mouseButton = blue => ViewerTools.SetContents[tool.dfNames, NIL]; ViewerTools.GetSelectedViewer[] = tool.dfNames => { NextName: PROC [this: ROPE, list: LIST OF ROPE] RETURNS [next: ROPE _ NIL] = { IF list = NIL THEN RETURN; FOR l: LIST OF ROPE _ list, l.rest UNTIL l = NIL DO IF this.Equal[l.first, FALSE] THEN RETURN[IF l.rest = NIL THEN list.first ELSE l.rest.first] ENDLOOP; RETURN[list.first] }; contents: ROPE _ ViewerTools.GetContents[tool.dfNames]; ViewerTools.SetContents[tool.dfNames, contents _ NextName[contents, tool.parameters.dfNamePrefixes]]; selection _ NEW[ViewerTools.SelPosRec _ [start: contents.Length[], length: 0]]; }; ENDCASE; ViewerTools.SetSelection[tool.dfNames, selection]; }; SelectWorkingDirectory: Buttons.ButtonProc = { tool: DFTool = NARROW[clientData]; IF mouseButton = blue THEN ViewerTools.SetContents[tool.wDir, NIL]; ViewerTools.SetSelection[tool.wDir, NIL]; }; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ViewerOps.RegisterViewerClass[$DFPrompter, dfPrompter]; UserProfile.CallWhenProfileChanges[Tool.ReactToProfile]; Commander.Register[key: "DFTool", proc: DFToolCommand, doc: "User interface to DF files"]; NewDFTool[iconic: TRUE]; END. VDFInterfaceImpl.mesa last edited by Levin on December 6, 1983 3:30 pm Global "Variables" (constant after init) Configuration Parameters (private) Tool Construction ***Main Body of NewDFTool*** Interaction Stuff Button Action Procedures clean-up code appears in IdleNotifier Tool is really idle; any pending call of DoIt is hanging on the monitor. Note: runs synchronously with Viewers' notifier to ensure atomicity with `DoIt'. Get old options out of sight. Move typescript to proper place considering new options. Move new options into place (and paint). Note: runs synchronously with Viewers' notifier to ensure than manipulation of `tool.dfNames' is atomic. dfNames was previously selected, so we iterate through the prefixes. Note: runs synchronously with Viewers' notifier to ensure than manipulation of 'tool.wDir' is atomic. Initialization Êf˜Jšœ™Jšœ0™0J˜šÏk ˜ Jšœœœ˜Jšœœ˜Jšœ œ˜'Jšœœ/˜˜>Jšœ˜Jšœ˜Jšœ˜—J˜šœ'˜'Jšœ8˜;—J˜Jšœ œ ˜J˜Jšžœžœžœžœžœžœžœž˜'J™"Jšžœžœžœžœžœžœžœž˜'J˜Jšœœ˜J˜Jšœœ˜Jšœœ˜"J˜Jšžœžœžœžœžœžœžœž˜'Jšœ™Jšžœžœžœžœžœžœžœž˜'J˜J˜Jšœ:œ˜AJ˜šÏn œœ œ˜"J˜7Jšœœ/˜AJšœœ˜šŸœœ˜˜'J˜Jšœ˜Jšœ ž.˜9J˜Jšœ˜Jšœ˜—Jšœ+ž'˜RJšœ5ž˜JJ˜—šŸ œœ˜Jšœ!˜!Jšœœ˜"šœ˜!JšœO˜O—šœ˜˜Jšœ˜J˜Jšœ˜J˜Jšœ˜ J˜—J˜ Jšœœ˜ Jšœ˜Jšœ ˜Jšœ˜J˜—šœ˜˜Jšœ/˜/J˜Jšœ˜J˜Jšœ˜ J˜—J˜ Jšœœ˜ Jšœ˜Jšœ œ˜Jšœ˜J˜—šœ˜˜Jšœ/˜/J˜Jšœ˜J˜Jšœ˜ J˜—J˜Jšœœ˜ Jšœ˜Jšœ œ˜Jšœ˜J˜—šœ˜˜Jšœ1˜1J˜Jšœ˜J˜Jšœ˜ J˜—J˜Jšœ˜Jšœ œ˜Jšœ˜J˜—šœœ˜#Jšœ œ#˜4šœ˜šœ˜JšœU˜UJšœ˜Jšœ˜Jšœ˜Jšœ˜ Jšœ˜—Jšœ˜Jšœ˜—J˜—˜Jšœ/˜/Jšœ˜Jšœ˜JšœB˜BJšœ˜Jšœ˜—šœ˜˜Jšœ1˜1J˜Jšœ˜J˜Jšœ˜ J˜—J˜Jšœ˜Jšœ œ˜Jšœ˜J˜—šœœ˜#Jšœ œ˜"šœ˜šœ˜šœ ˜ JšœM˜M—Jšœ˜Jšœ˜Jšœ˜Jšœ˜ Jšœ˜—Jšœ˜Jšœ˜—J˜—JšœL˜LJ˜—šŸœœœœ˜AJšœœœH˜[J˜Jšœœ˜$Jšœœ˜'J˜Jšœ&˜&Jšœ˜Jšœž'˜/Jšœ ž.˜8Jšœ ž.˜8Jšœ˜Jšœœ˜Jšœ ˜Jšœ˜—JšœA˜AJšœA˜Ašœœ˜#Jšœœ˜2šœ˜šœ˜JšœM˜MJšœ˜Jšœ˜Jšœ˜Jšœ˜ Jšœ˜—Jšœ˜Jšœ˜—JšœL˜LJ˜—šœœœ˜-Jšœ œ,˜:šœ2œ˜:Jšœœ:˜Ršœ˜šœ˜Jšœ ˜ J˜Jšœ˜J˜Jšœ˜ J˜—J˜Jšœœ˜ Jšœ˜Jšœ˜J˜—šœ>˜Dšœ˜Jšœ˜Jšœ$˜$JšœQ˜QJšœ!˜!Jšœ˜ J˜——Jšœ#˜#Jšœ=˜=Jšœ œœ˜#J˜—Jšœ˜—JšœL˜L˜˜Jšœ˜Jšœ˜Jšœ˜J˜Jšœ˜ J˜—J˜Jšœœ˜ Jšœ˜Jšœ˜J˜—˜4Jšœ/˜/J˜Jšœ ž.˜9Jšœ˜šœ˜Jšœ"œœ˜0Jšœ&˜*—J˜Jšœ œ˜Jšœ˜ Jšœ˜—J˜CJšœL˜L˜˜"Jšœ˜Jšœ˜Jšœ˜J˜Jšœ˜ J˜—J˜Jšœœ˜ Jšœ˜Jšœ˜J˜—˜1Jšœ/˜/J˜Jšœ ž.˜9Jšœ˜Jšœ ˜ J˜Jšœ œ˜Jšœ˜ Jšœ˜—J˜CJšœL˜LJ˜šœ˜Jšœ˜Jšœ!˜!Jšœ#˜#Jšœ˜ J˜—J˜—šŸœœ˜Jšœœ˜J˜šœ'˜'Jšœ ˜ Jšœ ž.˜8Jšœ ž.˜8Jšœ˜Jšœœ˜Jšœ ˜Jšœ˜—JšœB˜BJšœB˜B˜Jšœ˜Jšœ ž.˜9J˜Jšœ˜Jšœ˜—Jšœ)ž'˜PJšœ˜šœœ˜#Jšœœ˜-šœ˜šœ˜JšœN˜NJšœ˜Jšœ˜Jšœ˜Jšœ˜ Jšœ˜—Jšœ˜Jšœ˜—Jšœ8˜8J˜—šœ,˜,Jšœ ˜ Jšœ ž.˜8Jšœž+˜3Jšœ˜Jšœœ˜Jšœ ˜Jšœ˜—JšœH˜H˜5J˜J˜Jšœ ž.˜9Jšœ4˜4Jšœ˜Jšœ˜Jšœ œ˜Jšœ˜ Jšœ˜—JšœJ˜JJšœ,˜,JšœS˜S˜˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜ J˜—J˜Jšœœž-˜;Jšœ˜Jšœ˜J˜—˜+J˜˜Jšœ)˜)Jšœ œ"œ&œ˜`Jšœœ˜"J˜ J˜ Jšœ˜Jšœ œ˜Jšœ˜ J˜—J˜—JšœB˜IJšœ5˜5Jšœœ"œ&œ˜lJšœ œ"˜/šœ˜Jšœ˜Jšœ/˜/Jšœ˜Jšœ˜ J˜—Jšœ$˜$˜Jšœ˜Jšœ ž.˜9J˜Jšœ˜Jšœ˜—Jšœ)ž'˜PJšœ˜šœœ˜#Jšœœ˜$šœ˜šœ˜JšœK˜KJšœ˜Jšœ˜Jšœ˜Jšœ˜ Jšœ˜—Jšœ˜Jšœ˜—Jšœ8˜8J˜—˜Jšœ˜J˜Jšœ ž.˜9Jšœ ž.˜9Jšœ˜Jšœ˜ Jšœ˜—J˜ Jšœ9˜9Jšœ9˜9šœ˜JšœI˜I—Jšœ3œ˜GJ˜J˜—Jšœ™˜Jšœ œœ˜HJšœž5˜DJšœ˜—Jšœ%˜%J˜J˜J˜J˜Jšœ1˜1Jšœ œœ>˜TJšœ œ.œ˜DJšœ%œ˜EJšœ,œ˜FJ˜—J˜Jšžœžœžœžœžœžœžœž˜'Jšœ™Jšžœžœžœžœžœžœžœž˜'J˜Jšœœœœ˜7J˜šœœ˜.Jšœœ ˜"Jšœ œœœ˜)šŸœœœ˜DJšœœ˜Jšœœœœ˜#šœœœ˜$˜(˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜ J˜—J˜Jšœ œ(˜7Jšœ˜Jšœ˜ J˜—Jš œ œœœ œ˜4Jšœ8˜8Jšœœœœ˜AJšœ˜Jšœ˜—J˜—šŸœœ˜-š œœœ%œœ˜CJšœ0œ˜7Jšœ˜—J˜—šœœ˜šœ œ˜šœœ˜"Jšœœœœ˜O˜šœ˜šœ ˜Jšœ@œ˜N—Jšœ˜—Jšœ˜J˜—J˜—šœœ˜$šŸ œœœœ˜#šœ˜Jšœœœ ˜&Jšœœœœ˜EJšœ˜—J˜—šœ ˜šœ ˜ šœ,œ˜J˜—šœœ˜"Jšœœœœ˜O˜'Jšœ˜šœ˜šœ ˜Jšœ4œœ˜D——Jšœ˜Jšœ0˜2šœ˜Jšœœ˜'šœœ˜šœ˜Jšœ ˜ Jšœ˜Jšœ ˜—Jšœ˜—J˜—Jšœ˜—J˜—šœœ˜!Jšœ œ*˜;Jšœ œœ˜Jšœœ˜ Jšœœœ˜ Jšœ œ˜J˜&JšœLœ˜SJ˜!Jšœ.˜.Jšœ ˜ J˜JšœMœ˜TJšœ.˜.Jšœœœ˜ Jšœ œ˜0J˜—šœœ˜&Jšœ œ*˜;Jšœœ˜Jšœœœœ˜#Jšœœ˜ Jšœœœ˜ JšœPœ˜WJ˜(Jšœ.˜.J˜J˜JšœMœ˜TJšœ.˜.Jšœœœ˜ Jšœ œ˜3J˜—Jšœ˜—J˜—šœœ˜Jšœœ˜ Jšœ(˜(Jšœœ˜Jšœ˜—Jšœ˜—J˜šœ)˜)Jšœœœ ˜4Jšœ!˜!Jšœ'˜'J˜J˜—šœ)˜)Jšœœ ˜"šœ(œ˜0Jšœœ˜7Jšœ˜J˜—Jšœœ˜