-- 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["\n%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 => "", text => "", addItem => "<+exp>", sum => "", ENDCASE => ERROR]}; DisplayTextForColControl: PROCEDURE[hca: HCellArray, con: ColControl] RETURNS[Rope.ROPE] = {RETURN[SELECT con FROM control => "", text => "", addZero => "<+0>", addItem => "<+exp>", subItem => "<-exp>", leftValTimesExp => "", leftVal => "", sum => "", total => "", idGetsT => "", idGetsS => "", idGetsLv => "", 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.. <> -- 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.