diff --git a/components/fpspreadsheet/examples/csvdemo/csvread.lpi b/components/fpspreadsheet/examples/csvdemo/csvread.lpi
new file mode 100644
index 000000000..5d808975b
--- /dev/null
+++ b/components/fpspreadsheet/examples/csvdemo/csvread.lpi
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/csvdemo/csvread.lpr b/components/fpspreadsheet/examples/csvdemo/csvread.lpr
new file mode 100644
index 000000000..a4cc1a4fc
--- /dev/null
+++ b/components/fpspreadsheet/examples/csvdemo/csvread.lpr
@@ -0,0 +1,62 @@
+{
+csvread.dpr
+
+Demonstrates how to read a CSV file using the fpspreadsheet library
+}
+
+program myexcel2read;
+
+{$mode delphi}{$H+}
+
+uses
+ Classes, SysUtils, fpspreadsheet, fpscsv;
+
+var
+ MyWorkbook: TsWorkbook;
+ MyWorksheet: TsWorksheet;
+ InputFilename: string;
+ MyDir: string;
+ i: Integer;
+ CurCell: PCell;
+begin
+ // Open the input file
+ MyDir := ExtractFilePath(ParamStr(0));
+ InputFileName := MyDir + 'test' + STR_COMMA_SEPARATED_EXTENSION;
+ if not FileExists(InputFileName) then begin
+ WriteLn('Input file ', InputFileName, ' does not exist. Please run excel2write first.');
+ Halt;
+ end;
+
+ WriteLn('Opening input file ', InputFilename);
+
+ CSVParams.ColDelimiter := #9;
+
+ // Create the spreadsheet
+ MyWorkbook := TsWorkbook.Create;
+ MyWorkbook.Options := MyWorkbook.Options + [boReadFormulas];
+ MyWorkbook.ReadFromFile(InputFilename, sfCSV);
+
+ MyWorksheet := MyWorkbook.GetFirstWorksheet;
+
+ // Write all cells with contents to the console
+ WriteLn('');
+ WriteLn('Contents of the first worksheet of the file:');
+ WriteLn('');
+
+ CurCell := MyWorkSheet.GetFirstCell();
+ for i := 0 to MyWorksheet.GetCellCount - 1 do
+ begin
+ if HasFormula(CurCell) then
+ WriteLn('Row: ', CurCell^.Row, ' Col: ', CurCell^.Col, ' Formula: ', MyWorksheet.ReadFormulaAsString(CurCell))
+ else
+ WriteLn('Row: ', CurCell^.Row,
+ ' Col: ', CurCell^.Col,
+ ' Value: ', UTF8ToAnsi(MyWorkSheet.ReadAsUTF8Text(CurCell^.Row, CurCell^.Col))
+ );
+ CurCell := MyWorkSheet.GetNextCell();
+ end;
+
+ // Finalization
+ MyWorkbook.Free;
+end.
+
diff --git a/components/fpspreadsheet/examples/csvdemo/csvwrite.lpi b/components/fpspreadsheet/examples/csvdemo/csvwrite.lpi
new file mode 100644
index 000000000..1967c5dff
--- /dev/null
+++ b/components/fpspreadsheet/examples/csvdemo/csvwrite.lpi
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/fpspreadsheet/examples/csvdemo/csvwrite.lpr b/components/fpspreadsheet/examples/csvdemo/csvwrite.lpr
new file mode 100644
index 000000000..f51a5d126
--- /dev/null
+++ b/components/fpspreadsheet/examples/csvdemo/csvwrite.lpr
@@ -0,0 +1,322 @@
+{
+csvwrite.dpr
+
+Demonstrates how to write a CSV file using the fpspreadsheet library
+
+}
+program csvwrite;
+
+{$mode delphi}{$H+}
+
+uses
+ Classes, SysUtils, fpspreadsheet, fpscsv;
+
+var
+ MyWorkbook: TsWorkbook;
+ MyWorksheet: TsWorksheet;
+ MyRPNFormula: TsRPNFormula;
+ MyDir: string;
+ number: Double;
+ lCol: TCol;
+ lRow: TRow;
+ r: Integer;
+ fmt: String;
+begin
+ // Open the output file
+ MyDir := ExtractFilePath(ParamStr(0));
+
+ // Create the spreadsheet
+ MyWorkbook := TsWorkbook.Create;
+ MyWorksheet := MyWorkbook.AddWorksheet('My Worksheet');
+
+ //MyWorksheet.WriteColWidth(0, 5);
+ //MyWorksheet.WriteColWidth(1, 30);
+
+ MyWorksheet.WriteRowHeight(0, 3); // 3 lines
+
+ // Turn off grid lines and hide headers
+ //MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines, soShowHeaders];
+
+// -- currently not working
+ MyWorksheet.Options := MyWorksheet.Options + [soHasFrozenPanes];
+ MyWorksheet.LeftPaneWidth := 1;
+ MyWorksheet.TopPaneHeight := 3;
+
+ // Write some number cells
+ MyWorksheet.WriteUsedFormatting(0, 0, [uffBold, uffNumberFormat]);
+ MyWorksheet.WriteNumber(0, 1, 2.0);
+ MyWorksheet.WriteNumber(0, 2, 3.0);
+ MyWorksheet.WriteNumber(0, 3, 4.0);
+
+ // Write some string cells
+ MyWorksheet.WriteUTF8Text(1, 0, 'First');
+ MyWorksheet.WriteFont (1, 0, 'Arial', 12, [fssBold, fssItalic, fssUnderline], scRed);
+ MyWorksheet.WriteUTF8Text(1, 1, 'Second');
+ MyWorksheet.WriteUTF8Text(1, 2, 'Third');
+ MyWorksheet.WriteUTF8Text(1, 3, 'Fourth');
+
+ // Write current date/time
+ MyWorksheet.WriteDateTime(2, 0, now);
+
+ // Write cell with background color
+ MyWorksheet.WriteUTF8Text(3, 0, 'Text');
+ MyWorksheet.WriteBackgroundColor(3, 0, scSilver);
+
+ // Empty cell with background color
+ MyWorksheet.WriteBackgroundColor(3, 1, scGrey);
+
+ // Cell2 with top and bottom borders
+ MyWorksheet.WriteUTF8Text(4, 0, 'Text');
+ MyWorksheet.WriteBorders(4, 0, [cbNorth, cbSouth]);
+ MyWorksheet.WriteBorders(4, 1, [cbNorth, cbSouth]);
+ MyWorksheet.WriteBorders(4, 2, [cbNorth, cbSouth]);
+
+ // Left, center, right aligned texts
+ MyWorksheet.WriteUTF8Text(5, 0, 'L');
+ MyWorksheet.WriteUTF8Text(5, 1, 'C');
+ MyWorksheet.WriteUTF8Text(5, 2, 'R');
+ MyWorksheet.WriteHorAlignment(5, 0, haLeft);
+ MyWorksheet.WriteHorAlignment(5, 1, haCenter);
+ MyWorksheet.WriteHorAlignment(5, 2, haRight);
+
+ // Red font, italic
+ MyWorksheet.WriteNumber(6, 0, 2014);
+ MyWorksheet.WriteFont(6, 0, 'Calibri', 15, [fssItalic], scRed);
+ MyWorksheet.WriteNumber(6, 1, 2015);
+ MyWorksheet.WriteFont(6, 1, 'Times New Roman', 9, [fssUnderline], scBlue);
+ MyWorksheet.WriteNumber(6, 2, 2016);
+ MyWorksheet.WriteFont(6, 2, 'Courier New', 8, [], scBlue);
+ MyWorksheet.WriteNumber(6, 3, 2017);
+ MyWorksheet.WriteFont(6, 3, 'Arial', 18, [fssBold], scBlue);
+
+ r:= 10;
+ // Write current date/time and test numbers for various formatting options
+
+ inc(r, 2);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongDate');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongDate);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortDateTime');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortDateTime);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, ''dd/mmm''');
+ MyWorksheet.WriteDateTime(r, 1, now, nfCustom, 'dd/mmm''');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, ''mmm/yy''');
+ MyWorksheet.WriteDateTime(r, 1, now, nfCustom, 'mmm/yy');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfShortTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfShortTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfLongTimeAM');
+ MyWorksheet.WriteDateTime(r, 1, now, nfLongTimeAM);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, nn:ss');
+ MyWorksheet.WriteDateTime(r, 1, now, nfCustom, 'nn:ss');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, nn:ss.z');
+ MyWorksheet.WriteDateTime(r, 1, now, nfCustom, 'nn:ss.z');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, mm:ss.zzz');
+ MyWorksheet.WriteDateTime(r, 1, now, nfCustom, 'mm:ss.zzz');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+
+ // Write formatted numbers
+ number := 12345.67890123456789;
+ inc(r, 2);
+ MyWorksheet.WriteUTF8Text(r, 1, '12345.67890123456789');
+ MyWorksheet.WriteUTF8Text(r, 2, '-12345.67890123456789');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfGeneral');
+ MyWorksheet.WriteNumber(r, 1, number, nfGeneral);
+ MyWorksheet.WriteNumber(r, 2, -number, nfGeneral);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 1);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixed, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixed, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixed, 3);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 0);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 1);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfFixedTh, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfFixedTh, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfFixedTh, 3);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 3, scGray);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 1);
+ MyWorksheet.WriteFontColor(r, 4, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 2);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 3, scGray);
+ MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
+ MyWorksheet.WriteFontColor(r, 4, scGray);
+ inc(r,2);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrency, 0 decs');
+ MyWorksheet.WriteCurrency(r, 1, number, nfCurrency, 0, '$');
+ MyWorksheet.WriteCurrency(r, 2, -number, nfCurrency, 0, '$');
+ MyWorksheet.WriteCurrency(r, 3, 0.0, nfCurrency, 0, '$');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCurrencyRed, 0 decs');
+ MyWorksheet.WriteCurrency(r, 1, number, nfCurrencyRed, 0, 'USD');
+ MyWorksheet.WriteCurrency(r, 2, -number, nfCurrencyRed, 0, 'USD');
+ MyWorksheet.WriteCurrency(r, 3, 0.0, nfCurrencyRed, 0, 'USD');
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0_);("$"#,##0)');
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ fmt := '"€"#,##0.0_);[Red]("€"#,##0.0)';
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, '+fmt);
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ fmt := '[Green]"¥"#,##0.0_);[Red]-"¥"#,##0.0';
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, '+fmt);
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteNumber(r, 1, number);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteNumber(r, 2, -number);
+ MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
+ MyWorksheet.WriteFontColor(r, 2, scGray);
+ inc(r, 2);
+ number := 1.333333333;
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 0 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 0);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 1 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 1);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 2 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 2);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfPercentage, 3 decs');
+ MyWorksheet.WriteNumber(r, 1, number, nfPercentage, 3);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm:ss');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'H:M:s');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+ MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
+ MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
+ MyWorksheet.WriteFontColor(r, 1, scGray);
+ inc(r);
+
+ // Set width of columns 0 to 3
+ MyWorksheet.WriteColWidth(0, 48); // 48 characters, default is 12 --> 4x default width
+ lCol.Width := 24; // 24 characters, default is 12 --> 2x default width
+ MyWorksheet.WriteColInfo(1, lCol);
+ MyWorksheet.WriteColInfo(2, lCol);
+ MyWorksheet.WriteColInfo(3, lCol);
+
+ // Set height of rows 5 and 6
+ lRow.Height := 4; // 4 lines
+ MyWorksheet.WriteRowInfo(5, lRow);
+ lRow.Height := 2; // 2 lines
+ MyWorksheet.WriteRowInfo(6, lRow);
+
+ CSVParams.ColDelimiter := #9;
+ CSVParams.DecimalSeparator := '.';
+ CSVParams.DateTimeFormat := 'YYYYMMDD-HHNNSS';
+ CSVParams.NumberFormat := '%.9f';
+ CSVParams.QuoteChar := '''';
+
+ // Save the spreadsheet to a file
+ MyWorkbook.WriteToFile(MyDir + 'test' + STR_COMMA_SEPARATED_EXTENSION, sfCSV, true);
+ MyWorkbook.Free;
+end.
+
diff --git a/components/fpspreadsheet/examples/spready/mainform.lfm b/components/fpspreadsheet/examples/spready/mainform.lfm
index 51d03ba73..e64b0770a 100644
--- a/components/fpspreadsheet/examples/spready/mainform.lfm
+++ b/components/fpspreadsheet/examples/spready/mainform.lfm
@@ -516,14 +516,14 @@ object MainFrm: TMainFrm
end
object OpenDialog: TOpenDialog
DefaultExt = '.xls'
- Filter = 'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlsx|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (pipes) (.wikitable_pipes)|*.wikitable_pipes|All files (*.*)|*.*'
+ Filter = 'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlsx|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Comma-delimited files (*.csv)|*.csv|Wikitable (pipes) (.wikitable_pipes)|*.wikitable_pipes|All files (*.*)|*.*'
Options = [ofExtensionDifferent, ofEnableSizing, ofViewDetail]
left = 184
top = 200
end
object SaveDialog: TSaveDialog
DefaultExt = '.xls'
- Filter = 'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlsx|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (wikimedia) (.wikitable_wikimedia)|*.wikitable_wikimedia'
+ Filter = 'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlsx|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Comma-delimited file (*.csv)|*.csv|Wikitable (wikimedia) (.wikitable_wikimedia)|*.wikitable_wikimedia'
Options = [ofOverwritePrompt, ofExtensionDifferent, ofEnableSizing, ofViewDetail]
left = 184
top = 264
diff --git a/components/fpspreadsheet/fpsallformats.pas b/components/fpspreadsheet/fpsallformats.pas
index fd4719b9c..2cf2c860a 100755
--- a/components/fpspreadsheet/fpsallformats.pas
+++ b/components/fpspreadsheet/fpsallformats.pas
@@ -10,7 +10,7 @@ unit fpsallformats;
interface
uses
- xlsbiff2, xlsbiff5, xlsbiff8, fpsopendocument, xlsxooxml, wikitable;
+ xlsbiff2, xlsbiff5, xlsbiff8, fpsopendocument, xlsxooxml, wikitable, fpscsv;
implementation
diff --git a/components/fpspreadsheet/fpscsv.pas b/components/fpspreadsheet/fpscsv.pas
new file mode 100644
index 000000000..5cbec9649
--- /dev/null
+++ b/components/fpspreadsheet/fpscsv.pas
@@ -0,0 +1,346 @@
+unit fpscsv;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils,
+ fpspreadsheet;
+
+type
+ TsCSVReader = class(TsCustomSpreadReader)
+ private
+ FFormatSettings: TFormatSettings;
+ FRow, FCol: Cardinal;
+ FCellValue: String;
+ FWorksheetName: String;
+ protected
+ procedure ProcessCellValue(AStream: TStream);
+ procedure ReadBlank(AStream: TStream); override;
+ procedure ReadFormula(AStream: TStream); override;
+ procedure ReadLabel(AStream: TStream); override;
+ procedure ReadNumber(AStream: TStream); override;
+ public
+ constructor Create(AWorkbook: TsWorkbook); override;
+ procedure ReadFromFile(AFileName: String; AData: TsWorkbook); override;
+ procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); override;
+ procedure ReadFromStrings(AStrings: TStrings; AData: TsWorkbook); override;
+ end;
+
+ TsCSVWriter = class(TsCustomSpreadWriter)
+ private
+ FFormatSettings: TFormatSettings;
+
+ protected
+ procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
+ ACell: PCell); override;
+ procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
+ const AValue: TDateTime; ACell: PCell); override;
+ procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal;
+ ACell: PCell); override;
+ procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
+ const AValue: string; ACell: PCell); override;
+ procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
+ const AValue: double; ACell: PCell); override;
+
+ procedure WriteSheet(AStream: TStream; AWorksheet: TsWorksheet);
+
+ public
+ constructor Create(AWorkbook: TsWorkbook); override;
+ procedure WriteToStream(AStream: TStream); override;
+ procedure WriteToStrings(AStrings: TStrings); override;
+ end;
+
+ TsCSVParams = record
+ LineDelimiter: String; // LineEnding
+ ColDelimiter: Char; // ';', ',', TAB (#9)
+ QuoteChar: Char; // use #0 if strings are not quoted
+ NumberFormat: String; // if empty, numbers are formatted as in sheet
+ DateTimeFormat: String; // if empty, date/times are formatted as in sheet
+ DecimalSeparator: Char; // '.', ',', #0 if using workbook's formatsetting
+ SheetIndex: Integer; // -1 for all sheets
+ end;
+
+var
+ CSVParams: TsCSVParams = (
+ LineDelimiter: ''; // is replaced by LineEnding at runtime
+ ColDelimiter: ';';
+ QuoteChar: '"';
+ NumberFormat: ''; // Use number format of worksheet
+ DateTimeFormat: ''; // Use DateTime format of worksheet
+ DecimalSeparator: '.';
+ SheetIndex: 0; // Store sheet #0
+ );
+
+implementation
+
+uses
+ StrUtils, DateUtils, fpsutils;
+
+{ -----------------------------------------------------------------------------}
+{ TsCSVReader }
+{------------------------------------------------------------------------------}
+constructor TsCSVReader.Create(AWorkbook: TsWorkbook);
+begin
+ inherited Create(AWorkbook);
+ FFormatSettings := AWorkbook.FormatSettings;
+ FWorksheetName := 'Sheet1';
+end;
+
+procedure TsCSVReader.ProcessCellValue(AStream: TStream);
+begin
+ if FCellValue = '' then
+ ReadBlank(AStream)
+ else
+ if (Length(FCellValue) > 1) and (
+ ((FCellValue[1] = '"') and (FCellValue[Length(FCellValue)] = '"'))
+ or
+ (not (CSVParams.QuoteChar in [#0, '"']) and (FCellValue[1] = CSVParams.QuoteChar)
+ and (FCellValue[Length(FCellValue)] = CSVParams.QuoteChar))
+ ) then
+ begin
+ Delete(FCellValue, Length(FCellValue), 1);
+ Delete(FCellValue, 1, 1);
+ ReadLabel(AStream);
+ end else
+ ReadNumber(AStream);
+end;
+
+procedure TsCSVReader.ReadBlank(AStream: TStream);
+begin
+ // We could write a blank cell, but since CSV does not support formatting
+ // this would be a waste of memory. --> Just do nothing
+end;
+
+procedure TsCSVReader.ReadFormula(AStream: TStream);
+begin
+ // Nothing to do - CSV does not support formulas
+end;
+
+procedure TsCSVReader.ReadFromFile(AFileName: String; AData: TsWorkbook);
+begin
+ FWorksheetName := ChangeFileExt(ExtractFileName(AFileName), '');
+ inherited;
+end;
+
+procedure TsCSVReader.ReadFromStream(AStream: TStream; AData: TsWorkbook);
+var
+ n: Int64;
+ ch: Char;
+ nextch: Char;
+begin
+ FWorkbook := AData;
+ FWorksheet := AData.AddWorksheet(FWorksheetName);
+ n := AStream.Size;
+ FCellValue := '';
+ FRow := 0;
+ FCol := 0;
+ while AStream.Position < n do begin
+ ch := char(AStream.ReadByte);
+ if ch = CSVParams.ColDelimiter then begin
+ // End of column reached
+ ProcessCellValue(AStream);
+ inc(FCol);
+ FCellValue := '';
+ end else
+ if (ch = #13) or (ch = #10) then begin
+ // End of row reached
+ ProcessCellValue(AStream);
+ inc(FRow);
+ FCol := 0;
+ FCellValue := '';
+
+ // look for CR+LF: if true, skip next byte
+ if AStream.Position+1 < n then begin
+ nextch := char(AStream.ReadByte);
+ if ((ch = #13) and (nextch <> #10)) then
+ AStream.Position := AStream.Position - 1; // re-read nextchar in next loop
+ end;
+ end else
+ FCellValue := FCellValue + ch;
+ end;
+end;
+
+procedure TsCSVReader.ReadFromStrings(AStrings: TStrings; AData: TsWorkbook);
+var
+ stream: TStringStream;
+begin
+ stream := TStringStream.Create(AStrings.Text);
+ try
+ ReadFromStream(stream, AData);
+ finally
+ stream.Free;
+ end;
+end;
+
+procedure TsCSVReader.ReadLabel(AStream: TStream);
+begin
+ Unused(AStream);
+ FWorksheet.WriteUTF8Text(FRow, FCol, FCellValue);
+end;
+
+procedure TsCSVReader.ReadNumber(AStream: TStream);
+var
+ dbl: Double;
+ dt: TDateTime;
+ fs: TFormatSettings;
+begin
+ Unused(AStream);
+
+ // Try as float
+ fs := FFormatSettings;
+ if CSVParams.DecimalSeparator <> #0 then
+ fs.DecimalSeparator := CSVParams.DecimalSeparator;
+ if TryStrToFloat(FCellValue, dbl, fs) then
+ begin
+ FWorksheet.WriteNumber(FRow, FCol, dbl);
+ FWorkbook.FormatSettings.DecimalSeparator := fs.DecimalSeparator;
+ exit;
+ end;
+ if fs.DecimalSeparator = '.'
+ then fs.DecimalSeparator := ','
+ else fs.DecimalSeparator := '.';
+ if TryStrToFloat(FCellValue, dbl, fs) then
+ begin
+ FWorksheet.WriteNumber(FRow, FCol, dbl);
+ FWorkbook.FormatSettings.DecimalSeparator := fs.DecimalSeparator;
+ exit;
+ end;
+
+ // Try as date/time
+ fs := FFormatSettings;
+ if TryStrToDateTime(FCellValue, dt, fs) then
+ begin
+ FWorksheet.WriteDateTime(FRow, FCol, dt);
+ exit;
+ end;
+
+ // Could not convert to float or date/time. Show at least as label.
+ FWorksheet.WriteUTF8Text(FRow, FCol, FCellValue);
+end;
+
+
+{ -----------------------------------------------------------------------------}
+{ TsCSVWriter }
+{------------------------------------------------------------------------------}
+constructor TsCSVWriter.Create(AWorkbook: TsWorkbook);
+begin
+ inherited Create(AWorkbook);
+ FFormatSettings := AWorkbook.FormatSettings;
+ if CSVParams.DecimalSeparator <> #0 then
+ FFormatSettings.DecimalSeparator := CSVParams.DecimalSeparator;
+ if CSVParams.LineDelimiter = '' then
+ CSVParams.LineDelimiter := LineEnding;
+end;
+
+procedure TsCSVWriter.WriteBlank(AStream: TStream; const ARow, ACol: Cardinal;
+ ACell: PCell);
+begin
+ Unused(AStream);
+ Unused(ARow, ACol, ACell);
+ // nothing to do
+end;
+
+procedure TsCSVWriter.WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
+ const AValue: TDateTime; ACell: PCell);
+var
+ s: String;
+begin
+ Unused(ARow, ACol);
+ if CSVParams.DateTimeFormat <> '' then
+ s := FormatDateTime(CSVParams.DateTimeFormat, AValue, FFormatSettings)
+ else
+ s := FWorksheet.ReadAsUTF8Text(ACell);
+ AppendToStream(AStream, s);
+end;
+
+procedure TsCSVWriter.WriteFormula(AStream: TStream; const ARow, ACol: Cardinal;
+ ACell: PCell);
+begin
+ // no formulas in CSV
+ Unused(AStream);
+ Unused(ARow, ACol, AStream);
+end;
+
+procedure TsCSVWriter.WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
+ const AValue: string; ACell: PCell);
+var
+ s: String;
+begin
+ Unused(ARow, ACol);
+ if ACell = nil then
+ exit;
+ s := ACell^.UTF8StringValue;
+ if CSVParams.QuoteChar <> #0 then
+ s := CSVParams.QuoteChar + s + CSVParams.QuoteChar;
+ AppendToStream(AStream, s);
+end;
+
+procedure TsCSVWriter.WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
+ const AValue: double; ACell: PCell);
+var
+ s: String;
+ mask: String;
+begin
+ Unused(ARow, ACol);
+ if ACell = nil then
+ exit;
+ if CSVParams.NumberFormat <> '' then
+ s := Format(CSVParams.NumberFormat, [AValue], FFormatSettings)
+ else
+ s := FWorksheet.ReadAsUTF8Text(ACell);
+ AppendToStream(AStream, s);
+end;
+
+procedure TsCSVWriter.WriteSheet(AStream: TStream; AWorksheet: TsWorksheet);
+var
+ r, c: Cardinal;
+ lastRow, lastCol: Cardinal;
+ cell: PCell;
+begin
+ FWorksheet := AWorksheet;
+ lastRow := FWorksheet.GetLastOccupiedRowIndex;
+ lastCol := FWorksheet.GetLastOccupiedColIndex;
+ for r := 0 to lastRow do
+ for c := 0 to lastCol do begin
+ cell := FWorksheet.FindCell(r, c);
+ if cell <> nil then
+ WriteCellCallback(cell, AStream);
+ if c = lastCol then
+ AppendToStream(AStream, CSVParams.LineDelimiter)
+ else
+ AppendToStream(AStream, CSVParams.ColDelimiter);
+ end;
+end;
+
+procedure TsCSVWriter.WriteToStream(AStream: TStream);
+var
+ n: Integer;
+begin
+ if (CSVParams.SheetIndex >= 0) and (CSVParams.SheetIndex < FWorkbook.GetWorksheetCount)
+ then n := CSVParams.SheetIndex
+ else n := 0;
+ WriteSheet(AStream, FWorkbook.GetWorksheetByIndex(n));
+end;
+
+procedure TsCSVWriter.WriteToStrings(AStrings: TStrings);
+var
+ stream: TStream;
+begin
+ stream := TStringStream.Create('');
+ try
+ WriteToStream(stream);
+ stream.Position := 0;
+ AStrings.LoadFromStream(stream);
+ finally
+ stream.Free;
+ end;
+end;
+
+
+initialization
+ RegisterSpreadFormat(TsCSVReader, TsCSVWriter, sfCSV);
+
+end.
+