<> <> <> <> <> <<>> <> <> <> <> <<(Added Nut connection)>> <<(Changed StripForIcon to remove all registry information from icon labels)>> <> <> DIRECTORY Ascii USING [ Letter ], Basics USING [BYTE, LongNumber], BasicTime USING [GMT, ToPupTime], Convert USING [CardFromRope], GVBasics USING [Timestamp], IO, Menus, Nut USING [SetNutInfo, CopyNutInfo], PopUpSelection USING [Request], RefText USING[line, AppendChar, ObtainScratch, ReleaseScratch], Rope, WalnutDocumentRope USING [Create], TEditSplit USING[ Split ], TEditDocument USING [TEditDocumentData, maxClip], TiogaOps USING [CancelSelection, GetSelection, RestoreSelB, SaveSelB, SelectDocument, SetStyle, ViewerDoc], TiogaMenuOps USING[ tiogaMenu, AllLevels ], UserProfile USING [Token], ViewerClasses USING [Viewer], ViewerEvents USING [ EventRegistration, EventProc, ViewerEvent, RegisterEventProc, UnRegisterEventProc ], ViewerLocks USING[ CallUnderWriteLock ], ViewerOps USING [AddProp, CreateViewer, DestroyViewer, FetchProp, GrowViewer, OpenIcon, PaintViewer, SetMenu], ViewerTools USING [TiogaContents, InhibitUserEdits, SetTiogaContents], WalnutOps USING [MsgSet, GetCategories, GetMsgShortName, GetMsg, MsgExists], WalnutOpsExtras USING [GetMsgSize], WalnutViewer USING [CreateMenuEntry], WalnutSendOps USING [Answer, Forward, WalnutSendProc], WalnutSendOpsExtras USING [ReSend], WalnutControlInternal USING [DoWaitCall], WalnutDisplayerInternal, WalnutPrintOps USING [MsgPrintProc], WalnutWindowInternal USING [msgIcon, walnutQueue, Report, ReportRope], WalnutWindow USING [EnumWalnutViewers]; WalnutMsgDisplayerImpl: CEDAR MONITOR IMPORTS Ascii, BasicTime, Convert, IO, Nut, PopUpSelection, RefText, Rope, WalnutDocumentRope, TiogaMenuOps, TiogaOps, TEditSplit, Menus, UserProfile, ViewerEvents, ViewerLocks, ViewerOps, ViewerTools, WalnutOps, WalnutOpsExtras, WalnutSendOps, WalnutSendOpsExtras, WalnutControlInternal, WalnutPrintOps, WalnutViewer, WalnutWindow, WalnutWindowInternal EXPORTS WalnutDisplayerInternal, WalnutWindow SHARES Menus = BEGIN ROPE: TYPE = Rope.ROPE; TiogaContents: TYPE = ViewerTools.TiogaContents; Viewer: TYPE = ViewerClasses.Viewer; MsgSet: TYPE = WalnutOps.MsgSet; msgMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; frozenMsgMenu: Menus.Menu _ Menus.CreateMenu[]; nilMenu: Menus.Menu _ Menus.CreateMenu[]; <<-------------------------->> <> GetMsgName: PUBLIC PROC[v: Viewer] RETURNS[mName: ROPE] = { <> mName _ NARROW[ViewerOps.FetchProp[v, $WalnutMsgName]]; IF mName = NIL THEN WalnutWindowInternal.Report[" Not a Walnut Msg viewer"]; }; InternalAddToMsgMenu: PUBLIC PROC[label: ROPE, proc: Menus.MenuProc, clientData: REF ANY _ NIL, onQueue: BOOL] = { frozenList: LIST OF Viewer; new: Menus.MenuEntry = IF onQueue THEN WalnutViewer.CreateMenuEntry[ WalnutWindowInternal.walnutQueue, label, proc, clientData] ELSE Menus.CreateEntry[label, proc, clientData]; Menus.AppendMenuEntry[msgMenu, new]; frozenList _ ChangeAllMsgMenus[]; FOR fL: LIST OF Viewer _ frozenList, fL.rest UNTIL fL = NIL DO v: Viewer = fL.first; Menus.AppendMenuEntry[v.menu, new]; ViewerOps.PaintViewer[v, menu]; ENDLOOP; }; RemoveFromMsgMenu: PUBLIC PROC[name: ROPE] = { old: Menus.MenuEntry = Menus.FindEntry[msgMenu, name]; notFound: BOOL _ FALSE; frozenList: LIST OF Viewer; IF old = NIL THEN RETURN; Menus.ReplaceMenuEntry[msgMenu, old ! Menus.targetNotFound => { notFound _ TRUE; CONTINUE}]; IF notFound THEN RETURN; frozenList _ ChangeAllMsgMenus[]; FOR fL: LIST OF Viewer _ frozenList, fL.rest UNTIL fL = NIL DO v: Viewer = fL.first; Menus.ReplaceMenuEntry[v.menu, old ! Menus.targetNotFound => CONTINUE]; ViewerOps.PaintViewer[v, menu]; ENDLOOP; }; onlyInTextViewer: ROPE = "Can only display msgs in Text viewers"; noSplitsAllowed: ROPE = "Can't display msg in a split viewer"; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *>> <<>> QDisplayMsg: PUBLIC PROC[msg: ROPE, oldV: Viewer, shift: BOOL, openIfIconic: BOOL _ TRUE] RETURNS[v: Viewer] = { contents: TiogaContents; herald, shortName: ROPE; iconName, date: ROPE; LockedSetMenu: PROC = {ViewerOps.SetMenu[v, msgMenu]}; IF ~WalnutOps.MsgExists[msg] THEN RETURN[NIL]; [contents, herald, shortName] _ WalnutOps.GetMsg[msg]; iconName _ Rope.Substr[shortName, 0, shortName.Length[] - 9]; date _ Rope.Substr[shortName, shortName.Length[] - 9]; IF oldV # NIL AND ~oldV.destroyed THEN { oldV.name _ herald; ViewerOps.PaintViewer[oldV, caption]; v _ oldV; } ELSE { v _ ViewerOps.CreateViewer[flavor: $Text, paint: ~shift, info: [name: herald, icon: WalnutWindowInternal.msgIcon, scrollable: TRUE, iconic: FALSE] ]; ViewerLocks.CallUnderWriteLock[LockedSetMenu, v]; IF shift THEN ViewerOps.GrowViewer[v]; shift _ FALSE; -- so don't end up toggling the Grow ViewerOps.AddProp[v, $DestroyMsgDisplayer, ViewerEvents.RegisterEventProc[DestroyMsgDisplayer, destroy, v]]; }; Nut.SetNutInfo[v, $Walnut, "Msg", msg]; ViewerOps.AddProp[v, $WalnutMsgName, msg]; <> ViewerOps.AddProp[v, $IconLabel, Rope.Cat[StripForIcon[iconName], " .", date]]; ShowMsgInMsgViewer[v, contents, shift, openIfIconic]; }; FixUpMsgViewer: PUBLIC PROC[msg: ROPE, v: Viewer] = { IF (msg.Length[] = 0) OR v.destroyed THEN RETURN; IF QDisplayMsg[msg, v, FALSE].v = NIL THEN { WalnutWindowInternal.Report["Msg: ", msg, " doesn't exist; destroying viewer"]; ViewerOps.DestroyViewer[v]; }; }; DisplayMsgFromMsgSet: PUBLIC PROC[msg: ROPE, msViewer: Viewer, shift: BOOL] = { v: Viewer = NARROW[ViewerOps.FetchProp[msViewer, $LastSpawned]]; newV: Viewer; newV _ QDisplayMsg[msg, v, shift]; IF newV = v THEN RETURN; ViewerOps.AddProp[newV, $WhoSpawnedMe, msViewer]; ViewerOps.AddProp[msViewer, $LastSpawned, newV]; }; <<***********************************************************>> <> MsgForwardProc: Menus.MenuProc = { self: Viewer _ NARROW[parent]; self.inhibitDestroy_ TRUE; []_ WalnutSendOps.Forward[self, self]; self.inhibitDestroy_ FALSE; }; MsgReSendProc: Menus.MenuProc = { self: Viewer _ NARROW[parent]; self.inhibitDestroy_ TRUE; []_ WalnutSendOpsExtras.ReSend[self, self]; self.inhibitDestroy_ FALSE; }; MsgAnswerProc: Menus.MenuProc = { OPEN TiogaOps; self: Viewer _ NARROW[parent]; msgR: ROPE; self.inhibitDestroy _ TRUE; TRUSTED { msgR _ WalnutDocumentRope.Create[LOOPHOLE[ViewerDoc[self]]]}; [] _ WalnutSendOps.Answer[msgR, self]; self.inhibitDestroy _ FALSE; }; MsgOpsProc: Menus.MenuProc = { self: Viewer = NARROW[parent]; msg: ROPE = NARROW[ViewerOps.FetchProp[self, $WalnutMsgName]]; which: INT = PopUpSelection.Request["MsgOps", LIST["Sender", "Categories", "SizeOf", "gvID", "PressPrint", "Interpress3.0Print"] ]; SELECT which FROM 1 => WalnutSendOps.WalnutSendProc[fromExec: FALSE]; 2 => MsgCategoriesProc[self, msg]; 3 => { textLen, formatLen: INT; [textLen, formatLen] _ WalnutOpsExtras.GetMsgSize[msg]; IF formatLen # 0 THEN WalnutWindowInternal.Report[IO.PutFR["Formatted Msg \" %g\" has %g bytes of text", IO.rope[msg], IO.int[textLen] ]] ELSE WalnutWindowInternal.Report[IO.PutFR["Msg \"%g\" has %g bytes of text", IO.rope[msg], IO.int[textLen] ]]; }; 4 => MsgGvId[msg, mouseButton # red]; 5 => MsgPrint[self: self, usePress: TRUE]; 6 => MsgPrint[self: self, usePress: FALSE]; ENDCASE => NULL; }; MsgCategoriesProc: PROC[self: Viewer, msg: ROPE] = { IF ViewerOps.FetchProp[self, $Frozen] # NIL AND ~WalnutOps.MsgExists[msg] THEN WalnutWindowInternal.Report[ "Msg ", msg, " in a frozen viewer doesn't exist in this database"] ELSE MsgCategories[msg]; }; MsgFreezeProc: Menus.MenuProc = { self: Viewer = NARROW[parent]; msViewer: Viewer = NARROW[ViewerOps.FetchProp[self, $WhoSpawnedMe]]; frozen: Menus.MenuEntry = Menus.FindEntry[self.menu, "Freeze"]; IF frozen # NIL THEN FreezeViewer[self]; <> IF self.link # NIL THEN -- you are part of a split viewer FOR newV: Viewer _ self.link, newV.link UNTIL newV = self DO FreezeViewer[newV] ENDLOOP; <> IF msViewer # NIL THEN ViewerOps.AddProp[msViewer, $LastSpawned, NIL] }; FreezeViewer: PROC[ v: Viewer ] = { ViewerOps.AddProp[ v, $Frozen, v ]; ViewerOps.SetMenu[v, frozenMsgMenu]; }; MsgSplitProc: Menus.MenuProc = { self: Viewer = NARROW[parent]; newV: Viewer; frozen: REF ANY = ViewerOps.FetchProp[self, $Frozen]; TEditSplit.Split[self]; <> FOR newV _ self.link, newV.link UNTIL newV.link = self DO ENDLOOP; Nut.CopyNutInfo[from: self, to: newV]; ViewerOps.AddProp[ newV, $WalnutMsgName, ViewerOps.FetchProp[self, $WalnutMsgName] ]; ViewerOps.AddProp[ newV, $WhoSpawnedMe, ViewerOps.FetchProp[ self, $WhoSpawnedMe ] ]; IF frozen # NIL THEN FreezeViewer[newV] ELSE ViewerOps.AddProp[ newV, $DestroyMsgDisplayer, ViewerEvents.RegisterEventProc[DestroyMsgDisplayer, destroy, newV] ]; newV.icon _ WalnutWindowInternal.msgIcon }; DestroyMsgDisplayer: ViewerEvents.EventProc = { eventProc: ViewerEvents.EventRegistration; next: Viewer = viewer.link; spawner: Viewer = NARROW[ ViewerOps.FetchProp[viewer, $WhoSpawnedMe] ]; IF ViewerOps.FetchProp[viewer, $Frozen] # NIL THEN RETURN; -- you're not involved IF spawner # NIL THEN ViewerOps.AddProp[ spawner, $LastSpawned, next ]; eventProc_ NARROW[ ViewerOps.FetchProp[viewer, $DestroyMsgDisplayer]]; ViewerEvents.UnRegisterEventProc[ eventProc, destroy]; }; MsgPlacesProc: Menus.MenuProc = Menus.CopyEntry[ Menus.FindEntry[ TiogaMenuOps.tiogaMenu, "Places" ] ].proc; MsgLevelsProc: Menus.MenuProc = Menus.CopyEntry[ Menus.FindEntry[ TiogaMenuOps.tiogaMenu, "Levels" ] ].proc; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *>> MsgCategories: PUBLIC PROC[msg: ROPE] = { Mc: PROC = { msL: LIST OF ROPE _ WalnutOps.GetCategories[msg]; first: BOOL _ TRUE; shortName: ROPE = WalnutOps.GetMsgShortName[msg]; WalnutWindowInternal.ReportRope[IO.PutFR[" %g is in: ", IO.rope[shortName]]]; IF msL = NIL THEN {WalnutWindowInternal.Report["no MsgSets! This is a bug."]; RETURN}; FOR mL: LIST OF ROPE _ msL, mL.rest UNTIL mL=NIL DO IF first THEN first _ FALSE ELSE WalnutWindowInternal.ReportRope[", "]; WalnutWindowInternal.ReportRope[mL.first]; ENDLOOP; WalnutWindowInternal.ReportRope["\n"]; }; [] _ WalnutControlInternal.DoWaitCall[Mc]; }; MsgGvId: PUBLIC PROC[msg: ROPE, all: BOOL] = { Mg: PROC = { gID, other: ROPE; WalnutWindowInternal.Report["gvID for msg is: ", msg]; IF ~all THEN RETURN; [gID, other] _ OtherIDFormats[msg]; WalnutWindowInternal.Report[gID]; WalnutWindowInternal.Report[other]; }; [] _ WalnutControlInternal.DoWaitCall[Mg]; }; MsgPrint: PROC[self: Viewer, usePress: BOOL] = { Mp: PROC = { WalnutPrintOps.MsgPrintProc[self, usePress] }; [] _ WalnutControlInternal.DoWaitCall[Mp]; }; OtherIDFormats: PROC[msg: ROPE] RETURNS[gID, other: ROPE] = { OPEN IO; ts: GVBasics.Timestamp; h: IO.STREAM _ IO.RIS[msg]; netAsRope, hostAsRope: ROPE; netAsLC, hostAsLC: LONG CARDINAL; tyme: BasicTime.GMT; net, host: Basics.BYTE; sender, gvTimeStamp: ROPE; BEGIN temp: REF TEXT = RefText.ObtainScratch[RefText.line]; ch: CHAR; temp.length _ 0; UNTIL (ch _ h.GetChar[]) = '$ DO [] _ RefText.AppendChar[temp, ch]; ENDLOOP; temp.length _ temp.length - 1; -- delete trailing SP sender _ Rope.FromRefText[temp]; RefText.ReleaseScratch[temp]; END; [] _ h.GetChar[]; -- space netAsRope _ h.GetCedarTokenRope[].token; [] _ h.GetChar[]; -- # hostAsRope _ h.GetCedarTokenRope[].token; [] _ h.GetChar[]; -- @ tyme _ h.GetTime[]; netAsLC _ Convert.CardFromRope[netAsRope, 8]; hostAsLC _ Convert.CardFromRope[hostAsRope, 8]; net _ LOOPHOLE[netAsLC, Basics.LongNumber].ll; host _ LOOPHOLE[hostAsLC, Basics.LongNumber].ll; ts _ [net: net, host: host, time: BasicTime.ToPupTime[tyme]]; gvTimeStamp _ RopeFromTimestamp[ts]; gID _ PutFR["[sender: %g, gvTimeStamp: %g]", rope[sender], rope[gvTimeStamp]]; }; <> RopeFromTimestamp: PROC[stamp: GVBasics.Timestamp] RETURNS[Rope.ROPE] = { RETURN[ IO.PutFR["%b#%b@%g", [integer[stamp.net]], [integer[stamp.host]], [cardinal[stamp.time]] ] ] }; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * *>> ChangeAllMsgMenus: PROC RETURNS[fL: LIST OF Viewer] = { <<-- a menu entry was added or removed - update all msg viewers>> vL: LIST OF Viewer _ WalnutWindow.EnumWalnutViewers[keepSeparate: TRUE].msgList; FOR vL2: LIST OF Viewer _ vL, vL2.rest UNTIL vL2 = NIL DO IF ViewerOps.FetchProp[vL2.first, $Frozen] # NIL THEN fL _ CONS[vL2.first, fL] ELSE ViewerOps.SetMenu[vL2.first, msgMenu]; ENDLOOP; }; plainTextStyle: PUBLIC ROPE _ UserProfile.Token[key: "Walnut.PlainTextStyle", default: "cedar"]; ShowMsgInMsgViewer: PROC[v: Viewer, contents: TiogaContents, shift: BOOL, open: BOOL _ TRUE] = { painted: BOOL _ FALSE; KillFeedbackSel[v]; IF v.link # NIL THEN DestroySplitMsgDisplayers[v]; <> BEGIN WITH v.data SELECT FROM tdd: TEditDocument.TEditDocumentData => IF tdd.clipLevel # TEditDocument.maxClip THEN painted _ TRUE ENDCASE; END; IF contents.formatting.IsEmpty[] AND NOT Rope.Equal[plainTextStyle, "cedar"] THEN { -- Plain Text ViewerTools.SetTiogaContents[v, contents, FALSE]; TiogaOps.SaveSelB[]; TiogaOps.SelectDocument[viewer: v, level: point]; TiogaOps.SetStyle[plainTextStyle, root]; v.newVersion _ FALSE; -- Is there a ``better'' way to do this? ViewerOps.PaintViewer[v, all]; TiogaOps.RestoreSelB[]; } ELSE { -- Tioga formatted; needn't reset the style ViewerTools.SetTiogaContents[v, contents, NOT painted]; TiogaMenuOps.AllLevels[v]; }; ViewerTools.InhibitUserEdits[v]; IF v.iconic THEN { IF ~open THEN RETURN; ViewerOps.OpenIcon[v, shift] } ELSE IF shift THEN ViewerOps.GrowViewer[v] }; <> KillFeedbackSel: PROC[v: Viewer] = { OPEN TiogaOps; who: Viewer _ GetSelection[feedback].viewer; IF who = v THEN CancelSelection[feedback]; }; DestroySplitMsgDisplayers: ENTRY PROC[keepThisOne: Viewer] = { ENABLE UNWIND => NULL; next: Viewer_ keepThisOne.link; next2: Viewer; event: ViewerEvents.EventRegistration; DO IF next = keepThisOne THEN EXIT; IF (event _ NARROW[ViewerOps.FetchProp[next, $DestroyMsgDisplayer]]) = NIL THEN LOOP; ViewerEvents.UnRegisterEventProc[event, destroy]; next2 _ next.link; ViewerOps.DestroyViewer[next]; -- DON'T FORK here next _ next2; ENDLOOP; }; StripForIcon: PROC[name: ROPE] RETURNS[ iconLabel: ROPE ] = { start: INT; dot: INT; suffixLength: NAT; <> start _ 0; WHILE (dot _ Rope.Find[Rope.Substr[name, start], "."]) # -1 DO length: INT = Rope.Length[name]; dot _ dot+start; IF length - dot < 2 THEN EXIT; suffixLength _ 0; WHILE dot+1+suffixLength < length AND Ascii.Letter[Rope.Fetch[name, dot+1+suffixLength]] DO suffixLength _ suffixLength+1 ENDLOOP; IF suffixLength >= 0 THEN { name _ Rope.Replace[name, dot, suffixLength+1]; start _ dot } ELSE start _ dot+suffixLength+1 ENDLOOP; iconLabel _ Rope.Substr[name, 0, Rope.Length[name]-1] }; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * *>> <> { OPEN Menus, WalnutWindowInternal; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Freeze", MsgFreezeProc]]; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Answer", MsgAnswerProc]]; AppendMenuEntry[msgMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Forward", MsgForwardProc]]; AppendMenuEntry[msgMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "ReSend", MsgReSendProc]]; AppendMenuEntry[msgMenu, Menus.CreateEntry["MsgOps", MsgOpsProc]]; <> <> AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Split", MsgSplitProc]]; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Places", MsgPlacesProc]]; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "Levels", MsgLevelsProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Answer", MsgAnswerProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Forward", MsgForwardProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["ReSend", MsgReSendProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["MsgOps", MsgOpsProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Split", MsgSplitProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Places", MsgPlacesProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Levels", MsgLevelsProc]]; }; END. Change Log. WSH on March 4, 1983: take out all DBText stuff