fpspreadsheet: Building a number format list which allows to drop most of the restrictions of the previous versions like number of decimal places. New number format "nfCustom" which passes the format string directly to the file.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3044 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-05-14 15:24:02 +00:00
parent ec0d54a269
commit c36a5e80ce
14 changed files with 2832 additions and 1446 deletions

View File

@ -20,6 +20,8 @@ var
number: Double;
lCol: TCol;
lRow: TRow;
r: Integer;
fmt: String;
begin
// Open the output file
MyDir := ExtractFilePath(ParamStr(0));
@ -34,7 +36,7 @@ begin
MyWorksheet.WriteRowHeight(0, 30); // 30 mm
// Turn off grid lines and hide headers
MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines, soShowHeaders];
//MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines, soShowHeaders];
{ -- currently not working
//MyWorksheet.Options := MyWorksheet.Options + [soHasFrozenPanes];
@ -108,67 +110,240 @@ begin
MyWorksheet.WriteNumber(6, 3, 2017);
MyWorksheet.WriteFont(6, 3, 'Arial', 18, [fssBold], scBlue);
// Write current date/time to cells B11:B16
MyWorksheet.WriteUTF8Text(10, 0, 'nfShortDate');
MyWorksheet.WriteDateTime(10, 1, now, nfShortDate);
MyWorksheet.WriteUTF8Text(11, 0, 'nfShortTime');
MyWorksheet.WriteDateTime(11, 1, now, nfShortTime);
MyWorksheet.WriteUTF8Text(12, 0, 'nfLongTime');
MyWorksheet.WriteDateTime(12, 1, now, nfLongTime);
MyWorksheet.WriteUTF8Text(13, 0, 'nfShortDateTime');
MyWorksheet.WriteDateTime(13, 1, now, nfShortDateTime);
MyWorksheet.WriteUTF8Text(14, 0, 'nfFmtDateTime, DM');
MyWorksheet.WriteDateTime(14, 1, now, nfFmtDateTime, 'DM');
MyWorksheet.WriteUTF8Text(15, 0, 'nfFmtDateTime, MY');
MyWorksheet.WriteDateTime(15, 1, now, nfFmtDateTime, 'MY');
MyWorksheet.WriteUTF8Text(16, 0, 'nfShortTimeAM');
MyWorksheet.WriteDateTime(16, 1, now, nfShortTimeAM);
MyWorksheet.WriteUTF8Text(17, 0, 'nfLongTimeAM');
MyWorksheet.WriteDateTime(17, 1, now, nfLongTimeAM);
MyWorksheet.WriteUTF8Text(18, 0, 'nfFmtDateTime, MS');
MyWorksheet.WriteDateTime(18, 1, now, nfFmtDateTime, 'MS');
MyWorksheet.WriteUTF8Text(19, 0, 'nfFmtDateTime, MSZ');
MyWorksheet.WriteDateTime(19, 1, now, nfFmtDateTime, 'MSZ');
r:= 10;
// Write current date/time and test numbers for various formatting options
MyWorksheet.WriteUTF8Text(r, 1, 'Formats in gray cells are not supported by BIFF2');
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, 'nfFmtDateTime, DM');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'DM');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MY');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MY');
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, 'nfFmtDateTime, MS');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MS');
MyWorksheet.WriteFontColor(r, 1, scGray);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MSZ');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MSZ');
MyWorksheet.WriteFontColor(r, 1, scGray);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
MyWorksheet.WriteFontColor(r, 1, scGray);
// Write formatted numbers
number := 12345.67890123456789;
MyWorksheet.WriteUTF8Text(24, 1, '12345.67890123456789');
MyWorksheet.WriteUTF8Text(24, 2, '-12345.67890123456789');
MyWorksheet.WriteUTF8Text(25, 0, 'nfFixed, 0 decs');
MyWorksheet.WriteNumber(25, 1, number, nfFixed, 0);
MyWorksheet.WriteNumber(25, 2, -number, nfFixed, 0);
MyWorksheet.WriteUTF8Text(26, 0, 'nfFixed, 2 decs');
MyWorksheet.WriteNumber(26, 1, number, nfFixed, 2);
MyWorksheet.WriteNumber(26, 2, -number, nfFixed, 2);
MyWorksheet.WriteUTF8Text(27, 0, 'nfFixedTh, 0 decs');
MyWorksheet.WriteNumber(27, 1, number, nfFixedTh, 0);
MyWorksheet.WriteNumber(27, 2, -number, nfFixedTh, 0);
MyWorksheet.WriteUTF8Text(28, 0, 'nfFixedTh, 2 decs');
MyWorksheet.WriteNumber(28, 1, number, nfFixedTh, 2);
MyWorksheet.WriteNumber(28, 2, -number, nfFixedTh, 2);
MyWorksheet.WriteUTF8Text(29, 0, 'nfSci, 1 dec');
MyWorksheet.WriteNumber(29, 1, number, nfSci);
MyWorksheet.WriteNumber(29, 2, -number, nfSci);
MyWorksheet.WriteNumber(29, 3, 1.0/number, nfSci);
MyWorksheet.WriteNumber(29, 4, -1.0/number, nfSci);
MyWorksheet.WriteUTF8Text(30, 0, 'nfExp, 2 decs');
MyWorksheet.WriteNumber(30, 1, number, nfExp, 2);
MyWorksheet.WriteNumber(30, 2, -number, nfExp, 2);
MyWorksheet.WriteNumber(30, 3, 1.0/number, nfExp, 2);
MyWorksheet.WriteNumber(30, 4, -1.0/number, nfExp, 2);
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, 'nfSci, 1 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
MyWorksheet.WriteFontColor(r, 1, scGray);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
MyWorksheet.WriteFontColor(r, 2, scGray);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 1);
MyWorksheet.WriteFontColor(r, 3, scGray);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 1);
MyWorksheet.WriteFontColor(r, 4, scGray);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 2 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 2);
MyWorksheet.WriteFontColor(r, 1, scGray);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 2);
MyWorksheet.WriteFontColor(r, 2, scGray);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 2);
MyWorksheet.WriteFontColor(r, 3, scGray);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 2);
MyWorksheet.WriteFontColor(r, 4, scGray);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 3 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 3);
MyWorksheet.WriteFontColor(r, 1, scGray);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 3);
MyWorksheet.WriteFontColor(r, 2, scGray);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
MyWorksheet.WriteFontColor(r, 3, scGray);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
MyWorksheet.WriteFontColor(r, 4, 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);
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(35, 0, 'nfPercentage, 0 decs');
MyWorksheet.WriteNumber(35, 1, number, nfPercentage, 0);
MyWorksheet.WriteUTF8Text(36, 0, 'nfPercentage, 2 decs');
MyWorksheet.WriteNumber(36, 1, number, nfPercentage, 2);
MyWorksheet.WriteUTF8Text(37, 0, 'nfTimeInterval');
MyWorksheet.WriteDateTime(37, 1, number, nfTimeInterval);
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);
// Set width of columns 0 and 1
MyWorksheet.WriteColWidth(0, 40);
lCol.Width := 35;
// Set width of columns 0 to 3
MyWorksheet.WriteColWidth(0, 50);
lCol.Width := 15;
MyWorksheet.WriteColInfo(1, lCol);
MyWorksheet.WriteColInfo(2, lCol);
MyWorksheet.WriteColInfo(3, lCol);
// Set height of rows 5 and 6
lRow.Height := 10;

View File

@ -25,8 +25,9 @@ var
MyWorksheet: TsWorksheet;
MyRPNFormula: TsRPNFormula;
MyDir: string;
i: Integer;
i, r: Integer;
number: Double;
fmt: string;
begin
MyDir := ExtractFilePath(ParamStr(0));
@ -50,6 +51,8 @@ begin
MyWorksheet.WriteColWidth(0, 40);
MyWorksheet.WriteColWidth(1, 20);
MyWorksheet.WriteColWidth(2, 20);
MyWorksheet.WriteColWidth(3, 15);
MyWorksheet.WriteColWidth(4, 15);
// Write some cells
MyWorksheet.WriteNumber(0, 0, 1.0);// A1
@ -155,62 +158,181 @@ begin
MyRPNFormula[1].ElementKind := fekABS;
MyWorksheet.WriteRPNFormula(0, 5, MyRPNFormula);
r:= 10;
// Write current date/time to cells B11:B16
MyWorksheet.WriteUTF8Text(10, 0, 'nfShortDate');
MyWorksheet.WriteDateTime(10, 1, now, nfShortDate);
MyWorksheet.WriteUTF8Text(11, 0, 'nfShortTime');
MyWorksheet.WriteDateTime(11, 1, now, nfShortTime);
MyWorksheet.WriteUTF8Text(12, 0, 'nfLongTime');
MyWorksheet.WriteDateTime(12, 1, now, nfLongTime);
MyWorksheet.WriteUTF8Text(13, 0, 'nfShortDateTime');
MyWorksheet.WriteDateTime(13, 1, now, nfShortDateTime);
MyWorksheet.WriteUTF8Text(14, 0, 'nfFmtDateTime, DM');
MyWorksheet.WriteDateTime(14, 1, now, nfFmtDateTime, 'DM');
MyWorksheet.WriteUTF8Text(15, 0, 'nfFmtDateTime, MY');
MyWorksheet.WriteDateTime(15, 1, now, nfFmtDateTime, 'MY');
MyWorksheet.WriteUTF8Text(16, 0, 'nfShortTimeAM');
MyWorksheet.WriteDateTime(16, 1, now, nfShortTimeAM);
MyWorksheet.WriteUTF8Text(17, 0, 'nfLongTimeAM');
MyWorksheet.WriteDateTime(17, 1, now, nfLongTimeAM);
MyWorksheet.WriteUTF8Text(18, 0, 'nfFmtDateTime, MS');
MyWorksheet.WriteDateTime(18, 1, now, nfFmtDateTime, 'MS');
MyWorksheet.WriteUTF8Text(19, 0, 'nfFmtDateTime, MSZ');
MyWorksheet.WriteDateTime(19, 1, now, nfFmtDateTime, 'MSZ');
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, 'nfFmtDateTime, DM');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'DM');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MY');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MY');
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, 'nfFmtDateTime, MS');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MS');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MSZ');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MSZ');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
// Write formatted numbers
number := 12345.67890123456789;
MyWorksheet.WriteUTF8Text(24, 1, '12345.67890123456789');
MyWorksheet.WriteUTF8Text(24, 2, '-12345.67890123456789');
MyWorksheet.WriteUTF8Text(25, 0, 'nfFixed, 0 decs');
MyWorksheet.WriteNumber(25, 1, number, nfFixed, 0);
MyWorksheet.WriteNumber(25, 2, -number, nfFixed, 0);
MyWorksheet.WriteUTF8Text(26, 0, 'nfFixed, 2 decs');
MyWorksheet.WriteNumber(26, 1, number, nfFixed, 2);
MyWorksheet.WriteNumber(26, 2, -number, nfFixed, 2);
MyWorksheet.WriteUTF8Text(27, 0, 'nfFixedTh, 0 decs');
MyWorksheet.WriteNumber(27, 1, number, nfFixedTh, 0);
MyWorksheet.WriteNumber(27, 2, -number, nfFixedTh, 0);
MyWorksheet.WriteUTF8Text(28, 0, 'nfFixedTh, 2 decs');
MyWorksheet.WriteNumber(28, 1, number, nfFixedTh, 2);
MyWorksheet.WriteNumber(28, 2, -number, nfFixedTh, 2);
MyWorksheet.WriteUTF8Text(29, 0, 'nfSci, 1 dec');
MyWorksheet.WriteNumber(29, 1, number, nfSci);
MyWorksheet.WriteNumber(29, 2, -number, nfSci);
MyWorksheet.WriteNumber(29, 3, 1.0/number, nfSci);
MyWorksheet.WriteNumber(29, 4, -1.0/number, nfSci);
MyWorksheet.WriteUTF8Text(30, 0, 'nfExp, 2 decs');
MyWorksheet.WriteNumber(30, 1, number, nfExp, 2);
MyWorksheet.WriteNumber(30, 2, -number, nfExp, 2);
MyWorksheet.WriteNumber(30, 3, 1.0/number, nfExp, 2);
MyWorksheet.WriteNumber(30, 4, -1.0/number, nfExp, 2);
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.WriteNumber(r, 2, -number, nfFixed, 1);
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.WriteNumber(r, 2, -number, nfFixed, 3);
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.WriteNumber(r, 2, -number, nfFixedTh, 1);
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.WriteNumber(r, 2, -number, nfFixedTh, 3);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 1);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 1);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 2 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 2);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 2);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 2);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 2);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 3 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 3);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 3);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 1);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 1);
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.WriteNumber(r, 2, -number, nfExp, 3);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0_);("$"#,##0)');
MyWorksheet.WriteNumber(r, 1, number);
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0_);("$"#,##0)');
MyWorksheet.WriteNumber(r, 2, -number);
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0_);("$"#,##0)');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0.0_);[Red]("$"#,##0.0)');
MyWorksheet.WriteNumber(r, 1, number);
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)');
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.WriteNumber(r, 2, -number);
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
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.WriteNumber(r, 2, -number);
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, UTF8ToAnsi(fmt));
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, _("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
MyWorksheet.WriteNumber(r, 1, number);
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
MyWorksheet.WriteNumber(r, 2, -number);
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)');
inc(r, 2);
number := 1.333333333;
MyWorksheet.WriteUTF8Text(35, 0, 'nfPercentage, 0 decs');
MyWorksheet.WriteNumber(35, 1, number, nfPercentage, 0);
MyWorksheet.WriteUTF8Text(36, 0, 'nfPercentage, 2 decs');
MyWorksheet.WriteNumber(36, 1, number, nfPercentage, 2);
MyWorksheet.WriteUTF8Text(37, 0, 'nfTimeInterval');
MyWorksheet.WriteDateTime(37, 1, number, nfTimeInterval);
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);
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);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm:ss');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'H:M:s');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
//MyFormula.FormulaStr := '';

View File

@ -34,12 +34,17 @@
<PackageName Value="laz_fpspreadsheet"/>
</Item1>
</RequiredPackages>
<Units Count="1">
<Units Count="2">
<Unit0>
<Filename Value="excel8read.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="excel8read"/>
</Unit0>
<Unit1>
<Filename Value="mysysutils.pas"/>
<IsPartOfProject Value="True"/>
<UnitName Value="mysysutils"/>
</Unit1>
</Units>
</ProjectOptions>
<CompilerOptions>
@ -53,6 +58,11 @@
<UseAnsiStrings Value="False"/>
</SyntaxOptions>
</Parsing>
<Linking>
<Debugging>
<DebugInfoType Value="dsStabs"/>
</Debugging>
</Linking>
<Other>
<CompilerMessages>
<UseMsgFile Value="True"/>

View File

@ -11,7 +11,7 @@ program excel8read;
uses
Classes, SysUtils, fpspreadsheet, xlsbiff8,
laz_fpspreadsheet;
laz_fpspreadsheet, fpsutils;
var
MyWorkbook: TsWorkbook;
@ -21,6 +21,8 @@ var
i: Integer;
CurCell: PCell;
{$R *.res}
begin
// Open the input file
MyDir := ExtractFilePath(ParamStr(0));

View File

@ -26,11 +26,10 @@ var
MyWorksheet: TsWorksheet;
MyRPNFormula: TsRPNFormula;
MyDir: string;
i: Integer;
lCell: PCell;
number: Double;
lCell: PCell;
lCol: TCol;
lRow: TRow;
i, r: Integer;
begin
MyDir := ExtractFilePath(ParamStr(0));
@ -41,7 +40,6 @@ begin
MyWorksheet := MyWorkbook.AddWorksheet(Str_Worksheet1);
MyWorksheet.Options := MyWorksheet.Options - [soShowGridLines];
MyWorksheet.Options := MyWorksheet.Options + [soHasFrozenPanes];
myWorksheet.LeftPaneWidth := 1;
MyWorksheet.TopPaneHeight := 2;
@ -129,7 +127,7 @@ begin
// Uncomment this to test large XLS files
for i := 40 to 1000 do
for i := 50 to 1000 do
begin
// MyWorksheet.WriteUTF8Text(i, 0, ParamStr(0));
// MyWorksheet.WriteUTF8Text(i, 1, ParamStr(0));
@ -158,67 +156,169 @@ begin
MyRPNFormula[1].ElementKind := fekABS;
MyWorksheet.WriteRPNFormula(0, 5, MyRPNFormula);
r:= 10;
// Write current date/time to cells B11:B16
MyWorksheet.WriteUTF8Text(10, 0, 'nfShortDate');
MyWorksheet.WriteDateTime(10, 1, now, nfShortDate);
MyWorksheet.WriteUTF8Text(11, 0, 'nfShortTime');
MyWorksheet.WriteDateTime(11, 1, now, nfShortTime);
MyWorksheet.WriteUTF8Text(12, 0, 'nfLongTime');
MyWorksheet.WriteDateTime(12, 1, now, nfLongTime);
MyWorksheet.WriteUTF8Text(13, 0, 'nfShortDateTime');
MyWorksheet.WriteDateTime(13, 1, now, nfShortDateTime);
MyWorksheet.WriteUTF8Text(14, 0, 'nfFmtDateTime, DM');
MyWorksheet.WriteDateTime(14, 1, now, nfFmtDateTime, 'DM');
MyWorksheet.WriteUTF8Text(15, 0, 'nfFmtDateTime, MY');
MyWorksheet.WriteDateTime(15, 1, now, nfFmtDateTime, 'MY');
MyWorksheet.WriteUTF8Text(16, 0, 'nfShortTimeAM');
MyWorksheet.WriteDateTime(16, 1, now, nfShortTimeAM);
MyWorksheet.WriteUTF8Text(17, 0, 'nfLongTimeAM');
MyWorksheet.WriteDateTime(17, 1, now, nfLongTimeAM);
MyWorksheet.WriteUTF8Text(18, 0, 'nfFmtDateTime, MS');
MyWorksheet.WriteDateTime(18, 1, now, nfFmtDateTime, 'MS');
MyWorksheet.WriteUTF8Text(19, 0, 'nfFmtDateTime, MSZ');
MyWorksheet.WriteDateTime(19, 1, now, nfFmtDateTime, 'MSZ');
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, 'nfFmtDateTime, DM');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'DM');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MY');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MY');
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, 'nfFmtDateTime, MS');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MS');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, MSZ');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'MSZ');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfFmtDateTime, mm:ss.zzz');
MyWorksheet.WriteDateTime(r, 1, now, nfFmtDateTime, 'mm:ss.zzz');
// Write formatted numbers
number := 12345.67890123456789;
MyWorksheet.WriteUTF8Text(24, 1, '12345.67890123456789');
MyWorksheet.WriteUTF8Text(24, 2, '-12345.67890123456789');
MyWorksheet.WriteUTF8Text(25, 0, 'nfFixed, 0 decs');
MyWorksheet.WriteNumber(25, 1, number, nfFixed, 0);
MyWorksheet.WriteNumber(25, 2, -number, nfFixed, 0);
MyWorksheet.WriteUTF8Text(26, 0, 'nfFixed, 2 decs');
MyWorksheet.WriteNumber(26, 1, number, nfFixed, 2);
MyWorksheet.WriteNumber(26, 2, -number, nfFixed, 2);
MyWorksheet.WriteUTF8Text(27, 0, 'nfFixedTh, 0 decs');
MyWorksheet.WriteNumber(27, 1, number, nfFixedTh, 0);
MyWorksheet.WriteNumber(27, 2, -number, nfFixedTh, 0);
MyWorksheet.WriteUTF8Text(28, 0, 'nfFixedTh, 2 decs');
MyWorksheet.WriteNumber(28, 1, number, nfFixedTh, 2);
MyWorksheet.WriteNumber(28, 2, -number, nfFixedTh, 2);
MyWorksheet.WriteUTF8Text(29, 0, 'nfSci, 1 dec');
MyWorksheet.WriteNumber(29, 1, number, nfSci);
MyWorksheet.WriteNumber(29, 2, -number, nfSci);
MyWorksheet.WriteNumber(29, 3, 1.0/number, nfSci);
MyWorksheet.WriteNumber(29, 4, -1.0/number, nfSci);
MyWorksheet.WriteUTF8Text(30, 0, 'nfExp, 2 decs');
MyWorksheet.WriteNumber(30, 1, number, nfExp, 2);
MyWorksheet.WriteNumber(30, 2, -number, nfExp, 2);
MyWorksheet.WriteNumber(30, 3, 1.0/number, nfExp, 2);
MyWorksheet.WriteNumber(30, 4, -1.0/number, nfExp, 2);
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.WriteNumber(r, 2, -number, nfFixed, 1);
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.WriteNumber(r, 2, -number, nfFixed, 3);
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.WriteNumber(r, 2, -number, nfFixedTh, 1);
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.WriteNumber(r, 2, -number, nfFixedTh, 3);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 1 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 1);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 1);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 1);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 1);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 2 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 2);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 2);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 2);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 2);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfSci, 3 dec');
MyWorksheet.WriteNumber(r, 1, number, nfSci, 3);
MyWorksheet.WriteNumber(r, 2, -number, nfSci, 3);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfSci, 3);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfSci, 3);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfExp, 1 dec');
MyWorksheet.WriteNumber(r, 1, number, nfExp, 1);
MyWorksheet.WriteNumber(r, 2, -number, nfExp, 1);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 1);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 1);
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.WriteNumber(r, 2, -number, nfExp, 3);
MyWorksheet.WriteNumber(r, 3, 1.0/number, nfExp, 3);
MyWorksheet.WriteNumber(r, 4, -1.0/number, nfExp, 3);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "EUR "#,##0_);("EUR "#,##0)');
MyWorksheet.WriteDateTime(r, 1, number);
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"EUR "#,##0_);("EUR "#,##0)');
MyWorksheet.WriteDateTime(r, 2, -number);
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"EUR "#,##0_);("EUR "#,##0)');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfCustom, "$"#,##0.0_);[Red]("$"#,##0.0)');
MyWorksheet.WriteDateTime(r, 1, number);
MyWorksheet.WriteNumberFormat(r, 1, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
MyWorksheet.WriteDateTime(r, 2, -number);
MyWorksheet.WriteNumberFormat(r, 2, nfCustom, '"$"#,##0.0_);[Red]("$"#,##0.0)');
inc(r, 2);
number := 1.333333333;
MyWorksheet.WriteUTF8Text(35, 0, 'nfPercentage, 0 decs');
MyWorksheet.WriteNumber(35, 1, number, nfPercentage, 0);
MyWorksheet.WriteUTF8Text(36, 0, 'nfPercentage, 2 decs');
MyWorksheet.WriteNumber(36, 1, number, nfPercentage, 2);
MyWorksheet.WriteUTF8Text(37, 0, 'nfTimeInterval');
MyWorksheet.WriteDateTime(37, 1, number, nfTimeInterval);
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);
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);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm:ss');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval);
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m:s');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'H:M:s');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, hh:mm');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'hh:mm');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h:m');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h:m');
inc(r);
MyWorksheet.WriteUTF8Text(r, 0, 'nfTimeInterval, h');
MyWorksheet.WriteDateTime(r, 1, number, nfTimeInterval, 'h');
// Set width of columns 0, 1 and 5
MyWorksheet.WriteColWidth(0, 25);
lCol.Width := 20;
MyWorksheet.WriteColInfo(1, lCol);
MyWorksheet.WriteColInfo(2, lCol);
MyWorksheet.WriteColWidth(3, 15);
MyWorksheet.WriteColWidth(4, 15);
lCol.Width := 5;
MyWorksheet.WriteColInfo(5, lCol);

View File

