You've already forked lazarus-ccr
fpspreadsheet: Heavy refactoring of ods row & cell reading. Intention is to read row and column formats, not 100% correct yet.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5260 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -97,17 +97,21 @@ type
|
||||
FRepeatedCols: TsRowColRange;
|
||||
FRepeatedRows: TsRowColRange;
|
||||
procedure ApplyColWidths;
|
||||
procedure ApplyStyleToCell(ACell: PCell; AStyleIndex: Integer);
|
||||
function ApplyStyleToCell(ACell: PCell; AStyleName: String): Boolean;
|
||||
function ApplyTableStyle(ASheet: TsWorksheet; AStyleName: String): Boolean;
|
||||
function ExtractBoolFromNode(ANode: TDOMNode): Boolean;
|
||||
function ExtractDateTimeFromNode(ANode: TDOMNode;
|
||||
ANumFormat: TsNumberFormat; const AFormatStr: String): TDateTime;
|
||||
function ExtractErrorFromNode(ANode: TDOMNode; out AErrorValue: TsErrorValue): Boolean;
|
||||
function ExtractFormatIndexFromStyle(ACellStyleName: String; ACol: Integer): Integer;
|
||||
function FindColumnByCol(AColIndex: Integer): Integer;
|
||||
function FindColStyleByName(AStyleName: String): integer;
|
||||
function FindNumFormatByName(ANumFmtName: String): Integer;
|
||||
function FindRowStyleByName(AStyleName: String): Integer;
|
||||
function FindTableStyleByName(AStyleName: String): Integer;
|
||||
procedure ReadCell(ANode: TDOMNode; ARow, ACol: Integer;
|
||||
AFormatIndex: Integer; out AColsRepeated: Integer);
|
||||
procedure ReadColumns(ATableNode: TDOMNode);
|
||||
procedure ReadColumnStyle(AStyleNode: TDOMNode);
|
||||
procedure ReadDateMode(SpreadSheetNode: TDOMNode);
|
||||
@ -138,14 +142,21 @@ type
|
||||
procedure ReadSettings(AOfficeSettingsNode: TDOMNode);
|
||||
procedure ReadStyles(AStylesNode: TDOMNode);
|
||||
{ Record writing methods }
|
||||
procedure ReadBlank(ARow, ACol: Cardinal; ACellNode: TDOMNode); reintroduce;
|
||||
procedure ReadBoolean(ARow, ACol: Cardinal; ACellNode: TDOMNode);
|
||||
procedure ReadBlank(ARow, ACol: Cardinal;
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode); reintroduce;
|
||||
procedure ReadBoolean(ARow, ACol: Cardinal;
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
procedure ReadComment(ARow, ACol: Cardinal; ACellNode: TDOMNode);
|
||||
procedure ReadDateTime(ARow, ACol: Cardinal; ACellNode: TDOMNode);
|
||||
procedure ReadError(ARow, ACol: Cardinal; ACellNode: TDOMNode);
|
||||
procedure ReadFormula(ARow, ACol: Cardinal; ACellNode: TDOMNode); reintroduce;
|
||||
procedure ReadLabel(ARow, ACol: Cardinal; ACellNode: TDOMNode); reintroduce;
|
||||
procedure ReadNumber(ARow, ACol: Cardinal; ACellNode: TDOMNode); reintroduce;
|
||||
procedure ReadDateTime(ARow, ACol: Cardinal;
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
procedure ReadError(ARow, ACol: Cardinal; AStyleIndex: Integer;
|
||||
ACellNode: TDOMNode);
|
||||
procedure ReadFormula(ARow, ACol: Cardinal; AstyleIndex: Integer;
|
||||
ACellNode: TDOMNode); reintroduce;
|
||||
procedure ReadLabel(ARow, ACol: Cardinal; AStyleIndex: Integer;
|
||||
ACellNode: TDOMNode); reintroduce;
|
||||
procedure ReadNumber(ARow, ACol: Cardinal; AStyleIndex: Integer;
|
||||
ACellNode: TDOMNode); reintroduce;
|
||||
|
||||
public
|
||||
constructor Create(AWorkbook: TsWorkbook); override;
|
||||
@ -958,6 +969,10 @@ constructor TsSpreadOpenDocReader.Create(AWorkbook: TsWorkbook);
|
||||
begin
|
||||
inherited Create(AWorkbook);
|
||||
|
||||
// http://en.wikipedia.org/wiki/List_of_spreadsheet_software#Specifications
|
||||
FLimitations.MaxColCount := 1024;
|
||||
FLimitations.MaxRowCount := 1048576;
|
||||
|
||||
FPointSeparatorSettings := DefaultFormatSettings;
|
||||
FPointSeparatorSettings.DecimalSeparator := '.';
|
||||
FPointSeparatorSettings.ListSeparator := ';'; // for formulas
|
||||
@ -1030,46 +1045,103 @@ end;
|
||||
procedure TsSpreadOpenDocReader.ApplyColWidths;
|
||||
var
|
||||
colIndex: Integer;
|
||||
colData: TColumnData;
|
||||
colStyleIndex: Integer;
|
||||
colStyle: TColumnStyleData;
|
||||
i: Integer;
|
||||
u: TsSizeUnits;
|
||||
defColWidth: Single;
|
||||
colWidth: Single;
|
||||
colWidthType: TsColWidthType;
|
||||
lastOccCol: Integer;
|
||||
begin
|
||||
u := FWorkbook.Units;
|
||||
defColWidth := FWorksheet.ReadDefaultColWidth(u);
|
||||
defColWidth := FWorksheet.ReadDefaultColWidth(FWorkbook.Units);
|
||||
lastOccCol := FWorksheet.GetLastOccupiedColIndex;
|
||||
for i:=0 to FColumnList.Count-1 do
|
||||
begin
|
||||
colIndex := TColumnData(FColumnList[i]).Col;
|
||||
colData := TColumnData(FColumnList[i]);
|
||||
colIndex := colData.Col;
|
||||
|
||||
// Skip column records beyond the last data column - there's a bug in OO/LO
|
||||
// which adds column records up to the max column limit.
|
||||
if colIndex > lastOccCol then
|
||||
Continue;
|
||||
colStyleIndex := TColumnData(FColumnList[i]).ColStyleIndex;
|
||||
|
||||
colStyleIndex := colData.ColStyleIndex;
|
||||
colStyle := TColumnStyleData(FColumnStyleList[colStyleIndex]);
|
||||
// Add only column records to the worksheet if their width is different from
|
||||
// the default column width. The column width stored in colStyle is already
|
||||
// in workbook units (see ReadColumnStyles).
|
||||
if not SameValue(colStyle.ColWidth, defColWidth, COLWIDTH_EPS) then
|
||||
FWorksheet.WriteColWidth(colIndex, colStyle.ColWidth, u);
|
||||
//defCellStyleIndex := colData.DefaultCellStyleIndex;
|
||||
{
|
||||
// Get column format
|
||||
fmt := FCellFormatList.Items[defCellStyleIndex];
|
||||
if fmt <> nil then
|
||||
fmtIndex := FWorkbook.AddCellFormat(fmt^)
|
||||
else
|
||||
fmtIndex := 0;
|
||||
}
|
||||
// Prepare column record for the worksheet
|
||||
colWidth := colStyle.ColWidth; // is already in workbook units
|
||||
if SameValue(colWidth, defColWidth, COLWIDTH_EPS) then
|
||||
colWidthType := cwtDefault
|
||||
else
|
||||
colWidthType := cwtCustom;
|
||||
|
||||
// Write non-default column width to the worksheet
|
||||
if (colWidthType = cwtCustom) then
|
||||
FWorksheet.WriteColWidth(colIndex, colWidth, FWorkbook.Units);
|
||||
|
||||
// Note: we don't store the column format index here; this is done in the
|
||||
// row/cell reading method (ReadRowsAndCells).
|
||||
end;
|
||||
end;
|
||||
|
||||
function TsSpreadOpenDocReader.ExtractFormatIndexFromStyle(ACellStyleName: String;
|
||||
ACol: Integer): Integer;
|
||||
var
|
||||
idx: Integer;
|
||||
begin
|
||||
Result := -1;
|
||||
if ACellStyleName <> '' then
|
||||
Result := FCellFormatList.FindIndexOfName(ACellStyleName);
|
||||
if Result = -1 then begin
|
||||
idx := FindColumnByCol(ACol);
|
||||
if idx > -1 then
|
||||
Result := TColumnData(FColumnList[idx]).DefaultCellStyleIndex;
|
||||
end;
|
||||
if Result = -1 then
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
|
||||
procedure TsSpreadOpenDocReader.ApplyStyleToCell(ACell: PCell; AStyleIndex: Integer);
|
||||
var
|
||||
fmt: TsCellFormat;
|
||||
begin
|
||||
if FWorksheet.HasHyperlink(ACell) then
|
||||
FWorksheet.WriteFont(ACell, HYPERLINK_FONTINDEX);
|
||||
|
||||
fmt := FCellFormatList.Items[AStyleIndex]^;
|
||||
if (AStyleIndex = 0) and FWorksheet.HasHyperlink(ACell) then begin
|
||||
// Make sure to use hyperlink font for hyperlink cells in case of default cell style
|
||||
fmt.FontIndex := HYPERLINK_FONTINDEX;
|
||||
Include(fmt.UsedFormattingFields, uffFont);
|
||||
end;
|
||||
ACell^.FormatIndex := FWorkbook.AddCellFormat(fmt);
|
||||
end;
|
||||
|
||||
{ Applies the style data referred to by the style name to the specified cell
|
||||
The function result is false if a style with the given name could not be found }
|
||||
function TsSpreadOpenDocReader.ApplyStyleToCell(ACell: PCell; AStyleName: String): Boolean;
|
||||
var
|
||||
fmt: TsCellFormat;
|
||||
styleIndex: Integer;
|
||||
i: Integer;
|
||||
//i: Integer;
|
||||
begin
|
||||
Result := false;
|
||||
|
||||
if FWorksheet.HasHyperlink(ACell) then
|
||||
FWorksheet.WriteFont(ACell, HYPERLINK_FONTINDEX);
|
||||
|
||||
styleIndex := ExtractFormatIndexFromStyle(AStyleName, ACell^.Col);
|
||||
(*
|
||||
// Is there a style attached to the cell?
|
||||
styleIndex := -1;
|
||||
if AStyleName <> '' then
|
||||
@ -1083,6 +1155,8 @@ begin
|
||||
exit;
|
||||
styleIndex := TColumnData(FColumnList[i]).DefaultCellStyleIndex;
|
||||
end;
|
||||
*)
|
||||
|
||||
fmt := FCellFormatList.Items[styleIndex]^;
|
||||
if (styleIndex = 0) and FWorksheet.HasHyperlink(ACell) then
|
||||
begin
|
||||
@ -1672,22 +1746,27 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadBlank(ARow, ACol: Cardinal;
|
||||
ACellNode: TDOMNode);
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
var
|
||||
styleName: String;
|
||||
// styleName: String;
|
||||
cell: PCell;
|
||||
lCell: TCell;
|
||||
// lCell: TCell;
|
||||
begin
|
||||
// No need to store a record for an empty, unformatted cell
|
||||
if AStyleIndex = 0 then
|
||||
exit;
|
||||
|
||||
(*
|
||||
// a temporary cell record to store the formatting if there is any
|
||||
lCell.Row := ARow; // to silence a compiler warning...
|
||||
InitCell(ARow, ACol, lCell);
|
||||
lCell.ContentType := cctEmpty;
|
||||
|
||||
lCell
|
||||
styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
if not ApplyStyleToCell(@lCell, stylename) then
|
||||
exit;
|
||||
// No need to store a record for an empty, unformatted cell
|
||||
|
||||
*)
|
||||
if FIsVirtualMode then
|
||||
begin
|
||||
InitCell(ARow, ACol, FVirtualCell);
|
||||
@ -1695,16 +1774,17 @@ begin
|
||||
end else
|
||||
cell := FWorksheet.AddCell(ARow, ACol);
|
||||
FWorkSheet.WriteBlank(cell);
|
||||
FWorksheet.CopyFormat(@lCell, cell);
|
||||
ApplyStyleToCell(cell, AStyleIndex);
|
||||
// FWorksheet.CopyFormat(@lCell, cell);
|
||||
|
||||
if FIsVirtualMode then
|
||||
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadBoolean(ARow, ACol: Cardinal;
|
||||
ACellNode: TDOMNode);
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
var
|
||||
styleName: String;
|
||||
// styleName: String;
|
||||
cell: PCell;
|
||||
boolValue: Boolean;
|
||||
begin
|
||||
@ -1718,9 +1798,11 @@ begin
|
||||
boolValue := ExtractBoolFromNode(ACellNode);
|
||||
FWorkSheet.WriteBoolValue(cell, boolValue);
|
||||
|
||||
ApplyStyleToCell(cell, AStyleIndex);
|
||||
{
|
||||
styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
ApplyStyleToCell(cell, stylename);
|
||||
|
||||
}
|
||||
if FIsVirtualMode then
|
||||
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
|
||||
end;
|
||||
@ -1758,13 +1840,14 @@ var
|
||||
colData.DefaultCellStyleIndex := defCellStyleIndex;
|
||||
FColumnList.Add(colData);
|
||||
end;
|
||||
|
||||
s := GetAttrValue(AColNode, 'table:number-columns-repeated');
|
||||
if s = '' then
|
||||
inc(col)
|
||||
else
|
||||
begin
|
||||
colsRepeated := StrToInt(s);
|
||||
if defCellStyleIndex > -1 then
|
||||
if defCellStyleIndex > -1 then begin
|
||||
for j:=1 to colsRepeated-1 do
|
||||
begin
|
||||
colData := TColumnData.Create;
|
||||
@ -1773,6 +1856,7 @@ var
|
||||
colData.DefaultCellStyleIndex := defCellStyleIndex;
|
||||
FColumnList.Add(colData);
|
||||
end;
|
||||
end;
|
||||
inc(col, colsRepeated);
|
||||
end;
|
||||
end;
|
||||
@ -1896,10 +1980,10 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadDateTime(ARow, ACol: Cardinal;
|
||||
ACellNode : TDOMNode);
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
var
|
||||
dt: TDateTime;
|
||||
styleName: String;
|
||||
// styleName: String;
|
||||
cell: PCell;
|
||||
fmt: PsCellFormat;
|
||||
begin
|
||||
@ -1910,8 +1994,9 @@ begin
|
||||
end else
|
||||
cell := FWorksheet.AddCell(ARow, ACol);
|
||||
|
||||
styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
ApplyStyleToCell(cell, stylename);
|
||||
ApplyStyleToCell(cell, AStyleIndex);
|
||||
//styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
//ApplyStyleToCell(cell, stylename);
|
||||
fmt := FWorkbook.GetPointerToCellFormat(cell^.FormatIndex);;
|
||||
|
||||
dt := ExtractDateTimeFromNode(ACellNode, fmt^.NumberFormat, fmt^.NumberFormatStr);
|
||||
@ -1922,9 +2007,9 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadError(ARow, ACol: Cardinal;
|
||||
ACellNode: TDOMNode);
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
var
|
||||
styleName: String;
|
||||
//styleName: String;
|
||||
cell: PCell;
|
||||
errValue: TsErrorValue;
|
||||
begin
|
||||
@ -1939,8 +2024,11 @@ begin
|
||||
FWorkSheet.WriteErrorValue(cell, errValue) else
|
||||
FWorksheet.WriteText(cell, 'ERROR');
|
||||
|
||||
ApplyStyleToCell(cell, AStyleIndex);
|
||||
{
|
||||
styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
ApplyStyleToCell(cell, stylename);
|
||||
}
|
||||
|
||||
if FIsVirtualMode then
|
||||
Workbook.OnReadCellData(Workbook, ARow, ACol, cell);
|
||||
@ -2152,11 +2240,11 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadFormula(ARow, ACol: Cardinal;
|
||||
ACellNode : TDOMNode);
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
var
|
||||
cell: PCell;
|
||||
formula: String;
|
||||
stylename: String;
|
||||
// stylename: String;
|
||||
floatValue: Double;
|
||||
boolValue: Boolean;
|
||||
errorValue: TsErrorValue;
|
||||
@ -2175,8 +2263,11 @@ begin
|
||||
end else
|
||||
cell := FWorksheet.GetCell(ARow, ACol); // Don't use AddCell here
|
||||
|
||||
ApplyStyleToCell(cell, AStyleIndex);
|
||||
{
|
||||
styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
ApplyStyleToCell(cell, stylename);
|
||||
}
|
||||
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
|
||||
|
||||
formula := '';
|
||||
@ -2464,7 +2555,7 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadLabel(ARow, ACol: Cardinal;
|
||||
ACellNode: TDOMNode);
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
var
|
||||
cellText, spanText: String;
|
||||
styleName: String;
|
||||
@ -2497,8 +2588,11 @@ begin
|
||||
|
||||
// Apply style to cell
|
||||
// We do this already here because we need the cell font for rich-text
|
||||
ApplyStyleToCell(cell, AStyleIndex);
|
||||
{
|
||||
styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
ApplyStyleToCell(cell, stylename);
|
||||
}
|
||||
fmt := FWorkbook.GetPointerToCellFormat(cell^.FormatIndex);
|
||||
fntIndex := fmt^.FontIndex;
|
||||
fnt := FWorkbook.GetFont(fntIndex);
|
||||
@ -2590,11 +2684,11 @@ begin
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadNumber(ARow, ACol: Cardinal;
|
||||
ACellNode : TDOMNode);
|
||||
AStyleIndex: Integer; ACellNode: TDOMNode);
|
||||
var
|
||||
Value, Str: String;
|
||||
lNumber: Double;
|
||||
styleName: String;
|
||||
// styleName: String;
|
||||
cell: PCell;
|
||||
fmt: PsCellFormat;
|
||||
numFmt: TsNumFormatParams;
|
||||
@ -2613,13 +2707,16 @@ begin
|
||||
else
|
||||
begin
|
||||
// Don't merge, or else we can't debug
|
||||
Str := GetAttrValue(ACellNode,'office:value');
|
||||
Str := GetAttrValue(ACellNode, 'office:value');
|
||||
lNumber := StrToFloat(Str, FPointSeparatorSettings);
|
||||
FWorkSheet.WriteNumber(cell, lNumber);
|
||||
end;
|
||||
|
||||
ApplyStyleToCell(cell, AStyleIndex);
|
||||
{
|
||||
styleName := GetAttrValue(ACellNode, 'table:style-name');
|
||||
ApplyStyleToCell(cell, stylename);
|
||||
}
|
||||
fmt := Workbook.GetPointerToCellFormat(cell^.FormatIndex);
|
||||
numFmt := Workbook.GetNumberFormat(fmt^.NumberFormatIndex);
|
||||
|
||||
@ -3233,6 +3330,82 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadCell(ANode: TDOMNode; ARow, ACol: Integer;
|
||||
AFormatIndex: Integer; out AColsRepeated: Integer);
|
||||
var
|
||||
paramValueType, paramFormula: String;
|
||||
s: String;
|
||||
colsSpanned, rowsSpanned: Integer;
|
||||
begin
|
||||
// select this cell value's type
|
||||
paramValueType := GetAttrValue(ANode, 'office:value-type');
|
||||
paramFormula := GetAttrValue(ANode, 'table:formula');
|
||||
|
||||
if paramFormula <> '' then
|
||||
ReadFormula(ARow, ACol, AFormatIndex, ANode)
|
||||
else
|
||||
begin
|
||||
if paramValueType = 'string' then
|
||||
ReadLabel(ARow, ACol, AFormatIndex, ANode)
|
||||
else
|
||||
if (paramValueType = 'float') or
|
||||
(paramValueType = 'percentage') or
|
||||
(paramValueType = 'currency')
|
||||
then
|
||||
ReadNumber(ARow, ACol, AFormatIndex, ANode)
|
||||
else if (paramValueType = 'date') or (paramValueType = 'time') then
|
||||
ReadDateTime(ARow, ACol, AFormatIndex, ANode)
|
||||
else if (paramValueType = 'boolean') then
|
||||
ReadBoolean(ARow, ACol, AFormatIndex, ANode)
|
||||
else
|
||||
if (paramValueType = '') and (AFormatIndex > 0) and
|
||||
(ARow < FLimitations.MaxRowCount-10) and
|
||||
(ACol < FLimitations.MaxColCount-10)
|
||||
then
|
||||
ReadBlank(ARow, ACol, AFormatIndex, ANode);
|
||||
{ NOTE 1: Empty cells having no cell format, but a column format only,
|
||||
are skipped here. --> Currently the reader does not detect the format
|
||||
of empty cells correctly.
|
||||
It would work if the "(cellStyleName <> '')" would be omitted, but // <--- wp: still up-to-date?
|
||||
then the reader would create a record for all 1E9 cells prepared by
|
||||
the Excel2007 export --> crash!
|
||||
The column format is available in the FColumnList, but since the usage
|
||||
of colsSpanned in the row it is possible to miss the correct column format.
|
||||
Pretty nasty situation!
|
||||
|
||||
NOTE 2: Sometimes, ods files have an additional empty cell at the end
|
||||
of the spreadsheet range. Adding a cell to the worksheet here would
|
||||
extend the sheet range unrealistically, and, if using the WorksheetGrid,
|
||||
would add unnecessary rows/columns to the grid. --> Check against
|
||||
FLimitations.MaxRowCount/MaxColCount; use some spare values because I
|
||||
don't understand this mechanism of ods at all }
|
||||
end;
|
||||
|
||||
// Read cell comment
|
||||
ReadComment(ARow, ACol, ANode);
|
||||
|
||||
s := GetAttrValue(ANode, 'table:number-columns-spanned');
|
||||
if s <> '' then
|
||||
colsSpanned := StrToInt(s) - 1
|
||||
else
|
||||
colsSpanned := 0;
|
||||
|
||||
s := GetAttrValue(ANode, 'table:number-rows-spanned');
|
||||
if s <> '' then
|
||||
rowsSpanned := StrToInt(s) - 1
|
||||
else
|
||||
rowsSpanned := 0;
|
||||
|
||||
if (colsSpanned <> 0) or (rowsSpanned <> 0) then
|
||||
FWorksheet.MergeCells(ARow, ACol, ARow + rowsSpanned, ACol + colsSpanned);
|
||||
|
||||
s := GetAttrValue(ANode, 'table:number-columns-repeated');
|
||||
if s <> '' then
|
||||
AColsRepeated := StrToInt(s)
|
||||
else
|
||||
AColsRepeated := 1;
|
||||
end;
|
||||
|
||||
{ Reads the cells in the given table. Loops through all rows, and then finds all
|
||||
cells of each row. }
|
||||
procedure TsSpreadOpenDocReader.ReadRowsAndCells(ATableNode: TDOMNode);
|
||||
@ -3241,8 +3414,10 @@ var
|
||||
rowNode, childnode: TDOMNode;
|
||||
nodeName: String;
|
||||
rowsRepeated: Integer;
|
||||
colFmt: array of Integer;
|
||||
isFirstRow: Boolean;
|
||||
|
||||
procedure ProcessRow(ARowNode: TDOMNode);
|
||||
procedure ProcessRow(ARowNode: TDOMNode; GetRowFormat: Boolean);
|
||||
var
|
||||
rowStyleName: String;
|
||||
rowStyleIndex: Integer;
|
||||
@ -3252,13 +3427,16 @@ var
|
||||
col: Integer;
|
||||
cellNode: TDOMNode;
|
||||
nodeName: String;
|
||||
lRow: PRow;
|
||||
cellRecord: TCell;
|
||||
cell: PCell;
|
||||
paramValueType, paramFormula, tableStyleName: String;
|
||||
paramColsSpanned, paramRowsSpanned: String;
|
||||
paramColsRepeated, paramRowsRepeated: String;
|
||||
rowsSpanned: Integer;
|
||||
colsSpanned: Integer;
|
||||
i, n: Integer;
|
||||
cellStyleName: String;
|
||||
s: String;
|
||||
colsRepeated: Integer;
|
||||
i: Integer;
|
||||
hasRowFormat: Boolean;
|
||||
styleIndex: Integer;
|
||||
firstStyleIndex: Integer;
|
||||
begin
|
||||
// Read rowstyle
|
||||
rowStyleName := GetAttrValue(ARowNode, 'table:style-name');
|
||||
@ -3269,11 +3447,13 @@ var
|
||||
rowHeight := rowStyle.RowHeight; // in Workbook units (see ReadRowStyles)
|
||||
rowHeightType := rowStyle.RowHeightType;
|
||||
end else begin
|
||||
rowHeight := FWorksheet.DefaultRowHeight;
|
||||
rowHeight := FWorksheet.ReadDefaultRowHeight(FWorkbook.Units);
|
||||
rowHeightTYpe := rhtDefault;
|
||||
end;
|
||||
|
||||
col := 0;
|
||||
firstStyleIndex := -1;
|
||||
hasRowFormat := true;
|
||||
|
||||
//process each cell of the row
|
||||
cellNode := ARowNode.FirstChild;
|
||||
@ -3283,61 +3463,38 @@ var
|
||||
nodeName := cellNode.NodeName;
|
||||
if nodeName = 'table:table-cell' then
|
||||
begin
|
||||
// select this cell value's type
|
||||
paramValueType := GetAttrValue(CellNode, 'office:value-type');
|
||||
paramFormula := GetAttrValue(CellNode, 'table:formula');
|
||||
tableStyleName := GetAttrValue(CellNode, 'table:style-name');
|
||||
cellStyleName := GetAttrValue(CellNode, 'table:style-name');
|
||||
styleIndex := ExtractFormatIndexFromStyle(cellStyleName, col);
|
||||
ReadCell(cellNode, row, col, styleIndex, colsRepeated);
|
||||
|
||||
if paramFormula <> '' then
|
||||
ReadFormula(row, col, cellNode)
|
||||
// Check whether the current cell format is still the same as for the
|
||||
// first cell. If it is then we might have a row format here.
|
||||
if (firstStyleIndex = -1) and hasRowFormat then
|
||||
firstStyleIndex := styleIndex
|
||||
else if (styleIndex <> firstStyleIndex) and (cellStyleName <> 'Default') then
|
||||
hasRowFormat := false;
|
||||
|
||||
// If all cell styles in the row are the same then hasRowFormat is true
|
||||
// and we can store the format of the first cell in the row record.
|
||||
if GetRowFormat and hasRowFormat and
|
||||
(col + colsRepeated >= LongInt(FLimitations.MaxColCount) - 10) then
|
||||
begin
|
||||
lRow := FWorksheet.GetRow(row);
|
||||
// Find first cell in row, all cells have the same format here.
|
||||
cell := FWorksheet.FindNextCellInRow(row, 0);
|
||||
if cell <> nil then
|
||||
// Cell found --> copy its format index to cell record
|
||||
lRow^.FormatIndex := cell^.FormatIndex
|
||||
else
|
||||
begin
|
||||
if paramValueType = 'string' then
|
||||
ReadLabel(row, col, cellNode)
|
||||
else
|
||||
if (paramValueType = 'float') or (paramValueType = 'percentage') or
|
||||
(paramValueType = 'currency')
|
||||
then
|
||||
ReadNumber(row, col, cellNode)
|
||||
else if (paramValueType = 'date') or (paramValueType = 'time') then
|
||||
ReadDateTime(row, col, cellNode)
|
||||
else if (paramValueType = 'boolean') then
|
||||
ReadBoolean(row, col, cellNode)
|
||||
else if (paramValueType = '') and (tableStyleName <> '') then
|
||||
ReadBlank(row, col, cellNode);
|
||||
{ NOTE: Empty cells having no cell format, but a column format only,
|
||||
are skipped here. --> Currently the reader does not detect the format
|
||||
of empty cells correctly.
|
||||
It would work if the "(tableStyleName <> '')" would be omitted, but
|
||||
then the reader would create a record for all 1E9 cells prepared by
|
||||
the Excel2007 export --> crash!
|
||||
The column format is available in the FColumnList, but since the usage
|
||||
of colsSpanned in the row it is possible to miss the correct column format.
|
||||
Pretty nasty situation! }
|
||||
// No cell in row --> appy format to dummy cell to get its format index
|
||||
InitCell(row, 0, cellRecord);
|
||||
ApplyStyleToCell(@cellRecord, styleIndex);
|
||||
lRow^.FormatIndex := cellRecord.FormatIndex;
|
||||
end;
|
||||
end;
|
||||
|
||||
// Read cell comment
|
||||
ReadComment(row, col, cellNode);
|
||||
|
||||
paramColsSpanned := GetAttrValue(cellNode, 'table:number-columns-spanned');
|
||||
if paramColsSpanned <> '' then
|
||||
colsSpanned := StrToInt(paramColsSpanned) - 1
|
||||
else
|
||||
colsSpanned := 0;
|
||||
|
||||
paramRowsSpanned := GetAttrValue(cellNode, 'table:number-rows-spanned');
|
||||
if paramRowsSpanned <> '' then
|
||||
rowsSpanned := StrToInt(paramRowsSpanned) - 1
|
||||
else
|
||||
rowsSpanned := 0;
|
||||
|
||||
if (colsSpanned <> 0) or (rowsSpanned <> 0) then
|
||||
FWorksheet.MergeCells(row, col, row+rowsSpanned, col+colsSpanned);
|
||||
|
||||
paramColsRepeated := GetAttrValue(cellNode, 'table:number-columns-repeated');
|
||||
if paramColsRepeated = '' then paramColsRepeated := '1';
|
||||
n := StrToInt(paramColsRepeated);
|
||||
if (n > 1) and (col + n < LongInt(FLimitations.MaxColCount) - 10) then
|
||||
if (colsRepeated > 1) and (col + colsRepeated < LongInt(FLimitations.MaxColCount) - 10) then
|
||||
begin
|
||||
// The 2nd condition belongs to a workaround for a bug of LO/OO whichs
|
||||
// extends imported xlsx files with blank cols up to their
|
||||
@ -3346,27 +3503,27 @@ var
|
||||
// sometimes split into two parts.
|
||||
cell := FWorksheet.FindCell(row, col);
|
||||
if cell <> nil then
|
||||
for i:=1 to n-1 do
|
||||
for i:=1 to colsRepeated-1 do
|
||||
FWorksheet.CopyCell(row, col, row, col+i);
|
||||
end;
|
||||
end
|
||||
else
|
||||
if nodeName = 'table:covered-table-cell' then
|
||||
begin
|
||||
paramColsRepeated := GetAttrValue(cellNode, 'table:number-columns-repeated');
|
||||
if paramColsRepeated = '' then paramColsRepeated := '1';
|
||||
s := GetAttrValue(cellNode, 'table:number-columns-repeated');
|
||||
if s = '' then colsRepeated := 1;
|
||||
end else
|
||||
paramColsRepeated := '0';
|
||||
colsRepeated := 0;
|
||||
|
||||
col := col + StrToInt(paramColsRepeated);
|
||||
col := col + colsRepeated;
|
||||
cellNode := cellNode.NextSibling;
|
||||
end; //while Assigned(cellNode)
|
||||
|
||||
paramRowsRepeated := GetAttrValue(RowNode, 'table:number-rows-repeated');
|
||||
if paramRowsRepeated = '' then
|
||||
s := GetAttrValue(RowNode, 'table:number-rows-repeated');
|
||||
if s = '' then
|
||||
rowsRepeated := 1
|
||||
else
|
||||
rowsRepeated := StrToInt(paramRowsRepeated);
|
||||
rowsRepeated := StrToInt(s);
|
||||
|
||||
// Transfer non-default row heights to sheet's rows
|
||||
// This first "if" is a workaround for a bug of LO/OO whichs extends imported
|
||||
@ -3377,12 +3534,47 @@ var
|
||||
for i:=1 to rowsRepeated do
|
||||
FWorksheet.WriteRowHeight(row + i - 1, rowHeight, FWorkbook.Units, rowHeightType);
|
||||
|
||||
row := row + rowsRepeated;
|
||||
// Prepare checking of column format
|
||||
if GetRowFormat then begin
|
||||
// Store the format indexes of all cells in the first row
|
||||
if isFirstRow then begin
|
||||
SetLength(colFmt, col);
|
||||
for col:=0 to High(colFmt) do begin
|
||||
cell := FWorksheet.FindCell(row, col);
|
||||
if cell <> nil then
|
||||
colFmt[col] := cell^.FormatIndex
|
||||
else begin
|
||||
InitCell(row, col, cellRecord);
|
||||
ApplyStyleToCell(@cellRecord, styleIndex);
|
||||
colFmt[col] := cellRecord.FormatIndex;
|
||||
end;
|
||||
end;
|
||||
end else
|
||||
// In the other rows compare the cell format indexes with those stored
|
||||
// from the first row. If an index does not match then this col cannot
|
||||
// have a column format.
|
||||
for col:=0 to High(colFmt) do begin
|
||||
if colFmt[col] > -1 then begin
|
||||
cell := FWorksheet.FindCell(row, col);
|
||||
if ((cell <> nil) and (cell^.FormatIndex <> colFmt[col])) then
|
||||
colFmt[col] := -1;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
row := row + rowsRepeated;
|
||||
isFirstRow := false;
|
||||
end;
|
||||
|
||||
var
|
||||
PrintRowMode: Boolean;
|
||||
c: Cardinal;
|
||||
|
||||
begin
|
||||
rowsRepeated := 0;
|
||||
row := 0;
|
||||
isFirstRow := true;
|
||||
PrintRowMode := false;
|
||||
|
||||
rownode := ATableNode.FirstChild;
|
||||
while Assigned(rowNode) do
|
||||
@ -3392,6 +3584,7 @@ begin
|
||||
// Repeated print rows
|
||||
if nodeName = 'table:table-header-rows' then
|
||||
begin
|
||||
PrintRowMode := true;
|
||||
if FRepeatedRows.FirstIndex = Cardinal(UNASSIGNED_ROW_COL_INDEX) then
|
||||
FRepeatedRows.FirstIndex := row;
|
||||
childnode := rowNode.FirstChild;
|
||||
@ -3400,19 +3593,26 @@ begin
|
||||
nodename := childnode.NodeName;
|
||||
if nodename = 'table:table-row' then
|
||||
begin
|
||||
ProcessRow(childnode);
|
||||
ProcessRow(childnode, false);
|
||||
end;
|
||||
childnode := childnode.NextSibling;
|
||||
end;
|
||||
FRepeatedRows.LastIndex := row-1;
|
||||
end else
|
||||
end
|
||||
else
|
||||
// "normal" rows
|
||||
if nodeName = 'table:table-row' then
|
||||
begin
|
||||
ProcessRow(rowNode);
|
||||
end;
|
||||
ProcessRow(rowNode, true);
|
||||
|
||||
rowNode := rowNode.NextSibling;
|
||||
end;
|
||||
|
||||
// Construct column records with column format
|
||||
if not PrintRowMode and (row > FLimitations.MaxRowCount-10) then begin
|
||||
for c := 0 to High(colFmt) do
|
||||
if colFmt[c] > 0 then
|
||||
FWorksheet.WriteColFormatIndex(c, colFmt[c]);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TsSpreadOpenDocReader.ReadRowStyle(AStyleNode: TDOMNode);
|
||||
@ -3466,6 +3666,8 @@ begin
|
||||
showGrid := true;
|
||||
showHeaders := true;
|
||||
zoom := 100.0;
|
||||
actRow := 0;
|
||||
actCol := 0;
|
||||
cfgItemSetNode := AOfficeSettingsNode.FirstChild;
|
||||
while Assigned(cfgItemSetNode) do
|
||||
begin
|
||||
@ -3547,13 +3749,13 @@ begin
|
||||
sheet.TopPaneHeight := vsp;
|
||||
end else
|
||||
sheet.Options := sheet.Options - [soHasFrozenPanes];
|
||||
end;
|
||||
// Active cell
|
||||
sheet.SelectCell(actRow, actCol);
|
||||
// Zoom factor
|
||||
sheet.ZoomFactor := zoom / 100.0;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
cfgTableItemNode := cfgTableItemNode.NextSibling;
|
||||
end;
|
||||
end;
|
||||
|
@ -3291,7 +3291,7 @@ end;
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsCustomWorksheetGrid.GetDefaultHeaderColWidth: Integer;
|
||||
begin
|
||||
Result := Canvas.TextWidth(' 999999 ');
|
||||
Result := Canvas.TextWidth(' 9999999 ');
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user