fpspreadsheet: starts implementing formulas. RPN version working for Excel 5

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@832 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2009-06-09 11:19:10 +00:00
parent 6eb3432e9a
commit bb04dbc318
5 changed files with 179 additions and 100 deletions

View File

@ -11,7 +11,7 @@
<TargetFileExt Value=".exe"/>
<Title Value="excel5write"/>
<UseAppBundle Value="False"/>
<ActiveEditorIndexAtStart Value="3"/>
<ActiveEditorIndexAtStart Value="1"/>
</General>
<VersionInfo>
<ProjectVersion Value=""/>
@ -38,8 +38,8 @@
<Filename Value="excel5write.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="excel5write"/>
<CursorPos X="36" Y="32"/>
<TopLine Value="26"/>
<CursorPos X="25" Y="56"/>
<TopLine Value="37"/>
<EditorIndex Value="0"/>
<UsageCount Value="309"/>
<Loaded Value="True"/>
@ -68,8 +68,8 @@
<Unit4>
<Filename Value="..\..\xlsbiff5.pas"/>
<UnitName Value="xlsbiff5"/>
<CursorPos X="1" Y="1063"/>
<TopLine Value="1047"/>
<CursorPos X="1" Y="1"/>
<TopLine Value="1"/>
<EditorIndex Value="3"/>
<UsageCount Value="140"/>
<Loaded Value="True"/>
@ -86,8 +86,8 @@
<Unit6>
<Filename Value="..\..\xlsbiff2.pas"/>
<UnitName Value="xlsbiff2"/>
<CursorPos X="34" Y="256"/>
<TopLine Value="236"/>
<CursorPos X="1" Y="286"/>
<TopLine Value="275"/>
<EditorIndex Value="6"/>
<UsageCount Value="139"/>
<Loaded Value="True"/>
@ -116,8 +116,8 @@
<Unit10>
<Filename Value="..\..\fpspreadsheet.pas"/>
<UnitName Value="fpspreadsheet"/>
<CursorPos X="1" Y="13"/>
<TopLine Value="12"/>
<CursorPos X="79" Y="836"/>
<TopLine Value="819"/>
<EditorIndex Value="1"/>
<UsageCount Value="92"/>
<Loaded Value="True"/>
@ -150,123 +150,123 @@
<JumpHistory Count="30" HistoryIndex="29">
<Position1>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="405" Column="5" TopLine="386"/>
<Caret Line="314" Column="39" TopLine="296"/>
</Position1>
<Position2>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="404" Column="14" TopLine="401"/>
<Caret Line="479" Column="1" TopLine="469"/>
</Position2>
<Position3>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="79" Column="42" TopLine="72"/>
<Caret Line="470" Column="1" TopLine="460"/>
</Position3>
<Position4>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="78" Column="31" TopLine="67"/>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="217" Column="3" TopLine="205"/>
</Position4>
<Position5>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="314" Column="39" TopLine="296"/>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="218" Column="23" TopLine="208"/>
</Position5>
<Position6>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="479" Column="1" TopLine="469"/>
<Caret Line="78" Column="10" TopLine="66"/>
</Position6>
<Position7>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="470" Column="1" TopLine="460"/>
<Caret Line="375" Column="1" TopLine="367"/>
</Position7>
<Position8>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="217" Column="3" TopLine="205"/>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="76" Column="17" TopLine="65"/>
</Position8>
<Position9>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="218" Column="23" TopLine="208"/>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="363" Column="1" TopLine="357"/>
</Position9>
<Position10>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="78" Column="10" TopLine="66"/>
<Caret Line="77" Column="7" TopLine="76"/>
</Position10>
<Position11>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="375" Column="1" TopLine="367"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="137" Column="40" TopLine="129"/>
</Position11>
<Position12>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="76" Column="17" TopLine="65"/>
<Caret Line="563" Column="5" TopLine="544"/>
</Position12>
<Position13>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="363" Column="1" TopLine="357"/>
<Caret Line="486" Column="5" TopLine="467"/>
</Position13>
<Position14>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="77" Column="7" TopLine="76"/>
<Caret Line="510" Column="5" TopLine="491"/>
</Position14>
<Position15>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="137" Column="40" TopLine="129"/>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="94" Column="46" TopLine="84"/>
</Position15>
<Position16>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="563" Column="5" TopLine="544"/>
<Caret Line="686" Column="5" TopLine="667"/>
</Position16>
<Position17>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="486" Column="5" TopLine="467"/>
<Caret Line="567" Column="5" TopLine="548"/>
</Position17>
<Position18>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="510" Column="5" TopLine="491"/>
<Caret Line="622" Column="1" TopLine="618"/>
</Position18>
<Position19>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="94" Column="46" TopLine="84"/>
<Caret Line="621" Column="29" TopLine="611"/>
</Position19>
<Position20>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="686" Column="5" TopLine="667"/>
</Position20>
<Position21>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="567" Column="5" TopLine="548"/>
</Position21>
<Position22>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="622" Column="1" TopLine="618"/>
</Position22>
<Position23>
<Filename Value="..\..\fpolestorage.pas"/>
<Caret Line="621" Column="29" TopLine="611"/>
</Position23>
<Position24>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="100" Column="17" TopLine="92"/>
</Position24>
<Position25>
</Position20>
<Position21>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="615" Column="34" TopLine="593"/>
</Position25>
<Position26>
</Position21>
<Position22>
<Filename Value="..\..\fpsopendocument.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position26>
<Position27>
</Position22>
<Position23>
<Filename Value="..\..\fpsopendocument.pas"/>
<Caret Line="56" Column="88" TopLine="43"/>
</Position27>
<Position28>
</Position23>
<Position24>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position28>
<Position29>
</Position24>
<Position25>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="69" Column="88" TopLine="56"/>
</Position25>
<Position26>
<Filename Value="excel5write.lpr"/>
<Caret Line="47" Column="30" TopLine="33"/>
</Position26>
<Position27>
<Filename Value="excel5write.lpr"/>
<Caret Line="53" Column="21" TopLine="40"/>
</Position27>
<Position28>
<Filename Value="excel5write.lpr"/>
<Caret Line="54" Column="27" TopLine="40"/>
</Position28>
<Position29>
<Filename Value="excel5write.lpr"/>
<Caret Line="52" Column="38" TopLine="43"/>
</Position29>
<Position30>
<Filename Value="excel5write.lpr"/>
<Caret Line="47" Column="30" TopLine="33"/>
<Caret Line="56" Column="25" TopLine="37"/>
</Position30>
</JumpHistory>
</ProjectOptions>

