
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@690 8e941d3f-bd1b-0410-a28a-d453659cc2b4
832 lines
18 KiB
ObjectPascal
Executable File
832 lines
18 KiB
ObjectPascal
Executable File
{
|
|
fpspreadsheet.pas
|
|
|
|
Writes an spreadsheet document
|
|
|
|
AUTHORS: Felipe Monteiro de Carvalho
|
|
}
|
|
unit fpspreadsheet;
|
|
|
|
{$ifdef fpc}
|
|
{$mode delphi}
|
|
{$endif}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils;
|
|
|
|
type
|
|
TsSpreadsheetFormat = (sfExcel2, sfExcel3, sfExcel4, sfExcel5, sfExcel8,
|
|
sfOOXML, sfOpenDocument, sfCSV);
|
|
|
|
const
|
|
{ Default extensions }
|
|
STR_EXCEL_EXTENSION = '.xls';
|
|
STR_OOXML_EXCEL_EXTENSION = '.xlsx';
|
|
STR_OPENDOCUMENT_CALC_EXTENSION = '.ods';
|
|
|
|
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;
|
|
|
|
type
|
|
|
|
{@@ A Token of a RPN Token array for formulas }
|
|
|
|
TRPNToken = record
|
|
TokenID: Byte;
|
|
Col: Byte;
|
|
Row: Word;
|
|
DoubleValue: double;
|
|
end;
|
|
|
|
{@@ RPN Token array for formulas }
|
|
|
|
TRPNFormula = array of TRPNToken;
|
|
|
|
{@@ Describes the type of content of a cell on a TsWorksheet }
|
|
|
|
TCellContentType = (cctEmpty, cctFormula, cctNumber, cctUTF8String);
|
|
|
|
{@@ Cell structure for TsWorksheet }
|
|
|
|
TCell = record
|
|
Col: Byte;
|
|
Row: Word;
|
|
ContentType: TCellContentType;
|
|
FormulaValue: TRPNFormula;
|
|
NumberValue: double;
|
|
UTF8StringValue: ansistring;
|
|
end;
|
|
|
|
PCell = ^TCell;
|
|
|
|
type
|
|
|
|
TsCustomSpreadReader = class;
|
|
TsCustomSpreadWriter = class;
|
|
|
|
{@@ TsWorksheet }
|
|
|
|
{ TsWorksheet }
|
|
|
|
TsWorksheet = class
|
|
private
|
|
procedure RemoveCallback(data, arg: pointer);
|
|
public
|
|
FCells: TFPList;
|
|
Name: string;
|
|
{ Base methods }
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
{ Data manipulation methods }
|
|
function FindCell(ARow, ACol: Cardinal): PCell;
|
|
function GetCell(ARow, ACol: Cardinal): PCell;
|
|
function GetCellCount: Cardinal;
|
|
function GetCellByIndex(AIndex: Cardinal): PCell;
|
|
function GetLastColNumber: Cardinal;
|
|
function GetLastRowNumber: Cardinal;
|
|
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
|
|
procedure RemoveAllCells;
|
|
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
|
|
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double);
|
|
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TRPNFormula);
|
|
end;
|
|
|
|
{@@ TsWorkbook }
|
|
|
|
{ TsWorkbook }
|
|
|
|
TsWorkbook = class
|
|
private
|
|
{ Internal data }
|
|
FWorksheets: TFPList;
|
|
{ Internal methods }
|
|
procedure RemoveCallback(data, arg: pointer);
|
|
public
|
|
{ Base methods }
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader;
|
|
function CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter;
|
|
procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat);
|
|
procedure ReadFromStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
|
procedure WriteToFile(AFileName: string; AFormat: TsSpreadsheetFormat);
|
|
procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
|
{ Worksheet list handling methods }
|
|
function AddWorksheet(AName: string): TsWorksheet;
|
|
function GetFirstWorksheet: TsWorksheet;
|
|
function GetWorksheetByIndex(AIndex: Cardinal): TsWorksheet;
|
|
function GetWorksheetCount: Cardinal;
|
|
procedure RemoveAllWorksheets;
|
|
end;
|
|
|
|
{@@ TsSpreadReader class reference type }
|
|
|
|
TsSpreadReaderClass = class of TsCustomSpreadReader;
|
|
|
|
{@@ TsCustomSpreadReader }
|
|
|
|
{ TsCustomSpreadReader }
|
|
|
|
TsCustomSpreadReader = class
|
|
protected
|
|
FWorkbook: TsWorkbook;
|
|
FCurrentWorksheet: TsWorksheet;
|
|
public
|
|
{ General writing methods }
|
|
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); virtual;
|
|
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); virtual;
|
|
{ Record reading methods }
|
|
procedure ReadFormula(AStream: TStream); virtual; abstract;
|
|
procedure ReadLabel(AStream: TStream); virtual; abstract;
|
|
procedure ReadNumber(AStream: TStream); virtual; abstract;
|
|
end;
|
|
|
|
{@@ TsSpreadWriter class reference type }
|
|
|
|
TsSpreadWriterClass = class of TsCustomSpreadWriter;
|
|
|
|
{@@ TsCustomSpreadWriter }
|
|
|
|
{ TsCustomSpreadWriter }
|
|
|
|
TsCustomSpreadWriter = class
|
|
public
|
|
{ General writing methods }
|
|
procedure WriteCellCallback(data, arg: pointer);
|
|
procedure WriteCellsToStream(AStream: TStream; ACells: TFPList);
|
|
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: TRPNFormula); virtual; abstract;
|
|
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;
|
|
|
|
{@@ List of registered formats }
|
|
|
|
TsSpreadFormatData = record
|
|
ReaderClass: TsSpreadReaderClass;
|
|
WriterClass: TsSpreadWriterClass;
|
|
Format: TsSpreadsheetFormat;
|
|
end;
|
|
|
|
var
|
|
GsSpreadFormats: array of TsSpreadFormatData;
|
|
|
|
procedure RegisterSpreadFormat(
|
|
AReaderClass: TsSpreadReaderClass;
|
|
AWriterClass: TsSpreadWriterClass;
|
|
AFormat: TsSpreadsheetFormat);
|
|
|
|
implementation
|
|
|
|
var
|
|
{ Translatable strings }
|
|
lpUnsupportedReadFormat, lpUnsupportedWriteFormat: string;
|
|
|
|
{@@
|
|
Registers a new reader/writer pair for a format
|
|
}
|
|
procedure RegisterSpreadFormat(
|
|
AReaderClass: TsSpreadReaderClass;
|
|
AWriterClass: TsSpreadWriterClass;
|
|
AFormat: TsSpreadsheetFormat);
|
|
var
|
|
len: Integer;
|
|
begin
|
|
len := Length(GsSpreadFormats);
|
|
SetLength(GsSpreadFormats, len + 1);
|
|
|
|
GsSpreadFormats[len].ReaderClass := AReaderClass;
|
|
GsSpreadFormats[len].WriterClass := AWriterClass;
|
|
GsSpreadFormats[len].Format := AFormat;
|
|
end;
|
|
|
|
{ TsWorksheet }
|
|
|
|
{@@
|
|
Helper method for clearing the records in a spreadsheet.
|
|
}
|
|
procedure TsWorksheet.RemoveCallback(data, arg: pointer);
|
|
begin
|
|
FreeMem(data);
|
|
end;
|
|
|
|
{@@
|
|
Constructor.
|
|
}
|
|
constructor TsWorksheet.Create;
|
|
begin
|
|
inherited Create;
|
|
|
|
FCells := TFPList.Create;
|
|
end;
|
|
|
|
{@@
|
|
Destructor.
|
|
}
|
|
destructor TsWorksheet.Destroy;
|
|
begin
|
|
RemoveAllCells;
|
|
|
|
FCells.Free;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{@@
|
|
Tryes to locate a Cell in the list of already
|
|
written Cells
|
|
|
|
@param ARow The row of the cell
|
|
@param ACol The column of the cell
|
|
|
|
@return Nil if no existing cell was found,
|
|
otherwise a pointer to the desired Cell
|
|
|
|
@see TCell
|
|
}
|
|
function TsWorksheet.FindCell(ARow, ACol: Cardinal): PCell;
|
|
var
|
|
i: Integer;
|
|
ACell: PCell;
|
|
begin
|
|
i := 0;
|
|
Result := nil;
|
|
|
|
while (i < FCells.Count) do
|
|
begin
|
|
ACell := PCell(FCells.Items[i]);
|
|
|
|
if (ACell^.Row = ARow) and (ACell^.Col = ACol) then
|
|
begin
|
|
Result := ACell;
|
|
Exit;
|
|
end;
|
|
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Obtains an allocated cell at the desired location.
|
|
|
|
If the Cell already exists, a pointer to it will
|
|
be returned.
|
|
|
|
If not, then new memory for the cell will be allocated,
|
|
a pointer to it will be returned and it will be added
|
|
to the list of Cells.
|
|
|
|
@param ARow The row of the cell
|
|
@param ACol The column of the cell
|
|
|
|
@return A pointer to the Cell on the desired location.
|
|
|
|
@see TCell
|
|
}
|
|
function TsWorksheet.GetCell(ARow, ACol: Cardinal): PCell;
|
|
begin
|
|
Result := FindCell(ARow, ACol);
|
|
|
|
if (Result = nil) then
|
|
begin
|
|
Result := GetMem(SizeOf(TCell));
|
|
FillChar(Result^, SizeOf(TCell), #0);
|
|
|
|
Result^.Row := ARow;
|
|
Result^.Col := ACol;
|
|
|
|
FCells.Add(Result);
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Returns the number of cells in the worksheet with contents.
|
|
|
|
This routine is used together with GetCellByIndex to
|
|
iterate througth all cells in a worksheet efficiently.
|
|
|
|
@return The number of cells with contents in the worksheet
|
|
|
|
@see TCell
|
|
@see GetCellByIndex
|
|
}
|
|
function TsWorksheet.GetCellCount: Cardinal;
|
|
begin
|
|
Result := FCells.Count;
|
|
end;
|
|
|
|
{@@
|
|
Obtains the cell with a specific index in the internal list of cells.
|
|
|
|
The index goes from 0 to GetCellCount - 1.
|
|
|
|
This routine is used together with GetCellCount to
|
|
iterate througth all cells in a worksheet efficiently.
|
|
|
|
@param AIndex The index of the cell to be obtained
|
|
|
|
@return A pointer to the cell, or nil if it doesn't exist
|
|
|
|
@see TCell
|
|
@see GetCellCount
|
|
}
|
|
function TsWorksheet.GetCellByIndex(AIndex: Cardinal): PCell;
|
|
begin
|
|
if FCells.Count > AIndex then Result := PCell(FCells.Items[AIndex])
|
|
else Result := nil;
|
|
end;
|
|
|
|
{@@
|
|
Returns the number of the last column with a cell with contents.
|
|
|
|
If no cells have contents, zero will be returned, which is also a valid value.
|
|
|
|
Use GetCellCount to verify if there is at least one cell with contents in the
|
|
worksheet.
|
|
|
|
@see GetCellCount
|
|
}
|
|
function TsWorksheet.GetLastColNumber: Cardinal;
|
|
var
|
|
i: Integer;
|
|
ACell: PCell;
|
|
begin
|
|
i := 0;
|
|
Result := 0;
|
|
|
|
while (i < FCells.Count) do
|
|
begin
|
|
ACell := PCell(FCells.Items[i]);
|
|
|
|
if ACell^.Col > Result then Result := ACell^.Col;
|
|
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Returns the number of the last row with a cell with contents.
|
|
|
|
If no cells have contents, zero will be returned, which is also a valid value.
|
|
|
|
Use GetCellCount to verify if there is at least one cell with contents in the
|
|
worksheet.
|
|
|
|
@see GetCellCount
|
|
}
|
|
function TsWorksheet.GetLastRowNumber: Cardinal;
|
|
var
|
|
i: Integer;
|
|
ACell: PCell;
|
|
begin
|
|
i := 0;
|
|
Result := 0;
|
|
|
|
while (i < FCells.Count) do
|
|
begin
|
|
ACell := PCell(FCells.Items[i]);
|
|
|
|
if ACell^.Row > Result then Result := ACell^.Row;
|
|
|
|
Inc(i);
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Reads the contents of a cell and returns an user readable text
|
|
representing the contents of the cell.
|
|
|
|
The resulting ansistring is UTF-8 encoded.
|
|
|
|
@param ARow The row of the cell
|
|
@param ACol The column of the cell
|
|
|
|
@return The text representation of the cell
|
|
}
|
|
function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
|
|
var
|
|
ACell: PCell;
|
|
begin
|
|
ACell := FindCell(ARow, ACol);
|
|
|
|
if ACell = nil then
|
|
begin
|
|
Result := '';
|
|
Exit;
|
|
end;
|
|
|
|
case ACell^.ContentType of
|
|
|
|
//cctFormula
|
|
cctNumber: Result := FloatToStr(ACell^.NumberValue);
|
|
cctUTF8String: Result := UTF8ToAnsi(ACell^.UTF8StringValue);
|
|
else
|
|
Result := '';
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Clears the list of Cells and releases their memory.
|
|
}
|
|
procedure TsWorksheet.RemoveAllCells;
|
|
begin
|
|
FCells.ForEachCall(RemoveCallback, nil);
|
|
end;
|
|
|
|
{@@
|
|
Writes UTF-8 encoded text to a determined cell.
|
|
|
|
On formats that only support unicode the text will be converted
|
|
to the unicode encoding that the format supports.
|
|
|
|
@param ARow The row of the cell
|
|
@param ACol The column of the cell
|
|
@param AText The text to be written encoded with the system encoding
|
|
}
|
|
procedure TsWorksheet.WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
|
|
var
|
|
ACell: PCell;
|
|
begin
|
|
ACell := GetCell(ARow, ACol);
|
|
|
|
ACell^.ContentType := cctUTF8String;
|
|
ACell^.UTF8StringValue := AText;
|
|
end;
|
|
|
|
{@@
|
|
Writes a floating-point number to a determined cell
|
|
|
|
@param ARow The row of the cell
|
|
@param ACol The column of the cell
|
|
@param ANumber The number to be written
|
|
}
|
|
procedure TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: double);
|
|
var
|
|
ACell: PCell;
|
|
begin
|
|
ACell := GetCell(ARow, ACol);
|
|
|
|
ACell^.ContentType := cctNumber;
|
|
ACell^.NumberValue := ANumber;
|
|
end;
|
|
|
|
{@@
|
|
Writes a formula to a determined cell
|
|
|
|
@param ARow The row of the cell
|
|
@param ACol The column of the cell
|
|
@param AFormula The formula in RPN array format
|
|
}
|
|
procedure TsWorksheet.WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TRPNFormula);
|
|
var
|
|
ACell: PCell;
|
|
begin
|
|
ACell := GetCell(ARow, ACol);
|
|
|
|
ACell^.ContentType := cctFormula;
|
|
ACell^.FormulaValue := AFormula;
|
|
end;
|
|
|
|
{ TsWorkbook }
|
|
|
|
{@@
|
|
Helper method for clearing the spreadsheet list.
|
|
}
|
|
procedure TsWorkbook.RemoveCallback(data, arg: pointer);
|
|
begin
|
|
TsWorksheet(data).Free;
|
|
end;
|
|
|
|
{@@
|
|
Constructor.
|
|
}
|
|
constructor TsWorkbook.Create;
|
|
begin
|
|
inherited Create;
|
|
|
|
FWorksheets := TFPList.Create;
|
|
|
|
// In the future: add support for translations
|
|
lpUnsupportedReadFormat := 'Tryed to read a spreadsheet using an unsupported format';
|
|
lpUnsupportedWriteFormat := 'Tryed to write a spreadsheet using an unsupported format';
|
|
end;
|
|
|
|
{@@
|
|
Destructor.
|
|
}
|
|
destructor TsWorkbook.Destroy;
|
|
begin
|
|
RemoveAllWorksheets;
|
|
|
|
FWorksheets.Free;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
{@@
|
|
Convenience method which creates the correct
|
|
reader object for a given spreadsheet format.
|
|
}
|
|
function TsWorkbook.CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
|
|
for i := 0 to Length(GsSpreadFormats) - 1 do
|
|
if GsSpreadFormats[i].Format = AFormat then
|
|
begin
|
|
Result := GsSpreadFormats[i].ReaderClass.Create;
|
|
|
|
Break;
|
|
end;
|
|
|
|
if Result = nil then raise Exception.Create(lpUnsupportedReadFormat);
|
|
end;
|
|
|
|
{@@
|
|
Convenience method which creates the correct
|
|
writer object for a given spreadsheet format.
|
|
}
|
|
function TsWorkbook.CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := nil;
|
|
|
|
for i := 0 to Length(GsSpreadFormats) - 1 do
|
|
if GsSpreadFormats[i].Format = AFormat then
|
|
begin
|
|
Result := GsSpreadFormats[i].WriterClass.Create;
|
|
|
|
Break;
|
|
end;
|
|
|
|
if Result = nil then raise Exception.Create(lpUnsupportedWriteFormat);
|
|
end;
|
|
|
|
{@@
|
|
Reads the document from a file.
|
|
}
|
|
procedure TsWorkbook.ReadFromFile(AFileName: string;
|
|
AFormat: TsSpreadsheetFormat);
|
|
var
|
|
AReader: TsCustomSpreadReader;
|
|
begin
|
|
AReader := CreateSpreadReader(AFormat);
|
|
|
|
try
|
|
AReader.ReadFromFile(AFileName, Self);
|
|
finally
|
|
AReader.Free;
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Reads the document from a seekable stream.
|
|
}
|
|
procedure TsWorkbook.ReadFromStream(AStream: TStream;
|
|
AFormat: TsSpreadsheetFormat);
|
|
var
|
|
AReader: TsCustomSpreadReader;
|
|
begin
|
|
AReader := CreateSpreadReader(AFormat);
|
|
|
|
try
|
|
AReader.ReadFromStream(AStream, Self);
|
|
finally
|
|
AReader.Free;
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Writes the document to a file.
|
|
|
|
If the file doesn't exist, it will be created.
|
|
}
|
|
procedure TsWorkbook.WriteToFile(AFileName: string; AFormat: TsSpreadsheetFormat);
|
|
var
|
|
AWriter: TsCustomSpreadWriter;
|
|
begin
|
|
AWriter := CreateSpreadWriter(AFormat);
|
|
|
|
try
|
|
AWriter.WriteToFile(AFileName, Self);
|
|
finally
|
|
AWriter.Free;
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Writes the document to a stream
|
|
}
|
|
procedure TsWorkbook.WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
|
var
|
|
AWriter: TsCustomSpreadWriter;
|
|
begin
|
|
AWriter := CreateSpreadWriter(AFormat);
|
|
|
|
try
|
|
AWriter.WriteToStream(AStream, Self);
|
|
finally
|
|
AWriter.Free;
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Adds a new worksheet to the workbook
|
|
|
|
It is added to the end of the list of worksheets
|
|
|
|
@param AName The name of the new worksheet
|
|
|
|
@return The instace of the newly created worksheet
|
|
|
|
@see TsWorkbook
|
|
}
|
|
function TsWorkbook.AddWorksheet(AName: string): TsWorksheet;
|
|
begin
|
|
Result := TsWorksheet.Create;
|
|
|
|
Result.Name := AName;
|
|
|
|
FWorksheets.Add(Pointer(Result));
|
|
end;
|
|
|
|
{@@
|
|
Quick helper routine which returns the first worksheet
|
|
|
|
@return A TsWorksheet instance if at least one is present.
|
|
nil otherwise.
|
|
|
|
@see TsWorkbook.GetWorksheetByIndex
|
|
@see TsWorksheet
|
|
}
|
|
function TsWorkbook.GetFirstWorksheet: TsWorksheet;
|
|
begin
|
|
Result := TsWorksheet(FWorksheets.First);
|
|
end;
|
|
|
|
{@@
|
|
Gets the worksheet with a given index
|
|
|
|
The index is zero-based, so the first worksheet
|
|
added has index 0, the second 1, etc.
|
|
|
|
@param AIndex The index of the worksheet (0-based)
|
|
|
|
@return A TsWorksheet instance if one is present at that index.
|
|
nil otherwise.
|
|
|
|
@see TsWorkbook.GetFirstWorksheet
|
|
@see TsWorksheet
|
|
}
|
|
function TsWorkbook.GetWorksheetByIndex(AIndex: Cardinal): TsWorksheet;
|
|
begin
|
|
if AIndex < FWorksheets.Count then Result := TsWorksheet(FWorksheets.Items[AIndex])
|
|
else Result := nil;
|
|
end;
|
|
|
|
{@@
|
|
The number of worksheets on the workbook
|
|
|
|
@see TsWorksheet
|
|
}
|
|
function TsWorkbook.GetWorksheetCount: Cardinal;
|
|
begin
|
|
Result := FWorksheets.Count;
|
|
end;
|
|
|
|
{@@
|
|
Clears the list of Worksheets and releases their memory.
|
|
}
|
|
procedure TsWorkbook.RemoveAllWorksheets;
|
|
begin
|
|
FWorksheets.ForEachCall(RemoveCallback, nil);
|
|
end;
|
|
|
|
{ TsCustomSpreadReader }
|
|
|
|
{@@
|
|
Default file reading method.
|
|
|
|
Opens the file and calls ReadFromStream
|
|
|
|
@param AFileName The input file name.
|
|
@param AData The Workbook to be filled with information from the file.
|
|
|
|
@see TsWorkbook
|
|
}
|
|
procedure TsCustomSpreadReader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
|
var
|
|
InputFile: TFileStream;
|
|
begin
|
|
InputFile := TFileStream.Create(AFileName, fmOpenRead);
|
|
try
|
|
ReadFromStream(InputFile, AData);
|
|
finally
|
|
InputFile.Free;
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
This routine should be overriden in descendent classes.
|
|
}
|
|
procedure TsCustomSpreadReader.ReadFromStream(AStream: TStream; AData: TsWorkbook);
|
|
begin
|
|
raise Exception.Create(lpUnsupportedReadFormat);
|
|
end;
|
|
|
|
{ TsCustomSpreadWriter }
|
|
|
|
{@@
|
|
Helper function for the spreadsheet writers.
|
|
|
|
@see TsCustomSpreadWriter.WriteCellsToStream
|
|
}
|
|
procedure TsCustomSpreadWriter.WriteCellCallback(data, arg: pointer);
|
|
var
|
|
ACell: PCell;
|
|
AStream: TStream;
|
|
begin
|
|
ACell := PCell(data);
|
|
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);
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
Helper function for the spreadsheet writers.
|
|
|
|
Iterates all cells on a list, calling the appropriate write method for them.
|
|
|
|
@param AStream The output stream.
|
|
@param ACells List of cells to be writeen
|
|
}
|
|
procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream; ACells: TFPList);
|
|
begin
|
|
ACells.ForEachCall(WriteCellCallback, Pointer(AStream));
|
|
end;
|
|
|
|
{@@
|
|
Default file writting method.
|
|
|
|
Opens the file and calls WriteToStream
|
|
|
|
@param AFileName The output file name.
|
|
If the file already exists it will be replaced.
|
|
@param AData The Workbook to be saved.
|
|
|
|
@see TsWorkbook
|
|
}
|
|
procedure TsCustomSpreadWriter.WriteToFile(AFileName: string; AData: TsWorkbook);
|
|
var
|
|
OutputFile: TFileStream;
|
|
begin
|
|
OutputFile := TFileStream.Create(AFileName, fmCreate or fmOpenWrite);
|
|
try
|
|
WriteToStream(OutputFile, AData);
|
|
finally
|
|
OutputFile.Free;
|
|
end;
|
|
end;
|
|
|
|
{@@
|
|
This routine should be overriden in descendent classes.
|
|
}
|
|
procedure TsCustomSpreadWriter.WriteToStream(AStream: TStream; AData: TsWorkbook);
|
|
begin
|
|
raise Exception.Create(lpUnsupportedWriteFormat);
|
|
|
|
end;
|
|
|
|
finalization
|
|
|
|
SetLength(GsSpreadFormats, 0);
|
|
|
|
end.
|
|
|