You've already forked lazarus-ccr
fpspreadsheet: Make sure that biff writers do not write colors exceeding the maximum palette count. Add casse to error tests (passed, but the biff2 font color test fails now...)
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3470 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -28,6 +28,7 @@ type
|
|||||||
TsSpreadsheetFormatLimitations = record
|
TsSpreadsheetFormatLimitations = record
|
||||||
MaxRowCount: Cardinal;
|
MaxRowCount: Cardinal;
|
||||||
MaxColCount: Cardinal;
|
MaxColCount: Cardinal;
|
||||||
|
MaxPaletteSize: Cardinal;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
const
|
const
|
||||||
@ -859,7 +860,8 @@ type
|
|||||||
|
|
||||||
{ Color handling }
|
{ Color handling }
|
||||||
function AddColorToPalette(AColorValue: TsColorValue): TsColor;
|
function AddColorToPalette(AColorValue: TsColorValue): TsColor;
|
||||||
function FindClosestColor(AColorValue: TsColorValue): TsColor;
|
function FindClosestColor(AColorValue: TsColorValue;
|
||||||
|
AMaxPaletteCount: Integer): TsColor;
|
||||||
function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String;
|
function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String;
|
||||||
function GetColorName(AColorIndex: TsColor): string;
|
function GetColorName(AColorIndex: TsColor): string;
|
||||||
function GetPaletteColor(AColorIndex: TsColor): TsColorValue;
|
function GetPaletteColor(AColorIndex: TsColor): TsColorValue;
|
||||||
@ -869,6 +871,7 @@ type
|
|||||||
procedure UseDefaultPalette;
|
procedure UseDefaultPalette;
|
||||||
procedure UsePalette(APalette: PsPalette; APaletteCount: Word;
|
procedure UsePalette(APalette: PsPalette; APaletteCount: Word;
|
||||||
ABigEndian: Boolean = false);
|
ABigEndian: Boolean = false);
|
||||||
|
function UsesColor(AColorIndex: TsColor): Boolean;
|
||||||
|
|
||||||
{ Error messages }
|
{ Error messages }
|
||||||
procedure AddErrorMsg(const AMsg: String); overload;
|
procedure AddErrorMsg(const AMsg: String); overload;
|
||||||
@ -987,6 +990,8 @@ type
|
|||||||
FWorkbook: TsWorkbook;
|
FWorkbook: TsWorkbook;
|
||||||
{@@ Instance of the worksheet which is currently being read. }
|
{@@ Instance of the worksheet which is currently being read. }
|
||||||
FWorksheet: TsWorksheet;
|
FWorksheet: TsWorksheet;
|
||||||
|
{@@ Limitations for the specific data file format }
|
||||||
|
FLimitations: TsSpreadsheetFormatLimitations;
|
||||||
protected
|
protected
|
||||||
{@@ List of number formats found in the file }
|
{@@ List of number formats found in the file }
|
||||||
FNumFormatList: TsCustomNumFormatList;
|
FNumFormatList: TsCustomNumFormatList;
|
||||||
@ -994,6 +999,7 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); virtual; // to allow descendents to override it
|
constructor Create(AWorkbook: TsWorkbook); virtual; // to allow descendents to override it
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
function Limitations: TsSpreadsheetFormatLimitations;
|
||||||
{@@ Instance of the workbook which is currently being read/written. }
|
{@@ Instance of the workbook which is currently being read/written. }
|
||||||
property Workbook: TsWorkbook read FWorkbook;
|
property Workbook: TsWorkbook read FWorkbook;
|
||||||
{@@ List of number formats found in the workbook. }
|
{@@ List of number formats found in the workbook. }
|
||||||
@ -1048,13 +1054,13 @@ type
|
|||||||
for each individual file format. }
|
for each individual file format. }
|
||||||
TsCustomSpreadWriter = class(TsCustomSpreadReaderWriter)
|
TsCustomSpreadWriter = class(TsCustomSpreadReaderWriter)
|
||||||
protected
|
protected
|
||||||
{@@ Limitations for the specific data file format }
|
|
||||||
FLimitations: TsSpreadsheetFormatLimitations;
|
|
||||||
{ Helper routines }
|
{ Helper routines }
|
||||||
procedure AddDefaultFormats(); virtual;
|
procedure AddDefaultFormats(); virtual;
|
||||||
procedure CheckLimitations;
|
procedure CheckLimitations;
|
||||||
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
|
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
|
||||||
function FindFormattingInList(AFormat: PCell): Integer;
|
function FindFormattingInList(AFormat: PCell): Integer;
|
||||||
|
procedure FixCellColors(ACell: PCell);
|
||||||
|
function FixColor(AColor: TsColor): TsColor; virtual;
|
||||||
procedure FixFormat(ACell: PCell); virtual;
|
procedure FixFormat(ACell: PCell); virtual;
|
||||||
procedure GetSheetDimensions(AWorksheet: TsWorksheet;
|
procedure GetSheetDimensions(AWorksheet: TsWorksheet;
|
||||||
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual;
|
out AFirstRow, ALastRow, AFirstCol, ALastCol: Cardinal); virtual;
|
||||||
@ -1089,7 +1095,6 @@ type
|
|||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
function Limitations: TsSpreadsheetFormatLimitations;
|
|
||||||
{ General writing methods }
|
{ General writing methods }
|
||||||
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
|
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
|
||||||
procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual;
|
procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual;
|
||||||
@ -1169,8 +1174,13 @@ resourcestring
|
|||||||
lpUnsupportedWriteFormat = 'Tried to write a spreadsheet using an unsupported format';
|
lpUnsupportedWriteFormat = 'Tried to write a spreadsheet using an unsupported format';
|
||||||
lpNoValidSpreadsheetFile = '"%s" is not a valid spreadsheet file';
|
lpNoValidSpreadsheetFile = '"%s" is not a valid spreadsheet file';
|
||||||
lpUnknownSpreadsheetFormat = 'unknown format';
|
lpUnknownSpreadsheetFormat = 'unknown format';
|
||||||
lpMaxRowsExceeded = 'This workbook contains %d rows, but the selected file format does not support more than %d rows.';
|
lpMaxRowsExceeded = 'This workbook contains %d rows, but the selected ' +
|
||||||
lpMaxColsExceeded = 'This workbook contains %d columns, but the selected file format does not support more than %d columns.';
|
'file format does not support more than %d rows.';
|
||||||
|
lpMaxColsExceeded = 'This workbook contains %d columns, but the selected ' +
|
||||||
|
'file format does not support more than %d columns.';
|
||||||
|
lpTooManyPaletteColors = 'This workbook contains more colors (%d) than are ' +
|
||||||
|
'supported by the file format (%d). The redundant colors are replaced by '+
|
||||||
|
'the best-matching palette colors.';
|
||||||
lpInvalidFontIndex = 'Invalid font index';
|
lpInvalidFontIndex = 'Invalid font index';
|
||||||
lpInvalidNumberFormat = 'Trying to use an incompatible number format.';
|
lpInvalidNumberFormat = 'Trying to use an incompatible number format.';
|
||||||
lpInvalidDateTimeFormat = 'Trying to use an incompatible date/time format.';
|
lpInvalidDateTimeFormat = 'Trying to use an incompatible date/time format.';
|
||||||
@ -5315,7 +5325,7 @@ begin
|
|||||||
SameText(AFontName, fnt.FontName) and
|
SameText(AFontName, fnt.FontName) and
|
||||||
(abs(ASize - fnt.Size) < 0.001) and // careful when comparing floating point numbers
|
(abs(ASize - fnt.Size) < 0.001) and // careful when comparing floating point numbers
|
||||||
(AStyle = fnt.Style) and
|
(AStyle = fnt.Style) and
|
||||||
(AColor = fnt.Color)
|
(AColor = fnt.Color) // Take care of limited palette size!
|
||||||
then
|
then
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
@ -5496,27 +5506,33 @@ end;
|
|||||||
Finds the palette color index which points to a color that is closest to a
|
Finds the palette color index which points to a color that is closest to a
|
||||||
given color. "Close" means here smallest length of the rgb-difference vector.
|
given color. "Close" means here smallest length of the rgb-difference vector.
|
||||||
|
|
||||||
@param AColorValue Rgb color value to be considered
|
@param AColorValue Rgb color value to be considered
|
||||||
|
@param AMaxPaletteCount Number of palette entries considered. Example:
|
||||||
|
BIFF5/BIFF8 can write only 64 colors, i.e
|
||||||
|
AMaxPaletteCount = 64
|
||||||
@return Palette index of the color closest to AColorValue
|
@return Palette index of the color closest to AColorValue
|
||||||
}
|
}
|
||||||
function TsWorkbook.FindClosestColor(AColorValue: TsColorValue): TsColor;
|
function TsWorkbook.FindClosestColor(AColorValue: TsColorValue;
|
||||||
|
AMaxPaletteCount: Integer): TsColor;
|
||||||
type
|
type
|
||||||
TRGBA = record r,g,b, a: Byte end;
|
TRGBA = record r,g,b, a: Byte end;
|
||||||
var
|
var
|
||||||
rgb: TRGBA;
|
rgb: TRGBA;
|
||||||
rgb0: TRGBA absolute AColorValue;
|
rgb0: TRGBA absolute AColorValue;
|
||||||
dist: Double;
|
dist: Double;
|
||||||
mindist: Double;
|
minDist: Double;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
n: Integer;
|
||||||
begin
|
begin
|
||||||
Result := scNotDefined;
|
Result := scNotDefined;
|
||||||
mindist := 1E108;
|
minDist := 1E108;
|
||||||
for i:=0 to Length(FPalette)-1 do begin
|
n := Min(Length(FPalette), AMaxPaletteCount);
|
||||||
|
for i:=0 to n-1 do begin
|
||||||
rgb := TRGBA(GetPaletteColor(i));
|
rgb := TRGBA(GetPaletteColor(i));
|
||||||
dist := sqr(rgb.r - rgb0.r) + sqr(rgb.g - rgb0.g) + sqr(rgb.b - rgb0.b);
|
dist := sqr(rgb.r - rgb0.r) + sqr(rgb.g - rgb0.g) + sqr(rgb.b - rgb0.b);
|
||||||
if dist < mindist then begin
|
if dist < minDist then begin
|
||||||
Result := i;
|
Result := i;
|
||||||
mindist := dist;
|
minDist := dist;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -5685,6 +5701,45 @@ begin
|
|||||||
{$ENDIF}
|
{$ENDIF}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Checks whether a given color is used somewhere within the entire workbook
|
||||||
|
|
||||||
|
@param AColorIndex Palette index of the color
|
||||||
|
@result True if the color is used by at least one cell, false if not.
|
||||||
|
}
|
||||||
|
function TsWorkbook.UsesColor(AColorIndex: TsColor): Boolean;
|
||||||
|
var
|
||||||
|
Node: TAVLTreeNode;
|
||||||
|
sheet: TsWorksheet;
|
||||||
|
cell: PCell;
|
||||||
|
i: Integer;
|
||||||
|
fnt: TsFont;
|
||||||
|
b: TsCellBorder;
|
||||||
|
begin
|
||||||
|
Result := true;
|
||||||
|
for i:=0 to GetWorksheetCount-1 do begin
|
||||||
|
sheet := GetWorksheetByIndex(i);
|
||||||
|
Node := sheet.Cells.FindLowest;
|
||||||
|
while Assigned(Node) do
|
||||||
|
begin
|
||||||
|
cell := PCell(Node.Data);
|
||||||
|
if (uffBackgroundColor in cell^.UsedFormattingFields) then
|
||||||
|
if cell^.BackgroundColor = AColorIndex then exit;
|
||||||
|
if (uffBorder in cell^.UsedFormattingFields) then
|
||||||
|
for b in TsCellBorders do
|
||||||
|
if cell^.BorderStyles[b].Color = AColorIndex then
|
||||||
|
exit;
|
||||||
|
if (uffFont in cell^.UsedFormattingFields) then
|
||||||
|
begin
|
||||||
|
fnt := GetFont(cell^.FontIndex);
|
||||||
|
if fnt.Color = AColorIndex then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
Node := sheet.Cells.FindSuccessor(Node);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := false;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TsCustomNumFormatList }
|
{ TsCustomNumFormatList }
|
||||||
|
|
||||||
@ -6073,6 +6128,11 @@ constructor TsCustomSpreadReaderWriter.Create(AWorkbook: TsWorkbook);
|
|||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FWorkbook := AWorkbook;
|
FWorkbook := AWorkbook;
|
||||||
|
{ A good starting point valid for many formats ... }
|
||||||
|
FLimitations.MaxColCount := 256;
|
||||||
|
FLimitations.MaxRowCount := 65536;
|
||||||
|
FLimitations.MaxPaletteSize := $FFFFFFFF;
|
||||||
|
// Number formats
|
||||||
CreateNumFormatList;
|
CreateNumFormatList;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -6097,6 +6157,14 @@ begin
|
|||||||
// nothing to do here
|
// nothing to do here
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Returns a record containing limitations of the specific file format of the
|
||||||
|
writer.
|
||||||
|
}
|
||||||
|
function TsCustomSpreadReaderWriter.Limitations: TsSpreadsheetFormatLimitations;
|
||||||
|
begin
|
||||||
|
Result := FLimitations;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TsCustomSpreadReader }
|
{ TsCustomSpreadReader }
|
||||||
|
|
||||||
@ -6209,9 +6277,6 @@ end;
|
|||||||
constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
|
constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
|
||||||
begin
|
begin
|
||||||
inherited Create(AWorkbook);
|
inherited Create(AWorkbook);
|
||||||
{ A good starting point valid for many formats... }
|
|
||||||
FLimitations.MaxColCount := 256;
|
|
||||||
FLimitations.MaxRowCount := 65536;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
@ -6226,6 +6291,7 @@ var
|
|||||||
i, n: Integer;
|
i, n: Integer;
|
||||||
b: TsCellBorder;
|
b: TsCellBorder;
|
||||||
equ: Boolean;
|
equ: Boolean;
|
||||||
|
clr: TsColor;
|
||||||
begin
|
begin
|
||||||
Result := -1;
|
Result := -1;
|
||||||
|
|
||||||
@ -6251,7 +6317,7 @@ begin
|
|||||||
equ := false;
|
equ := false;
|
||||||
Break;
|
Break;
|
||||||
end;
|
end;
|
||||||
if FFormattingStyles[i].BorderStyles[b].Color <> AFormat^.BorderStyles[b].Color
|
if FFormattingStyles[i].BorderStyles[b].Color <> FixColor(AFormat^.BorderStyles[b].Color)
|
||||||
then begin
|
then begin
|
||||||
equ := false;
|
equ := false;
|
||||||
Break;
|
Break;
|
||||||
@ -6261,7 +6327,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
if uffBackgroundColor in AFormat^.UsedFormattingFields then
|
if uffBackgroundColor in AFormat^.UsedFormattingFields then
|
||||||
if (FFormattingStyles[i].BackgroundColor <> AFormat^.BackgroundColor) then Continue;
|
if (FFormattingStyles[i].BackgroundColor <> FixColor(AFormat^.BackgroundColor)) then Continue;
|
||||||
|
|
||||||
if uffNumberFormat in AFormat^.UsedFormattingFields then begin
|
if uffNumberFormat in AFormat^.UsedFormattingFields then begin
|
||||||
if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue;
|
if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue;
|
||||||
@ -6276,6 +6342,41 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Makes sure that all colors used in a given cell belong to the workbook's
|
||||||
|
color palette.
|
||||||
|
}
|
||||||
|
procedure TsCustomSpreadWriter.FixCellColors(ACell: PCell);
|
||||||
|
var
|
||||||
|
b: TsCellBorder;
|
||||||
|
begin
|
||||||
|
if ACell = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
ACell^.BackgroundColor := FixColor(ACell^.BackgroundColor);
|
||||||
|
|
||||||
|
for b in TsCellBorders do
|
||||||
|
ACell^.BorderStyles[b].Color := FixColor(ACell^.BorderStyles[b].Color);
|
||||||
|
|
||||||
|
// Font color is not corrected here because this would affect other writers.
|
||||||
|
// Font color is handled immediately before writing.
|
||||||
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
If a color index is greater then the maximum palette color count this
|
||||||
|
color is replaced by the closest palette color.
|
||||||
|
|
||||||
|
The present implementation does not change the color. Must be overridden by
|
||||||
|
writers of formats with limited palette sizes.
|
||||||
|
|
||||||
|
@param AColor Color palette index to be checked
|
||||||
|
@return Closest color to AColor. If AColor belongs to the palette it must
|
||||||
|
be returned unchanged. }
|
||||||
|
function TsCustomSpreadWriter.FixColor(AColor: TsColor): TsColor;
|
||||||
|
begin
|
||||||
|
Result := AColor;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
If formatting features of a cell are not supported by the destination file
|
If formatting features of a cell are not supported by the destination file
|
||||||
format of the writer, here is the place to apply replacements.
|
format of the writer, here is the place to apply replacements.
|
||||||
@ -6291,15 +6392,6 @@ begin
|
|||||||
// to be overridden
|
// to be overridden
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{@@
|
|
||||||
Returns a record containing limitations of the specific file format of the
|
|
||||||
writer.
|
|
||||||
}
|
|
||||||
function TsCustomSpreadWriter.Limitations: TsSpreadsheetFormatLimitations;
|
|
||||||
begin
|
|
||||||
Result := FLimitations;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Determines the size of the worksheet to be written. VirtualMode is respected.
|
Determines the size of the worksheet to be written. VirtualMode is respected.
|
||||||
Is called when the writer needs the size for output. Column and row count
|
Is called when the writer needs the size for output. Column and row count
|
||||||
@ -6354,14 +6446,29 @@ end;
|
|||||||
procedure TsCustomSpreadWriter.CheckLimitations;
|
procedure TsCustomSpreadWriter.CheckLimitations;
|
||||||
var
|
var
|
||||||
lastCol, lastRow: Cardinal;
|
lastCol, lastRow: Cardinal;
|
||||||
|
i, n: Integer;
|
||||||
|
fnt: TsFont;
|
||||||
begin
|
begin
|
||||||
Workbook.GetLastRowColIndex(lastRow, lastCol);
|
Workbook.GetLastRowColIndex(lastRow, lastCol);
|
||||||
|
|
||||||
|
// Check row count
|
||||||
if lastRow >= FLimitations.MaxRowCount then
|
if lastRow >= FLimitations.MaxRowCount then
|
||||||
Workbook.AddErrorMsg(lpMaxRowsExceeded, [lastRow+1, FLimitations.MaxRowCount]);
|
Workbook.AddErrorMsg(lpMaxRowsExceeded, [lastRow+1, FLimitations.MaxRowCount]);
|
||||||
|
|
||||||
|
// Check column count
|
||||||
if lastCol >= FLimitations.MaxColCount then
|
if lastCol >= FLimitations.MaxColCount then
|
||||||
Workbook.AddErrorMsg(lpMaxColsExceeded, [lastCol+1, FLimitations.MaxColCount]);
|
Workbook.AddErrorMsg(lpMaxColsExceeded, [lastCol+1, FLimitations.MaxColCount]);
|
||||||
end;
|
|
||||||
|
|
||||||
|
// Check color count.
|
||||||
|
n := Workbook.GetPaletteSize;
|
||||||
|
if n > FLimitations.MaxPaletteSize then
|
||||||
|
for i:= FLimitations.MaxPaletteSize to n-1 do
|
||||||
|
if Workbook.UsesColor(i) then
|
||||||
|
begin
|
||||||
|
Workbook.AddErrorMsg(lpTooManyPaletteColors, [n, FLimitations.MaxPaletteSize]);
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Callback function for collecting all formatting styles found in the worksheet.
|
Callback function for collecting all formatting styles found in the worksheet.
|
||||||
@ -6385,6 +6492,10 @@ begin
|
|||||||
SetLength(FFormattingStyles, Len+1);
|
SetLength(FFormattingStyles, Len+1);
|
||||||
FFormattingStyles[Len] := ACell^;
|
FFormattingStyles[Len] := ACell^;
|
||||||
|
|
||||||
|
// Make sure that all colors of the formatting style cell are used in the workbook's
|
||||||
|
// palette.
|
||||||
|
FixCellColors(@FFormattingStyles[Len]);
|
||||||
|
|
||||||
// We store the index of the XF record that will be assigned to this style in
|
// We store the index of the XF record that will be assigned to this style in
|
||||||
// the "row" of the style. Will be needed when writing the XF record.
|
// the "row" of the style. Will be needed when writing the XF record.
|
||||||
FFormattingStyles[Len].Row := NextXFIndex;
|
FFormattingStyles[Len].Row := NextXFIndex;
|
||||||
|
@ -35,7 +35,7 @@ type
|
|||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
StrUtils;
|
StrUtils, xlsbiff5;
|
||||||
|
|
||||||
const
|
const
|
||||||
ERROR_SHEET = 'ErrorTest'; //worksheet name
|
ERROR_SHEET = 'ErrorTest'; //worksheet name
|
||||||
@ -65,6 +65,7 @@ var
|
|||||||
s: String;
|
s: String;
|
||||||
TempFile: String;
|
TempFile: String;
|
||||||
ErrList: TStringList;
|
ErrList: TStringList;
|
||||||
|
newColor: TsColor;
|
||||||
begin
|
begin
|
||||||
formula.FormulaStr := '=A1';
|
formula.FormulaStr := '=A1';
|
||||||
formula.DoubleValue := 0.0;
|
formula.DoubleValue := 0.0;
|
||||||
@ -77,7 +78,7 @@ begin
|
|||||||
MyWorkSheet:= MyWorkBook.AddWorksheet(ERROR_SHEET);
|
MyWorkSheet:= MyWorkBook.AddWorksheet(ERROR_SHEET);
|
||||||
row1 := MAX_ROW_COUNT[TTestFormat(AFormat)] - 5;
|
row1 := MAX_ROW_COUNT[TTestFormat(AFormat)] - 5;
|
||||||
row2 := MAX_ROW_COUNT[TTestFormat(AFormat)] + 5;
|
row2 := MAX_ROW_COUNT[TTestFormat(AFormat)] + 5;
|
||||||
for row :=row1 to row2 do begin
|
for row := row1 to row2 do begin
|
||||||
MyWorksheet.WriteBlank(row, 0);
|
MyWorksheet.WriteBlank(row, 0);
|
||||||
MyWorksheet.WriteNumber(row, 1, 1.0);
|
MyWorksheet.WriteNumber(row, 1, 1.0);
|
||||||
MyWorksheet.WriteUTF8Text(row, 2, 'A');
|
MyWorksheet.WriteUTF8Text(row, 2, 'A');
|
||||||
@ -117,7 +118,31 @@ begin
|
|||||||
DeleteFile(TempFile);
|
DeleteFile(TempFile);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Test 3: Too long cell label
|
// Test 3: Too many colors
|
||||||
|
if (TTestFormat(AFormat) in [sfExcel2, sfExcel5, sfExcel8]) then begin
|
||||||
|
MyWorkbook := TsWorkbook.Create;
|
||||||
|
try
|
||||||
|
// Prepare a full palette
|
||||||
|
MyWorkbook.UsePalette(@PALETTE_BIFF5[0], Length(PALETTE_BIFF5));
|
||||||
|
// Add 1 more color - this is one too many for BIFF5 and 8, and a lot
|
||||||
|
// too many for BIFF2 !
|
||||||
|
newColor := MyWorkbook.AddColorToPalette($FF7878);
|
||||||
|
|
||||||
|
MyWorkSheet:= MyWorkBook.AddWorksheet(ERROR_SHEET);
|
||||||
|
MyWorksheet.WriteUTF8Text(0, 0, s);
|
||||||
|
MyWorksheet.WriteFontColor(0, 0, newColor);
|
||||||
|
|
||||||
|
TempFile:=NewTempFile;
|
||||||
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
|
ErrList.Text := MyWorkbook.ErrorMsg;
|
||||||
|
CheckEquals(1, ErrList.Count, 'Error count mismatch in test 3');
|
||||||
|
finally
|
||||||
|
MyWorkbook.Free;
|
||||||
|
DeleteFile(TempFile);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Test 4: Too long cell label
|
||||||
if MAX_CELL_LEN[TTestFormat(AFormat)] <> Cardinal(-1) then begin
|
if MAX_CELL_LEN[TTestFormat(AFormat)] <> Cardinal(-1) then begin
|
||||||
s := DupeString('A', MAX_CELL_LEN[TTestFormat(AFormat)] + 10);
|
s := DupeString('A', MAX_CELL_LEN[TTestFormat(AFormat)] + 10);
|
||||||
MyWorkbook := TsWorkbook.Create;
|
MyWorkbook := TsWorkbook.Create;
|
||||||
@ -127,7 +152,7 @@ begin
|
|||||||
TempFile:=NewTempFile;
|
TempFile:=NewTempFile;
|
||||||
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
ErrList.Text := MyWorkbook.ErrorMsg;
|
ErrList.Text := MyWorkbook.ErrorMsg;
|
||||||
CheckEquals(1, ErrList.Count, 'Error count mismatch in test 3');
|
CheckEquals(1, ErrList.Count, 'Error count mismatch in test 4');
|
||||||
finally
|
finally
|
||||||
MyWorkbook.Free;
|
MyWorkbook.Free;
|
||||||
DeleteFile(TempFile);
|
DeleteFile(TempFile);
|
||||||
|
@ -82,6 +82,7 @@
|
|||||||
<Unit8>
|
<Unit8>
|
||||||
<Filename Value="colortests.pas"/>
|
<Filename Value="colortests.pas"/>
|
||||||
<IsPartOfProject Value="True"/>
|
<IsPartOfProject Value="True"/>
|
||||||
|
<UnitName Value="colortests"/>
|
||||||
</Unit8>
|
</Unit8>
|
||||||
<Unit9>
|
<Unit9>
|
||||||
<Filename Value="fonttests.pas"/>
|
<Filename Value="fonttests.pas"/>
|
||||||
|
@ -77,6 +77,7 @@ type
|
|||||||
procedure ReadWindow2(AStream: TStream); override;
|
procedure ReadWindow2(AStream: TStream); override;
|
||||||
procedure ReadXF(AStream: TStream);
|
procedure ReadXF(AStream: TStream);
|
||||||
public
|
public
|
||||||
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
{ General reading methods }
|
{ General reading methods }
|
||||||
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); override;
|
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); override;
|
||||||
end;
|
end;
|
||||||
@ -124,6 +125,7 @@ type
|
|||||||
procedure WriteWindow1(AStream: TStream); override;
|
procedure WriteWindow1(AStream: TStream); override;
|
||||||
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
|
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
|
||||||
public
|
public
|
||||||
|
constructor Create(AWorkbook: TsWorkbook); override;
|
||||||
{ General writing methods }
|
{ General writing methods }
|
||||||
procedure WriteToStream(AStream: TStream); override;
|
procedure WriteToStream(AStream: TStream); override;
|
||||||
end;
|
end;
|
||||||
@ -320,6 +322,12 @@ end;
|
|||||||
|
|
||||||
{ TsSpreadBIFF2Reader }
|
{ TsSpreadBIFF2Reader }
|
||||||
|
|
||||||
|
constructor TsSpreadBIFF2Reader.Create(AWorkbook: TsWorkbook);
|
||||||
|
begin
|
||||||
|
inherited Create(AWorkbook);
|
||||||
|
FLimitations.MaxPaletteSize := 16;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBIFF2Reader.ApplyCellFormatting(ACell: PCell; XFIndex: Word);
|
procedure TsSpreadBIFF2Reader.ApplyCellFormatting(ACell: PCell; XFIndex: Word);
|
||||||
var
|
var
|
||||||
xfData: TXFListData;
|
xfData: TXFListData;
|
||||||
@ -925,6 +933,12 @@ end;
|
|||||||
|
|
||||||
{ TsSpreadBIFF2Writer }
|
{ TsSpreadBIFF2Writer }
|
||||||
|
|
||||||
|
constructor TsSpreadBIFF2Writer.Create(AWorkbook: TsWorkbook);
|
||||||
|
begin
|
||||||
|
inherited Create(AWorkbook);
|
||||||
|
FLimitations.MaxPaletteSize := 16;
|
||||||
|
end;
|
||||||
|
|
||||||
{ Creates the correct version of the number format list.
|
{ Creates the correct version of the number format list.
|
||||||
It is for BIFF2 and BIFF3 file formats. }
|
It is for BIFF2 and BIFF3 file formats. }
|
||||||
procedure TsSpreadBIFF2Writer.CreateNumFormatList;
|
procedure TsSpreadBIFF2Writer.CreateNumFormatList;
|
||||||
@ -1443,7 +1457,7 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(2));
|
AStream.WriteWord(WordToLE(2));
|
||||||
|
|
||||||
{ Font color index, only first 8 palette entries allowed! }
|
{ Font color index, only first 8 palette entries allowed! }
|
||||||
AStream.WriteWord(WordToLE(word(font.Color)));
|
AStream.WriteWord(WordToLE(word(FixColor(font.Color))));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadBiff2Writer.WriteFonts(AStream: TStream);
|
procedure TsSpreadBiff2Writer.WriteFonts(AStream: TStream);
|
||||||
|
@ -134,7 +134,6 @@ type
|
|||||||
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
|
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
|
||||||
procedure WriteXFRecords(AStream: TStream);
|
procedure WriteXFRecords(AStream: TStream);
|
||||||
public
|
public
|
||||||
constructor Create(AWorkbook: TsWorkbook); override;
|
|
||||||
{ General writing methods }
|
{ General writing methods }
|
||||||
procedure WriteToFile(const AFileName: string;
|
procedure WriteToFile(const AFileName: string;
|
||||||
const AOverwriteExisting: Boolean = False); override;
|
const AOverwriteExisting: Boolean = False); override;
|
||||||
@ -329,11 +328,6 @@ type
|
|||||||
|
|
||||||
{ TsSpreadBIFF5Writer }
|
{ TsSpreadBIFF5Writer }
|
||||||
|
|
||||||
constructor TsSpreadBIFF5Writer.Create(AWorkbook: TsWorkbook);
|
|
||||||
begin
|
|
||||||
inherited Create(AWorkbook);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{*******************************************************************
|
{*******************************************************************
|
||||||
* TsSpreadBIFF5Writer.WriteToFile ()
|
* TsSpreadBIFF5Writer.WriteToFile ()
|
||||||
*
|
*
|
||||||
@ -634,7 +628,7 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(optn));
|
AStream.WriteWord(WordToLE(optn));
|
||||||
|
|
||||||
{ Colour index }
|
{ Colour index }
|
||||||
AStream.WriteWord(WordToLE(ord(AFont.Color)));
|
AStream.WriteWord(WordToLE(ord(FixColor(AFont.Color))));
|
||||||
|
|
||||||
{ Font weight }
|
{ Font weight }
|
||||||
if fssBold in AFont.Style then
|
if fssBold in AFont.Style then
|
||||||
|
@ -665,7 +665,7 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(optn));
|
AStream.WriteWord(WordToLE(optn));
|
||||||
|
|
||||||
{ Colour index }
|
{ Colour index }
|
||||||
AStream.WriteWord(WordToLE(ord(AFont.Color)));
|
AStream.WriteWord(WordToLE(ord(FixColor(AFont.Color))));
|
||||||
|
|
||||||
{ Font weight }
|
{ Font weight }
|
||||||
if fssBold in AFont.Style then
|
if fssBold in AFont.Style then
|
||||||
|
@ -457,6 +457,7 @@ type
|
|||||||
procedure AddDefaultFormats; override;
|
procedure AddDefaultFormats; override;
|
||||||
procedure CreateNumFormatList; override;
|
procedure CreateNumFormatList; override;
|
||||||
function FindXFIndex(ACell: PCell): Integer;
|
function FindXFIndex(ACell: PCell): Integer;
|
||||||
|
function FixColor(AColor: TsColor): TsColor; override;
|
||||||
procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
|
procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
|
||||||
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
|
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
|
||||||
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
|
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
|
||||||
@ -685,11 +686,6 @@ const
|
|||||||
INT_EXCEL_TOKEN_TATTR {fekOpSum}
|
INT_EXCEL_TOKEN_TATTR {fekOpSum}
|
||||||
);
|
);
|
||||||
|
|
||||||
resourcestring
|
|
||||||
rsTooManyPaletteColors = 'This workbook contains more colors (%d) than are ' +
|
|
||||||
'supported by the file format (%d). The redundant colors are replaced by '+
|
|
||||||
'the best-matching palette colors.';
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TBIFF58BlankRecord = packed record
|
TBIFF58BlankRecord = packed record
|
||||||
RecordID: Word;
|
RecordID: Word;
|
||||||
@ -841,6 +837,10 @@ begin
|
|||||||
FXFList := TFPList.Create;
|
FXFList := TFPList.Create;
|
||||||
// Initial base date in case it won't be read from file
|
// Initial base date in case it won't be read from file
|
||||||
FDateMode := dm1900;
|
FDateMode := dm1900;
|
||||||
|
// Limitations of BIFF5 and BIFF8 file format
|
||||||
|
FLimitations.MaxColCount := 256;
|
||||||
|
FLimitations.MaxRowCount := 65536;
|
||||||
|
FLimitations.MaxPaletteSize := 64;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TsSpreadBIFFReader.Destroy;
|
destructor TsSpreadBIFFReader.Destroy;
|
||||||
@ -1126,7 +1126,7 @@ begin
|
|||||||
//BIFF2 BIFF3 BIFF4 BIFF5 BIFF8
|
//BIFF2 BIFF3 BIFF4 BIFF5 BIFF8
|
||||||
//0022H 0022H 0022H 0022H 0022H
|
//0022H 0022H 0022H 0022H 0022H
|
||||||
//This record specifies the base date for displaying date values. All dates are stored as count of days past this base date. In
|
//This record specifies the base date for displaying date values. All dates are stored as count of days past this base date. In
|
||||||
//BIFF2-BIFF4 this record is part of the Calculation Settings Block (➜4.3). In BIFF5-BIFF8 it is stored in the Workbook
|
//BIFF2-BIFF4 this record is part of the Calculation Settings Block (➜4.3). In BIFF5-BIFF8 it is stored in the Workbookk
|
||||||
//Globals Substream.
|
//Globals Substream.
|
||||||
//Record DATEMODE, BIFF2-BIFF8:
|
//Record DATEMODE, BIFF2-BIFF8:
|
||||||
//Offset Size Contents
|
//Offset Size Contents
|
||||||
@ -1739,9 +1739,15 @@ end;
|
|||||||
constructor TsSpreadBIFFWriter.Create(AWorkbook: TsWorkbook);
|
constructor TsSpreadBIFFWriter.Create(AWorkbook: TsWorkbook);
|
||||||
begin
|
begin
|
||||||
inherited Create(AWorkbook);
|
inherited Create(AWorkbook);
|
||||||
|
|
||||||
// Initial base date in case it won't be set otherwise.
|
// Initial base date in case it won't be set otherwise.
|
||||||
// Use 1900 to get a bit more range between 1900..1904.
|
// Use 1900 to get a bit more range between 1900..1904.
|
||||||
FDateMode := dm1900;
|
FDateMode := dm1900;
|
||||||
|
|
||||||
|
// Limitations of BIFF5 and BIFF8 file formats
|
||||||
|
FLimitations.MaxColCount := 256;
|
||||||
|
FLimitations.MaxRowCount := 65536;
|
||||||
|
FLimitations.MaxPaletteSize := 64;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TsSpreadBIFFWriter.Destroy;
|
destructor TsSpreadBIFFWriter.Destroy;
|
||||||
@ -1804,6 +1810,18 @@ begin
|
|||||||
Result := FFormattingStyles[idx].Row;
|
Result := FFormattingStyles[idx].Row;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsSpreadBIFFWriter.FixColor(AColor: TsColor): TsColor;
|
||||||
|
var
|
||||||
|
rgb: TsColorValue;
|
||||||
|
begin
|
||||||
|
if AColor >= Limitations.MaxPaletteSize then begin
|
||||||
|
// if AColor >= 64 then begin
|
||||||
|
rgb := Workbook.GetPaletteColor(AColor);
|
||||||
|
Result := Workbook.FindClosestColor(rgb, FLimitations.MaxPaletteSize);
|
||||||
|
end else
|
||||||
|
Result := AColor;
|
||||||
|
end;
|
||||||
|
|
||||||
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
|
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
|
||||||
AElementKind: TFEKind; out ASecondaryID: Word): Word;
|
AElementKind: TFEKind; out ASecondaryID: Word): Word;
|
||||||
begin
|
begin
|
||||||
@ -2095,9 +2113,6 @@ begin
|
|||||||
{ Take the colors from the palette of the Worksheet }
|
{ Take the colors from the palette of the Worksheet }
|
||||||
n := Workbook.GetPaletteSize;
|
n := Workbook.GetPaletteSize;
|
||||||
|
|
||||||
if n > 64 then
|
|
||||||
Workbook.AddErrorMsg(rsTooManyPaletteColors, [n, 64]);
|
|
||||||
|
|
||||||
{ Skip the first 8 entries - they are hard-coded into Excel }
|
{ Skip the first 8 entries - they are hard-coded into Excel }
|
||||||
for i:=8 to 63 do
|
for i:=8 to 63 do
|
||||||
begin
|
begin
|
||||||
|
Reference in New Issue
Block a user