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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,307 +1,308 @@
{ This is an automatically generated lazarus resource file } { This is an automatically generated lazarus resource file }
LazarusResources.Add('TForm1','FORMDATA',[ 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' 'TPF0'#6'TForm1'#5'Form1'#4'Left'#3'g'#1#6'Height'#3'Q'#2#3'Top'#3#193#0#5'Wi'
+'th'#3'|'#2#7'Caption'#6#7'fpsGrid'#12'ClientHeight'#3#130#1#11'ClientWidth' +'dth'#3#210#2#7'Caption'#6#7'fpsGrid'#12'ClientHeight'#3'8'#2#11'ClientWidth'
+#3'|'#2#4'Menu'#7#9'MainMenu1'#10'OnActivate'#7#12'FormActivate'#8'OnCreate' +#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' +#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' +#4'Left'#2#0#6'Height'#2'L'#3'Top'#3#236#1#5'Width'#3#210#2#5'Align'#7#8'alB'
+'tom'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'I'#11'ClientWidth'#3'|'#2 +'ottom'#10'BevelOuter'#7#6'bvNone'#12'ClientHeight'#2'L'#11'ClientWidth'#3
+#8'TabOrder'#2#0#0#9'TCheckBox'#13'CbShowHeaders'#4'Left'#2#8#6'Height'#2#19 +#210#2#8'TabOrder'#2#0#0#9'TCheckBox'#13'CbShowHeaders'#4'Left'#2#8#6'Height'
+#3'Top'#2#11#5'Width'#2']'#7'Caption'#6#12'Show headers'#7'Checked'#9#7'OnCl' +#2#24#3'Top'#2#11#5'Width'#2't'#7'Caption'#6#12'Show headers'#7'Checked'#9#7
+'ick'#7#18'CbShowHeadersClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#0#0#0#9 +'OnClick'#7#18'CbShowHeadersClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#0#0
+'TCheckBox'#15'CbShowGridLines'#4'Left'#2#8#6'Height'#2#19#3'Top'#2'$'#5'Wid' +#0#9'TCheckBox'#15'CbShowGridLines'#4'Left'#2#8#6'Height'#2#24#3'Top'#2'$'#5
+'th'#2'd'#7'Caption'#6#15'Show grid lines'#7'Checked'#9#7'OnClick'#7#20'CbSh' +'Width'#2'}'#7'Caption'#6#15'Show grid lines'#7'Checked'#9#7'OnClick'#7#20'C'
+'owGridLinesClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#1#0#0#9'TSpinEdit' +'bShowGridLinesClick'#5'State'#7#9'cbChecked'#8'TabOrder'#2#1#0#0#9'TSpinEdi'
+#12'EdFrozenCols'#4'Left'#3#238#0#6'Height'#2#23#3'Top'#2#8#5'Width'#2'4'#8 +'t'#12'EdFrozenCols'#4'Left'#3#238#0#6'Height'#2#28#3'Top'#2#8#5'Width'#2'4'
+'OnChange'#7#18'EdFrozenColsChange'#8'TabOrder'#2#2#0#0#9'TSpinEdit'#12'EdFr' +#8'OnChange'#7#18'EdFrozenColsChange'#8'TabOrder'#2#2#0#0#9'TSpinEdit'#12'Ed'
+'ozenRows'#4'Left'#3#238#0#6'Height'#2#23#3'Top'#2''''#5'Width'#2'4'#8'OnCha' +'FrozenRows'#4'Left'#3#238#0#6'Height'#2#28#3'Top'#2''''#5'Width'#2'4'#8'OnC'
+'nge'#7#18'EdFrozenRowsChange'#8'TabOrder'#2#3#0#0#6'TLabel'#6'Label1'#4'Lef' +'hange'#7#18'EdFrozenRowsChange'#8'TabOrder'#2#3#0#0#6'TLabel'#6'Label1'#4'L'
+'t'#3#152#0#6'Height'#2#15#3'Top'#2#13#5'Width'#2'>'#7'Caption'#6#12'Frozen ' +'eft'#3#152#0#6'Height'#2#20#3'Top'#2#13#5'Width'#2'M'#7'Caption'#6#12'Froze'
+'cols:'#12'FocusControl'#7#12'EdFrozenCols'#11'ParentColor'#8#0#0#6'TLabel'#6 +'n cols:'#12'FocusControl'#7#12'EdFrozenCols'#11'ParentColor'#8#0#0#6'TLabel'
+'Label2'#4'Left'#3#153#0#6'Height'#2#15#3'Top'#2'('#5'Width'#2'B'#7'Caption' +#6'Label2'#4'Left'#3#153#0#6'Height'#2#20#3'Top'#2'('#5'Width'#2'R'#7'Captio'
+#6#12'Frozen rows:'#12'FocusControl'#7#12'EdFrozenRows'#11'ParentColor'#8#0#0 +'n'#6#12'Frozen rows:'#12'FocusControl'#7#12'EdFrozenRows'#11'ParentColor'#8
+#0#12'TPageControl'#12'PageControl1'#4'Left'#2#0#6'Height'#3#4#1#3'Top'#2'5' +#0#0#0#12'TPageControl'#12'PageControl1'#4'Left'#2#0#6'Height'#3#183#1#3'Top'
+#5'Width'#3'|'#2#10'ActivePage'#7#9'TabSheet1'#5'Align'#7#8'alClient'#8'TabI' +#2'5'#5'Width'#3#210#2#10'ActivePage'#7#9'TabSheet1'#5'Align'#7#8'alClient'#8
+'ndex'#2#0#8'TabOrder'#2#1#8'OnChange'#7#18'PageControl1Change'#0#9'TTabShee' +'TabIndex'#2#0#8'TabOrder'#2#1#8'OnChange'#7#18'PageControl1Change'#0#9'TTab'
+'t'#9'TabSheet1'#7'Caption'#6#6'Sheet1'#12'ClientHeight'#3#232#0#11'ClientWi' +'Sheet'#9'TabSheet1'#7'Caption'#6#6'Sheet1'#12'ClientHeight'#3#150#1#11'Clie'
+'dth'#3't'#2#0#15'TsWorksheetGrid'#15'sWorksheetGrid1'#4'Left'#2#0#6'Height' +'ntWidth'#3#202#2#0#15'TsWorksheetGrid'#15'sWorksheetGrid1'#4'Left'#2#0#6'He'
+#3#232#0#3'Top'#2#0#5'Width'#3't'#2#10'FrozenCols'#2#0#10'FrozenRows'#2#0#5 +'ight'#3#150#1#3'Top'#2#0#5'Width'#3#202#2#10'FrozenCols'#2#0#10'FrozenRows'
+'Align'#7#8'alClient'#8'ColCount'#2#2#14'ExtendedSelect'#8#7'Options'#11#15 +#2#0#5'Align'#7#8'alClient'#8'ColCount'#2#2#14'ExtendedSelect'#8#7'Options'
+'goFixedVertLine'#15'goFixedHorzLine'#10'goVertLine'#10'goHorzLine'#13'goRan' +#11#15'goFixedVertLine'#15'goFixedHorzLine'#10'goVertLine'#10'goHorzLine'#13
+'geSelect'#11'goRowSizing'#11'goColSizing'#15'goThumbTracking'#14'goSmoothSc' +'goRangeSelect'#11'goRowSizing'#11'goColSizing'#15'goThumbTracking'#14'goSmo'
+'roll'#16'goFixedColSizing'#0#8'RowCount'#2#2#8'TabOrder'#2#0#10'TitleStyle' +'othScroll'#16'goFixedColSizing'#0#8'RowCount'#2#2#8'TabOrder'#2#0#10'TitleS'
+#7#8'tsNative'#11'OnSelection'#7#24'sWorksheetGrid1Selection'#9'ColWidths'#1 +'tyle'#7#8'tsNative'#11'OnSelection'#7#24'sWorksheetGrid1Selection'#9'ColWid'
+#2'*'#2'@'#0#0#0#0#0#8'TToolBar'#8'ToolBar1'#4'Left'#2#0#6'Height'#2#26#3'To' +'ths'#1#2'8'#2'@'#0#0#0#0#0#8'TToolBar'#8'ToolBar1'#4'Left'#2#0#6'Height'#2
+'p'#2#0#5'Width'#3'|'#2#12'ButtonHeight'#2#24#7'Caption'#6#8'ToolBar1'#11'Ed' +#26#3'Top'#2#0#5'Width'#3#210#2#12'ButtonHeight'#2#24#7'Caption'#6#8'ToolBar'
+'geBorders'#11#0#6'Images'#7#10'ImageList1'#8'TabOrder'#2#2#0#11'TToolButton' +'1'#11'EdgeBorders'#11#0#6'Images'#7#10'ImageList1'#8'TabOrder'#2#2#0#11'TTo'
+#11'ToolButton1'#4'Left'#2#1#3'Top'#2#0#6'Action'#7#6'AcOpen'#0#0#11'TToolBu' +'olButton'#11'ToolButton1'#4'Left'#2#1#3'Top'#2#0#6'Action'#7#6'AcOpen'#0#0
+'tton'#11'ToolButton2'#4'Left'#2#24#3'Top'#2#0#6'Action'#7#8'AcSaveAs'#0#0#11 +#11'TToolButton'#11'ToolButton2'#4'Left'#2#24#3'Top'#2#0#6'Action'#7#8'AcSav'
+'TToolButton'#11'ToolButton3'#4'Left'#2'P'#3'Top'#2#0#6'Action'#7#6'AcQuit'#0 +'eAs'#0#0#11'TToolButton'#11'ToolButton3'#4'Left'#2'P'#3'Top'#2#0#6'Action'#7
+#0#11'TToolButton'#11'ToolButton5'#4'Left'#2'/'#3'Top'#2#0#5'Width'#2#5#7'Ca' +#6'AcQuit'#0#0#11'TToolButton'#11'ToolButton5'#4'Left'#2'/'#3'Top'#2#0#5'Wid'
+'ption'#6#11'ToolButton5'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#11'T' +'th'#2#5#7'Caption'#6#11'ToolButton5'#5'Style'#7#10'tbsDivider'#0#0#11'TTool'
+'oolButton4'#4'Left'#2'4'#3'Top'#2#0#6'Action'#7#6'AcEdit'#0#0#11'TToolButto' +'Button'#11'ToolButton4'#4'Left'#2'4'#3'Top'#2#0#6'Action'#7#6'AcEdit'#0#0#11
+'n'#11'ToolButton6'#4'Left'#2'K'#3'Top'#2#0#5'Width'#2#5#7'Caption'#6#11'Too' +'TToolButton'#11'ToolButton6'#4'Left'#2'K'#3'Top'#2#0#5'Width'#2#5#7'Caption'
+'lButton6'#5'Style'#7#10'tbsDivider'#0#0#0#8'TToolBar'#13'FormatToolBar'#4'L' +#6#11'ToolButton6'#5'Style'#7#10'tbsDivider'#0#0#0#8'TToolBar'#13'FormatTool'
+'eft'#2#0#6'Height'#2#27#3'Top'#2#26#5'Width'#3'|'#2#12'ButtonHeight'#2#23#7 +'Bar'#4'Left'#2#0#6'Height'#2#27#3'Top'#2#26#5'Width'#3#210#2#12'ButtonHeigh'
+'Caption'#6#13'FormatToolBar'#6'Images'#7#10'ImageList1'#8'TabOrder'#2#3#0#11 +'t'#2#23#7'Caption'#6#13'FormatToolBar'#6'Images'#7#10'ImageList1'#8'TabOrde'
+'TToolButton'#12'ToolButton10'#4'Left'#3'('#1#3'Top'#2#2#6'Action'#7#11'AcLe' +'r'#2#3#0#11'TToolButton'#12'ToolButton10'#4'Left'#3'('#1#3'Top'#2#2#6'Actio'
+'ftAlign'#0#0#11'TToolButton'#12'ToolButton12'#4'Left'#3'?'#1#3'Top'#2#2#6'A' +'n'#7#11'AcLeftAlign'#0#0#11'TToolButton'#12'ToolButton12'#4'Left'#3'?'#1#3
+'ction'#7#16'AcHorCenterAlign'#0#0#11'TToolButton'#12'ToolButton13'#4'Left'#3 +'Top'#2#2#6'Action'#7#16'AcHorCenterAlign'#0#0#11'TToolButton'#12'ToolButton'
+'V'#1#3'Top'#2#2#6'Action'#7#12'AcRightAlign'#0#0#9'TComboBox'#12'FontComboB' +'13'#4'Left'#3'V'#1#3'Top'#2#2#6'Action'#7#12'AcRightAlign'#0#0#9'TComboBox'
+'ox'#4'Left'#2#24#6'Height'#2#23#3'Top'#2#2#5'Width'#2#127#10'ItemHeight'#2 +#12'FontComboBox'#4'Left'#2#24#6'Height'#2#28#3'Top'#2#2#5'Width'#2#127#10'I'
+#15#8'OnSelect'#7#18'FontComboBoxSelect'#8'TabOrder'#2#0#0#0#9'TComboBox'#16 +'temHeight'#2#20#8'OnSelect'#7#18'FontComboBoxSelect'#8'TabOrder'#2#0#0#0#9
+'FontSizeComboBox'#4'Left'#3#151#0#6'Height'#2#23#3'Top'#2#2#5'Width'#2'0'#10 +'TComboBox'#16'FontSizeComboBox'#4'Left'#3#151#0#6'Height'#2#28#3'Top'#2#2#5
+'ItemHeight'#2#15#13'Items.Strings'#1#6#1'8'#6#1'9'#6#2'10'#6#2'11'#6#2'12'#6 +'Width'#2'0'#10'ItemHeight'#2#20#13'Items.Strings'#1#6#1'8'#6#1'9'#6#2'10'#6
+#2'14'#6#2'16'#6#2'18'#6#2'20'#6#2'24'#0#8'OnSelect'#7#22'FontSizeComboBoxSe' +#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'
+'lect'#8'TabOrder'#2#1#0#0#11'TToolButton'#11'ToolButton7'#4'Left'#3#199#0#3 +'ntSizeComboBoxSelect'#8'TabOrder'#2#1#0#0#11'TToolButton'#11'ToolButton7'#4
+'Top'#2#2#6'Action'#7#10'AcFontBold'#0#0#11'TToolButton'#11'ToolButton8'#4'L' +'Left'#3#199#0#3'Top'#2#2#6'Action'#7#10'AcFontBold'#0#0#11'TToolButton'#11
+'eft'#3#222#0#3'Top'#2#2#6'Action'#7#12'AcFontItalic'#0#0#11'TToolButton'#11 +'ToolButton8'#4'Left'#3#222#0#3'Top'#2#2#6'Action'#7#12'AcFontItalic'#0#0#11
+'ToolButton9'#4'Left'#3#245#0#3'Top'#2#2#6'Action'#7#15'AcFontUnderline'#0#0 +'TToolButton'#11'ToolButton9'#4'Left'#3#245#0#3'Top'#2#2#6'Action'#7#15'AcFo'
+#11'TToolButton'#12'ToolButton11'#4'Left'#3#12#1#3'Top'#2#2#6'Action'#7#15'A' +'ntUnderline'#0#0#11'TToolButton'#12'ToolButton11'#4'Left'#3#12#1#3'Top'#2#2
+'cFontStrikeout'#0#0#11'TToolButton'#12'ToolButton14'#4'Left'#3'#'#1#3'Top'#2 +#6'Action'#7#15'AcFontStrikeout'#0#0#11'TToolButton'#12'ToolButton14'#4'Left'
+#2#5'Width'#2#5#7'Caption'#6#12'ToolButton14'#5'Style'#7#10'tbsDivider'#0#0 +#3'#'#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButton14'#5'Style'#7#10
+#11'TToolButton'#12'ToolButton15'#4'Left'#3'm'#1#3'Top'#2#2#5'Width'#2#5#7'C' +'tbsDivider'#0#0#11'TToolButton'#12'ToolButton15'#4'Left'#3'm'#1#3'Top'#2#2#5
+'aption'#6#12'ToolButton15'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#12 +'Width'#2#5#7'Caption'#6#12'ToolButton15'#5'Style'#7#10'tbsDivider'#0#0#11'T'
+'ToolButton16'#4'Left'#3'r'#1#3'Top'#2#2#6'Action'#7#11'AcVAlignTop'#0#0#11 +'ToolButton'#12'ToolButton16'#4'Left'#3'r'#1#3'Top'#2#2#6'Action'#7#11'AcVAl'
+'TToolButton'#12'ToolButton17'#4'Left'#3#137#1#3'Top'#2#2#6'Action'#7#14'AcV' +'ignTop'#0#0#11'TToolButton'#12'ToolButton17'#4'Left'#3#137#1#3'Top'#2#2#6'A'
,'AlignCenter'#0#0#11'TToolButton'#12'ToolButton18'#4'Left'#3#160#1#3'Top'#2#2 ,'ction'#7#14'AcVAlignCenter'#0#0#11'TToolButton'#12'ToolButton18'#4'Left'#3
+#6'Action'#7#14'AcVAlignBottom'#0#0#11'TToolButton'#12'ToolButton19'#4'Left' +#160#1#3'Top'#2#2#6'Action'#7#14'AcVAlignBottom'#0#0#11'TToolButton'#12'Tool'
+#3#183#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButton19'#5'Style'#7#10 +'Button19'#4'Left'#3#183#1#3'Top'#2#2#5'Width'#2#5#7'Caption'#6#12'ToolButto'
+'tbsDivider'#0#0#11'TToolButton'#9'TbBorders'#4'Left'#3#188#1#3'Top'#2#2#6'A' +'n19'#5'Style'#7#10'tbsDivider'#0#0#11'TToolButton'#9'TbBorders'#4'Left'#3
+'ction'#7#12'AcBorderNone'#12'DropdownMenu'#7#16'BordersPopupMenu'#5'Style'#7 +#188#1#3'Top'#2#2#6'Action'#7#12'AcBorderNone'#12'DropdownMenu'#7#16'Borders'
+#11'tbsDropDown'#0#0#9'TColorBox'#17'CbBackgroundColor'#4'Left'#3#223#1#6'He' +'PopupMenu'#5'Style'#7#11'tbsDropDown'#0#0#9'TColorBox'#17'CbBackgroundColor'
+'ight'#2#22#3'Top'#2#2#5'Width'#3#132#0#5'Style'#11#13'cbPrettyNames'#14'cbC' +#4'Left'#3#223#1#6'Height'#2#22#3'Top'#2#2#5'Width'#3#132#0#5'Style'#11#13'c'
+'ustomColors'#0#11'OnGetColors'#7#26'CbBackgroundColorGetColors'#10'ItemHeig' +'bPrettyNames'#14'cbCustomColors'#0#11'OnGetColors'#7#26'CbBackgroundColorGe'
+'ht'#2#16#8'OnSelect'#7#23'CbBackgroundColorSelect'#8'TabOrder'#2#2#0#0#11'T' +'tColors'#10'ItemHeight'#2#16#8'OnSelect'#7#23'CbBackgroundColorSelect'#8'Ta'
+'ToolButton'#12'ToolButton21'#4'Left'#2#1#3'Top'#2#2#6'Action'#7#6'AcFont'#0 +'bOrder'#2#2#0#0#11'TToolButton'#12'ToolButton21'#4'Left'#2#1#3'Top'#2#2#6'A'
+#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4'.xls'#6'Filter'#6#192 +'ction'#7#6'AcFont'#0#0#0#11'TOpenDialog'#11'OpenDialog1'#10'DefaultExt'#6#4
+'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlxs|Libre' +'.xls'#6'Filter'#6#192'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet'
+'Office/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (pipes) (.wikitable_p' +' (*.xlsx)|*.xlxs|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable'
+'ipes)|.wikitable_pipes|All files (*.*)|*.*'#7'Options'#11#20'ofExtensionDif' +' (pipes) (.wikitable_pipes)|.wikitable_pipes|All files (*.*)|*.*'#7'Options'
+'ferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#2'@'#3'top'#3#176#0#0 +#11#20'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#2
+#0#11'TSaveDialog'#11'SaveDialog1'#10'DefaultExt'#6#4'.xls'#6'Filter'#6#185 +'@'#3'top'#3#176#0#0#0#11'TSaveDialog'#11'SaveDialog1'#10'DefaultExt'#6#4'.x'
+'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet (*.xlsx)|*.xlsx|Libre' +'ls'#6'Filter'#6#185'Excel spreadsheet (*.xls)|*.xls|Excel XML spreadsheet ('
+'Office/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable (wikimedia) (.wikitab' +'*.xlsx)|*.xlsx|LibreOffice/OpenOffice spreadsheet (*.ods)|*.ods|Wikitable ('
+'le_wikimedia)|*.wikitable_wikimedia'#7'Options'#11#17'ofOverwritePrompt'#20 +'wikimedia) (.wikitable_wikimedia)|*.wikitable_wikimedia'#7'Options'#11#17'o'
+'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDetail'#0#4'left'#3#176#0 +'fOverwritePrompt'#20'ofExtensionDifferent'#14'ofEnableSizing'#12'ofViewDeta'
+#3'top'#3#176#0#0#0#9'TMainMenu'#9'MainMenu1'#6'Images'#7#10'ImageList1'#4'l' +'il'#0#4'left'#3#176#0#3'top'#3#176#0#0#0#9'TMainMenu'#9'MainMenu1'#6'Images'
+'eft'#3' '#1#3'top'#2'@'#0#9'TMenuItem'#7'mnuFile'#7'Caption'#6#5'&File'#0#9 +#7#10'ImageList1'#4'left'#3' '#1#3'top'#2'@'#0#9'TMenuItem'#7'mnuFile'#7'Cap'
+'TMenuItem'#7'mnuOpen'#6'Action'#7#6'AcOpen'#11'Bitmap.Data'#10':'#4#0#0'6'#4 +'tion'#6#5'&File'#0#9'TMenuItem'#7'mnuOpen'#6'Action'#7#6'AcOpen'#11'Bitmap.'
+#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 +'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#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 +#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
+#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136 +#0'-'#136#216#247'-'#135#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247
+#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#135#216#247'-'#136 +'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247'-'#136#216#247
+#216#247','#134#216#0#255#255#255#0#255#255#255#0'3'#142#217#251#220#240#250 +'-'#135#216#247'-'#136#216#247','#134#216#0#255#255#255#0#255#255#255#0'3'
+#255#152#225#246#255#149#224#246#255#146#223#246#255#142#222#245#255#137#220 +#142#217#251#220#240#250#255#152#225#246#255#149#224#246#255#146#223#246#255
+#245#255#133#218#244#255#128#217#244#255'z'#215#243#255't'#213#243#255'p'#211 +#142#222#245#255#137#220#245#255#133#218#244#255#128#217#244#255'z'#215#243
+#242#255#194#234#248#255'5'#148#218#255#255#255#255#0#255#255#255#0'5'#148 +#255't'#213#243#255'p'#211#242#255#194#234#248#255'5'#148#218#255#255#255#255
+#218#247#239#250#254#255#147#229#248#255#143#228#248#255#137#227#248#255#130 +#0#255#255#255#0'5'#148#218#247#239#250#254#255#147#229#248#255#143#228#248
+#225#247#255'z'#223#247#255'q'#222#246#255'g'#219#245#255'['#216#244#255'M' +#255#137#227#248#255#130#225#247#255'z'#223#247#255'q'#222#246#255'g'#219#245
+#212#243#255'@'#209#242#255#202#242#251#255'5'#148#218#255#255#255#255#0#255 +#255'['#216#244#255'M'#212#243#255'@'#209#242#255#202#242#251#255'5'#148#218
+#255#255#0'6'#154#218#248#242#250#253#255#148#230#248#255#146#229#248#255#144 +#255#255#255#255#0#255#255#255#0'6'#154#218#248#242#250#253#255#148#230#248
+#229#248#255#139#227#248#255#134#226#247#255#127#225#247#255'w'#222#246#255 +#255#146#229#248#255#144#229#248#255#139#227#248#255#134#226#247#255#127#225
+'l'#220#246#255'^'#217#244#255'O'#213#243#255#204#242#251#255'5'#148#218#255 +#247#255'w'#222#246#255'l'#220#246#255'^'#217#244#255'O'#213#243#255#204#242
+#255#255#255#0#255#255#255#0'6'#161#218#249#246#252#254#255#148#229#248#255 +#251#255'5'#148#218#255#255#255#255#0#255#255#255#0'6'#161#218#249#246#252
+#147#229#248#255#147#229#248#255#145#229#248#255#147#219#233#255#147#215#227 +#254#255#148#229#248#255#147#229#248#255#147#229#248#255#145#229#248#255#147
+#255#147#210#220#255#144#206#215#255#140#200#207#255#134#193#198#255#201#216 +#219#233#255#147#215#227#255#147#210#220#255#144#206#215#255#140#200#207#255
+#214#255'5'#148#218#255#197'tD'#232#202#127'S'#241'7'#166#218#250#254#255#255 +#134#193#198#255#201#216#214#255'5'#148#218#255#197'tD'#232#202#127'S'#241'7'
+#255#248#253#255#255#246#253#255#255#245#252#255#255#243#252#254#255#154#228 +#166#218#250#254#255#255#255#248#253#255#255#246#253#255#255#245#252#255#255
+#244#255#154#230#247#255#155#230#246#255#157#229#245#255#158#229#245#255#159 +#243#252#254#255#154#228#244#255#154#230#247#255#155#230#246#255#157#229#245
+#229#244#255#218#243#248#255'5'#148#218#255#253#244#238#255#202#128'T'#249'5' +#255#158#229#245#255#159#229#244#255#218#243#248#255'5'#148#218#255#253#244
+#171#218#250#232#246#251#255'p'#188#231#255'U'#170#226#255'M'#165#224#255#145 +#238#255#202#128'T'#249'5'#171#218#250#232#246#251#255'p'#188#231#255'U'#170
+#201#235#255#250#243#239#255#253#254#253#255#255#253#252#255#255#253#252#255 +#226#255'M'#165#224#255#145#201#235#255#250#243#239#255#253#254#253#255#255
+#254#253#252#255#254#252#251#255#254#254#253#255'5'#148#218#255#239#242#232 +#253#252#255#255#253#252#255#254#253#252#255#254#252#251#255#254#254#253#255
+#255#206#129'V'#255'6'#170#218#242#241#250#253#255#148#222#245#255#147#220 +'5'#148#218#255#239#242#232#255#206#129'V'#255'6'#170#218#242#241#250#253#255
+#244#255'd'#188#233#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148 +#148#222#245#255#147#220#244#255'd'#188#233#255'5'#148#218#255'5'#148#218#255
+#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148 +'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255'5'#148#218#255
+#218#255#251#246#239#255#204#131'U'#254'5'#175#218#240#247#252#254#255#142 +'5'#148#218#255'5'#148#218#255#251#246#239#255#204#131'U'#254'5'#175#218#240
+#228#248#255#145#222#245#255#159#224#245#255#172#225#246#255#202#132'R'#255 +#247#252#254#255#142#228#248#255#145#222#245#255#159#224#245#255#172#225#246
+#255#247#241#255#255#233#217#255#255#234#219#255#255#233#217#255#255#231#215 +#255#202#132'R'#255#255#247#241#255#255#233#217#255#255#234#219#255#255#233
+#255#255#229#210#255#255#226#203#255#255#247#241#255#203#133'U'#254'6'#179 +#217#255#255#231#215#255#255#229#210#255#255#226#203#255#255#247#241#255#203
+#218#248#253#254#254#255#254#255#255#255#254#254#255#255#253#254#255#255#254 +#133'U'#254'6'#179#218#248#253#254#254#255#254#255#255#255#254#254#255#255
+#255#255#255#228#186#145#255#255#247#240#255#255#231#213#255#253#231#214#255 +#253#254#255#255#254#255#255#255#228#186#145#255#255#247#240#255#255#231#213
+#253#230#212#255#252#228#208#255#251#227#203#255#250#220#194#255#254#243#232 +#255#253#231#214#255#253#230#212#255#252#228#208#255#251#227#203#255#250#220
+#255#204#134'V'#254'4'#180#217#208'^'#194#225#250'`'#195#226#250'`'#195#226 +#194#255#254#243#232#255#204#134'V'#254'4'#180#217#208'^'#194#225#250'`'#195
+#250'`'#195#226#250'_'#195#226#250#228#187#145#255#255#247#242#255#254#231 +#226#250'`'#195#226#250'`'#195#226#250'_'#195#226#250#228#187#145#255#255#247
+#213#255#254#231#213#255#253#229#209#255#250#224#202#255#249#222#196#255#247 +#242#255#254#231#213#255#254#231#213#255#253#229#209#255#250#224#202#255#249
+#217#188#255#253#242#231#255#204#135'W'#254#255#255#255#0#255#255#255#0#255 +#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#228#187#146#255#254#247 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187
+#241#255#252#229#210#255#252#228#209#255#251#226#204#255#249#221#196#255#246 +#146#255#254#247#241#255#252#229#210#255#252#228#209#255#251#226#204#255#249
+#215#187#255#243#209#175#255#250#239#228#255#204#135'X'#254#255#255#255#0#255 +#221#196#255#246#215#187#255#243#209#175#255#250#239#228#255#204#135'X'#254
,#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#228#187 ,#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+#146#255#254#246#240#255#252#226#205#255#252#227#205#255#250#223#200#255#247 +#255#255#0#228#187#146#255#254#246#240#255#252#226#205#255#252#227#205#255
+#217#188#255#245#233#221#255#250#243#235#255#251#248#243#255#202#131'S'#254 +#250#223#200#255#247#217#188#255#245#233#221#255#250#243#235#255#251#248#243
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#202#131'S'#254#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#0#228#187#147#255#254#245#237#255#252#222#197#255#251#224#199#255 +#255#255#255#0#255#255#255#0#228#187#147#255#254#245#237#255#252#222#197#255
+#249#220#194#255#245#211#180#255#254#249#243#255#250#226#196#255#236#193#147 +#251#224#199#255#249#220#194#255#245#211#180#255#254#249#243#255#250#226#196
+#255#195'}H'#147#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#255#236#193#147#255#195'}H'#147#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#0#255#255#255#0#229#190#150#255#255#255#254#255#253#243#233#255#253 +#255#255#255#0#255#255#255#0#255#255#255#0#229#190#150#255#255#255#254#255
+#243#234#255#252#242#232#255#250#239#227#255#250#242#231#255#234#187#136#255 +#253#243#233#255#253#243#234#255#252#242#232#255#250#239#227#255#250#242#231
+#207#133'U'#179#180'i='#12#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#255#234#187#136#255#207#133'U'#179#180'i='#12#255#255#255#0#255#255#255#0
+#255#0#255#255#255#0#255#255#255#0#234#195#157#255#230#191#150#255#228#187 +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#234#195#157#255#230
+#146#255#228#187#146#255#209#160'l'#245#208#158'm'#246#204#150'_'#218#196'yB' +#191#150#255#228#187#146#255#228#187#146#255#209#160'l'#245#208#158'm'#246
+'~'#178'g<'#9#255#255#255#0#7'OnClick'#7#13'acOpenExecute'#0#0#9'TMenuItem'#9 +#204#150'_'#218#196'yB~'#178'g<'#9#255#255#255#0#7'OnClick'#7#13'acOpenExecu'
+'mnuSaveAs'#6'Action'#7#8'AcSaveAs'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6' +'te'#0#0#9'TMenuItem'#9'mnuSaveAs'#6'Action'#7#8'AcSaveAs'#11'Bitmap.Data'#10
+#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 +':'#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
+'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' +' '#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
+#255#181'h5'#255#180'g4'#255#178'f4'#255#176'e3'#255#174'd3'#255#172'c2'#255 +#184'i5'#238#183'h5'#255#181'h5'#255#180'g4'#255#178'f4'#255#176'e3'#255#174
+#170'b2'#255#169'a2'#255#168'`1'#255#167'`1'#254#166'`1'#241#168'a1'#196#186 +'d3'#255#172'c2'#255#170'b2'#255#169'a2'#255#168'`1'#255#167'`1'#254#166'`1'
+'j5'#222#235#198#173#255#234#197#173#255#254#251#248#255#254#251#248#255#254 +#241#168'a1'#196#186'j5'#222#235#198#173#255#234#197#173#255#254#251#248#255
+#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
+#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248 +#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#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#200#154
+#255#187'j6'#255#240#210#190#255#226#163'z'#255#226#163'z'#255#225#163'z'#255 +'|'#255#199#152'y'#255#167'`1'#237#186'k7'#254#237#202#179#255#224#162'z'#255
+#226#163'{'#255#225#163'{'#255#224#161'x'#255#222#159'w'#255#221#159'v'#255 +#254#250#247#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+#220#157't'#255#217#155'r'#255#216#153'q'#255#214#153'p'#255#213#171#142#255 +'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255#253#249#246#255
+#173'c3'#255#187'j6'#255#242#213#194#255#227#163'z'#255#227#163'z'#255#226 +#202#141'e'#255#201#155'|'#255#167'`1'#254#187'l8'#255#238#204#182#255#225
+#163'{'#255#226#163'{'#255#226#164'{'#255#225#162'y'#255#224#161'x'#255#222 +#162'z'#255#254#250#247#255#191#220#194#255#191#220#194#255#191#220#194#255
+#160'w'#255#222#158'u'#255#220#157't'#255#218#155's'#255#217#155's'#255#218 +#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194#255#191#220#194
+#176#149#255#175'd3'#255#187'j6'#255#242#216#197#255#227#164'{'#255#227#163 +#255#253#249#246#255#205#144'h'#255#204#158#129#255#168'a2'#255#187'k8'#255
+'z'#255#227#164'z'#255#226#164'{'#255#226#163'{'#255#225#163'{'#255#225#162 +#239#206#184#255#225#162'y'#255#254#250#247#255'b'#192#136#255'b'#192#136#255
+'y'#255#223#160'w'#255#222#159'v'#255#221#158't'#255#219#156'r'#255#220#157 +'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255'b'#192#136#255
+'t'#255#221#181#154#255#177'e4'#255#187'k6'#255#244#217#199#255#230#166'}' +'b'#192#136#255#253#249#246#255#207#147'j'#255#206#163#132#255#170'a2'#255
+#255#200#140'd'#255#201#141'e'#255#201#142'g'#255#203#146'l'#255#203#146'm' +#186'j6'#255#239#208#187#255#226#162'z'#255#254#251#248#255#254#251#248#255
+#255#202#144'i'#255#200#140'e'#255#200#140'd'#255#200#140'd'#255#200#140'd' +#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248#255#254#251#248
+#255#218#156't'#255#225#186#159#255#179'f4'#255#187'k6'#254#244#220#201#255 +#255#254#251#248#255#254#251#248#255#254#251#248#255#211#150'm'#255#210#167
+#231#167'}'#255#249#236#225#255#249#236#225#255#249#237#227#255#252#244#238 +#138#255#171'b2'#255#187'j6'#255#240#210#190#255#226#163'z'#255#226#163'z'
+#255#253#250#247#255#253#247#243#255#250#237#229#255#247#231#219#255#247#229 +#255#225#163'z'#255#226#163'{'#255#225#163'{'#255#224#161'x'#255#222#159'w'
+#217#255#246#229#216#255#222#160'w'#255#228#190#164#255#180'g4'#255#188'k6' +#255#221#159'v'#255#220#157't'#255#217#155'r'#255#216#153'q'#255#214#153'p'
+#250#245#221#204#255#231#168'~'#255#250#240#232#255#250#240#232#255#201#141 +#255#213#171#142#255#173'c3'#255#187'j6'#255#242#213#194#255#227#163'z'#255
+'f'#255#250#240#233#255#253#248#243#255#254#250#248#255#252#244#239#255#249 +#227#163'z'#255#226#163'{'#255#226#163'{'#255#226#164'{'#255#225#162'y'#255
+#233#223#255#247#231#219#255#247#229#217#255#224#162'x'#255#231#194#169#255 +#224#161'x'#255#222#160'w'#255#222#158'u'#255#220#157't'#255#218#155's'#255
+#182'h5'#255#188'k6'#240#246#223#208#255#232#168'~'#255#252#246#241#255#252 +#217#155's'#255#218#176#149#255#175'd3'#255#187'j6'#255#242#216#197#255#227
+#246#241#255#200#140'd'#255#250#241#233#255#251#244#238#255#253#250#247#255 +#164'{'#255#227#163'z'#255#227#164'z'#255#226#164'{'#255#226#163'{'#255#225
+#253#249#246#255#250#240#232#255#248#232#221#255#247#230#219#255#225#163'z' +#163'{'#255#225#162'y'#255#223#160'w'#255#222#159'v'#255#221#158't'#255#219
+#255#239#213#195#255#183'i5'#254#188'k6'#216#246#223#209#255#233#170#128#255 +#156'r'#255#220#157't'#255#221#181#154#255#177'e4'#255#187'k6'#255#244#217
+#254#250#246#255#253#250#246#255#200#140'd'#255#251#243#238#255#251#241#234 +#199#255#230#166'}'#255#200#140'd'#255#201#141'e'#255#201#142'g'#255#203#146
+#255#252#246#242#255#254#251#248#255#252#246#241#255#249#236#226#255#248#231 +'l'#255#203#146'm'#255#202#144'i'#255#200#140'e'#255#200#140'd'#255#200#140
+#219#255#238#208#186#255#236#208#189#255#187'p>'#248#188'k6'#155#246#224#209 +'d'#255#200#140'd'#255#218#156't'#255#225#186#159#255#179'f4'#255#187'k6'#254
+#255#247#224#209#255#254#251#248#255#254#251#247#255#253#249#246#255#252#245 +#244#220#201#255#231#167'}'#255#249#236#225#255#249#236#225#255#249#237#227
+#240#255#250#240#234#255#251#242#237#255#253#249#246#255#253#250#247#255#251 +#255#252#244#238#255#253#250#247#255#253#247#243#255#250#237#229#255#247#231
+#241#235#255#248#233#223#254#236#208#189#251#201#137'^'#236#181'i5c'#188'k6q' +#219#255#247#229#217#255#246#229#216#255#222#160'w'#255#228#190#164#255#180
+#188'k6'#144#188'k6'#204#188'k6'#238#188'k6'#250#187'k6'#254#187'k6'#255#187 +'g4'#255#188'k6'#250#245#221#204#255#231#168'~'#255#250#240#232#255#250#240
,'j6'#255#187'j6'#255#188'l9'#255#189'n;'#255#187'm:'#255#187'k8'#239#187'p>' +#232#255#201#141'f'#255#250#240#233#255#253#248#243#255#254#250#248#255#252
+#203#182'i5T'#255#255#255#0#7'OnClick'#7#15'acSaveAsExecute'#0#0#9'TMenuItem' +#244#239#255#249#233#223#255#247#231#219#255#247#229#217#255#224#162'x'#255
+#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#7'mnuQuit'#6'Action'#7#6'Ac' +#231#194#169#255#182'h5'#255#188'k6'#240#246#223#208#255#232#168'~'#255#252
+'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 +#246#241#255#252#246#241#255#200#140'd'#255#250#241#233#255#251#244#238#255
+#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 +#253#250#247#255#253#249#246#255#250#240#232#255#248#232#221#255#247#230#219
+#0#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#255#225#163'z'#255#239#213#195#255#183'i5'#254#188'k6'#216#246#223#209#255
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#29'c'#155#22#25'`' +#233#170#128#255#254#250#246#255#253#250#246#255#200#140'd'#255#251#243#238
+#152'9'#20']'#149'b'#16'Z'#146#136#13'X'#144#164#19'\'#146#252#12'W'#143#237 +#255#251#241#234#255#252#246#242#255#254#251#248#255#252#246#241#255#249#236
+#153#153#153#255'qqq'#255'TTT'#255'QQQ'#255'OOO'#255'LLL'#255'JJJ'#255'GGG' +#226#255#248#231#219#255#238#208#186#255#236#208#189#255#187'p>'#248#188'k6'
+#255'EEE'#255'%g'#157#255'2t'#168#255'=|'#175#255'G'#132#181#255'N'#138#186 +#155#246#224#209#255#247#224#209#255#254#251#248#255#254#251#247#255#253#249
+#255'>~'#173#255#12'W'#143#234#255#255#255#0#255#255#255#0'XXX'#255#162#162 +#246#255#252#245#240#255#250#240#234#255#251#242#237#255#253#249#246#255#253
+#162#255#162#162#162#255#163#163#163#255#164#164#164#255#164#164#164#255#165 +#250#247#255#251#241#235#255#248#233#223#254#236#208#189#251#201#137'^'#236
+#165#165#255'/o'#165#255'x'#171#210#255'x'#171#211#255's'#167#209#255'i'#160 +#181'i5c'#188'k6q'#188'k6'#144#188'k6'#204#188'k6'#238#188'k6'#250#187'k6'
+#205#255'@'#127#174#255#15'Y'#145#234#255#255#255#0#255#255#255#0'\\\'#255 ,#254#187'k6'#255#187'j6'#255#187'j6'#255#188'l9'#255#189'n;'#255#187'm:'#255
+#161#161#161#255'<s@'#255#160#161#161#255#163#163#163#255#163#163#163#255#164 +#187'k8'#239#187'p>'#203#182'i5T'#255#255#255#0#7'OnClick'#7#15'acSaveAsExec'
+#164#164#255'6t'#170#255'}'#175#212#255'['#154#201#255'T'#149#199#255'X'#150 +'ute'#0#0#9'TMenuItem'#9'MenuItem1'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#7'mnu'
+#200#255'A'#128#174#255#19'\'#148#234#255#255#255#0#255#255#255#0'```'#255 +'Quit'#6'Action'#7#6'AcQuit'#11'Bitmap.Data'#10':'#4#0#0'6'#4#0#0'BM6'#4#0#0
+#160#160#160#255'=vA'#255'6q9'#255#162#162#162#255#162#162#162#255#163#163 +#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
+#163#255'=y'#176#255#130#179#215#255'b'#159#204#255'Z'#154#201#255'^'#155#202 +#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'C'#129#175#255#25'`'#152#234'7'#130'>'#255'4~;'#255'1y7'#255'.u4'#255'I' +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#145'P'#255'F'#143'L'#255'9s='#255#161#161#161#255#162#162#162#255'E~'#180 +#29'c'#155#22#25'`'#152'9'#20']'#149'b'#16'Z'#146#136#13'X'#144#164#19'\'#146
+#255#136#183#217#255'g'#163#207#255'a'#158#204#255'c'#159#204#255'E'#131#177 +#252#12'W'#143#237#153#153#153#255'qqq'#255'TTT'#255'QQQ'#255'OOO'#255'LLL'
+#255#31'd'#156#234';'#135'B'#255#137#203#146#255#132#200#141#255#128#198#136 +#255'JJJ'#255'GGG'#255'EEE'#255'%g'#157#255'2t'#168#255'=|'#175#255'G'#132
+#255'{'#195#131#255'w'#193#127#255'G'#143'M'#255';t?'#255#161#161#161#255'L' +#181#255'N'#138#186#255'>~'#173#255#12'W'#143#234#255#255#255#0#255#255#255#0
+#132#186#255#141#187#219#255'n'#168#209#255'f'#166#209#255'_'#180#223#255'G' +'XXX'#255#162#162#162#255#162#162#162#255#163#163#163#255#164#164#164#255#164
+#133#177#255'%i'#161#234'>'#139'F'#255#143#206#153#255'}'#198#135#255'x'#195 +#164#164#255#165#165#165#255'/o'#165#255'x'#171#210#255'x'#171#211#255's'#167
+#129#255's'#192'|'#255't'#192'|'#255'y'#194#129#255'I'#144'O'#255'T'#127'W' +#209#255'i'#160#205#255'@'#127#174#255#15'Y'#145#234#255#255#255#0#255#255
+#255'T'#137#191#255#148#191#221#255'u'#173#212#255'c'#184#225#255'K'#212#255 +#255#0'\\\'#255#161#161#161#255'<s@'#255#160#161#161#255#163#163#163#255#163
+#255'B'#139#184#255',n'#166#234'A'#144'J'#255#148#210#159#255#145#208#154#255 +#163#163#255#164#164#164#255'6t'#170#255'}'#175#212#255'['#154#201#255'T'#149
+#141#205#150#255#137#203#146#255#132#200#141#255'Q'#152'X'#255'A|F'#255#159 +#199#255'X'#150#200#255'A'#128#174#255#19'\'#148#234#255#255#255#0#255#255
+#159#159#255'Z'#142#196#255#152#195#224#255'|'#179#215#255't'#175#214#255'^' +#255#0'```'#255#160#160#160#255'=vA'#255'6q9'#255#162#162#162#255#162#162#162
+#196#237#255'K'#136#179#255'4s'#171#234'D'#148'M'#255'B'#145'K'#255'?'#141'H' +#255#163#163#163#255'=y'#176#255#130#179#215#255'b'#159#204#255'Z'#154#201
+#255'='#137'E'#255']'#164'e'#255'Z'#160'a'#255'E'#131'K'#255#158#158#158#255 +#255'^'#155#202#255'C'#129#175#255#25'`'#152#234'7'#130'>'#255'4~;'#255'1y7'
+#158#158#158#255'`'#146#201#255#158#199#226#255#131#184#218#255'}'#180#215 +#255'.u4'#255'I'#145'P'#255'F'#143'L'#255'9s='#255#161#161#161#255#162#162
+#255'~'#179#215#255'O'#137#180#255';y'#177#234#255#255#255#0#255#255#255#0'w' +#162#255'E~'#180#255#136#183#217#255'g'#163#207#255'a'#158#204#255'c'#159#204
+'ww'#255#154#154#154#255'='#138'E'#255'I'#138'O'#255#156#156#156#255#157#157 +#255'E'#131#177#255#31'd'#156#234';'#135'B'#255#137#203#146#255#132#200#141
+#157#255#157#157#157#255'f'#150#204#255#162#203#227#255#137#189#220#255#131 +#255#128#198#136#255'{'#195#131#255'w'#193#127#255'G'#143'M'#255';t?'#255#161
+#185#218#255#132#185#218#255'Q'#139#181#255'C~'#182#234#255#255#255#0#255#255 +#161#161#255'L'#132#186#255#141#187#219#255'n'#168#209#255'f'#166#209#255'_'
+#255#0'zzz'#255#153#153#153#255'R'#145'Y'#255#153#154#153#255#155#155#155#255 +#180#223#255'G'#133#177#255'%i'#161#234'>'#139'F'#255#143#206#153#255'}'#198
+#156#156#156#255#156#156#156#255'l'#154#208#255#167#206#229#255#143#193#223 +#135#255'x'#195#129#255's'#192'|'#255't'#192'|'#255'y'#194#129#255'I'#144'O'
+#255#137#189#220#255#139#189#220#255'S'#141#182#255'K'#132#188#234#255#255 +#255'T'#127'W'#255'T'#137#191#255#148#191#221#255'u'#173#212#255'c'#184#225
+#255#0#255#255#255#0'}}}'#255#153#153#153#255#153#153#153#255#154#154#154#255 +#255'K'#212#255#255'B'#139#184#255',n'#166#234'A'#144'J'#255#148#210#159#255
+#154#154#154#255#155#155#155#255#155#155#155#255'o'#157#211#255#170#209#231 +#145#208#154#255#141#205#150#255#137#203#146#255#132#200#141#255'Q'#152'X'
+#255#171#209#231#255#152#199#225#255#145#194#222#255'V'#143#183#255'R'#137 +#255'A|F'#255#159#159#159#255'Z'#142#196#255#152#195#224#255'|'#179#215#255
+#193#234#255#255#255#0#255#255#255#0#128#128#128#255'~~~'#255'|||'#255'zzz' +'t'#175#214#255'^'#196#237#255'K'#136#179#255'4s'#171#234'D'#148'M'#255'B'
+#255'www'#255'uuu'#255'rrr'#255'q'#158#212#255'o'#158#214#255#135#178#220#255 +#145'K'#255'?'#141'H'#255'='#137'E'#255']'#164'e'#255'Z'#160'a'#255'E'#131'K'
+#171#211#232#255#169#208#230#255'X'#144#184#255'Y'#142#198#234#255#255#255#0 +#255#158#158#158#255#158#158#158#255'`'#146#201#255#158#199#226#255#131#184
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#218#255'}'#180#215#255'~'#179#215#255'O'#137#180#255';y'#177#234#255#255#255
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'p'#158#214 +#0#255#255#255#0'www'#255#154#154#154#255'='#138'E'#255'I'#138'O'#255#156#156
+#219'm'#156#212#255#133#177#218#255'Z'#145#185#255'`'#147#203#234#255#255#255 +#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 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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'`'
+#255#0#255#255#255#0'm'#156#212#137'j'#154#210#251'f'#151#207#238#7'OnClick' +#147#203#234#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#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#0#255#255#255#0#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#255#255#255#0#255#255#255#0#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#255#255#0#255#255#255#0#255#255#255#0'm'#156#212#137'j'#154#210#251'f'
+#255#21'B^'#255'%i'#156#255',v'#180#255';'#139#186#173#255#255#255#0#255#255 +#151#207#238#7'OnClick'#7#13'acQuitExecute'#0#0#0#9'TMenuItem'#7'mnuEdit'#7
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +'Caption'#6#4'Edit'#0#9'TMenuItem'#9'MenuItem2'#6'Action'#7#6'AcEdit'#9'Auto'
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#18'BY'#255']'#156 +'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'('
+#212#255#166#207#245#255#169#207#236#255'H'#139#193#255',v'#180#255#255#255 +#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
,#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#255#255#255#0#255#255#255#0#255#255#255#0#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#255#0#255#255#255#0#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';' +#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 +#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 +#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0''''#144#191
+#195#237#248#255#179#244#252#255'`'#220#245#255'D'#214#244#255#142#238#250 +#255#195#237#248#255#179#244#252#255'`'#220#245#255'D'#214#244#255#142#238
+#255']'#180#230#255';'#143#217#255#255#255#255#0#255#255#255#0#255#255#255#0 +#250#255']'#180#230#255';'#143#217#255#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'/'#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#0#255#255#255#0#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 +#255#255#255#0'/'#186#228#255#195#237#248#255#179#244#252#255'`'#220#245#255
+#203#227#248#255'B'#149#202#255'1'#130#194#174#255#255#255#0#255#255#255#0 +'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#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#255#0#255#255#255#0#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#255#0#255#255#255#0#255#255#255#0#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' +#255#0#255#255#255#0#255#255#255#0#255#255#255#0'P'#168#217#255'j'#165#216
+'mat'#7'Caption'#6#6'Format'#0#9'TMenuItem'#7'MnuFOnt'#6'Action'#7#6'AcFont' +#255#201#225#247#255#203#227#248#255'B'#149#202#255'1'#130#194#174#255#255
+#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 +#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#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'/'#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#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#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#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#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#0#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 +#207'j6\'#223#157'h'#246#218#139'R'#209#203'_1N'#199'Y.*'#205'g7'#160#225#166
+'P+'#141#189'B#'#16#188'?"*'#195'M+'#162#208'qB'#234#214'~Q'#255#213'|M'#255 +'z'#255#216#134'S'#242#191'F%'#13#255#255#255#0#255#255#255#0#255#255#255#0
+#198'U1'#189#182'9'#29'1'#255#255#255#0#255#255#255#0#255#255#255#0#202'\/' +#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#208'j5'#3#215#128'B'
+#10#203'_0D'#225#164'u'#255#218#140'X'#236#198'R,='#255#255#255#0#255#255#255 +#170#223#159'j'#247#205'f4f'#201']/'#10#204'a3'#136#225#166'y'#255#213'zD'
+#0#191'E$'#19#195'H'''#127#220#150'k'#255#219#143'`'#255#189'?!T'#182'8'#30#2 +#210#194'J'''#6#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#203']0'#1#211't?' +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#209'q8"'#222#155'c'#226
+#155#226#169'|'#255#204'f7'#153#255#255#255#0#255#255#255#0#255#255#255#0#204 +#220#150'^'#223#207'i5T'#207'i5'#128#226#169'|'#255#209'l:'#165#255#255#255#0
+'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
+#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#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 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#212'y<w'#226#166'p'#247
+#207'i5T'#207'i5'#128#226#169'|'#255#209'l:'#165#255#255#255#0#255#255#255#0 +#218#136'G'#173#214'~C'#160#228#174#130#255#207'm:'#153#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#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#0#255#255#255#0#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 +#255#255#255#0#255#255#255#0#255#255#255#0#214'};'#28#221#150'V'#186#227#169
+'s'#245#225#164'q'#247#211'w>'#152#203'_0'#8#255#255#255#0#255#255#255#0#255 +'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#255#0#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#0#255#255#255#0#255#255#255#0#215#131'>S'#226#167'l'#222#233#188#145#255
+#255#231#183#139#255#226#164'q'#251#214'~B'#182#203'\/'#10#255#255#255#0#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#255#0#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 +#255#0#255#255#255#0#255#255#255#0#216#135'@@'#216#139'C'#133#218#142'I'#148
+#216#132'@'#144#216#132'A'#154#211's:'#138#204'b2'#13#201'[.'#1#255#255#255#0 +#217#137'C'#143#216#132'@'#144#216#132'A'#154#211's:'#138#204'b2'#13#201'[.'
+#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#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' +#255#255#255#0#0#0#9'TMenuItem'#15'MnuTextRotation'#7'Caption'#6#13'Text rot'
+'nuItem'#10'MenuItem29'#6'Action'#7#11'AcTextHoriz'#9'AutoCheck'#9#0#0#9'TMe' +'ation'#0#9'TMenuItem'#10'MenuItem29'#6'Action'#7#11'AcTextHoriz'#9'AutoChec'
+'nuItem'#10'MenuItem30'#6'Action'#7#12'AcTextVertCW'#9'AutoCheck'#9#0#0#9'TM' +'k'#9#0#0#9'TMenuItem'#10'MenuItem30'#6'Action'#7#12'AcTextVertCW'#9'AutoChe'
+'enuItem'#10'MenuItem31'#6'Action'#7#13'AcTextVertCCW'#9'AutoCheck'#9#0#0#9 +'ck'#9#0#0#9'TMenuItem'#10'MenuItem31'#6'Action'#7#13'AcTextVertCCW'#9'AutoC'
+'TMenuItem'#10'MenuItem32'#6'Action'#7#13'AcTextStacked'#9'AutoCheck'#9#0#0#0 +'heck'#9#0#0#9'TMenuItem'#10'MenuItem32'#6'Action'#7#13'AcTextStacked'#9'Aut'
+#9'TMenuItem'#15'MnuHorAlignment'#7'Caption'#6#20'Horizontal alignment'#0#9 +'oCheck'#9#0#0#0#9'TMenuItem'#15'MnuHorAlignment'#7'Caption'#6#20'Horizontal'
+'TMenuItem'#13'MnuHorDefault'#6'Action'#7#17'AcHorDefaultAlign'#9'AutoCheck' +' alignment'#0#9'TMenuItem'#13'MnuHorDefault'#6'Action'#7#17'AcHorDefaultAli'
+#9#0#0#9'TMenuItem'#9'MenuItem6'#7'Caption'#6#1'-'#0#0#9'TMenuItem'#9'MenuIt' +'gn'#9'AutoCheck'#9#0#0#9'TMenuItem'#9'MenuItem6'#7'Caption'#6#1'-'#0#0#9'TM'
+'em3'#6'Action'#7#11'AcLeftAlign'#9'AutoCheck'#9#11'Bitmap.Data'#10':'#4#0#0 +'enuItem'#9'MenuItem3'#6'Action'#7#11'AcLeftAlign'#9'AutoCheck'#9#11'Bitmap.'
+'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 +'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#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 +#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
+#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#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 +#255#255#255#0'<<<'#255'555'#255'///'#255')))'#255'$$$'#255#30#30#30#255#25
+#20#255#15#15#15#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0 +#25#25#255#20#20#20#255#15#15#15#255#255#255#255#0#255#255#255#0#255#255#255
+#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#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#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0'JJJ'#255'DDD'#255'>'
+#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22#255#17#17#17 +'>>'#255'888'#255'222'#255',,,'#255'&&&'#255' '#255#27#27#27#255#22#22#22
+#255#12#12#12#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255 +#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'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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255
+#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'III' +#255#255#0'XXX'#255'RRR'#255'LLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'..'
+#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0'ooo'#255'kkk'#255'fff'
+'\\'#255'WWW'#255'QQQ'#255'KKK'#255'EEE'#255#255#255#255#0#255#255#255#0#255 +#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#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 +#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'#255'SSS'#255'NNN' +#255#0'vvv'#255'ttt'#255'ppp'#255'lll'#255'hhh'#255'ccc'#255'^^^'#255'YYY'
+#255'HHH'#255'BBB'#255#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255 +#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 +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#30#30#30#255#25#25#25#255#20
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +#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#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#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#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#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#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#255#255#255#0#255#255
+#255#0'RRRkLLL'#255'FFF'#255'@@@'#255':::'#255'444'#255'...'#255'((('#255'##' +#255#0#255#255#255#0#255#255#255#0'FFF'#255'@@@'#255':::'#255'444'#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#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#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#255#255#0#255#255#255#0'ddd'#255'___'#255'ZZZ'#255'TTT'#255'OOO'#255'II'
+'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0#255#255#255#0#255 +'I'#255'CCC'#255'==='#255'777'#255'111'#255'+++'#255'%%%'#255#255#255#255#0
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0
+#255#255#255#0#255#255#255#0#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#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#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#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#255#0#255#255#255#0#255#255#255#0#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#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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#255#255#255#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#255#255#255#0#255#255
+#255#0#255#255#255#0#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#255#255#255#0#255#255#255#0#255#255#255#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
+#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255 +'((('#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
+#255#0#255#255#255#0#255#255#255#0#255#255#255#0#0#0#0#9'TMenuItem'#16'MnuVe' +#3#3#3#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255
+'rtAlignment'#7'Caption'#6#18'Vertical alignment'#0#9'TMenuItem'#14'MnuVertD' +#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255#255#255#0#255
+'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#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#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 ,#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 +'==='#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; TsUsedFormattingFields = set of TsUsedFormattingField;
{@@ Number/cell formatting. Only uses a subset of the default formats, {@@ 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, TsNumberFormat = (nfGeneral, nfFixed, nfFixedTh, nfExp, nfSci, nfPercentage,
nfShortDateTime, nfFmtDateTime, nfShortDate, nfShortTime, nfLongTime, nfShortDateTime, nfFmtDateTime, nfShortDate, nfLongDate, nfShortTime, nfLongTime,
nfShortTimeAM, nfLongTimeAM, nfTimeInterval); nfShortTimeAM, nfLongTimeAM, nfTimeInterval, nfCustom);
{@@ Text rotation formatting. The text is rotated relative to the standard {@@ Text rotation formatting. The text is rotated relative to the standard
orientation, which is from left to right horizontal: orientation, which is from left to right horizontal:
@ -364,14 +365,17 @@ type
{ Writing of values } { Writing of values }
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring); procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double; 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 WriteBlank(ARow, ACol: Cardinal);
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime; procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime;
AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = ''); AFormat: TsNumberFormat = nfShortDateTime; AFormatStr: String = '');
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula); procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula); procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
{ Writing of cell attributes } { 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; function WriteFont(ARow, ACol: Cardinal; const AFontName: String;
AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload; AFontSize: Single; AFontStyle: TsFontStyles; AFontColor: TsColor): Integer; overload;
procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload; procedure WriteFont(ARow, ACol: Cardinal; AFontIndex: Integer); overload;
@ -481,6 +485,50 @@ type
property FileFormat: TsSpreadsheetFormat read FFormat; property FileFormat: TsSpreadsheetFormat read FFormat;
end; 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 } {@@ TsSpreadReader class reference type }
TsSpreadReaderClass = class of TsCustomSpreadReader; TsSpreadReaderClass = class of TsCustomSpreadReader;
@ -491,6 +539,8 @@ type
protected protected
FWorkbook: TsWorkbook; FWorkbook: TsWorkbook;
FWorksheet: TsWorksheet; FWorksheet: TsWorksheet;
FNumFormatList: TsCustomNumFormatList;
procedure CreateNumFormatList; virtual; abstract;
{ Record reading methods } { Record reading methods }
procedure ReadBlank(AStream: TStream); virtual; abstract; procedure ReadBlank(AStream: TStream); virtual; abstract;
procedure ReadFormula(AStream: TStream); virtual; abstract; procedure ReadFormula(AStream: TStream); virtual; abstract;
@ -498,11 +548,13 @@ type
procedure ReadNumber(AStream: TStream); virtual; abstract; procedure ReadNumber(AStream: TStream); virtual; abstract;
public public
constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
destructor Destroy; override;
{ General writing methods } { General writing methods }
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); virtual; procedure ReadFromFile(AFileName: string; AData: TsWorkbook); virtual;
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); virtual; procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); virtual;
procedure ReadFromStrings(AStrings: TStrings; AData: TsWorkbook); virtual; procedure ReadFromStrings(AStrings: TStrings; AData: TsWorkbook); virtual;
property Workbook: TsWorkbook read FWorkbook; property Workbook: TsWorkbook read FWorkbook;
property NumFormatList: TsCustomNumFormatList read FNumFormatList;
end; end;
{@@ TsSpreadWriter class reference type } {@@ TsSpreadWriter class reference type }
@ -517,12 +569,17 @@ type
private private
FWorkbook: TsWorkbook; FWorkbook: TsWorkbook;
protected protected
FNumFormatList: TsCustomNumFormatList;
{ Helper routines } { Helper routines }
procedure AddDefaultFormats(); virtual; procedure AddDefaultFormats(); virtual;
procedure CreateNumFormatList; virtual; abstract;
function ExpandFormula(AFormula: TsFormula): TsExpandedFormula; function ExpandFormula(AFormula: TsFormula): TsExpandedFormula;
function FindFormattingInList(AFormat: PCell): Integer; function FindFormattingInList(AFormat: PCell): Integer;
procedure FixFormat(ACell: PCell); virtual;
procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream); procedure ListAllFormattingStylesCallback(ACell: PCell; AStream: TStream);
procedure ListAllFormattingStyles; procedure ListAllFormattingStyles;
procedure ListAllNumFormatsCallback(ACell: PCell; AStream: TStream);
procedure ListAllNumFormats; virtual;
{ Helpers for writing } { Helpers for writing }
procedure WriteCellCallback(ACell: PCell; AStream: TStream); procedure WriteCellCallback(ACell: PCell; AStream: TStream);
procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree); procedure WriteCellsToStream(AStream: TStream; ACells: TAVLTree);
@ -541,12 +598,14 @@ type
FFormattingStyles: array of TCell; FFormattingStyles: array of TCell;
NextXFIndex: Integer; // Indicates which should be the next XF (Style) Index when filling the styles list 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 constructor Create(AWorkbook: TsWorkbook); virtual; // To allow descendents to override it
destructor Destroy; override;
{ General writing methods } { General writing methods }
procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback); procedure IterateThroughCells(AStream: TStream; ACells: TAVLTree; ACallback: TCellsCallback);
procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual; procedure WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); virtual;
procedure WriteToStream(AStream: TStream); virtual; procedure WriteToStream(AStream: TStream); virtual;
procedure WriteToStrings(AStrings: TStrings); virtual; procedure WriteToStrings(AStrings: TStrings); virtual;
property Workbook: TsWorkbook read FWorkbook; property Workbook: TsWorkbook read FWorkbook;
property NumFormatList: TsCustomNumFormatList read FNumFormatList;
end; end;
{@@ List of registered formats } {@@ List of registered formats }
@ -615,10 +674,6 @@ procedure RegisterSpreadFormat(
AFormat: TsSpreadsheetFormat); AFormat: TsSpreadsheetFormat);
function GetFileFormatName(AFormat: TsSpreadsheetFormat): String; function GetFileFormatName(AFormat: TsSpreadsheetFormat): String;
function SciFloat(AValue: Double; ADecimals: Word): String;
function TimeIntervalToString(AValue: TDateTime): String;
procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer); procedure MakeLEPalette(APalette: PsPalette; APaletteSize: Integer);
implementation implementation
@ -731,50 +786,6 @@ begin
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.
}
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 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 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 TsWorksheet.ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
function FloatToStrNoNaN(const Value: Double; function FloatToStrNoNaN(const Value: Double;
ANumberFormat: TsNumberFormat; ANumberFormatStr: ansistring): ansistring; ANumberFormat: TsNumberFormat; ANumberFormatStr: string; ADecimals: Word): ansistring;
begin begin
if IsNan(Value) then if IsNan(Value) then
Result := '' Result := ''
else else
if ANumberFormat = nfSci then if ANumberFormat = nfSci then
Result := SciFloat(Value, 1) Result := SciFloat(Value, ADecimals)
else else
if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then if (ANumberFormat = nfGeneral) or (ANumberFormatStr = '') then
Result := FloatToStr(Value) Result := FloatToStr(Value)
else else
if (ANumberFormat = nfPercentage) then if (ANumberFormat = nfPercentage) then
Result := FormatFloat(ANumberFormatStr, Value*100) + '%' Result := FormatFloat(ANumberFormatStr, Value*100) // '%' is already added to FormatStr.
else else
Result := FormatFloat(ANumberFormatStr, Value); Result := FormatFloat(ANumberFormatStr, Value);
end; end;
function DateTimeToStrNoNaN(const Value: Double; function DateTimeToStrNoNaN(const Value: Double;
ANumberFormat: TsNumberFormat; ANumberFormatStr: String): ansistring; ANumberFormat: TsNumberFormat; ANumberFormatStr: String; ADecimals: Word): ansistring;
begin begin
Result := ''; Result := '';
if not IsNaN(Value) then begin if not IsNaN(Value) then begin
(*
if ANumberFormat = nfTimeInterval then if ANumberFormat = nfTimeInterval then
Result := TimeIntervalToString(Value) Result := TimeIntervalToString(Value, ANumberFormatStr)
else else
*)
if ANumberFormatStr = '' then if ANumberFormatStr = '' then
Result := FormatDateTime('c', Value) Result := FormatDateTime('c', Value)
else else
@ -1152,11 +1165,14 @@ begin
Exit; Exit;
end; end;
case ACell^.ContentType of with ACell^ do
//cctFormula case ContentType of
cctNumber: Result := FloatToStrNoNaN(ACell^.NumberValue, ACell^.NumberFormat, ACell^.NumberFormatStr); cctNumber:
cctUTF8String: Result := ACell^.UTF8StringValue; Result := FloatToStrNoNaN(NumberValue, NumberFormat, NumberFormatStr, NumberDecimals);
cctDateTime: Result := DateTimeToStrNoNaN(ACell^.DateTimeValue, ACell^.NumberFormat, ACell^.NumberFormatStr); cctUTF8String:
Result := UTF8StringValue;
cctDateTime:
Result := DateTimeToStrNoNaN(DateTimeValue, NumberFormat, NumberFormatStr, NumberDecimals);
else else
Result := ''; Result := '';
end; end;
@ -1322,14 +1338,33 @@ begin
nfExp: nfExp:
ACell^.NumberFormatStr := '0' + decs + 'E+00'; ACell^.NumberFormatStr := '0' + decs + 'E+00';
nfSci: nfSci:
ACell^.NumberFormatStr := ''; ACell^.NumberFormatStr := '##0' + decs + 'E+0';
nfPercentage: nfPercentage:
ACell^.NumberFormatStr := '0' + decs; ACell^.NumberFormatStr := '0' + decs + '%';
end; end;
end; end;
ChangedCell(ARow, ACol); ChangedCell(ARow, ACol);
end; 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 Writes as empty cell
@ -1385,6 +1420,8 @@ begin
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat; ACell^.NumberFormatStr := FormatSettings.ShortDateFormat + ' ' + FormatSettings.ShortTimeFormat;
nfShortDate: nfShortDate:
ACell^.NumberFormatStr := FormatSettings.ShortDateFormat; ACell^.NumberFormatStr := FormatSettings.ShortDateFormat;
nfLongDate:
ACell^.NumberFormatStr := 'dd/mmm/yyyy';
nfShortTime: nfShortTime:
ACell^.NumberFormatStr := 't'; ACell^.NumberFormatStr := 't';
nfLongTime: nfLongTime:
@ -1397,13 +1434,14 @@ begin
begin begin
fmt := lowercase(AFormatStr); fmt := lowercase(AFormatStr);
if fmt = 'dm' then ACell^.NumberFormatStr := 'd/mmm' if fmt = 'dm' then ACell^.NumberFormatStr := 'd/mmm'
else if fmt = 'my' then ACell^.NumberFormatSTr := 'mmm/yy' else if fmt = 'my' then ACell^.NumberFormatStr := 'mmm/yy'
else if fmt = 'ms' then ACell^.NumberFormatStr := 'nn:ss' else if fmt = 'ms' then ACell^.NumberFormatStr := 'mm:ss' // Excel does not like the "n"
else if fmt = 'msz' then ACell^.NumberFormatStr := 'nn:ss.z' else if fmt = 'msz' then ACell^.NumberFormatStr := 'mm:ss.z'
else ACell^.NumberFormatStr := AFormatStr; else ACell^.NumberFormatStr := AFormatStr;
end; end;
nfTimeInterval: nfTimeInterval:
ACell^.NumberFormatStr := ''; if AFormatStr = '' then ACell^.NumberFormatStr := '[h]:mm:ss'
else ACell^.NumberFormatStr := AFormatStr;
end; end;
ChangedCell(ARow, ACol); ChangedCell(ARow, ACol);
end; end;
@ -1431,17 +1469,19 @@ end;
@param ARow The row of the cell @param ARow The row of the cell
@param ACol The column of the cell @param ACol The column of the cell
@param TsNumberFormat What format to apply @param TsNumberFormat What format to apply
@param string Formatstring
@see TsNumberFormat @see TsNumberFormat
} }
procedure TsWorksheet.WriteNumberFormat(ARow, ACol: Cardinal; procedure TsWorksheet.WriteNumberFormat(ARow, ACol: Cardinal;
ANumberFormat: TsNumberFormat); ANumberFormat: TsNumberFormat; const AFormatString: String);
var var
ACell: PCell; ACell: PCell;
begin begin
ACell := GetCell(ARow, ACol); ACell := GetCell(ARow, ACol);
Include(ACell^.UsedFormattingFields, uffNumberFormat); Include(ACell^.UsedFormattingFields, uffNumberFormat);
ACell^.NumberFormat := ANumberFormat; ACell^.NumberFormat := ANumberFormat;
ACell^.NumberFormatStr := AFormatString;
ChangedCell(ARow, ACol); ChangedCell(ARow, ACol);
end; end;
@ -2408,12 +2448,310 @@ begin
{$ENDIF} {$ENDIF}
end; 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 } { TsCustomSpreadReader }
constructor TsCustomSpreadReader.Create(AWorkbook: TsWorkbook); constructor TsCustomSpreadReader.Create(AWorkbook: TsWorkbook);
begin begin
inherited Create; inherited Create;
FWorkbook := AWorkbook; FWorkbook := AWorkbook;
CreateNumFormatList;
end;
destructor TsCustomSpreadReader.Destroy;
begin
FNumFormatList.Free;
inherited Destroy;
end; end;
{@@ {@@
@ -2471,6 +2809,13 @@ constructor TsCustomSpreadWriter.Create(AWorkbook: TsWorkbook);
begin begin
inherited Create; inherited Create;
FWorkbook := AWorkbook; FWorkbook := AWorkbook;
CreateNumFormatList;
end;
destructor TsCustomSpreadWriter.Destroy;
begin
FNumFormatList.Free;
inherited Destroy;
end; end;
{@@ {@@
@ -2522,10 +2867,10 @@ begin
if uffNumberFormat in AFormat^.UsedFormattingFields then begin if uffNumberFormat in AFormat^.UsedFormattingFields then begin
if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue; if (FFormattingStyles[i].NumberFormat <> AFormat^.NumberFormat) then Continue;
case AFormat^.NumberFormat of case AFormat^.NumberFormat of
nfFixed, nfFixedTh, nfPercentage, nfExp: nfFixed, nfFixedTh, nfPercentage, nfExp, nfSci:
if (FFormattingStyles[i].NumberDecimals <> AFormat^.NumberDecimals) then Continue; if (FFormattingStyles[i].NumberDecimals <> AFormat^.NumberDecimals) then Continue;
nfShortDate, nfShortDateTime, nfShortTime, nfLongTime, nfShortTimeAM, nfShortDate, nfLongDate, nfShortDateTime, nfShortTime, nfLongTime,
nfLongTimeAM, nfFmtDateTime, nfTimeInterval: nfShortTimeAM, nfLongTimeAM, nfFmtDateTime, nfTimeInterval, nfCustom:
if (FFormattingstyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue; if (FFormattingstyles[i].NumberFormatStr <> AFormat^.NumberFormatStr) then Continue;
end; end;
end; end;
@ -2538,6 +2883,20 @@ begin
end; end;
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. { Each descendent should define it's own default formats, if any.
Always add the normal, unformatted style first to speed up. } Always add the normal, unformatted style first to speed up. }
procedure TsCustomSpreadWriter.AddDefaultFormats(); procedure TsCustomSpreadWriter.AddDefaultFormats();
@ -2550,8 +2909,9 @@ procedure TsCustomSpreadWriter.ListAllFormattingStylesCallback(ACell: PCell; ASt
var var
Len: Integer; Len: Integer;
begin begin
if ACell^.UsedFormattingFields = [] then Exit; FixFormat(ACell);
if ACell^.UsedFormattingFields = [] then Exit;
if FindFormattingInList(ACell) <> -1 then Exit; if FindFormattingInList(ACell) <> -1 then Exit;
Len := Length(FFormattingStyles); Len := Length(FFormattingStyles);
@ -2575,6 +2935,30 @@ begin
end; end;
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, Expands a formula, separating it in it's constituent parts,
so that it is already partially parsed and it is easier to so that it is already partially parsed and it is easier to

View File

@ -1,6 +1,10 @@
{ {
Utility functions and constants from FPSpreadsheet 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; unit fpsutils;
{$mode objfpc}{$H+} {$mode objfpc}{$H+}
@ -59,8 +63,25 @@ function UTF8TextToXMLText(AText: ansistring): ansistring;
function TwipsToMillimeters(AValue: Integer): Single; function TwipsToMillimeters(AValue: Integer): Single;
function MillimetersToTwips(AValue: Single): Integer; 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 implementation
uses
Math;
{ {
Endianess helper functions Endianess helper functions
@ -467,5 +488,663 @@ begin
Result := Round((AValue * 20 * 72) / 25.4); Result := Round((AValue * 20 * 72) / 25.4);
end; 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. end.

View File

@ -38,6 +38,15 @@ uses
type type
{ TsBIFF2NumFormatList }
TsBIFF2NumFormatList = class(TsCustomNumFormatList)
protected
procedure AddBuiltinFormats; override;
public
constructor Create;
function FormatStringForWriting(AIndex: Integer): String; override;
end;
{ TsSpreadBIFF2Reader } { TsSpreadBIFF2Reader }
TsSpreadBIFF2Reader = class(TsSpreadBIFFReader) TsSpreadBIFF2Reader = class(TsSpreadBIFFReader)
@ -47,6 +56,7 @@ type
FFont: TsFont; FFont: TsFont;
protected protected
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); override; procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); override;
procedure CreateNumFormatList; override;
procedure ExtractNumberFormat(AXFIndex: WORD; procedure ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word; out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String); override; out ANumberFormatStr: String); override;
@ -80,9 +90,7 @@ type
procedure WriteEOF(AStream: TStream); procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFontIndex: Integer); procedure WriteFont(AStream: TStream; AFontIndex: Integer);
procedure WriteFonts(AStream: TStream); procedure WriteFonts(AStream: TStream);
procedure WriteFormat(AStream: TStream; AFormatCode: String);
procedure WriteFormatCount(AStream: TStream); procedure WriteFormatCount(AStream: TStream);
procedure WriteFormats(AStream: TStream);
procedure WriteIXFE(AStream: TStream; XFIndex: Word); procedure WriteIXFE(AStream: TStream; XFIndex: Word);
procedure WriteXF(AStream: TStream; AFontIndex, AFormatIndex: byte; procedure WriteXF(AStream: TStream; AFontIndex, AFormatIndex: byte;
ABorders: TsCellBorders = []; AHorAlign: TsHorAlignment = haLeft; ABorders: TsCellBorders = []; AHorAlign: TsHorAlignment = haLeft;
@ -90,12 +98,17 @@ type
procedure WriteXFFieldsForFormattingStyles(AStream: TStream); procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
procedure WriteXFRecords(AStream: TStream); procedure WriteXFRecords(AStream: TStream);
protected protected
procedure CreateNumFormatList; override;
procedure FixFormat(ACell: PCell); override;
procedure ListAllNumFormats; override;
procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); 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 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 WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); override;
procedure WriteRow(AStream: TStream; ASheet: TsWorksheet; procedure WriteRow(AStream: TStream; ASheet: TsWorksheet;
ARowIndex, AFirstColIndex, ALastColIndex: Cardinal; ARow: PRow); override; 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 WriteWindow1(AStream: TStream); override;
procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet); procedure WriteWindow2(AStream: TStream; ASheet: TsWorksheet);
public public
@ -116,7 +129,8 @@ var
$00FFFF // $07: cyan $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 the file. Note that, compared to the BUFF5+ built-in formats, two formats
are missing and the indexes are offset by 2 after #11. are missing and the indexes are offset by 2 after #11.
It seems that BIFF2 can handle only these 21 formats. The other formats It seems that BIFF2 can handle only these 21 formats. The other formats
@ -145,6 +159,7 @@ var
'h:mm:ss', 'h:mm:ss',
'M/D/YY h:mm' // 20 'M/D/YY h:mm' // 20
); );
*)
implementation implementation
@ -177,7 +192,7 @@ const
INT_EXCEL_SHEET = $0010; INT_EXCEL_SHEET = $0010;
INT_EXCEL_CHART = $0020; INT_EXCEL_CHART = $0020;
INT_EXCEL_MACRO_SHEET = $0040; INT_EXCEL_MACRO_SHEET = $0040;
(*
{ FORMAT record constants for BIFF2 } { FORMAT record constants for BIFF2 }
// Subset of the built-in formats for US Excel, // Subset of the built-in formats for US Excel,
// including those needed for date/time output // including those needed for date/time output
@ -206,6 +221,76 @@ const
FORMAT_TIME_MS = 19; //time MM:SS FORMAT_TIME_MS = 19; //time MM:SS
FORMAT_TIME_MSZ = 19; //time MM:SS.0 FORMAT_TIME_MSZ = 19; //time MM:SS.0
FORMAT_TIME_INTERVAL = 19; //time [hh]:mm:ss, hh can be >24 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 } { TsSpreadBIFF2Reader }
@ -252,6 +337,14 @@ begin
end; end;
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. { Extracts the number format data from an XF record indexed by AXFIndex.
Note that BIFF2 supports only 21 formats. } Note that BIFF2 supports only 21 formats. }
procedure TsSpreadBIFF2Reader.ExtractNumberFormat(AXFIndex: WORD; procedure TsSpreadBIFF2Reader.ExtractNumberFormat(AXFIndex: WORD;
@ -270,7 +363,7 @@ const
2, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 11..20 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 11..20
); );
var var
lFormatData: TFormatListData; lNumFormatData: TsNumFormatData;
lXFData: TXFListData; lXFData: TXFListData;
isAMPM: Boolean; isAMPM: Boolean;
isLongTime: Boolean; isLongTime: Boolean;
@ -280,9 +373,9 @@ begin
ANumberFormat := nfGeneral; ANumberFormat := nfGeneral;
ANumberFormatStr := ''; ANumberFormatStr := '';
ADecimals := 0; ADecimals := 0;
(*
lFormatData := FindFormatDataForCell(AXFIndex); lNumFormatData := FindNumFormatDataForCell(AXFIndex);
if lFormatData = nil then begin if lNumFormatData = nil then begin
// no custom format, so first test for default formats // no custom format, so first test for default formats
lXFData := TXFListData (FXFList.Items[AXFIndex]); lXFData := TXFListData (FXFList.Items[AXFIndex]);
if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 20) then begin if (lXFData.FormatIndex > 0) and (lXFData.FormatIndex <= 20) then begin
@ -291,20 +384,20 @@ begin
end; end;
end else end else
// The next is copied from xlscommon - I think it's not necessary here // 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 ANumberFormat := nfPercentage
else else
if IsExpNumberFormat(lFormatData.Formatstring, ADecimals) then if IsExpNumberFormat(lNumFormatData.Formatstring, ADecimals) then
ANumberFormat := nfExp ANumberFormat := nfExp
else else
if IsThousandSepNumberFormat(lFormatData.FormatString, ADecimals) then if IsThousandSepNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixedTh ANumberFormat := nfFixedTh
else else
if IsFixedNumberFormat(lFormatData.FormatString, ADecimals) then if IsFixedNumberFormat(lNumFormatData.FormatString, ADecimals) then
ANumberFormat := nfFixed ANumberFormat := nfFixed
else begin else begin
t := IsTimeFormat(lFormatData.FormatString, isLongTime, isAMPM, isMilliSec); t := IsTimeFormat(lNumFormatData.FormatString, isLongTime, isAMPM, isMilliSec);
d := IsDateFormat(lFormatData.FormatString); d := IsDateFormat(lNumFormatData.FormatString, isLongDate);
if d and t then if d and t then
ANumberFormat := nfShortDateTime ANumberFormat := nfShortDateTime
else else
@ -324,7 +417,7 @@ begin
ANumberFormat := nfShortTime; ANumberFormat := nfShortTime;
end; end;
end; end;
end; end; *)
end; end;
procedure TsSpreadBIFF2Reader.ReadBlank(AStream: TStream); procedure TsSpreadBIFF2Reader.ReadBlank(AStream: TStream);
@ -696,6 +789,14 @@ end;
{ TsSpreadBIFF2Writer } { 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; function TsSpreadBIFF2Writer.FindXFIndex(ACell: PCell): Word;
var var
i: Integer; i: Integer;
@ -712,6 +813,37 @@ begin
end; end;
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. Attaches cell formatting data for the given cell to the current record.
Is called from all writing methods of cell contents. Is called from all writing methods of cell contents.
@ -825,6 +957,7 @@ begin
WriteBOF(AStream); WriteBOF(AStream);
WriteFonts(AStream); WriteFonts(AStream);
WriteFormatCount(AStream);
WriteFormats(AStream); WriteFormats(AStream);
WriteXFRecords(AStream); WriteXFRecords(AStream);
WriteColWidths(AStream); WriteColWidths(AStream);
@ -940,7 +1073,7 @@ end;
procedure TsSpreadBIFF2Writer.WriteXFFieldsForFormattingStyles(AStream: TStream); procedure TsSpreadBIFF2Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var var
i: Integer; i, j: Integer;
lFontIndex: Word; lFontIndex: Word;
lFormatIndex: Word; //number format lFormatIndex: Word; //number format
lBorders: TsCellBorders; lBorders: TsCellBorders;
@ -958,65 +1091,18 @@ begin
lHorAlign := FFormattingStyles[i].HorAlignment; lHorAlign := FFormattingStyles[i].HorAlignment;
// Now apply the modifications. // Now apply the modifications.
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
case FFormattingStyles[i].NumberFormat of j := NumFormatList.Find(@FFormattingStyles[i]);
nfFixed: if j > -1 then begin
case FFormattingStyles[i].NumberDecimals of lFormatIndex := NumFormatList[j].Index;
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: // BIFF2 can only handle the 21 built-in formats. Here we find replacements
case FFormattingStyles[i].NumberDecimals of // for the others.
0: lFormatIndex := FORMAT_CURRENCY_0_DECIMALS; case NumFormatList[j].NumFormat of
2: lFormatIndex := FORMAT_CURRENCY_2_DECIMALS; nfSci : lFormatIndex := 11; // Exp
nfFmtDateTime : if lFormatIndex > 20 then lFormatIndex := 19;
end;}
end; 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;
end; end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then if uffBorder in FFormattingStyles[i].UsedFormattingFields then
@ -1149,6 +1235,24 @@ begin
WriteFont(AStream, i); WriteFont(AStream, i);
end; 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); procedure TsSpreadBIFF2Writer.WriteFormat(AStream: TStream; AFormatCode: String);
var var
len: Integer; len: Integer;
@ -1167,15 +1271,15 @@ begin
{ Write format string } { Write format string }
AStream.WriteByte(len); AStream.WriteByte(len);
AStream.WriteBuffer(s[1], len); AStream.WriteBuffer(s[1], len);
end; end; *)
procedure TsSpreadBIFF2Writer.WriteFormatCount(AStream: TStream); procedure TsSpreadBIFF2Writer.WriteFormatCount(AStream: TStream);
begin begin
AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMATCOUNT)); AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMATCOUNT));
AStream.WriteWord(WordToLE(2)); AStream.WriteWord(WordToLE(2));
AStream.WriteWord(WordToLE(High(NUMFORMAT_BIFF2)+1)); AStream.WriteWord(WordToLE(21)); // there are 21 built-in formats
end; end;
(*
procedure TsSpreadBIFF2Writer.WriteFormats(AStream: TStream); procedure TsSpreadBIFF2Writer.WriteFormats(AStream: TStream);
var var
i: Integer; i: Integer;
@ -1183,7 +1287,7 @@ begin
WriteFormatCount(AStream); WriteFormatCount(AStream);
for i:=0 to High(NUMFORMAT_BIFF2) do for i:=0 to High(NUMFORMAT_BIFF2) do
WriteFormat(AStream, NUMFORMAT_BIFF2[i]); WriteFormat(AStream, NUMFORMAT_BIFF2[i]);
end; end;*)
(* (*
var var
ds, ts: Char; //decimal separator, thousand separator ds, ts: Char; //decimal separator, thousand separator

View File

@ -84,8 +84,6 @@ type
procedure ReadBlank(AStream: TStream); override; procedure ReadBlank(AStream: TStream); override;
procedure ReadFont(const AStream: TStream); procedure ReadFont(const AStream: TStream);
procedure ReadFormat(AStream: TStream); override; procedure ReadFormat(AStream: TStream); override;
procedure ReadFormula(AStream: TStream); override;
procedure ReadFormulaExcel(AStream: TStream);
procedure ReadLabel(AStream: TStream); override; procedure ReadLabel(AStream: TStream); override;
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook); procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook); procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
@ -115,6 +113,8 @@ type
procedure WriteEOF(AStream: TStream); procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont); procedure WriteFont(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream); procedure WriteFonts(AStream: TStream);
procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
AListIndex: Integer); override;
procedure WriteIndex(AStream: TStream); procedure WriteIndex(AStream: TStream);
procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: string; ACell: PCell); override; const AValue: string; ACell: PCell); override;
@ -130,6 +130,7 @@ type
procedure WriteXFFieldsForFormattingStyles(AStream: TStream); procedure WriteXFFieldsForFormattingStyles(AStream: TStream);
procedure WriteXFRecords(AStream: TStream); procedure WriteXFRecords(AStream: TStream);
public public
constructor Create(AWorkbook: TsWorkbook); override;
{ General writing methods } { General writing methods }
procedure WriteToFile(const AFileName: string; procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); override; const AOverwriteExisting: Boolean = False); override;
@ -296,9 +297,21 @@ const
MASK_XF_BKGR_BACKGROUND_COLOR = $00003F80; MASK_XF_BKGR_BACKGROUND_COLOR = $00003F80;
MASK_XF_BKGR_FILLPATTERN = $003F0000; 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 } { TsSpreadBIFF5Writer }
constructor TsSpreadBIFF5Writer.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
end;
{******************************************************************* {*******************************************************************
* TsSpreadBIFF5Writer.WriteToFile () * TsSpreadBIFF5Writer.WriteToFile ()
* *
@ -362,6 +375,7 @@ begin
WriteCodepage(AStream, WorkBookEncoding); WriteCodepage(AStream, WorkBookEncoding);
WriteWindow1(AStream); WriteWindow1(AStream);
WriteFonts(AStream); WriteFonts(AStream);
WriteFormats(AStream);
WritePalette(AStream); WritePalette(AStream);
WriteXFRecords(AStream); WriteXFRecords(AStream);
WriteStyle(AStream); WriteStyle(AStream);
@ -632,6 +646,36 @@ begin
WriteFont(AStream, Workbook.GetFont(i)); WriteFont(AStream, Workbook.GetFont(i));
end; 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 () * TsSpreadBIFF5Writer.WriteRPNFormula ()
* *
@ -1047,7 +1091,7 @@ end;
procedure TsSpreadBIFF5Writer.WriteXFFieldsForFormattingStyles(AStream: TStream); procedure TsSpreadBIFF5Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var var
i: Integer; i, j: Integer;
lFontIndex: Word; lFontIndex: Word;
lFormatIndex: Word; //number format lFormatIndex: Word; //number format
lTextRotation: Byte; lTextRotation: Byte;
@ -1073,77 +1117,17 @@ begin
lBackgroundColor := FFormattingStyles[i].BackgroundColor; lBackgroundColor := FFormattingStyles[i].BackgroundColor;
// Now apply the modifications. // Now apply the modifications.
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
case FFormattingStyles[i].NumberFormat of j := NumFormatList.Find(@FFormattingStyles[i]);
nfFixed: if j > -1 then
case FFormattingStyles[i].NumberDecimals of lFormatIndex := NumFormatList[j].Index;
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; end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border; lBorders := FFormattingStyles[i].Border;
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
begin lTextRotation := TEXT_ROTATIONS[FFormattingStyles[i].TextRotation];
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;
if uffBold in FFormattingStyles[i].UsedFormattingFields then if uffBold in FFormattingStyles[i].UsedFormattingFields then
lFontIndex := 1; // must be before uffFont which overrides uffBold lFontIndex := 1; // must be before uffFont which overrides uffBold
@ -1270,7 +1254,7 @@ begin
INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream); INT_EXCEL_ID_MULRK : ReadMulRKValues(AStream);
INT_EXCEL_ID_COLINFO : ReadColInfo(AStream); INT_EXCEL_ID_COLINFO : ReadColInfo(AStream);
INT_EXCEL_ID_ROW : ReadRowInfo(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_WINDOW2 : ReadWindow2(AStream);
INT_EXCEL_ID_PANE : ReadPane(AStream); INT_EXCEL_ID_PANE : ReadPane(AStream);
INT_EXCEL_ID_BOF : ; INT_EXCEL_ID_BOF : ;
@ -1376,32 +1360,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF); ApplyCellFormatting(ARow, ACol, XF);
end; 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); procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
var var
MemStream: TMemoryStream; MemStream: TMemoryStream;
@ -1638,12 +1596,10 @@ end;
// Read the FORMAT record for formatting numerical data // Read the FORMAT record for formatting numerical data
procedure TsSpreadBIFF5Reader.ReadFormat(AStream: TStream); procedure TsSpreadBIFF5Reader.ReadFormat(AStream: TStream);
var var
lData: TFormatListData;
str: AnsiString;
len: byte; len: byte;
fmtIndex: Integer;
fmtString: AnsiString;
begin begin
lData := TFormatListData.Create;
// Record FORMAT, BIFF 8 (5.49): // Record FORMAT, BIFF 8 (5.49):
// Offset Size Contents // Offset Size Contents
// 0 2 Format index used in other records // 0 2 Format index used in other records
@ -1651,21 +1607,15 @@ begin
// From BIFF5 on: indexes 0..163 are built in // From BIFF5 on: indexes 0..163 are built in
// format index // format index
lData.Index := WordLEtoN(AStream.ReadWord); fmtIndex := WordLEtoN(AStream.ReadWord);
// number format string // number format string
len := AStream.ReadByte; len := AStream.ReadByte;
SetLength(str, len); SetLength(fmtString, len);
AStream.ReadBuffer(str[1], len); AStream.ReadBuffer(fmtString[1], len);
lData.FormatString := str;
// Add to the list // Add to the list
FFormatList.Add(lData); NumFormatList.AnalyzeAndAdd(fmtIndex, fmtString);
end;
procedure TsSpreadBIFF5Reader.ReadFormula(AStream: TStream);
begin
end; end;
procedure TsSpreadBIFF5Reader.ReadLabel(AStream: TStream); procedure TsSpreadBIFF5Reader.ReadLabel(AStream: TStream);

