You've already forked lazarus-ccr
fpspreadsheet: Write OOXML string formulas. Write biff2 dimension record.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3456 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -1372,7 +1372,6 @@ function fpsDATEDIF(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|||||||
= YD - The difference between the days (years and dates are ignored). }
|
= YD - The difference between the days (years and dates are ignored). }
|
||||||
var
|
var
|
||||||
interval: String;
|
interval: String;
|
||||||
data: TsArgStringArray;
|
|
||||||
start_date, end_date: TDate;
|
start_date, end_date: TDate;
|
||||||
res1, res2, res3: TsArgument;
|
res1, res2, res3: TsArgument;
|
||||||
begin
|
begin
|
||||||
@ -1599,7 +1598,6 @@ function fpsCOUNTBLANK(Args: TsArgumentStack; NumArgs: Integer): TsArgument;
|
|||||||
var
|
var
|
||||||
arg: TsArgument;
|
arg: TsArgument;
|
||||||
r, c, n: Cardinal;
|
r, c, n: Cardinal;
|
||||||
cell: PCell;
|
|
||||||
begin
|
begin
|
||||||
arg := Args.Pop;
|
arg := Args.Pop;
|
||||||
case arg.ArgumentType of
|
case arg.ArgumentType of
|
||||||
|
@ -584,6 +584,8 @@ type
|
|||||||
|
|
||||||
function WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula): PCell; overload;
|
function WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula): PCell; overload;
|
||||||
procedure WriteFormula(ACell: PCell; AFormula: TsFormula); overload;
|
procedure WriteFormula(ACell: PCell; AFormula: TsFormula); overload;
|
||||||
|
function WriteFormula(ARow, ACol: Cardinal; AFormula: String): PCell; overload;
|
||||||
|
procedure WriteFormula(ACell: PCell; AFormula: String); overload;
|
||||||
|
|
||||||
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double); overload;
|
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double); overload;
|
||||||
procedure WriteNumber(ACell: PCell; ANumber: Double); overload;
|
procedure WriteNumber(ACell: PCell; ANumber: Double); overload;
|
||||||
@ -1700,7 +1702,6 @@ end;
|
|||||||
procedure TsWorksheet.CalcRPNFormula(ACell: PCell);
|
procedure TsWorksheet.CalcRPNFormula(ACell: PCell);
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
formula: TsRPNFormula;
|
|
||||||
args: TsArgumentStack;
|
args: TsArgumentStack;
|
||||||
func: TsFormulaFunc;
|
func: TsFormulaFunc;
|
||||||
val: TsArgument;
|
val: TsArgument;
|
||||||
@ -2342,7 +2343,6 @@ function TsWorksheet.ReadAsUTF8Text(ACell: PCell): ansistring;
|
|||||||
ANumberFormat: TsNumberFormat; ANumberFormatStr: string): ansistring;
|
ANumberFormat: TsNumberFormat; ANumberFormatStr: string): ansistring;
|
||||||
var
|
var
|
||||||
fs: TFormatSettings;
|
fs: TFormatSettings;
|
||||||
left, right: String;
|
|
||||||
begin
|
begin
|
||||||
fs := FWorkbook.FormatSettings;
|
fs := FWorkbook.FormatSettings;
|
||||||
if IsNan(Value) then
|
if IsNan(Value) then
|
||||||
@ -3456,6 +3456,35 @@ begin
|
|||||||
ChangedCell(ACell^.Row, ACell^.Col);
|
ChangedCell(ACell^.Row, ACell^.Col);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Writes a formula to a given cell
|
||||||
|
|
||||||
|
@param ARow The row of the cell
|
||||||
|
@param ACol The column of the cell
|
||||||
|
@param AFormula The formula string to be written
|
||||||
|
@return Pointer to the cell
|
||||||
|
}
|
||||||
|
function TsWorksheet.WriteFormula(ARow, ACol: Cardinal; AFormula: string): PCell;
|
||||||
|
begin
|
||||||
|
Result := GetCell(ARow, ACol);
|
||||||
|
WriteFormula(Result, AFormula);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Writes a formula to a given cell
|
||||||
|
|
||||||
|
@param ACell Pointer to the cell
|
||||||
|
@param AFormula Formula string to be written
|
||||||
|
}
|
||||||
|
procedure TsWorksheet.WriteFormula(ACell: PCell; AFormula: String);
|
||||||
|
begin
|
||||||
|
if ACell = nil then
|
||||||
|
exit;
|
||||||
|
ACell^.ContentType := cctFormula;
|
||||||
|
ACell^.FormulaValue.FormulaStr := AFormula;
|
||||||
|
ChangedCell(ACell^.Row, ACell^.Col);
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Adds a number format to the formatting of a cell
|
Adds a number format to the formatting of a cell
|
||||||
|
|
||||||
|
@ -52,7 +52,6 @@
|
|||||||
<Unit2>
|
<Unit2>
|
||||||
<Filename Value="stringtests.pas"/>
|
<Filename Value="stringtests.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
<UnitName Value="stringtests"/>
|
|
||||||
</Unit2>
|
</Unit2>
|
||||||
<Unit3>
|
<Unit3>
|
||||||
<Filename Value="numberstests.pas"/>
|
<Filename Value="numberstests.pas"/>
|
||||||
@ -66,16 +65,15 @@
|
|||||||
<Unit5>
|
<Unit5>
|
||||||
<Filename Value="testsutility.pas"/>
|
<Filename Value="testsutility.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
<UnitName Value="testsutility"/>
|
|
||||||
</Unit5>
|
</Unit5>
|
||||||
<Unit6>
|
<Unit6>
|
||||||
<Filename Value="internaltests.pas"/>
|
<Filename Value="internaltests.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
<UnitName Value="internaltests"/>
|
|
||||||
</Unit6>
|
</Unit6>
|
||||||
<Unit7>
|
<Unit7>
|
||||||
<Filename Value="formattests.pas"/>
|
<Filename Value="formattests.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="formattests"/>
|
||||||
</Unit7>
|
</Unit7>
|
||||||
<Unit8>
|
<Unit8>
|
||||||
<Filename Value="colortests.pas"/>
|
<Filename Value="colortests.pas"/>
|
||||||
|
@ -93,6 +93,7 @@ type
|
|||||||
procedure WriteCellFormatting(AStream: TStream; ACell: PCell; XFIndex: Word);
|
procedure WriteCellFormatting(AStream: TStream; ACell: PCell; XFIndex: Word);
|
||||||
procedure WriteColWidth(AStream: TStream; ACol: PCol);
|
procedure WriteColWidth(AStream: TStream; ACol: PCol);
|
||||||
procedure WriteColWidths(AStream: TStream);
|
procedure WriteColWidths(AStream: TStream);
|
||||||
|
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
procedure WriteEOF(AStream: TStream);
|
procedure WriteEOF(AStream: TStream);
|
||||||
procedure WriteFont(AStream: TStream; AFontIndex: Integer);
|
procedure WriteFont(AStream: TStream; AFontIndex: Integer);
|
||||||
procedure WriteFonts(AStream: TStream);
|
procedure WriteFonts(AStream: TStream);
|
||||||
@ -148,6 +149,7 @@ uses
|
|||||||
|
|
||||||
const
|
const
|
||||||
{ Excel record IDs }
|
{ Excel record IDs }
|
||||||
|
INT_EXCEL_ID_DIMENSIONS = $0000;
|
||||||
INT_EXCEL_ID_BLANK = $0001;
|
INT_EXCEL_ID_BLANK = $0001;
|
||||||
INT_EXCEL_ID_INTEGER = $0002;
|
INT_EXCEL_ID_INTEGER = $0002;
|
||||||
INT_EXCEL_ID_NUMBER = $0003;
|
INT_EXCEL_ID_NUMBER = $0003;
|
||||||
@ -169,6 +171,15 @@ const
|
|||||||
INT_EXCEL_MACRO_SHEET = $0040;
|
INT_EXCEL_MACRO_SHEET = $0040;
|
||||||
|
|
||||||
type
|
type
|
||||||
|
TBIFF2DimensionsRecord = packed record
|
||||||
|
RecordID: Word;
|
||||||
|
RecordSize: Word;
|
||||||
|
FirstRow: Word;
|
||||||
|
LastRowPlus1: Word;
|
||||||
|
FirstCol: Word;
|
||||||
|
LastColPlus1: Word;
|
||||||
|
end;
|
||||||
|
|
||||||
TBIFF2LabelRecord = packed record
|
TBIFF2LabelRecord = packed record
|
||||||
RecordID: Word;
|
RecordID: Word;
|
||||||
RecordSize: Word;
|
RecordSize: Word;
|
||||||
@ -1112,6 +1123,30 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Writes an Excel 2 DIMENSIONS record
|
||||||
|
}
|
||||||
|
procedure TsSpreadBIFF2Writer.WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
|
var
|
||||||
|
firstRow, lastRow, firstCol, lastCol: Cardinal;
|
||||||
|
rec: TBIFF2DimensionsRecord;
|
||||||
|
begin
|
||||||
|
{ Determine sheet size }
|
||||||
|
GetSheetDimensions(AWorksheet, firstRow, lastRow, firstCol, lastCol);
|
||||||
|
|
||||||
|
{ Populate BIFF record }
|
||||||
|
rec.RecordID := WordToLE(INT_EXCEL_ID_DIMENSIONS);
|
||||||
|
rec.RecordSize := WordToLE(8);
|
||||||
|
rec.FirstRow := WordToLE(firstRow);
|
||||||
|
rec.LastRowPlus1 := WordToLE(Min(lastRow+1, $FFFF)); // avoid WORD overflow
|
||||||
|
rec.FirstCol := WordToLE(firstCol);
|
||||||
|
rec.LastColPlus1 := WordToLE(lastCol+1);
|
||||||
|
|
||||||
|
{ Write BIFF record to stream }
|
||||||
|
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Writes an Excel 2 IXFE record
|
Writes an Excel 2 IXFE record
|
||||||
This record contains the "real" XF index if it is > 62.
|
This record contains the "real" XF index if it is > 62.
|
||||||
@ -1143,6 +1178,7 @@ begin
|
|||||||
WriteFormats(AStream);
|
WriteFormats(AStream);
|
||||||
WriteXFRecords(AStream);
|
WriteXFRecords(AStream);
|
||||||
WriteColWidths(AStream);
|
WriteColWidths(AStream);
|
||||||
|
WriteDimensions(AStream, sheet);
|
||||||
WriteRows(AStream, sheet);
|
WriteRows(AStream, sheet);
|
||||||
|
|
||||||
if (boVirtualMode in Workbook.Options) then
|
if (boVirtualMode in Workbook.Options) then
|
||||||
|
@ -219,7 +219,7 @@ var
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
fpsStreams;
|
Math, fpsStreams;
|
||||||
|
|
||||||
const
|
const
|
||||||
{ Excel record IDs }
|
{ Excel record IDs }
|
||||||
@ -563,7 +563,6 @@ procedure TsSpreadBIFF5Writer.WriteDimensions(AStream: TStream; AWorksheet: TsWo
|
|||||||
var
|
var
|
||||||
rec: TBIFF5DimensionsRecord;
|
rec: TBIFF5DimensionsRecord;
|
||||||
firstCol, lastCol, firstRow, lastRow: Cardinal;
|
firstCol, lastCol, firstRow, lastRow: Cardinal;
|
||||||
lLastRow, lLastCol: Word;
|
|
||||||
begin
|
begin
|
||||||
{ Determine sheet size }
|
{ Determine sheet size }
|
||||||
GetSheetDimensions(AWorksheet, firstRow, lastRow, firstCol, lastCol);
|
GetSheetDimensions(AWorksheet, firstRow, lastRow, firstCol, lastCol);
|
||||||
@ -572,37 +571,13 @@ begin
|
|||||||
rec.RecordID := WordToLE(INT_EXCEL_ID_DIMENSIONS);
|
rec.RecordID := WordToLE(INT_EXCEL_ID_DIMENSIONS);
|
||||||
rec.RecordSize := WordToLE(10);
|
rec.RecordSize := WordToLE(10);
|
||||||
rec.FirstRow := WordToLE(firstRow);
|
rec.FirstRow := WordToLE(firstRow);
|
||||||
rec.LastRowPlus1 := WordToLE(lastRow+1);
|
rec.LastRowPlus1 := WordToLE(Min(lastRow+1, $FFFF)); // avoid word overflow
|
||||||
rec.FirstCol := WordToLe(firstCol);
|
rec.FirstCol := WordToLe(firstCol);
|
||||||
rec.LastColPlus1 := WordToLE(lastCol+1);
|
rec.LastColPlus1 := WordToLE(lastCol+1);
|
||||||
rec.NotUsed := 0;
|
rec.NotUsed := 0;
|
||||||
|
|
||||||
{ Write BIFF record }
|
{ Write BIFF record }
|
||||||
AStream.WriteBuffer(rec, SizeOf(rec));
|
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||||
|
|
||||||
(*
|
|
||||||
|
|
||||||
{ BIFF Record header }
|
|
||||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_DIMENSIONS));
|
|
||||||
AStream.WriteWord(WordToLE(10));
|
|
||||||
|
|
||||||
{ Index to first used row }
|
|
||||||
AStream.WriteWord(0);
|
|
||||||
|
|
||||||
{ Index to last used row, increased by 1 }
|
|
||||||
lLastRow := Word(GetLastRowIndex(AWorksheet)+1);
|
|
||||||
AStream.WriteWord(WordToLE(lLastRow)); // Old dummy value: 33
|
|
||||||
|
|
||||||
{ Index to first used column }
|
|
||||||
AStream.WriteWord(0);
|
|
||||||
|
|
||||||
{ Index to last used column, increased by 1 }
|
|
||||||
lLastCol := Word(GetLastColIndex(AWorksheet)+1);
|
|
||||||
AStream.WriteWord(WordToLE(lLastCol)); // Old dummy value: 10
|
|
||||||
|
|
||||||
{ Not used }
|
|
||||||
AStream.WriteWord(0);
|
|
||||||
*)
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
|
@ -606,30 +606,6 @@ begin
|
|||||||
|
|
||||||
{ Write BIFF record to stream }
|
{ Write BIFF record to stream }
|
||||||
AStream.WriteBuffer(rec, SizeOf(rec));
|
AStream.WriteBuffer(rec, SizeOf(rec));
|
||||||
|
|
||||||
(*
|
|
||||||
{ BIFF Record header }
|
|
||||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_DIMENSIONS));
|
|
||||||
AStream.WriteWord(WordToLE(14));
|
|
||||||
|
|
||||||
{ Determine sheet size }
|
|
||||||
GetSheetDimensions(AWorksheet, firstRow, lastRow, firstCol, lastCol);
|
|
||||||
|
|
||||||
{ Index to first used row }
|
|
||||||
AStream.WriteDWord(DWordToLE(firstRow));
|
|
||||||
|
|
||||||
{ Index to last used row, increased by 1 }
|
|
||||||
AStream.WriteDWord(DWordToLE(lastRow+1));
|
|
||||||
|
|
||||||
{ Index to first used column }
|
|
||||||
AStream.WriteWord(WordToLE(firstCol));
|
|
||||||
|
|
||||||
{ Index to last used column, increased by 1 }
|
|
||||||
AStream.WriteWord(WordToLE(lastCol+1));
|
|
||||||
|
|
||||||
{ Not used }
|
|
||||||
AStream.WriteWord(WordToLE(0));
|
|
||||||
*)
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
|
@ -114,6 +114,7 @@ type
|
|||||||
function GetStyleIndex(ACell: PCell): Cardinal;
|
function GetStyleIndex(ACell: PCell): Cardinal;
|
||||||
procedure ListAllBorders;
|
procedure ListAllBorders;
|
||||||
procedure ListAllFills;
|
procedure ListAllFills;
|
||||||
|
function PrepareFormula(const AFormula: TsFormula): String;
|
||||||
procedure ResetStreams;
|
procedure ResetStreams;
|
||||||
procedure WriteBorderList(AStream: TStream);
|
procedure WriteBorderList(AStream: TStream);
|
||||||
procedure WriteCols(AStream: TStream; AWorksheet: TsWorksheet);
|
procedure WriteCols(AStream: TStream; AWorksheet: TsWorksheet);
|
||||||
@ -143,10 +144,16 @@ type
|
|||||||
protected
|
protected
|
||||||
{ Record writing methods }
|
{ Record writing methods }
|
||||||
//todo: add WriteDate
|
//todo: add WriteDate
|
||||||
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override;
|
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); override;
|
ACell: PCell); override;
|
||||||
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); override;
|
procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal; const AValue: TDateTime; ACell: PCell); override;
|
const AFormula: TsFormula; ACell: PCell); override;
|
||||||
|
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
|
const AValue: string; ACell: PCell); override;
|
||||||
|
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
|
const AValue: double; ACell: PCell); override;
|
||||||
|
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
|
||||||
|
const AValue: TDateTime; ACell: PCell); override;
|
||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
@ -1907,15 +1914,6 @@ begin
|
|||||||
end else
|
end else
|
||||||
begin
|
begin
|
||||||
// The cells need to be written in order, row by row, cell by cell
|
// The cells need to be written in order, row by row, cell by cell
|
||||||
(*
|
|
||||||
c1 := AWorksheet.GetFirstColIndex;
|
|
||||||
c2 := AWorksheet.GetLastColIndex;
|
|
||||||
if (c1 = $FFFFFFFF) and (c2 = 0) then c1 := 0; // avoid arithmetic overflow in case of empty worksheet
|
|
||||||
r1 := AWorksheet.GetFirstRowIndex;
|
|
||||||
r2 := AWorksheet.GetlastRowIndex;
|
|
||||||
if (r1 = $FFFFFFFF) and (r2 = 0) then r1 := 0; // avoid arithmetic overflow in case of empty worksheet
|
|
||||||
// for r := 0 to AWorksheet.GetLastRowIndex do begin
|
|
||||||
*)
|
|
||||||
for r := r1 to r2 do begin
|
for r := r1 to r2 do begin
|
||||||
// If the row has a custom height add this value to the <row> specification
|
// If the row has a custom height add this value to the <row> specification
|
||||||
row := AWorksheet.FindRow(r);
|
row := AWorksheet.FindRow(r);
|
||||||
@ -2364,6 +2362,13 @@ begin
|
|||||||
SetLength(FSSheets, 0);
|
SetLength(FSSheets, 0);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Prepares a string formula for writing }
|
||||||
|
function TsSpreadOOXMLWriter.PrepareFormula(const AFormula: TsFormula): String;
|
||||||
|
begin
|
||||||
|
Result := AFormula.FormulaStr;
|
||||||
|
if (Result <> '') and (Result[1] = '=') then Delete(Result, 1, 1);
|
||||||
|
end;
|
||||||
|
|
||||||
{ Is called before zipping the individual file parts. Rewinds the streams. }
|
{ Is called before zipping the individual file parts. Rewinds the streams. }
|
||||||
procedure TsSpreadOOXMLWriter.ResetStreams;
|
procedure TsSpreadOOXMLWriter.ResetStreams;
|
||||||
var
|
var
|
||||||
@ -2486,6 +2491,24 @@ begin
|
|||||||
'</c>');
|
'</c>');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Writes a string formula to the given cell. }
|
||||||
|
procedure TsSpreadOOXMLWriter.WriteFormula(AStream: TStream;
|
||||||
|
const ARow, ACol: Cardinal; const AFormula: TsFormula; ACell: PCell);
|
||||||
|
var
|
||||||
|
cellPosText: String;
|
||||||
|
lStyleIndex: Integer;
|
||||||
|
begin
|
||||||
|
cellPosText := TsWorksheet.CellPosToText(ARow, ACol);
|
||||||
|
lStyleIndex := GetStyleIndex(ACell);
|
||||||
|
|
||||||
|
AppendToStream(AStream, Format(
|
||||||
|
'<c r="%s" s="%d">' +
|
||||||
|
'<f>%s</f>' +
|
||||||
|
'</c>', [
|
||||||
|
CellPosText, lStyleIndex,
|
||||||
|
PrepareFormula(AFormula)
|
||||||
|
]));
|
||||||
|
end;
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
* TsSpreadOOXMLWriter.WriteLabel ()
|
* TsSpreadOOXMLWriter.WriteLabel ()
|
||||||
|
Reference in New Issue
Block a user