@ -126,6 +126,7 @@
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="mainform"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="1"/>
<WindowIndex Value="0"/>
<TopLine Value="309"/>
@ -137,25 +138,24 @@
<Unit2>
<Filename Value="..\..\fpspreadsheet.pas"/>
<UnitName Value="fpspreadsheet"/>
<EditorIndex Value="8"/>
<EditorIndex Value="3"/>
<WindowIndex Value="0"/>
<TopLine Value="280"/>
<CursorPos X="17" Y="312"/>
<TopLine Value="2539"/>
<CursorPos X="19" Y="2550"/>
<UsageCount Value="100"/>
<Bookmarks Count="1">
<Item0 X="33" Y="1214" ID="1"/>
</Bookmarks>
<Loaded Value="True"/>
</Unit2>
<Unit3>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<UnitName Value="fpspreadsheetgrid"/>
<IsVisibleTab Value="True"/>
<EditorIndex Value="6"/>
<EditorIndex Value="2"/>
<WindowIndex Value="0"/>
<TopLine Value="2096"/>
<CursorPos X="1" Y="2120"/>
<TopLine Value="83"/>
<CursorPos X="15" Y="96"/>
<UsageCount Value="100"/>
<Bookmarks Count="1">
<Item0 X="7" Y="1938" ID="1"/>
</Bookmarks>
<Loaded Value="True"/>
</Unit3>
<Unit4>
@ -224,20 +224,20 @@
<Unit12>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<UnitName Value="Grids"/>
<EditorIndex Value="2"/>
<WindowIndex Value="0"/>
<TopLine Value="2464"/>
<CursorPos X="1" Y="2495"/>
<UsageCount Value="48"/>
<Loaded Value="True"/>
</Unit12>
<Unit13>
<Filename Value="..\..\fpsutils.pas"/>
<UnitName Value="fpsutils"/>
<EditorIndex Value="8"/>
<WindowIndex Value="0"/>
<TopLine Value="35"/>
<CursorPos X="1" Y="62"/>
<TopLine Value="614"/>
<CursorPos X="23" Y="621"/>
<UsageCount Value="47"/>
<Loaded Value="True"/>
</Unit13>
<Unit14>
<Filename Value="d:\lazarus-svn\lcl\include\canvas.inc"/>
@ -249,12 +249,10 @@
<Unit15>
<Filename Value="d:\lazarus-svn\lcl\graphics.pp"/>
<UnitName Value="Graphics"/>
<EditorIndex Value="5"/>
<WindowIndex Value="0"/>
<TopLine Value="1937"/>
<CursorPos X="11" Y="1956"/>
<UsageCount Value="33"/>
<Loaded Value="True"/>
</Unit15>
<Unit16>
<Filename Value="d:\lazarus-svn\fpc\2.6.2\source\rtl\objpas\classes\classesh.inc"/>
@ -266,11 +264,11 @@
<Unit17>
<Filename Value="..\..\xlsbiff8.pas"/>
<UnitName Value="xlsbiff8"/>
<EditorIndex Value="10"/>
<EditorIndex Value="5"/>
<WindowIndex Value="0"/>
<TopLine Value="2010"/>
<CursorPos X="39" Y="1983"/>
<UsageCount Value="77"/>
<TopLine Value="61"/>
<CursorPos X="26" Y="70"/>
<UsageCount Value="78"/>
<Loaded Value="True"/>
</Unit17>
<Unit18>
@ -291,31 +289,31 @@
<Unit20>
<Filename Value="..\..\xlscommon.pas"/>
<UnitName Value="xlscommon"/>
<EditorIndex Value="9"/>
<EditorIndex Value="4"/>
<WindowIndex Value="0"/>
<TopLine Value="1461"/>
<CursorPos X="43" Y="1479"/>
<UsageCount Value="73"/>
<TopLine Value="1139"/>
<CursorPos X="12" Y="1157"/>
<UsageCount Value="74"/>
<Loaded Value="True"/>
</Unit20>
<Unit21>
<Filename Value="..\..\xlsbiff5.pas"/>
<UnitName Value="xlsbiff5"/>
<EditorIndex Value="11"/>
<EditorIndex Value="6"/>
<WindowIndex Value="0"/>
<TopLine Value="1"/>
<CursorPos X="1" Y="1"/>
<UsageCount Value="60"/>
<TopLine Value="1230"/>
<CursorPos X="39" Y="1257"/>
<UsageCount Value="61"/>
<Loaded Value="True"/>
</Unit21>
<Unit22>
<Filename Value="..\..\xlsbiff2.pas"/>
<UnitName Value="xlsbiff2"/>
<EditorIndex Value="12"/>
<EditorIndex Value="7"/>
<WindowIndex Value="0"/>
<TopLine Value="547"/>
<CursorPos X="1" Y="563"/>
<UsageCount Value="61"/>
<TopLine Value="225"/>
<CursorPos X="37" Y="224"/>
<UsageCount Value="62"/>
<Loaded Value="True"/>
</Unit22>
<Unit23>
@ -398,12 +396,10 @@
<Unit33>
<Filename Value="d:\lazarus-svn\lcl\colorbox.pas"/>
<UnitName Value="ColorBox"/>
<EditorIndex Value="4"/>
<WindowIndex Value="0"/>
<TopLine Value="584"/>
<CursorPos X="3" Y="598"/>
<UsageCount Value="14"/>
<Loaded Value="True"/>
</Unit33>
<Unit34>
<Filename Value="d:\lazarus-svn\lcl\dialogs.pp"/>
@ -565,144 +561,136 @@
</Unit54>
<Unit55>
<Filename Value="d:\lazarus-svn\lcl\include\font.inc"/>
<EditorIndex Value="3"/>
<WindowIndex Value="0"/>
<TopLine Value="648"/>
<CursorPos X="1" Y="675"/>
<UsageCount Value="12"/>
<Loaded Value="True"/>
</Unit55>
<Unit56>
<Filename Value="d:\lazarus-svn\lcl\include\fontdialog.inc"/>
<EditorIndex Value="7"/>
<WindowIndex Value="0"/>
<TopLine Value="24"/>
<CursorPos X="1" Y="49"/>
<UsageCount Value="12"/>
<Loaded Value="True"/>
</Unit56>
</Units>
<JumpHistory Count="30" HistoryIndex="29">
<JumpHistory Count="29" HistoryIndex="28">
<Position1>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="1368" Column="1" TopLine="1336"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="1365" Column="1" TopLine="1346"/>
</Position1>
<Position2>
<Filename Value="mainform.pas"/>
<Caret Line="610" Column="1" TopLine="602"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="1366" Column="1" TopLine="1346"/>
</Position2>
<Position3>
<Filename Value="mainform.pas"/>
<Caret Line="613" Column="1" TopLine="602"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1624" Column="1" TopLine="1621"/>
</Position3>
<Position4>
<Filename Value="mainform.pas"/>
<Caret Line="603" Column="19" TopLine="603"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1627" Column="1" TopLine="1621"/>
</Position4>
<Position5>
<Filename Value="mainform.pas"/>
<Caret Line="310" Column="3" TopLine="310"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1630" Column="1" TopLine="1621"/>
</Position5>
<Position6>
<Filename Value="mainform.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1633" Column="1" TopLine="1621"/>
</Position6>
<Position7>
<Filename Value="mainform.pas"/>
<Caret Line="173" Column="29" TopLine="142"/>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="11" Column="45" TopLine="1"/>
</Position7>
<Position8>
<Filename Value="mainform.pas"/>
<Caret Line="556" Column="17" TopLine="524"/>
<Filename Value="..\..\xlsbiff5.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position8>
<Position9>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="2038" Column="1" TopLine="2031"/>
<Filename Value="..\..\xlsbiff2.pas"/>
<Caret Line="563" Column="1" TopLine="547"/>
</Position9>
<Position10>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="2041" Column="1" TopLine="2031"/>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="351" Column="26" TopLine="340"/>
</Position10>
<Position11>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="2044" Column="1" TopLine="2031"/>
<Filename Value="..\..\xlsbiff8.pas"/>
<Caret Line="1611" Column="1" TopLine="1582"/>
</Position11>
<Position12>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2483" Column="1" TopLine="2464"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1034" Column="35" TopLine="1026"/>
</Position12>
<Position13>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2484" Column="1" TopLine="2464"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="2021" Column="1" TopLine="1991"/>
</Position13>
<Position14>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2485" Column="1" TopLine="2464"/>
<Filename Value="..\..\xlsbiff2.pas"/>
<Caret Line="82" Column="57" TopLine="52"/>
</Position14>
<Position15>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2486" Column="1" TopLine="2464"/>
<Filename Value="..\..\xlsbiff2.pas"/>
<Caret Line="1702" Column="5" TopLine="1672"/>
</Position15>
<Position16>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2490" Column="1" TopLine="2464"/>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="634" Column="32" TopLine="609"/>
</Position16>
<Position17>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2492" Column="1" TopLine="2464"/>
<Filename Value="..\..\fpsutils.pas"/>
<Caret Line="629" Column="17" TopLine="612"/>
</Position17>
<Position18>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2494" Column="1" TopLine="2464"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="266" Column="28" TopLine="244"/>
</Position18>
<Position19>
<Filename Value="d:\lazarus-svn\lcl\grids.pas"/>
<Caret Line="2495" Column="1" TopLine="2464"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1150" Column="3" TopLine="1136"/>
</Position19>
<Position20>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="2038" Column="1" TopLine="2031"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="386" Column="15" TopLine="370"/>
</Position20>
<Position21>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="1626" Column="1" TopLine="1607"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1938" Column="1" TopLine="1908"/>
</Position21>
<Position22>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="414" Column="14" TopLine="397"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position22>
<Position23>
<Filename Value="mainform.pas"/>
<Caret Line="564" Column="1" TopLine="557"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="393" Column="20" TopLine="368"/>
</Position23>
<Position24>
<Filename Value="mainform.pas"/>
<Caret Line="640" Column="31" TopLine="604"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="796" Column="35" TopLine="771"/>
</Position24>
<Position25>
<Filename Value="mainform.pas"/>
<Caret Line="641" Column="31" TopLine="605"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="980" Column="14" TopLine="956"/>
</Position25>
<Position26>
<Filename Value="mainform.pas"/>
<Caret Line="640" Column="31" TopLine="604"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1038" Column="14" TopLine="1013"/>
</Position26>
<Position27>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="2024" Column="25" TopLine="2007"/>
<Filename Value="..\..\xlscommon.pas"/>
<Caret Line="1073" Column="12" TopLine="1048"/>
</Position27>
<Position28>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="2262" Column="19" TopLine="2255"/>
<Caret Line="524" Column="36" TopLine="519"/>
</Position28>
<Position29>
<Filename Value="..\..\fpspreadsheet.pas"/>
<Caret Line="1" Column="1" TopLine="1"/>
</Position29>
<Position30>
<Filename Value="..\..\fpspreadsheetgrid.pas"/>
<Caret Line="2104" Column="68" TopLine="2087"/>
</Position30>
</JumpHistory>
</ProjectOptions>
<CompilerOptions>

View File

