fpspreadsheet: Initial commit with row and column formats. Display in grid seems to work. Reading implemented for biff8 and biff5.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5249 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2016-10-07 13:52:08 +00:00
parent baaf12ebfa
commit e47b907659
4 changed files with 333 additions and 115 deletions

View File

@ -41,32 +41,6 @@ type
TsWorksheet = class; TsWorksheet = class;
TsWorkbook = class; TsWorkbook = class;
{@@ The record TRow contains information about a spreadsheet row:
@param Row The index of the row (beginning with 0)
@param Height The height of the row (expressed in the units defined by
the workbook)
@param RowHeightType Specifies default, automatic or custom row height }
TRow = record
Row: Cardinal;
Height: Single;
RowHeightType: TsRowHeightType;
end;
{@@ Pointer to a TRow record }
PRow = ^TRow;
{@@ The record TCol contains information about a spreadsheet column:
@param Col The index of the column (beginning with 0)
@param Width The width of the column (expressed in the units defined in the workbook)
Only columns with non-default widths have a column record. }
TCol = record
Col: Cardinal;
Width: Single;
end;
{@@ Pointer to a TCol record }
PCol = ^TCol;
{@@ Worksheet user interface options: {@@ Worksheet user interface options:
@param soShowGridLines Show or hide the grid lines in the spreadsheet @param soShowGridLines Show or hide the grid lines in the spreadsheet
@param soShowHeaders Show or hide the column or row headers of the spreadsheet @param soShowHeaders Show or hide the column or row headers of the spreadsheet
@ -200,6 +174,10 @@ type
function GetNumberFormatAttributes(ACell: PCell; out ADecimals: Byte; function GetNumberFormatAttributes(ACell: PCell; out ADecimals: Byte;
out ACurrencySymbol: String): Boolean; out ACurrencySymbol: String): Boolean;
function GetEffectiveCellFormatIndex(ACell: PCell): Integer;
function GetPointerToEffectiveCellFormat(ARow, ACol: Cardinal): PsCellFormat; overload;
function GetPointerToEffectiveCellFormat(ACell: PCell): PsCellFormat; overload;
function ReadUsedFormatting(ACell: PCell): TsUsedFormattingFields; function ReadUsedFormatting(ACell: PCell): TsUsedFormattingFields;
function ReadBackground(ACell: PCell): TsFillPattern; function ReadBackground(ACell: PCell): TsFillPattern;
function ReadBackgroundColor(ACell: PCell): TsColor; function ReadBackgroundColor(ACell: PCell): TsColor;
@ -438,10 +416,12 @@ type
function GetCellCountInRow(ARow: Cardinal): Cardinal; function GetCellCountInRow(ARow: Cardinal): Cardinal;
function GetCellCountInCol(ACol: Cardinal): Cardinal; function GetCellCountInCol(ACol: Cardinal): Cardinal;
function GetRow(ARow: Cardinal): PRow; function GetRow(ARow: Cardinal): PRow;
function GetRowFormatIndex(ARow: Cardinal): Integer;
function GetRowHeight(ARow: Cardinal; AUnits: TsSizeUnits): Single; overload; function GetRowHeight(ARow: Cardinal; AUnits: TsSizeUnits): Single; overload;
function GetRowHeight(ARow: Cardinal): Single; overload; deprecated 'Use version with parameter AUnits.'; function GetRowHeight(ARow: Cardinal): Single; overload; deprecated 'Use version with parameter AUnits.';
function GetRowHeightType(ARow: Cardinal): TsRowHeightType; function GetRowHeightType(ARow: Cardinal): TsRowHeightType;
function GetCol(ACol: Cardinal): PCol; function GetCol(ACol: Cardinal): PCol;
function GetColFormatIndex(ACol: Cardinal): Integer;
function GetColWidth(ACol: Cardinal; AUnits: TsSizeUnits): Single; overload; function GetColWidth(ACol: Cardinal; AUnits: TsSizeUnits): Single; overload;
function GetColWidth(ACol: Cardinal): Single; overload; deprecated 'Use version with parameter AUnits.'; function GetColWidth(ACol: Cardinal): Single; overload; deprecated 'Use version with parameter AUnits.';
procedure DeleteCol(ACol: Cardinal); procedure DeleteCol(ACol: Cardinal);
@ -457,11 +437,13 @@ type
procedure WriteDefaultColWidth(AValue: Single; AUnits: TsSizeUnits); procedure WriteDefaultColWidth(AValue: Single; AUnits: TsSizeUnits);
procedure WriteDefaultRowHeight(AValue: Single; AUnits: TsSizeUnits); procedure WriteDefaultRowHeight(AValue: Single; AUnits: TsSizeUnits);
procedure WriteRowInfo(ARow: Cardinal; AData: TRow); procedure WriteRowInfo(ARow: Cardinal; AData: TRow);
procedure WriteRowFormatIndex(ARow: Cardinal; AFormatIndex: Integer);
procedure WriteRowHeight(ARow: Cardinal; AHeight: Single; AUnits: TsSizeUnits; procedure WriteRowHeight(ARow: Cardinal; AHeight: Single; AUnits: TsSizeUnits;
ARowHeightType: TsRowHeightType = rhtCustom); overload; ARowHeightType: TsRowHeightType = rhtCustom); overload;
procedure WriteRowHeight(ARow: Cardinal; AHeight: Single; procedure WriteRowHeight(ARow: Cardinal; AHeight: Single;
ARowHeightType: TsRowHeightType = rhtCustom); overload; deprecated 'Use version with parameter AUnits'; ARowHeightType: TsRowHeightType = rhtCustom); overload; deprecated 'Use version with parameter AUnits';
procedure WriteColInfo(ACol: Cardinal; AData: TCol); procedure WriteColInfo(ACol: Cardinal; AData: TCol);
procedure WriteColFormatIndex(ACol: Cardinal; AFormatIndex: Integer);
procedure WriteColWidth(ACol: Cardinal; AWidth: Single; AUnits: TsSizeUnits); overload; procedure WriteColWidth(ACol: Cardinal; AWidth: Single; AUnits: TsSizeUnits); overload;
procedure WriteColWidth(ACol: Cardinal; AWidth: Single); overload; deprecated 'Use version with parameter AUnits'; procedure WriteColWidth(ACol: Cardinal; AWidth: Single); overload; deprecated 'Use version with parameter AUnits';
@ -2873,6 +2855,70 @@ begin
end; end;
end; end;
{@@ ----------------------------------------------------------------------------
Returns the index of the effective cell format to be used at the specified
cell.
"Effective" cell format means: At first, look for the cell format.
If it is default, look for the row format. If it is default, look for
the column format. (see "excelfileformat", p. 89)
-------------------------------------------------------------------------------}
function TsWorksheet.GetEffectiveCellFormatIndex(ACell: PCell): Integer;
begin
Result := 0;
if ACell <> nil then
Result := ACell^.FormatIndex;
if Result = 0 then
Result := GetRowFormatIndex(ACell^.Row);
if Result = 0 then
Result := GetColFormatIndex(ACell^.Col);
end;
{@@ ----------------------------------------------------------------------------
Returns a pointer to the effective cell format to be used at the cell in
ARow and ACol.
"Effective" cell format means: At first, look for the cell format.
If it is default, look for the row format. If it is default, look for
the column format. (see "excelfileformat", p. 89)
-------------------------------------------------------------------------------}
function TsWorksheet.GetPointerToEffectiveCellFormat(ARow, ACol: Cardinal): PsCellFormat;
var
cell: PCell;
fmtIndex: Integer;
begin
cell := FindCell(ARow, ACol);
if (cell <> nil) and (cell^.FormatIndex > 0) then
fmtIndex := cell^.FormatIndex
else begin
fmtIndex := GetRowFormatIndex(ARow);
if fmtIndex = 0 then
fmtIndex := GetColFormatIndex(ACol);
end;
Result := FWorkbook.GetPointerToCellFormat(fmtIndex);
end;
{@@ ----------------------------------------------------------------------------
Mainly like GetPointerToEffectiveCellFormat(ARow, ACol), but avoids looking
for the cell if ACell <> nil
-------------------------------------------------------------------------------}
function TsWorksheet.GetPointerToEffectiveCellFormat(ACell: PCell): PsCellFormat;
var
fmtIndex: Integer;
begin
fmtIndex := 0;
if (ACell <> nil) then begin
if (ACell^.FormatIndex > 0) then
fmtIndex := ACell^.FormatIndex
else begin
fmtIndex := GetRowFormatIndex(ACell^.Row);
if fmtIndex = 0 then
fmtIndex := GetColFormatIndex(ACell^.Col);
end;
end;
Result := FWorkbook.GetPointerToCellFormat(fmtIndex);
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Reads the set of used formatting fields of a cell. Reads the set of used formatting fields of a cell.
@ -4545,6 +4591,7 @@ var
isMixed: Boolean; isMixed: Boolean;
rtParams: TsRichTextParams; rtParams: TsRichTextParams;
plain: String; plain: String;
fmtIndex: Integer;
begin begin
if ACell = nil then if ACell = nil then
exit; exit;
@ -4564,8 +4611,10 @@ begin
WriteNumberFormat(ACell, nfText); WriteNumberFormat(ACell, nfText);
end; end;
fmt := Workbook.GetCellFormat(ACell^.FormatIndex); fmtIndex := GetEffectiveCellFormatIndex(ACell);
fmt := Workbook.GetCellFormat(fmtIndex);
numFmtParams := Workbook.GetNumberFormat(fmt.NumberFormatIndex); numFmtParams := Workbook.GetNumberFormat(fmt.NumberFormatIndex);
ACell^.FormatIndex := fmtIndex;
isPercent := Pos('%', AValue) = Length(AValue); isPercent := Pos('%', AValue) = Length(AValue);
if isPercent then Delete(AValue, Length(AValue), 1); if isPercent then Delete(AValue, Length(AValue), 1);
@ -6430,6 +6479,28 @@ begin
end; end;
end; end;
{@@ ----------------------------------------------------------------------------
Returns the index to the cell format to be used for a given column.
If there is no column record then the default format (index 0) is used.
@param ACol Index of the column considered
@return Index of the format into the workbook's FCellFormatList. This format
will be used for formatting a cell if itself does not have a
non-zero format index, and if there is no row format either.
-------------------------------------------------------------------------------}
function TsWorksheet.GetColFormatIndex(ACol: Cardinal): Integer;
var
col: PCol;
begin
Result := 0; // Default format has index 0
if ACol <> UNASSIGNED_ROW_COL_INDEX then
begin
col := FindCol(ACol);
if col <> nil then
Result := col^.FormatIndex
end;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Returns the width of the given column. If there is no column record then Returns the width of the given column. If there is no column record then
the default column width is returned. the default column width is returned.
@ -6460,6 +6531,28 @@ begin
Result := GetColWidth(ACol, suChars); Result := GetColWidth(ACol, suChars);
end; end;
{@@ ----------------------------------------------------------------------------
Returns the index to the cell format to be used for a given row.
If there is no row record then the default format (index 0) is returned.
@param ARow Index of the row considered
@return Index of the format into the workbook's FCellFormatList. This format
will be used for formatting a cell if itself does not have a
non-zero format index.
-------------------------------------------------------------------------------}
function TsWorksheet.GetRowFormatIndex(ARow: Cardinal): Integer;
var
row: PRow;
begin
Result := 0; // Default format has index 0
if ARow <> UNASSIGNED_ROW_COL_INDEX then
begin
row := FindRow(ARow);
if row <> nil then
Result := row^.FormatIndex
end;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Returns the height of the given row. If there is no row record then the Returns the height of the given row. If there is no row record then the
default row height is returned default row height is returned
@ -6905,24 +6998,40 @@ end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Writes a row record for the row at a given index to the spreadsheet. Writes a row record for the row at a given index to the spreadsheet.
Currently the row record contains only the row height (and the row index, The row record contains info on the row height and the row format index.
of course).
Creates a new row record if it does not yet exist. Creates a new row record if it does not yet exist.
@param ARow Index of the row record which will be created or modified @param ARow Index of the row record which will be created or modified
@param AData Data to be written. Expected to be already in the units @param AData Data to be written. Row height expected to be already in the
defined for the workbook units defined for the workbook.
Note that the row height value can be negative to indicate
that this is an auto-calculated value (i.e. the value can
change for example when the font size changes).
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsWorksheet.WriteRowInfo(ARow: Cardinal; AData: TRow); procedure TsWorksheet.WriteRowInfo(ARow: Cardinal; AData: TRow);
var var
AElement: PRow; lRow: PRow;
begin begin
AElement := GetRow(ARow); lRow := GetRow(ARow);
AElement^.Height := AData.Height; lRow^.Height := AData.Height;
lRow^.RowHeightType := AData.RowHeightType;
lRow^.FormatIndex := AData.FormatIndex;
end;
{@@ ----------------------------------------------------------------------------
Sets the cell format index for a specific row.
Creates a new row record if it does not yet exist.
@param ARow Index of the row to be considered
@param AFormatIndex Index into the workbook's FCellFormatList. This format
will be used if a cell has default format index (0).
-------------------------------------------------------------------------------}
procedure TsWorksheet.WriteRowFormatIndex(ARow: Cardinal; AFormatIndex:Integer);
var
lRow: PRow;
begin
if ARow = UNASSIGNED_ROW_COL_INDEX then
exit;
lRow := GetRow(ARow);
lRow^.FormatIndex := AFormatIndex;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -6938,13 +7047,13 @@ end;
procedure TsWorksheet.WriteRowHeight(ARow: Cardinal; AHeight: Single; procedure TsWorksheet.WriteRowHeight(ARow: Cardinal; AHeight: Single;
AUnits: TsSizeUnits; ARowHeightType: TsRowHeightType = rhtCustom); AUnits: TsSizeUnits; ARowHeightType: TsRowHeightType = rhtCustom);
var var
AElement: PRow; lRow: PRow;
begin begin
if ARow = UNASSIGNED_ROW_COL_INDEX then if ARow = UNASSIGNED_ROW_COL_INDEX then
exit; exit;
AElement := GetRow(ARow); lRow := GetRow(ARow);
AElement^.Height := FWorkbook.ConvertUnits(AHeight, AUnits, FWorkbook.FUnits); lRow^.Height := FWorkbook.ConvertUnits(AHeight, AUnits, FWorkbook.FUnits);
AElement^.RowHeightType := ARowHeightType; lRow^.RowHeightType := ARowHeightType;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -6961,22 +7070,42 @@ begin
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Writes a column record for the column at a given index to the spreadsheet. Writes a column record for the column at a specific index to the spreadsheet.
Currently the column record contains only the column width (and the column The column record contains info on the column width and the format index.
index, of course).
Creates a new column record if it does not yet exist. Creates a new column record if it does not yet exist.
@param ACol Index of the column record which will be created or modified @param ACol Index of the column record which will be created or modified
@param AData Data to be written (essentially column width). The column @param AData Data to be written. The column width must already be in
width is already in the units defined for the workbook. the units defined for the workbook.
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsWorksheet.WriteColInfo(ACol: Cardinal; AData: TCol); procedure TsWorksheet.WriteColInfo(ACol: Cardinal; AData: TCol);
var var
AElement: PCol; lCol: PCol;
begin begin
AElement := GetCol(ACol); lCol := GetCol(ACol);
AElement^.Width := AData.Width; lCol^.Width := AData.Width;
lCol^.ColWidthType := AData.ColWidthType;
lCol^.FormatIndex := AData.FormatIndex;
end;
{@@ ----------------------------------------------------------------------------
Sets the cell format index for a specific column.
Creates a new column record if it does not yet exist.
@param ACol Index of the column to be considered
@param AFormatIndex Index into the workbook's FCellFormatList. This format
will be used if a cell has default format index (0) and
if there is no specific default row format.
-------------------------------------------------------------------------------}
procedure TsWorksheet.WriteColFormatIndex(ACol: Cardinal; AFormatIndex:Integer);
var
lCol: PCol;
begin
if ACol = UNASSIGNED_ROW_COL_INDEX then
exit;
lCol := GetCol(ACol);
lCol^.FormatIndex := AFormatIndex;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -6990,12 +7119,12 @@ end;
procedure TsWorksheet.WriteColWidth(ACol: Cardinal; AWidth: Single; procedure TsWorksheet.WriteColWidth(ACol: Cardinal; AWidth: Single;
AUnits: TsSizeUnits); AUnits: TsSizeUnits);
var var
AElement: PCol; lCol: PCol;
begin begin
if ACol = UNASSIGNED_ROW_COL_INDEX then if ACol = UNASSIGNED_ROW_COL_INDEX then
exit; exit;
AElement := GetCol(ACol); lCol := GetCol(ACol);
AElement^.Width := FWorkbook.ConvertUnits(AWidth, AUnits, FWorkbook.FUnits); lCol^.Width := FWorkbook.ConvertUnits(AWidth, AUnits, FWorkbook.FUnits);
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------

View File

@ -498,7 +498,7 @@ type
TsWorksheetGrid = class(TsCustomWorksheetGrid) TsWorksheetGrid = class(TsCustomWorksheetGrid)
published published
// inherited from TsCustomWorksheetGrid // inherited from TsCustomWorksheetGrid
{@@ Automatically recalculates the worksheet if a cell value changes. } {@@ Automatically recalculates the worksheet formulas if a cell value changes. }
property AutoCalc; property AutoCalc;
{@@ Automatically expand grid dimensions } {@@ Automatically expand grid dimensions }
property AutoExpand default [aeData, aeNavigation]; property AutoExpand default [aeData, aeNavigation];
@ -1307,8 +1307,8 @@ begin
if (cell = nil) or not (cell^.ContentType in [cctUTF8String]) then // ... non-label cells if (cell = nil) or not (cell^.ContentType in [cctUTF8String]) then // ... non-label cells
exit; exit;
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
fmt := Worksheet.GetPointerToEffectiveCellFormat(cell);
if (uffWordWrap in fmt^.UsedFormattingFields) then // ... word-wrap if (uffWordWrap in fmt^.UsedFormattingFields) then // ... word-wrap
exit; exit;
if (uffTextRotation in fmt^.UsedFormattingFields) and // ... vertical text if (uffTextRotation in fmt^.UsedFormattingFields) and // ... vertical text
@ -1717,10 +1717,13 @@ begin
r := ARow - FHeaderCount; r := ARow - FHeaderCount;
c := ACol - FHeaderCount; c := ACol - FHeaderCount;
fmt := Worksheet.GetPointerToEffectiveCellFormat(r, c);
lCell := Worksheet.FindCell(r, c); lCell := Worksheet.FindCell(r, c);
if lCell <> nil then
begin //if lCell <> nil then
fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); //begin
// fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex);
// numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); // numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex);
// Background color // Background color
@ -1760,7 +1763,7 @@ begin
end; end;
// Font // Font
if Worksheet.HasHyperlink(lCell) then if (lcell <> nil) and Worksheet.HasHyperlink(lCell) then
fnt := Workbook.GetHyperlinkFont fnt := Workbook.GetHyperlinkFont
else else
fnt := Workbook.GetDefaultFont; fnt := Workbook.GetDefaultFont;
@ -1771,7 +1774,7 @@ begin
Canvas.Font.Height := Round(ZoomFactor * Canvas.Font.Height); Canvas.Font.Height := Round(ZoomFactor * Canvas.Font.Height);
// Wordwrap, text alignment and text rotation are handled by "DrawTextInCell". // Wordwrap, text alignment and text rotation are handled by "DrawTextInCell".
end; //end;
end; end;
if IsSelected then if IsSelected then
@ -1997,7 +2000,8 @@ begin
DrawBorderLine(ARect.Bottom-1, ARect, drawHor, bs); DrawBorderLine(ARect.Bottom-1, ARect, drawHor, bs);
if ACell <> nil then begin if ACell <> nil then begin
fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); fmt := Worksheet.GetPointerToEffectiveCellFormat(ACell);
// fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex);
{ {
if Worksheet.IsMergeBase(ACell) then if Worksheet.IsMergeBase(ACell) then
begin begin
@ -2212,7 +2216,8 @@ begin
then then
Continue; Continue;
// Overflow possible from non-merged, non-right-aligned, horizontal label cells // Overflow possible from non-merged, non-right-aligned, horizontal label cells
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
fmt := Worksheet.GetPointerToEffectiveCellFormat(cell);
if (not Worksheet.IsMerged(cell)) and if (not Worksheet.IsMerged(cell)) and
(cell^.ContentType = cctUTF8String) and (cell^.ContentType = cctUTF8String) and
not (uffTextRotation in fmt^.UsedFormattingFields) and not (uffTextRotation in fmt^.UsedFormattingFields) and
@ -2239,7 +2244,8 @@ begin
then then
continue; continue;
// Overflow possible from non-merged, horizontal, non-left-aligned label cells // Overflow possible from non-merged, horizontal, non-left-aligned label cells
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
fmt := Worksheet.GetPointerToEffectiveCellFormat(cell);
if (not Worksheet.IsMerged(cell)) and if (not Worksheet.IsMerged(cell)) and
(cell^.ContentType = cctUTF8String) and (cell^.ContentType = cctUTF8String) and
not (uffTextRotation in fmt^.UsedFormattingFields) and not (uffTextRotation in fmt^.UsedFormattingFields) and
@ -2496,15 +2502,7 @@ begin
ts.Layout := tlCenter; ts.Layout := tlCenter;
ts.Opaque := false; ts.Opaque := false;
Canvas.TextStyle := ts; Canvas.TextStyle := ts;
{
writeLn('HEADER');
writeln(Format('1 - col=%d, row=%d, font size=%d', [acol, arow, canvas.font.size]));
}
inherited DrawCellText(aCol, aRow, aRect, aState, GetCellText(ACol,ARow)); inherited DrawCellText(aCol, aRow, aRect, aState, GetCellText(ACol,ARow));
{
writeln(GetCellText(ACol, ARow));
writeln(Format('2 - col=%d, row=%d, font size=%d', [acol, arow, canvas.font.size]));
}
exit; exit;
end; end;
@ -2516,7 +2514,8 @@ begin
if txt = '' then if txt = '' then
exit; exit;
fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex);
fmt := Worksheet.GetPointerToEffectiveCellFormat(lCell);
wrapped := (uffWordWrap in fmt^.UsedFormattingFields) or (fmt^.TextRotation = rtStacked); wrapped := (uffWordWrap in fmt^.UsedFormattingFields) or (fmt^.TextRotation = rtStacked);
RTL := IsRightToLeft; RTL := IsRightToLeft;
if (uffBiDi in fmt^.UsedFormattingFields) then if (uffBiDi in fmt^.UsedFormattingFields) then
@ -2702,9 +2701,10 @@ begin
if (Worksheet = nil) or (ACell = nil) then if (Worksheet = nil) or (ACell = nil) then
exit; exit;
fmt := Worksheet.GetPointerToEffectiveCellFormat(ACell);
with ACell^ do with ACell^ do
begin begin
fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex);
if Col > 0 then if Col > 0 then
SetNeighborBorder(Row, Col-1, cbEast, fmt^.BorderStyles[cbWest], cbWest in fmt^.Border); SetNeighborBorder(Row, Col-1, cbEast, fmt^.BorderStyles[cbWest], cbWest in fmt^.Border);
SetNeighborBorder(Row, Col+1, cbWest, fmt^.BorderStyles[cbEast], cbEast in fmt^.Border); SetNeighborBorder(Row, Col+1, cbWest, fmt^.BorderStyles[cbEast], cbEast in fmt^.Border);
@ -3121,7 +3121,8 @@ begin
DoPrepareCanvas(ACol, ARow, []); DoPrepareCanvas(ACol, ARow, []);
fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(lCell^.FormatIndex);
fmt := Worksheet.GetPointerToEffectiveCellFormat(lCell);
if (uffFont in fmt^.UsedFormattingFields) then if (uffFont in fmt^.UsedFormattingFields) then
fntIndex := fmt^.FontIndex else fntIndex := DEFAULT_FONTINDEX; fntIndex := fmt^.FontIndex else fntIndex := DEFAULT_FONTINDEX;
if (uffTextRotation in fmt^.UsedFormattingFields) then if (uffTextRotation in fmt^.UsedFormattingFields) then
@ -4670,7 +4671,8 @@ begin
if (Result = '') or ((ACell <> nil) and (ACell^.ContentType = cctUTF8String)) then if (Result = '') or ((ACell <> nil) and (ACell^.ContentType = cctUTF8String)) then
exit; exit;
fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(ACell^.FormatIndex);
fmt := Worksheet.GetPointerToEffectiveCellFormat(ACell^.Row, ACell^.Col);
isRotated := (fmt^.TextRotation <> trHorizontal); isRotated := (fmt^.TextRotation <> trHorizontal);
isStacked := (fmt^.TextRotation = rtStacked); isStacked := (fmt^.TextRotation = rtStacked);
numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex);
@ -5646,8 +5648,10 @@ begin
// If it is a date/time format write a date/time cell... // If it is a date/time format write a date/time cell...
if cell <> nil then if cell <> nil then
begin begin
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex); // fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
if fmt <> nil then nfp := Workbook.GetNumberFormat(fmt^.NumberFormatIndex); fmt := Worksheet.GetPointerToEffectiveCellFormat(cell);
if fmt <> nil then
nfp := Workbook.GetNumberFormat(fmt^.NumberFormatIndex);
if (fmt <> nil) and IsDateTimeFormat(nfp) then if (fmt <> nil) and IsDateTimeFormat(nfp) then
Worksheet.WriteDateTime(r, c, VarToDateTime(AValue)) else Worksheet.WriteDateTime(r, c, VarToDateTime(AValue)) else
Worksheet.WriteNumber(r, c, AValue); Worksheet.WriteNumber(r, c, AValue);

