diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas
index 0e138b8da..dc630504f 100755
--- a/components/fpspreadsheet/fpspreadsheet.pas
+++ b/components/fpspreadsheet/fpspreadsheet.pas
@@ -94,7 +94,21 @@ type
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,
rt90DegreeCounterClockwiseRotation);
diff --git a/components/fpspreadsheet/laz_fpspreadsheet.lpk b/components/fpspreadsheet/laz_fpspreadsheet.lpk
index ee2de23b9..c301fcbdb 100644
--- a/components/fpspreadsheet/laz_fpspreadsheet.lpk
+++ b/components/fpspreadsheet/laz_fpspreadsheet.lpk
@@ -4,16 +4,21 @@
-
+
+
+
+
+
+
-
+
@@ -90,6 +95,10 @@
+
+
+
+
diff --git a/components/fpspreadsheet/laz_fpspreadsheet.pas b/components/fpspreadsheet/laz_fpspreadsheet.pas
index 7c8dcafbd..1d0f5c817 100644
--- a/components/fpspreadsheet/laz_fpspreadsheet.pas
+++ b/components/fpspreadsheet/laz_fpspreadsheet.pas
@@ -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.
}
@@ -11,7 +11,7 @@ uses
xlsbiff5, xlsbiff8, xlsxooxml, fpsutils, fpszipper, uvirtuallayer_types,
uvirtuallayer, uvirtuallayer_ole, uvirtuallayer_ole_helpers,
uvirtuallayer_ole_types, uvirtuallayer_stream, fpolebasic, xlscommon,
- fpsconvencoding, LazarusPackageIntf;
+ fpsconvencoding, xlsbiffcommon, LazarusPackageIntf;
implementation
diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas
index 99b0c7395..fe630c05c 100755
--- a/components/fpspreadsheet/xlsbiff8.pas
+++ b/components/fpspreadsheet/xlsbiff8.pas
@@ -53,7 +53,7 @@ interface
uses
Classes, SysUtils, fpcanvas,
- fpspreadsheet,
+ fpspreadsheet, xlsbiffcommon,
{$ifdef USE_NEW_OLE}
fpolebasic,
{$else}
@@ -65,7 +65,7 @@ type
{ TsSpreadBIFF8Reader }
- TsSpreadBIFF8Reader = class(TsCustomSpreadReader)
+ TsSpreadBIFF8Reader = class(TsSpreadBIFFReader)
private
RecordSize: Word;
PendingRecordSize: SizeInt;
@@ -101,13 +101,12 @@ type
{ TsSpreadBIFF8Writer }
- TsSpreadBIFF8Writer = class(TsCustomSpreadWriter)
+ TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter)
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();
+ procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
+ protected
+ procedure AddDefaultFormats(); override;
public
// constructor Create;
// destructor Destroy; override;
@@ -249,9 +248,19 @@ const
{ TsSpreadBIFF8Writer }
-{@@ Index to XF record, according to formatting }
+{ Index to XF record, according to formatting }
procedure TsSpreadBIFF8Writer.WriteXFIndex(AStream: TStream; ACell: PCell);
+var
+ lIndex: Integer;
+ lXFIndex: Word;
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
begin
case ACell^.TextRotation of
@@ -260,56 +269,93 @@ begin
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);
+ Exit;
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;
-procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles();
+procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
+var
+ i: Integer;
+ lFontIndex: Word;
+ lTextRotation: Byte;
+ lBorders: TsCellBorders;
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;
{*******************************************************************
@@ -430,39 +476,9 @@ begin
WriteXF(AStream, 0, 0, XF_ROTATION_90_DEGREE_CLOCKWISE, []);
// XF18 - Bold
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
-// ListAllFormattingStyles(AData);
-// WriteXFFieldsForFormattingStyles();
+ ListAllFormattingStyles(AData);
+ WriteXFFieldsForFormattingStyles(AStream);
WriteStyle(AStream);
diff --git a/components/fpspreadsheet/xlsbiffcommon.pas b/components/fpspreadsheet/xlsbiffcommon.pas
new file mode 100644
index 000000000..5143a94d8
--- /dev/null
+++ b/components/fpspreadsheet/xlsbiffcommon.pas
@@ -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.
+