@ -1,11 +1,11 @@
object Form1: TForm1
Left = 370
Height = 406
Top = 258
Width = 636
Left = 359
Height = 593
Top = 193
Width = 722
Caption = 'fpsGrid'
ClientHeight = 386
ClientWidth = 636
ClientHeight = 568
ClientWidth = 722
Menu = MainMenu1
OnActivate = FormActivate
OnCreate = FormCreate
@ -13,19 +13,19 @@ object Form1: TForm1
LCLVersion = '1.3'
object Panel1: TPanel
Left = 0
Height = 73
Top = 313
Width = 636
Height = 76
Top = 492
Width = 722
Align = alBottom
BevelOuter = bvNone
ClientHeight = 73
ClientWidth = 636
ClientHeight = 76
ClientWidth = 722
TabOrder = 0
object CbShowHeaders: TCheckBox
Left = 8
Height = 19
Height = 24
Top = 11
Width = 93
Width = 116
Caption = 'Show headers'
Checked = True
OnClick = CbShowHeadersClick
@ -34,9 +34,9 @@ object Form1: TForm1
end
object CbShowGridLines: TCheckBox
Left = 8
Height = 19
Height = 24
Top = 36
Width = 100
Width = 125
Caption = 'Show grid lines'
Checked = True
OnClick = CbShowGridLinesClick
@ -45,7 +45,7 @@ object Form1: TForm1
end
object EdFrozenCols: TSpinEdit
Left = 238
Height = 23
Height = 28
Top = 8
Width = 52
OnChange = EdFrozenColsChange
@ -53,7 +53,7 @@ object Form1: TForm1
end
object EdFrozenRows: TSpinEdit
Left = 238
Height = 23
Height = 28
Top = 39
Width = 52
OnChange = EdFrozenRowsChange
@ -61,18 +61,18 @@ object Form1: TForm1
end
object Label1: TLabel
Left = 152
Height = 15
Height = 20
Top = 13
Width = 62
Width = 77
Caption = 'Frozen cols:'
FocusControl = EdFrozenCols
ParentColor = False
end
object Label2: TLabel
Left = 153
Height = 15
Height = 20
Top = 40
Width = 66
Width = 82
Caption = 'Frozen rows:'
FocusControl = EdFrozenRows
ParentColor = False
@ -80,9 +80,9 @@ object Form1: TForm1
end
object PageControl1: TPageControl
Left = 0
Height = 260
Height = 439
Top = 53
Width = 636
Width = 722
ActivePage = TabSheet1
Align = alClient
TabIndex = 0
@ -90,13 +90,13 @@ object Form1: TForm1
OnChange = PageControl1Change
object TabSheet1: TTabSheet
Caption = 'Sheet1'
ClientHeight = 232
ClientWidth = 628
ClientHeight = 406
ClientWidth = 714
object sWorksheetGrid1: TsWorksheetGrid
Left = 0
Height = 232
Height = 406
Top = 0
Width = 628
Width = 714
FrozenCols = 0
FrozenRows = 0
Align = alClient
@ -108,7 +108,7 @@ object Form1: TForm1
TitleStyle = tsNative
OnSelection = sWorksheetGrid1Selection
ColWidths = (
42
56
64
)
end
@ -118,7 +118,7 @@ object Form1: TForm1
Left = 0
Height = 26
Top = 0
Width = 636
Width = 722
ButtonHeight = 24
Caption = 'ToolBar1'
EdgeBorders = []
@ -163,7 +163,7 @@ object Form1: TForm1
Left = 0
Height = 27
Top = 26
Width = 636
Width = 722
ButtonHeight = 23
Caption = 'FormatToolBar'
Images = ImageList1
@ -185,19 +185,19 @@ object Form1: TForm1
end
object FontComboBox: TComboBox
Left = 24
Height = 23
Height = 28
Top = 2
Width = 127
ItemHeight = 15
ItemHeight = 20
OnSelect = FontComboBoxSelect
TabOrder = 0
end
object FontSizeComboBox: TComboBox
Left = 151
Height = 23
Height = 28
Top = 2
Width = 48
ItemHeight = 15
ItemHeight = 20
Items.Strings = (
'8'
'9'

View File

@ -1,307 +1,308 @@
{ This is an automatically generated lazarus resource file }
LazarusResources.Add('TForm1','FORMDATA',[
'TPF0'#6'TForm1'#5'Form1'#4'Left'#3'r'#1#6'Height'#3#150#1#3'Top'#3#2#1#5'Wid'
+'th'#3'|'#2#7'Caption'#6#7'fpsGrid'#12'ClientHeight'#3#130#1#11'ClientWidth'
+#3'|'#2#4'Menu'#7#9'MainMenu1'#10'OnActivate'#7#12'FormActivate'#8'OnCreate'
'TPF0'#6'TForm1'#5'Form1'#4'Left'#3'g'#1#6'Height'#3'Q'#2#3'Top'#3#193#0#5'Wi'
+'dth'#3#210#2#7'Caption'#6#7'fpsGrid'#12'ClientHeight'#3'8'#2#11'ClientWidth'
+#3#210#2#4'Menu'#7#9'MainMenu1'#10'OnActivate'#7#12'FormActivate'#8'OnCreate'
+#7#10'FormCreate'#8'ShowHint'#9#10'LCLVersion'#6#3'1.3'#0#6'TPanel'#6'Panel1'
+#4'Left'#2#0#6'Height'#2'I'#3'Top'#3'9'#1#5'Width'#3'|'#2#5'Align'#7#8'alBot'
+'tom'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'I'#11'ClientWidth'#3'|'#2
+#8'TabOrder'#2#0#0#9'TCheckBox'#13'CbShowHeaders'#4'Left'#2#8#6'Height'#2#19
+#3'Top'#2#11#5'Width'#2']'#7'Caption'#6#12'Show headers'#7'Checked'#9#7'OnCl'
+'ick'#7#18'CbShowHeadersClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#0#0#0#9
+'TCheckBox'#15'CbShowGridLines'#4'Left'#2#8#6'Height'#2#19#3'Top'#2'$'#5'Wid'
+'th'#2'd'#7'Caption'#6#15'Show grid lines'#7'Checked'#9#7'OnClick'#7#20'CbSh'
+'owGridLinesClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#1#0#0#9'TSpinEdit'
+#12'EdFrozenCols'#4'Left'#3#238#0#6'Height'#2#23#3'Top'#2#8#5'Width'#2'4'#8
+'OnChange'#7#18'EdFrozenColsChange'#8'TabOrder'#2#2#0#0#9'TSpinEdit'#12'EdFr'
+'ozenRows'#4'Left'#3#238#0#6'Height'#2#23#3'Top'#2''''#5'Width'#2'4'#8'OnCha'
+'nge'#7#18'EdFrozenRowsChange'#8'TabOrder'#2#3#0#0#6'TLabel'#6'Label1'#4'Lef'
+'t'#3#152#0#6'Height'#2#15#3'Top'#2#13#5'Width'#2'>'#7'Caption'#6#12'Frozen '
+'cols:'#12'FocusControl'#7#12'EdFrozenCols'#11'ParentColor'#8#0#0#6'TLabel'#6
+'Label2'#4'Left'#3#153#0#6'Height'#2#15#3'Top'#2'('#5'Width'#2'B'#7'Caption'
+#6#12'Frozen rows:'#12'FocusControl'#7#12'EdFrozenRows'#11'ParentColor'#8#0#0
+#0#12'TPageControl'#12'PageControl1'#4'Left'#2#0#6'Height'#3#4#1#3'Top'#2'5'
+#5'Width'#3'|'#2#10'ActivePage'#7#9'TabSheet1'#5'Align'#7#8'alClient'#8'TabI'
+'ndex'#2#0#8'TabOrder'#2#1#8'OnChange'#7#18'PageControl1Change'#0#9'TTabShee'
+'t'#9'TabSheet1'#7'Caption'#6#6'Sheet1'#12'ClientHeight'#3#232#0#11'ClientWi'
+'dth'#3't'#2#0#15'TsWorksheetGrid'#15'sWorksheetGrid1'#4'Left'#2#0#6'Height'
+#3#232#0#3'Top'#2#0#5'Width'#3't'#2#10'FrozenCols'#2#0#10'FrozenRows'#2#0#5
+'Align'#7#8'alClient'#8'ColCount'#2#2#14'ExtendedSelect'#8#7'Options'#11#15
+'goFixedVertLine'#15'goFixedHorzLine'#10'goVertLine'#10'goHorzLine'#13'goRan'
+'geSelect'#11'goRowSizing'#11'goColSizing'#15'goThumbTracking'#14'goSmoothSc'
+'roll'#16'goFixedColSizing'#0#8'RowCount'#2#2#8'TabOrder'#2#0#10'TitleStyle'
+#7#8'tsNative'#11'OnSelection'#7#24'sWorksheetGrid1Selection'#9'ColWidths'#1
+#2'*'#2'@'#0#0#0#0#0#8'TToolBar'#8'ToolBar1'#4'Left'#2#0#6'Height'#2#26#3'To'
+'p'#2#0#5'Width'#3'|'#2#12'ButtonHeight'#2#24#7'Caption'#6#8'ToolBar1'#11'Ed'
+'geBorders'#11#0#6'Images'#7#10'ImageList1'#8'TabOrder'#2#2#0#11'TToolButton'
+#11'ToolButton1'#4'Left'#2#1#3'Top'#2#0#6'Action'#7#6'AcOpen'#0#0#11'TToolBu'
+'tton'#11'ToolButton2'#4'Left'#2#24#3'Top'#2#0#6'Action'#7#8'AcSaveAs'#0#0#11
+'TToolButton'#11'ToolButton3'#4'Left'#2'P'#3'Top'#2#0#6'Action'#7#6'AcQuit'#0
+#0#11'TToolButton'#11'ToolButton5'#4'Left'#2'/'#3'Top'#2#0#5'Width'#2#5#7'Ca'
+'ption'#6#11'ToolButton5'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#11'T'
+'oolButton4'#4'Left'#2'4'#3'Top'#2#0#6'Action'#7#6'AcEdit'#0#0#11'TToolButto'
+'n'#11'ToolButton6'#4'Left'#2'K'#3'Top'#2#0#5'Width'#2#5#7'Caption'#6#11'Too'
+'lButton6'#5'Style'#7#10'tbsDivider'#0#0#0#8'TToolBar'#13'FormatToolBar'#4'L'
+'eft'#2#0#6'Height'#2#27#3'Top'#2#26#5'Width'#3'|'#2#12'ButtonHeight'#2#23#7
+'Caption'#6#13'FormatToolBar'#6'Images'#7#10'ImageList1'#8'TabOrder'#2#3#0#11
+'TToolButton'#12'ToolButton10'#4'Left'#3'('#1#3'Top'#2#2#6'Action'#7#11'AcLe'
+'ftAlign'#0#0#11'TToolButton'#12'ToolButton12'#4'Left'#3'?'#1#3'Top'#2#2#6'A'
+'ction'#7#16'AcHorCenterAlign'#0#0#11'TToolButton'#12'ToolButton13'#4'Left'#3
+'V'#1#3'Top'#2#2#6'Action'#7#12'AcRightAlign'#0#0#9'TComboBox'#12'FontComboB'
+'ox'#4'Left'#2#24#6'Height'#2#23#3'Top'#2#2#5'Width'#2#127#10'ItemHeight'#2
+#15#8'OnSelect'#7#18'FontComboBoxSelect'#8'TabOrder'#2#0#0#0#9'TComboBox'#16
+'FontSizeComboBox'#4'Left'#3#151#0#6'Height'#2#23#3'Top'#2#2#5'Width'#2'0'#10
+'ItemHeight'#2#15#13'Items.Strings'#1#6#1'8'#6#1'9'#6#2'10'#6#2'11'#6#2'12'#6
+#2'14'#6#2'16'#6#2'18'#6#2'20'#6#2'24'#0#8'OnSelect'#7#22'FontSizeComboBoxSe'
+'lect'#8'TabOrder'#2#1#0#0#11'TToolButton'#11'ToolButton7'#4'Left'#3#199#0#3
+'Top'#2#2#6'Action'#7#10'AcFontBold'#0#0#11'TToolButton'#11'ToolButton8'#4'L'
+'eft'#3#222#0#3'Top'#2#2#6'Action'#7#12'AcFontItalic'#0#0#11'TToolButton'#11
+'ToolButton9'#4'Left'#3#245#0#3'Top'#2#2#6'Action'#7#15'AcFontUnderline'#0#0
+#11'TToolButton'#12'ToolButton11'#4'Left'#3#12#1#3'Top'#2#2#6'Action'#7#15'A'
+'cFontStrikeout'#0#0#11'TToolButton'#12'ToolButton14'#4'Left'#3'#'#1#3'Top'#2
+#2#5'Width'#2#5#7'Caption'#6#12'ToolButton14'#5'Style'#7#10'tbsDivider'#0#0
+#11'TToolButton'#12'ToolButton15'#4'Left'#3'm'#1#3'Top'#2#2#5'Width'#2#5#7'C'
+'aption'#6#12'ToolButton15'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#12
+'ToolButton16'#4'Left'#3'r'#1#3'Top'#2#2#6'Action'#7#11'AcVAlignTop'#0#0#11
+'TToolButton'#12'ToolButton17'#4'Left'#3#137#1#3'Top'#2#2#6'Action'#7#14'AcV'
,'AlignCenter'#0#0#11'TToolButton'#12'ToolButton18'#4'Left'#3#160#1#3'Top'#2#2
+#6'Action'#7#14'AcVAlignBottom'#0#0#11'TToolButton'#12'ToolButton19'#4'Left'
+#3#183#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButton19'#5'Style'#7#10
+'tbsDivider'#0#0#11'TToolButton'#9'TbBorders'#4'Left'#3#188#1#3'Top'#2#2#6'A'
+'ction'#7#12'AcBorderNone'#12'DropdownMenu'#7#16'BordersPopupMenu'#5'Style'#7
+#11'tbsDropDown'#0#0#9'TColorBox'#17'CbBackgroundColor'#4'Left'#3#223#1#6'He'
+'ight'#2#22#3'Top'#2#2#5'Width'#3#132#0#5'Style'#11#13'cbPrettyNames'#14'cbC'
+'ustomColors'#0#11'OnGetColors'#7#26'CbBackgroundColorGetColors'#10'ItemHeig'
+'ht'#2#16#8'OnSelect'#7#23'CbBackgroundColorSelect'#8'TabOrder'#2#2#0#0#11'T'
+'ToolButton'#12'ToolButton21'#4'Left'#2#1#3'Top'#2#2#6'Action'#7#6'AcFont'#0
+#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4'.xls'#6'Filter'#6#192
+'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlxs|Libre'
+'Office/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (pipes) (.wikitable_p'
+'ipes)|.wikitable_pipes|All files (*.*)|*.*'#7'Options'#11#20'ofExtensionDif'
+'ferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#2'@'#3'top'#3#176#0#0
+#0#11'TSaveDialog'#11'SaveDialog1'#10'DefaultExt'#6#4'.xls'#6'Filter'#6#185
+'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlsx|Libre'
+'Office/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (wikimedia) (.wikitab'
+'le_wikimedia)|*.wikitable_wikimedia'#7'Options'#11#17'ofOverwritePrompt'#20
+'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#3#176#0
+#3'top'#3#176#0#0#0#9'TMainMenu'#9'MainMenu1'#6'Images'#7#10'ImageList1'#4'l'
+'eft'#3' '#1#3'top'#2'@'#0#9'TMenuItem'#7'mnuFile'#7'Caption'#6#5'&File'#0#9
+'TMenuItem'#7'mnuOpen'#6'Action'#7#6'AcOpen'#11'Bitmap.Data'#10':'#4#0#0'6'#4
+#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0
+#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0','#134#216#0'-'#136#216#247'-'#135
+#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136
+#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#135#216#247'-'#136
+#216#247','#134#216#0#255#255#255#0#255#255#255#0'3'#142#217#251#220#240#250
+#255#152#225#246#255#149#224#246#255#146#223#246#255#142#222#245#255#137#220
+#245#255#133#218#244#255#128#217#244#255'z'#215#243#255't'#213#243#255'p'#211
+#242#255#194#234#248#255'5'#148#218#255#255#255#255#0#255#255#255#0'5'#148
+#218#247#239#250#254#255#147#229#248#255#143#228#248#255#137#227#248#255#130
+#225#247#255'z'#223#247#255'q'#222#246#255'g'#219#245#255'['#216#244#255'M'
+#212#243#255'@'#209#242#255#202#242#251#255'5'#148#218#255#255#255#255#0#255
+#255#255#0'6'#154#218#248#242#250#253#255#148#230#248#255#146#229#248#255#144
+#229#248#255#139#227#248#255#134#226#247#255#127#225#247#255'w'#222#246#255
+'l'#220#246#255'^'#217#244#255'O'#213#243#255#204#242#251#255'5'#148#218#255
+#255#255#255#0#255#255#255#0'6'#161#218#249#246#252#254#255#148#229#248#255
+#147#229#248#255#147#229#248#255#145#229#248#255#147#219#233#255#147#215#227
+#255#147#210#220#255#144#206#215#255#140#200#207#255#134#193#198#255#201#216
+#214#255'5'#148#218#255#197'tD'#232#202#127'S'#241'7'#166#218#250#254#255#255
+#255#248#253#255#255#246#253#255#255#245#252#255#255#243#252#254#255#154#228
+#244#255#154#230#247#255#155#230#246#255#157#229#245#255#158#229#245#255#159
+#229#244#255#218#243#248#255'5'#148#218#255#253#244#238#255#202#128'T'#249'5'
+#171#218#250#232#246#251#255'p'#188#231#255'U'#170#226#255'M'#165#224#255#145
+#201#235#255#250#243#239#255#253#254#253#255#255#253#252#255#255#253#252#255
+#254#253#252#255#254#252#251#255#254#254#253#255'5'#148#218#255#239#242#232
+#255#206#129'V'#255'6'#170#218#242#241#250#253#255#148#222#245#255#147#220
+#244#255'd'#188#233#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148
+#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148
+#218#255#251#246#239#255#204#131'U'#254'5'#175#218#240#247#252#254#255#142
+#228#248#255#145#222#245#255#159#224#245#255#172#225#246#255#202#132'R'#255
+#255#247#241#255#255#233#217#255#255#234#219#255#255#233#217#255#255#231#215
+#255#255#229#210#255#255#226#203#255#255#247#241#255#203#133'U'#254'6'#179
+#218#248#253#254#254#255#254#255#255#255#254#254#255#255#253#254#255#255#254
+#255#255#255#228#186#145#255#255#247#240#255#255#231#213#255#253#231#214#255
+#253#230#212#255#252#228#208#255#251#227#203#255#250#220#194#255#254#243#232
+#255#204#134'V'#254'4'#180#217#208'^'#194#225#250'`'#195#226#250'`'#195#226
+#250'`'#195#226#250'_'#195#226#250#228#187#145#255#255#247#242#255#254#231
+#213#255#254#231#213#255#253#229#209#255#250#224#202#255#249#222#196#255#247
+#217#188#255#253#242#231#255#204#135'W'#254#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187#146#255#254#247
+#241#255#252#229#210#255#252#228#209#255#251#226#204#255#249#221#196#255#246
+#215#187#255#243#209#175#255#250#239#228#255#204#135'X'#254#255#255#255#0#255
,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187
+#146#255#254#246#240#255#252#226#205#255#252#227#205#255#250#223#200#255#247
+#217#188#255#245#233#221#255#250#243#235#255#251#248#243#255#202#131'S'#254
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#228#187#147#255#254#245#237#255#252#222#197#255#251#224#199#255
+#249#220#194#255#245#211#180#255#254#249#243#255#250#226#196#255#236#193#147
+#255#195'}H'#147#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#229#190#150#255#255#255#254#255#253#243#233#255#253
+#243#234#255#252#242#232#255#250#239#227#255#250#242#231#255#234#187#136#255
+#207#133'U'#179#180'i='#12#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#234#195#157#255#230#191#150#255#228#187
+#146#255#228#187#146#255#209#160'l'#245#208#158'm'#246#204#150'_'#218#196'yB'
+'~'#178'g<'#9#255#255#255#0#7'OnClick'#7#13'acOpenExecute'#0#0#9'TMenuItem'#9
+'mnuSaveAs'#6'Action'#7#8'AcSaveAs'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'
+#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0
+'d'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#186'j6'#0#185'i5'#181#184'i5'#238#183'h5'
+#255#181'h5'#255#180'g4'#255#178'f4'#255#176'e3'#255#174'd3'#255#172'c2'#255
+#170'b2'#255#169'a2'#255#168'`1'#255#167'`1'#254#166'`1'#241#168'a1'#196#186
+'j5'#222#235#198#173#255#234#197#173#255#254#251#248#255#254#251#248#255#254
+#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255
+#254#251#248#255#254#251#248#255#254#251#248#255#200#154'|'#255#199#152'y'
+#255#167'`1'#237#186'k7'#254#237#202#179#255#224#162'z'#255#254#250#247#255
+'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+'b'#192#136#255'b'#192#136#255'b'#192#136#255#253#249#246#255#202#141'e'#255
+#201#155'|'#255#167'`1'#254#187'l8'#255#238#204#182#255#225#162'z'#255#254
+#250#247#255#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194#255
+#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194#255#253#249#246
+#255#205#144'h'#255#204#158#129#255#168'a2'#255#187'k8'#255#239#206#184#255
+#225#162'y'#255#254#250#247#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+#253#249#246#255#207#147'j'#255#206#163#132#255#170'a2'#255#186'j6'#255#239
+#208#187#255#226#162'z'#255#254#251#248#255#254#251#248#255#254#251#248#255
+#4'Left'#2#0#6'Height'#2'L'#3'Top'#3#236#1#5'Width'#3#210#2#5'Align'#7#8'alB'
+'ottom'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'L'#11'ClientWidth'#3
+#210#2#8'TabOrder'#2#0#0#9'TCheckBox'#13'CbShowHeaders'#4'Left'#2#8#6'Height'
+#2#24#3'Top'#2#11#5'Width'#2't'#7'Caption'#6#12'Show headers'#7'Checked'#9#7
+'OnClick'#7#18'CbShowHeadersClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#0#0
+#0#9'TCheckBox'#15'CbShowGridLines'#4'Left'#2#8#6'Height'#2#24#3'Top'#2'$'#5
+'Width'#2'}'#7'Caption'#6#15'Show grid lines'#7'Checked'#9#7'OnClick'#7#20'C'
+'bShowGridLinesClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#1#0#0#9'TSpinEdi'
+'t'#12'EdFrozenCols'#4'Left'#3#238#0#6'Height'#2#28#3'Top'#2#8#5'Width'#2'4'
+#8'OnChange'#7#18'EdFrozenColsChange'#8'TabOrder'#2#2#0#0#9'TSpinEdit'#12'Ed'
+'FrozenRows'#4'Left'#3#238#0#6'Height'#2#28#3'Top'#2''''#5'Width'#2'4'#8'OnC'
+'hange'#7#18'EdFrozenRowsChange'#8'TabOrder'#2#3#0#0#6'TLabel'#6'Label1'#4'L'
+'eft'#3#152#0#6'Height'#2#20#3'Top'#2#13#5'Width'#2'M'#7'Caption'#6#12'Froze'
+'n cols:'#12'FocusControl'#7#12'EdFrozenCols'#11'ParentColor'#8#0#0#6'TLabel'
+#6'Label2'#4'Left'#3#153#0#6'Height'#2#20#3'Top'#2'('#5'Width'#2'R'#7'Captio'
+'n'#6#12'Frozen rows:'#12'FocusControl'#7#12'EdFrozenRows'#11'ParentColor'#8
+#0#0#0#12'TPageControl'#12'PageControl1'#4'Left'#2#0#6'Height'#3#183#1#3'Top'
+#2'5'#5'Width'#3#210#2#10'ActivePage'#7#9'TabSheet1'#5'Align'#7#8'alClient'#8
+'TabIndex'#2#0#8'TabOrder'#2#1#8'OnChange'#7#18'PageControl1Change'#0#9'TTab'
+'Sheet'#9'TabSheet1'#7'Caption'#6#6'Sheet1'#12'ClientHeight'#3#150#1#11'Clie'
+'ntWidth'#3#202#2#0#15'TsWorksheetGrid'#15'sWorksheetGrid1'#4'Left'#2#0#6'He'
+'ight'#3#150#1#3'Top'#2#0#5'Width'#3#202#2#10'FrozenCols'#2#0#10'FrozenRows'
+#2#0#5'Align'#7#8'alClient'#8'ColCount'#2#2#14'ExtendedSelect'#8#7'Options'
+#11#15'goFixedVertLine'#15'goFixedHorzLine'#10'goVertLine'#10'goHorzLine'#13
+'goRangeSelect'#11'goRowSizing'#11'goColSizing'#15'goThumbTracking'#14'goSmo'
+'othScroll'#16'goFixedColSizing'#0#8'RowCount'#2#2#8'TabOrder'#2#0#10'TitleS'
+'tyle'#7#8'tsNative'#11'OnSelection'#7#24'sWorksheetGrid1Selection'#9'ColWid'
+'ths'#1#2'8'#2'@'#0#0#0#0#0#8'TToolBar'#8'ToolBar1'#4'Left'#2#0#6'Height'#2
+#26#3'Top'#2#0#5'Width'#3#210#2#12'ButtonHeight'#2#24#7'Caption'#6#8'ToolBar'
+'1'#11'EdgeBorders'#11#0#6'Images'#7#10'ImageList1'#8'TabOrder'#2#2#0#11'TTo'
+'olButton'#11'ToolButton1'#4'Left'#2#1#3'Top'#2#0#6'Action'#7#6'AcOpen'#0#0
+#11'TToolButton'#11'ToolButton2'#4'Left'#2#24#3'Top'#2#0#6'Action'#7#8'AcSav'
+'eAs'#0#0#11'TToolButton'#11'ToolButton3'#4'Left'#2'P'#3'Top'#2#0#6'Action'#7
+#6'AcQuit'#0#0#11'TToolButton'#11'ToolButton5'#4'Left'#2'/'#3'Top'#2#0#5'Wid'
+'th'#2#5#7'Caption'#6#11'ToolButton5'#5'Style'#7#10'tbsDivider'#0#0#11'TTool'
+'Button'#11'ToolButton4'#4'Left'#2'4'#3'Top'#2#0#6'Action'#7#6'AcEdit'#0#0#11
+'TToolButton'#11'ToolButton6'#4'Left'#2'K'#3'Top'#2#0#5'Width'#2#5#7'Caption'
+#6#11'ToolButton6'#5'Style'#7#10'tbsDivider'#0#0#0#8'TToolBar'#13'FormatTool'
+'Bar'#4'Left'#2#0#6'Height'#2#27#3'Top'#2#26#5'Width'#3#210#2#12'ButtonHeigh'
+'t'#2#23#7'Caption'#6#13'FormatToolBar'#6'Images'#7#10'ImageList1'#8'TabOrde'
+'r'#2#3#0#11'TToolButton'#12'ToolButton10'#4'Left'#3'('#1#3'Top'#2#2#6'Actio'
+'n'#7#11'AcLeftAlign'#0#0#11'TToolButton'#12'ToolButton12'#4'Left'#3'?'#1#3
+'Top'#2#2#6'Action'#7#16'AcHorCenterAlign'#0#0#11'TToolButton'#12'ToolButton'
+'13'#4'Left'#3'V'#1#3'Top'#2#2#6'Action'#7#12'AcRightAlign'#0#0#9'TComboBox'
+#12'FontComboBox'#4'Left'#2#24#6'Height'#2#28#3'Top'#2#2#5'Width'#2#127#10'I'
+'temHeight'#2#20#8'OnSelect'#7#18'FontComboBoxSelect'#8'TabOrder'#2#0#0#0#9
+'TComboBox'#16'FontSizeComboBox'#4'Left'#3#151#0#6'Height'#2#28#3'Top'#2#2#5
+'Width'#2'0'#10'ItemHeight'#2#20#13'Items.Strings'#1#6#1'8'#6#1'9'#6#2'10'#6
+#2'11'#6#2'12'#6#2'14'#6#2'16'#6#2'18'#6#2'20'#6#2'24'#0#8'OnSelect'#7#22'Fo'
+'ntSizeComboBoxSelect'#8'TabOrder'#2#1#0#0#11'TToolButton'#11'ToolButton7'#4
+'Left'#3#199#0#3'Top'#2#2#6'Action'#7#10'AcFontBold'#0#0#11'TToolButton'#11
+'ToolButton8'#4'Left'#3#222#0#3'Top'#2#2#6'Action'#7#12'AcFontItalic'#0#0#11
+'TToolButton'#11'ToolButton9'#4'Left'#3#245#0#3'Top'#2#2#6'Action'#7#15'AcFo'
+'ntUnderline'#0#0#11'TToolButton'#12'ToolButton11'#4'Left'#3#12#1#3'Top'#2#2
+#6'Action'#7#15'AcFontStrikeout'#0#0#11'TToolButton'#12'ToolButton14'#4'Left'
+#3'#'#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButton14'#5'Style'#7#10
+'tbsDivider'#0#0#11'TToolButton'#12'ToolButton15'#4'Left'#3'm'#1#3'Top'#2#2#5
+'Width'#2#5#7'Caption'#6#12'ToolButton15'#5'Style'#7#10'tbsDivider'#0#0#11'T'
+'ToolButton'#12'ToolButton16'#4'Left'#3'r'#1#3'Top'#2#2#6'Action'#7#11'AcVAl'
+'ignTop'#0#0#11'TToolButton'#12'ToolButton17'#4'Left'#3#137#1#3'Top'#2#2#6'A'
,'ction'#7#14'AcVAlignCenter'#0#0#11'TToolButton'#12'ToolButton18'#4'Left'#3
+#160#1#3'Top'#2#2#6'Action'#7#14'AcVAlignBottom'#0#0#11'TToolButton'#12'Tool'
+'Button19'#4'Left'#3#183#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButto'
+'n19'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#9'TbBorders'#4'Left'#3
+#188#1#3'Top'#2#2#6'Action'#7#12'AcBorderNone'#12'DropdownMenu'#7#16'Borders'
+'PopupMenu'#5'Style'#7#11'tbsDropDown'#0#0#9'TColorBox'#17'CbBackgroundColor'
+#4'Left'#3#223#1#6'Height'#2#22#3'Top'#2#2#5'Width'#3#132#0#5'Style'#11#13'c'
+'bPrettyNames'#14'cbCustomColors'#0#11'OnGetColors'#7#26'CbBackgroundColorGe'
+'tColors'#10'ItemHeight'#2#16#8'OnSelect'#7#23'CbBackgroundColorSelect'#8'Ta'
+'bOrder'#2#2#0#0#11'TToolButton'#12'ToolButton21'#4'Left'#2#1#3'Top'#2#2#6'A'
+'ction'#7#6'AcFont'#0#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4
+'.xls'#6'Filter'#6#192'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet'
+' (*.xlsx)|*.xlxs|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable'
+' (pipes) (.wikitable_pipes)|.wikitable_pipes|All files (*.*)|*.*'#7'Options'
+#11#20'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#2
+'@'#3'top'#3#176#0#0#0#11'TSaveDialog'#11'SaveDialog1'#10'DefaultExt'#6#4'.x'
+'ls'#6'Filter'#6#185'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet ('
+'*.xlsx)|*.xlsx|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable ('
+'wikimedia) (.wikitable_wikimedia)|*.wikitable_wikimedia'#7'Options'#11#17'o'
+'fOverwritePrompt'#20'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDeta'
+'il'#0#4'left'#3#176#0#3'top'#3#176#0#0#0#9'TMainMenu'#9'MainMenu1'#6'Images'
+#7#10'ImageList1'#4'left'#3' '#1#3'top'#2'@'#0#9'TMenuItem'#7'mnuFile'#7'Cap'
+'tion'#6#5'&File'#0#9'TMenuItem'#7'mnuOpen'#6'Action'#7#6'AcOpen'#11'Bitmap.'
+'Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16
+#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0','#134#216
+#0'-'#136#216#247'-'#135#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247
+'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247
+'-'#135#216#247'-'#136#216#247','#134#216#0#255#255#255#0#255#255#255#0'3'
+#142#217#251#220#240#250#255#152#225#246#255#149#224#246#255#146#223#246#255
+#142#222#245#255#137#220#245#255#133#218#244#255#128#217#244#255'z'#215#243
+#255't'#213#243#255'p'#211#242#255#194#234#248#255'5'#148#218#255#255#255#255
+#0#255#255#255#0'5'#148#218#247#239#250#254#255#147#229#248#255#143#228#248
+#255#137#227#248#255#130#225#247#255'z'#223#247#255'q'#222#246#255'g'#219#245
+#255'['#216#244#255'M'#212#243#255'@'#209#242#255#202#242#251#255'5'#148#218
+#255#255#255#255#0#255#255#255#0'6'#154#218#248#242#250#253#255#148#230#248
+#255#146#229#248#255#144#229#248#255#139#227#248#255#134#226#247#255#127#225
+#247#255'w'#222#246#255'l'#220#246#255'^'#217#244#255'O'#213#243#255#204#242
+#251#255'5'#148#218#255#255#255#255#0#255#255#255#0'6'#161#218#249#246#252
+#254#255#148#229#248#255#147#229#248#255#147#229#248#255#145#229#248#255#147
+#219#233#255#147#215#227#255#147#210#220#255#144#206#215#255#140#200#207#255
+#134#193#198#255#201#216#214#255'5'#148#218#255#197'tD'#232#202#127'S'#241'7'
+#166#218#250#254#255#255#255#248#253#255#255#246#253#255#255#245#252#255#255
+#243#252#254#255#154#228#244#255#154#230#247#255#155#230#246#255#157#229#245
+#255#158#229#245#255#159#229#244#255#218#243#248#255'5'#148#218#255#253#244
+#238#255#202#128'T'#249'5'#171#218#250#232#246#251#255'p'#188#231#255'U'#170
+#226#255'M'#165#224#255#145#201#235#255#250#243#239#255#253#254#253#255#255
+#253#252#255#255#253#252#255#254#253#252#255#254#252#251#255#254#254#253#255
+'5'#148#218#255#239#242#232#255#206#129'V'#255'6'#170#218#242#241#250#253#255
+#148#222#245#255#147#220#244#255'd'#188#233#255'5'#148#218#255'5'#148#218#255
+'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255
+'5'#148#218#255'5'#148#218#255#251#246#239#255#204#131'U'#254'5'#175#218#240
+#247#252#254#255#142#228#248#255#145#222#245#255#159#224#245#255#172#225#246
+#255#202#132'R'#255#255#247#241#255#255#233#217#255#255#234#219#255#255#233
+#217#255#255#231#215#255#255#229#210#255#255#226#203#255#255#247#241#255#203
+#133'U'#254'6'#179#218#248#253#254#254#255#254#255#255#255#254#254#255#255
+#253#254#255#255#254#255#255#255#228#186#145#255#255#247#240#255#255#231#213
+#255#253#231#214#255#253#230#212#255#252#228#208#255#251#227#203#255#250#220
+#194#255#254#243#232#255#204#134'V'#254'4'#180#217#208'^'#194#225#250'`'#195
+#226#250'`'#195#226#250'`'#195#226#250'_'#195#226#250#228#187#145#255#255#247
+#242#255#254#231#213#255#254#231#213#255#253#229#209#255#250#224#202#255#249
+#222#196#255#247#217#188#255#253#242#231#255#204#135'W'#254#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187
+#146#255#254#247#241#255#252#229#210#255#252#228#209#255#251#226#204#255#249
+#221#196#255#246#215#187#255#243#209#175#255#250#239#228#255#204#135'X'#254
,#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#228#187#146#255#254#246#240#255#252#226#205#255#252#227#205#255
+#250#223#200#255#247#217#188#255#245#233#221#255#250#243#235#255#251#248#243
+#255#202#131'S'#254#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#228#187#147#255#254#245#237#255#252#222#197#255
+#251#224#199#255#249#220#194#255#245#211#180#255#254#249#243#255#250#226#196
+#255#236#193#147#255#195'}H'#147#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#229#190#150#255#255#255#254#255
+#253#243#233#255#253#243#234#255#252#242#232#255#250#239#227#255#250#242#231
+#255#234#187#136#255#207#133'U'#179#180'i='#12#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#234#195#157#255#230
+#191#150#255#228#187#146#255#228#187#146#255#209#160'l'#245#208#158'm'#246
+#204#150'_'#218#196'yB~'#178'g<'#9#255#255#255#0#7'OnClick'#7#13'acOpenExecu'
+'te'#0#0#9'TMenuItem'#9'mnuSaveAs'#6'Action'#7#8'AcSaveAs'#11'Bitmap.Data'#10
+':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0
+' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#186'j6'#0#185'i5'#181
+#184'i5'#238#183'h5'#255#181'h5'#255#180'g4'#255#178'f4'#255#176'e3'#255#174
+'d3'#255#172'c2'#255#170'b2'#255#169'a2'#255#168'`1'#255#167'`1'#254#166'`1'
+#241#168'a1'#196#186'j5'#222#235#198#173#255#234#197#173#255#254#251#248#255
+#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248
+#255#254#251#248#255#254#251#248#255#211#150'm'#255#210#167#138#255#171'b2'
+#255#187'j6'#255#240#210#190#255#226#163'z'#255#226#163'z'#255#225#163'z'#255
+#226#163'{'#255#225#163'{'#255#224#161'x'#255#222#159'w'#255#221#159'v'#255
+#220#157't'#255#217#155'r'#255#216#153'q'#255#214#153'p'#255#213#171#142#255
+#173'c3'#255#187'j6'#255#242#213#194#255#227#163'z'#255#227#163'z'#255#226
+#163'{'#255#226#163'{'#255#226#164'{'#255#225#162'y'#255#224#161'x'#255#222
+#160'w'#255#222#158'u'#255#220#157't'#255#218#155's'#255#217#155's'#255#218
+#176#149#255#175'd3'#255#187'j6'#255#242#216#197#255#227#164'{'#255#227#163
+'z'#255#227#164'z'#255#226#164'{'#255#226#163'{'#255#225#163'{'#255#225#162
+'y'#255#223#160'w'#255#222#159'v'#255#221#158't'#255#219#156'r'#255#220#157
+'t'#255#221#181#154#255#177'e4'#255#187'k6'#255#244#217#199#255#230#166'}'
+#255#200#140'd'#255#201#141'e'#255#201#142'g'#255#203#146'l'#255#203#146'm'
+#255#202#144'i'#255#200#140'e'#255#200#140'd'#255#200#140'd'#255#200#140'd'
+#255#218#156't'#255#225#186#159#255#179'f4'#255#187'k6'#254#244#220#201#255
+#231#167'}'#255#249#236#225#255#249#236#225#255#249#237#227#255#252#244#238
+#255#253#250#247#255#253#247#243#255#250#237#229#255#247#231#219#255#247#229
+#217#255#246#229#216#255#222#160'w'#255#228#190#164#255#180'g4'#255#188'k6'
+#250#245#221#204#255#231#168'~'#255#250#240#232#255#250#240#232#255#201#141
+'f'#255#250#240#233#255#253#248#243#255#254#250#248#255#252#244#239#255#249
+#233#223#255#247#231#219#255#247#229#217#255#224#162'x'#255#231#194#169#255
+#182'h5'#255#188'k6'#240#246#223#208#255#232#168'~'#255#252#246#241#255#252
+#246#241#255#200#140'd'#255#250#241#233#255#251#244#238#255#253#250#247#255
+#253#249#246#255#250#240#232#255#248#232#221#255#247#230#219#255#225#163'z'
+#255#239#213#195#255#183'i5'#254#188'k6'#216#246#223#209#255#233#170#128#255
+#254#250#246#255#253#250#246#255#200#140'd'#255#251#243#238#255#251#241#234
+#255#252#246#242#255#254#251#248#255#252#246#241#255#249#236#226#255#248#231
+#219#255#238#208#186#255#236#208#189#255#187'p>'#248#188'k6'#155#246#224#209
+#255#247#224#209#255#254#251#248#255#254#251#247#255#253#249#246#255#252#245
+#240#255#250#240#234#255#251#242#237#255#253#249#246#255#253#250#247#255#251
+#241#235#255#248#233#223#254#236#208#189#251#201#137'^'#236#181'i5c'#188'k6q'
+#188'k6'#144#188'k6'#204#188'k6'#238#188'k6'#250#187'k6'#254#187'k6'#255#187
,'j6'#255#187'j6'#255#188'l9'#255#189'n;'#255#187'm:'#255#187'k8'#239#187'p>'
+#203#182'i5T'#255#255#255#0#7'OnClick'#7#15'acSaveAsExecute'#0#0#9'TMenuItem'
+#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#7'mnuQuit'#6'Action'#7#6'Ac'
+'Quit'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0
+#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0
+#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#29'c'#155#22#25'`'
+#152'9'#20']'#149'b'#16'Z'#146#136#13'X'#144#164#19'\'#146#252#12'W'#143#237
+#153#153#153#255'qqq'#255'TTT'#255'QQQ'#255'OOO'#255'LLL'#255'JJJ'#255'GGG'
+#255'EEE'#255'%g'#157#255'2t'#168#255'=|'#175#255'G'#132#181#255'N'#138#186
+#255'>~'#173#255#12'W'#143#234#255#255#255#0#255#255#255#0'XXX'#255#162#162
+#162#255#162#162#162#255#163#163#163#255#164#164#164#255#164#164#164#255#165
+#165#165#255'/o'#165#255'x'#171#210#255'x'#171#211#255's'#167#209#255'i'#160
+#205#255'@'#127#174#255#15'Y'#145#234#255#255#255#0#255#255#255#0'\\\'#255
+#161#161#161#255'<s@'#255#160#161#161#255#163#163#163#255#163#163#163#255#164
+#164#164#255'6t'#170#255'}'#175#212#255'['#154#201#255'T'#149#199#255'X'#150
+#200#255'A'#128#174#255#19'\'#148#234#255#255#255#0#255#255#255#0'```'#255
+#160#160#160#255'=vA'#255'6q9'#255#162#162#162#255#162#162#162#255#163#163
+#163#255'=y'#176#255#130#179#215#255'b'#159#204#255'Z'#154#201#255'^'#155#202
+#255'C'#129#175#255#25'`'#152#234'7'#130'>'#255'4~;'#255'1y7'#255'.u4'#255'I'
+#145'P'#255'F'#143'L'#255'9s='#255#161#161#161#255#162#162#162#255'E~'#180
+#255#136#183#217#255'g'#163#207#255'a'#158#204#255'c'#159#204#255'E'#131#177
+#255#31'd'#156#234';'#135'B'#255#137#203#146#255#132#200#141#255#128#198#136
+#255'{'#195#131#255'w'#193#127#255'G'#143'M'#255';t?'#255#161#161#161#255'L'
+#132#186#255#141#187#219#255'n'#168#209#255'f'#166#209#255'_'#180#223#255'G'
+#133#177#255'%i'#161#234'>'#139'F'#255#143#206#153#255'}'#198#135#255'x'#195
+#129#255's'#192'|'#255't'#192'|'#255'y'#194#129#255'I'#144'O'#255'T'#127'W'
+#255'T'#137#191#255#148#191#221#255'u'#173#212#255'c'#184#225#255'K'#212#255
+#255'B'#139#184#255',n'#166#234'A'#144'J'#255#148#210#159#255#145#208#154#255
+#141#205#150#255#137#203#146#255#132#200#141#255'Q'#152'X'#255'A|F'#255#159
+#159#159#255'Z'#142#196#255#152#195#224#255'|'#179#215#255't'#175#214#255'^'
+#196#237#255'K'#136#179#255'4s'#171#234'D'#148'M'#255'B'#145'K'#255'?'#141'H'
+#255'='#137'E'#255']'#164'e'#255'Z'#160'a'#255'E'#131'K'#255#158#158#158#255
+#158#158#158#255'`'#146#201#255#158#199#226#255#131#184#218#255'}'#180#215
+#255'~'#179#215#255'O'#137#180#255';y'#177#234#255#255#255#0#255#255#255#0'w'
+'ww'#255#154#154#154#255'='#138'E'#255'I'#138'O'#255#156#156#156#255#157#157
+#157#255#157#157#157#255'f'#150#204#255#162#203#227#255#137#189#220#255#131
+#185#218#255#132#185#218#255'Q'#139#181#255'C~'#182#234#255#255#255#0#255#255
+#255#0'zzz'#255#153#153#153#255'R'#145'Y'#255#153#154#153#255#155#155#155#255
+#156#156#156#255#156#156#156#255'l'#154#208#255#167#206#229#255#143#193#223
+#255#137#189#220#255#139#189#220#255'S'#141#182#255'K'#132#188#234#255#255
+#255#0#255#255#255#0'}}}'#255#153#153#153#255#153#153#153#255#154#154#154#255
+#154#154#154#255#155#155#155#255#155#155#155#255'o'#157#211#255#170#209#231
+#255#171#209#231#255#152#199#225#255#145#194#222#255'V'#143#183#255'R'#137
+#193#234#255#255#255#0#255#255#255#0#128#128#128#255'~~~'#255'|||'#255'zzz'
+#255'www'#255'uuu'#255'rrr'#255'q'#158#212#255'o'#158#214#255#135#178#220#255
+#171#211#232#255#169#208#230#255'X'#144#184#255'Y'#142#198#234#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'p'#158#214
+#219'm'#156#212#255#133#177#218#255'Z'#145#185#255'`'#147#203#234#255#255#255
+#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#200#154
+'|'#255#199#152'y'#255#167'`1'#237#186'k7'#254#237#202#179#255#224#162'z'#255
+#254#250#247#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255#253#249#246#255
+#202#141'e'#255#201#155'|'#255#167'`1'#254#187'l8'#255#238#204#182#255#225
+#162'z'#255#254#250#247#255#191#220#194#255#191#220#194#255#191#220#194#255
+#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194
+#255#253#249#246#255#205#144'h'#255#204#158#129#255#168'a2'#255#187'k8'#255
+#239#206#184#255#225#162'y'#255#254#250#247#255'b'#192#136#255'b'#192#136#255
+'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+'b'#192#136#255#253#249#246#255#207#147'j'#255#206#163#132#255#170'a2'#255
+#186'j6'#255#239#208#187#255#226#162'z'#255#254#251#248#255#254#251#248#255
+#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248
+#255#254#251#248#255#254#251#248#255#254#251#248#255#211#150'm'#255#210#167
+#138#255#171'b2'#255#187'j6'#255#240#210#190#255#226#163'z'#255#226#163'z'
+#255#225#163'z'#255#226#163'{'#255#225#163'{'#255#224#161'x'#255#222#159'w'
+#255#221#159'v'#255#220#157't'#255#217#155'r'#255#216#153'q'#255#214#153'p'
+#255#213#171#142#255#173'c3'#255#187'j6'#255#242#213#194#255#227#163'z'#255
+#227#163'z'#255#226#163'{'#255#226#163'{'#255#226#164'{'#255#225#162'y'#255
+#224#161'x'#255#222#160'w'#255#222#158'u'#255#220#157't'#255#218#155's'#255
+#217#155's'#255#218#176#149#255#175'd3'#255#187'j6'#255#242#216#197#255#227
+#164'{'#255#227#163'z'#255#227#164'z'#255#226#164'{'#255#226#163'{'#255#225
+#163'{'#255#225#162'y'#255#223#160'w'#255#222#159'v'#255#221#158't'#255#219
+#156'r'#255#220#157't'#255#221#181#154#255#177'e4'#255#187'k6'#255#244#217
+#199#255#230#166'}'#255#200#140'd'#255#201#141'e'#255#201#142'g'#255#203#146
+'l'#255#203#146'm'#255#202#144'i'#255#200#140'e'#255#200#140'd'#255#200#140
+'d'#255#200#140'd'#255#218#156't'#255#225#186#159#255#179'f4'#255#187'k6'#254
+#244#220#201#255#231#167'}'#255#249#236#225#255#249#236#225#255#249#237#227
+#255#252#244#238#255#253#250#247#255#253#247#243#255#250#237#229#255#247#231
+#219#255#247#229#217#255#246#229#216#255#222#160'w'#255#228#190#164#255#180
+'g4'#255#188'k6'#250#245#221#204#255#231#168'~'#255#250#240#232#255#250#240
+#232#255#201#141'f'#255#250#240#233#255#253#248#243#255#254#250#248#255#252
+#244#239#255#249#233#223#255#247#231#219#255#247#229#217#255#224#162'x'#255
+#231#194#169#255#182'h5'#255#188'k6'#240#246#223#208#255#232#168'~'#255#252
+#246#241#255#252#246#241#255#200#140'd'#255#250#241#233#255#251#244#238#255
+#253#250#247#255#253#249#246#255#250#240#232#255#248#232#221#255#247#230#219
+#255#225#163'z'#255#239#213#195#255#183'i5'#254#188'k6'#216#246#223#209#255
+#233#170#128#255#254#250#246#255#253#250#246#255#200#140'd'#255#251#243#238
+#255#251#241#234#255#252#246#242#255#254#251#248#255#252#246#241#255#249#236
+#226#255#248#231#219#255#238#208#186#255#236#208#189#255#187'p>'#248#188'k6'
+#155#246#224#209#255#247#224#209#255#254#251#248#255#254#251#247#255#253#249
+#246#255#252#245#240#255#250#240#234#255#251#242#237#255#253#249#246#255#253
+#250#247#255#251#241#235#255#248#233#223#254#236#208#189#251#201#137'^'#236
+#181'i5c'#188'k6q'#188'k6'#144#188'k6'#204#188'k6'#238#188'k6'#250#187'k6'
,#254#187'k6'#255#187'j6'#255#187'j6'#255#188'l9'#255#189'n;'#255#187'm:'#255
+#187'k8'#239#187'p>'#203#182'i5T'#255#255#255#0#7'OnClick'#7#15'acSaveAsExec'
+'ute'#0#0#9'TMenuItem'#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#7'mnu'
+'Quit'#6'Action'#7#6'AcQuit'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0
+#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0
+#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#29'c'#155#22#25'`'#152'9'#20']'#149'b'#16'Z'#146#136#13'X'#144#164#19'\'#146
+#252#12'W'#143#237#153#153#153#255'qqq'#255'TTT'#255'QQQ'#255'OOO'#255'LLL'
+#255'JJJ'#255'GGG'#255'EEE'#255'%g'#157#255'2t'#168#255'=|'#175#255'G'#132
+#181#255'N'#138#186#255'>~'#173#255#12'W'#143#234#255#255#255#0#255#255#255#0
+'XXX'#255#162#162#162#255#162#162#162#255#163#163#163#255#164#164#164#255#164
+#164#164#255#165#165#165#255'/o'#165#255'x'#171#210#255'x'#171#211#255's'#167
+#209#255'i'#160#205#255'@'#127#174#255#15'Y'#145#234#255#255#255#0#255#255
+#255#0'\\\'#255#161#161#161#255'<s@'#255#160#161#161#255#163#163#163#255#163
+#163#163#255#164#164#164#255'6t'#170#255'}'#175#212#255'['#154#201#255'T'#149
+#199#255'X'#150#200#255'A'#128#174#255#19'\'#148#234#255#255#255#0#255#255
+#255#0'```'#255#160#160#160#255'=vA'#255'6q9'#255#162#162#162#255#162#162#162
+#255#163#163#163#255'=y'#176#255#130#179#215#255'b'#159#204#255'Z'#154#201
+#255'^'#155#202#255'C'#129#175#255#25'`'#152#234'7'#130'>'#255'4~;'#255'1y7'
+#255'.u4'#255'I'#145'P'#255'F'#143'L'#255'9s='#255#161#161#161#255#162#162
+#162#255'E~'#180#255#136#183#217#255'g'#163#207#255'a'#158#204#255'c'#159#204
+#255'E'#131#177#255#31'd'#156#234';'#135'B'#255#137#203#146#255#132#200#141
+#255#128#198#136#255'{'#195#131#255'w'#193#127#255'G'#143'M'#255';t?'#255#161
+#161#161#255'L'#132#186#255#141#187#219#255'n'#168#209#255'f'#166#209#255'_'
+#180#223#255'G'#133#177#255'%i'#161#234'>'#139'F'#255#143#206#153#255'}'#198
+#135#255'x'#195#129#255's'#192'|'#255't'#192'|'#255'y'#194#129#255'I'#144'O'
+#255'T'#127'W'#255'T'#137#191#255#148#191#221#255'u'#173#212#255'c'#184#225
+#255'K'#212#255#255'B'#139#184#255',n'#166#234'A'#144'J'#255#148#210#159#255
+#145#208#154#255#141#205#150#255#137#203#146#255#132#200#141#255'Q'#152'X'
+#255'A|F'#255#159#159#159#255'Z'#142#196#255#152#195#224#255'|'#179#215#255
+'t'#175#214#255'^'#196#237#255'K'#136#179#255'4s'#171#234'D'#148'M'#255'B'
+#145'K'#255'?'#141'H'#255'='#137'E'#255']'#164'e'#255'Z'#160'a'#255'E'#131'K'
+#255#158#158#158#255#158#158#158#255'`'#146#201#255#158#199#226#255#131#184
+#218#255'}'#180#215#255'~'#179#215#255'O'#137#180#255';y'#177#234#255#255#255
+#0#255#255#255#0'www'#255#154#154#154#255'='#138'E'#255'I'#138'O'#255#156#156
+#156#255#157#157#157#255#157#157#157#255'f'#150#204#255#162#203#227#255#137
+#189#220#255#131#185#218#255#132#185#218#255'Q'#139#181#255'C~'#182#234#255
+#255#255#0#255#255#255#0'zzz'#255#153#153#153#255'R'#145'Y'#255#153#154#153
+#255#155#155#155#255#156#156#156#255#156#156#156#255'l'#154#208#255#167#206
+#229#255#143#193#223#255#137#189#220#255#139#189#220#255'S'#141#182#255'K'
+#132#188#234#255#255#255#0#255#255#255#0'}}}'#255#153#153#153#255#153#153#153
+#255#154#154#154#255#154#154#154#255#155#155#155#255#155#155#155#255'o'#157
+#211#255#170#209#231#255#171#209#231#255#152#199#225#255#145#194#222#255'V'
+#143#183#255'R'#137#193#234#255#255#255#0#255#255#255#0#128#128#128#255'~~~'
+#255'|||'#255'zzz'#255'www'#255'uuu'#255'rrr'#255'q'#158#212#255'o'#158#214
+#255#135#178#220#255#171#211#232#255#169#208#230#255'X'#144#184#255'Y'#142
+#198#234#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0'm'#156#212#137'j'#154#210#251'f'#151#207#238#7'OnClick'
+#7#13'acQuitExecute'#0#0#0#9'TMenuItem'#7'mnuEdit'#7'Caption'#6#4'Edit'#0#9
+'TMenuItem'#9'MenuItem2'#6'Action'#7#6'AcEdit'#9'AutoCheck'#9#11'Bitmap.Data'
+#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0
+#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#255#0'p'#158#214#219'm'#156#212#255#133#177#218#255'Z'#145#185#255'`'
+#147#203#234#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#19'@X'
+#255#21'B^'#255'%i'#156#255',v'#180#255';'#139#186#173#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#18'BY'#255']'#156
+#212#255#166#207#245#255#169#207#236#255'H'#139#193#255',v'#180#255#255#255
,#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#30'm'#147#255#203
+#227#249#255'a'#170#236#255'@'#152#232#255#21'g'#194#255#22'`'#170#255',v'
+#180#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#30'm'#147#255#200
+#225#242#255#209#231#250#255'4}'#181#255'1'#153#195#255'm'#196#220#255'J'#156
+#207#255'4'#131#199#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0' c'#152' &'#137
+#185#255#176#203#225#255'g'#169#200#255'`'#220#245#255'D'#214#244#255#142#238
+#250#255']'#180#230#255';'#143#217#255#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0'&'#137#185#255#190#230#242#255#179#244#252#255'`'#220#245#255
+'D'#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0'm'#156#212#137'j'#154#210#251'f'
+#151#207#238#7'OnClick'#7#13'acQuitExecute'#0#0#0#9'TMenuItem'#7'mnuEdit'#7
+'Caption'#6#4'Edit'#0#9'TMenuItem'#9'MenuItem2'#6'Action'#7#6'AcEdit'#9'Auto'
+'Check'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('
+#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0
+#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0''''#144#191#255#195#237#248#255#179
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#19'@X'#255#21'B^'#255'%i'#156#255',v'#180#255';'#139#186
+#173#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#18'BY'#255']'#156#212#255#166#207#245#255#169#207#236#255'H'#139
,#193#255',v'#180#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#30'm'#147#255#203#227#249#255'a'#170#236#255'@'#152#232#255#21'g'
+#194#255#22'`'#170#255',v'#180#255#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#30'm'#147#255#200#225#242#255#209#231#250#255'4}'#181#255'1'#153
+#195#255'm'#196#220#255'J'#156#207#255'4'#131#199#255#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0' c'#152' &'#137#185#255#176#203#225#255'g'#169#200#255'`'#220
+#245#255'D'#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0'&'#137#185#255#190#230#242#255#179
+#244#252#255'`'#220#245#255'D'#214#244#255#142#238#250#255']'#180#230#255';'
+#143#217#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255
+#195#237#248#255#179#244#252#255'`'#220#245#255'D'#214#244#255#142#238#250
+#255']'#180#230#255';'#143#217#255#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0'/'#186#228#255#195#237#248#255#179#244#252#255'`'#220#245#255'D'
+#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195#237#248#255#179#244#252
+#255'h'#217#245#255'o'#207#243#255'Y'#157#208#255's'#171#221#255'O'#145#201
+#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195
+#237#248#255#168#226#248#255'l'#174#221#255#165#207#244#255#165#207#244#255
+#189#219#247#255'S'#147#203#247#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0'/'#186#228#255#167#212#244#255#197#225#248#255#204#227#249#255#204#227
+#249#255#189#219#247#255'O'#144#201#253#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0''''#144#191
+#255#195#237#248#255#179#244#252#255'`'#220#245#255'D'#214#244#255#142#238
+#250#255']'#180#230#255';'#143#217#255#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0'P'#168#217#255'j'#165#216#255#201#225#247#255
+#203#227#248#255'B'#149#202#255'1'#130#194#174#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#9'O'#170#219#234'P'#147#202
+#253'N'#144#200#255'/'#157#210#223'5'#164#222#25#255#255#255#0#255#255#255#0
+#255#255#255#0'/'#186#228#255#195#237#248#255#179#244#252#255'`'#220#245#255
+'D'#214#244#255#142#238#250#255']'#180#230#255';'#143#217#255#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195#237#248#255#179#244
+#252#255'`'#220#245#255'D'#214#244#255#142#238#250#255']'#180#230#255';'#143
+#217#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#255#195
+#237#248#255#179#244#252#255'h'#217#245#255'o'#207#243#255'Y'#157#208#255's'
+#171#221#255'O'#145#201#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+'/'#186#228#255#195#237#248#255#168#226#248#255'l'#174#221#255#165#207#244
+#255#165#207#244#255#189#219#247#255'S'#147#203#247#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0'/'#186#228#255#167#212#244#255#197#225#248#255#204
+#227#249#255#204#227#249#255#189#219#247#255'O'#144#201#253#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'TMenuItem'#9'mnuFor'
+'mat'#7'Caption'#6#6'Format'#0#9'TMenuItem'#7'MnuFOnt'#6'Action'#7#6'AcFont'
+#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16
+#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0'P'#168#217#255'j'#165#216
+#255#201#225#247#255#203#227#248#255'B'#149#202#255'1'#130#194#174#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'/'#186#228#9'O'#170
+#219#234'P'#147#202#253'N'#144#200#255'/'#157#210#223'5'#164#222#25#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'T'
+'MenuItem'#9'mnuFormat'#7'Caption'#6#6'Format'#0#9'TMenuItem'#7'MnuFOnt'#6'A'
+'ction'#7#6'AcFont'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0
+'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0
+#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
@ -310,110 +311,156 @@ LazarusResources.Add('TForm1','FORMDATA',[
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#206'h8'#174#218#143']'#254#219#144'`'#255
+#215#131'P'#237#196'P+'#141#189'B#'#16#188'?"*'#195'M+'#162#208'qB'#234#214
+'~Q'#255#213'|M'#255#198'U1'#189#182'9'#29'1'#255#255#255#0#255#255#255#0#255
+#255#255#0#202'\/'#10#203'_0D'#225#164'u'#255#218#140'X'#236#198'R,='#255#255
+#255#0#255#255#255#0#191'E$'#19#195'H'''#127#220#150'k'#255#219#143'`'#255
+#189'?!T'#182'8'#30#2#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#203']0'#1#211't?'#155#226#169'|'#255#204'f7'#153#255#255#255#0#255#255#255#0
+#255#255#255#0#204'c7'#177#223#160'w'#255#218#137'Z'#255#187'>""'#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#204
+'c2'#21#219#147'^'#234#226#167'y'#255#216#131'J'#211#207'j:'#178#206'h9'#181
,#213'zE'#216#227#168#129#255#217#134'V'#249#190'A#'#27#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#206'h8'#174#218#143']'#254#219#144'`'#255#215#131'P'#237#196
+'P+'#141#189'B#'#16#188'?"*'#195'M+'#162#208'qB'#234#214'~Q'#255#213'|M'#255
+#198'U1'#189#182'9'#29'1'#255#255#255#0#255#255#255#0#255#255#255#0#202'\/'
+#10#203'_0D'#225#164'u'#255#218#140'X'#236#198'R,='#255#255#255#0#255#255#255
+#0#191'E$'#19#195'H'''#127#220#150'k'#255#219#143'`'#255#189'?!T'#182'8'#30#2
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#203']0'#1#211't?'
+#155#226#169'|'#255#204'f7'#153#255#255#255#0#255#255#255#0#255#255#255#0#204
+'c7'#177#223#160'w'#255#218#137'Z'#255#187'>""'#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#204'c2'#21#219#147
+'^'#234#226#167'y'#255#216#131'J'#211#207'j:'#178#206'h9'#181#213'zE'#216#227
,#168#129#255#217#134'V'#249#190'A#'#27#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#207'j6\'#223
+#157'h'#246#218#139'R'#209#203'_1N'#199'Y.*'#205'g7'#160#225#166'z'#255#216
+#134'S'#242#191'F%'#13#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#208'j5'#3#215#128'B'#170#223#159
+'j'#247#205'f4f'#201']/'#10#204'a3'#136#225#166'y'#255#213'zD'#210#194'J'''#6
+#207'j6\'#223#157'h'#246#218#139'R'#209#203'_1N'#199'Y.*'#205'g7'#160#225#166
+'z'#255#216#134'S'#242#191'F%'#13#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#208'j5'#3#215#128'B'
+#170#223#159'j'#247#205'f4f'#201']/'#10#204'a3'#136#225#166'y'#255#213'zD'
+#210#194'J'''#6#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#209'q8"'#222#155'c'#226
+#220#150'^'#223#207'i5T'#207'i5'#128#226#169'|'#255#209'l:'#165#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#209'q8"'#222#155'c'#226#220#150'^'#223
+#207'i5T'#207'i5'#128#226#169'|'#255#209'l:'#165#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#212'y<w'#226#166'p'#247#218#136'G'#173
+#214'~C'#160#228#174#130#255#207'm:'#153#255#255#255#0#255#255#255#0#255#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#212'y<w'#226#166'p'#247
+#218#136'G'#173#214'~C'#160#228#174#130#255#207'm:'#153#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#214'};'#28#221#150'V'#186#227#169's'#242#225#168
+'s'#245#225#164'q'#247#211'w>'#152#203'_0'#8#255#255#255#0#255#255#255#0#255
+#255#255#255#0#255#255#255#0#255#255#255#0#214'};'#28#221#150'V'#186#227#169
+'s'#242#225#168's'#245#225#164'q'#247#211'w>'#152#203'_0'#8#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#215#131'>S'#226#167'l'#222#233#188#145#255#231#186#143
+#255#231#183#139#255#226#164'q'#251#214'~B'#182#203'\/'#10#255#255#255#0#255
+#255#0#255#255#255#0#255#255#255#0#215#131'>S'#226#167'l'#222#233#188#145#255
+#231#186#143#255#231#183#139#255#226#164'q'#251#214'~B'#182#203'\/'#10#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#216#135'@@'#216#139'C'#133#218#142'I'#148#217#137'C'#143
+#216#132'@'#144#216#132'A'#154#211's:'#138#204'b2'#13#201'[.'#1#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#0#255#255#255#0#255#255#255#0#216#135'@@'#216#139'C'#133#218#142'I'#148
+#217#137'C'#143#216#132'@'#144#216#132'A'#154#211's:'#138#204'b2'#13#201'[.'
+#1#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#0#0#9'TMenuItem'#15'MnuTextRotation'#7'Caption'#6#13'Text rotation'#0#9'TMe'
+'nuItem'#10'MenuItem29'#6'Action'#7#11'AcTextHoriz'#9'AutoCheck'#9#0#0#9'TMe'
+'nuItem'#10'MenuItem30'#6'Action'#7#12'AcTextVertCW'#9'AutoCheck'#9#0#0#9'TM'
+'enuItem'#10'MenuItem31'#6'Action'#7#13'AcTextVertCCW'#9'AutoCheck'#9#0#0#9
+'TMenuItem'#10'MenuItem32'#6'Action'#7#13'AcTextStacked'#9'AutoCheck'#9#0#0#0
+#9'TMenuItem'#15'MnuHorAlignment'#7'Caption'#6#20'Horizontal alignment'#0#9
+'TMenuItem'#13'MnuHorDefault'#6'Action'#7#17'AcHorDefaultAlign'#9'AutoCheck'
+#9#0#0#9'TMenuItem'#9'MenuItem6'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#9'MenuIt'
+'em3'#6'Action'#7#11'AcLeftAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0
+'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0
+#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#255#0#0#0#9'TMenuItem'#15'MnuTextRotation'#7'Caption'#6#13'Text rot'
+'ation'#0#9'TMenuItem'#10'MenuItem29'#6'Action'#7#11'AcTextHoriz'#9'AutoChec'
+'k'#9#0#0#9'TMenuItem'#10'MenuItem30'#6'Action'#7#12'AcTextVertCW'#9'AutoChe'
+'ck'#9#0#0#9'TMenuItem'#10'MenuItem31'#6'Action'#7#13'AcTextVertCCW'#9'AutoC'
+'heck'#9#0#0#9'TMenuItem'#10'MenuItem32'#6'Action'#7#13'AcTextStacked'#9'Aut'
+'oCheck'#9#0#0#0#9'TMenuItem'#15'MnuHorAlignment'#7'Caption'#6#20'Horizontal'
+' alignment'#0#9'TMenuItem'#13'MnuHorDefault'#6'Action'#7#17'AcHorDefaultAli'
+'gn'#9'AutoCheck'#9#0#0#9'TMenuItem'#9'MenuItem6'#7'Caption'#6#1'-'#0#0#9'TM'
+'enuItem'#9'MenuItem3'#6'Action'#7#11'AcLeftAlign'#9'AutoCheck'#9#11'Bitmap.'
+'Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16
+#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+'<<<'#255'555'#255'///'#255')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20#20
+#20#255#15#15#15#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#255#0'<<<'#255'555'#255'///'#255')))'#255'$$$'#255#30#30#30#255#25
+#25#25#255#20#20#20#255#15#15#15#255#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>>>'#255'888'
+#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22#255#17#17#17
+#255#12#12#12#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'XXX'
+#255'RRR'#255'LLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'...'#255'((('#255
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>'
+'>>'#255'888'#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22
+#255#17#17#17#255#12#12#12#255#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'III'
+#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#255
+#255#255#0'XXX'#255'RRR'#255'LLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'..'
+'.'#255'((('#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'O'
+'OO'#255'III'#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
,#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0'ooo'#255'kkk'#255'fff'#255'aaa'#255'\'
+'\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'ooo'#255'kkk'#255'fff'
+#255'aaa'#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255
+'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'
+#255'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0'vvv'#255'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'
+#255'SSS'#255'NNN'#255'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#9'TMe'
+'nuItem'#9'MenuItem4'#6'Action'#7#16'AcHorCenterAlign'#9'AutoCheck'#9#11'Bit'
+'map.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0
+#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0'555k///'#255')))'#255'$$$'#255#30#30#30
+#255#25#25#25#255#20#20#20#255#15#15#15#255#11#11#11#255#7#7#7'k'#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>'
+'>>'#255'888'#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22
+#255#17#17#17#255#12#12#12#255#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0'RRRkLLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'..'
+'.'#255'((('#255'###'#255#29#29#29'k'#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'II'
+'I'#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'kkkkfff'#255'aaa'
+#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'999k'#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255'ttt'#255'p'
+'pp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'#255'HHH'
+#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
,#255#255#0#255#255#255#0#255#255#255#0#0#0#9'TMenuItem'#9'MenuItem5'#6'Actio'
+'n'#7#12'AcRightAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'B'
+'M6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0
+#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#9'TMenuItem'#9'MenuItem'
+'4'#6'Action'#7#16'AcHorCenterAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0
+#0'6'#4#0#0'BM6'#4#0#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0
+#0#0#0#0#4#0#0'd'#0#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0'555k///'#255')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20#20
+#20#255#15#15#15#255#11#11#11#255#7#7#7'k'#255#255#255#0#255#255#255#0#255
+#255#255#255#0#255#255#255#0')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20
+#20#20#255#15#15#15#255#11#11#11#255#7#7#7#255#3#3#3#255#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
@ -423,95 +470,48 @@ LazarusResources.Add('TForm1','FORMDATA',[
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0'RRRkLLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'...'#255'((('#255'##'
+'#'#255#29#29#29'k'#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#0#255#255#255#0#255#255#255#0'FFF'#255'@@@'#255':::'#255'444'#255'...'
+#255'((('#255'###'#255#29#29#29#255#24#24#24#255#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'III'#255'CCC'#255
+'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0'kkkkfff'#255'aaa'#255'\\\'#255'WWW'
+#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'999k'#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'II'
+'I'#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255'ttt'#255'ppp'#255'lll'
+#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'#255'HHH'#255'BBB'#255
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0'aaa'#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'99'
+'9'#255'333'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'
+#255'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255
+'NNN'#255'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
,#255#255#255#0#255#255#255#0#0#0#9'TMenuItem'#9'MenuItem5'#6'Action'#7#12'Ac'
+'RightAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0#0
+#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0#0
+'d'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0')))'#255'$$$'#255#30#30#30#255#25#25#25#255#20#20#20#255
+#15#15#15#255#11#11#11#255#7#7#7#255#3#3#3#255#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>>>'#255'888'#255'222'#255',,'
+','#255'&&&'#255' '#255#27#27#27#255#22#22#22#255#17#17#17#255#12#12#12#255
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0'FFF'#255'@@@'#255':::'#255'444'#255'...'#255'((('
+#255'###'#255#29#29#29#255#24#24#24#255#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'III'#255'C'
+'CC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+'aaa'#255'\\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255'???'#255'999'#255'333'
+#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'vvv'#255'ttt'
+#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN'#255
+'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'TMenuItem'#16'M'
+'nuVertAlignment'#7'Caption'#6#18'Vertical alignment'#0#9'TMenuItem'#14'MnuV'
+'ertDefault'#6'Action'#7#15'AcVAlignDefault'#9'AutoCheck'#9#0#0#9'TMenuItem'
+#9'MenuItem7'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#10'MnuVertTop'#6'Action'#7
+#11'AcVAlignTop'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0
+#0#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0
+#0#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'TMenuItem'#16'MnuVe'
+'rtAlignment'#7'Caption'#6#18'Vertical alignment'#0#9'TMenuItem'#14'MnuVertD'
+'efault'#6'Action'#7#15'AcVAlignDefault'#9'AutoCheck'#9#0#0#9'TMenuItem'#9'M'
+'enuItem7'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#10'MnuVertTop'#6'Action'#7#11
+'AcVAlignTop'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0
+#0#0#0#0'6'#0#0#0'('#0#0#0#16#0#0#0#16#0#0#0#1#0' '#0#0#0#0#0#0#4#0#0'd'#0#0
+#0'd'#0#0#0#0#0#0#0#0#0#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0';;;'#0'444'#0'...'#0'(('
+'('#0'###'#0#29#29#29#0#24#24#24#0#19#19#19#0#15#15#15#0#11#11#11#0#7#7#7#0#3
+#3#3#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0';;;'#0'444'#0'...'#0
+'((('#0'###'#0#29#29#29#0#24#24#24#0#19#19#19#0#15#15#15#0#11#11#11#0#7#7#7#0
+#3#3#3#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
,#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'III'#0'CCC'#0
+'==='#0'777'#0'111'#0'+++'#0'%%%'#0#31#31#31#0#26#26#26#0#21#21#21#0#17#17#17

View File

@ -137,10 +137,11 @@ type
TsUsedFormattingFields = set of TsUsedFormattingField;
{@@ Number/cell formatting. Only uses a subset of the default formats,
enough to be able to read/write date values. }
enough to be able to read/write date/time values.
nfCustom allows to apply a format string directly. }
TsNumberFormat = (nfGeneral, nfFixed, nfFixedTh, nfExp, nfSci, nfPercentage,
nfShortDateTime, nfFmtDateTime, nfShortDate, nfShortTime, nfLongTime,
nfShortTimeAM, nfLongTimeAM, nfTimeInterval);
nfShortDateTime, nfFmtDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
nfShortTimeAM, nfLongTimeAM, nfTimeInterval, nfCustom);
{@@ Text rotation formatting. The text is rotated relative to the standard
orientation, which is from left to right horizontal:
@ -364,14 +365,17 @@ type
{ Writing of values }
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
AFormat: TsNumberFormat = nfGeneral; ADecimals: Word = 2);
AFormat: TsNumberFormat = nfGeneral; ADecimals: Word = 2); overload;
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double;
AFormatString: String); overload;
procedure WriteBlank(ARow, ACol: Cardinal);
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
{ Writing of cell attributes }
procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat);
procedure WriteNumberFormat(ARow, ACol: Cardinal; ANumberFormat: TsNumberFormat;
const AFormatString: String);
function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
@ -481,6 +485,50 @@ type
property FileFormat: TsSpreadsheetFormat read FFormat;
end;
{@@ Contents of the format record }
TsNumFormatData = class
public
Index: Integer;
NumFormat: TsNumberFormat;
Decimals: Integer;
FormatString: string;
end;
{@@ Specialized list for number format items }
TsCustomNumFormatList = class(TFPList)
private
function GetItem(AIndex: Integer): TsNumFormatData;
procedure SetItem(AIndex: Integer; AValue: TsNumFormatData);
protected
FFirstFormatIndexInFile: Integer;
FNextFormatIndex: Integer;
procedure AddBuiltinFormats; virtual;
procedure Analyze(var AFormatString: String; var ANumFormat: TsNumberFormat;
var ADecimals: Word); virtual;
procedure RemoveFormat(AIndex: Integer);
public
constructor Create;
destructor Destroy; override;
function AddFormat(AFormatCell: PCell): Integer; overload;
function AddFormat(AFormatIndex: Integer; ANumFormat: TsNumberFormat;
AFormatString: String = ''; ADecimals: Integer = 0): Integer; overload;
procedure AnalyzeAndAdd(AFormatIndex: Integer; AFormatString: String);
procedure Clear;
procedure Delete(AIndex: Integer);
function Find(AFormatCell: PCell): integer; overload;
function Find(ANumFormat: TsNumberFormat; AFormatString: String;
ADecimals: Integer): Integer; overload;
function Find(AFormatIndex: Integer): Integer; overload;
function FormatStringForWriting(AIndex: Integer): String; virtual;
procedure Sort;
property FirstFormatIndexInFile: Integer read FFirstFormatIndexInFile;
property Items[AIndex: Integer]: TsNumFormatData read GetItem write SetItem; default;
end;
{@@ TsSpreadReader class reference type }
TsSpreadReaderClass = class of TsCustomSpreadReader;
@ -491,6 +539,8 @@ type
protected
FWorkbook: TsWorkbook;
FWorksheet: TsWorksheet;
FNumFormatList: TsCustomNumFormatList;
procedure CreateNumFormatList; virtual; abstract;
{ Record reading methods }
procedure ReadBlank(AStream: TStream); virtual; abstract;
procedure ReadFormula(AStream: TStream); virtual; abstract;
@ -498,11 +548,13 @@ type
procedure ReadNumber(AStream: TStream); virtual; abstract;
public
constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
destructor Destroy; override;
{ General writing methods }
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); virtual;
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); virtual;
procedure ReadFromStrings(AStrings: TStrings; AData: TsWorkbook); virtual;
property Workbook: TsWorkbook read FWorkbook;
property NumFormatList: TsCustomNumFormatList read FNumFormatList;
end;
{@@ TsSpreadWriter class reference type }
@ -517,12 +569,17 @@ type
private
FWorkbook: TsWorkbook;
protected
FNumFormatList: TsCustomNumFormatList;
{ Helper routines }
procedure AddDefaultFormats(); virtual;
procedure CreateNumFormatList; virtual; abstract;
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
function FindFormattingInList(AFormat: PCell): Integer;
procedure FixFormat(ACell: PCell); virtual;
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
procedure ListAllFormattingStyles;
procedure ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
procedure ListAllNumFormats; virtual;
{ Helpers for writing }
procedure WriteCellCallback(ACell: PCell; AStream: TStream);
procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
@ -541,12 +598,14 @@ type
FFormattingStyles: array of TCell;
NextXFIndex: Integer; // Indicates which should be the next XF (Style) Index when filling the styles list
constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
destructor Destroy; override;
{ General writing methods }
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual;
procedure WriteToStream(AStream: TStream); virtual;
procedure WriteToStrings(AStrings: TStrings); virtual;
property Workbook: TsWorkbook read FWorkbook;
property NumFormatList: TsCustomNumFormatList read FNumFormatList;
end;
{@@ List of registered formats }
@ -615,10 +674,6 @@ procedure RegisterSpreadFormat(
AFormat: TsSpreadsheetFormat);
function GetFileFormatName(AFormat: TsSpreadsheetFormat): String;
function SciFloat(AValue: Double; ADecimals: Word): String;
function TimeIntervalToString(AValue: TDateTime): String;
procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
implementation
@ -731,50 +786,6 @@ begin
end;
{@@
Formats the number AValue in "scientific" format with the given number of
decimals. "Scientific" is the same as "exponential", but with exponents rounded
to multiples of 3.
}
function SciFloat(AValue: Double; ADecimals: Word): String;
var
m: Double;
ex: Integer;
begin
if AValue = 0 then
Result := '0.0'
else begin
ex := floor(log10(abs(AValue))); // exponent
// round exponent to multiples of 3
ex := (ex div 3) * 3;
if ex < 0 then dec(ex, 3);
m := AValue * Power(10, -ex); // mantisse
Result := Format('%.*fE%d', [ADecimals, m, ex]);
end;
end;
{@@
Formats the number AValue as a time string with hours, minutes and seconds.
Unlike TimeToStr there can be more than 24 hours.
}
function TimeIntervalToString(AValue: TDateTime): String;
var
hrs: Integer;
diff: Double;
h,m,s,z: Word;
ts: String;
begin
ts := DefaultFormatSettings.TimeSeparator;
DecodeTime(frac(abs(AValue)), h, m, s, z);
hrs := h + trunc(abs(AValue))*24;
if z > 499 then inc(s);
if hrs > 0 then
Result := Format('%d%s%.2d%s%.2d', [hrs, ts, m, ts, s])
else
Result := Format('%d%s%.2d', [m, ts, s]);
if AValue < 0.0 then Result := '-' + Result;
end;
{@@
If a palette is coded as big-endian (e.g. by copying the rgb values from
the OpenOffice doc) the palette values can be converted by means of this
@ -1109,31 +1120,33 @@ end;
function TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
function FloatToStrNoNaN(const Value: Double;
ANumberFormat: TsNumberFormat; ANumberFormatStr: ansistring): ansistring;
ANumberFormat: TsNumberFormat; ANumberFormatStr: string; ADecimals: Word): ansistring;
begin
if IsNan(Value) then
Result := ''
else
if ANumberFormat = nfSci then
Result := SciFloat(Value, 1)
Result := SciFloat(Value, ADecimals)
else
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
Result := FloatToStr(Value)
else
if (ANumberFormat = nfPercentage) then
Result := FormatFloat(ANumberFormatStr, Value*100) + '%'
Result := FormatFloat(ANumberFormatStr, Value*100) // '%' is already added to FormatStr.
else
Result := FormatFloat(ANumberFormatStr, Value);
end;
function DateTimeToStrNoNaN(const Value: Double;
ANumberFormat: TsNumberFormat; ANumberFormatStr: String): ansistring;
ANumberFormat: TsNumberFormat; ANumberFormatStr: String; ADecimals: Word): ansistring;
begin
Result := '';
if not IsNaN(Value) then begin
(*
if ANumberFormat = nfTimeInterval then
Result := TimeIntervalToString(Value)
Result := TimeIntervalToString(Value, ANumberFormatStr)
else
*)
if ANumberFormatStr = '' then
Result := FormatDateTime('c', Value)
else
@ -1152,14 +1165,17 @@ begin
Exit;
end;
case ACell^.ContentType of
//cctFormula
cctNumber: Result := FloatToStrNoNaN(ACell^.NumberValue, ACell^.NumberFormat, ACell^.NumberFormatStr);
cctUTF8String: Result := ACell^.UTF8StringValue;
cctDateTime: Result := DateTimeToStrNoNaN(ACell^.DateTimeValue, ACell^.NumberFormat, ACell^.NumberFormatStr);
else
Result := '';
end;
with ACell^ do
case ContentType of
cctNumber:
Result := FloatToStrNoNaN(NumberValue, NumberFormat, NumberFormatStr, NumberDecimals);
cctUTF8String:
Result := UTF8StringValue;
cctDateTime:
Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr, NumberDecimals);
else
Result := '';
end;
end;
function TsWorksheet.ReadAsNumber(ARow, ACol: Cardinal): Double;
@ -1322,14 +1338,33 @@ begin
nfExp:
ACell^.NumberFormatStr := '0' + decs + 'E+00';
nfSci:
ACell^.NumberFormatStr := '';
ACell^.NumberFormatStr := '##0' + decs + 'E+0';
nfPercentage:
ACell^.NumberFormatStr := '0' + decs;
ACell^.NumberFormatStr := '0' + decs + '%';
end;
end;
ChangedCell(ARow, ACol);
end;
{@@
Writes a floating point number to the cell and uses a custom number format
specified by the format string.
NOTE that fpspreadsheet may not be able to detect the formatting when reading
the file. }
procedure TsWorksheet.WriteNumber(ARow, ACol: Cardinal; ANumber: Double;
AFormatString: String);
var
ACell: PCell;
begin
ACell := GetCell(ARow, ACol);
Include(ACell^.UsedFormattingFields, uffNumberFormat);
ACell^.ContentType := cctNumber;
ACell^.NumberValue := ANumber;
ACell^.NumberFormat := nfCustom;
ACell^.NumberFormatStr := AFormatString;
ChangedCell(ARow, ACol);
end;
{@@
Writes as empty cell
@ -1385,6 +1420,8 @@ begin
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat;
nfShortDate:
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat;
nfLongDate:
ACell^.NumberFormatStr := 'dd/mmm/yyyy';
nfShortTime:
ACell^.NumberFormatStr := 't';
nfLongTime:
@ -1397,13 +1434,14 @@ begin
begin
fmt := lowercase(AFormatStr);
if fmt = 'dm' then ACell^.NumberFormatStr := 'd/mmm'
else if fmt = 'my' then ACell^.NumberFormatSTr := 'mmm/yy'
else if fmt = 'ms' then ACell^.NumberFormatStr := 'nn:ss'
else if fmt = 'msz' then ACell^.NumberFormatStr := 'nn:ss.z'
else if fmt = 'my' then ACell^.NumberFormatStr := 'mmm/yy'
else if fmt = 'ms' then ACell^.NumberFormatStr := 'mm:ss' // Excel does not like the "n"
else if fmt = 'msz' then ACell^.NumberFormatStr := 'mm:ss.z'
else ACell^.NumberFormatStr := AFormatStr;
end;
nfTimeInterval:
ACell^.NumberFormatStr := '';
if AFormatStr = '' then ACell^.NumberFormatStr := '[h]:mm:ss'
else ACell^.NumberFormatStr := AFormatStr;
end;
ChangedCell(ARow, ACol);
end;
@ -1431,17 +1469,19 @@ end;
@param ARow The row of the cell
@param ACol The column of the cell
@param TsNumberFormat What format to apply
@param string Formatstring
@see TsNumberFormat
}
procedure TsWorksheet.WriteNumberFormat(ARow, ACol: Cardinal;
ANumberFormat: TsNumberFormat);
ANumberFormat: TsNumberFormat; const AFormatString: String);
var
ACell: PCell;
begin
ACell := GetCell(ARow, ACol);
Include(ACell^.UsedFormattingFields, uffNumberFormat);
ACell^.NumberFormat := ANumberFormat;
ACell^.NumberFormatStr := AFormatString;
ChangedCell(ARow, ACol);
end;
@ -2408,12 +2448,310 @@ begin
{$ENDIF}
end;
{ TsCustomNumFormatList }
constructor TsCustomNumFormatList.Create;
begin
inherited Create;
AddBuiltinFormats;
end;
destructor TsCustomNumFormatList.Destroy;
begin
Clear;
inherited Destroy;
end;
{ Adds a new number format data to the list and returns the list index of the
new (or present) item. }
function TsCustomNumFormatList.AddFormat(AFormatIndex: Integer; ANumFormat: TsNumberFormat;
AFormatString: String = ''; ADecimals: Integer = 0): integer;
var
item: TsNumFormatData;
begin
item := TsNumFormatData.Create;
item.Index := AFormatIndex;
item.NumFormat := ANumFormat;
item.FormatString := AFormatString;
item.Decimals := ADecimals;
Result := inherited Add(item);
end;
function TsCustomNumFormatList.AddFormat(AFormatCell: PCell): Integer;
var
item: TsNumFormatData;
begin
if AFormatCell = nil then
raise Exception.Create('TsCustomNumFormat.Add: No nil pointers please');
if Count = 0 then
raise Exception.Create('TsCustomNumFormatList: Error in program logics: You must provide built-in formats first.');
Result := AddFormat(FNextFormatIndex, AFormatCell^.NumberFormat,
AFormatCell^.NumberFormatStr, AFormatCell^.NumberDecimals);
inc(FNextFormatIndex);
end;
{ Adds the builtin format items to the list. Must be called before user items
are added. Must specify FFirstFormatIndexInFile (BIFF5-8, e.g. don't save
formats <164) and must initialize the index of the first user format
(FNextFormatIndex) which is automatically incremented when adding user formats. }
procedure TsCustomNumFormatList.AddBuiltinFormats;
begin
// must be overridden
end;
{ Takes the format string (AFormatString) as it is read from the file and
extracts the number format type (ANumFormat) and the number of decimals
(ADecimals) out of it. If the format string cannot be directly handled by
fpc it has to be transformed to make it compatible. Can be done in
overridden versions which know more about the structure of the string in
the actual file format. }
procedure TsCustomNumFormatList.Analyze(var AFormatString: String;
var ANumFormat: TsNumberFormat; var ADecimals: Word);
const
SHORT_LONG_DATE: array[boolean] of TsNumberFormat = (
nfShortDate, nfLongDate
);
AMPM_SHORT_LONG_TIME: array[boolean, boolean] of TsNumberFormat = (
(nfShortTime, nfLongTime),
(nfShortTimeAM, nfLongTimeAM)
);
EXP_SCI: array[boolean] of TsNumberFormat = (
nfExp, nfSci
);
var
decs: Word;
isAMPM: Boolean;
isLongTime: Boolean;
isLongDate: Boolean;
isInterval: Boolean;
isSci: Boolean;
isTime, isDate: Boolean;
begin
ANumFormat := nfGeneral;
if IsPercentNumberFormat(AFormatString, ADecimals) then
ANumFormat := nfPercentage
else
if IsExpNumberFormat(AFormatstring, ADecimals, isSci) then
ANumFormat := EXP_SCI[isSci]
else
if IsThousandSepNumberFormat(AFormatString, ADecimals) then
ANumFormat := nfFixedTh
else
if IsFixedNumberFormat(AFormatString, ADecimals) then
ANumFormat := nfFixed
else begin
isTime := IsTimeFormat(AFormatString, isLongTime, isAMPM, isInterval, ADecimals);
isDate := IsDateFormat(AFormatString, isLongDate);
if isInterval then
ANumFormat := nfTimeInterval
else
if isDate and isTime then
ANumFormat := nfShortDateTime
else if isDate then
ANumFormat := SHORT_LONG_DATE[isLongDate]
else if isTime then
ANumFormat := AMPM_SHORT_LONG_TIME[isAMPM, isLongTime]
else if AFormatString <> '' then
ANumFormat := nfCustom;
end;
end;
{ Called from the reader when a format item has been read from the file.
Determines the numFormat type, format string etc and stores the format in the
list. If necessary, the format string has to be made compatible with fpc
afterwards - it is used directly for getting the cell text. }
procedure TsCustomNumFormatList.AnalyzeAndAdd(AFormatIndex: Integer;
AFormatString: String);
var
nf: TsNumberFormat;
decs: Word;
begin
if Find(AFormatIndex) > -1 then
raise Exception.Create('TsCustomNumFormatList.AnalyzeAndAdd: Format index must be unique.');
// Analyze the format string and extract information for internal formatting
Analyze(AFormatString, nf, decs);
// Add the new item
AddFormat(AFormatIndex, nf, AFormatString, decs);
end;
{ Clears the list and frees memory occupied by the format items. }
procedure TsCustomNumFormatList.Clear;
var
i: Integer;
begin
for i:=0 to Count-1 do RemoveFormat(i);
inherited Clear;
end;
{ Deletes a format item from the list, and makes sure that its memory is
released. }
procedure TsCustomNumFormatList.Delete(AIndex: Integer);
begin
RemoveFormat(AIndex);
Delete(AIndex);
end;
{ Determines whether the format attributed to the given cell is already
contained in the list and returns its list index. }
function TsCustomNumFormatList.Find(AFormatCell: PCell): integer;
begin
if AFormatCell = nil then
Result := -1
else
Result := Find(AFormatCell^.NumberFormat, AFormatCell^.NumberFormatStr, AFormatCell^.NumberDecimals);
end;
{ Seeks a format item with the given properties and returns its list index,
or -1 if not found. }
function TsCustomNumFormatList.Find(ANumFormat: TsNumberFormat;
AFormatString: String; ADecimals: Integer): Integer;
var
item: TsNumFormatData;
fmt: String;
itemfmt: String;
begin
// These are pre-defined formats - no need to check format string & decimals
if ANumFormat in [ nfGeneral, nfShortDateTime, nfShortDate, nfLongDate,
nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM ]
then
for Result := 0 to Count-1 do begin
item := Items[Result];
if (item <> nil) and (item.NumFormat = ANumFormat) then
exit;
end
else
if (ANumFormat = nfFmtDateTime) then begin
fmt := lowercase(AFormatString);
for Result := 0 to Count-1 do begin
item := Items[Result];
if (item <> nil) and (item.NumFormat = nfFmtDateTime) then begin
itemfmt := lowercase(item.FormatString);
if ((itemfmt = 'dm') or (itemfmt = 'd-mmm') or (itemfmt = 'd mmm') or (itemfmt = 'd. mmm') or (itemfmt ='d/mmm'))
and ((fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm'))
then
exit;
if ((itemfmt = 'my') or (itemfmt = 'mmm-yy') or (itemfmt = 'mmm yyy') or (itemfmt = 'mmm/yy'))
and ((fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy'))
then
exit;
if ((itemfmt = 'ms') or (itemfmt = 'nn:ss') or (itemfmt = 'mm:ss'))
and ((fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss'))
then
exit;
if ((itemfmt = 'msz') or (itemfmt = 'mm:ss.z') or (itemfmt = 'mm:ss.0'))
and ((fmt = 'msz') or (fmt = 'mm:ss.z') or (fmt = 'mm:ss.0'))
then
exit;
end;
end;
for Result := 0 to Count-1 do begin
item := Items[Result];
if fmt = lowercase(item.FormatString) then
exit;
end;
end else
// Check only the format string for nfCustom.
if (ANumFormat = nfCustom) then begin
for Result := 0 to Count-1 do begin
item := Items[Result];
if (item <> nil)
and (item.NumFormat = ANumFormat)
and (item.FormatString = AFormatString)
then
exit;
end;
end else
// The other formats can carry additional information
for Result := 0 to Count-1 do begin
item := Items[Result];
if (item <> nil)
and (item.NumFormat = ANumFormat)
and (item.FormatString = AFormatString)
and (item.Decimals = ADecimals)
then
exit;
end;
Result := -1;
end;
{ Finds the item with the given format index and returns its index in
the format list. }
function TsCustomNumFormatList.Find(AFormatIndex: Integer): integer;
var
item: TsNumFormatData;
begin
for Result := 0 to Count-1 do begin
item := Items[Result];
if item.Index = AFormatIndex then
exit;
end;
Result := -1;
end;
{ Determines the format string to be written into the spreadsheet file.
Needs to be overridden if the format strings are different from the fpc
convention. }
function TsCustomNumFormatList.FormatStringForWriting(AIndex: Integer): String;
var
item: TsNumFormatdata;
begin
item := Items[AIndex];
if item <> nil then Result := item.FormatString else Result := '';
end;
function TsCustomNumFormatList.GetItem(AIndex: Integer): TsNumFormatData;
begin
Result := TsNumFormatData(inherited Items[AIndex]);
end;
{ Deletes the memory occupied by the formatting data, but keeps the item in then
list to maintain the indexes of followint items. }
procedure TsCustomNumFormatList.RemoveFormat(AIndex: Integer);
var
item: TsNumFormatData;
begin
item := GetItem(AIndex);
if item <> nil then begin
item.Free;
SetItem(AIndex, nil);
end;
end;
procedure TsCustomNumFormatList.SetItem(AIndex: Integer; AValue: TsNumFormatData);
begin
inherited Items[AIndex] := AValue;
end;
function CompareNumFormatData(Item1, Item2: Pointer): Integer;
begin
Result := CompareValue(TsNumFormatData(Item1).Index, TsNumFormatData(Item2).Index);
end;
{ Sorts the format data items in ascending order of the format indexes. }
procedure TsCustomNumFormatList.Sort;
begin
inherited Sort(@CompareNumFormatData);
end;
{ TsCustomSpreadReader }
constructor TsCustomSpreadReader.Create(AWorkbook: TsWorkbook);
begin
inherited Create;
FWorkbook := AWorkbook;
CreateNumFormatList;
end;
destructor TsCustomSpreadReader.Destroy;
begin
FNumFormatList.Free;
inherited Destroy;
end;
{@@
@ -2471,6 +2809,13 @@ constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
begin
inherited Create;
FWorkbook := AWorkbook;
CreateNumFormatList;
end;
destructor TsCustomSpreadWriter.Destroy;
begin
FNumFormatList.Free;
inherited Destroy;
end;
{@@
@ -2522,10 +2867,10 @@ begin
if uffNumberFormat in AFormat^.UsedFormattingFields then begin
if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue;
case AFormat^.NumberFormat of
nfFixed, nfFixedTh, nfPercentage, nfExp:
nfFixed, nfFixedTh, nfPercentage, nfExp, nfSci:
if (FFormattingStyles[i].NumberDecimals <> AFormat^.NumberDecimals) then Continue;
nfShortDate, nfShortDateTime, nfShortTime, nfLongTime, nfShortTimeAM,
nfLongTimeAM, nfFmtDateTime, nfTimeInterval:
nfShortDate, nfLongDate, nfShortDateTime, nfShortTime, nfLongTime,
nfShortTimeAM, nfLongTimeAM, nfFmtDateTime, nfTimeInterval, nfCustom:
if (FFormattingstyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue;
end;
end;
@ -2538,6 +2883,20 @@ begin
end;
end;
{ If formatting features of a cell are not supported by the destination file
format of the writer, here is the place to apply replacements.
Must be overridden by descendants. See BIFF2 }
procedure TsCustomSpreadWriter.FixFormat(ACell: PCell);
var
isLong, isAMPM, isInterval: Boolean;
decs: Word;
begin
if ACell^.NumberFormat = nfFmtDateTime then begin
if IsTimeFormat(ACell^.NumberFormatStr, isLong, isAMPM, isInterval, decs) then
ACell^.NumberDecimals := decs;
end;
end;
{ Each descendent should define it's own default formats, if any.
Always add the normal, unformatted style first to speed up. }
procedure TsCustomSpreadWriter.AddDefaultFormats();
@ -2550,8 +2909,9 @@ procedure TsCustomSpreadWriter.ListAllFormattingStylesCallback(ACell: PCell; ASt
var
Len: Integer;
begin
if ACell^.UsedFormattingFields = [] then Exit;
FixFormat(ACell);
if ACell^.UsedFormattingFields = [] then Exit;
if FindFormattingInList(ACell) <> -1 then Exit;
Len := Length(FFormattingStyles);
@ -2575,6 +2935,30 @@ begin
end;
end;
{@@
Adds the number format of the given cell to the NumFormatList, but only if
it does not yet exist in the list.
}
procedure TsCustomSpreadWriter.ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
begin
FixFormat(ACell);
if FNumFormatList.Find(ACell) = -1 then
FNumFormatList.AddFormat(ACell);
end;
{@@
Iterats through all cells and collects the number formats in
FNumFormatList (without duplicates).
The index of the list item is needed for the field FormatIndex of the XF record. }
procedure TsCustomSpreadWriter.ListAllNumFormats;
var
i: Integer;
begin
for i:=0 to Workbook.GetWorksheetCount-1 do
IterateThroughCells(nil, Workbook.GetWorksheetByIndex(i).Cells, ListAllNumFormatsCallback);
NumFormatList.Sort;
end;
{@@
Expands a formula, separating it in it's constituent parts,
so that it is already partially parsed and it is easier to

View File

@ -1,6 +1,10 @@
{
Utility functions and constants from FPSpreadsheet
}
// to do: Remove the patched FormatDateTime when the feature of square brackets
// in time format codes is in the rtl
unit fpsutils;
{$mode objfpc}{$H+}
@ -59,8 +63,25 @@ function UTF8TextToXMLText(AText: ansistring): ansistring;
function TwipsToMillimeters(AValue: Integer): Single;
function MillimetersToTwips(AValue: Single): Integer;
function IsExpNumberFormat(s: String; out Decimals: Word; out IsSci: Boolean): Boolean;
function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
function IsTimeFormat(s: String; out isLong, isAMPM, isInterval: Boolean;
out SecDecimals: Word): Boolean;
function SciFloat(AValue: Double; ADecimals: Word): String;
//function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
function FormatDateTime(const FormatStr: string; DateTime: TDateTime): string;
implementation
uses
Math;
{
Endianess helper functions
@ -467,5 +488,663 @@ begin
Result := Round((AValue * 20 * 72) / 25.4);
end;
{ Format checking procedures }
{ This simple parsing procedure of the Excel format string checks for a fixed
float format s, i.e. s can be '0', '0.00', '000', '0,000', and returns the
number of decimals, i.e. number of zeros behind the decimal point }
function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
var
i: Integer;
p: Integer;
decs: String;
begin
Decimals := 0;
// Excel time formats with milliseconds ("mm:ss.000") can be incorrectly
// detected as fixed number formats. Check this case at first.
if pos('s.0', s) > 0 then begin
Result := false;
exit;
end;
// Check if s is a valid format mask.
try
FormatFloat(s, 1.0);
except
on EConvertError do begin
Result := false;
exit;
end;
end;
// If it is count the zeros - each one is a decimal.
if s = '0' then
Result := true
else begin
p := pos('.', s); // position of decimal point;
if p = 0 then begin
Result := false;
end else begin
Result := true;
for i:= p+1 to Length(s) do
if s[i] = '0' then begin
inc(Decimals)
end
else
exit; // ignore characters after the last 0
end;
end;
end;
{ This function checks whether the format string corresponds to a thousand
separator format like "#,##0.000' and returns the number of fixed decimals
(i.e. zeros after the decimal point) }
function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
var
i, p: Integer;
begin
Decimals := 0;
// Check if s is a valid format string
try
FormatFloat(s, 1.0);
except
on EConvertError do begin
Result := false;
exit;
end;
end;
// If it is look for the thousand separator. If found count decimals.
Result := (Pos(',', s) > 0);
if Result then begin
p := pos('.', s);
if p > 0 then
for i := p+1 to Length(s) do
if s[i] = '0' then
inc(Decimals)
else
exit; // ignore format characters after the last 0
end;
end;
{ This function checks whether the format string corresponds to percent
formatting and determines the number of decimals }
function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
var
i, p: Integer;
begin
Decimals := 0;
// The signature of the percent format is a percent sign at the end of the
// format string.
Result := (s <> '') and (s[Length(s)] = '%');
if Result then begin
// Check for a valid format string
try
FormatDateTime(s, 1.0);
except
on EConvertError do begin
Result := false;
exit;
end;
end;
// Count decimals
p := pos('.', s);
if p > 0 then
for i := p+1 to Length(s)-1 do
if s[i] = '0' then
inc(Decimals)
else
exit; // ignore characters after last 0
end;
end;
{ This function checks whether the format string corresponds to exponential
formatting and determines the number of decimals. If it contains a # character
the function assumes a "scientific" format rounding the exponent to multiples
of 2. }
function IsExpNumberFormat(s: String; out Decimals: Word;
out IsSci: Boolean): Boolean;
var
i, pdp, pe, ph: Integer;
begin
Result := false;
Decimals := 0;
IsSci := false;
if SameText(s, 'General') then
exit;
// Check for a valid format string
try
FormatDateTime(s, 1.0);
except
on EConvertError do begin
exit;
end;
end;
pe := pos('e', lowercase(s));
result := pe > 0;
if Result then begin
// The next character must be a "+", "-", or "0"
if (pe = Length(s)) or not (s[pe+1] in ['+', '-', '0']) then begin
Result := false;
exit;
end;
// Count decimals
pdp := pos('.', s);
if (pdp > 0) then begin
if pdp < pe then
for i:=pdp+1 to pe-1 do
if s[i] = '0' then
inc(Decimals)
else
break; // ignore characters after last 0
end;
// Look for hash signs # as indicator of the "scientific" format
ph := pos('#', s);
if ph > 0 then IsSci := true;
end;
end;
{ IsDateFormat checks if the format string s corresponds to a date format }
function IsDateFormat(s: String; out IsLong: Boolean): Boolean;
begin
// Day, month, year are separated by a slash
Result := (pos('/', s) > 0);
if Result then
// Check validity of format string
try
FormatDateTime(s, now);
s := Lowercase(s);
isLong := (pos('mmm', s) <> 0) or (pos('mmmm', s) <> 0);
except on EConvertError do
Result := false;
end;
end;
{ IsTimeFormat checks if the format string s is a time format. isLong is
true if the string contains hours, minutes and seconds (two colons).
isAMPM is true if the string contains "AM/PM", "A/P" or "AMPM".
isInterval is true if the string contains square bracket codes for time intervals.
SecDecimals is the number of decimals for the seconds. }
function IsTimeFormat(s: String; out isLong, isAMPM, isInterval: Boolean;
out SecDecimals: Word): Boolean;
var
p, pdp, i, count: Integer;
begin
isLong := false;
isAMPM := false;
SecDecimals := 0;
// Time parts are separated by a colon
p := pos(':', s);
result := p > 0;
if Result then begin
count := 1;
s := Uppercase(s);
// If there are is a second colon s is a "long" time format
for i:=p+1 to Length(s) do
if s[i] = ':' then begin
isLong := true;
break;
end;
// Seek for "AM/PM" etc to detect that specific format
isAMPM := (pos('AM/PM', s) > 0) or (pos('A/P', s) > 0) or (pos('AMPM', s) > 0);
// Look for square brackets indicating the interval format.
p := pos('[', s);
if p > 0 then isInterval := (pos(']', s) > 0) else isInterval := false;
// Count decimals
pdp := pos('.', s);
if (pdp > 0) then
for i:=pdp+1 to Length(s) do
if (s[i] in ['0', 'z', 'Z']) then
inc(SecDecimals)
else
break; // ignore characters after last 0
// Check validity of format string
try
FormatDateTime(s, now);
except on EConvertError do
Result := false;
end;
end;
end;
{ Formats the number AValue in "scientific" format with the given number of
decimals. "Scientific" is the same as "exponential", but with exponents rounded
to multiples of 3 (like for "kilo" - "Mega" - "Giga" etc.). }
function SciFloat(AValue: Double; ADecimals: Word): String;
var
m: Double;
ex: Integer;
begin
if AValue = 0 then
Result := '0.0'
else begin
ex := floor(log10(abs(AValue))); // exponent
// round exponent to multiples of 3
ex := (ex div 3) * 3;
if ex < 0 then dec(ex, 3);
m := AValue * Power(10, -ex); // mantisse
Result := Format('%.*fE%d', [ADecimals, m, ex]);
end;
end;
(*
{ Formats the number AValue as a time string according to the format string.
If the hour part is between square brackets it can be greater than 24 hours.
Dto for the minutes or seconds part, with the higher-value part being added
and no longer being shown explicitly.
Example:
AValue = 1:30:02, FormatStr = "[mm]:ss]" --> "90:02" }
function TimeIntervalToString(AValue: TDateTime; AFormatStr: String): String;
var
hrs, mins, secs: Integer;
diff: Double;
h,m,s,z: Word;
ts: String;
fmt: String;
p: Integer;
begin {
fmt := Lowercase(AFormatStr);
p := pos('h]', fmt);
if p > 0 then begin
System.Delete(fmt, 1, p+2);
Result := FormatDateTime(fmt, AValue);
DecodeTime(frac(abs(AValue)), h, m, s, z);
hrs := h + trunc(abs(AValue))*24;
Result := FormatDateTime(fmt, AValue);
end;
for i
p := pos('h
}
ts := DefaultFormatSettings.TimeSeparator;
DecodeTime(frac(abs(AValue)), h, m, s, z);
hrs := h + trunc(abs(AValue))*24;
if z > 499 then inc(s);
if hrs > 0 then
Result := Format('%d%s%.2d%s%.2d', [hrs, ts, m, ts, s])
else
Result := Format('%d%s%.2d', [m, ts, s]);
if AValue < 0.0 then Result := '-' + Result;
end;
*)
{ Creates a "time interval" format string having the first code identifier
in square brackets. }
procedure MakeTimeIntervalMask(Src: String; var Dest: String);
var
L: TStrings;
begin
L := TStringList.Create;
try
L.StrictDelimiter := true;
L.Delimiter := ':';
L.DelimitedText := Src;
if L[0][1] <> '[' then L[0] := '[' + L[0];
if L[0][Length(L[0])] <> ']' then L[0] := L[0] + ']';
Dest := L.DelimitedText;
finally
L.Free;
end;
end;
{******************************************************************************}
{******************************************************************************}
{ Patch for SysUtils.FormatDateTime }
{ Remove when the feature of square brackets in time format masks is in rtl }
{******************************************************************************}
{******************************************************************************}
// Copied from "fpc/rtl/objpas/sysutils/datei.inc"
procedure DateTimeToString(out Result: string; const FormatStr: string; const DateTime: TDateTime; const FormatSettings: TFormatSettings);
var
ResultLen: integer;
ResultBuffer: array[0..255] of char;
ResultCurrent: pchar;
{$IFDEF MSWindows}
isEnable_E_Format : Boolean;
isEnable_G_Format : Boolean;
eastasiainited : boolean;
{$ENDIF MSWindows}
(* This part is in the original code. It is not needed here and avoids a
dependency on the unit Windows.
{$IFDEF MSWindows}
procedure InitEastAsia;
var ALCID : LCID;
PriLangID , SubLangID : Word;
begin
ALCID := GetThreadLocale;
PriLangID := ALCID and $3FF;
if (PriLangID>0) then
SubLangID := (ALCID and $FFFF) shr 10
else
begin
PriLangID := SysLocale.PriLangID;
SubLangID := SysLocale.SubLangID;
end;
isEnable_E_Format := (PriLangID = LANG_JAPANESE)
or
(PriLangID = LANG_KOREAN)
or
((PriLangID = LANG_CHINESE)
and
(SubLangID = SUBLANG_CHINESE_TRADITIONAL)
);
isEnable_G_Format := (PriLangID = LANG_JAPANESE)
or
((PriLangID = LANG_CHINESE)
and
(SubLangID = SUBLANG_CHINESE_TRADITIONAL)
);
eastasiainited :=true;
end;
{$ENDIF MSWindows}
*)
procedure StoreStr(Str: PChar; Len: Integer);
begin
if ResultLen + Len < SizeOf(ResultBuffer) then
begin
StrMove(ResultCurrent, Str, Len);
ResultCurrent := ResultCurrent + Len;
ResultLen := ResultLen + Len;
end;
end;
procedure StoreString(const Str: string);
var Len: integer;
begin
Len := Length(Str);
if ResultLen + Len < SizeOf(ResultBuffer) then
begin
StrMove(ResultCurrent, pchar(Str), Len);
ResultCurrent := ResultCurrent + Len;
ResultLen := ResultLen + Len;
end;
end;
procedure StoreInt(Value, Digits: Integer);
var
S: string[16];
Len: integer;
begin
System.Str(Value:Digits, S);
for Len := 1 to Length(S) do
begin
if S[Len] = ' ' then
S[Len] := '0'
else
Break;
end;
StoreStr(pchar(@S[1]), Length(S));
end ;
var
Year, Month, Day, DayOfWeek, Hour, Minute, Second, MilliSecond: word;
procedure StoreFormat(const FormatStr: string; Nesting: Integer; TimeFlag: Boolean);
var
Token, lastformattoken, prevlasttoken: char;
FormatCurrent: pchar;
FormatEnd: pchar;
Count: integer;
Clock12: boolean;
P: pchar;
tmp: integer;
isInterval: Boolean;
begin
if Nesting > 1 then // 0 is original string, 1 is included FormatString
Exit;
FormatCurrent := PChar(FormatStr);
FormatEnd := FormatCurrent + Length(FormatStr);
Clock12 := false;
isInterval := false;
P := FormatCurrent;
// look for unquoted 12-hour clock token
while P < FormatEnd do
begin
Token := P^;
case Token of
'''', '"':
begin
Inc(P);
while (P < FormatEnd) and (P^ <> Token) do
Inc(P);
end;
'A', 'a':
begin
if (StrLIComp(P, 'A/P', 3) = 0) or
(StrLIComp(P, 'AMPM', 4) = 0) or
(StrLIComp(P, 'AM/PM', 5) = 0) then
begin
Clock12 := true;
break;
end;
end;
end; // case
Inc(P);
end ;
token := #255;
lastformattoken := ' ';
prevlasttoken := 'H';
while FormatCurrent < FormatEnd do
begin
Token := UpCase(FormatCurrent^);
Count := 1;
P := FormatCurrent + 1;
case Token of
'''', '"':
begin
while (P < FormatEnd) and (p^ <> Token) do
Inc(P);
Inc(P);
Count := P - FormatCurrent;
StoreStr(FormatCurrent + 1, Count - 2);
end ;
'A':
begin
if StrLIComp(FormatCurrent, 'AMPM', 4) = 0 then
begin
Count := 4;
if Hour < 12 then
StoreString(FormatSettings.TimeAMString)
else
StoreString(FormatSettings.TimePMString);
end
else if StrLIComp(FormatCurrent, 'AM/PM', 5) = 0 then
begin
Count := 5;
if Hour < 12 then StoreStr(FormatCurrent, 2)
else StoreStr(FormatCurrent+3, 2);
end
else if StrLIComp(FormatCurrent, 'A/P', 3) = 0 then
begin
Count := 3;
if Hour < 12 then StoreStr(FormatCurrent, 1)
else StoreStr(FormatCurrent+2, 1);
end
else
raise EConvertError.Create('Illegal character in format string');
end ;
'/': StoreStr(@FormatSettings.DateSeparator, 1);
':': StoreStr(@FormatSettings.TimeSeparator, 1);
'[': isInterval := true;
']': isInterval := false;
' ', 'C', 'D', 'H', 'M', 'N', 'S', 'T', 'Y','Z' :
begin
while (P < FormatEnd) and (UpCase(P^) = Token) do
Inc(P);
Count := P - FormatCurrent;
case Token of
' ': StoreStr(FormatCurrent, Count);
'Y': begin
if Count > 2 then
StoreInt(Year, 4)
else
StoreInt(Year mod 100, 2);
end;
'M': begin
if isInterval and ((prevlasttoken = 'H') or TimeFlag) then
StoreInt(Minute + Hour*60 + trunc(DateTime)*24*60, 0)
else
if (lastformattoken = 'H') or TimeFlag then
begin
if Count = 1 then
StoreInt(Minute, 0)
else
StoreInt(Minute, 2);
end
else
begin
case Count of
1: StoreInt(Month, 0);
2: StoreInt(Month, 2);
3: StoreString(FormatSettings.ShortMonthNames[Month]);
else
StoreString(FormatSettings.LongMonthNames[Month]);
end;
end;
end;
'D': begin
case Count of
1: StoreInt(Day, 0);
2: StoreInt(Day, 2);
3: StoreString(FormatSettings.ShortDayNames[DayOfWeek]);
4: StoreString(FormatSettings.LongDayNames[DayOfWeek]);
5: StoreFormat(FormatSettings.ShortDateFormat, Nesting+1, False);
else
StoreFormat(FormatSettings.LongDateFormat, Nesting+1, False);
end ;
end ;
'H':
if isInterval then
StoreInt(Hour + trunc(DateTime)*24, 0)
else
if Clock12 then
begin
tmp := hour mod 12;
if tmp=0 then tmp:=12;
if Count = 1 then
StoreInt(tmp, 0)
else
StoreInt(tmp, 2);
end
else begin
if Count = 1 then
StoreInt(Hour, 0)
else
StoreInt(Hour, 2);
end;
'N': if isInterval then
StoreInt(Minute + 60*Hour + 60*24*trunc(DateTime), 0)
else
if Count = 1 then
StoreInt(Minute, 0)
else
StoreInt(Minute, 2);
'S': if isInterval then
StoreInt(Second + Minute*60 + Hour*60*60 + trunc(DateTime)*24*60*60, 0)
else
if Count = 1 then
StoreInt(Second, 0)
else
StoreInt(Second, 2);
'Z': if Count = 1 then
StoreInt(MilliSecond, 0)
else
StoreInt(MilliSecond, 3);
'T': if Count = 1 then
StoreFormat(FormatSettings.ShortTimeFormat, Nesting+1, True)
else
StoreFormat(FormatSettings.LongTimeFormat, Nesting+1, True);
'C': begin
StoreFormat(FormatSettings.ShortDateFormat, Nesting+1, False);
if (Hour<>0) or (Minute<>0) or (Second<>0) then
begin
StoreString(' ');
StoreFormat(FormatSettings.LongTimeFormat, Nesting+1, True);
end;
end;
(* This part is in the original code. It is not needed here and avoids a
dependency on the unit Windows.
{$IFDEF MSWindows}
'E':
begin
if not Eastasiainited then InitEastAsia;
if Not(isEnable_E_Format) then StoreStr(@FormatCurrent^, 1)
else
begin
while (P < FormatEnd) and (UpCase(P^) = Token) do
P := P + 1;
Count := P - FormatCurrent;
StoreString(ConvertEraYearString(Count,Year,Month,Day));
end;
lastformattoken:=token;
end;
'G':
begin
if not Eastasiainited then InitEastAsia;
if Not(isEnable_G_Format) then StoreStr(@FormatCurrent^, 1)
else
begin
while (P < FormatEnd) and (UpCase(P^) = Token) do
P := P + 1;
Count := P - FormatCurrent;
StoreString(ConvertEraString(Count,Year,Month,Day));
end;
lastformattoken:=token;
end;
{$ENDIF MSWindows}
*)
end;
prevlasttoken := lastformattoken;
lastformattoken := token;
end;
else
StoreStr(@Token, 1);
end ;
Inc(FormatCurrent, Count);
end;
end;
begin
{$ifdef MSWindows}
eastasiainited:=false;
{$endif MSWindows}
DecodeDateFully(DateTime, Year, Month, Day, DayOfWeek);
DecodeTime(DateTime, Hour, Minute, Second, MilliSecond);
ResultLen := 0;
ResultCurrent := @ResultBuffer[0];
if FormatStr <> '' then
StoreFormat(FormatStr, 0, False)
else
StoreFormat('C', 0, False);
ResultBuffer[ResultLen] := #0;
result := StrPas(@ResultBuffer[0]);
end ;
function FormatDateTime(const FormatStr: string; DateTime: TDateTime): string;
begin
DateTimeToString(Result, FormatStr, DateTime, DefaultFormatSettings);
end;
end.

View File

@ -38,6 +38,15 @@ uses
type
{ TsBIFF2NumFormatList }
TsBIFF2NumFormatList = class(TsCustomNumFormatList)
protected
procedure AddBuiltinFormats; override;
public
constructor Create;
function FormatStringForWriting(AIndex: Integer): String; override;
end;
{ TsSpreadBIFF2Reader }
TsSpreadBIFF2Reader = class(TsSpreadBIFFReader)
@ -47,6 +56,7 @@ type
FFont: TsFont;
protected
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); override;
procedure CreateNumFormatList; override;
procedure ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String); override;
@ -80,9 +90,7 @@ type
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFontIndex: Integer);
procedure WriteFonts(AStream: TStream);
procedure WriteFormat(AStream: TStream; AFormatCode: String);
procedure WriteFormatCount(AStream: TStream);
procedure WriteFormats(AStream: TStream);
procedure WriteIXFE(AStream: TStream; XFIndex: Word);
procedure WriteXF(AStream: TStream; AFontIndex, AFormatIndex: byte;
ABorders: TsCellBorders = []; AHorAlign: TsHorAlignment = haLeft;
@ -90,12 +98,17 @@ type
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
procedure WriteXFRecords(AStream: TStream);
protected
procedure CreateNumFormatList; override;
procedure FixFormat(ACell: PCell); override;
procedure ListAllNumFormats; override;
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override;
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); override;
procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
AListIndex: Integer); 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 WriteRow(AStream: TStream; ASheet: TsWorksheet;
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); override;
procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); override;
procedure WriteWindow1(AStream: TStream); override;
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
public
@ -116,7 +129,8 @@ var
$00FFFF // $07: cyan
);
{ These are the built-in number formats of BIFF 2. They are not stored in
(*
{ These are the built-in number formats of BIFF2. They are not stored in
the file. Note that, compared to the BUFF5+ built-in formats, two formats
are missing and the indexes are offset by 2 after #11.
It seems that BIFF2 can handle only these 21 formats. The other formats
@ -145,6 +159,7 @@ var
'h:mm:ss',
'M/D/YY h:mm' // 20
);
*)
implementation
@ -177,7 +192,7 @@ const
INT_EXCEL_SHEET = $0010;
INT_EXCEL_CHART = $0020;
INT_EXCEL_MACRO_SHEET = $0040;
(*
{ FORMAT record constants for BIFF2 }
// Subset of the built-in formats for US Excel,
// including those needed for date/time output
@ -206,6 +221,76 @@ const
FORMAT_TIME_MS = 19; //time MM:SS
FORMAT_TIME_MSZ = 19; //time MM:SS.0
FORMAT_TIME_INTERVAL = 19; //time [hh]:mm:ss, hh can be >24
*)
{ TsBIFF2NumFormatList }
constructor TsBIFF2NumFormatList.Create;
begin
inherited Create;
end;
procedure TsBIFF2NumFormatList.AddBuiltinFormats;
begin
AddFormat( 0, nfGeneral);
AddFormat( 1, nfFixed, '0', 0);
AddFormat( 2, nfFixed, '0.00', 2);
AddFormat( 3, nfFixedTh, '#,##0', 0);
AddFormat( 4, nfFixedTh, '#,##0.00', 2);
AddFormat( 5, nfFixedTh, '"$"#,##0_);("$"#,##0)', 0);
AddFormat( 6, nfFixedTh, '"$"#,##0_);[Red]("$"#,##0)', 2);
AddFormat( 7, nfFixedTh, '"$"#,##0.00_);("$"#,##0.00)', 0);
AddFormat( 8, nfFixedTh, '"$"#,##0.00_);[Red]("$"#,##0.00)', 2);
AddFormat( 9, nfPercentage, '0%', 0);
AddFormat(10, nfPercentage, '0.00%', 2);
AddFormat(11, nfExp, '0.00E+00', 2);
AddFormat(12, nfShortDate);
AddFormat(13, nfLongDate);
AddFormat(14, nfFmtDateTime, 'd-mmm');
AddFormat(15, nfFmtDateTime, 'mmm-yy');
AddFormat(16, nfShortTimeAM);
AddFormat(17, nfLongTimeAM);
AddFormat(18, nfShortTime);
AddFormat(19, nfLongTime);
AddFormat(20, nfShortDateTime);
FFirstFormatIndexInFile := 0; // BIFF2 stores built-in formats to file.
FNextFormatIndex := 21; // not needed - there are not user-defined formats
end;
{ Creates formatting strings that are written into the file. }
function TsBIFF2NumFormatList.FormatStringForWriting(AIndex: Integer): String;
var
ds, ts, cs: string;
begin
ds := DefaultFormatSettings.DecimalSeparator;
ts := DefaultFormatSettings.ThousandSeparator;
cs := DefaultFormatSettings.CurrencyString;
case AIndex of
0: Result := 'General';
1: Result := '0';
2: Result := '0' + ds + '00'; // 0.00
3: Result := '#' + ts + '#0'; // #,##0
4: Result := '#' + ts + '#0' + ds + '0'; // #,##0.00
5: Result := UTF8ToAnsi(Format('"%s"#%s##0_);("%s"#%s##0)', [cs, ts, cs, ts]));
6: Result := UTF8ToAnsi(Format('"%s"#%s##0_);[Red]("%s"#%s##0)', [cs, ts, cs, ts]));
7: Result := UTF8ToAnsi(Format('"%s"#%s##0%s00_);("%s"#%s##0%s00)', [cs, ts, ds, cs, ts, ds]));
8: Result := UTF8ToAnsi(Format('"%s"#%s##0%s00_);[Red]("%s"#%s##0%s00)', [cs, ts, ds, cs, ts, ds]));
9: Result := '0%';
10: Result := '0' + ds + '00%'; // 0.00%
11: Result := '0' + ds + '00E+00'; // 0.00E+00
12: Result := 'm/d/yy';
13: Result := 'd-mmm-yy';
14: Result := 'd-mmm';
15: Result := 'mmm-yy';
16: Result := 'h:mm AM/PM';
17: Result := 'h:mm:ss AM/PM';
18: Result := 'h:mm';
19: Result := 'h:mm:ss';
20: Result := 'm/d/yy h:mm';
end;
end;
{ TsSpreadBIFF2Reader }
@ -252,6 +337,14 @@ begin
end;
end;
{ Creates the correct version of the number format list.
It is for BIFF2 and BIFF3 file formats. }
procedure TsSpreadBIFF2Reader.CreateNumFormatList;
begin
FreeAndNil(FNumFormatList);
FNumFormatList := TsBIFF2NumFormatList.Create;
end;
{ Extracts the number format data from an XF record indexed by AXFIndex.
Note that BIFF2 supports only 21 formats. }
procedure TsSpreadBIFF2Reader.ExtractNumberFormat(AXFIndex: WORD;
@ -270,7 +363,7 @@ const
2, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 11..20
);
var
lFormatData: TFormatListData;
lNumFormatData: TsNumFormatData;
lXFData: TXFListData;
isAMPM: Boolean;
isLongTime: Boolean;
@ -280,9 +373,9 @@ begin
ANumberFormat := nfGeneral;
ANumberFormatStr := '';
ADecimals := 0;
lFormatData := FindFormatDataForCell(AXFIndex);
if lFormatData = nil then begin
(*
lNumFormatData := FindNumFormatDataForCell(AXFIndex);
if lNumFormatData = nil then begin
// no custom format, so first test for default formats
lXFData := TXFListData (FXFList.Items[AXFIndex]);
if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 20) then begin
@ -291,20 +384,20 @@ begin
end;
end else
// The next is copied from xlscommon - I think it's not necessary here
if IsPercentNumberFormat(lFormatData.FormatString, ADecimals) then
if IsPercentNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfPercentage
else
if IsExpNumberFormat(lFormatData.Formatstring, ADecimals) then
if IsExpNumberFormat(lNumFormatData.Formatstring, ADecimals) then
ANumberFormat := nfExp
else
if IsThousandSepNumberFormat(lFormatData.FormatString, ADecimals) then
if IsThousandSepNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixedTh
else
if IsFixedNumberFormat(lFormatData.FormatString, ADecimals) then
if IsFixedNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixed
else begin
t := IsTimeFormat(lFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
d := IsDateFormat(lFormatData.FormatString);
t := IsTimeFormat(lNumFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
d := IsDateFormat(lNumFormatData.FormatString, isLongDate);
if d and t then
ANumberFormat := nfShortDateTime
else
@ -324,7 +417,7 @@ begin
ANumberFormat := nfShortTime;
end;
end;
end;
end; *)
end;
procedure TsSpreadBIFF2Reader.ReadBlank(AStream: TStream);
@ -696,6 +789,14 @@ end;
{ TsSpreadBIFF2Writer }
{ Creates the correct version of the number format list.
It is for BIFF2 and BIFF3 file formats. }
procedure TsSpreadBIFF2Writer.CreateNumFormatList;
begin
FreeAndNil(FNumFormatList);
FNumFormatList := TsBIFF2NumFormatList.Create;
end;
function TsSpreadBIFF2Writer.FindXFIndex(ACell: PCell): Word;
var
i: Integer;
@ -712,6 +813,37 @@ begin
end;
end;
procedure TsSpreadBIFF2Writer.FixFormat(ACell: PCell);
var
j: Integer;
begin
case ACell.NumberFormat of
nfExp:
if ACell.NumberDecimals <> 2 then begin
ACell.NumberDecimals := 2;
ACell.NumberFormatStr := '0.00E+00';
end;
nfSci:
begin
ACell.NumberFormat := nfExp;
ACell.NumberFormatStr := '0.00E+00';
ACell.NumberDecimals := 2;
end;
nfFmtDateTime:
begin
j := NumFormatList.Find(ACell);
if j = -1 then ACell.NumberFormat := nfLongTime;
end;
nfCustom:
ACell.NumberFormat := nfGeneral;
end;
end;
procedure TsSpreadBIFF2Writer.ListAllNumFormats;
begin
// Nothing to do. All formats have already been added by the NumFormatList.
end;
{
Attaches cell formatting data for the given cell to the current record.
Is called from all writing methods of cell contents.
@ -825,6 +957,7 @@ begin
WriteBOF(AStream);
WriteFonts(AStream);
WriteFormatCount(AStream);
WriteFormats(AStream);
WriteXFRecords(AStream);
WriteColWidths(AStream);
@ -940,7 +1073,7 @@ end;
procedure TsSpreadBIFF2Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var
i: Integer;
i, j: Integer;
lFontIndex: Word;
lFormatIndex: Word; //number format
lBorders: TsCellBorders;
@ -958,66 +1091,19 @@ begin
lHorAlign := FFormattingStyles[i].HorAlignment;
// Now apply the modifications.
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then
case FFormattingStyles[i].NumberFormat of
nfFixed:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_FIXED_0_DECIMALS;
2: lFormatIndex := FORMAT_FIXED_2_DECIMALS;
end;
nfFixedTh:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_FIXED_THOUSANDS_0_DECIMALS;
2: lFormatIndex := FORMAT_FIXED_THOUSANDS_2_DECIMALS;
end;
nfExp:
lFormatIndex := FORMAT_EXP_2_DECIMALS;
nfSci:
lFormatIndex := FORMAT_SCI_1_DECIMAL;
nfPercentage:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_PERCENT_0_DECIMALS;
2: lFormatIndex := FORMAT_PERCENT_2_DECIMALS;
end;
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
j := NumFormatList.Find(@FFormattingStyles[i]);
if j > -1 then begin
lFormatIndex := NumFormatList[j].Index;
{
nfCurrency:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS;
2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS;
end;
}
nfShortDate:
lFormatIndex := FORMAT_SHORT_DATE;
nfShortTime:
lFormatIndex := FORMAT_SHORT_TIME;
nfLongTime:
lFormatIndex := FORMAT_LONG_TIME;
nfShortTimeAM:
lFormatIndex := FORMAT_SHORT_TIME_AM;
nfLongTimeAM:
lFormatIndex := FORMAT_LONG_TIME_AM;
nfShortDateTime:
lFormatIndex := FORMAT_SHORT_DATETIME;
nfFmtDateTime:
begin
fmt := lowercase(FFormattingStyles[i].NumberFormatStr);
if (fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm') then
lFormatIndex := FORMAT_DATE_DM
else
if (fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy') then
lFormatIndex := FORMAT_DATE_MY
else
{ Because of limitations of BIFF2 the next two formats are mapped
to the same format index! }
if (fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss') then
lFormatIndex := FORMAT_TIME_MS
else
if (fmt = 'msz') or (fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or (fmt = 'mm:ss.0') or (fmt = 'mm:ss.z') or (fmt = 'nn:ss.z') then
lFormatIndex := FORMAT_TIME_MSZ;
end;
nfTimeInterval:
lFormatIndex := FORMAT_TIME_INTERVAL;
// BIFF2 can only handle the 21 built-in formats. Here we find replacements
// for the others.
case NumFormatList[j].NumFormat of
nfSci : lFormatIndex := 11; // Exp
nfFmtDateTime : if lFormatIndex > 20 then lFormatIndex := 19;
end;}
end;
end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border;
@ -1149,6 +1235,24 @@ begin
WriteFont(AStream, i);
end;
procedure TsSpreadBiff2Writer.WriteFormat(AStream: TStream;
AFormatData: TsNumFormatData; AListIndex: Integer);
var
len: Integer;
s: ansistring;
begin
s := NumFormatList.FormatStringForWriting(AListIndex);
len := Length(s);
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT));
AStream.WriteWord(WordToLE(1 + len));
{ Format string }
AStream.WriteByte(len); // AnsiString, char count in 1 byte
AStream.WriteBuffer(s[1], len); // String data
end;
(*
procedure TsSpreadBIFF2Writer.WriteFormat(AStream: TStream; AFormatCode: String);
var
len: Integer;
@ -1167,15 +1271,15 @@ begin
{ Write format string }
AStream.WriteByte(len);
AStream.WriteBuffer(s[1], len);
end;
end; *)
procedure TsSpreadBIFF2Writer.WriteFormatCount(AStream: TStream);
begin
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMATCOUNT));
AStream.WriteWord(WordToLE(2));
AStream.WriteWord(WordToLE(High(NUMFORMAT_BIFF2)+1));
AStream.WriteWord(WordToLE(21)); // there are 21 built-in formats
end;
(*
procedure TsSpreadBIFF2Writer.WriteFormats(AStream: TStream);
var
i: Integer;
@ -1183,7 +1287,7 @@ begin
WriteFormatCount(AStream);
for i:=0 to High(NUMFORMAT_BIFF2) do
WriteFormat(AStream, NUMFORMAT_BIFF2[i]);
end;
end;*)
(*
var
ds, ts: Char; //decimal separator, thousand separator

View File

@ -84,8 +84,6 @@ type
procedure ReadBlank(AStream: TStream); override;
procedure ReadFont(const AStream: TStream);
procedure ReadFormat(AStream: TStream); override;
procedure ReadFormula(AStream: TStream); override;
procedure ReadFormulaExcel(AStream: TStream);
procedure ReadLabel(AStream: TStream); override;
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
@ -115,6 +113,8 @@ type
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream);
procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
AListIndex: Integer); override;
procedure WriteIndex(AStream: TStream);
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: string; ACell: PCell); override;
@ -130,6 +130,7 @@ type
procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
procedure WriteXFRecords(AStream: TStream);
public
constructor Create(AWorkbook: TsWorkbook); override;
{ General writing methods }
procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); override;
@ -296,9 +297,21 @@ const
MASK_XF_BKGR_BACKGROUND_COLOR = $00003F80;
MASK_XF_BKGR_FILLPATTERN = $003F0000;
TEXT_ROTATIONS: Array[TsTextRotation] of Byte = (
XF_ROTATION_HORIZONTAL,
XF_ROTATION_90DEG_CW,
XF_ROTATION_90DEG_CCW,
XF_ROTATION_STACKED
);
{ TsSpreadBIFF5Writer }
constructor TsSpreadBIFF5Writer.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
end;
{*******************************************************************
* TsSpreadBIFF5Writer.WriteToFile ()
*
@ -362,6 +375,7 @@ begin
WriteCodepage(AStream, WorkBookEncoding);
WriteWindow1(AStream);
WriteFonts(AStream);
WriteFormats(AStream);
WritePalette(AStream);
WriteXFRecords(AStream);
WriteStyle(AStream);
@ -632,6 +646,36 @@ begin
WriteFont(AStream, Workbook.GetFont(i));
end;
{*******************************************************************
* TsSpreadBIFF5Writer.WriteFormat
*
* DESCRIPTION: Writes an Excel 5 FORMAT record
*
*******************************************************************}
procedure TsSpreadBiff5Writer.WriteFormat(AStream: TStream;
AFormatData: TsNumFormatData; AListIndex: Integer);
var
len: Integer;
s: ansistring;
begin
if (AFormatData = nil) or (AFormatData.FormatString = '') then
exit;
s := NumFormatList.FormatStringForWriting(AListIndex);
len := Length(s);
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT));
AStream.WriteWord(WordToLE(2 + 1 + len * SizeOf(AnsiChar)));
{ Format index }
AStream.WriteWord(WordToLE(AFormatData.Index));
{ Format string }
AStream.WriteByte(len); // AnsiString, char count in 1 byte
AStream.WriteBuffer(s[1], len * SizeOf(AnsiChar)); // String data
end;
{*******************************************************************
* TsSpreadBIFF5Writer.WriteRPNFormula ()
*
@ -1047,7 +1091,7 @@ end;
procedure TsSpreadBIFF5Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var
i: Integer;
i, j: Integer;
lFontIndex: Word;
lFormatIndex: Word; //number format
lTextRotation: Byte;
@ -1073,77 +1117,17 @@ begin
lBackgroundColor := FFormattingStyles[i].BackgroundColor;
// Now apply the modifications.
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then
case FFormattingStyles[i].NumberFormat of
nfFixed:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_FIXED_0_DECIMALS;
2: lFormatIndex := FORMAT_FIXED_2_DECIMALS;
end;
nfFixedTh:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_FIXED_THOUSANDS_0_DECIMALS;
2: lFormatIndex := FORMAT_FIXED_THOUSANDS_2_DECIMALS;
end;
nfExp:
lFormatIndex := FORMAT_EXP_2_DECIMALS;
nfSci:
lFormatIndex := FORMAT_SCI_1_DECIMAL;
nfPercentage:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_PERCENT_0_DECIMALS;
2: lFormatIndex := FORMAT_PERCENT_2_DECIMALS;
end;
{
nfCurrency:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS;
2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS;
end;
}
nfShortDate:
lFormatIndex := FORMAT_SHORT_DATE;
nfShortTime:
lFormatIndex := FORMAT_SHORT_TIME;
nfLongTime:
lFormatIndex := FORMAT_LONG_TIME;
nfShortTimeAM:
lFormatIndex := FORMAT_SHORT_TIME_AM;
nfLongTimeAM:
lFormatIndex := FORMAT_LONG_TIME_AM;
nfShortDateTime:
lFormatIndex := FORMAT_SHORT_DATETIME;
nfFmtDateTime:
begin
fmt := lowercase(FFormattingStyles[i].NumberFormatStr);
if (fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm') then
lFormatIndex := FORMAT_DATE_DM
else
if (fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy') then
lFormatIndex := FORMAT_DATE_MY
else
if (fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss') then
lFormatIndex := FORMAT_TIME_MS
else
if (fmt = 'msz') or (fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or (fmt = 'mm:ss.0') or (fmt = 'mm:ss.z') or (fmt = 'nn:ss.z') then
lFormatIndex := FORMAT_TIME_MSZ
end;
nfTimeInterval:
lFormatIndex := FORMAT_TIME_INTERVAL;
end;
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
j := NumFormatList.Find(@FFormattingStyles[i]);
if j > -1 then
lFormatIndex := NumFormatList[j].Index;
end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border;
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
begin
case FFormattingStyles[i].TextRotation of
trHorizontal : lTextRotation := XF_ROTATION_HORIZONTAL;
rt90DegreeClockwiseRotation : lTextRotation := XF_ROTATION_90DEG_CW;
rt90DegreeCounterClockwiseRotation : lTextRotation := XF_ROTATION_90DEG_CCW;
rtStacked : lTextRotation := XF_ROTATION_STACKED;
end;
end;
lTextRotation := TEXT_ROTATIONS[FFormattingStyles[i].TextRotation];
if uffBold in FFormattingStyles[i].UsedFormattingFields then
lFontIndex := 1; // must be before uffFont which overrides uffBold
@ -1270,7 +1254,7 @@ begin
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(AStream);
INT_EXCEL_ID_FORMULA : ReadFormulaExcel(AStream);
INT_EXCEL_ID_FORMULA : ReadFormula(AStream);
INT_EXCEL_ID_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ;
@ -1376,32 +1360,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF);
end;
procedure TsSpreadBIFF5Reader.ReadFormulaExcel(AStream: TStream);
var
ARow, ACol: Cardinal;
XF: WORD;
ResultFormula: Double;
Data: array [0..7] of BYTE;
Flags: WORD;
FormulaSize: BYTE;
begin
ReadRowColXF(AStream, ARow, ACol, XF);
AStream.ReadBuffer(Data,Sizeof(Data));
Flags:=WordLEtoN(AStream.ReadWord);
AStream.ReadDWord; //Not used.
FormulaSize:=AStream.ReadByte;
//RPN data not used by now
AStream.Position:=AStream.Position+FormulaSize;
if SizeOf(Double)<>8 then Raise Exception.Create('Double is not 8 bytes');
Move(Data[0],ResultFormula,sizeof(Data));
FWorksheet.WriteNumber(ARow, ACol, ResultFormula);
{ Add attributes to cell }
ApplyCellFormatting(ARow, ACol, XF);
end;
procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
var
MemStream: TMemoryStream;
@ -1638,12 +1596,10 @@ end;
// Read the FORMAT record for formatting numerical data
procedure TsSpreadBIFF5Reader.ReadFormat(AStream: TStream);
var
lData: TFormatListData;
str: AnsiString;
len: byte;
fmtIndex: Integer;
fmtString: AnsiString;
begin
lData := TFormatListData.Create;
// Record FORMAT, BIFF 8 (5.49):
// Offset Size Contents
// 0 2 Format index used in other records
@ -1651,21 +1607,15 @@ begin
// From BIFF5 on: indexes 0..163 are built in
// format index
lData.Index := WordLEtoN(AStream.ReadWord);
fmtIndex := WordLEtoN(AStream.ReadWord);
// number format string
len := AStream.ReadByte;
SetLength(str, len);
AStream.ReadBuffer(str[1], len);
lData.FormatString := str;
SetLength(fmtString, len);
AStream.ReadBuffer(fmtString[1], len);
// Add to the list
FFormatList.Add(lData);
end;
procedure TsSpreadBIFF5Reader.ReadFormula(AStream: TStream);
begin
NumFormatList.AnalyzeAndAdd(fmtIndex, fmtString);
end;
procedure TsSpreadBIFF5Reader.ReadLabel(AStream: TStream);

View File

@ -89,7 +89,6 @@ type
procedure ReadFormat(AStream: TStream); override;
{ Record reading methods }
procedure ReadBlank(AStream: TStream); override;
procedure ReadFormula(AStream: TStream); override;
procedure ReadLabel(AStream: TStream); override;
procedure ReadRichString(const AStream: TStream);
public
@ -115,6 +114,8 @@ type
procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream);
procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
AListIndex: Integer); override;
procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal;
const AFormula: TsFormula; ACell: PCell); override;
procedure WriteIndex(AStream: TStream);
@ -131,6 +132,7 @@ type
AddBackground: Boolean = false; ABackgroundColor: TsColor = scSilver);
procedure WriteXFRecords(AStream: TStream);
public
constructor Create(AWorkbook: TsWorkbook); override;
{ General writing methods }
procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); override;
@ -263,12 +265,24 @@ const
MASK_XF_BORDER_TOP_COLOR = $0000007F;
MASK_XF_BORDER_BOTTOM_COLOR = $00003F80;
TEXT_ROTATIONS: Array[TsTextRotation] of Byte = (
XF_ROTATION_HORIZONTAL,
XF_ROTATION_90DEG_CW,
XF_ROTATION_90DEG_CCW,
XF_ROTATION_STACKED
);
{ TsSpreadBIFF8Writer }
constructor TsSpreadBIFF8Writer.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
end;
procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var
i: Integer;
i, j: Integer;
lFontIndex: Word;
lFormatIndex: Word; //number format
lTextRotation: Byte;
@ -281,7 +295,7 @@ var
lWordWrap: Boolean;
fmt: String;
begin
// The first style was already added
// The first style was already added --> begin loop with 1
for i := 1 to Length(FFormattingStyles) - 1 do begin
// Default styles
lFontIndex := 0;
@ -294,77 +308,17 @@ begin
lBackgroundColor := FFormattingStyles[i].BackgroundColor;
// Now apply the modifications.
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then
case FFormattingStyles[i].NumberFormat of
nfFixed:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_FIXED_0_DECIMALS;
2: lFormatIndex := FORMAT_FIXED_2_DECIMALS;
end;
nfFixedTh:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_FIXED_THOUSANDS_0_DECIMALS;
2: lFormatIndex := FORMAT_FIXED_THOUSANDS_2_DECIMALS;
end;
nfExp:
lFormatIndex := FORMAT_EXP_2_DECIMALS;
nfSci:
lFormatIndex := FORMAT_SCI_1_DECIMAL;
nfPercentage:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_PERCENT_0_DECIMALS;
2: lFormatIndex := FORMAT_PERCENT_2_DECIMALS;
end;
{
nfCurrency:
case FFormattingStyles[i].NumberDecimals of
0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS;
2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS;
end;
}
nfShortDate:
lFormatIndex := FORMAT_SHORT_DATE;
nfShortTime:
lFormatIndex := FORMAT_SHORT_TIME;
nfLongTime:
lFormatIndex := FORMAT_LONG_TIME;
nfShortTimeAM:
lFormatIndex := FORMAT_SHORT_TIME_AM;
nfLongTimeAM:
lFormatIndex := FORMAT_LONG_TIME_AM;
nfShortDateTime:
lFormatIndex := FORMAT_SHORT_DATETIME;
nfFmtDateTime:
begin
fmt := lowercase(FFormattingStyles[i].NumberFormatStr);
if (fmt = 'dm') or (fmt = 'd-mmm') or (fmt = 'd mmm') or (fmt = 'd. mmm') or (fmt = 'd/mmm') then
lFormatIndex := FORMAT_DATE_DM
else
if (fmt = 'my') or (fmt = 'mmm-yy') or (fmt = 'mmm yy') or (fmt = 'mmm/yy') then
lFormatIndex := FORMAT_DATE_MY
else
if (fmt = 'ms') or (fmt = 'nn:ss') or (fmt = 'mm:ss') then
lFormatIndex := FORMAT_TIME_MS
else
if (fmt = 'msz') or (fmt = 'nn:ss.zzz') or (fmt = 'mm:ss.zzz') or (fmt = 'mm:ss.0') or (fmt = 'mm:ss.z') or (fmt = 'nn:ss.z') then
lFormatIndex := FORMAT_TIME_MSZ
end;
nfTimeInterval:
lFormatIndex := FORMAT_TIME_INTERVAL;
end;
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
j := NumFormatList.Find(@FFormattingStyles[i]);
if j > -1 then
lFormatIndex := NumFormatList[j].Index;
end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border;
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
begin
case FFormattingStyles[i].TextRotation of
trHorizontal: lTextRotation := XF_ROTATION_HORIZONTAL;
rt90DegreeClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CW;
rt90DegreeCounterClockwiseRotation: lTextRotation := XF_ROTATION_90DEG_CCW;
rtStacked: lTextRotation := XF_ROTATION_STACKED;
end;
end;
lTextRotation := TEXT_ROTATIONS[FFormattingStyles[i].TextRotation];
if uffBold in FFormattingStyles[i].UsedFormattingFields then
lFontIndex := 1; // must be before uffFont which overrides uffBold
@ -445,6 +399,7 @@ begin
WriteWindow1(AStream);
WriteFonts(AStream);
WriteFormats(AStream);
WritePalette(AStream);
WriteXFRecords(AStream);
WriteStyle(AStream);
@ -713,6 +668,34 @@ begin
WriteFont(AStream, Workbook.GetFont(i));
end;
procedure TsSpreadBiff8Writer.WriteFormat(AStream: TStream;
AFormatData: TsNumFormatData; AListIndex: Integer);
var
len: Integer;
s: widestring;
begin
if (AFormatData = nil) or (AFormatData.FormatString = '') then
exit;
s := NumFormatList.FormatStringForWriting(AListIndex);
len := Length(s);
{ BIFF Record header }
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT));
AStream.WriteWord(WordToLE(2 + 2 + 1 + len * SizeOf(WideChar)));
{ Format index }
AStream.WriteWord(WordToLE(AFormatData.Index));
{ Format string }
{ - Unicodestring, char count in 2 bytes }
AStream.WriteWord(WordToLE(len));
{ - Widestring flags, 1=regular unicode LE string }
AStream.WriteByte(1);
{ - String data }
AStream.WriteBuffer(WideStringToLE(s)[1], len * Sizeof(WideChar));
end;
{*******************************************************************
* TsSpreadBIFF8Writer.WriteFormula ()
*
@ -1435,16 +1418,16 @@ begin
if RecordType <> INT_EXCEL_ID_CONTINUE then begin
case RecordType of
INT_EXCEL_ID_BOF: ;
INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_BOUNDSHEET: ReadBoundSheet(AStream);
INT_EXCEL_ID_EOF: SectionEOF := True;
INT_EXCEL_ID_SST: ReadSST(AStream);
INT_EXCEL_ID_CODEPAGE: ReadCodepage(AStream);
INT_EXCEL_ID_FONT: ReadFont(AStream);
INT_EXCEL_ID_XF: ReadXF(AStream);
INT_EXCEL_ID_FORMAT: ReadFormat(AStream);
INT_EXCEL_ID_DATEMODE: ReadDateMode(AStream);
INT_EXCEL_ID_PALETTE: ReadPalette(AStream);
INT_EXCEL_ID_EOF : SectionEOF := True;
INT_EXCEL_ID_SST : ReadSST(AStream);
INT_EXCEL_ID_CODEPAGE : ReadCodepage(AStream);
INT_EXCEL_ID_FONT : ReadFont(AStream);
INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
INT_EXCEL_ID_XF : ReadXF(AStream);
INT_EXCEL_ID_DATEMODE : ReadDateMode(AStream);
INT_EXCEL_ID_PALETTE : ReadPalette(AStream);
else
// nothing
end;
@ -1624,51 +1607,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF);
end;
procedure TsSpreadBIFF8Reader.ReadFormula(AStream: TStream);
var
ARow, ACol: Cardinal;
XF: WORD;
ResultFormula: Double;
Data: array [0..7] of BYTE;
Flags: WORD;
FormulaSize: BYTE;
i: Integer;
begin
{ BIFF Record header }
{ BIFF Record data }
{ Index to XF Record }
ReadRowColXF(AStream, ARow, ACol, XF);
{ Result of the formula in IEE 754 floating-point value }
AStream.ReadBuffer(Data, Sizeof(Data));
{ Options flags }
Flags := WordLEtoN(AStream.ReadWord);
{ Not used }
AStream.ReadDWord;
{ Formula size }
FormulaSize := WordLEtoN(AStream.ReadWord);
{ Formula data, output as debug info }
{ Write('Formula Element: ');
for i := 1 to FormulaSize do
Write(IntToHex(AStream.ReadByte, 2) + ' ');
WriteLn('');}
//RPN data not used by now
AStream.Position := AStream.Position + FormulaSize;
if SizeOf(Double) <> 8 then
raise Exception.Create('Double is not 8 bytes');
Move(Data[0], ResultFormula, SizeOf(Data));
FWorksheet.WriteNumber(ARow, ACol, ResultFormula);
{Add attributes}
ApplyCellFormatting(ARow, ACol, XF);
end;
procedure TsSpreadBIFF8Reader.ReadLabel(AStream: TStream);
var
L: Word;
@ -1975,22 +1913,21 @@ end;
// Read the FORMAT record for formatting numerical data
procedure TsSpreadBIFF8Reader.ReadFormat(AStream: TStream);
var
lData: TFormatListData;
fmtString: String;
fmtIndex: Integer;
begin
lData := TFormatListData.Create;
// Record FORMAT, BIFF 8 (5.49):
// Offset Size Contents
// 0 2 Format index used in other records
// 2 var Number format string (Unicode string, 16-bit string length)
// From BIFF5 on: indexes 0..163 are built in
lData.Index := WordLEtoN(AStream.ReadWord);
fmtIndex := WordLEtoN(AStream.ReadWord);
// 2 var. Number format string (Unicode string, 16-bit string length, ➜2.5.3)
lData.FormatString := ReadWideString(AStream, False);
fmtString := ReadWideString(AStream, False);
// Add to the list
FFormatList.Add(lData);
NumFormatList.AnalyzeAndAdd(fmtIndex, fmtString);
end;

View File

@ -236,7 +236,7 @@ const
{ DATEMODE record, 5.28 }
DATEMODE_1900_BASE=1; //1/1/1900 minus 1 day in FPC TDateTime
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
(*
{ FORMAT record constants for BIFF5-BIFF8}
// Subset of the built-in formats for US Excel,
// including those needed for date/time output
@ -262,6 +262,7 @@ const
FORMAT_TIME_INTERVAL = 46; //time [hh]:mm:ss, hh can be >24
FORMAT_TIME_MSZ = 47; //time MM:SS.0
FORMAT_SCI_1_DECIMAL = 48; //scientific, 1 decimal
*)
{ WINDOW1 record constants - BIFF5-BIFF8 }
MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001;
@ -361,11 +362,12 @@ type
BackgroundColor: TsColor;
end;
{ Contents of the format record for BIFF5/8 }
TFormatListData = class
{ TsBIFFNumFormatList }
TsBIFFNumFormatList = class(TsCustomNumFormatList)
protected
procedure AddBuiltinFormats; override;
public
Index: Integer;
FormatString: widestring;
function FormatStringForWriting(AIndex: Integer): String; override;
end;
{ TsSpreadBIFFReader }
@ -376,8 +378,8 @@ type
FDateMode: TDateMode;
FPaletteFound: Boolean;
FXFList: TFPList; // of TXFListData
FFormatList: TFPList; // of TFormatListData
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual;
procedure CreateNumFormatList; override;
// Extracts a number out of an RK value
function DecodeRKValue(const ARK: DWORD): Double;
// Returns the numberformat for a given XF record
@ -386,7 +388,7 @@ type
out ANumberFormatStr: String); virtual;
// Finds format record for XF record pointed to by cell
// Will not return info for built-in formats
function FindFormatDataForCell(const AXFIndex: Integer): TFormatListData;
function FindNumFormatDataForCell(const AXFIndex: Integer): TsNumFormatData;
// Tries to find if a number cell is actually a date/datetime/time cell and retrieves the value
function IsDateTime(Number: Double; ANumberFormat: TsNumberFormat; var ADateTime: TDateTime): Boolean;
// Here we can add reading of records which didn't change across BIFF5-8 versions
@ -397,6 +399,8 @@ type
procedure ReadDateMode(AStream: TStream);
// Read FORMAT record (cell formatting)
procedure ReadFormat(AStream: TStream); virtual;
// Read FORMULA record
procedure ReadFormula(AStream: TStream); override;
// Read multiple blank cells
procedure ReadMulBlank(AStream: TStream);
// Read multiple RK cells
@ -428,6 +432,7 @@ type
FLastRow: Integer;
FLastCol: Word;
procedure AddDefaultFormats; override;
procedure CreateNumFormatList; override;
procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
procedure GetLastColCallback(ACell: PCell; AStream: TStream);
@ -453,6 +458,11 @@ type
// Writes out a TIME/DATE/TIMETIME
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: TDateTime; ACell: PCell); override;
// Writes out a FORMAT record
procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
AListIndex: Integer); virtual;
// Writes out all FORMAT records
procedure WriteFormats(AStream: TStream);
// Writes out a floating point NUMBER record
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: Double; ACell: PCell); override;
@ -478,17 +488,38 @@ type
destructor Destroy; override;
end;
function IsExpNumberFormat(s: String; out Decimals: Word): Boolean;
function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
function IsDateFormat(s: String): Boolean;
function IsTimeFormat(s: String; out isLong, isAMPM, isMillisec: Boolean): Boolean;
implementation
uses
StrUtils;
const
{ see ➜ 5.49 }
COUNT_DEFAULT_FORMATS = 58;
NOT_USED = nfGeneral;
DEFAULT_NUM_FORMATS: array[1..COUNT_DEFAULT_FORMATS] of TsNumberFormat = (
nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5
nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10
nfExp, NOT_USED, NOT_USED, nfShortDate, nfShortDate, // 11..15
nfFmtDateTime, nfFmtDateTime, nfShortTimeAM, nfLongTimeAM, nfShortTime, // 16..20
nfLongTime, nfShortDateTime, NOT_USED, NOT_USED, NOT_USED, // 21..25
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 26..30
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 31..35
NOT_USED, nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, // 36..40
nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, nfFmtDateTime, // 41..45
nfTimeInterval, nfFmtDateTime, nfSci, NOT_USED, NOT_USED, // 46..50
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 51..55
NOT_USED, NOT_USED, NOT_USED // 56..58
);
DEFAULT_NUM_FORMAT_DECIMALS: array[1..COUNT_DEFAULT_FORMATS] of word = (
0, 2, 0, 2, 0, 0, 2, 2, 0, 2, // 1..10
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11..20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21..30
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, // 31..40
0, 0, 2, 2, 0, 3, 0, 1, 0, 0, // 41..50 #48 is "scientific", use "exponential" instead
0, 0, 0, 0, 0, 0, 0, 0); // 51..58
function ConvertExcelDateTimeToDateTime(
const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
begin
@ -540,13 +571,75 @@ begin
end;
{ TsBIFFNumFormatList }
{ These are the built-in number formats as used by fpc. Before writing to file
some code will be modified to become compatible with Excel
(--> FormatStringForWriting) }
procedure TsBIFFNumFormatList.AddBuiltinFormats;
begin
AddFormat( 0, nfGeneral);
AddFormat( 1, nfFixed, '0', 0);
AddFormat( 2, nfFixed, '0.00', 2);
AddFormat( 3, nfFixedTh, '#,##0', 0);
AddFormat( 4, nfFixedTh, '#,##0.00', 2);
// 5..8 currently not supported
AddFormat( 9, nfPercentage, '0%', 0);
AddFormat(10, nfPercentage, '0.00%', 2);
AddFormat(11, nfExp, '0.00E+00', 2);
// fraction formats 12 ('# ?/?') and 13 ('# ??/??') not supported
AddFormat(14, nfShortDate);
AddFormat(15, nfLongDate);
AddFormat(16, nfFmtDateTime, 'D-MMM');
AddFormat(17, nfFmtDateTime, 'MMM-YY');
AddFormat(18, nfShortTimeAM);
AddFormat(19, nfLongTimeAM);
AddFormat(20, nfShortTime);
AddFormat(21, nfLongTime);
AddFormat(22, nfShortDateTime);
// 23..44 not supported
AddFormat(45, nfFmtDateTime, 'mm:ss');
AddFormat(46, nfTimeInterval, '[h]:mm:ss');
AddFormat(47, nfFmtDateTime, 'mm:ss.z'); // z will be replace by 0 later
AddFormat(48, nfSci, '##0.0E+0', 1);
// 49 ("Text") not supported
// All indexes from 0 to 163 are reserved for built-in formats.
// The first user-defined format starts at 164.
FFirstFormatIndexInFile := 164;
FNextFormatIndex := 164;
end;
{ Creates formatting strings that are written into the file. }
function TsBIFFNumFormatList.FormatStringForWriting(AIndex: Integer): String;
var
item: TsNumFormatData;
i: Integer;
begin
Result := inherited FormatStringForWriting(AIndex);
item := Items[AIndex];
case item.NumFormat of
nfFmtDateTime:
begin
Result := lowercase(item.FormatString);
for i:=1 to Length(Result) do
if Result[i] in ['z', 'Z'] then Result[i] := '0';
end;
nfTimeInterval:
// Time interval format string could still be without square brackets
// if added by user.
// We check here for safety and add the brackets if not there.
MakeTimeIntervalMask(item.FormatString, Result);
end;
end;
{ TsSpreadBIFFReader }
constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
FXFList := TFPList.Create;
FFormatList := TFPList.Create;
// Initial base date in case it won't be read from file
FDateMode := dm1900;
end;
@ -557,8 +650,6 @@ var
begin
for j := FXFList.Count-1 downto 0 do TObject(FXFList[j]).Free;
FXFList.Free;
for j := FFormatList.Count-1 downto 0 do TObject(FFormatList[j]).Free;
FFormatList.Free;
inherited Destroy;
end;
@ -614,6 +705,15 @@ begin
end;
end;
{ Creates the correct version of the number format list. It is for BIFF file
formats.
Valid for BIFF5.BIFF8. Needs to be overridden for BIFF2. }
procedure TsSpreadBIFFReader.CreateNumFormatList;
begin
FreeAndNil(FNumFormatList);
FNumFormatList := TsBIFFNumFormatList.Create;
end;
{ Extracts a number out of an RK value.
Valid since BIFF3. }
function TsSpreadBIFFReader.DecodeRKValue(const ARK: DWORD): Double;
@ -651,120 +751,51 @@ end;
procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String);
const
{ see ➜ 5.49 }
NOT_USED = nfGeneral;
fmts: array[1..58] of TsNumberFormat = (
nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5
nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10
nfExp, NOT_USED, NOT_USED, nfShortDate, nfShortDate, // 11..15
nfFmtDateTime, nfFmtDateTime, nfShortTimeAM, nfLongTimeAM, nfShortTime, // 16..20
nfLongTime, nfShortDateTime, NOT_USED, NOT_USED, NOT_USED, // 21..25
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 26..30
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 31..35
NOT_USED, nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, // 36..40
nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, nfFmtDateTime, // 41..45
nfTimeInterval, nfFmtDateTime, nfSci, NOT_USED, NOT_USED, // 46..50
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 51..55
NOT_USED, NOT_USED, NOT_USED // 56..58
);
decs: array[1..58] of word = (
0, 2, 0, 2, 0, 0, 2, 2, 0, 2, // 1..10
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11..20
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 21..30
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, // 31..40
0, 0, 2, 2, 0, 3, 0, 1, 0, 0, // 41..50 #48 is "scientific", use "exponential" instead
0, 0, 0, 0, 0, 0, 0, 0); // 51..58
var
lFormatData: TFormatListData;
lXFData: TXFListData;
isAMPM: Boolean;
isLongTime: Boolean;
isMilliSec: Boolean;
t,d: Boolean;
begin
ANumberFormat := nfGeneral;
ANumberFormatStr := '';
ADecimals := 0;
lFormatData := FindFormatDataForCell(AXFIndex);
{Record FORMAT, BIFF 5/8 (5.49):
Offset Size Contents
0 2 Format index used in other records
}
if lFormatData = nil then begin
// no custom format, so first test for default formats
lXFData := TXFListData(FXFList.Items[AXFIndex]);
case lXFData.FormatIndex of
FORMAT_DATE_DM:
begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'DM'; end;
FORMAT_DATE_MY:
begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'MY'; end;
FORMAT_TIME_MS:
begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'MS'; end;
FORMAT_TIME_MSZ:
begin ANumberFormat := nfFmtDateTime; ANumberFormatStr := 'MSZ'; end;
else
if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 58) then begin
ANumberFormat := fmts[lXFData.FormatIndex];
ADecimals := decs[lXFData.FormatIndex];
procedure FixMilliseconds;
var
isLong, isAMPM, isInterval: Boolean;
decs: Word;
i: Integer;
begin
if IsTimeFormat(ANumberFormatStr, isLong, isAMPM, isInterval, decs)
and (decs > 0)
then
for i:= Length(ANumberFormatStr) downto 1 do
case ANumberFormatStr[i] of
'0': ANumberFormatStr[i] := 'z';
'.': break;
end;
end;
end else
// Check custom formats if they have "/" in format string (this can fail for
// custom text formats)
if IsPercentNumberFormat(lFormatData.FormatString, ADecimals) then
ANumberFormat := nfPercentage
else
if IsExpNumberFormat(lFormatData.Formatstring, ADecimals) then
ANumberFormat := nfExp
else
if IsThousandSepNumberFormat(lFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixedTh
else
if IsFixedNumberFormat(lFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixed
else begin
t := IsTimeFormat(lFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
d := IsDateFormat(lFormatData.FormatString);
if d and t then
ANumberFormat := nfShortDateTime
else
if d then
ANumberFormat := nfShortDate
else
if t then begin
if isAMPM then begin
if isLongTime then
ANumberFormat := nfLongTimeAM
else
ANumberFormat := nfShortTimeAM;
end else begin
if isLongTime then
ANumberFormat := nfLongTime
else
ANumberFormat := nfShortTime;
end;
end;
end;
var
lNumFormatData: TsNumFormatData;
begin
lNumFormatData := FindNumFormatDataForCell(AXFIndex);
if lNumFormatData <> nil then begin
ANumberFormat := lNumFormatData.NumFormat;
ANumberFormatStr := lNumFormatData.FormatString;
ADecimals := lNumFormatData.Decimals;
FixMilliseconds;
end else begin
ANumberFormat := nfGeneral;
ANumberFormatStr := '';
ADecimals := 0;
end;
end;
{ Determines the format data (for numerical formatting) which belong to a given
XF record.
Does not return data for built-in formats. }
function TsSpreadBIFFReader.FindFormatDataForCell(const AXFIndex: Integer
): TFormatListData;
XF record. }
function TsSpreadBIFFReader.FindNumFormatDataForCell(const AXFIndex: Integer
): TsNumFormatData;
var
lXFData: TXFListData;
i: Integer;
begin
lXFData := TXFListData(FXFList.Items[AXFIndex]);
for i := 0 to FFormatList.Count-1 do begin
Result := TFormatListData(FFormatList.Items[i]);
if Result.Index = lXFData.FormatIndex then Exit;
end;
Result := nil;
lXFData := TXFListData(FXFList.Items[AXFIndex]);
i := NumFormatList.Find(lXFData.FormatIndex);
if i <> -1 then Result := NumFormatList[i];
end;
{ Convert the number to a date/time and return that if it is }
@ -772,7 +803,7 @@ function TsSpreadBIFFReader.IsDateTime(Number: Double;
ANumberFormat: TsNumberFormat; var ADateTime: TDateTime): boolean;
begin
if ANumberFormat in [
nfShortDateTime, nfFmtDateTime, nfShortDate,
nfShortDateTime, nfFmtDateTime, nfShortDate, nfLongDate,
nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM] then
begin
ADateTime := ConvertExcelDateTimeToDateTime(Number, FDateMode);
@ -788,7 +819,7 @@ begin
end;
end;
// In BIFF 8 it seams to always use the UTF-16 codepage
// In BIFF8 it seams to always use the UTF-16 codepage
procedure TsSpreadBIFFReader.ReadCodePage(AStream: TStream);
var
lCodePage: Word;
@ -892,6 +923,76 @@ begin
// to be overridden
end;
{ Reads a FORMULA record, retrieves the RPN formula and puts the result in the
corresponding field. The formula is not recalculated here!
Valid for BIFF5 and BIFF8. }
procedure TsSpreadBIFFReader.ReadFormula(AStream: TStream);
var
ARow, ACol: Cardinal;
XF: WORD;
ResultFormula: Double;
Data: array [0..7] of BYTE;
Flags: WORD;
FormulaSize: BYTE;
i: Integer;
dt: TDateTime;
nf: TsNumberFormat;
nd: Word;
nfs: String;
begin
{ BIFF Record header }
{ BIFF Record data }
{ Index to XF Record }
ReadRowColXF(AStream, ARow, ACol, XF);
{ Result of the formula in IEE 754 floating-point value }
AStream.ReadBuffer(Data, Sizeof(Data));
{ Options flags }
Flags := WordLEtoN(AStream.ReadWord);
{ Not used }
AStream.ReadDWord;
{ Formula size }
FormulaSize := WordLEtoN(AStream.ReadWord);
{ Formula data, output as debug info }
{ Write('Formula Element: ');
for i := 1 to FormulaSize do
Write(IntToHex(AStream.ReadByte, 2) + ' ');
WriteLn('');}
//RPN data not used by now
AStream.Position := AStream.Position + FormulaSize;
if (Data[6] = $FF) and (Data[7] = $FF) then
case Data[0] of
0: FWorksheet.WriteUTF8Text(ARow, ACol, '(String)');
1: FWorksheet.WriteUTF8Text(ARow, ACol, '(Bool)');
2: FWorksheet.WriteUTF8Text(ARow, ACol, '(ERROR)');
3: FWorksheet.WriteUTF8Text(ARow, ACol, '(empty)');
end
else begin
if SizeOf(Double) <> 8 then
raise Exception.Create('Double is not 8 bytes');
// Result is a number or a date/time
Move(Data[0], ResultFormula, SizeOf(Data));
{Find out what cell type, set content type and value}
ExtractNumberFormat(XF, nf, nd, nfs);
if IsDateTime(ResultFormula, nf, dt) then
FWorksheet.WriteDateTime(ARow, ACol, dt, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, ResultFormula, nf, nd);
end;
{Add attributes}
ApplyCellFormatting(ARow, ACol, XF);
end;
// Reads multiple blank cell records
// Valid for BIFF5 and BIFF8 (does not exist before)
procedure TsSpreadBIFFReader.ReadMulBlank(AStream: TStream);
@ -1168,6 +1269,15 @@ begin
// "15" is the index of the last pre-defined xf record
end;
{ Creates the correct version of the number format list. It is for BIFF file
formats.
Valid for BIFF5.BIFF8. Needs to be overridden for BIFF2. }
procedure TsSpreadBIFFWriter.CreateNumFormatList;
begin
FreeAndNil(FNumFormatList);
FNumFormatList := TsBIFFNumFormatList.Create;
end;
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
AElementKind: TFEKind; out ASecondaryID: Word): Word;
const
@ -1469,6 +1579,30 @@ begin
WriteNumber(AStream, ARow, ACol, ExcelDateSerial, ACell);
end;
{ Writes a BIFF format record defined in AFormatData. AListIndex the index of
the formatdata in the format list (not the FormatIndex!).
Needs to be overridden by descendants. }
procedure TsSpreadBIFFWriter.WriteFormat(AStream: TStream;
AFormatData: TsNumFormatData; AListIndex: Integer);
begin
// needs to be overridden
end;
{ Writes all number formats to the stream. Saving starts at the item with the
FirstFormatIndexInFile. }
procedure TsSpreadBIFFWriter.WriteFormats(AStream: TStream);
var
i: Integer;
begin
ListAllNumFormats;
i := NumFormatList.Find(NumFormatList.FirstFormatIndexInFile);
while i < NumFormatList.Count do begin
if NumFormatList[i] <> nil then
WriteFormat(AStream, NumFormatList[i], i);
inc(i);
end;
end;
{ Writes a 64-bit floating point NUMBER record.
Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure.). }
procedure TsSpreadBIFFWriter.WriteNumber(AStream: TStream;
@ -1806,204 +1940,5 @@ begin
AStream.WriteWord(WordToLE(lXFIndex));
end;
{ Format checking procedures }
{ This simple parsing procedure of the Excel format string checks for a fixed
float format s, i.e. s can be '0', '0.00', '000', '0,000', and returns the
number of decimals, i.e. number of zeros behind the decimal point }
function IsFixedNumberFormat(s: String; out Decimals: Word): Boolean;
var
i: Integer;
p: Integer;
decs: String;
begin
Decimals := 0;
// Check if s is a valid format mask.
try
FormatFloat(s, 1.0);
except
on EConvertError do begin
Result := false;
exit;
end;
end;
// If it is count the zeros - each one is a decimal.
if s = '0' then
Result := true
else begin
p := pos('.', s); // position of decimal point;
if p = 0 then begin
Result := false;
end else begin
Result := true;
for i:= p+1 to Length(s) do
if s[i] = '0' then begin
inc(Decimals)
end
else
exit; // ignore characters after the last 0
end;
end;
end;
{ This function checks whether the format string corresponds to a thousand
separator format like "#,##0.000' and returns the number of fixed decimals
(i.e. zeros after the decimal point) }
function IsThousandSepNumberFormat(s: String; out Decimals: Word): Boolean;
var
i, p: Integer;
begin
Decimals := 0;
// Check if s is a valid format string
try
FormatFloat(s, 1.0);
except
on EConvertError do begin
Result := false;
exit;
end;
end;
// If it is look for the thousand separator. If found count decimals.
Result := (Pos(',', s) > 0);
if Result then begin
p := pos('.', s);
if p > 0 then
for i := p+1 to Length(s) do
if s[i] = '0' then
inc(Decimals)
else
exit; // ignore format characters after the last 0
end;
end;
{ This function checks whether the format string corresponds to percent
formatting and determines the number of decimals }
function IsPercentNumberFormat(s: String; out Decimals: Word): Boolean;
var
i, p: Integer;
begin
Decimals := 0;
// The signature of the percent format is a percent sign at the end of the
// format string.
Result := (s <> '') and (s[Length(s)] = '%');
if Result then begin
// Check for a valid format string
Delete(s, Length(s), 1);
try
FormatDateTime(s, 1.0);
except
on EConvertError do begin
Result := false;
exit;
end;
end;
// Count decimals
p := pos('.', s);
if p > 0 then
for i := p+1 to Length(s)-1 do
if s[i] = '0' then
inc(Decimals)
else
exit; // ignore characters after last 0
end;
end;
{ This function checks whether the format string corresponds to exponential
formatting and determines the number of decimals }
function IsExpNumberFormat(s: String; out Decimals: Word): Boolean;
var
i, p, pe: Integer;
begin
Result := false;
Decimals := 0;
if SameText(s, 'General') then
exit;
// Check for a valid format string
try
FormatDateTime(s, 1.0);
except
on EConvertError do begin
exit;
end;
end;
// Count decimals
pe := pos('e', lowercase(s));
result := pe > 0;
if Result then begin
p := pos('.', s);
if (p > 0) then begin
if p < pe then
for i:=1 to pe-1 do
if s[i] = '0' then
inc(Decimals)
else
exit; // ignore characters after last 0
end;
end;
end;
{ IsDateFormat checks if the format string s corresponds to a date format }
function IsDateFormat(s: String): Boolean;
begin
// Day, month, year are separated by a slash
Result := (pos('/', s) > 0);
if Result then
// Check validity of format string
try
FormatDateTime(s, now);
except on EConvertError do
Result := false;
end;
end;
{ IsTimeFormat checks if the format string s is a time format. isLong is
true if the string contains hours, minutes and seconds (two colons).
isAMPM is true if the string contains "AM/PM", "A/P" or "AMPM".
isMilliSec is true if the string ends with a "z". }
function IsTimeFormat(s: String; out isLong, isAMPM, isMillisec: Boolean): Boolean;
var
p, i, count: Integer;
begin
// Time parts are separated by a colon
p := pos(':', s);
isLong := false;
isAMPM := false;
result := p > 0;
if Result then begin
count := 1;
s := Uppercase(s);
// If there are is a second colon s is a "long" time format
for i:=p+1 to Length(s) do
if s[i] = ':' then begin
isLong := true;
break;
end;
// Seek for "AM/PM" etc to detect that specific format
isAMPM := (pos('AM/PM', s) > 0) or (pos('A/P', s) > 0) or (pos('AMPM', s) > 0);
// Look for the "milliseconds" character z
isMilliSec := (s[Length(s)] = 'Z');
// Check validity of format string
try
FormatDateTime(s, now);
except on EConvertError do
Result := false;
end;
end;
end;
end.