View File

@ -89,7 +89,6 @@ type
procedure ReadFormat(AStream: TStream); override; procedure ReadFormat(AStream: TStream); override;
{ Record reading methods } { Record reading methods }
procedure ReadBlank(AStream: TStream); override; procedure ReadBlank(AStream: TStream); override;
procedure ReadFormula(AStream: TStream); override;
procedure ReadLabel(AStream: TStream); override; procedure ReadLabel(AStream: TStream); override;
procedure ReadRichString(const AStream: TStream); procedure ReadRichString(const AStream: TStream);
public public
@ -115,6 +114,8 @@ type
procedure WriteEOF(AStream: TStream); procedure WriteEOF(AStream: TStream);
procedure WriteFont(AStream: TStream; AFont: TsFont); procedure WriteFont(AStream: TStream; AFont: TsFont);
procedure WriteFonts(AStream: TStream); procedure WriteFonts(AStream: TStream);
procedure WriteFormat(AStream: TStream; AFormatData: TsNumFormatData;
AListIndex: Integer); override;
procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteFormula(AStream: TStream; const ARow, ACol: Cardinal;
const AFormula: TsFormula; ACell: PCell); override; const AFormula: TsFormula; ACell: PCell); override;
procedure WriteIndex(AStream: TStream); procedure WriteIndex(AStream: TStream);
@ -131,6 +132,7 @@ type
AddBackground: Boolean = false; ABackgroundColor: TsColor = scSilver); AddBackground: Boolean = false; ABackgroundColor: TsColor = scSilver);
procedure WriteXFRecords(AStream: TStream); procedure WriteXFRecords(AStream: TStream);
public public
constructor Create(AWorkbook: TsWorkbook); override;
{ General writing methods } { General writing methods }
procedure WriteToFile(const AFileName: string; procedure WriteToFile(const AFileName: string;
const AOverwriteExisting: Boolean = False); override; const AOverwriteExisting: Boolean = False); override;
@ -263,12 +265,24 @@ const
MASK_XF_BORDER_TOP_COLOR = $0000007F; MASK_XF_BORDER_TOP_COLOR = $0000007F;
MASK_XF_BORDER_BOTTOM_COLOR = $00003F80; 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 } { TsSpreadBIFF8Writer }
constructor TsSpreadBIFF8Writer.Create(AWorkbook: TsWorkbook);
begin
inherited Create(AWorkbook);
end;
procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(AStream: TStream); procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(AStream: TStream);
var var
i: Integer; i, j: Integer;
lFontIndex: Word; lFontIndex: Word;
lFormatIndex: Word; //number format lFormatIndex: Word; //number format
lTextRotation: Byte; lTextRotation: Byte;
@ -281,7 +295,7 @@ var
lWordWrap: Boolean; lWordWrap: Boolean;
fmt: String; fmt: String;
begin 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 for i := 1 to Length(FFormattingStyles) - 1 do begin
// Default styles // Default styles
lFontIndex := 0; lFontIndex := 0;
@ -294,77 +308,17 @@ begin
lBackgroundColor := FFormattingStyles[i].BackgroundColor; lBackgroundColor := FFormattingStyles[i].BackgroundColor;
// Now apply the modifications. // Now apply the modifications.
if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then if uffNumberFormat in FFormattingStyles[i].UsedFormattingFields then begin
case FFormattingStyles[i].NumberFormat of j := NumFormatList.Find(@FFormattingStyles[i]);
nfFixed: if j > -1 then
case FFormattingStyles[i].NumberDecimals of lFormatIndex := NumFormatList[j].Index;
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; end;
if uffBorder in FFormattingStyles[i].UsedFormattingFields then if uffBorder in FFormattingStyles[i].UsedFormattingFields then
lBorders := FFormattingStyles[i].Border; lBorders := FFormattingStyles[i].Border;
if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then if uffTextRotation in FFormattingStyles[i].UsedFormattingFields then
begin lTextRotation := TEXT_ROTATIONS[FFormattingStyles[i].TextRotation];
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;
if uffBold in FFormattingStyles[i].UsedFormattingFields then if uffBold in FFormattingStyles[i].UsedFormattingFields then
lFontIndex := 1; // must be before uffFont which overrides uffBold lFontIndex := 1; // must be before uffFont which overrides uffBold
@ -445,6 +399,7 @@ begin
WriteWindow1(AStream); WriteWindow1(AStream);
WriteFonts(AStream); WriteFonts(AStream);
WriteFormats(AStream);
WritePalette(AStream); WritePalette(AStream);
WriteXFRecords(AStream); WriteXFRecords(AStream);
WriteStyle(AStream); WriteStyle(AStream);
@ -713,6 +668,34 @@ begin
WriteFont(AStream, Workbook.GetFont(i)); WriteFont(AStream, Workbook.GetFont(i));
end; 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 () * TsSpreadBIFF8Writer.WriteFormula ()
* *
@ -1435,16 +1418,16 @@ begin
if RecordType <> INT_EXCEL_ID_CONTINUE then begin if RecordType <> INT_EXCEL_ID_CONTINUE then begin
case RecordType of case RecordType of
INT_EXCEL_ID_BOF: ; INT_EXCEL_ID_BOF : ;
INT_EXCEL_ID_BOUNDSHEET: ReadBoundSheet(AStream); INT_EXCEL_ID_BOUNDSHEET: ReadBoundSheet(AStream);
INT_EXCEL_ID_EOF: SectionEOF := True; INT_EXCEL_ID_EOF : SectionEOF := True;
INT_EXCEL_ID_SST: ReadSST(AStream); INT_EXCEL_ID_SST : ReadSST(AStream);
INT_EXCEL_ID_CODEPAGE: ReadCodepage(AStream); INT_EXCEL_ID_CODEPAGE : ReadCodepage(AStream);
INT_EXCEL_ID_FONT: ReadFont(AStream); INT_EXCEL_ID_FONT : ReadFont(AStream);
INT_EXCEL_ID_XF: ReadXF(AStream); INT_EXCEL_ID_FORMAT : ReadFormat(AStream);
INT_EXCEL_ID_FORMAT: ReadFormat(AStream); INT_EXCEL_ID_XF : ReadXF(AStream);
INT_EXCEL_ID_DATEMODE: ReadDateMode(AStream); INT_EXCEL_ID_DATEMODE : ReadDateMode(AStream);
INT_EXCEL_ID_PALETTE: ReadPalette(AStream); INT_EXCEL_ID_PALETTE : ReadPalette(AStream);
else else
// nothing // nothing
end; end;
@ -1624,51 +1607,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF); ApplyCellFormatting(ARow, ACol, XF);
end; 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); procedure TsSpreadBIFF8Reader.ReadLabel(AStream: TStream);
var var
L: Word; L: Word;
@ -1975,22 +1913,21 @@ end;
// Read the FORMAT record for formatting numerical data // Read the FORMAT record for formatting numerical data
procedure TsSpreadBIFF8Reader.ReadFormat(AStream: TStream); procedure TsSpreadBIFF8Reader.ReadFormat(AStream: TStream);
var var
lData: TFormatListData; fmtString: String;
fmtIndex: Integer;
begin begin
lData := TFormatListData.Create;
// Record FORMAT, BIFF 8 (5.49): // Record FORMAT, BIFF 8 (5.49):
// Offset Size Contents // Offset Size Contents
// 0 2 Format index used in other records // 0 2 Format index used in other records
// 2 var Number format string (Unicode string, 16-bit string length) // 2 var Number format string (Unicode string, 16-bit string length)
// From BIFF5 on: indexes 0..163 are built in // 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) // 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 // Add to the list
FFormatList.Add(lData); NumFormatList.AnalyzeAndAdd(fmtIndex, fmtString);
end; end;

