-- file: IntDisplayCom.Mesa
-- last edited by Horning, March 2, 1978 10:58 PM
-- last edited by Kierr, March 8, 1978 4:51 PM
-- last edited by Brotz, March 23, 1981 4:01 PM
-- last edited by Schroeder, Wednesday Nov. 5, 1980 3:14 pm PST.
-- last edited by Levin, January 8, 1981 10:19 AM.

DIRECTORY
crD: FROM "CoreDefs",
displayCommon,
dsD: FROM "DisplayDefs",
exD: FROM "ExceptionDefs",
inD: FROM "InteractorDefs",
intCommon,
opD: FROM "OperationsDefs",
ovD: FROM "OverviewDefs",
String,
tsD: FROM "TOCSelectionDefs",
vmD: FROM "VirtualMgrDefs";

IntDisplayCom: PROGRAM
IMPORTS crD, disC: displayCommon, dsD, exD, inD, intC: intCommon, opD, String,
tsD, vmD
EXPORTS inD =

BEGIN
OPEN inD;

-- Purpose: handles user interactions including the display, keyboard and mouse. This
-- division gathers together commands and their arguments and is responsible for the
-- display of all error messages.


DeleteCommand: PUBLIC CommandProcedure =
-- Sets deleted field for each selected TOCEntry. Updates the display to reflect the changes.
BEGIN
ModifyTOCOperation[delete];
DoDisplayAfterDelete[];
END; -- of DeleteCommand --


DoDisplayAfterDelete: PRIVATE PROCEDURE =
BEGIN
index: vmD.TOCIndex ← intC.displayMessageIndex;
IF intC.displayAfterDelete AND intC.haveMailFile AND ~tsD.TOCSelectionEmpty[]
AND index = tsD.FirstSelectedEntry[] AND index = tsD.LastSelectedEntry[]
AND index + 1 < vmD.GetFirstFreeTOCIndex[] THEN
BEGIN
fp: vmD.TOCFixedPart;
vmD.GetTOCFixedPart[index + 1, @fp];
IF ~fp.seen THEN
BEGIN
exception: exD.Exception ← DisplayMessageOperation[];
SELECT exception FROM
exD.nil, exD.noUndeletedMessages => NULL;
ENDCASE => exD.DisplayException[exception];
END;
END;
END; -- of DoDisplayAfterDelete --


ModifyTOCOperation: PRIVATE PROCEDURE [action: {delete, undelete, move}] =
-- Sets fields for each selected TOCEntry. Updates the display to reflect the changes.
BEGIN
toc: TOCTextNbrPtr = intC.tocTextNbr;
line: LinePtr ← toc.lines;
topLineNumber: TOCLineNumber ← line.linePair.lineNumber;
index: vmD.TOCIndex;
fp: vmD.TOCFixedPart;

IF ~intC.haveMailFile THEN {exD.DisplayException[exD.noCurrentFile]; RETURN};
IF tsD.TOCSelectionEmpty[] THEN {exD.DisplayException[exD.noSelectedEntries]; RETURN};

FOR index ← tsD.FirstSelectedEntry[], tsD.NextSelectedEntry[index] UNTIL index = 0 DO
vmD.GetTOCFixedPart[index, @fp];
IF action = move AND ~ fp.deleted THEN fp.mark ← ’m;
fp.deleted ← (action = delete OR action = move);
vmD.PutTOCFixedPart[index, @fp];
ENDLOOP;
index ← line.linePair.index;
IF tsD.IsSelected[index] THEN
-- TOC entry at top of screen may be only partially visible
[line, ] ← DisplayTOCEntry
[tnp: toc, index: index, suppressed: topLineNumber - 1, firstLine: line];
UNTIL (index ← tsD.NextSelectedEntry[index]) = 0
OR (line ← MapTOCIndexToTOCLine[index, toc]) = NIL DO
[ , ] ← DisplayTOCEntry[toc, index, 0, line];
ENDLOOP;
END; -- of ModifyTOCOperation --


