FPSpreadsheet: Finishes implementing a generic font style manager for biff formats. Finishes integrating it with biff8

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1646 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
sekelsenmat
2011-05-26 09:25:56 +00:00
parent a4b7594f31
commit 4570c4785a
5 changed files with 235 additions and 90 deletions

View File

@ -94,7 +94,21 @@ type
TsUsedFormattingFields = set of TsUsedFormattingField; TsUsedFormattingFields = set of TsUsedFormattingField;
{@@ Text rotation formatting } {@@ Text rotation formatting. The text is rotated relative to the standard
orientation, which is from left to right horizontal: --->
ABC
So 90 degrees clockwise means that the text will be:
| A
| B
\|/ C
And 90 degree counter clockwise will be:
/|\ C
| B
| A
}
TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation, TsTextRotation = (trHorizontal, rt90DegreeClockwiseRotation,
rt90DegreeCounterClockwiseRotation); rt90DegreeCounterClockwiseRotation);

View File

@ -4,16 +4,21 @@
<PathDelim Value="\"/> <PathDelim Value="\"/>
<Name Value="laz_fpspreadsheet"/> <Name Value="laz_fpspreadsheet"/>
<CompilerOptions> <CompilerOptions>
<Version Value="8"/> <Version Value="10"/>
<PathDelim Value="\"/> <PathDelim Value="\"/>
<SearchPaths> <SearchPaths>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
<Parsing>
<SyntaxOptions>
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<Other> <Other>
<CompilerPath Value="$(CompPath)"/> <CompilerPath Value="$(CompPath)"/>
</Other> </Other>
</CompilerOptions> </CompilerOptions>
<Files Count="19"> <Files Count="20">
<Item1> <Item1>
<Filename Value="fpolestorage.pas"/> <Filename Value="fpolestorage.pas"/>
<UnitName Value="fpolestorage"/> <UnitName Value="fpolestorage"/>
@ -90,6 +95,10 @@
<Filename Value="fpsconvencoding.pas"/> <Filename Value="fpsconvencoding.pas"/>
<UnitName Value="fpsconvencoding"/> <UnitName Value="fpsconvencoding"/>
</Item19> </Item19>
<Item20>
<Filename Value="xlsbiffcommon.pas"/>
<UnitName Value="xlsbiffcommon"/>
</Item20>
</Files> </Files>
<Type Value="RunAndDesignTime"/> <Type Value="RunAndDesignTime"/>
<RequiredPkgs Count="1"> <RequiredPkgs Count="1">

View File

@ -1,4 +1,4 @@
{ This file was automatically created by Lazarus. do not edit! { This file was automatically created by Lazarus. Do not edit!
This source is only used to compile and install the package. This source is only used to compile and install the package.
} }
@ -11,7 +11,7 @@ uses
xlsbiff5, xlsbiff8, xlsxooxml, fpsutils, fpszipper, uvirtuallayer_types, xlsbiff5, xlsbiff8, xlsxooxml, fpsutils, fpszipper, uvirtuallayer_types,
uvirtuallayer, uvirtuallayer_ole, uvirtuallayer_ole_helpers, uvirtuallayer, uvirtuallayer_ole, uvirtuallayer_ole_helpers,
uvirtuallayer_ole_types, uvirtuallayer_stream, fpolebasic, xlscommon, uvirtuallayer_ole_types, uvirtuallayer_stream, fpolebasic, xlscommon,
fpsconvencoding, LazarusPackageIntf; fpsconvencoding, xlsbiffcommon, LazarusPackageIntf;
implementation implementation

View File

