WalnutWindowMenuImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Willie-Sue, November 5, 1985 11:03:46 am PST
Contents: Menu control for the Top level Viewer for Walnut
created March, 1985 by Willie-Sue
DIRECTORY
FS USING [ComponentPositions, PagesForBytes, ExpandName],
IO,
Menus,
Rope,
TiogaMenuOps USING [PrevPlace],
TiogaOps USING [SearchDir, FindText],
UserProfile USING [Token],
ViewerBLT USING[ChangeNumberOfLines],
ViewerClasses USING [Viewer],
ViewerOps,
ViewerTools USING [GetSelectionContents],
WalnutNewMail USING [CheckGrapevine],
WalnutOps USING [ActiveMsgSetName, DeletedMsgSetName, MsgSet,
CreateMsgSet, DestroyMsgSet, LogLength, MsgSetExists, SizeOfDatabase, SizeOfMsgSet, WriteArchiveFile],
WalnutSendOps USING [WalnutSendProc],
WalnutControlInternal USING [walnutRootFile, DoWaitCall],
WalnutDisplayerInternal USING [QDisplayMsgSet],
WalnutPrintOps USING [PrintMsgSet],
WalnutWindowInternal USING [MsgSetButton,
msgSetsVersion, msgSetsTViewer, walnut, walnutQueue, walnutTS,
AddMsgSetButton, DeleteMsgSetButton, GetButton,
GetSelectedMsgSets, Report, ReportRope, RetrieveNewMail],
WalnutViewer USING [CreateMenuEntry],
WalnutWindow USING [EnumWalnutViewers, Expunge];
WalnutWindowMenuImpl: CEDAR MONITOR
IMPORTS
FS, Menus, IO, Rope, UserProfile,
TiogaMenuOps, TiogaOps,
ViewerBLT, ViewerOps, ViewerTools,
WalnutNewMail, WalnutOps,
WalnutControlInternal,
WalnutDisplayerInternal, WalnutPrintOps, WalnutSendOps,
WalnutViewer, WalnutWindow, WalnutWindowInternal
EXPORTS WalnutControlInternal =
BEGIN OPEN WalnutControlInternal, WalnutWindowInternal;
Walnut Viewers types and global data
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
responseSynch: CONDITION;
userHasResponded, userConfirmed: BOOLFALSE;
noMsgSetsSelected: ROPE = "No seleted MsgSet(s)";
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ChangeMenu: PUBLIC ENTRY PROC[m: Menus.Menu, isBusy: BOOL] = {
ENABLE UNWIND => NULL;
InternalChangeMenu[m, isBusy]
};
InternalChangeMenu: INTERNAL PROC[menu: Menus.Menu, isBusy: BOOL] = {
oldCount, newCount: Menus.MenuLine;
IF walnut = NIL THEN RETURN;
oldCount ← Menus.GetNumberOfLines[walnut.menu];
newCount ← Menus.GetNumberOfLines[menu];
walnut.menu ← menu;
IF oldCount # newCount THEN ViewerBLT.ChangeNumberOfLines[walnut, newCount];
ViewerOps.PaintViewer[walnut, menu];
walnut.newVersion ← isBusy;
ViewerOps.PaintViewer[walnut, caption];
};
GetUserResponse: PUBLIC ENTRY PROC[m: Menus.Menu ← NIL] RETURNS[BOOL] = {
ENABLE UNWIND => NULL;
InternalChangeMenu[IF m = NIL THEN confirmMenu ELSE m, FALSE];
IF walnut.iconic THEN ViewerOps.BlinkIcon[walnut, 0] ELSE ViewerOps.BlinkIcon[walnutTS];
UNTIL userHasResponded DO WAIT responseSynch; ENDLOOP;
userHasResponded ← FALSE;
InternalChangeMenu[workingMenu, FALSE];
RETURN[userConfirmed];
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
walnutMenu: PUBLIC Menus.Menu;
workingMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
confirmMenu: Menus.Menu ← Menus.CreateMenu[];
blankMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
startupConfirmMenu: Menus.Menu ← Menus.CreateMenu[];
forceQuitMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
maybeQuitMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
scavMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
mailDBMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
readOnlyDBMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
nonMailDBMenu: PUBLIC Menus.Menu ← Menus.CreateMenu[];
BuildWalnutMenus: PUBLIC PROC = {
OPEN Menus;
menu for personal mail database
AppendMenuEntry[mailDBMenu, CreateEntry["Sender", NewSenderProc]];
AppendMenuEntry[mailDBMenu, CreateEntry["NewMail", NewMailProc]];
AppendMenuEntry[mailDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]];
AppendMenuEntry[mailDBMenu, CreateEntry["MsgSetOps", MsgSetOpsProc]];
AppendMenuEntry[mailDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "NumMsgs", NumMsgsProc]];
AppendMenuEntry[mailDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "ExpInfo", ExpungeInfo]];
AppendMenuEntry[mailDBMenu, CreateEntry["Find", FindProc]];
now for the second line
AppendMenuEntry[mailDBMenu,
CreateEntry[name: "Exp", proc: MenuExpunge, guarded: TRUE], 1];
AppendMenuEntry[mailDBMenu, CreateEntry["Delete", DeleteMsgSetsProc], 1];
AppendMenuEntry[mailDBMenu, CreateEntry["SizeOf", SizeOfMsgSetsProc], 1];
AppendMenuEntry[mailDBMenu, CreateEntry["Print", PrintMsgSetsProc], 1];
AppendMenuEntry[mailDBMenu, CreateEntry["Create", CreateMsgSetButtonProc], 1];
AppendMenuEntry[mailDBMenu, CreateEntry["Archive", ArchiveButtonProc], 1];
AppendMenuEntry[mailDBMenu, CreateEntry["Append", AppendButtonProc], 1];
AppendMenuEntry[mailDBMenu, CreateEntry["PrevPlace", PrevPlaceProc], 1];
Menus.ChangeNumberOfLines[mailDBMenu, 1];
menu for read only database
AppendMenuEntry[readOnlyDBMenu, CreateEntry["Sender", NewSenderProc]];
AppendMenuEntry[readOnlyDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["SizeOf", SizeOfMsgSetsProc]];
AppendMenuEntry[readOnlyDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "NumMsgs", NumMsgsProc]];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["MsgSetOps", MsgSetOpsProc]];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["Find", FindProc]];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["Print", PrintMsgSetsProc],1];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["Archive", ArchiveButtonProc], 1];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["Append", AppendButtonProc], 1];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["PrevPlace", PrevPlaceProc], 1];
Menus.ChangeNumberOfLines[readOnlyDBMenu, 1];
menu for nonMail writeable database
AppendMenuEntry[nonMailDBMenu, CreateEntry["Sender", NewSenderProc]];
AppendMenuEntry[nonMailDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]];
AppendMenuEntry[nonMailDBMenu, CreateEntry["MsgSetOps", MsgSetOpsProc]];
AppendMenuEntry[nonMailDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "NumMsgs", NumMsgsProc]];
AppendMenuEntry[nonMailDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "ExpInfo", ExpungeInfo]];
AppendMenuEntry[nonMailDBMenu, CreateEntry["Find", FindProc]];
now for the second line
AppendMenuEntry[nonMailDBMenu,
CreateEntry[name: "Exp", proc: MenuExpunge, guarded: TRUE], 1];
AppendMenuEntry[nonMailDBMenu, CreateEntry["Delete", DeleteMsgSetsProc], 1];
AppendMenuEntry[nonMailDBMenu, CreateEntry["SizeOf", SizeOfMsgSetsProc], 1];
AppendMenuEntry[nonMailDBMenu, CreateEntry["Print", PrintMsgSetsProc], 1];
AppendMenuEntry[nonMailDBMenu, CreateEntry["Create", CreateMsgSetButtonProc], 1];
AppendMenuEntry[nonMailDBMenu, CreateEntry["Archive", ArchiveButtonProc], 1];
AppendMenuEntry[nonMailDBMenu, CreateEntry["Append", AppendButtonProc], 1];
AppendMenuEntry[nonMailDBMenu, CreateEntry["PrevPlace", PrevPlaceProc], 1];
Menus.ChangeNumberOfLines[nonMailDBMenu, 1];
AppendMenuEntry[workingMenu, CreateEntry["Sender", NewSenderProc]];
AppendMenuEntry[confirmMenu, CreateEntry["Sender", NewSenderProc]];
AppendMenuEntry[confirmMenu, CreateEntry["Confirm", WWConfirmProc]];
AppendMenuEntry[confirmMenu, CreateEntry["Deny", WWDenyProc]];
AppendMenuEntry[startupConfirmMenu, CreateEntry["Continue", WWConfirmProc]];
AppendMenuEntry[startupConfirmMenu, CreateEntry["Quit", WWDenyProc]];
AppendMenuEntry[forceQuitMenu, CreateEntry["Quit", WWConfirmProc]];
AppendMenuEntry[maybeQuitMenu, CreateEntry["Quit", WWConfirmProc]];
AppendMenuEntry[maybeQuitMenu, CreateEntry["Retry", WWDenyProc]];
AppendMenuEntry[scavMenu, CreateEntry["Quit", WWDenyProc]];
AppendMenuEntry[scavMenu, CreateEntry["Scavenge", WWConfirmProc]];
};
NewSenderProc: Menus.MenuProc = { WalnutSendOps.WalnutSendProc[fromExec: FALSE]};
Create a new blank form in a viewer for user to send msg with.
MsgSetOpsProc: Menus.MenuProc = {
v: Viewer = NARROW[parent];
count: NAT = Menus.GetNumberOfLines[v.menu];
newCount: NAT = IF count = 2 THEN 1 ELSE 2;
Menus.ChangeNumberOfLines[v.menu, newCount];
ViewerBLT.ChangeNumberOfLines[v, newCount];
};
MenuExpunge: Menus.MenuProc = {
ENABLE UNWIND => ChangeMenu[walnutMenu, FALSE];
ChangeMenu[workingMenu, TRUE];
WalnutWindow.Expunge[];
};
ExpungeInfo: Menus.MenuProc = {
len: INT ← WalnutOps.LogLength[];
numIn: INT ← WalnutOps.SizeOfMsgSet[WalnutOps.DeletedMsgSetName].messages;
total: INT ← WalnutOps.SizeOfDatabase[].messages;
Report[IO.PutFR[" The log file is %g bytes (%g pages) long",
IO.int[len], IO.int[FS.PagesForBytes[len]]]];
Report[IO.PutFR[
" There are %g deleted msgs, (%g total msgs)", IO.int[numIn], IO.int[total] ]];
};
NumMsgsProc: Menus.MenuProc = {
messages, msgSets: INT;
[messages, msgSets] ← WalnutOps.SizeOfDatabase[];
Report[IO.PutFR["There are %g messages & %g msgSets in this database",
IO.int[messages], IO.int[msgSets] ]];
};
NewMailProc: Menus.MenuProc = {
IF mouseButton = blue THEN WalnutNewMail.CheckGrapevine[]
ELSE WalnutWindowInternal.RetrieveNewMail[]
};
CloseAllProc: Menus.MenuProc = {
msgSetList, msgList: LIST OF Viewer;
mpViewer: Viewer;
[msgSetList, msgList] ← WalnutWindow.EnumWalnutViewers[TRUE];
FOR vL: LIST OF Viewer ← msgList, vL.rest UNTIL vL=NIL DO
IF ViewerOps.FetchProp[vL.first, $Frozen] = NIL THEN ViewerOps.DestroyViewer[vL.first];
ENDLOOP;
FOR vL: LIST OF Viewer ← msgSetList, vL.rest UNTIL vL=NIL DO
ViewerOps.CloseViewer[vL.first]; ENDLOOP;
IF (mpViewer ← ViewerOps.FindViewer["NewMail Retrieval"]) # NIL THEN
ViewerOps.CloseViewer[mpViewer];
ViewerOps.CloseViewer[walnut];
};
WWDenyProc: ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
userConfirmed ← FALSE;
userHasResponded ← TRUE;
BROADCAST responseSynch
};
WWConfirmProc: ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
userConfirmed ← TRUE;
userHasResponded ← TRUE;
BROADCAST responseSynch
};
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
"immediate" buttons that gather some parameters and then queue the real proc to call
CreateMsgSetButtonProc: Menus.MenuProc = {
msName: ROPE ← ViewerTools.GetSelectionContents[];
Cmsb: PROC = {
IF msName.Length[] = 0 THEN
{ Report["No MsgSet name specified"]; RETURN};
IF msName.Find[" "] >=0 THEN
{ Report[" MsgSet names may not contain spaces"]; RETURN};
IF WalnutOps.MsgSetExists[msName, WalnutWindowInternal.msgSetsVersion].exists
THEN Report["MsgSet: ", msName, " already exists"]
ELSE {
WalnutOps.CreateMsgSet[msName, WalnutWindowInternal.msgSetsVersion];
[] ← AddMsgSetButton[msName, TRUE];
WalnutWindowInternal.msgSetsVersion ← WalnutWindowInternal.msgSetsVersion + 1;
};
};
[] ← DoWaitCall[Cmsb];
};
SizeOfMsgSetsProc: Menus.MenuProc = {
Sms: PROC = {
msgSetList: LIST OF MsgSetButton ← GetSelectedMsgSets[];
msgSet: ROPE;
IF msgSetList = NIL THEN { Report[noMsgSetsSelected]; RETURN};
FOR mL: LIST OF MsgSetButton ← msgSetList, mL.rest UNTIL mL=NIL DO
num: INT ← WalnutOps.SizeOfMsgSet[msgSet ← mL.first.msgSet.name].messages;
Report[IO.PutFR[" %g msgs in MsgSet %g", IO.int[num], IO.rope[msgSet]]];
ENDLOOP;
};
[] ← DoWaitCall[Sms];
};
DeleteMsgSetsProc: Menus.MenuProc = {
Dms: PROC = {
msgSetList: LIST OF MsgSetButton ← GetSelectedMsgSets[];
name: ROPE;
someInDeleted: BOOL;
anyDeleted: BOOL TRUE;
IF msgSetList = NIL THEN { Report[noMsgSetsSelected, " to delete"]; RETURN};
ChangeMenu[workingMenu, TRUE];
FOR mL: LIST OF MsgSetButton ← msgSetList, mL.rest UNTIL mL=NIL DO
name ← mL.first.msgSet.name;
IF name.Equal[WalnutOps.DeletedMsgSetName, FALSE] THEN
{ Report["Can't delete the Deleted MsgSet"]; LOOP};
IF WalnutOps.SizeOfMsgSet[name].messages # 0 THEN {
Report[" Confirm deletion of messages in MsgSet: ", name];
IF ~GetUserResponse[] THEN
{ ChangeMenu[walnutMenu, FALSE]; RETURN }
};
DeleteMsgSetButton[name];
someInDeleted ← WalnutOps.DestroyMsgSet[
mL.first.msgSet, WalnutWindowInternal.msgSetsVersion];
anyDeleted ← anyDeleted OR someInDeleted;
IF ~name.Equal[WalnutOps.ActiveMsgSetName, FALSE] THEN
Report["MsgSet: ", name, " has been deleted"]
ELSE Report["Msgs have been removed from Active"];
WalnutWindowInternal.msgSetsVersion ← WalnutWindowInternal.msgSetsVersion + 1;
ENDLOOP;
IF anyDeleted THEN RedisplayDeleted[];
ChangeMenu[walnutMenu, FALSE];
};
[] ← DoWaitCall[Dms];
};
PrintMsgSetsProc: PUBLIC Menus.MenuProc = {
Pms: PROC = {
msgSetList: LIST OF MsgSetButton ← GetSelectedMsgSets[];
IF msgSetList = NIL THEN { Report[noMsgSetsSelected, " to print"]; RETURN };
ChangeMenu[workingMenu, TRUE];
FOR mL: LIST OF MsgSetButton ← msgSetList, mL.rest UNTIL mL=NIL DO
IF ~WalnutPrintOps.PrintMsgSet[mL.first.msgSet.name] THEN EXIT;
ENDLOOP;
ChangeMenu[walnutMenu, FALSE];
};
[] ← DoWaitCall[Pms];
};
ArchiveButtonProc: Menus.MenuProc =
{ ArchiveOrAppend[FALSE, mouseButton=blue] };
AppendButtonProc: Menus.MenuProc =
{ ArchiveOrAppend[TRUE, mouseButton=blue] };
ArchiveOrAppend: PROC[append, destroyMsgSets: BOOL] = {
fileName: ROPE ← ViewerTools.GetSelectionContents[];
msgSetList: LIST OF MsgSetButton ← GetSelectedMsgSets[];
AorA: PROC = {
ENABLE UNWIND => ChangeMenu[walnutMenu, FALSE];
anyInDeleted: BOOL FALSE;
msList: LIST OF WalnutOps.MsgSet;
ChangeMenu[workingMenu, TRUE];
FOR mL: LIST OF MsgSetButton ← msgSetList, mL.rest UNTIL mL=NIL DO
msList ← CONS[mL.first.msgSet, msList]; ENDLOOP;
IF ~DoArchive[fileName, msList, append] THEN
{ ChangeMenu[walnutMenu, FALSE]; RETURN };
IF ~destroyMsgSets THEN
{ ChangeMenu[walnutMenu, FALSE]; RETURN };
FOR mL: LIST OF MsgSetButton ← msgSetList, mL.rest UNTIL mL = NIL DO
someInDeleted: BOOL;
name: ROPE;
DeleteMsgSetButton[name ← mL.first.msgSet.name];  -- ignores Active & Deleted
IF ~name.Equal[WalnutOps.DeletedMsgSetName, FALSE] THEN
someInDeleted ← WalnutOps.DestroyMsgSet[
mL.first.msgSet, WalnutWindowInternal.msgSetsVersion ];
anyInDeleted ← anyInDeleted OR someInDeleted;
ENDLOOP;
IF anyInDeleted THEN RedisplayDeleted[];
ChangeMenu[walnutMenu, FALSE];
};
[] ← DoWaitCall[AorA];
};
DoArchive: PUBLIC PROC[fileName: ROPE, msList: LIST OF WalnutOps.MsgSet, append: BOOL]
RETURNS[ok: BOOL] = {
fullName: ROPE;
num: INT ← 0;
ok ← FALSE;
IF fileName.Length[] = 0 THEN { Report["No Archive file specified"]; RETURN};
IF msList = NIL THEN
{ Report[noMsgSetsSelected, " to archive"]; RETURN};
make sure didn't specify same name as log file
BEGIN
cp: FS.ComponentPositions;
wDir: ROPE ← UserProfile.Token["Walnut.DefaultArchiveDir"];
[fullName, cp, ] ← FS.ExpandName[fileName, wDir];
IF cp.ext.length = 0 THEN fullName ← fullName.Concat[".ArchiveLog"];
END;
IF Rope.Equal[fullName, walnutRootFile, FALSE] THEN
{ Report["Can't archive on log file"]; RETURN};
IF append THEN Report["Appending msgs to the file: ", fileName];
ReportRope["Archiving the MsgSet(s): "];
FOR mL: LIST OF WalnutOps.MsgSet ← msList, mL.rest UNTIL mL = NIL DO
msName: ROPE = mL.first.name;
this: INT ← WalnutOps.SizeOfMsgSet[msName].messages;
ReportRope[msName, IO.PutFR[" (%g messages) ", IO.int[this]]];
num ← num + this;
WalnutOps.WriteArchiveFile[file: fullName, msgSetList: LIST[mL.first], append: append];
append ← TRUE;  -- always true after the first write
ENDLOOP;
Report[IO.PutFR["\n %g messages archived on file: %g", IO.int[num], IO.rope[fullName]]];
RETURN[TRUE]
};
RedisplayDeleted: PROC = {
msb: MsgSetButton ← GetButton[WalnutOps.DeletedMsgSetName];
IF msb.msViewer = NIL THEN RETURN;
[] ← WalnutDisplayerInternal.QDisplayMsgSet[msb, msb.msViewer, FALSE];
};
FindProc: Menus.MenuProc = {
IF ~TiogaOps.FindText[
viewer: WalnutWindowInternal.msgSetsTViewer,
whichDir: GetDirection[mouseButton],
which: feedback,
case: ~shift]
THEN ViewerOps.BlinkIcon[WalnutWindowInternal.msgSetsTViewer];
};
PrevPlaceProc: Menus.MenuProc =
{ TiogaMenuOps.PrevPlace[WalnutWindowInternal.msgSetsTViewer] };
GetDirection: PROC[mb: Menus.MouseButton] RETURNS[sd: TiogaOps.SearchDir] = {
SELECT mb FROM
red => RETURN[forwards];
yellow => RETURN[anywhere];
blue => RETURN[backwards];
ENDCASE;
};
* * * * * * * * * *
END.