View File

@ -674,7 +674,7 @@ type
Worksheet: Pointer; // Must be cast to TsWorksheet when used (avoids circular unit reference) Worksheet: Pointer; // Must be cast to TsWorksheet when used (avoids circular unit reference)
{ Status flags } { Status flags }
Flags: TsCellFlags; Flags: TsCellFlags;
{ Index of format record in the workbook's FCellFormatList } { Index of format record in the workbook's CellFormatList }
FormatIndex: Integer; FormatIndex: Integer;
{ Cell content } { Cell content }
UTF8StringValue: String; // Strings cannot be part of a variant record UTF8StringValue: String; // Strings cannot be part of a variant record
@ -693,6 +693,57 @@ type
{@@ Pointer to a TCell record } {@@ Pointer to a TCell record }
PCell = ^TCell; PCell = ^TCell;
{@@ Types of row heights
rhtDefault - default row height
rhtAuto - automatically determined row height, depends on font size,
text rotation, rich-text parameters, word-wrap
rhtCustom - user-determined row height (dragging the row header borders in
the grid, or changed by code) }
TsRowHeightType = (rhtDefault, rhtCustom, rhtAuto);
{@@ Types of column widths
cwtDefault - default column width
cwtCustom - userdefined column width (dragging the column header border
in the grid, or by changed by code) }
TsColWidthtype = (cwtDefault, cwtCustom);
{@@ The record TRow contains information about a spreadsheet row:
@param Row The index of the row (beginning with 0)
@param Height The height of the row (expressed in the units defined
by the workbook)
@param RowHeightType Specifies whether the row has default, custom, or
automatic height
@param FormatIndex Row default format, index into the workbook's
FCellFormatList
Only rows with non-default height or non-default format have a row record. }
TRow = record
Row: Cardinal;
Height: Single;
RowHeightType: TsRowHeightType;
FormatIndex: Integer;
end;
{@@ Pointer to a TRow record }
PRow = ^TRow;
{@@ The record TCol contains information about a spreadsheet column:
@param Col The index of the column (beginning with 0)
@param Width The width of the column (expressed in the units defined
in the workbook)
@param ColWidthType Specifies whether the column has default or custom width
@param FormatIndex Column default format, index into the workbook's
FCellFormatlist
Only columns with non-default width or non-default format have a column record. }
TCol = record
Col: Cardinal;
Width: Single;
ColWidthType: TsColWidthType;
FormatIndex: Integer;
end;
{@@ Pointer to a TCol record }
PCol = ^TCol;
{@@ Embedded image } {@@ Embedded image }
TsImage = record TsImage = record
Row, Col: Cardinal; // cell for top/left edge of the image (anchor) Row, Col: Cardinal; // cell for top/left edge of the image (anchor)
@ -725,15 +776,6 @@ type
{@@ Array with all possible images in a header or a footer } {@@ Array with all possible images in a header or a footer }
TsHeaderFooterImages = array[TsHeaderFooterSectionIndex] of TsHeaderFooterImage; TsHeaderFooterImages = array[TsHeaderFooterSectionIndex] of TsHeaderFooterImage;
const
{@@ Indexes to be used for the various headers and footers }
HEADER_FOOTER_INDEX_FIRST = 0;
HEADER_FOOTER_INDEX_ODD = 1;
HEADER_FOOTER_INDEX_EVEN = 2;
HEADER_FOOTER_INDEX_ALL = 1;
type
{@@ Search option } {@@ Search option }
TsSearchOption = (soCompareEntireCell, soMatchCase, soRegularExpr, soAlongRows, TsSearchOption = (soCompareEntireCell, soMatchCase, soRegularExpr, soAlongRows,
soBackward, soWrapDocument, soEntireDocument); soBackward, soWrapDocument, soEntireDocument);
@ -770,18 +812,18 @@ type
TsStreamParam = (spClipboard, spWindowsClipboardHTML); TsStreamParam = (spClipboard, spWindowsClipboardHTML);
TsStreamParams = set of TsStreamParam; TsStreamParams = set of TsStreamParam;
{@@ Types of row heights
rhtDefault - default row height
rhtAuto - automatically determined row height, depends on font size,
text rotation, rich-text parameters, word-wrap
rhtCustom - user-determined row height (dragging the row header borders in
the grid }
TsRowHeightType = (rhtDefault, rhtAuto, rhtCustom);
const const
RowHeightTypeNames: array[TsRowHeightType] of string = ( RowHeightTypeNames: array[TsRowHeightType] of string = (
'Default', 'Auto', 'Custom'); 'Default', 'Auto', 'Custom');
ColWidthTypeNames: array[TsColWidthType] of string = (
'Default', 'Custom');
{@@ Indexes to be used for the various headers and footers }
HEADER_FOOTER_INDEX_FIRST = 0;
HEADER_FOOTER_INDEX_ODD = 1;
HEADER_FOOTER_INDEX_EVEN = 2;
HEADER_FOOTER_INDEX_ALL = 1;
implementation implementation

View File

@ -386,6 +386,7 @@ type
procedure AddBuiltinNumFormats; override; procedure AddBuiltinNumFormats; override;
procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual; procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual;
(* (*
procedure ApplyRichTextFormattingRuns(ACell: PCell; procedure ApplyRichTextFormattingRuns(ACell: PCell;
ARuns: TsRichTextFormattingRuns); ARuns: TsRichTextFormattingRuns);
@ -1001,6 +1002,7 @@ begin
ACell^.FormatIndex := 0; ACell^.FormatIndex := 0;
end; end;
end; end;
(* (*
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Converts the rich-text formatting run data as read from the file to the Converts the rich-text formatting run data as read from the file to the
@ -1401,19 +1403,37 @@ const
var var
c, c1, c2: Cardinal; c, c1, c2: Cardinal;
w: Word; w: Word;
colwidth: Double; xf: Word;
lCol: TCol;
idx: Integer;
fmt: PsCellFormat;
begin begin
// read column start and end index of column range { Read column start and end index of column range }
c1 := WordLEToN(AStream.ReadWord); c1 := WordLEToN(AStream.ReadWord);
c2 := WordLEToN(AStream.ReadWord); c2 := WordLEToN(AStream.ReadWord);
// read col width in 1/256 of the width of "0" character
{ Read col width in 1/256 of the width of "0" character }
w := WordLEToN(AStream.ReadWord); w := WordLEToN(AStream.ReadWord);
// calculate width in workbook units
colwidth := FWorkbook.ConvertUnits(w / 256, suChars, FWorkbook.Units); { Calculate width in workbook units }
// assign width to columns, but only if different from default column width lCol.Width := FWorkbook.ConvertUnits(w / 256, suChars, FWorkbook.Units);
if not SameValue(colwidth, FWorksheet.ReadDefaultColWidth(FWorkbook.Units), EPS) then if SameValue(lCol.Width, FWorksheet.ReadDefaultColWidth(FWorkbook.Units), EPS) then
lCol.ColWidthType := cwtDefault else
lCol.ColWidthType := cwtCustom;
{ Read xf record index }
xf := WordLEToN(AStream.ReadWord);
idx := FCellFormatList.FindIndexOfID(xf);
if idx > -1 then begin
fmt := FCellFormatList.Items[idx];
lCol.FormatIndex := FWorkbook.AddCellFormat(fmt^);
end else
lCol.FormatIndex := 0;
{ Assign width and format to columns, but only if different from defaults }
if (lCol.FormatIndex > 0) or (lCol.ColWidthType = cwtCustom) then
for c := c1 to c2 do for c := c1 to c2 do
FWorksheet.WriteColWidth(c, colwidth, FWorkbook.Units); FWorksheet.WriteColInfo(c, lCol);
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -2086,33 +2106,56 @@ type
end; end;
var var
rowrec: TRowRecord; rowrec: TRowRecord;
lRow: PRow; lRow: TRow;
h: word; h: word;
hpts: Single; hpts: Single;
hdef: Single; hdef: Single;
isNonDefaultHeight: Boolean; isNonDefaultHeight: Boolean;
isAutoSizeHeight: Boolean; isAutoSizeHeight: Boolean;
hasFormat: Boolean;
flags: DWord;
xf: Word;
idx: Integer;
fmt: PsCellFormat;
begin begin
rowrec.RowIndex := 0; // to silence the compiler... rowrec.RowIndex := 0; // to silence the compiler...
AStream.ReadBuffer(rowrec, SizeOf(TRowRecord)); AStream.ReadBuffer(rowrec, SizeOf(TRowRecord));
rowrec.RowIndex := WordLEToN(rowrec.RowIndex);
flags := DWordLEToN(rowrec.Flags);
{ Row height }
h := WordLEToN(rowrec.Height) and $7FFF; // mask off "custom" bit h := WordLEToN(rowrec.Height) and $7FFF; // mask off "custom" bit
hpts := FWorkbook.ConvertUnits(TwipsToPts(h), suPoints, FWorkbook.Units); hpts := FWorkbook.ConvertUnits(TwipsToPts(h), suPoints, FWorkbook.Units);
hdef := FWorksheet.ReadDefaultRowHeight(FWorkbook.Units); hdef := FWorksheet.ReadDefaultRowHeight(FWorkbook.Units);
isNonDefaultHeight := not SameValue(hpts, hdef, ROWHEIGHT_EPS); isNonDefaultHeight := not SameValue(hpts, hdef, ROWHEIGHT_EPS);
isAutoSizeHeight := WordLEToN(rowrec.Flags) and $00000040 = 0; isAutoSizeHeight := flags and $00000040 = 0;
// If this bis is set then font size and row height do NOT match, i.e. NO autosize // If this bit is set then font size and row height do NOT match, i.e. NO autosize
if isAutoSizeHeight then
lRow.RowHeightType := rhtAuto else
lRow.RowHeightType := rhtCustom;
lRow.Height := hpts;
{ Row format }
lRow.FormatIndex := 0;
hasFormat := flags and $00000080 <> 0;
// If this bit is set then the record contains an xf index.
if hasFormat then begin
xf := (flags and $0FFF0000) shr 16;
if xf = 15 then hasFormat := false;
end;
if hasFormat then begin
// Find the format with ID xf
idx := FCellFormatList.FindIndexOfID(xf);
if idx > -1 then begin
fmt := FCellFormatList.Items[idx];
lRow.FormatIndex := FWorkbook.AddCellFormat(fmt^);
end;
end;
// We only create a row record for fpspreadsheet if the row has a // We only create a row record for fpspreadsheet if the row has a
// non-standard height (i.e. different from default row height). // non-standard height (i.e. different from default row height) or format.
if isNonDefaultHeight then begin if isNonDefaultHeight or hasFormat then
lRow := FWorksheet.GetRow(WordLEToN(rowrec.RowIndex)); FWorksheet.WriteRowInfo(rowrec.RowIndex, lRow);
if isAutoSizeHeight then
lRow^.RowHeightType := rhtAuto else
lRow^.RowHeightType := rhtCustom;
lRow^.Height := hpts;
end;
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------