UndeleteCommand: PUBLIC CommandProcedure =
-- Clears deleted field for each selected TOCEntry. Updates the display to reflect the
-- changes.
BEGIN
ModifyTOCOperation[undelete];
END; -- of UndeleteCommand --


DisplayMessageCommand: PUBLIC CommandProcedure =
-- Clears DM text neighborhood. Sets TOC selection to the current displayed message if it
-- was already selected, otherwise the first selected TOCEntry. If the current display
-- message index equals is this selected message, then displays and selects the next
-- undeleted message, otherwise displays the selected message. Virtualizes the selected
-- message and refreshes the DM text Nbr.
BEGIN
exception: exD.Exception ← DisplayMessageOperation[];
IF exception # exD.nil THEN exD.DisplayException[exception];
END; -- of DisplayMessageCommand --


DisplayMessageOperation: PROCEDURE RETURNS [exception: exD.Exception] =
-- Clears DM text neighborhood. Sets TOC selection to the current displayed message if it
-- was already selected, otherwise the first selected TOCEntry. If the current display
-- message index equals is this selected message, then displays and selects the next
-- undeleted message, otherwise displays the selected message. Virtualizes the selected
-- message and refreshes the DM text Nbr.
BEGIN
fp: vmD.TOCFixedPart;
selectedIndex: vmD.TOCIndex;
dm: MessageTextNbrPtr = intC.dmTextNbr;
toc: TOCTextNbrPtr = intC.tocTextNbr;
exception ← exD.nil;

