You've already forked lazarus-ccr
fpspreadsheet: Add support for reading/writing of column widths in biff8 (specified as multiples of the width of the character "0"). Add test case. No regressions
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2945 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<CONFIG>
|
||||
<ProjectOptions>
|
||||
<Version Value="9"/>
|
||||
@ -43,7 +43,7 @@
|
||||
</Units>
|
||||
</ProjectOptions>
|
||||
<CompilerOptions>
|
||||
<Version Value="10"/>
|
||||
<Version Value="11"/>
|
||||
<PathDelim Value="\"/>
|
||||
<SearchPaths>
|
||||
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||
|
@ -141,13 +141,13 @@ begin
|
||||
MyWorksheet.WriteDateTime(37, 1, number, nfTimeInterval);
|
||||
|
||||
// Set width of columns 1 and 5
|
||||
lCol.Width := 100; //mm
|
||||
lCol.Width := 30;
|
||||
MyWorksheet.WriteColInfo(1, lCol);
|
||||
lCol.Width := 50;
|
||||
lCol.Width := 5;
|
||||
MyWorksheet.WriteColInfo(5, lCol);
|
||||
|
||||
// Set height of rows 5 and 6
|
||||
lRow.Height := 10; // mm
|
||||
lRow.Height := 10;
|
||||
MyWorksheet.WriteRowInfo(5, lRow);
|
||||
lRow.Height := 5;
|
||||
MyWorksheet.WriteRowInfo(6, lRow);
|
||||
|
Binary file not shown.
@ -247,7 +247,7 @@ type
|
||||
|
||||
TCol = record
|
||||
Col: Byte;
|
||||
Width: Single; // in milimeters
|
||||
Width: Single; // in "characters". Excel uses the with of char "0" in 1st font
|
||||
end;
|
||||
|
||||
PCol = ^TCol;
|
||||
@ -309,6 +309,7 @@ type
|
||||
procedure WriteColInfo(ACol: Cardinal; AData: TCol);
|
||||
{ Properties }
|
||||
property Cells: TAVLTree read FCells;
|
||||
property Cols: TIndexedAVLTree read FCols;
|
||||
end;
|
||||
|
||||
{ TsWorkbook }
|
||||
@ -1325,6 +1326,7 @@ begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
|
||||
{@@
|
||||
Helper method for determining the spreadsheet type from the file type extension
|
||||
|
||||
|
@ -28,6 +28,8 @@ var
|
||||
SollDateTimeFormats: array[0..9] of TsNumberFormat;
|
||||
SollDateTimeFormatStrings: array[0..9] of String;
|
||||
|
||||
SollColWidths: array[0..1] of Single;
|
||||
|
||||
procedure InitSollFmtData;
|
||||
|
||||
type
|
||||
@ -45,6 +47,8 @@ type
|
||||
procedure TestWriteReadNumberFormats;
|
||||
// Repeat with date/times
|
||||
procedure TestWriteReadDateTimeFormats;
|
||||
// Test column width
|
||||
procedure TestWriteReadColWidths;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -125,6 +129,10 @@ begin
|
||||
SollDateTimeStrings[i, 8] := FormatDateTime('nn:ss', SollDateTimes[i]);
|
||||
SollDateTimeStrings[i, 9] := TimeIntervalToString(SollDateTimes[i]);
|
||||
end;
|
||||
|
||||
// Column width
|
||||
SollColWidths[0] := 20; // characters based on width of "0"
|
||||
SollColWidths[1] := 40;
|
||||
end;
|
||||
|
||||
{ TSpreadWriteReadFormatTests }
|
||||
@ -222,6 +230,51 @@ begin
|
||||
DeleteFile(TempFile);
|
||||
end;
|
||||
|
||||
procedure TSpreadWriteReadFormatTests.TestWriteReadColWidths;
|
||||
var
|
||||
MyWorksheet: TsWorksheet;
|
||||
MyWorkbook: TsWorkbook;
|
||||
ActualColWidth: Single;
|
||||
Col: Integer;
|
||||
lpCol: PCol;
|
||||
lCol: TCol;
|
||||
TempFile: string; //write xls/xml to this file and read back from it
|
||||
begin
|
||||
TempFile:=GetTempFileName;
|
||||
{// Not needed: use workbook.writetofile with overwrite=true
|
||||
if fileexists(TempFile) then
|
||||
DeleteFile(TempFile);
|
||||
}
|
||||
// Write out all test values
|
||||
MyWorkbook := TsWorkbook.Create;
|
||||
MyWorkSheet:= MyWorkBook.AddWorksheet(FmtNumbersSheet);
|
||||
for Col := Low(SollColWidths) to High(SollColWidths) do begin
|
||||
lCol.Width := SollColWidths[Col];
|
||||
MyWorksheet.WriteColInfo(Col, lCol);
|
||||
end;
|
||||
MyWorkBook.WriteToFile(TempFile,sfExcel8,true);
|
||||
MyWorkbook.Free;
|
||||
|
||||
// Open the spreadsheet, as biff8
|
||||
MyWorkbook := TsWorkbook.Create;
|
||||
MyWorkbook.ReadFromFile(TempFile, sfExcel8);
|
||||
MyWorksheet:=GetWorksheetByName(MyWorkBook, FmtNumbersSheet);
|
||||
if MyWorksheet=nil then
|
||||
fail('Error in test code. Failed to get named worksheet');
|
||||
for Col := Low(SollColWidths) to High(SollColWidths) do begin
|
||||
lpCol := MyWorksheet.GetCol(Col);
|
||||
if lpCol = nil then
|
||||
fail('Error in test code. Failed to return saved column width');
|
||||
ActualColWidth := lpCol^.Width;
|
||||
CheckEquals(SollColWidths[Col], ActualColWidth, 'Test saved colwidth mismatch column '+ColNotation(MyWorkSheet,Col));
|
||||
end;
|
||||
// Finalization
|
||||
MyWorkbook.Free;
|
||||
|
||||
DeleteFile(TempFile);
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
RegisterTest(TSpreadWriteReadFormatTests);
|
||||
InitSollFmtData;
|
||||
|
@ -142,7 +142,7 @@
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions Count="4">
|
||||
<Exceptions Count="5">
|
||||
<Item1>
|
||||
<Name Value="EAbort"/>
|
||||
<Enabled Value="False"/>
|
||||
@ -157,8 +157,10 @@
|
||||
</Item3>
|
||||
<Item4>
|
||||
<Name Value="EAssertionFailedError"/>
|
||||
<Enabled Value="False"/>
|
||||
</Item4>
|
||||
<Item5>
|
||||
<Name Value="EIgnoredTest"/>
|
||||
</Item5>
|
||||
</Exceptions>
|
||||
</Debugging>
|
||||
</CONFIG>
|
||||
|
@ -25,6 +25,9 @@ const
|
||||
// Returns an A.. notation based on sheet, row, optional column (e.g. A1).
|
||||
function CellNotation(WorkSheet: TsWorksheet; Row: integer; Column: integer=0): string;
|
||||
|
||||
// Returns an A notation of column based on sheed and column
|
||||
function ColNotation(WorkSheet: TsWorksheet; Column:Integer): String;
|
||||
|
||||
// Note: using this function instead of GetWorkSheetByName for compatibility with
|
||||
// older fpspreadsheet versions that don't have that function
|
||||
function GetWorksheetByName(AWorkBook: TsWorkBook; AName: String): TsWorksheet;
|
||||
@ -70,6 +73,25 @@ begin
|
||||
result:=WorkSheet.Name+'!'+inttostr(Column+1)+':'+inttostr(Row+1)
|
||||
end;
|
||||
|
||||
function ColNotation(WorkSheet: TsWorksheet; Column:Integer): String;
|
||||
begin
|
||||
if not Assigned(Worksheet) then
|
||||
Result := 'ColNotation: error getting worksheet.'
|
||||
else begin
|
||||
if Column < 26 then
|
||||
Result := Worksheet.Name + '!' + char(Column+65)
|
||||
else
|
||||
if Column < 26*26 then
|
||||
Result := Worksheet.Name + '!' + char(Column div 26 + 65) + char(Column mod 26 + 65)
|
||||
else
|
||||
if Column < 26*26*26 then
|
||||
Result := Worksheet.Name + '!' + char(Column div (26*26) + 65) +
|
||||
char(Column mod (26*26) div 26 + 65) +
|
||||
char(Column mod (26*26*26) + 65)
|
||||
else
|
||||
Result := 'ColNotation: At most three digits supported.';
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
|
@ -117,6 +117,8 @@ type
|
||||
// procedure ReadCodepage in xlscommon
|
||||
// procedure ReadDateMode in xlscommon
|
||||
procedure ReadFont(const AStream: TStream);
|
||||
// Read col info
|
||||
procedure ReadColInfo(const AStream: TStream);
|
||||
public
|
||||
constructor Create; override;
|
||||
destructor Destroy; override;
|
||||
@ -140,6 +142,7 @@ type
|
||||
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
|
||||
protected
|
||||
procedure AddDefaultFormats(); override;
|
||||
procedure WriteColInfo(AStream: TStream; ASheet: TsWorksheet; ACol: PCol);
|
||||
public
|
||||
// constructor Create;
|
||||
// destructor Destroy; override;
|
||||
@ -176,6 +179,7 @@ const
|
||||
{ Excel record IDs }
|
||||
INT_EXCEL_ID_BOF = $0809;
|
||||
INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs
|
||||
INT_EXCEL_ID_COLINFO = $007D;
|
||||
INT_EXCEL_ID_COUNTRY = $008C;
|
||||
INT_EXCEL_ID_EOF = $000A;
|
||||
INT_EXCEL_ID_DIMENSIONS = $0200;
|
||||
@ -554,7 +558,9 @@ var
|
||||
MyData: TMemoryStream;
|
||||
CurrentPos: Int64;
|
||||
Boundsheets: array of Int64;
|
||||
i, len: Integer;
|
||||
sheet: TsWorksheet;
|
||||
i, j, len: Integer;
|
||||
col: PCol;
|
||||
begin
|
||||
{ Write workbook globals }
|
||||
|
||||
@ -643,6 +649,8 @@ begin
|
||||
|
||||
for i := 0 to AData.GetWorksheetCount - 1 do
|
||||
begin
|
||||
sheet := AData.GetWorksheetByIndex(i);
|
||||
|
||||
{ First goes back and writes the position of the BOF of the
|
||||
sheet on the respective BOUNDSHEET record }
|
||||
CurrentPos := AStream.Position;
|
||||
@ -654,11 +662,16 @@ begin
|
||||
|
||||
WriteIndex(AStream);
|
||||
|
||||
WriteDimensions(AStream, AData.GetWorksheetByIndex(i));
|
||||
for j := 0 to sheet.Cols.Count-1 do begin
|
||||
col := PCol(sheet.Cols[j]);
|
||||
WriteColInfo(AStream, sheet, col);
|
||||
end;
|
||||
|
||||
WriteDimensions(AStream, sheet);
|
||||
|
||||
WriteWindow2(AStream, True);
|
||||
|
||||
WriteCellsToStream(AStream, AData.GetWorksheetByIndex(i).Cells);
|
||||
WriteCellsToStream(AStream, sheet.Cells);
|
||||
|
||||
WriteEOF(AStream);
|
||||
end;
|
||||
@ -747,6 +760,32 @@ begin
|
||||
AStream.WriteBuffer(WideStringToLE(WideSheetName)[1], Len * Sizeof(WideChar));
|
||||
end;
|
||||
|
||||
{*******************************************************************
|
||||
* TsSpreadBIFF8Writer.WriteColumn ()
|
||||
*
|
||||
* DESCRIPTION: Writes a COLINFO record
|
||||
*******************************************************************}
|
||||
procedure TsSpreadBIFF8Writer.WriteColInfo(AStream: TStream;
|
||||
ASheet: TsWorkSheet; ACol: PCol);
|
||||
var
|
||||
w: Integer;
|
||||
begin
|
||||
if Assigned(ACol) and Assigned(ASheet) then begin
|
||||
{ BIFF Record header }
|
||||
AStream.WriteWord(WordToLE(INT_EXCEL_ID_COLINFO)); // BIFF record header
|
||||
AStream.WriteWord(WordToLE(12)); // Record size
|
||||
AStream.WriteWord(WordToLE(ACol^.Col)); // start column
|
||||
AStream.WriteWord(WordToLE(ACol^.Col)); // end column
|
||||
{ calculate width to be in units of 1/256 of pixel width of character "0" }
|
||||
w := round(ACol^.Width * 256);
|
||||
AStream.WriteWord(WordToLE(w)); // write width
|
||||
AStream.WriteWord(15); // XF record, ignored
|
||||
AStream.WriteWord(0); // option flags, ignored
|
||||
AStream.WriteWord(0); // "not used"
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{*******************************************************************
|
||||
* TsSpreadBIFF8Writer.WriteDateTime ()
|
||||
*
|
||||
@ -1868,6 +1907,7 @@ begin
|
||||
INT_EXCEL_ID_RK: ReadRKValue(AStream);
|
||||
INT_EXCEL_ID_MULRK: ReadMulRKValues(AStream);
|
||||
INT_EXCEL_ID_LABELSST:ReadLabelSST(AStream); //BIFF8 only
|
||||
INT_EXCEL_ID_COLINFO: ReadColInfo(AStream);
|
||||
INT_EXCEL_ID_BOF: ;
|
||||
INT_EXCEL_ID_EOF: SectionEOF := True;
|
||||
else
|
||||
@ -2384,6 +2424,25 @@ begin
|
||||
lFontName := ReadString(AStream, Len);
|
||||
end;
|
||||
|
||||
procedure TsSpreadBiff8Reader.ReadColInfo(const AStream: TStream);
|
||||
var
|
||||
c, c1, c2: Cardinal;
|
||||
w: Word;
|
||||
col: TCol;
|
||||
begin
|
||||
// read column start and end index of column range
|
||||
c1 := WordLEToN(AStream.ReadWord);
|
||||
c2 := WordLEToN(AStream.ReadWord);
|
||||
// read col width in 1/256 of the width of "0" character
|
||||
w := WordLEToN(AStream.ReadWord);
|
||||
// calculate width in units of "characters"
|
||||
col.Width := w / 256;
|
||||
// assign width to columns
|
||||
for c := c1 to c2 do
|
||||
FWorksheet.WriteColInfo(c, col);
|
||||
end;
|
||||
|
||||
|
||||
{*******************************************************************
|
||||
* Initialization section
|
||||
*
|
||||
|
Reference in New Issue
Block a user