DIRECTORY AMEvents USING [Debugging, Debugged], CIFS USING [Error], CedarSnapshot USING [CheckpointProc, Register, RollbackProc], Convert USING [Value, ValueToRope], IO USING [GetCard, EndOfStream, Close, CR, CreateFilterCommentsStream, GetChar, GetIndex, int, PeekChar, PutF, RIS, rope, STREAM, time, TAB, SP, GetToken, SkipOver, TokenProc, BreakProc, WhiteSpace], IOExtras USING [GetLine], IconRegistry USING [Failure], Icons USING [NewIconFromFile, IconFlavor], FileIO USING [Open, OpenFailed], MessageWindow USING [Append, Blink], PageFault USING [AddressFault], Process USING [Detach], Rope USING [Cat, Equal, IsEmpty, ROPE], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, RegisterEventProc], ViewerOps USING [FindViewer, RestoreViewer] ; IconRegistryImpl: CEDAR MONITOR IMPORTS AMEvents, CedarSnapshot, CIFS, Convert, FileIO, IO, IOExtras, MessageWindow, PageFault, Process, Rope, Icons, ViewerEvents, ViewerOps EXPORTS IconRegistry = BEGIN IconList: TYPE = LIST OF IconEntry; IconEntry: TYPE = REF IconRecord; IconRecord: TYPE = RECORD[ iconName: Rope.ROPE _ NIL, fileName: Rope.ROPE _ NIL, index: CARDINAL _ LAST[CARDINAL], flavor: Icons.IconFlavor _ unInit, position: INT _ -1 -- in catalogue ]; Failed: PUBLIC ERROR [why: IconRegistry.Failure, reason: Rope.ROPE] = CODE; RegisterIcon: PUBLIC ENTRY PROC [iconName: Rope.ROPE, fileName: Rope.ROPE, index: CARDINAL, saveInCatalogue: BOOL _ FALSE] = { ENABLE UNWIND => NULL; entry: IconEntry; IF iconList = NIL THEN Parse[]; -- first time FOR l: IconList _ iconList, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first.iconName, iconName, FALSE] THEN { IF Rope.Equal[l.first.fileName, fileName, FALSE] AND l.first.index = index THEN RETURN[]; -- multiple registrations are nops. LOOP; }; REPEAT FINISHED => {entry _ NEW[IconRecord _ []]; iconList _ CONS[entry, iconList];} ENDLOOP; entry^ _ [iconName: iconName, fileName: fileName, index: index, flavor: unInit, position: -1]; -- multiple entries permitted, guys registered later, i.e. appear earlier on list, take precedence. IF saveInCatalogue THEN WriteEntry[entry]; }; GetIcon: PUBLIC ENTRY PROC [iconName: Rope.ROPE, default: Icons.IconFlavor _ unInit] RETURNS [Icons.IconFlavor] = { ENABLE UNWIND => NULL; IF iconList = NIL THEN Parse[! Failed => IF default # unInit THEN GOTO Default]; -- first time FOR l: IconList _ iconList, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first.iconName, iconName, FALSE] THEN { IF l.first.flavor = unInit THEN l.first.flavor _ Icons.NewIconFromFile[l.first.fileName, l.first.index ! CIFS.Error => IF code # noSuchFile THEN REJECT ELSE IF default # unInit THEN GOTO Default ELSE ERROR Failed[fileNotFound, l.first.fileName]; PageFault.AddressFault => IF default # unInit THEN GOTO Default ELSE ERROR Failed[invalidIndex, Convert.ValueToRope[[signed[l.first.index]]]]; ]; -- NewIconFromFile raises this if given badindex. RETURN[l.first.flavor]; }; ENDLOOP; IF default # unInit THEN GOTO Default; ERROR Failed[noSuchIcon, iconName]; EXITS Default => RETURN[default]; }; IsRegistered: PUBLIC ENTRY PROC[iconName: Rope.ROPE _ NIL, fileName: Rope.ROPE _ NIL, index: CARDINAL _ LAST[CARDINAL]] RETURNS[name: Rope.ROPE, file: Rope.ROPE, i: CARDINAL] = { IF iconList = NIL THEN Parse[! Failed => GOTO Out]; -- first time FOR l: IconList _ iconList, l.rest UNTIL l = NIL DO IF (IF iconName # NIL THEN Rope.Equal[l.first.iconName, iconName, FALSE] ELSE Rope.Equal[l.first.fileName, fileName, FALSE] AND l.first.index = index) THEN RETURN[l.first.iconName, l.first.fileName, l.first.index]; ENDLOOP; RETURN[NIL, NIL, 0]; EXITS Out => RETURN[NIL, NIL, 0]; }; Lookup: PROC[iconName: Rope.ROPE] RETURNS[IconEntry] = { FOR l: IconList _ iconList, l.rest UNTIL l = NIL DO IF Rope.Equal[l.first.iconName, iconName, FALSE] THEN RETURN[l.first]; ENDLOOP; RETURN[NIL]; }; InvalidateCache: PUBLIC PROC [iconName: Rope.ROPE _ NIL] = { FOR l: IconList _ iconList, l.rest UNTIL l = NIL DO IF iconName = NIL OR Rope.Equal[l.first.iconName, iconName, FALSE] THEN l.first.flavor _ unInit; ENDLOOP; }; iconList: IconList _ NIL; catalogueName: Rope.ROPE _ "RegisteredIcons.Catalogue"; Parse: INTERNAL PROCEDURE = { OPEN IO; stream, ris: IO.STREAM; { ENABLE { Failed => REJECT; IO.EndOfStream => GOTO Out; }; stream _ CreateFilterCommentsStream[FileIO.Open[fileName: catalogueName, accessOptions: read, createOptions: oldOnly ! FileIO.OpenFailed => ERROR Failed[noCatalogue, catalogueName]]]; DO tokenProc: IO.BreakProc = { RETURN[SELECT char FROM IO.SP, IO.TAB, ', => sepr, IO.CR => break, ENDCASE => other ]; }; whiteSpace: IO.BreakProc = { RETURN[IF char = CR THEN break ELSE IO.WhiteSpace[char]] }; isACR: IO.BreakProc = { RETURN[IF char = CR THEN break ELSE other] }; entry: IconEntry; iconName, fileName: Rope.ROPE; index: CARDINAL; position: INT; IO.SkipOver[stream, IO.WhiteSpace]; position _ stream.GetIndex[]; iconName _ IO.GetToken[stream]; IO.SkipOver[stream, whiteSpace]; -- skips over spaces, tabs, but stops at CR IF stream.PeekChar[] # ': THEN { IO.SkipOver[stream, isACR]; Report1[msg: Rope.Cat["missing : at [", Convert.ValueToRope[[signed[position]]], "]"]]; LOOP; }; [] _ stream.GetChar[]; -- the : ris _ IO.RIS[IOExtras.GetLine[stream], ris]; -- read to CR, make this a stream. Reason is to bound the scope of the GetToken, GetCards below. fileName _ IO.GetToken[ris, tokenProc]; IF Rope.IsEmpty[fileName] THEN { Report1[msg: Rope.Cat["missing fileName at [", Convert.ValueToRope[[signed[position]]], "]"]]; LOOP; }; index _ IO.GetCard[ris]; entry _ Lookup[iconName]; IF entry # NIL THEN { entry.position _ position; -- comments may have changed. IF NOT (Rope.Equal[entry.fileName, fileName, FALSE] AND index = entry.index) THEN { entry.fileName _ fileName; entry.index _ index; entry.flavor _ unInit; }; } ELSE iconList _ CONS[NEW[IconRecord _ [iconName: iconName, fileName: fileName, index: index, position: position]], iconList]; ENDLOOP; EXITS Out => NULL; }; IF stream # NIL THEN stream.Close[]; IF errorLog # NIL THEN { MessageWindow.Append["problems encountered, see IconRegistry.log."]; MessageWindow.Blink[]; errorLog.Close[]; errorLog _ NIL; }; }; WriteEntry: INTERNAL PROC [entry: IconEntry] = { OPEN IO; viewer: ViewerClasses.Viewer; stream: STREAM = FileIO.Open[fileName: catalogueName, accessOptions: append, createOptions: oldOnly]; WriteOne[entry, stream]; stream.Close[]; IF (viewer _ ViewerOps.FindViewer[catalogueName]) # NIL THEN ViewerOps.RestoreViewer[viewer]; }; WriteOne: INTERNAL PROC [entry: IconEntry, stream: IO.STREAM] = { OPEN IO; entry.position _ stream.GetIndex[]; stream.PutF["\n%g: %g %d", rope[entry.iconName], rope[entry.fileName], int[entry.index]]; }; WriteCatalogue: PUBLIC ENTRY PROC [] = { OPEN IO; viewer: ViewerClasses.Viewer; stream: STREAM; lst: IconList; FOR l: IconList _ iconList, l.rest UNTIL l = NIL DO IF l.first.position = -1 THEN lst _ CONS[l.first, lst]; -- need to write them out in reverse order seen on lst, i.e. first one seen gets written out last ENDLOOP; IF lst = NIL THEN RETURN; FOR l: IconList _ lst, l.rest UNTIL l = NIL DO WriteOne[l.first, stream]; ENDLOOP; stream _ FileIO.Open[fileName: catalogueName, accessOptions: append, createOptions: oldOnly]; stream.Close[]; IF (viewer _ ViewerOps.FindViewer[catalogueName]) # NIL THEN ViewerOps.RestoreViewer[viewer]; }; Report: ENTRY PROCEDURE [entry: IconEntry _ NIL, msg: Rope.ROPE] = { Report1[entry, msg]; }; Report1: INTERNAL PROCEDURE [entry: IconEntry _ NIL, msg: Rope.ROPE] = { OPEN IO; ENABLE { UNWIND, AMEvents.Debugging, AMEvents.Debugged => NULL; ANY => CONTINUE; }; IF errorLog = NIL THEN { errorLog _ FileIO.Open[fileName: "IconRegistry.log", accessOptions: overwrite]; errorLog.PutF["Processing %g at %t", rope[catalogueName], time[]]; }; errorLog.PutF["\n\n%g", rope[msg]]; IF entry # NIL THEN errorLog.PutF[", at %g [%d]", rope[entry.iconName], int[entry.position]]; }; errorLog: IO.STREAM _ NIL; NoticeChanges: CedarSnapshot.RollbackProc = {IF iconList # NIL THEN ParseCatalogue[]}; ParseCatalogue: ENTRY PROC = {Parse[]}; WasCatalogueEdited: ViewerEvents.EventProc -- [viewer: ViewerClasses.Viewer, event: ViewerEvent] -- = { IF Rope.Equal[viewer.name, catalogueName, FALSE] THEN TRUSTED {Process.Detach[FORK ParseCatalogue[]]}; }; [] _ ViewerEvents.RegisterEventProc[proc: WasCatalogueEdited, event: save, before: FALSE]; TRUSTED {CedarSnapshot.Register[c: NIL, r: NoticeChanges]; }; END. 6IconRegistryImpl.mesa; Edited by Teitelman on April 16, 1983 2:13 pm Types Accessing Icon Catalogue Changes RegisteredIcons.Catalogue to reflect the indicated association. This definition will replace any previous definition. comments are for inclusion in the catalogue to help the user figure out what the icon looks like. Obtain an icon flavor for the icon associated with iconName. Create a new icon flavor if one has not previously been created. If for some reason it could not obtain the icon, and default # unInit, returns the default. Otherwise, raises Error (defined below) with appropriate parameters. for use by iconeditor, so that it can force creation of a new flavor when an icon that has been registered was edited, obtain name of icon when selected, etc. Can be called with either iconName, or fileName and index. for use by iconeditor, so that it can force creation of a new flavor when an icon that has been registered was edited. If an iconFlavor was previous created for this icon, discard the flavor, i.e. the next call to GetIcon will create a new flavor. If iconName = NIL, do this for all registered icons. For use by iconeditor. Parsing Icon Catalogue ANY => GOTO Out; -- see if key is followed by a : entry.endPosition _ endPosition; Reporting errors When the Icon Catalogue changes Initialization Κ – "Cedar" style˜J˜JšΟc™Jšœ™-J˜šΟk ˜ Jšœ žœ˜%Jšžœžœ ˜Jšœžœ*˜=Jšœžœ˜#JšžœžœžœEžœžœžœžœ8˜ΗJšœ žœ ˜Jšœ žœ ˜Jšœžœ˜*Jšœžœ˜ Jšœžœ˜$Jšœ žœ˜Jšœžœ ˜Jšœžœžœ˜'Jšœžœ ˜Jšœ žœ ˜2Jšœ žœ˜+J˜J˜—J˜JšΠblœžœž˜J˜Jšžœ1žœU˜J˜Jšžœ˜J˜Jšœžœ˜headšœ™JšΟnœž œžœ ˜#Jš  œžœžœ ˜!š  œžœžœ˜Jšœžœžœ˜Jšœžœžœ˜Jšœžœžœžœ˜!Jšœ"˜"Jšœ žœ˜#Jšœ˜—Jš  œžœžœ*žœžœ˜KJ˜—™š  œžœžœžœžœžœ žœžœžœ˜J™ΰJšž˜J˜Jšžœ žœžœ  ˜.šžœ žœžœž˜3šžœ(žœžœ˜7Jš žœ(žœžœžœžœ#˜~Jšž˜Jšž˜—Jšž˜Jšžœ žœžœ˜MJšž˜—Jšœad˜ΕJšžœžœ˜*J˜—J˜š œžœžœ$žœ˜sJš}™}J™ Jšž˜Jš žœ žœžœžœžœžœ  ˜_šžœ žœžœž˜3šžœ(žœžœ˜7šžœžœI˜hšžœ ˜ Jšžœžœž˜ Jšžœžœžœžœ˜*Jšžœžœ(˜2—šœ˜Jšžœžœžœ˜%JšžœžœD˜N—Jšœ1˜4—Jšžœ˜J˜—Jšž˜—Jšžœžœžœ ˜&Jšžœ˜#šž˜Jšœ žœ ˜—J˜J˜—š  œžœžœžœžœžœžœžœ žœžœžœžœ žœ žœžœ˜²J™ΩJš žœ žœžœžœ ˜Bšžœ žœžœž˜3šž˜Jš œžœ žœžœ(žœ˜EJš žœ(žœžœžœžœ4˜—Jšž˜—Jšžœž œ˜šž˜Jšœžœž œ˜Jšœ˜—J˜—š œžœžœžœ˜8J™všžœ žœžœž˜3Jšžœ(žœžœžœ ˜FJšž˜—Jšžœžœ˜ Jšœ˜J˜—š œž œž œ˜