DIRECTORY Atom USING[MakeAtom], BasicTime, Commander USING [CommandProc, Register], Convert USING[RopeFromTime], DB, DBIcons USING [Exists], DBNames USING [DecomposeName, MakeName], DBTools USING [ViewerToTool, ApplyTool, GetLoadFile], FileNames USING[GetShortName], Icons USING [IconFlavor], InputFocus USING [GetInputFocus, SetInputFocus], IO, Menus, Nut USING [GetNutInfo, SetFrozenProperty, Display, NoRegistration], Process USING[Detach], Rope, TIPUser USING[TIPScreenCoords], ViewerClasses USING [NotifyProc, Column, Viewer, ViewerClass, ViewerRec, ViewerFlavor], ViewerOps, ViewerPrivate USING[InvertForMenus], ViewerTools, WhiteboardDB, WhiteboardNut, WhiteboardOps, WhiteboardViewers; WhiteboardOpsImpl: CEDAR PROGRAM IMPORTS Atom, Commander, Convert, DBIcons, DBNames, DBTools, FileNames, InputFocus, IO, Menus, Nut, Process, Rope, ViewerOps, ViewerPrivate, ViewerTools, WhiteboardDB, WhiteboardNut, WhiteboardViewers EXPORTS WhiteboardOps SHARES ViewerOps, ViewerClasses, Menus = BEGIN OPEN ViewerClasses, WhiteboardOps; ROPE: TYPE = Rope.ROPE; Notify: PUBLIC NotifyProc = BEGIN OPEN WhiteboardViewers; p: TIPUser.TIPScreenCoords; FOR list: LIST OF REF ANY _ input, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM z: ATOM => { parent: Viewer = IF self.parent = NIL THEN self ELSE self.parent; KillInputFocus[parent]; -- get rid of blinking carat if there is one SELECT z FROM $Grow => IF parent.class.flavor = $Whiteboard THEN { v: Viewer = NearestChild[self, p.mouseX, p.mouseY, $Text]; IF v # NIL THEN GrowBox[parent, v, p.mouseX, parent.ch -p.mouseY] }; $Instructions => { [] _ WhiteboardDB.NewBox[self, 100, 100, 250, 104, NEW[ViewerTools.TiogaContentsRec _ [contents: "INSTRUCTIONS:\n LEFT => move entity\n shift LEFT => add text box\n ctrl LEFT => delete entity\n MIDDLE => open icon\n shift MIDDLE => open icon fullsize\n ctrl MIDDLE => expand whiteboard\n RIGHT => grow text box"]]] }; $NewBox => { [] _ WhiteboardDB.NewBox[parent, p.mouseX, parent.ch - p.mouseY, 128, 32] }; $Open => { v: Viewer = NearestChild[self, p.mouseX, p.mouseY, $WhiteboardIcon]; IF v # NIL THEN OpenProc[v] }; $OpenFull => { v: Viewer = NearestChild[self, p.mouseX, p.mouseY, $WhiteboardIcon]; IF v # NIL THEN OpenFullProc[v] }; $Remove => { child: Viewer = NearestChild[self, p.mouseX, p.mouseY]; parent: Viewer = IF self.parent = NIL THEN self ELSE self.parent; IF child = NIL THEN RETURN; WhiteboardDB.Delete[child]; parent.newVersion _ TRUE; ViewerOps.PaintViewer[parent, client]; ViewerOps.PaintViewer[parent, caption] }; $Expand => { v: Viewer = NearestChild[self, p.mouseX, p.mouseY]; parent: Viewer = IF self.parent = NIL THEN self ELSE self.parent; name: ROPE; type: ATOM; IF v = NIL THEN RETURN; [name, type] _ WhiteboardDB.GetIconProps[v]; IF type = WhiteboardDB.whiteboard AND WhiteboardDB.WBExists[name] THEN TRUSTED{ Process.Detach[ FORK ExpandProc[parent, v, name] ] } }; $Freeze => { self: Viewer = NARROW[parent]; frozen: Menus.MenuEntry = Menus.FindEntry[self.menu, "Freeze"]; IF frozen = NIL THEN RETURN; Menus.ReplaceMenuEntry[self.menu, frozen]; ViewerOps.PaintViewer[self, menu]; [] _ Nut.SetFrozenProperty[self, TRUE] }; $AddSelected => { icon: Viewer _ ViewerTools.GetSelectedViewer[]; parent: Viewer = IF self.parent = NIL THEN self ELSE self.parent; WHILE icon.parent # NIL DO icon _ icon.parent ENDLOOP; IF icon # NIL THEN AddNewIcon[parent, icon, 100, 100] }; $AddCommandFile => { parent: Viewer = IF self.parent = NIL THEN self ELSE self.parent; icon: Viewer _ ViewerTools.GetSelectedViewer[]; IF icon.icon # document THEN RETURN; [] _ WhiteboardDB.NewIcon[parent, 100, 100, icon.name, $ToolRope, "Typescript", FileNames.GetShortName[icon.name]] }; $Erase => { WhiteboardDB.Erase[self]; ViewerOps.PaintViewer[self, all] }; $Move => { child: Viewer = NearestChild[self, p.mouseX, p.mouseY]; IF child # NIL THEN MoveChild[child] }; ENDCASE => NULL }; z: TIPUser.TIPScreenCoords => p _ z; ENDCASE => NULL; ENDLOOP; END; KillInputFocus: PROC [v: Viewer] = BEGIN focus: Viewer _ InputFocus.GetInputFocus[].owner; WHILE focus # v AND focus # NIL DO focus _ focus.parent ENDLOOP; IF focus = v THEN InputFocus.SetInputFocus[]; END; AddNewIcon: PROC[wb, child: Viewer, x, y: INTEGER] = BEGIN name, label, iconName, argument: ROPE; segment: DB.Segment; domain, entity: ROPE; [segment , domain, entity] _ Nut.GetNutInfo[child]; IF NOT Rope.Equal[domain, NIL] AND NOT Rope.Equal[entity, NIL] THEN { IF Rope.Equal[domain, "Whiteboard"] THEN { -- it's one of ours! [] _ WhiteboardDB.NewIcon[wb, x, y, entity, WhiteboardDB.whiteboard, "Whiteboard"] } ELSE { name _ DBNames.MakeName[segment, domain, entity]; iconName _ IF DBIcons.Exists[domain] THEN domain ELSE "Acorn"; label _ NARROW[ViewerOps.FetchProp[child, $IconLabel]]; IF label = NIL THEN label _ entity; [] _ WhiteboardDB.NewIcon[wb, x, y, name, $Entity, iconName, label] }; RETURN }; IF child.icon = document THEN { [] _ WhiteboardDB.NewIcon[wb, x, y, child.name, $Text, "Document", FileNames.GetShortName[child.name]]; RETURN }; IF child.class.flavor = $Container AND child.child # NIL THEN child _ child.child; [name, argument] _ DBTools.ViewerToTool[child]; IF name = NIL THEN RETURN; -- the viewer can't be mapped into a tool IF child.class.flavor = $Sil OR child.class.flavor = $Press THEN { IF Rope.Equal[child.name, "No Name"] THEN label _ NIL ELSE { argument _ label; label _ FileNames.GetShortName[label] } } ELSE { label _ NARROW[ViewerOps.FetchProp[child, $IconLabel]]; IF Rope.Equal[label, ""] THEN label _ argument }; IF child.icon = typescript THEN { loadFileName: Rope.ROPE = Rope.Concat["///Commands/", DBTools.GetLoadFile[name]]; [] _ WhiteboardDB.NewIcon[wb, x, y, loadFileName, $ToolRope, "Typescript", label]; RETURN }; iconName _ IF DBIcons.Exists[name] THEN name ELSE "Tool"; [] _ WhiteboardDB.NewIcon[wb, x, y, name, $Tool, iconName, label, argument]; END; OpenProc: PROC[ clientData: REF ANY ] = TRUSTED { Process.Detach[ FORK OpenIcon[NARROW[clientData]] ] }; OpenIcon: PROCEDURE[icon: Viewer] = BEGIN ENABLE UNWIND => icon.spare0 _ FALSE; name: ROPE; type: ATOM; IF icon = NIL THEN RETURN; ViewerPrivate.InvertForMenus[icon, 0, 0, icon.ww, icon.wh]; icon.spare0 _ TRUE; -- remember that the viewer is inverted IF WhiteboardViewers.DontLog[icon] THEN { name _ icon.name; type _ WhiteboardDB.whiteboard } ELSE [name, type] _ WhiteboardDB.GetIconProps[icon]; SELECT type FROM NIL => NULL; $Entity => { domain, entity, segment: ROPE; seg: DB.Segment; [domain ~ domain, entity ~ entity, segment ~ segment] _ DBNames.DecomposeName[name]; seg _ IF NOT Rope.Equal[segment, ""] THEN Atom.MakeAtom[segment] ELSE NIL; IF seg # NIL THEN [] _ Nut.Display[entity, domain, seg, icon.parent ! Nut.NoRegistration => { CONTINUE }] }; $Whiteboard => WhiteboardNut.CreateWBViewer[name, icon.parent]; $Text => WhiteboardNut.CreateTextViewer[name]; $Tool => { v: Viewer _ ViewerOps.FindViewer[name]; IF v = NIL OR v.destroyed THEN { argument: ROPE = WhiteboardDB.GetToolArgument[icon]; DBTools.ApplyTool[name, argument] } ELSE { IF v.iconic THEN ViewerOps.OpenIcon[v]; ViewerOps.PaintViewer[v, all] } }; $ToolRope => { WhiteboardNut.DoCommandFile[name] }; ENDCASE; IF NOT icon.destroyed THEN ViewerPrivate.InvertForMenus[icon, 0, 0, icon.ww, icon.wh]; icon.spare0 _ FALSE -- reset the inverted bit (checked by PaintIconic) END; OpenFullProc: PROC[ clientData: REF ANY ] = { viewer: Viewer = NARROW[clientData]; CloseViewers: ViewerOps.EnumProc = { IF v.column = viewer.column THEN ViewerOps.CloseViewer[v] }; IF viewer # NIL THEN ViewerOps.EnumerateViewers[CloseViewers]; TRUSTED { Process.Detach[ FORK OpenIcon[NARROW[clientData]] ] } }; ExpandProc: PROC[parent, wb: Viewer, wbName: ROPE] = BEGIN wbList: LIST OF ROPE _ WhiteboardDB.GetChildren[wbName]; WhiteboardViewers.Expand[parent, wb, wbList]; END; RegisterProcs: PROC[] = { Commander.Register[key: "Whiteboard", proc: DisplayIt, doc: "\nDisplays the named whiteboard"]; Commander.Register[key: "WBDisplay", proc: DisplayIt, doc: "\nDisplays the named whiteboard"]; Commander.Register[key: "WBCreate", proc: DisplayIt, doc: "Creates a new whiteboard with the given name"]; Commander.Register[key: "WBDestroy", proc: DestroyIt, doc: "\nDestroys the named whiteboard (be careful!)"]; Commander.Register[key: "WBCopy", proc: CopyIt, doc: "\nCopyWB (for copying whiteboards)"]; Commander.Register[key: "WBlist", proc: Enumerate, doc: "\nEnumerates whiteboards contained in the named whiteboard\n (Enumerates all whiteboards if no name is given)"]; Commander.Register[key: "WBOpen", proc: OpenIt, doc: "\nWBOpen opens a new whiteboard database (closing a previously open one, if necessary)"]; Commander.Register[key: "WBClose", proc: CloseIt, doc: "\nWBClose closes the database connections whiteboards uses and destroys all current whiteboard viewers"]; }; DisplayIt: Commander.CommandProc = { ENABLE WhiteboardDB.WBError => { SELECT reason FROM $ServerDown => {msg _ "Display Failed -- server unavailable; retry later"; CONTINUE}; $TransactionAbort => {msg _ "Display Failed -- transaction aborted; retry later"; CONTINUE}; ENDCASE => REJECT }; h: IO.STREAM = IO.RIS[cmd.commandLine]; name: ROPE; success: BOOL; [] _ h.SkipWhitespace[]; IF h.EndOf THEN { msg _ "A whiteboard name must be supplied."; RETURN }; name _ h.GetID[]; IF NOT WhiteboardDB.WBExists[name] THEN { success _ WhiteboardDB.New[name]; IF success THEN msg _ "New whiteboard created." ELSE msg _ "Can't create new whiteboard." }; [] _ WhiteboardDB.Display[name] }; DestroyIt: Commander.CommandProc = { ENABLE WhiteboardDB.WBError => { SELECT reason FROM $ServerDown => {msg _ "Destroy Failed -- server unavailable; retry later"; CONTINUE}; $TransactionAbort => {msg _ "Destroy Failed -- transaction aborted; retry later"; CONTINUE}; $ReadOnly => {msg _ "Destroy Failed -- database is readonly"; CONTINUE}; ENDCASE => REJECT }; h: IO.STREAM = IO.RIS[cmd.commandLine]; name: ROPE; [] _ h.SkipWhitespace[]; IF h.EndOf THEN { msg _ "A whiteboard name must be supplied."; RETURN }; name _ h.GetID[]; IF NOT WhiteboardDB.WBExists[name] THEN msg _ "No such whiteboard" ELSE WhiteboardDB.Destroy[name] }; CopyIt: Commander.CommandProc = { ENABLE WhiteboardDB.WBError => { SELECT reason FROM $ServerDown => {msg _ "Copy Failed -- server unavailable; retry later"; CONTINUE}; $TransactionAbort => {msg _ "Copy Failed -- transaction aborted; retry later"; CONTINUE}; $ReadOnly => {msg _ "Copy Failed -- database is readonly"; CONTINUE}; ENDCASE => REJECT }; h: IO.STREAM = IO.RIS[cmd.commandLine]; from, to: ROPE; [] _ h.SkipWhitespace[]; IF h.EndOf THEN { msg _ "Syntax is: CopyWB "; RETURN }; from _ h.GetID[]; [] _ h.SkipWhitespace[]; IF h.EndOf THEN { msg _ "Syntax is: CopyWB "; RETURN }; to _ h.GetID[]; IF NOT WhiteboardDB.WBExists[from] THEN { msg _ "No such whiteboard to copy from"; RETURN }; WhiteboardDB.CopyWB[from, to] }; Enumerate: Commander.CommandProc = { ENABLE WhiteboardDB.WBError => { SELECT reason FROM $ServerDown => {msg _ "Enumerate Failed -- server unavailable; retry later"; CONTINUE}; $TransactionAbort => {msg _ "Enumerate Failed -- transaction aborted; retry later"; CONTINUE}; ENDCASE => REJECT }; h: IO.STREAM = IO.RIS[cmd.commandLine]; pattern: ROPE; wbList: LIST OF ROPE; [] _ h.SkipWhitespace[]; IF h.EndOf THEN pattern _ NIL ELSE pattern _ h.GetLineRope[]; wbList _ WhiteboardDB.Enumerate[pattern]; IF wbList = NIL THEN msg _ "No whiteboards matching pattern" ELSE TRUSTED { FOR wbNames: LIST OF ROPE _ wbList, wbNames.rest UNTIL wbNames = NIL DO createDate: BasicTime.GMT = WhiteboardDB.GetCreateDate[wbNames.first]; dateRope: Rope.ROPE = IF createDate = BasicTime.nullGMT THEN "unknown" ELSE LOOPHOLE[Convert.RopeFromTime[createDate]]; msg _ Rope.Cat[msg, wbNames.first, " last edited: "]; msg _ Rope.Cat[msg, dateRope, "\n"] ENDLOOP } }; OpenIt: Commander.CommandProc = { h: IO.STREAM = IO.RIS[cmd.commandLine]; name: ROPE; [] _ h.SkipWhitespace[]; IF h.EndOf THEN name _ NIL ELSE name _ h.GetLineRope[]; WhiteboardDB.EstablishWhiteboardDB[name] }; CloseIt: Commander.CommandProc = { WhiteboardDB.Close[] }; RegisterProcs[]; END.. dWhiteboardOpsImpl.mesa Copyright (C) 1984 by Xerox Corporation. All rights reserved. Last edited by Maxwell, June 25, 1984 1:31:29 pm PDT Cattell, September 1, 1983 10:40 am Donahue, June 14, 1985 4:49:17 pm PDT (Changed to reflect new error-handling policy) (Fixed treatment of ShowPress viewers) (Fixed bug in opening tool viewers -- didn't get tool argument properly) (Removed working directory stuff to be consistent with new DBTools) (Replaced "AddTool" with "AddCommandFile") Widom, August 24, 1984 5:05:57 pm PDT Last Edited by: Winkler, December 18, 1984 4:51:56 pm PST Command interpreter Support routines otherwise it's a tool This line is a hack to handle ShowPress viewers try finding an appropriate label from the tools database, the $IconLabel property, or the name of the tool we assume that we should save the load file for the tool and load it through a CommandTool when invoked it's a tool that creates a viewer; find an appropriate icon for it invert the icon first to give information on when display complete it's an ephemeral icon (one that doesn't really exist on the whiteboard); make it a whiteboard Note: in the case of tools, the name of the viewer is taken as the argument to be provided (unless it has the same name as the tool itself) now repaint the icon that was inverted when this got started Registration (with Commander) Initialization Κ <˜Jšœ™Jšœ=™=šœ™Jšœ%™%Jšœ#™#Jšœ%™%J™.J™&J™HJ™CJ™*Jšœ%™%J™9J˜—šΟk ˜ Jšœœ ˜J˜ Jšœ œ˜(Jšœœ˜Jšœ˜Jšœœ ˜Jšœœ˜(Jšœœ(˜5Jšœ œ˜Jšœœ˜Jšœ œ ˜0Jšœ˜J˜Jšœœ:˜CJšœœ ˜Jšœ˜Jšœœ˜JšœœD˜WJ˜ Jšœœ˜$J˜ J˜ J˜J˜J˜J˜—šœœ˜ šœ˜JšœLœr˜ΐ—Jšœ˜Jšœ"˜(Jš˜Jšœ˜"J˜—Jšœœœ˜Ihead1šœ™šœœ ˜š˜Jšœ˜J˜šœœœœœœœ˜@šœ œ˜šœœ˜ š œœœœœ ˜CJšœΟc,˜DJšœ˜ ˜šœ#œ˜+J˜:Jšœœœ5˜D——˜Jšœ9œŽ˜Κ—˜ JšœN˜N—˜ J˜DJšœœœ˜—˜J˜DJšœœœ˜"—˜ J˜7Jš œœœœœ ˜AJšœ œœœ˜J˜Jšœœ˜J˜&J˜)—˜ J˜3Jš œœœœœ ˜AJšœœ˜ Jšœœ˜ Jšœœœœ˜Jšœ,˜,šœ œ˜BJšœœœ#˜E——˜ šœœ ˜ J˜?Jšœ œœœ˜J˜*J˜"Jšœ!œ˜)——˜šœ1˜1Jš œœœœœ ˜AJšœœœœ˜6Jšœœœ&˜8——šœ˜Jš œœœœœ ˜AJšœ/˜/Jšœœœ˜$Jšœu˜u—˜ šœ˜Jšœ#˜#——˜ J˜7Jšœ œœ˜'—Jšœœ˜———J˜$Jšœœ˜Jšœ˜—Jšœ˜——K™šΟnœœ˜#š˜Jšœ1˜1šœ œ œ˜"Jšœ˜Jšœ˜—Jšœ œ˜-—Jšœ˜—J˜šŸ œœœ˜4š˜Jšœ!œ˜&Jšœ œ ˜Jšœœ˜Jšœ3˜3šœœœœœœœ˜Ešœ"œž˜?JšœT˜T—šœ˜Jšœ1˜1Jšœ œœœ ˜>Jšœœ)˜7Jšœ œœ˜#JšœF˜F—Jšœ˜ —šœœ˜Jšœg˜gJšœ˜ —J™šž/™/Jšœ!œœœ˜R—Jšœ/˜/Jš œœœœž)˜DJšœj™jšœœœ˜BJšœ#œ ˜5Jšœ>˜B—šœ˜Jšœœ)˜7Jšœœ˜1—šœœ˜!Jšœg™gJšœœ:˜QJšœR˜RJšœ˜ —JšœB™BJšœ œœœ˜9JšœL˜LJšœ˜——J˜šŸœœœœ˜'Jšœœ œ˜@J˜—šŸœ œ˜#Jšœœœœ˜,Jšœœ˜ Jšœœ˜ Jšœœœœ˜JšœB™BJ˜;Jšœœž'˜;šœ!œ˜)Jšœ^™^J˜J˜ —Jšœ0˜4šœ˜Jšœœ˜ šœ ˜ Jšœœ˜Jšœœ ˜JšœT˜TJš œœœœœœ˜Jšœœ˜JšœLœ˜[——Jšœ@˜@Jšœ.˜.šœ ˜ Jšœ‹™‹Jšœ'˜'šœœœ œ˜ Jšœ œ&˜4Jšœ#˜#—Jšœœ œ:˜Q—Jšœ3˜3Jšœ˜—Jšœ<™<šœœ˜J˜;—Jšœœž2˜FJšœ˜—J˜šŸ œœœœ˜-Jšœœ ˜$˜$Jšœœ˜šœœ œ˜BJ˜———šŸ œœœ˜4š˜Jšœœœœ$˜8J˜-Jšœ˜——Ihead™J˜šŸ œœ˜˜_J˜—˜^J˜—J˜jJ˜J˜lJ˜˜hJ˜—˜ͺJ˜—˜–J˜—˜‘J˜J˜——šœ$˜$šœ˜ Jšœ˜JšœKœ˜UJšœRœ˜\Jšœœ˜—Jš œœœœœ˜'Jšœœ˜ Jšœ œ˜J˜šœ œ˜Jšœ,˜,Jšœ˜ —Jšœ˜šœœœ˜)Jšœ!˜!Jšœ œ ˜/Jšœ(˜,—šœ"˜"J˜——šœ$˜$šœ˜ Jšœ˜JšœKœ˜UJšœRœ˜\Jšœ>œ˜HJšœœ˜—Jš œœœœœ˜'Jšœœ˜ J˜šœ œ˜Jšœ,˜,Jšœ˜ —Jšœ˜šœœœ˜BJšœ˜"——J˜šœ!˜!šœ˜ Jšœ˜JšœHœ˜RJšœOœ˜YJšœ;œ˜EJšœœ˜—Jš œœœœœ˜'Jšœ œ˜J˜šœ œ˜Jšœ'˜'Jšœ˜ —Jšœ˜J˜šœ œ˜Jšœ'˜'Jšœ˜ —Jšœ˜šœœœ˜)Jšœ(˜(Jšœ˜ —Jšœ ˜ —J˜šœ$˜$šœ˜ Jšœ˜JšœMœ˜WJšœTœ˜^Jšœœ˜—Jš œœœœœ˜'Jšœ œ˜Jšœœœœ˜J˜Jšœ œ œœ˜=Jšœ)˜)Jšœ œœ(˜<šœœ˜š œ œœœœ œ˜GJšœœ-˜FJš œœœ œ œœ#˜wJšœ6˜6Jšœ#˜#Jšœ˜ ———J˜šœ!˜!Jš œœœœœ˜'Jšœœ˜ J˜Jšœ œœœ˜7J˜(J˜J˜—Jšœ:˜:K™J˜J˜Jšœ˜J˜J™J™—…—/~B