@ -53,7 +53,7 @@ interface
uses uses
Classes, SysUtils, fpcanvas, Classes, SysUtils, fpcanvas,
fpspreadsheet, fpspreadsheet, xlsbiffcommon,
{$ifdef USE_NEW_OLE} {$ifdef USE_NEW_OLE}
fpolebasic, fpolebasic,
{$else} {$else}
@ -65,7 +65,7 @@ type
{ TsSpreadBIFF8Reader } { TsSpreadBIFF8Reader }
TsSpreadBIFF8Reader = class(TsCustomSpreadReader) TsSpreadBIFF8Reader = class(TsSpreadBIFFReader)
private private
RecordSize: Word; RecordSize: Word;
PendingRecordSize: SizeInt; PendingRecordSize: SizeInt;
@ -101,13 +101,12 @@ type
{ TsSpreadBIFF8Writer } { TsSpreadBIFF8Writer }
TsSpreadBIFF8Writer = class(TsCustomSpreadWriter) TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter)
private private
FFormattingStyles: array of TCell; // An array with cells which are models for the used styles
procedure WriteXFIndex(AStream: TStream; ACell: PCell); procedure WriteXFIndex(AStream: TStream; ACell: PCell);
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream); procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
procedure ListAllFormattingStyles(AData: TsWorkbook); protected
procedure WriteXFFieldsForFormattingStyles(); procedure AddDefaultFormats(); override;
public public
// constructor Create; // constructor Create;
// destructor Destroy; override; // destructor Destroy; override;
@ -249,9 +248,19 @@ const
{ TsSpreadBIFF8Writer } { TsSpreadBIFF8Writer }
{@@ Index to XF record, according to formatting } { Index to XF record, according to formatting }
procedure TsSpreadBIFF8Writer.WriteXFIndex(AStream: TStream; ACell: PCell); procedure TsSpreadBIFF8Writer.WriteXFIndex(AStream: TStream; ACell: PCell);
var
lIndex: Integer;
lXFIndex: Word;
begin begin
// First try the fast methods for default formats
if ACell^.UsedFormattingFields = [] then
begin
AStream.WriteWord(WordToLE(15));
Exit;
end;
if ACell^.UsedFormattingFields = [uffTextRotation] then if ACell^.UsedFormattingFields = [uffTextRotation] then
begin begin
case ACell^.TextRotation of case ACell^.TextRotation of
@ -260,56 +269,93 @@ begin
else else
AStream.WriteWord(WordToLE(15)); AStream.WriteWord(WordToLE(15));
end; end;
end Exit;
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; end;
// Unfinished ... if ACell^.UsedFormattingFields = [uffBold] then
begin
AStream.WriteWord(WordToLE(18));
Exit;
end;
// If not, then we need to search in the list of dynamic formats
lIndex := FindFormattingInList(ACell);
// Carefully check the index
if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then
raise Exception.Create('[TsSpreadBIFF8Writer.WriteXFIndex] Invalid Index, this should not happen!');
lXFIndex := FFormattingStyles[lIndex].Row;
AStream.WriteWord(WordToLE(lXFIndex));
end; end;
procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(); procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var
i: Integer;
lFontIndex: Word;
lTextRotation: Byte;
lBorders: TsCellBorders;
begin begin
// Unfinished ... // The first 4 styles were already added
for i := 4 to Length(FFormattingStyles) - 1 do
begin
// Default styles
lFontIndex := 0;
lTextRotation := XF_ROTATION_HORIZONTAL;
lBorders := [];
// Now apply the modifications
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border;
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
begin
case FFormattingStyles[i].TextRotation of
trHorizontal: lTextRotation := XF_ROTATION_HORIZONTAL;
rt90DegreeClockwiseRotation: lTextRotation := XF_ROTATION_90_DEGREE_CLOCKWISE;
rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90_DEGREE_COUNTERCLOCKWISE;
end;
end;
if uffBold in FFormattingStyles[i].UsedFormattingFields then
lFontIndex := 1;
// if uffBackgroundColor in FFormattingStyles[i].UsedFormattingFields then
// lFontIndex := 1;
// And finally write the style
WriteXF(AStream, lFontIndex, 0, lTextRotation, lBorders);
end;
end;
{@@
These are default formats which are added as XF fields regardless of being used
in the document or not.
}
procedure TsSpreadBIFF8Writer.AddDefaultFormats();
begin
NextXFIndex := 19;
SetLength(FFormattingStyles, 4);
// XF15 - Default, no formatting
FFormattingStyles[0].UsedFormattingFields := [];
FFormattingStyles[0].Row := 15;
// XF16 - Rotated
FFormattingStyles[1].UsedFormattingFields := [uffTextRotation];
FFormattingStyles[1].Row := 16;
FFormattingStyles[1].TextRotation := rt90DegreeCounterClockwiseRotation;
// XF17 - Rotated
FFormattingStyles[2].UsedFormattingFields := [uffTextRotation];
FFormattingStyles[2].Row := 17;
FFormattingStyles[2].TextRotation := rt90DegreeClockwiseRotation;
// XF18 - Bold
FFormattingStyles[3].UsedFormattingFields := [uffBold];
FFormattingStyles[3].Row := 18;
end; end;
{******************************************************************* {*******************************************************************
@ -430,39 +476,9 @@ begin
WriteXF(AStream, 0, 0, XF_ROTATION_90_DEGREE_CLOCKWISE, []); WriteXF(AStream, 0, 0, XF_ROTATION_90_DEGREE_CLOCKWISE, []);
// XF18 - Bold // XF18 - Bold
WriteXF(AStream, 1, 0, XF_ROTATION_HORIZONTAL, []); WriteXF(AStream, 1, 0, XF_ROTATION_HORIZONTAL, []);
// XF19 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth]);
// XF20 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbWest]);
// XF21 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbEast]);
// XF22 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbSouth]);
// XF23 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbWest]);
// XF24 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbEast]);
// XF25 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbSouth]);
// XF26 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbWest, cbEast]);
// XF27 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbWest, cbSouth]);
// XF28 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbEast, cbSouth]);
// XF29 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbWest, cbEast]);
// XF30 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbWest, cbSouth]);
// XF31 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbEast, cbSouth]);
// XF32 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbWest, cbEast, cbSouth]);
// XF33 - Border
WriteXF(AStream, 0, 0, XF_ROTATION_HORIZONTAL, [cbNorth, cbWest, cbEast, cbSouth]);
// Add further all non-standard formatting styles // Add further all non-standard formatting styles
// ListAllFormattingStyles(AData); ListAllFormattingStyles(AData);
// WriteXFFieldsForFormattingStyles(); WriteXFFieldsForFormattingStyles(AStream);
WriteStyle(AStream); WriteStyle(AStream);

View File

@ -0,0 +1,106 @@
unit xlsbiffcommon;
{$ifdef fpc}
{$mode delphi}
{$endif}
interface
uses
Classes, SysUtils,
fpspreadsheet,
fpsutils;
type
{ TsSpreadBIFFReader }
TsSpreadBIFFReader = class(TsCustomSpreadReader)
protected
end;
{ TsSpreadBIFFWriter }
TsSpreadBIFFWriter = class(TsCustomSpreadWriter)
protected
{
An array with cells which are models for the used styles
In this array the Row property holds the Index to the corresponding XF field
}
FFormattingStyles: array of TCell;
NextXFIndex: Integer; // Indicates which should be the next XF Index when filling the styles list
function FindFormattingInList(AFormat: PCell): Integer;
procedure AddDefaultFormats(); virtual;
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
procedure ListAllFormattingStyles(AData: TsWorkbook);
end;
implementation
{
Checks if the style of a cell is in the list FFormattingStyles and returns the index
or -1 if it isn't
}
function TsSpreadBIFFWriter.FindFormattingInList(AFormat: PCell): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to Length(FFormattingStyles) - 1 do
begin
if (FFormattingStyles[i].UsedFormattingFields <> AFormat^.UsedFormattingFields) then Continue;
if uffTextRotation in AFormat^.UsedFormattingFields then
if (FFormattingStyles[i].TextRotation <> AFormat^.TextRotation) then Continue;
if uffBorder in AFormat^.UsedFormattingFields then
if (FFormattingStyles[i].Border <> AFormat^.Border) then Continue;
if uffBackgroundColor in AFormat^.UsedFormattingFields then
if (FFormattingStyles[i].BackgroundColor <> AFormat^.BackgroundColor) then Continue;
// If we arrived here it means that the styles match
Exit(i);
end;
end;
{ Each descendent should define it's own default formats, if any.
Always add the normal, unformatted style first to speed up. }
procedure TsSpreadBIFFWriter.AddDefaultFormats();
begin
SetLength(FFormattingStyles, 0);
NextXFIndex := 0;
end;
procedure TsSpreadBIFFWriter.ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
var
Len: Integer;
begin
if ACell^.UsedFormattingFields = [] then Exit;
if FindFormattingInList(ACell) <> -1 then Exit;
Len := Length(FFormattingStyles);
SetLength(FFormattingStyles, Len+1);
FFormattingStyles[Len] := ACell^;
FFormattingStyles[Len].Row := NextXFIndex;
Inc(NextXFIndex);
end;
procedure TsSpreadBIFFWriter.ListAllFormattingStyles(AData: TsWorkbook);
var
i: Integer;
begin
SetLength(FFormattingStyles, 0);
AddDefaultFormats();
for i := 0 to AData.GetWorksheetCount - 1 do
begin
IterateThroughCells(nil, AData.GetWorksheetByIndex(i).Cells, ListAllFormattingStylesCallback);
end;
end;
end.