diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas
index f5f937fcd..0a8caded8 100755
--- a/components/fpspreadsheet/fpsopendocument.pas
+++ b/components/fpspreadsheet/fpsopendocument.pas
@@ -1780,10 +1780,14 @@ procedure TsSpreadOpenDocReader.ReadRowsAndCells(ATableNode: TDOMNode);
var
row: Integer;
col: Integer;
+ cell: PCell;
cellNode, rowNode: TDOMNode;
paramValueType, paramFormula, tableStyleName: String;
+ paramColsSpanned, paramRowsSpanned: String;
paramColsRepeated, paramRowsRepeated: String;
rowsRepeated: Integer;
+ rowsSpanned: Integer;
+ colsSpanned: Integer;
rowStyleName: String;
rowStyleIndex: Integer;
rowStyle: TRowStyleData;
@@ -1847,7 +1851,21 @@ begin
if ParamFormula <> '' then
ReadFormula(row, col, cellNode);
-// ReadLabel(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';
@@ -2926,29 +2944,24 @@ var
h1: Single;
colsRepeated: Cardinal;
rowsRepeated: Cardinal;
+ colsSpanned: Cardinal;
+ rowsSpanned: Cardinal;
colsRepeatedStr: String;
rowsRepeatedStr: String;
+ colsSpannedStr: String;
+ rowsSpannedStr: String;
firstCol, firstRow, lastCol, lastRow: Cardinal;
rowStyleData: TRowStyleData;
defFontSize: Single;
emptyRowsAbove: Boolean;
+ r1,c1,r2,c2: Cardinal;
begin
// some abbreviations...
defFontSize := Workbook.GetFont(0).Size;
GetSheetDimensions(ASheet, firstRow, lastRow, firstCol, lastCol);
- {
- firstCol := ASheet.GetFirstColIndex;
- firstRow := ASheet.GetFirstRowIndex;
- lastCol := ASheet.GetLastColIndex;
- lastRow := ASheet.GetLastRowIndex;
- // avoid arithmetic overflow in case of empty worksheet
- if (firstCol = $FFFFFFFF) and (lastCol = 0) then firstCol := 0;
- if (FirstRow = $FFFFFFFF) and (lastRow = 0) then firstRow := 0;
- }
emptyRowsAbove := firstRow > 0;
// Now loop through all rows
-// r := 0;
r := firstRow;
while (r <= lastRow) do begin
// Look for the row style of the current row (r)
@@ -3027,6 +3040,16 @@ begin
while c <= lastCol do begin
// Get the cell from the sheet
cell := ASheet.FindCell(r, c);
+
+ // Belongs to merged block?
+ if (cell <> nil) and not FWorksheet.IsMergeBase(cell) and (cell^.MergedNeighbors <> []) then
+ begin
+ AppendToStream(AStream,
+ '');
+ inc(c);
+ continue;
+ end;
+
// Empty cell? Need to count how many to add "table:number-columns-repeated"
colsRepeated := 1;
if cell = nil then begin
@@ -3216,18 +3239,31 @@ procedure TsSpreadOpenDocWriter.WriteBlank(AStream: TStream;
const ARow, ACol: Cardinal; ACell: PCell);
var
lIndex: Integer;
+ colsSpannedStr: String;
+ rowsSpannedStr: String;
+ spannedStr: String;
+ r1,c1,r2,c2: Cardinal;
begin
Unused(AStream, ACell);
Unused(ARow, ACol);
+ // Merged?
+ if FWorksheet.IsMergeBase(ACell) then begin
+ FWorksheet.FindMergedRange(ACell, r1, c1, r2, c2);
+ rowsSpannedStr := Format('table:number-rows-spanned="%d"', [r2 - r1 + 1]);
+ colsSpannedStr := Format('table:number-columns-spanned="%d"', [c2 - c1 + 1]);
+ spannedStr := colsSpannedStr + ' ' + rowsSpannedStr;
+ end else
+ spannedStr := '';
+
if ACell^.UsedFormattingFields <> [] then begin
lIndex := FindFormattingInList(ACell);
AppendToStream(AStream, Format(
- '', [lIndex]),
+ '', [lIndex, spannedStr]),
'');
end else
AppendToStream(AStream,
- '');
+ '');
end;
{ Creates an XML string for inclusion of the background color into the
@@ -3612,15 +3648,29 @@ var
valuetype: String;
value: string;
valueStr: String;
+ colsSpannedStr: String;
+ rowsSpannedStr: String;
+ spannedStr: String;
+ r1,c1,r2,c2: Cardinal;
begin
Unused(AStream, ARow, ACol);
+ // Style
if ACell^.UsedFormattingFields <> [] then begin
lIndex := FindFormattingInList(ACell);
lStyle := ' table:style-name="ce' + IntToStr(lIndex) + '" ';
end else
lStyle := '';
+ // Merged?
+ if FWorksheet.IsMergeBase(ACell) then begin
+ FWorksheet.FindMergedRange(ACell, r1, c1, r2, c2);
+ rowsSpannedStr := Format('table:number-rows-spanned="%d"', [r2 - r1 + 1]);
+ colsSpannedStr := Format('table:number-columns-spanned="%d"', [c2 - c1 + 1]);
+ spannedStr := colsSpannedStr + ' ' + rowsSpannedStr;
+ end else
+ spannedStr := '';
+
// Convert string formula to the format needed by ods: semicolon list separators!
parser := TsSpreadsheetParser.Create(FWorksheet);
try
@@ -3683,15 +3733,15 @@ begin
data type. Seems to work... }
if ACell^.CalcState=csCalculated then
AppendToStream(AStream, Format(
- '' +
+ '' +
valueStr +
'', [
- formula, valuetype, value, lStyle
+ formula, valuetype, value, lStyle, spannedStr
]))
else
AppendToStream(AStream, Format(
- '', [
- formula, lStyle
+ '', [
+ formula, lStyle, spannedStr
]));
end;
@@ -3707,21 +3757,43 @@ procedure TsSpreadOpenDocWriter.WriteLabel(AStream: TStream; const ARow,
var
lStyle: string = '';
lIndex: Integer;
+ colsSpannedStr: String;
+ rowsSpannedStr: String;
+ spannedStr: String;
+ r1,c1,r2,c2: Cardinal;
begin
Unused(AStream, ACell);
Unused(ARow, ACol);
+ // Style
if ACell^.UsedFormattingFields <> [] then begin
lIndex := FindFormattingInList(ACell);
lStyle := ' table:style-name="ce' + IntToStr(lIndex) + '" ';
end else
lStyle := '';
- // The row should already be the correct one
+ // Merged?
+ if FWorksheet.IsMergeBase(ACell) then begin
+ FWorksheet.FindMergedRange(ACell, r1, c1, r2, c2);
+ rowsSpannedStr := Format('table:number-rows-spanned="%d"', [r2 - r1 + 1]);
+ colsSpannedStr := Format('table:number-columns-spanned="%d"', [c2 - c1 + 1]);
+ spannedStr := colsSpannedStr + ' ' + rowsSpannedStr;
+ end else
+ spannedStr := '';
+
+ AppendToStream(AStream, Format(
+ '' +
+ '%s'+
+ '', [
+ lStyle, spannedStr,
+ UTF8TextToXMLText(AValue)
+ ]));
+ {
AppendToStream(AStream,
'' +
'' + UTF8TextToXMLText(AValue) + '' +
'');
+ }
end;
procedure TsSpreadOpenDocWriter.WriteNumber(AStream: TStream; const ARow,
@@ -3732,6 +3804,10 @@ var
lStyle: string = '';
lIndex: Integer;
valType: String;
+ colsSpannedStr: String;
+ rowsSpannedStr: String;
+ spannedStr: String;
+ r1,c1,r2,c2: Cardinal;
begin
Unused(AStream, ACell);
Unused(ARow, ACol);
@@ -3747,7 +3823,16 @@ begin
end else
lStyle := '';
- // The row should already be the correct one
+ // Merged?
+ if FWorksheet.IsMergeBase(ACell) then begin
+ FWorksheet.FindMergedRange(ACell, r1, c1, r2, c2);
+ rowsSpannedStr := Format('table:number-rows-spanned="%d"', [r2 - r1 + 1]);
+ colsSpannedStr := Format('table:number-columns-spanned="%d"', [c2 - c1 + 1]);
+ spannedStr := colsSpannedStr + ' ' + rowsSpannedStr;
+ end else
+ spannedStr := '';
+
+ // Displayed value
if IsInfinite(AValue) then begin
StrValue := '1.#INF';
DisplayStr := '1.#INF';
@@ -3756,10 +3841,20 @@ begin
DisplayStr := FloatToStr(AValue); // Uses locale decimal separator
end;
- AppendToStream(AStream,
+ AppendToStream(AStream, Format(
+ '' +
+ '%s' +
+ '', [
+ valType, StrValue, lStyle, spannedStr,
+ DisplayStr
+ ]));
+ {
+
+
'' +
'' + DisplayStr + '' +
'');
+ }
end;
{*******************************************************************
@@ -3781,36 +3876,52 @@ var
displayStr: String;
lIndex: Integer;
isTimeOnly: Boolean;
+ colsSpannedStr: String;
+ rowsSpannedStr: String;
+ spannedStr: String;
+ r1,c1,r2,c2: Cardinal;
begin
Unused(AStream, ACell);
Unused(ARow, ACol);
+ // Merged?
+ if FWorksheet.IsMergeBase(ACell) then begin
+ FWorksheet.FindMergedRange(ACell, r1, c1, r2, c2);
+ rowsSpannedStr := Format('table:number-rows-spanned="%d"', [r2 - r1 + 1]);
+ colsSpannedStr := Format('table:number-columns-spanned="%d"', [c2 - c1 + 1]);
+ spannedStr := colsSpannedStr + ' ' + rowsSpannedStr;
+ end else
+ spannedStr := '';
+
if ACell^.UsedFormattingFields <> [] then begin
lIndex := FindFormattingInList(ACell);
lStyle := 'table:style-name="ce' + IntToStr(lIndex) + '" ';
end else
lStyle := '';
- // The row should already be the correct one
-
// nfTimeInterval is a special case - let's handle it first:
if (ACell^.NumberFormat = nfTimeInterval) then begin
- //lcfmt := Lowercase(Copy(ACell^.NumberFormatStr, 1, 2));
strValue := FormatDateTime(ISO8601FormatHoursOverflow, AValue, [fdoInterval]);
displayStr := FormatDateTime(ACell^.NumberFormatStr, AValue, [fdoInterval]);
AppendToStream(AStream, Format(
- '' +
+ '' +
'%s' +
- '', [strValue, lStyle, displayStr]));
+ '', [
+ strValue, lStyle, spannedStr,
+ displayStr
+ ]));
end else begin
// We have to distinguish between time-only values and values that contain date parts.
isTimeOnly := IsTimeFormat(ACell^.NumberFormat) or IsTimeFormat(ACell^.NumberFormatStr);
strValue := FormatDateTime(FMT[isTimeOnly], AValue);
displayStr := FormatDateTime(ACell^.NumberFormatStr, AValue);
AppendToStream(AStream, Format(
- '' +
+ '' +
'%s ' +
- '', [DT[isTimeOnly], DT[isTimeOnly], strValue, lStyle, displayStr]));
+ '', [
+ DT[isTimeOnly], DT[isTimeOnly], strValue, lStyle, spannedStr,
+ displayStr
+ ]));
end;
end;
diff --git a/components/fpspreadsheet/tests/spreadtestgui.lpi b/components/fpspreadsheet/tests/spreadtestgui.lpi
index f4f30ee59..251664efc 100644
--- a/components/fpspreadsheet/tests/spreadtestgui.lpi
+++ b/components/fpspreadsheet/tests/spreadtestgui.lpi
@@ -56,6 +56,7 @@
+
@@ -65,20 +66,20 @@
+
-
+
-
@@ -109,12 +110,10 @@
-
-