fpspreadsheet: Write row formats to ods.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5264 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2016-10-16 20:20:04 +00:00
parent 755117f397
commit 5f7a98d5b9
3 changed files with 110 additions and 45 deletions

View File

@ -174,6 +174,8 @@ type
FRowStyleList: TFPList; FRowStyleList: TFPList;
FRichTextFontList: TStringList; FRichTextFontList: TStringList;
FHeaderFooterFontList: TObjectList; FHeaderFooterFontList: TObjectList;
FHasColFormats: Boolean;
FHasRowFormats: Boolean;
// Routines to write parts of files // Routines to write parts of files
procedure WriteAutomaticStyles(AStream: TStream); procedure WriteAutomaticStyles(AStream: TStream);
@ -4947,6 +4949,11 @@ procedure TsSpreadOpenDocWriter.WriteWorksheet(AStream: TStream;
begin begin
FWorksheet := FWorkbook.GetWorksheetByIndex(ASheetIndex); FWorksheet := FWorkbook.GetWorksheetByIndex(ASheetIndex);
// Buffer the information whether the worksheet contains column or row formats
// Needed for writing rows and cells
FHasColFormats := FWorksheet.HasColFormats;
FHasRowFormats := FWorksheet.HasRowFormats;
// Header // Header
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<table:table table:name="%s" table:style-name="ta%d" %s>', [ '<table:table table:name="%s" table:style-name="ta%d" %s>', [
@ -4974,6 +4981,8 @@ begin
'</table:table>'); '</table:table>');
end; end;
{ Writes the cell styles ("ce0", "ce1", ...). Directly maps to the CellFormats
list of the workbook. "ce0" is the default format }
procedure TsSpreadOpenDocWriter.WriteCellStyles(AStream: TStream); procedure TsSpreadOpenDocWriter.WriteCellStyles(AStream: TStream);
var var
i, j, p: Integer; i, j, p: Integer;
@ -5016,11 +5025,13 @@ begin
'style:parent-style-name="Default" '+ nfs + '>'); 'style:parent-style-name="Default" '+ nfs + '>');
// style:text-properties // style:text-properties
// - font
s := WriteFontStyleXMLAsString(fmt); s := WriteFontStyleXMLAsString(fmt);
if s <> '' then if s <> '' then
AppendToStream(AStream, AppendToStream(AStream,
'<style:text-properties '+ s + '/>'); '<style:text-properties '+ s + '/>');
// - border, background, wordwrap, text rotation, vertical alignment
s := WriteBorderStyleXMLAsString(fmt) + s := WriteBorderStyleXMLAsString(fmt) +
WriteBackgroundColorStyleXMLAsString(fmt) + WriteBackgroundColorStyleXMLAsString(fmt) +
WriteWordwrapStyleXMLAsString(fmt) + WriteWordwrapStyleXMLAsString(fmt) +
@ -5031,7 +5042,9 @@ begin
'<style:table-cell-properties ' + s + '/>'); '<style:table-cell-properties ' + s + '/>');
// style:paragraph-properties // style:paragraph-properties
s := WriteHorAlignmentStyleXMLAsString(fmt) + WriteBiDiModeStyleXMLAsString(fmt); // - hor alignment, bidi
s := WriteHorAlignmentStyleXMLAsString(fmt) +
WriteBiDiModeStyleXMLAsString(fmt);
if s <> '' then if s <> '' then
AppendToStream(AStream, AppendToStream(AStream,
'<style:paragraph-properties ' + s + '/>'); '<style:paragraph-properties ' + s + '/>');
@ -5082,6 +5095,7 @@ var
lastCol: Integer; lastCol: Integer;
c, k: Integer; c, k: Integer;
w: Double; w: Double;
fmt: Integer;
// w, w_mm: Double; // w, w_mm: Double;
// widthMultiplier: Double; // widthMultiplier: Double;
styleName: String; styleName: String;
@ -5118,8 +5132,12 @@ begin
styleName := TColumnStyleData(FColumnStyleList[k]).Name; styleName := TColumnStyleData(FColumnStyleList[k]).Name;
break; break;
end; end;
if stylename = '' then
stylename := 'co1';
{
if stylename = '' then if stylename = '' then
raise Exception.Create(rsColumnStyleNotFound); raise Exception.Create(rsColumnStyleNotFound);
}
// Determine value for "number-columns-repeated" // Determine value for "number-columns-repeated"
colsRepeated := 1; colsRepeated := 1;
@ -5142,6 +5160,9 @@ begin
break; break;
inc(k); inc(k);
end; end;
if FHasRowFormats and (k = lastcol) then
colsRepeated := FLimitations.MaxColCount - c;
colsRepeatedStr := IfThen(colsRepeated = 1, '', Format(' table:number-columns-repeated="%d"', [colsRepeated])); colsRepeatedStr := IfThen(colsRepeated = 1, '', Format(' table:number-columns-repeated="%d"', [colsRepeated]));
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
@ -5487,28 +5508,28 @@ begin
headerRows := true; headerRows := true;
end; end;
// Look for the row style of the current row (r) // Look for the row style of the current row (r): row style contains only
// row height, no row format!
row := ASheet.FindRow(r); row := ASheet.FindRow(r);
if row = nil then begin styleName := '';
styleName := 'ro1'; if row <> nil then
h := ASheet.ReadDefaultRowHeight(FWorkbook.Units);
end else
begin begin
styleName := '';
h := row^.Height; // row height in workbook units h := row^.Height; // row height in workbook units
for k := 0 to FRowStyleList.Count-1 do begin for k := 0 to FRowStyleList.Count-1 do begin
rowStyleData := TRowStyleData(FRowStyleList[k]); rowStyleData := TRowStyleData(FRowStyleList[k]);
// Compare row heights, but be aware of rounding errors // Compare row heights, but be aware of rounding errors
if SameValue(rowStyleData.RowHeight, h, ROWHEIGHT_EPS) and if SameValue(rowStyleData.RowHeight, h, ROWHEIGHT_EPS) and
(rowstyleData.RowHeightType = row^.RowHeightType) (rowstyleData.RowHeightType = row^.RowHeightType) and
(rowstyleData.RowHeightType <> rhtDefault)
then begin then begin
styleName := rowStyleData.Name; styleName := rowStyleData.Name;
break; break;
end; end;
end; end;
if styleName = '' then end;
raise Exception.Create(rsRowStyleNotFound); if styleName = '' then begin
styleName := 'ro1'; // "ro1" is default row record - see ListAllRowStyles
h := ASheet.ReadDefaultRowHeight(FWorkbook.Units);
end; end;
// Take care of empty rows above the first row // Take care of empty rows above the first row
@ -5517,7 +5538,9 @@ begin
rowsRepeated := r; rowsRepeated := r;
rowsRepeatedStr := IfThen(rowsRepeated = 1, '', rowsRepeatedStr := IfThen(rowsRepeated = 1, '',
Format('table:number-rows-repeated="%d"', [rowsRepeated])); Format('table:number-rows-repeated="%d"', [rowsRepeated]));
colsRepeated := lastCol + 1; if FHasRowFormats then
colsRepeated := FLimitations.MaxColCount else
colsRepeated := lastCol + 1;
colsRepeatedStr := IfThen(colsRepeated = 1, '', colsRepeatedStr := IfThen(colsRepeated = 1, '',
Format('table:number-columns-repeated="%d"', [colsRepeated])); Format('table:number-columns-repeated="%d"', [colsRepeated]));
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
@ -5544,7 +5567,9 @@ begin
rowsRepeated := rr - r; rowsRepeated := rr - r;
rowsRepeatedStr := IfThen(rowsRepeated = 1, '', rowsRepeatedStr := IfThen(rowsRepeated = 1, '',
Format('table:number-rows-repeated="%d"', [rowsRepeated])); Format('table:number-rows-repeated="%d"', [rowsRepeated]));
colsRepeated := lastCol - firstCol + 1; if FHasRowFormats then
colsRepeated := FLimitations.MaxColCount else
colsRepeated := lastCol - firstCol + 1;
colsRepeatedStr := IfThen(colsRepeated = 1, '', colsRepeatedStr := IfThen(colsRepeated = 1, '',
Format('table:number-columns-repeated="%d"', [colsRepeated])); Format('table:number-columns-repeated="%d"', [colsRepeated]));
@ -5600,11 +5625,17 @@ begin
break; break;
inc(cc) inc(cc)
end; end;
colsRepeated := cc - c; if FHasRowFormats and (cc > lastcol) then
colsRepeated := FLimitations.MaxColCount - c else
colsRepeated := cc - c;
colsRepeatedStr := IfThen(colsRepeated = 1, '', colsRepeatedStr := IfThen(colsRepeated = 1, '',
Format('table:number-columns-repeated="%d"', [colsRepeated])); Format(' table:number-columns-repeated="%d"', [colsRepeated]));
row := ASheet.FindRow(r);
if (row <> nil) and (row^.FormatIndex > 0) then
stylename := Format(' table:style-name="ce%d"', [row^.FormatIndex]) else
stylename := '';
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<table:table-cell %s/>', [colsRepeatedStr])); '<table:table-cell%s%s/>', [colsRepeatedStr, stylename]));
end else end else
WriteCellToStream(AStream, cell); WriteCellToStream(AStream, cell);
inc(c, colsRepeated); inc(c, colsRepeated);
@ -5625,6 +5656,8 @@ begin
end; end;
end; end;
{ Write the style nodes for rows ("ro1", "ro2", ...); they contain only
row height information. "ro1" is the default row height }
procedure TsSpreadOpenDocWriter.WriteRowStyles(AStream: TStream); procedure TsSpreadOpenDocWriter.WriteRowStyles(AStream: TStream);
var var
i: Integer; i: Integer;
@ -5632,10 +5665,13 @@ var
begin begin
if FRowStyleList.Count = 0 then if FRowStyleList.Count = 0 then
begin begin
AppendToStream(AStream, AppendToStream(AStream, Format(
'<style:style style:name="ro1" style:family="table-row">' + '<style:style style:name="ro1" style:family="table-row">' +
'<style:table-row-properties style:row-height="0.416cm" fo:break-before="auto" style:use-optimal-row-height="true"/>' + '<style:table-row-properties style:row-height="%.3fmm" ' +
'</style:style>'); 'fo:break-before="auto" style:use-optimal-row-height="true"/>' +
'</style:style>',
[FWorksheet.ReadDefaultRowHeight(suMillimeters)]
));
exit; exit;
end; end;
@ -5654,7 +5690,6 @@ begin
FPointSeparatorSettings)); FPointSeparatorSettings));
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'style:use-optimal-row-height="%s" ', [FALSE_TRUE[rowstyle.RowHeightType <> rhtCustom]])); 'style:use-optimal-row-height="%s" ', [FALSE_TRUE[rowstyle.RowHeightType <> rhtCustom]]));
// row height < 0 means: automatic row height
AppendToStream(AStream, AppendToStream(AStream,
'fo:break-before="auto"/>'); 'fo:break-before="auto"/>');
@ -7164,16 +7199,16 @@ begin
if FWorksheet.IsMergeBase(ACell) then if FWorksheet.IsMergeBase(ACell) then
begin begin
FWorksheet.FindMergedRange(ACell, r1, c1, r2, c2); 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]);
colsSpannedStr := Format('table:number-columns-spanned="%d"', [c2 - c1 + 1]); rowsSpannedStr := Format(' table:number-rows-spanned="%d"', [r2 - r1 + 1]);
spannedStr := colsSpannedStr + ' ' + rowsSpannedStr; spannedStr := colsSpannedStr + rowsSpannedStr;
end else end else
spannedStr := ''; spannedStr := '';
fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex); fmt := FWorkbook.GetCellFormat(ACell^.FormatIndex);
numFmtParams := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex); numFmtParams := FWorkbook.GetNumberFormat(fmt.NumberFormatIndex);
if fmt.UsedFormattingFields <> [] then if fmt.UsedFormattingFields <> [] then
lStyle := ' table:style-name="ce' + IntToStr(ACell^.FormatIndex) + '" ' lStyle := Format(' table:style-name="ce%d"', [ACell^.FormatIndex])
else else
lStyle := ''; lStyle := '';
@ -7194,7 +7229,7 @@ begin
displayStr := FWorksheet.ReadAsText(ACell); displayStr := FWorksheet.ReadAsText(ACell);
// displayStr := FormatDateTime(fmt.NumberFormatStr, AValue, [fdoInterval]); // displayStr := FormatDateTime(fmt.NumberFormatStr, AValue, [fdoInterval]);
AppendToStream(AStream, Format( AppendToStream(AStream, Format(
'<table:table-cell office:value-type="time" office:time-value="%s" %s %s>' + '<table:table-cell office:value-type="time" office:time-value="%s"%s%s>' +
comment + comment +
'<text:p>%s</text:p>' + '<text:p>%s</text:p>' +
'</table:table-cell>', [ '</table:table-cell>', [

View File

@ -425,6 +425,8 @@ type
function GetColFormatIndex(ACol: Cardinal): Integer; 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.';
function HasColFormats: Boolean;
function HasRowFormats: Boolean;
procedure DeleteCol(ACol: Cardinal); procedure DeleteCol(ACol: Cardinal);
procedure DeleteRow(ARow: Cardinal); procedure DeleteRow(ARow: Cardinal);
procedure InsertCol(ACol: Cardinal); procedure InsertCol(ACol: Cardinal);
@ -4622,7 +4624,6 @@ begin
Delete(AValue, 1, 1); Delete(AValue, 1, 1);
WriteNumberFormat(ACell, nfText); WriteNumberFormat(ACell, nfText);
end; end;
fmtIndex := GetEffectiveCellFormatIndex(ACell); fmtIndex := GetEffectiveCellFormatIndex(ACell);
fmt := Workbook.GetCellFormat(fmtIndex); fmt := Workbook.GetCellFormat(fmtIndex);
numFmtParams := Workbook.GetNumberFormat(fmt.NumberFormatIndex); numFmtParams := Workbook.GetNumberFormat(fmt.NumberFormatIndex);
@ -4661,25 +4662,6 @@ begin
exit; exit;
end; end;
if TryStrToFloat(AValue, number, FWorkbook.FormatSettings) then
begin
if isPercent then
WriteNumber(ACell, number/100, nfPercentage)
else
begin
if IsDateTimeFormat(numFmtParams) then
WriteNumber(ACell, number, nfGeneral)
else
WriteNumber(ACell, number);
end;
if IsTextFormat(numFmtParams) then
begin
WriteNumberFormat(ACell, nfText);
WriteText(ACell, AValue);
end;
exit;
end;
if TryStrToDateTime(AValue, number, FWorkbook.FormatSettings) then if TryStrToDateTime(AValue, number, FWorkbook.FormatSettings) then
begin begin
if number < 1.0 then // this is a time alone if number < 1.0 then // this is a time alone
@ -4709,6 +4691,25 @@ begin
exit; exit;
end; end;
if TryStrToFloat(AValue, number, FWorkbook.FormatSettings) then
begin
if isPercent then
WriteNumber(ACell, number/100, nfPercentage)
else
begin
if IsDateTimeFormat(numFmtParams) then
WriteNumber(ACell, number, nfGeneral)
else
WriteNumber(ACell, number);
end;
if IsTextFormat(numFmtParams) then
begin
WriteNumberFormat(ACell, nfText);
WriteText(ACell, AValue);
end;
exit;
end;
HTMLToRichText(FWorkbook, ReadcellFont(ACell), AValue, plain, rtParams); HTMLToRichText(FWorkbook, ReadcellFont(ACell), AValue, plain, rtParams);
WriteText(ACell, plain, rtParams); WriteText(ACell, plain, rtParams);
end; end;
@ -6629,6 +6630,32 @@ begin
Result := lRow^.RowHeightType; Result := lRow^.RowHeightType;
end; end;
function TsWorksheet.HasColFormats: Boolean;
var
c: Integer;
begin
for c := 0 to FCols.Count-1 do
if PCol(FCols[c]).FormatIndex > 0 then
begin
Result := true;
exit;
end;
Result := false;
end;
function TsWorksheet.HasRowFormats: Boolean;
var
r: Integer;
begin
for r := 0 to FRows.Count-1 do
if PRow(FRows[r]).FormatIndex > 0 then
begin
Result := true;
exit;
end;
Result := false;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Deletes the column at the index specified. Cells with greader column indexes Deletes the column at the index specified. Cells with greader column indexes
are moved one column to the left. Merged cell blocks and cell references in are moved one column to the left. Merged cell blocks and cell references in

View File

@ -3247,6 +3247,9 @@ begin
AStrings.Add(Format('RowHeightType=%s', [ AStrings.Add(Format('RowHeightType=%s', [
RowHeightTypeNames[lRow^.RowHeightType] RowHeightTypeNames[lRow^.RowHeightType]
])); ]));
AStrings.Add(Format('FormatIndex=%d', [
lRow^.FormatIndex
]));
end else end else
begin begin
AStrings.Add('No row record='); AStrings.Add('No row record=');