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:
wp_xxyyzz
2016-10-13 22:29:48 +00:00
parent 301f7034db
commit c908c87838
2 changed files with 319 additions and 117 deletions

View File

@ -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;

View File

@ -3291,7 +3291,7 @@ end;
-------------------------------------------------------------------------------}
function TsCustomWorksheetGrid.GetDefaultHeaderColWidth: Integer;
begin
Result := Canvas.TextWidth(' 999999 ');
Result := Canvas.TextWidth(' 9999999 ');
end;
{@@ ----------------------------------------------------------------------------