View File

@ -236,7 +236,7 @@ const
{ DATEMODE record, 5.28 } { DATEMODE record, 5.28 }
DATEMODE_1900_BASE=1; //1/1/1900 minus 1 day in FPC TDateTime DATEMODE_1900_BASE=1; //1/1/1900 minus 1 day in FPC TDateTime
DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime DATEMODE_1904_BASE=1462; //1/1/1904 in FPC TDateTime
(*
{ FORMAT record constants for BIFF5-BIFF8} { FORMAT record constants for BIFF5-BIFF8}
// Subset of the built-in formats for US Excel, // Subset of the built-in formats for US Excel,
// including those needed for date/time output // 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_INTERVAL = 46; //time [hh]:mm:ss, hh can be >24
FORMAT_TIME_MSZ = 47; //time MM:SS.0 FORMAT_TIME_MSZ = 47; //time MM:SS.0
FORMAT_SCI_1_DECIMAL = 48; //scientific, 1 decimal FORMAT_SCI_1_DECIMAL = 48; //scientific, 1 decimal
*)
{ WINDOW1 record constants - BIFF5-BIFF8 } { WINDOW1 record constants - BIFF5-BIFF8 }
MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001; MASK_WINDOW1_OPTION_WINDOW_HIDDEN = $0001;
@ -361,11 +362,12 @@ type
BackgroundColor: TsColor; BackgroundColor: TsColor;
end; end;
{ Contents of the format record for BIFF5/8 } { TsBIFFNumFormatList }
TFormatListData = class TsBIFFNumFormatList = class(TsCustomNumFormatList)
protected
procedure AddBuiltinFormats; override;
public public
Index: Integer; function FormatStringForWriting(AIndex: Integer): String; override;
FormatString: widestring;
end; end;
{ TsSpreadBIFFReader } { TsSpreadBIFFReader }
@ -376,8 +378,8 @@ type
FDateMode: TDateMode; FDateMode: TDateMode;
FPaletteFound: Boolean; FPaletteFound: Boolean;
FXFList: TFPList; // of TXFListData FXFList: TFPList; // of TXFListData
FFormatList: TFPList; // of TFormatListData
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual; procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual;
procedure CreateNumFormatList; override;
// Extracts a number out of an RK value // Extracts a number out of an RK value
function DecodeRKValue(const ARK: DWORD): Double; function DecodeRKValue(const ARK: DWORD): Double;
// Returns the numberformat for a given XF record // Returns the numberformat for a given XF record
@ -386,7 +388,7 @@ type
out ANumberFormatStr: String); virtual; out ANumberFormatStr: String); virtual;
// Finds format record for XF record pointed to by cell // Finds format record for XF record pointed to by cell
// Will not return info for built-in formats // 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 // 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; 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 // Here we can add reading of records which didn't change across BIFF5-8 versions
@ -397,6 +399,8 @@ type
procedure ReadDateMode(AStream: TStream); procedure ReadDateMode(AStream: TStream);
// Read FORMAT record (cell formatting) // Read FORMAT record (cell formatting)
procedure ReadFormat(AStream: TStream); virtual; procedure ReadFormat(AStream: TStream); virtual;
// Read FORMULA record
procedure ReadFormula(AStream: TStream); override;
// Read multiple blank cells // Read multiple blank cells
procedure ReadMulBlank(AStream: TStream); procedure ReadMulBlank(AStream: TStream);
// Read multiple RK cells // Read multiple RK cells
@ -428,6 +432,7 @@ type
FLastRow: Integer; FLastRow: Integer;
FLastCol: Word; FLastCol: Word;
procedure AddDefaultFormats; override; procedure AddDefaultFormats; override;
procedure CreateNumFormatList; override;
procedure GetLastRowCallback(ACell: PCell; AStream: TStream); procedure GetLastRowCallback(ACell: PCell; AStream: TStream);
function GetLastRowIndex(AWorksheet: TsWorksheet): Integer; function GetLastRowIndex(AWorksheet: TsWorksheet): Integer;
procedure GetLastColCallback(ACell: PCell; AStream: TStream); procedure GetLastColCallback(ACell: PCell; AStream: TStream);
@ -453,6 +458,11 @@ type
// Writes out a TIME/DATE/TIMETIME // Writes out a TIME/DATE/TIMETIME
procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: TDateTime; ACell: PCell); override; 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 // Writes out a floating point NUMBER record
procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal;
const AValue: Double; ACell: PCell); override; const AValue: Double; ACell: PCell); override;
@ -478,17 +488,38 @@ type
destructor Destroy; override; destructor Destroy; override;
end; 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 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( function ConvertExcelDateTimeToDateTime(
const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime; const AExcelDateNum: Double; ADateMode: TDateMode): TDateTime;
begin begin
@ -540,13 +571,75 @@ begin
end; 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 } { TsSpreadBIFFReader }
constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook); constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
begin begin
inherited Create(AWorkbook); inherited Create(AWorkbook);
FXFList := TFPList.Create; FXFList := TFPList.Create;
FFormatList := TFPList.Create;
// Initial base date in case it won't be read from file // Initial base date in case it won't be read from file
FDateMode := dm1900; FDateMode := dm1900;
end; end;
@ -557,8 +650,6 @@ var
begin begin
for j := FXFList.Count-1 downto 0 do TObject(FXFList[j]).Free; for j := FXFList.Count-1 downto 0 do TObject(FXFList[j]).Free;
FXFList.Free; FXFList.Free;
for j := FFormatList.Count-1 downto 0 do TObject(FFormatList[j]).Free;
FFormatList.Free;
inherited Destroy; inherited Destroy;
end; end;
@ -614,6 +705,15 @@ begin
end; end;
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. { Extracts a number out of an RK value.
Valid since BIFF3. } Valid since BIFF3. }
function TsSpreadBIFFReader.DecodeRKValue(const ARK: DWORD): Double; function TsSpreadBIFFReader.DecodeRKValue(const ARK: DWORD): Double;
@ -651,120 +751,51 @@ end;
procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD; procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word; out ANumberFormat: TsNumberFormat; out ADecimals: Word;
out ANumberFormatStr: String); out ANumberFormatStr: String);
const
{ see ➜ 5.49 } procedure FixMilliseconds;
NOT_USED = nfGeneral; var
fmts: array[1..58] of TsNumberFormat = ( isLong, isAMPM, isInterval: Boolean;
nfFixed, nfFixed, nfFixedTh, nfFixedTh, nfFixedTh, // 1..5 decs: Word;
nfFixedTh, nfFixedTh, nfFixedTh, nfPercentage, nfPercentage, // 6..10 i: Integer;
nfExp, NOT_USED, NOT_USED, nfShortDate, nfShortDate, // 11..15 begin
nfFmtDateTime, nfFmtDateTime, nfShortTimeAM, nfLongTimeAM, nfShortTime, // 16..20 if IsTimeFormat(ANumberFormatStr, isLong, isAMPM, isInterval, decs)
nfLongTime, nfShortDateTime, NOT_USED, NOT_USED, NOT_USED, // 21..25 and (decs > 0)
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 26..30 then
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 31..35 for i:= Length(ANumberFormatStr) downto 1 do
NOT_USED, nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, // 36..40 case ANumberFormatStr[i] of
nfFixedTh, nfFixedTh, nfFixedTh, nfFixedTh, nfFmtDateTime, // 41..45 '0': ANumberFormatStr[i] := 'z';
nfTimeInterval, nfFmtDateTime, nfSci, NOT_USED, NOT_USED, // 46..50 '.': break;
NOT_USED, NOT_USED, NOT_USED, NOT_USED, NOT_USED, // 51..55 end;
NOT_USED, NOT_USED, NOT_USED // 56..58 end;
);
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 var
lFormatData: TFormatListData; lNumFormatData: TsNumFormatData;
lXFData: TXFListData;
isAMPM: Boolean;
isLongTime: Boolean;
isMilliSec: Boolean;
t,d: Boolean;
begin begin
lNumFormatData := FindNumFormatDataForCell(AXFIndex);
if lNumFormatData <> nil then begin
ANumberFormat := lNumFormatData.NumFormat;
ANumberFormatStr := lNumFormatData.FormatString;
ADecimals := lNumFormatData.Decimals;
FixMilliseconds;
end else begin
ANumberFormat := nfGeneral; ANumberFormat := nfGeneral;
ANumberFormatStr := ''; ANumberFormatStr := '';
ADecimals := 0; 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];
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; end;
end; end;
{ Determines the format data (for numerical formatting) which belong to a given { Determines the format data (for numerical formatting) which belong to a given
XF record. XF record. }
Does not return data for built-in formats. } function TsSpreadBIFFReader.FindNumFormatDataForCell(const AXFIndex: Integer
function TsSpreadBIFFReader.FindFormatDataForCell(const AXFIndex: Integer ): TsNumFormatData;
): TFormatListData;
var var
lXFData: TXFListData; lXFData: TXFListData;
i: Integer; i: Integer;
begin 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; Result := nil;
lXFData := TXFListData(FXFList.Items[AXFIndex]);
i := NumFormatList.Find(lXFData.FormatIndex);
if i <> -1 then Result := NumFormatList[i];
end; end;
{ Convert the number to a date/time and return that if it is } { 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; ANumberFormat: TsNumberFormat; var ADateTime: TDateTime): boolean;
begin begin
if ANumberFormat in [ if ANumberFormat in [
nfShortDateTime, nfFmtDateTime, nfShortDate, nfShortDateTime, nfFmtDateTime, nfShortDate, nfLongDate,
nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM] then nfShortTime, nfLongTime, nfShortTimeAM, nfLongTimeAM] then
begin begin
ADateTime := ConvertExcelDateTimeToDateTime(Number, FDateMode); ADateTime := ConvertExcelDateTimeToDateTime(Number, FDateMode);
@ -788,7 +819,7 @@ begin
end; end;
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); procedure TsSpreadBIFFReader.ReadCodePage(AStream: TStream);
var var
lCodePage: Word; lCodePage: Word;
@ -892,6 +923,76 @@ begin
// to be overridden // to be overridden
end; 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 // Reads multiple blank cell records
// Valid for BIFF5 and BIFF8 (does not exist before) // Valid for BIFF5 and BIFF8 (does not exist before)
procedure TsSpreadBIFFReader.ReadMulBlank(AStream: TStream); procedure TsSpreadBIFFReader.ReadMulBlank(AStream: TStream);
@ -1168,6 +1269,15 @@ begin
// "15" is the index of the last pre-defined xf record // "15" is the index of the last pre-defined xf record
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 TsSpreadBIFFWriter.CreateNumFormatList;
begin
FreeAndNil(FNumFormatList);
FNumFormatList := TsBIFFNumFormatList.Create;
end;
function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID( function TsSpreadBIFFWriter.FormulaElementKindToExcelTokenID(
AElementKind: TFEKind; out ASecondaryID: Word): Word; AElementKind: TFEKind; out ASecondaryID: Word): Word;
const const
@ -1469,6 +1579,30 @@ begin
WriteNumber(AStream, ARow, ACol, ExcelDateSerial, ACell); WriteNumber(AStream, ARow, ACol, ExcelDateSerial, ACell);
end; 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. { Writes a 64-bit floating point NUMBER record.
Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure.). } Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure.). }
procedure TsSpreadBIFFWriter.WriteNumber(AStream: TStream; procedure TsSpreadBIFFWriter.WriteNumber(AStream: TStream;
@ -1806,204 +1940,5 @@ begin
AStream.WriteWord(WordToLE(lXFIndex)); AStream.WriteWord(WordToLE(lXFIndex));
end; 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. end.