1722 lines
46 KiB
Plaintext
1722 lines
46 KiB
Plaintext
|
|
|||
|
{ Copyright (c) 1989 by Borland International, Inc. }
|
|||
|
|
|||
|
unit TCSheet;
|
|||
|
{ Turbo Pascal 5.5 object-oriented example spreadsheet routines.
|
|||
|
This unit is used by TCALC.PAS.
|
|||
|
See TCALC.DOC for an more information about this example.
|
|||
|
}
|
|||
|
|
|||
|
{$N+,S-}
|
|||
|
|
|||
|
interface
|
|||
|
|
|||
|
uses Crt, Dos, Objects, TCUtil, TCInput, TCScreen, TCLStr, TCHash, TCCell,
|
|||
|
TCCellSp, TCParser;
|
|||
|
|
|||
|
const
|
|||
|
DefaultMaxCols = 65535;
|
|||
|
DefaultMaxRows = 65535;
|
|||
|
DefaultMaxDecimalPlaces = 8;
|
|||
|
DefaultDefaultDecimalPlaces = 4;
|
|||
|
DefaultDefaultColWidth = 10;
|
|||
|
EmptyRowsAtTop = 1;
|
|||
|
EmptyRowsAtBottom = 2;
|
|||
|
MinColWidth = 3;
|
|||
|
CurrentChar = #4;
|
|||
|
ChangedChar = '*';
|
|||
|
PrintNormalCols = 80;
|
|||
|
PrintCompressedCols = 132;
|
|||
|
PrintRows = 66;
|
|||
|
PrintTopMargin = 1;
|
|||
|
PrintBottomMargin = 1;
|
|||
|
PrinterCompressChar = #15;
|
|||
|
EditYes = True;
|
|||
|
EditNo = False;
|
|||
|
DisplayYes = True;
|
|||
|
DisplayNo = False;
|
|||
|
WasChanged = True;
|
|||
|
NotChanged = False;
|
|||
|
AutoCalcLetter = 'A';
|
|||
|
FormulaDisplayLetter = 'F';
|
|||
|
MemoryString = 'Memory: ';
|
|||
|
FileHeader = 'TurboCalc Spreadsheet'^Z;
|
|||
|
ErrorString = 'ERROR';
|
|||
|
TempFileName = 'TEMP.TMP'; { Temporary file used for rehashing }
|
|||
|
PrinterName = 'PRN';
|
|||
|
PromptFileSave = 'File to save';
|
|||
|
PromptFilePrint = 'File to print to (ENTER = Printer)';
|
|||
|
PromptOverwriteFile = 'The file exists. Overwrite it';
|
|||
|
PromptCompressPrint = 'Compress the printing';
|
|||
|
PromptBorderPrint = 'Print the borders';
|
|||
|
PromptColumnWidth = 'Column to change';
|
|||
|
PromptNewWidth = 'New width';
|
|||
|
PromptColumnDelete = 'Column to delete';
|
|||
|
PromptColumnInsert = 'Insert new column before column';
|
|||
|
PromptRowDelete = 'Row to delete';
|
|||
|
PromptRowInsert = 'Insert new row before row';
|
|||
|
PromptSaveYN = 'Save spreadsheet';
|
|||
|
ErrNoOpen = 'Cannot open file';
|
|||
|
ErrDiskFull = 'Disk full';
|
|||
|
ErrPrinterError = 'Printer error';
|
|||
|
ErrNotSpreadsheet = 'Not a TurboCalc spreadsheet file';
|
|||
|
MsgRecalc = 'Recalculating cell values';
|
|||
|
MsgSave = 'Saving spreadsheet';
|
|||
|
MsgLoad = 'Loading spreadsheet';
|
|||
|
MsgBlockDelete = 'Deleting block';
|
|||
|
|
|||
|
type
|
|||
|
ColStartArray = array[0..ScreenCols] of Byte;
|
|||
|
ColStartPtr = ^ColStartArray;
|
|||
|
SpreadsheetPtr = ^Spreadsheet;
|
|||
|
Spreadsheet = object
|
|||
|
Number : Byte;
|
|||
|
MaxRows : Word;
|
|||
|
MaxCols : Word;
|
|||
|
MaxDecimalPlaces : Byte;
|
|||
|
MaxColWidth : Byte;
|
|||
|
MaxScreenCols : Byte;
|
|||
|
DefaultColWidth : Byte;
|
|||
|
DefaultDecimalPlaces : Byte;
|
|||
|
RowNumberSpace : Byte;
|
|||
|
ColSpace : Byte;
|
|||
|
Current : Boolean;
|
|||
|
Changed : Boolean;
|
|||
|
CurrPos : CellPos;
|
|||
|
LastPos : CellPos;
|
|||
|
ScreenBlock : Block;
|
|||
|
CurrBlock : Block;
|
|||
|
BlockOn : Boolean;
|
|||
|
FileName : PathStr;
|
|||
|
TotalRows : ScreenRowRange;
|
|||
|
DisplayArea : ScreenArea;
|
|||
|
ColArea : ScreenArea;
|
|||
|
RowArea : ScreenArea;
|
|||
|
InfoArea : ScreenArea;
|
|||
|
DataArea : ScreenArea;
|
|||
|
ContentsArea : ScreenArea;
|
|||
|
BlankArea : ScreenArea;
|
|||
|
NoBlankArea : Boolean;
|
|||
|
ColStart : ColStartPtr;
|
|||
|
DisplayFormulas : Boolean;
|
|||
|
AutoCalc : Boolean;
|
|||
|
CellHash : CellHashTable;
|
|||
|
OverwriteHash : OverwriteHashTable;
|
|||
|
WidthHash : WidthHashTable;
|
|||
|
FormatHash : FormatHashTable;
|
|||
|
Next : SpreadsheetPtr;
|
|||
|
constructor Init(InitCells : Longint; InitMaxCols, InitMaxRows : Word;
|
|||
|
InitMaxDecimalPlaces, InitDefaultDecimalPlaces : Byte;
|
|||
|
InitDefaultColWidth : Byte);
|
|||
|
destructor Done;
|
|||
|
function GetColStart(Col : Word) : Byte;
|
|||
|
procedure SetAreas(NewNumber : Word; X1 : ScreenColRange;
|
|||
|
Y1 : ScreenRowRange; X2 : ScreenColRange;
|
|||
|
Y2 : ScreenRowRange);
|
|||
|
procedure DisplayCols;
|
|||
|
procedure DisplayRows;
|
|||
|
procedure DisplayInfo;
|
|||
|
procedure DisplayAllCells;
|
|||
|
procedure Display;
|
|||
|
procedure DisplayCell(P : CellPos);
|
|||
|
procedure DisplayCellData;
|
|||
|
procedure DisplayCellBlock(C1 : Word; R1 : Word; C2 : Word;
|
|||
|
R2 : Word);
|
|||
|
procedure DisplayBlock(B : Block);
|
|||
|
procedure DisplayBlockDiff(B1, B2 : Block);
|
|||
|
procedure DisplayCol(Col : Word);
|
|||
|
procedure DisplayRow(Row : Word);
|
|||
|
procedure DisplayMemory;
|
|||
|
procedure DisplayFileName;
|
|||
|
procedure SetChanged(IsChanged : Boolean);
|
|||
|
procedure MakeCurrent;
|
|||
|
procedure MakeNotCurrent;
|
|||
|
procedure Update(UDisplay : Boolean);
|
|||
|
procedure ToggleFormulaDisplay;
|
|||
|
procedure SetScreenColStart(NewCol : Word);
|
|||
|
procedure SetScreenColStop(NewCol: Word);
|
|||
|
procedure SetScreenRowStart(NewRow : Word);
|
|||
|
procedure SetScreenRowStop(NewRow : Word);
|
|||
|
procedure FindScreenColStart;
|
|||
|
procedure FindScreenColStop;
|
|||
|
procedure FindScreenRowStart;
|
|||
|
procedure FindScreenRowStop;
|
|||
|
procedure SetBlankArea;
|
|||
|
function AddCell(CellType : CellTypes; P : CellPos; E : Boolean;
|
|||
|
V : Extended; I : LStringPtr) : Boolean;
|
|||
|
procedure DeleteCell(P : CellPos; var Deleted : Boolean);
|
|||
|
procedure DeleteBlock(B : Block; var Deleted : Boolean);
|
|||
|
function CellToFString(P : CellPos; var Color : Byte) : String;
|
|||
|
procedure SetLastPos(DPos : CellPos);
|
|||
|
function GetCurrCol : Word;
|
|||
|
function GetCurrRow : Word;
|
|||
|
function ColToX(Col : Word) : Byte;
|
|||
|
function RowToY(Row : Word) : Byte;
|
|||
|
function ColWidth(Col : Word) : Byte;
|
|||
|
function SameCellPos(P1, P2 : CellPos) : Boolean;
|
|||
|
procedure FixOverwrite;
|
|||
|
function FromFile(Name : PathStr) : Boolean;
|
|||
|
procedure ToFile(Name : PathStr);
|
|||
|
procedure CheckForSave;
|
|||
|
procedure ChangeWidth;
|
|||
|
function CellHashStart(TotalCells : Longint) : BucketRange;
|
|||
|
function WidthHashStart(TotalCells : Longint) : BucketRange;
|
|||
|
function OverwriteHashStart(TotalCells : Longint) : BucketRange;
|
|||
|
procedure Print;
|
|||
|
procedure DeleteColumn;
|
|||
|
procedure InsertColumn;
|
|||
|
procedure DeleteRow;
|
|||
|
procedure InsertRow;
|
|||
|
end;
|
|||
|
|
|||
|
function GetColWidth(var WHash : WidthHashTable; C : Word) : Byte;
|
|||
|
|
|||
|
implementation
|
|||
|
|
|||
|
function GetColWidth(var WHash : WidthHashTable; C : Word) : Byte;
|
|||
|
{ Returns the width of a column }
|
|||
|
var
|
|||
|
W : Word;
|
|||
|
begin
|
|||
|
W := WHash.Search(C);
|
|||
|
if W = 0 then
|
|||
|
GetColWidth := WHash.GetDefaultColWidth
|
|||
|
else
|
|||
|
GetColWidth := W;
|
|||
|
end; { GetColWidth }
|
|||
|
|
|||
|
constructor Spreadsheet.Init(InitCells : Longint; InitMaxCols,
|
|||
|
InitMaxRows : Word; InitMaxDecimalPlaces,
|
|||
|
InitDefaultDecimalPlaces : Byte;
|
|||
|
InitDefaultColWidth : Byte);
|
|||
|
{ Sets up a new spreadsheet }
|
|||
|
begin
|
|||
|
if not CellHash.Init(CellHashStart(InitCells)) then
|
|||
|
Fail;
|
|||
|
if not WidthHash.Init(WidthHashStart(InitCells), InitDefaultColWidth) then
|
|||
|
begin
|
|||
|
CellHash.Done;
|
|||
|
Fail;
|
|||
|
end;
|
|||
|
if not OverwriteHash.Init(OverwriteHashStart(InitCells)) then
|
|||
|
begin
|
|||
|
CellHash.Done;
|
|||
|
WidthHash.Done;
|
|||
|
Fail;
|
|||
|
end;
|
|||
|
if not FormatHash.Init then
|
|||
|
begin
|
|||
|
CellHash.Done;
|
|||
|
WidthHash.Done;
|
|||
|
OverwriteHash.Done;
|
|||
|
Fail;
|
|||
|
end;
|
|||
|
MaxCols := InitMaxCols;
|
|||
|
MaxRows := InitMaxRows;
|
|||
|
RowNumberSpace := Ord(MaxRows >= 10000) + Ord(MaxRows >= 1000) +
|
|||
|
Ord(MaxRows >= 100) + Ord(MaxRows >= 10) + 2;
|
|||
|
MaxColWidth := ScreenCols - RowNumberSpace;
|
|||
|
MaxScreenCols := MaxColWidth div MinColWidth;
|
|||
|
GetMem(ColStart, MaxScreenCols);
|
|||
|
if ColStart = nil then
|
|||
|
begin
|
|||
|
CellHash.Done;
|
|||
|
WidthHash.Done;
|
|||
|
OverwriteHash.Done;
|
|||
|
FormatHash.Done;
|
|||
|
Fail;
|
|||
|
end;
|
|||
|
CurrPos.Col := 1;
|
|||
|
CurrPos.Row := 1;
|
|||
|
LastPos := CurrPos;
|
|||
|
BlockOn := False;
|
|||
|
FileName := '';
|
|||
|
DisplayFormulas := False;
|
|||
|
AutoCalc := False;
|
|||
|
Current := False;
|
|||
|
Changed := False;
|
|||
|
ScreenBlock.Start.Col := 1;
|
|||
|
ScreenBlock.Start.Row := 1;
|
|||
|
ColSpace := Succ(Ord(MaxCols >= 18279) + Ord(MaxCols >= 703) +
|
|||
|
Ord(MaxCols >= 27));
|
|||
|
MaxDecimalPlaces := InitMaxDecimalPlaces;
|
|||
|
DefaultColWidth := InitDefaultColWidth;
|
|||
|
DefaultDecimalPlaces := InitDefaultDecimalPlaces;
|
|||
|
end; { Spreadsheet.Init }
|
|||
|
|
|||
|
destructor Spreadsheet.Done;
|
|||
|
{ Removes a spreadsheet from memory }
|
|||
|
begin
|
|||
|
CellHash.Done;
|
|||
|
WidthHash.Done;
|
|||
|
OverwriteHash.Done;
|
|||
|
FormatHash.Done;
|
|||
|
FreeMem(ColStart, MaxScreenCols);
|
|||
|
end; { Spreadsheet.Done }
|
|||
|
|
|||
|
function Spreadsheet.GetColStart(Col : Word) : Byte;
|
|||
|
begin
|
|||
|
GetColStart := ColStart^[Col];
|
|||
|
end; { Spreadsheet.GetColStart }
|
|||
|
|
|||
|
procedure Spreadsheet.SetAreas(NewNumber : Word; X1 : ScreenColRange;
|
|||
|
Y1 : ScreenRowRange; X2 : ScreenColRange;
|
|||
|
Y2 : ScreenRowRange);
|
|||
|
{ Sets up a spreadsheet's display areas }
|
|||
|
begin
|
|||
|
Number := NewNumber;
|
|||
|
TotalRows := Y2 - Y1 - 2;
|
|||
|
ColArea.Init(X1 + RowNumberSpace, Y1, X2, Y1, Colors.ColColor);
|
|||
|
RowArea.Init(X1, Succ(Y1), Pred(X1 + RowNumberSpace), Y2 - 2,
|
|||
|
Colors.RowColor);
|
|||
|
InfoArea.Init(X1, Y1, Pred(X1 + RowNumberSpace), Y1, Colors.InfoColor);
|
|||
|
DisplayArea.Init(X1 + RowNumberSpace, Succ(Y1), X2, Y2 - 2,
|
|||
|
Colors.BlankColor);
|
|||
|
DataArea.Init(X1, Pred(Y2), X2, Pred(Y2), Colors.BlankColor);
|
|||
|
ContentsArea.Init(X1, Y2, X2, Y2, Colors.ContentsColor);
|
|||
|
SetScreenColStart(ScreenBlock.Start.Col);
|
|||
|
SetScreenRowStart(ScreenBlock.Start.Row);
|
|||
|
SetBlankArea;
|
|||
|
end; { Spreadsheet.SetAreas }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayCols;
|
|||
|
{ Shows the column headings }
|
|||
|
var
|
|||
|
C : Word;
|
|||
|
begin
|
|||
|
ColArea.Clear;
|
|||
|
with ScreenBlock do
|
|||
|
begin
|
|||
|
for C := Start.Col to Stop.Col do
|
|||
|
WriteXY(CenterStr(ColToString(C), ColWidth(C)),
|
|||
|
ColStart^[C - Start.Col], ColArea.UpperLeft.Row,
|
|||
|
Colors.ColColor);
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.DisplayCols }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayRows;
|
|||
|
{ Shows the row headings }
|
|||
|
var
|
|||
|
R : Word;
|
|||
|
begin
|
|||
|
RowArea.Clear;
|
|||
|
with ScreenBlock do
|
|||
|
begin
|
|||
|
for R := Start.Row to Stop.Row do
|
|||
|
with RowArea do
|
|||
|
WriteXY(LeftJustStr(RowToString(R), RowNumberSpace),
|
|||
|
UpperLeft.Col, R - Start.Row + UpperLeft.Row,
|
|||
|
Colors.RowColor);
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.DisplayRows }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayInfo;
|
|||
|
{ Shows the spreadsheet number, current dot, and state of AutoCalc and
|
|||
|
formula display }
|
|||
|
begin
|
|||
|
InfoArea.Clear;
|
|||
|
with InfoArea do
|
|||
|
WriteXY(NumToString(Number), UpperLeft.Col, UpperLeft.Row,
|
|||
|
Colors.InfoColor);
|
|||
|
if Current then
|
|||
|
Write(CurrentChar)
|
|||
|
else
|
|||
|
Write(' ');
|
|||
|
if AutoCalc then
|
|||
|
Write(AutoCalcLetter)
|
|||
|
else
|
|||
|
Write(' ');
|
|||
|
if DisplayFormulas then
|
|||
|
Write(FormulaDisplayLetter)
|
|||
|
else
|
|||
|
Write(' ');
|
|||
|
end; { Spreadsheet.DisplayRows }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayAllCells;
|
|||
|
{ Displays all of the cells on the screen }
|
|||
|
begin
|
|||
|
DisplayArea.Clear;
|
|||
|
DisplayBlock(ScreenBlock);
|
|||
|
end; { Spreadsheet.DisplayAllCells }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayCell(P : CellPos);
|
|||
|
{ Displays a single cell }
|
|||
|
var
|
|||
|
S : String[ScreenCols];
|
|||
|
Color : Byte;
|
|||
|
begin
|
|||
|
S := CellToFString(P, Color);
|
|||
|
WriteXY(S, ColToX(P.Col), RowToY(P.Row), Color);
|
|||
|
end; { Spreadsheet.DisplayCell }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayCellData;
|
|||
|
{ Displays information about a cell - its type and its contents }
|
|||
|
var
|
|||
|
CP : CellPtr;
|
|||
|
begin
|
|||
|
CP := CellHash.Search(CurrPos);
|
|||
|
with DataArea do
|
|||
|
WriteXY(LeftJustStr(ColToString(CurrPos.Col) +
|
|||
|
RowToString(CurrPos.Row) + ' ' + CP^.Name, 19),
|
|||
|
UpperLeft.Col, UpperLeft.Row, Colors.CellDataColor);
|
|||
|
with ContentsArea do
|
|||
|
begin
|
|||
|
Clear;
|
|||
|
WriteXY(LeftJustStr(CP^.DisplayString(DisplayFormulas,
|
|||
|
MaxDecimalPlaces), Scr.CurrCols), UpperLeft.Col,
|
|||
|
UpperLeft.Row, Colors.ContentsColor);
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.DisplayCellData }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayCellBlock(C1 : Word; R1 : Word;
|
|||
|
C2 : Word; R2 : Word);
|
|||
|
{ Displays all cells within a range of rows and columns }
|
|||
|
var
|
|||
|
P : CellPos;
|
|||
|
begin
|
|||
|
with ScreenBlock do
|
|||
|
begin
|
|||
|
for P.Row := Max(R1, Start.Row) to Min(R2, Stop.Row) do
|
|||
|
begin
|
|||
|
for P.Col := Max(C1, Start.Col) to Min(C2, Stop.Col) do
|
|||
|
DisplayCell(P);
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.DisplayCellBlock }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayBlock(B : Block);
|
|||
|
{ Displays all cells within a certain block }
|
|||
|
begin
|
|||
|
with B do
|
|||
|
DisplayCellBlock(Start.Col, Start.Row, Stop.Col, Stop.Row);
|
|||
|
end; { Spreadsheet.DisplayBlock }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayBlockDiff(B1, B2 : Block);
|
|||
|
{ When a block is extended, this will update the screen to show the new
|
|||
|
block }
|
|||
|
var
|
|||
|
B : Block;
|
|||
|
DisplayMiddle : Boolean;
|
|||
|
begin
|
|||
|
if Compare(B1, B2, SizeOf(Block)) then
|
|||
|
Exit;
|
|||
|
with B do
|
|||
|
begin
|
|||
|
DisplayMiddle := False;
|
|||
|
if B1.Stop.Col <> B2.Stop.Col then
|
|||
|
begin
|
|||
|
B.Start.Row := B1.Start.Row;
|
|||
|
B.Start.Col := Min(Succ(B1.Stop.Col), Succ(B2.Stop.Col));
|
|||
|
B.Stop.Row := Min(B1.Stop.Row, B2.Stop.Row);
|
|||
|
B.Stop.Col := Max(B1.Stop.Col, B2.Stop.Col);
|
|||
|
DisplayBlock(B);
|
|||
|
DisplayMiddle := True;
|
|||
|
end;
|
|||
|
if B1.Stop.Row <> B2.Stop.Row then
|
|||
|
begin
|
|||
|
B.Start.Row := Min(Succ(B1.Stop.Row), Succ(B2.Stop.Row));
|
|||
|
B.Start.Col := B1.Start.Col;
|
|||
|
B.Stop.Row := Max(B1.Stop.Row, B2.Stop.Row);
|
|||
|
B.Stop.Col := Min(B1.Stop.Col, B2.Stop.Col);
|
|||
|
DisplayBlock(B);
|
|||
|
DisplayMiddle := True;
|
|||
|
end;
|
|||
|
if DisplayMiddle then
|
|||
|
begin
|
|||
|
B.Start.Row := Min(Succ(B1.Stop.Row), Succ(B2.Stop.Row));
|
|||
|
B.Start.Col := Min(Succ(B1.Stop.Col), Succ(B2.Stop.Col));
|
|||
|
B.Stop.Row := Max(B1.Stop.Row, B2.Stop.Row);
|
|||
|
B.Stop.Col := Max(B1.Stop.Col, B2.Stop.Col);
|
|||
|
DisplayBlock(B);
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.DisplayBlockDiff }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayCol(Col : Word);
|
|||
|
{ Display a column of cells }
|
|||
|
begin
|
|||
|
with ScreenBlock do
|
|||
|
DisplayCellBlock(Col, Start.Row, Col, Stop.Row);
|
|||
|
end; { Spreadsheet.DisplayCol }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayRow(Row : Word);
|
|||
|
{ Display a row of cells }
|
|||
|
begin
|
|||
|
with ScreenBlock do
|
|||
|
DisplayCellBlock(Start.Col, Row, Stop.Col, Row);
|
|||
|
end; { Spreadsheet.DisplayRow }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayMemory;
|
|||
|
{ Display the amount of free memory }
|
|||
|
begin
|
|||
|
WriteXY(RightJustStr(NumToString(MemAvail), 6), Scr.CurrCols - 5, 1,
|
|||
|
Colors.MemoryColor);
|
|||
|
end; { Spreadsheet.DisplayMemory }
|
|||
|
|
|||
|
procedure Spreadsheet.DisplayFileName;
|
|||
|
{ Display the spreadsheet's file name, and whether or not it has been
|
|||
|
updated }
|
|||
|
var
|
|||
|
S : PathStr;
|
|||
|
begin
|
|||
|
with DataArea do
|
|||
|
begin
|
|||
|
if FileName = '' then
|
|||
|
S := 'No file'
|
|||
|
else
|
|||
|
S := FExpand(FileName);
|
|||
|
WriteXY(LeftJustStr(S, LowerRight.Col - UpperLeft.Col - 20),
|
|||
|
UpperLeft.Col + 21, UpperLeft.Row, Colors.FileNameColor);
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.DisplayFileName }
|
|||
|
|
|||
|
procedure Spreadsheet.Display;
|
|||
|
{ Display the entire spreadsheet }
|
|||
|
begin
|
|||
|
DisplayCols;
|
|||
|
DisplayRows;
|
|||
|
DisplayInfo;
|
|||
|
DisplayAllCells;
|
|||
|
DisplayMemory;
|
|||
|
DisplayCellData;
|
|||
|
DisplayFileName;
|
|||
|
SetChanged(Changed);
|
|||
|
end; { Spreadsheet.Display }
|
|||
|
|
|||
|
procedure Spreadsheet.SetChanged(IsChanged : Boolean);
|
|||
|
{ Sets a spreadsheet as being changed or not changed }
|
|||
|
var
|
|||
|
C : Char;
|
|||
|
begin
|
|||
|
Changed := IsChanged;
|
|||
|
if Changed then
|
|||
|
C := ChangedChar
|
|||
|
else
|
|||
|
C := ' ';
|
|||
|
with DataArea.UpperLeft do
|
|||
|
WriteXY(C, Col + 19, Row, Colors.ChangedColor);
|
|||
|
end; { Spreadsheet.SetChanged }
|
|||
|
|
|||
|
procedure Spreadsheet.MakeCurrent;
|
|||
|
{ Make a spreadsheet the current one }
|
|||
|
begin
|
|||
|
Current := True;
|
|||
|
DisplayInfo;
|
|||
|
end; { Spreadsheet.MakeCurrent }
|
|||
|
|
|||
|
procedure Spreadsheet.MakeNotCurrent;
|
|||
|
{ Make a spreadsheet not the current one }
|
|||
|
begin
|
|||
|
Current := False;
|
|||
|
DisplayInfo;
|
|||
|
end; { Spreadsheet.MakeNotCurrent }
|
|||
|
|
|||
|
procedure Spreadsheet.Update(UDisplay : Boolean);
|
|||
|
{ Update any cells in the spreadsheet that need updating }
|
|||
|
var
|
|||
|
P, U : CellPos;
|
|||
|
CP : CellPtr;
|
|||
|
O : Word;
|
|||
|
begin
|
|||
|
Scr.PrintMessage(MsgRecalc);
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
for P.Row := 1 to LastPos.Row do
|
|||
|
begin
|
|||
|
for P.Col := 1 to LastPos.Col do
|
|||
|
begin
|
|||
|
CP := Search(P);
|
|||
|
if CP^.ShouldUpdate then
|
|||
|
begin
|
|||
|
with FormulaCellPtr(CP)^ do
|
|||
|
begin
|
|||
|
Parser.Init(@CellHash, Formula, MaxCols, MaxRows);
|
|||
|
Parser.Parse;
|
|||
|
Value := Parser.ParseValue;
|
|||
|
Error := Parser.ParseError;
|
|||
|
O := CP^.Overwritten(CellHash, FormatHash, WidthHash,
|
|||
|
LastPos, MaxCols, GetColWidth, DisplayFormulas);
|
|||
|
if (OverwriteHash.Change(CP, O)) and UDisplay and
|
|||
|
(CP^.Loc.Col + O >= ScreenBlock.Start.Col) then
|
|||
|
begin
|
|||
|
U := CP^.Loc;
|
|||
|
for U.Col := CP^.Loc.Col to ScreenBlock.Stop.Col do
|
|||
|
begin
|
|||
|
if ScreenBlock.CellInBlock(U) then
|
|||
|
DisplayCell(U);
|
|||
|
end;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
end;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
if UDisplay then
|
|||
|
DisplayMemory;
|
|||
|
Scr.ClearMessage;
|
|||
|
end; { Spreadsheet.Update }
|
|||
|
|
|||
|
procedure Spreadsheet.ToggleFormulaDisplay;
|
|||
|
{ Change from showing formulas to showing values and vice versa }
|
|||
|
var
|
|||
|
CP : CellPtr;
|
|||
|
OChanged : Boolean;
|
|||
|
begin
|
|||
|
DisplayFormulas := not DisplayFormulas;
|
|||
|
DisplayInfo;
|
|||
|
OChanged := True;
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
CP := FirstItem;
|
|||
|
while (CP <> nil) and OChanged do
|
|||
|
begin
|
|||
|
if CP^.ShouldUpdate then
|
|||
|
OChanged := OverwriteHash.Change(CP, CP^.Overwritten(CellHash,
|
|||
|
FormatHash, WidthHash, LastPos,
|
|||
|
MaxCols, GetColWidth,
|
|||
|
DisplayFormulas));
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
DisplayAllCells;
|
|||
|
DisplayMemory;
|
|||
|
end; { Spreadsheet.ToggleFormulaDisplay }
|
|||
|
|
|||
|
procedure Spreadsheet.SetScreenColStart(NewCol : Word);
|
|||
|
{ Find the starting screen column }
|
|||
|
begin
|
|||
|
ScreenBlock.Start.Col := NewCol;
|
|||
|
FindScreenColStop;
|
|||
|
FindScreenColStart;
|
|||
|
end; { Spreadsheet.SetScreenColStart }
|
|||
|
|
|||
|
procedure Spreadsheet.SetScreenColStop(NewCol : Word);
|
|||
|
{ Find the ending screen column }
|
|||
|
begin
|
|||
|
ScreenBlock.Stop.Col := NewCol;
|
|||
|
FindScreenColStart;
|
|||
|
FindScreenColStop;
|
|||
|
end; { Spreadsheet.SetScreenColStop }
|
|||
|
|
|||
|
procedure Spreadsheet.SetScreenRowStart(NewRow : Word);
|
|||
|
{ Find the starting screen row }
|
|||
|
begin
|
|||
|
ScreenBlock.Start.Row := NewRow;
|
|||
|
FindScreenRowStop;
|
|||
|
end; { Spreadsheet.SetScreenRowStart }
|
|||
|
|
|||
|
procedure Spreadsheet.SetScreenRowStop(NewRow : Word);
|
|||
|
{ Find the ending screen row }
|
|||
|
begin
|
|||
|
ScreenBlock.Stop.Row := NewRow;
|
|||
|
FindScreenRowStart;
|
|||
|
end; { Spreadsheet.SetScreenRowStop }
|
|||
|
|
|||
|
procedure Spreadsheet.FindScreenColStart;
|
|||
|
{ Find the starting screen column when the ending column is known }
|
|||
|
var
|
|||
|
Index, Place : Integer;
|
|||
|
Temp, Width : Byte;
|
|||
|
begin
|
|||
|
with ScreenBlock do
|
|||
|
begin
|
|||
|
Index := 0;
|
|||
|
Place := Succ(DisplayArea.LowerRight.Col);
|
|||
|
Width := ColWidth(Stop.Col);
|
|||
|
repeat
|
|||
|
ColStart^[Index] := Place - Width;
|
|||
|
Dec(Place, Width);
|
|||
|
Inc(Index);
|
|||
|
if Stop.Col - Index = 0 then
|
|||
|
Width := 0
|
|||
|
else
|
|||
|
Width := ColWidth(Stop.Col - Index);
|
|||
|
until (Width = 0) or (Place - Width < DisplayArea.UpperLeft.Col);
|
|||
|
Start.Col := Succ(Stop.Col - Index);
|
|||
|
Dec(Index);
|
|||
|
if ColStart^[Index] <> DisplayArea.UpperLeft.Col then
|
|||
|
begin
|
|||
|
Temp := ColStart^[Index] - DisplayArea.UpperLeft.Col;
|
|||
|
for Place := 0 to Index do
|
|||
|
Dec(ColStart^[Place], Temp);
|
|||
|
end;
|
|||
|
if Index > 0 then
|
|||
|
begin
|
|||
|
for Place := 0 to (Pred(Index) shr 1) do
|
|||
|
begin
|
|||
|
Temp := ColStart^[Index - Place];
|
|||
|
ColStart^[Index - Place] := ColStart^[Place];
|
|||
|
ColStart^[Place] := Temp;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.FindScreenColStart }
|
|||
|
|
|||
|
procedure Spreadsheet.FindScreenColStop;
|
|||
|
{ Find the ending screen column when the starting column is known }
|
|||
|
var
|
|||
|
Index, Place : Byte;
|
|||
|
Width : Byte;
|
|||
|
begin
|
|||
|
with ScreenBlock do
|
|||
|
begin
|
|||
|
Index := 0;
|
|||
|
Place := DisplayArea.UpperLeft.Col;
|
|||
|
Width := ColWidth(Start.Col);
|
|||
|
repeat
|
|||
|
ColStart^[Index] := Place;
|
|||
|
Inc(Place, Width);
|
|||
|
Inc(Index);
|
|||
|
if Longint(Index) + Start.Col > MaxCols then
|
|||
|
Width := 0
|
|||
|
else
|
|||
|
Width := ColWidth(Index + Start.Col);
|
|||
|
until (Width = 0) or (Place + Width > Succ(DisplayArea.LowerRight.Col));
|
|||
|
Stop.Col := Pred(Start.Col + Index);
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.FindScreenColStop }
|
|||
|
|
|||
|
procedure Spreadsheet.FindScreenRowStart;
|
|||
|
{ Find the starting screen row when the ending row is known }
|
|||
|
begin
|
|||
|
with ScreenBlock do
|
|||
|
begin
|
|||
|
if Longint(Stop.Row) - TotalRows < 0 then
|
|||
|
begin
|
|||
|
Start.Row := 1;
|
|||
|
FindScreenRowStop;
|
|||
|
end
|
|||
|
else
|
|||
|
Start.Row := Succ(Stop.Row - TotalRows);
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.FindScreenRowStart }
|
|||
|
|
|||
|
procedure Spreadsheet.FindScreenRowStop;
|
|||
|
{ Find the ending screen row when the starting row is known }
|
|||
|
begin
|
|||
|
with ScreenBlock do
|
|||
|
begin
|
|||
|
if Longint(Start.Row) + TotalRows > Succ(LongInt(MaxRows)) then
|
|||
|
begin
|
|||
|
Stop.Row := MaxRows;
|
|||
|
FindScreenRowStart;
|
|||
|
end
|
|||
|
else
|
|||
|
Stop.Row := Pred(Start.Row + TotalRows);
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.FindScreenRowStop }
|
|||
|
|
|||
|
procedure Spreadsheet.SetBlankArea;
|
|||
|
{ Find the size of the blank area (the area at the right edge of the
|
|||
|
spreadsheet that is not used }
|
|||
|
var
|
|||
|
C : Word;
|
|||
|
begin
|
|||
|
with BlankArea do
|
|||
|
begin
|
|||
|
Move(DisplayArea, BlankArea, SizeOf(DisplayArea));
|
|||
|
with ScreenBlock do
|
|||
|
C := ColStart^[Stop.Col - Start.Col] + ColWidth(Stop.Col);
|
|||
|
if C > DisplayArea.LowerRight.Col then
|
|||
|
NoBlankArea := True
|
|||
|
else begin
|
|||
|
NoBlankArea := False;
|
|||
|
UpperLeft.Col := C;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.SetBlankArea }
|
|||
|
|
|||
|
function Spreadsheet.AddCell(CellType : CellTypes; P : CellPos; E : Boolean;
|
|||
|
V : Extended; I : LStringPtr) : Boolean;
|
|||
|
{ Add a new cell to the spreadsheet }
|
|||
|
var
|
|||
|
CP, S : CellPtr;
|
|||
|
OldLastPos : CellPos;
|
|||
|
Good : Boolean;
|
|||
|
begin
|
|||
|
AddCell := False;
|
|||
|
case CellType of
|
|||
|
ClValue : CP := New(ValueCellPtr, Init(P, E, V));
|
|||
|
ClFormula : CP := New(FormulaCellPtr, Init(P, E, V, I));
|
|||
|
ClText : CP := New(TextCellPtr, Init(P, I));
|
|||
|
ClRepeat : CP := New(RepeatCellPtr, Init(P, I^.Data^[2]));
|
|||
|
end; { case }
|
|||
|
if CP = nil then
|
|||
|
Exit;
|
|||
|
if not CellHash.Add(CP) then
|
|||
|
begin
|
|||
|
Dispose(CP, Done);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
OldLastPos := LastPos;
|
|||
|
LastPos.Col := Max(P.Col, LastPos.Col);
|
|||
|
LastPos.Row := Max(P.Row, LastPos.Row);
|
|||
|
if not OverwriteHash.Add(CP, CP^.Overwritten(CellHash, FormatHash,
|
|||
|
WidthHash, LastPos, MaxCols, GetColWidth,
|
|||
|
DisplayFormulas)) then
|
|||
|
begin
|
|||
|
LastPos := OldLastPos;
|
|||
|
CellHash.Delete(CP^.Loc, S);
|
|||
|
Dispose(CP, Done);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
S := OverwriteHash.Search(CP^.Loc);
|
|||
|
if S <> Empty then
|
|||
|
Good := OverwriteHash.Change(S, S^.Overwritten(CellHash, FormatHash,
|
|||
|
WidthHash, LastPos, MaxCols, GetColWidth,
|
|||
|
DisplayFormulas));
|
|||
|
AddCell := True;
|
|||
|
end; { Spreadsheet.AddCell }
|
|||
|
|
|||
|
procedure Spreadsheet.DeleteCell(P : CellPos; var Deleted : Boolean);
|
|||
|
{ Delete a cell from the spreadsheet }
|
|||
|
var
|
|||
|
CP : CellPtr;
|
|||
|
Good : Boolean;
|
|||
|
begin
|
|||
|
CellHash.Delete(P, CP);
|
|||
|
if CP <> nil then
|
|||
|
begin
|
|||
|
Dispose(CP, Done);
|
|||
|
OverwriteHash.Delete(P);
|
|||
|
if P.Col > 1 then
|
|||
|
begin
|
|||
|
Dec(P.Col);
|
|||
|
CP := OverwriteHash.Search(P);
|
|||
|
if CP = Empty then
|
|||
|
CP := CellHash.Search(P);
|
|||
|
if CP <> Empty then
|
|||
|
Good := OverwriteHash.Change(CP, CP^.Overwritten(CellHash,
|
|||
|
FormatHash, WidthHash, LastPos, MaxCols,
|
|||
|
GetColWidth, DisplayFormulas));
|
|||
|
end;
|
|||
|
Deleted := True;
|
|||
|
end
|
|||
|
else
|
|||
|
Deleted := False;
|
|||
|
end; { Spreadsheet.DeleteCell }
|
|||
|
|
|||
|
procedure Spreadsheet.DeleteBlock(B : Block; var Deleted : Boolean);
|
|||
|
{ Delete a block of cells from the spreadsheet }
|
|||
|
var
|
|||
|
P : CellPos;
|
|||
|
H, D : HashItemPtr;
|
|||
|
Counter : Word;
|
|||
|
CP : CellPtr;
|
|||
|
begin
|
|||
|
Scr.PrintMessage(MsgBlockDelete);
|
|||
|
Deleted := False;
|
|||
|
with CellHash, B do
|
|||
|
begin
|
|||
|
for Counter := 1 to Buckets do
|
|||
|
begin
|
|||
|
H := HashData^[Counter];
|
|||
|
while H <> nil do
|
|||
|
begin
|
|||
|
D := H;
|
|||
|
H := H^.Next;
|
|||
|
Move(D^.Data, CP, SizeOf(CP));
|
|||
|
with CP^ do
|
|||
|
begin
|
|||
|
if CellInBlock(Loc) then
|
|||
|
DeleteCell(Loc, Deleted);
|
|||
|
end; { with }
|
|||
|
end;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
Scr.ClearMessage;
|
|||
|
end; { DeleteBlock }
|
|||
|
|
|||
|
function Spreadsheet.CellToFString(P : CellPos; var Color : Byte) : String;
|
|||
|
{ Create a formatted string from a cell }
|
|||
|
var
|
|||
|
CP : CellPtr;
|
|||
|
S : String;
|
|||
|
S1 : DollarStr;
|
|||
|
F : FormatType;
|
|||
|
ColorFound : Boolean;
|
|||
|
Colr : Byte;
|
|||
|
begin
|
|||
|
ColorFound := True;
|
|||
|
if Current and (SameCellPos(P, CurrPos)) then
|
|||
|
Color := Colors.HighlightColor
|
|||
|
else if BlockOn and (CurrBlock.CellInBlock(P)) then
|
|||
|
Color := Colors.BlockColor
|
|||
|
else
|
|||
|
ColorFound := False;
|
|||
|
CP := CellHash.Search(P);
|
|||
|
if (CP^.HasError) then
|
|||
|
begin
|
|||
|
S := ErrorString;
|
|||
|
S1 := '';
|
|||
|
if ColorFound then
|
|||
|
Inc(Color, Blink)
|
|||
|
else
|
|||
|
Color := Colors.CellErrorColor;
|
|||
|
F := Ord(JCenter) shl JustShift;
|
|||
|
end
|
|||
|
else begin
|
|||
|
S := CP^.FormattedString(OverwriteHash, FormatHash, WidthHash,
|
|||
|
GetColWidth, P, DisplayFormulas, 1,
|
|||
|
ColWidth(P.Col), S1, Colr);
|
|||
|
if not ColorFound then
|
|||
|
Color := Colr;
|
|||
|
F := CP^.Format(FormatHash, DisplayFormulas);
|
|||
|
end;
|
|||
|
case Justification((F shr JustShift) and JustPart) of
|
|||
|
JLeft : CellToFString := S1 + LeftJustStr(S, ColWidth(P.Col) -
|
|||
|
Length(S1));
|
|||
|
JCenter : CellToFString := S1 + CenterStr(S, ColWidth(P.Col) -
|
|||
|
Length(S1));
|
|||
|
JRight : CellToFString := S1 + RightJustStr(S, ColWidth(P.Col) -
|
|||
|
Length(S1));
|
|||
|
end; { case }
|
|||
|
end; { Spreadsheet.CellToFString }
|
|||
|
|
|||
|
procedure Spreadsheet.SetLastPos(DPos : CellPos);
|
|||
|
{ Find the last position used in a spreadsheet }
|
|||
|
var
|
|||
|
CP : CellPtr;
|
|||
|
Counter : Word;
|
|||
|
ColFound, RowFound : Boolean;
|
|||
|
begin
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
ColFound := DPos.Col < LastPos.Col;
|
|||
|
RowFound := DPos.Row < LastPos.Row;
|
|||
|
if (not ColFound) or (not RowFound) then
|
|||
|
begin
|
|||
|
if not ColFound then
|
|||
|
LastPos.Col := 1;
|
|||
|
if not RowFound then
|
|||
|
LastPos.Row := 1;
|
|||
|
CP := FirstItem;
|
|||
|
while CP <> nil do
|
|||
|
begin
|
|||
|
if not ColFound then
|
|||
|
begin
|
|||
|
if CP^.Loc.Col > LastPos.Col then
|
|||
|
begin
|
|||
|
LastPos.Col := CP^.Loc.Col;
|
|||
|
ColFound := LastPos.Col = DPos.Col;
|
|||
|
if ColFound and RowFound then
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
if not RowFound then
|
|||
|
begin
|
|||
|
if CP^.Loc.Row > LastPos.Row then
|
|||
|
begin
|
|||
|
LastPos.Row := CP^.Loc.Row;
|
|||
|
RowFound := LastPos.Row = DPos.Row;
|
|||
|
if ColFound and RowFound then
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.SetLastPos }
|
|||
|
|
|||
|
function Spreadsheet.GetCurrCol : Word;
|
|||
|
{ Find the current column }
|
|||
|
begin
|
|||
|
GetCurrCol := CurrPos.Col;
|
|||
|
end; { Spreadsheet.GetCurrCol }
|
|||
|
|
|||
|
function Spreadsheet.GetCurrRow : Word;
|
|||
|
{ Find the current row }
|
|||
|
begin
|
|||
|
GetCurrRow := CurrPos.Row;
|
|||
|
end; { Spreadsheet.GetCurrRow }
|
|||
|
|
|||
|
function Spreadsheet.ColToX(Col : Word) : Byte;
|
|||
|
{ Find where on the screen a column starts }
|
|||
|
begin
|
|||
|
ColToX := ColStart^[Col - ScreenBlock.Start.Col];
|
|||
|
end; { Spreadsheet.ColToX }
|
|||
|
|
|||
|
function Spreadsheet.RowToY(Row : Word) : Byte;
|
|||
|
{ Find where on the screen a row starts }
|
|||
|
begin
|
|||
|
RowToY := Row + DisplayArea.UpperLeft.Row - ScreenBlock.Start.Row;
|
|||
|
end; { Spreadsheet.RowToY }
|
|||
|
|
|||
|
{$F+}
|
|||
|
|
|||
|
function Spreadsheet.ColWidth(Col : Word) : Byte;
|
|||
|
{ Returns the width of a column }
|
|||
|
var
|
|||
|
Width : Word;
|
|||
|
begin
|
|||
|
Width := WidthHash.Search(Col);
|
|||
|
if Width = 0 then
|
|||
|
ColWidth := DefaultColWidth
|
|||
|
else
|
|||
|
ColWidth := Width;
|
|||
|
end; { Spreadsheet.ColWidth }
|
|||
|
|
|||
|
{$F-}
|
|||
|
|
|||
|
function Spreadsheet.SameCellPos(P1, P2 : CellPos) : Boolean;
|
|||
|
{ Returns True if two cells are at the same position }
|
|||
|
begin
|
|||
|
SameCellPos := Compare(P1, P2, SizeOf(CellPos));
|
|||
|
end; { Spreadsheet.SameCellPos }
|
|||
|
|
|||
|
procedure Spreadsheet.FixOverwrite;
|
|||
|
{ Fixes the overwrite hash table when the formats have been changed }
|
|||
|
var
|
|||
|
CP, D : CellPtr;
|
|||
|
Counter : Word;
|
|||
|
Good : Boolean;
|
|||
|
begin
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
CP := FirstItem;
|
|||
|
while CP <> nil do
|
|||
|
begin
|
|||
|
if not OverwriteHash.Add(CP, CP^.Overwritten(CellHash, FormatHash,
|
|||
|
WidthHash, LastPos, MaxCols, GetColWidth,
|
|||
|
DisplayFormulas)) then
|
|||
|
begin
|
|||
|
CellHash.Delete(CP^.Loc, D);
|
|||
|
Dispose(CP, Done);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
CP := OverwriteHash.Search(CP^.Loc);
|
|||
|
if CP <> Empty then
|
|||
|
Good := OverwriteHash.Change(CP, CP^.Overwritten(CellHash,
|
|||
|
FormatHash, WidthHash, LastPos,
|
|||
|
MaxCols, GetColWidth,
|
|||
|
DisplayFormulas));
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
end; { Spreadsheet.FixOverwrite }
|
|||
|
|
|||
|
function Spreadsheet.FromFile(Name : PathStr) : Boolean;
|
|||
|
{ Reads a spreadsheet from disk }
|
|||
|
var
|
|||
|
Header : String[Length(FileHeader)];
|
|||
|
TotalC : Longint;
|
|||
|
TotalW : Word;
|
|||
|
TotalF : Longint;
|
|||
|
S : SSStream;
|
|||
|
NewLastPos : CellPos;
|
|||
|
begin
|
|||
|
FromFile := True;
|
|||
|
Name := UpperCase(Name);
|
|||
|
S.Init(Name, SOpen);
|
|||
|
if S.Status <> 0 then
|
|||
|
begin
|
|||
|
Scr.PrintError(ErrNoOpen);
|
|||
|
Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces,
|
|||
|
DefaultDefaultDecimalPlaces, DefaultDefaultColWidth);
|
|||
|
Exit;
|
|||
|
end
|
|||
|
else begin
|
|||
|
Header[0] := Chr(Length(FileHeader));
|
|||
|
S.Read(Header[1], Length(FileHeader));
|
|||
|
if (S.Status <> 0) or (Header <> FileHeader) then
|
|||
|
begin
|
|||
|
Scr.PrintError(ErrNotSpreadsheet);
|
|||
|
S.Done;
|
|||
|
Init(0, DefaultMaxCols, DefaultMaxRows, DefaultMaxDecimalPlaces,
|
|||
|
DefaultDefaultDecimalPlaces, DefaultDefaultColWidth);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
FileName := Name;
|
|||
|
S.Read(NewLastPos, SizeOf(NewLastPos));
|
|||
|
S.Read(TotalW, SizeOf(TotalW));
|
|||
|
S.Read(TotalF, SizeOf(TotalF));
|
|||
|
S.Read(TotalC, SizeOf(TotalC));
|
|||
|
if not Init(TotalC, DefaultMaxCols, DefaultMaxRows,
|
|||
|
DefaultMaxDecimalPlaces, DefaultDefaultDecimalPlaces,
|
|||
|
DefaultDefaultColWidth) then
|
|||
|
begin
|
|||
|
S.Done;
|
|||
|
FromFile := False;
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
LastPos := NewLastPos;
|
|||
|
Scr.PrintMessage(MsgLoad);
|
|||
|
FileName := Name;
|
|||
|
WidthHash.Load(S, TotalW);
|
|||
|
FormatHash.Load(S, TotalF);
|
|||
|
CellHash.Load(S, TotalC);
|
|||
|
S.Done;
|
|||
|
FixOverwrite;
|
|||
|
Update(DisplayNo);
|
|||
|
Scr.ClearMessage;
|
|||
|
end;
|
|||
|
FromFile := True;
|
|||
|
end; { Spreadsheet.FromFile }
|
|||
|
|
|||
|
procedure Spreadsheet.ToFile(Name : PathStr);
|
|||
|
{ Writes a spreadsheet to disk }
|
|||
|
var
|
|||
|
Header : String[Length(FileHeader)];
|
|||
|
S : SSStream;
|
|||
|
begin
|
|||
|
S.Init(Name, SCreate);
|
|||
|
if S.Status <> 0 then
|
|||
|
begin
|
|||
|
Scr.PrintError(ErrNoOpen);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
Scr.PrintMessage(MsgSave);
|
|||
|
FileName := Name;
|
|||
|
Header := FileHeader;
|
|||
|
S.Write(Header[1], Length(Header));
|
|||
|
S.Write(LastPos, SizeOf(LastPos));
|
|||
|
S.Write(WidthHash.Items, 2);
|
|||
|
S.Write(FormatHash.Items, SizeOf(FormatHash.Items));
|
|||
|
S.Write(CellHash.Items, SizeOf(CellHash.Items));
|
|||
|
WidthHash.Store(S);
|
|||
|
FormatHash.Store(S);
|
|||
|
CellHash.Store(S);
|
|||
|
Scr.ClearMessage;
|
|||
|
S.Done;
|
|||
|
if S.Status <> 0 then
|
|||
|
Scr.PrintError(ErrDiskFull)
|
|||
|
else
|
|||
|
SetChanged(NotChanged);
|
|||
|
end; { Spreadsheet.ToFile }
|
|||
|
|
|||
|
procedure Spreadsheet.CheckForSave;
|
|||
|
{ Before prompting for a file name, this will check to see if you want to
|
|||
|
save the spreadsheet }
|
|||
|
var
|
|||
|
S : PathStr;
|
|||
|
GoodFile, ESCPressed : Boolean;
|
|||
|
begin
|
|||
|
if Changed and (GetYesNo(PromptSaveYN, ESCPressed)) then
|
|||
|
begin
|
|||
|
S := FileName;
|
|||
|
repeat
|
|||
|
GoodFile := True;
|
|||
|
if S = '' then
|
|||
|
begin
|
|||
|
S := ReadString(PromptFileSave, Pred(SizeOf(PathStr)), ESCPressed);
|
|||
|
if S = '' then
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
if FileExists(S) then
|
|||
|
begin
|
|||
|
GoodFile := GetYesNo(PromptOverwriteFile, ESCPressed);
|
|||
|
if ESCPressed then
|
|||
|
Exit;
|
|||
|
if not GoodFile then
|
|||
|
S := '';
|
|||
|
end;
|
|||
|
until GoodFile;
|
|||
|
ToFile(S);
|
|||
|
end;
|
|||
|
end; { Spreadsheet.CheckForSave }
|
|||
|
|
|||
|
procedure Spreadsheet.ChangeWidth;
|
|||
|
{ Changes the width of a column }
|
|||
|
var
|
|||
|
W, C : Word;
|
|||
|
Good : Boolean;
|
|||
|
P : CellPos;
|
|||
|
O : Word;
|
|||
|
CP : CellPtr;
|
|||
|
begin
|
|||
|
C := GetColumn(PromptColumnWidth, MaxCols, ColSpace);
|
|||
|
if C = 0 then
|
|||
|
Exit;
|
|||
|
W := GetNumber(PromptNewWidth, MinColWidth, MaxColWidth, Good);
|
|||
|
if not Good then
|
|||
|
Exit;
|
|||
|
with WidthHash do
|
|||
|
begin
|
|||
|
Delete(C);
|
|||
|
if W <> DefaultColWidth then
|
|||
|
Good := Add(C, W);
|
|||
|
end; { with }
|
|||
|
if not Good then
|
|||
|
Exit;
|
|||
|
SetScreenColStart(ScreenBlock.Start.Col);
|
|||
|
SetChanged(WasChanged);
|
|||
|
with OverwriteHash do
|
|||
|
begin
|
|||
|
Done;
|
|||
|
Init(OverwriteHashStart(CellHash.Items));
|
|||
|
end;
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
CP := FirstItem;
|
|||
|
while CP <> nil do
|
|||
|
begin
|
|||
|
O := CP^.Overwritten(CellHash, FormatHash, WidthHash, LastPos,
|
|||
|
MaxCols, GetColWidth, DisplayFormulas);
|
|||
|
if O <> 0 then
|
|||
|
Good := OverwriteHash.Add(CP, O);
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
if CurrPos.Col > ScreenBlock.Stop.Col then
|
|||
|
SetScreenColStart(CurrPos.Col);
|
|||
|
Display;
|
|||
|
end; { Spreadsheet.ChangeWidth }
|
|||
|
|
|||
|
function Spreadsheet.CellHashStart(TotalCells : Longint) : BucketRange;
|
|||
|
{ Formula that determines the number of cell hash table buckets }
|
|||
|
begin
|
|||
|
CellHashStart := Max(100, Min(MaxBuckets, TotalCells div 10));
|
|||
|
end; { Spreadsheet.CellHashStart }
|
|||
|
|
|||
|
function Spreadsheet.WidthHashStart(TotalCells : Longint) : BucketRange;
|
|||
|
{ Formula that determines the number of width hash table buckets }
|
|||
|
begin
|
|||
|
WidthHashStart := 10;
|
|||
|
end; { Spreadsheet.WidthHashStart }
|
|||
|
|
|||
|
function Spreadsheet.OverwriteHashStart(TotalCells : Longint) : BucketRange;
|
|||
|
{ Formula that determines the number of overwrite hash table buckets }
|
|||
|
begin
|
|||
|
OverwriteHashStart := 10;
|
|||
|
end; { Spreadsheet.OverwriteHashStart }
|
|||
|
|
|||
|
procedure Spreadsheet.Print;
|
|||
|
{ Prints a spreadsheet to a file or a printer }
|
|||
|
var
|
|||
|
S : PathStr;
|
|||
|
F : Text;
|
|||
|
PageCols : Byte;
|
|||
|
PageV, PageH : Word;
|
|||
|
Finished, GoodFile, Error, Compress, Border, ESCPressed : Boolean;
|
|||
|
StartCol : Word;
|
|||
|
StartRow : Word;
|
|||
|
|
|||
|
procedure WString(S : String);
|
|||
|
begin
|
|||
|
Writeln(F, S);
|
|||
|
if IOResult <> 0 then
|
|||
|
begin
|
|||
|
if S = PrinterName then
|
|||
|
Scr.PrintError(ErrPrinterError)
|
|||
|
else
|
|||
|
Scr.PrintError(ErrDiskFull);
|
|||
|
Error := True;
|
|||
|
Finished := True;
|
|||
|
end;
|
|||
|
end; { WString }
|
|||
|
|
|||
|
function RowStartString(Row : Word) : String;
|
|||
|
begin
|
|||
|
if (PageH = 1) and Border then
|
|||
|
RowStartString := LeftJustStr(RowToString(Row), RowNumberSpace)
|
|||
|
else
|
|||
|
RowStartString := '';
|
|||
|
end; { RowStartString }
|
|||
|
|
|||
|
procedure PrintPage;
|
|||
|
var
|
|||
|
Counter : Word;
|
|||
|
S : String;
|
|||
|
Color, Cols, Rows : Byte;
|
|||
|
P : CellPos;
|
|||
|
begin
|
|||
|
for Counter := 1 to PrintTopMargin do
|
|||
|
begin
|
|||
|
WString('');
|
|||
|
if Error then
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
Rows := Min(PrintRows - PrintTopMargin - PrintBottomMargin,
|
|||
|
Succ(MaxRows - StartRow));
|
|||
|
if Border then
|
|||
|
Dec(Rows);
|
|||
|
Cols := 0;
|
|||
|
Counter := Length(RowStartString(StartRow));
|
|||
|
while Counter <= PageCols do
|
|||
|
begin
|
|||
|
Inc(Counter, ColWidth(Cols + StartCol));
|
|||
|
Inc(Cols);
|
|||
|
end;
|
|||
|
Dec(Cols);
|
|||
|
Cols := Min(Cols, Succ(MaxCols - StartCol));
|
|||
|
if Border and (PageV = 1) then
|
|||
|
begin
|
|||
|
S := FillString(Length(RowStartString(StartRow)), ' ');
|
|||
|
for Counter := StartCol to Pred(StartCol + Cols) do
|
|||
|
S := S + CenterStr(ColToString(Counter), ColWidth(Counter));
|
|||
|
WString(S);
|
|||
|
if Error then
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
for P.Row := StartRow to Pred(StartRow + Rows) do
|
|||
|
begin
|
|||
|
S := RowStartString(P.Row);
|
|||
|
for P.Col := StartCol to Pred(StartCol + Cols) do
|
|||
|
S := S + CellToFString(P, Color);
|
|||
|
WString(S);
|
|||
|
if Error then
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
Inc(StartCol, Cols);
|
|||
|
if (StartCol > LastPos.Col) or (StartCol = 0) then
|
|||
|
begin
|
|||
|
Inc(StartRow, Rows);
|
|||
|
if (StartRow > LastPos.Row) or (StartRow = 0) then
|
|||
|
Finished := True
|
|||
|
else begin
|
|||
|
Inc(PageV);
|
|||
|
PageH := 1;
|
|||
|
StartCol := 1;
|
|||
|
end;
|
|||
|
end
|
|||
|
else
|
|||
|
Inc(PageH);
|
|||
|
Write(F, Chr(FF));
|
|||
|
end; { PrintPage }
|
|||
|
|
|||
|
begin { Spreadsheet.Print }
|
|||
|
repeat
|
|||
|
GoodFile := True;
|
|||
|
S := ReadString(PromptFilePrint, Pred(SizeOf(PathStr)), ESCPressed);
|
|||
|
if ESCPressed then
|
|||
|
Exit;
|
|||
|
if S = '' then
|
|||
|
S := PrinterName
|
|||
|
else begin
|
|||
|
if FileExists(S) then
|
|||
|
begin
|
|||
|
GoodFile := GetYesNo(PromptOverwriteFile, ESCPressed);
|
|||
|
if ESCPressed then
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
end;
|
|||
|
until GoodFile;
|
|||
|
Compress := GetYesNo(PromptCompressPrint, ESCPressed);
|
|||
|
if ESCPressed then
|
|||
|
Exit;
|
|||
|
Border := GetYesNo(PromptBorderPrint, ESCPressed);
|
|||
|
if ESCPressed then
|
|||
|
Exit;
|
|||
|
Error := False;
|
|||
|
{$I-}
|
|||
|
Assign(F, S);
|
|||
|
Rewrite(F);
|
|||
|
if IOResult <> 0 then
|
|||
|
begin
|
|||
|
Scr.PrintError(ErrNoOpen);
|
|||
|
Exit;
|
|||
|
end;
|
|||
|
if Compress then
|
|||
|
begin
|
|||
|
PageCols := PrintCompressedCols;
|
|||
|
Write(F, PrinterCompressChar);
|
|||
|
end
|
|||
|
else
|
|||
|
PageCols := PrintNormalCols;
|
|||
|
PageV := 1;
|
|||
|
PageH := 1;
|
|||
|
StartCol := 1;
|
|||
|
StartRow := 1;
|
|||
|
Finished := False;
|
|||
|
repeat
|
|||
|
PrintPage;
|
|||
|
until Finished;
|
|||
|
Close(F);
|
|||
|
{$I+}
|
|||
|
end; { Spreadsheet.Print }
|
|||
|
|
|||
|
procedure Spreadsheet.DeleteColumn;
|
|||
|
{ Deletes a column from the spreadsheet }
|
|||
|
var
|
|||
|
C : Word;
|
|||
|
Start, Stop, P, OldPos, OldSPos : CellPos;
|
|||
|
Deleted : Boolean;
|
|||
|
OldName : PathStr;
|
|||
|
CP : CellPtr;
|
|||
|
H : HashItemPtr;
|
|||
|
B : Block;
|
|||
|
F : File;
|
|||
|
Good : Boolean;
|
|||
|
begin
|
|||
|
C := GetColumn(PromptColumnDelete, MaxCols, ColSpace);
|
|||
|
if C = 0 then
|
|||
|
Exit;
|
|||
|
OldPos := CurrPos;
|
|||
|
OldSPos := ScreenBlock.Start;
|
|||
|
P.Col := C;
|
|||
|
Deleted := False;
|
|||
|
if P.Col <= LastPos.Col then
|
|||
|
begin
|
|||
|
with B do
|
|||
|
begin
|
|||
|
Start.Col := P.Col;
|
|||
|
Start.Row := 1;
|
|||
|
Stop.Col := P.Col;
|
|||
|
Stop.Row := LastPos.Row;
|
|||
|
Good := FormatHash.Delete(Start, Stop);
|
|||
|
end; { with }
|
|||
|
DeleteBlock(B, Deleted);
|
|||
|
end;
|
|||
|
Dec(LastPos.Col);
|
|||
|
WidthHash.Delete(C);
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
CP := FirstItem;
|
|||
|
while CP <> nil do
|
|||
|
begin
|
|||
|
with CP^ do
|
|||
|
begin
|
|||
|
if Loc.Col > C then
|
|||
|
Dec(Loc.Col);
|
|||
|
if (CP^.ShouldUpdate) and (Loc.Col > C) then
|
|||
|
FixFormulaCol(CP, -1, MaxCols, MaxRows);
|
|||
|
end; { with }
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
with WidthHash do
|
|||
|
begin
|
|||
|
H := FirstItem;
|
|||
|
while H <> nil do
|
|||
|
begin
|
|||
|
if WordPtr(@H^.Data)^ > C then
|
|||
|
Dec(WordPtr(@H^.Data)^);
|
|||
|
H := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
with FormatHash do
|
|||
|
begin
|
|||
|
H := FirstItem;
|
|||
|
while H <> nil do
|
|||
|
begin
|
|||
|
Move(H^.Data, Start, SizeOf(Start));
|
|||
|
Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop));
|
|||
|
if (Start.Col = C) and (Stop.Col = C) then
|
|||
|
Good := Delete(Start, Stop)
|
|||
|
else begin
|
|||
|
if Start.Col > C then
|
|||
|
begin
|
|||
|
Dec(Start.Col);
|
|||
|
Move(Start, H^.Data, SizeOf(Start));
|
|||
|
end;
|
|||
|
if Stop.Col > C then
|
|||
|
begin
|
|||
|
Dec(Stop.Col);
|
|||
|
Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop));
|
|||
|
end;
|
|||
|
end;
|
|||
|
H := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
OldName := FileName;
|
|||
|
ToFile(TempFileName);
|
|||
|
Done;
|
|||
|
Good := FromFile(TempFileName);
|
|||
|
Assign(F, TempFileName);
|
|||
|
Erase(F);
|
|||
|
FileName := OldName;
|
|||
|
if Deleted then
|
|||
|
P.Row := LastPos.Row
|
|||
|
else
|
|||
|
P.Row := 1;
|
|||
|
Dec(P.Col);
|
|||
|
SetLastPos(P);
|
|||
|
MakeCurrent;
|
|||
|
SetChanged(WasChanged);
|
|||
|
CurrPos := OldPos;
|
|||
|
SetScreenColStart(OldSPos.Col);
|
|||
|
SetScreenRowStart(OldSPos.Row);
|
|||
|
Display;
|
|||
|
end; { Spreadsheet.DeleteColumn }
|
|||
|
|
|||
|
procedure Spreadsheet.InsertColumn;
|
|||
|
{ Inserts a column into the spreadsheet }
|
|||
|
var
|
|||
|
C : Word;
|
|||
|
Start, Stop, P, OldPos, OldSPos : CellPos;
|
|||
|
Deleted : Boolean;
|
|||
|
H : HashItemPtr;
|
|||
|
OldName : PathStr;
|
|||
|
CP : CellPtr;
|
|||
|
B : Block;
|
|||
|
F : File;
|
|||
|
Good : Boolean;
|
|||
|
begin
|
|||
|
C := GetColumn(PromptColumnInsert, MaxCols, ColSpace);
|
|||
|
if C = 0 then
|
|||
|
Exit;
|
|||
|
OldPos := CurrPos;
|
|||
|
OldSPos := ScreenBlock.Start;
|
|||
|
Deleted := False;
|
|||
|
if LastPos.Col = MaxCols then
|
|||
|
begin
|
|||
|
with B do
|
|||
|
begin
|
|||
|
Start.Col := MaxCols;
|
|||
|
Start.Row := 1;
|
|||
|
Stop.Col := MaxCols;
|
|||
|
Stop.Row := LastPos.Row;
|
|||
|
Good := FormatHash.Delete(Start, Stop);
|
|||
|
end; { with }
|
|||
|
DeleteBlock(B, Deleted);
|
|||
|
end
|
|||
|
else
|
|||
|
Inc(LastPos.Col);
|
|||
|
P.Col := C;
|
|||
|
WidthHash.Delete(MaxCols);
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
CP := FirstItem;
|
|||
|
while CP <> nil do
|
|||
|
begin
|
|||
|
with CP^ do
|
|||
|
begin
|
|||
|
if Loc.Col >= C then
|
|||
|
Inc(Loc.Col);
|
|||
|
if (CP^.ShouldUpdate) and (Loc.Col >= C) then
|
|||
|
FixFormulaCol(CP, 1, MaxCols, MaxRows);
|
|||
|
end; { with }
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
with WidthHash do
|
|||
|
begin
|
|||
|
H := FirstItem;
|
|||
|
while H <> nil do
|
|||
|
begin
|
|||
|
if WordPtr(@H^.Data)^ >= C then
|
|||
|
Inc(WordPtr(@H^.Data)^);
|
|||
|
H := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
with FormatHash do
|
|||
|
begin
|
|||
|
H := FirstItem;
|
|||
|
while H <> nil do
|
|||
|
begin
|
|||
|
Move(H^.Data, Start, SizeOf(Start));
|
|||
|
Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop));
|
|||
|
if Start.Col >= C then
|
|||
|
begin
|
|||
|
Inc(Start.Col);
|
|||
|
Move(Start, H^.Data, SizeOf(Start));
|
|||
|
end;
|
|||
|
if Stop.Col >= C then
|
|||
|
begin
|
|||
|
Inc(Stop.Col);
|
|||
|
Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop));
|
|||
|
end;
|
|||
|
H := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
OldName := FileName;
|
|||
|
ToFile(TempFileName);
|
|||
|
Done;
|
|||
|
Good := FromFile(TempFileName);
|
|||
|
Assign(F, TempFileName);
|
|||
|
Erase(F);
|
|||
|
FileName := OldName;
|
|||
|
if Deleted then
|
|||
|
P.Row := LastPos.Row
|
|||
|
else
|
|||
|
P.Row := 1;
|
|||
|
if LastPos.Col = MaxCols then
|
|||
|
P.Col := MaxCols
|
|||
|
else
|
|||
|
Inc(P.Col);
|
|||
|
SetLastPos(P);
|
|||
|
MakeCurrent;
|
|||
|
SetChanged(WasChanged);
|
|||
|
CurrPos := OldPos;
|
|||
|
SetScreenColStart(OldSPos.Col);
|
|||
|
SetScreenRowStart(OldSPos.Row);
|
|||
|
Display;
|
|||
|
end; { Spreadsheet.InsertColumn }
|
|||
|
|
|||
|
procedure Spreadsheet.DeleteRow;
|
|||
|
{ Deletes a row from the spreadsheet }
|
|||
|
var
|
|||
|
R : Word;
|
|||
|
Start, Stop, P, OldPos, OldSPos : CellPos;
|
|||
|
Deleted : Boolean;
|
|||
|
OldName : PathStr;
|
|||
|
CP : CellPtr;
|
|||
|
B : Block;
|
|||
|
F : File;
|
|||
|
Good : Boolean;
|
|||
|
H : HashItemPtr;
|
|||
|
begin
|
|||
|
R := GetRow(PromptRowDelete, MaxRows);
|
|||
|
if (R = 0) or (R > LastPos.Row) then
|
|||
|
Exit;
|
|||
|
OldPos := CurrPos;
|
|||
|
OldSPos := ScreenBlock.Start;
|
|||
|
P.Row := R;
|
|||
|
if P.Row <= LastPos.Row then
|
|||
|
begin
|
|||
|
with B do
|
|||
|
begin
|
|||
|
Start.Col := 1;
|
|||
|
Start.Row := P.Row;
|
|||
|
Stop.Col := LastPos.Col;
|
|||
|
Stop.Row := P.Row;
|
|||
|
Good := FormatHash.Delete(Start, Stop);
|
|||
|
end; { with }
|
|||
|
DeleteBlock(B, Deleted);
|
|||
|
end;
|
|||
|
Dec(LastPos.Row);
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
CP := FirstItem;
|
|||
|
while CP <> nil do
|
|||
|
begin
|
|||
|
with CP^ do
|
|||
|
begin
|
|||
|
if Loc.Row > R then
|
|||
|
Dec(Loc.Row);
|
|||
|
if (CP^.ShouldUpdate) and (Loc.Row > R) then
|
|||
|
FixFormulaRow(CP, -1, MaxCols, MaxRows);
|
|||
|
end; { with }
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
with FormatHash do
|
|||
|
begin
|
|||
|
H := FirstItem;
|
|||
|
while H <> nil do
|
|||
|
begin
|
|||
|
Move(H^.Data, Start, SizeOf(Start));
|
|||
|
Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop));
|
|||
|
if (Start.Row = R) and (Stop.Row = R) then
|
|||
|
Good := Delete(Start, Stop)
|
|||
|
else begin
|
|||
|
if Start.Row > R then
|
|||
|
begin
|
|||
|
Dec(Start.Row);
|
|||
|
Move(Start, H^.Data, SizeOf(Start));
|
|||
|
end;
|
|||
|
if Stop.Row > R then
|
|||
|
begin
|
|||
|
Dec(Stop.Row);
|
|||
|
Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop));
|
|||
|
end;
|
|||
|
end;
|
|||
|
H := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
OldName := FileName;
|
|||
|
ToFile(TempFileName);
|
|||
|
Done;
|
|||
|
Good := FromFile(TempFileName);
|
|||
|
Assign(F, TempFileName);
|
|||
|
Erase(F);
|
|||
|
FileName := OldName;
|
|||
|
if Deleted then
|
|||
|
P.Col := LastPos.Col
|
|||
|
else
|
|||
|
P.Col := 1;
|
|||
|
Dec(P.Row);
|
|||
|
SetLastPos(P);
|
|||
|
MakeCurrent;
|
|||
|
SetChanged(WasChanged);
|
|||
|
CurrPos := OldPos;
|
|||
|
SetScreenColStart(OldSPos.Col);
|
|||
|
SetScreenRowStart(OldSPos.Row);
|
|||
|
Display;
|
|||
|
end; { Spreadsheet.DeleteRow }
|
|||
|
|
|||
|
procedure Spreadsheet.InsertRow;
|
|||
|
{ Inserts a row into the spreadsheet }
|
|||
|
var
|
|||
|
R : Word;
|
|||
|
Start, Stop, P, OldPos, OldSPos : CellPos;
|
|||
|
Deleted : Boolean;
|
|||
|
OldName : PathStr;
|
|||
|
CP : CellPtr;
|
|||
|
B : Block;
|
|||
|
F : File;
|
|||
|
Good : Boolean;
|
|||
|
H : HashItemPtr;
|
|||
|
begin
|
|||
|
R := GetRow(PromptRowInsert, MaxRows);
|
|||
|
if (R = 0) or (R > LastPos.Row) then
|
|||
|
Exit;
|
|||
|
OldPos := CurrPos;
|
|||
|
OldSPos := ScreenBlock.Start;
|
|||
|
if LastPos.Row = MaxRows then
|
|||
|
begin
|
|||
|
with B do
|
|||
|
begin
|
|||
|
Start.Col := 1;
|
|||
|
Start.Row := MaxRows;
|
|||
|
Stop.Col := LastPos.Col;
|
|||
|
Stop.Row := MaxRows;
|
|||
|
Good := FormatHash.Delete(Start, Stop);
|
|||
|
end; { with }
|
|||
|
DeleteBlock(B, Deleted);
|
|||
|
end
|
|||
|
else
|
|||
|
Inc(LastPos.Row);
|
|||
|
P.Row := R;
|
|||
|
with CellHash do
|
|||
|
begin
|
|||
|
CP := FirstItem;
|
|||
|
while CP <> nil do
|
|||
|
begin
|
|||
|
with CP^ do
|
|||
|
begin
|
|||
|
if Loc.Row >= R then
|
|||
|
Inc(Loc.Row);
|
|||
|
if (CP^.ShouldUpdate) and (Loc.Row >= R) then
|
|||
|
FixFormulaRow(CP, 1, MaxCols, MaxRows);
|
|||
|
end; { with }
|
|||
|
CP := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
with FormatHash do
|
|||
|
begin
|
|||
|
H := FirstItem;
|
|||
|
while H <> nil do
|
|||
|
begin
|
|||
|
Move(H^.Data, Start, SizeOf(Start));
|
|||
|
Move(H^.Data[SizeOf(CellPos)], Stop, SizeOf(Stop));
|
|||
|
if Start.Row >= R then
|
|||
|
begin
|
|||
|
Inc(Start.Row);
|
|||
|
Move(Start, H^.Data, SizeOf(Start));
|
|||
|
end;
|
|||
|
if Stop.Row >= R then
|
|||
|
begin
|
|||
|
Inc(Stop.Row);
|
|||
|
Move(Stop, H^.Data[SizeOf(CellPos)], SizeOf(Stop));
|
|||
|
end;
|
|||
|
H := NextItem;
|
|||
|
end;
|
|||
|
end; { with }
|
|||
|
OldName := FileName;
|
|||
|
ToFile(TempFileName);
|
|||
|
Done;
|
|||
|
Good := FromFile(TempFileName);
|
|||
|
Assign(F, TempFileName);
|
|||
|
Erase(F);
|
|||
|
FileName := OldName;
|
|||
|
if Deleted then
|
|||
|
P.Col := LastPos.Col
|
|||
|
else
|
|||
|
P.Col := 1;
|
|||
|
if LastPos.Row = MaxRows then
|
|||
|
P.Row := MaxRows
|
|||
|
else
|
|||
|
Inc(P.Row);
|
|||
|
SetLastPos(P);
|
|||
|
MakeCurrent;
|
|||
|
SetChanged(WasChanged);
|
|||
|
CurrPos := OldPos;
|
|||
|
SetScreenColStart(OldSPos.Col);
|
|||
|
SetScreenRowStart(OldSPos.Row);
|
|||
|
Display;
|
|||
|
end; { Spreadsheet.InsertRow }
|
|||
|
|
|||
|
end.
|
|||
|
|