<> <> <> <> <<>> DIRECTORY FileViewerOps USING [], FS USING [Error, ExpandName, FileInfo], Icons USING [IconFlavor, NewIconFromFile], IO USING [PutF1, PutRope, ROS, STREAM], Menus USING [AppendMenuEntry, ClickProc, CreateEntry, FindEntry, MenuEntry, ReplaceMenuEntry], MessageWindow USING [Append], Process USING [CheckForAbort, Pause, SecondsToTicks], Rope USING [Cat, Concat, Fetch, Find, Length, Replace, ROPE, Run], TiogaMenuOps USING [DefaultMenus, Open], ViewerClasses USING [Viewer], ViewerOps USING [BlinkIcon, CreateViewer, DestroyViewer, EnumerateViewers, EnumProc, FindViewer, OpenIcon, PaintViewer]; FileViewerOpsImpl: CEDAR PROGRAM IMPORTS FS, Icons, IO, Menus, MessageWindow, Process, Rope, TiogaMenuOps, ViewerOps EXPORTS FileViewerOps = BEGIN Viewer: TYPE = ViewerClasses.Viewer; ViewerSaveStatus: TYPE = {none, old, new, saving}; ShowLog: PUBLIC PROC [fileName: Rope.ROPE, destroyIt: BOOL _ FALSE, createIconic: BOOL _ FALSE, blinkIfIconic: BOOL _ TRUE] = { logViewer: ViewerClasses.Viewer _ FindFileViewer[fileName]; IF destroyIt THEN {IF logViewer # NIL THEN ViewerOps.DestroyViewer[logViewer]} ELSE { IF logViewer = NIL THEN { icon: Icons.IconFlavor; SELECT TRUE FROM Rope.Find[fileName, ".errlog", 0, FALSE] # -1 => icon _ typescript; Rope.Find[fileName, ".log", 0, FALSE] # -1 => icon _ typescript; Rope.Find[fileName, ".mesa", 0, FALSE] # -1 => icon _ needsToBeCompiled; ENDCASE => icon _ document; logViewer _ CreateLog[fileName, icon, createIconic]}; IF logViewer # NIL AND logViewer.iconic AND blinkIfIconic THEN ViewerOps.BlinkIcon[logViewer]}; }; WaitUntilSaved: PUBLIC PROC [fileName: Rope.ROPE, feedBack: IO.STREAM _ NIL] = { lastState: ViewerSaveStatus _ none; fileNameLen: INT _ Rope.Length[fileName _ FS.ExpandName[fileName].fullFName]; IF feedBack = NIL THEN feedBack _ IO.ROS[]; DO state: ViewerSaveStatus _ none; vName: Rope.ROPE _ NIL; innerCheck: ViewerOps.EnumProc = { <<[v: ViewerClasses.Viewer] RETURNS [BOOL _ TRUE]>> IF Rope.Run[fileName, 0, v.file, 0, FALSE] # fileNameLen THEN RETURN; vName _ v.file; state _ CheckViewer[v]; SELECT state FROM new, saving => {vName _ v.file; RETURN [FALSE]}; ENDCASE => RETURN [TRUE]; }; Process.CheckForAbort[]; state _ none; vName _ NIL; ViewerOps.EnumerateViewers[innerCheck]; IF lastState # none AND state # lastState THEN IO.PutRope[feedBack, "\n"]; SELECT state FROM none => RETURN; lastState => {}; new => IO.PutF1[feedBack, "** Please save %g ...", [rope[vName]] ]; saving => IO.PutF1[feedBack, "** Saving %g ...", [rope[vName]] ]; ENDCASE => RETURN; Process.CheckForAbort[! ABORTED => IO.PutRope[feedBack, "\n"]]; lastState _ state; Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; }; AttachErrorLog: PUBLIC PROC [sourceFileName: Rope.ROPE] = { viewer: Viewer _ FindFileViewer[sourceFileName]; IF viewer # NIL THEN { AppendMenuEntry[viewer, "ErrorLog", OpenErrorLog]; SetIcon[viewer: viewer, from: document, to: needsToBeCompiled]}; }; RemoveErrorLog: PUBLIC PROC [sourceFileName: Rope.ROPE] = { errlogName: Rope.ROPE; errlog: Viewer; viewer: Viewer _ FindFileViewer[sourceFileName]; IF viewer # NIL THEN { RemoveMenuEntry[viewer, "ErrorLog"]; SetIcon[viewer: viewer, from: needsToBeCompiled, to: document]; }; errlogName _ ErrorLogName[sourceFileName]; WHILE (errlog _ ViewerOps.FindViewer[errlogName]) # NIL DO ViewerOps.DestroyViewer[errlog]; ENDLOOP; }; AppendMenuEntry: PROC [viewer: Viewer, name: Rope.ROPE, proc: Menus.ClickProc] = { FOR v: Viewer _ viewer, v.link WHILE v # NIL DO entry: Menus.MenuEntry _ Menus.FindEntry[v.menu, name]; IF entry = NIL THEN { entry _ Menus.CreateEntry[name: name, proc: proc, fork: FALSE]; Menus.AppendMenuEntry[menu: v.menu, line: 0, entry: entry]; IF NOT v.iconic THEN ViewerOps.PaintViewer[v, menu]; }; IF v.link = viewer THEN EXIT; ENDLOOP; }; RemoveMenuEntry: PROC [viewer: Viewer, name: Rope.ROPE] = { FOR v: Viewer _ viewer, v.link WHILE v # NIL DO entry: Menus.MenuEntry _ Menus.FindEntry[v.menu, name]; IF entry # NIL THEN { Menus.ReplaceMenuEntry[v.menu, entry]; -- deletes it IF NOT v.iconic THEN ViewerOps.PaintViewer[v, menu]; }; IF v.link = viewer THEN EXIT; ENDLOOP; }; OpenErrorLog: Menus.ClickProc = { log: Viewer; viewer: Viewer = NARROW[parent]; name: Rope.ROPE = ErrorLogName[viewer.name]; log _ ViewerOps.FindViewer[name]; IF log = NIL THEN log _ CreateLog[name, typescript, FALSE] ELSE IF log.iconic THEN ViewerOps.OpenIcon[log] ELSE ViewerOps.PaintViewer[log, client]; }; ErrorLogName: PROC [file: Rope.ROPE] RETURNS [errlog: Rope.ROPE] = { pos: INT _ Rope.Length[file]; WHILE (pos _ pos - 1) > 0 DO SELECT Rope.Fetch[file, pos] FROM '. => RETURN [Rope.Replace[base: file, start: pos+1, with: "errlog"]]; '>, '], '/ => EXIT; ENDCASE; ENDLOOP; RETURN [Rope.Concat[file, ".errlog"]]; }; FindFileViewer: PROC [file: Rope.ROPE] RETURNS [viewer: Viewer] = { FindViewer: ViewerOps.EnumProc = { IF Rope.Find[v.file, file, 0, FALSE] = 0 THEN {viewer _ v; RETURN [FALSE]} ELSE RETURN [TRUE]; }; ViewerOps.EnumerateViewers[FindViewer]; }; CreateLog: PROC [fileName: Rope.ROPE, icon: Icons.IconFlavor, iconic: BOOL] RETURNS [viewer: ViewerClasses.Viewer] = { IF ~FileExists[fileName] THEN { MessageWindow.Append[Rope.Cat[fileName, " does not exist."], TRUE]; RETURN; }; IF iconic THEN { viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [name: fileName, file: fileName, iconic: iconic, icon: icon]]; IF viewer # NIL THEN TiogaMenuOps.DefaultMenus[viewer]; } ELSE { viewer _ TiogaMenuOps.Open[fileName]; IF viewer # NIL THEN viewer.icon _ icon; }; }; FileExists: PROC [fileName: Rope.ROPE] RETURNS [BOOL] = { bytes: INT _ -1; [bytes: bytes] _ FS.FileInfo[fileName ! FS.Error => CONTINUE]; RETURN [bytes >= 0]; }; SetIcon: PROC [viewer: Viewer, from, to: Icons.IconFlavor] = { IF to = unInit THEN RETURN; FOR v: Viewer _ viewer, v.link WHILE v # NIL DO IF from = unInit OR v.icon = from THEN IF v.icon # to THEN { v.icon _ to; IF v.iconic THEN ViewerOps.PaintViewer[v, all]; }; IF v.link = viewer THEN EXIT; ENDLOOP; }; CheckViewer: PROC [viewer: ViewerClasses.Viewer] RETURNS [ViewerSaveStatus] = { IF viewer # NIL AND NOT viewer.destroyed THEN { v: ViewerClasses.Viewer _ viewer; IF viewer.saveInProgress THEN RETURN [saving]; WHILE (v _ v.link) # NIL AND (v # viewer) DO IF v.saveInProgress THEN RETURN [saving]; ENDLOOP; IF viewer.newVersion THEN RETURN [new]; RETURN [old]; }; RETURN [none]; }; needsToBeCompiled: Icons.IconFlavor _ document; needsToBeCompiled _ Icons.NewIconFromFile["///UserExec.icons", 9 ! FS.Error => CONTINUE]; END.