IF ~intC.haveMailFile THEN RETURN[exD.noCurrentFile];
IF tsD.TOCSelectionEmpty[] THEN RETURN[exD.noSelectedEntries];
selectedIndex ← intC.displayMessageIndex;
BEGIN -- for EXITS --
SELECT TRUE FROM
(~dm.haveMessage OR ~tsD.IsSelected[selectedIndex]) =>
BEGIN
selectedIndex ← tsD.FirstSelectedEntry[];
MakeTOCIndexVisible[selectedIndex];
END;
(tsD.FirstSelectedEntry[] # tsD.LastSelectedEntry[]) =>
BEGIN -- currently viewing one of a series of selected entries.
originalSelectedIndex: vmD.TOCIndex ← selectedIndex;
DO
selectedIndex ← IF selectedIndex = tsD.LastSelectedEntry[]
THEN tsD.FirstSelectedEntry[] ELSE tsD.NextSelectedEntry[selectedIndex];
IF selectedIndex = originalSelectedIndex THEN
BEGIN
selectedIndex ← tsD.FirstSelectedEntry[];
GO TO SelectNextUndeletedEntry;
END;
vmD.GetTOCFixedPart[selectedIndex, @fp];
IF ~fp.deleted THEN EXIT;
ENDLOOP;
MakeTOCIndexVisible[selectedIndex];
END
ENDCASE => GO TO SelectNextUndeletedEntry;
EXITS
SelectNextUndeletedEntry =>
BEGIN
DO
nextMessageExists, visible, postVisible: BOOLEAN;
initialY, postSelectionY: ScreenYCoord;
[initialY, visible] ← MapTOCIndexToTopY[selectedIndex, toc];
[nextMessageExists, selectedIndex] ← NextTOCEntry[toc, selectedIndex];
IF ~nextMessageExists THEN RETURN[exD.noUndeletedMessages];
MakeTOCIndexVisible[selectedIndex];
[postSelectionY, postVisible] ← MapTOCIndexToTopY[selectedIndex, toc];
IF visible AND postVisible AND toc.firstLineOffScreen.state # empty THEN
IF initialY < postSelectionY THEN
ScrollUpTOC[toc.topY + postSelectionY - initialY, toc]
ELSE IF initialY > postSelectionY THEN
ScrollDownTOC[toc.topY + initialY - postSelectionY, toc];
vmD.GetTOCFixedPart[selectedIndex, @fp];
IF ~fp.deleted THEN EXIT;
ENDLOOP;
tsD.DeconsiderAll[toc];
tsD.SetTOCSelection[selectedIndex];
Consider[selectedIndex, selectedIndex, toc];
END;
END; -- of EXITS --

UpdateTOCThumbLine[];
IF vmD.VirtualizeMessage[selectedIndex, LOOPHOLE[dm.message]] # ovD.ok THEN
{dm.haveMessage ← FALSE; RETURN[exD.cantDisplayMessage]};
dm.haveMessage ← TRUE;
intC.displayMessageIndex ← selectedIndex;
dsD.ClearRectangle[leftMargin, rightMargin, dm.topY, dm.bottomY];
DisplayDMTail[dm, dm.lines, 0];
vmD.GetTOCFixedPart[selectedIndex, @fp];
IF ~fp.seen THEN
BEGIN
line: LinePtr;
fp.seen ← TRUE;
vmD.PutTOCFixedPart[selectedIndex, @fp];
line ← MapTOCIndexToTOCLine[selectedIndex, toc];
IF line # NIL THEN
BEGIN
dsD.ClearRectangle[markLeftX, numberLeftX, line.y, line.y + dsD.lineHeight];
[] ← dsD.PutCharInBitMap[fp.mark, markLeftX, line.y, plainFace];
END;
END;
END; -- of DisplayMessageOperation --


MoveMessageToFileCommand: PUBLIC CommandProcedure =
-- Calls AppendMailToFileOperation for all selected messages in the current mail file to be
-- appended to the file whose name appears in the Move to brackets. If the operation is
-- successful, then the messages are Deleted.
BEGIN
appendFileHandle: crD.UFileHandle;
appendFileName: crD.UFilename;
fName: STRING = [75];
i: CARDINAL;
returnCode: ovD.ErrorCode;
fileCreated: BOOLEAN ← FALSE;
bracketsText: STRING = intC.moveToBracketsHouse.text;

IF ~confirmed AND
~ConfirmBrackets[hp: intC.moveToBracketsHouse, fileExtension: ".mail."L] THEN RETURN;
IF ~intC.haveMailFile THEN {exD.DisplayException[exD.noCurrentFile]; RETURN};
IF tsD.TOCSelectionEmpty[] THEN {exD.DisplayException[exD.noSelectedEntries]; RETURN};

-- first check for extension
String.AppendString[fName, bracketsText];
appendFileName ← fName;
IF fName.length > 0 THEN
FOR i IN [0 .. fName.length) DO
IF fName[i] = ’. THEN EXIT;
REPEAT
FINISHED => String.AppendString[fName, ".mail"L];
ENDLOOP;

-- Now check for new file:
[returnCode, appendFileHandle] ← crD.OpenFile[intC.user, appendFileName,read];
[] ← crD.CloseFile[appendFileHandle];
SELECT returnCode FROM
ovD.fileNotFound =>
BEGIN
exD.DisplayException[exD.newFile];
IF ~ inD.Confirm[2] THEN RETURN;
fileCreated ← TRUE;
END;
ovD.fileInUse => {exD.DisplayException[exD.cantMoveToFileInUse]; RETURN};
ENDCASE;

returnCode ← opD.AppendMailToFileOperation[appendFileName];
SELECT returnCode FROM
ovD.ok => {ModifyTOCOperation[move]; DoDisplayAfterDelete[]};
ovD.noMessagesMoved =>
BEGIN
IF fileCreated THEN
BEGIN
[returnCode, appendFileHandle] ← crD.OpenFile[intC.user, appendFileName, read];
IF returnCode = ovD.ok THEN [] ← crD.DeleteFile[appendFileHandle];
END;
exD.DisplayException[exD.noMessagesMoved];
END;
ovD.fileTooBig, ovD.diskFull => exD.DisplayException[exD.moveWouldOverfill];
ovD.illegalFilename => exD.DisplayException[exD.noMoveIllegalName];
ENDCASE => exD.DisplayException[exD.diskErrorTargetDamage];
END; -- of MoveMessageToFileCommand --


END. -- of IntDisplayCom --