WalnutPrintImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Willie-Sue, October 13, 1986 11:23:49 am 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, GetPName],
Commander USING [CommandObject, Handle],
CommandTool USING [AddSearchRule],
FS,
Imager USING [Context, metersPerPoint, ScaleT],
ImagerInterpress USING [Ref, Create, Close, DoPage],
ImagerPress USING [Close, NewPage, SimpleCreate],
Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc],
Install USING [Install],
IO,
List USING [PutAssoc],
NodeProps USING [GetProp, PutProp],
NodeStyleOps USING [defaultStyleName, Ref, Create],
PeachPrint USING [PupAborted, DoPeachPrintCommand],
PressPrinter USING [CurrentStateMessage, ProgressProc, SendPressFile],
Process USING [Detach],
ProcessProps USING [AddPropList],
PutGet USING [FromRope, ToFile],
RefText USING [AppendChar, ObtainScratch, ReleaseScratch],
Rope,
TextEdit USING [SetLooks],
TextLooks USING [Looks, noLooks, RopeToLooks],
TextNode USING [Location, Ref, LastChild, NarrowToTextNode, NewTextNode, StepForward],
TiogaImager USING [FormattedPage, Destroy, FormatPage, Render],
TiogaFileOps USING [CreateRoot, Ref, SetContents, SetFormat],
TiogaOps USING [Ref, FirstChild, LastLocWithin, PutProp],
TypeScript USING [Create],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [AddProp, FetchProp, FindViewer, SetMenu],
ViewerTools USING [TiogaContents],
UserCredentials USING [Get],
UserProfile USING [Boolean, Token],
ViewerClasses USING [Viewer],
WalnutDefs USING [Error],
WalnutOps USING [MsgsInSetEnumeration, GetDisplayProps, GetMsg, MsgExists, SizeOfMsgSet],
WalnutPrintOps USING [],
WalnutControlInternal USING [
invocationDirectory, walnutMenu, workingMenu, ChangeMenu],
WalnutWindowInternal USING [walnut, MsgSetButton, GetTSStream, Report, ReportRope];
WalnutPrintImpl: CEDAR MONITOR
IMPORTS
Ascii, Atom, CommandTool, FS,
Imager, ImagerInterpress, ImagerPress, Install,
IO, List, Menus, NodeProps, NodeStyleOps, PeachPrint, PressPrinter,
Process, ProcessProps, RefText, Rope,
UserProfile, UserCredentials, ViewerIO, ViewerOps,
PutGet, TextEdit, TextLooks, TextNode, TiogaFileOps, TiogaImager, TiogaOps, TypeScript,
WalnutDefs, WalnutOps,
WalnutControlInternal, WalnutWindowInternal
EXPORTS
WalnutPrintOps =
BEGIN OPEN WalnutWindowInternal;
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
STREAM: TYPE = IO.STREAM;
blankMenu: PUBLIC Menus.Menu = Menus.CreateMenu[];
printingMenu: Menus.Menu ← Menus.CreateMenu[];
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NodeProc: TYPE = PROC RETURNS [node: TextNode.Ref];
PrintCallReturned: CONDITION;
PrintingInfoObject: TYPE = RECORD[done: BOOL, abortRef: REF BOOL, allOK: BOOLTRUE];
PrintingInfo: TYPE = REF PrintingInfoObject;
lastReportFromPrinter: ROPENIL;
defaultPrintName: ROPE = "///temp/WalnutPrint.press$";
ipDefaultPrintName: ROPE = "///temp/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[viewer: Viewer, usePress: BOOL] =
BEGIN ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ← viewer.menu;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo: PrintingInfo;
msgSet: ROPE;
IF ~CheckForPrinting[usePress: usePress] THEN RETURN;
msgSet ← NARROW[ViewerOps.FetchProp[viewer, $WalnutMsgSetName]];
IF ~AnyMessages[msgSet] THEN RETURN;
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[viewer, $PrintingInfo, printInfo];
viewer.inhibitDestroy ← TRUE;
TRUSTED {Process.Detach[FORK PrintMSProc[msgSet, NIL, usePress, 1, printInfo]]};
ViewerOps.SetMenu[viewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
ViewerOps.SetMenu[viewer, prevMenu];
viewer.inhibitDestroy ← FALSE;
END;
MsgSetTOCPrintProc: PUBLIC ENTRY PROC[viewer: Viewer, usePress: BOOL] =
BEGIN ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ← viewer.menu;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo: PrintingInfo;
msgSet: ROPE;
IF ~CheckForPrinting[usePress: usePress] THEN RETURN;
msgSet ← NARROW[ViewerOps.FetchProp[viewer, $WalnutMsgSetName]];
IF ~AnyMessages[msgSet] THEN RETURN;
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[viewer, $PrintingInfo, printInfo];
viewer.inhibitDestroy ← TRUE;
TRUSTED {Process.Detach[FORK PrintMSTOCProc[msgSet, NIL, usePress, 1, printInfo]]};
ViewerOps.SetMenu[viewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
ViewerOps.SetMenu[viewer, prevMenu];
viewer.inhibitDestroy ← FALSE;
END;
MsgPrintProc: PUBLIC ENTRY PROC[viewer: Viewer, usePress: BOOL] =
BEGIN ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ← viewer.menu;
msg: ROPE = NARROW[ViewerOps.FetchProp[viewer, $WalnutMsgName]];
IF ViewerOps.FetchProp[viewer, $Frozen] # NIL AND ~WalnutOps.MsgExists[msg] THEN {
WalnutWindowInternal.Report[
"Msg ", msg, " in a frozen viewer doesn't exist in this database"];
RETURN
};
IF ~CheckForPrinting[usePress: usePress] THEN RETURN;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo: PrintingInfo;
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[viewer, $PrintingInfo, printInfo];
viewer.inhibitDestroy ← TRUE;
Report["Printing the msg: ", viewer.name];
TRUSTED {Process.Detach[FORK PrintML[LIST[msg], msg, NIL, usePress, 1, printInfo]]};
ViewerOps.SetMenu[viewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
ViewerOps.SetMenu[viewer, prevMenu];
viewer.inhibitDestroy ← FALSE;
END;
PrintMsgSetCmd: PUBLIC ENTRY PROC[msgSet, server: ROPE, usePress: BOOL, copies: INT] =
{ [] ← PrintMsgSetInternal[msgSet, server, usePress, copies] };
PrintMsgSet: PUBLIC ENTRY PROC[msgSet: ROPE, usePress: BOOL] RETURNS[allOK: BOOL] =
{ RETURN[PrintMsgSetInternal[msgSet, NIL, usePress, 1]] };
PrintMsgSetInternal: INTERNAL PROC[msgSet, server: ROPE, usePress: BOOL, copies: INT]
  RETURNS[allOK: BOOL] =
BEGIN ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
IF ~CheckForPrinting[usePress: usePress] THEN RETURN;
IF ~AnyMessages[msgSet] THEN RETURN;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[walnut, $PrintingInfo, printInfo];
walnut.inhibitDestroy ← TRUE;
TRUSTED {Process.Detach[FORK PrintMSProc[msgSet, server, usePress, copies, printInfo]]};
WalnutControlInternal.ChangeMenu[printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
WalnutControlInternal.ChangeMenu[WalnutControlInternal.walnutMenu, FALSE];
walnut.inhibitDestroy ← FALSE;
RETURN[printInfo.allOK];
END;
PrintMsgSetTOCCmd: PUBLIC ENTRY PROC[msgSet, server: ROPE, usePress: BOOL, copies: INT] =
{ [] ← PrintMsgSetTOCInternal[msgSet, server, usePress, copies] };
PrintMsgSetTOC: PUBLIC ENTRY PROC[msgSet: ROPE, usePress: BOOL] RETURNS[allOK: BOOL] =
{ RETURN[PrintMsgSetTOCInternal[msgSet, NIL, usePress, 1]] };
PrintMsgSetTOCInternal: INTERNAL PROC[msgSet, server: ROPE, usePress: BOOL, copies: INT]
  RETURNS[allOK: BOOL] =
BEGIN ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
IF ~CheckForPrinting[usePress: usePress] THEN RETURN;
IF ~AnyMessages[msgSet] THEN RETURN;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[walnut, $PrintingInfo, printInfo];
walnut.inhibitDestroy ← TRUE;
TRUSTED
{ Process.Detach[FORK PrintMSTOCProc[msgSet, server, usePress, copies, printInfo]] };
WalnutControlInternal.ChangeMenu[printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
WalnutControlInternal.ChangeMenu[WalnutControlInternal.walnutMenu, FALSE];
walnut.inhibitDestroy ← FALSE;
RETURN[printInfo.allOK];
END;
PrintMsgCmd: PUBLIC ENTRY PROC[msg, server: ROPE, usePress: BOOL, copies: INT] = {
ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
IF ~CheckForPrinting[usePress: usePress] THEN RETURN;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[walnut, $PrintingInfo, printInfo];
walnut.inhibitDestroy ← TRUE;
TRUSTED
{ Process.Detach[FORK PrintML[LIST[msg], msg, server, usePress, copies, printInfo]] };
WalnutControlInternal.ChangeMenu[printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
WalnutControlInternal.ChangeMenu[WalnutControlInternal.walnutMenu, FALSE];
walnut.inhibitDestroy ← FALSE;
};
PrintMsgList: PUBLIC ENTRY PROC[
 mList: LIST OF ROPE,
 msViewer: Viewer, server: ROPENIL, usePress: BOOLTRUE, copies: INT ← 1]
RETURNS[allOK: BOOL] =
BEGIN ENABLE UNWIND => NULL;
prevMenu: Menus.Menu ← msViewer.menu;
printInfo: PrintingInfo;
IF ~CheckForPrinting[usePress: usePress] THEN RETURN;
IF mList = NIL THEN RETURN;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[msViewer, $PrintingInfo, printInfo];
msViewer.inhibitDestroy ← TRUE;
Report["Printing selected msgs from ", msViewer.name];
Report["Printing selected msg from ", msViewer.name];
TRUSTED { Process.Detach[
FORK PrintML[mList, msViewer.name, server, usePress, copies, printInfo]];
};
ViewerOps.SetMenu[msViewer, printingMenu];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
ViewerOps.SetMenu[msViewer, prevMenu];
msViewer.inhibitDestroy ← FALSE;
RETURN[printInfo.allOK];
END;
WriteMsgSets: PUBLIC ENTRY PROC[msgSetList: LIST OF MsgSetButton, fileName: ROPE] = {
BEGIN ENABLE UNWIND => NULL;
printInfo: PrintingInfo;
BEGIN ENABLE UNWIND => CONTINUE;
aborted: REF BOOL = NEW[BOOLFALSE];
printInfo ← NEW[PrintingInfoObject ← [done: FALSE, abortRef: aborted]];
ViewerOps.AddProp[walnut, $PrintingInfo, printInfo];
walnut.inhibitDestroy ← TRUE;
TRUSTED {Process.Detach[FORK WriteMSProc[msgSetList, printInfo, fileName]]};
WalnutControlInternal.ChangeMenu[printingMenu, TRUE];
UNTIL printInfo.done DO WAIT PrintCallReturned; ENDLOOP;
END;
WalnutControlInternal.ChangeMenu[WalnutControlInternal.walnutMenu, FALSE];
walnut.inhibitDestroy ← FALSE;
END;
};
CheckForPrinting: INTERNAL PROC[usePress: BOOL] RETURNS[ok: BOOL] =
BEGIN
foundFile, failed: BOOL;
Installit: PROC = {
IF usePress THEN
[foundFile, failed] ← Install.Install["WalnutPressPrint", cmdHandleForPrinting]
ELSE
[foundFile, failed] ← Install.Install["WalnutInterpressPrint", cmdHandleForPrinting];
};
IF cmdHandleForPrinting = NIL THEN {
cmdHandleForPrinting ←
NEW[Commander.CommandObject ← [propertyList: LIST[aNecessaryProperty]]];
cmdHandleForPrinting.in ← IO.noInputStream;
cmdHandleForPrinting.err ← cmdHandleForPrinting.out ←
  WalnutWindowInternal.GetTSStream[];
CommandTool.AddSearchRule[
cmdHandleForPrinting, WalnutControlInternal.invocationDirectory];
CommandTool.AddSearchRule[cmdHandleForPrinting, "///Commands/"]
};
ProcessProps.AddPropList[List.PutAssoc[key: $WorkingDirectory, val: WalnutControlInternal.invocationDirectory, aList: NIL], Installit];
IF ~foundFile THEN RETURN[FALSE];
IF failed THEN {
Report["Couldn't run one of the files needed for printing - printing NOT done"];
RETURN[FALSE];
};
RETURN[TRUE];
END;
AnyMessages: PROC[msgSet: ROPE] RETURNS[any: BOOL] = {
IF any ← (WalnutOps.SizeOfMsgSet[msgSet].messages # 0) THEN RETURN;
Report["Msgset: ", msgSet, " contains no msgs"];
};
lotaStars: ROPE = "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n";
prints msgSet
PrintMSProc: PROC[msgSet, server: ROPE, usePress: BOOL, copies: INT, printInfo: PrintingInfo] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msL: LIST OF ROPE;
msg: ROPE;
firstCall: BOOLTRUE;
firstMsg: BOOLTRUE;
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[firstMsg];
node ← FormatMsg[msg ← msL.first, firstMsg, newPage, smallHeaders].node;
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: TextNode.Ref;
IF ~useDefaultFile THEN fName ← Rope.Concat["///temp/Msgset-", msgSet ];
Report["Printing msgs from ", rootName];
msL ← WalnutOps.MsgsInSetEnumeration[msgSet, TRUE].mL;
root ← BuildTiogaTree[SupplyMsg, printInfo.abortRef];
IF root # NIL THEN
IF usePress THEN
PressPrintRootNode[root, printInfo.abortRef, server, fName, copies]
ELSE Interpress3PrintRootNode[root, printInfo.abortRef, server, fName, copies];
SignalPrintDone[printInfo];
END;  -- for UNWIND
};
WriteMSProc: PROC[
msgSetList: LIST OF MsgSetButton, printInfo: PrintingInfo, fileName: ROPE] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msL: LIST OF MsgSetButtonmsgSetList;
msgList: LIST OF ROPE;
msg: ROPE;
firstCall: BOOLTRUE;
firstMsg: BOOLTRUE;
smallHeaders: BOOL = UserProfile.Boolean[key: "Walnut.PrintSmallHeaders", default: TRUE];
SupplyMsgs: NodeProc = {
IF firstCall THEN
{ node ← FirstNode[fileName];
firstCall ← FALSE;
RETURN
};
IF msgList = NIL THEN {
header: ROPE;
IF msL = NIL THEN RETURN[NIL];
ReportRope["\n\t", header ← Rope.Concat["MessageSet: ", msL.first.msgSet.name]];
node ← PutGet.FromRope[""];
TRUSTED {
TiogaFileOps.SetContents[LOOPHOLE[node], header];
TiogaFileOps.SetFormat[LOOPHOLE[node], "head2"]
};
msgList ← WalnutOps.MsgsInSetEnumeration[msL.first.msgSet.name, TRUE].mL;
msL ← msL.rest;
firstMsg ← TRUE;
RETURN
};
ReportProgress[firstMsg];
node ← FormatMsg[msg ← msgList.first, firstMsg, FALSE, smallHeaders].node;
msgList ← msgList.rest;
firstMsg ← FALSE;
};
Report["\nWriting MsgSets to file: ", fileName];
BEGIN ENABLE
WalnutDefs.Error, IO.Error, UNWIND => printInfo.abortRef^ ← TRUE;
root: TextNode.Ref;
root ← BuildTiogaTree[SupplyMsgs, printInfo.abortRef];
IF root # NIL THEN [] ← PutGet.ToFile[fileName, root];
Report["\t ...done"];
SignalPrintDone[printInfo];
END;  -- for UNWIND
};
PrintMSTOCProc: PROC[
msgSet, server: ROPE, usePress: BOOL, copies: INT, printInfo: PrintingInfo] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msL: LIST OF ROPE;
msg: ROPE;
firstCall: BOOLTRUE;
firstMsg: BOOLTRUE;
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[firstMsg];
IF firstMsg THEN {
looks: TextLooks.Looks ← TextLooks.noLooks;
looks['b] ← TRUE;
looks['l] ← TRUE;
firstMsg ← FALSE;
node ←
PutGet.FromRope[Rope.Concat["* * * * * * * * TableOfContents from ", rootName]];
TRUSTED {
first: TiogaOps.Ref ← TiogaOps.FirstChild[LOOPHOLE[node]];
TextEdit.SetLooks[LOOPHOLE[node], LOOPHOLE[first], looks];
};
}
ELSE {
node ← FormatTOC[msg ← msL.first];
msL ← msL.rest;
};
};
FormatTOC: PROC[msg: ROPE] RETURNS[node: TextNode.Ref] = {
hasBeenRead: BOOL;
tocEntry: ROPE;
looks: TextLooks.Looks ← TextLooks.noLooks;
[hasBeenRead, tocEntry, ] ← WalnutOps.GetDisplayProps[msg];
tocEntry ← IF ~hasBeenRead AND needsQ THEN Rope.Concat["?", tocEntry]
ELSE Rope.Concat[" ", tocEntry];
node ← PutGet.FromRope[tocEntry];
looks ← TextLooks.RopeToLooks[IF hasBeenRead THEN tocDefaultLooks ELSE tocUnreadLooks];
TRUSTED {
first: TiogaOps.Ref ← TiogaOps.FirstChild[LOOPHOLE[node]];
TextEdit.SetLooks[LOOPHOLE[node], LOOPHOLE[first], looks];
};
};
rootName: ROPE ← Rope.Concat["Message Set: ", msgSet];
lastReportFromPrinter ← NIL;
BEGIN ENABLE
WalnutDefs.Error, IO.Error, UNWIND => printInfo.abortRef^ ← TRUE;
fName: ROPE;
root: TextNode.Ref;
IF ~useDefaultFile THEN fName ← IO.PutFR["///temp/%g-TOC", IO.rope[msgSet] ];
Report["Printing Message TOCs from ", rootName];
msL ← WalnutOps.MsgsInSetEnumeration[msgSet, TRUE].mL;
root ← BuildTiogaTree[SupplyTOC, printInfo.abortRef];
IF root # NIL THEN
IF usePress THEN
PressPrintRootNode[root, printInfo.abortRef, server, fName, copies]
ELSE Interpress3PrintRootNode[root, printInfo.abortRef, server, fName, copies];
SignalPrintDone[printInfo];
END;  -- for UNWIND
};
PrintML: PROC [
mL: LIST OF ROPE, name, server: ROPE, usePress: BOOL, copies: INT, printInfo: PrintingInfo] = {
ENABLE BEGIN
WalnutDefs.Error => { Failure[printInfo, explanation]; CONTINUE};
UNWIND => SignalPrintDone[printInfo];
END;
msg: ROPE;
firstMsg: BOOLTRUE;
firstCall: BOOLTRUE;
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[firstMsg];
node ← FormatMsg[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[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["///temp/", 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: TextNode.Ref = BuildTiogaTree[nodeProc: SupplyMsg, aborted: printInfo.abortRef];
IF root # NIL THEN
IF usePress THEN
PressPrintRootNode[root, printInfo.abortRef, server, fName, copies]
ELSE Interpress3PrintRootNode[root, printInfo.abortRef, server, fName, copies];
SignalPrintDone[printInfo];
END;
};
ReportProgress: PROC[first: BOOL] =
{ IF first THEN ReportRope["\t."] ELSE ReportRope["."] };
PrintReport: PROC[r: ROPE] =
BEGIN
IF r = lastReportFromPrinter THEN RETURN;
ReportRope[lastReportFromPrinter ← r];
ReportRope["\n"];
END;
SignalPrintDone: ENTRY PROC[printInfo: PrintingInfo] =
BEGIN
printInfo.done ← TRUE;
BROADCAST PrintCallReturned;
END;
Failure: ENTRY PROC[printInfo: PrintingInfo, who: ROPE] =
BEGIN
Report[who, "; printing NOT done"];
printInfo.done ← TRUE;
printInfo.allOK ← FALSE;
BROADCAST PrintCallReturned;
END;
AbortPrintProc: PUBLIC ENTRY Menus.MenuProc =
BEGIN 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 = walnut THEN
WalnutControlInternal.ChangeMenu[WalnutControlInternal.workingMenu, FALSE]
ELSE ViewerOps.SetMenu[self, blankMenu];
END;
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
BuildTiogaTree: PROC[nodeProc: NodeProc, aborted: REF BOOL] RETURNS[TextNode.Ref] = {
root, node: TextNode.Ref;
prevLast: TextNode.Ref ← NIL;
prop: REF;
style: NodeStyleOps.Ref;
IsAborted: PROC RETURNS [BOOL] = {RETURN[IF aborted = NIL THEN FALSE ELSE aborted^]};
InsertNode: PROC [root, node: TextNode.Ref, child: BOOLFALSE] = {
-- if ~child then new is sibling of x
-- else new is first child of x
IF child THEN {
IF root.child # NIL THEN { node.next ← root.child; node.last ← FALSE }
ELSE { node.next ← root; node.last ← TRUE };
root.child ← node }
ELSE { node.next ← root.next; node.last ← root.last; root.next ← node; root.last ← FALSE };
};
InsertAsLastChild: PROCEDURE [root, node, prevLast: TextNode.Ref] = {
IF prevLast=NIL OR ~prevLast.last OR prevLast.next # root THEN
prevLast ← TextNode.NarrowToTextNode[TextNode.LastChild[root]];
IF prevLast=NIL THEN InsertNode[root, node, TRUE] ELSE InsertNode[prevLast, node, FALSE];
};
build a tree with the supplied nodes, each with the right style property
root ← TextNode.NewTextNode[];
root.last ← TRUE;
UNTIL ( node ← nodeProc[] ) = NIL DO
IF IsAborted[] THEN RETURN[NIL];
InsertAsLastChild[root, node, prevLast];
prevLast ← node;
put "styleName" Style in Prefix property
style ← NodeStyleOps.Create[];
prop ← NodeProps.GetProp[node, $Prefix];
IF prop # NIL THEN
NodeProps.PutProp[node, $Prefix, Rope.Cat[
NARROW[prop, Rope.ROPE],
" \"",
Atom.GetPName[NodeStyleOps.defaultStyleName],
"\" style"]];
ENDLOOP;
IF IsAborted[] THEN RETURN[NIL];
RETURN[root];
};
PressPrintRootNode: PROC[
 root: TextNode.Ref, aborted: REF BOOL, server, fileName: ROPE, copies: INT] = {
loc: TextNode.Location ← [node: TextNode.StepForward[root], where: 0];
pageCount: INT ← 0;
marks: Atom.PropList ← NIL;
fName: ROPE = IF fileName = NIL THEN defaultPrintName ELSE fileName.Concat[".press$"];
context: Imager.Context ← ImagerPress.SimpleCreate[fName];
IsAborted: PROC RETURNS [BOOL] = {RETURN[IF aborted = NIL THEN FALSE ELSE aborted^]};
WHILE loc.node # NIL DO
page: TiogaImager.FormattedPage =
TiogaImager.FormatPage[pageCounter: pageCount, startLoc: loc, marks: marks];
ImagerPress.NewPage[context];
Imager.ScaleT[context, Imager.metersPerPoint];
TiogaImager.Render[page.box, context, [0, 0]];
TiogaImager.Destroy[page.box];
loc ← page.nextLoc;
IF IsAborted[] THEN EXIT;  -- more or less clean state here
pageCount ← pageCount + 1;
marks ← page.marks;
ENDLOOP;
ImagerPress.Close[context];
IF IsAborted[] THEN RETURN;
IF server.Length[] = 0 THEN server ← UserProfile.Token["Hardcopy.PressPrinter", "Clover"];
IF server.Equal["*"] THEN {
Report[IO.PutFR["\nPress file (%g) written but not sent", IO.rope[fName] ]];
RETURN
};
Report[
"\nForking a process to watch press printing - see WalnutPrinting typescript viewer"];
TRUSTED { Process.Detach[FORK PressPrinting[server, copies, fName]] };
};
Interpress3PrintRootNode: PROC[
 root: TextNode.Ref, aborted: REF BOOL, server, fileName: ROPE, copies: INT] = {
header: ROPE = "Interpress/Xerox/3.0 ";
fName: ROPE =
IF fileName = NIL THEN ipDefaultPrintName ELSE fileName.Concat[".interpress"];
master: ImagerInterpress.Ref = ImagerInterpress.Create[fName, header];
pageCount: INT ← 0;
marks: Atom.PropList ← NIL;
loc: TextNode.Location ← [node: TextNode.StepForward[root], where: 0];
IsAborted: PROC RETURNS [BOOL] = {RETURN[IF aborted = NIL THEN FALSE ELSE aborted^]};
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];
IF IsAborted[] THEN RETURN;
IF server.Length[] = 0 THEN
 server ← UserProfile.Token["Walnut.InterpressPrinter", "Quoth"];
IF server.Equal["*"] THEN {
Report[IO.PutFR["\nInterPress file (%g) written but not sent", IO.rope[fName] ]];
RETURN
};
Report[
"\nForking a process to watch interpress printing - see WalnutPrinting typescript viewer"];
TRUSTED { Process.Detach[FORK PeachPrinting[server, copies, fName]] };
};
walnutPrintTS: ROPE = "WalnutPrinting";
PressPrinting: PROC[server: ROPE, copies: INT, fName: ROPE] = {
v: Viewer;
out: STREAM;
prgR: ROPE;
openFile: FS.OpenFile;
deleteAfterPrint: BOOL = UserProfile.Boolean["Walnut.DeleteFileAfterPrint", FALSE];
ProgressProc: PressPrinter.ProgressProc = {
this: ROPE = handle.CurrentStateMessage[];
IF prgR # this THEN {
out.PutRope[prgR ← this];
out.PutChar['\n];
};
};
[out, v] ← PrintingViewer["Press"];
IF deleteAfterPrint THEN openFile ← FS.Open[fName];  -- make sure doesn't go away
[] ← PressPrinter.SendPressFile[
fileName: fName,
server: server,
progressProc: ProgressProc,
copies: copies,
userName: UserCredentials.Get[].name
];
IF deleteAfterPrint THEN {
fullFName: ROPE = FS.GetName[openFile].fullFName;
FS.Close[openFile];
FS.Delete[fullFName ! FS.Error => {
out.PutRope[error.explanation];
out.PutChar['\n];
GOTO cant } ];
out.PutF[" Deleted press file %g\n", IO.rope[fName] ];
EXITS
cant => NULL;
};
v.inhibitDestroy ← FALSE;
};
PeachPrinting: PROC[server: ROPE, copies: INT, fName: ROPE] = {
out: STREAM;
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 PeachPrint.PupAborted => GOTO abt;
[out, v] ← PrintingViewer["Interpress"];
PeachPrint.DoPeachPrintCommand[
server: server,
file: fName,
log: out,
copies: copies
];
IF deleteAfterPrint THEN {
fullFName: ROPE = FS.GetName[openFile].fullFName;
FS.Close[openFile];
FS.Delete[fullFName ! FS.Error => {
out.PutRope[error.explanation];
out.PutChar['\n];
GOTO cant } ];
out.PutF[" Deleted interpress file %g\n", IO.rope[fName] ];
EXITS
cant => NULL;
};
EXITS
abt => out.PutRope["\nPupAborted from PeachPrint - quitting\n"];
END;
v.inhibitDestroy ← FALSE;
};
PrintingViewer: PROC[which: 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 at %g\n", IO.rope[which], IO.time[]];
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
FirstNode: PROC[rootName: ROPE] RETURNS[node: TextNode.Ref] =
BEGIN
root: TiogaFileOps.Ref ← TiogaFileOps.CreateRoot[];
mark: ROPE = "outsideFooter";  -- kludge
prefix: ROPE = "(cedar) style (firstHeadersAfterPage) (0) .cvx .def";  -- magic
TRUSTED
{ TiogaOps.PutProp[LOOPHOLE[root], $Mark, mark];
TiogaOps.PutProp[LOOPHOLE[root], $Prefix, prefix];
};
TiogaFileOps.SetContents[root, rootName];
TRUSTED {node ← LOOPHOLE[root, TextNode.Ref]};
END;
FormatMsg: PROC[msg: ROPE, firstMsg, newPage, smallHeaders: BOOL]
RETURNS[node: TextNode.Ref] = {
contents: ViewerTools.TiogaContents ← WalnutOps.GetMsg[msg].contents;
endHeadersPos: INT ← Rope.Find[contents.contents, "\n\n"];
tocAndSubject: ROPE;
[ , tocAndSubject, ] ← WalnutOps.GetDisplayProps[msg];
node ← PutGet.FromRope[Rope.Concat[contents.contents, contents.formatting]];
IF smallHeaders THEN IF endHeadersPos > 0 THEN
{ lastLoc: INT;
first: TiogaOps.Ref;
TRUSTED {first ← TiogaOps.FirstChild[LOOPHOLE[node]]};
lastLoc ← TiogaOps.LastLocWithin[first].where;
IF lastLoc > endHeadersPos THEN  -- no formatting already
{ looks: TextLooks.Looks ← TextLooks.noLooks;
looks['s] ← TRUE;
looks['p] ← TRUE;
TRUSTED {TextEdit.SetLooks[LOOPHOLE[node],
LOOPHOLE[first], looks, 0, 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["\n\n", tocAndSubject];
TRUSTED
{ TiogaFileOps.SetContents[LOOPHOLE[node], tocAndSubject];
TiogaFileOps.SetFormat[LOOPHOLE[node], IF newPage THEN "head" ELSE "head2"]
};
};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
start code
need an immediate menu button here, can't wait on walnutQueue
Menus.AppendMenuEntry[printingMenu, Menus.CreateEntry["AbortPrint", AbortPrintProc]];
END.