DIRECTORY
Containers USING [ChildXBound, ChildYBound],
IO,
Menus USING [MouseButton, Menu, MenuProc],
Nut USING[SetNutInfo],
Process USING [Pause, MsecToTicks],
Rope,
TBQueue USING [CreateTiogaButton],
ThisMachine USING [Address],
TiogaButtons
USING [
TiogaButton, TiogaButtonProc,
CreateViewer, ChangeButtonLooks, DeleteButton, SetStyleFromRope],
TiogaOps USING [InsertRope, SaveSelA, SetSelection, Delete, RestoreSelA, CancelSelection, GetSelection, InsertChar],
UserProfile USING [Boolean, Token],
ViewerClasses USING [Column, Viewer],
ViewerEvents USING [EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc],
ViewerOps
USING [AddProp, ComputeColumn, CreateViewer, DestroyViewer,
FetchProp, GrowViewer, OpenIcon, PaintViewer, SetMenu],
ViewerSpecs USING [bwScreenHeight, openLeftWidth, openRightWidth],
ViewerTools
USING [TiogaContents, TiogaContentsRec, GetSelectedViewer,
GetSelectionContents, GetTiogaContents],
WalnutParseMsg USING [ParseProc, MsgHeaders, ParseHeadersFromRope],
WalnutDefs USING [dontCareMsgSetVersion, Error],
WalnutOps
USING [MsgSet, ServerInfo, ActiveMsgSetName, DeletedMsgSetName,
AcceptNewMail, AddMsg, CreateMsg, EnumerateMsgsInSet, GetDisplayProps, GetNewMail,
MoveMsg, MsgSetExists, RemoveMsg, SetHasBeenRead],
WalnutDisplayerInternal USING [ DisplayMsgFromMsgSet, MsgCategories],
WalnutMsgSetDisplayerPrivate
USING [
MsgSetInfo, MsgSetInfoRec, MsgSetFieldHandle, MsgSetFieldHandleRec,
MsgInfo, MsgInfoRec,
activeMenu, buildingMenu, deletedMenu, displayerMenu, readOnlyMenu],
WalnutPrintOps USING [PrintMsgList],
WalnutWindowInternal
USING [MsgSetButton,
activeMsgSetButton, deletedMsgSetButton, initialActiveIconic, initialActiveOpen,
initialActiveRight, msgSetIcon, msgSetNamePrefix, personalMailDB, readOnlyAccess,
msgSetsVersion, walnutQueue,
GetButton, GetSelectedMsgSets, Report, ReportRope, RetrieveNewMail];
WalnutMsgSetDisplayerImpl:
CEDAR
PROGRAM
IMPORTS
IO, Nut, Process, Rope, UserProfile,
WalnutParseMsg, WalnutDefs, WalnutOps,
WalnutDisplayerInternal, WalnutMsgSetDisplayerPrivate,
WalnutPrintOps, WalnutWindowInternal,
Containers, TBQueue, ThisMachine, TiogaButtons, TiogaOps,
ViewerEvents, ViewerOps, ViewerSpecs, ViewerTools
EXPORTS
WalnutDisplayerInternal, WalnutMsgSetDisplayerPrivate, WalnutPrintOps =
Types
TiogaButton: TYPE = TiogaButtons.TiogaButton;
Viewer: TYPE = ViewerClasses.Viewer;
ROPE: TYPE = Rope.ROPE;
MsgSet: TYPE = WalnutOps.MsgSet;
MsgSetButton: TYPE = WalnutWindowInternal.MsgSetButton;
MsgSetInfo: TYPE = WalnutMsgSetDisplayerPrivate.MsgSetInfo;
MsgSetFieldHandle: TYPE = WalnutMsgSetDisplayerPrivate.MsgSetFieldHandle;
MsgInfo: TYPE = WalnutMsgSetDisplayerPrivate.MsgInfo;
tocDefaultLooks:
PUBLIC
ROPE ←
UserProfile.Token[key: "Walnut.TOCDefaultLooks", default: ""];
tocSelectedLooks:
PUBLIC
ROPE ←
UserProfile.Token[key: "Walnut.TOCSelectedLooks", default: "sb"];
tocUnreadLooks:
PUBLIC
ROPE ←
UserProfile.Token[key: "Walnut.TOCUnreadLooks", default: "i"];
userWantsQMs:
PUBLIC
BOOL ←
UserProfile.Boolean[key: "Walnut.ShowUnreadWithQMs", default: TRUE];
scrollWaitTime: CARDINAL ← 500; -- Milliseconds
GetMsgSetName:
PUBLIC
PROC[v: Viewer]
RETURNS[msName:
ROPE] = {
of v is a Viewer for a Walnut Entity, then return its name else NIL
msName ← NARROW[ViewerOps.FetchProp[v, $WalnutMsgSetName]];
IF msName = NIL THEN WalnutWindowInternal.Report[" Not a Walnut Message Set viewer"];
};
QDisplayMsgSet:
PUBLIC
PROC[msb: MsgSetButton, oldV: Viewer, shift:
BOOL, repaint:
BOOL]
RETURNS[v: Viewer] = {
IF oldV =
NIL
THEN {
IF msb = NIL THEN RETURN[NIL]; -- no such msgSet
oldV ← msb.msViewer };
IF oldV #
NIL
THEN
IF oldV.destroyed THEN oldV ← msb.msViewer ← NIL;
v ← MSViewer[msb: msb, oldV: oldV, shift: shift];
msb.msViewer ← v;
};
AddNewMsgsToActive:
PUBLIC
PROC[active: MsgSetButton]
RETURNS[responses: LIST OF WalnutOps.ServerInfo, complete: BOOL, numNew: INT] = {
activeV: Viewer = active.msViewer;
msI: MsgSetInfo;
NewMsgProc:
PROC[msg, TOCentry:
ROPE, startOfSubject:
INT] = {
numNew ← numNew + 1;
BuildMsgLineViewer[msI, CreateMsgInfo[msg, FALSE, TOCentry, startOfSubject]];
};
numNew ← 0;
IF activeV =
NIL
OR activeV.destroyed
THEN {
numNew ← -1; -- don't know, won't count
[responses, complete] ← WalnutOps.GetNewMail[WalnutDefs.dontCareMsgSetVersion, NIL];
IF ~complete THEN RETURN;
WalnutOps.AcceptNewMail[WalnutDefs.dontCareMsgSetVersion];
RETURN
};
msI ← NARROW[ViewerOps.FetchProp[activeV, $MsgSetInfo]];
[responses, complete] ← WalnutOps.GetNewMail[active.msgSet.version, NewMsgProc];
IF ~complete THEN RETURN;
WalnutOps.AcceptNewMail[active.msgSet.version];
active.msgSet.version ← active.msgSet.version+1
};
PrintSelectedProc:
PUBLIC PROC[viewer: Viewer, usePress:
BOOL] = {
PrintSel[msViewer: viewer, usePress: usePress]
};
PrintSel:
PROC[
msViewer: Viewer, server: ROPE ← NIL, usePress: BOOL ← TRUE , copies: INT ← 1] = {
msI: MsgSetInfo = NARROW[ViewerOps.FetchProp[msViewer, $MsgSetInfo]];
selected: MsgSetFieldHandle;
IF msI = NIL THEN RETURN;
selected ← msI.selected;
IF selected =
NIL
THEN
{ WalnutWindowInternal.Report[" No selected msg to be printed"]; RETURN};
IF selected.tocButton =
NIL
THEN
{ WalnutWindowInternal.Report[destroyedMsg]; RETURN};
[] ← WalnutPrintOps.PrintMsgList[
LIST[selected.msgInfo.msg], msViewer, server, usePress, copies];
};
PrintSelCmd:
PUBLIC PROC[msgSet:
ROPE, server:
ROPE, usePress:
BOOL, copies:
INT] = {
msb: MsgSetButton = WalnutWindowInternal.GetButton[msgSet];
IF msb = NIL THEN RETURN;
IF msb.msViewer = NIL THEN RETURN;
PrintSel[msb.msViewer, server, usePress, copies];
};
AppendMsgProc:
PUBLIC
PROC[msViewer: Viewer] = {
curSel: ROPE = ViewerTools.GetSelectionContents[];
curV: Viewer = ViewerTools.GetSelectedViewer[];
msI: MsgSetInfo = NARROW[ViewerOps.FetchProp[msViewer, $MsgSetInfo]];
tc: ViewerTools.TiogaContents;
from, sender, gvID, me, TOCentry: ROPE;
date: ROPE = IO.PutFR[NIL, IO.time[]];
startOfSubject: INT;
hasBeenRead: BOOL;
msgInfo: MsgInfo;
mh: WalnutParseMsg.MsgHeaders;
active: MsgSetButton ← WalnutWindowInternal.activeMsgSetButton;
WantThisField: WalnutParseMsg.ParseProc = {
SELECT
TRUE
FROM
fieldName.Equal["From", FALSE] => RETURN[TRUE, TRUE];
fieldName.Equal["Sender", FALSE] => RETURN[TRUE, TRUE];
ENDCASE => RETURN[FALSE, TRUE];
};
IF msI = NIL THEN RETURN;
IF curSel.Length[] < 2
THEN tc ← ViewerTools.GetTiogaContents[curV]
ELSE {
tc ← NEW[ViewerTools.TiogaContentsRec];
tc.contents ← curSel;
};
mh ← WalnutParseMsg.ParseHeadersFromRope[tc.contents, WantThisField];
FOR mhL: WalnutParseMsg.MsgHeaders ← mh, mhL.rest
UNTIL mhL=
NIL
DO
fieldName: ROPE = mhL.first.fieldName;
SELECT
TRUE
FROM
fieldName.Equal["Sender", FALSE] => sender ← mhL.first.value;
fieldName.Equal["From", FALSE] => from ← mhL.first.value;
ENDCASE => NULL;
ENDLOOP;
IF sender = NIL THEN sender ← from;
IF sender = NIL THEN sender ← "UnknownSender";
me ← ThisMachine.Address[];
gvID ←
IO.PutFR["%g $ %g@%g",
IO.rope[sender], IO.rope[me.Substr[len: me.Length[] - 1] ], IO.rope[date] ];
WalnutOps.CreateMsg[gvID, tc];
[hasBeenRead, TOCentry, startOfSubject] ← WalnutOps.GetDisplayProps[gvID];
msgInfo ← CreateMsgInfo[gvID, hasBeenRead, TOCentry, startOfSubject];
IF msI.button # active
THEN {
active.msgSet.version ← active.msgSet.version + 1;
[] ← WalnutOps.MoveMsg[msg: gvID, from: active.msgSet, to: msI.button.msgSet];
active.msgSet.version ← active.msgSet.version + 1;
};
AddToDisplayedMsgSet[msI.button, msgInfo, msI]
};
MSViewer:
PROC[msb: MsgSetButton, oldV: Viewer, shift:
BOOL]
RETURNS[msV: Viewer] = {
OPEN WalnutWindowInternal;
iconic: BOOL ← FALSE;
whichSide: ViewerClasses.Column ← left;
msgSet: MsgSet = msb.msgSet;
caption: ROPE = Rope.Concat[msgSet.name, " Messages"];
msI: MsgSetInfo;
IF msgSet.name.Equal[WalnutOps.ActiveMsgSetName,
FALSE]
THEN {
iconic ← initialActiveIconic AND initialActiveOpen;
IF initialActiveRight THEN whichSide ← right
};
IF oldV # NIL THEN IF oldV.destroyed THEN oldV ← NIL;
IF oldV #
NIL
THEN
{ oldMsgSetName:
ROPE =
NARROW[ViewerOps.FetchProp[oldV, $WalnutMsgSetName]];
msI ← NARROW[ViewerOps.FetchProp[oldV, $MsgSetInfo]];
oldV.inhibitDestroy ← TRUE;
IF ~Rope.Equal[msgSet.name, oldMsgSetName,
FALSE]
THEN {
oldV.name ← caption;
WalnutWindowInternal.GetButton[oldMsgSetName].msViewer ← NIL;
WalnutWindowInternal.GetButton[msgSet.name].msViewer ← oldV }
ELSE {
-- check the version to see if all's well
IF msI.button.msgSet.version = WalnutOps.MsgSetExists[
msgSet.name, WalnutWindowInternal.msgSetsVersion].version
THEN {
oldV.inhibitDestroy ← FALSE;
RETURN[oldV]
}
};
ViewerOps.DestroyViewer[msI.tiogaViewer];
msI.selected ← NIL;
msI.lastMFH ← NIL;
msI.tiogaViewer ← NIL;
msV ← oldV;
}
ELSE {
msV ← ViewerOps.CreateViewer[
flavor: $Container,
info: [name: caption, column: whichSide, menu:
NIL,
iconic: iconic, icon: msgSetIcon, scrollable: FALSE, inhibitDestroy: TRUE]];
msI ← NEW[MsgSetInfoRec];
msI.button ← msb;
msI.container ← msV;
msI.destroyER ←
ViewerEvents.RegisterEventProc[DestroyMSViewer, destroy, msV, TRUE];
IF msI.tiogaViewer =
NIL
THEN {
width:
INT ←
IF msV.column = right
THEN ViewerSpecs.openRightWidth
ELSE
ViewerSpecs.openLeftWidth;
msI.tiogaViewer ← TiogaButtons.CreateViewer[
info: [parent: msV, border: FALSE, ww: width, wh: ViewerSpecs.bwScreenHeight]];
TiogaButtons.SetStyleFromRope[v: msI.tiogaViewer, styleRope: msgSetStyle];
Containers.ChildXBound[msV, msI.tiogaViewer];
Containers.ChildYBound[msV, msI.tiogaViewer];
};
ViewerOps.AddProp[msV, $MsgSetInfo, msI];
Nut.SetNutInfo[msV, $Walnut, "MsgSet", msgSet.name];
ViewerOps.AddProp[msV, $WalnutMsgSetName, msgSet.name];
ViewerOps.AddProp[msV, $IconLabel, msgSet.name];
MsgSetInViewer[msgSet, msI, shift];
};
msgSetStyle:
ROPE ← "BeginStyle
(Cedar) AttachStyle
(header) \"a message header\" {
default
200 pt restIndent
} StyleRule
DestroyMSViewer: ViewerEvents.EventProc = {
msI: MsgSetInfo = NARROW[ViewerOps.FetchProp[viewer, $MsgSetInfo]];
msI.button.msgSet.version ← WalnutDefs.dontCareMsgSetVersion;
msI.button.msViewer ← NIL;
ViewerEvents.UnRegisterEventProc[msI.destroyER, destroy];
};
MsgSetInViewer:
PROC[msgSet: MsgSet, msI: MsgSetInfo, shift:
BOOL] = {
OPEN ViewerOps;
firstUnread, last: INT;
autoScroll: BOOL = UserProfile.Boolean[key: "Walnut.AutoScrollMsgSets", default: TRUE];
v: Viewer = msI.tiogaViewer;
parent: Viewer = v.parent;
menu: Menus.Menu ←
IF WalnutWindowInternal.readOnlyAccess
THEN readOnlyMenu
ELSE
IF msgSet.name.Equal[WalnutOps.ActiveMsgSetName,
FALSE]
THEN
IF WalnutWindowInternal.personalMailDB
THEN activeMenu
ELSE displayerMenu
ELSE
IF msgSet.name.Equal[WalnutOps.DeletedMsgSetName, FALSE] THEN deletedMenu ELSE displayerMenu;
ScrollMsgSet:
PROC = {
IF autoScroll
AND last#-1
THEN
{
IF v.parent.iconic
THEN
{ scroll: ViewerEvents.EventRegistration ←
ViewerEvents.RegisterEventProc[AutoScroll, open, v.parent, FALSE];
after
ViewerOps.AddProp[v.parent, $autoScroll,
NEW[AutoScrollObject ← [scroll, v, firstUnread, last]]];
}
ELSE DoScroll[v, firstUnread, last];
};
SetMenu[parent, menu];
};
[] ← v.class.scroll[v, thumb, 0]; -- position at beginning
IF ~parent.iconic THEN ComputeColumn[parent.column, TRUE];
parent.newVersion ← TRUE; PaintViewer[parent, caption];
SetMenu[parent, buildingMenu];
[firstUnread, last] ← FillInMsgSetWindow[msI, msgSet.name];
ScrollMsgSet[];
ViewerLocks.CallUnderWriteLock[ScrollMsgSet, v];
parent.newVersion ← FALSE; PaintViewer[parent, caption];
IF shift
THEN
{ IF parent.iconic THEN ViewerOps.OpenIcon[parent, shift] ELSE ViewerOps.GrowViewer[parent]};
parent.inhibitDestroy ← FALSE;
};