View File

@ -16,7 +16,7 @@ uses
var
MyWorkbook: TsWorkbook;
MyWorksheet: TsWorksheet;
MyFormula: TsFormula;
MyRPNFormula: TsRPNFormula;
MyDir: string;
i: Integer;
begin
@ -45,8 +45,17 @@ begin
}
// Write the formula E1 = A1 + B1
SetLength(MyRPNFormula, 3);
MyRPNFormula[0].ElementKind := fekCell;
MyRPNFormula[0].Col := 0;
MyRPNFormula[0].Row := 0;
MyRPNFormula[1].ElementKind := fekCell;
MyRPNFormula[1].Col := 1;
MyRPNFormula[1].Row := 0;
MyRPNFormula[2].ElementKind := fekAdd;
MyWorksheet.WriteRPNFormula(0, 4, MyRPNFormula);
//MyFormula.FormulaStr := '';
// MyWorksheet.WriteFormula(0, 4, MyFormula);
// Creates a new worksheet
MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet 2');

View File

@ -49,24 +49,31 @@ type
TsFormulaElement = record
ElementKind: TFEKind;
Row1, Row2: Word;
Col1, Col2: Byte;
Row, Row2: Word; // zero-based
Col, Col2: Byte; // zero-based
DoubleValue: double;
end;
TsExpandedFormula = array of TsFormulaElement;
{@@ RPN formula. Similar to the expanded formula, but in RPN notation.
Simplifies the task of format writers which need RPN }
TsRPNFormula = array of TsFormulaElement;
{@@ Describes the type of content of a cell on a TsWorksheet }
TCellContentType = (cctEmpty, cctFormula, cctNumber, cctUTF8String);
TCellContentType = (cctEmpty, cctFormula, cctRPNFormula, cctNumber, cctUTF8String);
{@@ Cell structure for TsWorksheet }
TCell = record
Col: Byte;
Row: Word;
Col: Byte; // zero-based
Row: Word; // zero-based
ContentType: TCellContentType;
{ Possible values for the cells }
FormulaValue: TsFormula;
RPNFormulaValue: TsRPNFormula;
NumberValue: double;
UTF8StringValue: ansistring;
end;
@ -101,6 +108,7 @@ type
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double);
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
end;
{ TsWorkbook }
@ -165,7 +173,8 @@ type
procedure WriteToFile(AFileName: string; AData: TsWorkbook); virtual;
procedure WriteToStream(AStream: TStream; AData: TsWorkbook); virtual;
{ Record writing methods }
procedure WriteFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TsFormula); virtual; abstract;
procedure WriteFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TsFormula); virtual;
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TsRPNFormula); virtual;
procedure WriteLabel(AStream: TStream; const ARow, ACol: Word; const AValue: string); virtual; abstract;
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double); virtual; abstract;
end;
@ -500,6 +509,17 @@ begin
ACell^.FormulaValue := AFormula;
end;
procedure TsWorksheet.WriteRPNFormula(ARow, ACol: Cardinal;
AFormula: TsRPNFormula);
var
ACell: PCell;
begin
ACell := GetCell(ARow, ACol);
ACell^.ContentType := cctRPNFormula;
ACell^.RPNFormulaValue := AFormula;
end;
{ TsWorkbook }
{@@
@ -810,9 +830,10 @@ begin
AStream := TStream(arg);
case ACell.ContentType of
cctFormula: WriteFormula(AStream, ACell^.Row, ACell^.Col, ACell^.FormulaValue);
cctNumber: WriteNumber(AStream, ACell^.Row, ACell^.Col, ACell^.NumberValue);
cctUTF8String: WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue);
cctFormula: WriteFormula(AStream, ACell^.Row, ACell^.Col, ACell^.FormulaValue);
cctRPNFormula: WriteRPNFormula(AStream, ACell^.Row, ACell^.Col, ACell^.RPNFormulaValue);
end;
end;
@ -861,6 +882,18 @@ begin
end;
procedure TsCustomSpreadWriter.WriteFormula(AStream: TStream; const ARow,
ACol: Word; const AFormula: TsFormula);
begin
end;
procedure TsCustomSpreadWriter.WriteRPNFormula(AStream: TStream; const ARow,
ACol: Word; const AFormula: TsRPNFormula);
begin
end;
finalization
SetLength(GsSpreadFormats, 0);

