-- HCellArrayImpl.mesa
-- Last Edited by: Sturgis, October 4, 1984 10:02:40 am PDT
-- Swinehart, August 11, 1985 10:16:19 pm PDT
DIRECTORY
Dependencies USING[Action, DeactivateAction, DefineAction, MarkActionDirty],
HCells USING[ArrayMode, CreateHCell, DisplayMode, DoColSum, DoItemArrayColSum, DoRowSum, DoRowTotal, ForceHCellSelection, GetHCellText, HCell, IdMode, Justification, RowColSumMode, SetHCellParameters, ValueMode],
IO USING[BreakProc, CharClass, Close, GetChar, GetInt, GetTokenRope, int, Put, PutChar, PutFR, PutRope, RIS, rope, RopeFromROS, ROS, SkipWhitespace, STREAM],
NewCalcGlobal USING[Displayer, Document],
Rope USING[Concat, Equal, Fetch, FromChar, Index, Length, ROPE, Substr],
StructureNodes USING[Action, AddColumnAt, AddRowAt, ColHandle, CreateDisplayArray, DACell, DeleteColumnAt, DeleteRowAt, DisplayArray, GetColInfoAt, GetColNumber, GetContextDA, GetElementAt, GetRowInfoAt, GetRowNumber, RowHandle, PrePaintPass, SetColInfoAt, SetElementAt, SetRowInfoAt, StructureNode, StructureNodeBody, StructureNodeProcs],
ViewerClasses USING[Viewer];
HCellArrayImpl: PROGRAM IMPORTS Dependencies, HCells, IO, Rope, StructureNodes EXPORTS HCells =
BEGIN
HCellArray: TYPE = REF HCellArrayBody;
HCellArrayBody: PUBLIC TYPE = RECORD[
da: StructureNodes.DisplayArray, -- this and next item refer to the associated Display Array
daSn: StructureNodes.StructureNode,
hcaSn: StructureNodes.StructureNode,
nRows, nColumns: CARDINAL,
document: NewCalcGlobal.Document,
displayer: NewCalcGlobal.Displayer,
vParent: ViewerClasses.Viewer,
pageName: Rope.ROPE,
zvt: Rope.ROPE ← NIL,
arrayIdText: Rope.ROPE ← NIL,
mode: HCells.ArrayMode ← individual,
itemArrayRowHandle: StructureNodes.RowHandle ← NIL, -- if this is a groupItem array, then this is the handle of the corresponding row in the groupSummary array
summaryArray: HCellArray ← NIL, -- if this is a groupItem array, then this is the groupSummary array
nItemArrays: CARDINAL ← 0, -- if this is a groupSummary array, then this is the number of groupItem arrays
controlVisible: BOOLEAN ← TRUE];
RowControl: TYPE = {control, text, addItem, sum};
ColControl: TYPE = {control, text, addZero, addItem, subItem, leftValTimesExp, leftVal, sum, total, idGetsT, idGetsS, idGetsLv};
-- HCell Array Group Code
CreateSummaryHCellArray: PUBLIC PROCEDURE[document: NewCalcGlobal.Document, displayer: NewCalcGlobal.Displayer, vParent: ViewerClasses.Viewer, pageName: Rope.ROPE] RETURNS[StructureNodes.StructureNode] =
BEGIN
s: IO.STREAM ← IO.RIS["3 {foo} {0.00} 3 6 abd abdddh {} {} {} {} {} {} {} {textCol} {addCol} {addCol} {addCol} {sumCol} {} {sumRow} {} {} {} {}"];
hcaSn: StructureNodes.StructureNode ← LoadHCellArray[document, displayer, vParent, pageName, NIL, s, 0, groupSummary];
hca: HCellArray ← NARROW[hcaSn.ref];
s.Close[];
hca.mode ← groupSummary;
hca.itemArrayRowHandle ← GetRowInfo[hca, 2].rowHandle; -- appending an item array to the summary array will insert after this row.
hca.summaryArray ← hca;
RETURN[hcaSn];
END;
CreateHCellArrayModeledAfter: PUBLIC PROCEDURE[modelHcaSn: StructureNodes.StructureNode, document: NewCalcGlobal.Document, displayer: NewCalcGlobal.Displayer, vParent: ViewerClasses.Viewer, pageName: Rope.ROPE] RETURNS[StructureNodes.StructureNode] =
BEGIN
modelHca: HCellArray ← NARROW[modelHcaSn.ref];
modelOutS: IO.STREAM;
modelRope: Rope.ROPE;
modelInS: IO.STREAM;
newHcaSn: StructureNodes.StructureNode;
newHca: HCellArray;
modelOutS ← IO.ROS[];
SaveHCellArray[modelHcaSn, modelOutS];
modelRope ← IO.RopeFromROS[modelOutS];
modelInS ← IO.RIS[modelRope];
newHcaSn ← LoadHCellArray[document, displayer, vParent, pageName, NIL, modelInS, 0, modelHca.mode];
newHca ← NARROW[newHcaSn.ref];
modelInS.Close[];
newHca.mode ← individual;
RETURN[newHcaSn];
END;
AppendHCellArrayInGroup: PUBLIC PROCEDURE[newItemHcaSn: StructureNodes.StructureNode, afterHcaSn: StructureNodes.StructureNode] =
BEGIN
newHca: HCellArray ← NARROW[newItemHcaSn.ref];
afterHca: HCellArray ← NARROW[afterHcaSn.ref];
summaryArray: HCellArray;
newRowNumber: CARDINAL;
IF afterHca.mode # groupSummary AND afterHca.mode # groupItem THEN ERROR;
summaryArray ← afterHca.summaryArray; -- note: summary array should point to self
newRowNumber ← StructureNodes.GetRowNumber[afterHca.itemArrayRowHandle]+1; -- note: summary array should point to row immediately preceding first item row
[] ← BasicInstallRowAt[summaryArray, newRowNumber, addItem];
ConnectHCellArrayInGroup[newHca.hcaSn, summaryArray.hcaSn, newRowNumber];
END;
InsertHCellArrayInGroup: PUBLIC PROCEDURE[newItemHcaSn: StructureNodes.StructureNode, beforeHcaSn: StructureNodes.StructureNode] =
BEGIN
newHca: HCellArray ← NARROW[newItemHcaSn.ref];
beforeHca: HCellArray ← NARROW[beforeHcaSn.ref];
summaryArray: HCellArray;
newRowNumber: CARDINAL;
IF beforeHca.mode # groupItem THEN ERROR;
summaryArray ← beforeHca.summaryArray;
newRowNumber ← StructureNodes.GetRowNumber[beforeHca.itemArrayRowHandle];
[] ← BasicInstallRowAt[summaryArray, newRowNumber, addItem];
ConnectHCellArrayInGroup[newHca.hcaSn, summaryArray.hcaSn, newRowNumber];
END;
ConnectHCellArrayInGroup: PUBLIC PROCEDURE[newItemHcaSn, summaryHcaSn: StructureNodes.StructureNode, atRowNumber: CARDINAL] =
BEGIN
newHca: HCellArray ← NARROW[newItemHcaSn.ref];
summaryArray: HCellArray ← NARROW[summaryHcaSn.ref];
-- assumes the row exists in the summary array, either it was just made, or during loading all the appropriate rows were loaded.
IF newHca.mode # individual THEN ERROR;
newHca.mode ← groupItem;
NoteItemArrayCorrespondingToRow[summaryArray, atRowNumber, newHca];
-- now get all of the appropriate new cells tied together
SetRowCellParameters[summaryArray, atRowNumber, NIL];
FOR J: CARDINAL IN [1..newHca.nRows] DO
SetRowCellParameters[newHca, J, NIL]; -- no text in the row for now, need it however
ENDLOOP;
-- finally
summaryArray.nItemArrays ← summaryArray.nItemArrays + 1;
END;
GetSummaryArray: PUBLIC PROCEDURE[itemHcaSn: StructureNodes.StructureNode] RETURNS[summaryHcaSn: StructureNodes.StructureNode, atRow: CARDINAL] =
BEGIN
hca: HCellArray ← NARROW[itemHcaSn.ref];
IF hca.mode # groupItem THEN ERROR;
RETURN[hca.summaryArray.hcaSn, StructureNodes.GetRowNumber[hca.itemArrayRowHandle]];
END;
UnusedDeleteHCellArrayFromGroup: --PUBLIC-- PROCEDURE[hcaSn: StructureNodes.StructureNode] =
BEGIN
hca: HCellArray ← NARROW[hcaSn.ref];
SELECT hca.mode FROM
groupItem =>
BEGIN
summaryArray: HCellArray ← hca.summaryArray;
rowNumber: CARDINAL ← StructureNodes.GetRowNumber[hca.itemArrayRowHandle];
AbandonHCellArray[hcaSn];
RemoveRowAt[summaryArray.hcaSn, summaryArray, rowNumber];
summaryArray.nItemArrays ← summaryArray.nItemArrays - 1;
END;
groupSummary =>
BEGIN
IF hca.nItemArrays # 0 THEN ERROR;
AbandonHCellArray[hcaSn];
END;
ENDCASE => ERROR;
END;
-- these are the primary creation routines
CreateHCellArray: PUBLIC PROCEDURE[document: NewCalcGlobal.Document, displayer: NewCalcGlobal.Displayer, vParent: ViewerClasses.Viewer, pageName: Rope.ROPE, arrayName: Rope.ROPE] RETURNS[StructureNodes.StructureNode] =
BEGIN
s: IO.STREAM ← IO.RIS["3 {foo} {0.00} 5 6 abccd abdddh {} {} {} {} {} {} {} {textCol} {addCol} {addCol} {addCol} {sumCol} {} {addRow} {25} {36} {45} {} {} {addRow} {44} {87} {23} {} {} {sumRow} {} {} {} {}"];
hcaSn: StructureNodes.StructureNode ← LoadHCellArray[document, displayer, vParent, pageName, arrayName, s, 0, individual];
hca: HCellArray ← NARROW[hcaSn.ref];
s.Close[];
RETURN[hcaSn];
END;
LoadHCellArray: PUBLIC PROCEDURE[document: NewCalcGlobal.Document, displayer: NewCalcGlobal.Displayer, vParent: ViewerClasses.Viewer, pageName: Rope.ROPE, arrayName: Rope.ROPE, from: IO.STREAM, version: CARDINAL, mode: HCells.ArrayMode] RETURNS[StructureNodes.StructureNode] =
BEGIN
hca: HCellArray ← NEW[HCellArrayBody ← [NIL, NIL, NIL, 0, 0, document, displayer, vParent, pageName]];
hcaSn: StructureNodes.StructureNode ← NEW[StructureNodes.StructureNodeBody ← [hca, HCellSNProcs]];
nRows, nColumns: CARDINAL;
HCAVersion: INT;
hca.hcaSn ← hcaSn;
[hca.daSn, hca.da] ← StructureNodes.CreateDisplayArray[hcaSn];
HCAVersion ← IO.GetInt[from];
IF HCAVersion # INT[3] AND HCAVersion # INT[4] THEN ERROR;
hca.arrayIdText ← ReadCellText[from];
IF arrayName # NIL THEN hca.arrayIdText ← arrayName;
hca.zvt ← ReadCellText[from];
IF HCAVersion = 4 THEN
BEGIN
[] ← IO.SkipWhitespace[from];
hca.controlVisible ← DecodeControlVisibilityChar[from.GetChar[]]
END;
hca.mode ← mode;
nRows ← IO.GetInt[from];
nColumns ← IO.GetInt[from];
[] ← IO.SkipWhitespace[from];
FOR J: CARDINAL IN [1..nRows] DO
-- get row control info
char: CHARACTER ← from.GetChar[];
con: RowControl ← DecodeRowControlChar[char];
[] ← BasicInstallRowAt[hca, J, con];
ENDLOOP;
[] ← IO.SkipWhitespace[from];
FOR I: CARDINAL IN [1..nColumns] DO
-- get column control info
char: CHARACTER ← from.GetChar[];
con: ColControl ← DecodeColControlChar[char];
[] ← BasicInstallColumnAt[hca, I, con];
ENDLOOP;
FOR J: CARDINAL IN [1..nRows] DO
SetRowCellParameters[hca, J, from];
ENDLOOP;
RETURN[hcaSn]
END;
-- these routines are called through the containing structure node
HCellSNProcs: REF StructureNodes.StructureNodeProcs ← NEW[StructureNodes.StructureNodeProcs ← [
CheckHCellArrayForDirtyData,
PreShowHCellArray,
ShowHCellArrayLine,
PrePrePaintHCellArray,
PrePaintHCellArray,
PaintHCellArray,
UnPaintHCellArray,
NoteEnclosingCellHCellArray,
NoteCoordinatesHCellArray,
SaveHCellArray,
ActHCellArray,
SubstituteInHCellArray,
AbandonHCellArray,
VerifyHCellArray
]];
CheckHCellArrayForDirtyData: PROCEDURE[node: StructureNodes.StructureNode] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
hca.daSn.procs.CheckForDirtyData[hca.daSn];
END;
PreShowHCellArray: PROCEDURE[node: StructureNodes.StructureNode] RETURNS[lead, height: INTEGER, space, L, A, B, R, W: INTEGER] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
[lead, height, space, L, A, B, R, W] ← hca.daSn.procs.PreShow[hca.daSn];
END;
ShowHCellArrayLine: PROCEDURE[node: StructureNodes.StructureNode, L, R, W: INTEGER, lineX: INTEGER, to: IO.STREAM] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
hca.daSn.procs.ShowLine[hca.daSn, L, R, W, lineX, to];
END;
PrePrePaintHCellArray: PROCEDURE[node: StructureNodes.StructureNode] RETURNS[lead, height: INTEGER, space, L, A, B, R, W: INTEGER] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
[lead, height, space, L, A, B, R, W] ← hca.daSn.procs.PrePrePaint[hca.daSn];
END;
PrePaintHCellArray: PROCEDURE[node: StructureNodes.StructureNode, y, x, L, R, W: INTEGER, pass: StructureNodes.PrePaintPass] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
hca.daSn.procs.PrePaint[hca.daSn, y, x, L, R, W, pass];
END;
PaintHCellArray: PROCEDURE[node: StructureNodes.StructureNode, dirtyOnly: BOOLEAN] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
hca.daSn.procs.Paint[hca.daSn, dirtyOnly];
END;
UnPaintHCellArray: PROCEDURE[node: StructureNodes.StructureNode] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
hca.daSn.procs.UnPaint[hca.daSn];
END;
NoteEnclosingCellHCellArray: PROCEDURE[node: StructureNodes.StructureNode, dac: StructureNodes.DACell] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
hca.daSn.procs.NoteEnclosingCell[hca.daSn, dac];
END;
NoteCoordinatesHCellArray: PROCEDURE[node: StructureNodes.StructureNode, da: StructureNodes.DisplayArray, I, J: CARDINAL] =
BEGIN
hca: HCellArray ← NARROW[node.ref];
hca.daSn.procs.NoteCoordinates[hca.daSn, da, I, J];
END;
SaveHCellArray: PROCEDURE[info: StructureNodes.StructureNode, to: IO.STREAM] =
BEGIN
hca: HCellArray ← NARROW[info.ref];
to.PutChar[' ];
to.Put[IO.int[4]]; -- version
to.PutChar[' ];
WriteCellText[to, hca.arrayIdText];
to.PutChar[' ];
WriteCellText[to, hca.zvt];
to.PutChar[' ];
to.PutChar[EncodeControlVisibility[hca.controlVisible]];
to.PutChar[' ];
to.Put[IO.int[hca.nRows]]; to.PutChar[' ];
to.Put[IO.int[hca.nColumns]]; to.PutChar[' ];
FOR J: CARDINAL IN [1..hca.nRows] DO
rowControl: RowControl ← GetRowInfo[hca, J].rowControl;
to.PutChar[EncodeRowControl[rowControl]];
ENDLOOP;
to.PutChar[' ];
FOR I: CARDINAL IN [1..hca.nColumns] DO
colControl: ColControl ← GetColumnInfo[hca, I].colControl;
to.PutChar[EncodeColControl[colControl]];
ENDLOOP;
to.PutChar[' ];
FOR J: CARDINAL IN [1..hca.nRows] DO
FOR I: CARDINAL IN [1..hca.nColumns] DO
cell: HCells.HCell ← GetCell[hca, I, J];
WriteCellText[to, HCells.GetHCellText[cell]];
to.PutChar[' ];
ENDLOOP;
ENDLOOP;
END;
ActHCellArray: PROCEDURE[info: StructureNodes.StructureNode, I, J: CARDINAL, action: StructureNodes.Action, p1, p2: REF ANY] RETURNS[StructureNodes.StructureNode, CARDINAL, CARDINAL] =
BEGIN
n: StructureNodes.StructureNode; newI, newJ: CARDINAL;
[n, newI, newJ] ← LocalActHCellArray[info, I, J, action, p1, p2, FALSE];
RETURN[n, newI, newJ];
END;
LocalActHCellArray: PROCEDURE[info: StructureNodes.StructureNode, I, J: CARDINAL, action: StructureNodes.Action, p1, p2: REF ANY, allowActionsOnGroupArray: BOOLEAN] RETURNS[StructureNodes.StructureNode, CARDINAL, CARDINAL] =
BEGIN
hca: HCellArray ← NARROW[info.ref];
BEGIN
IF NOT allowActionsOnGroupArray AND hca.mode = groupItem THEN
SELECT action FROM
InsertColumn, AppendColumn, DeleteColumn, SetColControlToControl, SetColControlToText, SetColControlToAddZero, SetColControlToAddZero, SetColControlToAddItem, SetColControlToSubItem, SetColControlToLeftValTimesExp, SetColControlToLeftVal, SetColControlToSum, SetColControlToTotal, SetColControlToIdGetsTotal, SetColControlToIdGetsSum, SetColControlToIdGetsLv => GOTO skipAction;
ENDCASE => NULL;
IF NOT allowActionsOnGroupArray AND hca.mode = groupSummary THEN
SELECT action FROM
InsertRow, AppendRow, DeleteRow, SetRowControlToControl, SetRowControlToText, SetRowControlToAddItem, SetRowControlToSum => GOTO skipAction;
ENDCASE => NULL;
SELECT action FROM
InsertColumn => {InstallColumnAt[info, hca, I, I]; [] ← MoveSelectionTo[hca, I+1, J]};
AppendColumn => {InstallColumnAt[info, hca, I+1, I]; [] ← MoveSelectionTo[hca, I, J]};
DeleteColumn => {RemoveColumnAt[info, hca, I]; IF I <= hca.nColumns THEN [] ← MoveSelectionTo[hca, I, J]};
InsertRow => {InstallRowAt[info, hca, J, J]; [] ← MoveSelectionTo[hca, I, J+1]};
AppendRow => {InstallRowAt[info, hca, J+1, J]; [] ← MoveSelectionTo[hca, I, J]};
DeleteRow => {RemoveRowAt[info, hca, J]; IF J <= hca.nRows THEN [] ← MoveSelectionTo[hca, I, J]};
SetRowControlToControl => IF hca.controlVisible THEN SetRowControlTo[hca, J, control];
SetRowControlToText => IF hca.controlVisible THEN SetRowControlTo[hca, J, text];
SetRowControlToAddItem => IF hca.controlVisible THEN SetRowControlTo[hca, J, addItem];
SetRowControlToSum => IF hca.controlVisible THEN SetRowControlTo[hca, J, sum];
SetColControlToControl => IF hca.controlVisible THEN SetColControlTo[hca, I, control];
SetColControlToText => IF hca.controlVisible THEN SetColControlTo[hca, I, text];
SetColControlToAddZero => IF hca.controlVisible THEN SetColControlTo[hca, I, addZero];
SetColControlToAddItem => IF hca.controlVisible THEN SetColControlTo[hca, I, addItem];
SetColControlToSubItem => IF hca.controlVisible THEN SetColControlTo[hca, I, subItem];
SetColControlToLeftValTimesExp => IF hca.controlVisible THEN SetColControlTo[hca, I, leftValTimesExp];
SetColControlToLeftVal => IF hca.controlVisible THEN SetColControlTo[hca, I, leftVal];
SetColControlToSum => IF hca.controlVisible THEN SetColControlTo[hca, I, sum];
SetColControlToTotal=> IF hca.controlVisible THEN SetColControlTo[hca, I, total];
SetColControlToIdGetsTotal => IF hca.controlVisible THEN SetColControlTo[hca, I, idGetsT];
SetColControlToIdGetsSum => IF hca.controlVisible THEN SetColControlTo[hca, I, idGetsS];
SetColControlToIdGetsLv => IF hca.controlVisible THEN SetColControlTo[hca, I, idGetsLv];
ToggleControlVisibility => ToggleControlVisibility[hca];
SetZeroValueText => SetZVT[hca, p1];
SetArrayId => SetArrayId[hca, p1];
MoveSelectionToNext => MoveSelectionToNext[hca, I, J];
MoveSelectionToPrevious => MoveSelectionToPrevious[hca, I, J];
SubstituteInArray => SubstituteInWholeArray[hca, p1, p2];
SubstituteInRow => SubstituteInRow[hca, J, p1, p2];
SubstituteInColumn => SubstituteInColumn[hca, I, p1, p2];
--NoteArraySelection => NoteArraySelection[hca.displayer, info, I, J];
ENDCASE => GOTO skipAction;
RETURN[NIL, 0, 0];
EXITS
skipAction =>
BEGIN
cSn: StructureNodes.StructureNode; cI, cJ: CARDINAL;
[cSn, cI, cJ] ← StructureNodes.GetContextDA[hca.da];
RETURN[cSn, cI, cJ];
END;
END;
END;
SubstituteInHCellArray: PROCEDURE[info: StructureNodes.StructureNode, newText, oldText: Rope.ROPE] =
{ERROR};
AbandonHCellArray: PROCEDURE[info: StructureNodes.StructureNode] =
BEGIN
hca: HCellArray ← NARROW[info.ref];
SELECT hca.mode FROM
groupItem =>
BEGIN
summaryArray: HCellArray ← hca.summaryArray;
rowNumber: CARDINAL ← StructureNodes.GetRowNumber[hca.itemArrayRowHandle];
RemoveRowAt[summaryArray.hcaSn, summaryArray, rowNumber];
summaryArray.nItemArrays ← summaryArray.nItemArrays - 1;
END;
groupSummary => IF hca.nItemArrays # 0 THEN ERROR;
ENDCASE => NULL;
WHILE hca.nColumns # 0 DO RemoveColumnAt[info, hca, hca.nColumns] ENDLOOP;
WHILE hca.nRows # 0 DO RemoveRowAt[info, hca, hca.nRows] ENDLOOP;
END;
VerifyHCellArray: PROCEDURE[info: StructureNodes.StructureNode] =
BEGIN
hca: HCellArray ← NARROW[info.ref];
-- first see if it ties together with other arrays correctly
SELECT hca.mode FROM
individual => NULL;
groupItem => VerifyItemArrayInGroup[hca, hca.summaryArray];
groupSummary =>
BEGIN
FOR J: CARDINAL IN [1..hca.nRows] DO
rowInfo: RowInfo ← GetRowInfo[hca, J];
IF (rowInfo.rowControl = addItem) # (rowInfo.itemArray # NIL) THEN ERROR;
IF rowInfo.itemArray # NIL THEN VerifyItemArrayInGroup[rowInfo.itemArray, hca];
ENDLOOP;
END;
ENDCASE => ERROR;
END;
VerifyItemArrayInGroup: PROCEDURE[itemArray, summaryArray: HCellArray] =
BEGIN
rowNumber: CARDINAL ← StructureNodes.GetRowNumber[itemArray.itemArrayRowHandle];
IF GetRowInfo[summaryArray, rowNumber].itemArray # itemArray THEN ERROR;
IF itemArray.nColumns # summaryArray.nColumns THEN ERROR;
IF itemArray.mode # groupItem THEN ERROR;
IF summaryArray.mode # groupSummary THEN ERROR;
FOR I: CARDINAL IN [1..itemArray.nColumns] DO
itemColInfo: ColInfo ← GetColumnInfo[itemArray, I];
summaryColInfo: ColInfo ← GetColumnInfo[summaryArray, I];
summaryArrayCell: HCells.HCell ← GetCell[summaryArray, I, rowNumber];
IF summaryArrayCell # itemColInfo.summaryArrayCell THEN ERROR;
IF itemColInfo.colControl # summaryColInfo.colControl THEN ERROR;
-- something like VerifyHCell[summaryArrayCell, colInfo.colSummer, etc
ENDLOOP;
END;


-- misc
MoveSelectionToNext: PROCEDURE[hca: HCellArray, I, J: CARDINAL] =
BEGIN
WHILE TRUE DO
IF I # hca.nColumns THEN I ← I+1
ELSE IF J # hca.nRows THEN {I ← 1; J ← J + 1}
ELSE RETURN;
IF MoveSelectionTo[hca, I, J, TRUE] THEN RETURN;
ENDLOOP;
END;
MoveSelectionToPrevious: PROCEDURE[hca: HCellArray, I, J: CARDINAL] =
BEGIN
WHILE TRUE DO
IF I # 1 THEN I ← I - 1
ELSE IF J # 1 THEN {I ← hca.nColumns; J ← J - 1}
ELSE RETURN;
IF MoveSelectionTo[hca, I, J, TRUE] THEN RETURN;
ENDLOOP;
END;
MoveSelectionTo: PROCEDURE[hca: HCellArray, I, J: CARDINAL, conditional: BOOLEAN ← FALSE] RETURNS[succeeded: BOOLEAN] =
BEGIN
hcSn: StructureNodes.StructureNode;
[sn: hcSn] ← StructureNodes.GetElementAt[hca.da, I, J];
RETURN[HCells.ForceHCellSelection[hcSn, conditional]];
END;
SubstituteInWholeArray: PROCEDURE[hca: HCellArray, p1, p2: REF ANY] =
BEGIN
FOR I: CARDINAL IN [1..hca.nColumns] DO
SubstituteInColumn[hca, I, p1, p2];
ENDLOOP;
END;
SubstituteInRow: PROCEDURE[hca: HCellArray, J: CARDINAL, p1, p2: REF ANY] =
BEGIN
newText: Rope.ROPE ← NARROW[p1];
oldText: Rope.ROPE ← NARROW[p2];
FOR I: CARDINAL IN [1..hca.nColumns] DO
hcSn: StructureNodes.StructureNode;
[sn: hcSn] ← StructureNodes.GetElementAt[hca.da, I, J];
hcSn.procs.Substitute[hcSn, newText, oldText];
ENDLOOP;
END;
SubstituteInColumn: PROCEDURE[hca: HCellArray, I: CARDINAL, p1, p2: REF ANY] =
BEGIN
newText: Rope.ROPE ← NARROW[p1];
oldText: Rope.ROPE ← NARROW[p2];
FOR J: CARDINAL IN [1..hca.nRows] DO
hcSn: StructureNodes.StructureNode;
[sn: hcSn] ← StructureNodes.GetElementAt[hca.da, I, J];
hcSn.procs.Substitute[hcSn, newText, oldText];
ENDLOOP;
END;
ToggleControlVisibility: PROCEDURE[hca: HCellArray] =
BEGIN
hca.controlVisible ← NOT hca.controlVisible;
FOR I: CARDINAL IN [1..hca.nColumns] DO
colControl: ColControl ← GetColumnInfo[hca, I].colControl;
IF colControl = control THEN SetColumnCellParameters[hca, I, NIL];
ENDLOOP;
FOR J: CARDINAL IN [1..hca.nRows] DO
rowControl: RowControl ← GetRowInfo[hca, J].rowControl;
IF rowControl = control THEN SetRowCellParameters[hca, J, NIL];
ENDLOOP;
END;
SetZVT: PROCEDURE[hca: HCellArray, p1: REF ANY] =
BEGIN
newZvt: Rope.ROPE ← NARROW[p1];
IF NOT Rope.Equal[newZvt, hca.zvt] THEN
BEGIN
hca.zvt ← newZvt;
FOR J: CARDINAL IN [1..hca.nRows] DO
SetRowCellParameters[hca, J, NIL];
ENDLOOP;
END;
END;
ResetPageNameOfHCellArray: PUBLIC PROCEDURE[hcaSn: StructureNodes.StructureNode, pageName: Rope.ROPE] =
BEGIN
hca: HCellArray ← NARROW[hcaSn.ref];
IF NOT Rope.Equal[pageName, hca.pageName] THEN
BEGIN
hca.pageName ← pageName;
FOR J: CARDINAL IN [1..hca.nRows] DO
SetRowCellParameters[hca, J, NIL];
ENDLOOP;
END;
END;
SetArrayId: PROCEDURE[hca: HCellArray, p1: REF ANY] =
BEGIN
newIdText: Rope.ROPE ← NARROW[p1];
IF NOT Rope.Equal[newIdText, hca.arrayIdText] THEN
BEGIN
hca.arrayIdText ← newIdText;
FOR J: CARDINAL IN [1..hca.nRows] DO
SetRowCellParameters[hca, J, NIL];
ENDLOOP;
END;
END;
-- column and row activity
RowInfo: TYPE = REF RowInfoBody;
RowInfoBody: TYPE = RECORD[
hca: HCellArray,
rowHandle: StructureNodes.RowHandle ← NIL,
rowSummer: Dependencies.Action ← NIL,
itemArray: HCellArray ← NIL, -- used only in summary arrays, names the corresponding item array
rowControl: RowControl
];
ColInfo: TYPE = REF ColInfoBody;
ColInfoBody: TYPE = RECORD[
hca: HCellArray,
colHandle: StructureNodes.ColHandle ← NIL,
colSummer: Dependencies.Action ← NIL,
summaryArrayCell: HCells.HCell ← NIL, -- used only in item arrays, column totals are sent to this cell
colControl: ColControl
];
InstallRowAt: PROCEDURE[hcaSn: StructureNodes.StructureNode, hca: HCellArray, J: CARDINAL, copyFrom: CARDINAL] =
BEGIN
rowControl: RowControl ← GetRowInfo[hca, copyFrom].rowControl;
rowText: Rope.ROPE ← GetRowTextRope[hca, copyFrom];
rowTextStream: IO.STREAM ← IO.RIS[rowText];
[] ← BasicInstallRowAt[hca, J, rowControl];
IF J > 1 THEN SetRowCellParameters[hca, J-1, NIL];
SetRowCellParameters[hca, J, rowTextStream];
IF J < hca.nRows THEN SetRowCellParameters[hca, J+1, NIL];
rowTextStream.Close[];
END;
BasicInstallRowAt: PROCEDURE[hca: HCellArray, J: CARDINAL, con: RowControl] RETURNS[rowSummer: Dependencies.Action] =
BEGIN
rowInfo: RowInfo ← NEW[RowInfoBody ← [hca: hca, rowControl: con]];
hca.nRows ← hca.nRows+1;
StructureNodes.AddRowAt[hca.da, J];
rowInfo.rowHandle ← StructureNodes.SetRowInfoAt[hca.da, J, rowInfo];
rowSummer ← rowInfo.rowSummer ← Dependencies.DefineAction[hca.document.dSet, RowSummer, rowInfo];
FOR I: CARDINAL IN [1..hca.nColumns] DO
BasicInstallSlot[hca, I, J];
ENDLOOP;
END;
NoteItemArrayCorrespondingToRow: PROCEDURE[hca: HCellArray, J: CARDINAL, itemArray: HCellArray] =
BEGIN
rowInfo: RowInfo ← GetRowInfo[hca, J];
IF hca.mode # groupSummary THEN ERROR;
IF itemArray.mode # groupItem THEN ERROR;
IF hca.nColumns # itemArray.nColumns THEN ERROR;
itemArray.summaryArray ← hca;
itemArray.itemArrayRowHandle ← rowInfo.rowHandle;
FOR I: CARDINAL IN [1..hca.nColumns] DO
itemArrayColInfo: ColInfo ← GetColumnInfo[itemArray, I];
cell: HCells.HCell ← GetCell[hca, I, J];
itemArrayColInfo.summaryArrayCell ← cell;
ENDLOOP;
rowInfo.itemArray ← itemArray;
END;
DisconnectItemArrayCorrespondingToRow: PROCEDURE[hca: HCellArray, J: CARDINAL] =
BEGIN
rowInfo: RowInfo ← GetRowInfo[hca, J];
itemArray: HCellArray ← rowInfo.itemArray;
IF hca.mode # groupSummary THEN ERROR;
IF itemArray.mode # groupItem THEN ERROR;
IF hca.nColumns # itemArray.nColumns THEN ERROR;
itemArray.summaryArray ← NIL;
itemArray.itemArrayRowHandle ← NIL;
FOR I: CARDINAL IN [1..hca.nColumns] DO
itemArrayColInfo: ColInfo ← GetColumnInfo[itemArray, I];
itemArrayColInfo.summaryArrayCell ← NIL;
ENDLOOP;
rowInfo.itemArray ← NIL;
END;
RemoveRowAt: PROCEDURE[hcaSn: StructureNodes.StructureNode, hca: HCellArray, J: CARDINAL] =
BEGIN
rowInfo: RowInfo ← GetRowInfo[hca, J];
rowSummer: Dependencies.Action ← rowInfo.rowSummer;
Dependencies.DeactivateAction[rowSummer];
StructureNodes.DeleteRowAt[hca.da, J];
hca.nRows ← hca.nRows-1;
FOR I: CARDINAL IN [1..hca.nColumns] DO
Dependencies.MarkActionDirty[GetColumnInfo[hca, I].colSummer];
ENDLOOP;
END;
SetRowControlTo: PROCEDURE[hca: HCellArray, J: CARDINAL, rowControl: RowControl] =
BEGIN
rowInfo: RowInfo ← NARROW[StructureNodes.GetRowInfoAt[hca.da, J]];
rowInfo.rowControl ← rowControl;
SetRowCellParameters[hca, J, NIL];
END;
InstallColumnAt: PROCEDURE[hcaSn: StructureNodes.StructureNode, hca: HCellArray, I: CARDINAL, copyFrom: CARDINAL, loadInProgress: BOOLEAN ← FALSE] =
BEGIN
colInfo: ColInfo ← GetColumnInfo[hca, copyFrom];
colText: Rope.ROPE ← GetColumnTextRope[hca, copyFrom];
colTextStream: IO.STREAM ← IO.RIS[colText];
[] ← BasicInstallColumnAt[hca, I, colInfo.colControl];
-- watch out for group summaries
IF hca.mode = groupSummary AND NOT loadInProgress THEN
FOR J: CARDINAL IN [1..hca.nRows] DO
rowInfo: RowInfo ← GetRowInfo[hca, J];
IF (rowInfo.rowControl = addItem) # (rowInfo.itemArray # NIL) THEN ERROR;
IF rowInfo.itemArray # NIL THEN InstallColumnAt[rowInfo.itemArray.hcaSn, rowInfo.itemArray, I, copyFrom, loadInProgress];
ENDLOOP;
-- watch out for group items
IF hca.mode = groupItem AND NOT loadInProgress THEN
BEGIN
newColInfo: ColInfo ← GetColumnInfo[hca, I];
newColInfo.summaryArrayCell ← GetCell[hca.summaryArray, I, StructureNodes.GetRowNumber[hca.itemArrayRowHandle]];
END;
IF I > 1 THEN SetColumnCellParameters[hca, I-1, NIL];
SetColumnCellParameters[hca, I, colTextStream];
IF I < hca.nColumns THEN SetColumnCellParameters[hca, I+1, NIL];
colTextStream.Close[];
END;
BasicInstallColumnAt: PROCEDURE[hca: HCellArray, I: CARDINAL, con: ColControl] RETURNS[colSummer: Dependencies.Action] =
BEGIN
colInfo: ColInfo ← NEW[ColInfoBody ← [hca: hca, colControl: con]];
hca.nColumns ← hca.nColumns+1;
StructureNodes.AddColumnAt[hca.da, I];
colInfo.colHandle ← StructureNodes.SetColInfoAt[hca.da, I, colInfo];
colSummer ← colInfo.colSummer ← Dependencies.DefineAction[hca.document.dSet, ColumnSummer, colInfo];
FOR J: CARDINAL IN [1..hca.nRows] DO
BasicInstallSlot[hca, I, J];
ENDLOOP;
  
END;
RemoveColumnAt: PROCEDURE[hcaSn: StructureNodes.StructureNode, hca: HCellArray, I: CARDINAL, loadInProgress: BOOLEAN ← FALSE] =
BEGIN
colInfo: ColInfo ← GetColumnInfo[hca, I];
colSummer: Dependencies.Action ← colInfo.colSummer;
colControl: ColControl← colInfo.colControl;
Dependencies.DeactivateAction[colSummer];
StructureNodes.DeleteColumnAt[hca.da, I];
hca.nColumns ← hca.nColumns-1;
IF I > 1 AND (colControl = leftValTimesExp OR colControl = leftVal OR colControl = idGetsLv) THEN
SetColumnCellParameters[hca, I-1, NIL];
IF I <= hca.nColumns THEN
BEGIN
rightColControl: ColControl ← GetColumnInfo[hca, I].colControl;
IF rightColControl = leftValTimesExp OR rightColControl = leftVal OR rightColControl = idGetsLv THEN
SetColumnCellParameters[hca, I, NIL];
END;
FOR J: CARDINAL IN [1..hca.nRows] DO
Dependencies.MarkActionDirty[GetRowInfo[hca, J].rowSummer];
ENDLOOP;
-- watch out for group summaries
IF hca.mode = groupSummary AND NOT loadInProgress THEN
FOR J: CARDINAL IN [1..hca.nRows] DO
rowInfo: RowInfo ← GetRowInfo[hca, J];
IF (rowInfo.rowControl = addItem) # (rowInfo.itemArray # NIL) THEN ERROR;
IF rowInfo.itemArray # NIL THEN RemoveColumnAt[rowInfo.itemArray.hcaSn, rowInfo.itemArray, I, loadInProgress];
ENDLOOP;
END;
SetColControlTo: PROCEDURE[hca: HCellArray, I: CARDINAL, colControl: ColControl, loadInProgress: BOOLEAN ← FALSE] =
BEGIN
colInfo: ColInfo ← NARROW[StructureNodes.GetColInfoAt[hca.da, I]];
colInfo.colControl ← colControl;
IF I > 1 THEN SetColumnCellParameters[hca, I-1, NIL];
SetColumnCellParameters[hca, I, NIL];
IF I < hca.nColumns THEN SetColumnCellParameters[hca, I+1, NIL];
-- watch out for group summaries
IF hca.mode = groupSummary AND NOT loadInProgress THEN
FOR J: CARDINAL IN [1..hca.nRows] DO
rowInfo: RowInfo ← GetRowInfo[hca, J];
IF (rowInfo.rowControl = addItem) # (rowInfo.itemArray # NIL) THEN ERROR;
IF rowInfo.itemArray # NIL THEN SetColControlTo[rowInfo.itemArray, I, colControl, loadInProgress];
ENDLOOP;
END;
SetRowCellParameters: PROCEDURE[hca: HCellArray, J: CARDINAL, textStream: IO.STREAM] =
BEGIN
nColumns: CARDINAL ← hca.nColumns;
rowInfo: RowInfo ← GetRowInfo[hca, J];
prevCell: HCells.HCell ← NIL;
currCell: HCells.HCell ← NIL;
nextCell: HCells.HCell ← GetCell[hca, 1, J];
nextColInfo: ColInfo ← GetColumnInfo[hca, 1];
currColControl, nextColControl: ColControl;
currColSummer, nextColSummer: Dependencies.Action;
nextColControl ← nextColInfo.colControl;
nextColSummer ← nextColInfo.colSummer;
FOR I: CARDINAL IN [1..nColumns] DO
-- get cell text, and set the cell parameters
-- at start, prevCell holds I-2, currCell holds I-1, and nextCell holds I
text: Rope.ROPE ← IF textStream = NIL THEN NIL ELSE ReadCellText[textStream];
itemArrayColSummer: Dependencies.Action ← IF hca.mode # groupSummary OR rowInfo.rowControl # addItem OR rowInfo.itemArray = NIL THEN NIL ELSE GetColumnInfo[rowInfo.itemArray, I].colSummer;
prevCell ← currCell; currCell ← nextCell;
nextCell ← IF I # nColumns THEN GetCell[hca, I+1, J] ELSE NIL;
currColControl ← nextColControl;
currColSummer ← nextColSummer;
IF I # nColumns THEN
BEGIN
nextColInfo ← GetColumnInfo[hca, I+1];
nextColControl ← nextColInfo.colControl;
nextColSummer ← nextColInfo.colSummer;
END
ELSE {nextColInfo ← NIL; nextColControl ← text; nextColSummer ← NIL};
SetCell[hca, currCell, currColControl, currColSummer, rowInfo.rowControl, rowInfo.rowSummer, itemArrayColSummer, prevCell, nextCell, nextColControl, text, (I=2)];
ENDLOOP;
END;
SetColumnCellParameters: PROCEDURE[hca: HCellArray, I: CARDINAL, textStream: IO.STREAM] =
BEGIN
nRows: CARDINAL ← hca.nRows;
currColInfo: ColInfo ← GetColumnInfo[hca, I];
currColControl: ColControl ← currColInfo.colControl;
currColSummer: Dependencies.Action ← currColInfo.colSummer;
nextColControl: ColControl;
IF I < hca.nColumns THEN nextColControl ← GetColumnInfo[hca, I+1].colControl ELSE nextColControl ← text;
FOR J: CARDINAL IN [1..nRows] DO
rowInfo: RowInfo ← GetRowInfo[hca, J];
prevCell: HCells.HCell ← IF (currColControl # leftVal AND currColControl # leftValTimesExp AND currColControl # idGetsLv) OR I = 1 THEN NIL ELSE GetCell[hca, I-1, J];
nextCell: HCells.HCell ← IF nextColControl # leftVal AND nextColControl # leftValTimesExp AND nextColControl # idGetsLv THEN NIL ELSE GetCell[hca, I+1, J];
currCell: HCells.HCell ← GetCell[hca, I, J];
text: Rope.ROPE ← IF textStream = NIL THEN NIL ELSE ReadCellText[textStream];
itemArrayColSummer: Dependencies.Action ← IF hca.mode # groupSummary OR rowInfo.rowControl # addItem THEN NIL ELSE GetColumnInfo[rowInfo.itemArray, I].colSummer;
SetCell[hca, currCell, currColControl, currColSummer, rowInfo.rowControl, rowInfo.rowSummer, itemArrayColSummer, prevCell, nextCell, nextColControl, text, (I = 2)];
ENDLOOP;
END;
GetRowInfo: PROCEDURE[hca: HCellArray, J: CARDINAL] RETURNS[rowInfo: RowInfo] =
{RETURN[NARROW[StructureNodes.GetRowInfoAt[hca.da, J]]]};
GetColumnInfo: PROCEDURE[hca: HCellArray, I: CARDINAL] RETURNS[ColInfo] =
{RETURN[NARROW[StructureNodes.GetColInfoAt[hca.da, I]]]};
GetRowTextRope: PROCEDURE[hca: HCellArray, J: CARDINAL] RETURNS[Rope.ROPE] =
BEGIN
s: IO.STREAM ← IO.ROS[];
FOR I: CARDINAL IN [1..hca.nColumns] DO
cell: HCells.HCell ← GetCell[hca, I, J];
WriteCellText[s, HCells.GetHCellText[cell]];
s.PutChar[' ];
ENDLOOP;
RETURN[IO.RopeFromROS[s, TRUE]];
END;
GetColumnTextRope: PROCEDURE[hca: HCellArray, I: CARDINAL] RETURNS[Rope.ROPE] =
BEGIN
s: IO.STREAM ← IO.ROS[];
FOR J: CARDINAL IN [1..hca.nRows] DO
cell: HCells.HCell ← GetCell[hca, I, J];
WriteCellText[s, HCells.GetHCellText[cell]];
s.PutChar[' ];
ENDLOOP;
RETURN[IO.RopeFromROS[s, TRUE]];
END;
-- row and column summers
RowSummer: PROCEDURE[action: Dependencies.Action, info: REF ANY] =
BEGIN
rowInfo: RowInfo ← NARROW[info];
sum: REAL ← 0;
J: CARDINAL ← StructureNodes.GetRowNumber[rowInfo.rowHandle];
FOR I: CARDINAL IN [1..rowInfo.hca.nColumns] DO
hcSn: StructureNodes.StructureNode;
[sn: hcSn] ← StructureNodes.GetElementAt[rowInfo.hca.da, I, J];
sum ← HCells.DoRowSum[hcSn, sum];
ENDLOOP;
FOR I: CARDINAL IN [1..rowInfo.hca.nColumns] DO
hcSn: StructureNodes.StructureNode;
colControl: ColControl ← GetColumnInfo[rowInfo.hca, I].colControl;
IF colControl = total OR colControl = idGetsT THEN
BEGIN
[sn: hcSn] ← StructureNodes.GetElementAt[rowInfo.hca.da, I, J];
HCells.DoRowTotal[hcSn, sum];
END;
ENDLOOP;
END;
ColumnSummer: PROCEDURE[action: Dependencies.Action, info: REF ANY] =
BEGIN
colInfo: ColInfo ← NARROW[info];
sum: REAL ← 0;
I: CARDINAL ← StructureNodes.GetColNumber[colInfo.colHandle];
FOR J: CARDINAL IN [1..colInfo.hca.nRows] DO
hcSn: StructureNodes.StructureNode;
[sn: hcSn] ← StructureNodes.GetElementAt[colInfo.hca.da, I, J];
sum ← HCells.DoColSum[hcSn, sum];
ENDLOOP;
IF colInfo.summaryArrayCell # NIL THEN HCells.DoItemArrayColSum[colInfo.summaryArrayCell, sum];
END;
-- slot operations
-- needed because one cannot narrow to an opaque type
SlotInfo: TYPE = REF SlotInfoBody;
SlotInfoBody: TYPE = RECORD[cell: HCells.HCell];
BasicInstallSlot: PROCEDURE[hca: HCellArray, I, J: CARDINAL] =
BEGIN
hcSn: StructureNodes.StructureNode;
cell: HCells.HCell;
[hcSn, cell] ← HCells.CreateHCell[hca.document, hca.displayer, hca.hcaSn, hca.vParent];
StructureNodes.SetElementAt[hca.da, I, J, hcSn, NEW[SlotInfoBody ← [cell]]];
END;
GetCell: PROCEDURE[hca: HCellArray, I, J: CARDINAL] RETURNS[HCells.HCell] =
BEGIN
info: SlotInfo ← NARROW[StructureNodes.GetElementAt[hca.da, I, J].info];
RETURN[info.cell];
END;
SetCell: PROCEDURE[hca: HCellArray, cell: HCells.HCell, colControl: ColControl, colSummer: Dependencies.Action, rowControl: RowControl, rowSummer: Dependencies.Action, itemArrayColSummer: Dependencies.Action, prevCell: HCells.HCell, nextCell: HCells.HCell, nextColControl: ColControl, tentativeText: Rope.ROPE, colEqualTwo: BOOLEAN] =
BEGIN
-- begin wth tentative parameter assignments;
leftCell: HCells.HCell ← NIL;
rightCell: HCells.HCell ← NIL;
editable: BOOLEAN ← TRUE;
finalText: Rope.ROPE ← tentativeText;
valueMode: HCells.ValueMode ← exp;
rowSumMode: HCells.RowColSumMode ← none;
colSumMode: HCells.RowColSumMode ← none;
idMode: HCells.IdMode ← none;
displayMode: HCells.DisplayMode ← text;
justification: HCells.Justification ← rightDecimal;
zeroValueText: Rope.ROPE ← hca.zvt;
-- now adjust them
SELECT TRUE FROM
colControl = control AND rowControl = control =>
BEGIN
editable ← FALSE;
IF hca.controlVisible THEN
BEGIN
finalText ← IO.PutFR["<zvt: ""%g"">\n%g<id: ""%g"">",
IO.rope[hca.zvt], IO.rope[finalText], IO.rope[hca.arrayIdText]];
END
ELSE finalText ← "";
valueMode ← none; justification ← centered; displayMode ← control
END;
colControl = control =>
BEGIN
editable ← FALSE;
IF hca.controlVisible THEN finalText ← DisplayTextForRowControl[hca, rowControl]
ELSE finalText ← "";
valueMode ← none; justification ← centered
END;
rowControl = control =>
BEGIN
editable ← FALSE;
justification ← centered; -- tentative
IF hca.controlVisible THEN finalText ← DisplayTextForColControl[hca, colControl]
ELSE IF colEqualTwo THEN {finalText ← hca.arrayIdText; justification ← left}
ELSE finalText ← "";
valueMode ← none
END;
colControl = text OR rowControl = text =>
{valueMode ← none; justification ← right};
ENDCASE =>
BEGIN
SELECT rowControl FROM
addItem =>
BEGIN
colSumMode ← add;
IF hca.mode = groupSummary THEN
SELECT colControl FROM
addZero => {valueMode ← none; colSumMode ← none};
addItem => {valueMode ← itemArrayColTotal; rowSumMode ← add; displayMode ← value; editable ← FALSE};
subItem => {valueMode ← itemArrayColTotal; rowSumMode ← sub; displayMode ← value; editable ← FALSE};
leftValTimesExp =>
{valueMode ← itemArrayColTotal; rowSumMode ← add};
leftVal =>
{leftCell ← prevCell; editable ← FALSE; valueMode ← lv; displayMode ← value};
sum =>
{editable ← FALSE; finalText ← NIL; valueMode ← rowSum; displayMode ← value};
total =>
{editable ← FALSE; finalText ← NIL; valueMode ← rowTotal; displayMode ← value};
idGetsT => {valueMode ← rowTotal; idMode ← setId};
idGetsS => {valueMode ← rowSum; idMode ← setId};
idGetsLv => {leftCell ← prevCell; valueMode ← lv; idMode ← setId};
ENDCASE => ERROR
ELSE
SELECT colControl FROM
addZero => NULL;
addItem => {rowSumMode ← add};
subItem => {rowSumMode ← sub};
leftValTimesExp =>
{leftCell ← prevCell; valueMode ← lvTimesExp; rowSumMode ← add};
leftVal =>
{leftCell ← prevCell; editable ← FALSE; valueMode ← lv; displayMode ← value};
sum =>
{editable ← FALSE; finalText ← NIL; valueMode ← rowSum; displayMode ← value};
total =>
{editable ← FALSE; finalText ← NIL; valueMode ← rowTotal; displayMode ← value};
idGetsT => {valueMode ← rowTotal; idMode ← setId};
idGetsS => {valueMode ← rowSum; idMode ← setId};
idGetsLv => {leftCell ← prevCell; valueMode ← lv; idMode ← setId};
ENDCASE => ERROR;
IF nextCell # NIL AND (nextColControl = leftValTimesExp OR nextColControl = leftVal OR nextColControl = idGetsLv) THEN rightCell ← nextCell;
END;
sum =>
BEGIN
editable ← FALSE; valueMode ← colSum; displayMode ← value;
SELECT colControl FROM
addZero => {displayMode ← text; finalText ← " "};
addItem => {rowSumMode ← add};
subItem => {rowSumMode ← sub};
leftValTimesExp => {displayMode ← text; finalText ← " "; rowSumMode ← add};
leftVal => NULL;
sum => NULL;
total => NULL;
idGetsT, idGetsS, idGetsLv => NULL;
ENDCASE => ERROR;
END;
ENDCASE => ERROR;
END;
HCells.SetHCellParameters[cell, rowSummer, colSummer, itemArrayColSummer, leftCell, rightCell, editable, finalText, valueMode, rowSumMode, colSumMode, idMode, displayMode, justification, zeroValueText, hca.pageName, hca.arrayIdText];
END;
-- Control Visibility handling
DecodeControlVisibilityChar: PROCEDURE[char: CHARACTER] RETURNS[BOOLEAN] =
{RETURN[SELECT char FROM
't => TRUE,
'f => FALSE,
ENDCASE => ERROR]};
EncodeControlVisibility: PROCEDURE[visible: BOOLEAN] RETURNS[CHARACTER] =
{RETURN[SELECT visible FROM
TRUE => 't,
FALSE => 'f,
ENDCASE => ERROR]};
-- control handling
DecodeRowControlChar: PROCEDURE[char: CHARACTER] RETURNS[RowControl] =
{RETURN[SELECT char FROM
'a => control,
'b => text,
'c => addItem,
'd => sum,
ENDCASE => ERROR]};
DecodeColControlChar: PROCEDURE[char: CHARACTER] RETURNS[ColControl] =
{RETURN[SELECT char FROM
'a => control,
'b => text,
'c => addZero,
'd => addItem,
'e => subItem,
'f => leftValTimesExp,
'g => leftVal,
'h => sum,
'i => total,
'j => idGetsT,
'k => idGetsS,
'l => idGetsLv,
ENDCASE => ERROR]};
EncodeRowControl: PROCEDURE[con: RowControl] RETURNS[CHARACTER] =
{RETURN[SELECT con FROM
control => 'a,
text => 'b,
addItem => 'c,
sum => 'd,
ENDCASE => ERROR]};
EncodeColControl: PROCEDURE[con: ColControl] RETURNS[CHARACTER] =
{RETURN[SELECT con FROM
control => 'a,
text => 'b,
addZero => 'c,
addItem => 'd,
subItem => 'e,
leftValTimesExp => 'f,
leftVal => 'g,
sum => 'h,
total => 'i,
idGetsT => 'j,
idGetsS => 'k,
idGetsLv => 'l,
ENDCASE => ERROR]};
DisplayTextForRowControl: PROCEDURE[hca: HCellArray, con: RowControl] RETURNS[Rope.ROPE] =
{RETURN[SELECT con FROM
control => "<con>",
text => "<text>",
addItem => "<+exp>",
sum => "<sum>",
ENDCASE => ERROR]};
DisplayTextForColControl: PROCEDURE[hca: HCellArray, con: ColControl] RETURNS[Rope.ROPE] =
{RETURN[SELECT con FROM
control => "<con>",
text => "<text>",
addZero => "<+0>",
addItem => "<+exp>",
subItem => "<-exp>",
leftValTimesExp => "<lv*exp>",
leftVal => "<lv>",
sum => "<sum>",
total => "<total>",
idGetsT => "<id←t>",
idGetsS => "<id←s>",
idGetsLv => "<id←lv>",
ENDCASE => ERROR]};
-- cell text IO routines
-- format is {text}, and embedded ' and } are preceded by a '.
WriteCellText: PUBLIC PROCEDURE[to: IO.STREAM, text: Rope.ROPE] =
BEGIN
pos1: INT ← 0; pos2: INT; posQuote, posBracket: INT;
to.PutChar['{];
WHILE TRUE DO
posQuote ← Rope.Index[text, pos1, "'"];
posBracket ← Rope.Index[text, pos1, "}"];
pos2 ← MIN[posQuote, posBracket];
IF pos2 = Rope.Length[text] AND pos1 = 0 THEN
{to.PutRope[text]; EXIT};
to.PutRope[Rope.Substr[text, pos1, pos2-pos1]];
IF pos2 = Rope.Length[text] THEN EXIT;
to.PutChar[''];
to.PutChar[Rope.Fetch[text, pos2]];
pos1 ← pos2+1;
IF pos1 = Rope.Length[text] THEN EXIT;
ENDLOOP;
to.PutChar['}];
END;
ReadCellText: PUBLIC PROCEDURE[from: IO.STREAM] RETURNS[Rope.ROPE] =
BEGIN
text: Rope.ROPE ← ""; -- tentative
bp: IO.BreakProc = TRUSTED
BEGIN
IF char = '' OR char = '} THEN RETURN[break];
RETURN[other];
END;
token1, token2: Rope.ROPE;
WHILE from.GetChar[] # '{ DO ENDLOOP;
WHILE TRUE DO
token1 ← IO.GetTokenRope[from, bp].token;
IF Rope.Equal[token1, "'"] OR Rope.Equal[token1, "}"] THEN
{token2 ← token1; token1 ← ""}
ELSE
token2 ← IO.GetTokenRope[from, bp].token;
text ← Rope.Concat[text, token1];
IF Rope.Equal[token2, "}"] THEN EXIT;
IF NOT Rope.Equal[token2, "'"] THEN ERROR;
text ← Rope.Concat[text, Rope.FromChar[from.GetChar[]]];
ENDLOOP;
RETURN[text];
END;
END..
June 27, 1984 3:13:25 pm PDT: Sturgis, started HCellArrayImpl.mesa, edit from peices of GCellArrayImpl
-- RTE: June 28, 1984 5:11:38 pm PDT: used a variable named control of an enumerated type one of whose elements was control. Thus, was always using the constant value "control" when I intended to use the variable named "control". Ths also caused some confusion in earlier compilations, thought the compiler should have been reporting a type error when it wasn't.
-- RTE: June 30, 1984 1:50:36 pm PDT: GetCOlumnTextRope did not put out a blank between cell text ropes.
-- RTE: June 30, 1984 1:58:05 pm PDT: WriteCellText forgot to incoude the bounding { and }.
-- RTE: June 30, 1984 2:08:28 pm PDT: InstallRow and InstallColumn used the same text stream from each of the columns whose parameters were being change. In fact, they should have used NIL for the text entries.
-- RTE: June 30, 1984 2:38:15 pm PDT: WriteCellText forgot to output the special char it found, or to step over it.
-- RTE: June 30, 1984 2:44:52 pm PDT: WriteCellText did not notice the end of the text, when there were special chars.
-- RTE: July 1, 1984 1:44:12 pm PDT: ReadCellText skipped over blank chars in the text.
-- RTE: July 1, 1984 2:31:17 pm PDT: InsertColumn and InsertRow actions were copying info from wrong place, and moving selection to wrong place.
-- July 2, 1984 10:27:34 am PDT: Add actions to set col and row control.
-- July 3, 1984 9:31:02 am PDT: add save code.
-- July 9, 1984 5:10:32 pm PDT: add control visibility
-- July 10, 1984 9:26:07 am PDT: add zero value text control
-- July 18, 1984 3:59:16 pm PDT: begin adding code tto support array groups
-- RTE: October 4, 1984 10:03:26 am PDT: neglected to save and restore hca.controlVisibility. Changed to Version 4 to include this information. Old save files (version 3) still work.