FPSpreadsheet: Starts implementing biff2 formatting and also flexible support for biff formats, but all parts are unfinished

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1644 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2011-05-25 15:50:18 +00:00
parent 088628a9bc
commit 68f1ccd497
3 changed files with 123 additions and 49 deletions

View File

@ -88,7 +88,7 @@ type
{@@ List of possible formatting fields } {@@ List of possible formatting fields }
TsUsedFormattingField = (uffTextRotation, uffBold, uffBorder{, uffBackgroundColor}); TsUsedFormattingField = (uffTextRotation, uffBold, uffBorder, uffBackgroundColor);
{@@ Describes which formatting fields are active } {@@ Describes which formatting fields are active }
@ -109,7 +109,7 @@ type
{.@@ Colors in FPSpreadsheet as given by a list of possible default values } {.@@ Colors in FPSpreadsheet as given by a list of possible default values }
//TsColor = (); TsColor = (scLtGrey);
{@@ Cell structure for TsWorksheet {@@ Cell structure for TsWorksheet
@ -133,7 +133,7 @@ type
UsedFormattingFields: TsUsedFormattingFields; UsedFormattingFields: TsUsedFormattingFields;
TextRotation: TsTextRotation; TextRotation: TsTextRotation;
Border: TsCellBorders; Border: TsCellBorders;
//BackgroundColor: TsColor; BackgroundColor: TsColor;
end; end;
PCell = ^TCell; PCell = ^TCell;
@ -232,6 +232,8 @@ type
TsSpreadWriterClass = class of TsCustomSpreadWriter; TsSpreadWriterClass = class of TsCustomSpreadWriter;
TCellsCallback = procedure (ACell: PCell; AStream: TStream) of object;
{ TsCustomSpreadWriter } { TsCustomSpreadWriter }
TsCustomSpreadWriter = class TsCustomSpreadWriter = class
@ -239,8 +241,9 @@ type
{ Helper routines } { Helper routines }
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula; function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
{ General writing methods } { General writing methods }
procedure WriteCellCallback(data, arg: pointer); procedure WriteCellCallback(ACell: PCell; AStream: TStream);
procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree); procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
procedure WriteToFile(const AFileName: string; AData: TsWorkbook; procedure WriteToFile(const AFileName: string; AData: TsWorkbook;
const AOverwriteExisting: Boolean = False); virtual; const AOverwriteExisting: Boolean = False); virtual;
procedure WriteToStream(AStream: TStream; AData: TsWorkbook); virtual; procedure WriteToStream(AStream: TStream; AData: TsWorkbook); virtual;
@ -1000,14 +1003,8 @@ end;
@see TsCustomSpreadWriter.WriteCellsToStream @see TsCustomSpreadWriter.WriteCellsToStream
} }
procedure TsCustomSpreadWriter.WriteCellCallback(data, arg: pointer); procedure TsCustomSpreadWriter.WriteCellCallback(ACell: PCell; AStream: TStream);
var
ACell: PCell;
AStream: TStream;
begin begin
ACell := PCell(data);
AStream := TStream(arg);
case ACell.ContentType of case ACell.ContentType of
cctNumber: WriteNumber(AStream, ACell^.Row, ACell^.Col, ACell^.NumberValue, ACell); cctNumber: WriteNumber(AStream, ACell^.Row, ACell^.Col, ACell^.NumberValue, ACell);
cctUTF8String: WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue, ACell); cctUTF8String: WriteLabel(AStream, ACell^.Row, ACell^.Col, ACell^.UTF8StringValue, ACell);
@ -1025,13 +1022,18 @@ end;
@param ACells List of cells to be writeen @param ACells List of cells to be writeen
} }
procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream; ACells: TAVLTree); procedure TsCustomSpreadWriter.WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
begin
IterateThroughCells(AStream, ACells, WriteCellCallback);
end;
procedure TsCustomSpreadWriter.IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
var var
AVLNode: TAVLTreeNode; AVLNode: TAVLTreeNode;
begin begin
AVLNode := ACells.FindLowest; AVLNode := ACells.FindLowest;
While Assigned(AVLNode) do While Assigned(AVLNode) do
begin begin
WriteCellCallback(AVLNode.Data, Pointer(AStream)); ACallback(PCell(AVLNode.Data), AStream);
AVLNode := ACells.FindSuccessor(AVLNode); AVLNode := ACells.FindSuccessor(AVLNode);
end; end;
end; end;

View File

