From 8d6ec7316c02d6e67d530f39e58547fafd25c55f Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Sat, 12 Jul 2014 21:51:44 +0000 Subject: [PATCH] fpspreadsheet: Remove string-based writing code of ods files --> significant speed improvement particularly for large grids (20000x100 cells 120 sec (old) --> 7 sec (new)). git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3311 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../examples/opendocdemo/opendocwrite.lpr | 7 +- components/fpspreadsheet/fpsopendocument.pas | 709 +++++++++++------- 2 files changed, 449 insertions(+), 267 deletions(-) diff --git a/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpr b/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpr index 6615c5a8f..cd5b83481 100644 --- a/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpr +++ b/components/fpspreadsheet/examples/opendocdemo/opendocwrite.lpr @@ -40,9 +40,10 @@ begin MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet'); // Write some cells - MyWorksheet.WriteNumber(0, 1, 2.0);// B1 - MyWorksheet.WriteNumber(0, 2, 3.0);// C1 - MyWorksheet.WriteNumber(0, 3, 4.0);// D1 + MyWorksheet.WriteNumber(0, 0, 1.0); // A1 + MyWorksheet.WriteNumber(0, 1, 2.0); // B1 + MyWorksheet.WriteNumber(0, 2, 3.0); // C1 + MyWorksheet.WriteNumber(0, 3, 4.0); // D1 MyWorksheet.WriteUTF8Text(4, 2, 'Total:');// C5 MyWorksheet.WriteNumber(4, 3, 10); // D5 MyWorksheet.WriteDateTime(5, 0, now); diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index 430a425ab..0eb47c027 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -131,38 +131,36 @@ type FRowStyleList: TFPList; // Routines to write parts of files - function WriteCellStylesXMLAsString: string; - function WriteColStylesXMLAsString: String; - function WriteNumFormatsXMLAsString: String; - function WriteRowStylesXMLAsString: String; - - function WriteColumnsXMLAsString(ASheet: TsWorksheet): String; - function WriteRowsAndCellsXMLAsString(ASheet: TsWorksheet): String; + procedure WriteCellStyles(AStream: TStream); + procedure WriteColStyles(AStream: TStream); + procedure WriteColumns(AStream: TStream; ASheet: TsWorksheet); + procedure WriteFontNames(AStream: TStream); + procedure WriteNumFormats(AStream: TStream); + procedure WriteRowStyles(AStream: TStream); + procedure WriteRowsAndCells(AStream: TStream; ASheet: TsWorksheet); + procedure WriteTableSettings(AStream: TStream); function WriteBackgroundColorStyleXMLAsString(const AFormat: TCell): String; function WriteBorderStyleXMLAsString(const AFormat: TCell): String; function WriteDefaultFontXMLAsString: String; - function WriteFontNamesXMLAsString: String; function WriteFontStyleXMLAsString(const AFormat: TCell): String; function WriteHorAlignmentStyleXMLAsString(const AFormat: TCell): String; function WriteTextRotationStyleXMLAsString(const AFormat: TCell): String; function WriteVertAlignmentStyleXMLAsString(const AFormat: TCell): String; function WriteWordwrapStyleXMLAsString(const AFormat: TCell): String; - function WriteTableSettingsXMLAsString(AIndent: String): String; protected FPointSeparatorSettings: TFormatSettings; - // Strings with the contents of files - FMeta, FSettings, FStyles, FContent, FCellContent, FMimetype: string; - FMetaInfManifest: string; // Streams with the contents of files - FSMeta, FSSettings, FSStyles, FSContent, FSMimetype: TStringStream; - FSMetaInfManifest: TStringStream; + FSMeta, FSSettings, FSStyles, FSContent, FSMimeType, FSMetaInfManifest: TStream; // Helpers procedure CreateNumFormatList; override; + procedure CreateStreams; + procedure DestroyStreams; procedure ListAllColumnStyles; procedure ListAllNumFormats; override; procedure ListAllRowStyles; + procedure ResetStreams; // Routines to write those files procedure WriteMimetype; procedure WriteMetaInfManifest; @@ -170,7 +168,7 @@ type procedure WriteSettings; procedure WriteStyles; procedure WriteContent; - procedure WriteWorksheet(CurSheet: TsWorksheet); + procedure WriteWorksheet(AStream: TStream; CurSheet: TsWorksheet); { Record writing methods } procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override; @@ -2235,6 +2233,54 @@ begin FNumFormatList := TsSpreadOpenDocNumFormatList.Create(Workbook); end; +{ Creates the streams for the individual data files. Will be zipped into a + single xlsx file. } +procedure TsSpreadOpenDocWriter.CreateStreams; +var + dir: String; +begin + if (woSaveMemory in Workbook.WritingOptions) then begin + dir := IncludeTrailingPathDelimiter(GetTempDir); + FSMeta := TFileStream.Create(GetTempFileName(dir, 'fpsM'), fmCreate+fmOpenRead); + FSSettings := TFileStream.Create(GetTempFileName(dir, 'fpsS'), fmCreate+fmOpenRead); + FSStyles := TFileStream.Create(GetTempFileName(dir, 'fpsSTY'), fmCreate+fmOpenRead); + FSContent := TFileStream.Create(GetTempFileName(dir, 'fpsC'), fmCreate+fmOpenRead); + FSMimeType := TFileStream.Create(GetTempFileName(dir, 'fpsMT'), fmCreate+fmOpenRead); + FSMetaInfManifest := TFileStream.Create(GetTempFileName(dir, 'fpsMIM'), fmCreate+fmOpenRead); + end else begin; + FSMeta := TMemoryStream.Create; + FSSettings := TMemoryStream.Create; + FSStyles := TMemoryStream.Create; + FSContent := TMemoryStream.Create; + FSMimeType := TMemoryStream.Create; + FSMetaInfManifest := TMemoryStream.Create; + end; + // FSSheets will be created when needed. +end; + +{ Destroys the streams that were created by the writer } +procedure TsSpreadOpenDocWriter.DestroyStreams; + + procedure DestroyStream(AStream: TStream); + var + fn: String; + begin + if AStream is TFileStream then begin + fn := TFileStream(AStream).Filename; + DeleteFile(fn); + end; + AStream.Free; + end; + +begin + DestroyStream(FSMeta); + DestroyStream(FSSettings); + DestroyStream(FSStyles); + DestroyStream(FSContent); + DestroyStream(FSMimeType); + DestroyStream(FSMetaInfManifest); +end; + procedure TsSpreadOpenDocWriter.ListAllColumnStyles; var i, j, c: Integer; @@ -2355,38 +2401,59 @@ begin end; end; +{ Is called before zipping the individual file parts. Rewinds the streams. } +procedure TsSpreadOpenDocWriter.ResetStreams; +begin + FSMeta.Position := 0; + FSSettings.Position := 0; + FSStyles.Position := 0; + FSContent.Position := 0; + FSMimeType.Position := 0; + FSMetaInfManifest.Position := 0; +end; + procedure TsSpreadOpenDocWriter.WriteMimetype; begin - FMimetype := 'application/vnd.oasis.opendocument.spreadsheet'; + AppendToStream(FSMimeType, + 'application/vnd.oasis.opendocument.spreadsheet' + ); end; procedure TsSpreadOpenDocWriter.WriteMetaInfManifest; begin - FMetaInfManifest := - XML_HEADER + LineEnding + - '' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ''; + AppendToStream(FSMetaInfManifest, + ''); + AppendToStream(FSMetaInfManifest, + ''); + AppendToStream(FSMetaInfManifest, + ''); + AppendToStream(FSMetaInfManifest, + ''); + AppendToStream(FSMetaInfManifest, + ''); + AppendToStream(FSMetaInfManifest, + ''); + AppendToStream(FSMetaInfManifest, + ''); end; procedure TsSpreadOpenDocWriter.WriteMeta; begin - FMeta := - XML_HEADER + LineEnding + - '' + LineEnding + - ' ' + LineEnding + - ' FPSpreadsheet Library' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ''; + AppendToStream(FSMeta, + XML_HEADER); + AppendToStream(FSMeta, + ''); + AppendToStream(FSMeta, + '', + 'FPSpreadsheet Library' + + '', + ''); + AppendToStream(FSMeta, + ''); end; procedure TsSpreadOpenDocWriter.WriteSettings; @@ -2406,71 +2473,115 @@ begin if not (soShowHeaders in sheet.Options) then showHeaders := false; end; - FSettings := - XML_HEADER + LineEnding + - '' + LineEnding + - '' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' Tabelle1' + LineEnding + - ' 100' + LineEnding + - ' 100' + LineEnding + - ' false' + LineEnding + - ' '+FALSE_TRUE[showGrid]+'' + LineEnding + - ' '+FALSE_TRUE[showHeaders]+'' + LineEnding + - ' ' + LineEnding + - WriteTableSettingsXMLAsString(' ') + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ''; + '" xmlns:ooo="' + SCHEMAS_XMLNS_OOO + '">'); + AppendToStream(FSSettings, + ''); + AppendToStream(FSSettings, + ''); + AppendToStream(FSSettings, + ''); + AppendToStream(FSSettings, + ''); + AppendToStream(FSSettings, + 'Tabelle1'); + AppendToStream(FSSettings, + '100'); + AppendToStream(FSSettings, + '100'); + AppendToStream(FSSettings, + 'false'); + AppendToStream(FSSettings, + ''+FALSE_TRUE[showGrid]+''); + AppendToStream(FSSettings, + ''+FALSE_TRUE[showHeaders]+''); + AppendToStream(FSSettings, + ''); + + WriteTableSettings(FSSettings); + + AppendToStream(FSSettings, + ''); + AppendToStream(FSSettings, + ' '); + AppendToStream(FSSettings, + ' '); + AppendToStream(FSSettings, + ' '); + AppendToStream(FSSettings, + ' '); + AppendToStream(FSSettings, + ''); end; procedure TsSpreadOpenDocWriter.WriteStyles; begin - FStyles := - XML_HEADER + LineEnding + - '' + LineEnding + - '' + LineEnding + - ' '+WriteFontNamesXMLAsString + LineEnding + -// ' ' + LineEnding + - '' + LineEnding + - '' + LineEnding + - ' ' + LineEnding + - ' ' + WriteDefaultFontXMLAsString + LineEnding + - ' ' + LineEnding + - '' + LineEnding + - '' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - '' + LineEnding + - '' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding + - '' + LineEnding + - ''; + AppendToStream(FSStyles, + XML_HEADER); + + AppendToStream(FSStyles, + ''); + + AppendToStream(FSStyles, + ''); + WriteFontNames(FSStyles); + AppendToStream(FSStyles, + ''); + + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + '', + WriteDefaultFontXMLAsString, + ''); + AppendToStream(FSStyles, + ''); + + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + '', + '', + ''); + AppendToStream(FSStyles, + '', + '', + ''); + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + ''); + + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + '', + ''); + AppendToStream(FSStyles, + '', + ''); + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + ''); + AppendToStream(FSStyles, + ''); end; procedure TsSpreadOpenDocWriter.WriteContent; @@ -2481,11 +2592,69 @@ var lRowStylesCode: String; lNumFmtCode: String; begin - ListAllNumFormats; - ListAllFormattingStyles; - ListAllColumnStyles; - ListAllRowStyles; + AppendToStream(FSContent, + XML_HEADER); + AppendToStream(FSContent, + '' + + ''); + // Fonts + WriteFontNames(FSContent); + + // Automatic styles + AppendToStream(FSContent, + ''); + + WriteNumFormats(FSContent); + WriteColStyles(FSContent); + WriteRowStyles(FSContent); + + AppendToStream(FSContent, + '', + '', + ''); + // Automatically generated styles + WriteCellStyles(FSContent); + AppendToStream(FSContent, + ''); + + // Body + AppendToStream(FSContent, + '', + ''); + + // Write all worksheets + for i := 0 to Workbook.GetWorksheetCount - 1 do + WriteWorksheet(FSContent, Workbook.GetWorksheetByIndex(i)); + + AppendToStream(FSContent, + '', + '', + '' + ); + + + + (* lNumFmtCode := WriteNumFormatsXMLAsString; lColStylesCode := WriteColStylesXMLAsString; @@ -2557,58 +2726,55 @@ begin ' ' + LineEnding + ' ' + LineEnding + ''; + *) end; -procedure TsSpreadOpenDocWriter.WriteWorksheet(CurSheet: TsWorksheet); +procedure TsSpreadOpenDocWriter.WriteWorksheet(AStream: TStream; + CurSheet: TsWorksheet); begin // Header - FContent := FContent + - ' ' + LineEnding; + AppendToStream(AStream, + ''); // columns - FContent := FContent + WriteColumnsXMLAsString(CurSheet); + WriteColumns(AStream, CurSheet); // rows and cells // The cells need to be written in order, row by row, cell by cell - FContent := FContent + WriteRowsAndCellsXMLAsString(CurSheet); + WriteRowsAndCells(AStream, CurSheet); // Footer - FContent := FContent + - ' ' + LineEnding; + AppendToStream(AStream, + ''); end; -function TsSpreadOpenDocWriter.WriteCellStylesXMLAsString: string; +procedure TsSpreadOpenDocWriter.WriteCellStyles(AStream: TStream); var i: Integer; s: String; fmtIndex: Integer; fmt: String; begin - Result := ''; - - for i := 0 to Length(FFormattingStyles) - 1 do - begin + for i := 0 to Length(FFormattingStyles) - 1 do begin fmtIndex := NumFormatList.Find(FFormattingStyles[i].NumberFormatStr); if fmtIndex <> -1 then fmt := 'style:data-style-name="' + NumFormatList[fmtIndex].Name +'"' else fmt := ''; - // Start and Name - Result := Result + - ' ' + LineEnding; - - // Fields + // Start and name + AppendToStream(AStream, + ''); // style:text-properties if uffBold in FFormattingStyles[i].UsedFormattingFields then - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, + ''); s := WriteFontStyleXMLAsString(FFormattingStyles[i]); if s <> '' then - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, + ''); // style:table-cell-properties s := WriteBorderStyleXMLAsString(FFormattingStyles[i]) + @@ -2617,48 +2783,54 @@ begin WriteTextRotationStyleXMLAsString(FFormattingStyles[i]) + WriteVertAlignmentStyleXMLAsString(FFormattingStyles[i]); if s <> '' then - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, + ''); // style:paragraph-properties s := WriteHorAlignmentStyleXMLAsString(FFormattingStyles[i]); if s <> '' then - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, + ''); // End - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, + ''); end; end; -function TsSpreadOpenDocWriter.WriteColStylesXMLAsString: string; +procedure TsSpreadOpenDocWriter.WriteColStyles(AStream: TStream); var i: Integer; colstyle: TColumnStyleData; begin - Result := ''; + if FColumnStyleList.Count = 0 then begin + AppendToStream(AStream, + '', + '', + ''); + exit; + end; for i := 0 to FColumnStyleList.Count-1 do begin colStyle := TColumnStyleData(FColumnStyleList[i]); // Start and Name - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, Format( + '', [colStyle.Name])); // Column width - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, Format( + '', + [colStyle.ColWidth], FPointSeparatorSettings)); // End - Result := Result + - ' ' + LineEnding; - - Result := Format(Result, [colStyle.Name, colStyle.ColWidth], FPointSeparatorSettings); + AppendToStream(AStream, + ''); end; end; -function TsSpreadOpenDocWriter.WriteColumnsXMLAsString(ASheet: TsWorksheet): String; +procedure TsSpreadOpenDocWriter.WriteColumns(AStream: TStream; + ASheet: TsWorksheet); var lastCol: Integer; j, k: Integer; @@ -2668,8 +2840,6 @@ var colsRepeated: Integer; colsRepeatedStr: String; begin - Result := ''; - widthMultiplier := Workbook.GetFont(0).Size / 2; lastCol := ASheet.GetLastColIndex; @@ -2701,22 +2871,48 @@ begin end; colsRepeatedStr := IfThen(colsRepeated = 1, '', Format(' table:number-columns-repeated="%d"', [colsRepeated])); - Result := Result + Format( - ' ', - [styleName, colsRepeatedStr]) + LineEnding; + AppendToStream(AStream, Format( + '', + [styleName, colsRepeatedStr])); j := j + colsRepeated; end; end; -function TsSpreadOpenDocWriter.WriteNumFormatsXMLAsString: String; +procedure TsSpreadOpenDocWriter.WriteFontNames(AStream: TStream); +var + L: TStringList; + fnt: TsFont; + i: Integer; +begin + AppendToStream(AStream, + ''); + + L := TStringList.Create; + try + for i:=0 to Workbook.GetFontCount-1 do begin + fnt := Workbook.GetFont(i); + if (fnt <> nil) and (L.IndexOf(fnt.FontName) = -1) then + L.Add(fnt.FontName); + end; + for i:=0 to L.Count-1 do + AppendToStream(AStream, Format( + '', [L[i], L[i]])); + finally + L.Free; + end; + + AppendToStream(AStream, + ''); +end; + +procedure TsSpreadOpenDocWriter.WriteNumFormats(AStream: TStream); var i: Integer; numFmtXML: String; fmtItem: TsNumFormatData; parser: TsSpreadOpenDocNumFormatParser; begin - Result := ''; for i:=0 to FNumFormatList.Count-1 do begin fmtItem := FNumFormatList.Items[i]; parser := TsSpreadOpenDocNumFormatParser.Create(Workbook, fmtItem.FormatString, @@ -2724,14 +2920,14 @@ begin try numFmtXML := parser.BuildXMLAsString(' ', fmtItem.Name); if numFmtXML <> '' then - Result := Result + numFmtXML; + AppendToStream(AStream, numFmtXML); finally parser.Free; end; end; end; -function TsSpreadOpenDocWriter.WriteRowsAndCellsXMLAsString(ASheet: TsWorksheet): String; +procedure TsSpreadOpenDocWriter.WriteRowsAndCells(AStream: TStream; ASheet: TsWorksheet); var r, rr: Cardinal; // row index in sheet c, cc: Cardinal; // column index in sheet @@ -2749,8 +2945,6 @@ var rowStyleData: TRowStyleData; defFontSize: Single; begin - Result := ''; - // some abbreviations... lastCol := ASheet.GetLastColIndex; lastRow := ASheet.GetLastRowIndex; @@ -2799,19 +2993,22 @@ begin colsRepeated := lastCol+1; colsRepeatedStr := IfThen(colsRepeated = 1, '', Format('table:number-columns-repeated="%d"', [colsRepeated])); - Result := Result + Format( - ' ' + LineEnding + - ' ' + LineEnding + - ' ' + LineEnding, - [styleName, rowsRepeatedStr, colsRepeatedStr]); + + AppendToStream(AStream, Format( + '', [styleName, rowsRepeatedStr])); + AppendToStream(AStream, Format( + '', [colsRepeatedStr])); + AppendToStream(AStream, + ''); + r := rr; continue; end; // Now we know that there are cells. // Write the row XML - Result := Result + Format( - ' ', [styleName]) + LineEnding; + AppendToStream(AStream, Format( + '', [styleName])); // Loop along the row and find the cells. c := 0; @@ -2831,50 +3028,53 @@ begin colsRepeated := cc - c; colsRepeatedStr := IfThen(colsRepeated = 1, '', Format('table:number-columns-repeated="%d"', [colsRepeated])); - Result := Result + Format( - ' ', [colsRepeatedStr]) + LineEnding; - end - else begin - WriteCellCallback(cell, nil); - Result := Result + FCellContent; - end; + AppendToStream(AStream, Format( + '', [colsRepeatedStr])); + end else + WriteCellCallback(cell, AStream); inc(c, colsRepeated); end; - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, + ''); // Next row inc(r, rowsRepeated); end; end; -function TsSpreadOpenDocWriter.WriteRowStylesXMLAsString: string; +procedure TsSpreadOpenDocWriter.WriteRowStyles(AStream: TStream); var i: Integer; rowstyle: TRowStyleData; + s: String; + useOptRowH: String; begin - Result := ''; + if FRowStyleList.Count = 0 then begin + AppendToStream(AStream, + '', + '', + ''); + exit; + end; for i := 0 to FRowStyleList.Count-1 do begin rowStyle := TRowStyleData(FRowStyleList[i]); // Start and Name - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, Format( + '', [rowStyle.Name])); // Column width - Result := Result + - ' ' + LineEnding; + AppendToStream(AStream, Format( + ''); // End - Result := Result + - ' ' + LineEnding; - - Result := Format(Result, [rowStyle.Name, rowStyle.RowHeight], FPointSeparatorSettings); + AppendToStream(AStream, + ''); end; end; @@ -2929,8 +3129,16 @@ var begin Unused(AOverwriteExisting); - { Fill the strings with the contents of the files } + { Analyze the workbook and collect all information needed } + ListAllNumFormats; + ListAllFormattingStyles; + ListAllColumnStyles; + ListAllRowStyles; + { Create the streams that will hold the file contents } + CreateStreams; + + { Fill the strings with the contents of the files } WriteMimetype(); WriteMetaInfManifest(); WriteMeta(); @@ -2938,17 +3146,7 @@ begin WriteStyles(); WriteContent; - { Write the data to streams } - - FSMeta := TStringStream.Create(FMeta); - FSSettings := TStringStream.Create(FSettings); - FSStyles := TStringStream.Create(FStyles); - FSContent := TStringStream.Create(FContent); - FSMimetype := TStringStream.Create(FMimetype); - FSMetaInfManifest := TStringStream.Create(FMetaInfManifest); - { Now compress the files } - FZip := TZipper.Create; try FZip.FileName := AFileName; @@ -2960,15 +3158,12 @@ begin FZip.Entries.AddFileEntry(FSMimetype, OPENDOC_PATH_MIMETYPE); FZip.Entries.AddFileEntry(FSMetaInfManifest, OPENDOC_PATH_METAINF_MANIFEST); + ResetStreams; + FZip.ZipAllFiles; finally + DestroyStreams; FZip.Free; - FSMeta.Free; - FSSettings.Free; - FSStyles.Free; - FSContent.Free; - FSMimetype.Free; - FSMetaInfManifest.Free; end; end; @@ -3012,12 +3207,10 @@ begin // Write empty cell only if it has formatting if ACell^.UsedFormattingFields <> [] then begin lIndex := FindFormattingInList(ACell); - lStyle := ' table:style-name="ce' + IntToStr(lIndex) + '" '; - FCellContent := - ' ' + LineEnding + - ' ' + LineEnding; - end else - FCellContent := ''; + AppendToStream(AStream, Format( + '', [lIndex]), + ''); + end; end; { Creates an XML string for inclusion of the background color into the @@ -3034,7 +3227,6 @@ begin Result := Format('fo:background-color="%s" ', [ Workbook.GetPaletteColorAsHTMLStr(AFormat.BackgroundColor) ]); -// + Workbook.FPSColorToHexString(FFormattingStyles[i].BackgroundColor, FFormattingStyles[i].RGBBackgroundColor) +'" '; end; { Creates an XML string for inclusion of borders and border styles into the @@ -3106,30 +3298,6 @@ begin ); end; -function TsSpreadOpenDocWriter.WriteFontNamesXMLAsString: String; -var - L: TStringList; - fnt: TsFont; - i: Integer; -begin - Result := ''; - L := TStringList.Create; - try - for i:=0 to Workbook.GetFontCount-1 do begin - fnt := Workbook.GetFont(i); - if (fnt <> nil) and (L.IndexOf(fnt.FontName) = -1) then - L.Add(fnt.FontName); - end; - for i:=0 to L.Count-1 do - Result := Format( - '', - [ L[i], L[i] ] - ); - finally - L.Free; - end; -end; - function TsSpreadOpenDocWriter.WriteFontStyleXMLAsString(const AFormat: TCell): String; var fnt: TsFont; @@ -3182,7 +3350,7 @@ begin end; end; -function TsSpreadOpenDocWriter.WriteTableSettingsXMLAsString(AIndent: String): String; +procedure TsSpreadOpenDocWriter.WriteTableSettings(AStream: TStream); var i: Integer; sheet: TsWorkSheet; @@ -3191,11 +3359,12 @@ var asr: Integer; // ActiveSplitRange showGrid: Boolean; begin - Result := ''; for i:=0 to Workbook.GetWorksheetCount-1 do begin sheet := Workbook.GetWorksheetByIndex(i); - Result := Result + AIndent + - '' + LineEnding; + + AppendToStream(AStream, + ''); + hsm := 0; vsm := 0; asr := 2; if (soHasFrozenPanes in sheet.Options) then begin if (sheet.LeftPaneWidth > 0) and (sheet.TopPaneHeight > 0) then begin @@ -3208,21 +3377,34 @@ begin end; end; showGrid := (soShowGridLines in sheet.Options); - Result := Result + AIndent + - ' '+IntToStr(sheet.LeftPaneWidth)+'' + LineEnding + AIndent + - ' '+IntToStr(sheet.TopPaneHeight)+'' + LineEnding + AIndent + - ' '+IntToStr(hsm)+'' + LineEnding + AIndent + - ' '+IntToStr(vsm)+'' + LineEnding + AIndent + - ' '+IntToStr(sheet.LeftPaneWidth)+'' + LineEnding + AIndent + - ' '+IntToStr(sheet.TopPaneHeight)+'' + LineEnding + AIndent + - ' '+IntToStr(asr)+'' + LineEnding + AIndent + - ' 0' + LineEnding + AIndent + - ' '+IntToStr(sheet.LeftPaneWidth)+'' + LineEnding + AIndent + - ' 0' + LineEnding + AIndent + - ' '+IntToStr(sheet.TopPaneHeight)+'' + LineEnding + AIndent + - ' true' + LineEnding + AIndent + + + AppendToStream(AStream, + ''+IntToStr(sheet.LeftPaneWidth)+''); + AppendToStream(AStream, + ''+IntToStr(sheet.TopPaneHeight)+''); + AppendToStream(AStream, + ''+IntToStr(hsm)+''); + AppendToStream(AStream, + ''+IntToStr(vsm)+''); + AppendToStream(AStream, + ''+IntToStr(sheet.LeftPaneWidth)+''); + AppendToStream(AStream, + ''+IntToStr(sheet.TopPaneHeight)+''); + AppendToStream(AStream, + ''+IntToStr(asr)+''); + AppendToStream(AStream, + '0'); + AppendToStream(AStream, + ''+IntToStr(sheet.LeftPaneWidth)+''); + AppendToStream(AStream, + '0'); + AppendToStream(AStream, + ''+IntToStr(sheet.TopPaneHeight)+''); + AppendToStream(AStream, + 'true'); // this "ShowGrid" overrides the global setting. But Open/LibreOffice do not allow to change ShowGrid per sheet. - '' + LineEnding; + AppendToStream(AStream, + ''); end; end; @@ -3293,10 +3475,10 @@ begin lStyle := ''; // The row should already be the correct one - FCellContent := - ' ' + LineEnding + - ' ' + UTF8TextToXMLText(AValue) + '' + LineEnding + - ' ' + LineEnding; + AppendToStream(AStream, + '', + '' + UTF8TextToXMLText(AValue) + '', + ''); end; procedure TsSpreadOpenDocWriter.WriteNumber(AStream: TStream; const ARow, @@ -3324,16 +3506,17 @@ begin // The row should already be the correct one if IsInfinite(AValue) then begin - StrValue:='1.#INF'; - DisplayStr:='1.#INF'; + StrValue := '1.#INF'; + DisplayStr := '1.#INF'; end else begin - StrValue:=FloatToStr(AValue,FPointSeparatorSettings); //Uses '.' as decimal separator - DisplayStr:=FloatToStr(AValue); // Uses locale decimal separator + StrValue := FloatToStr(AValue, FPointSeparatorSettings); // Uses '.' as decimal separator + DisplayStr := FloatToStr(AValue); // Uses locale decimal separator end; - FCellContent := - ' ' + LineEnding + - ' ' + DisplayStr + '' + LineEnding + - ' ' + LineEnding; + + AppendToStream(AStream, + '', + '' + DisplayStr + '', + ''); end; {******************************************************************* @@ -3372,12 +3555,10 @@ begin strValue := FormatDateTime(FMT[isTimeOnly], AValue); displayStr := FormatDateTime(ACell^.NumberFormatStr, AValue); - FCellContent := Format( - ' ' + LineEnding + - ' %s ' + LineEnding + - ' ' + LineEnding, [ - DT[isTimeOnly], DT[isTimeOnly], strValue, lStyle, displayStr - ]); + AppendToStream(AStream, Format( + '' + + '%s ' + + '', [DT[isTimeOnly], DT[isTimeOnly], strValue, lStyle, displayStr])); end; {