{ Copyright (c) 1989 by Borland International, Inc. } unit TCCell; { Turbo Pascal 5.5 object-oriented example cell routines. This unit is used by TCALC.PAS. See TCALC.DOC for an more information about this example. } {$N+,S-} interface uses Objects, TCUtil, TCLStr, TCScreen, TCHash; const DollarString = ' $ '; RepeatFirstChar = '\'; TextFirstChar = ' '; EmptyCellName = 'Empty'; ValueCellName = 'Value'; TextCellName = 'Text'; FormulaCellName = 'Formula'; RepeatCellName = 'Repeat'; DecPlacesPart = $0F; JustShift = 4; JustPart = $03; DollarPart = $40; CommasPart = $80; NoMemory = 203; type SSStream = object(DosStream) procedure RegisterTypes; virtual; end; CellTypes = (ClEmpty, ClValue, ClText, ClFormula, ClRepeat); CellPos = record Col : Word; Row : Word; end; FormatType = Byte; Justification = (JLeft, JCenter, JRight); DollarStr = String[Length(DollarString)]; Block = object Start, Stop : CellPos; constructor Init(InitStart : CellPos); function ExtendTo(NewLoc : CellPos) : Boolean; function CellInBlock(CheckCell : CellPos) : Boolean; end; CellHashTablePtr = ^CellHashTable; CellPtr = ^Cell; CellHashTable = object(HashTable) { Keeps pointers to all cells } CurrCell : CellPtr; { Information about the cell that is being } CurrLoc : CellPos; { added, deleted, or searched for } constructor Init(InitBuckets : BucketRange); destructor Done; function Add(ACell : CellPtr) : Boolean; procedure Delete(DelLoc : CellPos; var DeletedCell : CellPtr); { Removes a cell from the hash table } function Search(SPos : CellPos) : CellPtr; { Searches for a cell in the hash table } function HashValue : Word; virtual; { Computes the hash value of the cell } function Found(Item : HashItemPtr) : Boolean; virtual; { Returns True if the hash item being searched for is found } procedure CreateItem(var Item : HashItemPtr); virtual; { Fills in the information for a new hash item } function ItemSize : HashItemSizeRange; virtual; procedure Load(var S : SSStream; Total : Longint); procedure Store(var S : SSStream); function FirstItem : CellPtr; function NextItem : CellPtr; end; FormatHashTable = object(HashTable) CurrStart, CurrStop : CellPos; CurrFormat : FormatType; constructor Init; destructor Done; function Overwrite(NewStart, NewStop : CellPos) : Boolean; function Add(NewStart, NewStop : CellPos; NewFormat : FormatType) : Boolean; function Delete(DStart, DStop : CellPos) : Boolean; function Search(SPos : CellPos; var F : FormatType) : Boolean; function HashValue : Word; virtual; function Found(Item : HashItemPtr) : Boolean; virtual; procedure CreateItem(var Item : HashItemPtr); virtual; function ItemSize : HashItemSizeRange; virtual; procedure Load(var S : SSStream; Total : Longint); procedure Store(var S : SSStream); end; WidthHashTable = object(HashTable) CurrCol : Word; CurrWidth : Byte; DefaultColWidth : Byte; constructor Init(InitBuckets : BucketRange; InitDefaultColWidth : Byte); destructor Done; function Add(SCol : Word; NewWidth : Byte) : Boolean; procedure Delete(Col : Word); function Search(Col : Word) : Byte; function HashValue : Word; virtual; function Found(Item : HashItemPtr) : Boolean; virtual; procedure CreateItem(var Item : HashItemPtr); virtual; function ItemSize : HashItemSizeRange; virtual; function GetDefaultColWidth : Byte; procedure Load(var S : SSStream; Total : Longint); procedure Store(var S : SSStream); end; OverwriteHashTable = object(HashTable) CurrCell : CellPtr; CurrPos : CellPos; EndCol : Word; constructor Init(InitBuckets : BucketRange); destructor Done; function Add(SCell : CellPtr; Overwritten : Word) : Boolean; procedure Delete(SPos : CellPos); function Change(SCell : CellPtr; Overwritten : Word) : Boolean; function Search(SPos : CellPos) : CellPtr; function HashValue : Word; virtual; function Found(Item : HashItemPtr) : Boolean; virtual; procedure CreateItem(var Item : HashItemPtr); virtual; function ItemSize : HashItemSizeRange; virtual; end; GetColWidthFunc = function(var WHash : WidthHashTable; C : Word) : Byte; Cell = object(Base) Loc : CellPos; constructor Init(InitLoc : CellPos); destructor Done; virtual; function CellType : CellTypes; virtual; function LegalValue : Boolean; virtual; function Name : String; virtual; function Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; virtual; function Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; virtual; function Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; virtual; function ShouldUpdate : Boolean; virtual; function HasError : Boolean; virtual; function CurrValue : Extended; virtual; function OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; virtual; procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; function DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; virtual; function FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; virtual; function CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; virtual; end; EmptyCellPtr = ^EmptyCell; EmptyCell = object(Cell) constructor Init; function CellType : CellTypes; virtual; function LegalValue : Boolean; virtual; function Name : String; virtual; function Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; virtual; function Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; virtual; function Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; virtual; function ShouldUpdate : Boolean; virtual; function HasError : Boolean; virtual; function CurrValue : Extended; virtual; function OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; virtual; procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; function DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; virtual; function FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; virtual; function CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; virtual; end; ValueCellPtr = ^ValueCell; ValueCell = object(Cell) Error : Boolean; Value : Extended; { A cell with a numeric value } constructor Init(InitLoc : CellPos; InitError : Boolean; InitValue : Extended); function CellType : CellTypes; virtual; function LegalValue : Boolean; virtual; function Name : String; virtual; function Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; virtual; function Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; virtual; function Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; virtual; function ShouldUpdate : Boolean; virtual; function HasError : Boolean; virtual; function CurrValue : Extended; virtual; function OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; virtual; procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; function DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; virtual; function FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; virtual; function CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; virtual; constructor Load(var S : SSStream); procedure Store(var S : SSStream); end; TextCellPtr = ^TextCell; TextCell = object(Cell) Txt : LStringPtr; { A cell with text } constructor Init(InitLoc : CellPos; InitTxt : LStringPtr); destructor Done; virtual; function CellType : CellTypes; virtual; function LegalValue : Boolean; virtual; function Name : String; virtual; function Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; virtual; function Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; virtual; function Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; virtual; function ShouldUpdate : Boolean; virtual; function HasError : Boolean; virtual; function CurrValue : Extended; virtual; function OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; virtual; procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; function DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; virtual; function FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; virtual; function CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; virtual; constructor Load(var S : SSStream); procedure Store(var S : SSStream); end; FormulaCellPtr = ^FormulaCell; FormulaCell = object(Cell) Error : Boolean; Value : Extended; Formula : LStringPtr; { A cell with a formula } constructor Init(InitLoc : CellPos; InitError : Boolean; InitValue : Extended; InitFormula : LStringPtr); destructor Done; virtual; function CellType : CellTypes; virtual; function LegalValue : Boolean; virtual; function Name : String; virtual; function Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; virtual; function Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; virtual; function Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; virtual; function ShouldUpdate : Boolean; virtual; function HasError : Boolean; virtual; function CurrValue : Extended; virtual; function OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; virtual; procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; function DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; virtual; function FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; virtual; function CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; virtual; constructor Load(var S : SSStream); procedure Store(var S : SSStream); function GetFormula : LStringPtr; end; RepeatCellPtr = ^RepeatCell; RepeatCell = object(Cell) RepeatChar : Char; { A cell with text that will repeat - used for underlining, etc. } constructor Init(InitLoc : CellPos; InitChar : Char); function CellType : CellTypes; virtual; function LegalValue : Boolean; virtual; function Name : String; virtual; function Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; virtual; function Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; virtual; function Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; virtual; function ShouldUpdate : Boolean; virtual; function HasError : Boolean; virtual; function CurrValue : Extended; virtual; function OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; virtual; procedure EditString(MaxDecPlaces : Byte; var L : LStringPtr); virtual; function DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; virtual; function FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; virtual; function CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; virtual; constructor Load(var S : SSStream); procedure Store(var S : SSStream); end; var Empty : CellPtr; { This is a special cell. It is used as the return value if a cell cannot be found so that the EmptyCell methods can be executed instead of having special routines that act differently depending on whether a cell is found ot not. } implementation var SavedExitProc : Pointer; procedure SSStream.RegisterTypes; { Registers the different cell types so that they will be written out correctly to disk } begin DosStream.RegisterTypes; Register(TypeOf(ValueCell), @ValueCell.Store, @ValueCell.Load); Register(TypeOf(TextCell), @TextCell.Store, @TextCell.Load); Register(TypeOf(FormulaCell), @FormulaCell.Store, @FormulaCell.Load); Register(TypeOf(RepeatCell), @RepeatCell.Store, @RepeatCell.Load); end; { SSStream.RegisterTypes } constructor Block.Init(InitStart : CellPos); { Initializes a block of cells, setting the end to be the same as the start } begin Start := InitStart; Stop := Start; end; { Block.Init } function Block.ExtendTo(NewLoc : CellPos) : Boolean; { Extends a block to a new position, as long as the new position is to the right and down from the old position } begin if (NewLoc.Col >= Start.Col) and (NewLoc.Row >= Start.Row) then begin Stop := NewLoc; ExtendTo := True; end else ExtendTo := False; end; { Block.ExtendTo } function Block.CellInBlock(CheckCell : CellPos) : Boolean; { Checks to see if a cell is inside a particular block } begin CellInBlock := (CheckCell.Col >= Start.Col) and (CheckCell.Col <= Stop.Col) and (CheckCell.Row >= Start.Row) and (CheckCell.Row <= Stop.Row); end; { Block.CellInBlock } constructor CellHashTable.Init(InitBuckets : BucketRange); { Initializes a cell hash table, which stores pointers to the cells in a spreadsheet } begin if not HashTable.Init(InitBuckets) then Fail; end; { CellHashTable.Init } destructor CellHashTable.Done; { Removes a cell hash table from memory } var CP : CellPtr; begin CP := FirstItem; while CP <> nil do begin Dispose(CP, Done); CP := NextItem; end; HashTable.Done; end; { CellHashTable.Done } function CellHashTable.Add(ACell : CellPtr) : Boolean; { Adds a cell to a cell hash table } begin CurrCell := ACell; CurrLoc := CurrCell^.Loc; Add := HashTable.Add; end; { CellHashTable.Add } procedure CellHashTable.Delete(DelLoc : CellPos; var DeletedCell : CellPtr); { Deletes a cell from a cell hash table } begin CurrLoc := DelLoc; HashTable.Delete(@DeletedCell); end; { CellHashTable.Delete } function CellHashTable.Search(SPos : CellPos) : CellPtr; { Searches for a cell in a cell hash table, returning the cell if found, or returning the Empty cell if not found } var I : HashItemPtr; C : CellPtr; begin CurrLoc := SPos; I := HashTable.Search; if I = nil then Search := Empty else begin Move(I^.Data, C, SizeOf(C)); Search := C; end; end; { CellHashTable.Search } function CellHashTable.HashValue : Word; { Calculates the hash value of a cell } begin HashValue := CurrLoc.Col + CurrLoc.Row; end; { CellHashTable.HashValue } function CellHashTable.Found(Item : HashItemPtr) : Boolean; { Checks to see if a hash item is the one searched for by comparing the location information in both } var C : CellPtr; begin Move(Item^.Data, C, SizeOf(C)); Found := Compare(C^.Loc, CurrLoc, SizeOf(CurrLoc)); end; { CellHashTable.Found } procedure CellHashTable.CreateItem(var Item : HashItemPtr); { Writes the cell poionter information out to the hash item } begin Move(CurrCell, Item^.Data, SizeOf(CurrCell)); end; { CellHashTable.CreateItem } function CellHashTable.ItemSize : HashItemSizeRange; { The hash item size is current - just cell pointers are stored } begin ItemSize := SizeOf(CurrCell); end; { CellHashTable.ItemSize } procedure CellHashTable.Load(var S : SSStream; Total : Longint); { Loads a cell hash table from disk } var Counter : Longint; begin for Counter := 1 to Total do begin if not Add(CellPtr(S.Get)) then begin S.Error(NoMemory); Exit; end; end; end; { CellHashTable.Load } procedure CellHashTable.Store(var S : SSStream); { Writes a cell hash table to disk } var CP : CellPtr; begin CP := FirstItem; while CP <> nil do begin S.Put(CP); CP := NextItem; end; end; { CellHashTable.Store } function HashItemPtrToCellPtr(H : HashItemPtr) : CellPtr; { Converts a hash item pointer to a cell pointer } var CP : CellPtr; begin if H = nil then HashItemPtrToCellPtr := nil else begin Move(H^.Data, CP, SizeOf(CP)); HashItemPtrToCellPtr := CP; end; end; { HashItemPtrToCellPtr } function CellHashTable.FirstItem : CellPtr; { Returns the first hash item in a cell hash table } begin FirstItem := HashItemPtrToCellPtr(HashTable.FirstItem); end; { CellHashTable.FirstItem } function CellHashTable.NextItem : CellPtr; { Returns the second and subsequent hash items in a cell hash table } begin NextItem := HashItemPtrToCellPtr(HashTable.NextItem); end; { CellHashTable.NextItem } constructor WidthHashTable.Init(InitBuckets : BucketRange; InitDefaultColWidth : Byte); { Initializes the width hash table, which stores column widths that are different than the default. It stores the column and the width in the hash table } begin if not HashTable.Init(InitBuckets) then Fail; DefaultColWidth := InitDefaultColWidth; end; { WidthHashTable.Init } destructor WidthHashTable.Done; begin HashTable.Done; end; { WidthHashTable.Done } function WidthHashTable.Add(SCol : Word; NewWidth : Byte) : Boolean; begin CurrCol := SCol; CurrWidth := NewWidth; Add := HashTable.Add; end; { WidthHashTable } procedure WidthHashTable.Delete(Col : Word); begin CurrCol := Col; HashTable.Delete(nil); end; { WidthHashTable.Delete } function WidthHashTable.Search(Col : Word) : Byte; var I : HashItemPtr; W : Byte; begin CurrCol := Col; I := HashTable.Search; if I = nil then Search := 0 else begin Move(I^.Data[SizeOf(CurrCol)], W, SizeOf(W)); Search := W; end; end; { WidthHashTable.Search } function WidthHashTable.HashValue : Word; begin HashValue := CurrCol; end; { WidthHashTable.HashValue } function WidthHashTable.Found(Item : HashItemPtr) : Boolean; var C : Word; begin Move(Item^.Data, C, SizeOf(C)); Found := CurrCol = C; end; { WidthHashTable.Found } procedure WidthHashTable.CreateItem(var Item : HashItemPtr); begin Move(CurrCol, Item^.Data, SizeOf(CurrCol)); Move(CurrWidth, Item^.Data[SizeOf(CurrCol)], SizeOf(CurrWidth)); end; { WidthHashTable.CreateItem } function WidthHashTable.ItemSize : HashItemSizeRange; begin ItemSize := SizeOf(CurrCol) + SizeOf(CurrWidth); end; { WidthHashTable.ItemSize } function WidthHashTable.GetDefaultColWidth : Byte; begin GetDefaultColWidth := DefaultColWidth; end; { WidthHashTable.GetDefaultColWidth } procedure WidthHashTable.Load(var S : SSStream; Total : Longint); var Counter : Longint; Col : Word; Width : Byte; begin for Counter := 1 to Total do begin S.Read(Col, SizeOf(Col)); S.Read(Width, SizeOf(Width)); if not Add(Col, Width) then begin S.Error(NoMemory); Exit; end; end; end; { WidthHashTable.Load } procedure WidthHashTable.Store(var S : SSStream); var H : HashItemPtr; Col : Word; Width : Byte; begin H := FirstItem; while H <> nil do begin Move(H^.Data, Col, SizeOf(Col)); S.Write(Col, SizeOf(Col)); Move(H^.Data[SizeOf(Col)], Width, SizeOf(Width)); S.Write(Width, SizeOf(Width)); H := NextItem; end; end; { WidthHashTable.Store } constructor FormatHashTable.Init; { Initializes a format hash table, which is used to store formatted areas that differ from the default. The area and the format are stored in the hash table } begin if not HashTable.Init(1) then { Use a single bucket so that a search Fail; will be possible } end; { FormatHashTable.Init } destructor FormatHashTable.Done; begin HashTable.Done; end; { FormatHashTable.Done } function FormatHashTable.Overwrite(NewStart, NewStop : CellPos) : Boolean; { Checks to see if a new format area has overwritten an old one, requiring the old area to be overwritten or broken into parts } var H : HashItemPtr; AStart, AStop, BStart, BStop : CellPos; OldF, F : FormatType; P : CellPos; Added : Boolean; begin Overwrite := False; H := HashData^[1]; while H <> nil do begin Move(H^.Data, BStart, SizeOf(CellPos)); Move(H^.Data[SizeOf(CellPos)], BStop, SizeOf(CellPos)); if ((((NewStart.Col >= BStart.Col) and (NewStart.Col <= BStop.Col)) or ((NewStop.Col >= BStart.Col) and (NewStop.Col <= BStop.Col))) and (((NewStart.Row >= BStart.Row) and (NewStart.Row <= BStop.Row)) or ((NewStop.Row >= BStart.Row) and (NewStop.Row <= BStop.Row)))) or ((((BStart.Col >= NewStart.Col) and (BStart.Col <= NewStop.Col)) or ((BStop.Col >= NewStart.Col) and (BStop.Col <= NewStop.Col))) and (((BStart.Row >= NewStart.Row) and (BStart.Row <= NewStop.Row)) or ((BStop.Row >= NewStart.Row) and (BStop.Row <= NewStop.Row)))) then begin Move(H^.Data[SizeOf(CellPos) shl 1], F, SizeOf(F)); CurrStart := BStart; CurrStop := BStop; HashTable.Delete(nil); if BStart.Row < NewStart.Row then begin AStart := BStart; AStop.Col := BStop.Col; AStop.Row := Pred(NewStart.Row); if not Add(AStart, AStop, F) then Exit; end; if BStop.Row > NewStop.Row then begin AStart.Col := BStart.Col; AStart.Row := Succ(NewStop.Row); AStop.Col := BStop.Col; AStop.Row := BStop.Row; if not Add(AStart, AStop, F) then Exit; end; if BStart.Col < NewStart.Col then begin AStart.Col := BStart.Col; AStart.Row := Max(BStart.Row, NewStart.Row); AStop.Col := Pred(NewStart.Col); AStop.Row := Min(BStop.Row, NewStop.Row); if not Add(AStart, AStop, F) then Exit; end; if BStop.Col > NewStop.Col then begin AStart.Col := Succ(NewStop.Col); AStart.Row := Max(BStart.Row, NewStart.Row); AStop.Col := BStop.Col; AStop.Row := Min(BStop.Row, NewStop.Row); if not Add(AStart, AStop, F) then Exit; end; end; H := H^.Next; end; Overwrite := True; end; { FormatHashTable.Overwrite } function FormatHashTable.Add(NewStart, NewStop : CellPos; NewFormat : FormatType) : Boolean; begin if not Overwrite(NewStart, NewStop) then begin Add := False; Exit; end; CurrStart := NewStart; CurrStop := NewStop; CurrFormat := NewFormat; Add := HashTable.Add; end; { FormatHashTable.Add } function FormatHashTable.Delete(DStart, DStop : CellPos) : Boolean; begin Delete := Overwrite(DStart, DStop); end; { FormatHashTable.Delete } function FormatHashTable.Search(SPos : CellPos; var F : FormatType) : Boolean; var H : HashItemPtr; begin CurrStart := SPos; H := HashTable.Search; if H = nil then Search := False else begin Move(H^.Data[SizeOf(CellPos) shl 1], F, SizeOf(F)); Search := True; end; end; { FormatHashTable.Search } function FormatHashTable.HashValue : Word; { Since the hash table has only one bucket, the hash value is always 1 } begin HashValue := 1; end; { FormatHashTable.HashValue } function FormatHashTable.Found(Item : HashItemPtr) : Boolean; var P : CellPos; B : Block; Start, Stop : CellPos; Good : Boolean; begin Move(Item^.Data, Start, SizeOf(CellPos)); Move(Item^.Data[SizeOf(CellPos)], Stop, SizeOf(CellPos)); B.Init(Start); B.Stop := Stop; Found := B.CellInBlock(CurrStart); end; { FormatHashTable.Found } procedure FormatHashTable.CreateItem(var Item : HashItemPtr); begin with Item^ do begin Move(CurrStart, Data, SizeOf(CellPos)); Move(CurrStop, Data[SizeOf(CellPos)], SizeOf(CellPos)); Move(CurrFormat, Data[SizeOf(CellPos) shl 1], SizeOf(CurrFormat)); end; { with } end; { FormatHashTable.CreateItem } function FormatHashTable.ItemSize : HashItemSizeRange; begin ItemSize := (SizeOf(CellPos) shl 1) + SizeOf(FormatType); end; { FormatHashTable.ItemSize } procedure FormatHashTable.Load(var S : SSStream; Total : Longint); var Counter : Longint; C1, C2 : CellPos; Format : FormatType; begin for Counter := 1 to Total do begin S.Read(C1, SizeOf(C1)); S.Read(C2, SizeOf(C2)); S.Read(Format, SizeOf(Format)); if not Add(C1, C2, Format) then begin S.Error(NoMemory); Exit; end; end; end; { FormatHashTable.Load } procedure FormatHashTable.Store(var S : SSStream); var H : HashItemPtr; C : CellPos; Format : Byte; begin H := FirstItem; while H <> nil do begin Move(H^.Data, C, SizeOf(C)); S.Write(C, SizeOf(C)); Move(H^.Data[SizeOf(CellPos)], C, SizeOf(C)); S.Write(C, SizeOf(C)); Move(H^.Data[SizeOf(CellPos) shl 1], Format, SizeOf(Format)); S.Write(Format, SizeOf(Format)); H := NextItem; end; end; { FormatHashTable.Store } constructor OverwriteHashTable.Init(InitBuckets : BucketRange); { Initializes an overwrite hash table, which keeps track of which cells are overwritten by other cells } begin if not HashTable.Init(InitBuckets) then Fail; end; { OverwriteHashTable.Init } destructor OverwriteHashTable.Done; begin HashTable.Done; end; { OverwriteHashTable.Done } function OverwriteHashTable.Add(SCell : CellPtr; Overwritten : Word) : Boolean; var CP : CellPtr; begin if Overwritten = 0 then begin Add := True; Exit; end; CP := Search(SCell^.Loc); if CP <> Empty then begin if not Change(CP, Pred(SCell^.Loc.Col)) then begin Add := False; Exit; end; end; CurrCell := SCell; CurrPos := SCell^.Loc; EndCol := CurrPos.Col + Overwritten; Add := HashTable.Add; end; { OverwriteHashTable.Add } procedure OverwriteHashTable.Delete(SPos : CellPos); begin CurrPos := SPos; HashTable.Delete(nil); end; { OverwriteHashTable.Delete } function OverwriteHashTable.Change(SCell : CellPtr; Overwritten : Word) : Boolean; begin if Overwritten = 0 then begin Delete(SCell^.Loc); Change := True; end else begin CurrCell := SCell; CurrPos := CurrCell^.Loc; EndCol := SCell^.Loc.Col + Overwritten; Change := HashTable.Change; end; end; { OverwriteHashTable.Change } function OverwriteHashTable.Search(SPos : CellPos) : CellPtr; var I : HashItemPtr; C : CellPtr; begin CurrPos := SPos; I := HashTable.Search; if I = nil then Search := Empty else begin Move(I^.Data, C, SizeOf(C)); Search := C; end; end; { OverwriteHashTable.Search } function OverwriteHashTable.HashValue : Word; begin HashValue := CurrPos.Row; end; { OverwriteHashTable.HashValue } function OverwriteHashTable.Found(Item : HashItemPtr) : Boolean; var C : CellPtr; E : Word; begin Move(Item^.Data, C, SizeOf(C)); Move(Item^.Data[SizeOf(C)], E, SizeOf(E)); with CurrPos do Found := (Row = C^.Loc.Row) and (Col >= C^.Loc.Col) and (Col <= E); end; { OverwriteHashTable.Found } procedure OverwriteHashTable.CreateItem(var Item : HashItemPtr); begin Move(CurrCell, Item^.Data, SizeOf(CurrCell)); Move(EndCol, Item^.Data[SizeOf(CurrCell)], SizeOf(EndCol)); end; { OverwriteHashTable.CreateItem } function OverwriteHashTable.ItemSize : HashItemSizeRange; begin ItemSize := SizeOf(CurrCell) + SizeOf(EndCol); end; { OverwriteHashTable.ItemSize } constructor Cell.Init(InitLoc : CellPos); { Initializes a cell's location } begin Loc := InitLoc; end; { Cell.Init } destructor Cell.Done; { Frees memory used by the cell } begin end; { Cell.Done } function Cell.CellType : CellTypes; { Returns the type of a cell - used in copying cells } begin Abstract('Cell.CellType'); end; { Cell.CellType } function Cell.LegalValue : Boolean; { Returns True if the cell has a legal numeric value } begin Abstract('Cell.LegalValue'); end; { Cell.LegalValue } function Cell.Name : String; { Returns the name of the cell type } begin Abstract('Cell.Name'); end; { Cell.Name } function Cell.Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; { Returns the format of a cell } begin Abstract('Cell.Format'); end; { Cell.Format } function Cell.Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; { Returns the width of a cell (including the cells that it will overwrite) } begin Abstract('Cell.Width'); end; { Cell.Width } function Cell.Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; { Calculates how many cells a cell will overwrite } begin Abstract('Cell.Overwritten'); end; { Cell.Overwritten } function Cell.ShouldUpdate : Boolean; { Returns True if the cell needs to be updated when the spreadsheet changes } begin Abstract('Cell.ShouldUpdate'); end; { Cell.ShouldUpdate } function Cell.HasError : Boolean; { Returns True if the cell has a numeric error in it } begin Abstract('Cell.HasError'); end; { Cell.HasError } function Cell.CurrValue : Extended; { Returns the current numeric value of a cell } begin Abstract('Cell.CurrValue'); end; { Cell.CurrValue } function Cell.OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; { Determines, for overwritten cells, where in the overwriting data they will Start to display a value } begin Abstract('Cell.OverwriteStart'); end; { Cell.OverwriteStart } procedure Cell.EditString(MaxDecPlaces : Byte; var L : LStringPtr); { Sets up a long string with the cell's value that can be edited } begin Abstract('Cell.EditString'); end; { Cell.EditString } function Cell.DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; { Returns the string that will be displayed just above the input line } begin Abstract('Cell.DisplayString'); end; { Cell.DisplayString } function Cell.FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; { Returns the string that will be printed in a cell } begin Abstract('Cell.FormattedString'); end; { Cell.FormattedString } function Cell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; { Copies a cell's string information to another cell's } begin Abstract('Cell.CopyString'); end; { Cell.CopyString } constructor EmptyCell.Init; var NewLoc : CellPos; begin NewLoc.Col := 0; NewLoc.Row := 0; Cell.Init(NewLoc); end; { EmptyCell.Init } function EmptyCell.CellType : CellTypes; begin CellType := ClEmpty; end; { EmptyCell.CellType } function EmptyCell.LegalValue : Boolean; begin LegalValue := True; end; { EmptyCell.LegalValue } function EmptyCell.Name : String; begin Name := EmptyCellName; end; { EmptyCell.Name } function EmptyCell.Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; begin Format := 0; end; { EmptyCell.Format } function EmptyCell.Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; begin Width := 0; end; { EmptyCell.Width } function EmptyCell.Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; begin Overwritten := 0; end; { EmptyCell.Overwritten } function EmptyCell.ShouldUpdate : Boolean; begin ShouldUpdate := False; end; { EmptyCell.ShouldUpdate } function EmptyCell.HasError : Boolean; begin HasError := False; end; { Cell.HasError } function EmptyCell.CurrValue : Extended; begin CurrValue := 0; end; { EmptyCell.CurrValue } function EmptyCell.OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; begin OverwriteStart := 1; end; { EmptyCell.OverwriteStart } procedure EmptyCell.EditString(MaxDecPlaces : Byte; var L : LStringPtr); var Good : Boolean; begin Good := L^.FromString(''); end; { EmptyCell.EditString } function EmptyCell.DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; begin DisplayString := ''; end; { EmptyCell.DisplayString } function EmptyCell.FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; var CP : CellPtr; begin CP := OHash.Search(CPos); if CP <> Empty then FormattedString := CP^.FormattedString(OHash, FHash, WHash, GetColWidth, Loc, FormulasDisplayed, CP^.OverWriteStart(FHash, WHash, GetColWidth, CPos.Col, FormulasDisplayed), ColWidth, DString, Color) else begin FormattedString := ''; DString := ''; Color := Colors.BlankColor; end; end; { EmptyCell.FormattedString } function EmptyCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; begin CopyString := L; end; { EmptyCell.CopyString } constructor ValueCell.Init(InitLoc : CellPos; InitError : Boolean; InitValue : Extended); begin Cell.Init(InitLoc); Error := InitError; Value := InitValue; end; { ValueCell.Init } function ValueCell.CellType : CellTypes; begin CellType := ClValue; end; { ValueCell.CellType } function ValueCell.LegalValue : Boolean; begin LegalValue := True; end; { ValueCell.LegalValue } function ValueCell.Name : String; begin Name := ValueCellName; end; { ValueCell.Name } function ValueCell.Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; var F : FormatType; begin if FHash.Search(Loc, F) then Format := F else Format := (Ord(JRight) shl 4) + 4; end; { ValueCell.Format } function ValueCell.Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; var S : String; F : FormatType; P, W : Word; begin F := Format(FHash, FormulasDisplayed); Str(Value:1:(F and DecPlacesPart), S); W := Length(S); if (F and DollarPart) <> 0 then Inc(W, Length(DollarString)); if (F and CommasPart) <> 0 then begin P := Pos('.', S); if P = 0 then P := Length(S); Inc(W, (P - 2) div 3); end; Width := W; end; { ValueCell.Width } function ValueCell.Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; var CellWidth : Longint; Total : Word; P : CellPos; begin P := Loc; CellWidth := Width(FHash, FormulasDisplayed); Total := 0; repeat Inc(Total); Dec(CellWidth, GetColWidth(WHash, P.Col)); Inc(P.Col); until (CellWidth <= 0) or (P.Col = MaxCols) or (CHash.Search(P) <> Empty); Dec(Total); Overwritten := Total; end; { ValueCell.Overwritten } function ValueCell.ShouldUpdate : Boolean; begin ShouldUpdate := False; end; { ValueCell.ShouldUpdate } function ValueCell.HasError : Boolean; begin HasError := Error; end; { ValueCell.HasError } function ValueCell.CurrValue : Extended; begin CurrValue := Value; end; { ValueCell.CurrValue } function ValueCell.OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; var F : FormatType; C, Place : Word; begin F := Format(FHash, DisplayFormulas); Place := 1; C := Loc.Col; repeat Inc(Place, GetColWidth(WHash, C)); Inc(C); until C = EndCol; if (F and DollarPart) <> 0 then Dec(Place, Length(DollarString)); OverwriteStart := Place; end; { ValueCell.OverwriteStart } procedure ValueCell.EditString(MaxDecPlaces : Byte; var L : LStringPtr); var S : String; Good : Boolean; begin Str(Value:1:MaxDecPlaces, S); Good := L^.FromString(S); end; { ValueCell.EditString } function ValueCell.DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; var S : String; begin Str(Value:1:MaxDecPlaces, S); DisplayString := S; end; { ValueCell.DisplayString } function ValueCell.FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; var Counter : Word; S : String; F : FormatType; begin F := Format(FHash, FormulasDisplayed); Str(Value:1:F and DecPlacesPart, S); if (Start = 1) and ((F and DollarPart) <> 0) then DString := ' $ ' else DString := ''; if (F and CommasPart) <> 0 then begin Counter := Pos('.', S); if Counter = 0 then Counter := System.Length(S); while Counter > 4 do begin System.Insert(',', S, Counter - 3); Dec(Counter, 3); end; end; Color := Colors.ValueCellColor; FormattedString := Copy(S, Start, ColWidth); end; { ValueCell.FormattedString } function ValueCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; begin CopyString := L; end; { ValueCell.CopyString } constructor ValueCell.Load(var S : SSStream); begin S.Read(Loc, SizeOf(Loc)); S.Read(Error, SizeOf(Error)); S.Read(Value, SizeOf(Value)); end; { ValueCell.Load } procedure ValueCell.Store(var S : SSStream); begin S.Write(Loc, SizeOf(Loc)); S.Write(Error, SizeOf(Error)); S.Write(Value, SizeOf(Value)); end; { ValueCell.Store } constructor TextCell.Init(InitLoc : CellPos; InitTxt : LStringPtr); begin Cell.Init(InitLoc); Txt := New(LStringPtr, Init); if Txt = nil then Fail; if not Txt^.Assign(InitTxt^) then begin Done; Fail; end; end; { TextCell.Init } destructor TextCell.Done; begin Dispose(Txt, Done); end; { TextCell.Done } function TextCell.CellType : CellTypes; begin CellType := ClText; end; { TextCell.CellType } function TextCell.LegalValue : Boolean; begin LegalValue := False; end; { TextCell.LegalValue } function TextCell.Name : String; begin Name := TextCellName; end; { TextCell.Name } function TextCell.Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; var F : FormatType; begin if FHash.Search(Loc, F) then Format := F else Format := 0; end; { TextCell.Format } function TextCell.Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; begin Width := Txt^.Length; end; { TextCell.Width } function TextCell.Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; var CellWidth : Longint; Total : Word; P : CellPos; begin P := Loc; CellWidth := Width(FHash, FormulasDisplayed); Total := 0; repeat Inc(Total); Dec(CellWidth, GetColWidth(WHash, P.Col)); Inc(P.Col); until (CellWidth <= 0) or (P.Col = MaxCols) or (CHash.Search(P) <> Empty); Dec(Total); Overwritten := Total; end; { TextCell.Overwritten } function TextCell.ShouldUpdate : Boolean; begin ShouldUpdate := False; end; { TextCell.ShouldUpdate } function TextCell.HasError : Boolean; begin HasError := False; end; { TextCell.HasError } function TextCell.CurrValue : Extended; begin CurrValue := 0; end; { TextCell.CurrValue } function TextCell.OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; var F : FormatType; C, Place : Word; begin F := Format(FHash, DisplayFormulas); Place := 1; C := Loc.Col; repeat Inc(Place, GetColWidth(WHash, C)); Inc(C); until C = EndCol; OverwriteStart := Place; end; { TextCell.OverwriteStart } procedure TextCell.EditString(MaxDecPlaces : Byte; var L : LStringPtr); var Good : Boolean; begin Good := L^.Assign(Txt^); end; { TextCell.EditString } function TextCell.DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; begin DisplayString := Txt^.Copy(2, Scr.CurrCols); end; { TextCell.DisplayString } function TextCell.FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; begin DString := ''; Color := Colors.TextCellColor; FormattedString := Txt^.Copy(Succ(Start), ColWidth); end; { TextCell.FormattedString } function TextCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; var Good : Boolean; begin Good := L^.Assign(Txt^); CopyString := L; end; { TextCell.CopyString } constructor TextCell.Load(var S : SSStream); begin S.Read(Loc, SizeOf(Loc)); Txt := New(LStringPtr, Init); if Txt = nil then begin S.Error(NoMemory); Exit; end; if not Txt^.FromStream(S) then begin Dispose(Txt, Done); S.Error(NoMemory); end; end; { TextCell.Load } procedure TextCell.Store(var S : SSStream); begin S.Write(Loc, SizeOf(Loc)); Txt^.ToStream(S); end; { TextCell.Store } constructor FormulaCell.Init(InitLoc : CellPos; InitError : Boolean; InitValue : Extended; InitFormula : LStringPtr); begin Cell.Init(InitLoc); Formula := New(LStringPtr, Init); if Formula = nil then Fail; if not Formula^.Assign(InitFormula^) then begin Done; Fail; end; Error := InitError; Value := InitValue; end; { FormulaCell.Init } destructor FormulaCell.Done; begin Dispose(Formula, Done); end; { FormulaCell.Done } function FormulaCell.CellType : CellTypes; begin CellType := ClFormula; end; { FormulaCell.CellType } function FormulaCell.LegalValue : Boolean; begin LegalValue := True; end; { FormulaCell.LegalValue } function FormulaCell.Name : String; begin Name := FormulaCellName; end; { FormulaCell.Name } function FormulaCell.Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; var F : FormatType; begin if FHash.Search(Loc, F) then Format := F else if FormulasDisplayed then Format := 0 else Format := (Ord(JRight) shl 4) + 4; end; { FormulaCell.Format } function FormulaCell.Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; var S : String; F : Byte; P, W : Word; begin if FormulasDisplayed then Width := Formula^.Length else begin F := Format(FHash, FormulasDisplayed); Str(Value:1:(F and DecPlacesPart), S); W := Length(S); if (F and DollarPart) <> 0 then Inc(W, Length(DollarString)); if (F and CommasPart) <> 0 then begin P := Pos('.', S); if P = 0 then P := Length(S); Inc(W, (P - 2) div 3); end; Width := W; end; end; { FormulaCell.Width } function FormulaCell.Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; var CellWidth : Longint; Total : Word; P : CellPos; begin P := Loc; CellWidth := Width(FHash, FormulasDisplayed); Total := 0; repeat Inc(Total); Dec(CellWidth, GetColWidth(WHash, P.Col)); Inc(P.Col); until (CellWidth <= 0) or (P.Col = MaxCols) or (CHash.Search(P) <> Empty); Dec(Total); Overwritten := Total; end; { FormulaCell.Overwritten } function FormulaCell.ShouldUpdate : Boolean; begin ShouldUpdate := True; end; { FormulaCell.ShouldUpdate } function FormulaCell.HasError : Boolean; begin HasError := Error; end; { FormulaCell.HasError } function FormulaCell.CurrValue : Extended; begin CurrValue := Value; end; { FormulaCell.CurrValue } function FormulaCell.OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; var F : FormatType; C, Place : Word; begin F := Format(FHash, DisplayFormulas); Place := 1; C := Loc.Col; repeat Inc(Place, GetColWidth(WHash, C)); Inc(C); until C = EndCol; if (not DisplayFormulas) and ((F and DollarPart) <> 0) then Dec(Place, Length(DollarString)); OverwriteStart := Place; end; { FormulaCell.OverwriteStart } procedure FormulaCell.EditString(MaxDecPlaces : Byte; var L : LStringPtr); var Good : Boolean; begin Good := L^.Assign(Formula^); end; { FormulaCell.EditString } function FormulaCell.DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; var S : String; begin if not FormulasDisplayed then DisplayString := Formula^.ToString else begin Str(Value:1:MaxDecPlaces, S); DisplayString := S; end; end; { FormulaCell.DisplayString } function FormulaCell.FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; var S : String; Counter : Word; F : FormatType; begin if FormulasDisplayed then begin DString := ''; Color := Colors.FormulaCellColor; FormattedString := Formula^.Copy(1, ColWidth); end else begin F := Format(FHash, FormulasDisplayed); Str(Value:1:F and DecPlacesPart, S); if (Start = 1) and ((F and DollarPart) <> 0) then DString := ' $ ' else DString := ''; if (F and CommasPart) <> 0 then begin Counter := Pos('.', S); if Counter = 0 then Counter := Length(S); while Counter > 4 do begin Insert(',', S, Counter - 3); Dec(Counter, 3); end; end; Color := Colors.ValueCellColor; FormattedString := Copy(S, Start, ColWidth); end; end; { FormulaCell.FormattedString } function FormulaCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; var Good : Boolean; begin Good := L^.Assign(Formula^); CopyString := L; end; { FormulaCell.CopyString } constructor FormulaCell.Load(var S : SSStream); begin S.Read(Loc, SizeOf(Loc)); Formula := New(LStringPtr, Init); if Formula = nil then begin S.Error(NoMemory); Exit; end; if not Formula^.FromStream(S) then begin Dispose(Formula, Done); S.Error(NoMemory); end; end; { FormulaCell.Load } procedure FormulaCell.Store(var S : SSStream); begin S.Write(Loc, SizeOf(Loc)); Formula^.ToStream(S); end; { FormulaCell.Store } function FormulaCell.GetFormula : LStringPtr; begin GetFormula := Formula; end; { FormulaCell.GetFormula } constructor RepeatCell.Init(InitLoc : CellPos; InitChar : Char); begin Cell.Init(InitLoc); RepeatChar := InitChar; end; { RepeatCell.Init } function RepeatCell.CellType : CellTypes; begin CellType := ClRepeat; end; { RepeatCell.CellType } function RepeatCell.LegalValue : Boolean; begin LegalValue := False; end; { RepeatCell.LegalValue } function RepeatCell.Name : String; begin Name := RepeatCellName; end; { RepeatCell.Name } function RepeatCell.Format(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : FormatType; begin Format := 0; end; { RepeatCell.Format } function RepeatCell.Width(var FHash : FormatHashTable; FormulasDisplayed : Boolean) : Word; begin Width := 2; end; { RepeatCell.Width } function RepeatCell.Overwritten(var CHash : CellHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; var LastPos : CellPos; MaxCols : Word; GetColWidth : GetColWidthFunc; FormulasDisplayed : Boolean) : Word; var Total : Word; P : CellPos; begin P := Loc; Total := 0; repeat Inc(Total); Inc(P.Col); until (P.Col > LastPos.Col) or (CHash.Search(P) <> Empty) or (P.Col = 0); Dec(Total); if (P.Col > LastPos.Col) or (P.Col = 0) then Total := MaxCols - Loc.Col; Overwritten := Total; end; { RepeatCell.Overwritten } function RepeatCell.ShouldUpdate : Boolean; begin ShouldUpdate := False; end; { RepeatCell.ShouldUpdate } function RepeatCell.HasError : Boolean; begin HasError := False; end; { RepeatCell.HasError } function RepeatCell.CurrValue : Extended; begin CurrValue := 0; end; { RepeatCell.CurrValue } function RepeatCell.OverwriteStart(var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; EndCol : Word; DisplayFormulas : Boolean) : Word; begin OverwriteStart := 1; end; { RepeatCell.OverwriteStart } procedure RepeatCell.EditString(MaxDecPlaces : Byte; var L : LStringPtr); var Good : Boolean; begin Good := L^.FromString(RepeatFirstChar + RepeatChar); end; { RepeatCell.EditString } function RepeatCell.DisplayString(FormulasDisplayed : Boolean; MaxDecPlaces : Byte) : String; begin DisplayString := FillString(Scr.CurrCols, RepeatChar); end; { RepeatCell.DisplayString } function RepeatCell.FormattedString(var OHash : OverwriteHashTable; var FHash : FormatHashTable; var WHash : WidthHashTable; GetColWidth : GetColWidthFunc; CPos : CellPos; FormulasDisplayed : Boolean; Start : Word; ColWidth : Byte; var DString : DollarStr; var Color : Byte) : String; begin DString := ''; Color := Colors.RepeatCellColor; FormattedString := PadChar('', RepeatChar, ColWidth); end; { RepeatCell.FormattedString } function RepeatCell.CopyString(ColLit, RowLit : Boolean; Diff : Longint; var L : LStringPtr) : LStringPtr; begin EditString(0, L); CopyString := L; end; { RepeatCell.CopyString } constructor RepeatCell.Load(var S : SSStream); begin S.Read(Loc, SizeOf(Loc)); S.Read(RepeatChar, SizeOf(RepeatChar)); end; { RepeatCell.Load } procedure RepeatCell.Store(var S : SSStream); begin S.Write(Loc, SizeOf(Loc)); S.Write(RepeatChar, SizeOf(RepeatChar)); end; { RepeatCell.Store } {$F+} procedure CellExit; { Removes Empty cell from memory, restores ExitProc } begin Dispose(Empty, Done); ExitProc := SavedExitProc; end; { CellExit } {$F-} begin SavedExitProc := ExitProc; ExitProc := @CellExit; Empty := New(EmptyCellPtr, Init); end.