@ -58,6 +58,7 @@ type
TsSpreadBIFF2Writer = class(TsCustomSpreadWriter) TsSpreadBIFF2Writer = class(TsCustomSpreadWriter)
private private
function FEKindToExcelID(AElement: TFEKind; var AParamsNum, AFuncNum: Byte): Byte; function FEKindToExcelID(AElement: TFEKind; var AParamsNum, AFuncNum: Byte): Byte;
procedure WriteCellFormatting(AStream: TStream; ACell: PCell);
public public
{ General writing methods } { General writing methods }
procedure WriteToStream(AStream: TStream; AData: TsWorkbook); override; procedure WriteToStream(AStream: TStream; AData: TsWorkbook); override;
@ -120,6 +121,40 @@ begin
end; end;
end; end;
procedure TsSpreadBIFF2Writer.WriteCellFormatting(AStream: TStream; ACell: PCell);
var
BorderByte: Byte = 0;
begin
if ACell^.UsedFormattingFields = [] then
begin
AStream.WriteByte($0);
AStream.WriteByte($0);
AStream.WriteByte($0);
Exit;
end;
AStream.WriteByte($0);
AStream.WriteByte($0);
// The Border and Background
BorderByte := 0;
if uffBorder in ACell^.UsedFormattingFields then
begin
if cbNorth in ACell^.Border then BorderByte := BorderByte or $20;
if cbWest in ACell^.Border then BorderByte := BorderByte or $08;
if cbEast in ACell^.Border then BorderByte := BorderByte or $10;
if cbSouth in ACell^.Border then BorderByte := BorderByte or $40;
end;
// BIFF2 does not support a background color, just a "shaded" option
if uffBackgroundColor in ACell^.UsedFormattingFields then
BorderByte := BorderByte or $80;
AStream.WriteByte(BorderByte);
end;
{ {
Writes an Excel 2 file to a stream Writes an Excel 2 file to a stream
@ -298,9 +333,7 @@ begin
AStream.WriteWord(WordToLE(ACol)); AStream.WriteWord(WordToLE(ACol));
{ BIFF2 Attributes } { BIFF2 Attributes }
AStream.WriteByte($0); WriteCellFormatting(AStream, ACell);
AStream.WriteByte($0);
AStream.WriteByte($0);
{ String with 8-bit size } { String with 8-bit size }
AStream.WriteByte(L); AStream.WriteByte(L);

View File

@ -102,6 +102,12 @@ type
{ TsSpreadBIFF8Writer } { TsSpreadBIFF8Writer }
TsSpreadBIFF8Writer = class(TsCustomSpreadWriter) TsSpreadBIFF8Writer = class(TsCustomSpreadWriter)
private
FFormattingStyles: array of TCell; // An array with cells which are models for the used styles
procedure WriteXFIndex(AStream: TStream; ACell: PCell);
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
procedure ListAllFormattingStyles(AData: TsWorkbook);
procedure WriteXFFieldsForFormattingStyles();
public public
// constructor Create; // constructor Create;
// destructor Destroy; override; // destructor Destroy; override;
@ -243,6 +249,69 @@ const
{ TsSpreadBIFF8Writer } { TsSpreadBIFF8Writer }
{@@ Index to XF record, according to formatting }
procedure TsSpreadBIFF8Writer.WriteXFIndex(AStream: TStream; ACell: PCell);
begin
if ACell^.UsedFormattingFields = [uffTextRotation] then
begin
case ACell^.TextRotation of
rt90DegreeCounterClockwiseRotation: AStream.WriteWord(WordToLE(16));
rt90DegreeClockwiseRotation: AStream.WriteWord(WordToLE(17));
else
AStream.WriteWord(WordToLE(15));
end;
end
else if ACell^.UsedFormattingFields = [uffBold] then
begin
AStream.WriteWord(WordToLE(18));
end
else if ACell^.UsedFormattingFields = [uffBorder] then
begin
if ACell^.Border = [] then AStream.WriteWord(WordToLE(15))
else if ACell^.Border = [cbNorth] then AStream.WriteWord(WordToLE(19))
else if ACell^.Border = [cbWest] then AStream.WriteWord(WordToLE(20))
else if ACell^.Border = [cbEast] then AStream.WriteWord(WordToLE(21))
else if ACell^.Border = [cbSouth] then AStream.WriteWord(WordToLE(22))
else if ACell^.Border = [cbNorth, cbWest] then AStream.WriteWord(WordToLE(23))
else if ACell^.Border = [cbNorth, cbEast] then AStream.WriteWord(WordToLE(24))
else if ACell^.Border = [cbNorth, cbSouth] then AStream.WriteWord(WordToLE(25))
else if ACell^.Border = [cbWest, cbEast] then AStream.WriteWord(WordToLE(26))
else if ACell^.Border = [cbWest, cbSouth] then AStream.WriteWord(WordToLE(27))
else if ACell^.Border = [cbEast, cbSouth] then AStream.WriteWord(WordToLE(28))
else if ACell^.Border = [cbNorth, cbWest, cbEast] then AStream.WriteWord(WordToLE(29))
else if ACell^.Border = [cbNorth, cbWest, cbSouth] then AStream.WriteWord(WordToLE(30))
else if ACell^.Border = [cbNorth, cbEast, cbSouth] then AStream.WriteWord(WordToLE(31))
else if ACell^.Border = [cbWest, cbEast, cbSouth] then AStream.WriteWord(WordToLE(32))
else if ACell^.Border = [cbNorth, cbWest, cbEast, cbSouth] then AStream.WriteWord(WordToLE(33));
end
else
AStream.WriteWord(WordToLE(15));
end;
procedure TsSpreadBIFF8Writer.ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
begin
if ACell^.UsedFormattingFields = [] then Exit;
// Unfinished ...
end;
procedure TsSpreadBIFF8Writer.ListAllFormattingStyles(AData: TsWorkbook);
var
i: Integer;
begin
for i := 0 to AData.GetWorksheetCount - 1 do
begin
IterateThroughCells(nil, AData.GetWorksheetByIndex(i).Cells, ListAllFormattingStylesCallback);
end;
// Unfinished ...
end;
procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles();
begin
// Unfinished ...
end;
{******************************************************************* {*******************************************************************
* TsSpreadBIFF8Writer.WriteToFile () * TsSpreadBIFF8Writer.WriteToFile ()
* *
@ -391,6 +460,9 @@ begin
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbWest, cbEast, cbSouth]); WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbWest, cbEast, cbSouth]);
// XF33 - Border // XF33 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbWest, cbEast, cbSouth]); WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbWest, cbEast, cbSouth]);
// Add further all non-standard formatting styles
// ListAllFormattingStyles(AData);
// WriteXFFieldsForFormattingStyles();
WriteStyle(AStream); WriteStyle(AStream);
@ -770,40 +842,7 @@ begin
AStream.WriteWord(WordToLE(ACol)); AStream.WriteWord(WordToLE(ACol));
{ Index to XF record, according to formatting } { Index to XF record, according to formatting }
if ACell^.UsedFormattingFields = [uffTextRotation] then WriteXFIndex(AStream, ACell);
begin
case ACell^.TextRotation of
rt90DegreeCounterClockwiseRotation: AStream.WriteWord(WordToLE(16));
rt90DegreeClockwiseRotation: AStream.WriteWord(WordToLE(17));
else
AStream.WriteWord(WordToLE(15));
end;
end
else if ACell^.UsedFormattingFields = [uffBold] then
begin
AStream.WriteWord(WordToLE(18));
end
else if ACell^.UsedFormattingFields = [uffBorder] then
begin
if ACell^.Border = [] then AStream.WriteWord(WordToLE(15))
else if ACell^.Border = [cbNorth] then AStream.WriteWord(WordToLE(19))
else if ACell^.Border = [cbWest] then AStream.WriteWord(WordToLE(20))
else if ACell^.Border = [cbEast] then AStream.WriteWord(WordToLE(21))
else if ACell^.Border = [cbSouth] then AStream.WriteWord(WordToLE(22))
else if ACell^.Border = [cbNorth, cbWest] then AStream.WriteWord(WordToLE(23))
else if ACell^.Border = [cbNorth, cbEast] then AStream.WriteWord(WordToLE(24))
else if ACell^.Border = [cbNorth, cbSouth] then AStream.WriteWord(WordToLE(25))
else if ACell^.Border = [cbWest, cbEast] then AStream.WriteWord(WordToLE(26))
else if ACell^.Border = [cbWest, cbSouth] then AStream.WriteWord(WordToLE(27))
else if ACell^.Border = [cbEast, cbSouth] then AStream.WriteWord(WordToLE(28))
else if ACell^.Border = [cbNorth, cbWest, cbEast] then AStream.WriteWord(WordToLE(29))
else if ACell^.Border = [cbNorth, cbWest, cbSouth] then AStream.WriteWord(WordToLE(30))
else if ACell^.Border = [cbNorth, cbEast, cbSouth] then AStream.WriteWord(WordToLE(31))
else if ACell^.Border = [cbWest, cbEast, cbSouth] then AStream.WriteWord(WordToLE(32))
else if ACell^.Border = [cbNorth, cbWest, cbEast, cbSouth] then AStream.WriteWord(WordToLE(33));
end
else
AStream.WriteWord(WordToLE(15));
{ Byte String with 16-bit size } { Byte String with 16-bit size }
AStream.WriteWord(WordToLE(L)); AStream.WriteWord(WordToLE(L));