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
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: BOOL ← TRUE];
PrintingInfo: TYPE = REF PrintingInfoObject;
lastReportFromPrinter: ROPE ← NIL;
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[BOOL ← FALSE];
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[BOOL ← FALSE];
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[BOOL ← FALSE];
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[BOOL ← FALSE];
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[BOOL ← FALSE];
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[BOOL ← FALSE];
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: ROPE ← NIL, usePress: BOOL ← TRUE, 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[BOOL ← FALSE];
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[BOOL ← FALSE];
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: 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[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 MsgSetButton ← msgSetList;
msgList: LIST OF ROPE;
msg: ROPE;
firstCall: BOOL ← TRUE;
firstMsg: BOOL ← TRUE;
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: 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[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: 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[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:
BOOL ←
FALSE] = {
-- 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] ];
};
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
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.