WalnutPrintImpl.mesa
Copyright Ó 1985, 1986, 1987, 1988, 1989, 1992 by Xerox Corporation. All rights reserved.
Willie-sue, September 4, 1992 1:31 pm PDT
Doug Terry, January 8, 1992 11:31 am PST
Swinehar, October 22, 1991 10:31 pm PDT
Contents: Implementation of printing of Msgs, MsgSets, MsgSetTOC's (someday)
Taken from:
[Cedar]<CedarChest6.0>TiogaImager>TiogaToInterpressImpl
WalnutPrintImpl
Created by: Willie-Sue, June 29, 1983
Last edit by:
Willie-Sue on: December 27, 1984 2:45:23 pm PST
DIRECTORY
Ascii USING [Digit, Letter],
Atom USING [DottedPair, DottedPairNode, PropList],
BasicTime USING [Now],
Commander USING [CommandObject, Handle],
CommanderOps USING [DoCommand],
EditSpan,
FS,
Imager USING [Context, ScaleT],
ImagerInterpress USING [Ref, Create, Close, DoPage],
Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc],
IO,
List USING [PutAssoc],
PFS,
Process USING [Detach],
ProcessProps USING [AddPropList],
RefText USING [AppendChar, ObtainScratch, ReleaseScratch],
Rope,
TextEdit USING [ChangeLooks, ChangeStyle, FromRope, PutFormat, PutProp, ReplaceByRope],
TextLooks USING [Looks, noLooks, RopeToLooks],
TextNode USING [FirstChild, LastLocWithin, LastWithin, Location, MakeNodeLoc, MakeNodeSpan, NewTextNode, Root, StepForward],
Tioga USING [Location, Node, Place, Span],
TiogaImager USING [FormattedPage, Destroy, FormatPage, Render],
TiogaIO USING [FromPair, FromRope, ToFile],
TypeScript USING [Create],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [AddProp, FetchProp, FindViewer, SetMenu],
ViewerTools USING [TiogaContents],
UserProfile USING [Boolean, Token],
ViewerClasses USING [Viewer],
XNSPrint USING [Context, Error, GetDefaults, GetPrintRequestStatus, PrintFromFile, RequestStatus, StatusChangedProc],
WalnutDefs USING [Error],
WalnutOps USING [MsgsInSetEnumeration, GetDisplayProps, GetMsg, MsgExists, SizeOfMsgSet],
WalnutInternal USING [ blankMenu, invocationDirectory, ChangeMenu, HowToPrint, workingMenu],
WalnutWindow USING [Report, ReportFormat, ReportRope],
WalnutWindowPrivate USING [MsgAndHandle, MsgSetButton, MsgSetInfo, WalnutHandle, WalnutHandleRec];
WalnutPrintImpl: CEDAR MONITOR
IMPORTS
Ascii, BasicTime, CommanderOps, FS,
Imager, ImagerInterpress,
IO, List, Menus,
PFS, Process, ProcessProps, RefText, Rope,
UserProfile, ViewerIO, ViewerOps,
EditSpan, TextEdit, TextLooks, TextNode, TiogaImager, TiogaIO, TypeScript,
XNSPrint,
WalnutDefs, WalnutOps,
WalnutInternal, WalnutWindow
EXPORTS
WalnutInternal, WalnutWindow =
BEGIN OPEN WalnutInternal;
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
STREAM: TYPE = IO.STREAM;
HowToPrint: TYPE = WalnutInternal.HowToPrint;
MsgSetButton: TYPE = WalnutWindowPrivate.MsgSetButton;
MsgAndHandle: TYPE = WalnutWindowPrivate.MsgAndHandle;
WalnutHandle: TYPE = WalnutWindowPrivate.WalnutHandle;
WalnutHandleRec: PUBLIC TYPE = WalnutWindowPrivate.WalnutHandleRec;
printingMenu: Menus.Menu ¬ Menus.CreateMenu[];
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NodeProc: TYPE = PROC RETURNS [node: Tioga.Node];
PrintCallReturned: CONDITION;
PrintingInfoRec: TYPE =
RECORD[wH: WalnutHandle, done: BOOL, abortRef: REF BOOL, allOK: BOOL ¬ TRUE];
PrintingInfo: TYPE = REF PrintingInfoRec;
lastReportFromPrinter: ROPE ¬ NIL;
ipDefaultPrintName: ROPE = "/tmp/WalnutPrint.interpress";
cmdHandleForPrinting: Commander.Handle ¬ NIL;
aNecessaryProperty: Atom.DottedPair =
NEW[Atom.DottedPairNode ¬ [key: $WalnutPrintCommandHandle, val: NIL]];
prints msgset, using the msgset viewer
MsgSetPrintProc: PUBLIC ENTRY PROC[wH: WalnutHandle, viewer: Viewer, howToPrint: HowToPrint] = {
ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ¬ viewer.menu;
{ ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo: PrintingInfo;
msI: WalnutWindowPrivate.MsgSetInfo;
msgSet: ROPE;
IF ~CheckForPrinting[wH, howToPrint = press] THEN RETURN;
msI ¬ NARROW[ViewerOps.FetchProp[viewer, $MsgSetInfo]];
IF msI = NIL THEN RETURN;
IF ~AnyMessages[wH, msgSet ¬ msI.button.msgSet.name] THEN RETURN;
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[viewer, $PrintingInfo, printInfo];
viewer.inhibitDestroy ¬ TRUE;
TRUSTED {Process.Detach[FORK PrintMSProc[wH, msgSet, NIL, howToPrint, 1, printInfo]]};
ViewerOps.SetMenu[viewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
};
ViewerOps.SetMenu[viewer, prevMenu];
viewer.inhibitDestroy ¬ FALSE;
};
MsgSetTOCPrintProc: PUBLIC ENTRY PROC[wH: WalnutHandle, viewer: Viewer, howToPrint: HowToPrint] = {
ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ¬ viewer.menu;
{ ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo: PrintingInfo;
msI: WalnutWindowPrivate.MsgSetInfo;
msgSet: ROPE;
IF ~CheckForPrinting[wH, howToPrint = press] THEN RETURN;
msI ¬ NARROW[ViewerOps.FetchProp[viewer, $MsgSetInfo]];
IF msI = NIL THEN RETURN;
IF ~AnyMessages[wH, msgSet ¬ msI.button.msgSet.name] THEN RETURN;
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[viewer, $PrintingInfo, printInfo];
viewer.inhibitDestroy ¬ TRUE;
TRUSTED
{Process.Detach[FORK PrintMSTOCProc[wH, msgSet, NIL, howToPrint, 1, printInfo]]};
ViewerOps.SetMenu[viewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
};
ViewerOps.SetMenu[viewer, prevMenu];
viewer.inhibitDestroy ¬ FALSE;
};
MsgPrintProc: PUBLIC ENTRY PROC[wH: WalnutHandle, viewer: Viewer, howToPrint: HowToPrint] = {
ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ¬ viewer.menu;
msgAndWH: MsgAndHandle = NARROW[ViewerOps.FetchProp[viewer, $WalnutMsgName]];
IF ViewerOps.FetchProp[viewer, $Frozen] # NIL AND ~WalnutOps.MsgExists[wH.opsH, msgAndWH.msg] THEN {
WalnutWindow.Report[wH,
"Msg ", msgAndWH.msg, " in a frozen viewer doesn't exist in this database"];
RETURN
};
IF ~CheckForPrinting[wH, howToPrint = press] THEN RETURN;
{ ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo: PrintingInfo;
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[viewer, $PrintingInfo, printInfo];
viewer.inhibitDestroy ¬ TRUE;
WalnutWindow.Report[wH, "Printing the msg: ", viewer.name];
TRUSTED {
Process.Detach[
FORK PrintML[wH, LIST[msgAndWH.msg], viewer.name, NIL, howToPrint, 1, printInfo]]
};
ViewerOps.SetMenu[viewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
};
ViewerOps.SetMenu[viewer, prevMenu];
viewer.inhibitDestroy ¬ FALSE;
};
PrintMsgSetCmd: PUBLIC ENTRY PROC[wH: WalnutHandle,
 msgSet, server: ROPE, howToPrint: HowToPrint, copies: INT] =
{ [] ¬ PrintMsgSetInternal[wH, msgSet, server, howToPrint, copies] };
PrintMsgSet: PUBLIC ENTRY PROC[wH: WalnutHandle,
 msgSet: ROPE, howToPrint: HowToPrint] RETURNS[allOK: BOOL] =
{ RETURN[PrintMsgSetInternal[wH, msgSet, NIL, howToPrint, 1]] };
PrintMsgSetInternal: INTERNAL PROC[wH: WalnutHandle,
 msgSet, server: ROPE, howToPrint: HowToPrint, copies: INT] RETURNS[allOK: BOOL] = {
ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
IF ~CheckForPrinting[wH, howToPrint = press] THEN RETURN[FALSE];
IF ~AnyMessages[wH, msgSet] THEN RETURN[TRUE];
{ ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[wH.walnut, $PrintingInfo, printInfo];
wH.walnut.inhibitDestroy ¬ TRUE;
TRUSTED
{Process.Detach[FORK PrintMSProc[wH, msgSet, server, howToPrint, copies, printInfo]]};
ChangeMenu[wH, printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
};
ChangeMenu[wH, wH.walnutMenu, FALSE];
wH.walnut.inhibitDestroy ¬ FALSE;
RETURN[printInfo.allOK];
};
PrintMsgSetTOCCmd: PUBLIC ENTRY PROC[wH: WalnutHandle,
 msgSet, server: ROPE, howToPrint: HowToPrint, copies: INT] =
{ [] ¬ PrintMsgSetTOCInternal[wH, msgSet, server, howToPrint, copies] };
PrintMsgSetTOC: PUBLIC ENTRY PROC[wH: WalnutHandle, msgSet: ROPE, howToPrint: HowToPrint]
RETURNS[allOK: BOOL] =
{ RETURN[PrintMsgSetTOCInternal[wH, msgSet, NIL, howToPrint, 1]] };
PrintMsgSetTOCInternal: INTERNAL PROC[wH: WalnutHandle, msgSet, server: ROPE, howToPrint: HowToPrint, copies: INT]
 RETURNS[allOK: BOOL] = {
ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
IF ~CheckForPrinting[wH, howToPrint = press] THEN RETURN[FALSE];
IF ~AnyMessages[wH, msgSet] THEN RETURN[TRUE];
{ ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[wH.walnut, $PrintingInfo, printInfo];
wH.walnut.inhibitDestroy ¬ TRUE;
TRUSTED
{ Process.Detach[FORK PrintMSTOCProc[wH, msgSet, server, howToPrint, copies, printInfo]] };
ChangeMenu[wH, printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
};
ChangeMenu[wH, wH.walnutMenu, FALSE];
wH.walnut.inhibitDestroy ¬ FALSE;
RETURN[printInfo.allOK];
};
PrintMsgCmd: PUBLIC ENTRY PROC[wH: WalnutHandle, msg, server: ROPE, howToPrint: HowToPrint, copies: INT] = {
ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
IF ~CheckForPrinting[wH, howToPrint = press] THEN RETURN;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[wH.walnut, $PrintingInfo, printInfo];
wH.walnut.inhibitDestroy ¬ TRUE;
TRUSTED
{ Process.Detach[FORK PrintML[wH, LIST[msg], msg, server, howToPrint, copies, printInfo]] };
ChangeMenu[wH, printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
ChangeMenu[wH, wH.walnutMenu, FALSE];
wH.walnut.inhibitDestroy ¬ FALSE;
};
PrintMsgList: PUBLIC ENTRY PROC[wH: WalnutHandle, mList: LIST OF ROPE, msViewer: Viewer, server: ROPE ¬ NIL, howToPrint: HowToPrint ¬ ip3, copies: INT ¬ 1]
 RETURNS[allOK: BOOL] = {
ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ¬ msViewer.menu;
printInfo: PrintingInfo;
IF ~CheckForPrinting[wH, howToPrint = press] THEN RETURN[FALSE];
IF mList = NIL THEN RETURN[TRUE];
{ ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[msViewer, $PrintingInfo, printInfo];
msViewer.inhibitDestroy ¬ TRUE;
WalnutWindow.Report[wH, "Printing selected msg from ", msViewer.name];
TRUSTED { Process.Detach[
FORK PrintML[wH, mList, msViewer.name, server, howToPrint, copies, printInfo]];
};
ViewerOps.SetMenu[msViewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
};
ViewerOps.SetMenu[msViewer, prevMenu];
msViewer.inhibitDestroy ¬ FALSE;
RETURN[printInfo.allOK];
};
WriteMsgSets: PUBLIC ENTRY PROC[wH: WalnutHandle, msgSetList: LIST OF MsgSetButton, tocsOnly: BOOL, fileName: ROPE] = {
ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
{ ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOL ¬ FALSE];
printInfo ¬ NEW[PrintingInfoRec ¬ [wH: wH, done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[wH.walnut, $PrintingInfo, printInfo];
wH.walnut.inhibitDestroy ¬ TRUE;
TRUSTED
{ Process.Detach[FORK WriteMSProc[wH, msgSetList, printInfo, tocsOnly, fileName]] };
ChangeMenu[wH, printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
};
ChangeMenu[wH, wH.walnutMenu, FALSE];
wH.walnut.inhibitDestroy ¬ FALSE;
};
CheckForPrinting: INTERNAL PROC[wH: WalnutHandle, usePress: BOOL]
RETURNS[ok: BOOL] = {
res: REF;
Installit: PROC = {
res ¬ CommanderOps.DoCommand["Install WalnutInterpressPrint", cmdHandleForPrinting];
};
IF usePress THEN RETURN[FALSE];
IF cmdHandleForPrinting = NIL THEN {
cmdHandleForPrinting ¬
NEW[Commander.CommandObject ¬ [propertyList: LIST[aNecessaryProperty]]];
cmdHandleForPrinting.in ¬ IO.noInputStream;
};
always get the current walnut typescript stream
cmdHandleForPrinting.err ¬ cmdHandleForPrinting.out ¬ wH.wtsOut;
ProcessProps.AddPropList[List.PutAssoc[key: $WorkingDirectory, val: invocationDirectory, aList: NIL], Installit];
IF res = $Failure THEN RETURN[FALSE];
IF failed THEN {
WalnutWindow.Report[
wH, "Couldn't run one of the files needed for printing - printing NOT done"];
RETURN[FALSE];
};
RETURN[TRUE];
};
AnyMessages: PROC[wH: WalnutHandle, msgSet: ROPE] RETURNS[any: BOOL] = {
IF any ¬ (WalnutOps.SizeOfMsgSet[wH.opsH, msgSet].messages # 0) THEN RETURN;
WalnutWindow.ReportFormat[wH, "Msgset: %g contains no msgs", [rope[msgSet]] ];
};
lotaStars: ROPE = "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\r";
prints msgSet
PrintMSProc: PROC[wH: WalnutHandle, msgSet, server: ROPE, howToPrint: HowToPrint, copies: INT, printInfo: PrintingInfo] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[wH, printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msL: LIST OF ROPE;
msg: ROPE;
firstCall: BOOL ¬ TRUE;
firstMsg: BOOL ¬ TRUE;
newPage, smallHeaders: BOOL;
useDefaultFile: BOOL = UserProfile.Boolean[key: "Walnut.UseDefaultPrintFile", default: TRUE];
SupplyMsg: NodeProc = {
IF firstCall THEN
{ node ¬ FirstNode[rootName];
firstCall ¬ FALSE;
RETURN
};
IF msL = NIL THEN RETURN[NIL];
ReportProgress[wH, firstMsg];
node ¬ FormatMsg[wH, msg ¬ msL.first, firstMsg, newPage, smallHeaders];
msL ¬ msL.rest;
firstMsg ¬ FALSE;
};
rootName: ROPE ¬ Rope.Concat["Message Set: ", msgSet];
lastReportFromPrinter ¬ NIL;
newPage ¬ UserProfile.Boolean[key: "Walnut.NewPageEveryMsg", default: FALSE];
smallHeaders ¬ UserProfile.Boolean[key: "Walnut.PrintSmallHeaders", default: TRUE];
BEGIN ENABLE
WalnutDefs.Error, IO.Error, UNWIND => printInfo.abortRef­ ¬ TRUE;
fName: ROPE;
root: Tioga.Node;
IF ~useDefaultFile THEN fName ¬ Rope.Concat["/tmp/Msgset-", msgSet ];
WalnutWindow.Report[wH, "Printing msgs from ", rootName];
msL ¬ WalnutOps.MsgsInSetEnumeration[wH.opsH, msgSet, TRUE].mL;
root ¬ BuildTiogaTree[SupplyMsg, printInfo.abortRef, howToPrint];
IF root # NIL THEN
InterpressPrintRootNode[wH, root, printInfo.abortRef, server, fName, howToPrint, copies];
SignalPrintDone[printInfo];
END;  -- for UNWIND
};
WriteMSProc: PROC[wH: WalnutHandle, msgSetList: LIST OF MsgSetButton, printInfo: PrintingInfo, tocsOnly: BOOL, fileName: ROPE] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[wH, printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msL: LIST OF MsgSetButton ¬ msgSetList;
msgList: LIST OF ROPE;
msg: ROPE;
firstCall: BOOL ¬ TRUE;
firstMsg: BOOL ¬ TRUE;
smallHeaders: BOOL = UserProfile.Boolean[key: "Walnut.PrintSmallHeaders", default: TRUE];
tocDefaultLooks: ROPE = UserProfile.Token[key: "Walnut.TOCDefaultLooks", default: ""];
tocUnreadLooks: ROPE = UserProfile.Token[key: "Walnut.TOCUnreadLooks", default: "i"];
userWantsQMs: BOOL = UserProfile.Boolean[key: "Walnut.ShowUnreadWithQMs", default: TRUE];
needsQ: BOOL = userWantsQMs OR (tocUnreadLooks = NIL);
SupplyMsgs: NodeProc = {
IF firstCall THEN
{ node ¬ FirstNode[fileName];
firstCall ¬ FALSE;
RETURN
};
IF msgList = NIL THEN {
header: ROPE;
IF msL = NIL THEN RETURN[NIL];
WalnutWindow.ReportRope[wH,
"\n\t", header ¬ Rope.Concat["MessageSet: ", msL.first.msgSet.name]];
node ¬ TextNode.NewTextNode[];
[] ¬ TextEdit.ReplaceByRope[root: node, dest: node, rope: header];
TextEdit.PutFormat[node, $head2];
msgList ¬ WalnutOps.MsgsInSetEnumeration[wH.opsH, msL.first.msgSet.name, TRUE].mL;
msL ¬ msL.rest;
firstMsg ¬ TRUE;
RETURN
};
ReportProgress[wH, firstMsg];
node ¬ FormatMsg[wH, msg ¬ msgList.first, firstMsg, FALSE, smallHeaders];
msgList ¬ msgList.rest;
firstMsg ¬ FALSE;
};
SupplyTOC: NodeProc = {
IF firstCall THEN {
node ¬ FirstNode[fileName];
firstCall ¬ FALSE;
RETURN
};
IF msgList = NIL THEN {
looks: TextLooks.Looks ¬ TextLooks.noLooks;
IF msL = NIL THEN RETURN[NIL];
WalnutWindow.ReportRope[wH,
"\n\t", Rope.Concat["TOCs from MessageSet: ", msL.first.msgSet.name]];
looks['b] ¬ TRUE;
looks['l] ¬ TRUE;
firstMsg ¬ FALSE;
node ¬
TiogaIO.FromRope[Rope.Concat["\r\r* * * * * * * * TableOfContents from ", msL.first.msgSet.name]];
TextEdit.ChangeLooks[root: node, text: TextNode.FirstChild[node], add: looks];
msgList ¬ WalnutOps.MsgsInSetEnumeration[wH.opsH, msL.first.msgSet.name, TRUE].mL;
msL ¬ msL.rest;
firstMsg ¬ TRUE;
RETURN
};
ReportProgress[wH, firstMsg];
node ¬ FormatTOC[wH, msg ¬ msgList.first, needsQ, tocDefaultLooks, tocUnreadLooks];
msgList ¬ msgList.rest;
firstMsg ¬ FALSE;
};
IF tocsOnly THEN
WalnutWindow.Report[wH, "\nWriting MsgSet TOCs to file: ", fileName]
ELSE
WalnutWindow.Report[wH, "\nWriting MsgSets to file: ", fileName];
BEGIN ENABLE
WalnutDefs.Error, IO.Error, UNWIND => printInfo.abortRef­ ¬ TRUE;
root: Tioga.Node;
IF tocsOnly THEN root ¬ BuildTiogaTree[SupplyTOC, printInfo.abortRef, ip3]
ELSE root ¬ BuildTiogaTree[SupplyMsgs, printInfo.abortRef, ip3];
IF root # NIL THEN [] ¬ TiogaIO.ToFile[PFS.PathFromRope[fileName], root];
WalnutWindow.Report[wH, "\t ...done"];
SignalPrintDone[printInfo];
END;  -- for UNWIND
};
PrintMSTOCProc: PROC[wH: WalnutHandle, msgSet, server: ROPE, howToPrint: HowToPrint, copies: INT, printInfo: PrintingInfo] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[wH, printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msL: LIST OF ROPE;
msg: ROPE;
firstCall: BOOL ¬ TRUE;
firstMsg: BOOL ¬ TRUE;
tocDefaultLooks: ROPE = UserProfile.Token[key: "Walnut.TOCDefaultLooks", default: ""];
tocUnreadLooks: ROPE = UserProfile.Token[key: "Walnut.TOCUnreadLooks", default: "i"];
userWantsQMs: BOOL = UserProfile.Boolean[key: "Walnut.ShowUnreadWithQMs", default: TRUE];
useDefaultFile: BOOL = UserProfile.Boolean[key: "Walnut.UseDefaultPrintFile", default: TRUE];
needsQ: BOOL = userWantsQMs OR (tocUnreadLooks = NIL);
SupplyTOC: NodeProc = {
IF firstCall THEN {
node ¬ FirstNode[rootName];
firstCall ¬ FALSE;
RETURN
};
IF msL = NIL THEN RETURN[NIL];
ReportProgress[wH, firstMsg];
IF firstMsg THEN {
looks: TextLooks.Looks ¬ TextLooks.noLooks;
looks['b] ¬ TRUE;
looks['l] ¬ TRUE;
firstMsg ¬ FALSE;
node ¬
TiogaIO.FromRope[Rope.Concat["* * * * * * * * TableOfContents from ", rootName]];
TextEdit.ChangeLooks[root: node, text: TextNode.FirstChild[node], add: looks];
}
ELSE {
node ¬ FormatTOC[wH, msg ¬ msL.first, needsQ, tocDefaultLooks, tocUnreadLooks];
msL ¬ msL.rest;
};
};
rootName: ROPE ¬ Rope.Concat["Message Set: ", msgSet];
lastReportFromPrinter ¬ NIL;
BEGIN ENABLE
WalnutDefs.Error, IO.Error, UNWIND => printInfo.abortRef­ ¬ TRUE;
fName: ROPE;
root: Tioga.Node;
IF ~useDefaultFile THEN fName ¬ IO.PutFR1["/tmp/%g-TOC", [rope[msgSet]] ];
WalnutWindow.Report[wH, "Printing Message TOCs from ", rootName];
msL ¬ WalnutOps.MsgsInSetEnumeration[wH.opsH, msgSet, TRUE].mL;
root ¬ BuildTiogaTree[SupplyTOC, printInfo.abortRef, howToPrint];
IF root # NIL THEN
InterpressPrintRootNode[wH, root, printInfo.abortRef, server, fName, howToPrint, copies];
SignalPrintDone[printInfo];
END;  -- for UNWIND
};
PrintML: PROC [wH: WalnutHandle, mL: LIST OF ROPE, name, server: ROPE, howToPrint: HowToPrint, copies: INT, printInfo: PrintingInfo] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[wH, printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msg: ROPE;
firstMsg: BOOL ¬ TRUE;
firstCall: BOOL ¬ TRUE;
newPage, smallHeaders: BOOL;
useDefaultFile: BOOL = UserProfile.Boolean[key: "Walnut.UseDefaultPrintFile", default: TRUE];
fName: ROPE;
SupplyMsg: NodeProc = {
IF firstCall THEN
{ node ¬ FirstNode[name];
firstCall ¬ FALSE;
RETURN
};
IF mL = NIL THEN RETURN;
msg ¬ mL.first;
mL ¬ mL.rest;
ReportProgress[wH, firstMsg];
node ¬ FormatMsg[wH, msg, firstMsg, newPage, smallHeaders];
firstMsg ¬ FALSE;
};
IF ~useDefaultFile THEN BEGIN
msg: ROPE = mL.first;
tocAndSubject, subject: ROPE;
startOfSubject: INT;
rt: REF TEXT ¬ RefText.ObtainScratch[20];
len: INT ¬ 0;
[ , tocAndSubject, startOfSubject] ¬ WalnutOps.GetDisplayProps[wH.opsH, msg];
subject ¬ tocAndSubject.Substr[startOfSubject];
FOR i: INT IN [0..subject.Length[]) DO
c: CHAR = subject.Fetch[i];
IF ~(Ascii.Letter[c] OR Ascii.Digit[c]) THEN LOOP;
rt ¬ RefText.AppendChar[rt, c];
IF (len ¬ len + 1) >= 20 THEN EXIT;
ENDLOOP;
fName ¬ Rope.Concat["/tmp/", Rope.FromRefText[rt] ];
RefText.ReleaseScratch[rt];
END;
lastReportFromPrinter ¬ NIL;
newPage ¬ UserProfile.Boolean[key: "Walnut.NewPageEveryMsg", default: FALSE];
smallHeaders ¬ UserProfile.Boolean[key: "Walnut.PrintSmallHeaders", default: TRUE];
BEGIN ENABLE WalnutDefs.Error, IO.Error => {printInfo.abortRef­ ¬ TRUE};
root: Tioga.Node =
BuildTiogaTree[SupplyMsg, printInfo.abortRef, howToPrint];
IF root # NIL THEN
InterpressPrintRootNode[wH, root, printInfo.abortRef, server, fName, howToPrint, copies];
SignalPrintDone[printInfo];
END;
};
ReportProgress: PROC[wH: WalnutHandle, first: BOOL] = {
IF first THEN WalnutWindow.ReportRope[wH, "\t."] ELSE WalnutWindow.ReportRope[wH, "."];
};
PrintReport: PROC[wH: WalnutHandle, r: ROPE] = {
IF r = lastReportFromPrinter THEN RETURN;
WalnutWindow.ReportRope[wH, lastReportFromPrinter ¬ r];
WalnutWindow.ReportRope[wH, "\n"];
};
SignalPrintDone: ENTRY PROC[printInfo: PrintingInfo] = {
printInfo.done ¬ TRUE;
BROADCAST PrintCallReturned;
};
Failure: ENTRY PROC[wH: WalnutHandle, printInfo: PrintingInfo, who: ROPE] = {
WalnutWindow.Report[wH, who, "; printing NOT done"];
printInfo.done ¬ TRUE;
printInfo.allOK ¬ FALSE;
BROADCAST PrintCallReturned;
};
AbortPrintProc: PUBLIC ENTRY Menus.MenuProc = {
ENABLE UNWIND => NULL;
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;
IF self = printInfo.wH.walnut THEN ChangeMenu[printInfo.wH, workingMenu, FALSE]
ELSE ViewerOps.SetMenu[self, blankMenu];
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
BuildTiogaTree: PROC[nodeProc: NodeProc, aborted: REF BOOL, howToPrint: HowToPrint]
RETURNS[Tioga.Node] = {
root, node: Tioga.Node;
prev: Tioga.Node ¬ NIL;
IsAborted: PROC RETURNS [BOOL] = {RETURN[IF aborted = NIL THEN FALSE ELSE aborted­]};
build a tree with the supplied nodes
where: Tioga.Place ¬ child;
prev ¬ root ¬ TextNode.NewTextNode[];
UNTIL ( node ¬ nodeProc[] ) = NIL DO
new: Tioga.Node;
IF IsAborted[] THEN RETURN[NIL];
new ¬ InsertNode[prev, node, where];
where ¬ sibling;  -- child just the first time
prev ¬ new;
ENDLOOP;
TextEdit.ChangeStyle[node: root, name: "cedar"]; -- set root style
IF IsAborted[] THEN RETURN[NIL];
RETURN[root];
};
InsertNode: PROC [prev, node: Tioga.Node, where: Tioga.Place] RETURNS[new: Tioga.Node] = {
node may have children, but no siblings
destLoc: Tioga.Location ~ TextNode.MakeNodeLoc[prev];
sourceSpan: Tioga.Span ~ TextNode.MakeNodeSpan[node, TextNode.LastWithin[node]];
resSpan: Tioga.Span ¬ EditSpan.Copy[
destRoot: TextNode.Root[prev], sourceRoot: TextNode.Root[node],
dest: destLoc, source: sourceSpan, where: where];
new ¬ resSpan.start.node;
};
InterpressPrintRootNode: PROC[wH: WalnutHandle, root: Tioga.Node, aborted: REF BOOL, server, fileName: ROPE, howToPrint: HowToPrint, copies: INT] = {
IsAborted: PROC RETURNS [BOOL] = {RETURN[IF aborted = NIL THEN FALSE ELSE aborted­]};
header: ROPE = IF howToPrint = ip2 THEN "Interpress/Xerox/2.0 " ELSE "Interpress/Xerox/3.0 ";
fName: ROPE =
IF fileName = NIL THEN ipDefaultPrintName ELSE fileName.Concat[".interpress"];
tName: ROPE ~ fileName.Concat[".tioga"];
master: ImagerInterpress.Ref = ImagerInterpress.Create[fName, header];
pageCount: INT ¬ 0;
marks: Atom.PropList ¬ NIL;
loc: TextNode.Location ¬ [node: TextNode.StepForward[root], where: 0];
WHILE loc.node # NIL DO
page: TiogaImager.FormattedPage;
paint: PROC [context: Imager.Context] = {
Imager.ScaleT[context, 0.0254/72.27];
TiogaImager.Render[page.box, context, [0, 0]];
};
page ¬ TiogaImager.FormatPage[
 pageCounter: pageCount, startLoc: loc, filter: NIL, marks: marks];
ImagerInterpress.DoPage[master, paint];
TiogaImager.Destroy[page.box];
pageCount ¬ pageCount + 1;
marks ¬ page.marks;
loc ¬ page.nextLoc;
ENDLOOP;
ImagerInterpress.Close[master];
[] ¬ TiogaIO.ToFile[PFS.PathFromRope[tName], root]; -- debugging
IF IsAborted[] THEN RETURN;
IF server.Length[] = 0 THEN
 server ¬ UserProfile.Token["Hardcopy.InterpressPrinter", "Snoball"];
IF server.Equal["*"] THEN {
WalnutWindow.ReportFormat[wH, "\nInterPress%g file (%g) written but not sent\n",
[rope[IF howToPrint = ip2 THEN "2.0" ELSE "3.0"]], [rope[fName]] ];
RETURN
};
WalnutWindow.Report[wH,
"\nForking a process to watch interpress printing - see WalnutPrinting typescript viewer"];
TRUSTED { Process.Detach[FORK InterpressPrinting[server, copies, fName]] };
};
walnutPrintTS: ROPE = "WalnutPrinting";
ipPrintingContext: XNSPrint.Context ¬ NIL;
ipPrintViewerOut: STREAM;
InterpressPrinting: PROC[server: ROPE, copies: INT, fName: ROPE] = {
v: ViewerClasses.Viewer;
openFile: FS.OpenFile;
deleteAfterPrint: BOOL = UserProfile.Boolean["Walnut.DeleteFileAfterPrint", FALSE];
IF deleteAfterPrint THEN openFile ¬ FS.Open[fName];  -- make sure doesn't go away
BEGIN ENABLE XNSPrint.Error => {
ipPrintViewerOut.PutF1["\n**** Error from XNSPrint, explanation is: %g\nquitting\n",
 [rope[explanation]] ];
GOTO err;
};
[ipPrintViewerOut, v] ¬ PrintingViewer["Interpress", fName];
ipPrintingContext ¬ XNSPrint.GetDefaults[ipPrintingContext];
IF server.Length[] # 0 THEN ipPrintingContext.printerName ¬ server;
ipPrintingContext.copyCount ¬ copies;
[] ¬ XNSPrint.PrintFromFile[
file: fName,
context: ipPrintingContext
update: WatchInterpressPrinting
];
ipPrintViewerOut.PutF1["File has been sent to %g\n", [rope[ipPrintingContext.printerName]] ];
IF deleteAfterPrint THEN {
fullFName: ROPE = FS.GetName[openFile].fullFName;
FS.Close[openFile];
FS.Delete[fullFName
! FS.Error => {
ipPrintViewerOut.PutRope[error.explanation];
ipPrintViewerOut.PutChar['\n];
GOTO cant } ];
ipPrintViewerOut.PutF1[" Deleted interpress file %g\n", [rope[fName]] ];
EXITS
cant => NULL;
};
EXITS
err => NULL;
END;
v.inhibitDestroy ¬ FALSE;
};
WatchInterpressPrinting: XNSPrint.StatusChangedProc = {
status: XNSPrint.RequestStatus = XNSPrint.GetPrintRequestStatus[request];
BEGIN ENABLE IO.Error => GOTO ignore;
ipPrintViewerOut.PutRope[status.statusMessage];
ipPrintViewerOut.PutChar['\n];
EXITS ignore => NULL;
END;
};
PrintingViewer: PROC[which, fName: ROPE] RETURNS[out: STREAM, v: Viewer] = {
v ¬ ViewerOps.FindViewer[walnutPrintTS];
IF v = NIL THEN
v ¬ TypeScript.Create[
info: [name: walnutPrintTS, iconic: TRUE, column: left, openHeight: 78],
paint: TRUE];
v.inhibitDestroy ¬ TRUE;
out ¬ ViewerIO.CreateViewerStreams[name: NIL, viewer: v].out;
out.PutF["\n*****Start sending (%g) file \"%g\" at %g\n",
 [rope[which]], [rope[fName]], [time[BasicTime.Now[]]] ];
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
FirstNode: PROC[rootName: ROPE] RETURNS[node: Tioga.Node] = {
node ¬ TextEdit.FromRope[rootName];
TextEdit.PutProp[node, $Mark, Rope.Literal["outsideFooter"]];
};
FormatMsg: PROC[wH: WalnutHandle, msg: ROPE, firstMsg, newPage, smallHeaders: BOOL]
RETURNS[Tioga.Node] = {
tocRoot, toc, body: Tioga.Node;
contents: ViewerTools.TiogaContents ~ WalnutOps.GetMsg[wH.opsH, msg].contents;
tocAndSubject: ROPE ¬ WalnutOps.GetDisplayProps[wH.opsH, msg].tocEntry;
endHeadersPos: INT ¬ Rope.Find[contents.contents, "\n\n"];
IF endHeadersPos < 0 THEN endHeadersPos ¬ Rope.Find[contents.contents, "\r\r"];
body ¬ TiogaIO.FromPair[[contents: contents.contents, formatting: contents.formatting]];
IF smallHeaders AND ( endHeadersPos > 0 ) THEN {
first: Tioga.Node ¬ TextNode.FirstChild[body];
lastLoc: INT ~ TextNode.LastLocWithin[first].where;
IF lastLoc > endHeadersPos THEN  -- no formatting already
{ looks: TextLooks.Looks ¬ TextLooks.noLooks;
looks['s] ¬ TRUE;
looks['p] ¬ TRUE;
TextEdit.ChangeLooks[root: body, text: first, add: looks, start: 0, len: endHeadersPos+1];
};
};
IF tocAndSubject.Length[] > 75 THEN
tocAndSubject ¬ Rope.Concat[tocAndSubject.Substr[0, 70], " . . ."];
IF ~newPage THEN tocAndSubject ¬ Rope.Concat[lotaStars, tocAndSubject];
IF ~firstMsg THEN tocAndSubject ¬ Rope.Concat["\r\r", tocAndSubject];
toc ¬ TextNode.FirstChild[tocRoot ¬ TiogaIO.FromRope[tocAndSubject]];
TextEdit.PutFormat[toc, IF newPage THEN $head ELSE $head2];
[] ¬ InsertNode[toc, body, child];
RETURN[tocRoot];
};
FormatTOC: PROC[wH: WalnutHandle, msg: ROPE, needsQ: BOOL, tocDefaultLooks, tocUnreadLooks: ROPE] RETURNS[Tioga.Node] = {
node: Tioga.Node;
hasBeenRead: BOOL;
tocEntry: ROPE;
looks: TextLooks.Looks ¬ TextLooks.noLooks;
[hasBeenRead, tocEntry, ] ¬ WalnutOps.GetDisplayProps[wH.opsH, msg];
tocEntry ¬ IF ~hasBeenRead AND needsQ THEN Rope.Concat["?", tocEntry]
ELSE Rope.Concat[" ", tocEntry];
node ¬ TiogaIO.FromRope[tocEntry];
looks ¬ TextLooks.RopeToLooks[IF hasBeenRead THEN tocDefaultLooks ELSE tocUnreadLooks];
TextEdit.ChangeLooks[root: node, text: TextNode.FirstChild[node], add: looks];
RETURN[node];
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
start code
need an immediate menu button here, can't wait on walnutQueue
Menus.AppendMenuEntry[printingMenu, Menus.CreateEntry["AbortPrint", AbortPrintProc]];
END.