View File

@ -53,13 +53,15 @@ type
{ TsSpreadBIFF2Writer }
TsSpreadBIFF2Writer = class(TsCustomSpreadWriter)
private
function FEKindToExcelID(AElement: TFEKind): Byte;
public
{ General writing methods }
procedure WriteToStream(AStream: TStream; AData: TsWorkbook); override;
{ Record writing methods }
procedure WriteBOF(AStream: TStream);
procedure WriteEOF(AStream: TStream);
procedure WriteFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TsFormula); override;
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TsRPNFormula); override;
procedure WriteLabel(AStream: TStream; const ARow, ACol: Word; const AValue: string); override;
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double); override;
end;
@ -84,17 +86,6 @@ const
INT_EXCEL_CHART = $0020;
INT_EXCEL_MACRO_SHEET = $0040;
{ Types and constants for formulas }
type
TRPNItem = record
TokenID: Byte;
Col: Byte;
Row: Word;
DoubleValue: Double;
end;
TRPNFormula = array of TRPNItem;
const
{ TokenID values }
@ -115,6 +106,17 @@ const
{ TsSpreadBIFF2Writer }
function TsSpreadBIFF2Writer.FEKindToExcelID(AElement: TFEKind): Byte;
begin
case AElement of
fekCell: Result := INT_EXCEL_TOKEN_TREFV;
fekAdd: Result := INT_EXCEL_TOKEN_TADD;
fekSub: Result := INT_EXCEL_TOKEN_TSUB;
fekDiv: Result := INT_EXCEL_TOKEN_TDIV;
fekMul: Result := INT_EXCEL_TOKEN_TMUL;
end;
end;
{
Writes an Excel 2 file to a stream
@ -176,15 +178,16 @@ end;
MyFormula[1].Row := 0;
MyFormula[2].TokenID := INT_EXCEL_TOKEN_TADD; +
}
procedure TsSpreadBIFF2Writer.WriteFormula(AStream: TStream; const ARow,
ACol: Word; const AFormula: TsFormula);
{var
procedure TsSpreadBIFF2Writer.WriteRPNFormula(AStream: TStream; const ARow,
ACol: Word; const AFormula: TsRPNFormula);
var
FormulaResult: double;
i: Integer;
RPNLength: Word;
TokenArraySizePos, RecordSizePos, FinalPos: Cardinal;}
TokenArraySizePos, RecordSizePos, FinalPos: Cardinal;
FormulaKind: Byte;
begin
(* RPNLength := 0;
RPNLength := 0;
FormulaResult := 0.0;
{ BIFF Record header }
@ -220,11 +223,12 @@ begin
for i := 0 to Length(AFormula) - 1 do
begin
{ Token identifier }
AStream.WriteByte(AFormula[i].TokenID);
FormulaKind := FEKindToExcelID(AFormula[i].ElementKind);
AStream.WriteByte(FormulaKind);
Inc(RPNLength);
{ Additional data }
case AFormula[i].TokenID of
case FormulaKind of
{ binary operation tokens }
@ -253,7 +257,7 @@ begin
AStream.WriteByte(RPNLength);
AStream.Position := RecordSizePos;
AStream.WriteWord(WordToLE(17 + RPNLength));
AStream.position := FinalPos;*)
AStream.position := FinalPos;
end;
{*******************************************************************

View File

@ -97,6 +97,8 @@ type
{ TsSpreadBIFF5Writer }
TsSpreadBIFF5Writer = class(TsCustomSpreadWriter)
private
function FEKindToExcelID(AElement: TFEKind): Byte;
public
// constructor Create;
// destructor Destroy; override;
@ -109,7 +111,7 @@ type
procedure WriteDimensions(AStream: TStream);
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TFPCustomFont);
procedure WriteFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TsFormula); override;
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Word; const AFormula: TsRPNFormula); override;
procedure WriteIndex(AStream: TStream);
procedure WriteLabel(AStream: TStream; const ARow, ACol: Word; const AValue: string); override;
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double); override;
@ -220,12 +222,41 @@ const
MASK_XF_VERT_ALIGN = $70;
const
{ TokenID values }
{ Binary Operator Tokens }
INT_EXCEL_TOKEN_TADD = $03;
INT_EXCEL_TOKEN_TSUB = $04;
INT_EXCEL_TOKEN_TMUL = $05;
INT_EXCEL_TOKEN_TDIV = $06;
INT_EXCEL_TOKEN_TPOWER = $07;
{ Constant Operand Tokens }
INT_EXCEL_TOKEN_TNUM = $1F;
{ Operand Tokens }
INT_EXCEL_TOKEN_TREFR = $24;
INT_EXCEL_TOKEN_TREFV = $44;
INT_EXCEL_TOKEN_TREFA = $64;
{
Exported functions
}
{ TsSpreadBIFF5Writer }
function TsSpreadBIFF5Writer.FEKindToExcelID(AElement: TFEKind): Byte;
begin
case AElement of
fekCell: Result := INT_EXCEL_TOKEN_TREFV;
fekAdd: Result := INT_EXCEL_TOKEN_TADD;
fekSub: Result := INT_EXCEL_TOKEN_TSUB;
fekDiv: Result := INT_EXCEL_TOKEN_TDIV;
fekMul: Result := INT_EXCEL_TOKEN_TMUL;
end;
end;
{*******************************************************************
* TsSpreadBIFF5Writer.WriteToFile ()
*
@ -550,15 +581,16 @@ end;
* AFormula array
*
*******************************************************************}
procedure TsSpreadBIFF5Writer.WriteFormula(AStream: TStream; const ARow,
ACol: Word; const AFormula: TsFormula);
{var
procedure TsSpreadBIFF5Writer.WriteRPNFormula(AStream: TStream; const ARow,
ACol: Word; const AFormula: TsRPNFormula);
var
FormulaResult: double;
i: Integer;
RPNLength: Word;
TokenArraySizePos, RecordSizePos, FinalPos: Int64;}
TokenArraySizePos, RecordSizePos, FinalPos: Int64;
FormulaKind: Byte;
begin
(* RPNLength := 0;
RPNLength := 0;
FormulaResult := 0.0;
{ BIFF Record header }
@ -594,11 +626,12 @@ begin
for i := 0 to Length(AFormula) - 1 do
begin
{ Token identifier }
AStream.WriteByte(AFormula[i].TokenID);
FormulaKind := FEKindToExcelID(AFormula[i].ElementKind);
AStream.WriteByte(FormulaKind);
Inc(RPNLength);
{ Additional data }
case AFormula[i].TokenID of
case FormulaKind of
{ binary operation tokens }
@ -627,7 +660,7 @@ begin
AStream.WriteByte(RPNLength);
AStream.Position := RecordSizePos;
AStream.WriteWord(WordToLE(22 + RPNLength));
AStream.position := FinalPos;*)
AStream.position := FinalPos;
end;
{*******************************************************************