You've already forked lazarus-ccr
fpspreadsheet: Row height and column width reading/writing code for ods files complete. Test cases ok, but extremely slow speed of test application for numbertest and datetimetests. Changed units of row heights in worksheet: used to be points, is "lines" now (more consistent user interface - column width is in "standard characters", I prefer these units over centimeters because row heights/column widths become independent of screen pixels per inch this way)
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3118 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -33,7 +33,7 @@ begin
|
|||||||
//MyWorksheet.WriteColWidth(0, 5);
|
//MyWorksheet.WriteColWidth(0, 5);
|
||||||
//MyWorksheet.WriteColWidth(1, 30);
|
//MyWorksheet.WriteColWidth(1, 30);
|
||||||
|
|
||||||
MyWorksheet.WriteRowHeight(0, 30); // 30 mm
|
MyWorksheet.WriteRowHeight(0, 3); // 3 lines
|
||||||
|
|
||||||
// Turn off grid lines and hide headers
|
// Turn off grid lines and hide headers
|
||||||
//MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines, soShowHeaders];
|
//MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines, soShowHeaders];
|
||||||
@ -367,16 +367,16 @@ begin
|
|||||||
inc(r);
|
inc(r);
|
||||||
|
|
||||||
// Set width of columns 0 to 3
|
// Set width of columns 0 to 3
|
||||||
MyWorksheet.WriteColWidth(0, 50);
|
MyWorksheet.WriteColWidth(0, 48); // 48 characters, default is 12 --> 4x default width
|
||||||
lCol.Width := 15;
|
lCol.Width := 24; // 24 characters, default is 12 --> 2x default width
|
||||||
MyWorksheet.WriteColInfo(1, lCol);
|
MyWorksheet.WriteColInfo(1, lCol);
|
||||||
MyWorksheet.WriteColInfo(2, lCol);
|
MyWorksheet.WriteColInfo(2, lCol);
|
||||||
MyWorksheet.WriteColInfo(3, lCol);
|
MyWorksheet.WriteColInfo(3, lCol);
|
||||||
|
|
||||||
// Set height of rows 5 and 6
|
// Set height of rows 5 and 6
|
||||||
lRow.Height := 10;
|
lRow.Height := 4; // 4 lines
|
||||||
MyWorksheet.WriteRowInfo(5, lRow);
|
MyWorksheet.WriteRowInfo(5, lRow);
|
||||||
lRow.Height := 5;
|
lRow.Height := 2; // 2 lines
|
||||||
MyWorksheet.WriteRowInfo(6, lRow);
|
MyWorksheet.WriteRowInfo(6, lRow);
|
||||||
|
|
||||||
// Save the spreadsheet to a file
|
// Save the spreadsheet to a file
|
||||||
|
@ -45,7 +45,7 @@ begin
|
|||||||
MyWorkbook.AddFont('Calibri', 20, [], scRed);
|
MyWorkbook.AddFont('Calibri', 20, [], scRed);
|
||||||
|
|
||||||
// Change row height
|
// Change row height
|
||||||
MyWorksheet.WriteRowHeight(0, 20); // modify height of row 0 to 20 mm
|
MyWorksheet.WriteRowHeight(0, 1.1); // modify height of row 0 to 3 lines
|
||||||
|
|
||||||
// Change colum widths
|
// Change colum widths
|
||||||
MyWorksheet.WriteColWidth(0, 40);
|
MyWorksheet.WriteColWidth(0, 40);
|
||||||
|
@ -383,7 +383,7 @@ begin
|
|||||||
MyWorksheet.WriteColInfo(5, lCol);
|
MyWorksheet.WriteColInfo(5, lCol);
|
||||||
|
|
||||||
// Set height of rows 0
|
// Set height of rows 0
|
||||||
MyWorksheet.WriteRowHeight(0, 30); // 30 mm
|
MyWorksheet.WriteRowHeight(0, 5); // 5 lines
|
||||||
|
|
||||||
// Creates a new worksheet
|
// Creates a new worksheet
|
||||||
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet2);
|
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet2);
|
||||||
|
@ -32,6 +32,7 @@ begin
|
|||||||
MyWorksheet.WriteUTF8Text(4, 2, 'Total:');// C5
|
MyWorksheet.WriteUTF8Text(4, 2, 'Total:');// C5
|
||||||
MyWorksheet.WriteNumber(4, 3, 10); // D5
|
MyWorksheet.WriteNumber(4, 3, 10); // D5
|
||||||
MyWorksheet.WriteDateTime(5, 0, now);
|
MyWorksheet.WriteDateTime(5, 0, now);
|
||||||
|
|
||||||
// Add some formatting
|
// Add some formatting
|
||||||
MyWorksheet.WriteUsedFormatting(0, 0, [uffBold]);
|
MyWorksheet.WriteUsedFormatting(0, 0, [uffBold]);
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -335,16 +335,22 @@ type
|
|||||||
|
|
||||||
PCell = ^TCell;
|
PCell = ^TCell;
|
||||||
|
|
||||||
|
const
|
||||||
|
// Takes account of effect of cell margins on row height by adding this
|
||||||
|
// value to the nominal row height. Note that this is an empirical value and may be wrong.
|
||||||
|
ROW_HEIGHT_CORRECTION = 0.2;
|
||||||
|
|
||||||
|
type
|
||||||
TRow = record
|
TRow = record
|
||||||
Row: Cardinal;
|
Row: Cardinal;
|
||||||
Height: Single; // in millimeters
|
Height: Single; // in "lines"
|
||||||
end;
|
end;
|
||||||
|
|
||||||
PRow = ^TRow;
|
PRow = ^TRow;
|
||||||
|
|
||||||
TCol = record
|
TCol = record
|
||||||
Col: Cardinal;
|
Col: Cardinal;
|
||||||
Width: Single; // in "characters". Excel uses the with of char "0" in 1st font
|
Width: Single; // in "characters". Excel uses the width of char "0" in 1st font
|
||||||
end;
|
end;
|
||||||
|
|
||||||
PCol = ^TCol;
|
PCol = ^TCol;
|
||||||
@ -368,7 +374,7 @@ type
|
|||||||
FWorkbook: TsWorkbook;
|
FWorkbook: TsWorkbook;
|
||||||
FCells: TAvlTree; // Items are TCell
|
FCells: TAvlTree; // Items are TCell
|
||||||
FCurrentNode: TAVLTreeNode; // For GetFirstCell and GetNextCell
|
FCurrentNode: TAVLTreeNode; // For GetFirstCell and GetNextCell
|
||||||
FRows, FCols: TIndexedAVLTree; // This lists contain only rows or cols with styles different from the standard
|
FRows, FCols: TIndexedAVLTree; // This lists contain only rows or cols with styles different from default
|
||||||
FLeftPaneWidth: Integer;
|
FLeftPaneWidth: Integer;
|
||||||
FTopPaneHeight: Integer;
|
FTopPaneHeight: Integer;
|
||||||
FOptions: TsSheetOptions;
|
FOptions: TsSheetOptions;
|
||||||
@ -475,8 +481,12 @@ type
|
|||||||
{ Data manipulation methods - For Rows and Cols }
|
{ Data manipulation methods - For Rows and Cols }
|
||||||
function FindRow(ARow: Cardinal): PRow;
|
function FindRow(ARow: Cardinal): PRow;
|
||||||
function FindCol(ACol: Cardinal): PCol;
|
function FindCol(ACol: Cardinal): PCol;
|
||||||
|
function GetCellCountInRow(ARow: Cardinal): Cardinal;
|
||||||
|
function GetCellCountInCol(ACol: Cardinal): Cardinal;
|
||||||
function GetRow(ARow: Cardinal): PRow;
|
function GetRow(ARow: Cardinal): PRow;
|
||||||
|
function GetRowHeight(ARow: Cardinal): Single;
|
||||||
function GetCol(ACol: Cardinal): PCol;
|
function GetCol(ACol: Cardinal): PCol;
|
||||||
|
function GetColWidth(ACol: Cardinal): Single;
|
||||||
procedure RemoveAllRows;
|
procedure RemoveAllRows;
|
||||||
procedure RemoveAllCols;
|
procedure RemoveAllCols;
|
||||||
procedure WriteRowInfo(ARow: Cardinal; AData: TRow);
|
procedure WriteRowInfo(ARow: Cardinal; AData: TRow);
|
||||||
@ -511,10 +521,15 @@ type
|
|||||||
FBuiltinFontCount: Integer;
|
FBuiltinFontCount: Integer;
|
||||||
FPalette: array of TsColorValue;
|
FPalette: array of TsColorValue;
|
||||||
FReadFormulas: Boolean;
|
FReadFormulas: Boolean;
|
||||||
|
FDefaultColWidth: Single; // in "characters". Excel uses the width of char "0" in 1st font
|
||||||
|
FDefaultRowHeight: Single; // in "character heights", i.e. line count
|
||||||
|
|
||||||
{ Internal methods }
|
{ Internal methods }
|
||||||
procedure RemoveWorksheetsCallback(data, arg: pointer);
|
procedure RemoveWorksheetsCallback(data, arg: pointer);
|
||||||
|
|
||||||
public
|
public
|
||||||
FormatSettings: TFormatSettings;
|
FormatSettings: TFormatSettings;
|
||||||
|
|
||||||
{ Base methods }
|
{ Base methods }
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -530,6 +545,7 @@ type
|
|||||||
const AOverwriteExisting: Boolean = False); overload;
|
const AOverwriteExisting: Boolean = False); overload;
|
||||||
procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False); overload;
|
procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False); overload;
|
||||||
procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat);
|
||||||
|
|
||||||
{ Worksheet list handling methods }
|
{ Worksheet list handling methods }
|
||||||
function AddWorksheet(AName: string): TsWorksheet;
|
function AddWorksheet(AName: string): TsWorksheet;
|
||||||
function GetFirstWorksheet: TsWorksheet;
|
function GetFirstWorksheet: TsWorksheet;
|
||||||
@ -537,6 +553,7 @@ type
|
|||||||
function GetWorksheetByName(AName: String): TsWorksheet;
|
function GetWorksheetByName(AName: String): TsWorksheet;
|
||||||
function GetWorksheetCount: Cardinal;
|
function GetWorksheetCount: Cardinal;
|
||||||
procedure RemoveAllWorksheets;
|
procedure RemoveAllWorksheets;
|
||||||
|
|
||||||
{ Font handling }
|
{ Font handling }
|
||||||
function AddFont(const AFontName: String; ASize: Single;
|
function AddFont(const AFontName: String; ASize: Single;
|
||||||
AStyle: TsFontStyles; AColor: TsColor): Integer; overload;
|
AStyle: TsFontStyles; AColor: TsColor): Integer; overload;
|
||||||
@ -544,11 +561,13 @@ type
|
|||||||
procedure CopyFontList(ASource: TFPList);
|
procedure CopyFontList(ASource: TFPList);
|
||||||
function FindFont(const AFontName: String; ASize: Single;
|
function FindFont(const AFontName: String; ASize: Single;
|
||||||
AStyle: TsFontStyles; AColor: TsColor): Integer;
|
AStyle: TsFontStyles; AColor: TsColor): Integer;
|
||||||
|
function GetDefaultFontSize: Single;
|
||||||
function GetFont(AIndex: Integer): TsFont;
|
function GetFont(AIndex: Integer): TsFont;
|
||||||
function GetFontCount: Integer;
|
function GetFontCount: Integer;
|
||||||
procedure InitFonts;
|
procedure InitFonts;
|
||||||
procedure RemoveAllFonts;
|
procedure RemoveAllFonts;
|
||||||
procedure SetDefaultFont(const AFontName: String; ASize: Single);
|
procedure SetDefaultFont(const AFontName: String; ASize: Single);
|
||||||
|
|
||||||
{ Color handling }
|
{ Color handling }
|
||||||
function AddColorToPalette(AColorValue: TsColorValue): TsColor;
|
function AddColorToPalette(AColorValue: TsColorValue): TsColor;
|
||||||
function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String;
|
function FPSColorToHexString(AColor: TsColor; ARGBColor: TFPColor): String;
|
||||||
@ -560,6 +579,13 @@ type
|
|||||||
procedure UseDefaultPalette;
|
procedure UseDefaultPalette;
|
||||||
procedure UsePalette(APalette: PsPalette; APaletteCount: Word;
|
procedure UsePalette(APalette: PsPalette; APaletteCount: Word;
|
||||||
ABigEndian: Boolean = false);
|
ABigEndian: Boolean = false);
|
||||||
|
|
||||||
|
{@@ The default column width given in "character units" (width of the
|
||||||
|
character "0" in the default font) }
|
||||||
|
property DefaultColWidth: Single read FDefaultColWidth;
|
||||||
|
{@@ The default row height is given in "line count" (height of the
|
||||||
|
default font }
|
||||||
|
property DefaultRowHeight: Single read FDefaultRowHeight;
|
||||||
{@@ This property is only used for formats which don't support unicode
|
{@@ This property is only used for formats which don't support unicode
|
||||||
and support a single encoding for the whole document, like Excel 2 to 5 }
|
and support a single encoding for the whole document, like Excel 2 to 5 }
|
||||||
property Encoding: TsEncoding read FEncoding write FEncoding;
|
property Encoding: TsEncoding read FEncoding write FEncoding;
|
||||||
@ -1366,6 +1392,7 @@ end;
|
|||||||
function TsWorksheet.GetLastColIndex: Cardinal;
|
function TsWorksheet.GetLastColIndex: Cardinal;
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
AVLNode: TAVLTreeNode;
|
||||||
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
|
|
||||||
@ -1378,6 +1405,12 @@ begin
|
|||||||
Result := Math.Max(Result, PCell(AVLNode.Data)^.Col);
|
Result := Math.Max(Result, PCell(AVLNode.Data)^.Col);
|
||||||
AVLNode := FCells.FindSuccessor(AVLNode);
|
AVLNode := FCells.FindSuccessor(AVLNode);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
// In addition, there may be column records defining the column width even
|
||||||
|
// without content
|
||||||
|
for i:=0 to FCols.Count-1 do
|
||||||
|
if FCols[i] <> nil then
|
||||||
|
Result := Math.Max(Result, PCol(FCols[i])^.Col);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsWorksheet.GetLastColNumber: Cardinal;
|
function TsWorksheet.GetLastColNumber: Cardinal;
|
||||||
@ -1424,12 +1457,18 @@ end;
|
|||||||
function TsWorksheet.GetLastRowIndex: Cardinal;
|
function TsWorksheet.GetLastRowIndex: Cardinal;
|
||||||
var
|
var
|
||||||
AVLNode: TAVLTreeNode;
|
AVLNode: TAVLTreeNode;
|
||||||
|
i: Integer;
|
||||||
begin
|
begin
|
||||||
Result := 0;
|
Result := 0;
|
||||||
|
|
||||||
AVLNode := FCells.FindHighest;
|
AVLNode := FCells.FindHighest;
|
||||||
if Assigned(AVLNode) then
|
if Assigned(AVLNode) then
|
||||||
Result := PCell(AVLNode.Data).Row;
|
Result := PCell(AVLNode.Data).Row;
|
||||||
|
|
||||||
|
// In addition, there may be row records even for empty rows.
|
||||||
|
for i:=0 to FRows.Count-1 do
|
||||||
|
if FRows[i] <> nil then
|
||||||
|
Result := Math.Max(Result, PRow(FRows[i])^.Row);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TsWorksheet.GetLastRowNumber: Cardinal;
|
function TsWorksheet.GetLastRowNumber: Cardinal;
|
||||||
@ -2243,7 +2282,6 @@ var
|
|||||||
AVLNode: TAVGLVLTreeNode;
|
AVLNode: TAVGLVLTreeNode;
|
||||||
begin
|
begin
|
||||||
Result := nil;
|
Result := nil;
|
||||||
|
|
||||||
LElement.Row := ARow;
|
LElement.Row := ARow;
|
||||||
AVLNode := FRows.Find(@LElement);
|
AVLNode := FRows.Find(@LElement);
|
||||||
if Assigned(AVLNode) then
|
if Assigned(AVLNode) then
|
||||||
@ -2256,7 +2294,6 @@ var
|
|||||||
AVLNode: TAVGLVLTreeNode;
|
AVLNode: TAVGLVLTreeNode;
|
||||||
begin
|
begin
|
||||||
Result := nil;
|
Result := nil;
|
||||||
|
|
||||||
LElement.Col := ACol;
|
LElement.Col := ACol;
|
||||||
AVLNode := FCols.Find(@LElement);
|
AVLNode := FCols.Find(@LElement);
|
||||||
if Assigned(AVLNode) then
|
if Assigned(AVLNode) then
|
||||||
@ -2285,6 +2322,72 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Counts how many cells exist in the given column. Blank cells do contribute
|
||||||
|
to the sum, as well as rows with a non-default style. }
|
||||||
|
function TsWorksheet.GetCellCountInCol(ACol: Cardinal): Cardinal;
|
||||||
|
var
|
||||||
|
cell: PCell;
|
||||||
|
r: Cardinal;
|
||||||
|
row: PRow;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
for r := 0 to GetLastRowIndex do begin
|
||||||
|
cell := FindCell(r, ACol);
|
||||||
|
if cell <> nil then
|
||||||
|
inc(Result)
|
||||||
|
else begin
|
||||||
|
row := FindRow(r);
|
||||||
|
if row <> nil then inc(Result);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Counts how many cells exist in the given row. Blank cells do contribute
|
||||||
|
to the sum, as well as columns with a non-default style. }
|
||||||
|
function TsWorksheet.GetCellCountInRow(ARow: Cardinal): Cardinal;
|
||||||
|
var
|
||||||
|
cell: PCell;
|
||||||
|
c: Cardinal;
|
||||||
|
col: PCol;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
for c := 0 to GetLastColIndex do begin
|
||||||
|
cell := FindCell(ARow, c);
|
||||||
|
if cell <> nil then
|
||||||
|
inc(Result)
|
||||||
|
else begin
|
||||||
|
col := FindCol(c);
|
||||||
|
if col <> nil then inc(Result);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Returns the width of the given column. If there is no column record then
|
||||||
|
the default column width is returned. }
|
||||||
|
function TsWorksheet.GetColWidth(ACol: Cardinal): Single;
|
||||||
|
var
|
||||||
|
col: PCol;
|
||||||
|
begin
|
||||||
|
col := FindCol(ACol);
|
||||||
|
if col <> nil then
|
||||||
|
Result := col^.Width
|
||||||
|
else
|
||||||
|
Result := FWorkbook.DefaultColWidth;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Returns the height of the given row. If there is no row record then the
|
||||||
|
default row height is returned }
|
||||||
|
function TsWorksheet.GetRowHeight(ARow: Cardinal): Single;
|
||||||
|
var
|
||||||
|
row: PRow;
|
||||||
|
begin
|
||||||
|
row := FindRow(ARow);
|
||||||
|
if row <> nil then
|
||||||
|
Result := row^.Height
|
||||||
|
else
|
||||||
|
Result := FWorkbook.DefaultRowHeight;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TsWorksheet.RemoveAllRows;
|
procedure TsWorksheet.RemoveAllRows;
|
||||||
var
|
var
|
||||||
Node: Pointer;
|
Node: Pointer;
|
||||||
@ -2359,6 +2462,8 @@ constructor TsWorkbook.Create;
|
|||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
FWorksheets := TFPList.Create;
|
FWorksheets := TFPList.Create;
|
||||||
|
FDefaultColWidth := 12;
|
||||||
|
FDefaultRowHeight := 1;
|
||||||
FormatSettings := DefaultFormatSettings;
|
FormatSettings := DefaultFormatSettings;
|
||||||
FFontList := TFPList.Create;
|
FFontList := TFPList.Create;
|
||||||
SetDefaultFont('Arial', 10.0);
|
SetDefaultFont('Arial', 10.0);
|
||||||
@ -2777,7 +2882,6 @@ begin
|
|||||||
// FONT4 which does not exist in BIFF is added automatically with nil as place-holder
|
// FONT4 which does not exist in BIFF is added automatically with nil as place-holder
|
||||||
AddFont(fntName, fntSize, [fssBold, fssItalic], scBlack); // FONT5 for uffBoldItalic
|
AddFont(fntName, fntSize, [fssBold, fssItalic], scBlack); // FONT5 for uffBoldItalic
|
||||||
|
|
||||||
|
|
||||||
FBuiltinFontCount := FFontList.Count;
|
FBuiltinFontCount := FFontList.Count;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2816,6 +2920,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{@@
|
||||||
|
Returns the point size of the default font
|
||||||
|
}
|
||||||
|
function TsWorkbook.GetDefaultFontSize: Single;
|
||||||
|
begin
|
||||||
|
Result := GetFont(0).Size;
|
||||||
|
end;
|
||||||
|
|
||||||
{@@
|
{@@
|
||||||
Returns the font with the given index.
|
Returns the font with the given index.
|
||||||
}
|
}
|
||||||
|
@ -525,10 +525,13 @@ begin
|
|||||||
Result := h;
|
Result := h;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Converts the row height, given in mm, to pixels }
|
{ Converts the row height (from a worksheet row), given in lines, to pixels }
|
||||||
function TsCustomWorksheetGrid.CalcRowHeight(AHeight: Single): Integer;
|
function TsCustomWorksheetGrid.CalcRowHeight(AHeight: Single): Integer;
|
||||||
|
var
|
||||||
|
h_pts: Single;
|
||||||
begin
|
begin
|
||||||
Result := round(AHeight / 25.4 * Screen.PixelsPerInch) + 4;
|
h_pts := AHeight * (Workbook.GetFont(0).Size + ROW_HEIGHT_CORRECTION);
|
||||||
|
Result := PtsToPX(h_pts, Screen.PixelsPerInch) + 4;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsCustomWorksheetGrid.ChangedCellHandler(ASender: TObject; ARow, ACol:Cardinal);
|
procedure TsCustomWorksheetGrid.ChangedCellHandler(ASender: TObject; ARow, ACol:Cardinal);
|
||||||
@ -1871,7 +1874,7 @@ end;
|
|||||||
procedure TsCustomWorksheetGrid.HeaderSized(IsColumn: Boolean; index: Integer);
|
procedure TsCustomWorksheetGrid.HeaderSized(IsColumn: Boolean; index: Integer);
|
||||||
var
|
var
|
||||||
w0: Integer;
|
w0: Integer;
|
||||||
h: Single;
|
h, h_pts: Single;
|
||||||
begin
|
begin
|
||||||
if FWorksheet = nil then
|
if FWorksheet = nil then
|
||||||
exit;
|
exit;
|
||||||
@ -1884,8 +1887,9 @@ begin
|
|||||||
FWorksheet.WriteColWidth(GetWorksheetCol(Index), ColWidths[Index] div w0);
|
FWorksheet.WriteColWidth(GetWorksheetCol(Index), ColWidths[Index] div w0);
|
||||||
end else begin
|
end else begin
|
||||||
// The grid's row heights are in "pixels", the worksheet's row heights are
|
// The grid's row heights are in "pixels", the worksheet's row heights are
|
||||||
// in millimeters.
|
// in "lines"
|
||||||
h := (RowHeights[Index] - 4) / Screen.PixelsPerInch * 25.4;
|
h_pts := PxToPts(RowHeights[Index] - 4, Screen.PixelsPerInch); // in points
|
||||||
|
h := h_pts / (FWorkbook.GetFont(0).Size + ROW_HEIGHT_CORRECTION);
|
||||||
FWorksheet.WriteRowHeight(GetWorksheetRow(Index), h);
|
FWorksheet.WriteRowHeight(GetWorksheetRow(Index), h);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -2616,6 +2620,7 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
fpsutils.ScreenPixelsPerInch := Screen.PixelsPerInch;
|
||||||
|
|
||||||
finalization
|
finalization
|
||||||
FreeAndNil(FillPattern_BIFF2);
|
FreeAndNil(FillPattern_BIFF2);
|
||||||
|
@ -66,9 +66,6 @@ function GetErrorValueStr(AErrorValue: TsErrorValue): String;
|
|||||||
|
|
||||||
function UTF8TextToXMLText(AText: ansistring): ansistring;
|
function UTF8TextToXMLText(AText: ansistring): ansistring;
|
||||||
|
|
||||||
function TwipsToMillimeters(AValue: Integer): Single;
|
|
||||||
function MillimetersToTwips(AValue: Single): Integer;
|
|
||||||
|
|
||||||
function IfThen(ACondition: Boolean; AValue1,AValue2: TsNumberFormat): TsNumberFormat; overload;
|
function IfThen(ACondition: Boolean; AValue1,AValue2: TsNumberFormat): TsNumberFormat; overload;
|
||||||
|
|
||||||
function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean;
|
function IsDateTimeFormat(AFormat: TsNumberFormat): Boolean;
|
||||||
@ -102,12 +99,24 @@ function FormatDateTime(const FormatStr: string; DateTime: TDateTime;
|
|||||||
function FormatDateTime(const FormatStr: string; DateTime: TDateTime;
|
function FormatDateTime(const FormatStr: string; DateTime: TDateTime;
|
||||||
const FormatSettings: TFormatSettings; Options : TFormatDateTimeOptions = []): string;
|
const FormatSettings: TFormatSettings; Options : TFormatDateTimeOptions = []): string;
|
||||||
|
|
||||||
|
function TwipsToPts(AValue: Integer): Single;
|
||||||
|
function PtsToTwips(AValue: Single): Integer;
|
||||||
function cmToPts(AValue: Double): Double;
|
function cmToPts(AValue: Double): Double;
|
||||||
|
function PtsToCm(AValue: Double): Double;
|
||||||
|
function InToPts(AValue: Double): Double;
|
||||||
function mmToPts(AValue: Double): Double;
|
function mmToPts(AValue: Double): Double;
|
||||||
|
function PtsToMM(AValue: Double): Double;
|
||||||
|
function pxToPts(AValue, AScreenPixelsPerInch: Integer): Double;
|
||||||
|
function PtsToPx(AValue: Double; AScreenPixelsPerInch: Integer): Integer;
|
||||||
|
function HTMLLengthStrToPts(AValue: String): Double;
|
||||||
|
//function HMTLLengthStrToPts(AValue: String): Double;
|
||||||
|
|
||||||
function HTMLColorStrToColor(AValue: String): TsColorValue;
|
function HTMLColorStrToColor(AValue: String): TsColorValue;
|
||||||
function ColorToHTMLColorStr(AValue: TsColorValue): String;
|
function ColorToHTMLColorStr(AValue: TsColorValue): String;
|
||||||
|
|
||||||
|
var
|
||||||
|
ScreenPixelsPerInch: Integer = 96;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
@ -533,19 +542,6 @@ begin
|
|||||||
Result:=WrkStr;
|
Result:=WrkStr;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Excel's unit of row heights is "twips", i.e. 1/20 point. 72 pts = 1 inch = 25.4 mm
|
|
||||||
The procedure TwipsToMillimeters performs the conversion to millimeters. }
|
|
||||||
function TwipsToMillimeters(AValue: Integer): Single;
|
|
||||||
begin
|
|
||||||
Result := 25.4 * AValue / (20 * 72);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Converts Millimeters to Twips, i.e. 1/20 pt }
|
|
||||||
function MillimetersToTwips(AValue: Single): Integer;
|
|
||||||
begin
|
|
||||||
Result := Round((AValue * 20 * 72) / 25.4);
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ Returns either AValue1 or AValue2, depending on the condition.
|
{ Returns either AValue1 or AValue2, depending on the condition.
|
||||||
For reduciton of typing... }
|
For reduciton of typing... }
|
||||||
function IfThen(ACondition: Boolean; AValue1, AValue2: TsNumberFormat): TsNumberFormat;
|
function IfThen(ACondition: Boolean; AValue1, AValue2: TsNumberFormat): TsNumberFormat;
|
||||||
@ -1296,16 +1292,82 @@ begin
|
|||||||
DateTimeToString(Result, FormatStr, DateTime, FormatSettings,Options);
|
DateTimeToString(Result, FormatStr, DateTime, FormatSettings,Options);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Excel's unit of row heights is "twips", i.e. 1/20 point.
|
||||||
|
Converts Twips to points. }
|
||||||
|
function TwipsToPts(AValue: Integer): Single;
|
||||||
|
begin
|
||||||
|
Result := AValue / 20;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Converts points to twips (1 twip = 1/20 point) }
|
||||||
|
function PtsToTwips(AValue: Single): Integer;
|
||||||
|
begin
|
||||||
|
Result := round(AValue * 20);
|
||||||
|
end;
|
||||||
|
|
||||||
{ Converts centimeters to points (72 pts = 1 inch) }
|
{ Converts centimeters to points (72 pts = 1 inch) }
|
||||||
function cmToPts(AValue: Double): Double;
|
function cmToPts(AValue: Double): Double;
|
||||||
begin
|
begin
|
||||||
Result := AValue/2.54*72;
|
Result := AValue * 72 / 2.54;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Converts points to centimeters }
|
||||||
|
function PtsToCm(AValue: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := AValue / 72 * 2.54;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Converts inches to points (72 pts = 1 inch) }
|
||||||
|
function InToPts(AValue: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := AValue * 72;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Converts millimeters to points (72 pts = 1 inch) }
|
{ Converts millimeters to points (72 pts = 1 inch) }
|
||||||
function mmToPts(AValue: Double): Double;
|
function mmToPts(AValue: Double): Double;
|
||||||
begin
|
begin
|
||||||
Result := AValue/25.4*72;
|
Result := AValue * 72 / 25.4;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Converts points to millimeters }
|
||||||
|
function PtsToMM(AValue: Double): Double;
|
||||||
|
begin
|
||||||
|
Result := AValue / 72 * 25.4;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Converts pixels to points. }
|
||||||
|
function pxToPts(AValue, AScreenPixelsPerInch: Integer): Double;
|
||||||
|
begin
|
||||||
|
Result := (AValue / AScreenPixelsPerInch) * 72;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Converts points to pixels }
|
||||||
|
function PtsToPx(AValue: Double; AScreenPixelsPerInch: Integer): Integer;
|
||||||
|
begin
|
||||||
|
Result := Round(AValue / 72 * AScreenPixelsPerInch);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ converts a HTML length string to points. The units are assumed to be the last
|
||||||
|
two digits of the string }
|
||||||
|
function HTMLLengthStrToPts(AValue: String): Double;
|
||||||
|
var
|
||||||
|
units: String;
|
||||||
|
x: Double;
|
||||||
|
res: Word;
|
||||||
|
begin
|
||||||
|
units := lowercase(Copy(AValue, Length(AValue)-1, 2));
|
||||||
|
val(copy(AValue, 1, Length(AValue)-2), x, res);
|
||||||
|
// No hasseling with the decimal point...
|
||||||
|
if units = 'in' then
|
||||||
|
Result := InToPts(x)
|
||||||
|
else if units = 'cm' then
|
||||||
|
Result := cmToPts(x)
|
||||||
|
else if units = 'mm' then
|
||||||
|
Result := mmToPts(x)
|
||||||
|
else if units = 'px' then
|
||||||
|
Result := pxToPts(Round(x), ScreenPixelsPerInch)
|
||||||
|
else
|
||||||
|
raise Exception.Create('Unknown length units');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ converts a HTML color string to a TsColorValue. For ods }
|
{ converts a HTML color string to a TsColorValue. For ods }
|
||||||
|
@ -107,6 +107,8 @@ type
|
|||||||
procedure TestWriteRead_ODS_Alignment;
|
procedure TestWriteRead_ODS_Alignment;
|
||||||
procedure TestWriteRead_ODS_Border;
|
procedure TestWriteRead_ODS_Border;
|
||||||
procedure TestWriteRead_ODS_BorderStyles;
|
procedure TestWriteRead_ODS_BorderStyles;
|
||||||
|
procedure TestWriteRead_ODS_ColWidths;
|
||||||
|
procedure TestWriteRead_ODS_RowHeights;
|
||||||
procedure TestWriteRead_ODS_TextRotation;
|
procedure TestWriteRead_ODS_TextRotation;
|
||||||
procedure TestWriteRead_ODS_WordWrap;
|
procedure TestWriteRead_ODS_WordWrap;
|
||||||
end;
|
end;
|
||||||
@ -203,13 +205,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// Column width
|
// Column width
|
||||||
SollColWidths[0] := 20; // characters based on width of "0"
|
SollColWidths[0] := 20; // characters based on width of "0" of default font
|
||||||
SollColWidths[1] := 40;
|
SollColWidths[1] := 40;
|
||||||
|
|
||||||
// Row heights
|
// Row heights
|
||||||
SollRowHeights[0] := 5;
|
SollRowHeights[0] := 1; // Lines of default font
|
||||||
SollRowHeights[1] := 10;
|
SollRowHeights[1] := 2;
|
||||||
SollRowHeights[2] := 50;
|
SollRowHeights[2] := 4;
|
||||||
|
|
||||||
// Cell borders
|
// Cell borders
|
||||||
SollBorders[0] := [];
|
SollBorders[0] := [];
|
||||||
@ -723,6 +725,7 @@ begin
|
|||||||
MyWorkSheet:= MyWorkBook.AddWorksheet(ColWidthSheet);
|
MyWorkSheet:= MyWorkBook.AddWorksheet(ColWidthSheet);
|
||||||
for Col := Low(SollColWidths) to High(SollColWidths) do begin
|
for Col := Low(SollColWidths) to High(SollColWidths) do begin
|
||||||
lCol.Width := SollColWidths[Col];
|
lCol.Width := SollColWidths[Col];
|
||||||
|
//MyWorksheet.WriteNumber(0, Col, 1);
|
||||||
MyWorksheet.WriteColInfo(Col, lCol);
|
MyWorksheet.WriteColInfo(Col, lCol);
|
||||||
end;
|
end;
|
||||||
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
MyWorkBook.WriteToFile(TempFile, AFormat, true);
|
||||||
@ -742,6 +745,7 @@ begin
|
|||||||
if lpCol = nil then
|
if lpCol = nil then
|
||||||
fail('Error in test code. Failed to return saved column width');
|
fail('Error in test code. Failed to return saved column width');
|
||||||
ActualColWidth := lpCol^.Width;
|
ActualColWidth := lpCol^.Width;
|
||||||
|
if abs(SollColWidths[Col] - ActualColWidth) > 1E-2 then // take rounding errors into account
|
||||||
CheckEquals(SollColWidths[Col], ActualColWidth,
|
CheckEquals(SollColWidths[Col], ActualColWidth,
|
||||||
'Test saved colwidth mismatch, column '+ColNotation(MyWorkSheet,Col));
|
'Test saved colwidth mismatch, column '+ColNotation(MyWorkSheet,Col));
|
||||||
end;
|
end;
|
||||||
@ -766,6 +770,10 @@ begin
|
|||||||
TestWriteReadColWidths(sfExcel8);
|
TestWriteReadColWidths(sfExcel8);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_ODS_ColWidths;
|
||||||
|
begin
|
||||||
|
TestWriteReadColWidths(sfOpenDocument);
|
||||||
|
end;
|
||||||
|
|
||||||
{ --- Row height tests --- }
|
{ --- Row height tests --- }
|
||||||
|
|
||||||
@ -801,13 +809,10 @@ begin
|
|||||||
if MyWorksheet=nil then
|
if MyWorksheet=nil then
|
||||||
fail('Error in test code. Failed to get named worksheet');
|
fail('Error in test code. Failed to get named worksheet');
|
||||||
for Row := Low(SollRowHeights) to High(SollRowHeights) do begin
|
for Row := Low(SollRowHeights) to High(SollRowHeights) do begin
|
||||||
lpRow := MyWorksheet.GetRow(Row);
|
ActualRowHeight := MyWorksheet.GetRowHeight(Row);
|
||||||
if lpRow = nil then
|
// Take care of rounding errors
|
||||||
fail('Error in test code. Failed to return saved row height');
|
if abs(ActualRowHeight - SollRowHeights[Row]) > 1e-2 then
|
||||||
// Rounding to twips in Excel would cause severe rounding error if we'd compare millimeters
|
CheckEquals(SollRowHeights[Row], ActualRowHeight,
|
||||||
// --> go back to twips
|
|
||||||
ActualRowHeight := MillimetersToTwips(lpRow^.Height);
|
|
||||||
CheckEquals(MillimetersToTwips(SollRowHeights[Row]), ActualRowHeight,
|
|
||||||
'Test saved row height mismatch, row '+RowNotation(MyWorkSheet,Row));
|
'Test saved row height mismatch, row '+RowNotation(MyWorkSheet,Row));
|
||||||
end;
|
end;
|
||||||
// Finalization
|
// Finalization
|
||||||
@ -831,6 +836,11 @@ begin
|
|||||||
TestWriteReadRowHeights(sfExcel8);
|
TestWriteReadRowHeights(sfExcel8);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TSpreadWriteReadFormatTests.TestWriteRead_ODS_RowHeights;
|
||||||
|
begin
|
||||||
|
TestWriteReadRowHeights(sfOpenDocument);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ --- Text rotation tests --- }
|
{ --- Text rotation tests --- }
|
||||||
|
|
||||||
|
@ -708,7 +708,12 @@ begin
|
|||||||
if h and $8000 = 0 then begin // if this bit were set, rowheight would be default
|
if h and $8000 = 0 then begin // if this bit were set, rowheight would be default
|
||||||
lRow := FWorksheet.GetRow(WordLEToN(rowrec.RowIndex));
|
lRow := FWorksheet.GetRow(WordLEToN(rowrec.RowIndex));
|
||||||
// Row height is encoded into the 15 remaining bits in units "twips" (1/20 pt)
|
// Row height is encoded into the 15 remaining bits in units "twips" (1/20 pt)
|
||||||
lRow^.Height := TwipsToMillimeters(h and $7FFF);
|
// We need it in "lines" units.
|
||||||
|
lRow^.Height := TwipsToPts(h and $7FFF) / Workbook.GetFont(0).Size;
|
||||||
|
if lRow^.Height > ROW_HEIGHT_CORRECTION then
|
||||||
|
lRow^.Height := lRow^.Height - ROW_HEIGHT_CORRECTION
|
||||||
|
else
|
||||||
|
lRow^.Height := 0;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1632,6 +1637,7 @@ var
|
|||||||
containsXF: Boolean;
|
containsXF: Boolean;
|
||||||
rowheight: Word;
|
rowheight: Word;
|
||||||
w: Word;
|
w: Word;
|
||||||
|
h: Single;
|
||||||
begin
|
begin
|
||||||
containsXF := false;
|
containsXF := false;
|
||||||
|
|
||||||
@ -1649,10 +1655,14 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(Word(ALastColIndex) + 1));
|
AStream.WriteWord(WordToLE(Word(ALastColIndex) + 1));
|
||||||
|
|
||||||
{ Row height (in twips, 1/20 point) and info on custom row height }
|
{ Row height (in twips, 1/20 point) and info on custom row height }
|
||||||
if (ARow = nil) or (ARow^.Height = 0) then
|
h := Workbook.GetFont(0).Size;
|
||||||
rowheight := round(Workbook.GetFont(0).Size*20)
|
if (ARow = nil) or (ARow^.Height = Workbook.DefaultRowHeight) then
|
||||||
|
rowheight := PtsToTwips((Workbook.DefaultRowHeight + ROW_HEIGHT_CORRECTION) * h)
|
||||||
else
|
else
|
||||||
rowheight := MillimetersToTwips(ARow^.Height);
|
if (ARow^.Height = 0) then
|
||||||
|
rowheight := 0
|
||||||
|
else
|
||||||
|
rowheight := PtsToTwips((ARow^.Height + ROW_HEIGHT_CORRECTION) * h);
|
||||||
w := rowheight and $7FFF;
|
w := rowheight and $7FFF;
|
||||||
AStream.WriteWord(WordToLE(w));
|
AStream.WriteWord(WordToLE(w));
|
||||||
|
|
||||||
|
@ -1329,12 +1329,13 @@ begin
|
|||||||
if h and $8000 = 0 then begin // if this bit were set, rowheight would be default
|
if h and $8000 = 0 then begin // if this bit were set, rowheight would be default
|
||||||
lRow := FWorksheet.GetRow(WordLEToN(rowrec.RowIndex));
|
lRow := FWorksheet.GetRow(WordLEToN(rowrec.RowIndex));
|
||||||
// Row height is encoded into the 15 remaining bits in units "twips" (1/20 pt)
|
// Row height is encoded into the 15 remaining bits in units "twips" (1/20 pt)
|
||||||
lRow^.Height := TwipsToMillimeters(h and $7FFF);
|
// We need it in "lines", i.e. we divide the points by the point size of the default font
|
||||||
end else
|
lRow^.Height := TwipsToPts(h and $7FFF) / FWorkbook.GetFont(0).Size;
|
||||||
|
if lRow^.Height > ROW_HEIGHT_CORRECTION then
|
||||||
|
lRow^.Height := lRow^.Height - ROW_HEIGHT_CORRECTION
|
||||||
|
else
|
||||||
lRow^.Height := 0;
|
lRow^.Height := 0;
|
||||||
//lRow^.AutoHeight := rowrec.Flags and $00000040 = 0;
|
end;
|
||||||
// If this bit is set row height does not change with font height, i.e. has been
|
|
||||||
// changed manually.
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Reads the cell address used in an RPN formula element. Evaluates the corresponding
|
{ Reads the cell address used in an RPN formula element. Evaluates the corresponding
|
||||||
@ -1903,6 +1904,7 @@ var
|
|||||||
spaceabove, spacebelow: Boolean;
|
spaceabove, spacebelow: Boolean;
|
||||||
colindex: Cardinal;
|
colindex: Cardinal;
|
||||||
rowheight: Word;
|
rowheight: Word;
|
||||||
|
h: Single;
|
||||||
begin
|
begin
|
||||||
// Check for additional space above/below row
|
// Check for additional space above/below row
|
||||||
spaceabove := false;
|
spaceabove := false;
|
||||||
@ -1934,10 +1936,14 @@ begin
|
|||||||
AStream.WriteWord(WordToLE(Word(ALastColIndex) + 1));
|
AStream.WriteWord(WordToLE(Word(ALastColIndex) + 1));
|
||||||
|
|
||||||
{ Row height (in twips, 1/20 point) and info on custom row height }
|
{ Row height (in twips, 1/20 point) and info on custom row height }
|
||||||
if (ARow = nil) or (ARow^.Height = 0) then
|
h := Workbook.GetFont(0).Size; // Point size of default font
|
||||||
rowheight := round(Workbook.GetFont(0).Size*20)
|
if (ARow = nil) or (ARow^.Height = Workbook.DefaultRowHeight) then
|
||||||
|
rowheight := PtsToTwips((Workbook.DefaultRowHeight + ROW_HEIGHT_CORRECTION) * h)
|
||||||
else
|
else
|
||||||
rowheight := MillimetersToTwips(ARow^.Height);
|
if (ARow^.Height = 0) then
|
||||||
|
rowheight := 0
|
||||||
|
else
|
||||||
|
rowheight := PtsToTwips((ARow^.Height + ROW_HEIGHT_CORRECTION)*h);
|
||||||
w := rowheight and $7FFF;
|
w := rowheight and $7FFF;
|
||||||
AStream.WriteWord(WordToLE(w));
|
AStream.WriteWord(WordToLE(w));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user