FPSpreadsheet: Adds some code for formula handling
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1659 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
e23fbc9f1d
commit
f62592925f
215
components/fpspreadsheet/examples/other/test_write_formula.lpi
Normal file
215
components/fpspreadsheet/examples/other/test_write_formula.lpi
Normal file
@ -0,0 +1,215 @@
|
||||
<?xml version="1.0"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="9"/>
|
||||
<General>
|
||||
<Flags>
|
||||
<MainUnitHasCreateFormStatements Value="False"/>
|
||||
<MainUnitHasTitleStatement Value="False"/>
|
||||
</Flags>
|
||||
<MainUnit Value="0"/>
|
||||
<Title Value="test_write_formula"/>
|
||||
<ResourceType Value="res"/>
|
||||
<UseXPManifest Value="True"/>
|
||||
<Icon Value="0"/>
|
||||
<ActiveWindowIndexAtStart Value="0"/>
|
||||
</General>
|
||||
<i18n>
|
||||
<EnableI18N LFM="False"/>
|
||||
</i18n>
|
||||
<VersionInfo>
|
||||
<StringTable ProductVersion=""/>
|
||||
</VersionInfo>
|
||||
<BuildModes Count="1" Active="Default">
|
||||
<Item1 Name="Default" Default="True"/>
|
||||
</BuildModes>
|
||||
<PublishOptions>
|
||||
<Version Value="2"/>
|
||||
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
|
||||
<ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/>
|
||||
</PublishOptions>
|
||||
<RunParams>
|
||||
<local>
|
||||
<FormatVersion Value="1"/>
|
||||
<LaunchingApplication PathPlusParams="/usr/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
|
||||
</local>
|
||||
</RunParams>
|
||||
<RequiredPackages Count="1">
|
||||
<Item1>
|
||||
<PackageName Value="laz_fpspreadsheet"/>
|
||||
</Item1>
|
||||
</RequiredPackages>
|
||||
<Units Count="4">
|
||||
<Unit0>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<IsPartOfProject Value="True"/>
|
||||
<UnitName Value="test_write_formula"/>
|
||||
<IsVisibleTab Value="True"/>
|
||||
<EditorIndex Value="0"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="23"/>
|
||||
<CursorPos X="42" Y="45"/>
|
||||
<UsageCount Value="20"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit0>
|
||||
<Unit1>
|
||||
<Filename Value="../../fpspreadsheet.pas"/>
|
||||
<UnitName Value="fpspreadsheet"/>
|
||||
<EditorIndex Value="3"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="38"/>
|
||||
<CursorPos X="13" Y="66"/>
|
||||
<UsageCount Value="10"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit1>
|
||||
<Unit2>
|
||||
<Filename Value="../../xlsbiff8.pas"/>
|
||||
<UnitName Value="xlsbiff8"/>
|
||||
<EditorIndex Value="1"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="840"/>
|
||||
<CursorPos X="10" Y="862"/>
|
||||
<UsageCount Value="10"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit2>
|
||||
<Unit3>
|
||||
<Filename Value="../../xlscommon.pas"/>
|
||||
<UnitName Value="xlscommon"/>
|
||||
<EditorIndex Value="2"/>
|
||||
<WindowIndex Value="0"/>
|
||||
<TopLine Value="125"/>
|
||||
<CursorPos X="1" Y="150"/>
|
||||
<UsageCount Value="10"/>
|
||||
<Loaded Value="True"/>
|
||||
</Unit3>
|
||||
</Units>
|
||||
<JumpHistory Count="25" HistoryIndex="24">
|
||||
<Position1>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="3" Column="1" TopLine="1"/>
|
||||
</Position1>
|
||||
<Position2>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="179" Column="1" TopLine="136"/>
|
||||
</Position2>
|
||||
<Position3>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="29" Column="17" TopLine="10"/>
|
||||
</Position3>
|
||||
<Position4>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="27" Column="24" TopLine="1"/>
|
||||
</Position4>
|
||||
<Position5>
|
||||
<Filename Value="../../fpspreadsheet.pas"/>
|
||||
<Caret Line="205" Column="64" TopLine="181"/>
|
||||
</Position5>
|
||||
<Position6>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="35" Column="22" TopLine="3"/>
|
||||
</Position6>
|
||||
<Position7>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="13" Column="42" TopLine="1"/>
|
||||
</Position7>
|
||||
<Position8>
|
||||
<Filename Value="../../xlsbiff8.pas"/>
|
||||
<Caret Line="524" Column="14" TopLine="493"/>
|
||||
</Position8>
|
||||
<Position9>
|
||||
<Filename Value="../../fpspreadsheet.pas"/>
|
||||
<Caret Line="1147" Column="27" TopLine="1123"/>
|
||||
</Position9>
|
||||
<Position10>
|
||||
<Filename Value="../../xlsbiff8.pas"/>
|
||||
<Caret Line="124" Column="25" TopLine="94"/>
|
||||
</Position10>
|
||||
<Position11>
|
||||
<Filename Value="../../fpspreadsheet.pas"/>
|
||||
<Caret Line="1072" Column="74" TopLine="1067"/>
|
||||
</Position11>
|
||||
<Position12>
|
||||
<Filename Value="../../fpspreadsheet.pas"/>
|
||||
<Caret Line="206" Column="70" TopLine="175"/>
|
||||
</Position12>
|
||||
<Position13>
|
||||
<Filename Value="../../xlsbiff8.pas"/>
|
||||
<Caret Line="850" Column="14" TopLine="831"/>
|
||||
</Position13>
|
||||
<Position14>
|
||||
<Filename Value="../../xlsbiff8.pas"/>
|
||||
<Caret Line="104" Column="35" TopLine="102"/>
|
||||
</Position14>
|
||||
<Position15>
|
||||
<Filename Value="../../xlscommon.pas"/>
|
||||
<Caret Line="81" Column="76" TopLine="49"/>
|
||||
</Position15>
|
||||
<Position16>
|
||||
<Filename Value="../../xlscommon.pas"/>
|
||||
<Caret Line="40" Column="1" TopLine="17"/>
|
||||
</Position16>
|
||||
<Position17>
|
||||
<Filename Value="../../xlscommon.pas"/>
|
||||
<Caret Line="145" Column="41" TopLine="129"/>
|
||||
</Position17>
|
||||
<Position18>
|
||||
<Filename Value="../../xlscommon.pas"/>
|
||||
<Caret Line="91" Column="40" TopLine="69"/>
|
||||
</Position18>
|
||||
<Position19>
|
||||
<Filename Value="../../xlscommon.pas"/>
|
||||
<Caret Line="149" Column="3" TopLine="128"/>
|
||||
</Position19>
|
||||
<Position20>
|
||||
<Filename Value="../../xlsbiff8.pas"/>
|
||||
<Caret Line="104" Column="35" TopLine="102"/>
|
||||
</Position20>
|
||||
<Position21>
|
||||
<Filename Value="../../xlsbiff8.pas"/>
|
||||
<Caret Line="857" Column="72" TopLine="835"/>
|
||||
</Position21>
|
||||
<Position22>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="52" Column="1" TopLine="18"/>
|
||||
</Position22>
|
||||
<Position23>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="42" Column="27" TopLine="20"/>
|
||||
</Position23>
|
||||
<Position24>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="45" Column="15" TopLine="23"/>
|
||||
</Position24>
|
||||
<Position25>
|
||||
<Filename Value="test_write_formula.pas"/>
|
||||
<Caret Line="46" Column="38" TopLine="23"/>
|
||||
</Position25>
|
||||
</JumpHistory>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="10"/>
|
||||
<Target>
|
||||
<Filename Value="test_write_formula"/>
|
||||
</Target>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||
</SearchPaths>
|
||||
<Other>
|
||||
<CompilerPath Value="$(CompPath)"/>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="3">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
</Item1>
|
||||
<Item2>
|
||||
<Name Value="ECodetoolError"/>
|
||||
</Item2>
|
||||
<Item3>
|
||||
<Name Value="EFOpenError"/>
|
||||
</Item3>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
@ -0,0 +1,84 @@
|
||||
{
|
||||
test_write_formula.pas
|
||||
|
||||
Demonstrates how to write an formula using the fpspreadsheet library
|
||||
|
||||
AUTHORS: Felipe Monteiro de Carvalho
|
||||
}
|
||||
program test_write_formula;
|
||||
|
||||
{$mode delphi}{$H+}
|
||||
|
||||
uses
|
||||
Classes, SysUtils, fpspreadsheet, xlsbiff8, fpsopendocument,
|
||||
laz_fpspreadsheet, fpsconvencoding;
|
||||
|
||||
var
|
||||
MyWorkbook: TsWorkbook;
|
||||
MyWorksheet: TsWorksheet;
|
||||
MyDir: string;
|
||||
MyCell: PCell;
|
||||
|
||||
procedure WriteFirstWorksheet();
|
||||
var
|
||||
MyFormula: TsFormula;
|
||||
MyRPNFormula: TsRPNFormula;
|
||||
begin
|
||||
MyWorksheet := MyWorkbook.AddWorksheet('Worksheet1');
|
||||
|
||||
// Write some cells
|
||||
MyWorksheet.WriteUTF8Text(1, 0, 'Text Formulas');// A2
|
||||
|
||||
MyWorksheet.WriteUTF8Text(1, 1, '=Sum(D2:d5) Text Formula'); // B2
|
||||
|
||||
MyFormula.FormulaStr := '=Sum(D2:d5)';
|
||||
MyFormula.DoubleValue := 0.0;
|
||||
MyWorksheet.WriteFormula(1, 2, MyFormula); // C2
|
||||
|
||||
MyWorksheet.WriteUTF8Text(1, 1, '=Sum(D2:d5) RPN'); // B3
|
||||
|
||||
MyFormula.FormulaStr := '=Sum(D2:d5)';
|
||||
MyFormula.DoubleValue := 0.0;
|
||||
MyWorksheet.WriteFormula(1, 2, MyFormula); // C3
|
||||
|
||||
SetLength(MyRPNFormula, 2);
|
||||
MyRPNFormula[0].ElementKind := fekOpSUM;
|
||||
MyRPNFormula[1].ElementKind := fekCellRange;
|
||||
MyRPNFormula[1].Row := 1;
|
||||
MyRPNFormula[1].Row := 4;
|
||||
MyRPNFormula[1].Col := 3;
|
||||
MyRPNFormula[1].Col := 3;
|
||||
MyWorksheet.WriteRPNFormula(1, 2, MyRPNFormula); // C2
|
||||
end;
|
||||
|
||||
procedure WriteSecondWorksheet();
|
||||
begin
|
||||
{ MyWorksheet := MyWorkbook.AddWorksheet('Worksheet2');
|
||||
|
||||
// Write some cells
|
||||
|
||||
// Line 1
|
||||
|
||||
MyWorksheet.WriteUTF8Text(1, 1, 'Relatório');
|
||||
MyCell := MyWorksheet.GetCell(1, 1);
|
||||
MyCell^.Border := [cbNorth, cbWest, cbSouth];
|
||||
MyCell^.BackgroundColor := scGrey20pct;
|
||||
MyCell^.UsedFormattingFields := [uffBorder, uffBackgroundColor, uffBold];}
|
||||
end;
|
||||
|
||||
begin
|
||||
MyDir := ExtractFilePath(ParamStr(0));
|
||||
|
||||
// Create the spreadsheet
|
||||
MyWorkbook := TsWorkbook.Create;
|
||||
|
||||
WriteFirstWorksheet();
|
||||
|
||||
WriteSecondWorksheet();
|
||||
|
||||
// Save the spreadsheet to a file
|
||||
MyWorkbook.WriteToFile(MyDir + 'test_formula.xls', sfExcel8, False);
|
||||
// MyWorkbook.WriteToFile(MyDir + 'test_formula.odt', sfOpenDocument, False);
|
||||
MyWorkbook.Free;
|
||||
end.
|
||||
|
@ -57,7 +57,7 @@ type
|
||||
|
||||
TFEKind = (
|
||||
{ Basic operands }
|
||||
fekCell, fekNum,
|
||||
fekCell, fekCellRange, fekNum,
|
||||
{ Basic operations }
|
||||
fekAdd, fekSub, fekDiv, fekMul,
|
||||
{ Build-in Functions}
|
||||
@ -1161,6 +1161,14 @@ begin
|
||||
IterateThroughCells(AStream, ACells, WriteCellCallback);
|
||||
end;
|
||||
|
||||
{@@
|
||||
A generic method to iterate through all cells in a worksheet and call a callback
|
||||
routine for each cell.
|
||||
|
||||
@param AStream The output stream, passed to the callback routine.
|
||||
@param ACells List of cells to be iterated
|
||||
@param ACallback The callback routine
|
||||
}
|
||||
procedure TsCustomSpreadWriter.IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
|
||||
var
|
||||
AVLNode: TAVLTreeNode;
|
||||
|
@ -121,6 +121,7 @@ type
|
||||
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; ACell: PCell); override;
|
||||
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); override;
|
||||
@ -808,6 +809,88 @@ begin
|
||||
AStream.position := FinalPos;*)
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Writer.WriteRPNFormula(AStream: TStream; const ARow,
|
||||
ACol: Word; const AFormula: TsRPNFormula);
|
||||
var
|
||||
FormulaResult: double;
|
||||
i: Integer;
|
||||
RPNLength: Word;
|
||||
TokenArraySizePos, RecordSizePos, FinalPos: Int64;
|
||||
TokenID: Byte;
|
||||
begin
|
||||
RPNLength := 0;
|
||||
FormulaResult := 0.0;
|
||||
|
||||
{ BIFF Record header }
|
||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMULA));
|
||||
RecordSizePos := AStream.Position;
|
||||
AStream.WriteWord(WordToLE(22 + RPNLength));
|
||||
|
||||
{ BIFF Record data }
|
||||
AStream.WriteWord(WordToLE(ARow));
|
||||
AStream.WriteWord(WordToLE(ACol));
|
||||
|
||||
{ Index to XF Record }
|
||||
AStream.WriteWord($0000);
|
||||
|
||||
{ Result of the formula in IEE 754 floating-point value }
|
||||
AStream.WriteBuffer(FormulaResult, 8);
|
||||
|
||||
{ Options flags }
|
||||
AStream.WriteWord(WordToLE(MASK_FORMULA_RECALCULATE_ALWAYS));
|
||||
|
||||
{ Not used }
|
||||
AStream.WriteDWord(0);
|
||||
|
||||
{ Formula }
|
||||
|
||||
{ The size of the token array is written later,
|
||||
because it's necessary to calculate if first,
|
||||
and this is done at the same time it is written }
|
||||
TokenArraySizePos := AStream.Position;
|
||||
AStream.WriteWord(RPNLength);
|
||||
|
||||
{ Formula data (RPN token array) }
|
||||
for i := 0 to Length(AFormula) - 1 do
|
||||
begin
|
||||
{ Token identifier }
|
||||
TokenID := FormulaElementKindToExcelTokenID(AFormula[i].ElementKind);
|
||||
AStream.WriteByte(TokenID);
|
||||
Inc(RPNLength);
|
||||
|
||||
{ Additional data }
|
||||
case TokenID of
|
||||
|
||||
{ binary operation tokens }
|
||||
|
||||
INT_EXCEL_TOKEN_TADD, INT_EXCEL_TOKEN_TSUB, INT_EXCEL_TOKEN_TMUL,
|
||||
INT_EXCEL_TOKEN_TDIV, INT_EXCEL_TOKEN_TPOWER: begin end;
|
||||
|
||||
INT_EXCEL_TOKEN_TNUM:
|
||||
begin
|
||||
AStream.WriteBuffer(AFormula[i].DoubleValue, 8);
|
||||
Inc(RPNLength, 8);
|
||||
end;
|
||||
|
||||
INT_EXCEL_TOKEN_TREFR, INT_EXCEL_TOKEN_TREFV, INT_EXCEL_TOKEN_TREFA:
|
||||
begin
|
||||
AStream.WriteWord(AFormula[i].Row and MASK_EXCEL_ROW);
|
||||
AStream.WriteByte(AFormula[i].Col);
|
||||
Inc(RPNLength, 3);
|
||||
end;
|
||||
|
||||
end;
|
||||
end;
|
||||
|
||||
{ Write sizes in the end, after we known them }
|
||||
FinalPos := AStream.Position;
|
||||
AStream.position := TokenArraySizePos;
|
||||
AStream.WriteByte(RPNLength);
|
||||
AStream.Position := RecordSizePos;
|
||||
AStream.WriteWord(WordToLE(22 + RPNLength));
|
||||
AStream.position := FinalPos;
|
||||
end;
|
||||
|
||||
{*******************************************************************
|
||||
* TsSpreadBIFF8Writer.WriteIndex ()
|
||||
*
|
||||
|
@ -19,7 +19,17 @@ const
|
||||
INT_EXCEL_TOKEN_TSUB = $04;
|
||||
INT_EXCEL_TOKEN_TMUL = $05;
|
||||
INT_EXCEL_TOKEN_TDIV = $06;
|
||||
INT_EXCEL_TOKEN_TPOWER = $07;
|
||||
INT_EXCEL_TOKEN_TPOWER = $07; // Power Exponentiation
|
||||
INT_EXCEL_TOKEN_TCONCAT = $08;
|
||||
INT_EXCEL_TOKEN_TLT = $09; // Less than
|
||||
INT_EXCEL_TOKEN_TLE = $0A; // Less than or equal
|
||||
INT_EXCEL_TOKEN_TEQ = $0B; // Equal
|
||||
INT_EXCEL_TOKEN_TGE = $0C; // Greater than or equal
|
||||
INT_EXCEL_TOKEN_TGT = $0D; // Greater than
|
||||
INT_EXCEL_TOKEN_TNE = $0E; // Not equal
|
||||
INT_EXCEL_TOKEN_TISECT = $0F; // Cell range intersection
|
||||
INT_EXCEL_TOKEN_TLIST = $10; // Cell range list
|
||||
INT_EXCEL_TOKEN_TRANGE = $11; // Cell range
|
||||
|
||||
{ Constant Operand Tokens }
|
||||
INT_EXCEL_TOKEN_TNUM = $1F;
|
||||
@ -78,6 +88,7 @@ type
|
||||
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
|
||||
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
|
||||
function GetLastColIndex(AWorksheet: TsWorksheet): Word;
|
||||
function FormulaElementKindToExcelTokenID(AElementKind: TFEKind): Byte;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -131,5 +142,28 @@ begin
|
||||
Result := FLastCol;
|
||||
end;
|
||||
|
||||
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
|
||||
AElementKind: TFEKind): Byte;
|
||||
begin
|
||||
case AElementKind of
|
||||
{ Operand Tokens }
|
||||
fekCell: Result := INT_EXCEL_TOKEN_TREFR;
|
||||
fekCellRange: Result := INT_EXCEL_TOKEN_TRANGE;
|
||||
fekNum: Result := INT_EXCEL_TOKEN_TNUM;
|
||||
{ Basic operations }
|
||||
fekAdd: Result := INT_EXCEL_TOKEN_TADD;
|
||||
fekSub: Result := INT_EXCEL_TOKEN_TSUB;
|
||||
fekDiv: Result := INT_EXCEL_TOKEN_TDIV;
|
||||
fekMul: Result := INT_EXCEL_TOKEN_TMUL;
|
||||
{ Build-in Functions}
|
||||
fekABS: Result := INT_EXCEL_SHEET_FUNC_ABS;
|
||||
fekROUND: Result := INT_EXCEL_SHEET_FUNC_ROUND;
|
||||
{ Other operations }
|
||||
fekOpSUM: Result := 0;
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user