-- File: WalnutMsgDisplayerImpl.mesa
-- Contents: Implementation of the Walnut Msg Display windows.
-- Last Edited by: Willie-Sue, December 8, 1982 10:25 am
-- Status: complete.
-- Created by: Rick Cattell & Willie-Sue Haugeland, 17-Feb-82
-- Last Edited by: Donahue, April 4, 1983 9:59 am
-- Rick on: April 13, 1982 11:50 am
-- Willie-Sue on: June 7, 1983 3:06 pm
DIRECTORY
DB,
Buttons,
IO,
Menus,
Process USING [Detach],
Rope,
Runtime USING [IsBound],
TSExtras USING [PrintTiogaViewer],
TSTranslate USING [FontNotFound],
TEditDocumentRope USING [Create],
TEditSplit USING[ Split ],
TiogaOps USING [CancelSelection, FirstChild, GetSelection, ViewerDoc],
TiogaMenuOps USING[ tiogaMenu ],
WalnutViewer,
WalnutSendMail,
WalnutDB,
WalnutLog,
WalnutDisplayerOps,
WalnutWindow,
ViewerEvents USING
[ EventRegistration, RegisterEventProc, EventProc, ViewerEvent, UnRegisterEventProc ],
ViewerOps USING
[AddProp, CreateViewer, DestroyViewer, FetchProp, GrowViewer, OpenIcon,
PaintViewer, SetMenu],
ViewerTools;
WalnutMsgDisplayerImpl: CEDAR MONITOR
IMPORTS
DB, IO, Process, Rope, Runtime, TSExtras, TSTranslate,
TEditDocumentRope, TiogaMenuOps, TiogaOps, TEditSplit,
Menus, ViewerOps, ViewerTools, ViewerEvents,
WalnutSendMail, WalnutDB, WalnutLog, WalnutViewer, WalnutWindow
EXPORTS
WalnutDisplayerOps
SHARES Menus =
BEGIN OPEN WalnutDB, WalnutLog, WalnutDisplayerOps, WalnutWindow;
TiogaContents: TYPE = ViewerTools.TiogaContents;
msgMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
printingMenu: Menus.Menu ← Menus.CreateMenu[];
nilMenu: Menus.Menu ← Menus.CreateMenu[];
msgName: PUBLIC ROPE← "Walnut!Msg!";
msgMenuAvailable: PUBLIC BOOL← FALSE;
MsgRebuildProblem: SIGNAL = CODE;
----------------------------
BuildMsgDisplayer: PUBLIC PROC[msg: Msg, shift: BOOL] RETURNS[Viewer] =
BEGIN
RETURN[NIL];
END;
DisplayMsgInViewer:
PUBLIC PROC[msg: Msg, mViewer: Viewer, shift: BOOL← FALSE] =
{ ShowMsgInMsgViewer[mViewer, TiogaMsgFromLog[msg].contents]};
DisplayMsgFromMsgSet:
PUBLIC PROC[mfh: MsgSetFieldHandle, msViewer: Viewer, shift: BOOL← FALSE]
RETURNS[v: Viewer] =
BEGIN
contents: TiogaContents;
name: ROPE = ShortMsgName[mfh.msg];
v ← NARROW[ViewerOps.FetchProp[msViewer, $LastSpawned]];
IF v # NIL AND ~v.destroyed THEN
{ v.name← name; ViewerOps.PaintViewer[v, caption]}
ELSE
{ v ← ViewerOps.CreateViewer[flavor: $Text, paint: ~shift,
info: [name: name, icon: msgIcon, scrollable: TRUE, iconic: FALSE]];
IF shift THEN ViewerOps.GrowViewer[v];
shift← FALSE; -- so don't end up toggling the Grow
ViewerOps.SetMenu[v, msgMenu];
ViewerOps.AddProp[v, $WhoSpawnedMe, msViewer];
ViewerOps.AddProp[msViewer, $LastSpawned, v];
ViewerOps.AddProp[v, $DestroyMsgDisplayer,
ViewerEvents.RegisterEventProc[DestroyMsgDisplayer, destroy, v]] };
ViewerOps.AddProp[v, $Entity, msgName.Concat[GetName[mfh.msg]]];
ViewerOps.AddProp[v, $WalnutEntity, mfh.msg];
IF mfh.posOK THEN
contents← WalnutLog.TiogaTextFromLog[mfh.headersPos, mfh.msgLength]
ELSE
{ hp, len: INT;
[contents, hp, len]← TiogaMsgFromLog[mfh.msg];
mfh.headersPos← hp;
mfh.msgLength← len;
mfh.posOK← TRUE };
ShowMsgInMsgViewer[v, contents];
IF v.iconic THEN ViewerOps.OpenIcon[v, shift]
ELSE IF shift THEN ViewerOps.GrowViewer[v];
END;
GetMsgName: PUBLIC PROC[v: Viewer] RETURNS[mName: ROPE] =
-- of v is a Viewer for a Walnut Entity, then return its name else NIL
BEGIN
ra: REF ANY = ViewerOps.FetchProp[v, $WhoSpawnedMe];
msg: Msg;
IF ra = NIL THEN {Report[" Not a Walnut Msg viewer"]; RETURN};
msg← V2E[ViewerOps.FetchProp[v, $WalnutEntity]];
IF NOT Null[msg] THEN RETURN[GetName[msg]];
END;
StuffMsgContents: PUBLIC PROC[v: Viewer, mName: ROPE] RETURNS[found: BOOLEAN] =
-- if mName is the name of a msg, then display that msg in v else return found← FALSE
BEGIN
msg: Msg← DeclareMsg[mName, OldOnly].msg;
IF (found← msg#NIL) THEN
{ IF v.class.flavor # $Text THEN
{ Report["Can only display msgs in Text viewers"]; RETURN[FALSE]};
IF ViewerOps.FetchProp[v, $WhoSpawnedMe] # NIL THEN
{ ShowMsgInMsgViewer[v, TiogaMsgFromLog[msg].contents]; RETURN};
IF v.link # NIL THEN
{ Report["Can't display msg in a split viewer"]; RETURN[FALSE]};
ViewerTools.SetTiogaContents[v, WalnutDB.TiogaMsgFromLog[msg].contents, FALSE]
};
END;
FixUpMsgViewer: PUBLIC PROC[mName: ROPE, v: Viewer] =
BEGIN
msg: Msg← DeclareMsg[mName, OldOnly].msg;
IF msg = NIL THEN
{ Report["Msg: ", mName, " doesn't exist; destroying viewer"];
ViewerOps.DestroyViewer[v];
RETURN
};
IF v.newVersion THEN ShowMsgInMsgViewer[v, TiogaMsgFromLog[msg].contents]
ELSE ViewerOps.AddProp[v, $WalnutEntity, msg];
END;
-- ***********************************************************
-- menu command procs:
MsgForwardProc: Menus.MenuProc =
{self: Viewer← NARROW[parent];
[]← WalnutSendMail.ForwardMsg[ViewerTools.GetTiogaContents[self], self];
};
MsgAnswerProc: Menus.MenuProc =
{ OPEN TiogaOps;
self: Viewer← NARROW[parent];
msgR: ROPE;
self.inhibitDestroy← TRUE;
TRUSTED { msgR← TEditDocumentRope.Create[LOOPHOLE[FirstChild[ViewerDoc[self]]]]};
[]← WalnutSendMail.AnswerMsg[msgR, self];
self.inhibitDestroy← FALSE;
};
MsgCategoriesProc: Menus.MenuProc =
BEGIN
self: Viewer← NARROW[parent];
ra: REF ANY← ViewerOps.FetchProp[self, $WalnutEntity];
msg: Msg← V2E[ra];
MsgCategories[msg];
END;
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];
-- now freeze everyone linked to you
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;
-- only need to do this once
IF msViewer # NIL THEN ViewerOps.AddProp[msViewer, $LastSpawned, NIL] };
FreezeViewer: PROC[ v: Viewer ] = {
freezeButton: Menus.MenuEntry = Menus.FindEntry[v.menu, "Freeze"];
ViewerOps.AddProp[ v, $Frozen, v ];
IF freezeButton # NIL THEN
{ Menus.ReplaceMenuEntry[v.menu, freezeButton]; ViewerOps.PaintViewer[v, menu] } };
MsgSplitProc: Menus.MenuProc = {
self: Viewer = NARROW[parent];
newV: Viewer;
frozen: REF ANY = ViewerOps.FetchProp[self, $Frozen];
TEditSplit.Split[self];
-- now find the newest link in the chain to copy properties
FOR newV ← self.link, newV.link UNTIL newV.link = self DO ENDLOOP;
ViewerOps.AddProp[ newV, $Entity, ViewerOps.FetchProp[ self, $Entity ] ];
ViewerOps.AddProp[ newV, $WalnutEntity, ViewerOps.FetchProp[ self, $WalnutEntity ] ];
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 ← 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;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
PrintCallReturned: CONDITION;
PrintingInfoObject: TYPE = RECORD[done: BOOL, abortRef: REF BOOL];
PrintingInfo: TYPE = REF PrintingInfoObject;
lastMsgFromPrinter: ROPE← NIL;
MsgPrintProc: ENTRY Menus.MenuProc =
BEGIN
self: Viewer = NARROW[parent];
BEGIN ENABLE UNWIND => GOTO unwound;
aborted: REF BOOL = NEW[BOOL← FALSE];
printInfo: PrintingInfo;
TRUSTED
{IF ~Runtime.IsBound[TSExtras.PrintTiogaViewer] THEN
{ Report[" Can't print messages unless TSetter has been loaded"]; RETURN}
};
printInfo← NEW[PrintingInfoObject← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[self, $PrintingInfo, printInfo];
self.inhibitDestroy ← TRUE;
TRUSTED {Process.Detach[FORK ForkPrintProc[self, printInfo]]};
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
ViewerOps.SetMenu[self, msgMenu];
self.inhibitDestroy ← FALSE;
EXITS
unwound => {ViewerOps.SetMenu[self, msgMenu]; self.inhibitDestroy ← FALSE};
END;
END;
ForkPrintProc: PROC [self: Viewer, printInfo: PrintingInfo] =
BEGIN
ViewerOps.SetMenu[self, printingMenu];
lastMsgFromPrinter← NIL;
TRUSTED {TSExtras.PrintTiogaViewer[viewer: self, nameForSeparatorPage: self.name,
aborted: printInfo.abortRef, messageProc: MsgReport !
TSTranslate.FontNotFound =>
{printInfo.abortRef^ ← TRUE; MsgReport[fontName];
MsgReport[" not found - aborting"]; CONTINUE}]};
SignalPrintDone[printInfo];
END;
MsgReport: PROC[r: ROPE] =
BEGIN
IF r = lastMsgFromPrinter THEN RETURN;
ReportRope[lastMsgFromPrinter← r];
ReportRope["\n"];
END;
SignalPrintDone: ENTRY PROC[printInfo: PrintingInfo] =
BEGIN
printInfo.done← TRUE;
BROADCAST PrintCallReturned;
END;
AbortPrintProc: ENTRY Menus.MenuProc =
BEGIN
self: Viewer← NARROW[parent];
printInfo: PrintingInfo← NARROW[ViewerOps.FetchProp[self, $PrintingInfo]];
IF printInfo = NIL THEN RETURN; -- perhaps an error??
IF printInfo.done THEN RETURN; -- too late??
printInfo.abortRef^ ← TRUE;
ViewerOps.SetMenu[self, nilMenu];
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
MsgCategories: PUBLIC PROC[msg: Msg] =
BEGIN
msL: LIST OF Value← DB.GetPList[msg, mCategoryIs];
first: BOOL← TRUE;
ReportRope[IO.PutFR[" %g is in: ", IO.rope[ShortMsgName[msg]]]];
IF msL = NIL THEN {Report["no MsgSets! This is a bug."]; RETURN};
FOR mL: LIST OF Value← msL, mL.rest UNTIL mL=NIL DO
name: ROPE← DB.GetName[V2E[mL.first]];
IF first THEN first← FALSE ELSE ReportRope[", "];
ReportRope[name];
ENDLOOP;
ReportRope["\n"];
END;
ShortMsgName: PROC[msg: Msg] RETURNS[name: ROPE] =
BEGIN
eName: ROPE← DB.GetName[msg];
name← eName.Substr[0, eName.Find[" $ "] + 3];
name← name.Cat[eName.Substr[eName.Find["@"]+1, 9]];
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ShowMsgInMsgViewer: PROC[v: Viewer, contents: TiogaContents] =
BEGIN
KillFeedbackSel[v];
IF v.link # NIL THEN DestroySplitMsgDisplayers[v];
ViewerTools.SetTiogaContents[v, contents, FALSE];
ViewerTools.InhibitUserEdits[v];
ViewerOps.PaintViewer[viewer: v, hint: client]
END;
-- bug in SetTiogaContents necessitates this
KillFeedbackSel: PROC[v: Viewer] =
BEGIN OPEN TiogaOps;
who: Viewer← GetSelection[feedback].viewer;
IF who = v THEN CancelSelection[feedback];
END;
DestroySplitMsgDisplayers: ENTRY PROC[keepThisOne: Viewer] =
BEGIN 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;
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-- initialize menues:
{ OPEN Menus;
AppendMenuEntry[ msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Freeze", MsgFreezeProc]];
AppendMenuEntry[ msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Categories", MsgCategoriesProc]];
AppendMenuEntry[ msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Answer", MsgAnswerProc]];
AppendMenuEntry[msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Forward", MsgForwardProc]];
AppendMenuEntry[msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Print", MsgPrintProc]];
AppendMenuEntry[ msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Split", MsgSplitProc]];
AppendMenuEntry[ msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Places", MsgPlacesProc]];
AppendMenuEntry[ msgMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Levels", MsgLevelsProc]];
-- need an immediate menu button here, can't wait on walnutQueue
AppendMenuEntry[printingMenu, CreateEntry["AbortPrint", AbortPrintProc]];
msgMenuAvailable← TRUE;
};
END.
Change Log.
WSH on March 4, 1983: take out all DBText stuff