WalnutWindowMenuImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Willie-Sue, October 10, 1986 4:56:12 pm PDT
Contents: Menu control for the Top level Viewer for Walnut
created March, 1985 by Willie-Sue
DIRECTORY
FS USING [ComponentPositions, PagesForBytes, ExpandName],
IO,
Menus,
PopUpSelection USING [Request],
Rope,
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, EmptyMsgSet, LogLength, MsgSetExists, SizeOfDatabase, SizeOfMsgSet, WriteArchiveFile],
WalnutSendOps USING [WalnutSendProc],
WalnutControlInternal USING [walnutRootFile, DoWaitCall],
WalnutDisplayerInternal USING [QDisplayMsgSet],
WalnutPrintOps USING [PrintMsgSet, WriteMsgSets],
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, PopUpSelection, Rope, UserProfile,
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)";
WhatToDoToMsgSets: TYPE = {nothing, empty, destroy};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
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[];
readOnlyMsgSetOpsList: LIST OF ROPE = LIST[
"Database Info", "Size of MsgSet(s)", "PressPrint", "InterpressPrint", "Archive", "Append"
];
BuildWalnutMenus: PUBLIC PROC = {
OPEN Menus;
expRope: ROPE = "Will Expunge the Walnut Mail database";
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, CreateEntry["Find", FindProc]];
AppendMenuEntry[mailDBMenu,
CreateEntry[name: "Expunge", proc: MenuExpunge,
documentation: expRope, guarded: TRUE
]];
menu for read only database
AppendMenuEntry[readOnlyDBMenu, CreateEntry["Sender", NewSenderProc]];
AppendMenuEntry[readOnlyDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["MsgSetOps", ROMsgSetOpsProc]];
AppendMenuEntry[readOnlyDBMenu, CreateEntry["Find", FindProc]];
menu for nonMail writeable database
AppendMenuEntry[nonMailDBMenu, CreateEntry["Sender", NewSenderProc]];
AppendMenuEntry[nonMailDBMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]];
AppendMenuEntry[nonMailDBMenu, CreateEntry["MsgSetOps", MsgSetOpsProc]];
AppendMenuEntry[nonMailDBMenu, CreateEntry["Find", FindProc]];
AppendMenuEntry[nonMailDBMenu,
CreateEntry[name: "Expunge", proc: MenuExpunge,
documentation: expRope, guarded: TRUE
]];
other menus
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 = {
which: INT =
PopUpSelection.Request[
header: "MessageSetOps",
choice: LIST["Database Info", "Size of MsgSet(s)",
 "PressPrint", "Interpress3.0Print", "Write MsgSet(s) To File",
 "Create MsgSet", "Delete MsgSet(s)", "Make MsgSet(s) Empty",
 "Archive MsgSet(s)", "Append MsgSet(s)", "ArchiveAndEmpty",
 "AppendAndEmpty", "ArchiveAndDelete", "AppendAndDelete"
] ];
SELECT which FROM
1 => DBInfoProc[];
2 => SizeOfMsgSetsProc[];
3 => PrintMsgSetsProc[usePress: TRUE];
4 => PrintMsgSetsProc[usePress: FALSE];
5 => WriteMsgSetsProc[];
6 => CreateMsgSetButtonProc[];
7 => EmptyDelMsgSetsProc[del: TRUE];
8 => EmptyDelMsgSetsProc[del: FALSE];
9 => ArchiveOrAppend[append: FALSE, whatToDoToMsgSets: nothing];
10 => ArchiveOrAppend[append: TRUE, whatToDoToMsgSets: nothing];
11 => ArchiveOrAppend[append: FALSE, whatToDoToMsgSets: empty];
12 => ArchiveOrAppend[append: TRUE, whatToDoToMsgSets: empty];
13 => ArchiveOrAppend[append: FALSE, whatToDoToMsgSets: destroy];
14 => ArchiveOrAppend[append: TRUE, whatToDoToMsgSets: destroy];
ENDCASE => NULL;
};
ROMsgSetOpsProc: Menus.MenuProc = {
which: INT =
PopUpSelection.Request[
header: "MessageSetOps",
choice: LIST["DB-Info", "SizeOf", "PressPrint", "InterpressPrint", "Archive", "Append"]
];
SELECT which FROM
1 => DBInfoProc[];
2 => SizeOfMsgSetsProc[];
3 => PrintMsgSetsProc[usePress: TRUE];
4 => PrintMsgSetsProc[usePress: FALSE];
5 => ArchiveOrAppend[append: FALSE, whatToDoToMsgSets: nothing];
6 => ArchiveOrAppend[append: TRUE, whatToDoToMsgSets: nothing];
ENDCASE => NULL;
};
MenuExpunge: Menus.MenuProc = {
ENABLE UNWIND => ChangeMenu[walnutMenu, FALSE];
ChangeMenu[workingMenu, TRUE];
WalnutWindow.Expunge[];
};
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: PROC = {
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: PROC = {
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];
};
EmptyDelMsgSetsProc: PROC[del: BOOL] = {
Dms: PROC = {
msgSetList: LIST OF MsgSetButton ← GetSelectedMsgSets[];
name: ROPE;
someInDeleted: BOOL;
anyDeleted: BOOL TRUE;
whatToDo: ROPE = IF del THEN "deleted" ELSE "empty";
IF msgSetList = NIL THEN { Report[noMsgSetsSelected, " to delete"]; RETURN};
ChangeMenu[workingMenu, TRUE];
FOR mL: LIST OF MsgSetButton ← msgSetList, mL.rest UNTIL mL=NIL DO
numIn: INT;
name ← mL.first.msgSet.name;
IF name.Equal[WalnutOps.DeletedMsgSetName, FALSE] THEN
{ Report["Can't ", whatToDo, " the Deleted MsgSet"]; LOOP};
IF del THEN IF (numIn ← WalnutOps.SizeOfMsgSet[name].messages) # 0 THEN {
Report[IO.PutFR[" Confirm deletion of %g messages in MsgSet: %g",
IO.int[numIn], IO.rope[name]] ];
IF ~GetUserResponse[] THEN
{ ChangeMenu[walnutMenu, FALSE]; RETURN }
};
IF del THEN {
DeleteMsgSetButton[name];
someInDeleted ← WalnutOps.DestroyMsgSet[
mL.first.msgSet, WalnutWindowInternal.msgSetsVersion];
}
ELSE someInDeleted ← WalnutOps.EmptyMsgSet[mL.first.msgSet];
IF ~del AND mL.first.msViewer # NIL THEN
[] ← WalnutDisplayerInternal.QDisplayMsgSet[mL.first, mL.first.msViewer, FALSE];
anyDeleted ← anyDeleted OR someInDeleted;
IF ~name.Equal[WalnutOps.ActiveMsgSetName, FALSE] THEN
Report[IO.PutFR["\nMsgSet: %g has been %g",
IO.rope[name], IO.rope[IF del THEN "deleted" ELSE "emptied"]] ]
ELSE Report["\nMsgs have been removed from Active"];
IF del THEN WalnutWindowInternal.msgSetsVersion ← WalnutWindowInternal.msgSetsVersion + 1;
ENDLOOP;
IF anyDeleted THEN RedisplayDeleted[];
ChangeMenu[walnutMenu, FALSE];
};
[] ← DoWaitCall[Dms];
};
PrintMsgSetsProc: PROC[usePress: BOOL] = {
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, usePress] THEN EXIT;
ENDLOOP;
ChangeMenu[walnutMenu, FALSE];
};
[] ← DoWaitCall[Pms];
};
WriteMsgSetsProc: PROC = {
Pms: PROC = {
msgSetList: LIST OF MsgSetButton ← GetSelectedMsgSets[];
fileName: ROPE ← ViewerTools.GetSelectionContents[];
fullName: ROPE;
cp: FS.ComponentPositions;
IF fileName.Length[] = 0 THEN {
Report["No fileName selected"];
RETURN
};
[fullName, cp, ] ← FS.ExpandName[fileName, NIL];
IF cp.ext.length = 0 THEN fullName ← fullName.Concat[".tioga"];
IF msgSetList = NIL THEN { Report[noMsgSetsSelected, " to write to file"]; RETURN };
ChangeMenu[workingMenu, TRUE];
WalnutPrintOps.WriteMsgSets[msgSetList, fullName];
ChangeMenu[walnutMenu, FALSE];
};
[] ← DoWaitCall[Pms];
};
ArchiveOrAppend: PROC[append: BOOL, whatToDoToMsgSets: WhatToDoToMsgSets ] = {
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 whatToDoToMsgSets = nothing THEN
{ ChangeMenu[walnutMenu, FALSE]; RETURN };
ReportRope["\t", IF whatToDoToMsgSets = destroy THEN "Deleting" ELSE "Emptying",
 " archived msgSet(s):"];
FOR mL: LIST OF MsgSetButton ← msgSetList, mL.rest UNTIL mL = NIL DO
someInDeleted: BOOLFALSE;
name: ROPE = mL.first.msgSet.name;
IF ~name.Equal[WalnutOps.DeletedMsgSetName, FALSE] THEN {
IF whatToDoToMsgSets = destroy THEN DeleteMsgSetButton[name];
ReportRope[" ", name];
IF whatToDoToMsgSets = destroy THEN
someInDeleted ← WalnutOps.DestroyMsgSet[
mL.first.msgSet, WalnutWindowInternal.msgSetsVersion ]
ELSE someInDeleted ← WalnutOps.EmptyMsgSet[mL.first.msgSet ];
IF whatToDoToMsgSets # destroy AND mL.first.msViewer # NIL THEN
[] ← WalnutDisplayerInternal.QDisplayMsgSet[mL.first, mL.first.msViewer, FALSE];
IF whatToDoToMsgSets = destroy THEN WalnutWindowInternal.msgSetsVersion ← WalnutWindowInternal.msgSetsVersion + 1;
anyInDeleted ← anyInDeleted OR someInDeleted;
};
ENDLOOP;
ReportRope["\n"];
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;
ok ← WalnutOps.WriteArchiveFile[file: fullName, msgSetList: LIST[mL.first], append: append];
IF ~ok THEN EXIT;
append ← TRUE;  -- always true after the first write
ENDLOOP;
IF ~ok THEN RETURN[FALSE];
Report[IO.PutFR["\n %g messages archived on file: %g", IO.int[num], IO.rope[fullName]]];
RETURN[TRUE]
};
DBInfoProc: PROC = {
len: INT ← WalnutOps.LogLength[];
numIn: INT ← WalnutOps.SizeOfMsgSet[WalnutOps.DeletedMsgSetName].messages;
messages, msgSets: INT;
[messages, msgSets] ← WalnutOps.SizeOfDatabase[];
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), & %g msgSets",
IO.int[numIn], IO.int[messages], IO.int[msgSets] ]];
};
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];
};
GetDirection: PROC[mb: Menus.MouseButton] RETURNS[sd: TiogaOps.SearchDir] = {
SELECT mb FROM
red => RETURN[forwards];
yellow => RETURN[anywhere];
blue => RETURN[backwards];
ENDCASE;
};
* * * * * * * * * *
END.